From 22ba308b149ac8946444f3a59d20d33aa366adc5 Mon Sep 17 00:00:00 2001 From: Terry Geng Date: Sun, 8 Mar 2020 21:25:30 +0800 Subject: [PATCH] feat: optimized autoplay with Lartz --- command.py | 16 ++++---- configuration.default.ini | 1 + configuration.example.ini | 2 + database.py | 84 ++++++++++++++++----------------------- interface.py | 6 +-- media/playlist.py | 27 +++++-------- 6 files changed, 60 insertions(+), 76 deletions(-) diff --git a/command.py b/command.py index 52d12e1..968fad1 100644 --- a/command.py +++ b/command.py @@ -11,7 +11,7 @@ import variables as var from librb import radiobrowser from database import SettingsDatabase, MusicDatabase from media.item import item_builders, item_loaders, item_id_generators, dict_to_item, dicts_to_items -from media.playlist import get_item_wrapper, get_item_wrapper_by_id, get_item_wrappers_by_tags +from media.playlist import get_item_wrapper_from_scrap, get_item_wrapper_by_id, get_item_wrappers_by_tags from media.file import FileItem from media.url_from_playlist import PlaylistURLItem, get_playlist_info from media.url import URLItem @@ -197,7 +197,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals # return if parameter in var.cache.files: - music_wrapper = get_item_wrapper(bot, type='file', path=parameter, user=user) + music_wrapper = get_item_wrapper_from_scrap(bot, type='file', path=parameter, user=user) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string()), text) @@ -301,7 +301,7 @@ def cmd_play_url(bot, user, text, command, parameter): url = util.get_url_from_input(parameter) if url: - music_wrapper = get_item_wrapper(bot, type='url', url=url, user=user) + music_wrapper = get_item_wrapper_from_scrap(bot, type='url', url=url, user=user) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) @@ -328,7 +328,7 @@ def cmd_play_playlist(bot, user, text, command, parameter): items = get_playlist_info(url=url, start_index=offset, user=user) if len(items) > 0: items = var.playlist.extend(list(map( - lambda item: get_item_wrapper(bot, **item), items))) + lambda item: get_item_wrapper_from_scrap(bot, **item), items))) for music in items: log.info("cmd: add to playlist: " + music.format_debug_string()) else: @@ -353,7 +353,7 @@ def cmd_play_radio(bot, user, text, command, parameter): parameter = parameter.split()[0] url = util.get_url_from_input(parameter) if url: - music_wrapper = get_item_wrapper(bot, type='radio', url=url) + music_wrapper = get_item_wrapper_from_scrap(bot, type='radio', url=url) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) @@ -452,7 +452,7 @@ def cmd_rb_play(bot, user, text, command, parameter): url = radiobrowser.geturl_byid(parameter) if url != "-1": log.info('cmd: Found url: ' + url) - music_wrapper = get_item_wrapper(bot, type='radio', url=url, name=stationname, user=user) + music_wrapper = get_item_wrapper_from_scrap(bot, type='radio', url=url, name=stationname, user=user) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) bot.async_download_next() @@ -966,7 +966,7 @@ def cmd_shortlist(bot, user, text, command, parameter): if 1 <= index <= len(song_shortlist): kwargs = song_shortlist[index - 1] kwargs['user'] = user - music_wrapper = get_item_wrapper(bot, **kwargs) + music_wrapper = get_item_wrapper_from_scrap(bot, **kwargs) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) msgs.append("
  • {}
  • ".format(music_wrapper.item().title)) @@ -984,7 +984,7 @@ def cmd_shortlist(bot, user, text, command, parameter): if 1 <= index <= len(song_shortlist): kwargs = song_shortlist[index - 1] kwargs['user'] = user - music_wrapper = get_item_wrapper(bot, **kwargs) + music_wrapper = get_item_wrapper_from_scrap(bot, **kwargs) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) bot.send_msg(constants.strings('file_added', item=music_wrapper.format_song_string()), text) diff --git a/configuration.default.ini b/configuration.default.ini index ca3d863..b7a19d8 100644 --- a/configuration.default.ini +++ b/configuration.default.ini @@ -33,6 +33,7 @@ comment = Hi, I'm here to play radio, local music or youtube/soundcloud music. H volume = 0.1 # playback mode should be one of "one-shot", "loop", "random", "autoplay" playback_mode = one-shot +autoplay_length = 5 # target version, stable or testing (testing need to bot installed with git) target_version = stable diff --git a/configuration.example.ini b/configuration.example.ini index 9b45300..fd5d1d6 100644 --- a/configuration.example.ini +++ b/configuration.example.ini @@ -32,7 +32,9 @@ port = 64738 # it should be one of "one-shot" (remove item once played), "repeat" (looping through the playlist), # or "random" (randomize the playlist), "autoplay" (randomly grab something from the music library). # This option will be overridden by value in the database. +# 'autoplay_length': how many songs the autoplay mode fills the playlist #playback_mode = one-shot +#autoplay_length = 5 # target version, stable or testing (testing need to bot installed with git) # stable will use simple bash with curl command to get releases, testing will follow github master branch with git commands diff --git a/database.py b/database.py index 0540834..cdc6363 100644 --- a/database.py +++ b/database.py @@ -217,27 +217,15 @@ class MusicDatabase: "WHERE %s" % condition_str, filler).fetchall() conn.close() - if len(results) > 0: - music_dicts = [] - for result in results: - music_dict = json.loads(result[3]) - music_dict['type'] = result[1] - music_dict['title'] = result[2] - music_dict['tags'] = result[4].strip(",").split(",") - music_dict['id'] = result[0] - music_dicts.append(music_dict) - - return music_dicts - else: - return None + return self._result_to_dict(results) def query_music_by_keywords(self, keywords): condition = [] filler = [] for keyword in keywords: - condition.append('title LIKE ?') - filler.append("%{:s}%".format(keyword)) + condition.append('LOWER(title) LIKE ?') + filler.append("%{:s}%".format(keyword.lower())) condition_str = " AND ".join(condition) @@ -248,30 +236,15 @@ class MusicDatabase: "WHERE %s" % condition_str, filler).fetchall() conn.close() - if len(results) > 0: - music_dicts = [] - for result in results: - music_dict = json.loads(result[3]) - music_dict['type'] = result[1] - music_dict['title'] = result[2] - music_dict['id'] = result[0] - music_dict['tags'] = result[4].strip(",").split(",") - if not music_dict['tags'][0]: - music_dict['tags'] = [] - - music_dicts.append(music_dict) - - return music_dicts - else: - return None + return self._result_to_dict(results) def query_music_by_tags(self, tags): condition = [] filler = [] for tag in tags: - condition.append('tags LIKE ?') - filler.append("%{:s},%".format(tag)) + condition.append('LOWER(tags) LIKE ?') + filler.append("%{:s},%".format(tag.lower())) condition_str = " AND ".join(condition) @@ -282,22 +255,7 @@ class MusicDatabase: "WHERE %s" % condition_str, filler).fetchall() conn.close() - if len(results) > 0: - music_dicts = [] - for result in results: - music_dict = json.loads(result[3]) - music_dict['type'] = result[1] - music_dict['title'] = result[2] - music_dict['id'] = result[0] - music_dict['tags'] = result[4].strip(",").split(",") - if not music_dict['tags'][0]: - music_dict['tags'] = [] - - music_dicts.append(music_dict) - - return music_dicts - else: - return None + return self._result_to_dict(results) def query_tags_by_id(self, id): conn = sqlite3.connect(self.db_path) @@ -313,6 +271,34 @@ class MusicDatabase: else: return None + def query_random_music(self, count): + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + results = cursor.execute("SELECT id, type, title, metadata, tags FROM music " + "WHERE id IN (SELECT id FROM music ORDER BY RANDOM() LIMIT ?)", (count,)).fetchall() + conn.close() + + return self._result_to_dict(results) + + + def _result_to_dict(self, results): + if len(results) > 0: + music_dicts = [] + for result in results: + music_dict = json.loads(result[3]) + music_dict['type'] = result[1] + music_dict['title'] = result[2] + music_dict['id'] = result[0] + music_dict['tags'] = result[4].strip(",").split(",") + if not music_dict['tags'][0]: + music_dict['tags'] = [] + + music_dicts.append(music_dict) + + return music_dicts + else: + return None + def delete_music(self, **kwargs): condition = [] filler = [] diff --git a/interface.py b/interface.py index 9870976..43ad53b 100644 --- a/interface.py +++ b/interface.py @@ -10,7 +10,7 @@ import shutil from werkzeug.utils import secure_filename import errno import media -from media.playlist import get_item_wrapper, get_item_wrapper_by_id, get_item_wrappers_by_tags +from media.playlist import get_item_wrapper_from_scrap, get_item_wrapper_by_id, get_item_wrappers_by_tags import logging import time @@ -238,7 +238,7 @@ def post(): elif 'add_url' in request.form: - music_wrapper = get_item_wrapper(var.bot, type='url', url=request.form['add_url'], user=user) + music_wrapper = get_item_wrapper_from_scrap(var.bot, type='url', url=request.form['add_url'], user=user) var.playlist.append(music_wrapper) log.info("web: add to playlist: " + music_wrapper.format_debug_string()) @@ -248,7 +248,7 @@ def post(): elif 'add_radio' in request.form: url = request.form['add_radio'] - music_wrapper = get_item_wrapper(var.bot, type='radio', url=url, user=user) + music_wrapper = get_item_wrapper_from_scrap(var.bot, type='radio', url=url, user=user) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) diff --git a/media/playlist.py b/media/playlist.py index 77f8a9c..347b423 100644 --- a/media/playlist.py +++ b/media/playlist.py @@ -6,6 +6,7 @@ import random import variables as var from media.file import FileItem +from media.item import dict_to_item from media.url import URLItem from media.url_from_playlist import PlaylistURLItem from media.radio import RadioItem @@ -96,12 +97,17 @@ class PlaylistItemWrapper: # Remember!!! Using these three get wrapper functions will automatically add items into the cache! -def get_item_wrapper(bot, **kwargs): +def get_item_wrapper_from_scrap(bot, **kwargs): item = var.cache.get_item(bot, **kwargs) if 'user' not in kwargs: raise KeyError("Which user added this song?") return PlaylistItemWrapper(var.cache, item.id, kwargs['type'], kwargs['user']) +def get_item_wrapper_from_dict(bot, dict_from_db, user): + item = dict_to_item(bot, dict_from_db) + var.cache[dict_from_db['id']] = item + return PlaylistItemWrapper(var.cache, item.id, item.type, user) + def get_item_wrapper_by_id(bot, id, user): item = var.cache.get_item_by_id(bot, id) if item: @@ -441,16 +447,14 @@ class RandomPlaylist(BasePlaylist): return self[0] -class AutoPlaylist(BasePlaylist): +class AutoPlaylist(OneshotPlaylist): def __init__(self): super().__init__() self.mode = "autoplay" def refresh(self): - _list = [] - ids = var.music_db.query_all_ids() - for _ in range(20): - _list.append(get_item_wrapper_by_id(var.bot, ids[random.randint(0, len(ids)-1)], 'AutoPlay')) + dicts = var.music_db.query_random_music(var.config.getint("bot", "autoplay_length", fallback=5)) + _list = [get_item_wrapper_from_dict(var.bot, _dict, "AutoPlay") for _dict in dicts] self.from_list(_list, -1) # def from_list(self, _list, current_index): @@ -465,14 +469,5 @@ class AutoPlaylist(BasePlaylist): def next(self): if len(self) == 0: self.refresh() - return False + return super().next() - self.version += 1 - - if self.current_index < len(self) - 1: - self.current_index += 1 - return self[self.current_index] - else: - self.refresh() - self.current_index = 0 - return self[0]