diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index 471a367..751e428 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -210,6 +210,10 @@ msgctxt "#32048" msgid "No downloaded videos for offline mode!" msgstr "" +msgctxt "#32049" +msgid "Use subtitles to show video locations" +msgstr "" + msgctxt "#32075" msgid "Enable 4K (default 1080p)" msgstr "" diff --git a/resources/language/resource.language.es_es/strings.po b/resources/language/resource.language.es_es/strings.po index 45922be..947b120 100644 --- a/resources/language/resource.language.es_es/strings.po +++ b/resources/language/resource.language.es_es/strings.po @@ -210,6 +210,10 @@ msgctxt "#32048" msgid "No downloaded videos for offline mode!" msgstr "" +msgctxt "#32049" +msgid "Use subtitles to show video locations" +msgstr "" + msgctxt "#32075" msgid "Enable 4K (default 1080p)" msgstr "Habilitar 4K" diff --git a/resources/language/resource.language.pt_pt/strings.po b/resources/language/resource.language.pt_pt/strings.po index 6c0a836..46bb081 100644 --- a/resources/language/resource.language.pt_pt/strings.po +++ b/resources/language/resource.language.pt_pt/strings.po @@ -210,6 +210,10 @@ msgctxt "#32048" msgid "Offline mode but no downloaded videos!" msgstr "Modo offline ativo mas não existem videos no disco" +msgctxt "#32049" +msgid "Use subtitles to show video locations" +msgstr "" + msgctxt "#32075" msgid "Enable 4K (default 1080p)" msgstr "Ativar 4K" diff --git a/resources/lib/atv.py b/resources/lib/atv.py index eaf1303..37d1aa9 100644 --- a/resources/lib/atv.py +++ b/resources/lib/atv.py @@ -7,7 +7,10 @@ """ import json +import os +import tempfile import threading +import time import xbmc import xbmcgui @@ -129,9 +132,42 @@ def onAction(self, action): addon.setSettingBool("is_locked", False) self.clearAll() + def create_sub(self, pois): + subfile = tempfile.NamedTemporaryFile(suffix=".srt", delete=False) + cursec = 0 + for i, poi in enumerate(pois, start=1): + subfile.write("{}\n".format(i).encode()) + start_ts = time.strftime('%H:%M:%S,000', time.gmtime(poi.secs)) + if i < len(pois): + end_ts = time.strftime('%H:%M:%S,000', time.gmtime(pois[i].secs)) + else: + end_ts = "99:59:59,999" + subfile.write("{} --> {}\n".format(start_ts, end_ts).encode()) + subfile.write("{}\n\n".format(poi.description).encode()) + subfile.close() + return subfile.name + + def do_play(self, url, pois): + do_subs = addon.getSettingBool("show-subtitles") + if do_subs: + subfile_path = self.create_sub(pois) + else: + subfile_path = None + + self.atv4player.play(url, windowed=True) + + if do_subs: + while not self.atv4player.isPlaying(): + xbmc.sleep(100) + self.atv4player.setSubtitles(subfile_path) + self.atv4player.showSubtitles(True) + + return subfile_path + def start_playback(self): self.playindex = 0 - self.atv4player.play(self.video_playlist[self.playindex], windowed=True) + playlist_item = self.video_playlist[self.playindex] + subfile_path = self.do_play(playlist_item.url, playlist_item.pois) while self.active and not monitor.abortRequested(): monitor.waitForAbort(1) # If we finish playing the video @@ -142,8 +178,10 @@ def start_playback(self): else: self.playindex = 0 # Using the updated iterator, start playing the next video - self.atv4player.play(self.video_playlist[self.playindex], windowed=True) - + playlist_item = self.video_playlist[self.playindex] + if subfile_path: + os.remove(subfile_path) + subfile_path = self.do_play(playlist_item.url, playlist_item.pois) def run(params=False): if not params: diff --git a/resources/lib/playlist.py b/resources/lib/playlist.py index 013cc24..04349b4 100644 --- a/resources/lib/playlist.py +++ b/resources/lib/playlist.py @@ -7,6 +7,7 @@ """ import json +import plistlib import os import tarfile from random import shuffle @@ -26,6 +27,18 @@ # Local save location of the entries.json file containing video URLs local_entries_json_path = os.path.join(addon_path, "resources", "entries.json") +# Path to the local file where we store the plist with video descriptions +local_plist_path_parts = [addon_path, "resources", "TVIdleScreenStrings.bundle", "{}.lproj", "Localizable.nocache.strings"] + +# location in the tar file for the plist file with descriptions +language_description_format_str = "TVIdleScreenStrings.bundle/{}.lproj/Localizable.nocache.strings" + +def tar_has_member(tar, key): + try: + tar.getmember(key) + return True + except KeyError: + return False # Fetch the TAR file containing the latest entries.json and overwrite the local copy def get_latest_entries_from_apple(): @@ -35,13 +48,32 @@ def get_latest_entries_from_apple(): request.urlretrieve(apple_resources_tar_url, apple_local_tar_path) # https://www.tutorialspoint.com/How-are-files-extracted-from-a-tar-file-using-Python apple_tar = tarfile.open(apple_local_tar_path) - xbmc.log("Extracting entries.json from resources.tar and placing in ./resources", level=xbmc.LOGDEBUG) - apple_tar.extract("entries.json", os.path.join(addon_path, "resources")) + xbmc.log("Extracting entries.json and video descriptions from resources.tar and placing in ./resources", level=xbmc.LOGDEBUG) + dest_dir = os.path.join(addon_path, "resources") + apple_tar.extract("entries.json", dest_dir) + language = xbmc.getLanguage(xbmc.ISO_639_1) + if tar_has_member(apple_tar, language_description_format_str.format(language)): + apple_tar.extract(language_description_format_str.format(language), dest_dir) + else: + xmbc.log("No descriptions for language {}, defaulting to English", level=xbmc.LOGWARNING) + apple_tar.extract(language_description_format_str.format('en'), dest_dir) apple_tar.close() - xbmc.log("Deleting resources.tar now that we've grabbed entries.json from it", level=xbmc.LOGDEBUG) + xbmc.log("Deleting resources.tar now that we've grabbed what we need from it", level=xbmc.LOGDEBUG) os.remove(apple_local_tar_path) +class PlaylistEntry: + def __init__(self, url, location, pois): + self.url = url + self.location = location + self.pois = pois + +class POI: + def __init__(self, secs, description): + self.secs = secs + self.description = description + def __repr__(self): + return "POI secs:{}, description: {}".format(self.secs, self.description) class AtvPlaylist: def __init__(self, ): @@ -61,6 +93,21 @@ def __init__(self, ): # Regardless of if we grabbed new Apple JSON, hit an exception, or are in offline mode, load the local copy with open(local_entries_json_path, "r") as f: self.top_level_json = json.loads(f.read()) + + language = xbmc.getLanguage(xbmc.ISO_639_1) + plist_language_parts = local_plist_path_parts.copy() + plist_language_parts[3] = plist_language_parts[3].format(language) + plist_path = os.path.join(*plist_language_parts) + if not xbmcvfs.exists(plist_path): + xbmc.log("No descriptions for language {}, defaulting to English", level=xbmc.LOGWARNING) + plist_language_parts[3] = "en.lproj" + plist_path = os.path.join(*plist_language_parts) + if xbmcvfs.exists(plist_path): + with open(plist_path, "rb") as f: + self.plist = plistlib.loads(f.read()) + else: + xbmc.log("Could not find description file, cannot enable subtitles", level=xbmc.LOGWARNING) + self.plist = None else: self.top_level_json = {} @@ -122,7 +169,18 @@ def compute_playlist_array(self): # If the file exists locally or we're not in offline mode, add it to the playlist if exists_on_disk or not self.force_offline: xbmc.log("Adding video for location {} to playlist".format(location), level=xbmc.LOGDEBUG) - self.playlist.append(url) + pois = [] + if self.plist: + if "pointsOfInterest" in block: + for secs, key in block["pointsOfInterest"].items(): + if key in self.plist: + pois.append(POI(int(secs), self.plist[key])) + elif "shotID" in block and block["shotID"] in self.plist: + pois.append(POI(0,self.plist[block["shotID"]])) + else: + xbmc.log("Could not find any descriptions for {}".format(url), level=xbmc.LOGWARNING) + pois.sort(key=lambda poi: poi.secs, reverse=False) + self.playlist.append(PlaylistEntry(url, location, pois)) # Now that we're done building the playlist, shuffle and return to the caller shuffle(self.playlist) diff --git a/resources/settings.xml b/resources/settings.xml index bde0650..1b43c84 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -13,6 +13,11 @@ false + + 0 + false + + 0 false