Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
782106e44a | ||
|
|
0e0a8b853f | ||
|
|
8c716130a3 | ||
|
|
dfc9be33d7 | ||
|
|
9b592cf761 | ||
|
|
d3122416cf | ||
|
|
a6af9d856b | ||
|
|
51aaa1f603 | ||
|
|
a71efe14c1 | ||
|
|
1879a8ed01 | ||
|
|
7d6ee45263 | ||
|
|
44ad891242 | ||
|
|
a94575f83c | ||
|
|
1c75b09824 | ||
|
|
ebd59760ae | ||
|
|
3184fa6f89 | ||
|
|
32f2b12708 | ||
|
|
b9a6b5056a | ||
|
|
238d30ab94 | ||
|
|
7d26589cf6 | ||
|
|
10857e39b1 | ||
|
|
30a07327bc | ||
|
|
50f2f1ac3c | ||
|
|
8041a0b9d8 | ||
|
|
d5920a381e | ||
|
|
36b2891353 | ||
|
|
4fa6d7d643 | ||
|
|
90151c2958 | ||
|
|
4133c03759 | ||
|
|
aab694c302 |
144
PATCHES.md
Normal file
144
PATCHES.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# JellyCon Patches
|
||||
|
||||
Diese Patches fügen neue Features und Fixes zu JellyCon hinzu.
|
||||
|
||||
## Patches Übersicht
|
||||
|
||||
### 1. websocket-keepalive-fix.patch (3.1 KB)
|
||||
**Was es behebt:** Session-Flapping Problem (ständige Reconnects alle 2 Minuten)
|
||||
|
||||
**Änderungen:**
|
||||
- Implementiert Jellyfin's ForceKeepAlive/KeepAlive Protokoll
|
||||
- Entfernt problematische `ping_timeout` und `reconnect` Parameter
|
||||
- WebSocketApp wird bei jedem Reconnect neu erstellt (verhindert Memory-Leaks)
|
||||
- Fügt `on_close` Callback hinzu für besseres Debugging
|
||||
|
||||
**Betroffene Dateien:**
|
||||
- `resources/lib/websocket_client.py`
|
||||
|
||||
**Anwendung:**
|
||||
```bash
|
||||
cd plugin.video.jellycon
|
||||
patch -p1 < websocket-keepalive-fix.patch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. transcode-target-codec.patch (4.4 KB)
|
||||
**Was es hinzufügt:** Konfigurierbare Transcode-Ziel-Codecs (H.264, H.265, AV1)
|
||||
|
||||
**Features:**
|
||||
- Neue Dropdown-Option: "Transcode target video codec"
|
||||
- H.264 (default)
|
||||
- H.265 (HEVC) - Perfekt für Raspberry Pi 5!
|
||||
- AV1
|
||||
- Neue Checkbox: "Force transcode h264"
|
||||
- Unabhängige Kontrolle über Quell- und Ziel-Codecs
|
||||
|
||||
**Perfekt für:**
|
||||
- Raspberry Pi 5 (H.265 Hardware-Decode)
|
||||
- Moderne GPUs mit AV1-Unterstützung
|
||||
- Optimierung der Client-Hardware-Beschleunigung
|
||||
|
||||
**Betroffene Dateien:**
|
||||
- `resources/lib/play_utils.py`
|
||||
- `resources/settings.xml`
|
||||
- `resources/language/resource.language.en_gb/strings.po`
|
||||
- `resources/language/resource.language.de/strings.po`
|
||||
|
||||
**Anwendung:**
|
||||
```bash
|
||||
cd plugin.video.jellycon
|
||||
patch -p1 < transcode-target-codec.patch
|
||||
```
|
||||
|
||||
**Konfiguration nach Installation:**
|
||||
```
|
||||
Kodi Settings → Add-ons → JellyCon → Playback
|
||||
|
||||
1. "Transcode target video codec" → H.265 (HEVC)
|
||||
2. "Force transcode h264" → ☑ Aktivieren
|
||||
3. "Force transcode h265" → ☐ Aus
|
||||
|
||||
Ergebnis:
|
||||
- H.264 Content → Server transcodiert zu H.265 → Pi 5 Hardware-Decode
|
||||
- H.265 Content → DirectPlay (Hardware!)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. disable-disk-cache.patch (3.8 KB)
|
||||
**Was es hinzufügt:** Option zum Deaktivieren von Disk-Caching
|
||||
|
||||
**Features:**
|
||||
- Neue Checkbox: "Disable disk caching (RAM only)"
|
||||
- Verhindert Schreiben von `.pickle` Cache-Dateien
|
||||
- Deaktiviert Artwork-Preloading
|
||||
- Daten bleiben nur im RAM
|
||||
|
||||
**Perfekt für:**
|
||||
- SD-Karten (Raspberry Pi) - reduziert Schreibzyklen massiv
|
||||
- Privacy - keine dauerhaften Cache-Dateien
|
||||
- Immer frische Daten vom Server
|
||||
|
||||
**Betroffene Dateien:**
|
||||
- `resources/lib/datamanager.py`
|
||||
- `resources/lib/cache_images.py`
|
||||
- `resources/settings.xml`
|
||||
- `resources/language/resource.language.en_gb/strings.po`
|
||||
- `resources/language/resource.language.de/strings.po`
|
||||
|
||||
**Anwendung:**
|
||||
```bash
|
||||
cd plugin.video.jellycon
|
||||
patch -p1 < disable-disk-cache.patch
|
||||
```
|
||||
|
||||
**Konfiguration nach Installation:**
|
||||
```
|
||||
Kodi Settings → Add-ons → JellyCon → Advanced
|
||||
|
||||
"Disable disk caching (RAM only)" → ☑ Aktivieren
|
||||
```
|
||||
|
||||
**Hinweis:** Kodi's eigener Texture-Cache (`~/.kodi/userdata/Thumbnails/`) läuft weiterhin!
|
||||
|
||||
---
|
||||
|
||||
## Alle Patches auf einmal anwenden
|
||||
|
||||
```bash
|
||||
cd plugin.video.jellycon
|
||||
patch -p1 < websocket-keepalive-fix.patch
|
||||
patch -p1 < transcode-target-codec.patch
|
||||
patch -p1 < disable-disk-cache.patch
|
||||
```
|
||||
|
||||
## Patches rückgängig machen
|
||||
|
||||
```bash
|
||||
cd plugin.video.jellycon
|
||||
patch -p1 -R < websocket-keepalive-fix.patch
|
||||
patch -p1 -R < transcode-target-codec.patch
|
||||
patch -p1 -R < disable-disk-cache.patch
|
||||
```
|
||||
|
||||
## Zusammenfassung der Änderungen
|
||||
|
||||
```
|
||||
7 Dateien geändert, 134 Zeilen hinzugefügt, 15 Zeilen entfernt
|
||||
|
||||
+ resources/lib/websocket_client.py (KeepAlive Fix)
|
||||
+ resources/lib/play_utils.py (Transcode Target)
|
||||
+ resources/lib/datamanager.py (Disk Cache Control)
|
||||
+ resources/lib/cache_images.py (Disk Cache Control)
|
||||
+ resources/settings.xml (Neue Settings)
|
||||
+ resources/language/.../strings.po (Sprachstrings DE+EN)
|
||||
```
|
||||
|
||||
## Getestet mit
|
||||
|
||||
- JellyCon Version: 0.9.0+py3
|
||||
- Kodi Version: Matrix 19+
|
||||
- Jellyfin Server: 10.8+
|
||||
- Raspberry Pi 5 (primärer Use-Case)
|
||||
12
default.py
12
default.py
@@ -8,10 +8,14 @@ from resources.lib.tracking import set_timing_enabled
|
||||
|
||||
log = LazyLogger('default')
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
log_timing_data = settings.getSetting('log_timing') == "true"
|
||||
if log_timing_data:
|
||||
set_timing_enabled(True)
|
||||
try:
|
||||
settings = xbmcaddon.Addon()
|
||||
log_timing_data = settings.getSetting('log_timing') == "true"
|
||||
if log_timing_data:
|
||||
set_timing_enabled(True)
|
||||
except Exception:
|
||||
# During installation/update, addon might not be fully registered yet
|
||||
pass
|
||||
|
||||
log.debug("About to enter mainEntryPoint()")
|
||||
|
||||
|
||||
15
release.yaml
15
release.yaml
@@ -1,19 +1,8 @@
|
||||
version: '0.9.0'
|
||||
version: '0.9.1'
|
||||
changelog: |-
|
||||
:tada: New features and improvements
|
||||
------------------------------------
|
||||
+ Add a page limit setting for tv shows (#393) @mcarlton00
|
||||
+ Add New Widgets (#381) @Aydanill
|
||||
+ Include track details in audio playback (#378) @davembg
|
||||
+ Add segment skip ability (#368) @Gorgorot38
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
+ Fix websocket reconnects (#396) @manuelschneider
|
||||
+ Ensure the filtered limit takes precedence over page limit (#395) @mcarlton00
|
||||
+ fix subtitle burn in (#384) @loztcf
|
||||
+ fix sdh/cc/hi subtitle for jellyfin > v10.9.0 (#385) @AndryYosua
|
||||
+ Fix bug with multiple external subtitles in the same languages (#369) @Gorgorot38
|
||||
+ Implement proper keepalives for websocket (#401) @mcarlton00
|
||||
dependencies:
|
||||
py2:
|
||||
- addon: 'xbmc.python'
|
||||
|
||||
@@ -1233,3 +1233,115 @@ msgstr "Alle – Favoriten"
|
||||
msgctxt "#30678"
|
||||
msgid "TV Shows per page"
|
||||
msgstr "Fernsehsendungen pro Seite"
|
||||
|
||||
msgctxt "#30679"
|
||||
msgid "Transcode Ziel-Video-Codec"
|
||||
msgstr "Transcode Ziel-Video-Codec"
|
||||
|
||||
msgctxt "#30680"
|
||||
msgid "H.264 (Standard)"
|
||||
msgstr "H.264 (Standard)"
|
||||
|
||||
msgctxt "#30681"
|
||||
msgid "H.265 (HEVC)"
|
||||
msgstr "H.265 (HEVC)"
|
||||
|
||||
msgctxt "#30682"
|
||||
msgid "H264 zum Transcoding zwingen"
|
||||
msgstr "H264 zum Transcoding zwingen"
|
||||
|
||||
msgctxt "#30683"
|
||||
msgid "AV1"
|
||||
msgstr "AV1"
|
||||
|
||||
msgctxt "#30684"
|
||||
msgid "Disk-Caching deaktivieren (nur RAM)"
|
||||
msgstr "Disk-Caching deaktivieren (nur RAM)"
|
||||
|
||||
msgctxt "#30685"
|
||||
msgid "Audio- & Untertitel-Einstellungen"
|
||||
msgstr "Audio- & Untertitel-Einstellungen"
|
||||
|
||||
msgctxt "#30686"
|
||||
msgid "Bevorzugte Audio-Sprache"
|
||||
msgstr "Bevorzugte Audio-Sprache"
|
||||
|
||||
msgctxt "#30687"
|
||||
msgid "Standard-Audiospur automatisch wählen"
|
||||
msgstr "Standard-Audiospur automatisch wählen"
|
||||
|
||||
msgctxt "#30688"
|
||||
msgid "Bevorzugte Untertitel-Sprache"
|
||||
msgstr "Bevorzugte Untertitel-Sprache"
|
||||
|
||||
msgctxt "#30689"
|
||||
msgid "Forced-Untertitel bevorzugen"
|
||||
msgstr "Forced-Untertitel bevorzugen"
|
||||
|
||||
msgctxt "#30690"
|
||||
msgid "SRT vor PGS/Bild-Untertiteln bevorzugen"
|
||||
msgstr "SRT vor PGS/Bild-Untertiteln bevorzugen"
|
||||
|
||||
msgctxt "#30691"
|
||||
msgid "Deutsch"
|
||||
msgstr "Deutsch"
|
||||
|
||||
msgctxt "#30692"
|
||||
msgid "Englisch"
|
||||
msgstr "Englisch"
|
||||
|
||||
msgctxt "#30693"
|
||||
msgid "Französisch"
|
||||
msgstr "Französisch"
|
||||
|
||||
msgctxt "#30694"
|
||||
msgid "Spanisch"
|
||||
msgstr "Spanisch"
|
||||
|
||||
msgctxt "#30695"
|
||||
msgid "Italienisch"
|
||||
msgstr "Italienisch"
|
||||
|
||||
msgctxt "#30696"
|
||||
msgid "Japanisch"
|
||||
msgstr "Japanisch"
|
||||
|
||||
msgctxt "#30697"
|
||||
msgid "Russisch"
|
||||
msgstr "Russisch"
|
||||
|
||||
msgctxt "#30698"
|
||||
msgid "Andere"
|
||||
msgstr "Andere"
|
||||
|
||||
msgctxt "#30699"
|
||||
msgid "Keine (nur Audio-Sprache)"
|
||||
msgstr "Keine (nur Audio-Sprache)"
|
||||
|
||||
msgctxt "#30700"
|
||||
msgid "Bei keinem Treffer automatisch 'Keine Untertitel' wählen"
|
||||
msgstr "Bei keinem Treffer automatisch 'Keine Untertitel' wählen"
|
||||
|
||||
msgctxt "#30701"
|
||||
msgid "Abspielen mit Track-Auswahl"
|
||||
msgstr "Abspielen mit Track-Auswahl"
|
||||
|
||||
msgctxt "#30702"
|
||||
msgid "Nur Forced-Untertitel auswählen (keine normalen)"
|
||||
msgstr "Nur Forced-Untertitel auswählen (keine normalen)"
|
||||
|
||||
msgctxt "#30703"
|
||||
msgid "Untertitel-Codec-Präferenz"
|
||||
msgstr "Untertitel-Codec-Präferenz"
|
||||
|
||||
msgctxt "#30704"
|
||||
msgid "PGS bevorzugt (bessere Qualität beim Brennen)"
|
||||
msgstr "PGS bevorzugt (bessere Qualität beim Brennen)"
|
||||
|
||||
msgctxt "#30705"
|
||||
msgid "SRT bevorzugt (flexibel, kann gestreamt werden)"
|
||||
msgstr "SRT bevorzugt (flexibel, kann gestreamt werden)"
|
||||
|
||||
msgctxt "#30706"
|
||||
msgid "Keine Präferenz"
|
||||
msgstr "Keine Präferenz"
|
||||
|
||||
@@ -1224,3 +1224,115 @@ msgstr "Recap Skipper"
|
||||
msgctxt "#30678"
|
||||
msgid "TV Shows per page"
|
||||
msgstr "TV Shows per page"
|
||||
|
||||
msgctxt "#30679"
|
||||
msgid "Transcode target video codec"
|
||||
msgstr "Transcode target video codec"
|
||||
|
||||
msgctxt "#30680"
|
||||
msgid "H.264 (default)"
|
||||
msgstr "H.264 (default)"
|
||||
|
||||
msgctxt "#30681"
|
||||
msgid "H.265 (HEVC)"
|
||||
msgstr "H.265 (HEVC)"
|
||||
|
||||
msgctxt "#30682"
|
||||
msgid "Force transcode h264"
|
||||
msgstr "Force transcode h264"
|
||||
|
||||
msgctxt "#30683"
|
||||
msgid "AV1"
|
||||
msgstr "AV1"
|
||||
|
||||
msgctxt "#30684"
|
||||
msgid "Disable disk caching (RAM only)"
|
||||
msgstr "Disable disk caching (RAM only)"
|
||||
|
||||
msgctxt "#30685"
|
||||
msgid "Audio & Subtitle Preferences"
|
||||
msgstr "Audio & Subtitle Preferences"
|
||||
|
||||
msgctxt "#30686"
|
||||
msgid "Preferred audio language"
|
||||
msgstr "Preferred audio language"
|
||||
|
||||
msgctxt "#30687"
|
||||
msgid "Auto-select default audio track"
|
||||
msgstr "Auto-select default audio track"
|
||||
|
||||
msgctxt "#30688"
|
||||
msgid "Preferred subtitle language"
|
||||
msgstr "Preferred subtitle language"
|
||||
|
||||
msgctxt "#30689"
|
||||
msgid "Prefer forced subtitles"
|
||||
msgstr "Prefer forced subtitles"
|
||||
|
||||
msgctxt "#30690"
|
||||
msgid "Prefer SRT over PGS/image subtitles"
|
||||
msgstr "Prefer SRT over PGS/image subtitles"
|
||||
|
||||
msgctxt "#30691"
|
||||
msgid "German"
|
||||
msgstr "German"
|
||||
|
||||
msgctxt "#30692"
|
||||
msgid "English"
|
||||
msgstr "English"
|
||||
|
||||
msgctxt "#30693"
|
||||
msgid "French"
|
||||
msgstr "French"
|
||||
|
||||
msgctxt "#30694"
|
||||
msgid "Spanish"
|
||||
msgstr "Spanish"
|
||||
|
||||
msgctxt "#30695"
|
||||
msgid "Italian"
|
||||
msgstr "Italian"
|
||||
|
||||
msgctxt "#30696"
|
||||
msgid "Japanese"
|
||||
msgstr "Japanese"
|
||||
|
||||
msgctxt "#30697"
|
||||
msgid "Russian"
|
||||
msgstr "Russian"
|
||||
|
||||
msgctxt "#30698"
|
||||
msgid "Other"
|
||||
msgstr "Other"
|
||||
|
||||
msgctxt "#30699"
|
||||
msgid "None (audio language only)"
|
||||
msgstr "None (audio language only)"
|
||||
|
||||
msgctxt "#30700"
|
||||
msgid "Auto-select 'No subtitles' if no match found"
|
||||
msgstr "Auto-select 'No subtitles' if no match found"
|
||||
|
||||
msgctxt "#30701"
|
||||
msgid "Play with track selection"
|
||||
msgstr "Play with track selection"
|
||||
|
||||
msgctxt "#30702"
|
||||
msgid "Only select forced subtitles (no regular subs)"
|
||||
msgstr "Only select forced subtitles (no regular subs)"
|
||||
|
||||
msgctxt "#30703"
|
||||
msgid "Subtitle codec preference"
|
||||
msgstr "Subtitle codec preference"
|
||||
|
||||
msgctxt "#30704"
|
||||
msgid "Prefer PGS (better quality when burned)"
|
||||
msgstr "Prefer PGS (better quality when burned)"
|
||||
|
||||
msgctxt "#30705"
|
||||
msgid "Prefer SRT (flexible, can be streamed)"
|
||||
msgstr "Prefer SRT (flexible, can be streamed)"
|
||||
|
||||
msgctxt "#30706"
|
||||
msgid "No preference"
|
||||
msgstr "No preference"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2025-12-23 08:05+0000\n"
|
||||
"PO-Revision-Date: 2026-01-05 12:25+0000\n"
|
||||
"Last-Translator: rimasx <riks_12@hot.ee>\n"
|
||||
"Language-Team: Estonian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/et/>\n"
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.14\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
@@ -73,7 +73,7 @@ msgstr "Port"
|
||||
|
||||
msgctxt "#30366"
|
||||
msgid "Manually enter user details"
|
||||
msgstr "Sisesta kasutaja andmed käsitsi"
|
||||
msgstr "Sisesta kasutajaandmed käsitsi"
|
||||
|
||||
msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
@@ -141,11 +141,11 @@ msgstr "- Albumi esitajad"
|
||||
|
||||
msgctxt "#30319"
|
||||
msgid "Music - All Album Artists"
|
||||
msgstr "Muusika – kõik albumi esitajad"
|
||||
msgstr "Muusika - Kõik albumi esitajad"
|
||||
|
||||
msgctxt "#30352"
|
||||
msgid "Music - Frequently Played"
|
||||
msgstr "Muusika – Sageli esitatud"
|
||||
msgstr "Muusika - Sageli esitatud"
|
||||
|
||||
msgctxt "#30327"
|
||||
msgid "Go To Season"
|
||||
@@ -161,11 +161,11 @@ msgstr "Episoodid - Viimati lisatud"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "Filmid – Viimati lisatud"
|
||||
msgstr "Filmid - Viimati lisatud"
|
||||
|
||||
msgctxt "#30349"
|
||||
msgid " - Recently Played"
|
||||
msgstr "- viimati esitatud"
|
||||
msgstr "- Viimati esitatud"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
@@ -173,11 +173,11 @@ msgstr "- Viimati lisatud"
|
||||
|
||||
msgctxt "#30351"
|
||||
msgid "Music - Recently Played"
|
||||
msgstr "Muusika – viimati esitatud"
|
||||
msgstr "Muusika - Viimati esitatud"
|
||||
|
||||
msgctxt "#30350"
|
||||
msgid "Music - Recently Added"
|
||||
msgstr "Muusika – Viimati lisatud"
|
||||
msgstr "Muusika - Viimati lisatud"
|
||||
|
||||
msgctxt "#30348"
|
||||
msgid "Add user ratings"
|
||||
@@ -245,7 +245,7 @@ msgstr "Filme lehel"
|
||||
|
||||
msgctxt "#30330"
|
||||
msgid "Show change user dialog"
|
||||
msgstr "Kuva kasutaja vahetamise dialoog"
|
||||
msgstr "Kuva kasutaja vahetamise aken"
|
||||
|
||||
msgctxt "#30329"
|
||||
msgid "Screensaver"
|
||||
@@ -269,7 +269,7 @@ msgstr "- Albumid"
|
||||
|
||||
msgctxt "#30318"
|
||||
msgid "Music - Albums"
|
||||
msgstr "Muusika – Albumid"
|
||||
msgstr "Muusika - Albumid"
|
||||
|
||||
msgctxt "#30317"
|
||||
msgid "Play All"
|
||||
@@ -281,7 +281,7 @@ msgstr "Ühenduse viga"
|
||||
|
||||
msgctxt "#30315"
|
||||
msgid "Suppress notifications for connection errors"
|
||||
msgstr "Lülita ühenduse veateavitused välja"
|
||||
msgstr "Peida ühenduse veateavitused"
|
||||
|
||||
msgctxt "#30314"
|
||||
msgid "Play"
|
||||
@@ -305,7 +305,7 @@ msgstr "Luba Jellyfini kaugjuhtimine"
|
||||
|
||||
msgctxt "#30309"
|
||||
msgid "Select Media Source"
|
||||
msgstr "Vali meedia allikas"
|
||||
msgstr "Vali meediaallikas"
|
||||
|
||||
msgctxt "#30308"
|
||||
msgid "Select Trailer"
|
||||
@@ -417,7 +417,7 @@ msgstr "Värskenda puhverdatud pilte"
|
||||
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
msgstr "Puuduv pealkiri"
|
||||
msgstr "Puuduv nimetus"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
@@ -431,7 +431,7 @@ msgctxt "#30277"
|
||||
msgid "JellyCon needs to prompt for resume on partily played items, Kodi can also prompt, this can cause a double prompt. Do you want to remove the double prompt?"
|
||||
msgstr ""
|
||||
"JellyCon peab küsima jätkamist osaliselt esitatud üksuste puhul. Kodi võib "
|
||||
"samuti küsida ja see võib põhjustada päringu. Kas soovid topeltpäringu "
|
||||
"samuti küsida ja see võib põhjustada topeltpäringu. Kas soovid topeltpäringu "
|
||||
"eemaldada?"
|
||||
|
||||
msgctxt "#30276"
|
||||
@@ -460,7 +460,7 @@ msgstr "Märgi vaadatuks"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "Filmid – Juhuslikud"
|
||||
msgstr "Filmid - Juhuslikud"
|
||||
|
||||
msgctxt "#30267"
|
||||
msgid " - In Progress"
|
||||
@@ -468,7 +468,7 @@ msgstr "- Pooleli"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
msgstr "Filmid – Lehed"
|
||||
msgstr "Filmid - Lehed"
|
||||
|
||||
msgctxt "#30265"
|
||||
msgid "Episodes - Next Up"
|
||||
@@ -492,11 +492,11 @@ msgstr "Kogumikud"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "Filmid – Lemmikud"
|
||||
msgstr "Filmid - Lemmikud"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "Filmid – Pooleli"
|
||||
msgstr "Filmid - Pooleli"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
@@ -508,7 +508,7 @@ msgstr "Sarjad - A-Ü"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
msgstr "Kuva lisamooduli seaded"
|
||||
msgstr "Lisamooduli seaded"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
@@ -516,7 +516,7 @@ msgstr "Filmid - A-Ü"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "Filmid – Žanrid"
|
||||
msgstr "Filmid - Žanrid"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
@@ -604,7 +604,7 @@ msgstr "HTTP otsevoog"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Serveri aadress"
|
||||
msgstr "Server"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
@@ -676,7 +676,7 @@ msgstr "Tehtud"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "Jätkamisel"
|
||||
msgstr "Taasesituse jätkamisel"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
@@ -684,7 +684,7 @@ msgstr "Kuva laadimise edenemine"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "Lisa nimedele vaatamata arv"
|
||||
msgstr "Lisa nimedele vaatamata episoodide arv"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
@@ -716,7 +716,7 @@ msgstr "Hoiatus: see toiming kustutab meediafailid serverist."
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "Kas kinnitada kustutamine?"
|
||||
msgstr "Kas kustutamine kinnitada?"
|
||||
|
||||
msgctxt "#30063"
|
||||
msgid "N/A"
|
||||
@@ -744,7 +744,7 @@ msgstr "Luba silumislogimine"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "Vidina toiming üksuse valikul"
|
||||
msgstr "Toiming vidina elemendi valimisel"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
@@ -768,7 +768,7 @@ msgstr "Filtreeritud episoodi nime vorming"
|
||||
|
||||
msgctxt "#30213"
|
||||
msgid "Video force 8 bit"
|
||||
msgstr "Sunni 8 bit video"
|
||||
msgstr "Sunni 8 bitine video"
|
||||
|
||||
msgctxt "#30368"
|
||||
msgid "Clear Password?"
|
||||
@@ -780,7 +780,7 @@ msgstr "Kohalike serverite skaneerimine"
|
||||
|
||||
msgctxt "#30376"
|
||||
msgid "Checking server url"
|
||||
msgstr "Serveri URL-i kontrollimine"
|
||||
msgstr "Serveri URL-i kontroll"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
@@ -824,7 +824,7 @@ msgstr "Süsteem -"
|
||||
|
||||
msgctxt "#30225"
|
||||
msgid "Interface Mode"
|
||||
msgstr "Kasutajaliidese režiim"
|
||||
msgstr "Kasutajaliidese olek"
|
||||
|
||||
msgctxt "#30226"
|
||||
msgid "Default"
|
||||
@@ -856,7 +856,7 @@ msgstr "Päringu saatmine"
|
||||
|
||||
msgctxt "#30375"
|
||||
msgid "Receiving data packet"
|
||||
msgstr "Andmepaketi vastuvõtmine"
|
||||
msgstr "Andmepaketi vastuvõtt"
|
||||
|
||||
msgctxt "#30378"
|
||||
msgid "Persist user details"
|
||||
@@ -864,7 +864,7 @@ msgstr "Säilita kasutajaandmed"
|
||||
|
||||
msgctxt "#30379"
|
||||
msgid "External subtitle prompt"
|
||||
msgstr "Väliste subtiitrite pakkumine"
|
||||
msgstr "Paku väliseid subtiitreid"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
@@ -1152,7 +1152,7 @@ msgstr "Kordusvaatamise päevad (0 = keelatud)"
|
||||
|
||||
msgctxt "#30453"
|
||||
msgid "Hide number of items to show on entry title"
|
||||
msgstr "Peida pealkirjas kuvatavate üksuste arv"
|
||||
msgstr "Peida kuvatavate üksuste arv avalehel"
|
||||
|
||||
msgctxt "#30455"
|
||||
msgid "TV Shows - Random"
|
||||
@@ -1173,3 +1173,51 @@ msgstr "Kõik - Lemmikud"
|
||||
msgctxt "#30678"
|
||||
msgid "TV Shows per page"
|
||||
msgstr "Sarjade arv lehel"
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
msgstr "Ära kuva üksikut hooaega"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
msgstr "Interaktsioon"
|
||||
|
||||
msgctxt "#30430"
|
||||
msgid "Label"
|
||||
msgstr "Silt"
|
||||
|
||||
msgctxt "#30438"
|
||||
msgid "Play cinema intros"
|
||||
msgstr "Esita filmi intro"
|
||||
|
||||
msgctxt "#30666"
|
||||
msgid "Segment Skipper"
|
||||
msgstr "Segmendi vahelejätja"
|
||||
|
||||
msgctxt "#30670"
|
||||
msgid "Intro Skipper"
|
||||
msgstr "Sissejuhatuse vahelejätja"
|
||||
|
||||
msgctxt "#30671"
|
||||
msgid "Credit Skipper"
|
||||
msgstr "Lõputiitrite vahelejätja"
|
||||
|
||||
msgctxt "#30675"
|
||||
msgid "Commercial Skipper"
|
||||
msgstr "Reklaamide vahelejätja"
|
||||
|
||||
msgctxt "#30676"
|
||||
msgid "Preview Skipper"
|
||||
msgstr "Eelvaatuse vahelejätja"
|
||||
|
||||
msgctxt "#30677"
|
||||
msgid "Recap Skipper"
|
||||
msgstr "Kokkuvõtte vahelejätja"
|
||||
|
||||
msgctxt "#30421"
|
||||
msgid "Views"
|
||||
msgstr "Vaated"
|
||||
|
||||
msgctxt "#30450"
|
||||
msgid "Next Up Rewatching"
|
||||
msgstr "Järgmisena kordusvaatamisel"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2025-07-21 20:37+0000\n"
|
||||
"Last-Translator: czlevi7 <czlevi7@gmail.com>\n"
|
||||
"PO-Revision-Date: 2026-01-04 21:05+0000\n"
|
||||
"Last-Translator: Levente Suli <suli.levente.07@icloud.com>\n"
|
||||
"Language-Team: Hungarian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/hu/>\n"
|
||||
"Language: hu\n"
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.11.4\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
|
||||
msgctxt "#30441"
|
||||
msgid "Use cached widget data"
|
||||
@@ -1086,7 +1086,7 @@ msgstr "Port"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Gazda"
|
||||
msgstr "Gazdagép"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
@@ -1207,3 +1207,23 @@ msgstr "Kérdezz"
|
||||
msgctxt "#30677"
|
||||
msgid "Recap Skipper"
|
||||
msgstr "Összefoglaló átugró"
|
||||
|
||||
msgctxt "#30455"
|
||||
msgid "TV Shows - Random"
|
||||
msgstr "TV Műsorok - Véletlenszerű"
|
||||
|
||||
msgctxt "#30456"
|
||||
msgid "All - Random"
|
||||
msgstr "Összes - Véletlenszerű"
|
||||
|
||||
msgctxt "#30457"
|
||||
msgid "All - Recently Added"
|
||||
msgstr "Összes - Nemrég hozzáadott"
|
||||
|
||||
msgctxt "#30458"
|
||||
msgid "All - Favorites"
|
||||
msgstr "Összes - Kedvencek"
|
||||
|
||||
msgctxt "#30678"
|
||||
msgid "TV Shows per page"
|
||||
msgstr "TV Műsorok oldalanként"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2025-06-28 11:51+0000\n"
|
||||
"Last-Translator: Nirwan <ny.unpar@gmail.com>\n"
|
||||
"PO-Revision-Date: 2026-01-05 12:25+0000\n"
|
||||
"Last-Translator: daryhanif <daryhanif00@gmail.com>\n"
|
||||
"Language-Team: Indonesian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/id/>\n"
|
||||
"Language: id\n"
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 5.11.4\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
@@ -1206,3 +1206,8 @@ msgstr "Lewatkan"
|
||||
msgctxt "#30677"
|
||||
msgid "Recap Skipper"
|
||||
msgstr "Lewati Rekap"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30457"
|
||||
msgid "All - Recently Added"
|
||||
msgstr "Semua - Baru-Baru ini ditambahkan"
|
||||
|
||||
@@ -41,6 +41,13 @@ class CacheArtwork(threading.Thread):
|
||||
last_update = 0
|
||||
home_window = HomeWindow()
|
||||
settings = xbmcaddon.Addon()
|
||||
|
||||
# Check if disk caching is disabled
|
||||
disable_disk_cache = settings.getSetting('disable_disk_cache') == 'true'
|
||||
if disable_disk_cache:
|
||||
log.debug("CacheArtwork : Disk caching disabled, artwork caching skipped")
|
||||
return
|
||||
|
||||
latest_content_hash = "never"
|
||||
check_interval = int(settings.getSetting('cacheImagesOnScreenSaver_interval'))
|
||||
check_interval = check_interval * 60
|
||||
|
||||
@@ -54,6 +54,13 @@ class DataManager:
|
||||
log.debug("last_content_url : use_cache={0} url={1}".format(use_cache, url))
|
||||
home_window.set_property("last_content_url", url)
|
||||
|
||||
# Check if disk caching is disabled
|
||||
settings = xbmcaddon.Addon()
|
||||
disable_disk_cache = settings.getSetting('disable_disk_cache') == 'true'
|
||||
if disable_disk_cache:
|
||||
use_cache = False
|
||||
log.debug("Disk caching disabled - data will be kept in RAM only")
|
||||
|
||||
user_id = self.user_details.get('user_id')
|
||||
server = self.api.server
|
||||
|
||||
@@ -164,6 +171,13 @@ class CacheManagerThread(threading.Thread):
|
||||
log.debug("CacheManagerThread : Started")
|
||||
|
||||
home_window = HomeWindow()
|
||||
settings = xbmcaddon.Addon()
|
||||
disable_disk_cache = settings.getSetting('disable_disk_cache') == 'true'
|
||||
|
||||
if disable_disk_cache:
|
||||
log.debug("CacheManagerThread : Disk caching disabled, skipping cache operations")
|
||||
return
|
||||
|
||||
is_fresh = False
|
||||
|
||||
# if the data is fresh then just save it
|
||||
|
||||
@@ -41,16 +41,22 @@ from .tracking import timer
|
||||
from .skin_cloner import clone_default_skin
|
||||
from .play_utils import play_file
|
||||
|
||||
__addon__ = xbmcaddon.Addon()
|
||||
__addondir__ = translate_path(__addon__.getAddonInfo('profile'))
|
||||
__cwd__ = __addon__.getAddonInfo('path')
|
||||
PLUGINPATH = translate_path(os.path.join(__cwd__))
|
||||
addon_id = __addon__.getAddonInfo('id')
|
||||
try:
|
||||
__addon__ = xbmcaddon.Addon()
|
||||
__addondir__ = translate_path(__addon__.getAddonInfo('profile'))
|
||||
__cwd__ = __addon__.getAddonInfo('path')
|
||||
PLUGINPATH = translate_path(os.path.join(__cwd__))
|
||||
addon_id = __addon__.getAddonInfo('id')
|
||||
except Exception:
|
||||
# During installation/update, addon might not be fully registered yet
|
||||
__addon__ = None
|
||||
__addondir__ = ''
|
||||
__cwd__ = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
PLUGINPATH = __cwd__
|
||||
addon_id = 'plugin.video.jellycon'
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
user_details = load_user_details()
|
||||
|
||||
|
||||
@timer
|
||||
def main_entry_point():
|
||||
@@ -119,7 +125,8 @@ def main_entry_point():
|
||||
elif mode == "CLONE_SKIN":
|
||||
clone_default_skin()
|
||||
elif mode == "SHOW_SETTINGS":
|
||||
__addon__.openSettings()
|
||||
addon = xbmcaddon.Addon()
|
||||
addon.openSettings()
|
||||
window = xbmcgui.getCurrentWindowId()
|
||||
if window == 10000:
|
||||
log.debug(
|
||||
@@ -343,6 +350,12 @@ def show_menu(params):
|
||||
li.setProperty('menu_id', 'play')
|
||||
action_items.append(li)
|
||||
|
||||
# Add "Play with track selection" for Movies and Episodes
|
||||
if result["Type"] in ["Episode", "Movie"]:
|
||||
li = xbmcgui.ListItem(translate_string(30701), offscreen=True)
|
||||
li.setProperty('menu_id', 'play_with_track_selection')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["Season", "MusicArtist", "MusicAlbum", "Playlist",
|
||||
"MusicGenre"]:
|
||||
li = xbmcgui.ListItem(translate_string(30317), offscreen=True)
|
||||
@@ -473,6 +486,11 @@ def show_menu(params):
|
||||
log.debug("Play Item")
|
||||
play_action(params)
|
||||
|
||||
elif selected_action == "play_with_track_selection":
|
||||
log.debug("Play Item with Track Selection")
|
||||
params["force_track_selection"] = "true"
|
||||
play_action(params)
|
||||
|
||||
elif selected_action == "set_view":
|
||||
log.debug("Setting view type for {0} to {1}".format(
|
||||
view_key, container_view_id)
|
||||
@@ -923,6 +941,9 @@ def play_action(params):
|
||||
audio_stream_index = params.get("audio_stream_index")
|
||||
log.debug("audio_stream_index: {0}".format(audio_stream_index))
|
||||
|
||||
force_track_selection = params.get("force_track_selection", "false") == "true"
|
||||
log.debug("force_track_selection: {0}".format(force_track_selection))
|
||||
|
||||
action = params.get("action", "play")
|
||||
|
||||
# set the current playing item id
|
||||
@@ -939,6 +960,7 @@ def play_action(params):
|
||||
play_info["media_source_id"] = media_source_id
|
||||
play_info["subtitle_stream_index"] = subtitle_stream_index
|
||||
play_info["audio_stream_index"] = audio_stream_index
|
||||
play_info["force_track_selection"] = force_track_selection
|
||||
log.info("Sending jellycon_play_action : {0}".format(play_info))
|
||||
play_file(play_info)
|
||||
|
||||
@@ -948,7 +970,8 @@ def play_item_trailer(item_id):
|
||||
handle = int(sys.argv[1]) if sys.argv and len(sys.argv) > 1 else -1
|
||||
if handle != -1:
|
||||
xbmcplugin.endOfDirectory(handle, succeeded=False, updateListing=False, cacheToDisc=False)
|
||||
|
||||
|
||||
user_details = load_user_details()
|
||||
url = "/Users/{}/Items/{}/LocalTrailers?format=json".format(
|
||||
user_details.get('user_id'), item_id
|
||||
)
|
||||
|
||||
@@ -11,7 +11,6 @@ import xbmcaddon
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
addon = xbmcaddon.Addon()
|
||||
|
||||
|
||||
class HomeWindow:
|
||||
@@ -41,6 +40,7 @@ def add_menu_directory_item(label, path, folder=True, art=None, properties=None)
|
||||
li = xbmcgui.ListItem(label, path=path, offscreen=True)
|
||||
if art is None:
|
||||
art = {}
|
||||
addon = xbmcaddon.Addon()
|
||||
art["thumb"] = addon.getAddonInfo('icon')
|
||||
if properties is not None:
|
||||
li.setProperties(properties)
|
||||
|
||||
@@ -12,8 +12,13 @@ from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
from .utils import translate_path
|
||||
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellycon')
|
||||
__pluginpath__ = translate_path(__addon__.getAddonInfo('path'))
|
||||
try:
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellycon')
|
||||
__pluginpath__ = translate_path(__addon__.getAddonInfo('path'))
|
||||
except Exception:
|
||||
# During installation/update, addon might not be fully registered yet
|
||||
__addon__ = None
|
||||
__pluginpath__ = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
def getLogger(name=None):
|
||||
@@ -32,27 +37,36 @@ class LogHandler(logging.StreamHandler):
|
||||
|
||||
self.sensitive = {'Token': [], 'Server': []}
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
self.server = settings.getSetting('server_address')
|
||||
self.debug = settings.getSetting('log_debug')
|
||||
try:
|
||||
settings = xbmcaddon.Addon()
|
||||
self.server = settings.getSetting('server_address')
|
||||
self.debug = settings.getSetting('log_debug')
|
||||
except Exception:
|
||||
# During installation/update, settings might not be available yet
|
||||
self.server = ''
|
||||
self.debug = 'false'
|
||||
|
||||
def emit(self, record):
|
||||
|
||||
if self._get_log_level(record.levelno):
|
||||
string = self.format(record)
|
||||
try:
|
||||
string = self.format(record)
|
||||
|
||||
# Hide server URL in logs
|
||||
string = string.replace(
|
||||
self.server or "{server}", "{jellyfin-server}"
|
||||
)
|
||||
# Hide server URL in logs
|
||||
string = string.replace(
|
||||
self.server or "{server}", "{jellyfin-server}"
|
||||
)
|
||||
|
||||
py_version = sys.version_info.major
|
||||
# Log level notation changed in Kodi v19
|
||||
if py_version > 2:
|
||||
log_level = xbmc.LOGINFO
|
||||
else:
|
||||
log_level = xbmc.LOGNOTICE
|
||||
xbmc.log(string, level=log_level)
|
||||
py_version = sys.version_info.major
|
||||
# Log level notation changed in Kodi v19
|
||||
if py_version > 2:
|
||||
log_level = xbmc.LOGINFO
|
||||
else:
|
||||
log_level = xbmc.LOGNOTICE
|
||||
xbmc.log(string, level=log_level)
|
||||
except Exception:
|
||||
# Silently fail if logging is disabled globally in Kodi
|
||||
pass
|
||||
|
||||
def _get_log_level(self, level):
|
||||
|
||||
@@ -92,13 +106,16 @@ class MyFormatter(logging.Formatter):
|
||||
return result
|
||||
|
||||
def formatException(self, exc_info):
|
||||
_pluginpath_real = os.path.realpath(__pluginpath__)
|
||||
try:
|
||||
_pluginpath_real = os.path.realpath(__pluginpath__)
|
||||
except Exception:
|
||||
_pluginpath_real = None
|
||||
res = []
|
||||
|
||||
for o in traceback.format_exception(*exc_info):
|
||||
o = ensure_text(o, get_filesystem_encoding())
|
||||
|
||||
if o.startswith(' File "'):
|
||||
if _pluginpath_real and o.startswith(' File "'):
|
||||
"""
|
||||
If this split can't handle your file names,
|
||||
you should seriously consider renaming your files.
|
||||
@@ -114,7 +131,10 @@ class MyFormatter(logging.Formatter):
|
||||
|
||||
def _gen_rel_path(self, record):
|
||||
if record.pathname:
|
||||
record.relpath = os.path.relpath(record.pathname, __pluginpath__)
|
||||
try:
|
||||
record.relpath = os.path.relpath(record.pathname, __pluginpath__)
|
||||
except Exception:
|
||||
record.relpath = record.pathname
|
||||
|
||||
|
||||
def get_filesystem_encoding():
|
||||
|
||||
@@ -242,8 +242,10 @@ def play_file(play_info):
|
||||
media_source_id = play_info.get("media_source_id", "")
|
||||
subtitle_stream_index = play_info.get("subtitle_stream_index", None)
|
||||
audio_stream_index = play_info.get("audio_stream_index", None)
|
||||
force_track_selection = play_info.get("force_track_selection", False)
|
||||
|
||||
log.debug("playFile id({0}) resume({1}) force_transcode({2})".format(item_id, auto_resume, force_transcode))
|
||||
log.debug("playFile id({0}) resume({1}) force_transcode({2}) force_track_selection({3})".format(
|
||||
item_id, auto_resume, force_transcode, force_track_selection))
|
||||
|
||||
addon_path = settings.getAddonInfo('path')
|
||||
force_auto_resume = settings.getSetting('forceAutoResume') == 'true'
|
||||
@@ -461,7 +463,7 @@ def play_file(play_info):
|
||||
|
||||
if playback_type == "2": # if transcoding then prompt for audio and subtitle
|
||||
playurl = audio_subs_pref(playurl, list_item, selected_media_source, item_id, audio_stream_index,
|
||||
subtitle_stream_index)
|
||||
subtitle_stream_index, force_track_selection)
|
||||
log.debug("New playurl for transcoding: {0}".format(playurl))
|
||||
|
||||
elif playback_type == "1": # for direct stream add any streamable subtitles
|
||||
@@ -778,12 +780,14 @@ def set_list_item_props(item_id, list_item, result, server, extra_props, title):
|
||||
# Present the list of audio and subtitles to select from
|
||||
# for external streamable subtitles add the URL to the Kodi item and let Kodi handle it
|
||||
# else ask for the subtitles to be burnt in when transcoding
|
||||
def audio_subs_pref(url, list_item, media_source, item_id, audio_stream_index, subtitle_stream_index):
|
||||
def audio_subs_pref(url, list_item, media_source, item_id, audio_stream_index, subtitle_stream_index, force_track_selection=False):
|
||||
dialog = xbmcgui.Dialog()
|
||||
audio_streams_list = {}
|
||||
audio_streams = []
|
||||
audio_streams_data = [] # Store full stream data for preference matching
|
||||
subtitle_streams_list = {}
|
||||
subtitle_streams = ['No subtitles']
|
||||
subtitle_streams_data = [] # Store full stream data for preference matching
|
||||
downloadable_streams = []
|
||||
select_audio_index = audio_stream_index
|
||||
select_subs_index = subtitle_stream_index
|
||||
@@ -792,6 +796,60 @@ def audio_subs_pref(url, list_item, media_source, item_id, audio_stream_index, s
|
||||
default_sub = media_source.get('DefaultSubtitleStreamIndex', "")
|
||||
source_id = media_source["Id"]
|
||||
|
||||
# Read user preferences
|
||||
# Map select index to language code
|
||||
lang_index_map = ['ger', 'eng', 'fra', 'spa', 'ita', 'jpn', 'rus', ''] # '' = other/custom
|
||||
sub_lang_index_map = ['', 'ger', 'eng', 'fra', 'spa', 'ita', 'jpn', 'rus', ''] # First is 'none'
|
||||
|
||||
audio_lang_index = int(settings.getSetting("preferred_audio_language") or "0")
|
||||
preferred_audio_lang = lang_index_map[audio_lang_index] if audio_lang_index < len(lang_index_map) else ''
|
||||
|
||||
auto_select_default_audio = settings.getSetting("auto_select_default_audio") == "true"
|
||||
|
||||
sub_lang_index = int(settings.getSetting("preferred_subtitle_language") or "1")
|
||||
preferred_sub_lang = sub_lang_index_map[sub_lang_index] if sub_lang_index < len(sub_lang_index_map) else ''
|
||||
|
||||
prefer_forced = settings.getSetting("prefer_forced_subtitles") == "true"
|
||||
only_forced = settings.getSetting("only_forced_subtitles") == "true"
|
||||
|
||||
# Subtitle codec preference: 0=PGS, 1=SRT, 2=No preference
|
||||
codec_pref_index = int(settings.getSetting("subtitle_codec_preference") or "0")
|
||||
prefer_pgs = codec_pref_index == 0
|
||||
prefer_srt = codec_pref_index == 1
|
||||
# codec_pref_index == 2 means no preference (both prefer_pgs and prefer_srt are False)
|
||||
|
||||
auto_no_subs = settings.getSetting("auto_no_subtitles_if_no_match") == "true"
|
||||
|
||||
# Language code mapping for better matching
|
||||
language_map = {
|
||||
'ger': ['ger', 'deu', 'de', 'german', 'deutsch'],
|
||||
'eng': ['eng', 'en', 'english'],
|
||||
'fra': ['fra', 'fr', 'fre', 'french', 'français'],
|
||||
'spa': ['spa', 'es', 'spanish', 'español'],
|
||||
'ita': ['ita', 'it', 'italian', 'italiano'],
|
||||
'jpn': ['jpn', 'ja', 'japanese', '日本語'],
|
||||
'rus': ['rus', 'ru', 'russian'],
|
||||
}
|
||||
|
||||
# Helper function to check if language matches
|
||||
def language_matches(stream_lang, preferred_lang):
|
||||
stream_lang = stream_lang.lower()
|
||||
preferred_lang = preferred_lang.lower()
|
||||
|
||||
# Direct match
|
||||
if preferred_lang in stream_lang or stream_lang in preferred_lang:
|
||||
return True
|
||||
|
||||
# Check against language map
|
||||
for key, variations in language_map.items():
|
||||
if preferred_lang in variations:
|
||||
# Check if stream language matches any variation
|
||||
for variant in variations:
|
||||
if variant in stream_lang or stream_lang.startswith(variant[:2]):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
media_streams = media_source['MediaStreams']
|
||||
|
||||
for stream in media_streams:
|
||||
@@ -801,6 +859,7 @@ def audio_subs_pref(url, list_item, media_source, item_id, audio_stream_index, s
|
||||
if 'Audio' in stream['Type']:
|
||||
codec = stream.get('Codec', None)
|
||||
channel_layout = stream.get('ChannelLayout', "")
|
||||
title = stream.get('Title', '')
|
||||
|
||||
if not codec:
|
||||
# Probably tvheadend and has no other info
|
||||
@@ -813,30 +872,161 @@ def audio_subs_pref(url, list_item, media_source, item_id, audio_stream_index, s
|
||||
# Track doesn't include language
|
||||
track = "%s - %s %s" % (index, codec, channel_layout)
|
||||
|
||||
# Add title if available
|
||||
if title:
|
||||
track = "%s - %s" % (track, title)
|
||||
|
||||
audio_streams_list[track] = index
|
||||
audio_streams.append(track)
|
||||
audio_streams_data.append(stream)
|
||||
|
||||
elif 'Subtitle' in stream['Type']:
|
||||
try:
|
||||
# Track includes language
|
||||
track = "%s - %s" % (index, stream['Language'])
|
||||
except KeyError:
|
||||
# Track doesn't include language
|
||||
track = "%s - %s" % (index, stream['Codec'])
|
||||
language = stream.get('Language', 'Unknown')
|
||||
codec = stream.get('Codec', 'Unknown')
|
||||
|
||||
codec_names = {
|
||||
'subrip': 'SRT',
|
||||
'hdmv_pgs_subtitle': 'PGS',
|
||||
'dvd_subtitle': 'VobSub',
|
||||
'ass': 'ASS'
|
||||
}
|
||||
codec_display = codec_names.get(codec.lower(), codec.upper())
|
||||
|
||||
track = "%s - %s (%s)" % (index, language, codec_display)
|
||||
|
||||
default = stream['IsDefault']
|
||||
forced = stream['IsForced']
|
||||
hearing_impaired = stream.get('IsHearingImpaired', False)
|
||||
downloadable = stream['IsTextSubtitleStream'] and stream['IsExternal'] and stream['SupportsExternalStream']
|
||||
|
||||
if default:
|
||||
track = "%s - Default" % track
|
||||
if forced:
|
||||
track = "%s - Forced" % track
|
||||
if hearing_impaired:
|
||||
track = "%s - SDH" % track
|
||||
if downloadable:
|
||||
downloadable_streams.append(index)
|
||||
|
||||
subtitle_streams_list[track] = index
|
||||
subtitle_streams.append(track)
|
||||
subtitle_streams_data.append(stream)
|
||||
|
||||
# Auto-select audio track based on preferences
|
||||
# Only auto-select if not already set by server/remote control AND not forcing manual selection
|
||||
if not force_track_selection and select_audio_index is None and len(audio_streams_data) > 0 and (preferred_audio_lang or auto_select_default_audio):
|
||||
auto_selected = None
|
||||
best_score = -1
|
||||
|
||||
# Try to match preferred language with scoring
|
||||
if preferred_audio_lang:
|
||||
for stream in audio_streams_data:
|
||||
score = 0
|
||||
stream_lang = stream.get('Language', '')
|
||||
|
||||
# Match against common variations using language map
|
||||
if language_matches(stream_lang, preferred_audio_lang):
|
||||
score += 100 # Language match
|
||||
|
||||
# Bonus for default track
|
||||
if stream.get('IsDefault', False):
|
||||
score += 50
|
||||
|
||||
# Bonus based on channel count (more channels = better quality)
|
||||
channels = stream.get('Channels', 2)
|
||||
score += min(channels * 5, 40) # Max +40 for 8 channels
|
||||
|
||||
# Bonus for high-quality codecs
|
||||
codec = stream.get('Codec', '').lower()
|
||||
if 'truehd' in codec or 'dts-hd' in codec or 'dts-ma' in codec:
|
||||
score += 30
|
||||
elif 'dts' in codec:
|
||||
score += 20
|
||||
elif 'ac3' in codec or 'eac3' in codec:
|
||||
score += 10
|
||||
|
||||
# Penalty for commentary tracks
|
||||
title = stream.get('Title', '').lower()
|
||||
display_title = stream.get('DisplayTitle', '').lower()
|
||||
if 'commentary' in title or 'kommentar' in title or 'commentary' in display_title:
|
||||
score -= 100 # Effectively exclude commentary
|
||||
|
||||
log.debug("Audio score for {0} ({1}): {2} (channels={3}, codec={4}, default={5})".format(
|
||||
stream_lang, stream['Index'], score, channels, codec, stream.get('IsDefault', False)))
|
||||
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
auto_selected = stream['Index']
|
||||
|
||||
# Fall back to default audio if enabled and no language match
|
||||
if auto_selected is None and auto_select_default_audio:
|
||||
auto_selected = default_audio
|
||||
log.debug("Auto-selected default audio (index {0})".format(auto_selected))
|
||||
|
||||
if auto_selected is not None:
|
||||
select_audio_index = auto_selected
|
||||
if best_score > 0:
|
||||
log.debug("Auto-selected audio (index {0}, score {1})".format(auto_selected, best_score))
|
||||
|
||||
# Auto-select subtitle track based on preferences
|
||||
# Only auto-select if not already set by server/remote control AND not forcing manual selection
|
||||
if force_track_selection:
|
||||
log.debug("Forcing manual track selection (from context menu)")
|
||||
elif select_subs_index is not None:
|
||||
log.debug("Using subtitle index from server/remote: {0}".format(select_subs_index))
|
||||
elif len(subtitle_streams_data) == 0:
|
||||
log.debug("No subtitle streams available")
|
||||
elif len(subtitle_streams_data) > 0 and preferred_sub_lang: # Only if user configured a language preference
|
||||
auto_selected = None
|
||||
best_score = -1
|
||||
|
||||
log.debug("Auto-selecting subtitle: preferred_lang={0}, prefer_forced={1}, only_forced={2}, prefer_pgs={3}, prefer_srt={4}".format(
|
||||
preferred_sub_lang, prefer_forced, only_forced, prefer_pgs, prefer_srt))
|
||||
|
||||
for stream in subtitle_streams_data:
|
||||
score = 0
|
||||
stream_lang = stream.get('Language', '')
|
||||
codec = stream.get('Codec', '').lower()
|
||||
is_forced = stream.get('IsForced', False)
|
||||
is_default = stream.get('IsDefault', False)
|
||||
|
||||
# Skip non-forced subtitles if only_forced is enabled
|
||||
if only_forced and not is_forced:
|
||||
log.debug("Skipping non-forced subtitle {0} ({1}) - only_forced is enabled".format(
|
||||
stream_lang, stream['Index']))
|
||||
continue
|
||||
|
||||
# Score based on language match
|
||||
if preferred_sub_lang and language_matches(stream_lang, preferred_sub_lang):
|
||||
score += 100
|
||||
|
||||
# Bonus for forced if preferred
|
||||
if prefer_forced and is_forced:
|
||||
score += 50
|
||||
|
||||
# Bonus for codec preference
|
||||
if prefer_pgs and codec in ['hdmv_pgs_subtitle', 'pgs']:
|
||||
score += 30
|
||||
elif prefer_srt and codec in ['subrip', 'srt']:
|
||||
score += 30
|
||||
|
||||
# Small bonus for default
|
||||
if is_default:
|
||||
score += 10
|
||||
|
||||
log.debug("Subtitle score for {0} ({1}): {2} (forced={3}, codec={4})".format(
|
||||
stream_lang, stream['Index'], score, is_forced, codec))
|
||||
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
auto_selected = stream['Index']
|
||||
|
||||
if auto_selected is not None and best_score >= 100: # Only auto-select if language matched
|
||||
select_subs_index = auto_selected
|
||||
log.debug("Auto-selected subtitle (index {0}, score {1})".format(auto_selected, best_score))
|
||||
elif auto_no_subs and preferred_sub_lang: # No match found but user wants auto "no subs"
|
||||
select_subs_index = -1 # Special value to indicate "no subtitles"
|
||||
log.debug("No matching subtitle found - auto-selected 'No subtitles'")
|
||||
|
||||
# set audio index
|
||||
if select_audio_index is not None:
|
||||
@@ -854,8 +1044,12 @@ def audio_subs_pref(url, list_item, media_source, item_id, audio_stream_index, s
|
||||
|
||||
# set subtitle index
|
||||
if select_subs_index is not None:
|
||||
# Handle special "no subtitles" value
|
||||
if select_subs_index == -1:
|
||||
# User wants no subtitles - do nothing
|
||||
pass
|
||||
# Load subtitles in the listitem if downloadable
|
||||
if select_subs_index in downloadable_streams:
|
||||
elif select_subs_index in downloadable_streams:
|
||||
subtitle_url = "%s/Videos/%s/%s/Subtitles/%s/Stream.srt"
|
||||
subtitle_url = subtitle_url % (settings.getSetting('server_address'), item_id, source_id, select_subs_index)
|
||||
log.debug("Streaming subtitles url: {0} {1}".format(select_subs_index, subtitle_url))
|
||||
@@ -1283,13 +1477,22 @@ def get_play_url(media_source, play_session_id, channel_id=None):
|
||||
audio_max_channels = settings.getSetting("audio_max_channels")
|
||||
playback_video_force_8 = settings.getSetting("playback_video_force_8") == "true"
|
||||
|
||||
# Determine target video codec for transcoding
|
||||
transcode_target_codec_setting = settings.getSetting("transcode_target_video_codec")
|
||||
if transcode_target_codec_setting == "1":
|
||||
transcode_video_codec = "hevc"
|
||||
elif transcode_target_codec_setting == "2":
|
||||
transcode_video_codec = "av1"
|
||||
else:
|
||||
transcode_video_codec = "h264"
|
||||
|
||||
transcode_params = {
|
||||
"MediaSourceId": item_id,
|
||||
"DeviceId": device_id,
|
||||
"PlaySessionId": play_session_id,
|
||||
"api_key": user_token,
|
||||
"SegmentContainer": "ts",
|
||||
"VideoCodec": "h264",
|
||||
"VideoCodec": transcode_video_codec,
|
||||
"VideoBitrate": bitrate,
|
||||
"MaxWidth": playback_max_width,
|
||||
"AudioCodec": audio_codec,
|
||||
@@ -1534,7 +1737,12 @@ class PlaybackService(xbmc.Monitor):
|
||||
|
||||
def get_item_playback_info(item_id, force_transcode):
|
||||
|
||||
# Filter codecs that should NEVER be played directly (always force transcoding)
|
||||
# These settings work independently from the target codec setting below
|
||||
# Example: force_transcode_h264=true + target=hevc means: H.264 files will be transcoded to H.265
|
||||
filtered_codecs = []
|
||||
if settings.getSetting("force_transcode_h264") == "true":
|
||||
filtered_codecs.append("h264")
|
||||
if settings.getSetting("force_transcode_h265") == "true":
|
||||
filtered_codecs.append("hevc")
|
||||
filtered_codecs.append("h265")
|
||||
@@ -1558,6 +1766,19 @@ def get_item_playback_info(item_id, force_transcode):
|
||||
|
||||
audio_bitrate = int(audio_playback_bitrate) * 1000
|
||||
|
||||
# Determine target video codec for transcoding
|
||||
# Note: force_transcode_* settings filter codecs for DirectPlay independently
|
||||
# This setting only affects what codec the server transcodes TO when transcoding is needed
|
||||
transcode_target_codec_setting = settings.getSetting("transcode_target_video_codec")
|
||||
log.debug("Transcode target codec setting value: '{0}'".format(transcode_target_codec_setting))
|
||||
if transcode_target_codec_setting == "1":
|
||||
transcode_video_codec = "hevc"
|
||||
elif transcode_target_codec_setting == "2":
|
||||
transcode_video_codec = "av1"
|
||||
else:
|
||||
transcode_video_codec = "h264"
|
||||
log.debug("Transcode target video codec: {0}".format(transcode_video_codec))
|
||||
|
||||
profile = {
|
||||
"Name": "Kodi",
|
||||
"MaxStaticBitrate": bitrate,
|
||||
@@ -1573,7 +1794,7 @@ def get_item_playback_info(item_id, force_transcode):
|
||||
"Protocol": "hls",
|
||||
"Type": "Video",
|
||||
"AudioCodec": audio_codec,
|
||||
"VideoCodec": "h264",
|
||||
"VideoCodec": transcode_video_codec,
|
||||
"MaxAudioChannels": audio_max_channels
|
||||
},
|
||||
{
|
||||
|
||||
1731
resources/lib/play_utils.py.orig
Normal file
1731
resources/lib/play_utils.py.orig
Normal file
File diff suppressed because it is too large
Load Diff
@@ -33,11 +33,11 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
self.__dict__ = self._shared_state
|
||||
self.monitor = xbmc.Monitor()
|
||||
self.retry_count = 0
|
||||
|
||||
self.device_id = get_device_id()
|
||||
|
||||
self._library_monitor = library_change_monitor
|
||||
self.websocket_error = False
|
||||
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
@@ -230,11 +230,16 @@ class WebSocketClient(threading.Thread):
|
||||
xbmc.executebuiltin(builtin[command])
|
||||
|
||||
def on_open(self, ws):
|
||||
# Wait to make sure previous keepalive cycle has ended
|
||||
if self.websocket_error:
|
||||
time.sleep(30)
|
||||
self.websocket_error = False
|
||||
log.debug("Connected")
|
||||
self.retry_count = 0
|
||||
self.post_capabilities()
|
||||
self.send_keepalive(ws)
|
||||
|
||||
def on_error(self, ws, error):
|
||||
self.websocket_error = True
|
||||
log.debug("Error: {0}".format(error))
|
||||
|
||||
def run(self):
|
||||
@@ -269,7 +274,7 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
while not self.monitor.abortRequested():
|
||||
|
||||
self._client.run_forever(ping_interval=5, reconnect=13, ping_timeout=2)
|
||||
self._client.run_forever(reconnect=30)
|
||||
|
||||
if self._stop_websocket:
|
||||
break
|
||||
@@ -278,8 +283,6 @@ class WebSocketClient(threading.Thread):
|
||||
# Abort was requested, exit
|
||||
break
|
||||
|
||||
if self.retry_count < 12:
|
||||
self.retry_count += 1
|
||||
log.debug("Reconnecting WebSocket")
|
||||
|
||||
log.debug("WebSocketClient Stopped")
|
||||
@@ -303,3 +306,22 @@ class WebSocketClient(threading.Thread):
|
||||
)
|
||||
|
||||
api.post_capabilities()
|
||||
|
||||
def send_keepalive(self, ws):
|
||||
# Stop the keepalive cycle if an error has been detected
|
||||
if self.websocket_error:
|
||||
return
|
||||
keepalive_payload = json.dumps({"MessageType": "KeepAlive", "Data": 30})
|
||||
# Send the keepalive, or register an error
|
||||
try:
|
||||
ws.send(keepalive_payload)
|
||||
except:
|
||||
self.websocket_error = True
|
||||
return
|
||||
# Schedule the next message
|
||||
self.schedule_keepalive(ws)
|
||||
|
||||
def schedule_keepalive(self, ws):
|
||||
# Schedule a keepalive message in 30 seconds
|
||||
timer = threading.Timer(30, self.send_keepalive, kwargs={'ws': ws})
|
||||
timer.start()
|
||||
|
||||
73
resources/lib/websocket_client.py.rej
Normal file
73
resources/lib/websocket_client.py.rej
Normal file
@@ -0,0 +1,73 @@
|
||||
@@ -46,7 +46,12 @@
|
||||
result = json.loads(message)
|
||||
message_type = result['MessageType']
|
||||
|
||||
- if message_type == 'Play':
|
||||
+ if message_type == 'ForceKeepAlive':
|
||||
+ timeout_seconds = result.get('Data', 60)
|
||||
+ log.debug("Received ForceKeepAlive with timeout: {0}s".format(timeout_seconds))
|
||||
+ self._send_keep_alive()
|
||||
+
|
||||
+ elif message_type == 'Play':
|
||||
data = result['Data']
|
||||
self._play(data)
|
||||
|
||||
@@ -237,6 +242,9 @@
|
||||
def on_error(self, ws, error):
|
||||
log.debug("Error: {0}".format(error))
|
||||
|
||||
+ def on_close(self, ws, close_status_code, close_msg):
|
||||
+ log.debug("WebSocket closed. Code: {0}, Message: {1}".format(close_status_code, close_msg))
|
||||
+
|
||||
def run(self):
|
||||
|
||||
token = None
|
||||
@@ -259,17 +267,23 @@
|
||||
)
|
||||
log.debug("websocket url: {0}".format(websocket_url))
|
||||
|
||||
- self._client = websocket.WebSocketApp(
|
||||
- websocket_url,
|
||||
- on_open=lambda ws: self.on_open(ws),
|
||||
- on_message=lambda ws, message: self.on_message(ws, message),
|
||||
- on_error=lambda ws, error: self.on_error(ws, error))
|
||||
-
|
||||
log.debug("Starting WebSocketClient")
|
||||
|
||||
while not self.monitor.abortRequested():
|
||||
|
||||
- self._client.run_forever(ping_interval=5, reconnect=13, ping_timeout=2)
|
||||
+ # Create a new WebSocketApp for each connection attempt to avoid
|
||||
+ # memory leaks from reusing a potentially dirty connection object
|
||||
+ self._client = websocket.WebSocketApp(
|
||||
+ websocket_url,
|
||||
+ on_open=lambda ws: self.on_open(ws),
|
||||
+ on_message=lambda ws, message: self.on_message(ws, message),
|
||||
+ on_error=lambda ws, error: self.on_error(ws, error),
|
||||
+ on_close=lambda ws, status, msg: self.on_close(ws, status, msg))
|
||||
+
|
||||
+ # Use ping_interval without ping_timeout to keep connection alive
|
||||
+ # without forcing disconnection. The server's ForceKeepAlive/KeepAlive
|
||||
+ # mechanism handles the actual keepalive logic.
|
||||
+ self._client.run_forever(ping_interval=10)
|
||||
|
||||
if self._stop_websocket:
|
||||
break
|
||||
@@ -291,6 +305,17 @@
|
||||
self._client.close()
|
||||
log.debug("Stopping WebSocket (stop_client called)")
|
||||
|
||||
+ def _send_keep_alive(self):
|
||||
+ """Send a KeepAlive message to the server to maintain the connection."""
|
||||
+ try:
|
||||
+ keep_alive_message = json.dumps({
|
||||
+ 'MessageType': 'KeepAlive'
|
||||
+ })
|
||||
+ self._client.send(keep_alive_message)
|
||||
+ log.debug("Sent KeepAlive message")
|
||||
+ except Exception as error:
|
||||
+ log.debug("Error sending KeepAlive: {0}".format(error))
|
||||
+
|
||||
def post_capabilities(self):
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
@@ -30,6 +30,8 @@
|
||||
<setting type="sep" />
|
||||
<setting id="max_stream_bitrate" type="enum" label="30208" values="0.5 Mbps|1 Mbps|1.5 Mbps|2.0 Mbps|2.5 Mbps|3.0 Mbps|4.0 Mbps|5.0 Mbps|6.0 Mbps|7.0 Mbps|8.0 Mbps|9.0 Mbps|10.0 Mbps|12.0 Mbps|14.0 Mbps|16.0 Mbps|18.0 Mbps|20.0 Mbps|25.0 Mbps|30.0 Mbps|35.0 Mbps|40.0 Mbps|100.0 Mbps|1000.0 Mbps [default]|Maximum" visible="true" default="23" />
|
||||
<setting id="allow_direct_file_play" type="bool" label="30433" default="false" visible="true" enable="true" />
|
||||
<setting id="transcode_target_video_codec" type="select" label="30679" lvalues="30680|30681|30683" default="0" visible="true" />
|
||||
<setting id="force_transcode_h264" type="bool" label="30682" default="false" visible="true" />
|
||||
<setting id="force_transcode_h265" type="bool" label="30236" default="false" visible="true" enable="true" />
|
||||
<setting id="force_transcode_mpeg2" type="bool" label="30239" default="false" visible="true" enable="true" />
|
||||
<setting id="force_transcode_msmpeg4v3" type="bool" label="30240" default="false" visible="true" enable="true" />
|
||||
@@ -45,6 +47,16 @@
|
||||
<setting id="audio_codec" type="select" label="30419" values="ac3|aac" default="ac3"/>
|
||||
<setting id="audio_playback_bitrate" type="select" label="30418" values="128|160|192|256|320|384|448|640" default="256" visible="true"/>
|
||||
<setting id="audio_max_channels" type="slider" label="30420" default="8" range="2,1,8" option="int" visible="true"/>
|
||||
|
||||
<setting label="30685" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting id="preferred_audio_language" type="select" label="30686" lvalues="30691|30692|30693|30694|30695|30696|30697|30698" default="0" visible="true"/>
|
||||
<setting id="auto_select_default_audio" type="bool" label="30687" default="true" visible="true"/>
|
||||
<setting id="preferred_subtitle_language" type="select" label="30688" lvalues="30699|30691|30692|30693|30694|30695|30696|30697|30698" default="1" visible="true"/>
|
||||
<setting id="prefer_forced_subtitles" type="bool" label="30689" default="true" visible="true"/>
|
||||
<setting id="only_forced_subtitles" type="bool" label="30702" default="true" visible="true"/>
|
||||
<setting id="subtitle_codec_preference" type="select" label="30703" lvalues="30704|30705|30706" default="0" visible="true"/>
|
||||
<setting id="auto_no_subtitles_if_no_match" type="bool" label="30700" default="true" visible="true"/>
|
||||
<setting id="max_play_queue" type="slider" label="30447" default="200" range="20, 10, 1000" option="int" visible="true"/>
|
||||
|
||||
</category>
|
||||
@@ -157,7 +169,8 @@
|
||||
<setting id="profile_count" type="slider" label="30010" default="0" range="0,1,20" option="int" visible="true" />
|
||||
<setting id="log_debug" type="bool" label="30027" default="false" visible="true" enable="true" />
|
||||
<setting id="log_timing" type="bool" label="30015" default="false" visible="true" enable="true" />
|
||||
<setting id="use_cache" type="bool" label="30345" default="true" visible="true" enable="true" />
|
||||
<setting id="disable_disk_cache" type="bool" label="30684" default="true" visible="true" enable="true" />
|
||||
<setting id="use_cache" type="bool" label="30345" default="false" visible="true" enable="true" />
|
||||
<setting id="use_cached_widget_data" type="bool" label="30441" default="false" visible="true" enable="true" />
|
||||
<setting id="showLoadProgress" type="bool" label="30120" default="false" visible="true" enable="true" />
|
||||
<setting id="suppressErrors" type="bool" label="30315" default="false" visible="true" enable="true" />
|
||||
|
||||
13
service.py
13
service.py
@@ -22,11 +22,14 @@ from resources.lib.image_server import HttpImageServerThread
|
||||
from resources.lib.playnext import PlayNextService
|
||||
from resources.lib.intro_skipper import IntroSkipperService
|
||||
|
||||
settings = xbmcaddon.Addon()
|
||||
|
||||
log_timing_data = settings.getSetting('log_timing') == "true"
|
||||
if log_timing_data:
|
||||
set_timing_enabled(True)
|
||||
try:
|
||||
settings = xbmcaddon.Addon()
|
||||
log_timing_data = settings.getSetting('log_timing') == "true"
|
||||
if log_timing_data:
|
||||
set_timing_enabled(True)
|
||||
except Exception:
|
||||
# During installation/update, addon might not be fully registered yet
|
||||
pass
|
||||
|
||||
# clear user and token when logging in
|
||||
home_window = HomeWindow()
|
||||
|
||||
Reference in New Issue
Block a user