From e86b5ca65954c1fbd3170ae3ad8b2d3f18b8b03c Mon Sep 17 00:00:00 2001 From: Terry Geng Date: Wed, 8 Apr 2020 08:55:43 +0800 Subject: [PATCH] refactor: rewrite confusing part --- command.py | 40 +++++++++++++++++----------------- configuration.default.ini | 4 ++-- interface.py | 33 ++++++++++++++-------------- media/cache.py | 44 +++++++++++++++++++------------------- media/file.py | 19 ++++++++-------- media/item.py | 32 ++++++++++++++------------- media/playlist.py | 29 +++++++++---------------- media/radio.py | 16 +++++++------- media/url.py | 34 ++++++++++++++--------------- media/url_from_playlist.py | 15 ++++++------- mumbleBot.py | 44 +++++++++++++++++++++++++++++++------- 11 files changed, 163 insertions(+), 147 deletions(-) diff --git a/command.py b/command.py index 85917da..2f14af5 100644 --- a/command.py +++ b/command.py @@ -227,7 +227,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals # if parameter is {index} if parameter.isdigit(): - music_wrappers = get_cached_wrappers_from_dicts(bot, var.music_db.query_music(Condition() + music_wrappers = get_cached_wrappers_from_dicts(var.music_db.query_music(Condition() .and_equal('type', 'file') .order_by('path') .limit(1) @@ -240,7 +240,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals return # assume parameter is a path - music_wrappers = get_cached_wrappers_from_dicts(bot, var.music_db.query_music(Condition().and_equal('path', parameter)), user) + music_wrappers = get_cached_wrappers_from_dicts(var.music_db.query_music(Condition().and_equal('path', parameter)), user) if music_wrappers: var.playlist.append(music_wrappers[0]) log.info("cmd: add to playlist: " + music_wrappers[0].format_debug_string()) @@ -248,7 +248,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals return # assume parameter is a folder - music_wrappers = get_cached_wrappers_from_dicts(bot, var.music_db.query_music(Condition() + music_wrappers = get_cached_wrappers_from_dicts(var.music_db.query_music(Condition() .and_equal('type', 'file') .and_like('path', parameter + '%')), user) if music_wrappers: @@ -268,7 +268,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals .and_equal('type', 'file') .and_like('path', '%' + parameter + '%', case_sensitive=False)) if len(matches) == 1: - music_wrapper = get_cached_wrapper_from_dict(bot, matches[0], user) + music_wrapper = get_cached_wrapper_from_dict(matches[0], 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) @@ -286,7 +286,7 @@ def cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=Fals if do_not_refresh_cache: bot.send_msg(constants.strings("no_file"), text) else: - var.cache.build_dir_cache(bot) + var.cache.build_dir_cache() cmd_play_file(bot, user, text, command, parameter, do_not_refresh_cache=True) @@ -304,7 +304,7 @@ def cmd_play_file_match(bot, user, text, command, parameter, do_not_refresh_cach match = re.search(parameter, file) if match and match[0]: count += 1 - music_wrapper = get_cached_wrapper(dict_to_item(bot, file_dict), user) + music_wrapper = get_cached_wrapper(dict_to_item(file_dict), user) music_wrappers.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) msgs.append("
  • {} ({})
  • ".format(music_wrapper.item().title, @@ -323,7 +323,7 @@ def cmd_play_file_match(bot, user, text, command, parameter, do_not_refresh_cach if do_not_refresh_cache: bot.send_msg(constants.strings("no_file"), text) else: - var.cache.build_dir_cache(bot) + var.cache.build_dir_cache() cmd_play_file_match(bot, user, text, command, parameter, do_not_refresh_cache=True) except re.error as e: @@ -338,7 +338,7 @@ def cmd_play_url(bot, user, text, command, parameter): url = util.get_url_from_input(parameter) if url: - music_wrapper = get_cached_wrapper_from_scrap(bot, type='url', url=url, user=user) + music_wrapper = get_cached_wrapper_from_scrap(type='url', url=url, user=user) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) @@ -364,7 +364,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_cached_wrapper_from_scrap(bot, **item), items))) + lambda item: get_cached_wrapper_from_scrap(**item), items))) for music in items: log.info("cmd: add to playlist: " + music.format_debug_string()) else: @@ -389,7 +389,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_cached_wrapper_from_scrap(bot, type='radio', url=url, user=user) + music_wrapper = get_cached_wrapper_from_scrap(type='radio', url=url, user=user) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) @@ -489,7 +489,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_cached_wrapper_from_scrap(bot, type='radio', url=url, name=stationname, user=user) + music_wrapper = get_cached_wrapper_from_scrap(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() @@ -870,7 +870,7 @@ def cmd_play_tags(bot, user, text, command, parameter): tags = parameter.split(",") tags = list(map(lambda t: t.strip(), tags)) - music_wrappers = get_cached_wrappers_by_tags(bot, tags, user) + music_wrappers = get_cached_wrappers_by_tags(tags, user) for music_wrapper in music_wrappers: count += 1 log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) @@ -991,7 +991,7 @@ def cmd_find_tagged(bot, user, text, command, parameter): song_shortlist = music_dicts for i, music_dict in enumerate(music_dicts): - item = dict_to_item(bot, music_dict) + item = dict_to_item(music_dict) count += 1 if count > ITEMS_PER_PAGE: break @@ -1024,7 +1024,7 @@ def cmd_search_library(bot, user, text, command, parameter): music_dicts = var.music_db.query_music_by_keywords(keywords) if music_dicts: - items = dicts_to_items(bot, music_dicts) + items = dicts_to_items(music_dicts) song_shortlist = music_dicts if len(items) == 1: @@ -1061,7 +1061,7 @@ def cmd_shortlist(bot, user, text, command, parameter): music_wrappers = [] for kwargs in song_shortlist: kwargs['user'] = user - music_wrapper = get_cached_wrapper_from_scrap(bot, **kwargs) + music_wrapper = get_cached_wrapper_from_scrap(**kwargs) music_wrappers.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) msgs.append("
  • [{}] {}
  • ".format(music_wrapper.item().type, music_wrapper.item().title)) @@ -1085,7 +1085,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_cached_wrapper_from_scrap(bot, **kwargs) + music_wrapper = get_cached_wrapper_from_scrap(**kwargs) music_wrappers.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) msgs.append("
  • [{}] {}
  • ".format(music_wrapper.item().type, music_wrapper.item().title)) @@ -1104,7 +1104,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_cached_wrapper_from_scrap(bot, **kwargs) + music_wrapper = get_cached_wrapper_from_scrap(**kwargs) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) bot.send_channel_msg(constants.strings('file_added', item=music_wrapper.format_song_string())) @@ -1128,7 +1128,7 @@ def cmd_delete_from_library(bot, user, text, command, parameter): if 1 <= index <= len(song_shortlist): music_dict = song_shortlist[index - 1] if 'id' in music_dict: - music_wrapper = get_cached_wrapper_by_id(bot, music_dict['id'], user) + music_wrapper = get_cached_wrapper_by_id(music_dict['id'], user) log.info("cmd: remove from library: " + music_wrapper.format_debug_string()) msgs.append("
  • [{}] {}
  • ".format(music_wrapper.item().type, music_wrapper.item().title)) var.playlist.remove_by_id(music_dict['id']) @@ -1150,7 +1150,7 @@ def cmd_delete_from_library(bot, user, text, command, parameter): if 1 <= index <= len(song_shortlist): music_dict = song_shortlist[index - 1] if 'id' in music_dict: - music_wrapper = get_cached_wrapper_by_id(bot, music_dict['id'], user) + music_wrapper = get_cached_wrapper_by_id(music_dict['id'], user) bot.send_msg(constants.strings('file_deleted', item=music_wrapper.format_song_string()), text) log.info("cmd: remove from library: " + music_wrapper.format_debug_string()) var.playlist.remove_by_id(music_dict['id']) @@ -1177,7 +1177,7 @@ def cmd_drop_database(bot, user, text, command, parameter): def cmd_refresh_cache(bot, user, text, command, parameter): global log if bot.is_admin(user): - var.cache.build_dir_cache(bot) + var.cache.build_dir_cache() log.info("command: Local file cache refreshed.") bot.send_msg(constants.strings('cache_refreshed'), text) else: diff --git a/configuration.default.ini b/configuration.default.ini index 38bd2ca..fea11d1 100644 --- a/configuration.default.ini +++ b/configuration.default.ini @@ -204,8 +204,8 @@ page_instruction = Page {current}/{total}. Use !{command} {{page}} to nav records_omitted = ... bad_url = Bad URL requested. preconfigurated_radio = Preconfigurated Radio available: -unable_download = Error while downloading music... -unable_play = Unable to play {item}. Removed from the library. +unable_download = Unable to download {item}. Removed from the library. +unable_play = Unable to play {item}. Removed from the library. which_command = Do you mean
    {commands} multiple_matches = File not found! Possible candidates: queue_contents = Items on the playlist: diff --git a/interface.py b/interface.py index adc5cd0..fd8c794 100644 --- a/interface.py +++ b/interface.py @@ -253,7 +253,7 @@ def post(): log.debug("web: Post request from %s: %s" % (request.remote_addr, str(request.form))) if 'add_item_at_once' in request.form: - music_wrapper = get_cached_wrapper_by_id(var.bot, request.form['add_item_at_once'], user) + music_wrapper = get_cached_wrapper_by_id(request.form['add_item_at_once'], user) if music_wrapper: var.playlist.insert(var.playlist.current_index + 1, music_wrapper) log.info('web: add to playlist(next): ' + music_wrapper.format_debug_string()) @@ -265,7 +265,7 @@ def post(): abort(404) if 'add_item_bottom' in request.form: - music_wrapper = get_cached_wrapper_by_id(var.bot, request.form['add_item_bottom'], user) + music_wrapper = get_cached_wrapper_by_id(request.form['add_item_bottom'], user) if music_wrapper: var.playlist.append(music_wrapper) @@ -274,7 +274,7 @@ def post(): abort(404) elif 'add_item_next' in request.form: - music_wrapper = get_cached_wrapper_by_id(var.bot, request.form['add_item_next'], user) + music_wrapper = get_cached_wrapper_by_id(request.form['add_item_next'], user) if music_wrapper: var.playlist.insert(var.playlist.current_index + 1, music_wrapper) log.info('web: add to playlist(next): ' + music_wrapper.format_debug_string()) @@ -282,7 +282,7 @@ def post(): abort(404) elif 'add_url' in request.form: - music_wrapper = get_cached_wrapper_from_scrap(var.bot, type='url', url=request.form['add_url'], user=user) + music_wrapper = get_cached_wrapper_from_scrap(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()) @@ -292,7 +292,7 @@ def post(): elif 'add_radio' in request.form: url = request.form['add_radio'] - music_wrapper = get_cached_wrapper_from_scrap(var.bot, type='radio', url=url, user=user) + music_wrapper = get_cached_wrapper_from_scrap(type='radio', url=url, user=user) var.playlist.append(music_wrapper) log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) @@ -335,7 +335,7 @@ def post(): elif 'delete_item_from_library' in request.form: _id = request.form['delete_item_from_library'] var.playlist.remove_by_id(_id) - item = var.cache.get_item_by_id(var.bot, _id) + item = var.cache.get_item_by_id(_id) if os.path.isfile(item.uri()): log.info("web: delete file " + item.uri()) @@ -345,7 +345,7 @@ def post(): time.sleep(0.1) elif 'add_tag' in request.form: - music_wrappers = get_cached_wrappers_by_tags(var.bot, [request.form['add_tag']], user) + music_wrappers = get_cached_wrappers_by_tags([request.form['add_tag']], user) for music_wrapper in music_wrappers: log.info("cmd: add to playlist: " + music_wrapper.format_debug_string()) var.playlist.extend(music_wrappers) @@ -373,7 +373,7 @@ def post(): var.db.set('playlist', 'playback_mode', "autoplay") log.info("web: playback mode changed to autoplay.") if action == "rescan": - var.cache.build_dir_cache(var.bot) + var.cache.build_dir_cache() log.info("web: Local file cache refreshed.") elif action == "stop": if var.config.getboolean("bot", "clear_when_stop_in_oneshot", fallback=False) \ @@ -462,7 +462,7 @@ def library(): return ('', 204) if request.form['action'] == 'add': - items = dicts_to_items(var.bot, var.music_db.query_music(condition)) + items = dicts_to_items(var.music_db.query_music(condition)) music_wrappers = [] for item in items: music_wrapper = get_cached_wrapper(item, user) @@ -474,10 +474,10 @@ def library(): return redirect("./", code=302) elif request.form['action'] == 'delete': - items = dicts_to_items(var.bot, var.music_db.query_music(condition)) + items = dicts_to_items(var.music_db.query_music(condition)) for item in items: var.playlist.remove_by_id(item.id) - item = var.cache.get_item_by_id(var.bot, item.id) + item = var.cache.get_item_by_id(item.id) if os.path.isfile(item.uri()): log.info("web: delete file " + item.uri()) @@ -500,7 +500,7 @@ def library(): current_page = 1 condition.limit(ITEM_PER_PAGE) - items = dicts_to_items(var.bot, var.music_db.query_music(condition)) + items = dicts_to_items(var.music_db.query_music(condition)) results = [] for item in items: @@ -531,7 +531,7 @@ def library(): elif request.form['action'] == 'edit_tags': tags = list(dict.fromkeys(request.form['tags'].split(","))) # remove duplicated items if request.form['id'] in var.cache: - music_wrapper = get_cached_wrapper_by_id(var.bot, request.form['id'], user) + music_wrapper = get_cached_wrapper_by_id(request.form['id'], user) music_wrapper.clear_tags() music_wrapper.add_tags(tags) var.playlist.version += 1 @@ -591,7 +591,7 @@ def upload(): else: continue - var.cache.build_dir_cache(var.bot) + var.cache.build_dir_cache() var.music_db.manage_special_tags() log.info("web: Local file cache refreshed.") @@ -603,8 +603,7 @@ def download(): global log if 'id' in request.args and request.args['id']: - item = dicts_to_items(var.bot, - var.music_db.query_music( + item = dicts_to_items(var.music_db.query_music( Condition().and_equal('id', request.args['id'])))[0] requested_file = item.uri() @@ -618,7 +617,7 @@ def download(): else: condition = build_library_query_condition(request.args) - items = dicts_to_items(var.bot, var.music_db.query_music(condition)) + items = dicts_to_items(var.music_db.query_music(condition)) zipfile = util.zipdir([item.uri() for item in items]) diff --git a/media/cache.py b/media/cache.py index 6834820..68551a5 100644 --- a/media/cache.py +++ b/media/cache.py @@ -21,12 +21,12 @@ class MusicCache(dict): self.log = logging.getLogger("bot") self.dir_lock = threading.Lock() - def get_item_by_id(self, bot, id): # Why all these functions need a bot? Because it need the bot to send message! + def get_item_by_id(self, id): if id in self: return self[id] # if not cached, query the database - item = self.fetch(bot, id) + item = self.fetch(id) if item is not None: self[id] = item self.log.debug("library: music found in database: %s" % item.format_debug_string()) @@ -36,7 +36,7 @@ class MusicCache(dict): # print(id) # raise KeyError("Unable to fetch item from the database! Please try to refresh the cache by !recache.") - def get_item(self, bot, **kwargs): + def get_item(self, **kwargs): # kwargs should provide type and id, and parameters to build the item if not existed in the library. # if cached if 'id' in kwargs: @@ -48,31 +48,31 @@ class MusicCache(dict): return self[id] # if not cached, query the database - item = self.fetch(bot, id) + item = self.fetch(id) if item is not None: self[id] = item self.log.debug("library: music found in database: %s" % item.format_debug_string()) return item # if not in the database, build one - self[id] = item_builders[kwargs['type']](bot, **kwargs) # newly built item will not be saved immediately + self[id] = item_builders[kwargs['type']](**kwargs) # newly built item will not be saved immediately return self[id] - def get_items_by_tags(self, bot, tags): + def get_items_by_tags(self, tags): music_dicts = self.db.query_music_by_tags(tags) items = [] if music_dicts: for music_dict in music_dicts: id = music_dict['id'] - self[id] = dict_to_item(bot, music_dict) + self[id] = dict_to_item(music_dict) items.append(self[id]) return items - def fetch(self, bot, id): + def fetch(self, id): music_dict = self.db.query_music_by_id(id) if music_dict: - self[id] = dict_to_item(bot, music_dict) + self[id] = dict_to_item(music_dict) return self[id] else: return None @@ -83,7 +83,7 @@ class MusicCache(dict): self.db.manage_special_tags() def free_and_delete(self, id): - item = self.get_item_by_id(None, id) + item = self.get_item_by_id(id) if item: self.log.debug("library: DELETE item from the database: %s" % item.format_debug_string()) @@ -104,14 +104,14 @@ class MusicCache(dict): self.log.debug("library: all cache freed") self.clear() - def build_dir_cache(self, bot): + def build_dir_cache(self): self.dir_lock.acquire() self.log.info("library: rebuild directory cache") files = util.get_recursive_file_list_sorted(var.music_folder) for file in files: results = self.db.query_music(Condition().and_equal('path', file)) if not results: - item = item_builders['file'](bot, path=file) + item = item_builders['file'](path=file) self.log.debug("library: music save into database: %s" % item.format_debug_string()) self.db.insert_music(item.to_dict()) @@ -207,33 +207,33 @@ def get_cached_wrappers(items, user): return wrappers -def get_cached_wrapper_from_scrap(bot, **kwargs): - item = var.cache.get_item(bot, **kwargs) +def get_cached_wrapper_from_scrap(**kwargs): + item = var.cache.get_item(**kwargs) if 'user' not in kwargs: raise KeyError("Which user added this song?") return CachedItemWrapper(var.cache, item.id, kwargs['type'], kwargs['user']) -def get_cached_wrapper_from_dict(bot, dict_from_db, user): +def get_cached_wrapper_from_dict(dict_from_db, user): if dict_from_db: - item = dict_to_item(bot, dict_from_db) + item = dict_to_item(dict_from_db) return get_cached_wrapper(item, user) return None -def get_cached_wrappers_from_dicts(bot, dicts_from_db, user): +def get_cached_wrappers_from_dicts(dicts_from_db, user): items = [] for dict_from_db in dicts_from_db: if dict_from_db: - items.append(get_cached_wrapper_from_dict(bot, dict_from_db, user)) + items.append(get_cached_wrapper_from_dict(dict_from_db, user)) return items -def get_cached_wrapper_by_id(bot, id, user): - item = var.cache.get_item_by_id(bot, id) +def get_cached_wrapper_by_id(id, user): + item = var.cache.get_item_by_id(id) if item: return CachedItemWrapper(var.cache, item.id, item.type, user) -def get_cached_wrappers_by_tags(bot, tags, user): - items = var.cache.get_items_by_tags(bot, tags) +def get_cached_wrappers_by_tags(tags, user): + items = var.cache.get_items_by_tags(tags) ret = [] for item in items: ret.append(CachedItemWrapper(var.cache, item.id, item.type, user)) diff --git a/media/file.py b/media/file.py index 91f52a3..a0bcd70 100644 --- a/media/file.py +++ b/media/file.py @@ -7,7 +7,7 @@ import mutagen from PIL import Image import variables as var -from media.item import BaseItem, item_builders, item_loaders, item_id_generators +from media.item import BaseItem, item_builders, item_loaders, item_id_generators, ValidationFailedError import constants ''' @@ -22,12 +22,12 @@ type : file ''' -def file_item_builder(bot, **kwargs): - return FileItem(bot, kwargs['path']) +def file_item_builder(**kwargs): + return FileItem(kwargs['path']) -def file_item_loader(bot, _dict): - return FileItem(bot, "", _dict) +def file_item_loader(_dict): + return FileItem("", _dict) def file_item_id_generator(**kwargs): @@ -40,9 +40,9 @@ item_id_generators['file'] = file_item_id_generator class FileItem(BaseItem): - def __init__(self, bot, path, from_dict=None): + def __init__(self, path, from_dict=None): if not from_dict: - super().__init__(bot) + super().__init__() self.path = path self.title = "" self.artist = "" @@ -53,7 +53,7 @@ class FileItem(BaseItem): self.ready = "yes" self.keywords = self.title + " " + self.artist else: - super().__init__(bot, from_dict) + super().__init__(from_dict) self.artist = from_dict['artist'] self.thumbnail = from_dict['thumbnail'] if not self.validate(): @@ -71,8 +71,7 @@ class FileItem(BaseItem): if not os.path.exists(self.uri()): self.log.info( "file: music file missed for %s" % self.format_debug_string()) - self.send_client_message(constants.strings('file_missed', file=self.path)) - return False + raise ValidationFailedError(constants.strings('file_missed', file=self.path)) if not self.keywords: self.keywords = self.title + " " + self.artist # migrate from previous version diff --git a/media/item.py b/media/item.py index 44d9477..6c1fe33 100644 --- a/media/item.py +++ b/media/item.py @@ -5,12 +5,12 @@ item_loaders = {} item_id_generators = {} -def example_builder(bot, **kwargs): - return BaseItem(bot) +def example_builder(**kwargs): + return BaseItem() -def example_loader(bot, _dict): - return BaseItem(bot, from_dict=_dict) +def example_loader(_dict): + return BaseItem(from_dict=_dict) def example_id_generator(**kwargs): @@ -22,22 +22,28 @@ item_loaders['base'] = example_loader item_id_generators['base'] = example_id_generator -def dicts_to_items(bot, music_dicts): +def dicts_to_items(music_dicts): items = [] for music_dict in music_dicts: type = music_dict['type'] - items.append(item_loaders[type](bot, music_dict)) + items.append(item_loaders[type](music_dict)) return items -def dict_to_item(bot, music_dict): +def dict_to_item(music_dict): type = music_dict['type'] - return item_loaders[type](bot, music_dict) + return item_loaders[type](music_dict) +class ValidationFailedError(Exception): + def __init__(self, msg = None): + self.msg = msg + +class PreparationFailedError(Exception): + def __init__(self, msg = None): + self.msg = msg class BaseItem: - def __init__(self, bot, from_dict=None): - self.bot = bot + def __init__(self, from_dict=None): self.log = logging.getLogger("bot") self.type = "base" self.title = "" @@ -64,7 +70,7 @@ class BaseItem: return True if self.ready == "failed" else False def validate(self): - return False + raise ValidationFailedError(None) def uri(self): raise @@ -104,10 +110,6 @@ class BaseItem: def display_type(self): return "" - def send_client_message(self, msg): - if self.bot: - self.bot.send_channel_msg(msg) # TODO: this is way too ugly. It mixed up bot with items. Change it into exceptions in the future. - def to_dict(self): return {"type": self.type, "id": self.id, diff --git a/media/playlist.py b/media/playlist.py index b515703..4f11da1 100644 --- a/media/playlist.py +++ b/media/playlist.py @@ -7,6 +7,7 @@ import time import variables as var from media.cache import CachedItemWrapper, get_cached_wrapper_from_dict, get_cached_wrapper_by_id from database import Condition +from media.item import ValidationFailedError, PreparationFailedError def get_playlist(mode, _list=None, index=None): @@ -196,7 +197,7 @@ class BasePlaylist(list): items.sort(key=lambda v: int(v[0])) for item in items: item = json.loads(item[1]) - music_wrapper = get_cached_wrapper_by_id(var.bot, item['id'], item['user']) + music_wrapper = get_cached_wrapper_by_id(item['id'], item['user']) if music_wrapper: music_wrappers.append(music_wrapper) self.from_list(music_wrappers, current_index) @@ -224,33 +225,23 @@ class BasePlaylist(list): item = self.pending_items.pop() self.log.debug("playlist: validating %s" % item.format_debug_string()) ver = item.version - if not item.validate() or item.is_failed(): + + try: + item.validate() + except ValidationFailedError as e: self.log.debug("playlist: validating failed.") + if var.bot: + var.bot.send_channel_msg(e.msg) var.cache.free_and_delete(item.id) self.remove_by_id(item.id) continue + if item.version > ver: self.version += 1 self.log.debug("playlist: validating finished.") self.validating_thread_lock.release() - def async_prepare(self, index): - th = threading.Thread( - target=self._prepare, name="Prepare-" + self[index].id[:7], args=(index,)) - self.log.info( - "%s: start preparing item in thread: " % self[index].item().type + self[index].format_debug_string()) - th.daemon = True - th.start() - return th - - def _prepare(self, index): - item = self[index] - ver = item.version - item.prepare() - if item.version > ver: - self.version += 1 - class OneshotPlaylist(BasePlaylist): def __init__(self): @@ -363,7 +354,7 @@ class AutoPlaylist(OneshotPlaylist): Condition().and_like('tags', "%don't autoplay,%"))) if dicts: - _list = [get_cached_wrapper_from_dict(var.bot, _dict, "AutoPlay") for _dict in dicts] + _list = [get_cached_wrapper_from_dict(_dict, "AutoPlay") for _dict in dicts] self.from_list(_list, -1) # def from_list(self, _list, current_index): diff --git a/media/radio.py b/media/radio.py index f7e10e5..d56bdb9 100644 --- a/media/radio.py +++ b/media/radio.py @@ -86,15 +86,15 @@ def get_radio_title(url): return url -def radio_item_builder(bot, **kwargs): +def radio_item_builder(**kwargs): if 'name' in kwargs: - return RadioItem(bot, kwargs['url'], kwargs['name']) + return RadioItem(kwargs['url'], kwargs['name']) else: - return RadioItem(bot, kwargs['url'], '') + return RadioItem(kwargs['url'], '') -def radio_item_loader(bot, _dict): - return RadioItem(bot, "", "", _dict) +def radio_item_loader(_dict): + return RadioItem("", "", _dict) def radio_item_id_generator(**kwargs): @@ -107,9 +107,9 @@ item_id_generators['radio'] = radio_item_id_generator class RadioItem(BaseItem): - def __init__(self, bot, url, name="", from_dict=None): + def __init__(self, url, name="", from_dict=None): if from_dict is None: - super().__init__(bot) + super().__init__() self.url = url if not name: self.title = get_radio_server_description(self.url) # The title of the radio station @@ -117,7 +117,7 @@ class RadioItem(BaseItem): self.title = name self.id = hashlib.md5(url.encode()).hexdigest() else: - super().__init__(bot, from_dict) + super().__init__(from_dict) self.url = from_dict['url'] self.title = from_dict['title'] diff --git a/media/url.py b/media/url.py index 2ae011f..07cc797 100644 --- a/media/url.py +++ b/media/url.py @@ -12,18 +12,19 @@ import base64 import constants import media import variables as var -from media.item import BaseItem, item_builders, item_loaders, item_id_generators +from media.item import BaseItem, item_builders, item_loaders, item_id_generators, ValidationFailedError, \ + PreparationFailedError import media.system log = logging.getLogger("bot") -def url_item_builder(bot, **kwargs): - return URLItem(bot, kwargs['url']) +def url_item_builder(**kwargs): + return URLItem(kwargs['url']) -def url_item_loader(bot, _dict): - return URLItem(bot, "", _dict) +def url_item_loader(_dict): + return URLItem("", _dict) def url_item_id_generator(**kwargs): @@ -36,10 +37,10 @@ item_id_generators['url'] = url_item_id_generator class URLItem(BaseItem): - def __init__(self, bot, url, from_dict=None): + def __init__(self, url, from_dict=None): self.validating_lock = threading.Lock() if from_dict is None: - super().__init__(bot) + super().__init__() self.url = url if url[-1] != "/" else url[:-1] self.title = '' self.duration = 0 @@ -47,7 +48,7 @@ class URLItem(BaseItem): self.path = var.tmp_folder + self.id + ".mp3" self.thumbnail = '' else: - super().__init__(bot, from_dict) + super().__init__(from_dict) self.url = from_dict['url'] self.duration = from_dict['duration'] self.path = from_dict['path'] @@ -77,10 +78,10 @@ class URLItem(BaseItem): self.validating_lock.release() return True - if self.ready == 'failed': - self.validating_lock.release() - return False - + # if self.ready == 'failed': + # self.validating_lock.release() + # return False + # if os.path.exists(self.path): self.validating_lock.release() self.ready = "yes" @@ -97,8 +98,7 @@ class URLItem(BaseItem): # Check the length, useful in case of playlist, it wasn't checked before) log.info( "url: " + self.url + " has a duration of " + str(self.duration) + " min -- too long") - self.send_client_message(constants.strings('too_long', song=self.title)) - return False + raise ValidationFailedError(constants.strings('too_long', song=self.title)) else: self.ready = "validated" self.version += 1 # notify wrapper to save me @@ -136,8 +136,7 @@ class URLItem(BaseItem): if not succeed: self.ready = 'failed' self.log.error("url: error while fetching info from the URL") - self.send_client_message(constants.strings('unable_download')) - return False + raise ValidationFailedError(constants.strings('unable_download', item=self.format_title())) def _download(self): media.system.clear_tmp_folder(var.tmp_folder, var.config.getint('bot', 'tmp_folder_max_size')) @@ -190,10 +189,9 @@ class URLItem(BaseItem): else: for f in glob.glob(base_path + "*"): os.remove(f) - self.send_client_message(constants.strings('unable_download')) self.ready = "failed" self.downloading = False - return False + raise PreparationFailedError(constants.strings('unable_download', item=self.format_title())) def _read_thumbnail_from_file(self, path_thumbnail): if os.path.isfile(path_thumbnail): diff --git a/media/url_from_playlist.py b/media/url_from_playlist.py index 99b6007..96af820 100644 --- a/media/url_from_playlist.py +++ b/media/url_from_playlist.py @@ -51,16 +51,15 @@ def get_playlist_info(url, start_index=0, user=""): return items -def playlist_url_item_builder(bot, **kwargs): - return PlaylistURLItem(bot, - kwargs['url'], +def playlist_url_item_builder(**kwargs): + return PlaylistURLItem(kwargs['url'], kwargs['title'], kwargs['playlist_url'], kwargs['playlist_title']) -def playlist_url_item_loader(bot, _dict): - return PlaylistURLItem(bot, "", "", "", "", _dict) +def playlist_url_item_loader(_dict): + return PlaylistURLItem("", "", "", "", _dict) item_builders['url_from_playlist'] = playlist_url_item_builder @@ -69,14 +68,14 @@ item_id_generators['url_from_playlist'] = url_item_id_generator class PlaylistURLItem(URLItem): - def __init__(self, bot, url, title, playlist_url, playlist_title, from_dict=None): + def __init__(self, url, title, playlist_url, playlist_title, from_dict=None): if from_dict is None: - super().__init__(bot, url) + super().__init__(url) self.title = title self.playlist_url = playlist_url self.playlist_title = playlist_title else: - super().__init__(bot, "", from_dict) + super().__init__("", from_dict) self.playlist_title = from_dict['playlist_title'] self.playlist_url = from_dict['playlist_url'] diff --git a/mumbleBot.py b/mumbleBot.py index ac3ec83..b71d914 100644 --- a/mumbleBot.py +++ b/mumbleBot.py @@ -24,6 +24,7 @@ import command import constants from database import SettingsDatabase, MusicDatabase import media.system +from media.item import ValidationFailedError, PreparationFailedError from media.playlist import BasePlaylist from media.cache import MusicCache @@ -393,14 +394,36 @@ class MumbleBot: # however, for performance consideration, youtube playlist won't be validate when added. # the validation has to be done here. next = var.playlist.next_item() - if next.validate(): + try: + next.validate() if not next.is_ready(): - var.playlist.async_prepare(var.playlist.next_index()) + self.async_download(next) + break - else: + except ValidationFailedError as e: + self.send_channel_msg(e.msg) var.playlist.remove_by_id(next.id) var.cache.free_and_delete(next.id) + def async_download(self, item): + th = threading.Thread( + target=self._download, name="Prepare-" + item.id[:7], args=(item,)) + self.log.info("bot: start preparing item in thread: %s" % item.format_debug_string()) + th.daemon = True + th.start() + return th + + def _download(self, item): + ver = item.version + try: + item.prepare() + except PreparationFailedError as e: + self.send_channel_msg(e.msg) + return False + + if item.version > ver: + var.playlist.version += 1 + # ======================= # Loop # ======================= @@ -460,13 +483,17 @@ class MumbleBot: if not self.wait_for_ready: # if wait_for_ready flag is not true, move to the next song. if var.playlist.next(): current = var.playlist.current_item() - if current.validate(): + try: + current.validate() if not current.is_ready(): self.log.info("bot: current music isn't ready, start downloading.") - var.playlist.async_prepare(var.playlist.current_index) - self.send_channel_msg(constants.strings('download_in_progress', item=current.format_title())) + self.async_download(current) + self.send_channel_msg( + constants.strings('download_in_progress', item=current.format_title())) self.wait_for_ready = True - else: + + except ValidationFailedError as e: + self.send_channel_msg(e.msg) var.playlist.remove_by_id(current.id) var.cache.free_and_delete(current.id) else: @@ -480,6 +507,7 @@ class MumbleBot: self.async_download_next() elif current.is_failed(): var.playlist.remove_by_id(current.id) + self.wait_for_ready = False else: self._loop_status = 'Wait for the next item to be ready' else: @@ -709,7 +737,7 @@ if __name__ == '__main__': command.register_all_commands(var.bot) if var.config.get("bot", "refresh_cache_on_startup", fallback=True): - var.cache.build_dir_cache(var.bot) + var.cache.build_dir_cache() # load playlist if var.config.getboolean('bot', 'save_playlist', fallback=True):