Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions emby/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,12 +642,12 @@ def get_Image_Binary(self, Id, ImageType, ImageIndex, ImageTag, UserImage):

if UserImage:
Params["Format"] = "original"
_, Header, Payload = self.EmbyServer.http.request("GET", f"Users/{Id}/Images/{ImageType}", Params, {}, True, "", None, "")
_, Header, Payload = self.EmbyServer.http.request("GET", f"Users/{Id}/Images/{ImageType}", Params, {}, True, "", None, "", False)
else:
if ImageTag:
Params["tag"] = ImageTag

_, Header, Payload = self.EmbyServer.http.request("GET", f"Items/{Id}/Images/{ImageType}/{ImageIndex}", Params, {}, True, "", None, "")
_, Header, Payload = self.EmbyServer.http.request("GET", f"Items/{Id}/Images/{ImageType}/{ImageIndex}", Params, {}, True, "", None, "", False)

if 'content-type' in Header:
ContentType = Header['content-type']
Expand Down Expand Up @@ -884,6 +884,15 @@ def get_upcoming(self, ParentId):

return []

def get_Episodes(self, SeriesId, AdjacentTo):
Params = {'UserId': self.EmbyServer.ServerData['UserId'], 'AdjacentTo': AdjacentTo, 'Fields': self.get_Fields("episode", False, False, True), 'EnableImages': True, 'EnableUserData': True}
_, _, Payload = self.EmbyServer.http.request("GET", f"Shows/{SeriesId}/Episodes", Params, {}, False, "", None, "")

if 'Items' in Payload:
return Payload['Items']

return []

def get_NextUp(self, ParentId):
_, _, Payload = self.EmbyServer.http.request("GET", "Shows/NextUp", {'UserId': self.EmbyServer.ServerData['UserId'], 'ParentId': ParentId, 'Fields': self.get_Fields("episode", False, True, True), 'EnableImages': True, 'EnableUserData': True, 'LegacyNextUp': True}, {}, False, "", None, "")
embydb = dbio.DBOpenRO(self.EmbyServer.ServerData['ServerId'], "get_NextUp")
Expand Down
21 changes: 13 additions & 8 deletions emby/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ def socket_open(self, ConnectionString, ConnectionId, CloseConnection):
if utils.DebugLog: xbmc.log(f"EMBY.emby.http (DEBUG): Socket {ConnectionId} opened", 1) # LOGDEBUG
return 0

def socket_close(self, ConnectionId):
def socket_close(self, ConnectionId, SkipPing=False):
if ConnectionId in self.Connection:
# Close sessions
if ConnectionId == "WEBSOCKET": # close websocket
Expand All @@ -372,7 +372,7 @@ def socket_close(self, ConnectionId):
self.websocket_send(b"", 0x8) # Close
except Exception as error:
xbmc.log(f"EMBY.emby.http: Socket {ConnectionId} send close error 1: {error}", 2) # LOGWARNING
elif ConnectionId in ("MAIN", "MAINFALLBACK", "ASYNC"): # send final ping to change tcp session from keep-alive to close
elif ConnectionId in ("MAIN", "MAINFALLBACK", "ASYNC") and not SkipPing: # send final ping to change tcp session from keep-alive to close
try:
self.Connection[ConnectionId]["Socket"].settimeout(1) # set timeout
self.Connection[ConnectionId]["Socket"].send(f'POST {self.Connection[ConnectionId]["SubUrl"]}System/Ping HTTP/1.1\r\nHost: {self.Connection[ConnectionId]["Hostname"]}:{self.Connection[ConnectionId]["Port"]}\r\nContent-Type: application/json; charset=utf-8\r\nAccept-Charset: utf-8\r\nAccept-Encoding: gzip,deflate\r\nUser-Agent: {utils.addon_name}/{utils.addon_version}\r\nConnection: close\r\nAuthorization: Emby Client="{utils.addon_name}", Device="{utils.device_name}", DeviceId="{self.EmbyServer.ServerData["DeviceId"]}", Version="{utils.addon_version}"\r\nContent-Length: 0\r\n\r\n'.encode("utf-8"))
Expand Down Expand Up @@ -753,7 +753,7 @@ def download_file(self):

break

def request(self, Method, Handler, Params, RequestHeader, Binary, ConnectionString, BusyFunction, ConnectionId):
def request(self, Method, Handler, Params, RequestHeader, Binary, ConnectionString, BusyFunction, ConnectionId, FollowRedirects=True):
CloseConnection = False

# Set Ids
Expand Down Expand Up @@ -781,7 +781,7 @@ def request(self, Method, Handler, Params, RequestHeader, Binary, ConnectionStri

# Simple request
if CloseConnection or not BusyFunction or not self.ThreadsRunning["QUEUEDREQUESTMAIN"] or not self.ThreadsRunning["QUEUEDREQUESTMAINFALLBACK"]:
self.send_request(Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, ConnectionId, RequestId)
self.send_request(Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, ConnectionId, RequestId, FollowRedirects)
Data = self.Response[RequestId]
del self.Response[RequestId]

Expand All @@ -796,7 +796,7 @@ def request(self, Method, Handler, Params, RequestHeader, Binary, ConnectionStri
self.RequestBusy[ConnectionId] = threading.Lock()
self.RequestBusy[RequestId] = threading.Lock()

self.Queues[f"QUEUEDREQUEST{ConnectionId}"].put(((Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, RequestId),))
self.Queues[f"QUEUEDREQUEST{ConnectionId}"].put(((Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, RequestId, FollowRedirects),))

# Check conditions while waiting for data -> BusyFunction
while True:
Expand Down Expand Up @@ -841,11 +841,11 @@ def queued_request(self, ConnectionId):

return

Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, RequestId = Incoming
Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, RequestId, FollowRedirects = Incoming
if utils.DebugLog: xbmc.log(f"EMBY.emby.http (DEBUG): [ http ] Method: {Method} / Handler: {Handler} / Params: {Params} / Binary: {Binary} / ConnectionString: {ConnectionString} / CloseConnection: {CloseConnection} / RequestHeader: {RequestHeader}", 1) # LOGDEBUG
self.send_request(Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, ConnectionId, RequestId)
self.send_request(Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, ConnectionId, RequestId, FollowRedirects)

def send_request(self, Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, ConnectionId, RequestId):
def send_request(self, Method, Handler, Params, RequestHeader, Binary, ConnectionString, CloseConnection, ConnectionId, RequestId, FollowRedirects=True):
self.Requests_Counter(True)

if not ConnectionString:
Expand Down Expand Up @@ -891,6 +891,11 @@ def send_request(self, Method, Handler, Params, RequestHeader, Binary, Connectio

# Redirects
if StatusCode in (301, 302, 307, 308):
if not FollowRedirects:
self.socket_close(ConnectionId, True)
self.Response[RequestId] = noData(StatusCode, {}, Binary)
break

self.socket_close(ConnectionId)
Location = Header.get("location", "")
Scheme, Hostname, Port, _ = utils.get_url_info(Location)
Expand Down
31 changes: 23 additions & 8 deletions emby/metadata.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from urllib.parse import unquote
import re
import xbmc

MediaIdMapping = {"m": "movie", "e": "episode", "M": "musicvideo", "p": "picture", "a": "audio", "t": "tvchannel", "i": "movie", "T": "video", "v": "video", "c": "channel"} # T=trailer, i=iso
EmbyArtworkIDs = {"p": "Primary", "a": "Art", "b": "Banner", "d": "Disc", "l": "Logo", "t": "Thumb", "B": "Backdrop", "c": "Chapter"}
IdentifierPattern = re.compile(r"^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$")
MediaSourceContextMenu = -1

def load_MetaData(Payload, isPicture, isAudio):
Expand All @@ -22,19 +24,32 @@ def load_MetaData(Payload, isPicture, isAudio):

if isPicture: # Image/picture
MetaData["PlayerId"] = -1
Data = PayloadMod[PayloadMod.rfind("/") + 1:].split("-") # MetaData
ServerId = PayloadSplit[2]
EmbyId = Data[1]
DataLen = len(Data)

if DataLen < 5:
Data = PayloadSplit[-1].split("-") # MetaData

if (
len(PayloadSplit) != 4
or PayloadSplit[:2] != ["", "picture"]
or len(Data) < 5
or any(Character.isspace() or ord(Character) < 32 or ord(Character) == 127 for Character in PayloadMod)
or "?" in PayloadMod
or "#" in PayloadMod
or Data[0] != "p"
or not IdentifierPattern.fullmatch(PayloadSplit[2])
or not IdentifierPattern.fullmatch(Data[1])
or not Data[2].isascii()
or not Data[2].isdigit()
or Data[3] not in EmbyArtworkIDs
or not IdentifierPattern.fullmatch(Data[4])
):
xbmc.log(f"EMBY.hooks.webservice: Invalid picture {PayloadMod}", 2) # LOGERROR
return {}

ServerId = PayloadSplit[2]
EmbyId = Data[1]
MetaData.update({'ImageIndex': Data[2], 'ImageType': EmbyArtworkIDs[Data[3]], 'ImageTag': Data[4]})

if DataLen >= 6 and Data[5]:
MetaData['Overlay'] = unquote(Data[5])
if len(Data) >= 6 and Data[5]:
MetaData['Overlay'] = unquote("-".join(Data[5:]))
else:
MetaData['Overlay'] = ""
elif isAudio:
Expand Down
24 changes: 16 additions & 8 deletions helper/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import xbmc
from database import dbio
from emby import listitem
from helper import utils, playerops, queue, cache
from helper import utils, playerops, queue, cache, upnext
from dialogs import skipintrocredits
TrackerPaused = False
VideoPlayback = "READY"
Expand Down Expand Up @@ -320,6 +320,7 @@ def PlayerCommands():
PlayingItem = QueuedPlayingItem.copy()
QueuedPlayingItem = []
init_EmbyPlayback()
upnext.dispatch(PlayingItem)

if VideoPlayback == "CONTENT":
VideoPlayback = "READY"
Expand Down Expand Up @@ -407,22 +408,29 @@ def PlayerCommands():
if utils.DebugLog: xbmc.log("EMBY.hooks.player (DEBUG): --<[ paused ]", 1) # LOGDEBUG
elif Commands[0] == "stop": # {'end': True, 'item': {'id': 33874, 'type': 'episode'}}; '{"end":false,"item":{"id":107446349,"type":"song"}}'
xbmc.log("EMBY.hooks.player: [ onPlayBackStopped ]", 1) # LOGINFO
PlayItem = (0, "")
EventData = json.loads(Commands[1])
KodiId = 0
KodiTypeId = 0

if "item" in EventData:
if 'id' in EventData['item']:
KodiId = EventData["item"]["id"]
KodiTypeId = EventData["item"]["type"]

if PlayItem[0] and KodiId and PlayItem != (KodiId, KodiTypeId):
xbmc.log(f"EMBY.hooks.player: Ignore stale stop for {KodiTypeId}/{KodiId}", 1) # LOGINFO
continue

PlayItem = (0, "")
utils.update_SyncPause('playing', False)
utils.unset_SyncLock()
ProgressBarEnable = 5

if "item" in EventData: # remove from skipped items list
if 'id' in EventData['item']:
KodiId = EventData["item"]["id"]
KodiTypeId = EventData["item"]["type"]

if KodiId:
if not EventData['end']: # remove from skipped items list
ItemsUpdateQueue.put(f'{{"DELETE": [{KodiId}, "{KodiTypeId}"]}}') # Do not delete the item diectly from utils.ItemKodiSkipUpdate, to keep the events in order
if KodiId:
if not EventData['end']: # remove from skipped items list
ItemsUpdateQueue.put(f'{{"DELETE": [{KodiId}, "{KodiTypeId}"]}}') # Do not delete the item diectly from utils.ItemKodiSkipUpdate, to keep the events in order

# Dummy (blankwav) played
if ForceStopKodiId == EventData["item"]["id"]:
Expand Down
Loading