Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c89de64cb | ||
|
|
79551c52c8 | ||
|
|
4d3011e23b | ||
|
|
2cd7c3bd7f | ||
|
|
6cc9583604 | ||
|
|
352f6594e3 | ||
|
|
2373ac2d19 | ||
|
|
dfe7f6372a | ||
|
|
3e02b72dde | ||
|
|
88b17be010 | ||
|
|
8dd3d774c4 | ||
|
|
974f233431 | ||
|
|
4fd3ccefb0 | ||
|
|
2067f158fe | ||
|
|
1ddf270847 | ||
|
|
7073aeb307 | ||
|
|
9af3415ac6 | ||
|
|
61720a5f90 | ||
|
|
e15a87ef7f | ||
|
|
997f6985ba | ||
|
|
b132f63871 | ||
|
|
6c4dad03b5 | ||
|
|
7efcb96921 | ||
|
|
22dcbe1c13 | ||
|
|
8ae8b5639f | ||
|
|
8b8d32e20b | ||
|
|
d004716c4b | ||
|
|
2b154a4cff | ||
|
|
df411a0e00 | ||
|
|
381ecb95a9 | ||
|
|
886160ca0f | ||
|
|
b178f785de | ||
|
|
9266b05fad | ||
|
|
973fc68893 | ||
|
|
a0b8af9aa0 | ||
|
|
4a97979027 | ||
|
|
c5f5834b64 | ||
|
|
8e10ff79b1 | ||
|
|
7950610b4d | ||
|
|
93277c7d4f | ||
|
|
9523d8252d | ||
|
|
f16f2748a6 | ||
|
|
f04c4d70b9 | ||
|
|
f8e337ea92 | ||
|
|
347ab47672 | ||
|
|
d25de226d0 | ||
|
|
aa5b813929 | ||
|
|
bf513dee43 | ||
|
|
cb68387437 | ||
|
|
f8da1f5337 | ||
|
|
952eb31cc2 | ||
|
|
1d9b401405 | ||
|
|
70ec2d8773 | ||
|
|
383e1fd67b | ||
|
|
a013c8efb0 | ||
|
|
1b255f211e | ||
|
|
7b64a7cdd3 | ||
|
|
e3b34b81fd | ||
|
|
d70d2c3374 | ||
|
|
af06f09269 | ||
|
|
b32043cfd9 | ||
|
|
00b611d6f6 | ||
|
|
afea58c53a | ||
|
|
0db36ea1b8 | ||
|
|
5aa3b543ce | ||
|
|
3dfde5eb04 | ||
|
|
351c872c46 | ||
|
|
802f93c30c | ||
|
|
94b0dce77e | ||
|
|
2d2d378dca | ||
|
|
f84afcd7ab | ||
|
|
b7f507271e | ||
|
|
399e5b1683 | ||
|
|
0140dc6ff4 | ||
|
|
d1d403815e | ||
|
|
af2dabaa9d | ||
|
|
c9a8cec161 | ||
|
|
190d439d36 | ||
|
|
0a53312dee | ||
|
|
1759115a80 |
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Update Draft
|
||||
uses: release-drafter/release-drafter@v5.21.1
|
||||
uses: release-drafter/release-drafter@v5.22.0
|
||||
id: draft
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Parse Changlog
|
||||
- name: Parse Changelog
|
||||
run: |
|
||||
pip install emoji
|
||||
cat << EOF >> cl.md
|
||||
|
||||
4
.github/workflows/publish.yaml
vendored
4
.github/workflows/publish.yaml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
py_version: [ 'py2', 'py3' ]
|
||||
steps:
|
||||
- name: Update Draft
|
||||
uses: release-drafter/release-drafter@v5.21.1
|
||||
uses: release-drafter/release-drafter@v5.22.0
|
||||
if: ${{ matrix.py_version == 'py3' }}
|
||||
with:
|
||||
publish: true
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
remote_key: ${{ secrets.DEPLOY_KEY }}
|
||||
|
||||
- name: Add to Kodi repo and clean up
|
||||
uses: appleboy/ssh-action@v0.1.5
|
||||
uses: appleboy/ssh-action@v0.1.7
|
||||
with:
|
||||
host: ${{ secrets.DEPLOY_HOST }}
|
||||
username: ${{ secrets.DEPLOY_USER }}
|
||||
|
||||
2
.github/workflows/release-drafter.yaml
vendored
2
.github/workflows/release-drafter.yaml
vendored
@@ -11,6 +11,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Update Release Draft
|
||||
uses: release-drafter/release-drafter@v5.21.1
|
||||
uses: release-drafter/release-drafter@v5.22.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||
|
||||
29
release.yaml
29
release.yaml
@@ -1,17 +1,36 @@
|
||||
version: '0.6.1'
|
||||
version: '0.7.0'
|
||||
changelog: |-
|
||||
:tada: New features and improvements
|
||||
------------------------------------
|
||||
+ Add ability to shuffle music genres (#267) @mcarlton00
|
||||
+ Add ability to shuffle entire music library (#255) @mcarlton00
|
||||
+ Increase maximum stream bitrate (#258) @mrkev-gh
|
||||
+ Start playing multiple items faster (#254) @mcarlton00
|
||||
+ Add instant mix and shuffle features for music (#253) @mcarlton00
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
+ Initialize variable before it's used (#238) @mcarlton00
|
||||
+ Don't crash if quickconnect is disabled on the server (#235) @mcarlton00
|
||||
+ Fix context menu in kodi v20 (#271) @mcarlton00
|
||||
+ Include LiveStreamId in session stopped api call (#266) @mcarlton00
|
||||
+ Fix support for the upnext addon (#262) @mcarlton00
|
||||
+ Add item limit to the list of parameters for recently added movies (#244) @IncredibleLaser
|
||||
|
||||
Code or Repo Maintenance
|
||||
------------------------
|
||||
+ refact: use f-string instead of format (#239) @EwertonBello
|
||||
+ Fix typos (#265) @kianmeng
|
||||
+ pep8 refactor - part 1 (#263) @mcarlton00
|
||||
+ Refactor imports for pep8 standards (#261) @mcarlton00
|
||||
+ Fix flake8 linting complaints (#260) @mcarlton00
|
||||
|
||||
:arrow_up: Dependency updates
|
||||
-----------------------------
|
||||
+ Update kodistubs requirement from ~=19.0 to ~=20.0 (#268) @dependabot
|
||||
|
||||
CI & build changes
|
||||
------------------
|
||||
+ Bump release-drafter/release-drafter from 5.21.0 to 5.21.1 (#234) @dependabot
|
||||
+ Bump appleboy/ssh-action from 0.1.6 to 0.1.7 (#259) @dependabot
|
||||
+ Bump release-drafter/release-drafter from 5.21.1 to 5.22.0 (#256) @dependabot
|
||||
+ Bump appleboy/ssh-action from 0.1.5 to 0.1.6 (#249) @dependabot
|
||||
dependencies:
|
||||
py2:
|
||||
- addon: 'xbmc.python'
|
||||
|
||||
@@ -6,7 +6,7 @@ requests >= 2.22
|
||||
futures >= 2.2; python_version < '3.0'
|
||||
|
||||
Kodistubs ~= 18.0; python_version < '3.0'
|
||||
Kodistubs ~= 19.0; python_version >= '3.6'
|
||||
Kodistubs ~= 20.0; python_version >= '3.6'
|
||||
|
||||
git+https://github.com/romanvm/kodi.six
|
||||
git+https://github.com/ruuk/script.module.addon.signals
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-06-05 14:22+0000\n"
|
||||
"Last-Translator: egymoh <egymoh2@hotmail.com>\n"
|
||||
"PO-Revision-Date: 2023-01-13 15:51+0000\n"
|
||||
"Last-Translator: 0TTA <OTTTA@protonmail.com>\n"
|
||||
"Language-Team: Arabic <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/ar/>\n"
|
||||
"Language: ar\n"
|
||||
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
|
||||
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
|
||||
"X-Generator: Weblate 4.10.1\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30361"
|
||||
msgid " - Programs"
|
||||
@@ -52,19 +52,17 @@ msgctxt "#30319"
|
||||
msgid "Music - All Album Artists"
|
||||
msgstr "كل فناني الألبوم"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30351"
|
||||
msgid "Music - Recently Played"
|
||||
msgstr "لعبت مؤخرا"
|
||||
msgstr "موسيقى - شُغلت مؤخرا"
|
||||
|
||||
msgctxt "#30350"
|
||||
msgid "Music - Recently Added"
|
||||
msgstr "أضيف مؤخرا"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30349"
|
||||
msgid " - Recently Played"
|
||||
msgstr "لعبت مؤخرا"
|
||||
msgstr "- شُغلت مؤخرا"
|
||||
|
||||
msgctxt "#30348"
|
||||
msgid "Add user ratings"
|
||||
@@ -359,7 +357,7 @@ msgstr "أضيف مؤخرا"
|
||||
|
||||
msgctxt "#30267"
|
||||
msgid " - In Progress"
|
||||
msgstr "في تقدم"
|
||||
msgstr "قيد المشاهدة"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
@@ -371,7 +369,7 @@ msgstr "الحلقات - التالي"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "الحلقات - قيد التقدم"
|
||||
msgstr "حلقات - قيد المشاهدة"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
@@ -391,7 +389,7 @@ msgstr "أفلام - المفضلة"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "أفلام - قيد التحميل"
|
||||
msgstr "أفلام - قيد المشاهدة"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
@@ -664,7 +662,7 @@ msgstr "اسم المستخدم:"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "إخفاء تفاصيل الحلقة التي لم تتم مشاهدتها"
|
||||
msgstr "إخفاء تفاصيل الحلقة غير المشاهدة"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
@@ -745,3 +743,235 @@ msgstr "أستضافة"
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "الحد الأقصى لمعدل نقل البيانات (Kbps)"
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "HTTP direct stream"
|
||||
msgstr "(بروتوكول نقل النص الفائق) مشاهدة مباشرة"
|
||||
|
||||
msgctxt "#30364"
|
||||
msgid "Do you want to save the password?"
|
||||
msgstr "أتود حفظ كلمة السر؟"
|
||||
|
||||
msgctxt "#30366"
|
||||
msgid "Manually enter user details"
|
||||
msgstr "أدخل معلومات المستخدم يدويا"
|
||||
|
||||
msgctxt "#30368"
|
||||
msgid "Clear Password?"
|
||||
msgstr "أتود حذف كلمة السر؟"
|
||||
|
||||
msgctxt "#30369"
|
||||
msgid "Do you want to clear your saved password?"
|
||||
msgstr "أتود حذف كلمة السر المحفوظة؟"
|
||||
|
||||
msgctxt "#30370"
|
||||
msgid "Do you want to manually enter a server url?"
|
||||
msgstr "أتود إدخال رابط الخادم يدويا؟"
|
||||
|
||||
msgctxt "#30373"
|
||||
msgid "Scanning for local servers"
|
||||
msgstr "يبحث عن خوادم داخل شبكة المنزل"
|
||||
|
||||
msgctxt "#30393"
|
||||
msgid "Clear Cache Result"
|
||||
msgstr "حذف نتائج الذاكرة المؤقتة"
|
||||
|
||||
msgctxt "#30394"
|
||||
msgid "Cache files deleted"
|
||||
msgstr "حُذفت ملفات الذاكرة المؤقتة"
|
||||
|
||||
msgctxt "#30398"
|
||||
msgid "Refresh Jellyfin Metadata"
|
||||
msgstr "حدث البيانات الوصفية"
|
||||
|
||||
msgctxt "#30401"
|
||||
msgid "Info"
|
||||
msgstr "المعلومات"
|
||||
|
||||
msgctxt "#30412"
|
||||
msgid " - Decades"
|
||||
msgstr "- عقود"
|
||||
|
||||
msgctxt "#30416"
|
||||
msgid "HTTP timeout seconds"
|
||||
msgstr "مدة الانتظار قبل قطع الاتصال لـ (بروتوكول نقل النص الفائق)"
|
||||
|
||||
msgctxt "#30420"
|
||||
msgid "Audio max channels"
|
||||
msgstr "الحد الأقصى لقنوات الصوت"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "حدث خطأ خلال تسجيل الدخول"
|
||||
|
||||
msgctxt "#30363"
|
||||
msgid "Save Password?"
|
||||
msgstr "أتود حفظ كلمة السر؟"
|
||||
|
||||
msgctxt "#30371"
|
||||
msgid "Could not connect to the URL you entered, do you want to try again?"
|
||||
msgstr "فشل الاتصال بالرابط المُدخل، أتود المحاولة مرة أخرى؟"
|
||||
|
||||
msgctxt "#30372"
|
||||
msgid "Server URL"
|
||||
msgstr "رابط الخادم"
|
||||
|
||||
msgctxt "#30381"
|
||||
msgid "More than one"
|
||||
msgstr "أكثر من واحدا"
|
||||
|
||||
msgctxt "#30392"
|
||||
msgid "HTTPS"
|
||||
msgstr "بروتوكول نقل النص الفائق الآمن"
|
||||
|
||||
msgctxt "#30399"
|
||||
msgid "Hide"
|
||||
msgstr "إخفاء"
|
||||
|
||||
msgctxt "#30403"
|
||||
msgid "Movies - Recommendations"
|
||||
msgstr "الأفلام - التوصيات"
|
||||
|
||||
msgctxt "#30418"
|
||||
msgid "Audio bitrate (Kbits)"
|
||||
msgstr "معدل نقل البت (بالكيلو بتّ بالثانية)"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "استئناف المشاهدة"
|
||||
|
||||
msgctxt "#30402"
|
||||
msgid "Add to Kodi Playlist"
|
||||
msgstr "أضفها إلى قائمة كودي"
|
||||
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "الفنانين"
|
||||
|
||||
msgctxt "#30352"
|
||||
msgid "Music - Frequently Played"
|
||||
msgstr "موسيقى - شُغلت مرارا"
|
||||
|
||||
msgctxt "#30365"
|
||||
msgid "Manual Login"
|
||||
msgstr "تسجيل الدخول يدويا"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
msgstr "- المفضلة"
|
||||
|
||||
msgctxt "#30382"
|
||||
msgid "Always"
|
||||
msgstr "دائما"
|
||||
|
||||
msgctxt "#30388"
|
||||
msgid "Server details"
|
||||
msgstr "تفاصيل الخادم"
|
||||
|
||||
msgctxt "#30389"
|
||||
msgid "User details"
|
||||
msgstr "تفاصيل المستخدم"
|
||||
|
||||
msgctxt "#30391"
|
||||
msgid "HTTP"
|
||||
msgstr "بروتوكول نقل النص الفائق"
|
||||
|
||||
msgctxt "#30405"
|
||||
msgid " - Show All"
|
||||
msgstr "- أظهر الكل"
|
||||
|
||||
msgctxt "#30406"
|
||||
msgid "Jellyfin Libraries"
|
||||
msgstr "مكتبات Jellyfin"
|
||||
|
||||
msgctxt "#30411"
|
||||
msgid " - Years"
|
||||
msgstr "- السنوات"
|
||||
|
||||
msgctxt "#30417"
|
||||
msgid "You do not have permision to delete this item"
|
||||
msgstr "لست مُخول لحذف هذا"
|
||||
|
||||
msgctxt "#30423"
|
||||
msgid "NotSet"
|
||||
msgstr "لم تُضبط الإعدادات"
|
||||
|
||||
msgctxt "#30419"
|
||||
msgid "Audio codec"
|
||||
msgstr "ترميز الصوت"
|
||||
|
||||
msgctxt "#30424"
|
||||
msgid "Default"
|
||||
msgstr "افتراضي"
|
||||
|
||||
msgctxt "#30425"
|
||||
msgid "Year"
|
||||
msgstr "سنة"
|
||||
|
||||
msgctxt "#30426"
|
||||
msgid "Title"
|
||||
msgstr "العنوان"
|
||||
|
||||
msgctxt "#30427"
|
||||
msgid "Added"
|
||||
msgstr "اُضيف"
|
||||
|
||||
msgctxt "#30428"
|
||||
msgid "Rating"
|
||||
msgstr "التقييم"
|
||||
|
||||
msgctxt "#30429"
|
||||
msgid "Genre"
|
||||
msgstr "التصنيف الأدبي"
|
||||
|
||||
msgctxt "#30431"
|
||||
msgid "Seasons"
|
||||
msgstr "المواسم"
|
||||
|
||||
msgctxt "#30432"
|
||||
msgid "Hide watched items in lists"
|
||||
msgstr "اخفي العناصر المُشاهدة من القائمة"
|
||||
|
||||
msgctxt "#30433"
|
||||
msgid "Allow direct file playback"
|
||||
msgstr "اسمح بالمشاهدة المباشرة"
|
||||
|
||||
msgctxt "#30435"
|
||||
msgid "Connection speed test"
|
||||
msgstr "اختبار سرعة الاتصال"
|
||||
|
||||
msgctxt "#30437"
|
||||
msgid "Playback options"
|
||||
msgstr "إعدادات التشغيل"
|
||||
|
||||
msgctxt "#30440"
|
||||
msgid "Play next"
|
||||
msgstr "شغل التالي"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "عشوائي"
|
||||
|
||||
msgctxt "#30353"
|
||||
msgid " - Frequently Played"
|
||||
msgstr "- شُغلت مرارا"
|
||||
|
||||
msgctxt "#30362"
|
||||
msgid " - Recordings"
|
||||
msgstr "- المُسجلات"
|
||||
|
||||
msgctxt "#30383"
|
||||
msgid "System - "
|
||||
msgstr "النظام -"
|
||||
|
||||
msgctxt "#30397"
|
||||
msgid " - Pages"
|
||||
msgstr "- الصفحات"
|
||||
|
||||
msgctxt "#30404"
|
||||
msgid " - A-Z"
|
||||
msgstr "- من أ إلى ي"
|
||||
|
||||
msgctxt "#30434"
|
||||
msgid "Force transcode stream bitrate (Kbits)"
|
||||
msgstr "إجبار الترميز على معدل نقل البت (بالكيلو بتّ بالثانية)"
|
||||
|
||||
244
resources/language/resource.language.ca/strings.po
Normal file
244
resources/language/resource.language.ca/strings.po
Normal file
@@ -0,0 +1,244 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2023-02-13 01:39+0000\n"
|
||||
"Last-Translator: jolupa <jolupameister@gmail.com>\n"
|
||||
"Language-Team: Catalan <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/ca/>\n"
|
||||
"Language: ca\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "Verifica el certificat HTTPS"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "Contrasenya"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[Canvia usuari]"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "Jellyfin"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "Nombre d'elements a mostrar a la llista filtrada"
|
||||
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
msgstr "Aplana sessions úniques"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "Nom d'usuari:"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "Esborran"
|
||||
|
||||
msgctxt "#30063"
|
||||
msgid "N/A"
|
||||
msgstr "No Permès"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "Serveis"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "Recuperant Dades"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "Afegir nombre de no vistes als noms"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "Mostrar la progressió de la carrega"
|
||||
|
||||
msgctxt "#30125"
|
||||
msgid "Done"
|
||||
msgstr "Fet"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "Afegeix (cc) si hi han subtítols disponibles"
|
||||
|
||||
msgctxt "#30167"
|
||||
msgid "Selected Server Address"
|
||||
msgstr "Adreça del servidor seleccionat"
|
||||
|
||||
msgctxt "#30169"
|
||||
msgid "Address: "
|
||||
msgstr "Adreça:"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
msgstr "Inclou sipnosi"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "Error en la URL"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
msgstr "Reproducció"
|
||||
|
||||
msgctxt "#30209"
|
||||
msgid "File direct path"
|
||||
msgstr "Ruta directa el fitxer"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Servidor"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "Nom d'usuari"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Nom d'usuari de Samba"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Contrasenya de Samba"
|
||||
|
||||
msgctxt "#30010"
|
||||
msgid "Number of performance profiles to capture"
|
||||
msgstr "Nombre de perfils de rendiment a capturar"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[Detecta el servidor local]"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "Temporitzador de dates del registre"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "Nom del dispositiu emissor"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "Mostrar clients conectats"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "Format del nom d'episodis filtrats"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "Mostra tots els episodis"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "Avançat"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "Amaga els detalls dels episodis no vistos"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "Contrasenya:"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "Acció al selecionar article d'un giny"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "Activar el registre de depuració"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "Nom d'Usuari/Contrasenya incorrectes"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "No s'ha trobat l'usuari"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "Esperant que sigui esborrat per el servidor"
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "Confirmes que el vols esborrar?"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr "Atenció: Això esborrarà els fitxers dels servidors."
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "Interfície"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "Carregant Contingut"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Saltar enrera segons"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
msgstr "Afegir percentatge de resum als noms"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "Retoman"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
msgstr "Processant l'article:"
|
||||
|
||||
msgctxt "#30139"
|
||||
msgid "No Media Type Set"
|
||||
msgstr "No s'ha fixat cap tipus de media"
|
||||
|
||||
msgctxt "#30166"
|
||||
msgid "Select Server"
|
||||
msgstr "Selecciona un servidor"
|
||||
|
||||
msgctxt "#30180"
|
||||
msgid "Select User"
|
||||
msgstr "Selecciona Usuari"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
msgstr "Inclou informació del contingut multimèdia"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "Inclou persones"
|
||||
|
||||
msgctxt "#30201"
|
||||
msgid "Unable to connect to server"
|
||||
msgstr "Imposible conectar al servidor"
|
||||
|
||||
msgctxt "#30206"
|
||||
msgid "Playback type"
|
||||
msgstr "Tipus de reproducció"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "Màxim bitrate del contingut (Kbps)"
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-10-04 05:54+0000\n"
|
||||
"Last-Translator: Adammantium <flubber98@web.de>\n"
|
||||
"PO-Revision-Date: 2023-02-02 09:51+0000\n"
|
||||
"Last-Translator: KingArthvr_ <arthurruckdeschel@gmail.com>\n"
|
||||
"Language-Team: German <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/de/>\n"
|
||||
"Language: de\n"
|
||||
@@ -1117,3 +1117,11 @@ msgstr "Bei der Anmeldung ist ein Fehler aufgetreten"
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "Zeige \"Nächste Episode\" bei verbleibender Zeit in Sekunden"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Maximale Länge der Warteschlange"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Zufallswiedergabe"
|
||||
|
||||
@@ -1,2 +1,154 @@
|
||||
msgid ""
|
||||
msgstr "X-Generator: Weblate\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit"
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2023-01-08 19:51+0000\n"
|
||||
"Last-Translator: Retrial <giwrgosmant@gmail.com>\n"
|
||||
"Language-Team: Greek <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/el/>\n"
|
||||
"Language: el\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Host"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Port"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "Επαληθεύστε το πιστοποιητικό HTTPS"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "Όνομα χρήστη"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "Κωδικός πρόσβασης"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Όνομα χρήστη Samba"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Κωδικός πρόσβασης Samba"
|
||||
|
||||
msgctxt "#30010"
|
||||
msgid "Number of performance profiles to capture"
|
||||
msgstr "Αριθμός προφίλ απόδοσης προς καταγραφή"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[Εντοπισμός τοπικού διακομιστή]"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[Αλλαγή χρήστη]"
|
||||
|
||||
msgctxt "#30014"
|
||||
msgid "Jellyfin"
|
||||
msgstr "Jellyfin"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "Καταγραφή δεδομένων χρονισμού"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "Εμφάνιση συνδεδεμένων πελατών"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "Αριθμός στοιχείων προς εμφάνιση σε φιλτραρισμένες λίστες"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "Φιλτραρισμένη μορφή ονόματος επεισοδίου"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "Εμφάνιση όλων των επεισοδίων"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "Όνομα χρήστη:"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "Κωδικός πρόσβασης:"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "Το όνομα χρήστη δεν βρέθηκε"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "Διαγραφή"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "Αναμονή για διαγραφή διακομιστή"
|
||||
|
||||
msgctxt "#30063"
|
||||
msgid "N/A"
|
||||
msgstr "N/A"
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "Διεπαφή"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "Υπηρεσίες"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "Ανάκτηση Δεδομένων"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "Πήδηξε πίσω δευτερόλεπτα"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "Εμφάνιση της προόδου φόρτωσης"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "Εμφανιζόμενο όνομα συσκευής"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "Απόκρυψη λεπτομερειών επεισοδίου που δεν έχετε παρακολουθήσει"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "Επιλογή ενέργειας στοιχείου widget"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "Ενεργοποίηση καταγραφής εντοπισμού σφαλμάτων"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "Λανθασμένο Όνομα χρήστη/Κωδικός πρόσβασης"
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "Επιβεβαίωση διαγραφής;"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr ""
|
||||
"Προειδοποίηση: Αυτή η ενέργεια θα διαγράψει τα αρχεία πολυμέσων από τον "
|
||||
"διακομιστή."
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "Φόρτωση Περιεχομένου"
|
||||
|
||||
@@ -1108,3 +1108,15 @@ msgstr "Continue Watching"
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "There was an error logging in"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Max Play Queue Size"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Shuffle"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Instant Mix"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-09-24 20:54+0000\n"
|
||||
"Last-Translator: Ariel Martín Estévez <arudamartineti@gmail.com>\n"
|
||||
"PO-Revision-Date: 2023-01-24 07:51+0000\n"
|
||||
"Last-Translator: Ecor <elias.coronado@uabc.edu.mx>\n"
|
||||
"Language-Team: Spanish <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/es/>\n"
|
||||
"Language: es\n"
|
||||
@@ -1109,3 +1109,19 @@ msgstr "Continuar viendo"
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "Mostrar reproducir el próximo episodio a los segundos restantes"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Se ha producido un error al iniciar sesión"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Tamaño máximo de la cola de reproducción"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Mezcla instantánea"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Mezclar"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-10-04 05:54+0000\n"
|
||||
"PO-Revision-Date: 2023-01-10 05:51+0000\n"
|
||||
"Last-Translator: Oskari Lavinto <olavinto@protonmail.com>\n"
|
||||
"Language-Team: Finnish <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/fi/>\n"
|
||||
@@ -1113,3 +1113,15 @@ msgstr ""
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Kirjauduttaessa tapahtui virhe"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Sekoitus"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Toistojonon enimmäiskoko"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Pikamiksaus"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-10-26 13:50+0000\n"
|
||||
"Last-Translator: Kilian <kilian.pichard@protonmail.com>\n"
|
||||
"PO-Revision-Date: 2023-01-17 19:51+0000\n"
|
||||
"Last-Translator: Thomas Schwery <thomas@inf3.ch>\n"
|
||||
"Language-Team: French <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/fr/>\n"
|
||||
"Language: fr\n"
|
||||
@@ -1000,7 +1000,6 @@ msgctxt "#30408"
|
||||
msgid "Custom Widgets"
|
||||
msgstr "Widgets personnalisés"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30416"
|
||||
msgid "HTTP timeout seconds"
|
||||
msgstr "Délai HTTP en secondes"
|
||||
@@ -1051,7 +1050,7 @@ msgstr "Vérification simple du nouveau contenu"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Quick Connect"
|
||||
msgstr "Connexion rapide"
|
||||
|
||||
msgctxt "#30367"
|
||||
msgid "Allow fast user switching password saving"
|
||||
@@ -1074,12 +1073,10 @@ msgctxt "#30400"
|
||||
msgid "Cache images interval minutes (0 = disabled)"
|
||||
msgstr "Intervalle de mise en cache des images en minutes (0 = désactivé)"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30409"
|
||||
msgid "Add-on Actions"
|
||||
msgstr "Actions complémentaires"
|
||||
msgstr "Add-on Actions"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30430"
|
||||
msgid "Label"
|
||||
msgstr "Étiquette"
|
||||
@@ -1115,3 +1112,15 @@ msgstr "Continuer à regarder"
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Il y a eu une erreur de connexion"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Taille maximale de la file d'attente"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Aléatoire"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Mix instantané"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-10-04 05:54+0000\n"
|
||||
"PO-Revision-Date: 2023-01-10 05:51+0000\n"
|
||||
"Last-Translator: Csaba <csab0825@gmail.com>\n"
|
||||
"Language-Team: Hungarian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/hu/>\n"
|
||||
@@ -1111,3 +1111,15 @@ msgstr "A következő epizód lejátszása a másodpercben hátralévő időpont
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Hiba történt a bejelentkezéskor"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Keverés"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Lejátszási sor maximális mérete"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Instant keverés"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-08-15 12:40+0000\n"
|
||||
"Last-Translator: Arief Hidayat <kekesed97@gmail.com>\n"
|
||||
"PO-Revision-Date: 2023-02-15 10:39+0000\n"
|
||||
"Last-Translator: Imamuzzaki Abu Salam <imamuzzaki@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 4.13.1\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
@@ -1101,3 +1101,24 @@ msgstr "Jumlah profil performa"
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Host"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Acak"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Maksimum Ukuran Antrian Putar"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr ""
|
||||
"Tampilkan putar episode berikutnya dengan waktu yang tersisa dalam detik"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Terjadi kesalahan saat masuk"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Campuran Instan"
|
||||
|
||||
396
resources/language/resource.language.ko/strings.po
Normal file
396
resources/language/resource.language.ko/strings.po
Normal file
@@ -0,0 +1,396 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-11-23 06:51+0000\n"
|
||||
"Last-Translator: wolfwork <wolfdate25@naver.com>\n"
|
||||
"Language-Team: Korean <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/ko/>\n"
|
||||
"Language: ko\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30006"
|
||||
msgid "Password"
|
||||
msgstr "비밀번호"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
msgstr "비밀번호:"
|
||||
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "위젯 항목 선택 작업"
|
||||
|
||||
msgctxt "#30045"
|
||||
msgid "Username not found"
|
||||
msgstr "사용자 이름을 찾을 수 없습니다"
|
||||
|
||||
msgctxt "#30112"
|
||||
msgid "Loading Content"
|
||||
msgstr "콘텐츠 로드 중"
|
||||
|
||||
msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "로드 진행률 표시"
|
||||
|
||||
msgctxt "#30121"
|
||||
msgid "On resume"
|
||||
msgstr "재개 시"
|
||||
|
||||
msgctxt "#30166"
|
||||
msgid "Select Server"
|
||||
msgstr "서버 선택"
|
||||
|
||||
msgctxt "#30212"
|
||||
msgid "Video max width"
|
||||
msgstr "비디오 최대 길이"
|
||||
|
||||
msgctxt "#30251"
|
||||
msgid "Movies - Genres"
|
||||
msgstr "영화 - 장르"
|
||||
|
||||
msgctxt "#30264"
|
||||
msgid "Episodes - In Progress"
|
||||
msgstr "에피소드 - 진행 중"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
msgstr "영화 - 랜덤"
|
||||
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "호스트"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "포트"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "HTTPS 인증서 확인"
|
||||
|
||||
msgctxt "#30005"
|
||||
msgid "Username"
|
||||
msgstr "사용자 이름"
|
||||
|
||||
msgctxt "#30007"
|
||||
msgid "Samba username"
|
||||
msgstr "Samba 사용자이름"
|
||||
|
||||
msgctxt "#30008"
|
||||
msgid "Samba password"
|
||||
msgstr "Samba 비밀번호"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[로컬 서버 찾기]"
|
||||
|
||||
msgctxt "#30012"
|
||||
msgid "[Change user]"
|
||||
msgstr "[사용자 변경]"
|
||||
|
||||
msgctxt "#30015"
|
||||
msgid "Log timing data"
|
||||
msgstr "로그 타이밍 데이터"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "장치 표시 이름"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "연결된 클라이언트 표시"
|
||||
|
||||
msgctxt "#30018"
|
||||
msgid "Number of items to show in filtered lists"
|
||||
msgstr "필터링된 목록에 표시할 항목 수"
|
||||
|
||||
msgctxt "#30019"
|
||||
msgid "Filtered episode name format"
|
||||
msgstr "필터링된 에피소드 이름 형식"
|
||||
|
||||
msgctxt "#30021"
|
||||
msgid "Show all episodes item"
|
||||
msgstr "모든 에피소드 보기"
|
||||
|
||||
msgctxt "#30022"
|
||||
msgid "Advanced"
|
||||
msgstr "고급"
|
||||
|
||||
msgctxt "#30023"
|
||||
msgid "Hide unwatched episode details"
|
||||
msgstr "시청하지 않은 에피소드 세부정보 숨기기"
|
||||
|
||||
msgctxt "#30024"
|
||||
msgid "Username:"
|
||||
msgstr "사용자이름:"
|
||||
|
||||
msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "디버그 로깅 활성화"
|
||||
|
||||
msgctxt "#30044"
|
||||
msgid "Incorrect Username/Password"
|
||||
msgstr "잘못된 사용자이름/비밀번호"
|
||||
|
||||
msgctxt "#30052"
|
||||
msgid "Deleting"
|
||||
msgstr "삭제 중"
|
||||
|
||||
msgctxt "#30053"
|
||||
msgid "Waiting for server to delete"
|
||||
msgstr "서버에서 삭제 대기 중"
|
||||
|
||||
msgctxt "#30091"
|
||||
msgid "Confirm delete?"
|
||||
msgstr "삭제하시겠습니까?"
|
||||
|
||||
msgctxt "#30092"
|
||||
msgid "Warning: This action will delete the media files from the server."
|
||||
msgstr "경고: 이 작업은 서버에서 미디어 파일을 삭제합니다."
|
||||
|
||||
msgctxt "#30110"
|
||||
msgid "Interface"
|
||||
msgstr "인터페이스"
|
||||
|
||||
msgctxt "#30111"
|
||||
msgid "Services"
|
||||
msgstr "서비스"
|
||||
|
||||
msgctxt "#30113"
|
||||
msgid "Retrieving Data"
|
||||
msgstr "데이터 수신 중"
|
||||
|
||||
msgctxt "#30114"
|
||||
msgid "Jump back seconds"
|
||||
msgstr "초 뒤로 이동"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
msgstr "이름에 시청하지 않은 카운트 수 추가"
|
||||
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
msgstr "이름에 재개율 추가"
|
||||
|
||||
msgctxt "#30125"
|
||||
msgid "Done"
|
||||
msgstr "완료"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
msgstr "진행중인 항목:"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "오류"
|
||||
|
||||
msgctxt "#30139"
|
||||
msgid "No Media Type Set"
|
||||
msgstr "미디어 타입 설정 안됨"
|
||||
|
||||
msgctxt "#30163"
|
||||
msgid "Add (cc) if subtitle is available"
|
||||
msgstr "자막이 존재할 경우 (cc) 추가"
|
||||
|
||||
msgctxt "#30167"
|
||||
msgid "Selected Server Address"
|
||||
msgstr "선택된 서버 주소"
|
||||
|
||||
msgctxt "#30169"
|
||||
msgid "Address: "
|
||||
msgstr "주소:"
|
||||
|
||||
msgctxt "#30180"
|
||||
msgid "Select User"
|
||||
msgstr "사용자 선택"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
msgstr "플롯 포함"
|
||||
|
||||
msgctxt "#30182"
|
||||
msgid "Include media stream info"
|
||||
msgstr "미디어 스트림 정보 포함"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "사람 포함"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "URL 오류"
|
||||
|
||||
msgctxt "#30201"
|
||||
msgid "Unable to connect to server"
|
||||
msgstr "서버에 연결할 수 없습니다"
|
||||
|
||||
msgctxt "#30206"
|
||||
msgid "Playback type"
|
||||
msgstr "재생 유형"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
msgstr "재생"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "최대 스트림 비트레이트 (Kbps)"
|
||||
|
||||
msgctxt "#30209"
|
||||
msgid "File direct path"
|
||||
msgstr "파일 직접 경로"
|
||||
|
||||
msgctxt "#30210"
|
||||
msgid "HTTP direct stream"
|
||||
msgstr "HTTP 직접 스트림"
|
||||
|
||||
msgctxt "#30211"
|
||||
msgid "Transcode options"
|
||||
msgstr "트랜스코드 옵션"
|
||||
|
||||
msgctxt "#30213"
|
||||
msgid "Video force 8 bit"
|
||||
msgstr "비디오 강제 8 bit"
|
||||
|
||||
msgctxt "#30214"
|
||||
msgid "Events"
|
||||
msgstr "이벤트"
|
||||
|
||||
msgctxt "#30215"
|
||||
msgid "On playback stop (100% = disabled)"
|
||||
msgstr "재생 중지 시(100% = 비활성화됨)"
|
||||
|
||||
msgctxt "#30216"
|
||||
msgid "Item Details"
|
||||
msgstr "항목 세부정보"
|
||||
|
||||
msgctxt "#30218"
|
||||
msgid "Play next episode after %"
|
||||
msgstr "% 후 다음 에피소드 재생"
|
||||
|
||||
msgctxt "#30222"
|
||||
msgid "Item Layout"
|
||||
msgstr "항목 레이아웃"
|
||||
|
||||
msgctxt "#30223"
|
||||
msgid "Page Size and Filtering"
|
||||
msgstr "페이지 크기와 필터링"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
msgstr "상호작용"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV 쇼"
|
||||
|
||||
msgctxt "#30231"
|
||||
msgid "Movies"
|
||||
msgstr "영화"
|
||||
|
||||
msgctxt "#30235"
|
||||
msgid "Episodes"
|
||||
msgstr "에피소드"
|
||||
|
||||
msgctxt "#30236"
|
||||
msgid "Force transcode h265 (hevc)"
|
||||
msgstr "강제 트랜스코드 h265 (hevc)"
|
||||
|
||||
msgctxt "#30237"
|
||||
msgid "Start from beginning"
|
||||
msgstr "처음부터 시작"
|
||||
|
||||
msgctxt "#30238"
|
||||
msgid "Playback stream options"
|
||||
msgstr "재생 스트림 옵션"
|
||||
|
||||
msgctxt "#30239"
|
||||
msgid "Force transcode mpeg2"
|
||||
msgstr "강제 트랜스코드 mpeg2"
|
||||
|
||||
msgctxt "#30240"
|
||||
msgid "Force transcode msmpeg4v3 (divx)"
|
||||
msgstr "강제 트랜스코드 msmpeg4v3 (divx)"
|
||||
|
||||
msgctxt "#30241"
|
||||
msgid "Force transcode mpeg4"
|
||||
msgstr "강제 트랜스코드 mpeg4"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
msgstr "검색"
|
||||
|
||||
msgctxt "#30247"
|
||||
msgid "Custom Widget Content"
|
||||
msgstr "사용자 지정 위젯 콘텐츠"
|
||||
|
||||
msgctxt "#30250"
|
||||
msgid "Unknown"
|
||||
msgstr "알수없음"
|
||||
|
||||
msgctxt "#30252"
|
||||
msgid "Movies - A-Z"
|
||||
msgstr "영화 - A-Z"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
msgstr "에드온 설정 보기"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "TV 쇼 - A-Z"
|
||||
|
||||
msgctxt "#30256"
|
||||
msgid "Movies"
|
||||
msgstr "영화"
|
||||
|
||||
msgctxt "#30257"
|
||||
msgid "Movies - Recently Added"
|
||||
msgstr "영화 - 최근에 추가됨"
|
||||
|
||||
msgctxt "#30258"
|
||||
msgid "Movies - In Progress"
|
||||
msgstr "영화 - 진행 중"
|
||||
|
||||
msgctxt "#30259"
|
||||
msgid "Movies - Favorites"
|
||||
msgstr "영화 - 즐겨찾기"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV 쇼"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "TV 쇼 - 즐겨찾기"
|
||||
|
||||
msgctxt "#30263"
|
||||
msgid "Episodes - Recently Added"
|
||||
msgstr "에피소드 - 최근에 추가됨"
|
||||
|
||||
msgctxt "#30266"
|
||||
msgid "Movies - Pages"
|
||||
msgstr "영화 - 페이지"
|
||||
|
||||
msgctxt "#30267"
|
||||
msgid " - In Progress"
|
||||
msgstr "- 진행 중"
|
||||
|
||||
msgctxt "#30268"
|
||||
msgid " - Recently Added"
|
||||
msgstr "- 최근에 추가됨"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
msgstr "본 것으로 표시"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "본 것으로 표시해제"
|
||||
|
||||
msgctxt "#30272"
|
||||
msgid "Set Favourite"
|
||||
msgstr "즐겨찾기 설정"
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-10-01 13:54+0000\n"
|
||||
"Last-Translator: Thanos <ahmetspam.42@hotmail.com>\n"
|
||||
"PO-Revision-Date: 2023-02-16 21:39+0000\n"
|
||||
"Last-Translator: Ruben Kremer <rubenkremer@gmail.com>\n"
|
||||
"Language-Team: Dutch <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/nl/>\n"
|
||||
"Language: nl\n"
|
||||
@@ -21,7 +21,7 @@ msgstr "Films"
|
||||
|
||||
msgctxt "#30255"
|
||||
msgid "TV Shows - A-Z"
|
||||
msgstr "TV Shows - A-Z"
|
||||
msgstr "TV Series - A-Z"
|
||||
|
||||
msgctxt "#30254"
|
||||
msgid "Show add-on settings"
|
||||
@@ -41,7 +41,7 @@ msgstr "Onbekend"
|
||||
|
||||
msgctxt "#30247"
|
||||
msgid "Custom Widget Content"
|
||||
msgstr "Custom Widget Inhoud"
|
||||
msgstr "Aangepaste widget inhoud"
|
||||
|
||||
msgctxt "#30246"
|
||||
msgid "Search"
|
||||
@@ -81,7 +81,7 @@ msgstr "Films"
|
||||
|
||||
msgctxt "#30229"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV Shows"
|
||||
msgstr "TV Series"
|
||||
|
||||
msgctxt "#30224"
|
||||
msgid "Interaction"
|
||||
@@ -89,7 +89,7 @@ msgstr "Interactie"
|
||||
|
||||
msgctxt "#30216"
|
||||
msgid "Item Details"
|
||||
msgstr "Item Details"
|
||||
msgstr "Item details"
|
||||
|
||||
msgctxt "#30223"
|
||||
msgid "Page Size and Filtering"
|
||||
@@ -97,7 +97,7 @@ msgstr "Paginagrootte en Filteren"
|
||||
|
||||
msgctxt "#30222"
|
||||
msgid "Item Layout"
|
||||
msgstr "Item Layout"
|
||||
msgstr "Item layout"
|
||||
|
||||
msgctxt "#30220"
|
||||
msgid "Prompt to delete movie after %"
|
||||
@@ -145,7 +145,7 @@ msgstr "Directe bestandslocatie"
|
||||
|
||||
msgctxt "#30208"
|
||||
msgid "Max stream bitrate (Kbits)"
|
||||
msgstr "Maximale stream bitrate (Kbps)"
|
||||
msgstr "Maximale stream bitsnelheid (Kbps)"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
@@ -161,7 +161,7 @@ msgstr "Kan niet verbinden met de server"
|
||||
|
||||
msgctxt "#30200"
|
||||
msgid "URL error"
|
||||
msgstr "URL error"
|
||||
msgstr "URL fout"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
@@ -201,7 +201,7 @@ msgstr "Geen mediatype ingesteld"
|
||||
|
||||
msgctxt "#30135"
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
msgstr "Fout"
|
||||
|
||||
msgctxt "#30126"
|
||||
msgid "Processing Item : "
|
||||
@@ -219,10 +219,9 @@ msgctxt "#30120"
|
||||
msgid "Show load progress"
|
||||
msgstr "Toon laadvoortgang"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30118"
|
||||
msgid "Add resume percent to names"
|
||||
msgstr "Voeg percentage bekeken toe aan namen"
|
||||
msgstr "Voeg bekeken percentage toe aan namen"
|
||||
|
||||
msgctxt "#30116"
|
||||
msgid "Add unwatched counts to names"
|
||||
@@ -280,10 +279,9 @@ msgctxt "#30027"
|
||||
msgid "Enable debug logging"
|
||||
msgstr "Schakel debug logging in"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30026"
|
||||
msgid "Widget item select action"
|
||||
msgstr "Widget item selecteer actie"
|
||||
msgstr "Widget onderdeel selecteer actie"
|
||||
|
||||
msgctxt "#30025"
|
||||
msgid "Password:"
|
||||
@@ -371,15 +369,15 @@ msgstr "Host"
|
||||
|
||||
msgctxt "#30352"
|
||||
msgid "Music - Frequently Played"
|
||||
msgstr "Muziek - Vaak Afgespeeld"
|
||||
msgstr "Muziek - Vaak afgespeeld"
|
||||
|
||||
msgctxt "#30351"
|
||||
msgid "Music - Recently Played"
|
||||
msgstr "Muziek - Recent Afgespeeld"
|
||||
msgstr "Muziek - Recent afgespeeld"
|
||||
|
||||
msgctxt "#30350"
|
||||
msgid "Music - Recently Added"
|
||||
msgstr "Muziek - Recent Toegevoegd"
|
||||
msgstr "Muziek - Recent toegevoegd"
|
||||
|
||||
msgctxt "#30339"
|
||||
msgid "Person"
|
||||
@@ -399,7 +397,7 @@ msgstr "Films per pagina"
|
||||
|
||||
msgctxt "#30327"
|
||||
msgid "Go To Season"
|
||||
msgstr "Ga Naar Seizoen"
|
||||
msgstr "Ga naar seizoen"
|
||||
|
||||
msgctxt "#30325"
|
||||
msgid " - Genres"
|
||||
@@ -407,7 +405,7 @@ msgstr "- Genres"
|
||||
|
||||
msgctxt "#30322"
|
||||
msgid "Auto resume"
|
||||
msgstr "Automatisch Hervatten"
|
||||
msgstr "Automatisch hervatten"
|
||||
|
||||
msgctxt "#30320"
|
||||
msgid " - Albums"
|
||||
@@ -419,7 +417,7 @@ msgstr "Muziek - Albums"
|
||||
|
||||
msgctxt "#30317"
|
||||
msgid "Play All"
|
||||
msgstr "Speel Alles Af"
|
||||
msgstr "Speel alles af"
|
||||
|
||||
msgctxt "#30316"
|
||||
msgid "Connection Error"
|
||||
@@ -431,7 +429,7 @@ msgstr "Meldingen van verbindingsfouten onderdrukken"
|
||||
|
||||
msgctxt "#30314"
|
||||
msgid "Play"
|
||||
msgstr "Speel Af"
|
||||
msgstr "Speel af"
|
||||
|
||||
msgctxt "#30313"
|
||||
msgid "Menu"
|
||||
@@ -439,23 +437,23 @@ msgstr "Menu"
|
||||
|
||||
msgctxt "#30308"
|
||||
msgid "Select Trailer"
|
||||
msgstr "Selecteer Trailer"
|
||||
msgstr "Selecteer trailer"
|
||||
|
||||
msgctxt "#30307"
|
||||
msgid "Play Trailer"
|
||||
msgstr "Speel Trailer Af"
|
||||
msgstr "Speel trailer af"
|
||||
|
||||
msgctxt "#30305"
|
||||
msgid "Not Found"
|
||||
msgstr "Niet Gevonden"
|
||||
msgstr "Niet gevonden"
|
||||
|
||||
msgctxt "#30302"
|
||||
msgid "Existing images : "
|
||||
msgstr "Bestaande Afbeeldingen:"
|
||||
msgstr "Bestaande afbeeldingen:"
|
||||
|
||||
msgctxt "#30298"
|
||||
msgid "Deleting Kodi Images"
|
||||
msgstr "Kodi Afbeeldingen Verwijderen"
|
||||
msgstr "Kodi afbeeldingen verwijderen"
|
||||
|
||||
msgctxt "#30297"
|
||||
msgid "Delete unused images?"
|
||||
@@ -475,19 +473,19 @@ msgstr "- Nieuwste"
|
||||
|
||||
msgctxt "#30286"
|
||||
msgid "Movies - Unwatched"
|
||||
msgstr "Films - Niet Bekeken"
|
||||
msgstr "Films - Niet bekeken"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
msgstr "- Niet Bekeken"
|
||||
msgstr "- Niet bekeken"
|
||||
|
||||
msgctxt "#30283"
|
||||
msgid "Play Next Episode?"
|
||||
msgstr "Speel Volgende Aflevering Af?"
|
||||
msgstr "Speel volgende aflevering af?"
|
||||
|
||||
msgctxt "#30282"
|
||||
msgid "No Jellyfin servers detected on your local network."
|
||||
msgstr "Geen Jellyfin Servers Gevonden Op Uw Lokale Netwerk."
|
||||
msgstr "Geen Jellyfin servers gevonden op jouw lokale netwerk."
|
||||
|
||||
msgctxt "#30280"
|
||||
msgid "Missing Title"
|
||||
@@ -507,19 +505,19 @@ msgstr "Verwijderen"
|
||||
|
||||
msgctxt "#30273"
|
||||
msgid "Unset Favourite"
|
||||
msgstr "Demarkeer Favoriet"
|
||||
msgstr "Favoriet ongedaan maken"
|
||||
|
||||
msgctxt "#30272"
|
||||
msgid "Set Favourite"
|
||||
msgstr "Markeer Favoriet"
|
||||
msgstr "Markeer als favoriet"
|
||||
|
||||
msgctxt "#30271"
|
||||
msgid "Mark Unwatched"
|
||||
msgstr "Markeer Niet Bekeken"
|
||||
msgstr "Markeer als niet-bekeken"
|
||||
|
||||
msgctxt "#30270"
|
||||
msgid "Mark Watched"
|
||||
msgstr "Markeer Bekeken"
|
||||
msgstr "Markeer als bekeken"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
@@ -600,7 +598,7 @@ msgstr ""
|
||||
|
||||
msgctxt "#30301"
|
||||
msgid "Caching Images"
|
||||
msgstr "Afbeeldingen Worden In Cache Geplaatst"
|
||||
msgstr "Afbeeldingen worden in cache geplaatst"
|
||||
|
||||
msgctxt "#30293"
|
||||
msgid "Cache images"
|
||||
@@ -608,7 +606,7 @@ msgstr "Afbeeldingen Cachen"
|
||||
|
||||
msgctxt "#30299"
|
||||
msgid "Cache Images"
|
||||
msgstr "Afbeeldingen Cachen"
|
||||
msgstr "Afbeeldingen cachen"
|
||||
|
||||
msgctxt "#30295"
|
||||
msgid "To use this feature you need HTTP control enabled"
|
||||
@@ -628,11 +626,11 @@ msgstr "Selecteer Audiostream"
|
||||
|
||||
msgctxt "#30289"
|
||||
msgid "TV Shows - Genres"
|
||||
msgstr "TV Shows - Genres"
|
||||
msgstr "TV Series - Genres"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "TV Shows - Nieuwste"
|
||||
msgstr "TV Series - Nieuwste"
|
||||
|
||||
msgctxt "#30281"
|
||||
msgid "Refresh Cached Images"
|
||||
@@ -640,7 +638,7 @@ msgstr "Ververs afbeeldingen in cache"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
msgstr "TV Shows - Niet bekeken"
|
||||
msgstr "TV Series - Niet bekeken"
|
||||
|
||||
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?"
|
||||
@@ -675,38 +673,35 @@ msgstr "Afleveringen - Recent Toegevoegd"
|
||||
|
||||
msgctxt "#30262"
|
||||
msgid "TV Shows - Favorites"
|
||||
msgstr "TV Shows - Favorieten"
|
||||
msgstr "TV Series - Favorieten"
|
||||
|
||||
msgctxt "#30261"
|
||||
msgid "TV Shows"
|
||||
msgstr "TV Shows"
|
||||
msgstr "TV Series"
|
||||
|
||||
msgctxt "#30260"
|
||||
msgid "BoxSets"
|
||||
msgstr "Boxsets"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30020"
|
||||
msgid "Flatten single season"
|
||||
msgstr "Enkel seizoen afvlakken"
|
||||
msgstr "Enkel seizoen samenvoegen"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Doorgaan met kijken"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
msgstr "Log in met snel verbinden"
|
||||
msgstr "Log in met Quick Connect"
|
||||
|
||||
msgctxt "#30443"
|
||||
msgid "Quick Connect"
|
||||
msgstr "Snel verbinden"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30442"
|
||||
msgid "Simple new content check"
|
||||
msgstr "Simpele nieuwe content check"
|
||||
msgstr "Simpele nieuwe inhoudscheck"
|
||||
|
||||
msgctxt "#30441"
|
||||
msgid "Use cached widget data"
|
||||
@@ -716,10 +711,9 @@ msgctxt "#30440"
|
||||
msgid "Play next"
|
||||
msgstr "Volgende afspelen"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "Toon speel volgende aflevering in laatste % seconden"
|
||||
msgstr "Toon speel volgende aflevering in laatste seconden"
|
||||
|
||||
msgctxt "#30438"
|
||||
msgid "Play cinema intros"
|
||||
@@ -803,7 +797,7 @@ msgstr "Audio codec"
|
||||
|
||||
msgctxt "#30418"
|
||||
msgid "Audio bitrate (Kbits)"
|
||||
msgstr "Audiobisnelheid (Kbps)"
|
||||
msgstr "Audio bitsnelheid (Kbps)"
|
||||
|
||||
msgctxt "#30417"
|
||||
msgid "You do not have permision to delete this item"
|
||||
@@ -815,7 +809,7 @@ msgstr "HTTP timeout seconden"
|
||||
|
||||
msgctxt "#30415"
|
||||
msgid " - Favorite Collections"
|
||||
msgstr "- Favoriete Collecties"
|
||||
msgstr "- Favoriete collecties"
|
||||
|
||||
msgctxt "#30414"
|
||||
msgid " - Favorites"
|
||||
@@ -827,7 +821,7 @@ msgstr "- Tags"
|
||||
|
||||
msgctxt "#30412"
|
||||
msgid " - Decades"
|
||||
msgstr "- Millenia"
|
||||
msgstr "- Decennia"
|
||||
|
||||
msgctxt "#30411"
|
||||
msgid " - Years"
|
||||
@@ -839,7 +833,7 @@ msgstr "- Collecties"
|
||||
|
||||
msgctxt "#30409"
|
||||
msgid "Add-on Actions"
|
||||
msgstr "Add-on Acties"
|
||||
msgstr "Add-on acties"
|
||||
|
||||
msgctxt "#30408"
|
||||
msgid "Custom Widgets"
|
||||
@@ -883,7 +877,7 @@ msgstr "Verbergen"
|
||||
|
||||
msgctxt "#30398"
|
||||
msgid "Refresh Jellyfin Metadata"
|
||||
msgstr "Ververs Jellyfin Metadata"
|
||||
msgstr "Ververs Jellyfin metadata"
|
||||
|
||||
msgctxt "#30397"
|
||||
msgid " - Pages"
|
||||
@@ -891,16 +885,15 @@ msgstr "- Pagina's"
|
||||
|
||||
msgctxt "#30395"
|
||||
msgid "Clear cached server data"
|
||||
msgstr "Verwijderd gecachede servergegevens"
|
||||
msgstr "Verwijder gecachte servergegevens"
|
||||
|
||||
msgctxt "#30394"
|
||||
msgid "Cache files deleted"
|
||||
msgstr "Cachebestanden verwijderd"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30393"
|
||||
msgid "Clear Cache Result"
|
||||
msgstr "Cache-resultaat wissen"
|
||||
msgstr "Resultaat cache wissen"
|
||||
|
||||
msgctxt "#30392"
|
||||
msgid "HTTPS"
|
||||
@@ -934,7 +927,6 @@ msgctxt "#30385"
|
||||
msgid "Existing images before delete : "
|
||||
msgstr "Bestaande afbeeldingen vóór verwijderen:"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30384"
|
||||
msgid "Random movies interval minutes (0 = disabled)"
|
||||
msgstr "Willekeurige films interval in minuten (0 = uitgeschakeld)"
|
||||
@@ -955,15 +947,13 @@ msgctxt "#30380"
|
||||
msgid "Never"
|
||||
msgstr "Nooit"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30379"
|
||||
msgid "External subtitle prompt"
|
||||
msgstr "Externe ondertitel prompt"
|
||||
msgstr "Externe ondertitel melding"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30378"
|
||||
msgid "Persist user details"
|
||||
msgstr "Blijvende gebruikersgegevens"
|
||||
msgstr "Vasthouden gebruikersgegevens"
|
||||
|
||||
msgctxt "#30377"
|
||||
msgid "Sending request"
|
||||
@@ -997,7 +987,7 @@ msgstr ""
|
||||
|
||||
msgctxt "#30369"
|
||||
msgid "Do you want to clear your saved password?"
|
||||
msgstr "Wilt u de opgeslagen wachtwoord verwijderen?"
|
||||
msgstr "Wilt u het opgeslagen wachtwoord verwijderen?"
|
||||
|
||||
msgctxt "#30370"
|
||||
msgid "Do you want to manually enter a server url?"
|
||||
@@ -1007,10 +997,9 @@ msgctxt "#30368"
|
||||
msgid "Clear Password?"
|
||||
msgstr "Wachtwoord verwijderen?"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30367"
|
||||
msgid "Allow fast user switching password saving"
|
||||
msgstr "Snel opslaan van het geschakelde gebruikerswachtwoord toestaan"
|
||||
msgstr "Snel opslaan van het gewisselde gebruikerswachtwoord toestaan"
|
||||
|
||||
msgctxt "#30366"
|
||||
msgid "Manually enter user details"
|
||||
@@ -1018,11 +1007,11 @@ msgstr "Gebruikersgegevens handmatig invoeren"
|
||||
|
||||
msgctxt "#30365"
|
||||
msgid "Manual Login"
|
||||
msgstr "Manueel inloggen"
|
||||
msgstr "Handmatig inloggen"
|
||||
|
||||
msgctxt "#30364"
|
||||
msgid "Do you want to save the password?"
|
||||
msgstr "Wil je deze wachtwoord opslaan?"
|
||||
msgstr "Wil je dit wachtwoord opslaan?"
|
||||
|
||||
msgctxt "#30363"
|
||||
msgid "Save Password?"
|
||||
@@ -1056,26 +1045,25 @@ msgctxt "#30357"
|
||||
msgid "Processing existing image list"
|
||||
msgstr "De bestaande afbeeldingenlijst aan het verwerken"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30355"
|
||||
msgid "Kodi Settings->Services->Allow remote control via HTTP"
|
||||
msgstr "Kodi Instellingen->Services->Toegang van afstand via HTTP toestaan"
|
||||
msgstr "Kodi instellingen->Services->Toegang van afstand via HTTP toestaan"
|
||||
|
||||
msgctxt "#30354"
|
||||
msgid "Go To Series"
|
||||
msgstr "Ga Naar Serie"
|
||||
msgstr "Ga naar serie"
|
||||
|
||||
msgctxt "#30353"
|
||||
msgid " - Frequently Played"
|
||||
msgstr "- Vaak Afgespeeld"
|
||||
msgstr "- Vaak afgespeeld"
|
||||
|
||||
msgctxt "#30321"
|
||||
msgid " - Album Artists"
|
||||
msgstr "- Album Artiesten"
|
||||
msgstr "- Album artiesten"
|
||||
|
||||
msgctxt "#30319"
|
||||
msgid "Music - All Album Artists"
|
||||
msgstr "Muziek - Alle Album Artiesten"
|
||||
msgstr "Muziek - Alle album artiesten"
|
||||
|
||||
msgctxt "#30349"
|
||||
msgid " - Recently Played"
|
||||
@@ -1116,3 +1104,19 @@ msgstr "Achtergrondafbeelding update interval (0 = uitgeschakeld)"
|
||||
msgctxt "#30340"
|
||||
msgid "Group movies into collections"
|
||||
msgstr "Groepeer films in collecties"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Er ging iets fout tijdens het inloggen"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Maximale afspeelwachtrijlengte"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Willekeurig"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Directe Mix"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-06-28 13:22+0000\n"
|
||||
"PO-Revision-Date: 2023-01-17 19:51+0000\n"
|
||||
"Last-Translator: Marcin Woliński <cierdek@gmail.com>\n"
|
||||
"Language-Team: Polish <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/pl/>\n"
|
||||
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 4.10.1\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30313"
|
||||
msgid "Menu"
|
||||
@@ -1101,3 +1101,27 @@ msgstr "Szybkie połączenie"
|
||||
msgctxt "#30323"
|
||||
msgid "Artists"
|
||||
msgstr "Artyści"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr "Pokaż odtworzenie następnego odcinka o czasie pozostałym w sekundach"
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Wystąpił błąd podczas logowania"
|
||||
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Kontynuuj oglądanie"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Maksymalny rozmiar kolejki odtwarzania"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Tasuj"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Natychmiastowe mieszanie"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-08-10 20:22+0000\n"
|
||||
"Last-Translator: WWWesten <wwwesten@gmail.com>\n"
|
||||
"PO-Revision-Date: 2023-02-13 01:39+0000\n"
|
||||
"Last-Translator: Ilya Garkavenko <fewdji@gmail.com>\n"
|
||||
"Language-Team: Russian <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/ru/>\n"
|
||||
"Language: ru\n"
|
||||
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 4.10.1\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30332"
|
||||
msgid "Stop media playback on screensaver activation"
|
||||
@@ -46,7 +46,7 @@ msgstr "Обработка элемента:"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "Показывать подсоединённых клиентов"
|
||||
msgstr "Показывать подсоединённые устройства"
|
||||
|
||||
msgctxt "#30275"
|
||||
msgid "Force Transcode"
|
||||
@@ -309,7 +309,7 @@ msgstr "ТВ-передачи - Жанры"
|
||||
|
||||
msgctxt "#30287"
|
||||
msgid "TV Shows - Latest"
|
||||
msgstr "ТВ-передачи - Крайние"
|
||||
msgstr "ТВ-передачи - Последние"
|
||||
|
||||
msgctxt "#30279"
|
||||
msgid "TV Shows - Unwatched"
|
||||
@@ -353,7 +353,7 @@ msgstr "Кэшировать рисунки"
|
||||
|
||||
msgctxt "#30288"
|
||||
msgid " - Latest"
|
||||
msgstr "- Крайние"
|
||||
msgstr "- Последние"
|
||||
|
||||
msgctxt "#30285"
|
||||
msgid " - Unwatched"
|
||||
@@ -389,7 +389,7 @@ msgstr "Ошибка URL"
|
||||
|
||||
msgctxt "#30183"
|
||||
msgid "Include people"
|
||||
msgstr "Включить людей"
|
||||
msgstr "Включить пользователей"
|
||||
|
||||
msgctxt "#30181"
|
||||
msgid "Include plot"
|
||||
@@ -621,7 +621,7 @@ msgstr "Подновить кэшированные рисунки"
|
||||
|
||||
msgctxt "#30278"
|
||||
msgid " - Next Up"
|
||||
msgstr "- Очередное"
|
||||
msgstr "- Последнее"
|
||||
|
||||
msgctxt "#30269"
|
||||
msgid "Movies - Random"
|
||||
@@ -1083,9 +1083,10 @@ msgctxt "#30001"
|
||||
msgid "Port"
|
||||
msgstr "Порт"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "Узел"
|
||||
msgstr "Хост"
|
||||
|
||||
msgctxt "#30444"
|
||||
msgid "Login using Quick Connect"
|
||||
@@ -1102,3 +1103,20 @@ msgstr "Исполнители"
|
||||
msgctxt "#30445"
|
||||
msgid "Continue Watching"
|
||||
msgstr "Продолжение просмотра"
|
||||
|
||||
msgctxt "#30439"
|
||||
msgid "Show play next episode at time left in seconds"
|
||||
msgstr ""
|
||||
"За сколько секунд до окончания показывать \"Воспроизвести следующий эпизод\""
|
||||
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "Произошла ошибка при входе"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Перемешать"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Максимальный размер очереди"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-10-17 05:50+0000\n"
|
||||
"Last-Translator: daniel knutzen <daniel@knutzen.se>\n"
|
||||
"PO-Revision-Date: 2023-01-13 15:51+0000\n"
|
||||
"Last-Translator: Weevild <Filip.westman@gmail.com>\n"
|
||||
"Language-Team: Swedish <https://translate.jellyfin.org/projects/jellycon/"
|
||||
"jellycon/sv/>\n"
|
||||
"Language: sv\n"
|
||||
@@ -549,7 +549,7 @@ msgstr "[Upptäck lokal server]"
|
||||
|
||||
msgctxt "#30003"
|
||||
msgid "Verify HTTPS certificate"
|
||||
msgstr "Verifiera HTTPS certifikat"
|
||||
msgstr "Verifiera HTTPS-certifikat"
|
||||
|
||||
msgctxt "#30001"
|
||||
msgid "Port"
|
||||
@@ -1106,3 +1106,15 @@ msgstr "Inte inställd"
|
||||
msgctxt "#30435"
|
||||
msgid "Connection speed test"
|
||||
msgstr "hastighets test"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "Maximal köstorlek"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "Slumpa"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "Direktmix"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-10-21 02:50+0000\n"
|
||||
"Last-Translator: wolong gl <wolong98@gmail.com>\n"
|
||||
"PO-Revision-Date: 2023-02-02 09:51+0000\n"
|
||||
"Last-Translator: kid1412621 <kid1412621@gmail.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <https://translate.jellyfin.org/projects/"
|
||||
"jellycon/jellycon/zh_Hans/>\n"
|
||||
"Language: zh_Hans\n"
|
||||
@@ -1106,3 +1106,15 @@ msgstr "显示播放下一集的剩余时间(s)"
|
||||
msgctxt "#30446"
|
||||
msgid "There was an error logging in"
|
||||
msgstr "登录时出错"
|
||||
|
||||
msgctxt "#30448"
|
||||
msgid "Shuffle"
|
||||
msgstr "随机"
|
||||
|
||||
msgctxt "#30449"
|
||||
msgid "Instant Mix"
|
||||
msgstr "速成合辑"
|
||||
|
||||
msgctxt "#30447"
|
||||
msgid "Max Play Queue Size"
|
||||
msgstr "最大播放队列数"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2022-04-14 06:13+0000\n"
|
||||
"Last-Translator: rayanamukami <rayanamukami@gmail.com>\n"
|
||||
"PO-Revision-Date: 2022-11-13 01:50+0000\n"
|
||||
"Last-Translator: siriuskoan <me@siriuskoan.one>\n"
|
||||
"Language-Team: Chinese (Traditional) <https://translate.jellyfin.org/"
|
||||
"projects/jellycon/jellycon/zh_Hant/>\n"
|
||||
"Language: zh_Hant\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 4.10.1\n"
|
||||
"X-Generator: Weblate 4.14.1\n"
|
||||
|
||||
msgctxt "#30207"
|
||||
msgid "Playback"
|
||||
@@ -102,3 +102,15 @@ msgstr "埠"
|
||||
msgctxt "#30000"
|
||||
msgid "Host"
|
||||
msgstr "主機"
|
||||
|
||||
msgctxt "#30016"
|
||||
msgid "Device display name"
|
||||
msgstr "裝置顯示名稱"
|
||||
|
||||
msgctxt "#30017"
|
||||
msgid "Show connected clients"
|
||||
msgstr "顯示已連線的用戶"
|
||||
|
||||
msgctxt "#30011"
|
||||
msgid "[Detect local server]"
|
||||
msgstr "[偵測本機使用者]"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import time
|
||||
import threading
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
# coding=utf-8
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
from six.moves.urllib.parse import unquote
|
||||
import requests
|
||||
import base64
|
||||
import sys
|
||||
import threading
|
||||
@@ -13,6 +11,8 @@ import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import requests
|
||||
from six.moves.urllib.parse import unquote
|
||||
|
||||
from .jellyfin import api
|
||||
from .lazylogger import LazyLogger
|
||||
@@ -208,7 +208,7 @@ class CacheArtwork(threading.Thread):
|
||||
dp.close()
|
||||
del dp
|
||||
if result_text is not None:
|
||||
log.debug("Cache Images reuslt : {0}".format(" - ".join(result_text)))
|
||||
log.debug("Cache Images result : {0}".format(" - ".join(result_text)))
|
||||
|
||||
def get_jellyfin_artwork(self, progress):
|
||||
log.debug("get_jellyfin_artwork")
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import threading
|
||||
import hashlib
|
||||
import os
|
||||
import time
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcvfs
|
||||
import xbmcgui
|
||||
from six.moves import cPickle
|
||||
|
||||
from .jellyfin import api
|
||||
@@ -15,11 +21,6 @@ from .tracking import timer
|
||||
from .filelock import FileLock
|
||||
from .utils import translate_string, load_user_details, translate_path
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcvfs
|
||||
import xbmcgui
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
|
||||
@@ -259,7 +260,7 @@ def clear_cached_server_data():
|
||||
del_count = 0
|
||||
for filename in files:
|
||||
if filename.startswith("cache_") and filename.endswith(".pickle"):
|
||||
log.debug("Deleteing CacheFile: {0}".format(filename))
|
||||
log.debug("Deleting CacheFile: {0}".format(filename))
|
||||
xbmcvfs.delete(os.path.join(addon_dir, filename))
|
||||
del_count += 1
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import xbmcgui
|
||||
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
import xbmcaddon
|
||||
import xbmcplugin
|
||||
import xbmcgui
|
||||
|
||||
from six.moves.urllib.parse import quote, unquote
|
||||
import sys
|
||||
import re
|
||||
|
||||
from .datamanager import DataManager
|
||||
from .lazylogger import LazyLogger
|
||||
from .item_functions import add_gui_item, ItemDetails
|
||||
from .utils import send_event_notification, translate_string, load_user_details, get_default_filters
|
||||
from .tracking import timer
|
||||
from .utils import (
|
||||
send_event_notification, translate_string,
|
||||
load_user_details, get_default_filters
|
||||
)
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -259,7 +263,7 @@ def process_directory(url, progress, params, use_cache_data=False):
|
||||
cache_file, item_list, total_records, cache_thread = data_manager.get_items(url, gui_options, use_cache)
|
||||
|
||||
# flatten single season
|
||||
# if there is only one result and it is a season and you have flatten signle season turned on then
|
||||
# if there is only one result and it is a season and you have flatten single season turned on then
|
||||
# build a new url, set the content media type and call get content again
|
||||
flatten_single_season = settings.getSetting("flatten_single_season") == "true"
|
||||
if flatten_single_season and len(item_list) == 1 and item_list[0].item_type == "Season":
|
||||
|
||||
@@ -1,30 +1,40 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
from six.moves.urllib.parse import quote, unquote, parse_qsl
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import cProfile
|
||||
import pstats
|
||||
from six import StringIO
|
||||
|
||||
import xbmcplugin
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
import xbmc
|
||||
from six import StringIO
|
||||
from six.moves.urllib.parse import quote, unquote, parse_qsl, urlencode
|
||||
|
||||
from .jellyfin import api
|
||||
from .utils import translate_string, get_version, load_user_details, get_art_url, get_default_filters, translate_path, kodi_version
|
||||
from .utils import (
|
||||
translate_string, get_version, load_user_details, get_art_url,
|
||||
get_default_filters, translate_path, kodi_version, get_jellyfin_url
|
||||
)
|
||||
from .kodi_utils import HomeWindow
|
||||
from .datamanager import clear_cached_server_data
|
||||
from .server_detect import check_server, check_connection_speed
|
||||
from .lazylogger import LazyLogger
|
||||
from .menu_functions import display_main_menu, display_menu, show_movie_alpha_list, show_tvshow_alpha_list, show_genre_list, show_search, show_movie_pages, show_artist_alpha_list
|
||||
from .menu_functions import (
|
||||
display_main_menu, display_menu, show_movie_alpha_list,
|
||||
show_tvshow_alpha_list, show_genre_list, show_search,
|
||||
show_movie_pages, show_artist_alpha_list
|
||||
)
|
||||
from .server_sessions import show_server_sessions
|
||||
from .action_menu import ActionMenu
|
||||
from .dialogs import BitrateDialog
|
||||
from .widgets import get_widget_content, get_widget_content_cast, check_for_new_content
|
||||
from .widgets import (
|
||||
get_widget_content, get_widget_content_cast, check_for_new_content
|
||||
)
|
||||
from .cache_images import CacheArtwork
|
||||
from .dir_functions import get_content, process_directory
|
||||
from .tracking import timer
|
||||
@@ -35,6 +45,7 @@ __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')
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -56,7 +67,9 @@ def main_entry_point():
|
||||
|
||||
log.debug("Running Python: {0}".format(sys.version_info))
|
||||
log.debug("Running JellyCon: {0}".format(get_version()))
|
||||
log.debug("Kodi BuildVersion: {0}".format(xbmc.getInfoLabel("System.BuildVersion")))
|
||||
log.debug("Kodi BuildVersion: {0}".format(
|
||||
xbmc.getInfoLabel("System.BuildVersion"))
|
||||
)
|
||||
log.debug("Kodi Version: {0}".format(kodi_version()))
|
||||
log.debug("Script argument data: {0}".format(sys.argv))
|
||||
|
||||
@@ -68,7 +81,9 @@ def main_entry_point():
|
||||
|
||||
mode = params.get("mode", None)
|
||||
|
||||
if len(params) == 1 and request_path and request_path.find("/library/movies") > -1:
|
||||
if (len(params) == 1 and request_path
|
||||
and request_path.find("/library/movies") > -1):
|
||||
|
||||
check_server()
|
||||
new_params = {}
|
||||
new_params["item_type"] = "Movie"
|
||||
@@ -107,7 +122,9 @@ def main_entry_point():
|
||||
__addon__.openSettings()
|
||||
window = xbmcgui.getCurrentWindowId()
|
||||
if window == 10000:
|
||||
log.debug("Currently in home - refreshing to allow new settings to be taken")
|
||||
log.debug(
|
||||
"Currently in home - refresh to allow new settings to be taken"
|
||||
)
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
elif mode == "CLEAR_CACHE":
|
||||
clear_cached_server_data()
|
||||
@@ -129,13 +146,6 @@ def main_entry_point():
|
||||
show_server_sessions()
|
||||
elif mode == "SHOW_ADDON_MENU":
|
||||
display_menu(params)
|
||||
elif mode == "GET_CONTENT_BY_TV_SHOW":
|
||||
parent_id = __get_parent_id_from(params)
|
||||
if parent_id is not None:
|
||||
enriched_url = param_url + "&ParentId=" + parent_id
|
||||
get_content(enriched_url, params)
|
||||
else:
|
||||
log.info("Unable to find TV show parent ID.")
|
||||
else:
|
||||
log.debug("JellyCon -> Mode: {0}".format(mode))
|
||||
log.debug("JellyCon -> URL: {0}".format(param_url))
|
||||
@@ -152,7 +162,9 @@ def main_entry_point():
|
||||
pr.disable()
|
||||
|
||||
file_time_stamp = time.strftime("%Y%m%d-%H%M%S")
|
||||
tab_file_name = __addondir__ + "profile(" + file_time_stamp + ").txt"
|
||||
tab_file_name = "{}-profile({}).txt".format(
|
||||
__addondir__, file_time_stamp
|
||||
)
|
||||
s = StringIO()
|
||||
ps = pstats.Stats(pr, stream=s)
|
||||
ps = ps.sort_stats('cumulative')
|
||||
@@ -166,33 +178,6 @@ def main_entry_point():
|
||||
log.debug("===== JellyCon FINISHED =====")
|
||||
|
||||
|
||||
def __enrich_url(param_url, params):
|
||||
enriched_url = param_url
|
||||
parent_id = __get_parent_id_from(params)
|
||||
if parent_id is not None:
|
||||
enriched_url = param_url + "&ParentId=" + parent_id
|
||||
return enriched_url
|
||||
|
||||
|
||||
def __get_parent_id_from(params):
|
||||
result = None
|
||||
show_provider_ids = params.get("show_ids")
|
||||
if show_provider_ids is not None:
|
||||
log.debug("TV show providers IDs: {}".format(show_provider_ids))
|
||||
get_show_url = "/Users/{}/Items?fields=MediaStreams&Recursive=true" \
|
||||
"&IncludeItemTypes=series&IncludeMedia=true&ImageTypeLimit=1&Limit=16" \
|
||||
"&AnyProviderIdEquals={}".format(api.user_id, show_provider_ids)
|
||||
content = api.get(get_show_url)
|
||||
show = content.get("Items")
|
||||
if len(show) == 1:
|
||||
result = content.get("Items")[0].get("Id")
|
||||
else:
|
||||
log.debug("TV show not found for ids: {}".format(show_provider_ids))
|
||||
else:
|
||||
log.error("TV show parameter not found in request.")
|
||||
return result
|
||||
|
||||
|
||||
def toggle_watched(params):
|
||||
log.debug("toggle_watched: {0}".format(params))
|
||||
item_id = params.get("item_id", None)
|
||||
@@ -214,61 +199,61 @@ def toggle_watched(params):
|
||||
|
||||
def mark_item_watched(item_id):
|
||||
log.debug("Mark Item Watched: {0}".format(item_id))
|
||||
url = "/Users/{}/PlayedItems/{}".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/PlayedItems/{}".format(api.user_id, item_id)
|
||||
api.post(url)
|
||||
check_for_new_content()
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
log.debug("markWatched_lastUrl: {0}".format(last_url))
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
|
||||
def mark_item_unwatched(item_id):
|
||||
log.debug("Mark Item UnWatched: {0}".format(item_id))
|
||||
url = "/Users/{}/PlayedItems/{}".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/PlayedItems/{}".format(api.user_id, item_id)
|
||||
api.delete(url)
|
||||
check_for_new_content()
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
log.debug("markUnwatched_lastUrl: {0}".format(last_url))
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
|
||||
def mark_item_favorite(item_id):
|
||||
log.debug("Add item to favourites: {0}".format(item_id))
|
||||
url = "/Users/{}/FavoriteItems/{}".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/FavoriteItems/{}".format(api.user_id, item_id)
|
||||
api.post(url)
|
||||
check_for_new_content()
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
|
||||
def unmark_item_favorite(item_id):
|
||||
log.debug("Remove item from favourites: {0}".format(item_id))
|
||||
url = "/Users/{}/FavoriteItems/{}".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/FavoriteItems/{}".format(api.user_id, item_id)
|
||||
api.delete(url)
|
||||
check_for_new_content()
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
|
||||
def delete(item_id):
|
||||
|
||||
item = api.delete("/Users/{}/Items/{}".format(user_details.get('user_id'), item_id))
|
||||
item = api.delete("/Users/{}/Items/{}".format(api.user_id, item_id))
|
||||
|
||||
item_id = item.get("Id")
|
||||
item_name = item.get("Name", "")
|
||||
@@ -278,18 +263,24 @@ def delete(item_id):
|
||||
final_name = ""
|
||||
|
||||
if series_name:
|
||||
final_name += series_name + " - "
|
||||
final_name += "{} -".format(series_name)
|
||||
|
||||
if ep_number != -1:
|
||||
final_name += "Episode %02d - " % (ep_number,)
|
||||
final_name += "Episode {:02d} - ".format(ep_number)
|
||||
|
||||
final_name += item_name
|
||||
|
||||
if not item.get("CanDelete", False):
|
||||
xbmcgui.Dialog().ok(translate_string(30135), translate_string(30417), final_name)
|
||||
xbmcgui.Dialog().ok(
|
||||
translate_string(30135), translate_string(30417), final_name
|
||||
)
|
||||
return
|
||||
|
||||
return_value = xbmcgui.Dialog().yesno(translate_string(30091), '{}\n{}'.format(final_name, translate_string(30092)))
|
||||
return_value = xbmcgui.Dialog().yesno(
|
||||
translate_string(30091), '{}\n{}'.format(
|
||||
final_name, translate_string(30092)
|
||||
)
|
||||
)
|
||||
if return_value:
|
||||
log.debug('Deleting Item: {0}'.format(item_id))
|
||||
url = '/Items/{}'.format(item_id)
|
||||
@@ -301,7 +292,9 @@ def delete(item_id):
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property(
|
||||
"skip_cache_for_{}".format(last_url), "true"
|
||||
)
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
@@ -320,7 +313,7 @@ def get_params():
|
||||
param = dict(parse_qsl(paramstring[1:]))
|
||||
|
||||
# add plugin path
|
||||
request_path = plugin_path.replace("plugin://plugin.video.jellycon", "")
|
||||
request_path = plugin_path.replace("plugin://{}".format(addon_id), "")
|
||||
param["request_path"] = request_path
|
||||
|
||||
log.debug("JellyCon -> Detected parameters: {0}".format(param))
|
||||
@@ -343,22 +336,39 @@ def show_menu(params):
|
||||
|
||||
action_items = []
|
||||
|
||||
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio", "TvChannel", "Program", "MusicVideo"]:
|
||||
# Additional items to include in the context menu for different item types
|
||||
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio",
|
||||
"TvChannel", "Program", "MusicVideo"]:
|
||||
li = xbmcgui.ListItem(translate_string(30314), offscreen=True)
|
||||
li.setProperty('menu_id', 'play')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["Season", "MusicArtist", "MusicAlbum", "Playlist"]:
|
||||
if result["Type"] in ["Season", "MusicArtist", "MusicAlbum", "Playlist",
|
||||
"MusicGenre"]:
|
||||
li = xbmcgui.ListItem(translate_string(30317), offscreen=True)
|
||||
li.setProperty('menu_id', 'play_all')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["Episode", "Movie", "Video", "TvChannel", "Program", "MusicVideo"]:
|
||||
if result["Type"] in ["MusicArtist", "MusicAlbum", "Playlist",
|
||||
"Series", "Season", "MusicGenre"]:
|
||||
li = xbmcgui.ListItem(translate_string(30448), offscreen=True)
|
||||
li.setProperty('menu_id', 'shuffle')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["MusicArtist", "MusicAlbum", "Audio"]:
|
||||
li = xbmcgui.ListItem(translate_string(30449), offscreen=True)
|
||||
li.setProperty('menu_id', 'instant_mix')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["Episode", "Movie", "Video", "TvChannel",
|
||||
"Program", "MusicVideo"]:
|
||||
li = xbmcgui.ListItem(translate_string(30275), offscreen=True)
|
||||
li.setProperty('menu_id', 'transcode')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio", "MusicArtist", "MusicAlbum", "MusicVideo"]:
|
||||
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio",
|
||||
"MusicArtist", "MusicAlbum", "MusicVideo",
|
||||
"MusicGenre"]:
|
||||
li = xbmcgui.ListItem(translate_string(30402), offscreen=True)
|
||||
li.setProperty('menu_id', 'add_to_playlist')
|
||||
action_items.append(li)
|
||||
@@ -431,12 +441,15 @@ def show_menu(params):
|
||||
window = xbmcgui.Window(xbmcgui.getCurrentWindowId())
|
||||
container_view_id = str(window.getFocusId())
|
||||
container_content_type = xbmc.getInfoLabel("Container.Content")
|
||||
view_key = "view-" + container_content_type
|
||||
view_key = "view-{}".format(container_content_type)
|
||||
current_default_view = settings.getSetting(view_key)
|
||||
view_match = container_view_id == current_default_view
|
||||
log.debug("View ID:{0} Content type:{1}".format(container_view_id, container_content_type))
|
||||
log.debug("View ID:{0} Content type:{1}".format(
|
||||
container_view_id, container_content_type)
|
||||
)
|
||||
|
||||
if container_content_type in ["movies", "tvshows", "seasons", "episodes", "sets"]:
|
||||
if container_content_type in ["movies", "tvshows", "seasons",
|
||||
"episodes", "sets"]:
|
||||
if view_match:
|
||||
li = xbmcgui.ListItem("Unset as default view", offscreen=True)
|
||||
li.setProperty('menu_id', 'unset_view')
|
||||
@@ -461,22 +474,30 @@ def show_menu(params):
|
||||
play_action(params)
|
||||
|
||||
elif selected_action == "set_view":
|
||||
log.debug("Settign view type for {0} to {1}".format(view_key, container_view_id))
|
||||
log.debug("Setting view type for {0} to {1}".format(
|
||||
view_key, container_view_id)
|
||||
)
|
||||
settings.setSetting(view_key, container_view_id)
|
||||
|
||||
elif selected_action == "unset_view":
|
||||
log.debug("Un-Settign view type for {0} to {1}".format(view_key, container_view_id))
|
||||
log.debug("Un-Settign view type for {0} to {1}".format(
|
||||
view_key, container_view_id)
|
||||
)
|
||||
settings.setSetting(view_key, "")
|
||||
|
||||
elif selected_action == "refresh_server":
|
||||
url = ("/Items/" + item_id + "/Refresh" +
|
||||
"?Recursive=true" +
|
||||
"&ImageRefreshMode=FullRefresh" +
|
||||
"&MetadataRefreshMode=FullRefresh" +
|
||||
"&ReplaceAllImages=true" +
|
||||
"&ReplaceAllMetadata=true")
|
||||
url_path = "/Items/{}/Refresh".format(item_id)
|
||||
url_params = {
|
||||
"Recursive": True,
|
||||
"ImageRefreshMode": "FullRefresh",
|
||||
"MetadataRefreshMode": "FullRefresh",
|
||||
"ReplaceAllImages": True,
|
||||
"ReplaceAllMetadata": True
|
||||
}
|
||||
|
||||
url = get_jellyfin_url(url_path, url_params)
|
||||
res = api.post(url)
|
||||
log.debug("Refresh Server Responce: {0}".format(res))
|
||||
log.debug("Refresh Server Response: {0}".format(res))
|
||||
|
||||
elif selected_action == "hide":
|
||||
user_details = load_user_details()
|
||||
@@ -485,37 +506,52 @@ def show_menu(params):
|
||||
url = "/Items/{}/Tags/Add".format(item_id)
|
||||
post_tag_data = {"Tags": [{"Name": hide_tag_string}]}
|
||||
res = api.post(url, post_tag_data)
|
||||
log.debug("Add Tag Responce: {0}".format(res))
|
||||
log.debug("Add Tag Response: {0}".format(res))
|
||||
|
||||
check_for_new_content()
|
||||
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
log.debug("markUnwatched_lastUrl: {0}".format(last_url))
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property(
|
||||
"skip_cache_for_{}".format(last_url), "true"
|
||||
)
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
elif selected_action == "play_all":
|
||||
play_action(params)
|
||||
|
||||
elif selected_action == "shuffle":
|
||||
params["action"] = "shuffle"
|
||||
play_action(params)
|
||||
|
||||
elif selected_action == "instant_mix":
|
||||
params["action"] = "instant_mix"
|
||||
play_action(params)
|
||||
|
||||
elif selected_action == "play_trailer":
|
||||
play_item_trailer(item_id)
|
||||
|
||||
elif selected_action == "transcode":
|
||||
params['force_transcode'] = 'true'
|
||||
|
||||
force_max_stream_bitrate = settings.getSetting("force_max_stream_bitrate")
|
||||
initial_bitrate_value = int(force_max_stream_bitrate)
|
||||
bitrate_dialog = BitrateDialog("BitrateDialog.xml", PLUGINPATH, "default", "720p")
|
||||
max_bitrate = settings.getSetting("force_max_stream_bitrate")
|
||||
initial_bitrate_value = int(max_bitrate)
|
||||
bitrate_dialog = BitrateDialog(
|
||||
"BitrateDialog.xml", PLUGINPATH, "default", "720p"
|
||||
)
|
||||
bitrate_dialog.initial_bitrate_value = initial_bitrate_value
|
||||
bitrate_dialog.doModal()
|
||||
selected_transcode_value = bitrate_dialog.selected_transcode_value
|
||||
del bitrate_dialog
|
||||
log.debug("selected_transcode_value: {0}".format(selected_transcode_value))
|
||||
log.debug("selected_transcode_value: {0}".format(
|
||||
selected_transcode_value)
|
||||
)
|
||||
|
||||
if selected_transcode_value > 0:
|
||||
settings.setSetting("force_max_stream_bitrate", str(selected_transcode_value))
|
||||
settings.setSetting(
|
||||
"force_max_stream_bitrate", str(selected_transcode_value))
|
||||
|
||||
play_action(params)
|
||||
|
||||
@@ -539,25 +575,49 @@ def show_menu(params):
|
||||
delete(item_id)
|
||||
|
||||
elif selected_action == "show_extras":
|
||||
u = "/Users/{}/Items/{}/SpecialFeatures".format(api.user_id, item_id)
|
||||
action_url = ("plugin://plugin.video.jellycon/?url=" + quote(u) + "&mode=GET_CONTENT&media_type=Videos")
|
||||
built_in_command = 'ActivateWindow(Videos, ' + action_url + ', return)'
|
||||
url = "/Users/{}/Items/{}/SpecialFeatures".format(api.user_id, item_id)
|
||||
plugin_params = {
|
||||
"url": url,
|
||||
"mode": "GET_CONTENT",
|
||||
"media_type": "Videos"
|
||||
}
|
||||
|
||||
action_params = urlencode(plugin_params)
|
||||
|
||||
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
||||
built_in_command = 'ActivateWindow(Videos, {}, return)'.format(
|
||||
action_url
|
||||
)
|
||||
xbmc.executebuiltin(built_in_command)
|
||||
|
||||
elif selected_action == "view_season":
|
||||
xbmc.executebuiltin("Dialog.Close(all,true)")
|
||||
parent_id = result["ParentId"]
|
||||
series_id = result["SeriesId"]
|
||||
u = ('/Shows/' + series_id +
|
||||
'/Episodes'
|
||||
'?userId={}'.format(api.user_id) +
|
||||
'&seasonId=' + parent_id +
|
||||
'&IsVirtualUnAired=false' +
|
||||
'&IsMissing=false' +
|
||||
'&Fields=SpecialEpisodeNumbers,{}'.format(get_default_filters()) +
|
||||
'&format=json')
|
||||
action_url = ("plugin://plugin.video.jellycon/?url=" + quote(u) + "&mode=GET_CONTENT&media_type=Season")
|
||||
built_in_command = 'ActivateWindow(Videos, ' + action_url + ', return)'
|
||||
|
||||
url_path = "/Shows/{}/Episodes".format(series_id)
|
||||
url_params = {
|
||||
"userId": api.user_id,
|
||||
"seasonId": parent_id,
|
||||
"IsVirtualUnAired": False,
|
||||
"IsMissing": False,
|
||||
"Fields": "SpecialEpisodeNumbers,{}".format(get_default_filters())
|
||||
}
|
||||
|
||||
url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
plugin_params = {
|
||||
"url": url,
|
||||
"mode": "GET_CONTENT",
|
||||
"media_type": "Season"
|
||||
}
|
||||
|
||||
action_params = urlencode(plugin_params)
|
||||
|
||||
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
||||
built_in_command = 'ActivateWindow(Videos, {}, return)'.format(
|
||||
action_url
|
||||
)
|
||||
xbmc.executebuiltin(built_in_command)
|
||||
|
||||
elif selected_action == "view_series":
|
||||
@@ -567,18 +627,30 @@ def show_menu(params):
|
||||
if not series_id:
|
||||
series_id = item_id
|
||||
|
||||
u = ('/Shows/' + series_id +
|
||||
'/Seasons'
|
||||
'?userId={}'.format(api.user_id) +
|
||||
'&Fields={}'.format(get_default_filters()) +
|
||||
'&format=json')
|
||||
url_path = "/Shows/{}/Seasons".format(series_id)
|
||||
url_params = {
|
||||
"userId": api.user_id,
|
||||
"Fields": get_default_filters(),
|
||||
}
|
||||
|
||||
action_url = ("plugin://plugin.video.jellycon/?url=" + quote(u) + "&mode=GET_CONTENT&media_type=Series")
|
||||
url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
plugin_params = {
|
||||
"url": url,
|
||||
"mode": "GET_CONTENT",
|
||||
"media_type": "Series"
|
||||
}
|
||||
|
||||
action_params = urlencode(plugin_params)
|
||||
|
||||
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
||||
|
||||
if xbmc.getCondVisibility("Window.IsActive(home)"):
|
||||
built_in_command = 'ActivateWindow(Videos, ' + action_url + ', return)'
|
||||
built_in_command = 'ActivateWindow(Videos, {}, return'.format(
|
||||
action_url
|
||||
)
|
||||
else:
|
||||
built_in_command = 'Container.Update(' + action_url + ')'
|
||||
built_in_command = 'Container.Update({})'.format(action_url)
|
||||
|
||||
xbmc.executebuiltin(built_in_command)
|
||||
|
||||
@@ -600,18 +672,21 @@ def show_content(params):
|
||||
if item_type.lower().find("movie") == -1:
|
||||
group_movies = False
|
||||
|
||||
content_url = ("/Users/{}/Items".format(api.user_id) +
|
||||
"?format=json" +
|
||||
"&ImageTypeLimit=1" +
|
||||
"&IsMissing=False" +
|
||||
"&Fields={}".format(get_default_filters()) +
|
||||
'&CollapseBoxSetItems=' + str(group_movies) +
|
||||
'&GroupItemsIntoCollections=' + str(group_movies) +
|
||||
"&Recursive=true" +
|
||||
'&SortBy=Name' +
|
||||
'&SortOrder=Ascending' +
|
||||
"&IsVirtualUnaired=false" +
|
||||
"&IncludeItemTypes=" + item_type)
|
||||
url_path = "/Users/{}/Items".format(api.user_id)
|
||||
url_params = {
|
||||
"ImageTypeLimit": 1,
|
||||
"IsMissing": False,
|
||||
"Fields": get_default_filters(),
|
||||
"CollapseBoxSetItems": group_movies,
|
||||
"GroupItemsIntoCollections": group_movies,
|
||||
"Recursive": True,
|
||||
"SortBy": "Name",
|
||||
"SortOrder": "Ascending",
|
||||
"IsVirtualUnaired": False,
|
||||
"IncludeItemTypes": item_type
|
||||
}
|
||||
|
||||
content_url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
log.debug("showContent Content Url: {0}".format(content_url))
|
||||
get_content(content_url, params)
|
||||
@@ -622,15 +697,21 @@ def search_results_person(params):
|
||||
handle = int(sys.argv[1])
|
||||
|
||||
person_id = params.get("person_id")
|
||||
details_url = ('/Users/{}/Items'.format(api.user_id) +
|
||||
'?PersonIds=' + person_id +
|
||||
'&Recursive=true' +
|
||||
'&Fields={}'.format(get_default_filters()) +
|
||||
'&format=json')
|
||||
|
||||
url_path = "/Users/{}/Items".format(api.user_id)
|
||||
url_params = {
|
||||
"PersonIds": person_id,
|
||||
"Recursive": True,
|
||||
"Fields": get_default_filters()
|
||||
}
|
||||
|
||||
details_url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
|
||||
dir_items, detected_type, total_records = process_directory(details_url, None, params)
|
||||
dir_items, detected_type, total_records = process_directory(
|
||||
details_url, None, params
|
||||
)
|
||||
|
||||
log.debug('search_results_person results: {0}'.format(dir_items))
|
||||
log.debug('search_results_person detect_type: {0}'.format(detected_type))
|
||||
@@ -646,7 +727,7 @@ def search_results_person(params):
|
||||
content_type = 'episodes'
|
||||
elif detected_type == "Series":
|
||||
content_type = 'tvshows'
|
||||
elif detected_type == "Music" or detected_type == "Audio" or detected_type == "Musicalbum":
|
||||
elif detected_type in ["Music", "Audio", "Musicalbum"]:
|
||||
content_type = 'songs'
|
||||
|
||||
if content_type:
|
||||
@@ -679,7 +760,7 @@ def search_results(params):
|
||||
heading_type = translate_string(30235)
|
||||
content_type = 'episodes'
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
elif item_type == "music" or item_type == "audio" or item_type == "musicalbum":
|
||||
elif item_type in ["music", "audio", "musicalalbum"]:
|
||||
heading_type = 'Music'
|
||||
content_type = 'songs'
|
||||
elif item_type == "person":
|
||||
@@ -695,7 +776,9 @@ def search_results(params):
|
||||
home_window = HomeWindow()
|
||||
last_search = home_window.get_property("last_search")
|
||||
kb = xbmc.Keyboard()
|
||||
kb.setHeading(heading_type.capitalize() + ' ' + translate_string(30246).lower())
|
||||
kb.setHeading("{} {}".format(
|
||||
heading_type.capitalize(), translate_string(30246).lower()
|
||||
))
|
||||
kb.setDefault(last_search)
|
||||
kb.doModal()
|
||||
|
||||
@@ -727,19 +810,23 @@ def search_results(params):
|
||||
|
||||
# what type of search
|
||||
if item_type == "person":
|
||||
search_url = ("/Persons" +
|
||||
"?searchTerm=" + query +
|
||||
"&IncludePeople=true" +
|
||||
"&IncludeMedia=false" +
|
||||
"&IncludeGenres=false" +
|
||||
"&IncludeStudios=false" +
|
||||
"&IncludeArtists=false" +
|
||||
"&Limit=16" +
|
||||
"&Fields=PrimaryImageAspectRatio,BasicSyncInfo,ProductionYear" +
|
||||
"&Recursive=true" +
|
||||
"&EnableTotalRecordCount=false" +
|
||||
"&ImageTypeLimit=1" +
|
||||
"&userId={}".format(api.user_id))
|
||||
url_path = "/Persons"
|
||||
url_params = {
|
||||
"searchTerm": query,
|
||||
"IncludePeople": True,
|
||||
"IncludeMedia": False,
|
||||
"IncludeGenres": False,
|
||||
"IncludeStudios": False,
|
||||
"IncludeArtists": False,
|
||||
"Limit": 16,
|
||||
"Fields": "PrimaryImageAspectRatio,BasicSyncInfo,ProductionYear",
|
||||
"Recursive": True,
|
||||
"EnableTotalRecordCount": False,
|
||||
"ImageTypeLimit": 1,
|
||||
"userId": api.user_id
|
||||
}
|
||||
|
||||
search_url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
person_search_results = api.get(search_url)
|
||||
log.debug("Person Search Result : {0}".format(person_search_results))
|
||||
@@ -755,7 +842,9 @@ def search_results(params):
|
||||
person_name = item.get('Name')
|
||||
person_thumbnail = get_art_url(item, "Primary", server=server)
|
||||
|
||||
action_url = sys.argv[0] + "?mode=NEW_SEARCH_PERSON&person_id=" + person_id
|
||||
action_url = "{}?mode=NEW_SEARCH_PERSON&person_id={}".format(
|
||||
addon_id, person_id
|
||||
)
|
||||
|
||||
list_item = xbmcgui.ListItem(label=person_name, offscreen=True)
|
||||
list_item.setProperty("id", person_id)
|
||||
@@ -767,31 +856,37 @@ def search_results(params):
|
||||
art_links["poster"] = person_thumbnail
|
||||
list_item.setArt(art_links)
|
||||
|
||||
item_tupple = (action_url, list_item, True)
|
||||
list_items.append(item_tupple)
|
||||
item_tuple = (action_url, list_item, True)
|
||||
list_items.append(item_tuple)
|
||||
|
||||
xbmcplugin.setContent(handle, 'artists')
|
||||
xbmcplugin.addDirectoryItems(handle, list_items)
|
||||
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
|
||||
|
||||
else:
|
||||
search_url = ("/Users/{}/Items".format(api.user_id) +
|
||||
"?searchTerm=" + query +
|
||||
"&IncludePeople=false" +
|
||||
"&IncludeMedia=true" +
|
||||
"&IncludeGenres=false" +
|
||||
"&IncludeStudios=false" +
|
||||
"&IncludeArtists=false" +
|
||||
"&IncludeItemTypes=" + item_type +
|
||||
"&Limit=16" +
|
||||
"&Fields={}".format(get_default_filters()) +
|
||||
"&Recursive=true" +
|
||||
"&EnableTotalRecordCount=false" +
|
||||
"&ImageTypeLimit=1")
|
||||
url_path = "/Users/{}/Items".format(api.user_id)
|
||||
url_params = {
|
||||
"searchTerm": query,
|
||||
"IncludePeople": False,
|
||||
"IncludeMedia": True,
|
||||
"IncludeGenres": False,
|
||||
"IncludeStudios": False,
|
||||
"IncludeArtists": False,
|
||||
"IncludeItemTypes": item_type,
|
||||
"Limit": 16,
|
||||
"Fields": get_default_filters(),
|
||||
"Recursive": True,
|
||||
"EnableTotalRecordCount": False,
|
||||
"ImageTypeLimit": 1
|
||||
}
|
||||
|
||||
search_url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
# set content type
|
||||
xbmcplugin.setContent(handle, content_type)
|
||||
dir_items, detected_type, total_records = process_directory(search_url, progress, params)
|
||||
dir_items, detected_type, total_records = process_directory(
|
||||
search_url, progress, params
|
||||
)
|
||||
xbmcplugin.addDirectoryItems(handle, dir_items)
|
||||
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
|
||||
|
||||
@@ -851,7 +946,9 @@ def play_action(params):
|
||||
def play_item_trailer(item_id):
|
||||
log.debug("== ENTER: playTrailer ==")
|
||||
|
||||
url = "/Users/{}/Items/{}/LocalTrailers?format=json".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/Items/{}/LocalTrailers?format=json".format(
|
||||
user_details.get('user_id'), item_id
|
||||
)
|
||||
|
||||
result = api.get(url)
|
||||
|
||||
@@ -868,7 +965,7 @@ def play_item_trailer(item_id):
|
||||
info["type"] = "local"
|
||||
name = trailer.get("Name")
|
||||
while not name or name in trailer_names:
|
||||
name = "Trailer " + str(count)
|
||||
name = "Trailer {}".format(count)
|
||||
count += 1
|
||||
info["name"] = name
|
||||
info["id"] = trailer.get("Id")
|
||||
@@ -876,7 +973,9 @@ def play_item_trailer(item_id):
|
||||
trailer_names.append(name)
|
||||
trailer_list.append(info)
|
||||
|
||||
url = "/Users/{}/Items/{}?format=json&Fields=RemoteTrailers".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/Items/{}?format=json&Fields=RemoteTrailers".format(
|
||||
user_details.get("user_id"), item_id
|
||||
)
|
||||
result = api.get(url)
|
||||
log.debug("RemoteTrailers: {0}".format(result))
|
||||
count = 1
|
||||
@@ -893,7 +992,7 @@ def play_item_trailer(item_id):
|
||||
info["url"] = url
|
||||
name = trailer.get("Name")
|
||||
while not name or name in trailer_names:
|
||||
name = "Trailer " + str(count)
|
||||
name = "Trailer {}".format(count)
|
||||
count += 1
|
||||
info["name"] = name
|
||||
trailer_names.append(name)
|
||||
@@ -903,7 +1002,9 @@ def play_item_trailer(item_id):
|
||||
|
||||
trailer_text = []
|
||||
for trailer in trailer_list:
|
||||
name = trailer.get("name") + " (" + trailer.get("type") + ")"
|
||||
name = "{} ({})".format(
|
||||
trailer.get("name"), trailer.get("type")
|
||||
)
|
||||
trailer_text.append(name)
|
||||
|
||||
dialog = xbmcgui.Dialog()
|
||||
@@ -919,7 +1020,8 @@ def play_item_trailer(item_id):
|
||||
|
||||
elif trailer.get("type") == "remote":
|
||||
youtube_id = trailer.get("url").rsplit('=', 1)[1]
|
||||
youtube_plugin = "RunPlugin(plugin://plugin.video.youtube/play/?video_id=%s)" % youtube_id
|
||||
log.debug("youtube_plugin: {0}".format(youtube_plugin))
|
||||
url_root = "plugin.video.youtube/play/?video_id="
|
||||
play_url = "RunPlugin(plugin://{}{})".format(url_root, youtube_id)
|
||||
log.debug("youtube_plugin: {0}".format(play_url))
|
||||
|
||||
xbmc.executebuiltin(youtube_plugin)
|
||||
xbmc.executebuiltin(play_url)
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import threading
|
||||
import io
|
||||
import base64
|
||||
import re
|
||||
from random import shuffle
|
||||
|
||||
import xbmcvfs
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import base64
|
||||
import re
|
||||
from random import shuffle
|
||||
import requests
|
||||
from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||
from six.moves.urllib.parse import urlparse
|
||||
from six import ensure_text
|
||||
|
||||
import threading
|
||||
import requests
|
||||
import io
|
||||
|
||||
from .jellyfin import api
|
||||
from .lazylogger import LazyLogger
|
||||
from .item_functions import get_art
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
from six.moves.urllib.parse import quote
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil import tz
|
||||
|
||||
from six import ensure_text
|
||||
from six.moves.urllib.parse import quote
|
||||
import xbmcgui
|
||||
|
||||
from .utils import datetime_from_string, get_art_url, image_url, get_current_datetime
|
||||
from .utils import (
|
||||
datetime_from_string, get_art_url, image_url, get_current_datetime
|
||||
)
|
||||
from .lazylogger import LazyLogger
|
||||
from six import ensure_text
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -206,12 +208,12 @@ def extract_item_info(item, gui_options):
|
||||
media_info["height"] = mediaStream.get("Height")
|
||||
media_info["width"] = mediaStream.get("Width")
|
||||
aspect_ratio = mediaStream.get("AspectRatio")
|
||||
media_info["apect"] = aspect_ratio
|
||||
media_info["aspect"] = aspect_ratio
|
||||
if aspect_ratio and len(aspect_ratio) >= 3:
|
||||
try:
|
||||
aspect_width, aspect_height = aspect_ratio.split(':')
|
||||
media_info["apect_ratio"] = float(aspect_width) / float(aspect_height)
|
||||
except:
|
||||
except: # noqa
|
||||
media_info["apect_ratio"] = 1.85
|
||||
else:
|
||||
media_info["apect_ratio"] = 1.85
|
||||
@@ -360,9 +362,6 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
else:
|
||||
u = sys.argv[0] + "?item_id=" + url + "&mode=PLAY"
|
||||
|
||||
# Create the ListItem that will be displayed
|
||||
thumb_path = item_details.art["thumb"]
|
||||
|
||||
list_item_name = item_details.name
|
||||
item_type = item_details.item_type.lower()
|
||||
is_video = item_type not in ['musicalbum', 'audio', 'music']
|
||||
@@ -572,8 +571,6 @@ def add_gui_item(url, item_details, display_options, folder=True, default_sort=F
|
||||
|
||||
item_properties["TotalSeasons"] = str(item_details.total_seasons)
|
||||
item_properties["TotalEpisodes"] = str(item_details.total_episodes)
|
||||
item_properties["WatchedEpisodes"] = str(item_details.watched_episodes)
|
||||
item_properties["UnWatchedEpisodes"] = str(item_details.unwatched_episodes)
|
||||
item_properties["NumEpisodes"] = str(item_details.number_episodes)
|
||||
|
||||
list_item.setRating("imdb", item_details.community_rating, 0, True)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import xbmcaddon
|
||||
from kodi_six.utils import py2_decode
|
||||
import json
|
||||
|
||||
import requests
|
||||
import json
|
||||
import xbmcaddon
|
||||
from kodi_six.utils import py2_decode
|
||||
|
||||
from .utils import get_device_id, get_version, load_user_details
|
||||
from .lazylogger import LazyLogger
|
||||
@@ -49,7 +51,7 @@ class API:
|
||||
response_data = json.loads(r.text)
|
||||
except ValueError:
|
||||
response_data = r.json()
|
||||
except:
|
||||
except: # noqa
|
||||
response_data = {}
|
||||
return response_data
|
||||
|
||||
@@ -66,7 +68,7 @@ class API:
|
||||
response_data = json.loads(r.text)
|
||||
except ValueError:
|
||||
response_data = r.json()
|
||||
except:
|
||||
except: # noqa
|
||||
response_data = {}
|
||||
return response_data
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import json
|
||||
|
||||
import xbmc
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
|
||||
import sys
|
||||
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
@@ -35,11 +37,13 @@ class HomeWindow:
|
||||
self.window.clearProperty(key)
|
||||
|
||||
|
||||
def add_menu_directory_item(label, path, folder=True, art=None):
|
||||
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 = {}
|
||||
art["thumb"] = addon.getAddonInfo('icon')
|
||||
if properties is not None:
|
||||
li.setProperties(properties)
|
||||
li.setArt(art)
|
||||
|
||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=folder)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
|
||||
class LazyLogger(object):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
|
||||
##################################################################################################
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import os
|
||||
import logging
|
||||
@@ -13,13 +12,9 @@ from kodi_six import xbmc, xbmcaddon
|
||||
|
||||
from .utils import translate_path
|
||||
|
||||
##################################################################################################
|
||||
|
||||
__addon__ = xbmcaddon.Addon(id='plugin.video.jellycon')
|
||||
__pluginpath__ = translate_path(__addon__.getAddonInfo('path'))
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
||||
def getLogger(name=None):
|
||||
if name is None:
|
||||
@@ -47,7 +42,9 @@ class LogHandler(logging.StreamHandler):
|
||||
string = self.format(record)
|
||||
|
||||
# Hide server URL in logs
|
||||
string = string.replace(self.server or "{server}", "{jellyfin-server}")
|
||||
string = string.replace(
|
||||
self.server or "{server}", "{jellyfin-server}"
|
||||
)
|
||||
|
||||
py_version = sys.version_info.major
|
||||
# Log level notation changed in Kodi v19
|
||||
@@ -75,12 +72,17 @@ class LogHandler(logging.StreamHandler):
|
||||
|
||||
class MyFormatter(logging.Formatter):
|
||||
|
||||
def __init__(self, fmt='%(name)s -> %(levelname)s::%(relpath)s:%(lineno)s %(message)s'):
|
||||
def __init__(
|
||||
self,
|
||||
fmt='%(name)s -> %(levelname)s::%(relpath)s:%(lineno)s %(message)s'
|
||||
):
|
||||
logging.Formatter.__init__(self, fmt)
|
||||
|
||||
def format(self, record):
|
||||
if record.pathname:
|
||||
record.pathname = ensure_text(record.pathname, get_filesystem_encoding())
|
||||
record.pathname = ensure_text(
|
||||
record.pathname, get_filesystem_encoding()
|
||||
)
|
||||
|
||||
self._gen_rel_path(record)
|
||||
|
||||
@@ -97,7 +99,10 @@ class MyFormatter(logging.Formatter):
|
||||
o = ensure_text(o, get_filesystem_encoding())
|
||||
|
||||
if o.startswith(' File "'):
|
||||
# If this split can't handle your file names, you should seriously consider renaming your files.
|
||||
"""
|
||||
If this split can't handle your file names,
|
||||
you should seriously consider renaming your files.
|
||||
"""
|
||||
fn = o.split(' File "', 2)[1].split('", line ', 1)[0]
|
||||
rfn = os.path.realpath(fn)
|
||||
if rfn.startswith(_pluginpath_real):
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
# coding=utf-8
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
from six import ensure_binary, ensure_text
|
||||
from six.moves.urllib.parse import quote
|
||||
import base64
|
||||
import string
|
||||
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
from six import ensure_binary, ensure_text
|
||||
from six.moves.urllib.parse import quote
|
||||
|
||||
from .jellyfin import api
|
||||
from .kodi_utils import add_menu_directory_item, HomeWindow
|
||||
from .lazylogger import LazyLogger
|
||||
from .utils import get_jellyfin_url, translate_string, get_art_url, get_default_filters, get_current_user_id
|
||||
from .utils import (
|
||||
get_jellyfin_url, translate_string, get_art_url,
|
||||
get_default_filters, get_current_user_id
|
||||
)
|
||||
from .item_functions import get_art
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
@@ -321,7 +324,9 @@ def show_genre_list(menu_params):
|
||||
for genre in result:
|
||||
title = genre.get('Name', translate_string(30250))
|
||||
|
||||
params["GenreIds"] = genre.get("Id")
|
||||
genre_id = genre.get("Id")
|
||||
params["GenreIds"] = genre_id
|
||||
li_properties = {"id": genre_id}
|
||||
|
||||
if parent_id is not None:
|
||||
params["ParentId"] = parent_id
|
||||
@@ -334,7 +339,7 @@ def show_genre_list(menu_params):
|
||||
"&mode=GET_CONTENT" +
|
||||
"&media_type=" + kodi_type)
|
||||
log.debug("addMenuDirectoryItem: {0} - {1} - {2}".format(title, url, art))
|
||||
add_menu_directory_item(title, url, art=art)
|
||||
add_menu_directory_item(title, url, art=art, properties=li_properties)
|
||||
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
|
||||
@@ -412,7 +417,6 @@ def show_tvshow_alpha_list(menu_params):
|
||||
return
|
||||
|
||||
parent_id = menu_params.get("parent_id")
|
||||
user_id = get_current_user_id()
|
||||
|
||||
prefixes = '#' + string.ascii_uppercase
|
||||
|
||||
@@ -606,8 +610,6 @@ def display_menu(params):
|
||||
def show_global_types(params):
|
||||
handle = int(sys.argv[1])
|
||||
|
||||
user_id = get_current_user_id()
|
||||
|
||||
continue_watching_url_params = {
|
||||
"Fields": get_default_filters(),
|
||||
"ImageTypeLimit": 1,
|
||||
@@ -631,7 +633,6 @@ def display_homevideos_type(menu_params, view):
|
||||
view_name = view.get("Name")
|
||||
item_limit = settings.getSetting("show_x_filtered_items")
|
||||
hide_watched = settings.getSetting("hide_watched") == "true"
|
||||
user_id = get_current_user_id()
|
||||
|
||||
# All Home Movies
|
||||
base_params = {
|
||||
@@ -696,7 +697,6 @@ def display_tvshow_type(menu_params, view):
|
||||
view_name = view.get("Name")
|
||||
|
||||
item_limit = settings.getSetting("show_x_filtered_items")
|
||||
user_id = get_current_user_id()
|
||||
|
||||
# All TV Shows
|
||||
base_params = {
|
||||
@@ -799,7 +799,6 @@ def display_music_type(menu_params, view):
|
||||
view_name = view.get("Name")
|
||||
|
||||
item_limit = settings.getSetting("show_x_filtered_items")
|
||||
user_id = get_current_user_id()
|
||||
|
||||
# all albums
|
||||
params = {
|
||||
@@ -876,6 +875,13 @@ def display_music_type(menu_params, view):
|
||||
add_menu_directory_item('{} - {}{}'.format(
|
||||
view_name, translate_string(30323), translate_string(30404)), path)
|
||||
|
||||
# Shuffle All
|
||||
path = "plugin://plugin.video.jellycon/?mode=PLAY&action=shuffle"
|
||||
if view is not None:
|
||||
path += "&item_id=" + view.get("Id")
|
||||
add_menu_directory_item('{} - {}'.format(
|
||||
view_name, translate_string(30448)), path, False)
|
||||
|
||||
xbmcplugin.endOfDirectory(handle)
|
||||
|
||||
|
||||
@@ -884,7 +890,6 @@ def display_musicvideos_type(params, view):
|
||||
xbmcplugin.setContent(handle, 'files')
|
||||
|
||||
view_name = view.get("Name")
|
||||
user_id = get_current_user_id()
|
||||
|
||||
# artists
|
||||
params = {
|
||||
@@ -906,7 +911,6 @@ def display_livetv_type(menu_params, view):
|
||||
xbmcplugin.setContent(handle, 'files')
|
||||
|
||||
view_name = view.get("Name")
|
||||
user_id = get_current_user_id()
|
||||
|
||||
# channels
|
||||
params = {
|
||||
@@ -957,7 +961,6 @@ def display_movies_type(menu_params, view):
|
||||
item_limit = settings.getSetting("show_x_filtered_items")
|
||||
group_movies = settings.getSetting('group_movies') == "true"
|
||||
hide_watched = settings.getSetting("hide_watched") == "true"
|
||||
user_id = get_current_user_id()
|
||||
|
||||
base_params = {
|
||||
"IncludeItemTypes": "Movie",
|
||||
@@ -1028,6 +1031,7 @@ def display_movies_type(menu_params, view):
|
||||
params["SortBy"] = "DateCreated"
|
||||
params["SortOrder"] = "Descending"
|
||||
params["Filters"] = "IsNotFolder"
|
||||
params["Limit"] = item_limit
|
||||
path = get_jellyfin_url("/Users/{userid}/Items", params)
|
||||
url = sys.argv[0] + "?url=" + quote(path) + "&mode=GET_CONTENT&media_type=movies&sort=none"
|
||||
add_menu_directory_item('{}{} ({})'.format(view_name, translate_string(30268), item_limit), url)
|
||||
@@ -1239,7 +1243,6 @@ def get_playlist_path(view_info):
|
||||
"Fields": get_default_filters(),
|
||||
"ImageTypeLimit": 1
|
||||
}
|
||||
user_id = get_current_user_id()
|
||||
|
||||
path = get_jellyfin_url("/Users/{userid}/Items", params)
|
||||
url = sys.argv[0] + "?url=" + quote(path) + "&mode=GET_CONTENT&media_type=playlists"
|
||||
@@ -1257,7 +1260,6 @@ def get_collection_path(view_info):
|
||||
"Recursive": True,
|
||||
"IsMissing": False
|
||||
}
|
||||
user_id = get_current_user_id()
|
||||
|
||||
path = get_jellyfin_url("/Users/{userid}/Items", params)
|
||||
url = sys.argv[0] + "?url=" + quote(path) + "&mode=GET_CONTENT&media_type=boxsets"
|
||||
@@ -1271,7 +1273,6 @@ def get_channel_path(view):
|
||||
"ImageTypeLimit": 1,
|
||||
"Fields": get_default_filters()
|
||||
}
|
||||
user_id = get_current_user_id()
|
||||
|
||||
path = get_jellyfin_url("/Users/{userid}/Items", params)
|
||||
url = sys.argv[0] + "?url=" + quote(path) + "&mode=GET_CONTENT&media_type=files"
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import threading
|
||||
import time
|
||||
|
||||
import xbmc
|
||||
|
||||
from .functions import show_menu
|
||||
from .lazylogger import LazyLogger
|
||||
from .widgets import check_for_new_content
|
||||
@@ -23,7 +26,11 @@ class ContextMonitor(threading.Thread):
|
||||
|
||||
while not xbmc.Monitor().abortRequested() and not self.stop_thread:
|
||||
|
||||
if xbmc.getCondVisibility("Window.IsActive(fullscreenvideo) | Window.IsActive(visualisation)"):
|
||||
visibility_check = (
|
||||
"Window.IsActive(fullscreenvideo) | "
|
||||
"Window.IsActive(visualisation)"
|
||||
)
|
||||
if xbmc.getCondVisibility(visibility_check):
|
||||
xbmc.sleep(1000)
|
||||
else:
|
||||
if xbmc.getCondVisibility("Window.IsVisible(contextmenu)"):
|
||||
@@ -34,7 +41,9 @@ class ContextMonitor(threading.Thread):
|
||||
show_menu(params)
|
||||
|
||||
container_id = xbmc.getInfoLabel("System.CurrentControlID")
|
||||
item_id = xbmc.getInfoLabel("Container(" + str(container_id) + ").ListItem.Property(id)")
|
||||
item_id = xbmc.getInfoLabel(
|
||||
"Container({}).ListItem.Property(id)".format(container_id)
|
||||
)
|
||||
|
||||
xbmc.sleep(100)
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import xbmcgui
|
||||
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import binascii
|
||||
from datetime import timedelta
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
import xbmcvfs
|
||||
import xbmcplugin
|
||||
|
||||
from datetime import timedelta
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from six.moves.urllib.parse import urlencode
|
||||
import sys
|
||||
|
||||
from .jellyfin import api
|
||||
from .lazylogger import LazyLogger
|
||||
from .dialogs import ResumeDialog
|
||||
from .utils import send_event_notification, convert_size, get_device_id, translate_string, load_user_details, translate_path, get_jellyfin_url, download_external_sub
|
||||
from .utils import send_event_notification, convert_size, get_device_id, translate_string, load_user_details, translate_path, get_jellyfin_url, download_external_sub, get_bitrate
|
||||
from .kodi_utils import HomeWindow
|
||||
from .datamanager import clear_old_cache_data
|
||||
from .item_functions import extract_item_info, add_gui_item, get_art
|
||||
@@ -103,9 +105,12 @@ def play_all_files(items, play_items=True):
|
||||
list_item = set_list_item_props(item_id, list_item, item, server, listitem_props, item_title)
|
||||
|
||||
playlist.add(playurl, list_item)
|
||||
if play_items and playlist.size() == 1:
|
||||
# Play the first item immediately before processing the rest
|
||||
xbmc.Player().play(playlist)
|
||||
|
||||
if play_items:
|
||||
xbmc.Player().play(playlist)
|
||||
# Should already be playing, don't need to return anything
|
||||
return None
|
||||
else:
|
||||
return playlist
|
||||
@@ -255,17 +260,52 @@ def play_file(play_info):
|
||||
log.debug("Playfile item was None, so can not play!")
|
||||
return
|
||||
|
||||
# if this is a season, playlist or album then play all items in that parent
|
||||
if result.get("Type") in ["Season", "MusicArtist", "MusicAlbum", "Playlist"]:
|
||||
# Generate an instant mix based on the item
|
||||
if action == 'instant_mix':
|
||||
max_queue = int(settings.getSetting('max_play_queue'))
|
||||
url_root = '/Items/{}/InstantMix'.format(item_id)
|
||||
url_params = {
|
||||
'UserId': api.user_id,
|
||||
'Fields': 'MediaSources',
|
||||
'IncludeItemTypes': 'Audio',
|
||||
'SortBy': 'SortName',
|
||||
'limit': max_queue
|
||||
}
|
||||
url = get_jellyfin_url(url_root, url_params)
|
||||
result = api.get(url)
|
||||
log.debug("PlayAllFiles items: {0}".format(result))
|
||||
|
||||
# process each item
|
||||
items = result["Items"]
|
||||
if items is None:
|
||||
items = []
|
||||
return play_all_files(items)
|
||||
|
||||
'''
|
||||
if this is a season, playlist, artist, album, or a full library then play
|
||||
*all* items in that parent.
|
||||
* Taking the max queue size setting into account
|
||||
'''
|
||||
if result.get("Type") in ["Season", "MusicArtist", "MusicAlbum",
|
||||
"Playlist", "CollectionFolder", "MusicGenre"]:
|
||||
max_queue = int(settings.getSetting('max_play_queue'))
|
||||
log.debug("PlayAllFiles for parent item id: {0}".format(item_id))
|
||||
url_root = '/Users/{}/Items'.format(api.user_id)
|
||||
# Look specifically for episodes or audio files
|
||||
url_params = {
|
||||
'ParentId': item_id,
|
||||
'Fields': 'MediaSources',
|
||||
'IncludeItemTypes': 'Episode,Audio',
|
||||
'Recursive': True
|
||||
'Recursive': True,
|
||||
'SortBy': 'SortName',
|
||||
'limit': max_queue
|
||||
}
|
||||
if result.get("Type") == "MusicGenre":
|
||||
url_params['genreIds'] = item_id
|
||||
else:
|
||||
url_params['ParentId'] = item_id
|
||||
|
||||
if action == 'shuffle':
|
||||
url_params['SortBy'] = 'Random'
|
||||
|
||||
url = get_jellyfin_url(url_root, url_params)
|
||||
result = api.get(url)
|
||||
@@ -441,6 +481,15 @@ def play_file(play_info):
|
||||
if result.get('Type') == 'Episode':
|
||||
next_episode = get_next_episode(result)
|
||||
data["next_episode"] = next_episode
|
||||
send_next_episode_details(result, next_episode)
|
||||
|
||||
# We need the livestream id to properly delete encodings
|
||||
if result.get("Type", "") in ["Program", "TvChannel"]:
|
||||
for media_source in media_sources:
|
||||
livestream_id = media_source.get("LiveStreamId")
|
||||
data["livestream_id"] = livestream_id
|
||||
if livestream_id:
|
||||
break
|
||||
|
||||
home_window.set_property('now_playing', json.dumps(data))
|
||||
|
||||
@@ -748,7 +797,7 @@ def audio_subs_pref(url, list_item, media_source, item_id, audio_stream_index, s
|
||||
try:
|
||||
# Track includes language
|
||||
track = "%s - %s - %s %s" % (index, stream['Language'], codec, channel_layout)
|
||||
except:
|
||||
except KeyError:
|
||||
# Track doesn't include language
|
||||
track = "%s - %s %s" % (index, codec, channel_layout)
|
||||
|
||||
@@ -757,8 +806,10 @@ def audio_subs_pref(url, list_item, media_source, item_id, audio_stream_index, s
|
||||
|
||||
elif 'Subtitle' in stream['Type']:
|
||||
try:
|
||||
# Track includes language
|
||||
track = "%s - %s" % (index, stream['Language'])
|
||||
except:
|
||||
except KeyError:
|
||||
# Track doesn't include language
|
||||
track = "%s - %s" % (index, stream['Codec'])
|
||||
|
||||
default = stream['IsDefault']
|
||||
@@ -840,8 +891,6 @@ def external_subs(media_source, list_item, item_id):
|
||||
sub_names = []
|
||||
|
||||
server = settings.getSetting('server_address')
|
||||
user_details = load_user_details()
|
||||
token = user_details.get('token')
|
||||
|
||||
for stream in media_streams:
|
||||
|
||||
@@ -850,9 +899,6 @@ def external_subs(media_source, list_item, item_id):
|
||||
and stream['IsTextSubtitleStream']
|
||||
and stream['SupportsExternalStream']):
|
||||
|
||||
index = stream['Index']
|
||||
source_id = media_source['Id']
|
||||
|
||||
language = stream.get('Language', '')
|
||||
if language and stream['IsDefault']:
|
||||
language = '{}.default'.format(language)
|
||||
@@ -985,20 +1031,20 @@ def prompt_for_stop_actions(item_id, data):
|
||||
prompt_delete_movie_percentage == 100):
|
||||
return
|
||||
|
||||
# if no runtime we cant calculate perceantge so just return
|
||||
# if no runtime we can't calculate perceantge so just return
|
||||
if duration == 0:
|
||||
log.debug("No duration so returing")
|
||||
log.debug("No duration so returning")
|
||||
return
|
||||
|
||||
# item percentage complete
|
||||
percenatge_complete = int((current_position / duration) * 100)
|
||||
log.debug("Episode Percentage Complete: {0}".format(percenatge_complete))
|
||||
percentage_complete = int((current_position / duration) * 100)
|
||||
log.debug("Episode Percentage Complete: {0}".format(percentage_complete))
|
||||
|
||||
# prompt for next episode
|
||||
if (next_episode is not None and
|
||||
prompt_next_percentage < 100 and
|
||||
item_type == "Episode" and
|
||||
percenatge_complete > prompt_next_percentage):
|
||||
percentage_complete > prompt_next_percentage):
|
||||
|
||||
if play_prompt:
|
||||
|
||||
@@ -1042,6 +1088,7 @@ def stop_all_playback():
|
||||
jellyfin_item_id = data.get("item_id")
|
||||
jellyfin_source_id = data.get("source_id")
|
||||
play_session_id = data.get("play_session_id")
|
||||
livestream_id = data.get('livestream_id')
|
||||
|
||||
if jellyfin_item_id is not None and current_position >= 0:
|
||||
log.debug("Playback Stopped at: {0}".format(current_position))
|
||||
@@ -1054,6 +1101,11 @@ def stop_all_playback():
|
||||
'RunTimeTicks': int(duration * 10000000),
|
||||
'PlaySessionId': play_session_id
|
||||
}
|
||||
|
||||
# If this is a livestream, include the id in the stopped call
|
||||
if livestream_id:
|
||||
postdata['LiveStreamId'] = livestream_id
|
||||
|
||||
api.post(url, postdata)
|
||||
data["currently_playing"] = False
|
||||
|
||||
@@ -1139,7 +1191,6 @@ def get_play_url(media_source, play_session_id, channel_id=None):
|
||||
|
||||
# get all the options
|
||||
server = settings.getSetting('server_address')
|
||||
use_https = settings.getSetting('protocol') == "1"
|
||||
allow_direct_file_play = settings.getSetting('allow_direct_file_play') == 'true'
|
||||
|
||||
can_direct_play = media_source["SupportsDirectPlay"]
|
||||
@@ -1195,8 +1246,7 @@ def get_play_url(media_source, play_session_id, channel_id=None):
|
||||
|
||||
user_details = load_user_details()
|
||||
user_token = user_details.get('token')
|
||||
playback_bitrate = settings.getSetting("force_max_stream_bitrate")
|
||||
bitrate = int(playback_bitrate) * 1000
|
||||
bitrate = get_bitrate(settings.getSetting("force_max_stream_bitrate"))
|
||||
playback_max_width = settings.getSetting("playback_max_width")
|
||||
audio_codec = settings.getSetting("audio_codec")
|
||||
audio_playback_bitrate = settings.getSetting("audio_playback_bitrate")
|
||||
@@ -1381,18 +1431,29 @@ class PlaybackService(xbmc.Monitor):
|
||||
home_window.set_property('exit', 'True')
|
||||
return
|
||||
|
||||
if sender != 'plugin.video.jellycon':
|
||||
if sender.lower() not in (
|
||||
'plugin.video.jellycon', 'xbmc', 'upnextprovider.signal'
|
||||
):
|
||||
return
|
||||
|
||||
|
||||
signal = method.split('.', 1)[-1]
|
||||
if signal not in ("jellycon_play_action", "jellycon_play_youtube_trailer_action", "set_view"):
|
||||
if signal not in (
|
||||
"jellycon_play_action", "jellycon_play_youtube_trailer_action",
|
||||
"set_view", "plugin.video.jellycon_play_action"):
|
||||
return
|
||||
|
||||
data_json = json.loads(data)
|
||||
play_info = data_json[0]
|
||||
if sender.lower() == "upnextprovider.signal":
|
||||
play_info = json.loads(binascii.unhexlify(data_json[0]))
|
||||
else:
|
||||
play_info = data_json[0]
|
||||
|
||||
log.debug("PlaybackService:onNotification:{0}".format(play_info))
|
||||
|
||||
if signal == "jellycon_play_action":
|
||||
if signal in (
|
||||
"jellycon_play_action", "plugin.video.jellycon_play_action"
|
||||
):
|
||||
play_file(play_info)
|
||||
elif signal == "jellycon_play_youtube_trailer_action":
|
||||
trailer_link = play_info["url"]
|
||||
@@ -1455,17 +1516,16 @@ def get_item_playback_info(item_id, force_transcode):
|
||||
if settings.getSetting("force_transcode_mpeg4") == "true":
|
||||
filtered_codecs.append("mpeg4")
|
||||
|
||||
playback_bitrate = settings.getSetting("max_stream_bitrate")
|
||||
force_playback_bitrate = settings.getSetting("force_max_stream_bitrate")
|
||||
if force_transcode:
|
||||
playback_bitrate = force_playback_bitrate
|
||||
if not force_transcode:
|
||||
bitrate = get_bitrate(settings.getSetting("max_stream_bitrate"))
|
||||
else:
|
||||
bitrate = get_bitrate(settings.getSetting("force_max_stream_bitrate"))
|
||||
|
||||
audio_codec = settings.getSetting("audio_codec")
|
||||
audio_playback_bitrate = settings.getSetting("audio_playback_bitrate")
|
||||
audio_max_channels = settings.getSetting("audio_max_channels")
|
||||
|
||||
audio_bitrate = int(audio_playback_bitrate) * 1000
|
||||
bitrate = int(playback_bitrate) * 1000
|
||||
|
||||
profile = {
|
||||
"Name": "Kodi",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import os
|
||||
import threading
|
||||
@@ -92,6 +94,6 @@ class PlayNextService(threading.Thread):
|
||||
if xbmc.Monitor().waitForAbort(1):
|
||||
break
|
||||
|
||||
def stop_servcie(self):
|
||||
def stop_service(self):
|
||||
log.debug("PlayNextService Stop Called")
|
||||
self.stop_thread = True
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import socket
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
@@ -13,7 +13,10 @@ import xbmc
|
||||
from .kodi_utils import HomeWindow
|
||||
from .jellyfin import API
|
||||
from .lazylogger import LazyLogger
|
||||
from .utils import datetime_from_string, translate_string, save_user_details, load_user_details, get_current_datetime, get_saved_users
|
||||
from .utils import (
|
||||
datetime_from_string, translate_string, save_user_details,
|
||||
load_user_details, get_current_datetime, get_saved_users
|
||||
)
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -107,7 +110,7 @@ def get_server_details():
|
||||
xbmc.sleep(1000)
|
||||
data, addr = sock.recvfrom(1024)
|
||||
servers.append(json.loads(data))
|
||||
except:
|
||||
except: # noqa
|
||||
break
|
||||
except Exception as e:
|
||||
log.error("UPD Discovery Error: {0}".format(e))
|
||||
@@ -288,7 +291,6 @@ def check_server(force=False, change_user=False, notify=False):
|
||||
log.info('There was an error logging in with user {}'.format(selected_user_name))
|
||||
xbmcgui.Dialog().ok(__addon_name__, translate_string(30446))
|
||||
|
||||
|
||||
if something_changed:
|
||||
home_window = HomeWindow()
|
||||
home_window.clear_property("jellycon_widget_reload")
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
@@ -47,10 +50,10 @@ def show_server_sessions():
|
||||
now_playing = session.get("NowPlayingItem", None)
|
||||
transcoding_info = session.get("TranscodingInfo", None)
|
||||
|
||||
session_info = user_name + " - " + client_name
|
||||
session_info = "{} - {}".format(user_name, client_name)
|
||||
user_session_details = ""
|
||||
|
||||
percenatge_played = 0
|
||||
percentage_played = 0
|
||||
position_ticks = 0
|
||||
runtime = 0
|
||||
play_method = "na"
|
||||
@@ -65,37 +68,50 @@ def show_server_sessions():
|
||||
|
||||
runtime = now_playing.get("RunTimeTicks", 0)
|
||||
if position_ticks > 0 and runtime > 0:
|
||||
percenatge_played = (position_ticks / float(runtime)) * 100.0
|
||||
percenatge_played = int(percenatge_played)
|
||||
percentage_played = (position_ticks / float(runtime)) * 100.0
|
||||
percentage_played = int(percentage_played)
|
||||
|
||||
session_info += " (" + now_playing.get("Name", "na") + " " + str(percenatge_played) + "%)"
|
||||
user_session_details += now_playing.get("Name", "na") + " " + str(percenatge_played) + "%" + "\n"
|
||||
session_info += " {} {}%".format(
|
||||
now_playing.get("Name", "na"), percentage_played
|
||||
)
|
||||
user_session_details += "{} {}%\n".format(
|
||||
now_playing.get("Name", "na"), percentage_played
|
||||
)
|
||||
|
||||
else:
|
||||
session_info += " (idle)"
|
||||
user_session_details += "Idle" + "\n"
|
||||
user_session_details += "Idle\n"
|
||||
|
||||
transcoding_details = ""
|
||||
if transcoding_info:
|
||||
if not transcoding_info.get("IsVideoDirect", None):
|
||||
transcoding_details += "Video:" + transcoding_info.get("VideoCodec", "") + ":" + str(transcoding_info.get("Width", 0)) + "x" + str(transcoding_info.get("Height", 0)) + "\n"
|
||||
transcoding_details += "Video:{}:{}x{}\n".format(
|
||||
transcoding_info.get("VideoCodec", ""),
|
||||
transcoding_info.get("Width", 0),
|
||||
transcoding_info.get("Height", 0)
|
||||
)
|
||||
else:
|
||||
transcoding_details += "Video:direct\n"
|
||||
|
||||
if not transcoding_info.get("IsAudioDirect", None):
|
||||
transcoding_details += "Audio:" + transcoding_info.get("AudioCodec", "") + ":" + str(transcoding_info.get("AudioChannels", 0)) + "\n"
|
||||
transcoding_details += "Audio:{}:{}\n".format(
|
||||
transcoding_info.get("AudioCodec", ""),
|
||||
transcoding_info.get("AudioChannels", 0)
|
||||
)
|
||||
else:
|
||||
transcoding_details += "Audio:direct\n"
|
||||
|
||||
transcoding_details += "Bitrate:" + str(transcoding_info.get("Bitrate", 0)) + "\n"
|
||||
transcoding_details += "Bitrate:{}\n".format(
|
||||
transcoding_info.get("Bitrate", 0)
|
||||
)
|
||||
|
||||
list_item = xbmcgui.ListItem(label=session_info)
|
||||
list_item.setArt(art)
|
||||
|
||||
user_session_details += device_name + "(" + client_version + ")\n"
|
||||
user_session_details += client_name + "\n"
|
||||
user_session_details += play_method + "\n"
|
||||
user_session_details += transcoding_details + "\n"
|
||||
user_session_details += "{}({})\n".format(device_name, client_version)
|
||||
user_session_details += "{}\n".format(client_name)
|
||||
user_session_details += "{}\n".format(play_method)
|
||||
user_session_details += "{}\n".format(transcoding_details)
|
||||
|
||||
info_labels = {}
|
||||
info_labels["duration"] = str(runtime / 10000000)
|
||||
@@ -105,7 +121,7 @@ def show_server_sessions():
|
||||
|
||||
list_item.setProperty('TotalTime', str(runtime / 10000000))
|
||||
list_item.setProperty('ResumeTime', str(position_ticks / 10000000))
|
||||
list_item.setProperty("complete_percentage", str(percenatge_played))
|
||||
list_item.setProperty("complete_percentage", str(percentage_played))
|
||||
|
||||
item_tuple = ("", list_item, False)
|
||||
list_items.append(item_tuple)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
@@ -19,9 +20,11 @@ def clone_default_skin():
|
||||
xbmc.executebuiltin("Dialog.Close(all,true)")
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
|
||||
response = xbmcgui.Dialog().yesno("JellyCon Skin Cloner",
|
||||
"This will clone the default Estuary Kodi skin and add JellyCon functionality to it.",
|
||||
"Do you want to continue?")
|
||||
response = xbmcgui.Dialog().yesno(
|
||||
"JellyCon Skin Cloner",
|
||||
("This will clone the default Estuary Kodi skin and"
|
||||
"add JellyCon functionality to it."),
|
||||
"Do you want to continue?")
|
||||
if not response:
|
||||
return
|
||||
|
||||
@@ -62,7 +65,9 @@ def clone_skin():
|
||||
log.debug("Found Path: {0}".format(found))
|
||||
|
||||
kodi_home_path = translate_path("special://home")
|
||||
kodi_skin_destination = os.path.join(kodi_home_path, "addons", "skin.estuary_jellycon")
|
||||
kodi_skin_destination = os.path.join(
|
||||
kodi_home_path, "addons", "skin.estuary_jellycon"
|
||||
)
|
||||
log.debug("Kodi Skin Destination: {0}".format(kodi_skin_destination))
|
||||
|
||||
# copy all skin files (clone)
|
||||
@@ -70,7 +75,7 @@ def clone_skin():
|
||||
total = len(all_files)
|
||||
for skin_file in all_files:
|
||||
percentage_done = int(float(count) / float(total) * 100.0)
|
||||
pdialog.update(percentage_done, "%s" % skin_file)
|
||||
pdialog.update(percentage_done, skin_file)
|
||||
|
||||
source = os.path.join(kodi_skin_source, skin_file)
|
||||
destination = os.path.join(kodi_skin_destination, skin_file)
|
||||
@@ -89,7 +94,9 @@ def clone_skin():
|
||||
addon_tree.write(addon_xml_path)
|
||||
|
||||
# get jellycon path
|
||||
jellycon_path = os.path.join(kodi_home_path, "addons", "plugin.video.jellycon")
|
||||
jellycon_path = os.path.join(
|
||||
kodi_home_path, "addons", "plugin.video.jellycon"
|
||||
)
|
||||
|
||||
log.debug("Major Version: {0}".format(kodi_version()))
|
||||
|
||||
@@ -101,7 +108,10 @@ def clone_skin():
|
||||
|
||||
# Copy customized skin files from our addon into cloned skin
|
||||
for file_name in file_list:
|
||||
source = os.path.join(jellycon_path, "resources", "skins", "skin.estuary", str(kodi_version), "xml", file_name)
|
||||
source = os.path.join(
|
||||
jellycon_path, "resources", "skins", "skin.estuary",
|
||||
str(kodi_version), "xml", file_name
|
||||
)
|
||||
destination = os.path.join(kodi_skin_destination, "xml", file_name)
|
||||
xbmcvfs.copy(source, destination)
|
||||
|
||||
@@ -110,7 +120,10 @@ def clone_skin():
|
||||
pdialog.close()
|
||||
del pdialog
|
||||
|
||||
response = xbmcgui.Dialog().yesno("JellyCon Skin Cloner", "Do you want to switch to the new cloned skin?")
|
||||
response = xbmcgui.Dialog().yesno(
|
||||
"JellyCon Skin Cloner",
|
||||
"Do you want to switch to the new cloned skin?"
|
||||
)
|
||||
if not response:
|
||||
return
|
||||
|
||||
@@ -121,10 +134,14 @@ def clone_skin():
|
||||
result = JsonRpc('Addons.SetAddonEnabled').execute(params)
|
||||
log.debug("Addons.SetAddonEnabled : {0}".format(result))
|
||||
|
||||
log.debug("SkinCloner : Current Skin : " + get_value("lookandfeel.skin"))
|
||||
log.debug("SkinCloner : Current Skin : {}".format(
|
||||
get_value("lookandfeel.skin"))
|
||||
)
|
||||
set_result = set_value("lookandfeel.skin", "skin.estuary_jellycon")
|
||||
log.debug("Save Setting : lookandfeel.skin : {0}".format(set_result))
|
||||
log.debug("SkinCloner : Current Skin : " + get_value("lookandfeel.skin"))
|
||||
log.debug("SkinCloner : Current Skin : {}".format(
|
||||
get_value("lookandfeel.skin"))
|
||||
)
|
||||
|
||||
|
||||
def update_kodi_settings():
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import sys
|
||||
import functools
|
||||
import time
|
||||
|
||||
from .lazylogger import LazyLogger
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
@@ -28,6 +30,8 @@ def timer(func):
|
||||
data = args[1]
|
||||
elif func.__name__ == "main_entry_point" and len(sys.argv) > 2:
|
||||
data = sys.argv[2]
|
||||
log.info("timing_data|{0}|{1}|{2}|{3}".format(func.__name__, started, ended, data))
|
||||
log.info("timing_data|{0}|{1}|{2}|{3}".format(
|
||||
func.__name__, started, ended, data)
|
||||
)
|
||||
return value
|
||||
return wrapper
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
# Gnu General Public License - see LICENSE.TXT
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import xbmcaddon
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from kodi_six.utils import py2_encode, py2_decode
|
||||
import sys
|
||||
|
||||
import binascii
|
||||
import string
|
||||
import random
|
||||
@@ -15,11 +11,16 @@ import time
|
||||
import math
|
||||
import os
|
||||
import hashlib
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from dateutil import tz
|
||||
import re
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
import requests
|
||||
from dateutil import tz
|
||||
import xbmcaddon
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from kodi_six.utils import py2_encode, py2_decode
|
||||
from six import ensure_text, ensure_binary, text_type
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
@@ -40,7 +41,8 @@ def kodi_version():
|
||||
else:
|
||||
default_versionstring = "19.1 (19.1.0) Git:20210509-85e05228b4"
|
||||
|
||||
version_string = xbmc.getInfoLabel('System.BuildVersion') or default_versionstring
|
||||
version_string = xbmc.getInfoLabel(
|
||||
'System.BuildVersion') or default_versionstring
|
||||
return int(version_string.split(' ', 1)[0].split('.', 1)[0])
|
||||
|
||||
|
||||
@@ -52,7 +54,7 @@ def get_jellyfin_url(path, params):
|
||||
|
||||
def get_checksum(item):
|
||||
userdata = item['UserData']
|
||||
checksum = "%s_%s_%s_%s_%s_%s_%s" % (
|
||||
checksum = "{}_{}_{}_{}_{}_{}_{}".format(
|
||||
item['Etag'],
|
||||
userdata['Played'],
|
||||
userdata['IsFavorite'],
|
||||
@@ -81,14 +83,15 @@ def send_event_notification(method, data=None, hexlify=False):
|
||||
Send events through Kodi's notification system
|
||||
'''
|
||||
data = data or {}
|
||||
data_str = json.dumps(data)
|
||||
|
||||
if hexlify:
|
||||
# Used exclusively for the upnext plugin
|
||||
data = ensure_text(binascii.hexlify(ensure_binary(json.dumps(data))))
|
||||
data_str = ensure_text(binascii.hexlify(ensure_binary(data_str)))
|
||||
sender = 'plugin.video.jellycon'
|
||||
data = '"[%s]"' % json.dumps(data).replace('"', '\\"')
|
||||
data = '"[{}]"'.format(data_str.replace('"', '\\"'))
|
||||
|
||||
xbmc.executebuiltin('NotifyAll(%s, %s, %s)' % (sender, method, data))
|
||||
xbmc.executebuiltin('NotifyAll({}, {}, {})'.format(sender, method, data))
|
||||
|
||||
|
||||
def datetime_from_string(time_string):
|
||||
@@ -97,15 +100,22 @@ def datetime_from_string(time_string):
|
||||
if time_string[-1:] == "Z":
|
||||
time_string = re.sub("[0-9]{1}Z", " UTC", time_string)
|
||||
elif time_string[-6:] == "+00:00":
|
||||
time_string = re.sub("[0-9]{1}\+00:00", " UTC", time_string)
|
||||
time_string = re.sub(
|
||||
"[0-9]{1}\+00:00", " UTC", time_string # noqa: W605
|
||||
)
|
||||
|
||||
try:
|
||||
dt = datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")
|
||||
except TypeError:
|
||||
# https://bugs.python.org/issue27400
|
||||
dt = datetime(*(time.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")[0:6]))
|
||||
dt = datetime(*(
|
||||
time.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")[0:6])
|
||||
)
|
||||
|
||||
# Dates received from the server are in UTC, but parsing them results in naive objects
|
||||
"""
|
||||
Dates received from the server are in UTC, but parsing them results
|
||||
in naive objects
|
||||
"""
|
||||
utc = tz.tzutc()
|
||||
utc_dt = dt.replace(tzinfo=utc)
|
||||
|
||||
@@ -128,7 +138,7 @@ def convert_size(size_bytes):
|
||||
i = int(math.floor(math.log(size_bytes, 1024)))
|
||||
p = math.pow(1024, i)
|
||||
s = round(size_bytes / p, 2)
|
||||
return "%s %s" % (s, size_name[i])
|
||||
return "{} {}".format(s, size_name[i])
|
||||
|
||||
|
||||
def translate_string(string_id):
|
||||
@@ -154,7 +164,9 @@ def get_device_id():
|
||||
rand_id = uuid4().hex
|
||||
return '{}-{}'.format(client_id, rand_id)
|
||||
|
||||
jellyfin_guid_path = py2_decode(translate_path("special://temp/jellycon_guid"))
|
||||
jellyfin_guid_path = py2_decode(
|
||||
translate_path("special://temp/jellycon_guid")
|
||||
)
|
||||
log.debug("jellyfin_guid_path: {0}".format(jellyfin_guid_path))
|
||||
guid = xbmcvfs.File(jellyfin_guid_path)
|
||||
client_id = guid.read()
|
||||
@@ -182,7 +194,8 @@ def get_version():
|
||||
|
||||
def save_user_details(user_name, user_id, token):
|
||||
settings = xbmcaddon.Addon()
|
||||
save_user_to_settings = settings.getSetting('save_user_to_settings') == 'true'
|
||||
save_user_to_settings = settings.getSetting(
|
||||
'save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
|
||||
# Save to a config file for reference later if desired
|
||||
@@ -190,7 +203,7 @@ def save_user_details(user_name, user_id, token):
|
||||
try:
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'rb') as infile:
|
||||
auth_data = json.load(infile)
|
||||
except:
|
||||
except: # noqa
|
||||
# File doesn't exist or is empty
|
||||
auth_data = {}
|
||||
|
||||
@@ -200,7 +213,8 @@ def save_user_details(user_name, user_id, token):
|
||||
}
|
||||
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'wb') as outfile:
|
||||
data = json.dumps(auth_data, sort_keys=True, indent=4, ensure_ascii=False)
|
||||
data = json.dumps(
|
||||
auth_data, sort_keys=True, indent=4, ensure_ascii=False)
|
||||
if isinstance(data, text_type):
|
||||
data = data.encode('utf-8')
|
||||
outfile.write(data)
|
||||
@@ -218,14 +232,14 @@ def load_user_details():
|
||||
user_name = window.get_property('user_name')
|
||||
if not user_name:
|
||||
user_name = settings.getSetting('username')
|
||||
save_user_to_settings = settings.getSetting('save_user_to_settings') == 'true'
|
||||
save_user = settings.getSetting('save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
|
||||
if save_user_to_settings:
|
||||
if save_user:
|
||||
try:
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'rb') as infile:
|
||||
auth_data = json.load(infile)
|
||||
except:
|
||||
except: # noqa
|
||||
# File doesn't exist yet
|
||||
return {}
|
||||
|
||||
@@ -250,20 +264,20 @@ def load_user_details():
|
||||
|
||||
def get_saved_users():
|
||||
settings = xbmcaddon.Addon()
|
||||
save_user_to_settings = settings.getSetting('save_user_to_settings') == 'true'
|
||||
save_user = settings.getSetting('save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
if not save_user_to_settings:
|
||||
if not save_user:
|
||||
return []
|
||||
|
||||
try:
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'rb') as infile:
|
||||
auth_data = json.load(infile)
|
||||
except:
|
||||
except: # noqa
|
||||
# File doesn't exist yet
|
||||
return []
|
||||
|
||||
users = []
|
||||
for user,values in auth_data.items():
|
||||
for user, values in auth_data.items():
|
||||
users.append(
|
||||
{
|
||||
'Name': user,
|
||||
@@ -276,8 +290,6 @@ def get_saved_users():
|
||||
return users
|
||||
|
||||
|
||||
|
||||
|
||||
def get_current_user_id():
|
||||
user_details = load_user_details()
|
||||
user_id = user_details.get('user_id')
|
||||
@@ -317,12 +329,13 @@ def get_art_url(data, art_type, parent=False, index=0, server=None):
|
||||
if image_tag_type:
|
||||
image_tag = image_tag_type
|
||||
elif parent is True:
|
||||
if (item_type == "Episode" or item_type == "Season") and art_type == 'Primary':
|
||||
if ((item_type == "Episode" or item_type == "Season") and
|
||||
art_type == 'Primary'):
|
||||
tag_name = 'SeriesPrimaryImageTag'
|
||||
id_name = 'SeriesId'
|
||||
else:
|
||||
tag_name = 'Parent%sImageTag' % art_type
|
||||
id_name = 'Parent%sItemId' % art_type
|
||||
tag_name = 'Parent{}ImageTag'.format(art_type)
|
||||
id_name = 'Parent{}ItemId'.format(art_type)
|
||||
parent_image_id = data.get(id_name)
|
||||
parent_image_tag = data.get(tag_name)
|
||||
if parent_image_id is not None and parent_image_tag is not None:
|
||||
@@ -330,7 +343,9 @@ def get_art_url(data, art_type, parent=False, index=0, server=None):
|
||||
image_tag = parent_image_tag
|
||||
|
||||
# ParentTag not passed for Banner and Art
|
||||
if not image_tag and not ((art_type == 'Banner' or art_type == 'Art') and parent is True):
|
||||
if (not image_tag and
|
||||
not ((art_type == 'Banner' or art_type == 'Art') and
|
||||
parent is True)):
|
||||
return ""
|
||||
|
||||
artwork = "{}/Items/{}/Images/{}/{}?Format=original&Tag={}".format(
|
||||
@@ -341,7 +356,9 @@ def get_art_url(data, art_type, parent=False, index=0, server=None):
|
||||
def image_url(item_id, art_type, index, width, height, image_tag, server):
|
||||
|
||||
# test imageTag e3ab56fe27d389446754d0fb04910a34
|
||||
artwork = "{}/Items/{}/Images/{}/{}?Format=original&Tag={}".format(server, item_id, art_type, index, image_tag)
|
||||
artwork = "{}/Items/{}/Images/{}/{}?Format=original&Tag={}".format(
|
||||
server, item_id, art_type, index, image_tag
|
||||
)
|
||||
if int(width) > 0:
|
||||
artwork += '&MaxWidth={}'.format(width)
|
||||
if int(height) > 0:
|
||||
@@ -414,8 +431,20 @@ def download_external_sub(language, codec, url):
|
||||
|
||||
# Write the subtitle file to the local filesystem
|
||||
file_name = 'Stream.{}.{}'.format(language, codec)
|
||||
file_path = py2_decode(translate_path('special://temp/{}'.format(file_name)))
|
||||
file_path = py2_decode(
|
||||
translate_path('special://temp/{}'.format(file_name))
|
||||
)
|
||||
with open(file_path, 'wb') as f:
|
||||
f.write(r.content)
|
||||
|
||||
return file_path
|
||||
|
||||
|
||||
def get_bitrate(enum_value):
|
||||
''' Get the video quality based on add-on settings.
|
||||
Max bit rate supported by server: 2147483 (max signed 32bit integer)
|
||||
'''
|
||||
bitrate = [500, 1000, 1500, 2000, 2500, 3000, 4000, 5000, 6000,
|
||||
7000, 8000, 9000, 10000, 12000, 14000, 16000, 18000,
|
||||
20000, 25000, 30000, 35000, 40000, 100000, 1000000, 2147483]
|
||||
return bitrate[int(enum_value) if enum_value else 24] * 1000
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
#################################################################################################
|
||||
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
import json
|
||||
import threading
|
||||
import websocket
|
||||
import time
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
import websocket
|
||||
|
||||
from .jellyfin import API
|
||||
from .functions import play_action
|
||||
@@ -158,7 +157,9 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
elif command == 'SetVolume':
|
||||
volume = arguments['Volume']
|
||||
xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume)
|
||||
xbmc.executebuiltin(
|
||||
'SetVolume({}[,showvolumebar])'.format(volume)
|
||||
)
|
||||
|
||||
elif command == 'SetAudioStreamIndex':
|
||||
index = int(arguments['Index'])
|
||||
@@ -170,7 +171,7 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
elif command == 'SetRepeatMode':
|
||||
mode = arguments['RepeatMode']
|
||||
xbmc.executebuiltin('xbmc.PlayerControl(%s)' % mode)
|
||||
xbmc.executebuiltin('xbmc.PlayerControl({})'.format(mode))
|
||||
|
||||
elif command == 'DisplayMessage':
|
||||
|
||||
@@ -253,7 +254,9 @@ class WebSocketClient(threading.Thread):
|
||||
else:
|
||||
server = server.replace('http://', 'ws://')
|
||||
|
||||
websocket_url = "%s/socket?api_key=%s&deviceId=%s" % (server, token, self.device_id)
|
||||
websocket_url = "{}/socket?api_key={}&deviceId={}".format(
|
||||
server, token, self.device_id
|
||||
)
|
||||
log.debug("websocket url: {0}".format(websocket_url))
|
||||
|
||||
self._client = websocket.WebSocketApp(
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
from __future__ import division, absolute_import, print_function, unicode_literals
|
||||
from __future__ import (
|
||||
division, absolute_import, print_function, unicode_literals
|
||||
)
|
||||
|
||||
import xbmcaddon
|
||||
import xbmcplugin
|
||||
import xbmcgui
|
||||
import hashlib
|
||||
import random
|
||||
import time
|
||||
|
||||
import xbmcaddon
|
||||
import xbmcplugin
|
||||
import xbmcgui
|
||||
|
||||
from .jellyfin import api
|
||||
from .utils import get_jellyfin_url, image_url, get_current_user_id, get_art_url, get_default_filters, kodi_version
|
||||
from .utils import (
|
||||
get_jellyfin_url, image_url, get_current_user_id,
|
||||
get_art_url, get_default_filters
|
||||
)
|
||||
from .lazylogger import LazyLogger
|
||||
from .kodi_utils import HomeWindow
|
||||
from .dir_functions import process_directory
|
||||
@@ -77,8 +83,9 @@ def set_background_image(force=False):
|
||||
background_items = []
|
||||
|
||||
if len(background_items) == 0:
|
||||
log.debug("set_background_image: Need to load more backgrounds {0} - {1}".format(
|
||||
len(background_items), background_current_item))
|
||||
log.debug("Need to load more backgrounds {0} - {1}".format(
|
||||
len(background_items), background_current_item)
|
||||
)
|
||||
|
||||
url_params = {}
|
||||
url_params["Recursive"] = True
|
||||
@@ -106,13 +113,17 @@ def set_background_image(force=False):
|
||||
background_items.append(item_background)
|
||||
|
||||
log.debug("set_background_image: Loaded {0} more backgrounds".format(
|
||||
len(background_items)))
|
||||
len(background_items))
|
||||
)
|
||||
|
||||
if len(background_items) > 0:
|
||||
bg_image = background_items[background_current_item].get("image")
|
||||
label = background_items[background_current_item].get("name")
|
||||
log.debug(
|
||||
"set_background_image: {0} - {1} - {2}".format(background_current_item, label, bg_image))
|
||||
"set_background_image: {0} - {1} - {2}".format(
|
||||
background_current_item, label, bg_image
|
||||
)
|
||||
)
|
||||
|
||||
background_current_item += 1
|
||||
if background_current_item >= len(background_items):
|
||||
@@ -171,7 +182,9 @@ def check_for_new_content():
|
||||
url_params["IncludeItemTypes"] = "Movie,Episode"
|
||||
url_params["ImageTypeLimit"] = 0
|
||||
|
||||
played_url = get_jellyfin_url('/Users/{}/Items'.format(user_id), url_params)
|
||||
played_url = get_jellyfin_url(
|
||||
'/Users/{}/Items'.format(user_id), url_params
|
||||
)
|
||||
|
||||
result = api.get(played_url)
|
||||
log.debug("LATEST_PLAYED_ITEM: {0}".format(result))
|
||||
@@ -215,7 +228,9 @@ def get_widget_content_cast(handle, params):
|
||||
if not result:
|
||||
return
|
||||
|
||||
if result.get("Type", "") in ["Episode", "Season"] and params.get("auto", "true") == "true":
|
||||
if (result.get("Type", "") in ["Episode", "Season"] and
|
||||
params.get("auto", "true") == "true"):
|
||||
|
||||
series_id = result.get("SeriesId")
|
||||
if series_id:
|
||||
params["id"] = series_id
|
||||
@@ -236,7 +251,9 @@ def get_widget_content_cast(handle, params):
|
||||
person_thumbnail = None
|
||||
if person_tag:
|
||||
person_thumbnail = image_url(
|
||||
person_id, "Primary", 0, 400, 400, person_tag, server=server)
|
||||
person_id, "Primary", 0, 400, 400,
|
||||
person_tag, server=server
|
||||
)
|
||||
|
||||
list_item = xbmcgui.ListItem(label=person_name, offscreen=True)
|
||||
|
||||
@@ -255,8 +272,8 @@ def get_widget_content_cast(handle, params):
|
||||
if person_role:
|
||||
list_item.setLabel2(person_role)
|
||||
|
||||
item_tupple = ("", list_item, False)
|
||||
list_items.append(item_tupple)
|
||||
item_tuple = ("", list_item, False)
|
||||
list_items.append(item_tuple)
|
||||
|
||||
xbmcplugin.setContent(handle, 'artists')
|
||||
xbmcplugin.addDirectoryItems(handle, list_items)
|
||||
@@ -387,12 +404,19 @@ def get_widget_content(handle, params):
|
||||
while len(ids) < item_limit and suggested_items:
|
||||
items = suggested_items[set_id]
|
||||
log.debug(
|
||||
"BaselineItemName : {0} - {1}".format(set_id, items.get("BaselineItemName")))
|
||||
"BaselineItemName : {0} - {1}".format(
|
||||
set_id, items.get("BaselineItemName")
|
||||
)
|
||||
)
|
||||
items = items["Items"]
|
||||
rand = random.randint(0, len(items) - 1)
|
||||
item = items[rand]
|
||||
if item["Type"] == "Movie" and item["Id"] not in ids and (not item["UserData"]["Played"] or not hide_watched):
|
||||
|
||||
if (item["Type"] == "Movie" and item["Id"] not in ids and
|
||||
(not item["UserData"]["Played"] or not hide_watched)):
|
||||
|
||||
ids.append(item["Id"])
|
||||
|
||||
del items[rand]
|
||||
if len(items) == 0:
|
||||
del suggested_items[set_id]
|
||||
@@ -406,22 +430,23 @@ def get_widget_content(handle, params):
|
||||
|
||||
items_url = get_jellyfin_url(url_verb, url_params)
|
||||
|
||||
if url_params.get('IncludeItemTypes', '') == 'Episode' or params.get('type', '') == 'nextup_episodes':
|
||||
if (url_params.get('IncludeItemTypes', '') == 'Episode' or
|
||||
params.get('type', '') == 'nextup_episodes'):
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
|
||||
list_items, detected_type, total_records = process_directory(
|
||||
items_url, None, params, use_cached_widget_data)
|
||||
|
||||
# Combine In Progress and Next Up Episodes, append next up after In Progress
|
||||
# Combine In Progress and Next Up Episodes, add next up after In Progress
|
||||
if widget_type == "nextup_episodes":
|
||||
inprogress_url = get_jellyfin_url(
|
||||
inprogress_url_verb, inprogress_url_params)
|
||||
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
list_items_inprogress, detected_type, total_records = process_directory(
|
||||
inprogress, detected_type, total_records = process_directory(
|
||||
inprogress_url, None, params, use_cached_widget_data)
|
||||
|
||||
list_items = list_items_inprogress + list_items
|
||||
list_items = inprogress + list_items
|
||||
|
||||
if detected_type is not None:
|
||||
# if the media type is not set then try to use the detected type
|
||||
@@ -434,7 +459,7 @@ def get_widget_content(handle, params):
|
||||
content_type = 'episodes'
|
||||
elif detected_type == "Series":
|
||||
content_type = 'tvshows'
|
||||
elif detected_type == "Music" or detected_type == "Audio" or detected_type == "Musicalbum":
|
||||
elif detected_type in ["Music", "Audio", "Musicalbum"]:
|
||||
content_type = 'songs'
|
||||
|
||||
if content_type:
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<setting label="30238" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting id="max_stream_bitrate" type="slider" label="30208" default="75000" range="400,100,100000" option="int" visible="true"/>
|
||||
<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="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" />
|
||||
@@ -38,12 +38,13 @@
|
||||
|
||||
<setting label="30211" type="lsep"/>
|
||||
<setting type="sep" />
|
||||
<setting id="force_max_stream_bitrate" type="slider" label="30434" default="7000" range="400,100,15000" option="int" visible="true"/>
|
||||
<setting id="force_max_stream_bitrate" type="enum" label="30434" 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 [default]|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|Maximum" visible="true" default="9" />
|
||||
<setting id="playback_max_width" type="select" label="30212" values="640|720|1024|1280|1440|1600|1920|2600|4096" default="1920" visible="true"/>
|
||||
<setting id="playback_video_force_8" type="bool" label="30213" default="false" visible="true" enable="true"/>
|
||||
<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 id="max_play_queue" type="slider" label="30447" default="200" range="20, 10, 1000" option="int" visible="true"/>
|
||||
|
||||
</category>
|
||||
<category label="30214">
|
||||
|
||||
@@ -177,15 +177,15 @@ websocket_client.stop_client()
|
||||
# call stop on the library update monitor
|
||||
library_change_monitor.stop()
|
||||
|
||||
# stop the play next episdoe service
|
||||
# stop the play next episode service
|
||||
if play_next_service:
|
||||
play_next_service.stop_servcie()
|
||||
play_next_service.stop_service()
|
||||
|
||||
# call stop on the context menu monitor
|
||||
if context_monitor:
|
||||
context_monitor.stop_monitor()
|
||||
|
||||
# clear user and token when loggin off
|
||||
# clear user and token when logging off
|
||||
home_window.clear_property("user_name")
|
||||
home_window.clear_property("AccessToken")
|
||||
home_window.clear_property("userimage")
|
||||
|
||||
Reference in New Issue
Block a user