diff --git a/script.service.checkpreviousepisode/README.md b/script.service.checkpreviousepisode/README.md index d55ec2234f..bab0573ddf 100644 --- a/script.service.checkpreviousepisode/README.md +++ b/script.service.checkpreviousepisode/README.md @@ -8,11 +8,13 @@ Kodi Check Previous Episode Kodi script to prevent accidental spoilers by checking you have actually watched the previous episode (i.e. as recorded in the Kodi library). -You can mark shows where episode order doesn't matter as shows to be ignored (and unmark them in the addon settings if you change your mind), and if you're in the habit of e.g. deleting seasons you have watched, you can force it to only check when the prior epsiode is actually in your library. +You can mark shows where episode order doesn't matter as shows to be ignored (and unmark them in the add-on settings if you change your mind), and if you're in the habit of e.g. deleting seasons you have watched, you can force it to only check when the prior episode is actually in your library. If it detects you've started playback of an episode you probably shouldn't have, the video will be paused, and you'll get a pop up window with options to stop playback, carry on on this occasion, or carry on and also mark the show as one to ignore from now on. -Support via the forum thread: +Skinners can even skin the select dialogue by listening to a Window property `CheckPreviousEpisode` which is set to `MissingPreviousEpisode` when the select dialogue is showing (search the [Confluence repo](https://github.com/xbmc/skin.confluence) for `CheckPreviousEpisode` for an example of how this can be done). -Available form the main Kodi repository (legacy Python 2 version for Kodi Leia and below, Python 3 version for Kodi Matrix and the on). +Support via the forum thread: , or open an issue here. + +Available form the main Kodi repository (legacy Python 2 version for Kodi Leia and below, Python 3 version for Kodi Matrix and on). diff --git a/script.service.checkpreviousepisode/addon.xml b/script.service.checkpreviousepisode/addon.xml index 830341939f..4e80b65da2 100644 --- a/script.service.checkpreviousepisode/addon.xml +++ b/script.service.checkpreviousepisode/addon.xml @@ -1,5 +1,5 @@ - + @@ -17,9 +17,9 @@ https://forum.kodi.tv/showthread.php?tid=355464 https://kodi.wiki/view/Add-on:XBMC_Check_Previous_Episode https://github.com/bossanova808/script.service.checkpreviousepisode - v0.4.8 -- Remove old common code, use new module -- Fix bug if last ignored show is removed from ignore list then that show is re-played in same Kodi session + v0.4.9 +- Prep for Piers, use new module Logger +- Sundry fixes/tightening from CodeRabbit reviews icon.png diff --git a/script.service.checkpreviousepisode/changelog.txt b/script.service.checkpreviousepisode/changelog.txt index 9833f0681c..bc55bd15c8 100644 --- a/script.service.checkpreviousepisode/changelog.txt +++ b/script.service.checkpreviousepisode/changelog.txt @@ -1,3 +1,7 @@ +v0.4.9 +- Prep for Piers, use new module Logger +- Sundry fixes/tightening from CodeRabbit reviews + v0.4.8 - Remove old common code, use new module - Fix bug if last ignored show is removed from ignore list then that show is re-played in same Kodi session diff --git a/script.service.checkpreviousepisode/default.py b/script.service.checkpreviousepisode/default.py index 3f912f0551..4316d6db26 100644 --- a/script.service.checkpreviousepisode/default.py +++ b/script.service.checkpreviousepisode/default.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from resources.lib import check_previous_episode import sys from bossanova808 import exception_logger diff --git a/script.service.checkpreviousepisode/resources/language/resource.language.sv_se/strings.po b/script.service.checkpreviousepisode/resources/language/resource.language.sv_se/strings.po index 819a5d25c7..f066551177 100644 --- a/script.service.checkpreviousepisode/resources/language/resource.language.sv_se/strings.po +++ b/script.service.checkpreviousepisode/resources/language/resource.language.sv_se/strings.po @@ -1,4 +1,4 @@ -# XBMC Media Center language file +# XBMC Media Center language file - Swedish # Addon Name: XBMC Version Check # Addon id: script.xbmc.checkpreviousepisode # Addon Provider: Lucleonhart @@ -7,43 +7,56 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: xbmc@lucleonhart.de\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: JKB\n" -"Language-Team: English (http://www.transifex.com/projects/p/xbmc-addons/language/en/)\n" +"PO-Revision-Date: 2025-09-10 11:32+0200\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish\n" +"Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.7\n" + +msgctxt "#32020" +msgid "Previous episode not watched! Choose to:" +msgstr "Föregående avsnitt har inte visats! Välj att:" + +msgctxt "#32021" +msgid "Stop playback" +msgstr "Stoppa uppspelning" + +msgctxt "#32022" +msgid "Continue playback" +msgstr "Fortsätt uppspelning" -msgctxt "#32001" -msgid "Missing Episode" -msgstr "Saknat avsnitt" +msgctxt "#32023" +msgid "Continue playback (and from now on ignore this show)" +msgstr "Fortsätt uppspelningen (och från och med nu ignorera denna serie)" -msgctxt "#32002" -msgid "The previous episode is missing from your library!" -msgstr "Föregående avsnitt saknas i ditt bibliotek!" +msgctxt "#32050" +msgid "Force Kodi to browse to show in library after playback prevention?" +msgstr "Tvinga Kodi att bläddra för att visa i biblioteket efter uppspelningsförebyggande?" -msgctxt "#32003" -msgid "Are you sure you want to play this one?" -msgstr "Är du säker på att du vill spela upp denna?" +msgctxt "#32051" +msgid "Warn only if previous episode actually found in library and unwatched?" +msgstr "Varning endast om föregående avsnitt faktiskt finns i biblioteket och är osett?" -msgctxt "#32004" -msgid "Unwatched Episode" -msgstr "Osett avsnitt" +msgctxt "#32052" +msgid "Remove a show from your ignored list..." +msgstr "Ta bort en serie från din ignorerade lista..." -msgctxt "#32005" -msgid "You have not watched the previous episode!" -msgstr "Du har inte tittat på föregående avsnitt!" +msgctxt "#32053" +msgid "Browse to All Seasons rather than episode season" +msgstr "Bläddra till Alla säsonger snarare än avsnittssäsong" -msgctxt "#32006" -msgid "Browse show" -msgstr "Bläddra i serien" +msgctxt "#32060" +msgid "No ignored shows to manage." +msgstr "Inga ignorerade serier att hantera." -msgctxt "#32007" -msgid "Would you like to browse the episodes of this show?" -msgstr "Önskar du bläddra bland seriens avsnitt?" +msgctxt "#32061" +msgid "General" +msgstr "Allmänt" -msgctxt "#32008" -msgid "Show Option to browse the show" -msgstr "Visa val för att bläddra i serien" \ No newline at end of file +msgctxt "#32062" +msgid "Select show to stop ignoring" +msgstr "Välj serie att inte ignorera" diff --git a/script.service.checkpreviousepisode/resources/lib/check_previous_episode.py b/script.service.checkpreviousepisode/resources/lib/check_previous_episode.py index d59fd18a3d..a9bf3ba633 100644 --- a/script.service.checkpreviousepisode/resources/lib/check_previous_episode.py +++ b/script.service.checkpreviousepisode/resources/lib/check_previous_episode.py @@ -1,5 +1,6 @@ -from bossanova808.utilities import * -from bossanova808.constants import * +import xbmcgui + +from bossanova808.constants import TRANSLATE from bossanova808.logger import Logger from bossanova808.notify import Notify # noinspection PyPackages @@ -8,8 +9,6 @@ from .monitor import KodiEventMonitor # noinspection PyPackages from .player import KodiPlayer -import xbmc -import os def manage_ignored(): @@ -25,26 +24,26 @@ def manage_ignored(): # Short circuit if no ignored shows, so nothing to manage... if len(Store.ignored_shows) < 1: - Notify.info(LANGUAGE(32060), 5000) + Notify.info(TRANSLATE(32060), 5000) return # OK, there are ignored shows in the list... - # Convert our dict to a list for the dialog... - ignored_list = [] - for key, value in list(Store.ignored_shows.items()): - ignored_list.append(value) + # Build a sorted (id, title) list for stable mapping and to handle duplicate titles + sorted_pairs = sorted( + Store.ignored_shows.items(), + key=lambda kv:((kv[1] or '').casefold(), str(kv[0])) + ) + labels = [title for (_, title) in sorted_pairs] - if ignored_list: - selected = dialog.select(LANGUAGE(32062), ignored_list) + if labels: + selected = dialog.select(TRANSLATE(32062), labels) if selected != -1: - show_title = ignored_list[selected] + tvshow_id, show_title = sorted_pairs[selected] Logger.info("User has requested we stop ignoring: " + show_title) Logger.debug("Ignored shows before removal is: " + str(Store.ignored_shows)) - # find the key (new_to_ignore_tv_show_id) for this show& remove from dict - key = list(Store.ignored_shows.keys())[list(Store.ignored_shows.values()).index(show_title)] - Store.ignored_shows.pop(key, None) - Logger.debug("Ignored shows after removal is: " + str(Store.ignored_shows)) + Store.ignored_shows.pop(tvshow_id, None) + Logger.debug("Ignored shows after removal is: " + str(Store.ignored_shows)) Store.write_ignored_shows_to_config() @@ -54,27 +53,26 @@ def run(args): :return: """ - footprints() - # Initialise the global store and load the addon settings - Store() + try: + Logger.start() + # Initialise the global store and load the addon settings + Store() - # TWO RUN-MODES - we're either running as a service, or we're running the tool to manage ignored shows... + # TWO RUN-MODES - we're either running as a service, or we're running the tool to manage ignored shows... - # MANAGE IGNORED SHOWS - if len(args) > 1: - if args[1].startswith('ManageIgnored'): + # MANAGE IGNORED SHOWS + if len(args) > 1 and args[1].startswith('ManageIgnored'): manage_ignored() - - # DEFAULT - RUN AS A SERVICE & WATCH PLAYBACK EVENTS - else: - Logger.info("Listening to onAvStarted for episode playback.") - Store.kodi_event_monitor = KodiEventMonitor(xbmc.Monitor) - Store.kodi_player = KodiPlayer(xbmc.Player) - - while not Store.kodi_event_monitor.abortRequested(): - # Sleep/wait for abort for 10 seconds - if Store.kodi_event_monitor.waitForAbort(1): - # Abort was requested while waiting. We should exit - break - - footprints(False) + # DEFAULT - RUN AS A SERVICE & WATCH PLAYBACK EVENTS + else: + Logger.info("Listening to onAVStarted for episode playback.") + kodi_event_monitor = KodiEventMonitor() + # Keep instance alive to receive Kodi player events + _kodi_player = KodiPlayer() + + while not kodi_event_monitor.waitForAbort(1): + pass + Logger.debug('Abort Requested') + + finally: + Logger.stop() diff --git a/script.service.checkpreviousepisode/resources/lib/monitor.py b/script.service.checkpreviousepisode/resources/lib/monitor.py index 3ceb33588b..0e8057daa4 100644 --- a/script.service.checkpreviousepisode/resources/lib/monitor.py +++ b/script.service.checkpreviousepisode/resources/lib/monitor.py @@ -6,13 +6,10 @@ class KodiEventMonitor(xbmc.Monitor): - def __init__(self, *args, **kwargs): - xbmc.Monitor.__init__(self) + def __init__(self): + super().__init__() Logger.debug('KodiEventMonitor __init__') def onSettingsChanged(self): Logger.info('onSettingsChanged - reload them.') Store.load_config_from_settings() - - def onAbortRequested(self): - Logger.debug('onAbortRequested') diff --git a/script.service.checkpreviousepisode/resources/lib/player.py b/script.service.checkpreviousepisode/resources/lib/player.py index c0db42bb41..2015605087 100644 --- a/script.service.checkpreviousepisode/resources/lib/player.py +++ b/script.service.checkpreviousepisode/resources/lib/player.py @@ -1,9 +1,12 @@ +import json +import xbmc +import xbmcgui + +from bossanova808.constants import TRANSLATE, HOME_WINDOW +from bossanova808.utilities import send_kodi_json, is_playback_paused from bossanova808.logger import Logger -from bossanova808.utilities import * # noinspection PyPackages from .store import Store -import xbmc -import json class KodiPlayer(xbmc.Player): @@ -11,8 +14,8 @@ class KodiPlayer(xbmc.Player): This class represents/monitors the Kodi video player """ - def __init__(self, *args): - xbmc.Player.__init__(self) + def __init__(self): + super().__init__() Logger.debug('KodiPlayer __init__') def onAVStarted(self): @@ -23,141 +26,165 @@ def onAVStarted(self): """ Logger.debug('onAVStarted') + # Get active players command = json.dumps({ - "jsonrpc": "2.0", - "id": 1, - "method": "Player.GetActivePlayers", + "jsonrpc":"2.0", + "id":1, + "method":"Player.GetActivePlayers", }) json_object = send_kodi_json("Get active players", command) - # Only do something is we get a result for our query back from Kodi - if len(json_object['result']) == 1: + active_players = json_object.get('result') or [] + video_players = [p for p in active_players if p.get('type') == 'video'] + if video_players: + playerid = video_players[0].get('playerid') + Logger.debug(f"Video player running with ID: {playerid}") + else: + Logger.debug("Player is not a video player") + return - Logger.debug(f"Player running with ID: {json_object['result'][0]['playerid']}") + command = json.dumps({ + "jsonrpc":"2.0", + "id":1, + "method":"Player.GetItem", + "params":{"playerid":playerid}, + }) + json_object = send_kodi_json("Get playing item", command) - command = json.dumps({ - "jsonrpc": "2.0", - "id": 1, - "method": "Player.GetItem", - "params": { - "playerid": json_object['result'][0]['playerid'] - } - }) - json_object = send_kodi_json("Get playing item", command) + item = json_object.get('result', {}).get('item', {}) + # Only do something if this is an episode of a TV show + if item.get('type') == 'episode': + + episode_id = item.get('id') or item.get('episodeid') + if not episode_id: + Logger.warning("An episode is playing but no episode id was found; cannot check previous episode in the library.") + return - # Only do something is this is an episode of a TV show - if json_object['result']['item']['type'] == 'episode': + Logger.info(f"A TV show episode is playing (id: {episode_id}).") - if 'id' not in json_object['result']['item']: - Logger.warning("An episode is playing, but it doesn't have an id, so can't check previous episode in Kodi library.") + command = json.dumps({ + "jsonrpc":"2.0", + "id":1, + "method":"VideoLibrary.GetEpisodeDetails", + "params":{ + "episodeid":episode_id, + "properties":["tvshowid", "showtitle", "season", "episode", "resume"] + } + }) + json_object = send_kodi_json("Get episode details", command) + + # Only do something if we can get the episode details from Kodi + episodedetails = json_object.get('result', {}).get('episodedetails') + if episodedetails: + playing_tvshowid = episodedetails.get('tvshowid') + playing_tvshow_title = episodedetails.get('showtitle') + playing_season = episodedetails.get('season') + playing_episode = episodedetails.get('episode') + resume = episodedetails.get('resume') or {} + resume_point = resume.get('position') or 0.0 + + Logger.info(f'Playing - title: {playing_tvshow_title} , id: {playing_tvshowid} , season: {playing_season}, episode: {playing_episode}, resume: {resume_point}') + + # Is show set to be ignored? + if Store.ignored_shows and playing_tvshowid in Store.ignored_shows: + Logger.info(f'Show {playing_tvshow_title} set to ignore, so allowing.') return - Logger.info(f"A TV show episode is playing (id: {json_object['result']['item']['id']}).") + # Is the resume point is non-zero - then we've previously made a decision about playing this episode, so don't make the user make it again + if resume_point > 0.0: + Logger.info(f"Show {playing_tvshow_title} Season {playing_season} Episode {playing_episode} has a non-zero resume point, so decision has been previously made to play this episode, so allowing.") + return - command = json.dumps({ - "jsonrpc": "2.0", - "id": 1, - "method": "VideoLibrary.GetEpisodeDetails", - "params": { - "episodeid": json_object['result']['item']['id'], - "properties": ["tvshowid", "showtitle", "season", "episode", "resume"] - } - }) - json_object = send_kodi_json("Get episode details", command) - - # Only do something if we can get the episode details from Kodi - if len(json_object['result']) == 1: - - playing_tvshowid = json_object['result']['episodedetails']['tvshowid'] - playing_tvshow_title = json_object['result']['episodedetails']['showtitle'] - playing_season = json_object['result']['episodedetails']['season'] - playing_episode = json_object['result']['episodedetails']['episode'] - resume_point = json_object['result']['episodedetails']['resume']['position'] - - Logger.info(f'Playing - title: {playing_tvshow_title} , id: {playing_tvshowid} , season: {playing_season}, episode: {playing_episode}, resume: {resume_point}') - - # Is show set to be ignored? - if Store.ignored_shows and playing_tvshowid in Store.ignored_shows: - Logger.info(f'Show {playing_tvshow_title} set to ignore, so allowing.') - return - - # Is the resume point is non-zero - then we've previously made a decision about playing this episode, so don't make the user make it again - if resume_point > 0.0: - Logger.info(f"Show {playing_tvshow_title} Season {playing_season} Episode {playing_episode} has a non-zero resume point, so decision has been previously made to play this episode, so allowing.") - return - - # We ignore first episodes... - if json_object['result']['episodedetails']['episode'] > 1: - - command = json.dumps({ - "jsonrpc": "2.0", - "id": 1, - "method": "VideoLibrary.GetEpisodes", - "params": { - "tvshowid": json_object['result']['episodedetails']['tvshowid'], - "season": json_object['result']['episodedetails']['season'], - "properties": ["episode", "playcount"] + # We ignore first episodes... + if playing_episode > 1: + + command = json.dumps({ + "jsonrpc":"2.0", + "id":1, + "method":"VideoLibrary.GetEpisodes", + "params":{ + "tvshowid":playing_tvshowid, + "season":playing_season, + "properties":["episode", "playcount"] } - }) - json_object = send_kodi_json("Get episodes for season", command) - - # We found some episodes for this show... - if len(json_object['result']) > 0: - found = False - playcount = 0 - for episode in json_object['result']['episodes']: - if episode['episode'] == (playing_episode - 1): - playcount += episode['playcount'] - found = True - - Logger.info(f'Found previous episode: {found}, playcount: {playcount}, ignore if absent: {Store.ignore_if_episode_absent_from_library}') - - # If we couldn't find the previous episode in the library - # AND the user has asked us to ignore this, we're done. - if not found and Store.ignore_if_episode_absent_from_library: - Logger.info("Previous episode was not found in library, and setting ignore if absent from library is true, so allowing.") - return - - # If we couldn't find the previous episode in the library, - # OR we have found the previous episode AND it is unwatched... - if not found or (found and playcount == 0): - - # Only trigger the pause if the player is actually playing as other addons may also have paused the player - if not is_playback_paused(): - Logger.info("Prior episode not watched! -> pausing playback") - self.pause() - - # Set a window property per Hitcher's request - https://forum.kodi.tv/showthread.php?tid=355464&pid=3191615#pid3191615 - HOME_WINDOW.setProperty("CheckPreviousEpisode", "MissingPreviousEpisode") - result = xbmcgui.Dialog().select(LANGUAGE(32020), [LANGUAGE(32021), LANGUAGE(32022), LANGUAGE(32023)], preselect=0) - HOME_WINDOW.setProperty("CheckPreviousEpisode", "") - - # User has requested we ignore this particular show from now on... - if result == 2: - Logger.info(f"User has requested we ignore ({playing_tvshowid}) {playing_tvshow_title} from now on.") - Store.write_ignored_shows_to_config(playing_tvshow_title, playing_tvshowid) - - if result == 1 or result == 2: - if is_playback_paused(): - Logger.info(f"Unpausing playback due to user input ({result})") - self.pause() - else: - Logger.info(f"Stopping playback due to user input ({result})") - self.stop() - - if Store.force_browse: - Logger.info("Force browsing to show/season, as per user configuration") - # Special case is the user wants to go to the All Seasons view - if Store.force_all_seasons: - playing_season = -1 - - command = json.dumps({ - "jsonrpc": "2.0", - "id": 1, - "method": "GUI.ActivateWindow", - "params": { - "window": "videos", - "parameters": [f'videodb://tvshows/titles/{playing_tvshowid}/{playing_season}'], - } - }) - send_kodi_json(f'Browse to {playing_tvshow_title}', command) + }) + json_object = send_kodi_json("Get episodes for season", command) + + episodes = json_object.get('result', {}).get('episodes', []) + + # Defaults + found = False + playcount = 0 + + if episodes: + for episode in episodes: + if episode.get('episode') == (playing_episode - 1): + playcount = (episode.get('playcount', 0) or 0) + found = True + break + + Logger.info(f'Found previous episode: {found}, playcount: {playcount}, ignore if absent: {Store.ignore_if_episode_absent_from_library}') + else: + # No episodes returned by Kodi for this season + if Store.ignore_if_episode_absent_from_library: + Logger.info("Previous episode not found in library listing and user has opted to ignore; allowing.") + return + # Treat as 'not found' and continue to prompt/pause path + found = False + playcount = 0 + + # If we couldn't find the previous episode in the library, + # OR we have found the previous episode AND it is unwatched... + if not found or playcount == 0: + + # Only trigger the pause if the player is actually playing as other addons may also have paused the player + if not is_playback_paused(): + Logger.info("Prior episode not watched! -> pausing playback") + self.pause() + + # Set a window property per Hitcher's request - https://forum.kodi.tv/showthread.php?tid=355464&pid=3191615#pid3191615 + HOME_WINDOW.setProperty("CheckPreviousEpisode", "MissingPreviousEpisode") + try: + result = xbmcgui.Dialog().select( + TRANSLATE(32020), + [TRANSLATE(32021), TRANSLATE(32022), TRANSLATE(32023)], + preselect=0 + ) + finally: + HOME_WINDOW.setProperty("CheckPreviousEpisode", "") + + if result == -1: + Logger.info("User cancelled; resuming playback.") + if is_playback_paused(): + self.pause() + return + + if result == 2: + Logger.info(f"User has requested we ignore ({playing_tvshowid}) {playing_tvshow_title} from now on.") + Store.write_ignored_shows_to_config(playing_tvshow_title, playing_tvshowid) + # fall through to unpause + + if result == 1 or result == 2: + if is_playback_paused(): + Logger.info(f"Unpausing playback due to user input ({result})") + self.pause() + else: + Logger.info(f"Stopping playback due to user input ({result})") + self.stop() + + if Store.force_browse: + Logger.info("Force browsing to show/season, as per user configuration") + # Special case is the user wants to go to the All Seasons view + if Store.force_all_seasons: + playing_season = -1 + + command = json.dumps({ + "jsonrpc":"2.0", + "id":1, + "method":"GUI.ActivateWindow", + "params":{ + "window":"videos", + "parameters":[f'videodb://tvshows/titles/{playing_tvshowid}/{playing_season}'], + } + }) + send_kodi_json(f'Browse to {playing_tvshow_title}', command) diff --git a/script.service.checkpreviousepisode/resources/lib/store.py b/script.service.checkpreviousepisode/resources/lib/store.py index 2fe95c7c50..5ad396aee5 100644 --- a/script.service.checkpreviousepisode/resources/lib/store.py +++ b/script.service.checkpreviousepisode/resources/lib/store.py @@ -1,11 +1,11 @@ import os import yaml -from bossanova808.logger import Logger -from bossanova808.constants import * -from bossanova808.utilities import * -import xbmc import xbmcvfs +from bossanova808.constants import PROFILE +from bossanova808.utilities import get_setting_as_bool +from bossanova808.logger import Logger + class Store: """ @@ -65,8 +65,9 @@ def get_ignored_shows_from_config_file(): # Update our internal list of ignored shows if there are any... if os.path.exists(Store.ignored_shows_file): Logger.info("Loading ignored shows from config file: " + Store.ignored_shows_file) - with open(Store.ignored_shows_file, 'r') as yaml_file: - Store.ignored_shows = yaml.load(yaml_file, Loader=yaml.FullLoader) + with open(Store.ignored_shows_file, 'r', encoding='utf-8') as yaml_file: + data = yaml.safe_load(yaml_file) + Store.ignored_shows = data if isinstance(data, dict) else {} else: Store.ignored_shows = {} @@ -93,6 +94,6 @@ def write_ignored_shows_to_config(new_to_ignore_tv_show_title=None, new_to_ignor return # Shows to ignore, so dump the current dict to our yaml file (clobber over any old file) - with open(Store.ignored_shows_file, 'w') as yaml_file: + with open(Store.ignored_shows_file, 'w', encoding='utf-8') as yaml_file: Logger.info(f'Ignored Shows to write to config is: {Store.ignored_shows}') - yaml.dump(Store.ignored_shows, yaml_file, default_flow_style=False) + yaml.safe_dump(Store.ignored_shows, yaml_file, default_flow_style=False, allow_unicode=True)