mirror of
https://github.com/sakaljurgis/plugin.video.sklk.git
synced 2026-11-06 14:38:03 +00:00
sync watched state with the server, single server url setting
- list items take playcount, resume point and last played from the server (folders: watched/total episodes), listings aren't cached - background service (service.py) reports playback to <server>/api/state/<id>: every 30 s, on pause, stop and end; on first start it sends Kodi's existing watched history of this add-on to the server once - one "Server URL" setting instead of api + video url (the old api url value, ending with /api, still works); no default address Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
99b8f071fe
commit
227a95abcd
5 files changed
+313
-16
No files matched your search
@@ -10,6 +10,7 @@
|
||||
#my_setting = my_addon.getSetting('my_setting') # returns the string 'true' or 'false'
|
||||
#my_addon.setSetting('my_setting', 'false')
|
||||
|
||||
import re
|
||||
import sys
|
||||
from urllib.parse import urlencode, parse_qsl
|
||||
import xbmcgui
|
||||
@@ -27,15 +28,14 @@ _url = sys.argv[0]
|
||||
# Get the plugin handle as an integer number.
|
||||
_handle = int(sys.argv[1])
|
||||
|
||||
# todo - get from settings
|
||||
#API_URL = xbmcplugin.getSetting(_handle, 'api_url') #if xbmcplugin.getSetting(_handle, 'api_url') else xbmc.getSetting("api_url")
|
||||
my_addon = xbmcaddon.Addon()
|
||||
API_URL = my_addon.getSetting('api_url')
|
||||
VIDEO_URL = xbmcplugin.getSetting(_handle, 'video_url')
|
||||
# the server, e.g. https://media.example.com: menus come from <server>/api, videos from the
|
||||
# server-relative paths it lists. Stored as "api_url", which used to end with /api (next to a
|
||||
# separate video url of the same server); either way works.
|
||||
SERVER_URL = re.sub(r'/api$', '', my_addon.getSetting('api_url').strip().rstrip('/'))
|
||||
API_URL = SERVER_URL + '/api'
|
||||
AUTH_KEY = my_addon.getSetting('auth_key')
|
||||
|
||||
xbmcplugin.getSetting
|
||||
|
||||
def getHttpURL(url):
|
||||
|
||||
request = urllib.request.Request(url)
|
||||
@@ -183,6 +183,9 @@ def list_APIresponse(objAPIresponse):
|
||||
if len(contextMenus) > 0:
|
||||
list_item.addContextMenuItems(listContextMenus)
|
||||
|
||||
# watched / resume point as the server has it (shared with other apps)
|
||||
set_watch_state(list_item, item, is_folder)
|
||||
|
||||
# Add our item to the Kodi virtual folder listing.
|
||||
xbmcplugin.addDirectoryItem(_handle, url, list_item, is_folder)
|
||||
|
||||
@@ -195,7 +198,47 @@ def list_APIresponse(objAPIresponse):
|
||||
xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_DATE)
|
||||
|
||||
# Finish creating a virtual folder.
|
||||
xbmcplugin.endOfDirectory(_handle)
|
||||
# not cached: watch state may have changed (on another device too) when coming back to it
|
||||
xbmcplugin.endOfDirectory(_handle, cacheToDisc=False)
|
||||
|
||||
|
||||
def set_watch_state(list_item, item, is_folder):
|
||||
"""
|
||||
Watched state and resume point from the server, which keeps them for all apps
|
||||
(the service reports Kodi's playback there). Set explicitly, they take
|
||||
precedence over Kodi's own database.
|
||||
"""
|
||||
if is_folder:
|
||||
# shows and seasons: watched episodes out of the total
|
||||
total = item.get('totalCount', 0)
|
||||
if total > 0:
|
||||
watched = item.get('watchedCount', 0)
|
||||
list_item.setProperty('TotalEpisodes', str(total))
|
||||
list_item.setProperty('WatchedEpisodes', str(watched))
|
||||
list_item.setProperty('UnWatchedEpisodes', str(total - watched))
|
||||
list_item.setInfo('video', {'playcount': 1 if watched >= total else 0})
|
||||
return
|
||||
|
||||
if 'playcount' not in item:
|
||||
return
|
||||
|
||||
info = {'playcount': item['playcount']}
|
||||
if 'lastplayed' in item:
|
||||
info['lastplayed'] = item['lastplayed']
|
||||
list_item.setInfo('video', info)
|
||||
|
||||
# no resume point = 0, which also clears one Kodi may have kept;
|
||||
# Kodi only takes it with a total time
|
||||
resume = item.get('resume', {})
|
||||
position = resume.get('position', 0)
|
||||
total = resume.get('total') or item.get('duration', 0)
|
||||
tag = list_item.getVideoInfoTag()
|
||||
if hasattr(tag, 'setResumePoint'):
|
||||
# Kodi 20+
|
||||
tag.setResumePoint(position, total)
|
||||
else:
|
||||
list_item.setProperty('ResumeTime', str(position))
|
||||
list_item.setProperty('TotalTime', str(total))
|
||||
|
||||
def select_APIresponse(objAPIresponse):
|
||||
|
||||
@@ -234,7 +277,8 @@ def play_video(path):
|
||||
#xbmcgui.Dialog().ok("debug", "playvideo", path)
|
||||
|
||||
if 'http' not in path:
|
||||
path = VIDEO_URL + path
|
||||
# server-relative, e.g. /api?path=all/play/103
|
||||
path = SERVER_URL + ('' if path.startswith('/') else '/') + path
|
||||
|
||||
# Create a playable item with a path to play.
|
||||
play_item = xbmcgui.ListItem(path=path)
|
||||
@@ -303,6 +347,11 @@ def router(paramstring):
|
||||
:type paramstring: str
|
||||
"""
|
||||
|
||||
if not SERVER_URL:
|
||||
xbmcgui.Dialog().ok("sklk", "Set the server URL in the add-on settings first.")
|
||||
my_addon.openSettings()
|
||||
return
|
||||
|
||||
# Parse a URL-encoded paramstring to the dictionary of
|
||||
# {<parameter>: <value>} elements
|
||||
params = dict(parse_qsl(paramstring))
|
||||
|
||||
Reference in new issue
Block a user