mirror of
https://github.com/jellyfin/jellyfin-mpv-shim.git
synced 2025-02-21 15:12:27 +00:00
Implement player profile logic.
This commit is contained in:
parent
011a6403d7
commit
e8970a4047
11
README.md
11
README.md
@ -92,13 +92,10 @@ You can adjust the basic transcoder settings via the menu.
|
||||
|
||||
- `always_transcode` - This will tell the client to always transcode, without asking. Default: `false`
|
||||
- This may be useful if you are using limited hardware that cannot handle advanced codecs.
|
||||
- You may have some luck changing `client_profile` in the configuration to a more restrictive one.
|
||||
- `auto_transcode` - This will ask the server to determine if transcoding is suggested. Default: `true`
|
||||
- `transcode_kbps` - Transcode bandwidth to request. Default: `2000`
|
||||
- `direct_limit` - Also limit direct play to `transcode_kbps`. Default: `false`
|
||||
- Note that `direct_limit` cannot be overriden without changing `transcode_kbps`.
|
||||
- If `direct_limit` is not set, the player assumes the server will set the limit.
|
||||
- `adaptive_transcode` - Tell the server to adjust the quality while streaming. Default: `false`
|
||||
- `transcode_h265` - Transcode HEVC videos. Default: `false`
|
||||
- `transcode_hi10p` - Transcode 10 bit color videos. Default: `false`
|
||||
- `remote_kbps` - Bandwidth to permit for remote streaming. Default: `2000`
|
||||
- `local_kbps` - Bandwidth to permit for local streaming. Default: `2147483`
|
||||
|
||||
### Shell Command Triggers
|
||||
|
||||
|
@ -10,7 +10,6 @@ import os.path
|
||||
import json
|
||||
|
||||
CLIENT_VERSION = "1.0.0"
|
||||
APP_NAME = 'jellyfin-mpv-shim'
|
||||
|
||||
CONNECTION_STATE = {
|
||||
'Unavailable': 0,
|
||||
@ -26,14 +25,14 @@ class ClientManager(object):
|
||||
|
||||
def connect(self):
|
||||
credentials = None
|
||||
credentials_location = conffile.get(APP_NAME,'cred.json')
|
||||
credentials_location = conffile.get("jellyfin-mpv-shim",'cred.json')
|
||||
if os.path.exists(credentials_location):
|
||||
with open(credentials_location) as cf:
|
||||
credentials = json.load(cf)
|
||||
|
||||
client = Jellyfin(None)
|
||||
client.config.data['app.default'] = True
|
||||
client.config.app(APP_NAME, CLIENT_VERSION, settings.player_name, settings.client_uuid)
|
||||
client.config.app("Jellyfin MPV Shim", CLIENT_VERSION, settings.player_name, settings.client_uuid)
|
||||
client.config.data['http.user_agent'] = "Jellyfin-MPV-Shim/%s" % CLIENT_VERSION
|
||||
client.config.data['auth.ssl'] = not settings.allow_http
|
||||
|
||||
|
@ -24,10 +24,10 @@ class Settings(object):
|
||||
"idle_cmd": None,
|
||||
"idle_cmd_delay": 60,
|
||||
"always_transcode": False,
|
||||
"auto_transcode": True,
|
||||
"adaptive_transcode": False,
|
||||
"direct_limit": False,
|
||||
"transcode_kbps": 2000,
|
||||
"transcode_h265": False,
|
||||
"transcode_hi10p": False,
|
||||
"remote_kbps": 2000,
|
||||
"local_kbps": 2147483,
|
||||
"subtitle_size": 100,
|
||||
"subtitle_color": "#FFFFFFFF",
|
||||
"subtitle_position": "bottom",
|
||||
|
@ -280,7 +280,7 @@ class OSDMenu(object):
|
||||
)
|
||||
|
||||
def transcode_settings_handle(self):
|
||||
settings.transcode_kbps = self.menu_list[self.menu_selection][2]
|
||||
settings.remote_kbps = self.menu_list[self.menu_selection][2]
|
||||
settings.save()
|
||||
|
||||
# Need to re-render preferences menu.
|
||||
@ -294,7 +294,7 @@ class OSDMenu(object):
|
||||
|
||||
for i, item in enumerate(TRANSCODE_LEVELS):
|
||||
self.menu_list.append((item[0], handle, item[1]))
|
||||
if settings.transcode_kbps == item[1]:
|
||||
if settings.remote_kbps == item[1]:
|
||||
self.menu_selection = i
|
||||
|
||||
def get_subtitle_color(self, color):
|
||||
@ -341,14 +341,14 @@ class OSDMenu(object):
|
||||
|
||||
def preferences_menu(self):
|
||||
self.put_menu("Preferences", [
|
||||
self.get_settings_toggle("Adaptive Transcode", "adaptive_transcode"),
|
||||
self.get_settings_toggle("Always Transcode", "always_transcode"),
|
||||
self.get_settings_toggle("Limit Direct Play", "direct_limit"),
|
||||
self.get_settings_toggle("Always Transcode", "always_transcode"),
|
||||
self.get_settings_toggle("Auto Play", "auto_play"),
|
||||
("Transcode Quality: {0:0.1f} Mbps".format(settings.transcode_kbps/1000), self.transcode_settings_menu),
|
||||
("Remote Transcode Quality: {0:0.1f} Mbps".format(settings.remote_kbps/1000), self.transcode_settings_menu),
|
||||
("Subtitle Size: {0}".format(settings.subtitle_size), self.subtitle_size_menu),
|
||||
("Subtitle Position: {0}".format(settings.subtitle_position), self.subtitle_position_menu),
|
||||
("Subtitle Color: {0}".format(self.get_subtitle_color(settings.subtitle_color)), self.subtitle_color_menu),
|
||||
self.get_settings_toggle("Transcode H265", "transcode_h265"),
|
||||
self.get_settings_toggle("Transcode Hi10p", "transcode_hi10p"),
|
||||
])
|
||||
|
||||
def unwatched_menu_handle(self):
|
||||
|
@ -1,10 +1,13 @@
|
||||
import socket
|
||||
import ipaddress
|
||||
import urllib.request
|
||||
|
||||
from .conf import settings
|
||||
from datetime import datetime
|
||||
from functools import wraps
|
||||
|
||||
APP_NAME = 'Jellyfin MPV Shim'
|
||||
|
||||
class Timer(object):
|
||||
def __init__(self):
|
||||
self.restart()
|
||||
@ -37,10 +40,174 @@ def synchronous(tlockname):
|
||||
return _synched
|
||||
|
||||
def is_local_domain(domain):
|
||||
return ipaddress.ip_address(socket.gethostbyname(domain)).is_private
|
||||
# With Jellyfin, it is significantly more likely the user will be using
|
||||
# an address that is a hairpin NAT. We want to detect this and avoid
|
||||
# imposing limits in this case.
|
||||
ip = socket.gethostbyname(domain)
|
||||
is_local = ipaddress.ip_address(ip).is_private
|
||||
|
||||
if not is_local:
|
||||
wan_ip = (urllib.request.urlopen("https://checkip.amazonaws.com/")
|
||||
.read().decode('ascii').replace('\n','').replace('\r',''))
|
||||
return ip == wan_ip
|
||||
return True
|
||||
|
||||
def mpv_color_to_plex(color):
|
||||
return '#'+color.lower()[3:]
|
||||
|
||||
def plex_color_to_mpv(color):
|
||||
return '#FF'+color.upper()[1:]
|
||||
|
||||
def get_profile(is_remote=False, video_bitrate=None, force_transcode=False, is_tv=False):
|
||||
if video_bitrate is None:
|
||||
if is_remote:
|
||||
bitrate = settings.remote_kbps
|
||||
else:
|
||||
bitrate = settings.local_kbps
|
||||
|
||||
profile = {
|
||||
"Name": APP_NAME,
|
||||
"MaxStreamingBitrate": video_bitrate * 1000,
|
||||
"MusicStreamingTranscodingBitrate": 1280000,
|
||||
"TimelineOffsetSeconds": 5,
|
||||
"TranscodingProfiles": [
|
||||
{
|
||||
"Type": "Audio"
|
||||
},
|
||||
{
|
||||
"Container": "m3u8",
|
||||
"Type": "Video",
|
||||
"AudioCodec": "aac,mp3,ac3,opus,flac,vorbis",
|
||||
"VideoCodec": "h264,mpeg4,mpeg2video",
|
||||
"MaxAudioChannels": "6"
|
||||
},
|
||||
{
|
||||
"Container": "jpeg",
|
||||
"Type": "Photo"
|
||||
}
|
||||
],
|
||||
"DirectPlayProfiles": [
|
||||
{
|
||||
"Type": "Video"
|
||||
},
|
||||
{
|
||||
"Type": "Audio"
|
||||
},
|
||||
{
|
||||
"Type": "Photo"
|
||||
}
|
||||
],
|
||||
"ResponseProfiles": [],
|
||||
"ContainerProfiles": [],
|
||||
"CodecProfiles": [],
|
||||
"SubtitleProfiles": [
|
||||
{
|
||||
"Format": "srt",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "srt",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "ass",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "ass",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "sub",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "sub",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "ssa",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "ssa",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "smi",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "smi",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "pgssub",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "pgssub",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "dvdsub",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "dvdsub",
|
||||
"Method": "External"
|
||||
},
|
||||
{
|
||||
"Format": "pgs",
|
||||
"Method": "Embed"
|
||||
},
|
||||
{
|
||||
"Format": "pgs",
|
||||
"Method": "External"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
if settings.transcode_h265:
|
||||
profile['DirectPlayProfiles'][0]['VideoCodec'] = "h264,mpeg4,mpeg2video"
|
||||
else:
|
||||
profile['TranscodingProfiles'].insert(0, {
|
||||
"Container": "m3u8",
|
||||
"Type": "Video",
|
||||
"AudioCodec": "aac,mp3,ac3,opus,flac,vorbis",
|
||||
"VideoCodec": "h264,h265,hevc,mpeg4,mpeg2video",
|
||||
"MaxAudioChannels": "6"
|
||||
})
|
||||
|
||||
if settings.transcode_hi10p:
|
||||
profile['CodecProfiles'].append(
|
||||
{
|
||||
'Type': 'Video',
|
||||
'codec': 'h264',
|
||||
'Conditions': [
|
||||
{
|
||||
'Condition': "LessThanEqual",
|
||||
'Property': "VideoBitDepth",
|
||||
'Value': "8"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
if settings.always_transcode or force_transcode:
|
||||
profile['DirectPlayProfiles'] = []
|
||||
|
||||
if is_tv:
|
||||
profile['TranscodingProfiles'].insert(0, {
|
||||
"Container": "ts",
|
||||
"Type": "Video",
|
||||
"AudioCodec": "mp3,aac",
|
||||
"VideoCodec": "h264",
|
||||
"Context": "Streaming",
|
||||
"Protocol": "hls",
|
||||
"MaxAudioChannels": "2",
|
||||
"MinSegments": "1",
|
||||
"BreakOnNonKeyFrames": True
|
||||
})
|
||||
|
||||
return profile
|
||||
|
Loading…
x
Reference in New Issue
Block a user