mirror of
https://github.com/jellyfin/jellyfin-mpv-shim.git
synced 2024-11-23 05:59:43 +00:00
Base localization support.
This commit is contained in:
parent
1a40f62677
commit
0b422624fd
@ -2,3 +2,4 @@ include jellyfin_mpv_shim/systray.png
|
||||
recursive-include jellyfin_mpv_shim/webclient_view/webclient *
|
||||
recursive-include jellyfin_mpv_shim/integration *
|
||||
recursive-include jellyfin_mpv_shim/default_shader_pack *
|
||||
recursive-include jellyfin_mpv_shim/messages *.mo
|
||||
|
20
README.md
20
README.md
@ -298,6 +298,7 @@ need to.
|
||||
- Update checks are performed when playing media, once per day.
|
||||
- `notify_updates` - Display update notification when playing media. Default: `true`
|
||||
- Notification will only display once until the application is restarted.
|
||||
- `lang` - Allows overriding system locale. (Enter a language code.) Default: `null`
|
||||
|
||||
### MPV Configuration
|
||||
|
||||
@ -477,6 +478,25 @@ If you are on Windows there are additional dependencies. Please see the Windows
|
||||
6. Install any platform-specific dependencies from the respective install tutorials.
|
||||
7. You should now be able to run the program with `./run.py` or `./run-desktop.py`. Installation is possible with `sudo pip3 install .`.
|
||||
|
||||
### Translation
|
||||
|
||||
This project uses gettext for translation. The current template language file is `base.pot` in `jellyfin_mpv_shim/messages/`.
|
||||
|
||||
To regenerate `base.pot`:
|
||||
```bash
|
||||
pygettext --default-domain=base -o jellyfin_mpv_shim/messages/base.pot jellyfin_mpv_shim/*.py jellyfin_mpv_shim/**/*.py
|
||||
```
|
||||
|
||||
To update an existing translation with new strings:
|
||||
```bash
|
||||
msgmerge --update jellyfin_mpv_shim/messages/es/LC_MESSAGES/base.po jellyfin_mpv_shim/messages/base.pot
|
||||
```
|
||||
|
||||
To compile all `*.po` files to `*.mo`:
|
||||
```bash
|
||||
find -iname '*.po' | while read -r file; do msgfmt "$file" -o "${file%.*}.mo"; done
|
||||
```
|
||||
|
||||
## Linux Installation
|
||||
|
||||
You can [install the software from flathub](https://flathub.org/apps/details/com.github.iwalton3.jellyfin-mpv-shim). The pip installation is less integrated but takes up less space if you're not already using flatpak.
|
||||
|
@ -8,7 +8,7 @@ rem The desktop version (and corresponding shim shortcut) do work, however.
|
||||
rem Edge-based build
|
||||
rem "C:\Program Files (x86)\Python37-32\Scripts\pyinstaller" -w --add-binary "mpv32\mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --add-binary "Microsoft.Toolkit.Forms.UI.Controls.WebView.dll;." --icon jellyfin.ico run-desktop-edge.py
|
||||
rem CEF-based build
|
||||
"C:\Program Files (x86)\Python37-32\Scripts\pyinstaller" -w --add-binary "mpv32\mpv-1.dll;." --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --icon jellyfin.ico run-desktop.py
|
||||
"C:\Program Files (x86)\Python37-32\Scripts\pyinstaller" -w --add-binary "mpv32\mpv-1.dll;." --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\messages;jellyfin_mpv_shim\messages" --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --icon jellyfin.ico run-desktop.py
|
||||
xcopy /E /Y cef32\cefpython3 dist\run-desktop\
|
||||
xcopy /E /Y mpv32\mpv-1.dll dist\run-desktop\
|
||||
del dist\run-desktop\run-desktop.exe.manifest
|
||||
|
@ -4,10 +4,10 @@ set PATH=%PATH%;%CD%
|
||||
rem Edge-based build
|
||||
rem pyinstaller -c --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --add-binary "Microsoft.Toolkit.Forms.UI.Controls.WebView.dll;." --icon jellyfin.ico run-desktop-edge.py
|
||||
rem CEF-based build
|
||||
pyinstaller -c --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --icon jellyfin.ico run-desktop.py
|
||||
pyinstaller -c --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\messages;jellyfin_mpv_shim\messages" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --icon jellyfin.ico run-desktop.py
|
||||
xcopy /E /Y cef\cefpython3 dist\run-desktop\
|
||||
del dist\run-desktop\run-desktop.exe.manifest
|
||||
copy hidpi.manifest dist\run-desktop\run-desktop.exe.manifest
|
||||
rd /s /q __pycache__ build
|
||||
pyinstaller -cF --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --add-binary "Microsoft.Toolkit.Forms.UI.Controls.WebView.dll;." --exclude-module cefpython3 --icon jellyfin.ico run.py
|
||||
pyinstaller -cF --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\messages;jellyfin_mpv_shim\messages" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --add-binary "Microsoft.Toolkit.Forms.UI.Controls.WebView.dll;." --exclude-module cefpython3 --icon jellyfin.ico run.py
|
||||
pause
|
||||
|
@ -4,10 +4,10 @@ set PATH=%PATH%;%CD%
|
||||
rem Edge-based build
|
||||
rem pyinstaller -w --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --add-binary "Microsoft.Toolkit.Forms.UI.Controls.WebView.dll;." --icon jellyfin.ico run-desktop-edge.py
|
||||
rem CEF-based build
|
||||
pyinstaller -w --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --icon jellyfin.ico run-desktop.py
|
||||
pyinstaller -w --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\messages;jellyfin_mpv_shim\messages" --add-data "jellyfin_mpv_shim\webclient_view\webclient;jellyfin_mpv_shim\webclient_view\webclient" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --icon jellyfin.ico run-desktop.py
|
||||
xcopy /E /Y cef\cefpython3 dist\run-desktop\
|
||||
del dist\run-desktop\run-desktop.exe.manifest
|
||||
copy hidpi.manifest dist\run-desktop\run-desktop.exe.manifest
|
||||
rd /s /q __pycache__ build
|
||||
pyinstaller -wF --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --add-binary "Microsoft.Toolkit.Forms.UI.Controls.WebView.dll;." --exclude-module cefpython3 --icon jellyfin.ico run.py
|
||||
pyinstaller -wF --add-binary "mpv-1.dll;." --add-data "jellyfin_mpv_shim\systray.png;jellyfin_mpv_shim" --add-data "jellyfin_mpv_shim\default_shader_pack;jellyfin_mpv_shim\default_shader_pack" --add-data "jellyfin_mpv_shim\messages;jellyfin_mpv_shim\messages" --add-data "jellyfin_mpv_shim\display_mirror\index.html;jellyfin_mpv_shim\display_mirror" --add-data "jellyfin_mpv_shim\display_mirror\jellyfin.css;jellyfin_mpv_shim\display_mirror" --add-binary "Microsoft.Toolkit.Forms.UI.Controls.WebView.dll;." --exclude-module cefpython3 --icon jellyfin.ico run.py
|
||||
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "Jellyfin MPV Desktop.iss"
|
||||
|
@ -1,6 +1,8 @@
|
||||
from collections import namedtuple
|
||||
from .utils import get_sub_display_title
|
||||
import urllib.parse
|
||||
from .i18n import _
|
||||
# TODO: Should probably support automatic profiles for languages other than English and Japanese...
|
||||
|
||||
import time
|
||||
import logging
|
||||
|
||||
@ -15,7 +17,7 @@ keep_messages = 6
|
||||
def render_message(message, show_text):
|
||||
log.info(message)
|
||||
messages.append(message)
|
||||
text = "Selecting Tracks..."
|
||||
text = _("Selecting Tracks...")
|
||||
for message in messages[-6:]:
|
||||
text += "\n " + message
|
||||
show_text(text,2**30,1)
|
||||
@ -41,9 +43,9 @@ def process_series(mode, player, m_raid=None, m_rsid=None):
|
||||
audio_list = [Audio(s.get("Index"), s.get("Language"), s.get("Title"),
|
||||
s.get("DisplayTitle")) for s in media_source["MediaStreams"]
|
||||
if s.get("Type") == "Audio"]
|
||||
subtitle_list = [Subtitle(s.get("Index"), s.get("Language"), s.get("Title"), s.get("IsForced"),
|
||||
get_sub_display_title(s)) for s in media_source["MediaStreams"]
|
||||
if s.get("Type") == "Subtitle"]
|
||||
subtitle_list = [Subtitle(s.get("Index"), s.get("Language"), s.get("Title"), s.get("IsForced"),
|
||||
get_sub_display_title(s)) for s in media_source["MediaStreams"]
|
||||
if s.get("Type") == "Subtitle"]
|
||||
part = Part(media_source.get("Id"), audio_list, subtitle_list)
|
||||
|
||||
aid = None
|
||||
@ -63,7 +65,7 @@ def process_series(mode, player, m_raid=None, m_rsid=None):
|
||||
aid, sid = audio.id, subtitle.id
|
||||
success_ct += 1
|
||||
elif audio:
|
||||
render_message("{0}: No Subtitles".format(name), show_text)
|
||||
render_message(_("{0}: No Subtitles").format(name), show_text)
|
||||
aid = audio.id
|
||||
partial_ct += 1
|
||||
elif mode == "manual":
|
||||
@ -86,26 +88,26 @@ def process_series(mode, player, m_raid=None, m_rsid=None):
|
||||
# This is a horrible hack to change the audio/subtitle settings without playing
|
||||
# the media. I checked the jelyfin source code and didn't find a better way.
|
||||
client.jellyfin.session_progress({
|
||||
"ItemId":part.id,
|
||||
"ItemId": part.id,
|
||||
"AudioStreamIndex": aid,
|
||||
"SubtitleStreamIndex": sid
|
||||
})
|
||||
|
||||
else:
|
||||
render_message("{0}: Fail".format(name), show_text)
|
||||
render_message(_("{0}: Fail").format(name), show_text)
|
||||
|
||||
if mode == "subbed":
|
||||
render_message("Set Subbed: {0} ok, {1} fail".format(
|
||||
render_message(_("Set Subbed: {0} ok, {1} fail").format(
|
||||
success_ct, count-success_ct), show_text)
|
||||
elif mode == "dubbed":
|
||||
render_message("Set Dubbed: {0} ok, {1} audio only, {2} fail".format(
|
||||
render_message(_("Set Dubbed: {0} ok, {1} audio only, {2} fail").format(
|
||||
success_ct, partial_ct, count-success_ct-partial_ct), show_text)
|
||||
elif mode == "manual":
|
||||
render_message("Manual: {0} ok, {1} fail".format(
|
||||
render_message(_("Manual: {0} ok, {1} fail").format(
|
||||
success_ct, count-success_ct), show_text)
|
||||
time.sleep(3)
|
||||
if c_aid:
|
||||
render_message("Setting Current...", show_text)
|
||||
render_message(_("Setting Current..."), show_text)
|
||||
player.put_task(player.set_streams, c_aid, c_sid)
|
||||
player.timeline_handle()
|
||||
|
||||
@ -116,7 +118,7 @@ def get_subbed(part):
|
||||
|
||||
for audio in part.audio:
|
||||
lower_title = audio.name.lower() if audio.name is not None else ""
|
||||
if audio.language_code != "jpn" and not "japan" in lower_title:
|
||||
if audio.language_code != "jpn" and "japan" not in lower_title:
|
||||
continue
|
||||
if "commentary" in lower_title:
|
||||
continue
|
||||
@ -127,7 +129,7 @@ def get_subbed(part):
|
||||
|
||||
for subtitle in part.subtitle:
|
||||
lower_title = subtitle.name.lower() if subtitle.name is not None else ""
|
||||
if subtitle.language_code != "eng" and not "english" in lower_title:
|
||||
if subtitle.language_code != "eng" and "english" not in lower_title:
|
||||
continue
|
||||
if subtitle.is_forced:
|
||||
continue
|
||||
@ -148,7 +150,7 @@ def get_dubbed(part):
|
||||
|
||||
for audio in part.audio:
|
||||
lower_title = audio.name.lower() if audio.name is not None else ""
|
||||
if audio.language_code != "eng" and not "english" in lower_title:
|
||||
if audio.language_code != "eng" and "english" not in lower_title:
|
||||
continue
|
||||
if "commentary" in lower_title:
|
||||
continue
|
||||
@ -159,7 +161,7 @@ def get_dubbed(part):
|
||||
|
||||
for subtitle in part.subtitle:
|
||||
lower_title = subtitle.name.lower() if subtitle.name is not None else ""
|
||||
if subtitle.language_code != "eng" and not "english" in lower_title:
|
||||
if subtitle.language_code != "eng" and "english" not in lower_title:
|
||||
continue
|
||||
if subtitle.is_forced:
|
||||
sign_subtitles = subtitle
|
||||
|
@ -4,6 +4,7 @@ from .conf import settings
|
||||
from . import conffile
|
||||
from getpass import getpass
|
||||
from .constants import CLIENT_VERSION, USER_APP_NAME, USER_AGENT, APP_NAME
|
||||
from .i18n import _
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
@ -41,18 +42,18 @@ class ClientManager(object):
|
||||
add_another = True
|
||||
|
||||
while not is_logged_in or add_another:
|
||||
server = input("Server URL: ")
|
||||
username = input("Username: ")
|
||||
password = getpass("Password: ")
|
||||
server = input(_("Server URL: "))
|
||||
username = input(_("Username: "))
|
||||
password = getpass(_("Password: "))
|
||||
|
||||
is_logged_in = self.login(server, username, password)
|
||||
|
||||
if is_logged_in:
|
||||
log.info("Successfully added server.")
|
||||
add_another = input("Add another server? [y/N] ")
|
||||
log.info(_("Successfully added server."))
|
||||
add_another = input(_("Add another server? [y/N] "))
|
||||
add_another = add_another in ("y", "Y", "yes", "Yes")
|
||||
else:
|
||||
log.warning("Adding server failed.")
|
||||
log.warning(_("Adding server failed."))
|
||||
|
||||
def client_factory(self):
|
||||
client = JellyfinClient(allow_multiple_clients=True)
|
||||
|
@ -92,6 +92,7 @@ class Settings(object):
|
||||
"screenshot_menu": True,
|
||||
"check_updates": True,
|
||||
"notify_updates": True,
|
||||
"lang": None,
|
||||
}
|
||||
|
||||
def __getattr__(self, name):
|
||||
|
@ -17,9 +17,9 @@ import webview # Python3-webview in Debian, pywebview in pypi
|
||||
|
||||
from ..clients import clientManager
|
||||
from ..utils import get_text
|
||||
from ..i18n import _
|
||||
from . import helpers
|
||||
|
||||
|
||||
# This makes me rather uncomfortable, but there's no easy way around this other than importing display_mirror in helpers.
|
||||
# Lambda needed because the 2.3 version of the JS api adds an argument even when not used.
|
||||
helpers.on_escape = lambda _x=None: load_idle()
|
||||
@ -100,8 +100,8 @@ def get_html(server_address=None, item=None):
|
||||
jinja_vars = {
|
||||
'random_backdrop': True, # Make the jinja template load some extra JS code for random backdrops
|
||||
'backdrop_src': helpers.getRandomBackdropUrl(), # Preinitialise it with a random backdrop though
|
||||
'display_name': "Ready to cast",
|
||||
'overview': "\n\nSelect your media in Jellyfin and play it here", # FIME: Mention the player_name here
|
||||
'display_name': _("Ready to cast"),
|
||||
'overview': "\n\n" + _("Select your media in Jellyfin and play it here"), # FIME: Mention the player_name here
|
||||
}
|
||||
|
||||
jinja_vars.update({
|
||||
|
@ -13,6 +13,7 @@ from .conffile import confdir
|
||||
from .clients import clientManager
|
||||
from .utils import get_resource
|
||||
from .log_utils import CustomFormatter
|
||||
from .i18n import _
|
||||
|
||||
log = logging.getLogger('gui_mgr')
|
||||
|
||||
@ -132,7 +133,7 @@ class LoggerWindowProcess(Process):
|
||||
self.tk = tk
|
||||
root = tk.Tk()
|
||||
self.root = root
|
||||
root.title("Application Log")
|
||||
root.title(_("Application Log"))
|
||||
text = tk.Text(root)
|
||||
text.pack(side=tk.LEFT, fill=tk.BOTH, expand = tk.YES)
|
||||
text.config(wrap=tk.WORD)
|
||||
@ -170,7 +171,7 @@ class PreferencesWindow(threading.Thread):
|
||||
else:
|
||||
self.handle("error")
|
||||
except Exception:
|
||||
log.error("Error while adding server.", exc_info=1)
|
||||
log.error("Error while adding server.", exc_info=True)
|
||||
self.handle("error")
|
||||
elif action == "remove":
|
||||
clientManager.remove_client(param)
|
||||
@ -206,7 +207,9 @@ class PreferencesWindowProcess(Process):
|
||||
self.add_button.config(state=self.tk.NORMAL)
|
||||
self.remove_button.config(state=self.tk.NORMAL)
|
||||
elif action == "error":
|
||||
self.messagebox.showerror("Add Server", "Could not add server.\nPlease check your connection infomation.")
|
||||
self.messagebox.showerror(
|
||||
_("Add Server"),
|
||||
_("Could not add server.\nPlease check your connection infomation."))
|
||||
self.add_button.config(state=self.tk.NORMAL)
|
||||
elif action == "die":
|
||||
self.root.destroy()
|
||||
@ -222,7 +225,7 @@ class PreferencesWindowProcess(Process):
|
||||
self.serverList.set(["{0} ({1}, {2})".format(
|
||||
server["Name"],
|
||||
server["username"],
|
||||
"Ok" if server["connected"] else "Fail"
|
||||
_("Ok") if server["connected"] else _("Fail")
|
||||
) for server in self.servers])
|
||||
|
||||
def run(self):
|
||||
@ -231,7 +234,7 @@ class PreferencesWindowProcess(Process):
|
||||
self.tk = tk
|
||||
self.messagebox = messagebox
|
||||
root = tk.Tk()
|
||||
root.title("Server Configuration")
|
||||
root.title(_("Server Configuration"))
|
||||
self.root = root
|
||||
|
||||
self.servers = {}
|
||||
@ -254,17 +257,17 @@ class PreferencesWindowProcess(Process):
|
||||
c.grid_columnconfigure(0, weight=1)
|
||||
c.grid_rowconfigure(4, weight=1)
|
||||
|
||||
servername_label = ttk.Label(c, text='Server:')
|
||||
servername_label = ttk.Label(c, text=_('Server:'))
|
||||
servername_label.grid(column=1, row=0, sticky=tk.E)
|
||||
self.servername = tk.StringVar()
|
||||
servername_box = ttk.Entry(c, textvariable=self.servername)
|
||||
servername_box.grid(column=2, row=0)
|
||||
username_label = ttk.Label(c, text='Username:')
|
||||
username_label = ttk.Label(c, text=_('Username:'))
|
||||
username_label.grid(column=1, row=1, sticky=tk.E)
|
||||
self.username = tk.StringVar()
|
||||
username_box = ttk.Entry(c, textvariable=self.username)
|
||||
username_box.grid(column=2, row=1)
|
||||
password_label = ttk.Label(c, text='Password:')
|
||||
password_label = ttk.Label(c, text=_('Password:'))
|
||||
password_label.grid(column=1, row=2, sticky=tk.E)
|
||||
self.password = tk.StringVar()
|
||||
password_box = ttk.Entry(c, textvariable=self.password, show="*")
|
||||
@ -285,11 +288,11 @@ class PreferencesWindowProcess(Process):
|
||||
def close():
|
||||
self.r_queue.put(("die", None))
|
||||
|
||||
self.add_button = ttk.Button(c, text='Add Server', command=add_server)
|
||||
self.add_button = ttk.Button(c, text=_('Add Server'), command=add_server)
|
||||
self.add_button.grid(column=2, row=3, pady=5, sticky=tk.E)
|
||||
self.remove_button = ttk.Button(c, text='Remove Server', command=remove_server)
|
||||
self.remove_button = ttk.Button(c, text=_('Remove Server'), command=remove_server)
|
||||
self.remove_button.grid(column=1, row=4, padx=5, pady=10, sticky=(tk.E, tk.S))
|
||||
close_button = ttk.Button(c, text='Close', command=close)
|
||||
close_button = ttk.Button(c, text=_('Close'), command=close)
|
||||
close_button.grid(column=2, row=4, pady=10, sticky=(tk.E, tk.S))
|
||||
|
||||
serverlist.bind('<<ListboxSelect>>', serverSelect)
|
||||
@ -393,11 +396,11 @@ class STrayProcess(Process):
|
||||
self.icon_stop()
|
||||
|
||||
menu_items = [
|
||||
MenuItem("Configure Servers", get_wrapper("show_preferences")),
|
||||
MenuItem("Show Console", get_wrapper("show_console")),
|
||||
MenuItem("Application Menu", get_wrapper("open_player_menu")),
|
||||
MenuItem("Open Config Folder", get_wrapper("open_config_brs")),
|
||||
MenuItem("Quit", die)
|
||||
MenuItem(_("Configure Servers"), get_wrapper("show_preferences")),
|
||||
MenuItem(_("Show Console"), get_wrapper("show_console")),
|
||||
MenuItem(_("Application Menu"), get_wrapper("open_player_menu")),
|
||||
MenuItem(_("Open Config Folder"), get_wrapper("open_config_brs")),
|
||||
MenuItem(_("Quit"), die)
|
||||
]
|
||||
|
||||
icon = Icon(USER_APP_NAME, menu=Menu(*menu_items))
|
||||
|
25
jellyfin_mpv_shim/i18n.py
Normal file
25
jellyfin_mpv_shim/i18n.py
Normal file
@ -0,0 +1,25 @@
|
||||
import gettext
|
||||
import builtins
|
||||
|
||||
from .conf import settings
|
||||
|
||||
translation = gettext.NullTranslations()
|
||||
|
||||
|
||||
def configure():
|
||||
global translation
|
||||
from .utils import get_resource
|
||||
messages_dir = get_resource("messages")
|
||||
|
||||
if settings.lang is not None:
|
||||
translation = gettext.translation("base", messages_dir, languages=[settings.lang], fallback=True)
|
||||
else:
|
||||
translation = gettext.translation("base", messages_dir, fallback=True)
|
||||
|
||||
|
||||
def get_translation():
|
||||
return translation
|
||||
|
||||
|
||||
def _(string: str) -> str:
|
||||
return translation.gettext(string)
|
@ -8,6 +8,7 @@ from sys import platform
|
||||
|
||||
from .conf import settings
|
||||
from .utils import is_local_domain, get_profile, get_seq
|
||||
from .i18n import _
|
||||
|
||||
log = logging.getLogger('media')
|
||||
|
||||
@ -101,7 +102,7 @@ class Video(object):
|
||||
if year is not None:
|
||||
title = "%s (%s)" % (title, year)
|
||||
setattr(self, "_title", title)
|
||||
return getattr(self, "_title") + (" (Transcode)" if self.is_transcode else "")
|
||||
return getattr(self, "_title") + (_(" (Transcode)") if self.is_transcode else "")
|
||||
|
||||
def set_trs_override(self, video_bitrate, force_transcode):
|
||||
if force_transcode:
|
||||
@ -282,9 +283,9 @@ class Media(object):
|
||||
return self.video
|
||||
|
||||
if index < len(self.queue):
|
||||
return Video(queue[index]["Id"], self)
|
||||
return Video(self.queue[index]["Id"], self)
|
||||
|
||||
log.error("Media::get_video couldn't find video at index %s" % video)
|
||||
log.error("Media::get_video couldn't find video at index %s" % index)
|
||||
|
||||
def insert_items(self, items, append=False):
|
||||
items = [{ "PlaylistItemId": "playlistItem{0}".format(get_seq()), "Id": id_num } for id_num in items]
|
||||
|
@ -4,6 +4,7 @@ from .conf import settings
|
||||
from .utils import mpv_color_to_plex, get_sub_display_title
|
||||
from .video_profile import VideoProfileManager
|
||||
from .svp_integration import SVPManager
|
||||
from .i18n import _
|
||||
|
||||
import time
|
||||
import logging
|
||||
@ -24,23 +25,23 @@ TRANSCODE_LEVELS = (
|
||||
)
|
||||
|
||||
COLOR_LIST = (
|
||||
("White", "#FFFFFFFF"),
|
||||
("Yellow", "#FFFFEE00"),
|
||||
("Black", "#FF000000"),
|
||||
("Cyan", "#FF00FFFF"),
|
||||
("Blue", "#FF0000FF"),
|
||||
("Green", "#FF00FF00"),
|
||||
("Magenta", "#FFEE00EE"),
|
||||
("Red", "#FFFF0000"),
|
||||
("Gray", "#FF808080"),
|
||||
(_("White"), "#FFFFFFFF"),
|
||||
(_("Yellow"), "#FFFFEE00"),
|
||||
(_("Black"), "#FF000000"),
|
||||
(_("Cyan"), "#FF00FFFF"),
|
||||
(_("Blue"), "#FF0000FF"),
|
||||
(_("Green"), "#FF00FF00"),
|
||||
(_("Magenta"), "#FFEE00EE"),
|
||||
(_("Red"), "#FFFF0000"),
|
||||
(_("Gray"), "#FF808080"),
|
||||
)
|
||||
|
||||
SIZE_LIST = (
|
||||
("Tiny", 50),
|
||||
("Small", 75),
|
||||
("Normal", 100),
|
||||
("Large", 125),
|
||||
("Huge", 200),
|
||||
(_("Tiny"), 50),
|
||||
(_("Small"), 75),
|
||||
(_("Normal"), 100),
|
||||
(_("Large"), 125),
|
||||
(_("Huge"), 200),
|
||||
)
|
||||
|
||||
HEX_TO_COLOR = {v:c for c,v in COLOR_LIST}
|
||||
@ -101,39 +102,39 @@ class OSDMenu(object):
|
||||
if hasattr(player, 'osc'):
|
||||
player.osc = False
|
||||
|
||||
self.menu_title = "Main Menu"
|
||||
self.menu_title = _("Main Menu")
|
||||
self.menu_selection = 0
|
||||
|
||||
if self.playerManager._video and not player.playback_abort:
|
||||
self.menu_list = [
|
||||
("Change Audio", self.change_audio_menu),
|
||||
("Change Subtitles", self.change_subtitle_menu),
|
||||
("Change Video Quality", self.change_transcode_quality),
|
||||
("SyncPlay", self.playerManager.syncplay.menu_action),
|
||||
(_("Change Audio"), self.change_audio_menu),
|
||||
(_("Change Subtitles"), self.change_subtitle_menu),
|
||||
(_("Change Video Quality"), self.change_transcode_quality),
|
||||
(_("SyncPlay"), self.playerManager.syncplay.menu_action),
|
||||
]
|
||||
if self.playerManager.update_check.new_version is not None:
|
||||
self.menu_list.insert(0, (
|
||||
"MPV Shim v{0} Release Info/Download".format(self.playerManager.update_check.new_version),
|
||||
_("MPV Shim v{0} Release Info/Download").format(self.playerManager.update_check.new_version),
|
||||
self.playerManager.update_check.open
|
||||
))
|
||||
if self.profile_menu is not None:
|
||||
self.menu_list.append(("Change Video Playback Profile", self.profile_menu))
|
||||
self.menu_list.append((_("Change Video Playback Profile"), self.profile_menu))
|
||||
if self.playerManager._video.parent.is_tv:
|
||||
self.menu_list.append(("Auto Set Audio/Subtitles (Entire Series)", self.change_tracks_menu))
|
||||
self.menu_list.append(("Quit and Mark Unwatched", self.unwatched_menu_handle))
|
||||
self.menu_list.append((_("Auto Set Audio/Subtitles (Entire Series)"), self.change_tracks_menu))
|
||||
self.menu_list.append((_("Quit and Mark Unwatched"), self.unwatched_menu_handle))
|
||||
if settings.screenshot_menu:
|
||||
self.menu_list.append(("Screenshot", self.screenshot))
|
||||
self.menu_list.append((_("Screenshot"), self.screenshot))
|
||||
else:
|
||||
self.menu_list = []
|
||||
if self.profile_menu is not None:
|
||||
self.menu_list.append(("Video Playback Profiles", self.profile_menu))
|
||||
self.menu_list.append((_("Video Playback Profiles"), self.profile_menu))
|
||||
|
||||
if self.svp_menu is not None and self.svp_menu.is_available():
|
||||
self.menu_list.append(("SVP Settings", self.svp_menu.menu_action))
|
||||
self.menu_list.append((_("SVP Settings"), self.svp_menu.menu_action))
|
||||
|
||||
self.menu_list.extend([
|
||||
("Preferences", self.preferences_menu),
|
||||
("Close Menu", self.hide_menu)
|
||||
(_("Preferences"), self.preferences_menu),
|
||||
(_("Close Menu"), self.hide_menu)
|
||||
])
|
||||
|
||||
self.refresh_menu()
|
||||
@ -211,7 +212,7 @@ class OSDMenu(object):
|
||||
self.menu_action("back")
|
||||
|
||||
def change_audio_menu(self):
|
||||
self.put_menu("Select Audio Track")
|
||||
self.put_menu(_("Select Audio Track"))
|
||||
|
||||
selected_aid = self.playerManager._video.aid
|
||||
audio_streams = [s for s in self.playerManager._video.media_source["MediaStreams"]
|
||||
@ -232,12 +233,12 @@ class OSDMenu(object):
|
||||
self.menu_action("back")
|
||||
|
||||
def change_subtitle_menu(self):
|
||||
self.put_menu("Select Subtitle Track")
|
||||
self.put_menu(_("Select Subtitle Track"))
|
||||
|
||||
selected_sid = self.playerManager._video.sid
|
||||
subtitle_streams = [s for s in self.playerManager._video.media_source["MediaStreams"]
|
||||
if s.get("Type") == "Subtitle"]
|
||||
self.menu_list.append(["None", self.change_subtitle_menu_handle, -1])
|
||||
self.menu_list.append([_("None"), self.change_subtitle_menu_handle, -1])
|
||||
for i, subtitle_track in enumerate(subtitle_streams):
|
||||
sid = subtitle_track.get("Index")
|
||||
self.menu_list.append([
|
||||
@ -263,9 +264,9 @@ class OSDMenu(object):
|
||||
|
||||
def change_transcode_quality(self):
|
||||
handle = self.change_transcode_quality_handle
|
||||
self.put_menu("Select Transcode Quality", [
|
||||
("No Transcode", handle, "none"),
|
||||
("Maximum", handle, "max")
|
||||
self.put_menu(_("Select Transcode Quality"), [
|
||||
(_("No Transcode"), handle, "none"),
|
||||
(_("Maximum"), handle, "max")
|
||||
])
|
||||
|
||||
for item in TRANSCODE_LEVELS:
|
||||
@ -300,10 +301,10 @@ class OSDMenu(object):
|
||||
process_series("manual", self.playerManager, aid, sid)
|
||||
|
||||
def change_tracks_menu(self):
|
||||
self.put_menu("Select Audio/Subtitle for Series", [
|
||||
("English Audio", self.change_tracks_handle, "dubbed"),
|
||||
("Japanese Audio w/ English Subtitles", self.change_tracks_handle, "subbed"),
|
||||
("Manual by Track Index (Less Reliable)", self.change_tracks_manual_s1),
|
||||
self.put_menu(_("Select Audio/Subtitle for Series"), [
|
||||
(_("English Audio"), self.change_tracks_handle, "dubbed"),
|
||||
(_("Japanese Audio w/ English Subtitles"), self.change_tracks_handle, "subbed"),
|
||||
(_("Manual by Track Index (Less Reliable)"), self.change_tracks_manual_s1),
|
||||
])
|
||||
|
||||
def settings_toggle_bool(self):
|
||||
@ -330,7 +331,7 @@ class OSDMenu(object):
|
||||
self.preferences_menu()
|
||||
|
||||
def transcode_settings_menu(self):
|
||||
self.put_menu("Select Default Transcode Profile")
|
||||
self.put_menu(_("Select Default Transcode Profile"))
|
||||
handle = self.transcode_settings_handle
|
||||
|
||||
for i, item in enumerate(TRANSCODE_LEVELS):
|
||||
@ -362,41 +363,41 @@ class OSDMenu(object):
|
||||
self.playerManager.update_subtitle_visuals()
|
||||
|
||||
def subtitle_color_menu(self):
|
||||
self.put_menu("Select Subtitle Color", [
|
||||
self.put_menu(_("Select Subtitle Color"), [
|
||||
(name, self.sub_settings_handle, "subtitle_color", color)
|
||||
for name, color in COLOR_LIST
|
||||
])
|
||||
|
||||
def subtitle_size_menu(self):
|
||||
self.put_menu("Select Subtitle Size", [
|
||||
self.put_menu(_("Select Subtitle Size"), [
|
||||
(name, self.sub_settings_handle, "subtitle_size", size)
|
||||
for name, size in SIZE_LIST
|
||||
], selected=2)
|
||||
|
||||
def subtitle_position_menu(self):
|
||||
self.put_menu("Select Subtitle Position", [
|
||||
("Bottom", self.sub_settings_handle, "subtitle_position", "bottom"),
|
||||
("Top", self.sub_settings_handle, "subtitle_position", "top"),
|
||||
("Middle", self.sub_settings_handle, "subtitle_position", "middle"),
|
||||
self.put_menu(_("Select Subtitle Position"), [
|
||||
(_("Bottom"), self.sub_settings_handle, "subtitle_position", "bottom"),
|
||||
(_("Top"), self.sub_settings_handle, "subtitle_position", "top"),
|
||||
(_("Middle"), self.sub_settings_handle, "subtitle_position", "middle"),
|
||||
])
|
||||
|
||||
def preferences_menu(self):
|
||||
self.put_menu("Preferences", [
|
||||
self.get_settings_toggle("Always Transcode", "always_transcode"),
|
||||
self.get_settings_toggle("Auto Play", "auto_play"),
|
||||
("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 to H264", "transcode_h265"),
|
||||
self.get_settings_toggle("Transcode Hi10p to 8bit", "transcode_hi10p"),
|
||||
self.get_settings_toggle("Direct Paths", "direct_paths"),
|
||||
self.get_settings_toggle("Auto Fullscreen", "fullscreen"),
|
||||
self.get_settings_toggle("Media Key Seek", "media_key_seek"),
|
||||
self.get_settings_toggle("Use Web Seek Pref", "use_web_seek"),
|
||||
self.get_settings_toggle("Display Mirroring", "display_mirroring"),
|
||||
self.get_settings_toggle("Transcode to H265", "transcode_to_h265"),
|
||||
self.get_settings_toggle("Write Logs to File", "write_logs"),
|
||||
self.put_menu(_("Preferences"), [
|
||||
self.get_settings_toggle(_("Always Transcode"), "always_transcode"),
|
||||
self.get_settings_toggle(_("Auto Play"), "auto_play"),
|
||||
(_("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 to H264"), "transcode_h265"),
|
||||
self.get_settings_toggle(_("Transcode Hi10p to 8bit"), "transcode_hi10p"),
|
||||
self.get_settings_toggle(_("Direct Paths"), "direct_paths"),
|
||||
self.get_settings_toggle(_("Auto Fullscreen"), "fullscreen"),
|
||||
self.get_settings_toggle(_("Media Key Seek"), "media_key_seek"),
|
||||
self.get_settings_toggle(_("Use Web Seek Pref"), "use_web_seek"),
|
||||
self.get_settings_toggle(_("Display Mirroring"), "display_mirroring"),
|
||||
self.get_settings_toggle(_("Transcode to H265"), "transcode_to_h265"),
|
||||
self.get_settings_toggle(_("Write Logs to File"), "write_logs"),
|
||||
])
|
||||
|
||||
def unwatched_menu_handle(self):
|
||||
|
526
jellyfin_mpv_shim/messages/base.pot
Normal file
526
jellyfin_mpv_shim/messages/base.pot
Normal file
@ -0,0 +1,526 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2020-08-10 02:57+EDT\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: ENCODING\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
#: jellyfin_mpv_shim/bulk_subtitle.py:20
|
||||
msgid "Selecting Tracks..."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/bulk_subtitle.py:68
|
||||
msgid "{0}: No Subtitles"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/bulk_subtitle.py:97
|
||||
msgid "{0}: Fail"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/bulk_subtitle.py:100
|
||||
msgid "Set Subbed: {0} ok, {1} fail"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/bulk_subtitle.py:103
|
||||
msgid "Set Dubbed: {0} ok, {1} audio only, {2} fail"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/bulk_subtitle.py:106
|
||||
msgid "Manual: {0} ok, {1} fail"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/bulk_subtitle.py:110
|
||||
msgid "Setting Current..."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/clients.py:45
|
||||
msgid "Server URL: "
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/clients.py:46
|
||||
msgid "Username: "
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/clients.py:47
|
||||
msgid "Password: "
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/clients.py:52
|
||||
msgid "Successfully added server."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/clients.py:53
|
||||
msgid "Add another server? [y/N] "
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/clients.py:56
|
||||
msgid "Adding server failed."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/display_mirror/__init__.py:103
|
||||
msgid "Ready to cast"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/display_mirror/__init__.py:104
|
||||
msgid "Select your media in Jellyfin and play it here"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:136
|
||||
msgid "Application Log"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:211 jellyfin_mpv_shim/gui_mgr.py:291
|
||||
msgid "Add Server"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:212
|
||||
msgid ""
|
||||
"Could not add server.\n"
|
||||
"Please check your connection infomation."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:228
|
||||
msgid "Fail"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:228
|
||||
msgid "Ok"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:237
|
||||
msgid "Server Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:260
|
||||
msgid "Server:"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:265
|
||||
msgid "Username:"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:270
|
||||
msgid "Password:"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:293
|
||||
msgid "Remove Server"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:295
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:399
|
||||
msgid "Configure Servers"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:400
|
||||
msgid "Show Console"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:401
|
||||
msgid "Application Menu"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:402
|
||||
msgid "Open Config Folder"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/gui_mgr.py:403
|
||||
msgid "Quit"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/media.py:105
|
||||
msgid " (Transcode)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:28
|
||||
msgid "White"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:29
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:30
|
||||
msgid "Black"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:31
|
||||
msgid "Cyan"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:32
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:33
|
||||
msgid "Green"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:34
|
||||
msgid "Magenta"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:35
|
||||
msgid "Red"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:36
|
||||
msgid "Gray"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:40
|
||||
msgid "Tiny"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:41
|
||||
msgid "Small"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:42
|
||||
msgid "Normal"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:43
|
||||
msgid "Large"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:44
|
||||
msgid "Huge"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:105
|
||||
msgid "Main Menu"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:110
|
||||
msgid "Change Audio"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:111
|
||||
msgid "Change Subtitles"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:112
|
||||
msgid "Change Video Quality"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:113 jellyfin_mpv_shim/syncplay.py:465
|
||||
msgid "SyncPlay"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:117
|
||||
msgid "MPV Shim v{0} Release Info/Download"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:121
|
||||
msgid "Change Video Playback Profile"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:123
|
||||
msgid "Auto Set Audio/Subtitles (Entire Series)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:124
|
||||
msgid "Quit and Mark Unwatched"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:126
|
||||
msgid "Screenshot"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:130
|
||||
msgid "Video Playback Profiles"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:133
|
||||
msgid "SVP Settings"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:136 jellyfin_mpv_shim/menu.py:385
|
||||
msgid "Preferences"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:137
|
||||
msgid "Close Menu"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:215
|
||||
msgid "Select Audio Track"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:236
|
||||
msgid "Select Subtitle Track"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:241
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:267
|
||||
msgid "Select Transcode Quality"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:268
|
||||
msgid "No Transcode"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:269
|
||||
msgid "Maximum"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:304
|
||||
msgid "Select Audio/Subtitle for Series"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:305
|
||||
msgid "English Audio"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:306
|
||||
msgid "Japanese Audio w/ English Subtitles"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:307
|
||||
msgid "Manual by Track Index (Less Reliable)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:334
|
||||
msgid "Select Default Transcode Profile"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:366
|
||||
msgid "Select Subtitle Color"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:372
|
||||
msgid "Select Subtitle Size"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:378
|
||||
msgid "Select Subtitle Position"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:379
|
||||
msgid "Bottom"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:380
|
||||
msgid "Top"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:381
|
||||
msgid "Middle"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:386
|
||||
msgid "Always Transcode"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:387
|
||||
msgid "Auto Play"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:388
|
||||
msgid "Remote Transcode Quality: {0:0.1f} Mbps"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:389
|
||||
msgid "Subtitle Size: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:390
|
||||
msgid "Subtitle Position: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:391
|
||||
msgid "Subtitle Color: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:392
|
||||
msgid "Transcode H265 to H264"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:393
|
||||
msgid "Transcode Hi10p to 8bit"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:394
|
||||
msgid "Direct Paths"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:395
|
||||
msgid "Auto Fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:396
|
||||
msgid "Media Key Seek"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:397
|
||||
msgid "Use Web Seek Pref"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:398
|
||||
msgid "Display Mirroring"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:399
|
||||
msgid "Transcode to H265"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/menu.py:400
|
||||
msgid "Write Logs to File"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/svp_integration.py:36
|
||||
#: jellyfin_mpv_shim/svp_integration.py:48
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/svp_integration.py:136
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/svp_integration.py:144
|
||||
msgid "Select SVP Profile"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/svp_integration.py:147
|
||||
msgid "SVP is Not Active"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/svp_integration.py:148
|
||||
msgid "Disable"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/svp_integration.py:149
|
||||
msgid "Retry"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/svp_integration.py:152
|
||||
msgid "SVP is Disabled"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/svp_integration.py:153
|
||||
msgid "Enable SVP"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:16
|
||||
msgid "The specified SyncPlay group does not exist."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:17
|
||||
msgid "Creating SyncPlay groups is not allowed."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:18
|
||||
msgid "SyncPlay group access was denied."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:19
|
||||
msgid "Access to the SyncPlay library was denied."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:128
|
||||
msgid "SpeedToSync (x{0})"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:138
|
||||
msgid "Sync Disabled (Too Many Attempts)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:146
|
||||
msgid "SkipToSync (x{0})"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:199
|
||||
msgid "SyncPlay enabled."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:218
|
||||
msgid "SyncPlay disabled."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:252
|
||||
msgid "{0} has joined."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:254
|
||||
msgid "{0} has left."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:256
|
||||
msgid "{0} is buffering."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:453 jellyfin_mpv_shim/video_profile.py:149
|
||||
msgid "None (Disabled)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/syncplay.py:457
|
||||
msgid "New Group"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/update_check.py:47
|
||||
msgid ""
|
||||
"MPV Shim v{0} Update Available\n"
|
||||
"Open menu (press c) for details."
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/utils.py:236
|
||||
msgid "Unkn"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/utils.py:237
|
||||
msgid " Forced"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:13
|
||||
msgid "Generic (FSRCNNX)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:14
|
||||
msgid "Generic High (FSRCNNX x16)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:15
|
||||
msgid "Anime4K x4 Faithful (For SD)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:16
|
||||
msgid "Anime4K x4 Perceptual (For SD)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:17
|
||||
msgid "Anime4K x4 Perceptual + Deblur (For SD)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:18
|
||||
msgid "Anime4K x2 Faithful (For HD)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:19
|
||||
msgid "Anime4K x2 Perceptual (For HD)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:20
|
||||
msgid "Anime4K x2 Perceptual + Deblur (For HD)"
|
||||
msgstr ""
|
||||
|
||||
#: jellyfin_mpv_shim/video_profile.py:160
|
||||
msgid "Select Shader Profile"
|
||||
msgstr ""
|
||||
|
@ -7,6 +7,7 @@ import multiprocessing
|
||||
from threading import Event
|
||||
|
||||
from . import conffile
|
||||
from . import i18n
|
||||
from .conf import settings
|
||||
from .clients import clientManager
|
||||
from .constants import APP_NAME
|
||||
@ -20,6 +21,7 @@ logging.getLogger('requests').setLevel(logging.CRITICAL)
|
||||
def main(desktop=False, cef=False):
|
||||
conf_file = conffile.get(APP_NAME, 'conf.json')
|
||||
settings.load(conf_file)
|
||||
i18n.configure()
|
||||
|
||||
if settings.sanitize_output:
|
||||
enable_sanitization()
|
||||
|
@ -1,4 +1,6 @@
|
||||
from .conf import settings
|
||||
from .i18n import _
|
||||
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
import logging
|
||||
@ -12,7 +14,7 @@ def list_request(path):
|
||||
response = urllib.request.urlopen(settings.svp_url + "?" + path)
|
||||
return response.read().decode('utf-8').replace('\r\n', '\n').split('\n')
|
||||
except urllib.error.URLError as ex:
|
||||
log.error("Could not reach SVP API server.", exc_info=1)
|
||||
log.error("Could not reach SVP API server.", exc_info=True)
|
||||
return None
|
||||
|
||||
def simple_request(path):
|
||||
@ -31,7 +33,7 @@ def get_profiles():
|
||||
if profile_id == "predef":
|
||||
continue
|
||||
if profile_id == "P10000001_1001_1001_1001_100000000001":
|
||||
profile_name = "Automatic"
|
||||
profile_name = _("Automatic")
|
||||
else:
|
||||
profile_name = simple_request("profiles.{0}.title".format(profile_id))
|
||||
if simple_request("profiles.{0}.on".format(profile_id)) == "false":
|
||||
@ -43,7 +45,7 @@ def get_profiles():
|
||||
def get_name_from_guid(profile_id):
|
||||
profile_id = "P" + profile_id[1:-1].replace("-", "_")
|
||||
if profile_id == "P10000001_1001_1001_1001_100000000001":
|
||||
return "Automatic"
|
||||
return _("Automatic")
|
||||
else:
|
||||
return simple_request("profiles.{0}.title".format(profile_id))
|
||||
|
||||
@ -55,7 +57,7 @@ def is_svp_alive():
|
||||
response = list_request("")
|
||||
return response is not None
|
||||
except Exception:
|
||||
log.error("Could not reach SVP API server.", exc_info=1)
|
||||
log.error("Could not reach SVP API server.", exc_info=True)
|
||||
return False
|
||||
|
||||
def is_svp_enabled():
|
||||
@ -131,7 +133,7 @@ class SVPManager:
|
||||
selected = 0
|
||||
active_profile = get_last_profile()
|
||||
profile_option_list = [
|
||||
("Disabled", self.menu_set_profile, None)
|
||||
(_("Disabled"), self.menu_set_profile, None)
|
||||
]
|
||||
for i, (profile_id, profile_name) in enumerate(get_profiles().items()):
|
||||
profile_option_list.append(
|
||||
@ -139,14 +141,14 @@ class SVPManager:
|
||||
)
|
||||
if profile_id == active_profile:
|
||||
selected = i+1
|
||||
self.menu.put_menu("Select SVP Profile", profile_option_list, selected)
|
||||
self.menu.put_menu(_("Select SVP Profile"), profile_option_list, selected)
|
||||
else:
|
||||
if is_svp_enabled():
|
||||
self.menu.put_menu("SVP is Not Active", [
|
||||
("Disable", self.menu_set_profile, None),
|
||||
("Retry", self.menu_set_enabled)
|
||||
self.menu.put_menu(_("SVP is Not Active"), [
|
||||
(_("Disable"), self.menu_set_profile, None),
|
||||
(_("Retry"), self.menu_set_enabled)
|
||||
], selected=1)
|
||||
else:
|
||||
self.menu.put_menu("SVP is Disabled", [
|
||||
("Enable SVP", self.menu_set_enabled)
|
||||
self.menu.put_menu(_("SVP is Disabled"), [
|
||||
(_("Enable SVP"), self.menu_set_enabled)
|
||||
])
|
||||
|
@ -3,6 +3,7 @@ import threading
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
from .media import Media
|
||||
from .i18n import _
|
||||
from time import sleep
|
||||
|
||||
# This is based on: https://github.com/jellyfin/jellyfin-web/blob/master/src/components/syncPlay/syncPlayManager.js
|
||||
@ -12,10 +13,10 @@ from .conf import settings
|
||||
log = logging.getLogger('syncplay')
|
||||
seconds_in_ticks = 10000000
|
||||
info_commands = {
|
||||
"GroupDoesNotExist": "The specified SyncPlay group does not exist.",
|
||||
"CreateGroupDenied": "Creating SyncPlay groups is not allowed.",
|
||||
"JoinGroupDenied": "SyncPlay group access was denied.",
|
||||
"LibraryAccessDenied": "Access to the SyncPlay library was denied."
|
||||
"GroupDoesNotExist": _("The specified SyncPlay group does not exist."),
|
||||
"CreateGroupDenied": _("Creating SyncPlay groups is not allowed."),
|
||||
"JoinGroupDenied": _("SyncPlay group access was denied."),
|
||||
"LibraryAccessDenied": _("Access to the SyncPlay library was denied.")
|
||||
}
|
||||
|
||||
|
||||
@ -124,7 +125,7 @@ class SyncPlayManager:
|
||||
self.sync_enabled = False
|
||||
self.attempts += 1
|
||||
log.info("SyncPlay Speed to Sync rate: {0}".format(speed))
|
||||
self.player_message("SpeedToSync (x{0})".format(speed))
|
||||
self.player_message(_("SpeedToSync (x{0})").format(speed))
|
||||
|
||||
def callback():
|
||||
self.player.speed = 1
|
||||
@ -134,7 +135,7 @@ class SyncPlayManager:
|
||||
if self.attempts > settings.sync_attempts:
|
||||
self.sync_enabled = False
|
||||
log.info("SyncPlay Sync Disabled due to too many attempts.")
|
||||
self.player_message("Sync Disabled (Too Many Attempts)")
|
||||
self.player_message(_("Sync Disabled (Too Many Attempts)"))
|
||||
return
|
||||
|
||||
# Skip To Sync Method
|
||||
@ -142,7 +143,7 @@ class SyncPlayManager:
|
||||
self.sync_enabled = False
|
||||
self.attempts += 1
|
||||
log.info("SyncPlay Skip to Sync Activated")
|
||||
self.player_message("SkipToSync (x{0})".format(self.attempts))
|
||||
self.player_message(_("SkipToSync (x{0})").format(self.attempts))
|
||||
|
||||
def callback():
|
||||
self.sync_enabled = True
|
||||
@ -195,7 +196,7 @@ class SyncPlayManager:
|
||||
|
||||
log.info("Syncplay enabled.")
|
||||
if from_server:
|
||||
self.player_message("SyncPlay enabled.")
|
||||
self.player_message(_("SyncPlay enabled."))
|
||||
|
||||
def disable_sync_play(self, from_server):
|
||||
self.player.speed = self.playback_rate
|
||||
@ -214,7 +215,7 @@ class SyncPlayManager:
|
||||
|
||||
log.info("Syncplay disabled.")
|
||||
if from_server:
|
||||
self.player_message("SyncPlay disabled.")
|
||||
self.player_message(_("SyncPlay disabled."))
|
||||
|
||||
# On Buffer
|
||||
def on_buffer(self):
|
||||
@ -248,11 +249,11 @@ class SyncPlayManager:
|
||||
elif command_type == "GroupLeft" or command_type == "NotInGroup":
|
||||
self.disable_sync_play(True)
|
||||
elif command_type == "UserJoined":
|
||||
self.player_message("{0} has joined.".format(command["Data"]))
|
||||
self.player_message(_("{0} has joined.").format(command["Data"]))
|
||||
elif command_type == "UserLeft":
|
||||
self.player_message("{0} has left.".format(command["Data"]))
|
||||
self.player_message(_("{0} has left.").format(command["Data"]))
|
||||
elif command_type == "GroupWait":
|
||||
self.player_message("{0} is buffering.".format(command["Data"]))
|
||||
self.player_message(_("{0} is buffering.").format(command["Data"]))
|
||||
else:
|
||||
log.error("Unknown SyncPlay command {0} payload {1}.".format(command_type, command))
|
||||
|
||||
@ -449,11 +450,11 @@ class SyncPlayManager:
|
||||
selected = 0
|
||||
offset = 1
|
||||
group_option_list = [
|
||||
("None (Disabled)", self.menu_disable, None),
|
||||
(_("None (Disabled)"), self.menu_disable, None),
|
||||
]
|
||||
if not self.is_enabled():
|
||||
offset = 2
|
||||
group_option_list.append(("New Group", self.menu_create_group, None))
|
||||
group_option_list.append((_("New Group"), self.menu_create_group, None))
|
||||
groups = self.client.jellyfin.get_sync_play(self.playerManager._video.item_id)
|
||||
for i, group in enumerate(groups):
|
||||
group_option_list.append(
|
||||
@ -461,4 +462,4 @@ class SyncPlayManager:
|
||||
)
|
||||
if group["GroupId"] == self.current_group:
|
||||
selected = i + offset
|
||||
self.menu.put_menu("SyncPlay", group_option_list, selected)
|
||||
self.menu.put_menu(_("SyncPlay"), group_option_list, selected)
|
||||
|
@ -5,6 +5,7 @@ import webbrowser
|
||||
|
||||
from .constants import CLIENT_VERSION
|
||||
from .conf import settings
|
||||
from .i18n import _
|
||||
log = logging.getLogger("update_check")
|
||||
|
||||
release_url = "https://github.com/iwalton3/jellyfin-mpv-shim/releases/"
|
||||
@ -43,7 +44,7 @@ class UpdateChecker:
|
||||
self.has_notified = True
|
||||
log.info("Update Available: {0}".format(self.new_version))
|
||||
self.playerManager._player.show_text(
|
||||
"MPV Shim v{0} Update Available\nOpen menu (press c) for details.".format(self.new_version),
|
||||
_("MPV Shim v{0} Update Available\nOpen menu (press c) for details.").format(self.new_version),
|
||||
5000, 1
|
||||
)
|
||||
|
||||
|
@ -11,6 +11,7 @@ from .conf import settings
|
||||
from datetime import datetime
|
||||
from functools import wraps
|
||||
from .constants import USER_APP_NAME
|
||||
from .i18n import _
|
||||
|
||||
log = logging.getLogger('utils')
|
||||
|
||||
@ -232,8 +233,8 @@ def get_profile(is_remote=False, video_bitrate=None, force_transcode=False, is_t
|
||||
|
||||
def get_sub_display_title(stream):
|
||||
return "{0}{1} ({2})".format(
|
||||
stream.get("Language", "Unkn").capitalize(),
|
||||
" Forced" if stream.get("IsForced") else "",
|
||||
stream.get("Language", _("Unkn")).capitalize(),
|
||||
_(" Forced") if stream.get("IsForced") else "",
|
||||
stream.get("Codec")
|
||||
)
|
||||
|
||||
|
@ -2,12 +2,24 @@ from .conf import settings
|
||||
from . import conffile
|
||||
from .utils import get_resource
|
||||
from .constants import APP_NAME
|
||||
from .i18n import _
|
||||
import logging
|
||||
import os.path
|
||||
import shutil
|
||||
import json
|
||||
import time
|
||||
|
||||
profile_name_translation = {
|
||||
"Generic (FSRCNNX)": _("Generic (FSRCNNX)"),
|
||||
"Generic High (FSRCNNX x16)": _("Generic High (FSRCNNX x16)"),
|
||||
"Anime4K x4 Faithful (For SD)": _("Anime4K x4 Faithful (For SD)"),
|
||||
"Anime4K x4 Perceptual (For SD)": _("Anime4K x4 Perceptual (For SD)"),
|
||||
"Anime4K x4 Perceptual + Deblur (For SD)": _("Anime4K x4 Perceptual + Deblur (For SD)"),
|
||||
"Anime4K x2 Faithful (For HD)": _("Anime4K x2 Faithful (For HD)"),
|
||||
"Anime4K x2 Perceptual (For HD)": _("Anime4K x2 Perceptual (For HD)"),
|
||||
"Anime4K x2 Perceptual + Deblur (For HD)": _("Anime4K x2 Perceptual + Deblur (For HD)")
|
||||
}
|
||||
|
||||
log = logging.getLogger('video_profile')
|
||||
|
||||
class MPVSettingError(Exception):
|
||||
@ -54,7 +66,7 @@ class VideoProfileManager:
|
||||
try:
|
||||
self.defaults[key] = getattr(self.playerManager._player, key)
|
||||
except Exception:
|
||||
log.warning("Your MPV does not support setting {0} used in shader pack.".format(key), exc_info=1)
|
||||
log.warning("Your MPV does not support setting {0} used in shader pack.".format(key), exc_info=True)
|
||||
|
||||
if settings.shader_pack_profile is not None:
|
||||
self.load_profile(settings.shader_pack_profile, reset=False)
|
||||
@ -102,15 +114,15 @@ class VideoProfileManager:
|
||||
self.current_profile = profile_name
|
||||
return True
|
||||
except MPVSettingError as ex:
|
||||
log.error("Could not apply shader profile.", exc_info=1)
|
||||
log.error("Could not apply shader profile.", exc_info=True)
|
||||
return False
|
||||
|
||||
def unload_profile(self):
|
||||
log.info("Unloading shader profile.")
|
||||
self.playerManager._player.glsl_shaders = []
|
||||
for setting in self.used_settings:
|
||||
value = self.defaults[setting]
|
||||
try:
|
||||
value = self.defaults[setting]
|
||||
setattr(self.playerManager._player, setting, value)
|
||||
except Exception:
|
||||
log.warning("Default setting {0} value {1} is invalid.".format(setting, value))
|
||||
@ -134,12 +146,15 @@ class VideoProfileManager:
|
||||
def menu_action(self):
|
||||
selected = 0
|
||||
profile_option_list = [
|
||||
("None (Disabled)", self.menu_handle, None)
|
||||
(_("None (Disabled)"), self.menu_handle, None)
|
||||
]
|
||||
for i, (profile_name, profile) in enumerate(self.profiles.items()):
|
||||
name = profile["displayname"]
|
||||
if name in profile_name_translation:
|
||||
name = profile_name_translation[name]
|
||||
profile_option_list.append(
|
||||
(profile["displayname"], self.menu_handle, profile_name)
|
||||
(name, self.menu_handle, profile_name)
|
||||
)
|
||||
if profile_name == self.current_profile:
|
||||
selected = i+1
|
||||
self.menu.put_menu("Select Shader Profile", profile_option_list, selected)
|
||||
self.menu.put_menu(_("Select Shader Profile"), profile_option_list, selected)
|
||||
|
Loading…
Reference in New Issue
Block a user