Skip to content

Commit

Permalink
Merge pull request #190 from jellyfin/bugfix
Browse files Browse the repository at this point in the history
Fix websocket forwarding.
  • Loading branch information
iwalton3 authored Mar 24, 2021
2 parents 2613f91 + db29196 commit 94b4c31
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Jellyfin MPV Desktop.iss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "Jellyfin Desktop"
#define MyAppVersion "1.10.0"
#define MyAppVersion "1.10.1"
#define MyAppPublisher "Ian Walton"
#define MyAppURL "https://github.com/jellyfin/jellyfin-desktop"
#define MyAppExeName "run-desktop.exe"
Expand Down
26 changes: 13 additions & 13 deletions jellyfin_mpv_shim/constants.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
APP_NAME = "jellyfin-mpv-shim"
USER_APP_NAME = "Jellyfin MPV Shim"
CLIENT_VERSION = "1.10.0"
CLIENT_VERSION = "1.10.1"
USER_AGENT = "Jellyfin-MPV-Shim/%s" % CLIENT_VERSION
CAPABILITIES = {
"PlayableMediaTypes": "Video",
"SupportsMediaControl": True,
"SupportedCommands": (
"MoveUp,MoveDown,MoveLeft,MoveRight,Select,"
"Back,ToggleFullscreen,"
"GoHome,GoToSettings,TakeScreenshot,"
"VolumeUp,VolumeDown,ToggleMute,"
"SetAudioStreamIndex,SetSubtitleStreamIndex,"
"Mute,Unmute,SetVolume,DisplayContent,"
"Play,Playstate,PlayNext,PlayMediaSource"
),
}
"PlayableMediaTypes": "Video",
"SupportsMediaControl": True,
"SupportedCommands": (
"MoveUp,MoveDown,MoveLeft,MoveRight,Select,"
"Back,ToggleFullscreen,"
"GoHome,GoToSettings,TakeScreenshot,"
"VolumeUp,VolumeDown,ToggleMute,"
"SetAudioStreamIndex,SetSubtitleStreamIndex,"
"Mute,Unmute,SetVolume,DisplayContent,"
"Play,Playstate,PlayNext,PlayMediaSource"
),
}
6 changes: 6 additions & 0 deletions jellyfin_mpv_shim/event_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ def play_media(self, client: "JellyfinClient_type", _event_name, arguments: dict
def general_command(
self, client: "JellyfinClient_type", _event_name, arguments: dict
):
# Pass GeneralCommands to desktop client when no media
# is playing.
if not playerManager.is_playing() and self.it_on_event:
self.it_on_event("GeneralCommand", arguments)
return

command = arguments.get("Name")
if command == "SetVolume":
# There is currently a bug that causes this to be spammed, so we
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@

<content_rating type="oars-1.1" />
<releases>
<release version="1.10.1" date="2021-03-24">
<description>
<p>This release fixes websocket forwarding and casting in the desktop client. Changes:</p>
<ul>
<li>Forward websocket events back to desktop web client.</li>
<li>Re-enable casting in the desktop web client.</li>
<li>Send remote control buttons to web client when MPV isn't open.</li>
<li>Upgrade the Flatpak platform version.</li>
</ul>
</description>
</release>
<release version="1.10.0" date="2021-03-23">
<description>
<p>This release changes how the web client works to improve reliability. Changes:</p>
Expand Down
8 changes: 6 additions & 2 deletions jellyfin_mpv_shim/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,12 @@ def __init__(self):
mpv_options = OrderedDict()
mpv_location = settings.mpv_ext_path
# Use bundled path for MPV if not specified by user, on Mac OS, and frozen
if mpv_location is None and platform.system() == "Darwin" and getattr(sys, 'frozen', False):
mpv_location = get_resource('mpv')
if (
mpv_location is None
and platform.system() == "Darwin"
and getattr(sys, "frozen", False)
):
mpv_location = get_resource("mpv")
self.timeline_trigger = None
self.action_trigger = None
self.external_subtitles = {}
Expand Down
2 changes: 1 addition & 1 deletion jellyfin_mpv_shim/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def get_resource(*path):
application_path = os.path.dirname(os.path.abspath(__file__))

# ! Test code for Mac
if getattr(sys, 'frozen', False) and platform.system() == 'Darwin':
if getattr(sys, "frozen", False) and platform.system() == "Darwin":
application_path = os.path.join(os.path.dirname(sys.executable), "../Resources")

return os.path.join(application_path, *path)
Expand Down
92 changes: 69 additions & 23 deletions jellyfin_mpv_shim/webclient_view/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def run(self):
app = Flask(
__name__,
static_url_path="",
static_folder=get_resource("webclient_view", "webclient")
static_folder=get_resource("webclient_view", "webclient"),
)

pl_event_queue = Queue()
Expand All @@ -78,7 +78,7 @@ def wrap_playstate(active, playstate=None, item=None):
"CanSeek": False,
"IsPaused": False,
"IsMuted": False,
"RepeatMode": "RepeatNone"
"RepeatMode": "RepeatNone",
}
res = {
"PlayState": playstate,
Expand All @@ -89,7 +89,7 @@ def wrap_playstate(active, playstate=None, item=None):
"SupportsMediaControl": True,
"SupportsContentUploading": False,
"SupportsPersistentIdentifier": False,
"SupportsSync": False
"SupportsSync": False,
},
"RemoteEndPoint": "0.0.0.0",
"PlayableMediaTypes": CAPABILITIES["PlayableMediaTypes"].split(","),
Expand All @@ -108,7 +108,7 @@ def wrap_playstate(active, playstate=None, item=None):
"HasCustomDeviceName": False,
"ServerId": last_server_id,
"SupportedCommands": CAPABILITIES["SupportedCommands"].split(","),
"dest": "player"
"dest": "player",
}
if "NowPlayingQueue" in playstate:
res["NowPlayingQueue"] = playstate["NowPlayingQueue"]
Expand All @@ -120,42 +120,70 @@ def wrap_playstate(active, playstate=None, item=None):

def on_playstate(state, payload=None, item=None):
pl_event_queue.put(wrap_playstate(True, payload, item))
if (state == "stopped"):
if state == "stopped":
pl_event_queue.put(wrap_playstate(False))

def it_on_event(name, event):
server_id = event["ServerId"]
if type(event) is dict and "value" in event and len(event) == 2:
event = event["value"]
pl_event_queue.put({
"dest": "ws",
"MessageType": name,
"Data": event
"Data": event,
"ServerId": server_id
})

playerManager.on_playstate = on_playstate
eventHandler.it_on_event = it_on_event
eventHandler.it_event_set = {"UserDataChanged"}
eventHandler.it_event_set = {
"ActivityLogEntry",
"LibraryChanged",
"PackageInstallationCancelled",
"PackageInstallationCompleted",
"PackageInstallationFailed",
"PackageInstalling",
"RefreshProgress",
"RestartRequired",
"ScheduledTasksInfo",
"SeriesTimerCancelled",
"SeriesTimerCancelled",
"SeriesTimerCreated",
"SeriesTimerCreated",
"ServerRestarting",
"ServerShuttingDown",
"Sessions",
"TimerCancelled",
"TimerCreated",
"UserDataChanged",
}

@app.after_request
def add_header(response):
if request.path == "/index.html":
do_not_cache(response)
client_data = base64.b64encode(json.dumps({
"appName": USER_APP_NAME,
"appVersion": CLIENT_VERSION,
"deviceName": settings.player_name,
"deviceId": settings.client_uuid
}).encode('ascii'))
client_data = base64.b64encode(
json.dumps(
{
"appName": USER_APP_NAME,
"appVersion": CLIENT_VERSION,
"deviceName": settings.player_name,
"deviceId": settings.client_uuid,
}
).encode("ascii")
)
# We need access to this data before we can make an async web call.
replacement = b"""<body><script type="application/json" id="clientData">%s</script>""" % client_data
replacement = (
b"""<body><script type="application/json" id="clientData">%s</script>"""
% client_data
)
if settings.desktop_scale != 1.0:
f_scale = float(settings.desktop_scale)
replacement = replacement + (b"""<style>body { zoom: %.2f; }</style>""" % f_scale)
response.make_sequence()
response.set_data(
response.get_data().replace(
b"<body>",
replacement,
replacement = replacement + (
b"""<style>body { zoom: %.2f; }</style>""" % f_scale
)
)
response.make_sequence()
response.set_data(response.get_data().replace(b"<body>", replacement,))

return response
if not response.cache_control.no_store:
Expand All @@ -168,7 +196,11 @@ def mpv_shim_session():
if request.headers["Content-Type"] != "application/json; charset=UTF-8":
return "Go Away"
req = request.json
log.info("Recieved session for server: {0}, user: {1}".format(req["Name"], req["username"]))
log.info(
"Recieved session for server: {0}, user: {1}".format(
req["Name"], req["username"]
)
)
if req["Id"] not in clientManager.clients:
is_logged_in = clientManager.connect_client(req)
log.info("Connection was successful.")
Expand Down Expand Up @@ -208,10 +240,24 @@ def mpv_shim_message():
if client is None:
log.warning("Message recieved but no client available. Ignoring.")
return resp
# Assume only 1 client is connected.
eventHandler.handle_event(client, req["name"], req["payload"])
return resp

@app.route("/mpv_shim_wsmessage", methods=["POST"])
def mpv_shim_wsmessage():
if request.headers["Content-Type"] != "application/json; charset=UTF-8":
return "Go Away"
req = request.json
client = clientManager.clients.get(req["ServerId"])
resp = jsonify({})
resp.status_code = 200
do_not_cache(resp)
if client is None:
log.warning("Message recieved but no client available. Ignoring.")
return resp
client.wsc.send(req["name"], req.get("payload", ""))
return resp

@app.route("/mpv_shim_teardown", methods=["POST"])
def mpv_shim_teardown():
if request.headers["Content-Type"] != "application/json; charset=UTF-8":
Expand Down
24 changes: 11 additions & 13 deletions setup-mac.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
from setuptools import setup

APP = ['/usr/local/bin/jellyfin-mpv-desktop']
APP = ["/usr/local/bin/jellyfin-mpv-desktop"]
OPTIONS = {
'argv_emulation' : True,
'iconfile' : 'jellyfin.icns',
'resources' : [
'/usr/local/bin/mpv',
'/usr/local/bin/jellyfin-mpv-shim',
'/usr/local/lib/python3.9/site-packages/jellyfin_mpv_shim/webclient_view'
"argv_emulation": True,
"iconfile": "jellyfin.icns",
"resources": [
"/usr/local/bin/mpv",
"/usr/local/bin/jellyfin-mpv-shim",
"/usr/local/lib/python3.9/site-packages/jellyfin_mpv_shim/webclient_view",
],
'packages': [
'pkg_resources'
]
"packages": ["pkg_resources"],
}

setup(
app=APP,
name='Jellyfin MPV Desktop',
options={'py2app': OPTIONS},
setup_requires=['py2app'],
name="Jellyfin MPV Desktop",
options={"py2app": OPTIONS},
setup_requires=["py2app"],
)
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(
name="jellyfin-mpv-shim",
version="1.10.0",
version="1.10.1",
author="Ian Walton",
author_email="[email protected]",
description="Cast media from Jellyfin Mobile and Web apps to MPV.",
Expand Down Expand Up @@ -51,7 +51,7 @@
python_requires=">=3.6",
install_requires=[
"python-mpv",
"jellyfin-apiclient-python>=1.7.0",
"jellyfin-apiclient-python>=1.7.2",
"python-mpv-jsonipc>=1.1.9",
"requests",
"pydantic",
Expand Down

0 comments on commit 94b4c31

Please sign in to comment.