From ffe973eee989582c5763bc775275442a8e188510 Mon Sep 17 00:00:00 2001 From: drinfernoo Date: Fri, 23 Jul 2021 20:07:58 -0700 Subject: [PATCH 1/7] :zap: - Cancel widget update during library scanning --- plugin.program.autowidget/resources/lib/common/utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugin.program.autowidget/resources/lib/common/utils.py b/plugin.program.autowidget/resources/lib/common/utils.py index 4f6f264a..f6412d41 100644 --- a/plugin.program.autowidget/resources/lib/common/utils.py +++ b/plugin.program.autowidget/resources/lib/common/utils.py @@ -364,6 +364,12 @@ def update_container(reload=False): refresh_time = os.path.join(_addon_data, "refresh.time") in_media = get_active_window() == "media" in_plugin = in_media and get_infolabel("Container.PluginName") == _addon_id + is_scanning = get_condition("Library.IsScanningVideo") or get_condition( + "Library.IsScanningMusic" + ) + if is_scanning: + return + if reload: if in_media: write_file(refresh_time, six.text_type(time.time())) From dee04daad0d91b25cef038604d28788e301f747d Mon Sep 17 00:00:00 2001 From: drinfernoo Date: Fri, 23 Jul 2021 20:51:31 -0700 Subject: [PATCH 2/7] :bug: - Fix "Next Page" for Python 2.7 --- plugin.program.autowidget/resources/lib/menu.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/plugin.program.autowidget/resources/lib/menu.py b/plugin.program.autowidget/resources/lib/menu.py index c359c444..38219c8d 100644 --- a/plugin.program.autowidget/resources/lib/menu.py +++ b/plugin.program.autowidget/resources/lib/menu.py @@ -728,14 +728,25 @@ def _create_action_items(group_def, _id): def _is_page_item(label, next=True): tag_pattern = r"(\[[^\]]*\])" page_count_pattern = r"(?:\W*(?:(?:\d+\D*\d*))\W*)?" - base_pattern = r"^(?:(?:.+)?(?:(?:\b{}\b)|(?:\b{}\b)){{1,2}}{}){{1}}(?:\W+)?$" + # base_pattern = r"^(?:(?:.+)?(?:(?:\b{}\b)|(?:\b{}\b)){{1,2}}{}){{1}}(?:\W+)?$" + base_pattern_prefix = r"^(?:(?:.+)?(?:" + word_pattern = r"(?:\b{}\b)" + base_pattern_suffix = r"){{1,2}}{}){{1}}(?:\W+)?$" cleaned_title = re.sub(tag_pattern, "", label.lower()).strip() next_page_words = [i.lower() for i in re.split(r"\s+", _next_page)] prev_page_words = [i.lower() for i in re.split(r"\s+", _previous_page)] - next_page_pattern = base_pattern.format(*next_page_words, page_count_pattern) - prev_page_pattern = base_pattern.format(*prev_page_words, page_count_pattern) + next_page_pattern = ( + base_pattern_prefix + + "|".join([word_pattern.format(i) for i in next_page_words]) + + base_pattern_suffix.format(page_count_pattern) + ) + prev_page_pattern = ( + base_pattern_prefix + + "|".join([word_pattern.format(i) for i in prev_page_words]) + + base_pattern_suffix.format(page_count_pattern) + ) contains_dir_page = ( re.search(next_page_pattern if next else prev_page_pattern, cleaned_title) From 78c28971f4d9d60e7f969dad05400b0259adf2ca Mon Sep 17 00:00:00 2001 From: drinfernoo Date: Sat, 24 Jul 2021 16:50:34 -0700 Subject: [PATCH 3/7] :art: - Use None for content type in menus --- .../resources/lib/add.py | 4 +- .../resources/lib/common/router.py | 4 +- .../resources/lib/edit.py | 5 +- .../resources/lib/menu.py | 74 ++++++++++--------- 4 files changed, 47 insertions(+), 40 deletions(-) diff --git a/plugin.program.autowidget/resources/lib/add.py b/plugin.program.autowidget/resources/lib/add.py index d0607daa..6252c87e 100644 --- a/plugin.program.autowidget/resources/lib/add.py +++ b/plugin.program.autowidget/resources/lib/add.py @@ -207,7 +207,7 @@ def add_group(target, group_name=""): "id": group_id, "art": folder_sync if target == "widget" else folder_shortcut, "version": settings.get_addon_info("version"), - "content": "files", + "content": None, } utils.write_json(filename, group_def) @@ -257,7 +257,7 @@ def _add_path(group_def, labels, over=False): labels["file"]["filetype"] = "file" labels["file"]["file"] = labels["file"]["file"].split("&")[0] elif labels["target"] == "shortcut" and labels["file"]["filetype"] == "file": - labels["content"] = "files" + labels["content"] = None manage.write_path(group_def, path_def=labels) diff --git a/plugin.program.autowidget/resources/lib/common/router.py b/plugin.program.autowidget/resources/lib/common/router.py index ff1b45eb..70fd46e0 100644 --- a/plugin.program.autowidget/resources/lib/common/router.py +++ b/plugin.program.autowidget/resources/lib/common/router.py @@ -120,4 +120,6 @@ def dispatch(_plugin, _handle, _params): if is_dir: directory.add_sort_methods(_handle) - directory.finish_directory(_handle, category, is_type) + directory.finish_directory( + _handle, category, is_type if is_type not in [None, "none"] else "" + ) diff --git a/plugin.program.autowidget/resources/lib/edit.py b/plugin.program.autowidget/resources/lib/edit.py index 5c71f54e..1c1c44ae 100644 --- a/plugin.program.autowidget/resources/lib/edit.py +++ b/plugin.program.autowidget/resources/lib/edit.py @@ -351,6 +351,7 @@ def _get_value(edit_def, key): value = utils.set_color() elif key == "content": options = [ + "none", "files", "movies", "tvshows", @@ -364,7 +365,9 @@ def _get_value(edit_def, key): "games", ] type = dialog.select( - utils.get_string(30119), options, preselect=options.index(default) + utils.get_string(30119), + options, + preselect=options.index(default if default in options else "none"), ) value = options[type] else: diff --git a/plugin.program.autowidget/resources/lib/menu.py b/plugin.program.autowidget/resources/lib/menu.py index 38219c8d..becdcbaa 100644 --- a/plugin.program.autowidget/resources/lib/menu.py +++ b/plugin.program.autowidget/resources/lib/menu.py @@ -53,7 +53,7 @@ def root_menu(): title=30008, params={"mode": "tools"}, art=utils.get_art("tools"), isFolder=True ) - return True, "AutoWidget", "files" + return True, "AutoWidget", None def my_groups_menu(): @@ -86,18 +86,20 @@ def my_groups_menu(): isFolder=False, props={"specialsort": "bottom"}, ) - directory.add_menu_item( - title=30010, - params={"mode": "manage", "action": "add_group", "target": "widget"}, - art=utils.get_art("folder-sync"), - ) directory.add_menu_item( title=30011, params={"mode": "manage", "action": "add_group", "target": "shortcut"}, art=utils.get_art("folder-shortcut"), + props={"specialsort": "bottom"}, + ) + directory.add_menu_item( + title=30010, + params={"mode": "manage", "action": "add_group", "target": "widget"}, + art=utils.get_art("folder-sync"), + props={"specialsort": "bottom"}, ) - return True, utils.get_string(30007), "files" + return True, utils.get_string(30007), None def group_menu(group_id): @@ -110,12 +112,12 @@ def group_menu(group_id): '"{}" is missing, please repoint the widget to fix it.'.format(group_id), "error", ) - return False, "AutoWidget", "files" + return False, "AutoWidget", None group_name = group_def["label"] group_type = group_def["type"] paths = group_def["paths"] - content = group_def.get("content", "files") + content = group_def.get("content") if len(paths) > 0: utils.log( @@ -243,7 +245,7 @@ def active_widgets_menu(): props={"specialsort": "bottom"}, ) - return True, utils.get_string(30052), "files" + return True, utils.get_string(30052), None def tools_menu(): @@ -251,7 +253,6 @@ def tools_menu(): title=30006, params={"mode": "force"}, art=utils.get_art("refresh"), - info={"plot": utils.get_string(30012)}, isFolder=False, ) directory.add_menu_item( @@ -279,7 +280,7 @@ def tools_menu(): isFolder=False, ) - return True, utils.get_string(30008), "files" + return True, utils.get_string(30008), None def show_path( @@ -299,28 +300,29 @@ def show_path( widget_def = manage.get_widget_by_id(widget_id) if not widget_def: - return True, "AutoWidget", "videos" + return True, "AutoWidget", None - content = widget_path.get("content", "videos") + content = widget_path.get("content") action = widget_def.get("action", "") if not titles: titles = [] stack = widget_def.get("stack", []) path = widget_path["file"]["file"] if not stack else stack[-1] - files, hash = refresh.get_files_list(path, widget_id) - if not files: - properties = { - "autoLabel": path_label, - "autoID": widget_id, - "autoAction": action, - "autoCache": hash, - } - if files is None: - show_error(path_label, properties) - elif files == []: - show_empty(path_label, properties) - return titles if titles else True, path_label, content + + files, hash = refresh.get_files_list(path, path_label, widget_id) + # if not files: + # properties = { + # "autoLabel": path_label, + # "autoID": widget_id, + # "autoAction": action, + # "autoCache": hash, + # } + # if files is None: + # show_error(path_label, properties) + # elif files == []: + # show_empty(path_label, properties) + # return titles if titles else True, path_label, content utils.log("Loading items from {}".format(path), "debug") @@ -485,13 +487,13 @@ def path_menu(group_id, action, widget_id): art=utils.get_art("alert"), isFolder=True, ) - return True, "AutoWidget", "files" + return True, "AutoWidget", None group_name = group_def.get("label", "") paths = group_def.get("paths", []) if len(paths) == 0: directory.add_menu_item(title=30019, art=utils.get_art("alert"), isFolder=True) - return True, group_name, "files" + return True, group_name, None widget_def = manage.get_widget_by_id(widget_id, group_id) if not widget_def: @@ -501,7 +503,7 @@ def path_menu(group_id, action, widget_id): utils.get_string(30088), paths, indices=True, single=True ) if idx == -1: - return True, "AutoWidget", "videos" + return True, "AutoWidget", None widget_def = manage.initialize(group_def, action, widget_id, keep=idx) elif action == "cycling": @@ -511,7 +513,7 @@ def path_menu(group_id, action, widget_id): ) if idx == -1: del dialog - return True, "AutoWidget", "videos" + return True, "AutoWidget", None _action = "random" if idx == 0 else "next" @@ -544,7 +546,7 @@ def path_menu(group_id, action, widget_id): return titles, cat, type else: directory.add_menu_item(title=30045, art=info, isFolder=True) - return True, group_name, "files" + return True, group_name, None def merged_path(group_id, widget_id): @@ -555,7 +557,7 @@ def merged_path(group_id, widget_id): paths = group_def.get("paths", []) if len(paths) == 0: directory.add_menu_item(title=30019, art=utils.get_art("alert"), isFolder=False) - return True, group_name, "files" + return True, group_name, None widget_def = manage.get_widget_by_id(widget_id, group_id) if widget_def and _window != "dialog": @@ -595,7 +597,7 @@ def merged_path(group_id, widget_id): return titles, cat, type else: directory.add_menu_item(title=30045, art=info, isFolder=True) - return True, group_name, "files" + return True, group_name, None def _create_group_context_items(group_id, target): @@ -764,7 +766,7 @@ def show_error(id, props=None): isFolder=False, ) - return True, id, "files" + return True, id, None def show_empty(id, props=None): @@ -775,4 +777,4 @@ def show_empty(id, props=None): isFolder=False, ) - return True, id, "files" + return True, id, None From 6f76263f5eef2159d75435d3eb4187524b459a68 Mon Sep 17 00:00:00 2001 From: drinfernoo Date: Sun, 25 Jul 2021 14:12:27 -0700 Subject: [PATCH 4/7] :bug: - Fix widget cleaning for skins that use favorites Close #100 --- plugin.program.autowidget/resources/lib/manage.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugin.program.autowidget/resources/lib/manage.py b/plugin.program.autowidget/resources/lib/manage.py index 07b18ea3..bdc7a3f7 100644 --- a/plugin.program.autowidget/resources/lib/manage.py +++ b/plugin.program.autowidget/resources/lib/manage.py @@ -7,6 +7,7 @@ from resources.lib.common import utils _addon_data = utils.translate_path(settings.get_addon_info("profile")) +_userdata = utils.translate_path("special://userdata/") _skin_shortcuts = utils.translate_path( settings.get_addon_info("profile", addon="script.skinshortcuts") ) @@ -39,6 +40,9 @@ def clean(widget_id=None, notify=False, all=False): if ext[-1] in ["xml", "properties"]: path = os.path.join(_skin_shortcuts, xml) files.append(path) + favorites = os.path.join(_userdata, "favourites.xml") + if os.path.exists(favorites): + files.append(favorites) remove = [] removed = 0 From 4d0339ff2dbfaac95fd5ad83eacf8008f1c6847c Mon Sep 17 00:00:00 2001 From: drinfernoo Date: Sun, 25 Jul 2021 14:33:37 -0700 Subject: [PATCH 5/7] :bug: - Fix refreshing for older widgets --- plugin.program.autowidget/resources/lib/manage.py | 6 +++--- plugin.program.autowidget/resources/lib/refresh.py | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/plugin.program.autowidget/resources/lib/manage.py b/plugin.program.autowidget/resources/lib/manage.py index bdc7a3f7..c5e88ded 100644 --- a/plugin.program.autowidget/resources/lib/manage.py +++ b/plugin.program.autowidget/resources/lib/manage.py @@ -152,7 +152,7 @@ def save_path_details(params): def get_group_by_id(group_id): if not group_id: - return + return {} filename = "{}.group".format(group_id) path = os.path.join(_addon_data, filename) @@ -168,7 +168,7 @@ def get_group_by_id(group_id): def get_path_by_id(path_id, group_id=None): if not path_id: - return + return {} for defined in find_defined_paths(group_id): if defined.get("id", "") == path_id: @@ -177,7 +177,7 @@ def get_path_by_id(path_id, group_id=None): def get_widget_by_id(widget_id, group_id=None): if not widget_id: - return + return {} for defined in find_defined_widgets(group_id): if defined.get("id", "") == widget_id: diff --git a/plugin.program.autowidget/resources/lib/refresh.py b/plugin.program.autowidget/resources/lib/refresh.py index e9e3a253..5ba396fb 100644 --- a/plugin.program.autowidget/resources/lib/refresh.py +++ b/plugin.program.autowidget/resources/lib/refresh.py @@ -211,7 +211,11 @@ def refresh(widget_id, widget_def=None, paths=None, force=False, single=False): paths = ( [p for p in cycle_paths] if cycle_paths - else manage.find_defined_paths(group_id) + else [ + p.get("id") + for p in manage.find_defined_paths(group_id) + if p.get("id") is not None + ] ) if action: From 510ee2df6e3f117e2d5482e92ea83fc7fc1028ca Mon Sep 17 00:00:00 2001 From: drinfernoo Date: Sun, 25 Jul 2021 14:40:15 -0700 Subject: [PATCH 6/7] :bug: - Automatically convert widget definitions to handle cycle_paths --- plugin.program.autowidget/resources/lib/refresh.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/plugin.program.autowidget/resources/lib/refresh.py b/plugin.program.autowidget/resources/lib/refresh.py index 5ba396fb..bab93fa5 100644 --- a/plugin.program.autowidget/resources/lib/refresh.py +++ b/plugin.program.autowidget/resources/lib/refresh.py @@ -208,15 +208,11 @@ def refresh(widget_id, widget_def=None, paths=None, force=False, single=False): if not paths: cycle_paths = widget_def.get("cycle_paths") - paths = ( - [p for p in cycle_paths] - if cycle_paths - else [ - p.get("id") - for p in manage.find_defined_paths(group_id) - if p.get("id") is not None - ] - ) + if cycle_paths is None: + cycle_paths = [p.get("id") for p in manage.find_defined_paths(group_id)] + widget_def["cycle_paths"] = cycle_paths + + paths = [p for p in cycle_paths] if action: if len(paths) > 0: From b9c5e5f30b39fb8f3649584a2c0ef248111c6895 Mon Sep 17 00:00:00 2001 From: Dylan Jay Date: Mon, 26 Jul 2021 22:10:43 +0700 Subject: [PATCH 7/7] only update requested path and with updating missing widget --- .../resources/lib/common/cache.py | 76 ++++++------------- .../resources/lib/refresh.py | 14 ++-- 2 files changed, 28 insertions(+), 62 deletions(-) diff --git a/plugin.program.autowidget/resources/lib/common/cache.py b/plugin.program.autowidget/resources/lib/common/cache.py index 609fa2a1..5dbd7971 100644 --- a/plugin.program.autowidget/resources/lib/common/cache.py +++ b/plugin.program.autowidget/resources/lib/common/cache.py @@ -79,7 +79,8 @@ def next_cache_queue(): # TODO: need to workout if a blocking write is happen while it was queued or right now. # probably need a .lock file to ensure foreground calls can get priority. cache_data = read_history(path, create_if_missing=True) - yield hash, cache_data + widget_id = utils.read_json(queue_path).get("widget_id", None) + yield path, cache_data, widget_id def push_cache_queue(path, widget_id=None): @@ -100,7 +101,7 @@ def push_cache_queue(path, widget_id=None): if os.path.exists(queue_path): pass # Leave original modification date so item is higher priority else: - utils.write_json(queue_path, {"hash": hash, "path": path}) + utils.write_json(queue_path, {"hash": hash, "path": path, "widget_id": widget_id}) def is_cache_queue(hash): @@ -130,63 +131,30 @@ def widgets_for_path(path): return set(widgets) -def cache_and_update(hash, widget_ids, notify=None): +def cache_and_update(path, widget_id, cache_data, notify=None): """a widget might have many paths. Ensure each path is either queued for an update or is expired and if so force it to be refreshed. When going through the queue this could mean we refresh paths that other widgets also use. These will then be skipped. """ - assert widget_ids - affected_widgets = set() + assert widget_id + assert cache_data.get("path") == path + assert widget_id in cache_data["widgets"] - changed = False - path = widget_ids.get("path", "") - # TODO: we might be updating paths used by widgets that weren't initiall queued. - # We need to return those and ensure they get refreshed also. - affected_widgets = affected_widgets.union(widgets_for_path(path)) - for widget_id in affected_widgets: - if is_cache_queue(hash): - # we need to update this path regardless - if notify is not None: - widget_def = manage.get_widget_by_id(widget_id) - notify(widget_def.get("label", ""), path) - new_files, files_changed = cache_files(path, widget_id) - changed = changed or files_changed - remove_cache_queue(hash) - # else: This bit is broken down below - # # double check this hasn't been updated already when updating another widget - # expiry, _ = cache.cache_expiry(hash, widget_id, no_queue=True) - # if expiry <= time.time(): - # cache.cache_files(path, widget_id) - # else: - # pass # Skipping this path because its already been updated - - # TODO: update every widget? - # for widget_id in widget_ids: - # widget_def = manage.get_widget_by_id(widget_id) - # if not widget_def: - # continue - # widget_path = widget_def.get("path", "") - # utils.log( - # "trying to update {} with widget def {}".format(widget_id, widget_def), - # "inspect", - # ) - - # if type(widget_path) != list: - # widget_path = [widget_path] - # for path_id in widget_path: - # # simple compatibility with pre-3.3.0 widgets - # if isinstance(path_id, dict): - # path_id = path_id.get("id", "") - # path = manage.get_path_by_id(path_id) - # if not path: - # continue - - # _label = path["label"] - # path = path["file"]["file"] - # # TODO: only need to do that if a path has changed which we can tell from the history - # if changed: - # _update_strings(widget_def) - return affected_widgets + hash = path2hash(path) + if not is_cache_queue(hash): + return [] + + if notify is not None: + widget_def = manage.get_widget_by_id(widget_id) + if widget_def is not None: + notify(widget_def.get("label", ""), path) + + new_files, files_changed = cache_files(path, widget_id) + remove_cache_queue(hash) + + # TODO: this is all widgets that ever requested this path. do we + # need to update all of them? + return cache_data["widgets"] if files_changed else [] def cache_files(path, widget_id): diff --git a/plugin.program.autowidget/resources/lib/refresh.py b/plugin.program.autowidget/resources/lib/refresh.py index ecac83a1..b521cd98 100644 --- a/plugin.program.autowidget/resources/lib/refresh.py +++ b/plugin.program.autowidget/resources/lib/refresh.py @@ -108,20 +108,18 @@ def __call__(self, groupname, path): progress = Progress() while queue: - hash, widget_ids = queue.pop(0) + path, cache_data, widget_id = queue.pop(0) + hash = cache.path2hash(path) utils.log("Dequeued cache update: {}".format(hash[:5]), "notice") - affected_widgets = cache.cache_and_update( - hash, widget_ids, notify=progress - ) + affected_widgets = set(cache.cache_and_update( + path, widget_id, cache_data, notify=progress + )) if affected_widgets: updated = True - cache.remove_cache_queue( - hash - ) # Just in queued path's widget defintion has changed and it didn't update this path unrefreshed_widgets = unrefreshed_widgets.union( affected_widgets - ).difference(set(widget_ids)) + ) # # wait 5s or for the skin to reload the widget # # this should reduce churn at startup where widgets take too long too long show up # before_update = time.time() # TODO: have .access file so we can put above update