From c124948456f233dd1a906099ab1ca0217d574dd1 Mon Sep 17 00:00:00 2001 From: codezapper Date: Sun, 22 Jan 2017 18:42:52 +0100 Subject: [PATCH 01/88] Python cleanup --- PyLister/lister/data_utils.py | 52 ++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index c0eaa39..32f1659 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -21,27 +21,12 @@ def data_for_songs_list(request, search_string=''): sql = 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id ''' if (len(search_filters) > 0): - query_strings = [] - for search_filter in search_filters: - query_strings.append( - '((artist like %s or album like %s) and title like %s)') - filter_query = ' (' + ' OR '.join(query_strings) + ') ' - - for search_filter in search_filters: - search_params.append('%' + search_filter[0] + '%') - search_params.append('%' + search_filter[0] + '%') - search_params.append('%' + search_filter[1] + '%') + (filter_query, query_params) = get_data_for_search_filters(search_filters) + search_params.extend(query_params) if (len(search_words) > 0): - section = 'songs' - string_conditions = [] - for i in (range(len(search_words))): - string_conditions.append( - '( title like %s or lister_album.description like %s or lister_artist.description like %s)') - word_query = '(' + ' OR '.join(string_conditions) + ')' - for search_word in search_words: - for i in range(0, 3): - search_params.append('%' + search_word + '%') + (word_query, query_params) = get_data_for_search_words(search_words) + search_params.extend(query_params) if (len(search_filters) > 0) and (len(search_words) > 0): sql += ' AND (' + filter_query + ' OR ' + word_query + ')' @@ -68,6 +53,35 @@ def data_for_songs_list(request, search_string=''): return JsonResponse(context) +def get_data_for_search_filters(search_filters): + query_strings = [] + for search_filter in search_filters: + query_strings.append( + '((artist like %s or album like %s) and title like %s)') + filter_query = ' (' + ' OR '.join(query_strings) + ') ' + + search_params = [] + for search_filter in search_filters: + search_params.append('%' + search_filter[0] + '%') + search_params.append('%' + search_filter[0] + '%') + search_params.append('%' + search_filter[1] + '%') + + return (filter_query, search_params) + + +def get_data_for_search_words(search_words): + string_conditions = [] + for i in (range(len(search_words))): + string_conditions.append( + '( title like %s or lister_album.description like %s or lister_artist.description like %s)') + word_query = '(' + ' OR '.join(string_conditions) + ')' + search_params = [] + for search_word in search_words: + for i in range(0, 3): + search_params.append('%' + search_word + '%') + return (word_query, search_params) + + def get_counters(): counters = {} cursor = connection.cursor() From f229c4e2f6688f5951fcf4a4f5543dfe0f35c36f Mon Sep 17 00:00:00 2001 From: codezapper Date: Mon, 23 Jan 2017 18:57:37 +0100 Subject: [PATCH 02/88] !WIP! Adding multi-filter , TODO: fix multi selection --- PyLister/lister/data_utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 32f1659..55a05ff 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -54,17 +54,17 @@ def data_for_songs_list(request, search_string=''): def get_data_for_search_filters(search_filters): - query_strings = [] + single_queries = [] for search_filter in search_filters: - query_strings.append( - '((artist like %s or album like %s) and title like %s)') - filter_query = ' (' + ' OR '.join(query_strings) + ') ' + query_strings = ['(artist like %s or album like %s or title like %s)'] * len(search_filter) + single_queries.append(' AND '.join(query_strings)) + + filter_query = ' (' + ' OR '.join(single_queries) + ') ' search_params = [] for search_filter in search_filters: - search_params.append('%' + search_filter[0] + '%') - search_params.append('%' + search_filter[0] + '%') - search_params.append('%' + search_filter[1] + '%') + for filter_term in search_filter: + search_params.extend(['%' + filter_term + '%'] * 3) return (filter_query, search_params) From 1b4cc8f7fa5460cc026ec6f336a045a72f5de6ba Mon Sep 17 00:00:00 2001 From: codezapper Date: Tue, 24 Jan 2017 16:14:47 +0100 Subject: [PATCH 03/88] Add files via upload --- doubly_linked_list.py | 76 +++++++++++++++++++++++++++++++++++++++++++ singly_linked_list.py | 69 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 doubly_linked_list.py create mode 100644 singly_linked_list.py diff --git a/doubly_linked_list.py b/doubly_linked_list.py new file mode 100644 index 0000000..ed373a5 --- /dev/null +++ b/doubly_linked_list.py @@ -0,0 +1,76 @@ +class Node(): + def __init__(self, payload): + self.payload = payload + self.prev = None + self.next = None + +class DoubleList(): + def __init__(self): + self.head = None + self.tail = None + + + def append(self, payload): + new_node = Node(payload) + new_node.prev = self.tail + + if self.tail is None: + self.head = self.tail = new_node + else: + temp_node = self.tail + self.tail.next = new_node + self.tail = self.tail.next + self.tail.prev = temp_node + + + def reverse(self): + current_node = self.head + temp_node = None + while current_node is not None: + temp_node = current_node.prev; + current_node.prev = current_node.next; + current_node.next = temp_node; + current_node = current_node.prev + + self.head = temp_node.prev + + + def remove(self, node_value): + current_node = self.head + + while current_node is not None: + if current_node.payload == node_value: + if current_node.prev is not None: + current_node.prev.next = current_node.next + current_node.next.prev = current_node.prev + else: + self.head = current_node.next + current_node.next.prev = None + + current_node = current_node.next + + + def show(self): + current_node = self.head + while current_node is not None: + print( current_node.payload) + current_node = current_node.next + + +d = DoubleList() + +d.append(1) +d.append(2) +d.append(3) +d.append(4) + +d.show() + +d.reverse() + +d.show() + +# d.remove(50) +# d.remove(5) + +# d.show() \ No newline at end of file diff --git a/singly_linked_list.py b/singly_linked_list.py new file mode 100644 index 0000000..b751173 --- /dev/null +++ b/singly_linked_list.py @@ -0,0 +1,69 @@ +class Node(): + def __init__(self, payload): + self.payload = payload + self.next = None + +class DoubleList(): + def __init__(self): + self.head = None + self.tail = None + + def append(self, payload): + new_node = Node(payload) + new_node.next = None + + if (self.tail is not None): + self.tail.next = new_node + self.tail = self.tail.next + else: + self.head = new_node + self.tail = self.head + + def reverse(self): + current_node = self.head + last_node = None + while (current_node is not None): + temp_node = current_node.next + current_node.next, last_node = last_node, current_node + current_node = temp_node + + return last_node + + def reverse_r(self, current_node): + if (current_node is None): + return None + + temp_node = current_node.next; + if (temp_node is None): + return None + + self.reverse_r(temp_node); + temp_node.next = current_node; + current_node.next = None; + current_node = temp_node; + return self.tail + + def print_payload(self): + current_node = self.head + while current_node is not None: + print( current_node.payload) + current_node = current_node.next + + +d = DoubleList() + +d.append(1) +d.append(2) +d.append(3) +d.append(4) + +d.print_payload() + +d.head = d.reverse_r(d.head) + +d.print_payload() + +# d.remove(50) +# d.remove(5) + +# d.show() \ No newline at end of file From a372f68e26cb5ed32c96f64582b115532ad72564 Mon Sep 17 00:00:00 2001 From: codezapper Date: Tue, 24 Jan 2017 22:53:59 +0100 Subject: [PATCH 04/88] Added shuffle filter --- PyLister/lister/data_utils.py | 49 ++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 55a05ff..534e1b9 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -18,24 +18,26 @@ def data_for_songs_list(request, search_string=''): section = '' search_params = [] cursor = connection.cursor() - sql = 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id ''' + # sql = 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id ''' + sql = '' if (len(search_filters) > 0): - (filter_query, query_params) = get_data_for_search_filters(search_filters) + (filter_query, query_params) = get_search_filters_sql(search_filters) search_params.extend(query_params) + sql = filter_query - if (len(search_words) > 0): - (word_query, query_params) = get_data_for_search_words(search_words) - search_params.extend(query_params) + # if (len(search_words) > 0): + # (word_query, query_params) = get_data_for_search_words(search_words) + # search_params.extend(query_params) - if (len(search_filters) > 0) and (len(search_words) > 0): - sql += ' AND (' + filter_query + ' OR ' + word_query + ')' - elif len(search_filters) > 0: - sql += ' AND ' + filter_query - elif len(search_words) > 0: - sql += ' AND ' + word_query + # if (len(search_filters) > 0) and (len(search_words) > 0): + # sql += ' AND (' + filter_query + ' OR ' + word_query + ')' + # elif len(search_filters) > 0: + # sql += ' AND ' + filter_query + # elif len(search_words) > 0: + # sql += ' AND ' + word_query - sql += ' ORDER BY lister_song.artist_id, lister_album.album_id, track_number' + # sql += ' ORDER BY lister_song.artist_id, lister_album.album_id, track_number' songs_list = [] track_index = 0 @@ -53,13 +55,30 @@ def data_for_songs_list(request, search_string=''): return JsonResponse(context) -def get_data_for_search_filters(search_filters): +def get_search_filters_sql(search_filters): single_queries = [] + must_shuffle = [] for search_filter in search_filters: - query_strings = ['(artist like %s or album like %s or title like %s)'] * len(search_filter) + if (search_filter[0] == 'shuffle'): + search_filter.pop(0) + must_shuffle.append(True) + else: + must_shuffle.append(False) + query_strings = [ + '(artist like %s or album like %s or title like %s)'] * len(search_filter) single_queries.append(' AND '.join(query_strings)) - filter_query = ' (' + ' OR '.join(single_queries) + ') ' + single_statements = [] + index = 0 + for single_query in single_queries: + sql = 'SELECT * FROM (SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ' + single_query + if (must_shuffle[index]): + sql += ' ORDER BY RANDOM() ' + sql += ')' + single_statements.append(sql) + index += 1 + + filter_query = ' UNION '.join(single_statements) search_params = [] for search_filter in search_filters: From ee6bf25915f2e8434915f497d0de7466bd57539b Mon Sep 17 00:00:00 2001 From: codezapper Date: Tue, 24 Jan 2017 23:09:51 +0100 Subject: [PATCH 05/88] Added multi-query --- PyLister/lister/data_utils.py | 37 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 534e1b9..bb7c3c2 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -18,26 +18,27 @@ def data_for_songs_list(request, search_string=''): section = '' search_params = [] cursor = connection.cursor() - # sql = 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id ''' sql = '' + filter_query_sql = '' + word_query_sql = '' if (len(search_filters) > 0): - (filter_query, query_params) = get_search_filters_sql(search_filters) + (filter_query_sql, query_params) = get_search_filters_sql(search_filters) search_params.extend(query_params) - sql = filter_query - # if (len(search_words) > 0): - # (word_query, query_params) = get_data_for_search_words(search_words) - # search_params.extend(query_params) + if (len(search_words) > 0): + (word_query_sql, query_params) = get_word_query_sql(search_words) + search_params.extend(query_params) - # if (len(search_filters) > 0) and (len(search_words) > 0): - # sql += ' AND (' + filter_query + ' OR ' + word_query + ')' - # elif len(search_filters) > 0: - # sql += ' AND ' + filter_query - # elif len(search_words) > 0: - # sql += ' AND ' + word_query + print filter_query_sql + print word_query_sql - # sql += ' ORDER BY lister_song.artist_id, lister_album.album_id, track_number' + if (len(search_filters) > 0) and (len(search_words) > 0): + sql += filter_query_sql + ' UNION ' + word_query_sql + elif len(search_filters) > 0: + sql += filter_query_sql + elif len(search_words) > 0: + sql += word_query_sql songs_list = [] track_index = 0 @@ -88,12 +89,12 @@ def get_search_filters_sql(search_filters): return (filter_query, search_params) -def get_data_for_search_words(search_words): - string_conditions = [] +def get_word_query_sql(search_words): + single_statements = [] for i in (range(len(search_words))): - string_conditions.append( - '( title like %s or lister_album.description like %s or lister_artist.description like %s)') - word_query = '(' + ' OR '.join(string_conditions) + ')' + single_statements.append( + 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ( title like %s or lister_album.description like %s or lister_artist.description like %s)') + word_query = ' UNION '.join(single_statements) search_params = [] for search_word in search_words: for i in range(0, 3): From 64c99c7245e7f0c8acc538417414b1c2d4b97aaf Mon Sep 17 00:00:00 2001 From: codezapper Date: Tue, 24 Jan 2017 23:18:51 +0100 Subject: [PATCH 06/88] !WIP! Removed shuffle on DB, adding shuffle in code --- PyLister/lister/data_utils.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index bb7c3c2..0c640df 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -15,7 +15,6 @@ def data_for_songs_list(request, search_string=''): search_words = [ search_word for search_word in all_search_words if ':' not in search_word] - section = '' search_params = [] cursor = connection.cursor() sql = '' @@ -23,16 +22,13 @@ def data_for_songs_list(request, search_string=''): word_query_sql = '' if (len(search_filters) > 0): - (filter_query_sql, query_params) = get_search_filters_sql(search_filters) + (filter_query_sql, query_params, _) = get_search_filters_sql(search_filters) search_params.extend(query_params) if (len(search_words) > 0): (word_query_sql, query_params) = get_word_query_sql(search_words) search_params.extend(query_params) - print filter_query_sql - print word_query_sql - if (len(search_filters) > 0) and (len(search_words) > 0): sql += filter_query_sql + ' UNION ' + word_query_sql elif len(search_filters) > 0: @@ -52,7 +48,7 @@ def data_for_songs_list(request, search_string=''): row = cursor.fetchone() context = {'songs_list': songs_list, - 'counters': get_counters(), 'section': section} + 'counters': get_counters()} return JsonResponse(context) @@ -72,10 +68,7 @@ def get_search_filters_sql(search_filters): single_statements = [] index = 0 for single_query in single_queries: - sql = 'SELECT * FROM (SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ' + single_query - if (must_shuffle[index]): - sql += ' ORDER BY RANDOM() ' - sql += ')' + sql = 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ' + single_query single_statements.append(sql) index += 1 @@ -86,7 +79,7 @@ def get_search_filters_sql(search_filters): for filter_term in search_filter: search_params.extend(['%' + filter_term + '%'] * 3) - return (filter_query, search_params) + return (filter_query, search_params, must_shuffle) def get_word_query_sql(search_words): From 647caa13b8756d39dbfbc98f7a04647fead7b9ad Mon Sep 17 00:00:00 2001 From: codezapper Date: Wed, 25 Jan 2017 17:10:36 +0100 Subject: [PATCH 07/88] Re-implemented shuffle --- PyLister/lister/data_utils.py | 57 ++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 0c640df..5b5e538 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -1,5 +1,6 @@ from django.db import connection from django.http import JsonResponse +import random def data_for_songs_list(request, search_string=''): @@ -10,34 +11,51 @@ def data_for_songs_list(request, search_string=''): search_filters = [] if ':' in search_string: - search_filters = [search_word.split(':') - for search_word in all_search_words if ':' in search_word] + for search_word in all_search_words: + if ':' in search_word: + tmp_filter = [] + for search_filter in search_word.split(':'): + if (search_filter != ''): + tmp_filter.append(search_filter) + search_filters.append(tmp_filter) + search_words = [ search_word for search_word in all_search_words if ':' not in search_word] search_params = [] cursor = connection.cursor() sql = '' - filter_query_sql = '' word_query_sql = '' + songs_list = [] + track_index = 0 + + results = [] if (len(search_filters) > 0): - (filter_query_sql, query_params, _) = get_search_filters_sql(search_filters) - search_params.extend(query_params) + (sql_queries, query_params, must_shuffle) = get_search_filters_sql(search_filters) + query_index = 0 + for sql_query in sql_queries: + print sql_query + print query_params[query_index] + cursor.execute(sql_query, query_params[query_index]) + row = cursor.fetchone() + while (row): + row_type = track_index % 2 + results.append( + {'title': row[0], 'album': row[1], 'artist': row[2], 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], 'row_type': row_type, 'track_index': track_index}) + track_index += 1 + row = cursor.fetchone() + if (must_shuffle[query_index]): + songs_list.extend(random.shuffle(results)) + else: + songs_list.extend(results) + query_index += 1 if (len(search_words) > 0): (word_query_sql, query_params) = get_word_query_sql(search_words) search_params.extend(query_params) + sql = word_query_sql - if (len(search_filters) > 0) and (len(search_words) > 0): - sql += filter_query_sql + ' UNION ' + word_query_sql - elif len(search_filters) > 0: - sql += filter_query_sql - elif len(search_words) > 0: - sql += word_query_sql - - songs_list = [] - track_index = 0 cursor.execute(sql, search_params) row = cursor.fetchone() while (row): @@ -63,7 +81,7 @@ def get_search_filters_sql(search_filters): must_shuffle.append(False) query_strings = [ '(artist like %s or album like %s or title like %s)'] * len(search_filter) - single_queries.append(' AND '.join(query_strings)) + single_queries.append('(' + ' AND '.join(query_strings) + ') ') single_statements = [] index = 0 @@ -72,14 +90,17 @@ def get_search_filters_sql(search_filters): single_statements.append(sql) index += 1 - filter_query = ' UNION '.join(single_statements) - search_params = [] + new_search_params = [] for search_filter in search_filters: + temp_params = [] for filter_term in search_filter: search_params.extend(['%' + filter_term + '%'] * 3) + temp_params.extend(['%' + filter_term + '%'] * 3) + new_search_params.append(temp_params) - return (filter_query, search_params, must_shuffle) + return (single_statements, new_search_params, must_shuffle) + # return (filter_query, search_params, must_shuffle) def get_word_query_sql(search_words): From 4de1c537947ffa3af88c851354006213cbaa7ed9 Mon Sep 17 00:00:00 2001 From: codezapper Date: Wed, 25 Jan 2017 23:36:31 +0100 Subject: [PATCH 08/88] !WIP! Removed duplicates server-side (must remove client side for playlist) --- PyLister/lister/data_utils.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 5b5e538..72c4002 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -29,20 +29,21 @@ def data_for_songs_list(request, search_string=''): songs_list = [] track_index = 0 - results = [] + results_lookup = {} if (len(search_filters) > 0): (sql_queries, query_params, must_shuffle) = get_search_filters_sql(search_filters) query_index = 0 for sql_query in sql_queries: - print sql_query - print query_params[query_index] cursor.execute(sql_query, query_params[query_index]) row = cursor.fetchone() + results = [] while (row): row_type = track_index % 2 - results.append( - {'title': row[0], 'album': row[1], 'artist': row[2], 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], 'row_type': row_type, 'track_index': track_index}) + if (results_lookup.get(row[7]) == None): + results_lookup[row[7]] = 1 + results.append( + {'title': row[0], 'album': row[1], 'artist': row[2], 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], 'row_type': row_type, 'track_index': track_index}) track_index += 1 row = cursor.fetchone() if (must_shuffle[query_index]): @@ -60,8 +61,10 @@ def data_for_songs_list(request, search_string=''): row = cursor.fetchone() while (row): row_type = track_index % 2 - songs_list.append( - {'title': row[0], 'album': row[1], 'artist': row[2], 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], 'row_type': row_type, 'track_index': track_index}) + if (results_lookup.get(row[7]) == None): + results_lookup[row[7]] = 1 + songs_list.append( + {'title': row[0], 'album': row[1], 'artist': row[2], 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], 'row_type': row_type, 'track_index': track_index}) track_index += 1 row = cursor.fetchone() @@ -86,7 +89,8 @@ def get_search_filters_sql(search_filters): single_statements = [] index = 0 for single_query in single_queries: - sql = 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ' + single_query + sql = 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number, lister_song.id song_id FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ' + \ + single_query + ' ORDER BY lister_song.artist_id, lister_album.album_id, track_number' single_statements.append(sql) index += 1 @@ -107,8 +111,9 @@ def get_word_query_sql(search_words): single_statements = [] for i in (range(len(search_words))): single_statements.append( - 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ( title like %s or lister_album.description like %s or lister_artist.description like %s)') - word_query = ' UNION '.join(single_statements) + 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number, lister_song.id song_id FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ( title like %s or lister_album.description like %s or lister_artist.description like %s)') + word_query = ' UNION '.join( + single_statements) + ' ORDER BY lister_song.artist_id, lister_album.album_id, track_number' search_params = [] for search_word in search_words: for i in range(0, 3): From 8e2b97a0fae2f97a1f55b01de052db5102a8127b Mon Sep 17 00:00:00 2001 From: codezapper Date: Thu, 26 Jan 2017 00:00:07 +0100 Subject: [PATCH 09/88] Cleaned up longer lines --- PyLister/lister/data_utils.py | 69 ++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 72c4002..dae45c4 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -2,16 +2,26 @@ from django.http import JsonResponse import random +inner_sql = '(artist like %s or album like %s or title like %s)' +selecting_tables = ['lister_song', 'lister_album', 'lister_artist'] +selecting_fields = ['title', 'lister_album.description album', + 'lister_artist.description artist', 'image_file', + 'path', 'year', 'track_number', 'lister_song.id song_id'] +common_conditions = ['lister_artist.artist_id = lister_song.artist_id', + 'lister_album.album_id = lister_song.album_id'] +sorting_fields = ['lister_song.artist_id', + 'lister_album.album_id', 'track_number'] + def data_for_songs_list(request, search_string=''): if (search_string == ''): return JsonResponse({}) - all_search_words = search_string.split() + all_words = search_string.split() search_filters = [] if ':' in search_string: - for search_word in all_search_words: + for search_word in all_words: if ':' in search_word: tmp_filter = [] for search_filter in search_word.split(':'): @@ -20,7 +30,7 @@ def data_for_songs_list(request, search_string=''): search_filters.append(tmp_filter) search_words = [ - search_word for search_word in all_search_words if ':' not in search_word] + search_word for search_word in all_words if ':' not in search_word] search_params = [] cursor = connection.cursor() @@ -32,18 +42,27 @@ def data_for_songs_list(request, search_string=''): results_lookup = {} if (len(search_filters) > 0): - (sql_queries, query_params, must_shuffle) = get_search_filters_sql(search_filters) + (sql_queries, params, must_shuffle) = get_filters_sql(search_filters) query_index = 0 for sql_query in sql_queries: - cursor.execute(sql_query, query_params[query_index]) + cursor.execute(sql_query, params[query_index]) row = cursor.fetchone() results = [] while (row): row_type = track_index % 2 - if (results_lookup.get(row[7]) == None): + if (results_lookup.get(row[7]) is None): results_lookup[row[7]] = 1 - results.append( - {'title': row[0], 'album': row[1], 'artist': row[2], 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], 'row_type': row_type, 'track_index': track_index}) + results.append({ + 'title': row[0], + 'album': row[1], + 'artist': row[2], + 'image_file': row[3], + 'path': row[4], + 'year': row[5], + 'track': row[6], + 'row_type': row_type, + 'track_index': track_index + }) track_index += 1 row = cursor.fetchone() if (must_shuffle[query_index]): @@ -53,18 +72,27 @@ def data_for_songs_list(request, search_string=''): query_index += 1 if (len(search_words) > 0): - (word_query_sql, query_params) = get_word_query_sql(search_words) - search_params.extend(query_params) + (word_query_sql, params) = get_word_query_sql(search_words) + search_params.extend(params) sql = word_query_sql cursor.execute(sql, search_params) row = cursor.fetchone() while (row): row_type = track_index % 2 - if (results_lookup.get(row[7]) == None): + if (results_lookup.get(row[7]) is None): results_lookup[row[7]] = 1 - songs_list.append( - {'title': row[0], 'album': row[1], 'artist': row[2], 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], 'row_type': row_type, 'track_index': track_index}) + songs_list.append({ + 'title': row[0], + 'album': row[1], + 'artist': row[2], + 'image_file': row[3], + 'path': row[4], + 'year': row[5], + 'track': row[6], + 'row_type': row_type, + 'track_index': track_index + }) track_index += 1 row = cursor.fetchone() @@ -73,7 +101,8 @@ def data_for_songs_list(request, search_string=''): return JsonResponse(context) -def get_search_filters_sql(search_filters): +def get_filters_sql(search_filters): + global inner_sql single_queries = [] must_shuffle = [] for search_filter in search_filters: @@ -82,15 +111,14 @@ def get_search_filters_sql(search_filters): must_shuffle.append(True) else: must_shuffle.append(False) - query_strings = [ - '(artist like %s or album like %s or title like %s)'] * len(search_filter) + query_strings = [inner_sql] * len(search_filter) single_queries.append('(' + ' AND '.join(query_strings) + ') ') single_statements = [] index = 0 for single_query in single_queries: - sql = 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number, lister_song.id song_id FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ' + \ - single_query + ' ORDER BY lister_song.artist_id, lister_album.album_id, track_number' + sql = 'SELECT ' + ','.join(selecting_fields) + ' FROM ' + ','.join(selecting_tables) + ' WHERE ' + ' AND '.join(common_conditions) + ' AND ' + \ + single_query + ' ORDER BY ' + ','.join(sorting_fields) single_statements.append(sql) index += 1 @@ -104,16 +132,15 @@ def get_search_filters_sql(search_filters): new_search_params.append(temp_params) return (single_statements, new_search_params, must_shuffle) - # return (filter_query, search_params, must_shuffle) def get_word_query_sql(search_words): single_statements = [] for i in (range(len(search_words))): single_statements.append( - 'SELECT title, lister_album.description album, lister_artist.description artist, image_file, path, year, track_number, lister_song.id song_id FROM lister_song, lister_album, lister_artist WHERE lister_artist.artist_id = lister_song.artist_id AND lister_album.album_id = lister_song.album_id AND ( title like %s or lister_album.description like %s or lister_artist.description like %s)') + 'SELECT ' + ','.join(selecting_fields) + ' FROM ' + ','.join(selecting_tables) + ' WHERE ' + ' AND '.join(common_conditions) + 'AND ( title like %s or lister_album.description like %s or lister_artist.description like %s)') word_query = ' UNION '.join( - single_statements) + ' ORDER BY lister_song.artist_id, lister_album.album_id, track_number' + single_statements) + ' ORDER BY ' + ','.join(sorting_fields) search_params = [] for search_word in search_words: for i in range(0, 3): From e1e32c9083c645b4a52229936250ef361f14f16f Mon Sep 17 00:00:00 2001 From: codezapper Date: Thu, 26 Jan 2017 08:28:53 +0100 Subject: [PATCH 10/88] Python cleanup --- PyLister/lister/data_utils.py | 36 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index dae45c4..2d8522c 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -37,8 +37,6 @@ def data_for_songs_list(request, search_string=''): sql = '' word_query_sql = '' songs_list = [] - track_index = 0 - results_lookup = {} if (len(search_filters) > 0): @@ -49,21 +47,9 @@ def data_for_songs_list(request, search_string=''): row = cursor.fetchone() results = [] while (row): - row_type = track_index % 2 if (results_lookup.get(row[7]) is None): results_lookup[row[7]] = 1 - results.append({ - 'title': row[0], - 'album': row[1], - 'artist': row[2], - 'image_file': row[3], - 'path': row[4], - 'year': row[5], - 'track': row[6], - 'row_type': row_type, - 'track_index': track_index - }) - track_index += 1 + results.append(_row_as_dict(row)) row = cursor.fetchone() if (must_shuffle[query_index]): songs_list.extend(random.shuffle(results)) @@ -79,7 +65,6 @@ def data_for_songs_list(request, search_string=''): cursor.execute(sql, search_params) row = cursor.fetchone() while (row): - row_type = track_index % 2 if (results_lookup.get(row[7]) is None): results_lookup[row[7]] = 1 songs_list.append({ @@ -90,10 +75,7 @@ def data_for_songs_list(request, search_string=''): 'path': row[4], 'year': row[5], 'track': row[6], - 'row_type': row_type, - 'track_index': track_index }) - track_index += 1 row = cursor.fetchone() context = {'songs_list': songs_list, @@ -117,7 +99,9 @@ def get_filters_sql(search_filters): single_statements = [] index = 0 for single_query in single_queries: - sql = 'SELECT ' + ','.join(selecting_fields) + ' FROM ' + ','.join(selecting_tables) + ' WHERE ' + ' AND '.join(common_conditions) + ' AND ' + \ + sql = 'SELECT ' + ','.join(selecting_fields) + ' FROM ' + \ + ','.join(selecting_tables) + ' WHERE ' + \ + ' AND '.join(common_conditions) + ' AND ' + \ single_query + ' ORDER BY ' + ','.join(sorting_fields) single_statements.append(sql) index += 1 @@ -135,10 +119,13 @@ def get_filters_sql(search_filters): def get_word_query_sql(search_words): + global inner_sql single_statements = [] for i in (range(len(search_words))): single_statements.append( - 'SELECT ' + ','.join(selecting_fields) + ' FROM ' + ','.join(selecting_tables) + ' WHERE ' + ' AND '.join(common_conditions) + 'AND ( title like %s or lister_album.description like %s or lister_artist.description like %s)') + 'SELECT ' + ','.join(selecting_fields) + ' FROM ' + + ','.join(selecting_tables) + ' WHERE ' + + ' AND '.join(common_conditions) + ' AND ' + inner_sql) word_query = ' UNION '.join( single_statements) + ' ORDER BY ' + ','.join(sorting_fields) search_params = [] @@ -148,6 +135,13 @@ def get_word_query_sql(search_words): return (word_query, search_params) +def _row_as_dict(row): + return { + 'title': row[0], 'album': row[1], 'artist': row[2], + 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6] + } + + def get_counters(): counters = {} cursor = connection.cursor() From f3cf0a439388cfb9a2b06486e0de75635fe6e5a6 Mon Sep 17 00:00:00 2001 From: codezapper Date: Thu, 26 Jan 2017 09:39:31 +0100 Subject: [PATCH 11/88] More Python cleanup --- PyLister/lister/data_utils.py | 107 ++++++++++++++++------------------ 1 file changed, 50 insertions(+), 57 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 2d8522c..818b3e9 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -9,48 +9,26 @@ 'path', 'year', 'track_number', 'lister_song.id song_id'] common_conditions = ['lister_artist.artist_id = lister_song.artist_id', 'lister_album.album_id = lister_song.album_id'] -sorting_fields = ['lister_song.artist_id', - 'lister_album.album_id', 'track_number'] +sorting_fields = ['artist', 'album', 'track_number'] def data_for_songs_list(request, search_string=''): if (search_string == ''): return JsonResponse({}) - all_words = search_string.split() - search_filters = [] - - if ':' in search_string: - for search_word in all_words: - if ':' in search_word: - tmp_filter = [] - for search_filter in search_word.split(':'): - if (search_filter != ''): - tmp_filter.append(search_filter) - search_filters.append(tmp_filter) - - search_words = [ - search_word for search_word in all_words if ':' not in search_word] + search_filters = get_search_filters(search_string) + search_words = [word for word in search_string.split() if ':' not in word] - search_params = [] cursor = connection.cursor() - sql = '' - word_query_sql = '' - songs_list = [] results_lookup = {} + songs_list = [] if (len(search_filters) > 0): - (sql_queries, params, must_shuffle) = get_filters_sql(search_filters) + (queries, params, must_shuffle) = get_filters_queries(search_filters) query_index = 0 - for sql_query in sql_queries: - cursor.execute(sql_query, params[query_index]) - row = cursor.fetchone() - results = [] - while (row): - if (results_lookup.get(row[7]) is None): - results_lookup[row[7]] = 1 - results.append(_row_as_dict(row)) - row = cursor.fetchone() + for query in queries: + results = get_rows_as_dict( + query, params[query_index], results_lookup) if (must_shuffle[query_index]): songs_list.extend(random.shuffle(results)) else: @@ -58,32 +36,43 @@ def data_for_songs_list(request, search_string=''): query_index += 1 if (len(search_words) > 0): - (word_query_sql, params) = get_word_query_sql(search_words) - search_params.extend(params) - sql = word_query_sql - - cursor.execute(sql, search_params) - row = cursor.fetchone() - while (row): - if (results_lookup.get(row[7]) is None): - results_lookup[row[7]] = 1 - songs_list.append({ - 'title': row[0], - 'album': row[1], - 'artist': row[2], - 'image_file': row[3], - 'path': row[4], - 'year': row[5], - 'track': row[6], - }) - row = cursor.fetchone() - - context = {'songs_list': songs_list, - 'counters': get_counters()} - return JsonResponse(context) - - -def get_filters_sql(search_filters): + songs_list.extend(get_rows_as_dict(*get_word_query_sql(search_words), + lookup=results_lookup)) + + return JsonResponse({ + 'songs_list': songs_list, + 'counters': get_counters() + }) + + +def get_rows_as_dict(sql, params, lookup={}): + results = [] + cursor = connection.cursor() + cursor.execute(sql, params) + row_dict = _row_as_dict(cursor.fetchone()) + while (row_dict is not None): + if (lookup.get(row_dict['song_id']) is None): + lookup[row_dict['song_id']] = 1 + results.append(row_dict) + row_dict = _row_as_dict(cursor.fetchone()) + + return results + + +def get_search_filters(search_string): + search_filters = [] + if ':' in search_string: + for search_word in search_string.split(): + if ':' in search_word: + tmp_filter = [] + for search_filter in search_word.split(':'): + if (search_filter != ''): + tmp_filter.append(search_filter) + search_filters.append(tmp_filter) + return search_filters + + +def get_filters_queries(search_filters): global inner_sql single_queries = [] must_shuffle = [] @@ -136,9 +125,13 @@ def get_word_query_sql(search_words): def _row_as_dict(row): + if (row is None): + return None + return { 'title': row[0], 'album': row[1], 'artist': row[2], - 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6] + 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], + 'song_id': row[7] } From 925798eaa164260e48d922df555432b5036c0e91 Mon Sep 17 00:00:00 2001 From: codezapper Date: Thu, 26 Jan 2017 09:53:16 +0100 Subject: [PATCH 12/88] Even more Python cleanup --- PyLister/lister/data_utils.py | 39 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 818b3e9..bf85631 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -88,33 +88,34 @@ def get_filters_queries(search_filters): single_statements = [] index = 0 for single_query in single_queries: - sql = 'SELECT ' + ','.join(selecting_fields) + ' FROM ' + \ - ','.join(selecting_tables) + ' WHERE ' + \ - ' AND '.join(common_conditions) + ' AND ' + \ - single_query + ' ORDER BY ' + ','.join(sorting_fields) + sql = 'SELECT ' + ','.join(selecting_fields) + \ + ' FROM ' + ','.join(selecting_tables) + \ + ' WHERE ' + ' AND '.join(common_conditions) + \ + ' AND ' + single_query + \ + ' ORDER BY ' + ','.join(sorting_fields) single_statements.append(sql) index += 1 search_params = [] - new_search_params = [] - for search_filter in search_filters: - temp_params = [] - for filter_term in search_filter: + ret_search_params = [] + for search_filter_terms in search_filters: + search_params = [] + for filter_term in search_filter_terms: search_params.extend(['%' + filter_term + '%'] * 3) - temp_params.extend(['%' + filter_term + '%'] * 3) - new_search_params.append(temp_params) + ret_search_params.append(search_params) - return (single_statements, new_search_params, must_shuffle) + return (single_statements, ret_search_params, must_shuffle) def get_word_query_sql(search_words): global inner_sql - single_statements = [] - for i in (range(len(search_words))): - single_statements.append( - 'SELECT ' + ','.join(selecting_fields) + ' FROM ' + - ','.join(selecting_tables) + ' WHERE ' + - ' AND '.join(common_conditions) + ' AND ' + inner_sql) + + single_statements = [ + 'SELECT ' + ','.join(selecting_fields) + + ' FROM ' + ','.join(selecting_tables) + + ' WHERE ' + ' AND '.join(common_conditions) + + ' AND ' + inner_sql + ] * len(search_words) word_query = ' UNION '.join( single_statements) + ' ORDER BY ' + ','.join(sorting_fields) search_params = [] @@ -130,8 +131,8 @@ def _row_as_dict(row): return { 'title': row[0], 'album': row[1], 'artist': row[2], - 'image_file': row[3], 'path': row[4], 'year': row[5], 'track': row[6], - 'song_id': row[7] + 'image_file': row[3], 'path': row[4], 'year': row[5], + 'track': row[6], 'song_id': row[7] } From a7251794d1aec3c499c3dbc476a57fc190ab96e3 Mon Sep 17 00:00:00 2001 From: codezapper Date: Thu, 26 Jan 2017 09:55:39 +0100 Subject: [PATCH 13/88] Updated TODO.txt --- PyLister/TODO.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PyLister/TODO.txt b/PyLister/TODO.txt index 0ca12f1..0f2bc37 100755 --- a/PyLister/TODO.txt +++ b/PyLister/TODO.txt @@ -1,11 +1,11 @@ - Cleanup main.js - Cleanup python code +- Fix sorting when mixing filters and search words +- Remove duplicates also on client side - Fix playing when not submitted (e.g. when clicking with the mouse before pressing enter) -- Add list shuffling - Add prefixes: - - "shuffle:" adds shuffled results to the playlist - "repeat:" adds results and repeats them. This replaces the current list - - "artist:", "album:", "title:" restrict search to related fields + - "random:" adds a single track randomly chosen from current filter - Add history of recently played songs - Implement callback to play through shown items instead of having the path saved in the template From d55b548d806ddb130b85e0e127b074b00b9b284d Mon Sep 17 00:00:00 2001 From: codezapper Date: Thu, 26 Jan 2017 17:56:36 +0100 Subject: [PATCH 14/88] More cleanup --- PyLister/lister/data_utils.py | 1 - PyLister/lister/templating_utils.py | 19 +------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index bf85631..8c5351a 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -19,7 +19,6 @@ def data_for_songs_list(request, search_string=''): search_filters = get_search_filters(search_string) search_words = [word for word in search_string.split() if ':' not in word] - cursor = connection.cursor() results_lookup = {} songs_list = [] diff --git a/PyLister/lister/templating_utils.py b/PyLister/lister/templating_utils.py index 9a5959c..4b69a60 100755 --- a/PyLister/lister/templating_utils.py +++ b/PyLister/lister/templating_utils.py @@ -1,11 +1,9 @@ -from django.db import connection from django.template import loader -import data_utils as du def render_wrapper(request): template = loader.get_template('lister/wrapper.html') - context = {'counters': get_counters()} + context = {} return template.render(context, request) @@ -14,18 +12,3 @@ def render_for_songs_list(request, album='', artist='', year=''): template = loader.get_template('lister/songs.html') context = {} return template.render(context, request) - - -def get_counters(): - counters = {} - cursor = connection.cursor() - cursor.execute('''SELECT count(*) FROM lister_song''') - counters['songs'] = cursor.fetchone()[0] - cursor.execute('''SELECT count(*) FROM lister_album''') - counters['albums'] = cursor.fetchone()[0] - cursor.execute('''SELECT count(*) FROM lister_artist''') - counters['artists'] = cursor.fetchone()[0] - cursor.execute('''SELECT count(distinct year) FROM lister_song''') - counters['years'] = cursor.fetchone()[0] - - return counters From 4ed3c4a5d8586f53591d1cba582a9ab2559fd641 Mon Sep 17 00:00:00 2001 From: codezapper Date: Fri, 27 Jan 2017 08:00:06 +0100 Subject: [PATCH 15/88] Added client-side duplicates filter --- PyLister/lister/static/lister/main.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/PyLister/lister/static/lister/main.js b/PyLister/lister/static/lister/main.js index c9b50f4..04e385f 100755 --- a/PyLister/lister/static/lister/main.js +++ b/PyLister/lister/static/lister/main.js @@ -21,7 +21,7 @@ var duration = -1; var playListTemplate; var prevSearchTerm; var currentSearchTerm; -var hasSubmitted = false; +var displayedSongIDs = {}; var trackListOperations = { REPLACE: 1, @@ -99,9 +99,15 @@ function setCurrentTrackList(searchTerm, searchResults, operation = trackListOpe trackList = searchResults; playTrack(0); } else if (operation === trackListOperations.PREPEND) { - trackList = searchResults.concat(trackList); + filteredSearchResults = searchResults.filter(function(song) { + return displayedSongIDs[song.song_id] != null; + }); + trackList = filteredSearchResults.concat(trackList); } else { - trackList = trackList.concat(searchResults); + filteredSearchResults = searchResults.filter(function(song) { + return displayedSongIDs[song.song_id] != null; + }); + trackList = trackList.concat(filteredSearchResults); } //TODO: This can be optimized to only render the new data and append it var html = Mustache.render(playListTemplate, {"playlist": trackList}); @@ -129,7 +135,6 @@ function bindUI() { playerElement.load(); finderBox.bind('keyup', function(event) { if (event.key != "Enter") { - hasSubmitted = false; if (inputBox.val() !== '') { showSongs(inputBox.val()); } else { @@ -143,7 +148,6 @@ function bindUI() { } else { if (searchResults.length > 0) { if (prevSearchTerm !== currentSearchTerm) { - hasSubmitted = true; inputBox.val(''); if (event.ctrlKey) { setCurrentTrackList(currentSearchTerm, searchResults, trackListOperations.REPLACE); From cb1c49c6cc2d6ddadd5d32c41540392b657cc31b Mon Sep 17 00:00:00 2001 From: codezapper Date: Fri, 27 Jan 2017 15:44:43 +0100 Subject: [PATCH 16/88] Fixed duplicates removal client-side --- PyLister/lister/static/lister/main.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/PyLister/lister/static/lister/main.js b/PyLister/lister/static/lister/main.js index 04e385f..04e13f1 100755 --- a/PyLister/lister/static/lister/main.js +++ b/PyLister/lister/static/lister/main.js @@ -100,12 +100,20 @@ function setCurrentTrackList(searchTerm, searchResults, operation = trackListOpe playTrack(0); } else if (operation === trackListOperations.PREPEND) { filteredSearchResults = searchResults.filter(function(song) { - return displayedSongIDs[song.song_id] != null; + if (displayedSongIDs[song.song_id] == null) { + displayedSongIDs[song.song_id] = 1; + return true; + } + return false; }); trackList = filteredSearchResults.concat(trackList); } else { filteredSearchResults = searchResults.filter(function(song) { - return displayedSongIDs[song.song_id] != null; + if (displayedSongIDs[song.song_id] == null) { + displayedSongIDs[song.song_id] = 1; + return true; + } + return false; }); trackList = trackList.concat(filteredSearchResults); } @@ -148,7 +156,6 @@ function bindUI() { } else { if (searchResults.length > 0) { if (prevSearchTerm !== currentSearchTerm) { - inputBox.val(''); if (event.ctrlKey) { setCurrentTrackList(currentSearchTerm, searchResults, trackListOperations.REPLACE); } else if (event.shiftKey) { @@ -160,6 +167,7 @@ function bindUI() { if (playerElement.paused || !playerElement.currentTime) { playTrack(currentTrack); } + inputBox.val(''); } } }); From e8a56bc33ac4f9e2d8f56c13f2ef7f860f49b1c0 Mon Sep 17 00:00:00 2001 From: codezapper Date: Fri, 27 Jan 2017 23:36:50 +0100 Subject: [PATCH 17/88] Added "random" filter --- PyLister/TODO.txt | 2 -- PyLister/lister/data_utils.py | 37 +++++++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/PyLister/TODO.txt b/PyLister/TODO.txt index 0f2bc37..6c600b9 100755 --- a/PyLister/TODO.txt +++ b/PyLister/TODO.txt @@ -2,10 +2,8 @@ - Cleanup python code - Fix sorting when mixing filters and search words -- Remove duplicates also on client side - Fix playing when not submitted (e.g. when clicking with the mouse before pressing enter) - Add prefixes: - "repeat:" adds results and repeats them. This replaces the current list - - "random:" adds a single track randomly chosen from current filter - Add history of recently played songs - Implement callback to play through shown items instead of having the path saved in the template diff --git a/PyLister/lister/data_utils.py b/PyLister/lister/data_utils.py index 8c5351a..065931d 100644 --- a/PyLister/lister/data_utils.py +++ b/PyLister/lister/data_utils.py @@ -12,6 +12,21 @@ sorting_fields = ['artist', 'album', 'track_number'] +def get_single_random(songs_list): + return [random.choice(songs_list)] + + +def get_shuffled_list(songs_list): + random.shuffle(songs_list) + return songs_list + + +do_something = { + 'random': get_single_random, + 'shuffle': get_shuffled_list +} + + def data_for_songs_list(request, search_string=''): if (search_string == ''): return JsonResponse({}) @@ -23,15 +38,17 @@ def data_for_songs_list(request, search_string=''): songs_list = [] if (len(search_filters) > 0): - (queries, params, must_shuffle) = get_filters_queries(search_filters) + (queries, params, filter_actions) = get_filters_queries(search_filters) query_index = 0 for query in queries: results = get_rows_as_dict( query, params[query_index], results_lookup) - if (must_shuffle[query_index]): - songs_list.extend(random.shuffle(results)) - else: - songs_list.extend(results) + if (len(results) > 0): + if (filter_actions[query_index]): + songs_list.extend( + do_something[filter_actions[query_index]](results)) + else: + songs_list.extend(results) query_index += 1 if (len(search_words) > 0): @@ -74,13 +91,13 @@ def get_search_filters(search_string): def get_filters_queries(search_filters): global inner_sql single_queries = [] - must_shuffle = [] + filter_actions = [] for search_filter in search_filters: - if (search_filter[0] == 'shuffle'): + if (search_filter[0] in do_something.keys()): + filter_actions.append(search_filter[0]) search_filter.pop(0) - must_shuffle.append(True) else: - must_shuffle.append(False) + filter_actions.append(None) query_strings = [inner_sql] * len(search_filter) single_queries.append('(' + ' AND '.join(query_strings) + ') ') @@ -103,7 +120,7 @@ def get_filters_queries(search_filters): search_params.extend(['%' + filter_term + '%'] * 3) ret_search_params.append(search_params) - return (single_statements, ret_search_params, must_shuffle) + return (single_statements, ret_search_params, filter_actions) def get_word_query_sql(search_words): From 06e1f3ef795c6b811f8c4a982f703e87fe50257b Mon Sep 17 00:00:00 2001 From: codezapper Date: Fri, 27 Jan 2017 23:51:57 +0100 Subject: [PATCH 18/88] Fixed highlighting active track --- PyLister/lister/static/lister/main.js | 2 +- PyLister/lister/templates/lister/songs.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PyLister/lister/static/lister/main.js b/PyLister/lister/static/lister/main.js index 04e13f1..17efbe9 100755 --- a/PyLister/lister/static/lister/main.js +++ b/PyLister/lister/static/lister/main.js @@ -150,7 +150,7 @@ function bindUI() { $('#playlist').css({display: 'block'}); if (!playerElement.paused || playerElement.currentTime) { - $('[data-index-playlist=' + currentTrack + ']').closest('ul').addClass('active-track'); + $('[data-index-playlist=' + trackList[currentTrack].song_id + ']').closest('ul').addClass('active-track'); } } } else { diff --git a/PyLister/lister/templates/lister/songs.html b/PyLister/lister/templates/lister/songs.html index c25f12b..f185e0c 100644 --- a/PyLister/lister/templates/lister/songs.html +++ b/PyLister/lister/templates/lister/songs.html @@ -13,7 +13,7 @@ {% verbatim %}{{#search_results}}