Implement player profile logic.

This commit is contained in:
Ian Walton 2020-01-12 10:19:51 -05:00
parent 011a6403d7
commit e8970a4047
5 changed files with 184 additions and 21 deletions

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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):

View File

@ -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