2023-01-12 21:02:32 -05:00
|
|
|
from __future__ import (
|
|
|
|
|
division, absolute_import, print_function, unicode_literals
|
|
|
|
|
)
|
2014-10-28 16:16:41 +11:00
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
import os
|
|
|
|
|
import time
|
|
|
|
|
import cProfile
|
|
|
|
|
import pstats
|
|
|
|
|
|
|
|
|
|
import xbmcplugin
|
|
|
|
|
import xbmcgui
|
|
|
|
|
import xbmcaddon
|
|
|
|
|
import xbmc
|
2023-01-12 20:50:41 -05:00
|
|
|
from six import StringIO
|
2023-01-14 16:47:48 -05:00
|
|
|
from six.moves.urllib.parse import quote, unquote, parse_qsl, urlencode
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2022-03-09 15:25:35 -05:00
|
|
|
from .jellyfin import api
|
2023-01-12 21:02:32 -05:00
|
|
|
from .utils import (
|
|
|
|
|
translate_string, get_version, load_user_details, get_art_url,
|
2023-01-14 16:47:48 -05:00
|
|
|
get_default_filters, translate_path, kodi_version, get_jellyfin_url
|
2023-01-12 21:02:32 -05:00
|
|
|
)
|
2018-09-26 08:41:23 +10:00
|
|
|
from .kodi_utils import HomeWindow
|
2022-03-07 19:25:44 -05:00
|
|
|
from .datamanager import clear_cached_server_data
|
2020-06-26 14:46:57 +10:00
|
|
|
from .server_detect import check_server, check_connection_speed
|
2022-03-09 22:27:18 +01:00
|
|
|
from .lazylogger import LazyLogger
|
2023-01-12 21:02:32 -05:00
|
|
|
from .menu_functions import (
|
|
|
|
|
display_main_menu, display_menu, show_movie_alpha_list,
|
|
|
|
|
show_tvshow_alpha_list, show_genre_list, show_search,
|
|
|
|
|
show_movie_pages, show_artist_alpha_list
|
|
|
|
|
)
|
2020-06-21 11:27:09 +10:00
|
|
|
from .server_sessions import show_server_sessions
|
2018-09-26 08:41:23 +10:00
|
|
|
from .action_menu import ActionMenu
|
2022-02-27 23:47:31 -05:00
|
|
|
from .dialogs import BitrateDialog
|
2023-01-12 21:02:32 -05:00
|
|
|
from .widgets import (
|
|
|
|
|
get_widget_content, get_widget_content_cast, check_for_new_content
|
|
|
|
|
)
|
2018-09-26 08:41:23 +10:00
|
|
|
from .cache_images import CacheArtwork
|
2020-06-21 11:27:09 +10:00
|
|
|
from .dir_functions import get_content, process_directory
|
2019-10-14 11:55:18 +11:00
|
|
|
from .tracking import timer
|
2020-01-03 10:00:19 +11:00
|
|
|
from .skin_cloner import clone_default_skin
|
2021-01-26 22:34:51 -05:00
|
|
|
from .play_utils import play_file
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2026-01-06 01:12:59 +01:00
|
|
|
try:
|
|
|
|
|
__addon__ = xbmcaddon.Addon()
|
|
|
|
|
__addondir__ = translate_path(__addon__.getAddonInfo('profile'))
|
|
|
|
|
__cwd__ = __addon__.getAddonInfo('path')
|
|
|
|
|
PLUGINPATH = translate_path(os.path.join(__cwd__))
|
|
|
|
|
addon_id = __addon__.getAddonInfo('id')
|
|
|
|
|
except Exception:
|
|
|
|
|
# During installation/update, addon might not be fully registered yet
|
|
|
|
|
__addon__ = None
|
|
|
|
|
__addondir__ = ''
|
|
|
|
|
__cwd__ = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
|
PLUGINPATH = __cwd__
|
|
|
|
|
addon_id = 'plugin.video.jellycon'
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log = LazyLogger(__name__)
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2019-10-14 11:55:18 +11:00
|
|
|
@timer
|
2020-06-21 11:27:09 +10:00
|
|
|
def main_entry_point():
|
2020-07-04 13:26:21 -04:00
|
|
|
log.debug("===== JellyCon START =====")
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2018-03-16 10:18:08 +11:00
|
|
|
settings = xbmcaddon.Addon()
|
2019-10-19 20:32:57 +11:00
|
|
|
profile_count = int(settings.getSetting('profile_count'))
|
2017-03-16 15:50:44 +11:00
|
|
|
pr = None
|
2019-10-19 20:32:57 +11:00
|
|
|
if profile_count > 0:
|
|
|
|
|
profile_count = profile_count - 1
|
|
|
|
|
settings.setSetting('profile_count', str(profile_count))
|
|
|
|
|
pr = cProfile.Profile()
|
|
|
|
|
pr.enable()
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Running Python: {0}".format(sys.version_info))
|
2021-12-29 16:54:05 -05:00
|
|
|
log.debug("Running JellyCon: {0}".format(get_version()))
|
2023-01-14 16:47:48 -05:00
|
|
|
log.debug("Kodi BuildVersion: {0}".format(
|
|
|
|
|
xbmc.getInfoLabel("System.BuildVersion"))
|
|
|
|
|
)
|
2022-03-09 23:19:09 +01:00
|
|
|
log.debug("Kodi Version: {0}".format(kodi_version()))
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Script argument data: {0}".format(sys.argv))
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2019-12-30 09:16:57 +11:00
|
|
|
params = get_params()
|
2022-02-27 22:15:54 -05:00
|
|
|
log.debug("Script params: {0}".format(params))
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2019-12-30 09:16:57 +11:00
|
|
|
request_path = params.get("request_path", None)
|
2014-10-28 16:16:41 +11:00
|
|
|
param_url = params.get('url', None)
|
|
|
|
|
|
2014-12-12 10:50:13 +11:00
|
|
|
mode = params.get("mode", None)
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
if (len(params) == 1 and request_path
|
|
|
|
|
and request_path.find("/library/movies") > -1):
|
|
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
check_server()
|
2019-12-30 09:16:57 +11:00
|
|
|
new_params = {}
|
|
|
|
|
new_params["item_type"] = "Movie"
|
|
|
|
|
new_params["media_type"] = "movies"
|
2020-06-21 11:27:09 +10:00
|
|
|
show_content(new_params)
|
2019-12-30 09:16:57 +11:00
|
|
|
elif mode == "CHANGE_USER":
|
2020-06-21 11:27:09 +10:00
|
|
|
check_server(change_user=True, notify=False)
|
2018-08-27 13:04:53 +10:00
|
|
|
elif mode == "CACHE_ARTWORK":
|
2018-05-18 14:53:00 +10:00
|
|
|
CacheArtwork().cache_artwork_interactive()
|
2017-05-19 20:14:14 -04:00
|
|
|
elif mode == "DETECT_SERVER":
|
2020-06-21 11:27:09 +10:00
|
|
|
check_server(force=True, notify=True)
|
2017-05-20 11:20:54 +10:00
|
|
|
elif mode == "DETECT_SERVER_USER":
|
2020-06-21 11:27:09 +10:00
|
|
|
check_server(force=True, change_user=True, notify=False)
|
2020-06-26 14:46:57 +10:00
|
|
|
elif mode == "DETECT_CONNECTION_SPEED":
|
|
|
|
|
check_connection_speed()
|
2018-11-04 08:00:46 +11:00
|
|
|
elif mode == "playTrailer":
|
|
|
|
|
item_id = params["id"]
|
2020-06-21 11:27:09 +10:00
|
|
|
play_item_trailer(item_id)
|
2017-04-06 20:08:10 +10:00
|
|
|
elif mode == "MOVIE_ALPHA":
|
2019-11-07 16:05:29 +11:00
|
|
|
show_movie_alpha_list(params)
|
2019-02-09 10:17:43 +11:00
|
|
|
elif mode == "TVSHOW_ALPHA":
|
2019-11-07 16:05:29 +11:00
|
|
|
show_tvshow_alpha_list(params)
|
2022-06-04 21:56:40 -04:00
|
|
|
elif mode == "ARTIST_ALPHA":
|
|
|
|
|
show_artist_alpha_list(params)
|
2018-02-25 10:26:11 +11:00
|
|
|
elif mode == "GENRES":
|
2019-11-07 16:05:29 +11:00
|
|
|
show_genre_list(params)
|
2018-05-10 15:27:42 +10:00
|
|
|
elif mode == "MOVIE_PAGES":
|
2019-11-07 16:05:29 +11:00
|
|
|
show_movie_pages(params)
|
2018-07-15 11:06:28 +10:00
|
|
|
elif mode == "TOGGLE_WATCHED":
|
|
|
|
|
toggle_watched(params)
|
2017-08-19 11:08:15 +10:00
|
|
|
elif mode == "SHOW_MENU":
|
2018-06-29 14:38:44 +10:00
|
|
|
show_menu(params)
|
2020-01-03 10:00:19 +11:00
|
|
|
elif mode == "CLONE_SKIN":
|
|
|
|
|
clone_default_skin()
|
2017-03-16 12:02:14 +11:00
|
|
|
elif mode == "SHOW_SETTINGS":
|
2017-05-29 06:19:33 -04:00
|
|
|
__addon__.openSettings()
|
2020-06-21 11:27:09 +10:00
|
|
|
window = xbmcgui.getCurrentWindowId()
|
|
|
|
|
if window == 10000:
|
2023-01-14 16:47:48 -05:00
|
|
|
log.debug(
|
|
|
|
|
"Currently in home - refresh to allow new settings to be taken"
|
|
|
|
|
)
|
2017-05-21 23:06:10 -04:00
|
|
|
xbmc.executebuiltin("ActivateWindow(Home)")
|
2019-03-03 10:43:56 +11:00
|
|
|
elif mode == "CLEAR_CACHE":
|
|
|
|
|
clear_cached_server_data()
|
2014-12-12 10:50:13 +11:00
|
|
|
elif mode == "WIDGET_CONTENT":
|
2020-06-21 11:27:09 +10:00
|
|
|
get_widget_content(int(sys.argv[1]), params)
|
2017-08-24 20:33:47 +10:00
|
|
|
elif mode == "WIDGET_CONTENT_CAST":
|
2018-04-07 13:31:47 +10:00
|
|
|
get_widget_content_cast(int(sys.argv[1]), params)
|
2017-03-11 21:07:08 +11:00
|
|
|
elif mode == "SHOW_CONTENT":
|
2020-06-21 11:27:09 +10:00
|
|
|
check_server()
|
|
|
|
|
show_content(params)
|
2017-06-13 16:56:35 -04:00
|
|
|
elif mode == "SEARCH":
|
|
|
|
|
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
2018-07-11 12:22:41 +10:00
|
|
|
show_search()
|
2017-06-13 16:56:35 -04:00
|
|
|
elif mode == "NEW_SEARCH":
|
2018-07-11 12:22:41 +10:00
|
|
|
search_results(params)
|
|
|
|
|
elif mode == "NEW_SEARCH_PERSON":
|
|
|
|
|
search_results_person(params)
|
2017-06-23 17:49:45 +10:00
|
|
|
elif mode == "SHOW_SERVER_SESSIONS":
|
2020-06-21 11:27:09 +10:00
|
|
|
show_server_sessions()
|
2019-11-06 07:14:33 +11:00
|
|
|
elif mode == "SHOW_ADDON_MENU":
|
|
|
|
|
display_menu(params)
|
2014-10-28 16:16:41 +11:00
|
|
|
else:
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("JellyCon -> Mode: {0}".format(mode))
|
|
|
|
|
log.debug("JellyCon -> URL: {0}".format(param_url))
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2014-12-12 10:50:13 +11:00
|
|
|
if mode == "GET_CONTENT":
|
2020-06-21 11:27:09 +10:00
|
|
|
get_content(param_url, params)
|
2017-04-13 06:58:25 +10:00
|
|
|
elif mode == "PLAY":
|
2020-06-21 11:27:09 +10:00
|
|
|
play_action(params)
|
2014-12-12 10:50:13 +11:00
|
|
|
else:
|
2020-06-21 11:27:09 +10:00
|
|
|
check_server()
|
2019-11-06 07:14:33 +11:00
|
|
|
display_main_menu()
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2019-10-19 20:32:57 +11:00
|
|
|
if pr:
|
2017-05-29 06:19:33 -04:00
|
|
|
pr.disable()
|
2017-03-16 15:50:44 +11:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
file_time_stamp = time.strftime("%Y%m%d-%H%M%S")
|
2023-01-14 16:47:48 -05:00
|
|
|
tab_file_name = "{}-profile({}).txt".format(
|
|
|
|
|
__addondir__, file_time_stamp
|
|
|
|
|
)
|
2022-07-08 21:22:20 -04:00
|
|
|
s = StringIO()
|
2017-03-16 15:50:44 +11:00
|
|
|
ps = pstats.Stats(pr, stream=s)
|
|
|
|
|
ps = ps.sort_stats('cumulative')
|
|
|
|
|
ps.print_stats()
|
|
|
|
|
ps.strip_dirs()
|
2017-07-01 15:15:04 +10:00
|
|
|
ps = ps.sort_stats('tottime')
|
2017-03-16 15:50:44 +11:00
|
|
|
ps.print_stats()
|
2022-07-08 21:22:20 -04:00
|
|
|
with open(tab_file_name, 'w') as f:
|
2017-07-15 23:53:36 +10:00
|
|
|
f.write(s.getvalue())
|
2017-03-16 15:50:44 +11:00
|
|
|
|
2020-07-04 13:26:21 -04:00
|
|
|
log.debug("===== JellyCon FINISHED =====")
|
2014-10-28 16:16:41 +11:00
|
|
|
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2018-07-15 11:06:28 +10:00
|
|
|
def toggle_watched(params):
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("toggle_watched: {0}".format(params))
|
2018-07-15 11:06:28 +10:00
|
|
|
item_id = params.get("item_id", None)
|
|
|
|
|
if item_id is None:
|
|
|
|
|
return
|
2022-02-27 22:15:54 -05:00
|
|
|
url = "/Users/{}/Items/{}?format=json".format(api.user_id, item_id)
|
2022-03-07 19:25:44 -05:00
|
|
|
result = api.get(url)
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("toggle_watched item info: {0}".format(result))
|
2018-07-15 11:06:28 +10:00
|
|
|
|
|
|
|
|
user_data = result.get("UserData", None)
|
|
|
|
|
if user_data is None:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if user_data.get("Played", False) is False:
|
2020-06-21 11:27:09 +10:00
|
|
|
mark_item_watched(item_id)
|
2018-07-15 11:06:28 +10:00
|
|
|
else:
|
2020-06-21 11:27:09 +10:00
|
|
|
mark_item_unwatched(item_id)
|
2018-07-15 11:06:28 +10:00
|
|
|
|
|
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
def mark_item_watched(item_id):
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Mark Item Watched: {0}".format(item_id))
|
2023-01-14 16:47:48 -05:00
|
|
|
url = "/Users/{}/PlayedItems/{}".format(api.user_id, item_id)
|
2022-02-27 22:15:54 -05:00
|
|
|
api.post(url)
|
2020-06-21 11:27:09 +10:00
|
|
|
check_for_new_content()
|
2017-05-26 03:48:48 -04:00
|
|
|
home_window = HomeWindow()
|
2020-06-21 11:27:09 +10:00
|
|
|
last_url = home_window.get_property("last_content_url")
|
2018-11-21 13:23:42 +11:00
|
|
|
if last_url:
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("markWatched_lastUrl: {0}".format(last_url))
|
2023-01-14 16:47:48 -05:00
|
|
|
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
2018-11-21 13:23:42 +11:00
|
|
|
|
2014-10-28 16:16:41 +11:00
|
|
|
xbmc.executebuiltin("Container.Refresh")
|
|
|
|
|
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
def mark_item_unwatched(item_id):
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Mark Item UnWatched: {0}".format(item_id))
|
2023-01-14 16:47:48 -05:00
|
|
|
url = "/Users/{}/PlayedItems/{}".format(api.user_id, item_id)
|
2022-02-27 22:15:54 -05:00
|
|
|
api.delete(url)
|
2020-06-21 11:27:09 +10:00
|
|
|
check_for_new_content()
|
2017-05-26 03:48:48 -04:00
|
|
|
home_window = HomeWindow()
|
2020-06-21 11:27:09 +10:00
|
|
|
last_url = home_window.get_property("last_content_url")
|
2018-11-21 13:23:42 +11:00
|
|
|
if last_url:
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("markUnwatched_lastUrl: {0}".format(last_url))
|
2023-01-14 16:47:48 -05:00
|
|
|
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
2018-11-21 13:23:42 +11:00
|
|
|
|
2014-10-28 16:16:41 +11:00
|
|
|
xbmc.executebuiltin("Container.Refresh")
|
|
|
|
|
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
def mark_item_favorite(item_id):
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Add item to favourites: {0}".format(item_id))
|
2023-01-14 16:47:48 -05:00
|
|
|
url = "/Users/{}/FavoriteItems/{}".format(api.user_id, item_id)
|
2022-02-27 22:15:54 -05:00
|
|
|
api.post(url)
|
2020-06-21 11:27:09 +10:00
|
|
|
check_for_new_content()
|
2017-05-26 03:48:48 -04:00
|
|
|
home_window = HomeWindow()
|
2020-06-21 11:27:09 +10:00
|
|
|
last_url = home_window.get_property("last_content_url")
|
2018-11-21 13:23:42 +11:00
|
|
|
if last_url:
|
2023-01-14 16:47:48 -05:00
|
|
|
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
2018-11-21 13:23:42 +11:00
|
|
|
|
2014-10-28 16:16:41 +11:00
|
|
|
xbmc.executebuiltin("Container.Refresh")
|
2017-05-29 06:19:33 -04:00
|
|
|
|
|
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
def unmark_item_favorite(item_id):
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Remove item from favourites: {0}".format(item_id))
|
2023-01-14 16:47:48 -05:00
|
|
|
url = "/Users/{}/FavoriteItems/{}".format(api.user_id, item_id)
|
2022-02-27 22:15:54 -05:00
|
|
|
api.delete(url)
|
2020-06-21 11:27:09 +10:00
|
|
|
check_for_new_content()
|
2017-05-26 03:48:48 -04:00
|
|
|
home_window = HomeWindow()
|
2020-06-21 11:27:09 +10:00
|
|
|
last_url = home_window.get_property("last_content_url")
|
2018-11-21 13:23:42 +11:00
|
|
|
if last_url:
|
2023-01-14 16:47:48 -05:00
|
|
|
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
2018-11-21 13:23:42 +11:00
|
|
|
|
2014-10-28 16:16:41 +11:00
|
|
|
xbmc.executebuiltin("Container.Refresh")
|
2017-05-29 06:19:33 -04:00
|
|
|
|
|
|
|
|
|
2020-03-28 17:58:29 +11:00
|
|
|
def delete(item_id):
|
2023-07-29 22:38:21 +01:00
|
|
|
item = api.get("/Users/{}/Items/{}".format(api.user_id, item_id))
|
2018-03-05 15:43:12 +11:00
|
|
|
|
|
|
|
|
item_id = item.get("Id")
|
2020-03-28 17:58:29 +11:00
|
|
|
item_name = item.get("Name", "")
|
|
|
|
|
series_name = item.get("SeriesName", "")
|
|
|
|
|
ep_number = item.get("IndexNumber", -1)
|
|
|
|
|
|
2023-07-29 22:48:37 +01:00
|
|
|
final_name_parts = []
|
2020-03-28 17:58:29 +11:00
|
|
|
|
2018-03-05 15:43:12 +11:00
|
|
|
if series_name:
|
2023-07-29 22:48:37 +01:00
|
|
|
final_name_parts.append(series_name)
|
2020-03-28 17:58:29 +11:00
|
|
|
|
|
|
|
|
if ep_number != -1:
|
2023-07-29 22:48:37 +01:00
|
|
|
final_name_parts.append("Episode {:02d}".format(ep_number))
|
2020-03-28 17:58:29 +11:00
|
|
|
|
2023-07-29 22:48:37 +01:00
|
|
|
final_name_parts.append(item_name)
|
|
|
|
|
final_name = " - ".join(final_name_parts)
|
2020-03-28 17:58:29 +11:00
|
|
|
|
|
|
|
|
if not item.get("CanDelete", False):
|
2023-01-14 16:47:48 -05:00
|
|
|
xbmcgui.Dialog().ok(
|
|
|
|
|
translate_string(30135), translate_string(30417), final_name
|
|
|
|
|
)
|
2020-03-28 17:58:29 +11:00
|
|
|
return
|
2018-03-05 15:43:12 +11:00
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
return_value = xbmcgui.Dialog().yesno(
|
|
|
|
|
translate_string(30091), '{}\n{}'.format(
|
|
|
|
|
final_name, translate_string(30092)
|
|
|
|
|
)
|
|
|
|
|
)
|
2014-10-28 16:16:41 +11:00
|
|
|
if return_value:
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug('Deleting Item: {0}'.format(item_id))
|
2022-02-27 22:15:54 -05:00
|
|
|
url = '/Items/{}'.format(item_id)
|
2014-10-28 16:16:41 +11:00
|
|
|
progress = xbmcgui.DialogProgress()
|
2021-12-30 17:05:10 -05:00
|
|
|
progress.create(translate_string(30052), translate_string(30053))
|
2022-02-27 22:15:54 -05:00
|
|
|
api.delete(url)
|
2014-10-28 16:16:41 +11:00
|
|
|
progress.close()
|
2020-06-21 11:27:09 +10:00
|
|
|
check_for_new_content()
|
2017-08-24 20:33:47 +10:00
|
|
|
home_window = HomeWindow()
|
2020-06-21 11:27:09 +10:00
|
|
|
last_url = home_window.get_property("last_content_url")
|
2018-11-21 13:23:42 +11:00
|
|
|
if last_url:
|
2023-01-14 16:47:48 -05:00
|
|
|
home_window.set_property(
|
|
|
|
|
"skip_cache_for_{}".format(last_url), "true"
|
|
|
|
|
)
|
2018-11-21 13:23:42 +11:00
|
|
|
|
2014-10-28 16:16:41 +11:00
|
|
|
xbmc.executebuiltin("Container.Refresh")
|
|
|
|
|
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2019-12-30 09:16:57 +11:00
|
|
|
def get_params():
|
2021-10-30 18:51:38 -04:00
|
|
|
'''
|
|
|
|
|
Retrieve the request data from Kodi
|
|
|
|
|
'''
|
2019-12-30 09:16:57 +11:00
|
|
|
|
|
|
|
|
plugin_path = sys.argv[0]
|
|
|
|
|
paramstring = sys.argv[2]
|
|
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Parameter string: {0}".format(paramstring))
|
|
|
|
|
log.debug("Plugin Path string: {0}".format(plugin_path))
|
2019-12-30 09:16:57 +11:00
|
|
|
|
2021-10-30 18:51:38 -04:00
|
|
|
param = dict(parse_qsl(paramstring[1:]))
|
2019-12-30 09:16:57 +11:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
# add plugin path
|
2023-01-14 16:47:48 -05:00
|
|
|
request_path = plugin_path.replace("plugin://{}".format(addon_id), "")
|
2019-12-30 09:16:57 +11:00
|
|
|
param["request_path"] = request_path
|
|
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("JellyCon -> Detected parameters: {0}".format(param))
|
2014-10-28 16:16:41 +11:00
|
|
|
return param
|
|
|
|
|
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2018-06-29 14:38:44 +10:00
|
|
|
def show_menu(params):
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("showMenu(): {0}".format(params))
|
2017-08-19 11:08:15 +10:00
|
|
|
|
2020-04-14 13:24:01 +10:00
|
|
|
home_window = HomeWindow()
|
2020-01-02 14:05:12 +11:00
|
|
|
settings = xbmcaddon.Addon()
|
2018-03-03 09:46:31 +11:00
|
|
|
item_id = params["item_id"]
|
2018-01-13 17:00:40 +11:00
|
|
|
|
2022-02-27 22:15:54 -05:00
|
|
|
url = "/Users/{}/Items/{}?format=json".format(api.user_id, item_id)
|
2022-03-07 19:25:44 -05:00
|
|
|
result = api.get(url)
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Menu item info: {0}".format(result))
|
2018-01-13 17:00:40 +11:00
|
|
|
|
|
|
|
|
if result is None:
|
|
|
|
|
return
|
|
|
|
|
|
2017-08-19 11:08:15 +10:00
|
|
|
action_items = []
|
2018-11-28 20:20:03 +11:00
|
|
|
|
2022-12-30 15:30:03 -05:00
|
|
|
# Additional items to include in the context menu for different item types
|
2023-01-14 16:47:48 -05:00
|
|
|
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio",
|
|
|
|
|
"TvChannel", "Program", "MusicVideo"]:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30314), offscreen=True)
|
2018-03-03 09:46:31 +11:00
|
|
|
li.setProperty('menu_id', 'play')
|
2018-01-13 17:00:40 +11:00
|
|
|
action_items.append(li)
|
|
|
|
|
|
2026-01-06 00:55:13 +01:00
|
|
|
# Add "Play with track selection" for Movies and Episodes
|
|
|
|
|
if result["Type"] in ["Episode", "Movie"]:
|
|
|
|
|
li = xbmcgui.ListItem(translate_string(30701), offscreen=True)
|
|
|
|
|
li.setProperty('menu_id', 'play_with_track_selection')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2023-01-21 11:27:30 -05:00
|
|
|
if result["Type"] in ["Season", "MusicArtist", "MusicAlbum", "Playlist",
|
|
|
|
|
"MusicGenre"]:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30317), offscreen=True)
|
2018-03-03 09:46:31 +11:00
|
|
|
li.setProperty('menu_id', 'play_all')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
if result["Type"] in ["MusicArtist", "MusicAlbum", "Playlist",
|
2023-01-21 11:27:30 -05:00
|
|
|
"Series", "Season", "MusicGenre"]:
|
2022-12-30 15:30:03 -05:00
|
|
|
li = xbmcgui.ListItem(translate_string(30448), offscreen=True)
|
|
|
|
|
li.setProperty('menu_id', 'shuffle')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
|
|
|
|
if result["Type"] in ["MusicArtist", "MusicAlbum", "Audio"]:
|
|
|
|
|
li = xbmcgui.ListItem(translate_string(30449), offscreen=True)
|
|
|
|
|
li.setProperty('menu_id', 'instant_mix')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
if result["Type"] in ["Episode", "Movie", "Video", "TvChannel",
|
|
|
|
|
"Program", "MusicVideo"]:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30275), offscreen=True)
|
2018-03-03 09:46:31 +11:00
|
|
|
li.setProperty('menu_id', 'transcode')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio",
|
2023-01-21 11:27:30 -05:00
|
|
|
"MusicArtist", "MusicAlbum", "MusicVideo",
|
|
|
|
|
"MusicGenre"]:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30402), offscreen=True)
|
2019-10-02 08:06:50 +10:00
|
|
|
li.setProperty('menu_id', 'add_to_playlist')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2019-02-10 17:10:19 +11:00
|
|
|
if result["Type"] in ("Movie", "Series"):
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30307), offscreen=True)
|
2018-03-03 09:46:31 +11:00
|
|
|
li.setProperty('menu_id', 'play_trailer')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
|
|
|
|
if result["Type"] == "Episode" and result["ParentId"] is not None:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30327), offscreen=True)
|
2018-03-03 09:46:31 +11:00
|
|
|
li.setProperty('menu_id', 'view_season')
|
|
|
|
|
action_items.append(li)
|
2018-01-13 17:00:40 +11:00
|
|
|
|
2019-06-02 20:09:18 +10:00
|
|
|
if result["Type"] in ("Series", "Season", "Episode"):
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30354), offscreen=True)
|
2018-12-01 14:14:39 +11:00
|
|
|
li.setProperty('menu_id', 'view_series')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2020-04-14 19:31:55 +10:00
|
|
|
if result["Type"] == "Movie":
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem("Show Extras", offscreen=True)
|
2020-04-14 19:31:55 +10:00
|
|
|
li.setProperty('menu_id', 'show_extras')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2018-07-31 11:12:13 +10:00
|
|
|
user_data = result.get("UserData", None)
|
|
|
|
|
if user_data:
|
|
|
|
|
progress = user_data.get("PlaybackPositionTicks", 0) != 0
|
|
|
|
|
played = user_data.get("Played", False)
|
|
|
|
|
if not played or progress:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30270), offscreen=True)
|
2018-07-31 11:12:13 +10:00
|
|
|
li.setProperty('menu_id', 'mark_watched')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
if played or progress:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30271), offscreen=True)
|
2018-07-31 11:12:13 +10:00
|
|
|
li.setProperty('menu_id', 'mark_unwatched')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
if user_data.get("IsFavorite", False) is False:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30272), offscreen=True)
|
2020-07-04 13:26:21 -04:00
|
|
|
li.setProperty('menu_id', 'jellyfin_set_favorite')
|
2018-07-31 11:12:13 +10:00
|
|
|
action_items.append(li)
|
|
|
|
|
else:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30273), offscreen=True)
|
2020-07-04 13:26:21 -04:00
|
|
|
li.setProperty('menu_id', 'jellyfin_unset_favorite')
|
2018-07-31 11:12:13 +10:00
|
|
|
action_items.append(li)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2019-03-30 12:16:39 +11:00
|
|
|
can_delete = result.get("CanDelete", False)
|
|
|
|
|
if can_delete:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30274), offscreen=True)
|
2019-03-30 12:16:39 +11:00
|
|
|
li.setProperty('menu_id', 'delete')
|
|
|
|
|
action_items.append(li)
|
2017-08-19 11:08:15 +10:00
|
|
|
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30398), offscreen=True)
|
2019-06-08 16:48:46 +10:00
|
|
|
li.setProperty('menu_id', 'refresh_server')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30281), offscreen=True)
|
2018-10-28 11:25:03 +11:00
|
|
|
li.setProperty('menu_id', 'refresh_images')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2020-03-28 17:58:29 +11:00
|
|
|
if result["Type"] in ["Movie", "Series"]:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30399), offscreen=True)
|
2020-06-21 11:27:09 +10:00
|
|
|
li.setProperty('menu_id', 'hide')
|
|
|
|
|
action_items.append(li)
|
2019-06-02 12:20:54 +10:00
|
|
|
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem(translate_string(30401), offscreen=True)
|
2019-08-25 08:44:25 +10:00
|
|
|
li.setProperty('menu_id', 'info')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
|
2020-01-02 14:05:12 +11:00
|
|
|
window = xbmcgui.Window(xbmcgui.getCurrentWindowId())
|
2020-02-06 19:14:54 +11:00
|
|
|
container_view_id = str(window.getFocusId())
|
2020-01-02 14:05:12 +11:00
|
|
|
container_content_type = xbmc.getInfoLabel("Container.Content")
|
2023-01-14 16:47:48 -05:00
|
|
|
view_key = "view-{}".format(container_content_type)
|
2020-02-06 19:14:54 +11:00
|
|
|
current_default_view = settings.getSetting(view_key)
|
|
|
|
|
view_match = container_view_id == current_default_view
|
2023-01-14 16:47:48 -05:00
|
|
|
log.debug("View ID:{0} Content type:{1}".format(
|
|
|
|
|
container_view_id, container_content_type)
|
|
|
|
|
)
|
2020-01-02 14:05:12 +11:00
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
if container_content_type in ["movies", "tvshows", "seasons",
|
|
|
|
|
"episodes", "sets"]:
|
2020-02-06 19:14:54 +11:00
|
|
|
if view_match:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem("Unset as default view", offscreen=True)
|
2020-02-06 19:14:54 +11:00
|
|
|
li.setProperty('menu_id', 'unset_view')
|
|
|
|
|
action_items.append(li)
|
|
|
|
|
else:
|
2022-06-12 10:52:49 -04:00
|
|
|
li = xbmcgui.ListItem("Set as default view", offscreen=True)
|
2020-02-06 19:14:54 +11:00
|
|
|
li.setProperty('menu_id', 'set_view')
|
|
|
|
|
action_items.append(li)
|
2020-01-02 14:05:12 +11:00
|
|
|
|
2017-08-19 11:08:15 +10:00
|
|
|
action_menu = ActionMenu("ActionMenu.xml", PLUGINPATH, "default", "720p")
|
|
|
|
|
action_menu.setActionItems(action_items)
|
|
|
|
|
action_menu.doModal()
|
|
|
|
|
selected_action_item = action_menu.getActionItem()
|
|
|
|
|
selected_action = ""
|
|
|
|
|
if selected_action_item is not None:
|
|
|
|
|
selected_action = selected_action_item.getProperty('menu_id')
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Menu Action Selected: {0}".format(selected_action))
|
2017-08-19 11:08:15 +10:00
|
|
|
del action_menu
|
|
|
|
|
|
|
|
|
|
if selected_action == "play":
|
|
|
|
|
log.debug("Play Item")
|
2020-06-21 11:27:09 +10:00
|
|
|
play_action(params)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2026-01-06 00:55:13 +01:00
|
|
|
elif selected_action == "play_with_track_selection":
|
|
|
|
|
log.debug("Play Item with Track Selection")
|
|
|
|
|
params["force_track_selection"] = "true"
|
|
|
|
|
play_action(params)
|
|
|
|
|
|
2020-01-02 14:05:12 +11:00
|
|
|
elif selected_action == "set_view":
|
2023-01-19 12:44:43 +08:00
|
|
|
log.debug("Setting view type for {0} to {1}".format(
|
2023-01-14 16:47:48 -05:00
|
|
|
view_key, container_view_id)
|
|
|
|
|
)
|
2020-02-06 19:14:54 +11:00
|
|
|
settings.setSetting(view_key, container_view_id)
|
|
|
|
|
|
|
|
|
|
elif selected_action == "unset_view":
|
2023-01-14 16:47:48 -05:00
|
|
|
log.debug("Un-Settign view type for {0} to {1}".format(
|
|
|
|
|
view_key, container_view_id)
|
|
|
|
|
)
|
2020-02-06 19:14:54 +11:00
|
|
|
settings.setSetting(view_key, "")
|
2020-01-02 14:05:12 +11:00
|
|
|
|
2019-06-08 16:48:46 +10:00
|
|
|
elif selected_action == "refresh_server":
|
2023-01-14 16:47:48 -05:00
|
|
|
url_path = "/Items/{}/Refresh".format(item_id)
|
|
|
|
|
url_params = {
|
|
|
|
|
"Recursive": True,
|
|
|
|
|
"ImageRefreshMode": "FullRefresh",
|
|
|
|
|
"MetadataRefreshMode": "FullRefresh",
|
|
|
|
|
"ReplaceAllImages": True,
|
|
|
|
|
"ReplaceAllMetadata": True
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
url = get_jellyfin_url(url_path, url_params)
|
2022-02-27 22:15:54 -05:00
|
|
|
res = api.post(url)
|
2023-01-19 12:44:43 +08:00
|
|
|
log.debug("Refresh Server Response: {0}".format(res))
|
2019-06-08 16:48:46 +10:00
|
|
|
|
2019-06-02 12:20:54 +10:00
|
|
|
elif selected_action == "hide":
|
2022-01-17 12:17:21 -05:00
|
|
|
user_details = load_user_details()
|
|
|
|
|
user_name = user_details["user_name"]
|
2019-06-02 12:20:54 +10:00
|
|
|
hide_tag_string = "hide-" + user_name
|
2022-02-27 22:15:54 -05:00
|
|
|
url = "/Items/{}/Tags/Add".format(item_id)
|
2019-06-02 12:20:54 +10:00
|
|
|
post_tag_data = {"Tags": [{"Name": hide_tag_string}]}
|
2022-02-27 22:15:54 -05:00
|
|
|
res = api.post(url, post_tag_data)
|
2023-01-19 12:44:43 +08:00
|
|
|
log.debug("Add Tag Response: {0}".format(res))
|
2019-06-02 12:20:54 +10:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
check_for_new_content()
|
2019-06-02 12:20:54 +10:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
last_url = home_window.get_property("last_content_url")
|
2019-06-02 12:20:54 +10:00
|
|
|
if last_url:
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("markUnwatched_lastUrl: {0}".format(last_url))
|
2023-01-14 16:47:48 -05:00
|
|
|
home_window.set_property(
|
|
|
|
|
"skip_cache_for_{}".format(last_url), "true"
|
|
|
|
|
)
|
2019-06-02 12:20:54 +10:00
|
|
|
|
|
|
|
|
xbmc.executebuiltin("Container.Refresh")
|
|
|
|
|
|
2018-03-03 09:46:31 +11:00
|
|
|
elif selected_action == "play_all":
|
2020-06-21 11:27:09 +10:00
|
|
|
play_action(params)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2022-12-30 15:30:03 -05:00
|
|
|
elif selected_action == "shuffle":
|
|
|
|
|
params["action"] = "shuffle"
|
|
|
|
|
play_action(params)
|
|
|
|
|
|
|
|
|
|
elif selected_action == "instant_mix":
|
|
|
|
|
params["action"] = "instant_mix"
|
|
|
|
|
play_action(params)
|
|
|
|
|
|
2018-03-03 09:46:31 +11:00
|
|
|
elif selected_action == "play_trailer":
|
2020-06-21 11:27:09 +10:00
|
|
|
play_item_trailer(item_id)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2017-08-19 11:08:15 +10:00
|
|
|
elif selected_action == "transcode":
|
|
|
|
|
params['force_transcode'] = 'true'
|
2020-06-24 20:31:47 +10:00
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
max_bitrate = settings.getSetting("force_max_stream_bitrate")
|
|
|
|
|
initial_bitrate_value = int(max_bitrate)
|
|
|
|
|
bitrate_dialog = BitrateDialog(
|
|
|
|
|
"BitrateDialog.xml", PLUGINPATH, "default", "720p"
|
|
|
|
|
)
|
2020-06-24 20:31:47 +10:00
|
|
|
bitrate_dialog.initial_bitrate_value = initial_bitrate_value
|
|
|
|
|
bitrate_dialog.doModal()
|
|
|
|
|
selected_transcode_value = bitrate_dialog.selected_transcode_value
|
|
|
|
|
del bitrate_dialog
|
2023-01-14 16:47:48 -05:00
|
|
|
log.debug("selected_transcode_value: {0}".format(
|
|
|
|
|
selected_transcode_value)
|
|
|
|
|
)
|
2020-06-24 20:31:47 +10:00
|
|
|
|
|
|
|
|
if selected_transcode_value > 0:
|
2023-01-14 16:47:48 -05:00
|
|
|
settings.setSetting(
|
|
|
|
|
"force_max_stream_bitrate", str(selected_transcode_value))
|
2020-06-24 20:31:47 +10:00
|
|
|
|
2020-06-26 14:46:57 +10:00
|
|
|
play_action(params)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2019-10-02 08:06:50 +10:00
|
|
|
elif selected_action == "add_to_playlist":
|
|
|
|
|
params["action"] = "add_to_playlist"
|
2020-06-21 11:27:09 +10:00
|
|
|
play_action(params)
|
2019-10-02 08:06:50 +10:00
|
|
|
|
2020-07-04 13:26:21 -04:00
|
|
|
elif selected_action == "jellyfin_set_favorite":
|
2020-06-21 11:27:09 +10:00
|
|
|
mark_item_favorite(item_id)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2020-07-04 13:26:21 -04:00
|
|
|
elif selected_action == "jellyfin_unset_favorite":
|
2020-06-21 11:27:09 +10:00
|
|
|
unmark_item_favorite(item_id)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2017-08-19 11:08:15 +10:00
|
|
|
elif selected_action == "mark_watched":
|
2020-06-21 11:27:09 +10:00
|
|
|
mark_item_watched(item_id)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2017-08-19 11:08:15 +10:00
|
|
|
elif selected_action == "mark_unwatched":
|
2020-06-21 11:27:09 +10:00
|
|
|
mark_item_unwatched(item_id)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2017-08-19 11:08:15 +10:00
|
|
|
elif selected_action == "delete":
|
2020-03-28 17:58:29 +11:00
|
|
|
delete(item_id)
|
2018-03-03 09:46:31 +11:00
|
|
|
|
2020-04-14 19:31:55 +10:00
|
|
|
elif selected_action == "show_extras":
|
2023-01-14 16:47:48 -05:00
|
|
|
url = "/Users/{}/Items/{}/SpecialFeatures".format(api.user_id, item_id)
|
|
|
|
|
plugin_params = {
|
|
|
|
|
"url": url,
|
|
|
|
|
"mode": "GET_CONTENT",
|
|
|
|
|
"media_type": "Videos"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
action_params = urlencode(plugin_params)
|
|
|
|
|
|
|
|
|
|
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
|
|
|
|
built_in_command = 'ActivateWindow(Videos, {}, return)'.format(
|
|
|
|
|
action_url
|
|
|
|
|
)
|
2020-04-14 19:31:55 +10:00
|
|
|
xbmc.executebuiltin(built_in_command)
|
2020-04-14 13:24:01 +10:00
|
|
|
|
2018-03-03 09:46:31 +11:00
|
|
|
elif selected_action == "view_season":
|
2018-11-18 13:16:47 +11:00
|
|
|
xbmc.executebuiltin("Dialog.Close(all,true)")
|
2018-01-13 17:00:40 +11:00
|
|
|
parent_id = result["ParentId"]
|
2018-12-21 11:33:41 +11:00
|
|
|
series_id = result["SeriesId"]
|
2023-01-14 16:47:48 -05:00
|
|
|
|
|
|
|
|
url_path = "/Shows/{}/Episodes".format(series_id)
|
|
|
|
|
url_params = {
|
|
|
|
|
"userId": api.user_id,
|
|
|
|
|
"seasonId": parent_id,
|
|
|
|
|
"IsVirtualUnAired": False,
|
|
|
|
|
"IsMissing": False,
|
|
|
|
|
"Fields": "SpecialEpisodeNumbers,{}".format(get_default_filters())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
url = get_jellyfin_url(url_path, url_params)
|
|
|
|
|
|
|
|
|
|
plugin_params = {
|
|
|
|
|
"url": url,
|
|
|
|
|
"mode": "GET_CONTENT",
|
|
|
|
|
"media_type": "Season"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
action_params = urlencode(plugin_params)
|
|
|
|
|
|
|
|
|
|
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
|
|
|
|
built_in_command = 'ActivateWindow(Videos, {}, return)'.format(
|
|
|
|
|
action_url
|
|
|
|
|
)
|
2018-12-21 11:33:41 +11:00
|
|
|
xbmc.executebuiltin(built_in_command)
|
2017-08-19 11:08:15 +10:00
|
|
|
|
2018-12-01 14:14:39 +11:00
|
|
|
elif selected_action == "view_series":
|
|
|
|
|
xbmc.executebuiltin("Dialog.Close(all,true)")
|
2019-06-02 20:09:18 +10:00
|
|
|
|
|
|
|
|
series_id = result["SeriesId"]
|
|
|
|
|
if not series_id:
|
|
|
|
|
series_id = item_id
|
|
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
url_path = "/Shows/{}/Seasons".format(series_id)
|
|
|
|
|
url_params = {
|
|
|
|
|
"userId": api.user_id,
|
|
|
|
|
"Fields": get_default_filters(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
url = get_jellyfin_url(url_path, url_params)
|
|
|
|
|
|
|
|
|
|
plugin_params = {
|
|
|
|
|
"url": url,
|
|
|
|
|
"mode": "GET_CONTENT",
|
|
|
|
|
"media_type": "Series"
|
|
|
|
|
}
|
2019-06-02 20:09:18 +10:00
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
action_params = urlencode(plugin_params)
|
|
|
|
|
|
|
|
|
|
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
2019-06-02 20:09:18 +10:00
|
|
|
|
|
|
|
|
if xbmc.getCondVisibility("Window.IsActive(home)"):
|
2023-01-14 16:47:48 -05:00
|
|
|
built_in_command = 'ActivateWindow(Videos, {}, return'.format(
|
|
|
|
|
action_url
|
|
|
|
|
)
|
2019-06-02 20:09:18 +10:00
|
|
|
else:
|
2023-01-14 16:47:48 -05:00
|
|
|
built_in_command = 'Container.Update({})'.format(action_url)
|
2019-06-02 20:09:18 +10:00
|
|
|
|
2018-12-01 14:14:39 +11:00
|
|
|
xbmc.executebuiltin(built_in_command)
|
|
|
|
|
|
2018-10-28 11:25:03 +11:00
|
|
|
elif selected_action == "refresh_images":
|
|
|
|
|
CacheArtwork().delete_cached_images(item_id)
|
|
|
|
|
|
2019-08-25 08:44:25 +10:00
|
|
|
elif selected_action == "info":
|
2019-09-06 07:25:06 +10:00
|
|
|
xbmc.executebuiltin("Dialog.Close(all,true)")
|
2019-08-25 08:44:25 +10:00
|
|
|
xbmc.executebuiltin("Action(info)")
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
|
|
|
|
|
def show_content(params):
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("showContent Called: {0}".format(params))
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2017-03-11 21:07:08 +11:00
|
|
|
item_type = params.get("item_type")
|
2018-09-18 14:29:54 +10:00
|
|
|
settings = xbmcaddon.Addon()
|
|
|
|
|
group_movies = settings.getSetting('group_movies') == "true"
|
|
|
|
|
|
|
|
|
|
if item_type.lower().find("movie") == -1:
|
|
|
|
|
group_movies = False
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
url_path = "/Users/{}/Items".format(api.user_id)
|
|
|
|
|
url_params = {
|
|
|
|
|
"ImageTypeLimit": 1,
|
|
|
|
|
"IsMissing": False,
|
|
|
|
|
"Fields": get_default_filters(),
|
|
|
|
|
"CollapseBoxSetItems": group_movies,
|
|
|
|
|
"GroupItemsIntoCollections": group_movies,
|
|
|
|
|
"Recursive": True,
|
|
|
|
|
"SortBy": "Name",
|
|
|
|
|
"SortOrder": "Ascending",
|
|
|
|
|
"IsVirtualUnaired": False,
|
|
|
|
|
"IncludeItemTypes": item_type
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
content_url = get_jellyfin_url(url_path, url_params)
|
2017-03-11 21:07:08 +11:00
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("showContent Content Url: {0}".format(content_url))
|
2020-06-21 11:27:09 +10:00
|
|
|
get_content(content_url, params)
|
2017-05-29 06:19:33 -04:00
|
|
|
|
2018-01-12 10:14:37 +11:00
|
|
|
|
2018-07-11 12:22:41 +10:00
|
|
|
def search_results_person(params):
|
|
|
|
|
|
|
|
|
|
handle = int(sys.argv[1])
|
|
|
|
|
|
|
|
|
|
person_id = params.get("person_id")
|
2023-01-14 16:47:48 -05:00
|
|
|
|
|
|
|
|
url_path = "/Users/{}/Items".format(api.user_id)
|
|
|
|
|
url_params = {
|
|
|
|
|
"PersonIds": person_id,
|
|
|
|
|
"Recursive": True,
|
|
|
|
|
"Fields": get_default_filters()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
details_url = get_jellyfin_url(url_path, url_params)
|
2018-07-11 12:22:41 +10:00
|
|
|
|
2018-12-30 15:40:28 +11:00
|
|
|
params["name_format"] = "Episode|episode_name_format"
|
|
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
dir_items, detected_type, total_records = process_directory(
|
|
|
|
|
details_url, None, params
|
|
|
|
|
)
|
2018-07-11 12:22:41 +10:00
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug('search_results_person results: {0}'.format(dir_items))
|
|
|
|
|
log.debug('search_results_person detect_type: {0}'.format(detected_type))
|
2018-07-11 12:22:41 +10:00
|
|
|
|
|
|
|
|
if detected_type is not None:
|
|
|
|
|
# if the media type is not set then try to use the detected type
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Detected content type: {0}".format(detected_type))
|
2018-07-11 20:35:12 +10:00
|
|
|
content_type = None
|
|
|
|
|
|
2018-07-11 12:22:41 +10:00
|
|
|
if detected_type == "Movie":
|
|
|
|
|
content_type = 'movies'
|
2018-07-11 20:35:12 +10:00
|
|
|
elif detected_type == "Episode":
|
2018-07-11 12:22:41 +10:00
|
|
|
content_type = 'episodes'
|
2018-07-11 20:35:12 +10:00
|
|
|
elif detected_type == "Series":
|
|
|
|
|
content_type = 'tvshows'
|
2023-01-14 16:47:48 -05:00
|
|
|
elif detected_type in ["Music", "Audio", "Musicalbum"]:
|
2018-07-11 20:35:12 +10:00
|
|
|
content_type = 'songs'
|
|
|
|
|
|
|
|
|
|
if content_type:
|
|
|
|
|
xbmcplugin.setContent(handle, content_type)
|
2018-07-11 12:22:41 +10:00
|
|
|
|
|
|
|
|
if dir_items is not None:
|
|
|
|
|
xbmcplugin.addDirectoryItems(handle, dir_items)
|
|
|
|
|
|
|
|
|
|
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
|
|
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
|
2018-07-11 12:22:41 +10:00
|
|
|
def search_results(params):
|
2017-12-27 23:10:54 +11:00
|
|
|
|
2017-06-13 16:56:35 -04:00
|
|
|
item_type = params.get('item_type')
|
2018-05-07 20:14:58 +10:00
|
|
|
query_string = params.get('query')
|
2018-05-08 09:11:54 +10:00
|
|
|
if query_string:
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("query_string : {0}".format(query_string))
|
2021-01-26 22:34:51 -05:00
|
|
|
query_string = unquote(query_string)
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("query_string : {0}".format(query_string))
|
2017-12-27 23:10:54 +11:00
|
|
|
|
2018-05-08 14:29:21 +10:00
|
|
|
item_type = item_type.lower()
|
|
|
|
|
|
|
|
|
|
if item_type == 'movie':
|
2021-12-30 17:05:10 -05:00
|
|
|
heading_type = translate_string(30231)
|
2018-05-08 14:29:21 +10:00
|
|
|
content_type = 'movies'
|
|
|
|
|
elif item_type == 'series':
|
2021-12-30 17:05:10 -05:00
|
|
|
heading_type = translate_string(30229)
|
2018-05-08 14:29:21 +10:00
|
|
|
content_type = 'tvshows'
|
|
|
|
|
elif item_type == 'episode':
|
2021-12-30 17:05:10 -05:00
|
|
|
heading_type = translate_string(30235)
|
2018-05-08 14:29:21 +10:00
|
|
|
content_type = 'episodes'
|
|
|
|
|
params["name_format"] = "Episode|episode_name_format"
|
2023-01-14 16:47:48 -05:00
|
|
|
elif item_type in ["music", "audio", "musicalalbum"]:
|
2018-05-08 14:29:21 +10:00
|
|
|
heading_type = 'Music'
|
|
|
|
|
content_type = 'songs'
|
2018-07-11 12:22:41 +10:00
|
|
|
elif item_type == "person":
|
2018-05-08 14:29:21 +10:00
|
|
|
heading_type = 'Artists'
|
|
|
|
|
content_type = 'artists'
|
2017-06-13 16:56:35 -04:00
|
|
|
else:
|
|
|
|
|
heading_type = item_type
|
2018-05-08 14:29:21 +10:00
|
|
|
content_type = 'video'
|
2017-12-27 23:10:54 +11:00
|
|
|
|
2018-05-07 20:14:58 +10:00
|
|
|
handle = int(sys.argv[1])
|
2017-12-27 23:10:54 +11:00
|
|
|
|
2018-05-07 20:14:58 +10:00
|
|
|
if not query_string:
|
|
|
|
|
home_window = HomeWindow()
|
2020-06-21 11:27:09 +10:00
|
|
|
last_search = home_window.get_property("last_search")
|
2018-05-07 20:14:58 +10:00
|
|
|
kb = xbmc.Keyboard()
|
2023-01-14 16:47:48 -05:00
|
|
|
kb.setHeading("{} {}".format(
|
|
|
|
|
heading_type.capitalize(), translate_string(30246).lower()
|
|
|
|
|
))
|
2018-05-07 20:14:58 +10:00
|
|
|
kb.setDefault(last_search)
|
|
|
|
|
kb.doModal()
|
|
|
|
|
|
|
|
|
|
if kb.isConfirmed():
|
|
|
|
|
user_input = kb.getText().strip()
|
|
|
|
|
else:
|
|
|
|
|
return
|
2017-12-27 23:10:54 +11:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
home_window.set_property("last_search", user_input)
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug('searchResults Called: {0}'.format(params))
|
2018-05-07 20:14:58 +10:00
|
|
|
query = user_input
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
query = query_string
|
2017-06-13 16:56:35 -04:00
|
|
|
|
2021-01-26 22:34:51 -05:00
|
|
|
query = quote(query)
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("query : {0}".format(query))
|
2018-07-11 20:35:12 +10:00
|
|
|
|
2017-06-13 16:56:35 -04:00
|
|
|
if (not item_type) or (not query):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# show a progress indicator if needed
|
2018-05-07 10:40:52 +10:00
|
|
|
settings = xbmcaddon.Addon()
|
2017-06-13 16:56:35 -04:00
|
|
|
progress = None
|
2018-05-07 10:40:52 +10:00
|
|
|
if settings.getSetting('showLoadProgress') == "true":
|
2017-06-13 16:56:35 -04:00
|
|
|
progress = xbmcgui.DialogProgress()
|
2021-12-30 17:05:10 -05:00
|
|
|
progress.create(translate_string(30112))
|
|
|
|
|
progress.update(0, translate_string(30113))
|
2017-06-13 16:56:35 -04:00
|
|
|
|
2019-07-22 09:26:57 +10:00
|
|
|
# what type of search
|
|
|
|
|
if item_type == "person":
|
2023-01-14 16:47:48 -05:00
|
|
|
url_path = "/Persons"
|
|
|
|
|
url_params = {
|
|
|
|
|
"searchTerm": query,
|
|
|
|
|
"IncludePeople": True,
|
|
|
|
|
"IncludeMedia": False,
|
|
|
|
|
"IncludeGenres": False,
|
|
|
|
|
"IncludeStudios": False,
|
|
|
|
|
"IncludeArtists": False,
|
|
|
|
|
"Limit": 16,
|
|
|
|
|
"Fields": "PrimaryImageAspectRatio,BasicSyncInfo,ProductionYear",
|
|
|
|
|
"Recursive": True,
|
|
|
|
|
"EnableTotalRecordCount": False,
|
|
|
|
|
"ImageTypeLimit": 1,
|
|
|
|
|
"userId": api.user_id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
search_url = get_jellyfin_url(url_path, url_params)
|
2019-07-22 09:26:57 +10:00
|
|
|
|
2022-03-07 19:25:44 -05:00
|
|
|
person_search_results = api.get(search_url)
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("Person Search Result : {0}".format(person_search_results))
|
2019-07-22 09:26:57 +10:00
|
|
|
if person_search_results is None:
|
|
|
|
|
return
|
2017-06-13 16:56:35 -04:00
|
|
|
|
2019-07-22 09:26:57 +10:00
|
|
|
person_items = person_search_results.get("Items", [])
|
2017-06-13 16:56:35 -04:00
|
|
|
|
2022-02-27 22:15:54 -05:00
|
|
|
server = settings.getSetting('server_address')
|
2018-07-11 12:22:41 +10:00
|
|
|
list_items = []
|
2019-07-22 09:26:57 +10:00
|
|
|
for item in person_items:
|
|
|
|
|
person_id = item.get('Id')
|
2018-07-11 12:22:41 +10:00
|
|
|
person_name = item.get('Name')
|
2022-02-27 22:15:54 -05:00
|
|
|
person_thumbnail = get_art_url(item, "Primary", server=server)
|
2018-07-11 12:22:41 +10:00
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
action_url = "{}?mode=NEW_SEARCH_PERSON&person_id={}".format(
|
|
|
|
|
addon_id, person_id
|
|
|
|
|
)
|
2018-07-11 12:22:41 +10:00
|
|
|
|
2022-06-12 10:52:49 -04:00
|
|
|
list_item = xbmcgui.ListItem(label=person_name, offscreen=True)
|
2018-07-11 12:22:41 +10:00
|
|
|
list_item.setProperty("id", person_id)
|
2019-08-21 10:40:54 +02:00
|
|
|
|
|
|
|
|
art_links = {}
|
|
|
|
|
art_links["icon"] = "DefaultActor.png"
|
2018-07-11 12:22:41 +10:00
|
|
|
if person_thumbnail:
|
|
|
|
|
art_links["thumb"] = person_thumbnail
|
|
|
|
|
art_links["poster"] = person_thumbnail
|
2019-08-21 10:40:54 +02:00
|
|
|
list_item.setArt(art_links)
|
2018-07-11 12:22:41 +10:00
|
|
|
|
2023-01-19 12:44:43 +08:00
|
|
|
item_tuple = (action_url, list_item, True)
|
|
|
|
|
list_items.append(item_tuple)
|
2018-07-11 12:22:41 +10:00
|
|
|
|
2019-07-25 15:06:20 +10:00
|
|
|
xbmcplugin.setContent(handle, 'artists')
|
|
|
|
|
xbmcplugin.addDirectoryItems(handle, list_items)
|
|
|
|
|
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
|
2018-07-11 12:22:41 +10:00
|
|
|
|
|
|
|
|
else:
|
2023-01-14 16:47:48 -05:00
|
|
|
url_path = "/Users/{}/Items".format(api.user_id)
|
|
|
|
|
url_params = {
|
|
|
|
|
"searchTerm": query,
|
|
|
|
|
"IncludePeople": False,
|
|
|
|
|
"IncludeMedia": True,
|
|
|
|
|
"IncludeGenres": False,
|
|
|
|
|
"IncludeStudios": False,
|
|
|
|
|
"IncludeArtists": False,
|
|
|
|
|
"IncludeItemTypes": item_type,
|
|
|
|
|
"Limit": 16,
|
|
|
|
|
"Fields": get_default_filters(),
|
|
|
|
|
"Recursive": True,
|
|
|
|
|
"EnableTotalRecordCount": False,
|
|
|
|
|
"ImageTypeLimit": 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
search_url = get_jellyfin_url(url_path, url_params)
|
2019-07-22 09:26:57 +10:00
|
|
|
|
|
|
|
|
# set content type
|
|
|
|
|
xbmcplugin.setContent(handle, content_type)
|
2023-01-14 16:47:48 -05:00
|
|
|
dir_items, detected_type, total_records = process_directory(
|
|
|
|
|
search_url, progress, params
|
|
|
|
|
)
|
2019-07-25 15:06:20 +10:00
|
|
|
xbmcplugin.addDirectoryItems(handle, dir_items)
|
|
|
|
|
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
|
2017-06-13 16:56:35 -04:00
|
|
|
|
|
|
|
|
if progress is not None:
|
2021-12-30 17:05:10 -05:00
|
|
|
progress.update(100, translate_string(30125))
|
2017-06-13 16:56:35 -04:00
|
|
|
progress.close()
|
|
|
|
|
|
|
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
def play_action(params):
|
2017-07-08 10:34:30 +10:00
|
|
|
log.debug("== ENTER: PLAY ==")
|
2017-04-13 06:58:25 +10:00
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("PLAY ACTION PARAMS: {0}".format(params))
|
2017-05-25 18:16:01 +10:00
|
|
|
item_id = params.get("item_id")
|
2017-04-13 06:58:25 +10:00
|
|
|
|
2020-09-05 17:49:18 -04:00
|
|
|
auto_resume = params.get("auto_resume", "-1")
|
|
|
|
|
if auto_resume == 'None':
|
|
|
|
|
auto_resume = '-1'
|
|
|
|
|
if auto_resume:
|
|
|
|
|
auto_resume = int(auto_resume)
|
|
|
|
|
else:
|
|
|
|
|
auto_resume = -1
|
|
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("AUTO_RESUME: {0}".format(auto_resume))
|
2017-04-13 06:58:25 +10:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
force_transcode = params.get("force_transcode", None) is not None
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("FORCE_TRANSCODE: {0}".format(force_transcode))
|
2017-06-10 13:01:04 +10:00
|
|
|
|
2017-12-14 16:15:39 +11:00
|
|
|
media_source_id = params.get("media_source_id", "")
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("media_source_id: {0}".format(media_source_id))
|
2017-12-14 13:43:23 +11:00
|
|
|
|
2018-11-08 19:39:28 +11:00
|
|
|
subtitle_stream_index = params.get("subtitle_stream_index")
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("subtitle_stream_index: {0}".format(subtitle_stream_index))
|
2018-11-08 19:39:28 +11:00
|
|
|
|
|
|
|
|
audio_stream_index = params.get("audio_stream_index")
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("audio_stream_index: {0}".format(audio_stream_index))
|
2017-12-14 13:43:23 +11:00
|
|
|
|
Add language-based track selection and context menu
Context Menu Integration:
- Add 'Play with track selection' option to video context menus
- Available for movies and episodes via long-press/context menu
- Forces manual track selection dialog even when auto-selection is configured
Language Selection Improvements:
- Add dropdown selectors for preferred audio/subtitle languages
- Support German, English, French, Spanish, Italian, Japanese, Russian
- Add comprehensive language matching (e.g., 'ger' matches 'deu', 'deutsch', 'german')
- Add setting to auto-select 'No subtitles' when no matching subtitle found
Track Selection Scoring System:
- Audio tracks: Language match (+100), default flag (+50),
channel count (+5-40), codec quality (+10-30), exclude commentary (-100)
- Subtitle tracks: Language match (+100), forced flag (+50),
SRT preference (+30), default flag (+10)
Implementation Details:
- Add force_track_selection parameter throughout playback chain
- Preserve server/remote control track selections when not forcing manual selection
- Add extensive debug logging for track selection decisions
- Respect user preferences while allowing manual override via context menu
2026-01-06 00:32:44 +01:00
|
|
|
force_track_selection = params.get("force_track_selection", "false") == "true"
|
|
|
|
|
log.debug("force_track_selection: {0}".format(force_track_selection))
|
|
|
|
|
|
2019-10-02 08:06:50 +10:00
|
|
|
action = params.get("action", "play")
|
|
|
|
|
|
2017-04-13 06:58:25 +10:00
|
|
|
# set the current playing item id
|
2017-04-14 20:21:20 +10:00
|
|
|
# set all the playback info, this will be picked up by the service
|
|
|
|
|
# the service will then start the playback
|
2017-06-10 13:01:04 +10:00
|
|
|
|
2017-11-19 16:07:45 +11:00
|
|
|
xbmc.Player().stop()
|
|
|
|
|
|
2017-06-10 13:01:04 +10:00
|
|
|
play_info = {}
|
2019-10-02 08:06:50 +10:00
|
|
|
play_info["action"] = action
|
2017-12-14 13:43:23 +11:00
|
|
|
play_info["item_id"] = item_id
|
2017-06-10 13:01:04 +10:00
|
|
|
play_info["auto_resume"] = str(auto_resume)
|
2020-06-21 11:27:09 +10:00
|
|
|
play_info["force_transcode"] = force_transcode
|
2017-12-14 16:15:39 +11:00
|
|
|
play_info["media_source_id"] = media_source_id
|
2018-11-08 19:39:28 +11:00
|
|
|
play_info["subtitle_stream_index"] = subtitle_stream_index
|
|
|
|
|
play_info["audio_stream_index"] = audio_stream_index
|
Add language-based track selection and context menu
Context Menu Integration:
- Add 'Play with track selection' option to video context menus
- Available for movies and episodes via long-press/context menu
- Forces manual track selection dialog even when auto-selection is configured
Language Selection Improvements:
- Add dropdown selectors for preferred audio/subtitle languages
- Support German, English, French, Spanish, Italian, Japanese, Russian
- Add comprehensive language matching (e.g., 'ger' matches 'deu', 'deutsch', 'german')
- Add setting to auto-select 'No subtitles' when no matching subtitle found
Track Selection Scoring System:
- Audio tracks: Language match (+100), default flag (+50),
channel count (+5-40), codec quality (+10-30), exclude commentary (-100)
- Subtitle tracks: Language match (+100), forced flag (+50),
SRT preference (+30), default flag (+10)
Implementation Details:
- Add force_track_selection parameter throughout playback chain
- Preserve server/remote control track selections when not forcing manual selection
- Add extensive debug logging for track selection decisions
- Respect user preferences while allowing manual override via context menu
2026-01-06 00:32:44 +01:00
|
|
|
play_info["force_track_selection"] = force_track_selection
|
2020-07-25 01:01:30 -04:00
|
|
|
log.info("Sending jellycon_play_action : {0}".format(play_info))
|
2021-01-26 22:34:51 -05:00
|
|
|
play_file(play_info)
|
2018-01-03 19:01:01 +11:00
|
|
|
|
2017-12-13 07:32:44 +11:00
|
|
|
|
2020-06-21 11:27:09 +10:00
|
|
|
def play_item_trailer(item_id):
|
2017-12-13 07:32:44 +11:00
|
|
|
log.debug("== ENTER: playTrailer ==")
|
2024-10-23 16:14:35 +03:00
|
|
|
handle = int(sys.argv[1]) if sys.argv and len(sys.argv) > 1 else -1
|
2024-10-23 10:05:14 +03:00
|
|
|
if handle != -1:
|
2024-10-23 16:14:35 +03:00
|
|
|
xbmcplugin.endOfDirectory(handle, succeeded=False, updateListing=False, cacheToDisc=False)
|
2026-01-06 01:12:59 +01:00
|
|
|
|
|
|
|
|
user_details = load_user_details()
|
2023-01-14 16:47:48 -05:00
|
|
|
url = "/Users/{}/Items/{}/LocalTrailers?format=json".format(
|
|
|
|
|
user_details.get('user_id'), item_id
|
|
|
|
|
)
|
2017-12-13 07:32:44 +11:00
|
|
|
|
2022-02-27 22:15:54 -05:00
|
|
|
result = api.get(url)
|
2018-03-18 10:14:51 +11:00
|
|
|
|
|
|
|
|
if result is None:
|
|
|
|
|
return
|
|
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("LocalTrailers {0}".format(result))
|
2018-03-05 22:16:04 +11:00
|
|
|
count = 1
|
2017-12-13 07:32:44 +11:00
|
|
|
|
2018-03-05 22:16:04 +11:00
|
|
|
trailer_names = []
|
2017-12-13 07:32:44 +11:00
|
|
|
trailer_list = []
|
|
|
|
|
for trailer in result:
|
|
|
|
|
info = {}
|
|
|
|
|
info["type"] = "local"
|
2018-03-05 22:16:04 +11:00
|
|
|
name = trailer.get("Name")
|
|
|
|
|
while not name or name in trailer_names:
|
2023-01-14 16:47:48 -05:00
|
|
|
name = "Trailer {}".format(count)
|
2018-03-05 22:16:04 +11:00
|
|
|
count += 1
|
|
|
|
|
info["name"] = name
|
2017-12-13 07:32:44 +11:00
|
|
|
info["id"] = trailer.get("Id")
|
2018-03-05 22:16:04 +11:00
|
|
|
count += 1
|
|
|
|
|
trailer_names.append(name)
|
2017-12-13 07:32:44 +11:00
|
|
|
trailer_list.append(info)
|
|
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
url = "/Users/{}/Items/{}?format=json&Fields=RemoteTrailers".format(
|
|
|
|
|
user_details.get("user_id"), item_id
|
|
|
|
|
)
|
2022-02-27 22:15:54 -05:00
|
|
|
result = api.get(url)
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("RemoteTrailers: {0}".format(result))
|
2018-03-05 22:16:04 +11:00
|
|
|
count = 1
|
2017-12-13 07:32:44 +11:00
|
|
|
|
2018-03-18 10:14:51 +11:00
|
|
|
if result is None:
|
|
|
|
|
return
|
|
|
|
|
|
2017-12-13 07:32:44 +11:00
|
|
|
remote_trailers = result.get("RemoteTrailers", [])
|
|
|
|
|
for trailer in remote_trailers:
|
|
|
|
|
info = {}
|
|
|
|
|
info["type"] = "remote"
|
|
|
|
|
url = trailer.get("Url", "none")
|
2019-02-09 19:26:27 +11:00
|
|
|
if url.lower().find("youtube") != -1:
|
2017-12-13 07:32:44 +11:00
|
|
|
info["url"] = url
|
2018-03-05 22:16:04 +11:00
|
|
|
name = trailer.get("Name")
|
|
|
|
|
while not name or name in trailer_names:
|
2023-01-14 16:47:48 -05:00
|
|
|
name = "Trailer {}".format(count)
|
2018-03-05 22:16:04 +11:00
|
|
|
count += 1
|
|
|
|
|
info["name"] = name
|
|
|
|
|
trailer_names.append(name)
|
2017-12-13 07:32:44 +11:00
|
|
|
trailer_list.append(info)
|
|
|
|
|
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("TrailerList: {0}".format(trailer_list))
|
2017-12-13 07:32:44 +11:00
|
|
|
|
|
|
|
|
trailer_text = []
|
|
|
|
|
for trailer in trailer_list:
|
2023-01-14 16:47:48 -05:00
|
|
|
name = "{} ({})".format(
|
|
|
|
|
trailer.get("name"), trailer.get("type")
|
|
|
|
|
)
|
2017-12-13 07:32:44 +11:00
|
|
|
trailer_text.append(name)
|
|
|
|
|
|
|
|
|
|
dialog = xbmcgui.Dialog()
|
2021-12-30 17:05:10 -05:00
|
|
|
resp = dialog.select(translate_string(30308), trailer_text)
|
2017-12-13 07:32:44 +11:00
|
|
|
if resp > -1:
|
|
|
|
|
trailer = trailer_list[resp]
|
2020-07-25 01:01:30 -04:00
|
|
|
log.debug("SelectedTrailer: {0}".format(trailer))
|
2017-12-13 07:32:44 +11:00
|
|
|
|
|
|
|
|
if trailer.get("type") == "local":
|
|
|
|
|
params = {}
|
|
|
|
|
params["item_id"] = trailer.get("id")
|
2020-06-21 11:27:09 +10:00
|
|
|
play_action(params)
|
2017-12-13 07:32:44 +11:00
|
|
|
|
|
|
|
|
elif trailer.get("type") == "remote":
|
|
|
|
|
youtube_id = trailer.get("url").rsplit('=', 1)[1]
|
2023-01-14 16:47:48 -05:00
|
|
|
url_root = "plugin.video.youtube/play/?video_id="
|
2024-10-23 10:05:14 +03:00
|
|
|
play_url = "PlayMedia(plugin://{}{})".format(url_root, youtube_id)
|
2023-01-14 16:47:48 -05:00
|
|
|
log.debug("youtube_plugin: {0}".format(play_url))
|
2019-02-10 09:17:59 +11:00
|
|
|
|
2023-01-14 16:47:48 -05:00
|
|
|
xbmc.executebuiltin(play_url)
|