diff --git a/script.artistslideshow/addon.xml b/script.artistslideshow/addon.xml index 88e84b09c..2dd8793f8 100644 --- a/script.artistslideshow/addon.xml +++ b/script.artistslideshow/addon.xml @@ -1,4 +1,4 @@ - + @@ -10,9 +10,8 @@ -v.3.3.6 -- fix to allow blank as illegal replace character in Nexus -- updated language files +v.3.3.7 +- fix to get fourth artwork from theAudioDB icon.png @@ -23,7 +22,6 @@ v.3.3.6 https://kodi.wiki/index.php?title=Add-on:Artist_Slideshow artistslideshow.xbmc@gmail.com https://github.com/pkscout/script.artistslideshow - حمل المزيد من الصور والمعلومات عن الفنان الذى يُغنِى حالياً Сваля изображения и допълнителна инф. за изпълнителя на текущата песен Descàrrega imatges i informació addicional de l'artista que s'està reproduint Download billeder og ekstra info om kunstneren, der spiller i øjeblikket @@ -31,6 +29,8 @@ v.3.3.6 Κατεβάστε εικόνες και επιπλέον πληροφορίες του τρέχοντος καλλιτέχνη Download images and additional info of the currently playing artist Download images and additional info of the currently playing artist + Download images and additional info of the currently playing artist + Download images and additional info of the currently playing artist Download images and additional info of the currently playing artist Bajá imágenes e información adicional sobre el artista Descarga imágenes e información adicional del intérprete que esté sonando @@ -38,9 +38,9 @@ v.3.3.6 Lae alla pilte ja lisateavet hetkel mängiva esitaja kohta Noutaa kuvia ja lisätietoja parhaillaan toistettavasta esittäjästä Télécharger des images et des infos additionnelles sur l'artiste écouté + Télécharger des images et des infos additionnelles sur l'artiste écouté Télécharger les images et les informations additionnelles de l'artiste en cours de lecture Descarga imaxes e info. adicional do artista que está a soar - הורד תמונות ומידע נוסף על האמן המושמע כעת Preuzimite slike i dodatne informacije o trenutno reproduciranom izvođaču Képeket és kiegészítő információkat tölt le a jelenleg játszott előadóról Scarica immagini e informazioni aggiuntive dell'artista attualmente in riproduzione @@ -50,13 +50,11 @@ v.3.3.6 Downloaden van afbeeldingen en extra informatie van te horen artiest Pobieraj obrazy i dodatkowe informacje o aktualnie odtwarzanym wykonawcy Transferência de imagens e informações adicionais de artistas que estejam sendo reproduzidos - Transferir imagens e info adicional do artista em reprodução agora Загружает изображения и дополнительную информацию об исполнителе, который воспроизводится в данный момент Stiahnuť obrázky a dodatočné informácie o práve hrajúcich interpretoch Naložite slike in dodatne informacije, za trenutno predvajanega izvajalca Ladda ner bilder samt ytterligare information om den spelade artisten 下载当前播放艺人的图片和附加信息 - ملحق يساعدك على تَنِزِيل صور ومعلومات إضافيه عن الفنان الذى تستمع اليه حالياً من موقع fanart.tv و theaudiodb.com. كما يمكنك جعل جلد واجهتك الحالى يستخدم كل ما سبق ﻹنشاء عروض شرائح للفنان الذى تستمع إليه Добавката сваля картинки и допълнителна информация от www.fanart.tv и www.theaudiodb.com за изпълнителя който звучи в момента. Картинките, заедно с фанарт изображенията на изпълнителя, може да се ползват от облика, за създаването на слайдшоу за изпълнителя, който звучи в момента. Complement per descarregar imatges i informació addicional de fanart.tv i theaudiodb.com de l'artista que s'està reproduint. Les imatges, juntament amb les imatges locals d'artistes, i la informació, pot ser utilitzada per la pell per crear una presentació de diapositives per a l'artista que s'està escoltant. Add-on til at downloade billeder og yderligere information fra fanart.tv og theaudiodb.com af den aktuelt afspillede kunstner. Billederne kan sammen med lokale kunstneres billeder og info bruges af dit skin til at skabe et diasshow for kunstneren, der lyttes til. @@ -64,15 +62,17 @@ v.3.3.6 Πρόσθετο για τη λήψη εικόνων και επιπλέον πληροφοριών από το fanart.tv και το theaudiodb.com για τον τρέχοντα καλλιτέχνη. Οι εικόνες, μαζί με τοπικές εικόνες του καλλιτέχνη καθώς και πληροφορίες, μπορούν να χρησιμοποιηθούν από το κέλυφος για τη δημιουργία παρουσιάσεων διαφανειών του καλλιτέχνη η μουσική του οποίου ακούγεται. Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to. Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to. + Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to. + Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to. Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to. Addon para descargar imágenes e información adicional de fanart.tv y theaudiodb.com del intérprete que se está reproduciendo. Las imágenes, junto con imágenes de intérpretes locales, y la información puede ser utilizada por la piel para crear una presentación de diapositivas para el intérprete que se está escuchando. Complemento para descargar imágenes e información adicional de fanart.tv y theaudiodb.com del artista actualmente en reproducción. Las imágenes, junto con las imágenes e información locales de los artistas pueden ser utilizados por la máscara para crear una presentación del artista que estés escuchando. Lisamoodul, millega saab alla laadida pilte ja lisateavet fanart.tv ja theaudiodb.com saitidelt hetkel mängiva esitaja kohta. Koos meediakogus leiduvate esitajate piltide ja teabega saab rüü neid kasutada kuulatava esitaja slaidiseansi loomiseks. Lisäosa parhaillaan kuunneltavan esittäjän kuvien ja tietojen noutoon mm. Fanart.tv- ja TheAudioDB.com-palveluista. Ulkoasut voivat luoda kuvaesityksiä kuunneltavasta esittäjästä käyttäen näitä tietoja ja esittäjien paikallisia kuvia. Addiciel pour télécharger des images et des informations additionnelles sur fanart.tv et theaudiodb.com de l'artiste en cours d'écoute. Les images, ainsi que les images locales de l'artiste, et les infos peuvent être utilisées par l'habillage pour créer un diaporama pour l'artiste en cours d'écoute. + Addiciel pour télécharger des images et des informations additionnelles sur fanart.tv et theaudiodb.com de l'artiste en cours d'écoute. Les images, ainsi que les images locales de l'artiste, et les infos peuvent être utilisées par l'habillage pour créer un diaporama pour l'artiste en cours d'écoute. Extension permettant de télécharger des images et des informations supplémentaires depuis fanart.tv et depuis theaudiodb.com de l'artiste en cours d'écoute. Les images téléchargées, les images locales des artistes et les informations peuvent être utilisées par le skin pour créer un diaporama pour l'artiste écouté. Complemento para descargar imaxes e información adicional de fanart.tv e theaudiodb.com do artista que está a soar. Estas imaxes, xunto cas do artista gardadas en local e a información pódeas usar o tema para crear unha presentación. - הרחבה להורדת תמונות ומידע נוסף על האמן המושמע כעת מ-fanart.tv ו- theaudiodb.com. התמונות, בנוסף לתמונות אמנים מקומיות והמידע על אמן יכולים לשמש את המעטפת ליצירת מצגת עבור האמן המושמע כעת. Dodatak za preuzimanje slika i dodatnih informacije trenutno reproduciranog izvođača s fanart.tv, theaudiodb.com i theaudiodb.com. Slike, zajedno s lokalnim slikama izvođača i informacijama mogu se koristiti s presvlakom za stvaranje slikovne prezentacije izvođača koji se sluša. A Kiegészítő letölt képeket és infromációkat a fanart.tv és theaudiodb.com oldalakról az éppen hallgatott előadóhoz. A képek a helyben tárolt képekkel együtt felhasználhatóak a Felszín által diavetítéshez. Add-on per scaricare immagini ed informazioni aggiuntive da fanart.tv e theaudiodb.com sull'artista attualmente in riproduzione. Le immagini possono essere usate dalla skin, insieme a quelle locali, per creare una presentazione per l'artista che si sta ascoltando. @@ -81,7 +81,6 @@ v.3.3.6 Add-on om afbeeldingen en bijkomende informatie van Fanart.tv en theaudiodb.com van de te horen artiest binnen te halen. de afbeeldingen, net als de lokaal aanwezige artiest-afbeeldingen en -info kunnen gebruikt worden door de skin om een diashow te tonen van de artiest di nu beluisterd wordt. Wtyczka pobiera obrazy i dodatkowe informacje z fanart.tv oraz theaudiodb.com o aktualnie odtwarzanym wykonawcy. Obrazami wraz z informacjami o wykonawcach, mogą być wykorzystywane przez skórę do tworzenia pokazu slajdów wykonawcy, którego aktualnie słuchasz. Addon para download de imagens e informações adicionais do artista que está sendo reproduzido provido por fanart.tv e theaudiodb. Tais dados e imagens serão usados pelas skins para criarem um slideshow dos artistas quando estivermos escutando-os. - Um add-on para transferir imagens e informação adicional do artista em reprodução no momento, a partir de fanart.tv e theaudiodb.com. As imagens e a informação, assim como as imagens locais dos artistas, podem ser usadas pelo tema para criar uma apresentação de slides do artista em escuta no momento. Дополнение для загрузки изображений и дополнительной информации о воспроизводимом исполнителе с ресурсов fanart.tv and theaudiodb.com. Загруженные изображения и доп. информация, наравне с локальными, могут быть использованы для создания слайд-шоу во время прослушивания композиций. Dodatek za prenos slik in dodatnih informacij iz fanart.tv in theaudiodb.com za trenutno predvajanega izvajalca. Slike, skupaj z lokalnimi slikami izvajalcev ter informacije, se lahko uporabljajo s preobleko za ustvarjanje diaprojekcije slik izvajalca, ki ga trenutno poslušate. Tillägg för att ladda ner bilder och tilläggsinformation från fanart.tv och theaudiodb.com om artisten som spelas för tillfället. Bilderna, tillsammans med lokala artistbilder och information, kan användas av skinnet för att skapa ett bildspel av artisten man lyssnar på. diff --git a/script.artistslideshow/changelog.txt b/script.artistslideshow/changelog.txt index 3cbd86792..a7da1ba19 100644 --- a/script.artistslideshow/changelog.txt +++ b/script.artistslideshow/changelog.txt @@ -1,3 +1,6 @@ +v.3.3.7 +- fix to get fourth artwork from theAudioDB + v.3.3.6 - fix to allow blank as illegal replace character in Nexus - updated language files diff --git a/script.artistslideshow/resources/language/resource.language.ar_sa/strings.po b/script.artistslideshow/resources/language/resource.language.ar_sa/strings.po index 9424b0537..c6f808ec1 100644 --- a/script.artistslideshow/resources/language/resource.language.ar_sa/strings.po +++ b/script.artistslideshow/resources/language/resource.language.ar_sa/strings.po @@ -19,11 +19,11 @@ msgstr "" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" -msgstr "حمل المزيد من الصور والمعلومات عن الفنان الذى يُغنِى حالياً" +msgstr "" msgctxt "Addon Description" msgid "Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to." -msgstr "ملحق يساعدك على تَنِزِيل صور ومعلومات إضافيه عن الفنان الذى تستمع اليه حالياً من موقع fanart.tv و theaudiodb.com. كما يمكنك جعل جلد واجهتك الحالى يستخدم كل ما سبق ﻹنشاء عروض شرائح للفنان الذى تستمع إليه" +msgstr "" # Section Headings msgctxt "#32000" diff --git a/script.artistslideshow/resources/language/resource.language.en_au/strings.po b/script.artistslideshow/resources/language/resource.language.en_au/strings.po index 6ddd720ed..ecb83b557 100644 --- a/script.artistslideshow/resources/language/resource.language.en_au/strings.po +++ b/script.artistslideshow/resources/language/resource.language.en_au/strings.po @@ -7,15 +7,14 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-03-09 14:05+0000\n" -"Last-Translator: Christian Gade \n" -"Language-Team: English (Australia) \n" -"Language: en_au\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en_AU\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.11.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -130,7 +129,7 @@ msgstr "" msgctxt "#32119" msgid "Enable debug logging" -msgstr "Enable debug logging" +msgstr "" msgctxt "#32120" msgid "Disable secondary and featured artist images" @@ -248,7 +247,7 @@ msgstr "" msgctxt "#32202" msgid "Error" -msgstr "Error" +msgstr "" msgctxt "#32203" msgid "Progress" diff --git a/script.artistslideshow/resources/language/resource.language.en_nz/strings.po b/script.artistslideshow/resources/language/resource.language.en_nz/strings.po index d7462ed26..7a35e0557 100644 --- a/script.artistslideshow/resources/language/resource.language.en_nz/strings.po +++ b/script.artistslideshow/resources/language/resource.language.en_nz/strings.po @@ -7,15 +7,14 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-03-09 14:05+0000\n" -"Last-Translator: Christian Gade \n" -"Language-Team: English (New Zealand) \n" -"Language: en_nz\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en_NZ\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.11.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -130,7 +129,7 @@ msgstr "" msgctxt "#32119" msgid "Enable debug logging" -msgstr "Enable debug logging" +msgstr "" msgctxt "#32120" msgid "Disable secondary and featured artist images" @@ -248,7 +247,7 @@ msgstr "" msgctxt "#32202" msgid "Error" -msgstr "Error" +msgstr "" msgctxt "#32203" msgid "Progress" diff --git a/script.artistslideshow/resources/language/resource.language.en_us/strings.po b/script.artistslideshow/resources/language/resource.language.en_us/strings.po index 077143fd2..bcdb25bc2 100644 --- a/script.artistslideshow/resources/language/resource.language.en_us/strings.po +++ b/script.artistslideshow/resources/language/resource.language.en_us/strings.po @@ -7,15 +7,14 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-03-11 00:15+0000\n" -"Last-Translator: Christian Gade \n" -"Language-Team: English (United States) \n" -"Language: en_us\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en_US\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.11.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -130,7 +129,7 @@ msgstr "" msgctxt "#32119" msgid "Enable debug logging" -msgstr "Enable debug logging" +msgstr "" msgctxt "#32120" msgid "Disable secondary and featured artist images" @@ -248,7 +247,7 @@ msgstr "" msgctxt "#32202" msgid "Error" -msgstr "Error" +msgstr "" msgctxt "#32203" msgid "Progress" diff --git a/script.artistslideshow/resources/language/resource.language.es_es/strings.po b/script.artistslideshow/resources/language/resource.language.es_es/strings.po index 8d2fe60f5..dfd4d710c 100644 --- a/script.artistslideshow/resources/language/resource.language.es_es/strings.po +++ b/script.artistslideshow/resources/language/resource.language.es_es/strings.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2023-02-27 11:31+0000\n" +"PO-Revision-Date: 2024-01-07 00:13+0000\n" "Last-Translator: José Antonio Alvarado \n" "Language-Team: Spanish (Spain) \n" "Language: es_es\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.15.2\n" +"X-Generator: Weblate 5.3\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -230,7 +230,7 @@ msgstr "Solo mostrar notificación si hay imágenes para descargar" msgctxt "#32144" msgid "Use more agressive artist search for streams" -msgstr "Usar una búsqueda de intérpretes más agresiva para streams" +msgstr "Utilizar una búsqueda de artistas más agresiva para las transmisiones" msgctxt "#32145" msgid "Pause slideshow on playback pause" diff --git a/script.artistslideshow/resources/language/resource.language.fa_af/strings.po b/script.artistslideshow/resources/language/resource.language.fa_af/strings.po index 51d9a0013..0bb7b32b3 100644 --- a/script.artistslideshow/resources/language/resource.language.fa_af/strings.po +++ b/script.artistslideshow/resources/language/resource.language.fa_af/strings.po @@ -10,7 +10,7 @@ msgstr "" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" -"Language: fa_af\n" +"Language: fa_AF\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" diff --git a/script.artistslideshow/resources/language/resource.language.fr_ca/strings.po b/script.artistslideshow/resources/language/resource.language.fr_ca/strings.po index efbb96595..3186f38be 100644 --- a/script.artistslideshow/resources/language/resource.language.fr_ca/strings.po +++ b/script.artistslideshow/resources/language/resource.language.fr_ca/strings.po @@ -7,15 +7,14 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2022-03-17 10:13+0000\n" -"Last-Translator: Christian Gade \n" -"Language-Team: French (Canada) \n" -"Language: fr_ca\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fr_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.11.2\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -130,7 +129,7 @@ msgstr "" msgctxt "#32119" msgid "Enable debug logging" -msgstr "Activer la journalisation de débogage" +msgstr "" msgctxt "#32120" msgid "Disable secondary and featured artist images" @@ -248,7 +247,7 @@ msgstr "" msgctxt "#32202" msgid "Error" -msgstr "Erreur" +msgstr "" msgctxt "#32203" msgid "Progress" diff --git a/script.artistslideshow/resources/language/resource.language.he_il/strings.po b/script.artistslideshow/resources/language/resource.language.he_il/strings.po index 29ac6d112..a0b61bdcc 100644 --- a/script.artistslideshow/resources/language/resource.language.he_il/strings.po +++ b/script.artistslideshow/resources/language/resource.language.he_il/strings.po @@ -19,11 +19,11 @@ msgstr "" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" -msgstr "הורד תמונות ומידע נוסף על האמן המושמע כעת" +msgstr "" msgctxt "Addon Description" msgid "Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to." -msgstr "הרחבה להורדת תמונות ומידע נוסף על האמן המושמע כעת מ-fanart.tv ו- theaudiodb.com. התמונות, בנוסף לתמונות אמנים מקומיות והמידע על אמן יכולים לשמש את המעטפת ליצירת מצגת עבור האמן המושמע כעת." +msgstr "" # Section Headings msgctxt "#32000" diff --git a/script.artistslideshow/resources/language/resource.language.pt_pt/strings.po b/script.artistslideshow/resources/language/resource.language.pt_pt/strings.po index 20952974e..dc8b71135 100644 --- a/script.artistslideshow/resources/language/resource.language.pt_pt/strings.po +++ b/script.artistslideshow/resources/language/resource.language.pt_pt/strings.po @@ -19,11 +19,11 @@ msgstr "" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" -msgstr "Transferir imagens e info adicional do artista em reprodução agora" +msgstr "" msgctxt "Addon Description" msgid "Addon to download images and additional information from fanart.tv and theaudiodb.com of the currently playing artist. The images, along with local artists' images, and info can be used by the skin to create a slideshow for the artist being listened to." -msgstr "Um add-on para transferir imagens e informação adicional do artista em reprodução no momento, a partir de fanart.tv e theaudiodb.com. As imagens e a informação, assim como as imagens locais dos artistas, podem ser usadas pelo tema para criar uma apresentação de slides do artista em escuta no momento." +msgstr "" # Section Headings msgctxt "#32000" diff --git a/script.artistslideshow/resources/language/resource.language.ru_ru/strings.po b/script.artistslideshow/resources/language/resource.language.ru_ru/strings.po index 521ed185a..adbb9f4ef 100644 --- a/script.artistslideshow/resources/language/resource.language.ru_ru/strings.po +++ b/script.artistslideshow/resources/language/resource.language.ru_ru/strings.po @@ -7,15 +7,15 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2023-04-25 18:16+0000\n" -"Last-Translator: vgbsd \n" +"PO-Revision-Date: 2024-02-29 09:13+0000\n" +"Last-Translator: Alexey \n" "Language-Team: Russian \n" "Language: ru_ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "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.15.2\n" +"X-Generator: Weblate 5.4\n" msgctxt "Addon Summary" msgid "Download images and additional info of the currently playing artist" @@ -102,7 +102,7 @@ msgstr "Использовать резервное слайд-шоу" msgctxt "#32112" msgid "Use override slideshow" -msgstr "" +msgstr "Использовать переопределение слайд-шоу" msgctxt "#32113" msgid "Custom location" @@ -234,7 +234,7 @@ msgstr "Использовать более интенсивный поиск и msgctxt "#32145" msgid "Pause slideshow on playback pause" -msgstr "" +msgstr "Приостановка слайд-шоу на паузу при воспроизведении" # empty strings from id 32145 to 32199 # Dialog headings diff --git a/script.artistslideshow/resources/plugins/theaudiodb.py b/script.artistslideshow/resources/plugins/theaudiodb.py index 77c68317f..54c37ed08 100644 --- a/script.artistslideshow/resources/plugins/theaudiodb.py +++ b/script.artistslideshow/resources/plugins/theaudiodb.py @@ -99,7 +99,7 @@ def getImageList(self, img_params): if json_data: artist = json_data.get('artists') if artist is not None: - for count in range(3): + for count in range(4): if count == 0: num = '' else: diff --git a/script.plexmod/LICENSE.txt b/script.plexmod/LICENSE.txt index ed5f05abe..48d882dcd 100644 --- a/script.plexmod/LICENSE.txt +++ b/script.plexmod/LICENSE.txt @@ -485,6 +485,61 @@ apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. +------------------------------------------------------------------------- + +https://github.com/phihag/ipaddress + +This package is a modified version of cpython's ipaddress module. +It is therefore distributed under the PSF license, as follows: + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are +retained in Python alone or in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + ------------------------------------------------------------------------- Fontawesome diff --git a/script.plexmod/README.md b/script.plexmod/README.md index 317bd7cab..50b922dcd 100644 --- a/script.plexmod/README.md +++ b/script.plexmod/README.md @@ -1,4 +1,6 @@ -# PlexMod (for Kodi) +# PM4K / PlexMod for Kodi + +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Z8Z8X6P9T) This is a modification of the official open-source Plex client for Kodi "plex-for-kodi" (Plex4Kodi) semi-maintained by me (pannal). @@ -6,7 +8,7 @@ Contrary to how this repository was handled before, this client does _not_ claim It implements features that are not implemented in other official Plex clients and may implement others in non-conform ways. -It is still based off of the original P4K source and critical bugfixes will be PR'd back. +It is still based off of the original P4K source and critical bugfixes might be PR'd back. ## Active branches * [develop-kodi21](https://github.com/pannal/plex-for-kodi/tree/develop_kodi21) (Kodi 19, 20, 21 cross-compatible) @@ -16,15 +18,21 @@ Master branch is based off of the official plex-for-kodi master branch. ## Installation -### Via repository +### Via repository (recommended) * Add `https://pannal.github.io/dontpanickodi/` to your Kodi installation as a file source -* Go back to addons, choose zip file, choose the file source you added and install the repository -* Install Plex via Addons->Install from repository->Don’t Panic->Video add-ons->Plex -* Optional, recommended: Install Plextuary via Addons->Install from repository->Don’t Panic->Look and Feel->Skin->Plextuary +* Go to Settings->Addons, choose "Install from zip file", choose the file source you added and install the repository +* Install Plex via Settings->Addons->Install from repository->Don't Panic->Video add-ons->Plex +* Optional, recommended: Install Plextuary via Settings->Addons->Install from repository->Don't Panic->Look and Feel->Skin->Plextuary + +### Installation (stable only, not optimized, possibly outdated) +* Install "PM4K for Kodi" from the official Kodi repository +* Optional, recommended: Install Plextuary skin using the above ### Manual * Checkout any branch of this GitHub repository, rename to `script.plexmod` and use as an addon +## Translation +You can help! Join the translation effort at [POEditor](https://poeditor.com/join/project/ASOl50YAXg) (thanks for the free open source license, guys). ## Help/Bug Reports https://forums.plex.tv/t/plexmod-for-kodi-18-19-20-21/481208 diff --git a/script.plexmod/addon.xml b/script.plexmod/addon.xml index 9222be922..32146aee2 100644 --- a/script.plexmod/addon.xml +++ b/script.plexmod/addon.xml @@ -1,7 +1,7 @@ @@ -33,7 +33,7 @@ https://github.com/pannal/plex-for-kodi all -- Based on 0.7.7-rev3 +- WIP icon2.png diff --git a/script.plexmod/changelog.txt b/script.plexmod/changelog.txt index d09735b45..d0a8537d5 100644 --- a/script.plexmod/changelog.txt +++ b/script.plexmod/changelog.txt @@ -1,7 +1,83 @@ +[-0.7.8-] +- Global: Use watched markers instead of unwatched markers (green checkmark vs. yellow triangle) +- Home: Blur in-progress episode thumbnails if Addon Setting “Use episode thumbnails in continue hub” is enabled and titles if requested +- Home: Refresh hubs when no episode spoiler setting changed +- Home/Settings: After changing home-relevant settings, reload Home on revisit, not immediately +- Home: Dynamically reload home when relevant settings have changed +- Home/Sections: Improve handling for sections that errored out once, and retry loading them just like any stale section every 5 minutes +- Home: Fix hubs not coming back after disconnect +- Home: Harden disconnect handling in general; PM4K should be able to "live" forever now +- Home: Refresh last section on: screensaver deactivated, DPMS deactivated, system wakeup after sleep +- Home/PowerEvents: Disable updates when system goes to sleep, enable them when it wakes up; force a hubs update when waking up +- Home: Probably fix long-running section change issue (partially reverting a previous change and being a little smarter about the current selection state); add debug logging for when we detect the "anomaly" +- Home: Don't let any tasks remain in a crashed state +- Core/Home: Add easy path mapping +- Core/Home: Add library context option to hide them for current user/server; Add context option for "Home" to unhide hidden libraries +- Home: Hide hidden library content from home hubs as well +- Home: Add library reordering functionality +- Home: Remove Hub round-robining altogether +- Home: Use ACTION_NAV_BACK/ACTION_PREVIOUS_MENU in home hubs to select the first item when any item other than the first item is selected +- Home: After refreshing stale section hubs (every 5m), re-select the last selected position in every hub, possibly re-extending the hubs to match the last position +- Episodes: Blur unwatched/in-progress episode thumbnails and redact spoiler texts, and episode titles if requested +- Episodes: Possibly use correct episode when playing TV Show from TV Show overview; always play latest in progress, unwatched, deprioritize specials +- Episodes: after watching an episode, remove chevron immediately +- Episodes: After watching multiple episodes in a row that span more than one season (e.g. watched S01E10, S02E01), properly redirect to the latest correct season view of the just watched episodes +- Episodes: Inject watched/progress state into listitem datasource (fixes wrong "Mark as (Un) Played" menu item behaviour immediately after watching an episode) +- Episodes: Don't play theme music when coming back from Home-Direct-Play (pressed P or ACTION_PLAYER_PLAY) +- Episodes: Select the correct episode after returning from direct playback from home (P/PLAY pressed) +- SeekDialog: Hide episode title if wanted +- SeekDialog: Properly update VideoPlaylist when using next/prev +- SeekDialog: Improve chapter visibility (selected and deselected (current)) +- SeekDialog: Throw away intro markers with an unreasonably late start offset (>10m) +- SeekDialog: Throw invalid markers away once, not every tick +- SeekDialog/Settings/Video Playlists: change the setting options for showing the prev/next and playlist buttons from "Only for Episodes" to "Only for Episodes/Playlists"; Show next/prev/playlist buttons in player for video playlists if wanted +- Core/Players: Remove all Kodi media-loading spinners when using Plextuary skin +- Core/Player: Always set infolabel "year" and remove it when downloading subtitles; don't set infolabels "episode" and "season" at all for non-TV-shows (fixes scrobbling issues with trakt plugin) +- Core/Player: Report all known Guids to script.trakt if it's installed; generate slug for movies +- Player/SeekDialog: Properly handle a manual stop action on episodes when OSD was visible (possibly other occasions) +- Player/PostPlay: Hide spoilers as well, if configured +- Postplay: Don't show the same episode on deck which is going to be played next +- TV Shows/Seasons: Try reloading instead of exiting to home when deleting a season if possible +- Libraries: Add movie/show year to label (thanks @bowlingbeeg) +- Libraries: Fix year display, fix Art display in listview 16x9; make small posters view a little less cramped +- VideoPlaylists: Show playback menu when an item can be resumed +- VideoPlaylists: Show playback menu when CONTEXT_MENU action is detected +- VideoPlaylists: Allow resuming, or, if possible, Start from Beginning +- Core: Ignore local IPv4 docker plex.direct hosts when checking for host mapping +- Core: Unify spoiler handling across multiple windows +- Core: API requests: Don't generally include markers, only for PlayableVideos +- Core: Open up translations to everyone, using POEditor +- Core/AddonSettings: Remove old compatibility profile code and setting +- Core/AddonSettings: Make caching home users optional; add setting (default: on) +- Core/Home: When home user caching is disabled, refresh home users when opening the user dropdown (once) +- Core: Add support for Guids in new library agents +- Core/Episodes/Player: Inject Show reference into episodes to speed up playback start and avoid additional API hits; Don't initiate a playlist if only one episode is being played +- Core: Compatibility with script.trakt +- Core: Add automated generic JSON data cache, stored as addon_data/script.plexmod/data_cache.json +- Core/TV: Store and use "once seen" genres for a show in the data cache to speed up certain views (such as postplay and continue watching, with no spoiler mode active) +- Core: Automatically clean up old unused data cache entries which haven't been accessed for 30 days +- Core/Settings: Add option to use watched markers instead of unwatched markers (default: on) +- Core/Settings: Add option to hide the black background on inverted watched markers (default: off) +- Core: Fix dialogs reverting the underlying window's watched marker setting temporarily +- Core: Memory usage and performance optimizations (possibly >10% in py3 and >30% in py2 by using __slots__ on massively used classes) +- Core: Allow for custom watched.png, unwatched.png, unwatched-rounded.png in addon_data/script.plexmod/media/ +- Core: Improve delete media clarity +- Core/Playlists: Fix context menu "play" action on playlist items when addonSetting playlist visit media is on +- Core/Windows: Optimize Imports +- Settings: Add setting to show indicators for libraries with active path mapping (default: on) +- Settings: Add setting to blur episode thumbnails and preview images, as well as redact spoilers for unwatched or unwatched+in progress episodes +- Settings: Add setting to also hide episode titles based on the above +- AddonSettings: Add setting to configure the blur amount for unwatched episodes (default: 16/255) +- AddonSettings: Add setting for ignoring local docker IPv4 hosts when checking for host mapping (default: enabled) +- AddonSettings: Change default of "Visit media in video playlist instead of playing it" to False +- AddonSettings: Add setting to define the maximum start offset of an intro marker to consider it (default: 600s/10m) +- Theme: Bump theme version to 3 + + [-0.7.7-rev2-] - UserSelect: When not switching user (startup), close the addon on cancel actions - Libraries/Photos: Do autoplay when Play or Shuffle buttons are pressed in photo library view -- Libraries/Photos: Fix wonky thumbnail display on photodirectories; support dynamic backgrounds for Photo items +- Libraries/Photos: Fix wonky thumbnail display on photodirectories - SeekDialog: Fix final credits marker skipping wrongly on manual marker skip - SeekDialog: Fix several marker issues (over-jumping, invalid markers) - SeekDialog: Show stream transport type in video session info (smb, nfs, path mapped, http(s)) diff --git a/script.plexmod/lib/_included_packages/_ipaddress.py b/script.plexmod/lib/_included_packages/_ipaddress.py new file mode 100644 index 000000000..3e6f9e499 --- /dev/null +++ b/script.plexmod/lib/_included_packages/_ipaddress.py @@ -0,0 +1,2420 @@ +# Copyright 2007 Google Inc. +# Licensed to PSF under a Contributor Agreement. + +"""A fast, lightweight IPv4/IPv6 manipulation library in Python. + +This library is used to create/poke/manipulate IPv4 and IPv6 addresses +and networks. + +""" + +from __future__ import unicode_literals + + +import itertools +import struct + +__version__ = '1.0.23' + +# Compatibility functions +_compat_int_types = (int,) +try: + _compat_int_types = (int, long) +except NameError: + pass +try: + _compat_str = unicode +except NameError: + _compat_str = str + assert bytes != str +if b'\0'[0] == 0: # Python 3 semantics + def _compat_bytes_to_byte_vals(byt): + return byt +else: + def _compat_bytes_to_byte_vals(byt): + return [struct.unpack(b'!B', b)[0] for b in byt] +try: + _compat_int_from_byte_vals = int.from_bytes +except AttributeError: + def _compat_int_from_byte_vals(bytvals, endianess): + assert endianess == 'big' + res = 0 + for bv in bytvals: + assert isinstance(bv, _compat_int_types) + res = (res << 8) + bv + return res + + +def _compat_to_bytes(intval, length, endianess): + assert isinstance(intval, _compat_int_types) + assert endianess == 'big' + if length == 4: + if intval < 0 or intval >= 2 ** 32: + raise struct.error("integer out of range for 'I' format code") + return struct.pack(b'!I', intval) + elif length == 16: + if intval < 0 or intval >= 2 ** 128: + raise struct.error("integer out of range for 'QQ' format code") + return struct.pack(b'!QQ', intval >> 64, intval & 0xffffffffffffffff) + else: + raise NotImplementedError() + + +if hasattr(int, 'bit_length'): + # Not int.bit_length , since that won't work in 2.7 where long exists + def _compat_bit_length(i): + return i.bit_length() +else: + def _compat_bit_length(i): + for res in itertools.count(): + if i >> res == 0: + return res + + +def _compat_range(start, end, step=1): + assert step > 0 + i = start + while i < end: + yield i + i += step + + +class _TotalOrderingMixin(object): + __slots__ = () + + # Helper that derives the other comparison operations from + # __lt__ and __eq__ + # We avoid functools.total_ordering because it doesn't handle + # NotImplemented correctly yet (http://bugs.python.org/issue10042) + def __eq__(self, other): + raise NotImplementedError + + def __ne__(self, other): + equal = self.__eq__(other) + if equal is NotImplemented: + return NotImplemented + return not equal + + def __lt__(self, other): + raise NotImplementedError + + def __le__(self, other): + less = self.__lt__(other) + if less is NotImplemented or not less: + return self.__eq__(other) + return less + + def __gt__(self, other): + less = self.__lt__(other) + if less is NotImplemented: + return NotImplemented + equal = self.__eq__(other) + if equal is NotImplemented: + return NotImplemented + return not (less or equal) + + def __ge__(self, other): + less = self.__lt__(other) + if less is NotImplemented: + return NotImplemented + return not less + + +IPV4LENGTH = 32 +IPV6LENGTH = 128 + + +class AddressValueError(ValueError): + """A Value Error related to the address.""" + + +class NetmaskValueError(ValueError): + """A Value Error related to the netmask.""" + + +def ip_address(address): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP address. Either IPv4 or + IPv6 addresses may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Address or IPv6Address object. + + Raises: + ValueError: if the *address* passed isn't either a v4 or a v6 + address + + """ + try: + return IPv4Address(address) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Address(address) + except (AddressValueError, NetmaskValueError): + pass + + if isinstance(address, bytes): + raise AddressValueError( + '%r does not appear to be an IPv4 or IPv6 address. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?' % address) + + raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % + address) + + +def ip_network(address, strict=True): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP network. Either IPv4 or + IPv6 networks may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Network or IPv6Network object. + + Raises: + ValueError: if the string passed isn't either a v4 or a v6 + address. Or if the network has host bits set. + + """ + try: + return IPv4Network(address, strict) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Network(address, strict) + except (AddressValueError, NetmaskValueError): + pass + + if isinstance(address, bytes): + raise AddressValueError( + '%r does not appear to be an IPv4 or IPv6 network. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?' % address) + + raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % + address) + + +def ip_interface(address): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP address. Either IPv4 or + IPv6 addresses may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Interface or IPv6Interface object. + + Raises: + ValueError: if the string passed isn't either a v4 or a v6 + address. + + Notes: + The IPv?Interface classes describe an Address on a particular + Network, so they're basically a combination of both the Address + and Network classes. + + """ + try: + return IPv4Interface(address) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Interface(address) + except (AddressValueError, NetmaskValueError): + pass + + raise ValueError('%r does not appear to be an IPv4 or IPv6 interface' % + address) + + +def v4_int_to_packed(address): + """Represent an address as 4 packed bytes in network (big-endian) order. + + Args: + address: An integer representation of an IPv4 IP address. + + Returns: + The integer address packed as 4 bytes in network (big-endian) order. + + Raises: + ValueError: If the integer is negative or too large to be an + IPv4 IP address. + + """ + try: + return _compat_to_bytes(address, 4, 'big') + except (struct.error, OverflowError): + raise ValueError("Address negative or too large for IPv4") + + +def v6_int_to_packed(address): + """Represent an address as 16 packed bytes in network (big-endian) order. + + Args: + address: An integer representation of an IPv6 IP address. + + Returns: + The integer address packed as 16 bytes in network (big-endian) order. + + """ + try: + return _compat_to_bytes(address, 16, 'big') + except (struct.error, OverflowError): + raise ValueError("Address negative or too large for IPv6") + + +def _split_optional_netmask(address): + """Helper to split the netmask and raise AddressValueError if needed""" + addr = _compat_str(address).split('/') + if len(addr) > 2: + raise AddressValueError("Only one '/' permitted in %r" % address) + return addr + + +def _find_address_range(addresses): + """Find a sequence of sorted deduplicated IPv#Address. + + Args: + addresses: a list of IPv#Address objects. + + Yields: + A tuple containing the first and last IP addresses in the sequence. + + """ + it = iter(addresses) + first = last = next(it) + for ip in it: + if ip._ip != last._ip + 1: + yield first, last + first = ip + last = ip + yield first, last + + +def _count_righthand_zero_bits(number, bits): + """Count the number of zero bits on the right hand side. + + Args: + number: an integer. + bits: maximum number of bits to count. + + Returns: + The number of zero bits on the right hand side of the number. + + """ + if number == 0: + return bits + return min(bits, _compat_bit_length(~number & (number - 1))) + + +def summarize_address_range(first, last): + """Summarize a network range given the first and last IP addresses. + + Example: + >>> list(summarize_address_range(IPv4Address('192.0.2.0'), + ... IPv4Address('192.0.2.130'))) + ... #doctest: +NORMALIZE_WHITESPACE + [IPv4Network('192.0.2.0/25'), IPv4Network('192.0.2.128/31'), + IPv4Network('192.0.2.130/32')] + + Args: + first: the first IPv4Address or IPv6Address in the range. + last: the last IPv4Address or IPv6Address in the range. + + Returns: + An iterator of the summarized IPv(4|6) network objects. + + Raise: + TypeError: + If the first and last objects are not IP addresses. + If the first and last objects are not the same version. + ValueError: + If the last object is not greater than the first. + If the version of the first address is not 4 or 6. + + """ + if (not (isinstance(first, _BaseAddress) and + isinstance(last, _BaseAddress))): + raise TypeError('first and last must be IP addresses, not networks') + if first.version != last.version: + raise TypeError("%s and %s are not of the same version" % ( + first, last)) + if first > last: + raise ValueError('last IP address must be greater than first') + + if first.version == 4: + ip = IPv4Network + elif first.version == 6: + ip = IPv6Network + else: + raise ValueError('unknown IP version') + + ip_bits = first._max_prefixlen + first_int = first._ip + last_int = last._ip + while first_int <= last_int: + nbits = min(_count_righthand_zero_bits(first_int, ip_bits), + _compat_bit_length(last_int - first_int + 1) - 1) + net = ip((first_int, ip_bits - nbits)) + yield net + first_int += 1 << nbits + if first_int - 1 == ip._ALL_ONES: + break + + +def _collapse_addresses_internal(addresses): + """Loops through the addresses, collapsing concurrent netblocks. + + Example: + + ip1 = IPv4Network('192.0.2.0/26') + ip2 = IPv4Network('192.0.2.64/26') + ip3 = IPv4Network('192.0.2.128/26') + ip4 = IPv4Network('192.0.2.192/26') + + _collapse_addresses_internal([ip1, ip2, ip3, ip4]) -> + [IPv4Network('192.0.2.0/24')] + + This shouldn't be called directly; it is called via + collapse_addresses([]). + + Args: + addresses: A list of IPv4Network's or IPv6Network's + + Returns: + A list of IPv4Network's or IPv6Network's depending on what we were + passed. + + """ + # First merge + to_merge = list(addresses) + subnets = {} + while to_merge: + net = to_merge.pop() + supernet = net.supernet() + existing = subnets.get(supernet) + if existing is None: + subnets[supernet] = net + elif existing != net: + # Merge consecutive subnets + del subnets[supernet] + to_merge.append(supernet) + # Then iterate over resulting networks, skipping subsumed subnets + last = None + for net in sorted(subnets.values()): + if last is not None: + # Since they are sorted, + # last.network_address <= net.network_address is a given. + if last.broadcast_address >= net.broadcast_address: + continue + yield net + last = net + + +def collapse_addresses(addresses): + """Collapse a list of IP objects. + + Example: + collapse_addresses([IPv4Network('192.0.2.0/25'), + IPv4Network('192.0.2.128/25')]) -> + [IPv4Network('192.0.2.0/24')] + + Args: + addresses: An iterator of IPv4Network or IPv6Network objects. + + Returns: + An iterator of the collapsed IPv(4|6)Network objects. + + Raises: + TypeError: If passed a list of mixed version objects. + + """ + addrs = [] + ips = [] + nets = [] + + # split IP addresses and networks + for ip in addresses: + if isinstance(ip, _BaseAddress): + if ips and ips[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, ips[-1])) + ips.append(ip) + elif ip._prefixlen == ip._max_prefixlen: + if ips and ips[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, ips[-1])) + try: + ips.append(ip.ip) + except AttributeError: + ips.append(ip.network_address) + else: + if nets and nets[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, nets[-1])) + nets.append(ip) + + # sort and dedup + ips = sorted(set(ips)) + + # find consecutive address ranges in the sorted sequence and summarize them + if ips: + for first, last in _find_address_range(ips): + addrs.extend(summarize_address_range(first, last)) + + return _collapse_addresses_internal(addrs + nets) + + +def get_mixed_type_key(obj): + """Return a key suitable for sorting between networks and addresses. + + Address and Network objects are not sortable by default; they're + fundamentally different so the expression + + IPv4Address('192.0.2.0') <= IPv4Network('192.0.2.0/24') + + doesn't make any sense. There are some times however, where you may wish + to have ipaddress sort these for you anyway. If you need to do this, you + can use this function as the key= argument to sorted(). + + Args: + obj: either a Network or Address object. + Returns: + appropriate key. + + """ + if isinstance(obj, _BaseNetwork): + return obj._get_networks_key() + elif isinstance(obj, _BaseAddress): + return obj._get_address_key() + return NotImplemented + + +class _IPAddressBase(_TotalOrderingMixin): + + """The mother class.""" + + __slots__ = () + + @property + def exploded(self): + """Return the longhand version of the IP address as a string.""" + return self._explode_shorthand_ip_string() + + @property + def compressed(self): + """Return the shorthand version of the IP address as a string.""" + return _compat_str(self) + + @property + def reverse_pointer(self): + """The name of the reverse DNS pointer for the IP address, e.g.: + >>> ipaddress.ip_address("127.0.0.1").reverse_pointer + '1.0.0.127.in-addr.arpa' + >>> ipaddress.ip_address("2001:db8::1").reverse_pointer + '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa' + + """ + return self._reverse_pointer() + + @property + def version(self): + msg = '%200s has no version specified' % (type(self),) + raise NotImplementedError(msg) + + def _check_int_address(self, address): + if address < 0: + msg = "%d (< 0) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, self._version)) + if address > self._ALL_ONES: + msg = "%d (>= 2**%d) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, self._max_prefixlen, + self._version)) + + def _check_packed_address(self, address, expected_len): + address_len = len(address) + if address_len != expected_len: + msg = ( + '%r (len %d != %d) is not permitted as an IPv%d address. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?') + raise AddressValueError(msg % (address, address_len, + expected_len, self._version)) + + @classmethod + def _ip_int_from_prefix(cls, prefixlen): + """Turn the prefix length into a bitwise netmask + + Args: + prefixlen: An integer, the prefix length. + + Returns: + An integer. + + """ + return cls._ALL_ONES ^ (cls._ALL_ONES >> prefixlen) + + @classmethod + def _prefix_from_ip_int(cls, ip_int): + """Return prefix length from the bitwise netmask. + + Args: + ip_int: An integer, the netmask in expanded bitwise format + + Returns: + An integer, the prefix length. + + Raises: + ValueError: If the input intermingles zeroes & ones + """ + trailing_zeroes = _count_righthand_zero_bits(ip_int, + cls._max_prefixlen) + prefixlen = cls._max_prefixlen - trailing_zeroes + leading_ones = ip_int >> trailing_zeroes + all_ones = (1 << prefixlen) - 1 + if leading_ones != all_ones: + byteslen = cls._max_prefixlen // 8 + details = _compat_to_bytes(ip_int, byteslen, 'big') + msg = 'Netmask pattern %r mixes zeroes & ones' + raise ValueError(msg % details) + return prefixlen + + @classmethod + def _report_invalid_netmask(cls, netmask_str): + msg = '%r is not a valid netmask' % netmask_str + raise NetmaskValueError(msg) + + @classmethod + def _prefix_from_prefix_string(cls, prefixlen_str): + """Return prefix length from a numeric string + + Args: + prefixlen_str: The string to be converted + + Returns: + An integer, the prefix length. + + Raises: + NetmaskValueError: If the input is not a valid netmask + """ + # int allows a leading +/- as well as surrounding whitespace, + # so we ensure that isn't the case + if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str): + cls._report_invalid_netmask(prefixlen_str) + try: + prefixlen = int(prefixlen_str) + except ValueError: + cls._report_invalid_netmask(prefixlen_str) + if not (0 <= prefixlen <= cls._max_prefixlen): + cls._report_invalid_netmask(prefixlen_str) + return prefixlen + + @classmethod + def _prefix_from_ip_string(cls, ip_str): + """Turn a netmask/hostmask string into a prefix length + + Args: + ip_str: The netmask/hostmask to be converted + + Returns: + An integer, the prefix length. + + Raises: + NetmaskValueError: If the input is not a valid netmask/hostmask + """ + # Parse the netmask/hostmask like an IP address. + try: + ip_int = cls._ip_int_from_string(ip_str) + except AddressValueError: + cls._report_invalid_netmask(ip_str) + + # Try matching a netmask (this would be /1*0*/ as a bitwise regexp). + # Note that the two ambiguous cases (all-ones and all-zeroes) are + # treated as netmasks. + try: + return cls._prefix_from_ip_int(ip_int) + except ValueError: + pass + + # Invert the bits, and try matching a /0+1+/ hostmask instead. + ip_int ^= cls._ALL_ONES + try: + return cls._prefix_from_ip_int(ip_int) + except ValueError: + cls._report_invalid_netmask(ip_str) + + def __reduce__(self): + return self.__class__, (_compat_str(self),) + + +class _BaseAddress(_IPAddressBase): + + """A generic IP object. + + This IP class contains the version independent methods which are + used by single IP addresses. + """ + + __slots__ = () + + def __int__(self): + return self._ip + + def __eq__(self, other): + try: + return (self._ip == other._ip and + self._version == other._version) + except AttributeError: + return NotImplemented + + def __lt__(self, other): + if not isinstance(other, _IPAddressBase): + return NotImplemented + if not isinstance(other, _BaseAddress): + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + self, other)) + if self._ip != other._ip: + return self._ip < other._ip + return False + + # Shorthand for Integer addition and subtraction. This is not + # meant to ever support addition/subtraction of addresses. + def __add__(self, other): + if not isinstance(other, _compat_int_types): + return NotImplemented + return self.__class__(int(self) + other) + + def __sub__(self, other): + if not isinstance(other, _compat_int_types): + return NotImplemented + return self.__class__(int(self) - other) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, _compat_str(self)) + + def __str__(self): + return _compat_str(self._string_from_ip_int(self._ip)) + + def __hash__(self): + return hash(hex(int(self._ip))) + + def _get_address_key(self): + return (self._version, self) + + def __reduce__(self): + return self.__class__, (self._ip,) + + +class _BaseNetwork(_IPAddressBase): + + """A generic IP network object. + + This IP class contains the version independent methods which are + used by networks. + + """ + def __init__(self, address): + self._cache = {} + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, _compat_str(self)) + + def __str__(self): + return '%s/%d' % (self.network_address, self.prefixlen) + + def hosts(self): + """Generate Iterator over usable hosts in a network. + + This is like __iter__ except it doesn't return the network + or broadcast addresses. + + """ + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network + 1, broadcast): + yield self._address_class(x) + + def __iter__(self): + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network, broadcast + 1): + yield self._address_class(x) + + def __getitem__(self, n): + network = int(self.network_address) + broadcast = int(self.broadcast_address) + if n >= 0: + if network + n > broadcast: + raise IndexError('address out of range') + return self._address_class(network + n) + else: + n += 1 + if broadcast + n < network: + raise IndexError('address out of range') + return self._address_class(broadcast + n) + + def __lt__(self, other): + if not isinstance(other, _IPAddressBase): + return NotImplemented + if not isinstance(other, _BaseNetwork): + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + self, other)) + if self.network_address != other.network_address: + return self.network_address < other.network_address + if self.netmask != other.netmask: + return self.netmask < other.netmask + return False + + def __eq__(self, other): + try: + return (self._version == other._version and + self.network_address == other.network_address and + int(self.netmask) == int(other.netmask)) + except AttributeError: + return NotImplemented + + def __hash__(self): + return hash(int(self.network_address) ^ int(self.netmask)) + + def __contains__(self, other): + # always false if one is v4 and the other is v6. + if self._version != other._version: + return False + # dealing with another network. + if isinstance(other, _BaseNetwork): + return False + # dealing with another address + else: + # address + return (int(self.network_address) <= int(other._ip) <= + int(self.broadcast_address)) + + def overlaps(self, other): + """Tell if self is partly contained in other.""" + return self.network_address in other or ( + self.broadcast_address in other or ( + other.network_address in self or ( + other.broadcast_address in self))) + + @property + def broadcast_address(self): + x = self._cache.get('broadcast_address') + if x is None: + x = self._address_class(int(self.network_address) | + int(self.hostmask)) + self._cache['broadcast_address'] = x + return x + + @property + def hostmask(self): + x = self._cache.get('hostmask') + if x is None: + x = self._address_class(int(self.netmask) ^ self._ALL_ONES) + self._cache['hostmask'] = x + return x + + @property + def with_prefixlen(self): + return '%s/%d' % (self.network_address, self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self.network_address, self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self.network_address, self.hostmask) + + @property + def num_addresses(self): + """Number of hosts in the current subnet.""" + return int(self.broadcast_address) - int(self.network_address) + 1 + + @property + def _address_class(self): + # Returning bare address objects (rather than interfaces) allows for + # more consistent behaviour across the network address, broadcast + # address and individual host addresses. + msg = '%200s has no associated address class' % (type(self),) + raise NotImplementedError(msg) + + @property + def prefixlen(self): + return self._prefixlen + + def address_exclude(self, other): + """Remove an address from a larger block. + + For example: + + addr1 = ip_network('192.0.2.0/28') + addr2 = ip_network('192.0.2.1/32') + list(addr1.address_exclude(addr2)) = + [IPv4Network('192.0.2.0/32'), IPv4Network('192.0.2.2/31'), + IPv4Network('192.0.2.4/30'), IPv4Network('192.0.2.8/29')] + + or IPv6: + + addr1 = ip_network('2001:db8::1/32') + addr2 = ip_network('2001:db8::1/128') + list(addr1.address_exclude(addr2)) = + [ip_network('2001:db8::1/128'), + ip_network('2001:db8::2/127'), + ip_network('2001:db8::4/126'), + ip_network('2001:db8::8/125'), + ... + ip_network('2001:db8:8000::/33')] + + Args: + other: An IPv4Network or IPv6Network object of the same type. + + Returns: + An iterator of the IPv(4|6)Network objects which is self + minus other. + + Raises: + TypeError: If self and other are of differing address + versions, or if other is not a network object. + ValueError: If other is not completely contained by self. + + """ + if not self._version == other._version: + raise TypeError("%s and %s are not of the same version" % ( + self, other)) + + if not isinstance(other, _BaseNetwork): + raise TypeError("%s is not a network object" % other) + + if not other.subnet_of(self): + raise ValueError('%s not contained in %s' % (other, self)) + if other == self: + return + + # Make sure we're comparing the network of other. + other = other.__class__('%s/%s' % (other.network_address, + other.prefixlen)) + + s1, s2 = self.subnets() + while s1 != other and s2 != other: + if other.subnet_of(s1): + yield s2 + s1, s2 = s1.subnets() + elif other.subnet_of(s2): + yield s1 + s1, s2 = s2.subnets() + else: + # If we got here, there's a bug somewhere. + raise AssertionError('Error performing exclusion: ' + 's1: %s s2: %s other: %s' % + (s1, s2, other)) + if s1 == other: + yield s2 + elif s2 == other: + yield s1 + else: + # If we got here, there's a bug somewhere. + raise AssertionError('Error performing exclusion: ' + 's1: %s s2: %s other: %s' % + (s1, s2, other)) + + def compare_networks(self, other): + """Compare two IP objects. + + This is only concerned about the comparison of the integer + representation of the network addresses. This means that the + host bits aren't considered at all in this method. If you want + to compare host bits, you can easily enough do a + 'HostA._ip < HostB._ip' + + Args: + other: An IP object. + + Returns: + If the IP versions of self and other are the same, returns: + + -1 if self < other: + eg: IPv4Network('192.0.2.0/25') < IPv4Network('192.0.2.128/25') + IPv6Network('2001:db8::1000/124') < + IPv6Network('2001:db8::2000/124') + 0 if self == other + eg: IPv4Network('192.0.2.0/24') == IPv4Network('192.0.2.0/24') + IPv6Network('2001:db8::1000/124') == + IPv6Network('2001:db8::1000/124') + 1 if self > other + eg: IPv4Network('192.0.2.128/25') > IPv4Network('192.0.2.0/25') + IPv6Network('2001:db8::2000/124') > + IPv6Network('2001:db8::1000/124') + + Raises: + TypeError if the IP versions are different. + + """ + # does this need to raise a ValueError? + if self._version != other._version: + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + # self._version == other._version below here: + if self.network_address < other.network_address: + return -1 + if self.network_address > other.network_address: + return 1 + # self.network_address == other.network_address below here: + if self.netmask < other.netmask: + return -1 + if self.netmask > other.netmask: + return 1 + return 0 + + def _get_networks_key(self): + """Network-only key function. + + Returns an object that identifies this address' network and + netmask. This function is a suitable "key" argument for sorted() + and list.sort(). + + """ + return (self._version, self.network_address, self.netmask) + + def subnets(self, prefixlen_diff=1, new_prefix=None): + """The subnets which join to make the current subnet. + + In the case that self contains only one IP + (self._prefixlen == 32 for IPv4 or self._prefixlen == 128 + for IPv6), yield an iterator with just ourself. + + Args: + prefixlen_diff: An integer, the amount the prefix length + should be increased by. This should not be set if + new_prefix is also set. + new_prefix: The desired new prefix length. This must be a + larger number (smaller prefix) than the existing prefix. + This should not be set if prefixlen_diff is also set. + + Returns: + An iterator of IPv(4|6) objects. + + Raises: + ValueError: The prefixlen_diff is too small or too large. + OR + prefixlen_diff and new_prefix are both set or new_prefix + is a smaller number than the current prefix (smaller + number means a larger network) + + """ + if self._prefixlen == self._max_prefixlen: + yield self + return + + if new_prefix is not None: + if new_prefix < self._prefixlen: + raise ValueError('new prefix must be longer') + if prefixlen_diff != 1: + raise ValueError('cannot set prefixlen_diff and new_prefix') + prefixlen_diff = new_prefix - self._prefixlen + + if prefixlen_diff < 0: + raise ValueError('prefix length diff must be > 0') + new_prefixlen = self._prefixlen + prefixlen_diff + + if new_prefixlen > self._max_prefixlen: + raise ValueError( + 'prefix length diff %d is invalid for netblock %s' % ( + new_prefixlen, self)) + + start = int(self.network_address) + end = int(self.broadcast_address) + 1 + step = (int(self.hostmask) + 1) >> prefixlen_diff + for new_addr in _compat_range(start, end, step): + current = self.__class__((new_addr, new_prefixlen)) + yield current + + def supernet(self, prefixlen_diff=1, new_prefix=None): + """The supernet containing the current network. + + Args: + prefixlen_diff: An integer, the amount the prefix length of + the network should be decreased by. For example, given a + /24 network and a prefixlen_diff of 3, a supernet with a + /21 netmask is returned. + + Returns: + An IPv4 network object. + + Raises: + ValueError: If self.prefixlen - prefixlen_diff < 0. I.e., you have + a negative prefix length. + OR + If prefixlen_diff and new_prefix are both set or new_prefix is a + larger number than the current prefix (larger number means a + smaller network) + + """ + if self._prefixlen == 0: + return self + + if new_prefix is not None: + if new_prefix > self._prefixlen: + raise ValueError('new prefix must be shorter') + if prefixlen_diff != 1: + raise ValueError('cannot set prefixlen_diff and new_prefix') + prefixlen_diff = self._prefixlen - new_prefix + + new_prefixlen = self.prefixlen - prefixlen_diff + if new_prefixlen < 0: + raise ValueError( + 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % + (self.prefixlen, prefixlen_diff)) + return self.__class__(( + int(self.network_address) & (int(self.netmask) << prefixlen_diff), + new_prefixlen)) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is a multicast address. + See RFC 2373 2.7 for details. + + """ + return (self.network_address.is_multicast and + self.broadcast_address.is_multicast) + + @staticmethod + def _is_subnet_of(a, b): + try: + # Always false if one is v4 and the other is v6. + if a._version != b._version: + raise TypeError( + "%s and %s are not of the same version" % (a, b)) + return (b.network_address <= a.network_address and + b.broadcast_address >= a.broadcast_address) + except AttributeError: + raise TypeError("Unable to test subnet containment " + "between %s and %s" % (a, b)) + + def subnet_of(self, other): + """Return True if this network is a subnet of other.""" + return self._is_subnet_of(self, other) + + def supernet_of(self, other): + """Return True if this network is a supernet of other.""" + return self._is_subnet_of(other, self) + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within one of the + reserved IPv6 Network ranges. + + """ + return (self.network_address.is_reserved and + self.broadcast_address.is_reserved) + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is reserved per RFC 4291. + + """ + return (self.network_address.is_link_local and + self.broadcast_address.is_link_local) + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv4-special-registry or iana-ipv6-special-registry. + + """ + return (self.network_address.is_private and + self.broadcast_address.is_private) + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, True if the address is not reserved per + iana-ipv4-special-registry or iana-ipv6-special-registry. + + """ + return not self.is_private + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 2373 2.5.2. + + """ + return (self.network_address.is_unspecified and + self.broadcast_address.is_unspecified) + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback address as defined in + RFC 2373 2.5.3. + + """ + return (self.network_address.is_loopback and + self.broadcast_address.is_loopback) + + +class _BaseV4(object): + + """Base IPv4 object. + + The following methods are used by IPv4 objects in both single IP + addresses and networks. + + """ + + __slots__ = () + _version = 4 + # Equivalent to 255.255.255.255 or 32 bits of 1's. + _ALL_ONES = (2 ** IPV4LENGTH) - 1 + _DECIMAL_DIGITS = frozenset('0123456789') + + # the valid octets for host and netmasks. only useful for IPv4. + _valid_mask_octets = frozenset([255, 254, 252, 248, 240, 224, 192, 128, 0]) + + _max_prefixlen = IPV4LENGTH + # There are only a handful of valid v4 netmasks, so we cache them all + # when constructed (see _make_netmask()). + _netmask_cache = {} + + def _explode_shorthand_ip_string(self): + return _compat_str(self) + + @classmethod + def _make_netmask(cls, arg): + """Make a (netmask, prefix_len) tuple from the given argument. + + Argument can be: + - an integer (the prefix length) + - a string representing the prefix length (e.g. "24") + - a string representing the prefix netmask (e.g. "255.255.255.0") + """ + if arg not in cls._netmask_cache: + if isinstance(arg, _compat_int_types): + prefixlen = arg + else: + try: + # Check for a netmask in prefix length form + prefixlen = cls._prefix_from_prefix_string(arg) + except NetmaskValueError: + # Check for a netmask or hostmask in dotted-quad form. + # This may raise NetmaskValueError. + prefixlen = cls._prefix_from_ip_string(arg) + netmask = IPv4Address(cls._ip_int_from_prefix(prefixlen)) + cls._netmask_cache[arg] = netmask, prefixlen + return cls._netmask_cache[arg] + + @classmethod + def _ip_int_from_string(cls, ip_str): + """Turn the given IP string into an integer for comparison. + + Args: + ip_str: A string, the IP ip_str. + + Returns: + The IP ip_str as an integer. + + Raises: + AddressValueError: if ip_str isn't a valid IPv4 Address. + + """ + if not ip_str: + raise AddressValueError('Address cannot be empty') + + octets = ip_str.split('.') + if len(octets) != 4: + raise AddressValueError("Expected 4 octets in %r" % ip_str) + + try: + return _compat_int_from_byte_vals( + map(cls._parse_octet, octets), 'big') + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + + @classmethod + def _parse_octet(cls, octet_str): + """Convert a decimal octet into an integer. + + Args: + octet_str: A string, the number to parse. + + Returns: + The octet as an integer. + + Raises: + ValueError: if the octet isn't strictly a decimal from [0..255]. + + """ + if not octet_str: + raise ValueError("Empty octet not permitted") + # Whitelist the characters, since int() allows a lot of bizarre stuff. + if not cls._DECIMAL_DIGITS.issuperset(octet_str): + msg = "Only decimal digits permitted in %r" + raise ValueError(msg % octet_str) + # We do the length check second, since the invalid character error + # is likely to be more informative for the user + if len(octet_str) > 3: + msg = "At most 3 characters permitted in %r" + raise ValueError(msg % octet_str) + # Convert to integer (we know digits are legal) + octet_int = int(octet_str, 10) + # Any octets that look like they *might* be written in octal, + # and which don't look exactly the same in both octal and + # decimal are rejected as ambiguous + if octet_int > 7 and octet_str[0] == '0': + msg = "Ambiguous (octal/decimal) value in %r not permitted" + raise ValueError(msg % octet_str) + if octet_int > 255: + raise ValueError("Octet %d (> 255) not permitted" % octet_int) + return octet_int + + @classmethod + def _string_from_ip_int(cls, ip_int): + """Turns a 32-bit integer into dotted decimal notation. + + Args: + ip_int: An integer, the IP address. + + Returns: + The IP address as a string in dotted decimal notation. + + """ + return '.'.join(_compat_str(struct.unpack(b'!B', b)[0] + if isinstance(b, bytes) + else b) + for b in _compat_to_bytes(ip_int, 4, 'big')) + + def _is_hostmask(self, ip_str): + """Test if the IP string is a hostmask (rather than a netmask). + + Args: + ip_str: A string, the potential hostmask. + + Returns: + A boolean, True if the IP string is a hostmask. + + """ + bits = ip_str.split('.') + try: + parts = [x for x in map(int, bits) if x in self._valid_mask_octets] + except ValueError: + return False + if len(parts) != len(bits): + return False + if parts[0] < parts[-1]: + return True + return False + + def _reverse_pointer(self): + """Return the reverse DNS pointer name for the IPv4 address. + + This implements the method described in RFC1035 3.5. + + """ + reverse_octets = _compat_str(self).split('.')[::-1] + return '.'.join(reverse_octets) + '.in-addr.arpa' + + @property + def max_prefixlen(self): + return self._max_prefixlen + + @property + def version(self): + return self._version + + +class IPv4Address(_BaseV4, _BaseAddress): + + """Represent and manipulate single IPv4 Addresses.""" + + __slots__ = ('_ip', '__weakref__') + + def __init__(self, address): + + """ + Args: + address: A string or integer representing the IP + + Additionally, an integer can be passed, so + IPv4Address('192.0.2.1') == IPv4Address(3221225985). + or, more generally + IPv4Address(int(IPv4Address('192.0.2.1'))) == + IPv4Address('192.0.2.1') + + Raises: + AddressValueError: If ipaddress isn't a valid IPv4 address. + + """ + # Efficient constructor from integer. + if isinstance(address, _compat_int_types): + self._check_int_address(address) + self._ip = address + return + + # Constructing from a packed address + if isinstance(address, bytes): + self._check_packed_address(address, 4) + bvs = _compat_bytes_to_byte_vals(address) + self._ip = _compat_int_from_byte_vals(bvs, 'big') + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP string. + addr_str = _compat_str(address) + if '/' in addr_str: + raise AddressValueError("Unexpected '/' in %r" % address) + self._ip = self._ip_int_from_string(addr_str) + + @property + def packed(self): + """The binary representation of this address.""" + return v4_int_to_packed(self._ip) + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within the + reserved IPv4 Network range. + + """ + return self in self._constants._reserved_network + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv4-special-registry. + + """ + return any(self in net for net in self._constants._private_networks) + + @property + def is_global(self): + return ( + self not in self._constants._public_network and + not self.is_private) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is multicast. + See RFC 3171 for details. + + """ + return self in self._constants._multicast_network + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 5735 3. + + """ + return self == self._constants._unspecified_address + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback per RFC 3330. + + """ + return self in self._constants._loopback_network + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is link-local per RFC 3927. + + """ + return self in self._constants._linklocal_network + + +class IPv4Interface(IPv4Address): + + def __init__(self, address): + if isinstance(address, (bytes, _compat_int_types)): + IPv4Address.__init__(self, address) + self.network = IPv4Network(self._ip) + self._prefixlen = self._max_prefixlen + return + + if isinstance(address, tuple): + IPv4Address.__init__(self, address[0]) + if len(address) > 1: + self._prefixlen = int(address[1]) + else: + self._prefixlen = self._max_prefixlen + + self.network = IPv4Network(address, strict=False) + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + return + + addr = _split_optional_netmask(address) + IPv4Address.__init__(self, addr[0]) + + self.network = IPv4Network(address, strict=False) + self._prefixlen = self.network._prefixlen + + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + + def __str__(self): + return '%s/%d' % (self._string_from_ip_int(self._ip), + self.network.prefixlen) + + def __eq__(self, other): + address_equal = IPv4Address.__eq__(self, other) + if not address_equal or address_equal is NotImplemented: + return address_equal + try: + return self.network == other.network + except AttributeError: + # An interface with an associated network is NOT the + # same as an unassociated address. That's why the hash + # takes the extra info into account. + return False + + def __lt__(self, other): + address_less = IPv4Address.__lt__(self, other) + if address_less is NotImplemented: + return NotImplemented + try: + return (self.network < other.network or + self.network == other.network and address_less) + except AttributeError: + # We *do* allow addresses and interfaces to be sorted. The + # unassociated address is considered less than all interfaces. + return False + + def __hash__(self): + return self._ip ^ self._prefixlen ^ int(self.network.network_address) + + __reduce__ = _IPAddressBase.__reduce__ + + @property + def ip(self): + return IPv4Address(self._ip) + + @property + def with_prefixlen(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.hostmask) + + +class IPv4Network(_BaseV4, _BaseNetwork): + + """This class represents and manipulates 32-bit IPv4 network + addresses.. + + Attributes: [examples for IPv4Network('192.0.2.0/27')] + .network_address: IPv4Address('192.0.2.0') + .hostmask: IPv4Address('0.0.0.31') + .broadcast_address: IPv4Address('192.0.2.32') + .netmask: IPv4Address('255.255.255.224') + .prefixlen: 27 + + """ + # Class to use when creating address objects + _address_class = IPv4Address + + def __init__(self, address, strict=True): + + """Instantiate a new IPv4 network object. + + Args: + address: A string or integer representing the IP [& network]. + '192.0.2.0/24' + '192.0.2.0/255.255.255.0' + '192.0.0.2/0.0.0.255' + are all functionally the same in IPv4. Similarly, + '192.0.2.1' + '192.0.2.1/255.255.255.255' + '192.0.2.1/32' + are also functionally equivalent. That is to say, failing to + provide a subnetmask will create an object with a mask of /32. + + If the mask (portion after the / in the argument) is given in + dotted quad form, it is treated as a netmask if it starts with a + non-zero field (e.g. /255.0.0.0 == /8) and as a hostmask if it + starts with a zero field (e.g. 0.255.255.255 == /8), with the + single exception of an all-zero mask which is treated as a + netmask == /0. If no mask is given, a default of /32 is used. + + Additionally, an integer can be passed, so + IPv4Network('192.0.2.1') == IPv4Network(3221225985) + or, more generally + IPv4Interface(int(IPv4Interface('192.0.2.1'))) == + IPv4Interface('192.0.2.1') + + Raises: + AddressValueError: If ipaddress isn't a valid IPv4 address. + NetmaskValueError: If the netmask isn't valid for + an IPv4 address. + ValueError: If strict is True and a network address is not + supplied. + + """ + _BaseNetwork.__init__(self, address) + + # Constructing from a packed address or integer + if isinstance(address, (_compat_int_types, bytes)): + self.network_address = IPv4Address(address) + self.netmask, self._prefixlen = self._make_netmask( + self._max_prefixlen) + # fixme: address/network test here. + return + + if isinstance(address, tuple): + if len(address) > 1: + arg = address[1] + else: + # We weren't given an address[1] + arg = self._max_prefixlen + self.network_address = IPv4Address(address[0]) + self.netmask, self._prefixlen = self._make_netmask(arg) + packed = int(self.network_address) + if packed & int(self.netmask) != packed: + if strict: + raise ValueError('%s has host bits set' % self) + else: + self.network_address = IPv4Address(packed & + int(self.netmask)) + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP prefix string. + addr = _split_optional_netmask(address) + self.network_address = IPv4Address(self._ip_int_from_string(addr[0])) + + if len(addr) == 2: + arg = addr[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + + if strict: + if (IPv4Address(int(self.network_address) & int(self.netmask)) != + self.network_address): + raise ValueError('%s has host bits set' % self) + self.network_address = IPv4Address(int(self.network_address) & + int(self.netmask)) + + if self._prefixlen == (self._max_prefixlen - 1): + self.hosts = self.__iter__ + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, True if the address is not reserved per + iana-ipv4-special-registry. + + """ + return (not (self.network_address in IPv4Network('100.64.0.0/10') and + self.broadcast_address in IPv4Network('100.64.0.0/10')) and + not self.is_private) + + +class _IPv4Constants(object): + + _linklocal_network = IPv4Network('169.254.0.0/16') + + _loopback_network = IPv4Network('127.0.0.0/8') + + _multicast_network = IPv4Network('224.0.0.0/4') + + _public_network = IPv4Network('100.64.0.0/10') + + _private_networks = [ + IPv4Network('0.0.0.0/8'), + IPv4Network('10.0.0.0/8'), + IPv4Network('127.0.0.0/8'), + IPv4Network('169.254.0.0/16'), + IPv4Network('172.16.0.0/12'), + IPv4Network('192.0.0.0/29'), + IPv4Network('192.0.0.170/31'), + IPv4Network('192.0.2.0/24'), + IPv4Network('192.168.0.0/16'), + IPv4Network('198.18.0.0/15'), + IPv4Network('198.51.100.0/24'), + IPv4Network('203.0.113.0/24'), + IPv4Network('240.0.0.0/4'), + IPv4Network('255.255.255.255/32'), + ] + + _reserved_network = IPv4Network('240.0.0.0/4') + + _unspecified_address = IPv4Address('0.0.0.0') + + +IPv4Address._constants = _IPv4Constants + + +class _BaseV6(object): + + """Base IPv6 object. + + The following methods are used by IPv6 objects in both single IP + addresses and networks. + + """ + + __slots__ = () + _version = 6 + _ALL_ONES = (2 ** IPV6LENGTH) - 1 + _HEXTET_COUNT = 8 + _HEX_DIGITS = frozenset('0123456789ABCDEFabcdef') + _max_prefixlen = IPV6LENGTH + + # There are only a bunch of valid v6 netmasks, so we cache them all + # when constructed (see _make_netmask()). + _netmask_cache = {} + + @classmethod + def _make_netmask(cls, arg): + """Make a (netmask, prefix_len) tuple from the given argument. + + Argument can be: + - an integer (the prefix length) + - a string representing the prefix length (e.g. "24") + - a string representing the prefix netmask (e.g. "255.255.255.0") + """ + if arg not in cls._netmask_cache: + if isinstance(arg, _compat_int_types): + prefixlen = arg + else: + prefixlen = cls._prefix_from_prefix_string(arg) + netmask = IPv6Address(cls._ip_int_from_prefix(prefixlen)) + cls._netmask_cache[arg] = netmask, prefixlen + return cls._netmask_cache[arg] + + @classmethod + def _ip_int_from_string(cls, ip_str): + """Turn an IPv6 ip_str into an integer. + + Args: + ip_str: A string, the IPv6 ip_str. + + Returns: + An int, the IPv6 address + + Raises: + AddressValueError: if ip_str isn't a valid IPv6 Address. + + """ + if not ip_str: + raise AddressValueError('Address cannot be empty') + + parts = ip_str.split(':') + + # An IPv6 address needs at least 2 colons (3 parts). + _min_parts = 3 + if len(parts) < _min_parts: + msg = "At least %d parts expected in %r" % (_min_parts, ip_str) + raise AddressValueError(msg) + + # If the address has an IPv4-style suffix, convert it to hexadecimal. + if '.' in parts[-1]: + try: + ipv4_int = IPv4Address(parts.pop())._ip + except AddressValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + parts.append('%x' % ((ipv4_int >> 16) & 0xFFFF)) + parts.append('%x' % (ipv4_int & 0xFFFF)) + + # An IPv6 address can't have more than 8 colons (9 parts). + # The extra colon comes from using the "::" notation for a single + # leading or trailing zero part. + _max_parts = cls._HEXTET_COUNT + 1 + if len(parts) > _max_parts: + msg = "At most %d colons permitted in %r" % ( + _max_parts - 1, ip_str) + raise AddressValueError(msg) + + # Disregarding the endpoints, find '::' with nothing in between. + # This indicates that a run of zeroes has been skipped. + skip_index = None + for i in _compat_range(1, len(parts) - 1): + if not parts[i]: + if skip_index is not None: + # Can't have more than one '::' + msg = "At most one '::' permitted in %r" % ip_str + raise AddressValueError(msg) + skip_index = i + + # parts_hi is the number of parts to copy from above/before the '::' + # parts_lo is the number of parts to copy from below/after the '::' + if skip_index is not None: + # If we found a '::', then check if it also covers the endpoints. + parts_hi = skip_index + parts_lo = len(parts) - skip_index - 1 + if not parts[0]: + parts_hi -= 1 + if parts_hi: + msg = "Leading ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # ^: requires ^:: + if not parts[-1]: + parts_lo -= 1 + if parts_lo: + msg = "Trailing ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # :$ requires ::$ + parts_skipped = cls._HEXTET_COUNT - (parts_hi + parts_lo) + if parts_skipped < 1: + msg = "Expected at most %d other parts with '::' in %r" + raise AddressValueError(msg % (cls._HEXTET_COUNT - 1, ip_str)) + else: + # Otherwise, allocate the entire address to parts_hi. The + # endpoints could still be empty, but _parse_hextet() will check + # for that. + if len(parts) != cls._HEXTET_COUNT: + msg = "Exactly %d parts expected without '::' in %r" + raise AddressValueError(msg % (cls._HEXTET_COUNT, ip_str)) + if not parts[0]: + msg = "Leading ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # ^: requires ^:: + if not parts[-1]: + msg = "Trailing ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # :$ requires ::$ + parts_hi = len(parts) + parts_lo = 0 + parts_skipped = 0 + + try: + # Now, parse the hextets into a 128-bit integer. + ip_int = 0 + for i in range(parts_hi): + ip_int <<= 16 + ip_int |= cls._parse_hextet(parts[i]) + ip_int <<= 16 * parts_skipped + for i in range(-parts_lo, 0): + ip_int <<= 16 + ip_int |= cls._parse_hextet(parts[i]) + return ip_int + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + + @classmethod + def _parse_hextet(cls, hextet_str): + """Convert an IPv6 hextet string into an integer. + + Args: + hextet_str: A string, the number to parse. + + Returns: + The hextet as an integer. + + Raises: + ValueError: if the input isn't strictly a hex number from + [0..FFFF]. + + """ + # Whitelist the characters, since int() allows a lot of bizarre stuff. + if not cls._HEX_DIGITS.issuperset(hextet_str): + raise ValueError("Only hex digits permitted in %r" % hextet_str) + # We do the length check second, since the invalid character error + # is likely to be more informative for the user + if len(hextet_str) > 4: + msg = "At most 4 characters permitted in %r" + raise ValueError(msg % hextet_str) + # Length check means we can skip checking the integer value + return int(hextet_str, 16) + + @classmethod + def _compress_hextets(cls, hextets): + """Compresses a list of hextets. + + Compresses a list of strings, replacing the longest continuous + sequence of "0" in the list with "" and adding empty strings at + the beginning or at the end of the string such that subsequently + calling ":".join(hextets) will produce the compressed version of + the IPv6 address. + + Args: + hextets: A list of strings, the hextets to compress. + + Returns: + A list of strings. + + """ + best_doublecolon_start = -1 + best_doublecolon_len = 0 + doublecolon_start = -1 + doublecolon_len = 0 + for index, hextet in enumerate(hextets): + if hextet == '0': + doublecolon_len += 1 + if doublecolon_start == -1: + # Start of a sequence of zeros. + doublecolon_start = index + if doublecolon_len > best_doublecolon_len: + # This is the longest sequence of zeros so far. + best_doublecolon_len = doublecolon_len + best_doublecolon_start = doublecolon_start + else: + doublecolon_len = 0 + doublecolon_start = -1 + + if best_doublecolon_len > 1: + best_doublecolon_end = (best_doublecolon_start + + best_doublecolon_len) + # For zeros at the end of the address. + if best_doublecolon_end == len(hextets): + hextets += [''] + hextets[best_doublecolon_start:best_doublecolon_end] = [''] + # For zeros at the beginning of the address. + if best_doublecolon_start == 0: + hextets = [''] + hextets + + return hextets + + @classmethod + def _string_from_ip_int(cls, ip_int=None): + """Turns a 128-bit integer into hexadecimal notation. + + Args: + ip_int: An integer, the IP address. + + Returns: + A string, the hexadecimal representation of the address. + + Raises: + ValueError: The address is bigger than 128 bits of all ones. + + """ + if ip_int is None: + ip_int = int(cls._ip) + + if ip_int > cls._ALL_ONES: + raise ValueError('IPv6 address is too large') + + hex_str = '%032x' % ip_int + hextets = ['%x' % int(hex_str[x:x + 4], 16) for x in range(0, 32, 4)] + + hextets = cls._compress_hextets(hextets) + return ':'.join(hextets) + + def _explode_shorthand_ip_string(self): + """Expand a shortened IPv6 address. + + Args: + ip_str: A string, the IPv6 address. + + Returns: + A string, the expanded IPv6 address. + + """ + if isinstance(self, IPv6Network): + ip_str = _compat_str(self.network_address) + elif isinstance(self, IPv6Interface): + ip_str = _compat_str(self.ip) + else: + ip_str = _compat_str(self) + + ip_int = self._ip_int_from_string(ip_str) + hex_str = '%032x' % ip_int + parts = [hex_str[x:x + 4] for x in range(0, 32, 4)] + if isinstance(self, (_BaseNetwork, IPv6Interface)): + return '%s/%d' % (':'.join(parts), self._prefixlen) + return ':'.join(parts) + + def _reverse_pointer(self): + """Return the reverse DNS pointer name for the IPv6 address. + + This implements the method described in RFC3596 2.5. + + """ + reverse_chars = self.exploded[::-1].replace(':', '') + return '.'.join(reverse_chars) + '.ip6.arpa' + + @property + def max_prefixlen(self): + return self._max_prefixlen + + @property + def version(self): + return self._version + + +class IPv6Address(_BaseV6, _BaseAddress): + + """Represent and manipulate single IPv6 Addresses.""" + + __slots__ = ('_ip', '__weakref__') + + def __init__(self, address): + """Instantiate a new IPv6 address object. + + Args: + address: A string or integer representing the IP + + Additionally, an integer can be passed, so + IPv6Address('2001:db8::') == + IPv6Address(42540766411282592856903984951653826560) + or, more generally + IPv6Address(int(IPv6Address('2001:db8::'))) == + IPv6Address('2001:db8::') + + Raises: + AddressValueError: If address isn't a valid IPv6 address. + + """ + # Efficient constructor from integer. + if isinstance(address, _compat_int_types): + self._check_int_address(address) + self._ip = address + return + + # Constructing from a packed address + if isinstance(address, bytes): + self._check_packed_address(address, 16) + bvs = _compat_bytes_to_byte_vals(address) + self._ip = _compat_int_from_byte_vals(bvs, 'big') + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP string. + addr_str = _compat_str(address) + if '/' in addr_str: + raise AddressValueError("Unexpected '/' in %r" % address) + self._ip = self._ip_int_from_string(addr_str) + + @property + def packed(self): + """The binary representation of this address.""" + return v6_int_to_packed(self._ip) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is a multicast address. + See RFC 2373 2.7 for details. + + """ + return self in self._constants._multicast_network + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within one of the + reserved IPv6 Network ranges. + + """ + return any(self in x for x in self._constants._reserved_networks) + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is reserved per RFC 4291. + + """ + return self in self._constants._linklocal_network + + @property + def is_site_local(self): + """Test if the address is reserved for site-local. + + Note that the site-local address space has been deprecated by RFC 3879. + Use is_private to test if this address is in the space of unique local + addresses as defined by RFC 4193. + + Returns: + A boolean, True if the address is reserved per RFC 3513 2.5.6. + + """ + return self in self._constants._sitelocal_network + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv6-special-registry. + + """ + return any(self in net for net in self._constants._private_networks) + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, true if the address is not reserved per + iana-ipv6-special-registry. + + """ + return not self.is_private + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 2373 2.5.2. + + """ + return self._ip == 0 + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback address as defined in + RFC 2373 2.5.3. + + """ + return self._ip == 1 + + @property + def ipv4_mapped(self): + """Return the IPv4 mapped address. + + Returns: + If the IPv6 address is a v4 mapped address, return the + IPv4 mapped address. Return None otherwise. + + """ + if (self._ip >> 32) != 0xFFFF: + return None + return IPv4Address(self._ip & 0xFFFFFFFF) + + @property + def teredo(self): + """Tuple of embedded teredo IPs. + + Returns: + Tuple of the (server, client) IPs or None if the address + doesn't appear to be a teredo address (doesn't start with + 2001::/32) + + """ + if (self._ip >> 96) != 0x20010000: + return None + return (IPv4Address((self._ip >> 64) & 0xFFFFFFFF), + IPv4Address(~self._ip & 0xFFFFFFFF)) + + @property + def sixtofour(self): + """Return the IPv4 6to4 embedded address. + + Returns: + The IPv4 6to4-embedded address if present or None if the + address doesn't appear to contain a 6to4 embedded address. + + """ + if (self._ip >> 112) != 0x2002: + return None + return IPv4Address((self._ip >> 80) & 0xFFFFFFFF) + + +class IPv6Interface(IPv6Address): + + def __init__(self, address): + if isinstance(address, (bytes, _compat_int_types)): + IPv6Address.__init__(self, address) + self.network = IPv6Network(self._ip) + self._prefixlen = self._max_prefixlen + return + if isinstance(address, tuple): + IPv6Address.__init__(self, address[0]) + if len(address) > 1: + self._prefixlen = int(address[1]) + else: + self._prefixlen = self._max_prefixlen + self.network = IPv6Network(address, strict=False) + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + return + + addr = _split_optional_netmask(address) + IPv6Address.__init__(self, addr[0]) + self.network = IPv6Network(address, strict=False) + self.netmask = self.network.netmask + self._prefixlen = self.network._prefixlen + self.hostmask = self.network.hostmask + + def __str__(self): + return '%s/%d' % (self._string_from_ip_int(self._ip), + self.network.prefixlen) + + def __eq__(self, other): + address_equal = IPv6Address.__eq__(self, other) + if not address_equal or address_equal is NotImplemented: + return address_equal + try: + return self.network == other.network + except AttributeError: + # An interface with an associated network is NOT the + # same as an unassociated address. That's why the hash + # takes the extra info into account. + return False + + def __lt__(self, other): + address_less = IPv6Address.__lt__(self, other) + if address_less is NotImplemented: + return NotImplemented + try: + return (self.network < other.network or + self.network == other.network and address_less) + except AttributeError: + # We *do* allow addresses and interfaces to be sorted. The + # unassociated address is considered less than all interfaces. + return False + + def __hash__(self): + return self._ip ^ self._prefixlen ^ int(self.network.network_address) + + __reduce__ = _IPAddressBase.__reduce__ + + @property + def ip(self): + return IPv6Address(self._ip) + + @property + def with_prefixlen(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.hostmask) + + @property + def is_unspecified(self): + return self._ip == 0 and self.network.is_unspecified + + @property + def is_loopback(self): + return self._ip == 1 and self.network.is_loopback + + +class IPv6Network(_BaseV6, _BaseNetwork): + + """This class represents and manipulates 128-bit IPv6 networks. + + Attributes: [examples for IPv6('2001:db8::1000/124')] + .network_address: IPv6Address('2001:db8::1000') + .hostmask: IPv6Address('::f') + .broadcast_address: IPv6Address('2001:db8::100f') + .netmask: IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0') + .prefixlen: 124 + + """ + + # Class to use when creating address objects + _address_class = IPv6Address + + def __init__(self, address, strict=True): + """Instantiate a new IPv6 Network object. + + Args: + address: A string or integer representing the IPv6 network or the + IP and prefix/netmask. + '2001:db8::/128' + '2001:db8:0000:0000:0000:0000:0000:0000/128' + '2001:db8::' + are all functionally the same in IPv6. That is to say, + failing to provide a subnetmask will create an object with + a mask of /128. + + Additionally, an integer can be passed, so + IPv6Network('2001:db8::') == + IPv6Network(42540766411282592856903984951653826560) + or, more generally + IPv6Network(int(IPv6Network('2001:db8::'))) == + IPv6Network('2001:db8::') + + strict: A boolean. If true, ensure that we have been passed + A true network address, eg, 2001:db8::1000/124 and not an + IP address on a network, eg, 2001:db8::1/124. + + Raises: + AddressValueError: If address isn't a valid IPv6 address. + NetmaskValueError: If the netmask isn't valid for + an IPv6 address. + ValueError: If strict was True and a network address was not + supplied. + + """ + _BaseNetwork.__init__(self, address) + + # Efficient constructor from integer or packed address + if isinstance(address, (bytes, _compat_int_types)): + self.network_address = IPv6Address(address) + self.netmask, self._prefixlen = self._make_netmask( + self._max_prefixlen) + return + + if isinstance(address, tuple): + if len(address) > 1: + arg = address[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + self.network_address = IPv6Address(address[0]) + packed = int(self.network_address) + if packed & int(self.netmask) != packed: + if strict: + raise ValueError('%s has host bits set' % self) + else: + self.network_address = IPv6Address(packed & + int(self.netmask)) + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP prefix string. + addr = _split_optional_netmask(address) + + self.network_address = IPv6Address(self._ip_int_from_string(addr[0])) + + if len(addr) == 2: + arg = addr[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + + if strict: + if (IPv6Address(int(self.network_address) & int(self.netmask)) != + self.network_address): + raise ValueError('%s has host bits set' % self) + self.network_address = IPv6Address(int(self.network_address) & + int(self.netmask)) + + if self._prefixlen == (self._max_prefixlen - 1): + self.hosts = self.__iter__ + + def hosts(self): + """Generate Iterator over usable hosts in a network. + + This is like __iter__ except it doesn't return the + Subnet-Router anycast address. + + """ + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network + 1, broadcast + 1): + yield self._address_class(x) + + @property + def is_site_local(self): + """Test if the address is reserved for site-local. + + Note that the site-local address space has been deprecated by RFC 3879. + Use is_private to test if this address is in the space of unique local + addresses as defined by RFC 4193. + + Returns: + A boolean, True if the address is reserved per RFC 3513 2.5.6. + + """ + return (self.network_address.is_site_local and + self.broadcast_address.is_site_local) + + +class _IPv6Constants(object): + + _linklocal_network = IPv6Network('fe80::/10') + + _multicast_network = IPv6Network('ff00::/8') + + _private_networks = [ + IPv6Network('::1/128'), + IPv6Network('::/128'), + IPv6Network('::ffff:0:0/96'), + IPv6Network('100::/64'), + IPv6Network('2001::/23'), + IPv6Network('2001:2::/48'), + IPv6Network('2001:db8::/32'), + IPv6Network('2001:10::/28'), + IPv6Network('fc00::/7'), + IPv6Network('fe80::/10'), + ] + + _reserved_networks = [ + IPv6Network('::/8'), IPv6Network('100::/8'), + IPv6Network('200::/7'), IPv6Network('400::/6'), + IPv6Network('800::/5'), IPv6Network('1000::/4'), + IPv6Network('4000::/3'), IPv6Network('6000::/3'), + IPv6Network('8000::/3'), IPv6Network('A000::/3'), + IPv6Network('C000::/3'), IPv6Network('E000::/4'), + IPv6Network('F000::/5'), IPv6Network('F800::/6'), + IPv6Network('FE00::/9'), + ] + + _sitelocal_network = IPv6Network('fec0::/10') + + +IPv6Address._constants = _IPv6Constants diff --git a/script.plexmod/lib/_included_packages/plexnet/asyncadapter.py b/script.plexmod/lib/_included_packages/plexnet/asyncadapter.py index 97fbcd741..2b427fb06 100644 --- a/script.plexmod/lib/_included_packages/plexnet/asyncadapter.py +++ b/script.plexmod/lib/_included_packages/plexnet/asyncadapter.py @@ -77,6 +77,8 @@ def getConnectTimeout(self): class AsyncVerifiedHTTPSConnection(VerifiedHTTPSConnection): + __slots__ = ("_canceled", "deadline", "_timeout") + def __init__(self, *args, **kwargs): VerifiedHTTPSConnection.__init__(self, *args, **kwargs) self._canceled = False @@ -166,6 +168,7 @@ def cancel(self): class AsyncHTTPConnection(HTTPConnection): + __slots__ = ("_canceled", "deadline") def __init__(self, *args, **kwargs): HTTPConnection.__init__(self, *args, **kwargs) self._canceled = False @@ -176,6 +179,8 @@ def cancel(self): class AsyncHTTPConnectionPool(HTTPConnectionPool): + __slots__ = ("connections",) + def __init__(self, *args, **kwargs): HTTPConnectionPool.__init__(self, *args, **kwargs) self.connections = [] @@ -209,6 +214,8 @@ def cancel(self): class AsyncHTTPSConnectionPool(HTTPSConnectionPool): + __slots__ = ("connections",) + def __init__(self, *args, **kwargs): HTTPSConnectionPool.__init__(self, *args, **kwargs) self.connections = [] diff --git a/script.plexmod/lib/_included_packages/plexnet/http.py b/script.plexmod/lib/_included_packages/plexnet/http.py index 21648590d..f94de43df 100644 --- a/script.plexmod/lib/_included_packages/plexnet/http.py +++ b/script.plexmod/lib/_included_packages/plexnet/http.py @@ -77,6 +77,8 @@ def __setattr__(self, attr, value): class HttpRequest(object): + __slots__ = ("server", "path", "hasParams", "ignoreResponse", "session", "currentResponse", "method", "url", + "thread", "__dict__") _cancel = False def __init__(self, url, method=None, forceCertificate=False): diff --git a/script.plexmod/lib/_included_packages/plexnet/locks.py b/script.plexmod/lib/_included_packages/plexnet/locks.py index 5e309f4ee..a7ab8d242 100644 --- a/script.plexmod/lib/_included_packages/plexnet/locks.py +++ b/script.plexmod/lib/_included_packages/plexnet/locks.py @@ -8,6 +8,8 @@ class Locks(object): + __slots__ = ("locks", "oneTimeLocks") + def __init__(self): self.locks = {} self.oneTimeLocks = {} diff --git a/script.plexmod/lib/_included_packages/plexnet/media.py b/script.plexmod/lib/_included_packages/plexnet/media.py index 28b0bc96f..d98f9e6b4 100644 --- a/script.plexmod/lib/_included_packages/plexnet/media.py +++ b/script.plexmod/lib/_included_packages/plexnet/media.py @@ -176,10 +176,11 @@ class TranscodeSession(plexobjects.PlexObject): class MediaTag(plexobjects.PlexObject): TYPE = None ID = 'None' + virtual = False def __repr__(self): tag = self.tag.replace(' ', '.')[0:20] - return '<%s:%s:%s>' % (self.__class__.__name__, self.id, tag) + return '<%s:%s:%s:%s>' % (self.__class__.__name__, self.id, tag, self.virtual) def __eq__(self, other): if other.__class__ != self.__class__: @@ -196,6 +197,11 @@ class Collection(MediaTag): FILTER = 'collection' +class Location(MediaTag): + TYPE = 'Location' + FILTER = 'location' + + class Country(MediaTag): TYPE = 'Country' FILTER = 'country' @@ -255,6 +261,11 @@ class Writer(MediaTag): FILTER = 'writer' +class Guid(MediaTag): + TYPE = 'Guid' + FILTER = 'guid' + + class Chapter(MediaTag): TYPE = 'Chapter' diff --git a/script.plexmod/lib/_included_packages/plexnet/myplexaccount.py b/script.plexmod/lib/_included_packages/plexnet/myplexaccount.py index 1d6ef2e33..953e686dc 100644 --- a/script.plexmod/lib/_included_packages/plexnet/myplexaccount.py +++ b/script.plexmod/lib/_included_packages/plexnet/myplexaccount.py @@ -35,6 +35,7 @@ def __init__(self): # Booleans self.isAuthenticated = util.INTERFACE.getPreference('auto_signin', False) + self.cacheHomeUsers = util.INTERFACE.getPreference('cache_home_users', True) self.isSignedIn = False self.isOffline = False self.isExpired = False @@ -70,10 +71,12 @@ def saveState(self): 'isSecure': self.isSecure, 'adminHasPlexPass': self.adminHasPlexPass, 'thumb': self.thumb, - 'homeUsers': self.homeUsers, 'lastHomeUserUpdate': self.lastHomeUserUpdate } + if self.cacheHomeUsers: + obj["homeUsers"] = self.homeUsers + util.INTERFACE.setRegistry("MyPlexAccount", json.dumps(obj), "myplex") def loadState(self): @@ -106,7 +109,8 @@ def loadState(self): self.adminHasPlexPass = obj.get('adminHasPlexPass') or self.adminHasPlexPass self.thumb = obj.get('thumb') self.lastHomeUserUpdate = obj.get('lastHomeUserUpdate') - self.homeUsers = [HomeUser(data) for data in obj.get('homeUsers', [])] + if self.cacheHomeUsers: + self.homeUsers = [HomeUser(data) for data in obj.get('homeUsers', [])] if self.homeUsers: util.LOG("cached home users: {0} (last update: {1})".format(self.homeUsers, self.lastHomeUserUpdate)) diff --git a/script.plexmod/lib/_included_packages/plexnet/plexapp.py b/script.plexmod/lib/_included_packages/plexnet/plexapp.py index 466230dcb..f07d1b200 100644 --- a/script.plexmod/lib/_included_packages/plexnet/plexapp.py +++ b/script.plexmod/lib/_included_packages/plexnet/plexapp.py @@ -25,6 +25,8 @@ def init(): SERVERMANAGER = plexservermanager.MANAGER from . import myplexmanager util.MANAGER = MANAGER = myplexmanager.MANAGER + util.ACCOUNT = ACCOUNT + util.SERVERMANAGER = SERVERMANAGER util.DEBUG_LOG("Verifying account...") ACCOUNT.verifyAccount() diff --git a/script.plexmod/lib/_included_packages/plexnet/plexconnection.py b/script.plexmod/lib/_included_packages/plexnet/plexconnection.py index dfdf7304b..db495d193 100644 --- a/script.plexmod/lib/_included_packages/plexnet/plexconnection.py +++ b/script.plexmod/lib/_included_packages/plexnet/plexconnection.py @@ -6,6 +6,11 @@ from . import callback from . import util +try: + from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network +except ImportError: + from _ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network + HAS_ICMPLIB = False try: from icmplib import ping, resolve, ICMPLibError @@ -14,16 +19,16 @@ else: HAS_ICMPLIB = True from urllib.parse import urlparse - from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network - # local networks - LOCAL_NETWORKS = { - 4: [IPv4Network('10.0.0.0/8'), IPv4Network('192.168.0.0/16'), IPv4Network('172.16.0.0/12'), - IPv4Network('127.0.0.0/8')], - 6: [IPv6Network('fd00::/8')] - } +# local networks +DOCKER_NETWORK = IPv4Network(u'172.16.0.0/12') +LOCAL_NETWORKS = { + 4: [IPv4Network(u'10.0.0.0/8'), IPv4Network(u'192.168.0.0/16'), DOCKER_NETWORK, + IPv4Network(u'127.0.0.0/8')], + 6: [IPv6Network(u'fd00::/8')] +} - LOCALS_SEEN = {} +LOCALS_SEEN = {} class ConnectionSource(int): diff --git a/script.plexmod/lib/_included_packages/plexnet/plexlibrary.py b/script.plexmod/lib/_included_packages/plexnet/plexlibrary.py index df1edbe2c..d04cd082b 100644 --- a/script.plexmod/lib/_included_packages/plexnet/plexlibrary.py +++ b/script.plexmod/lib/_included_packages/plexnet/plexlibrary.py @@ -10,6 +10,8 @@ from . import exceptions from . import util from . import signalsmixin +from lib.path_mapping import pmm, norm_sep +from lib.exceptions import NoDataException from six.moves import map @@ -90,10 +92,21 @@ class LibrarySection(plexobjects.PlexObject): isLibraryPQ = True + def __init__(self, data, initpath=None, server=None, container=None): + self.locations = [] + self._isMapped = None + super(LibrarySection, self).__init__(data, initpath=initpath, server=server, container=container) + def __repr__(self): title = self.title.replace(' ', '.')[0:20] return '<%s:%s>' % (self.__class__.__name__, title.encode('utf8')) + def _setData(self, data): + super(LibrarySection, self)._setData(data) + for loc in plexobjects.PlexItemList(data, media.Location, media.Location.TYPE, server=self.server): + sep = norm_sep(loc.path) + self.locations.append(loc.path if loc.path.endswith(sep) else loc.path + sep) + @staticmethod def fromFilter(filter_): cls = SECTION_IDS.get(filter_.getLibrarySectionType()) @@ -127,6 +140,30 @@ def isDirectory(self): def isLibraryItem(self): return True + def getMappedPath(self, loc=None): + if not self.locations: + return None, None + + return pmm.getMappedPathFor(loc or self.locations[0], self.server) + + def deleteMapping(self, target): + pmm.deletePathMapping(target, server=self.getServer()) + self._isMapped = None + + @property + def isMapped(self): + if self._isMapped is not None: + return self._isMapped + elif self._isMapped is False: + return False + + for loc in self.locations: + if all(self.getMappedPath(loc)): + self._isMapped = True + return True + self._isMapped = False + return self._isMapped + def getAbsolutePath(self, key): if key == 'key': return '/library/sections/{0}/all'.format(self.key) @@ -568,10 +605,13 @@ def reload(self, **kwargs): return self.initpath = self.key - self._setData(data) + try: + self._setData(data) + except: + raise NoDataException self.init(data) - def extend(self, start=None, size=None): + def extend(self, start=None, size=None, **kwargs): path = self.key args = {} @@ -580,6 +620,9 @@ def extend(self, start=None, size=None): args['X-Plex-Container-Start'] = start args['X-Plex-Container-Size'] = size + if kwargs: + args.update(kwargs) + if args: path += util.joinArgs(args) if '?' not in path else '&' + util.joinArgs(args).lstrip('?') diff --git a/script.plexmod/lib/_included_packages/plexnet/plexmedia.py b/script.plexmod/lib/_included_packages/plexnet/plexmedia.py index 76434d78a..882dd2044 100644 --- a/script.plexmod/lib/_included_packages/plexnet/plexmedia.py +++ b/script.plexmod/lib/_included_packages/plexnet/plexmedia.py @@ -10,6 +10,8 @@ class PlexMedia(plexobjects.PlexObject): + __slots__ = ("_data", "container_", "container", "indirectHeaders", "parts") + def __init__(self, data, initpath=None, server=None, container=None): self._data = data.attrib plexobjects.PlexObject.__init__(self, data, initpath, server) diff --git a/script.plexmod/lib/_included_packages/plexnet/plexobjects.py b/script.plexmod/lib/_included_packages/plexnet/plexobjects.py index cba919e90..5406dca92 100644 --- a/script.plexmod/lib/_included_packages/plexnet/plexobjects.py +++ b/script.plexmod/lib/_included_packages/plexnet/plexobjects.py @@ -34,6 +34,8 @@ def wrap(func): class PlexValue(six.text_type): + __slots__ = ("parent", "NA") + def __new__(cls, value, parent=None): self = super(PlexValue, cls).__new__(cls, value) self.parent = parent @@ -153,6 +155,8 @@ def isSettings(self): class PlexObject(Checks): + __slots__ = ("initpath", "key", "server", "container", "mediaChoice", "titleSort", "deleted", "_reloaded", "data") + def __init__(self, data, initpath=None, server=None, container=None): self.initpath = initpath self.key = None @@ -198,7 +202,7 @@ def exists(self, *args, **kwargs): return True def get(self, attr, default=''): - ret = self.__dict__.get(attr) + ret = self.__dict__.get(attr, getattr(self, attr) if attr in self.__slots__ else None) return ret is not None and ret or PlexValue(default, self) def set(self, attr, value): @@ -234,8 +238,6 @@ def reload(self, _soft=False, **kwargs): if _soft and self._reloaded: return self - kwargs["includeMarkers"] = 1 - try: if self.get('ratingKey'): data = self.server.query('/library/metadata/{0}'.format(self.ratingKey), params=kwargs) @@ -422,6 +424,8 @@ def serialize(self, full=False): class PlexContainer(PlexObject): + __slots__ = ("address",) + def __init__(self, data, initpath=None, server=None, address=None): PlexObject.__init__(self, data, initpath, server) self.setAddress(address) @@ -446,6 +450,8 @@ def getAbsolutePath(self, path): class PlexServerContainer(PlexContainer): + __slots__ = ("resources",) + def __init__(self, data, initpath=None, server=None, address=None): PlexContainer.__init__(self, data, initpath, server, address) from . import plexserver @@ -463,6 +469,8 @@ def __len__(self): class PlexItemList(object): + __slots__ = ("_data", "_itemClass", "_itemTag", "_server", "_container", "_items") + def __init__(self, data, item_cls, tag, server=None, container=None): self._data = data self._itemClass = item_cls @@ -502,6 +510,8 @@ def append(self, item): class PlexMediaItemList(PlexItemList): + __slots__ = ("_initpath", "_media", "_items") + def __init__(self, data, item_cls, tag, initpath=None, server=None, media=None): PlexItemList.__init__(self, data, item_cls, tag, server) self._initpath = initpath @@ -538,6 +548,8 @@ def buildItem(server, elem, initpath, bytag=False, container=None, tag_fallback= class ItemContainer(list): + __slots__ = ("container", "totalSize") + def __getattr__(self, attr): return getattr(self.container, attr) diff --git a/script.plexmod/lib/_included_packages/plexnet/plexpart.py b/script.plexmod/lib/_included_packages/plexnet/plexpart.py index 86cc5ddd9..1931d6b1f 100644 --- a/script.plexmod/lib/_included_packages/plexnet/plexpart.py +++ b/script.plexmod/lib/_included_packages/plexnet/plexpart.py @@ -5,7 +5,8 @@ from . import plexrequest from . import util -from lib.util import PATH_MAP, addonSettings +from lib.util import addonSettings +from lib.path_mapping import pmm, norm_sep class PlexPart(plexobjects.PlexObject): @@ -123,7 +124,6 @@ def setSelectedStream(self, streamType, streamId, _async): if _async: context = request.createRequestContext("ignored") - from . import plexapp util.APP.startRequest(request, context, "") else: request.postToStringWithTimeout() @@ -162,28 +162,21 @@ def hasStreams(self): def getPathMappedUrl(self, return_only_folder=False): verify = addonSettings.verifyMappedFiles - if PATH_MAP and util.INTERFACE.getPreference("path_mapping", True): - match = ("", "") - for map_path, pms_path in PATH_MAP.get(self.getServer().name, {}).items(): - # the longest matching path wins - if self.file.startswith(pms_path) and len(pms_path) > len(match[1]): - match = (map_path, pms_path) + map_path, pms_path = pmm.getMappedPathFor(self.file, self.getServer()) + if map_path and pms_path: + if return_only_folder: + return map_path - if all(match): - map_path, pms_path = match - if return_only_folder: - return map_path + sep = norm_sep(map_path) - sep = "\\" in map_path and "\\" or "/" + # replace match and normalize path separator to separator style of map_path + url = self.file.replace(pms_path, map_path, 1).replace(sep == "/" and "\\" or "/", sep) - # replace match and normalize path separator to separator style of map_path - url = self.file.replace(pms_path, map_path, 1).replace(sep == "/" and "\\" or "/", sep) - - if (verify and xbmcvfs.exists(url)) or not verify: - util.DEBUG_LOG("File {} found in path map, mapping to {}".format(self.file, pms_path)) - return url - util.LOG("Mapped file {} doesn't exist".format(url)) + if (verify and xbmcvfs.exists(url)) or not verify: + util.DEBUG_LOG("File {} found in path map, mapping to {}".format(self.file, pms_path)) + return url + util.LOG("Mapped file {} doesn't exist".format(url)) return "" @property diff --git a/script.plexmod/lib/_included_packages/plexnet/plexplayer.py b/script.plexmod/lib/_included_packages/plexnet/plexplayer.py index cfb8e84fb..da2c755d9 100644 --- a/script.plexmod/lib/_included_packages/plexnet/plexplayer.py +++ b/script.plexmod/lib/_included_packages/plexnet/plexplayer.py @@ -291,10 +291,7 @@ def getDecisionPath(self, directPlay=False): "mediaBufferSize={}".format(str(CACHE_SIZE * 1024))) decisionPath = http.addUrlParam(decisionPath, "hasMDE=1") - if not addonSettings.oldprofile: - decisionPath = http.addUrlParam(decisionPath, 'X-Plex-Client-Profile-Name=Generic') - else: - decisionPath = http.addUrlParam(decisionPath, 'X-Plex-Client-Profile-Name=Chrome') + decisionPath = http.addUrlParam(decisionPath, 'X-Plex-Client-Profile-Name=Generic') return decisionPath @@ -322,11 +319,7 @@ def buildTranscodeHls(self, obj): builder.extras = [] builder.addParam("protocol", "hls") - # TODO: This should be Generic, but will need to re-evaluate the augmentations with that change - if not addonSettings.oldprofile: - builder.addParam("X-Plex-Client-Profile-Name", "Generic") - else: - builder.addParam("X-Plex-Client-Profile-Name", "Chrome") + builder.addParam("X-Plex-Client-Profile-Name", "Generic") if self.choice.subtitleDecision == self.choice.SUBTITLES_SOFT_ANY: builder.addParam("skipSubtitles", "1") @@ -338,11 +331,7 @@ def buildTranscodeHls(self, obj): # Augment the server's profile for things that depend on the Roku's configuration. if self.item.settings.supportsAudioStream("ac3", 6): builder.extras.append("append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=ac3)") - if not addonSettings.oldprofile: - builder.extras.append("add-direct-play-profile(type=videoProfile&container=mkv&videoCodec=*&audioCodec=ac3)") - else: - builder.extras.append( - "add-direct-play-profile(type=videoProfile&container=matroska&videoCodec=*&audioCodec=ac3)") + builder.extras.append("add-direct-play-profile(type=videoProfile&container=mkv&videoCodec=*&audioCodec=ac3)") return builder @@ -356,10 +345,7 @@ def buildTranscodeMkv(self, obj, directStream=True): builder.extras = [] builder.addParam("protocol", "http") builder.addParam("copyts", "1") - if not addonSettings.oldprofile: - builder.addParam("X-Plex-Client-Profile-Name", "Generic") - else: - builder.addParam("X-Plex-Client-Profile-Name", "Chrome") + builder.addParam("X-Plex-Client-Profile-Name", "Generic") obj.subtitleUrl = None @@ -555,149 +541,6 @@ def buildTranscodeMkv(self, obj, directStream=True): return builder - def buildTranscodeMkvLegacy(self, obj, directStream=True): - util.DEBUG_LOG('buildTranscodeMkvLegacy()') - obj.streamFormat = "mkv" - obj.streamBitrates = [0] - obj.transcodeEndpoint = "/video/:/transcode/universal/start.mkv" - - builder = http.HttpRequest(obj.transcodeServer.buildUrl(obj.transcodeEndpoint, True)) - builder.extras = [] - builder.addParam("protocol", "http") - builder.addParam("copyts", "1") - builder.addParam("X-Plex-Client-Profile-Name", "Generic") - - obj.subtitleUrl = None - - # fixme: still necessary? - if True: # if self.choice.subtitleDecision == self.choice.SUBTITLES_BURN: # Must burn transcoded because we can't set offset - builder.addParam("subtitles", "burn") - captionSize = captions.CAPTIONS.getBurnedSize() - if captionSize is not None: - builder.addParam("subtitleSize", captionSize) - - else: - # TODO(rob): can we safely assume the id will also be 3 (one based index). - # If not, we will have to get tricky and select the subtitle stream after - # video playback starts via roCaptionRenderer: GetSubtitleTracks() and - # ChangeSubtitleTrack() - - obj.subtitleConfig = {'TrackName': "mkv/3"} - - # Allow text conversion of subtitles if we only burn image formats - if self.item.settings.getPreference("burn_subtitles") == "image": - builder.addParam("advancedSubtitles", "text") - - builder.addParam("subtitles", "auto") - - if directStream: - audioCodecs = "eac3,ac3,dca,aac,mp3,mp2,pcm,flac,alac,wmav2,wmapro,wmavoice,opus,vorbis,truehd" - else: - audioCodecs = "mp3,ac3,aac,opus" - - # Allow virtually anything in Kodi playback. - - # DP might not do anything here - # builder.extras.append( - # "add-direct-play-profile(type=videoProfile&videoCodec=" - # "h264,mpeg1video,mpeg2video,mpeg4,msmpeg4v2,msmpeg4v3,vc1,wmv3&container=*&" - # "audioCodec="+audioCodecs+"&protocol=http)") - - builder.extras.append( - "add-transcode-target(type=videoProfile&videoCodec=" - "h264,mpeg1video,mpeg2video,mpeg4,msmpeg4v2,msmpeg4v3,wmv3&container=mkv&" - "audioCodec="+audioCodecs+"&protocol=http&context=streaming)") - - # builder.extras.append( - # "append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + - # audioCodecs + ")") - - # if self.item.settings.supportsSurroundSound(): - # if self.choice.audioStream is not None: - # numChannels = self.choice.audioStream.channels.asInt(8) - # else: - # numChannels = 8 - # - # for codec in ("ac3", "eac3", "dca"): - # if self.item.settings.supportsAudioStream(codec, numChannels): - # builder.extras.append("append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + codec + ")") - # builder.extras.append("add-direct-play-profile(type=videoProfile&videoCodec=*&container=mkv&audioCodec=" + codec + ")") - # if codec == "dca": - # builder.extras.append( - # "add-limitation(scope=videoAudioCodec&scopeName=dca&type=upperBound&name=audio.channels&value=8&isRequired=false)" - # ) - # - # for codec in ("ac3", "eac3", "dca"): - # builder.extras.append("append-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=http&audioCodec=" + codec + ")") - # builder.extras.append("add-direct-play-profile(type=videoProfile&videoCodec=*&container=mkv&audioCodec=" + codec + ")") - - # limit OPUS to 334kbit - numChannels = self.choice.audioStream.channels.asInt(8) if self.choice.audioStream else 8 - - if numChannels == 8: - # 7.1 - opusBitrate = 334 - elif numChannels >= 6: - # 5.1 - opusBitrate = 256 - else: - # 2 - opusBitrate = 128 - - builder.extras.append( - "add-limitation(scope=videoAudioCodec&scopeName=opus&type=upperBound&name=audio.bitrate&" - "value={}&isRequired=false)".format(opusBitrate) - ) - - # limit AC3 - builder.extras.append( - "add-limitation(scope=videoAudioCodec&scopeName=ac3&type=upperBound&name=audio.bitrate&value=640)" - ) - - # limit audio to Kodi audio channels - builder.extras.append( - "add-limitation(scope=videoAudioCodec&scopeName=*&type=upperBound&" - "name=audio.channels&value={})".format(self.audioChannels) - ) - - # AAC sample rate cannot be less than 22050hz (HLS is capable). - if self.choice.audioStream is not None and self.choice.audioStream.samplingRate.asInt(22050) < 22050: - builder.extras.append( - "add-limitation(scope=videoAudioCodec&scopeName=aac&type=lowerBound&" - "name=audio.samplingRate&value=22050&isRequired=false)") - - # HEVC - if self.item.settings.getPreference("allow_hevc", True): - builder.extras.append( - "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" - "protocol=http&videoCodec=hevc)") - # builder.extras.append( - # "add-direct-play-profile(type=videoProfile&videoCodec=hevc&container=*&audioCodec=*)") - - # VP9 - if self.item.settings.getGlobal("vp9Support"): - builder.extras.append( - "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" - "protocol=http&videoCodec=vp9)") - # builder.extras.append( - # "add-direct-play-profile(type=videoProfile&videoCodec=vp9&container=*&audioCodec=*)") - - # AV1 - if self.item.settings.getPreference("allow_av1", False): - builder.extras.append( - "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" - "protocol=http&videoCodec=av1)") - # builder.extras.append( - # "add-direct-play-profile(type=videoProfile&videoCodec=av1&container=*&audioCodec=*)") - - # VC1 - if self.item.settings.getPreference("allow_vc1", True): - builder.extras.append( - "append-transcode-target-codec(type=videoProfile&context=streaming&container=mkv&" - "protocol=http&videoCodec=vc1)") - - return builder - def buildDirectPlay(self, obj, partIndex): util.DEBUG_LOG('buildDirectPlay()') part = self.media.parts[partIndex] @@ -767,10 +610,7 @@ def buildTranscode(self, server, obj, partIndex, directStream, isCurrentPart): # if server.supportsFeature("mkvTranscode") and self.item.settings.getPreference("transcode_format", 'mkv') != "hls": if server.supportsFeature("mkvTranscode"): - if not addonSettings.oldprofile: - builder = self.buildTranscodeMkv(obj, directStream=directStream) - else: - builder = self.buildTranscodeMkvLegacy(obj, directStream=directStream) + builder = self.buildTranscodeMkv(obj, directStream=directStream) else: builder = self.buildTranscodeHls(obj) diff --git a/script.plexmod/lib/_included_packages/plexnet/plexserver.py b/script.plexmod/lib/_included_packages/plexnet/plexserver.py index 4c073a073..7a2cc8166 100644 --- a/script.plexmod/lib/_included_packages/plexnet/plexserver.py +++ b/script.plexmod/lib/_included_packages/plexnet/plexserver.py @@ -65,6 +65,7 @@ def __init__(self, data=None): self.versionNorm = None self.rawVersion = None self.transcodeSupport = False + self.currentHubs = None if data is None: return @@ -118,7 +119,7 @@ def getObject(self, key): data = self.query(key) return plexobjects.buildItem(self, data[0], key, container=self) - def hubs(self, section=None, count=None, search_query=None): + def hubs(self, section=None, count=None, search_query=None, section_ids=None, ignore_hubs=None): hubs = [] params = {"includeMarkers": 1} @@ -143,6 +144,10 @@ def hubs(self, section=None, count=None, search_query=None): return hubs else: q = '/hubs/sections/%s' % section + else: + # home hub + if section_ids: + params['pinnedContentDirectoryID'] = ",".join(section_ids) if count is not None: params['count'] = count @@ -156,18 +161,36 @@ def hubs(self, section=None, count=None, search_query=None): if newCW: # home, add continueWatching cq = '/hubs/continueWatching' + if section_ids: + cq += util.joinArgs(params) + cdata = self.query(cq, params=params) ccontainer = plexobjects.PlexContainer(cdata, initpath=cq, server=self, address=cq) + self.currentHubs[cdata[0].attrib.get('hubIdentifier')] = cdata[0].attrib.get('title') hubs.append(plexlibrary.Hub(cdata[0], server=self, container=ccontainer)) + self.currentHubs = {} if self.currentHubs is None else self.currentHubs + for elem in data: hubIdent = elem.attrib.get('hubIdentifier') + self.currentHubs["{}:{}".format(section, hubIdent)] = elem.attrib.get('title') + # if we've added continueWatching, which combines continue and ondeck, skip those two hubs if newCW and hubIdent and \ (hubIdent.startswith('home.continue') or hubIdent.startswith('home.ondeck')): continue + if ignore_hubs and "{}:{}".format(section, hubIdent) in ignore_hubs: + continue + hubs.append(plexlibrary.Hub(elem, server=self, container=container)) + + if section_ids: + # when we have hidden sections, apply the filter to the hubs keys for subsequent queries + for hub in hubs: + if "pinnedContentDirectoryID" not in hub.key: + hub.key += util.joinArgs(params, '?' not in hub.key) + return hubs def playlists(self, start=0, size=10, hub=None): diff --git a/script.plexmod/lib/_included_packages/plexnet/signalsmixin.py b/script.plexmod/lib/_included_packages/plexnet/signalsmixin.py index 2efe9d6e6..cfe09f764 100644 --- a/script.plexmod/lib/_included_packages/plexnet/signalsmixin.py +++ b/script.plexmod/lib/_included_packages/plexnet/signalsmixin.py @@ -3,7 +3,7 @@ class SignalsMixin(object): - def __init__(self): + def __init__(self, *args, **kwargs): self._signals = {} def on(self, signalName, callback): @@ -14,6 +14,12 @@ def on(self, signalName, callback): signal.connect(callback) + def has_signal(self, signalName, callback): + if not self._signals: + return + + return signalName in self._signals and self._signals[signalName].is_connected(callback) + def off(self, signalName, callback): if not self._signals: return diff --git a/script.plexmod/lib/_included_packages/plexnet/util.py b/script.plexmod/lib/_included_packages/plexnet/util.py index a796c59c6..bece856d1 100644 --- a/script.plexmod/lib/_included_packages/plexnet/util.py +++ b/script.plexmod/lib/_included_packages/plexnet/util.py @@ -68,6 +68,8 @@ def resetBaseHeaders(): TIMER = None APP = None MANAGER = None +ACCOUNT = None +SERVERMANAGER = None try: _platform = platform.system() diff --git a/script.plexmod/lib/_included_packages/plexnet/video.py b/script.plexmod/lib/_included_packages/plexnet/video.py index 5768a635d..6e6995a87 100644 --- a/script.plexmod/lib/_included_packages/plexnet/video.py +++ b/script.plexmod/lib/_included_packages/plexnet/video.py @@ -12,6 +12,9 @@ from . import mediachoice from .mixins import AudioCodecMixin +from lib.data_cache import dcm +from lib.util import T + class PlexVideoItemList(plexobjects.PlexItemList): def __init__(self, data, initpath=None, server=None, container=None): @@ -45,15 +48,19 @@ def _impl(self, *method_args, **method_kwargs): class Video(media.MediaItem, AudioCodecMixin): + __slots__ = ("_settings",) + TYPE = None manually_selected_sub_stream = False current_subtitle_is_embedded = False _current_subtitle_idx = None + _noSpoilers = False def __init__(self, *args, **kwargs): self._settings = None media.MediaItem.__init__(self, *args, **kwargs) AudioCodecMixin.__init__(self) + self._noSpoilers = False def __eq__(self, other): return other and self.ratingKey == other.ratingKey @@ -372,6 +379,7 @@ def sectionOnDeckCount(self): class PlayableVideo(Video, media.RelatedMixin): + __slots__ = ("extras", "guids", "chapters") TYPE = None _videoStreams = None _audioStreams = None @@ -382,6 +390,7 @@ def _setData(self, data): Video._setData(self, data) if self.isFullObject(): self.extras = PlexVideoItemList(data.find('Extras'), initpath=self.initpath, server=self.server, container=self) + self.guids = plexobjects.PlexItemList(data, media.Guid, media.Guid.TYPE, server=self.server) # the PMS Extras API can return protocol=mp4 when it doesn't make sense, mark this as an extra so the MDE # knows what to do @@ -412,6 +421,8 @@ def reload(self, *args, **kwargs): fromMediaChoice = kwargs.get("fromMediaChoice", False) + kwargs["includeMarkers"] = 1 + # capture current IDs mediaID = None partID = None @@ -469,6 +480,8 @@ def postPlay(self, **params): @plexobjects.registerLibType class Movie(PlayableVideo): + __slots__ = ("collections", "countries", "directors", "genres", "media", "producers", "roles", "reviews", + "writers", "markers", "sessionKey", "user", "player", "session", "transcodeSession") TYPE = 'movie' def _setData(self, data): @@ -552,13 +565,15 @@ def getStreamURL(self, **params): @plexobjects.registerLibType class Show(Video, media.RelatedMixin, SectionOnDeckMixin): + __slots__ = ("_genres", "guids", "onDeck") TYPE = 'show' def _setData(self, data): Video._setData(self, data) if self.isFullObject(): - self.genres = plexobjects.PlexItemList(data, media.Genre, media.Genre.TYPE, server=self.server) + self._genres = plexobjects.PlexItemList(data, media.Genre, media.Genre.TYPE, server=self.server) self.roles = plexobjects.PlexItemList(data, media.Role, media.Role.TYPE, server=self.server, container=self.container) + self.guids = plexobjects.PlexItemList(data, media.Guid, media.Guid.TYPE, server=self.server) #self.related = plexobjects.PlexItemList(data.find('Related'), plexlibrary.Hub, plexlibrary.Hub.TYPE, server=self.server, container=self) self.extras = PlexVideoItemList(data.find('Extras'), initpath=self.initpath, server=self.server, container=self) self.onDeck = PlexVideoItemList(data.find('OnDeck'), initpath=self.initpath, server=self.server, @@ -572,6 +587,10 @@ def unViewedLeafCount(self): def isWatched(self): return self.viewedLeafCount == self.leafCount + @property + def isFullyWatched(self): + return self.isWatched + @property def playbackSettings(self): return util.INTERFACE.playbackManager(self) @@ -604,6 +623,17 @@ def unwatched(self): def refresh(self): self.server.query('/library/metadata/%s/refresh' % self.ratingKey) + def genres(self): + genres = dcm.getCacheData("show_genres", self.ratingKey) + if genres: + return [media.Genre(util.AttributeDict(tag="genre", attrib={"tag": g}, virtual=True)) for g in genres] + + if not self.isFullObject(): + self.reload(soft=True) + + dcm.setCacheData("show_genres", self.ratingKey, [g.tag for g in self._genres]) + return self._genres + @plexobjects.registerLibType class Season(Video): @@ -616,7 +646,7 @@ def _setData(self, data): @property def defaultTitle(self): - return self.parentTitle or self.title + return T(32303, "Season {}").format(self.index) @property def unViewedLeafCount(self): @@ -626,6 +656,10 @@ def unViewedLeafCount(self): def isWatched(self): return self.viewedLeafCount == self.leafCount + @property + def isFullyWatched(self): + return self.isWatched + def episodes(self, watched=None, offset=None, limit=None): path = self.key return plexobjects.listItems(self.server, path, watched=watched, offset=offset, limit=limit) @@ -649,6 +683,7 @@ def unwatched(self): @plexobjects.registerLibType class Episode(PlayableVideo, SectionOnDeckMixin): + __slots__ = ("_show", "_season") TYPE = 'episode' def init(self, data): @@ -708,6 +743,10 @@ def isWatched(self): def isFullyWatched(self): return self.get('viewCount').asInt() > 0 and not self.get('viewOffset').asInt() + @property + def inProgress(self): + return bool(self.get('viewOffset').asInt()) + @property def playbackSettings(self): return self.show().playbackSettings diff --git a/script.plexmod/lib/data_cache.py b/script.plexmod/lib/data_cache.py new file mode 100644 index 000000000..9766cbdea --- /dev/null +++ b/script.plexmod/lib/data_cache.py @@ -0,0 +1,121 @@ +# coding=utf-8 + +import os +import json +import time +import copy +import zlib + +from kodi_six import xbmcvfs + +from plexnet import plexapp + +from . util import translatePath, ADDON, ERROR, DEBUG_LOG, LOG + + +class DataCacheManager(object): + # store arbitrary data in JSON on disk + DATA_CACHES_VERSION = 2 + DATA_CACHES = { + "general": {}, + "cache": {} + } + DC_LAST_UPDATE = None + DC_PATH = os.path.join(translatePath(ADDON.getAddonInfo("profile")), "data_cache.json") + DC_LRU_TIMEOUT = 30 + DC_LRUP_TIMEOUT = 90 + USE_GZ = False + + def __init__(self): + self._currentServerUUID = None + plexapp.util.APP.on('change:selectedServer', self.setServerUUID) + if self.USE_GZ: + self.DC_PATH += "z" + if xbmcvfs.exists(self.DC_PATH): + try: + f = xbmcvfs.File(self.DC_PATH) + d = f.readBytes() if self.USE_GZ else f.read() + f.close() + + tdc = json.loads(zlib.decompress(d).decode("utf-8") if self.USE_GZ else d) + old_ver = tdc["general"].get("version", 0) + if old_ver < self.DATA_CACHES_VERSION: + # this is where we migrate + if old_ver == 1: + tdc = self.DATA_CACHES.copy() + tdc["general"]["version"] = self.DATA_CACHES_VERSION + tdc["general"]["updated"] = time.time() + self.DATA_CACHES = tdc + self.storeDataCache() + else: + tdc["general"]["version"] = self.DATA_CACHES_VERSION + self.DATA_CACHES.update(tdc) + self.dataCacheCleanup() + self.DC_LAST_UPDATE = self.DATA_CACHES["general"]["updated"] + except: + ERROR("Couldn't read data_cache.json") + self.DATA_CACHES["general"]["updated"] = time.time() + self.storeDataCache() + + def deinit(self): + plexapp.util.APP.off('change:selectedServer', self.setServerUUID) + + def getCacheData(self, context, identifier): + ret = self.DATA_CACHES["cache"].get(self._currentServerUUID, {}).get(context, {}).get(identifier, {}) + if "data" in ret and ret["data"]: + # purge old data (> X days last updated) + if ret["updated"] < time.time() - self.DC_LRUP_TIMEOUT * 3600 * 24: + del self.DATA_CACHES["cache"][self._currentServerUUID][context][identifier] + return None + + self.DATA_CACHES["cache"][self._currentServerUUID][context][identifier]["last_access"] = time.time() + return ret["data"] + + def setCacheData(self, context, identifier, value): + if self._currentServerUUID not in self.DATA_CACHES["cache"]: + self.DATA_CACHES["cache"][self._currentServerUUID] = {} + if context not in self.DATA_CACHES["cache"][self._currentServerUUID]: + self.DATA_CACHES["cache"][self._currentServerUUID][context] = {} + if identifier not in self.DATA_CACHES["cache"][self._currentServerUUID][context]: + self.DATA_CACHES["cache"][self._currentServerUUID][context][identifier] = {} + t = time.time() + self.DATA_CACHES["general"]["updated"] = t + self.DATA_CACHES["cache"][self._currentServerUUID][context][identifier] = { + "updated": t, + "last_access": t, + "data": value + } + + def setServerUUID(self, server=None, **kwargs): + if not server and not plexapp.SERVERMANAGER.selectedServer: + return + self._currentServerUUID = (server if server is not None else plexapp.SERVERMANAGER.selectedServer).uuid[-8:] + + def dataCacheCleanup(self): + d = copy.deepcopy(self.DATA_CACHES) + t = time.time() + for k, contexts in d["cache"].items(): + for context, identifiers in contexts.items(): + for identifier, iddata in identifiers.items(): + # clean up anything not accessed during the last X days + if iddata["last_access"] < t - self.DC_LRU_TIMEOUT * 3600 * 24: + DEBUG_LOG("Clearing cached data for: {}: {}".format(context, identifier)) + del self.DATA_CACHES["cache"][k][context][identifier] + + def storeDataCache(self): + lu = self.DATA_CACHES["general"].get("updated") + if self.DATA_CACHES and lu and self.DC_LAST_UPDATE != lu: + try: + dcf = xbmcvfs.File(self.DC_PATH, "w") + self.dataCacheCleanup() + d = json.dumps(self.DATA_CACHES) + if self.USE_GZ: + d = zlib.compress(d.encode("utf-8")) + dcf.write(d) + dcf.close() + LOG("Data cache written to: addon_data/script.plexmod/data_cache.json") + except: + ERROR("Couldn't write data_cache.json") + + +dcm = DataCacheManager() diff --git a/script.plexmod/lib/main.py b/script.plexmod/lib/main.py index 6285380f0..3a79cf751 100644 --- a/script.plexmod/lib/main.py +++ b/script.plexmod/lib/main.py @@ -19,6 +19,7 @@ from . import player from . import backgroundthread from . import util +from .data_cache import dcm BACKGROUND = None quitKodi = False @@ -170,6 +171,9 @@ def _main(): util.ERROR() finally: util.DEBUG_LOG('Main: SHUTTING DOWN...') + dcm.storeDataCache() + dcm.deinit() + plexapp.util.INTERFACE.playbackManager.deinit() background.setShutdown() player.shutdown() plexapp.util.APP.preShutdown() diff --git a/script.plexmod/lib/path_mapping.py b/script.plexmod/lib/path_mapping.py new file mode 100644 index 000000000..e6fe30919 --- /dev/null +++ b/script.plexmod/lib/path_mapping.py @@ -0,0 +1,123 @@ +# coding=utf-8 + +import os +import copy +import re +import json + +import plexnet.util + +from kodi_six import xbmcvfs + +from .util import translatePath, ADDON, ERROR, LOG, getSetting + + +PM_MCMT_RE = re.compile(r'/\*.+\*/\s?', re.IGNORECASE | re.MULTILINE | re.DOTALL) +PM_CMT_RE = re.compile(r'[\t ]+//.+\n?') +PM_COMMA_RE = re.compile(r',\s*}\s*}') + + +def norm_sep(s): + return "\\" in s and "\\" or "/" + + +class PathMappingManager(object): + mapfile = os.path.join(translatePath(ADDON.getAddonInfo("profile")), "path_mapping.json") + PATH_MAP = {} + + def __init__(self): + self.load() + + def load(self): + if xbmcvfs.exists(self.mapfile): + try: + f = xbmcvfs.File(self.mapfile) + # sanitize json + + # remove multiline comments + data = PM_MCMT_RE.sub("", f.read()) + # remove comments + data = PM_CMT_RE.sub("", data) + # remove invalid trailing comma + + data = PM_COMMA_RE.sub("}}", data) + self.PATH_MAP = json.loads(data) + f.close() + except: + ERROR("Couldn't read path_mapping.json") + else: + LOG("Path mapping: {}".format(repr(self.PATH_MAP))) + + @property + def mapping(self): + return self.PATH_MAP and getSetting("path_mapping", True) + + def getMappedPathFor(self, path, server): + if self.mapping: + match = ("", "") + + for map_path, pms_path in self.PATH_MAP.get(server.name, {}).items(): + # the longest matching path wins + if path.startswith(pms_path) and len(pms_path) > len(match[1]): + match = (map_path, pms_path) + + if all(match): + map_path, pms_path = match + return map_path, pms_path + return None, None + + def deletePathMapping(self, target, server=None, save=True): + server = server or plexnet.util.SERVERMANAGER.selectedServer + if not server: + ERROR("Delete path mapping: Something went wrong") + return + + if server.name not in self.PATH_MAP: + return + + pm = copy.deepcopy(self.PATH_MAP) + + deleted = None + for s, t in pm[server.name].items(): + if target == t: + deleted = s + del self.PATH_MAP[server.name][s] + break + if save and deleted and self.save(): + LOG("Path mapping stored after deletion of {}:{}".format(deleted, target)) + + def addPathMapping(self, source, target, server=None, save=True): + server = server or plexnet.util.SERVERMANAGER.selectedServer + if not server: + ERROR("Add path mapping: Something went wrong") + return + + if server.name not in self.PATH_MAP: + self.PATH_MAP[server.name] = {} + + sep = norm_sep(source) + + if not source.endswith(sep): + source += sep + + sep = norm_sep(target) + + if not target.endswith(sep): + target += sep + + self.PATH_MAP[server.name][source] = target + if save and self.save(): + LOG("Path mapping stored for {}:{}".format(source, target)) + + def save(self): + try: + f = xbmcvfs.File(self.mapfile, "w") + f.write(json.dumps(self.PATH_MAP)) + f.close() + except: + ERROR("Couldn't write path_mapping.json") + else: + return True + + +pmm = PathMappingManager() diff --git a/script.plexmod/lib/playback_utils.py b/script.plexmod/lib/playback_utils.py index 86b20a4b3..9cbf195f5 100644 --- a/script.plexmod/lib/playback_utils.py +++ b/script.plexmod/lib/playback_utils.py @@ -62,6 +62,11 @@ def __init__(self): plexapp.util.APP.on("change:user", lambda **kwargs: self.setUserID(**kwargs)) plexapp.util.APP.on('init', lambda **kwargs: self.setUserID(**kwargs)) + def deinit(self): + plexapp.util.APP.off('change:selectedServer', lambda **kwargs: self.setServerUUID(**kwargs)) + plexapp.util.APP.off("change:user", lambda **kwargs: self.setUserID(**kwargs)) + plexapp.util.APP.off('init', lambda **kwargs: self.setUserID(**kwargs)) + def __call__(self, obj, key=None, value=None, kv_dict=None): # shouldn't happen if not self._currentServerUUID or not self._currentUserID: diff --git a/script.plexmod/lib/player.py b/script.plexmod/lib/player.py index 65c443e18..2d4a2e52c 100644 --- a/script.plexmod/lib/player.py +++ b/script.plexmod/lib/player.py @@ -1,5 +1,6 @@ from __future__ import absolute_import import base64 +import json import threading import six import re @@ -419,11 +420,13 @@ def seekAbsolute(self, seek=None): def onAVChange(self): util.DEBUG_LOG('SeekHandler: onAVChange') + self.player.trigger('changed.video') if self.dialog: self.dialog.onAVChange() def onAVStarted(self): util.DEBUG_LOG('SeekHandler: onAVStarted') + self.player.trigger('started.video') if self.isDirectPlay: self.seekAbsolute() @@ -1220,28 +1223,86 @@ def _playVideo(self, offset=0, seeking=0, force_update=False, playerObject=None, util.setGlobalProperty("current_size", str(meta.size), base='videoinfo.{0}') imdbNum = None - if "com.plexapp.agents.imdb" in self.video.guid: - a = self.video.guid + + fill_trakt_ids = False + trakt_ids = {} + + # generate guids when script.trakt is installed + if "script.trakt" in util.USER_ADDONS: + fill_trakt_ids = True + + a = self.video.guid + if "com.plexapp.agents.imdb" in a: imdbNum = a.split("?lang=")[0][a.index("com.plexapp.agents.imdb://")+len("com.plexapp.agents.imdb://"):] - li.setInfo('video', { + if fill_trakt_ids: + if imdbNum: + trakt_ids["imdb"] = imdbNum + + elif fill_trakt_ids and "com.plexapp.agents.themoviedb" in a: + trakt_ids["tmdb"] = a.split("?lang=")[0][ + a.index("com.plexapp.agents.themoviedb://") + len("com.plexapp.agents.themoviedb://"):] + + elif fill_trakt_ids and "com.plexapp.agents.thetvdb" in a: + trakt_ids["tvdb"] = a.split("?lang=")[0][ + a.index("com.plexapp.agents.thetvdb://") + + len("com.plexapp.agents.thetvdb://"):].split("/", 1)[0] + + elif "plex://movie" in a or "plex://episode" in a: + ref = self.video + if fill_trakt_ids and "plex://episode" in a: + ref = self.video.show() + if not ref.isFullObject(): + ref.reload() + + for guid in ref.guids: + if not imdbNum and guid.id.startswith('imdb://'): + imdbNum = guid.id.split('imdb://')[1] + + if fill_trakt_ids: + sabbr, gid = guid.id.split("://") + try: + gid = int(gid) + except: + pass + + trakt_ids[sabbr] = gid + if fill_trakt_ids: + # generate trakt slug + if vtype == "movie": + year = self.video.year.asInt() + trakt_ids['slug'] = util.slugify("{}{}".format(self.video.title, year and " {}".format(year) or "")) + + util.DEBUG_LOG("Setting Trakt IDs: {}".format(trakt_ids)) + # report IDs to trakt + xbmcgui.Window(10000).setProperty('script.trakt.ids', json.dumps(trakt_ids)) + + info = { 'mediatype': vtype, 'title': self.video.title, 'originaltitle': self.video.title, 'tvshowtitle': self.video.grandparentTitle, - 'episode': vtype == "episode" and self.video.index.asInt() or '', - 'season': vtype == "episode" and self.video.parentIndex.asInt() or '', - #'year': self.video.year.asInt(), + 'year': self.video.year.asInt(), 'plot': self.video.summary, 'path': meta.path, 'size': meta.size, 'imdbnumber': imdbNum - }) + } + if vtype == "episode": + info.update({ + 'episode': self.video.index.asInt(), + 'season': self.video.parentIndex.asInt(), + }) + util.DEBUG_LOG("Setting VideoInfo: {}".format( + plexnetUtil.cleanObjTokens(info, flistkeys=[], fstrkeys=("path",)) + )) + li.setInfo('video', info) li.setArt({ 'poster': self.video.defaultThumb.asTranscodedImageURL(347, 518), 'fanart': self.video.defaultArt.asTranscodedImageURL(1920, 1080), 'thumb': self.video.defaultThumb.asTranscodedImageURL(256, 256), }) + self.trigger('starting.video') self.play(url, li) def playVideoPlaylist(self, playlist, resume=False, handler=None, session_id=None): @@ -1471,6 +1532,19 @@ def onPlayBackSeek(self, time, offset): return self.handler.onPlayBackSeek(time, offset) + def onPlayBackError(self): + if not self.sessionID: + return + util.DEBUG_LOG('Player - ERROR: {}'.format(self.handler)) + if not self.handler: + return + + if self.handler.onPlayBackFailed(): + self.ignoreStopEvents = True + util.showNotification('Playback Error!') + self.stopAndWait() + self.close() + def onPlayBackFailed(self): if not self.sessionID: return diff --git a/script.plexmod/lib/plex_hosts.py b/script.plexmod/lib/plex_hosts.py index 7a9a7ac00..758bfb7d7 100644 --- a/script.plexmod/lib/plex_hosts.py +++ b/script.plexmod/lib/plex_hosts.py @@ -7,10 +7,13 @@ import plexnet.http +from six import text_type + from lib import util from lib.advancedsettings import adv from plexnet.util import parsePlexDirectHost +from plexnet.plexconnection import DOCKER_NETWORK, IPv4Address HOSTS_RE = re.compile(r'\s*.*', re.S | re.I) HOST_RE = re.compile(r'(?P.+)') @@ -48,9 +51,14 @@ def newHosts(self, hosts, source="stored"): """ for address in hosts: parsed = urlparse(address) + ip = parsePlexDirectHost(parsed.hostname) + # ignore docker V4 hosts + if util.addonSettings.ignoreDockerV4 and ":" not in ip and IPv4Address(text_type(ip)) in DOCKER_NETWORK: + util.DEBUG_LOG("Ignoring plex.direct local Docker IPv4 address: {}".format(source, parsed.hostname)) + continue + if parsed.hostname not in self._hosts: - self._hosts[parsed.hostname] = plexnet.http.RESOLVED_PD_HOSTS.get(parsed.hostname, - parsePlexDirectHost(parsed.hostname)) + self._hosts[parsed.hostname] = plexnet.http.RESOLVED_PD_HOSTS.get(parsed.hostname, ip) util.LOG("Found new unmapped {} plex.direct host: {}".format(source, parsed.hostname)) @property diff --git a/script.plexmod/lib/util.py b/script.plexmod/lib/util.py index 6f4492640..6c5ea156d 100644 --- a/script.plexmod/lib/util.py +++ b/script.plexmod/lib/util.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import + import gc import sys import re @@ -10,12 +11,16 @@ import time import datetime import contextlib +import unicodedata + import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error import six import os import struct import requests +import plexnet.util + from .kodijsonrpc import rpc from kodi_six import xbmc from kodi_six import xbmcgui @@ -25,7 +30,7 @@ from . import colors # noinspection PyUnresolvedReferences from .exceptions import NoDataException -from plexnet import signalsmixin, plexapp +from plexnet import signalsmixin DEBUG = True _SHUTDOWN = False @@ -115,10 +120,10 @@ def getSetting(key, default=None): def getUserSetting(key, default=None): - if not plexapp.ACCOUNT: + if not plexnet.util.ACCOUNT: return default - key = '{}.{}'.format(key, plexapp.ACCOUNT.ID) + key = '{}.{}'.format(key, plexnet.util.ACCOUNT.ID) with SETTINGS_LOCK: setting = ADDON.getSetting(key) return _processSetting(setting, default) @@ -162,12 +167,11 @@ class AddonSettings(object): ("postplay_timeout", 16), ("skip_intro_button_timeout", 10), ("skip_credits_button_timeout", 10), - ("playlist_visit_media", True), + ("playlist_visit_media", False), ("intro_skip_early", False), ("show_media_ends_info", True), ("show_media_ends_label", True), ("background_colour", None), - ("oldprofile", False), ("skip_intro_button_show_early_threshold1", 60), ("requests_timeout", 5.0), ("local_reach_timeout", 10), @@ -188,7 +192,11 @@ class AddonSettings(object): ("consecutive_video_pb_wait", 0.0), ("retrieve_all_media_up_front", False), ("library_chunk_size", 240), - ("verify_mapped_files", True) + ("verify_mapped_files", True), + ("episode_no_spoiler_blur", 16), + ("ignore_docker_v4", True), + ("cache_home_users", True), + ("intro_marker_max_offset", 600), ) def __init__(self): @@ -294,8 +302,13 @@ def onNotification(self, sender, method, data): setGlobalProperty('stop_running', '1') return - elif sender == "xbmc" and method == "System.OnSleep" and getSetting('action_on_sleep', "none") != "none": - getattr(self, "action{}".format(getSetting('action_on_sleep', "none").capitalize()))() + elif sender == "xbmc" and method == "System.OnSleep": + if getSetting('action_on_sleep', "none") != "none": + getattr(self, "action{}".format(getSetting('action_on_sleep', "none").capitalize()))() + self.trigger('system.sleep') + + elif sender == "xbmc" and method == "System.OnWake": + self.trigger('system.wakeup') def stopPlayback(self): LOG('Monitor: Stopping media playback') @@ -303,11 +316,22 @@ def stopPlayback(self): def onScreensaverActivated(self): DEBUG_LOG("Monitor: OnScreensaverActivated") + self.trigger('screensaver.activated') if getSetting('player_stop_on_screensaver', True) and xbmc.Player().isPlayingVideo(): self.stopPlayback() + def onScreensaverDeactivated(self): + DEBUG_LOG("Monitor: OnScreensaverDeactivated") + self.trigger('screensaver.deactivated') + def onDPMSActivated(self): DEBUG_LOG("Monitor: OnDPMSActivated") + self.trigger('dpms.activated') + #self.stopPlayback() + + def onDPMSDeactivated(self): + DEBUG_LOG("Monitor: OnDPMSDeactivated") + self.trigger('dpms.deactivated') #self.stopPlayback() def onSettingsChanged(self): @@ -513,6 +537,9 @@ def scaleResolution(w, h, by=None): return w, h +SPOILER_ALLOWED_GENRES = ("Reality", "Game Show", "Documentary", "Sport") + + class TextBox: # constants WINDOW = 10147 @@ -790,7 +817,7 @@ def getTimeFormat(): timeFormat, timeFormatKN, padHour = getTimeFormat() DEF_THEME = "modern-colored" -THEME_VERSION = 2 +THEME_VERSION = 3 def applyTheme(theme=None): @@ -860,31 +887,26 @@ def applyTheme(theme=None): "script-plex-seek_dialog.xml")): applyTheme(theme) -PM_MCMT_RE = re.compile(r'/\*.+\*/\s?', re.IGNORECASE | re.MULTILINE | re.DOTALL) -PM_CMT_RE = re.compile(r'[\t ]+//.+\n?') -PM_COMMA_RE = re.compile(r',\s*}\s*}') -# path mapping -mapfile = os.path.join(translatePath(ADDON.getAddonInfo("profile")), "path_mapping.json") -PATH_MAP = None -if xbmcvfs.exists(mapfile): - try: - f = xbmcvfs.File(mapfile) - # sanitize json +# get mounts +KODI_SOURCES = [] - # remove multiline comments - data = PM_MCMT_RE.sub("", f.read()) - # remove comments - data = PM_CMT_RE.sub("", data) - # remove invalid trailing comma - data = PM_COMMA_RE.sub("}}", data) - PATH_MAP = json.loads(data) - f.close() +def getKodiSources(): + try: + data = rpc.Files.GetSources(media="files")["sources"] except: - ERROR("Couldn't read path_mapping.json") + LOG("Couldn't parse Kodi sources") else: - LOG("Path mapping: {}".format(repr(PATH_MAP))) + for d in data: + f = d["file"] + if f.startswith("smb://") or f.startswith("nfs://") or f.startswith("/") or ':\\\\' in f: + KODI_SOURCES.append(d) + LOG("Parsed {} Kodi sources: {}".format(len(KODI_SOURCES), KODI_SOURCES)) + + +if getSetting('path_mapping', True): + getKodiSources() def populateTimeFormat(): @@ -907,6 +929,38 @@ def getPlatform(): return key.rsplit('.', 1)[-1] +def getRunningAddons(): + try: + return xbmcvfs.listdir('addons://running/')[1] + except: + return [] + + +def getUserAddons(): + try: + return xbmcvfs.listdir('addons://user/all')[1] + except: + return [] + + +USER_ADDONS = getUserAddons() + + +SLUGIFY_RE1 = re.compile(r'[^\w\s-]') +SLUGIFY_RE2 = re.compile(r'[-\s]+') + + +def slugify(value): + """ + Converts to lowercase, removes non-word characters (alphanumerics and + underscores) and converts spaces to hyphens. Also strips leading and + trailing whitespace. + """ + value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii') + value = SLUGIFY_RE1.sub('', value).strip().lower() + return SLUGIFY_RE2.sub('-', value) + + def getProgressImage(obj, perc=None, view_offset=None): if not obj and not perc: return '' diff --git a/script.plexmod/lib/windows/__init__.py b/script.plexmod/lib/windows/__init__.py index f96b69008..90112572d 100644 --- a/script.plexmod/lib/windows/__init__.py +++ b/script.plexmod/lib/windows/__init__.py @@ -1,5 +1,6 @@ from __future__ import absolute_import -from . import kodigui + from lib import util +from . import kodigui kodigui.MONITOR = util.MONITOR diff --git a/script.plexmod/lib/windows/background.py b/script.plexmod/lib/windows/background.py index 8940d1c6b..58ad8cbb0 100644 --- a/script.plexmod/lib/windows/background.py +++ b/script.plexmod/lib/windows/background.py @@ -1,6 +1,7 @@ from __future__ import absolute_import -from . import kodigui + from lib import util +from . import kodigui util.setGlobalProperty('background.busy', '') util.setGlobalProperty('background.shutdown', '') diff --git a/script.plexmod/lib/windows/busy.py b/script.plexmod/lib/windows/busy.py index dd8e3ef06..edc992199 100644 --- a/script.plexmod/lib/windows/busy.py +++ b/script.plexmod/lib/windows/busy.py @@ -1,9 +1,12 @@ from __future__ import absolute_import -from . import kodigui -from lib import util -from kodi_six import xbmcgui + import threading +from kodi_six import xbmcgui + +from lib import util +from . import kodigui + class BusyWindow(kodigui.BaseDialog): xmlFile = 'script-plex-busy.xml' diff --git a/script.plexmod/lib/windows/currentplaylist.py b/script.plexmod/lib/windows/currentplaylist.py index 4a278cda7..9f9d23958 100644 --- a/script.plexmod/lib/windows/currentplaylist.py +++ b/script.plexmod/lib/windows/currentplaylist.py @@ -1,18 +1,17 @@ from __future__ import absolute_import + from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui +from lib import kodijsonrpc +from lib import player +from lib import util +from lib.util import T from . import busy -from . import windowutils from . import dropdown +from . import kodigui from . import opener - -from lib import util -from lib import player -from lib import kodijsonrpc - -from lib.util import T +from . import windowutils class CurrentPlaylistWindow(kodigui.ControlledWindow, windowutils.UtilMixin): @@ -65,8 +64,19 @@ def doClose(self, **kwargs): player.PLAYER.off('playlist.changed', self.playQueueCallback) if player.PLAYER.handler.playQueue and player.PLAYER.handler.playQueue.isRemote: player.PLAYER.handler.playQueue.off('change', self.updateProperties) + self.commonDeinit() kodigui.ControlledWindow.doClose(self) + def commonInit(self): + player.PLAYER.on('starting.audio', self.onAudioStarting) + player.PLAYER.on('started.audio', self.onAudioStarted) + player.PLAYER.on('changed.audio', self.onAudioChanged) + + def commonDeinit(self): + player.PLAYER.off('starting.audio', self.onAudioStarting) + player.PLAYER.off('started.audio', self.onAudioStarted) + player.PLAYER.off('changed.audio', self.onAudioChanged) + def onFirstInit(self): self.playlistListControl = kodigui.ManagedControlList(self, self.PLAYLIST_LIST_ID, 9) self.setupSeekbar() @@ -74,7 +84,7 @@ def onFirstInit(self): self.fillPlaylist() self.selectPlayingItem() self.setFocusId(self.PLAYLIST_LIST_ID) - + self.commonInit() self.updateProperties() if player.PLAYER.handler.playQueue and player.PLAYER.handler.playQueue.isRemote: player.PLAYER.handler.playQueue.on('change', self.updateProperties) @@ -125,6 +135,18 @@ def onFocus(self, controlID): def onPlayBackStarted(self, **kwargs): self.setDuration() + def onAudioStarting(self, *args, **kwargs): + util.setGlobalProperty('ignore_spinner', '1') + self.ignoreStopCommands = True + + def onAudioStarted(self, *args, **kwargs): + util.setGlobalProperty('ignore_spinner', '') + self.ignoreStopCommands = False + + def onAudioChanged(self, *args, **kwargs): + util.setGlobalProperty('ignore_spinner', '') + self.ignoreStopCommands = False + def repeatButtonClicked(self): if player.PLAYER.handler.playQueue and player.PLAYER.handler.playQueue.isRemote: if xbmc.getCondVisibility('Playlist.IsRepeatOne'): @@ -217,6 +239,7 @@ def playlistListClicked(self): mli = self.playlistListControl.getSelectedItem() if not mli: return + self.onAudioStarting() player.PLAYER.playselected(mli.pos()) def createListItem(self, pi, idx): diff --git a/script.plexmod/lib/windows/dropdown.py b/script.plexmod/lib/windows/dropdown.py index aefb7f0e1..0bcae6e03 100644 --- a/script.plexmod/lib/windows/dropdown.py +++ b/script.plexmod/lib/windows/dropdown.py @@ -1,8 +1,9 @@ from __future__ import absolute_import -from kodi_six import xbmc, xbmcgui -from . import kodigui + +from kodi_six import xbmcgui from lib import util +from . import kodigui SEPARATOR = None diff --git a/script.plexmod/lib/windows/episodes.py b/script.plexmod/lib/windows/episodes.py index 20ce0e44e..c1c594f38 100644 --- a/script.plexmod/lib/windows/episodes.py +++ b/script.plexmod/lib/windows/episodes.py @@ -3,29 +3,26 @@ import requests.exceptions from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui +from plexnet import plexapp, playlist, plexplayer -from lib import util from lib import backgroundthread from lib import metadata from lib import player - -from plexnet import plexapp, playlist, plexplayer - +from lib import util +from lib.util import T from . import busy -from . import videoplayer from . import dropdown -from . import windowutils -from . import opener -from . import search -from . import playersettings from . import info +from . import kodigui +from . import opener from . import optionsdialog from . import pagination from . import playbacksettings - -from lib.util import T -from .mixins import SeasonsMixin, RatingsMixin +from . import playersettings +from . import search +from . import videoplayer +from . import windowutils +from .mixins import SeasonsMixin, RatingsMixin, SpoilersMixin VIDEO_RELOAD_KW = dict(includeExtras=1, includeExtrasCount=10, includeChapters=1) @@ -73,8 +70,10 @@ def createListItem(self, data): return mli def prepareListItem(self, data, mli): + mli.setBoolProperty('watched', mli.dataSource.isFullyWatched) if not mli.dataSource.isWatched: mli.setProperty('unwatched.count', str(mli.dataSource.unViewedLeafCount)) + mli.setProperty('unwatched', '1') mli.setProperty('progress', util.getProgressImage(mli.dataSource)) def setEpisode(self, ep): @@ -172,7 +171,7 @@ def getData(self, offset, amount): return self.parentWindow.show_.getRelated(offset=offset, limit=amount) -class EpisodesWindow(kodigui.ControlledWindow, windowutils.UtilMixin, SeasonsMixin, RatingsMixin, +class EpisodesWindow(kodigui.ControlledWindow, windowutils.UtilMixin, SeasonsMixin, RatingsMixin, SpoilersMixin, playbacksettings.PlaybackSettingsMixin): xmlFile = 'script-plex-episodes.xml' path = util.ADDON.getAddonInfo('path') @@ -216,25 +215,16 @@ class EpisodesWindow(kodigui.ControlledWindow, windowutils.UtilMixin, SeasonsMix def __init__(self, *args, **kwargs): kodigui.ControlledWindow.__init__(self, *args, **kwargs) windowutils.UtilMixin.__init__(self) + SpoilersMixin.__init__(self, *args, **kwargs) self.episode = None self.reset(kwargs.get('episode'), kwargs.get('season'), kwargs.get('show')) - self.initialEpisode = kwargs.get('episode') self.parentList = kwargs.get('parentList') - self.lastItem = None - self.lastFocusID = None - self.lastNonOptionsFocusID = None - self.episodesPaginator = None - self.relatedPaginator = None self.cameFrom = kwargs.get('came_from') self.tasks = backgroundthread.Tasks() - self.initialized = False - self.currentItemLoaded = False - self.closing = False - self.manuallySelected = False - self._videoProgress = None def reset(self, episode, season=None, show=None): self.episode = episode + self.initialEpisode = episode self.season = season if season is not None else self.episode.season() try: self.show_ = show or (self.episode or self.season).show().reload(includeExtras=1, includeExtrasCount=10, @@ -242,11 +232,19 @@ def reset(self, episode, season=None, show=None): except IndexError: raise util.NoDataException + self.initialized = False + self.closing = False self.parentList = None + self.episodesPaginator = None + self.relatedPaginator = None self.seasons = None self.manuallySelected = False + self.currentItemLoaded = False + self.lastItem = None + self.lastFocusID = None + self.lastNonOptionsFocusID = None self._videoProgress = None - #self.initialized = False + self.openedWithAutoPlay = False def doClose(self): self.closing = True @@ -272,23 +270,31 @@ def _onFirstInit(self): self.extraListControl = kodigui.ManagedControlList(self, self.EXTRA_LIST_ID, 5) self.relatedListControl = kodigui.ManagedControlList(self, self.RELATED_LIST_ID, 5) + if not self.openedWithAutoPlay: + # we may have set up the hooks before + self._setup_hooks() self._setup() self.postSetup() def doAutoPlay(self): # First reload the video to get all the other info self.initialEpisode.reload(checkFiles=1, **VIDEO_RELOAD_KW) + + # We're not hitting onFirstInit when autoplaying from home, setup hooks here, so we can grab video progress + self._setup_hooks() + self.openedWithAutoPlay = True return self.playButtonClicked(force_episode=self.initialEpisode, from_auto_play=True) def onFirstInit(self): self._onFirstInit() if self.show_ and self.show_.theme and not util.getSetting("slow_connection", False) and \ - (not self.cameFrom or self.cameFrom != self.show_.ratingKey): + (not self.cameFrom or self.cameFrom != self.show_.ratingKey) and not self.openedWithAutoPlay: volume = self.show_.settings.getThemeMusicValue() if volume > 0: player.PLAYER.playBackgroundMusic(self.show_.theme.asURL(True), volume, self.show_.ratingKey) + self.openedWithAutoPlay = False @busy.dialog() def onReInit(self): @@ -304,10 +310,19 @@ def onReInit(self): util.DEBUG_LOG("Episodes: {}: Got progress info: {}".format( self.episode and self.episode.ratingKey or None, self._videoProgress)) try: - self.selectEpisode(progress_data=self._videoProgress) + redirect = self.selectEpisode(progress_data=self._videoProgress) except AttributeError: raise util.NoDataException + if redirect: + util.DEBUG_LOG("Got episode progress for a different season, redirecting") + self.episodeListControl.reset() + self.relatedListControl.reset() + self.reset(episode=redirect) + self._setup() + self.postSetup() + return + mli = self.episodeListControl.getSelectedItem() if not mli or not self.episodesPaginator: return @@ -353,9 +368,11 @@ def postSetup(self): def setup(self): self._setup() - def _setup(self): + def _setup_hooks(self): player.PLAYER.on('new.video', self.onNewVideo) player.PLAYER.on('video.progress', self.onVideoProgress) + + def _setup(self): (self.season or self.show_).reload(checkFiles=1, **VIDEO_RELOAD_KW) if not self.episodesPaginator: @@ -401,12 +418,21 @@ def selectEpisode(self, progress_data=None): # progress can be False (no entry), a number (progress), or True (fully watched just now) # select it if it's not watched or in progress if progress is True: + # ep was just watched just_fully_watched = True mli.setProperty('unwatched', '') + mli.setProperty('watched', '1') mli.setProperty('progress', '') + mli.setProperty('unwatched.count', '') + mli.dataSource.set('viewCount', 1) + self.setUserItemInfo(mli, fully_watched=True) elif progress and progress > 60000: + # ep has progress + mli.setProperty('watched', '') mli.setProperty('progress', util.getProgressImage(mli.dataSource, view_offset=progress)) + mli.dataSource.set('viewOffset', progress) + self.setUserItemInfo(mli, watched=True) set_main_progress_to = progress # after immediately updating the watched state, if we still have data left, continue @@ -437,6 +463,13 @@ def selectEpisode(self, progress_data=None): mli = self.episodeListControl.getSelectedItem() self.setProgress(mli, view_offset=0) + if progress_data_left: + # we've probably watched something in the next season + key = '/library/metadata/{0}'.format(list(progress_data_left.keys())[-1]) + ep = plexapp.SERVERMANAGER.selectedServer.getObject(key) + if ep.parentIndex != self.show_.parentIndex: + return ep + self.episode = None def onAction(self, action): @@ -773,17 +806,21 @@ def infoButtonClicked(self): episode = mli.dataSource if episode.index: - subtitle = u'{0} {1} {2} {3}'.format(T(32303, 'Season'), episode.parentIndex, T(32304, 'Episode'), episode.index) + subtitle = u'{0} {1}'.format(T(32303, 'Season').format(episode.parentIndex), + T(32304, 'Episode').format(episode.index)) else: subtitle = episode.originallyAvailableAt.asDatetime('%B %d, %Y') + hide_spoilers = self.hideSpoilers(episode) + opener.handleOpen( info.InfoWindow, - title=episode.title, + title=hide_spoilers and self.noTitles and T(33008, '') or episode.title, sub_title=subtitle, thumb=episode.thumb, + thumb_opts=self.getThumbnailOpts(episode, hide_spoilers=hide_spoilers), thumb_fallback='script.plex/thumb_fallbacks/show.png', - info=episode.summary, + info=hide_spoilers and T(33008, '') or episode.summary, background=self.getProperty('background'), is_16x9=True, video=episode @@ -828,7 +865,12 @@ def episodeListClicked(self, force_episode=None, from_auto_play=False): pl = playlist.LocalPlaylist(self.show_.all(), self.show_.getServer()) try: - if len(pl): # Don't use playlist if it's only this video + # inject our show in case we need to access show metadata from the player + episode._show = self.show_ + if len(pl) > 1: # Don't use playlist if it's only this video + for ep in pl: + ep._show = self.show_ + pl.setCurrent(episode) self.processCommand(videoplayer.play(play_queue=pl, resume=resume)) return True @@ -922,7 +964,7 @@ def optionsButtonClicked(self, from_item=False): elif choice['key'] == 'to_section': self.goHome(self.show_.getLibrarySectionId()) elif choice['key'] == 'delete': - self.delete() + self.delete(mli.dataSource) elif choice['key'] == 'playback_settings': self.playbackSettings(self.show_, pos, bottom) @@ -946,10 +988,11 @@ def mediaButtonClicked(self): choice['key'].set('selected', 1) self.setPostReloadItemInfo(ds, mli) - def delete(self): + def delete(self, item): button = optionsdialog.show( T(32326, 'Really delete?'), - T(32327, 'Are you sure you really want to delete this media?'), + T(33036, "Delete episode S{0:02d}E{1:02d} from {2}?").format(item.parentIndex.asInt(), + item.index.asInt(), item.defaultTitle), T(32328, 'Yes'), T(32329, 'No') ) @@ -1027,8 +1070,10 @@ def updateProperties(self): self.setProperty('season.title', (self.season or self.show_).title) if self.season: - self.setProperty('episodes.header', u'{0} \u2022 {1} {2}'.format(showTitle, T(32303, 'Season'), self.season.index)) - self.setProperty('extras.header', u'{0} \u2022 {1} {2}'.format(T(32305, 'Extras'), T(32303, 'Season'), self.season.index)) + self.setProperty('episodes.header', u'{0} \u2022 {1}'.format(showTitle, + T(32303, 'Season').format(self.season.index))) + self.setProperty('extras.header', u'{0} \u2022 {1}'.format(T(32305, 'Extras'), + T(32303, 'Season').format(self.season.index))) else: self.setProperty('episodes.header', u'Episodes') self.setProperty('extras.header', u'Extras') @@ -1042,27 +1087,73 @@ def updateProperties(self): def updateItems(self, item=None): if item: item.setProperty('unwatched', not item.dataSource.isWatched and '1' or '') + item.setProperty('watched', item.dataSource.isFullyWatched and '1' or '') self.setProgress(item) item.setProperty('progress', util.getProgressImage(item.dataSource)) (self.season or self.show_).reload() + + self.setUserItemInfo(item) else: self.fillEpisodes(update=True) if self.episode: self.episode.reload() + def setUserItemInfo(self, mli, video=None, types=("title", "thumbnail", "summary"), watched=None, + fully_watched=None, hide_spoilers=None): + video = video or mli.dataSource + + properties = {} + methods = [] + if self.noSpoilers == "off" and not hide_spoilers: + # no special handling + if "title" in types: + properties["title"] = video.title + methods.append(("setLabel", video.title)) + if "summary" in types: + properties["summary"] = video.summary.strip().replace('\t', ' ') + + if "thumbnail" in types: + methods.append(("setThumbnailImage", video.thumb.asTranscodedImageURL(*self.THUMB_AR16X9_DIM))) + + else: + hide_spoilers = hide_spoilers if hide_spoilers is not None else \ + self.hideSpoilers(video, fully_watched=fully_watched, watched=watched) + hide_title = hide_spoilers and self.noTitles + if "title" in types: + tit = hide_title and T(33008, '') or video.title + properties["title"] = tit + methods.append(("setLabel", tit)) + + if "summary" in types: + properties["summary"] = hide_spoilers and T(33008, '') or video.summary.strip().replace('\t', ' ') + + if "thumbnail" in types: + methods.append(("setThumbnailImage", + video.thumb.asTranscodedImageURL( + *self.THUMB_AR16X9_DIM, + **self.getThumbnailOpts(video, fully_watched=fully_watched, watched=watched, + hide_spoilers=hide_spoilers) + ) + )) + + for property, value in properties.items(): + mli.setProperty(property, value) + + for method, value in methods: + getattr(mli, method)(value) + def setItemInfo(self, video, mli): # video.reload(checkFiles=1) mli.setProperty('background', util.backgroundFromArt(video.art, width=self.width, height=self.height)) - mli.setProperty('title', video.title) mli.setProperty('show.title', video.grandparentTitle or (self.show_.title if self.show_ else '')) mli.setProperty('duration', util.durationToText(video.duration.asInt())) - mli.setProperty('summary', video.summary.strip().replace('\t', ' ')) mli.setProperty('video.rendering', video.videoCodecRendering) + self.setUserItemInfo(mli, video, types=("title", "summary")) if video.index: - mli.setProperty('season', u'{0} {1}'.format(T(32303, 'Season'), video.parentIndex)) - mli.setProperty('episode', u'{0} {1}'.format(T(32304, 'Episode'), video.index)) + mli.setProperty('season', T(32303, 'Season').format(video.parentIndex)) + mli.setProperty('episode', T(32304, 'Episode').format(video.index)) else: mli.setProperty('season', '') mli.setProperty('episode', '') @@ -1079,6 +1170,7 @@ def setItemInfo(self, video, mli): def setPostReloadItemInfo(self, video, mli): self.setItemAudioAndSubtitleInfo(video, mli) mli.setProperty('unwatched', not video.isWatched and '1' or '') + mli.setProperty('watched', video.isFullyWatched and '1' or '') mli.setProperty('video.res', video.resolutionString()) mli.setProperty('audio.codec', video.audioCodecString()) mli.setProperty('video.codec', video.videoCodecString()) @@ -1141,26 +1233,28 @@ def setProgress(self, mli, view_offset=None): def createListItem(self, episode): if episode.index: - subtitle = u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), episode.parentIndex, T(32311, 'E'), episode.index) + subtitle = u'{0} \u2022 {1}'.format(T(32310, 'S').format(episode.parentIndex), + T(32311, 'E').format(episode.index)) else: subtitle = episode.originallyAvailableAt.asDatetime('%m/%d/%y') mli = kodigui.ManagedListItem( - episode.title, + '', subtitle, - thumbnailImage=episode.thumb.asTranscodedImageURL(*self.THUMB_AR16X9_DIM), data_source=episode ) + self.setUserItemInfo(mli, types=("title", "thumbnail")) mli.setProperty('episode.number', str(episode.index) or '') mli.setProperty('episode.duration', util.durationToText(episode.duration.asInt())) mli.setProperty('unwatched', not episode.isWatched and '1' or '') + mli.setProperty('watched', episode.isFullyWatched and '1' or '') # mli.setProperty('progress', util.getProgressImage(obj)) return mli def fillEpisodes(self, update=False): items = self.episodesPaginator.paginate() if not update: - self.selectEpisode() + self.selectEpisode(progress_data=self._videoProgress) self.reloadItems(items, with_progress=True) def reloadItems(self, items, with_progress=False, skip_progress_for=None): diff --git a/script.plexmod/lib/windows/home.py b/script.plexmod/lib/windows/home.py index 7724205d1..ff9b413d1 100644 --- a/script.plexmod/lib/windows/home.py +++ b/script.plexmod/lib/windows/home.py @@ -1,28 +1,31 @@ from __future__ import absolute_import -import time + +import json import threading +import time +import math +import plexnet from kodi_six import xbmc from kodi_six import xbmcgui +from plexnet import plexapp +from six.moves import range -from . import kodigui -from lib import util from lib import backgroundthread from lib import player - -import plexnet -from plexnet import plexapp - -from . import windowutils -from . import playlists +from lib import util +from lib.path_mapping import pmm +from lib.plex_hosts import pdm +from lib.util import T from . import busy +from . import dropdown +from . import kodigui from . import opener -from . import search from . import optionsdialog - -from lib.util import T -from lib.plex_hosts import pdm -from six.moves import range +from . import playlists +from . import search +from . import windowutils +from .mixins import SpoilersMixin HUBS_REFRESH_INTERVAL = 300 # 5 Minutes HUB_PAGE_SIZE = 10 @@ -47,13 +50,17 @@ class HubsList(list): def init(self): self.lastUpdated = time.time() + self.invalid = False return self class SectionHubsTask(backgroundthread.Task): - def setup(self, section, callback): + def setup(self, section, callback, section_keys=None, ignore_hubs=None, reselect_pos_dict=None): self.section = section self.callback = callback + self.section_keys = section_keys + self.ignore_hubs = ignore_hubs + self.reselect_pos_dict = reselect_pos_dict return self def run(self): @@ -65,16 +72,23 @@ def run(self): return try: - hubs = HubsList(plexapp.SERVERMANAGER.selectedServer.hubs(self.section.key, count=HUB_PAGE_SIZE)).init() + hubs = HubsList(plexapp.SERVERMANAGER.selectedServer.hubs(self.section.key, count=HUB_PAGE_SIZE, + section_ids=self.section_keys, + ignore_hubs=self.ignore_hubs)).init() if self.isCanceled(): return - self.callback(self.section, hubs) + self.callback(self.section, hubs, reselect_pos_dict=self.reselect_pos_dict) except plexnet.exceptions.BadRequest: util.DEBUG_LOG('404 on section: {0}'.format(repr(self.section.title))) - self.callback(self.section, False) - except TypeError: + hubs = HubsList().init() + hubs.invalid = True + self.callback(self.section, hubs) + except: util.ERROR("No data - disconnected?", notify=True, time_ms=5000) - self.cancel() + util.DEBUG_LOG('Generic exception when fetching section: {0}'.format(repr(self.section.title))) + hubs = HubsList().init() + hubs.invalid = True + self.callback(self.section, hubs) class UpdateHubTask(backgroundthread.Task): @@ -97,14 +111,20 @@ def run(self): return self.callback(self.hub) except plexnet.exceptions.BadRequest: - util.DEBUG_LOG('404 on section: {0}'.format(repr(self.section.title))) + util.DEBUG_LOG('404 on hub: {0}'.format(repr(self.hub.hubIdentifier))) + except util.NoDataException: + util.ERROR("No data - disconnected?", notify=True, time_ms=5000) + except: + util.DEBUG_LOG('Something went wrong when updating hub: {0}'.format(repr(self.hub.hubIdentifier))) class ExtendHubTask(backgroundthread.Task): - def setup(self, hub, callback, canceledCallback=None): + def setup(self, hub, callback, canceledCallback=None, size=HUB_PAGE_SIZE, reselect_pos=None): self.hub = hub self.callback = callback self.canceledCallback = canceledCallback + self.size = size + self.reselect_pos = reselect_pos return self def run(self): @@ -119,16 +139,20 @@ def run(self): try: start = self.hub.offset.asInt() + self.hub.size.asInt() - items = self.hub.extend(start=start, size=HUB_PAGE_SIZE) + items = self.hub.extend(start=start, size=self.size) if self.isCanceled(): if self.canceledCallback: self.canceledCallback(self.hub) return - self.callback(self.hub, items) + self.callback(self.hub, items, reselect_pos=self.reselect_pos) except plexnet.exceptions.BadRequest: util.DEBUG_LOG('404 on hub: {0}'.format(repr(self.hub.hubIdentifier))) if self.canceledCallback: self.canceledCallback(self.hub) + except util.NoDataException: + util.ERROR("No data - disconnected?", notify=True, time_ms=5000) + except: + util.DEBUG_LOG('Something went wrong when extending hub: {0}'.format(repr(self.hub.hubIdentifier))) class HomeSection(object): @@ -136,12 +160,24 @@ class HomeSection(object): type = 'home' title = T(32332, 'Home') + locations = [] + isMapped = False + + +home_section = HomeSection() + class PlaylistsSection(object): key = 'playlists' type = 'playlists' title = T(32333, 'Playlists') + locations = [] + isMapped = False + + +playlists_section = PlaylistsSection() + class ServerListItem(kodigui.ManagedListItem): uuid = None @@ -229,7 +265,7 @@ def onDestroy(self): self.unHookSignals() -class HomeWindow(kodigui.BaseWindow, util.CronReceiver): +class HomeWindow(kodigui.BaseWindow, util.CronReceiver, SpoilersMixin): xmlFile = 'script-plex-home.xml' path = util.ADDON.getAddonInfo('path') theme = 'Main' @@ -348,7 +384,8 @@ class HomeWindow(kodigui.BaseWindow, util.CronReceiver): def __init__(self, *args, **kwargs): kodigui.BaseWindow.__init__(self, *args, **kwargs) - self.lastSection = HomeSection + SpoilersMixin.__init__(self, *args, **kwargs) + self.lastSection = home_section self.tasks = [] self.closeOption = None self.hubControls = None @@ -357,12 +394,19 @@ def __init__(self, *args, **kwargs): self.sectionChangeTimeout = 0 self.lastFocusID = None self.lastNonOptionsFocusID = None - self._lastSelectedItem = None self.sectionHubs = {} self.updateHubs = {} self.changingServer = False self._shuttingDown = False self._skipNextAction = False + self._reloadOnReinit = False + self._ignoreTick = False + self.librarySettings = None + self.hubSettings = None + self.anyLibraryHidden = False + self.wantedSections = None + self.movingSection = False + self.lastSelectedSectionPos = None windowutils.HOME = self self.lock = threading.Lock() @@ -427,8 +471,12 @@ def onFirstInit(self): self.checkPlexDirectHosts(plexapp.SERVERMANAGER.allConnections, source="stored") def onReInit(self): + if self._reloadOnReinit: + self.serverRefresh() + self._reloadOnReinit = False + if self.lastFocusID: - # try focusing the last focused ID. if that's a hub and it's empty (=not focusable), try focusing the + # try focusing the last focused ID. if that's a hub, and it's empty (=not focusable), try focusing the # next best hub if 399 < self.lastFocusID < 500: hubControlIndex = self.lastFocusID - 400 @@ -442,7 +490,8 @@ def onReInit(self): self.focusFirstValidHub(hubControlIndex) else: - self.setFocusId(self.lastFocusID) + if self.getFocusId() != self.lastFocusID: + self.setFocusId(self.lastFocusID) def checkPlexDirectHosts(self, hosts, source="stored", *args, **kwargs): handlePD = util.getSetting('handle_plexdirect', 'ask') @@ -494,6 +543,54 @@ def checkPlexDirectHosts(self, hosts, source="stored", *args, **kwargs): # be less intrusive util.showNotification(T(32996, ''), header=T(32995, '')) + def loadLibrarySettings(self): + setting_key = 'home.settings.{}.{}'.format(plexapp.SERVERMANAGER.selectedServer.uuid[-8:], plexapp.ACCOUNT.ID) + data = util.getSetting(setting_key, '') + self.librarySettings = {} + try: + self.librarySettings = json.loads(data) + except ValueError: + pass + except: + util.ERROR() + + def saveLibrarySettings(self): + if self.librarySettings: + setting_key = 'home.settings.{}.{}'.format(plexapp.SERVERMANAGER.selectedServer.uuid[-8:], + plexapp.ACCOUNT.ID) + util.setSetting(setting_key, json.dumps(self.librarySettings)) + + def loadHubSettings(self): + setting_key = 'hub.settings.{}.{}'.format(plexapp.SERVERMANAGER.selectedServer.uuid[-8:], plexapp.ACCOUNT.ID) + data = util.getSetting(setting_key, '') + self.hubSettings = {} + try: + self.hubSettings = json.loads(data) + except ValueError: + pass + except: + util.ERROR() + + def saveHubSettings(self): + if self.hubSettings: + setting_key = 'hub.settings.{}.{}'.format(plexapp.SERVERMANAGER.selectedServer.uuid[-8:], + plexapp.ACCOUNT.ID) + util.setSetting(setting_key, json.dumps(self.hubSettings)) + + @property + def currentHub(self): + hub_focus = int(self.getProperty('hub.focus')) + if len(self.hubControls) > hub_focus and self.hubControls[hub_focus]: + hub_control = self.hubControls[hub_focus] + hub = hub_control.dataSource + if not hub or hub.hubIdentifier == "home.continue": + return + return hub + + @property + def ignoredHubs(self): + return [combo for combo, data in self.hubSettings.items() if not data.get("show", True)] + def updateProperties(self, *args, **kwargs): self.setBoolProperty('bifurcation_lines', util.getSetting('hubs_bifurcation_lines', False)) @@ -537,11 +634,20 @@ def hookSignals(self): plexapp.util.APP.on('account:response', self.displayServerAndUser) plexapp.util.APP.on('sli:reachability:received', self.displayServerAndUser) plexapp.util.APP.on('change:hubs_bifurcation_lines', self.updateProperties) - plexapp.util.APP.on('change:hubs_use_new_continue_watching', self.fullyRefreshHome) + plexapp.util.APP.on('change:no_episode_spoilers2', self.setDirty) + plexapp.util.APP.on('change:no_unwatched_episode_titles', self.setDirty) + plexapp.util.APP.on('change:spoilers_allowed_genres', self.setDirty) + plexapp.util.APP.on('change:hubs_use_new_continue_watching', self.setDirty) + plexapp.util.APP.on('change:use_alt_watched', self.setDirty) + plexapp.util.APP.on('change:hide_aw_bg', self.setDirty) plexapp.util.APP.on('change:theme', self.setTheme) player.PLAYER.on('session.ended', self.updateOnDeckHubs) util.MONITOR.on('changed.watchstatus', self.updateOnDeckHubs) + util.MONITOR.on('screensaver.deactivated', self.refreshLastSection) + util.MONITOR.on('dpms.deactivated', self.refreshLastSection) + util.MONITOR.on('system.sleep', self.disableUpdates) + util.MONITOR.on('system.wakeup', self.refreshLastSection) def unhookSignals(self): plexapp.SERVERMANAGER.off('new:server', self.onNewServer) @@ -554,18 +660,27 @@ def unhookSignals(self): plexapp.util.APP.off('account:response', self.displayServerAndUser) plexapp.util.APP.off('sli:reachability:received', self.displayServerAndUser) plexapp.util.APP.off('change:hubs_bifurcation_lines', self.updateProperties) - plexapp.util.APP.off('change:hubs_use_new_continue_watching', self.fullyRefreshHome) + plexapp.util.APP.off('change:no_episode_spoilers2', self.setDirty) + plexapp.util.APP.off('change:no_unwatched_episode_titles', self.setDirty) + plexapp.util.APP.off('change:spoilers_allowed_genres', self.setDirty) + plexapp.util.APP.off('change:hubs_use_new_continue_watching', self.setDirty) + plexapp.util.APP.off('change:use_alt_watched', self.setDirty) + plexapp.util.APP.off('change:hide_aw_bg', self.setDirty) plexapp.util.APP.off('change:theme', self.setTheme) player.PLAYER.off('session.ended', self.updateOnDeckHubs) util.MONITOR.off('changed.watchstatus', self.updateOnDeckHubs) + util.MONITOR.off('screensaver.deactivated', self.refreshLastSection) + util.MONITOR.off('dpms.deactivated', self.refreshLastSection) + util.MONITOR.off('system.sleep', self.disableUpdates) + util.MONITOR.off('system.wakeup', self.refreshLastSection) def tick(self): - if not self.lastSection: + if not self.lastSection or self._ignoreTick: return hubs = self.sectionHubs.get(self.lastSection.key) - if not hubs: + if hubs is None: return if time.time() - hubs.lastUpdated > HUBS_REFRESH_INTERVAL and not xbmc.Player().isPlayingVideo(): @@ -623,6 +738,17 @@ def onAction(self, action): self.setFocusId(self.lastFocusID) if controlID == self.SECTION_LIST_ID: + if self.movingSection: + self.sectionMover(self.movingSection, action) + return + + if action == xbmcgui.ACTION_CONTEXT_MENU: + show_section = self.sectionMenu() + if not show_section: + return + else: + self.serverRefresh(section=show_section) + return self.checkSectionItem(action=action) if controlID == self.SERVER_BUTTON_ID: @@ -658,12 +784,20 @@ def onAction(self, action): elif controlID == self.PLAYER_STATUS_BUTTON_ID and action == xbmcgui.ACTION_MOVE_RIGHT: self.setFocusId(self.SERVER_BUTTON_ID) elif 399 < controlID < 500: - if action.getId() in MOVE_SET: - self.checkHubItem(controlID, actionID=action.getId()) - return - elif action.getId() == xbmcgui.ACTION_PLAYER_PLAY: + if action.getId() in MOVE_SET or action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + _continue = self.checkHubItem(controlID, action=action) + if not _continue: + return + elif action == xbmcgui.ACTION_PLAYER_PLAY: self.hubItemClicked(controlID, auto_play=True) return + elif action == xbmcgui.ACTION_CONTEXT_MENU: + show_section = self.hubMenu() + if not show_section: + return + else: + self.serverRefresh(section=show_section) + return if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_CONTEXT_MENU): optionsFocused = xbmc.getCondVisibility('ControlGroup({0}).HasFocus(0)'.format(self.OPTIONS_GROUP_ID)) @@ -682,7 +816,7 @@ def onAction(self, action): if controlID == self.SECTION_LIST_ID and self.sectionList.control.getSelectedPosition() > 0: self.sectionList.setSelectedItemByPos(0) - self.showHubs(HomeSection) + self.showHubs(home_section) return if util.addonSettings.fastBack and not optionsFocused and offSections \ @@ -726,7 +860,8 @@ def onAction(self, action): def onClick(self, controlID): if controlID == self.SECTION_LIST_ID: - self.sectionClicked() + if not self.movingSection: + self.sectionClicked() # elif controlID == self.SERVER_BUTTON_ID: # self.showServers() elif controlID == self.SERVER_LIST_ID: @@ -804,22 +939,42 @@ def updateOnDeckHubs(self, **kwargs): for mli in self.sectionList: if mli.dataSource is not None and mli.dataSource != self.lastSection: sections.add(mli.dataSource) - tasks = [SectionHubsTask().setup(s, self.sectionHubsCallback) for s in [self.lastSection] + list(sections)] + tasks = [SectionHubsTask().setup(s, self.sectionHubsCallback, self.wantedSections, self.ignoredHubs) + for s in [self.lastSection] + list(sections)] else: - tasks = [UpdateHubTask().setup(hub, self.updateHubCallback) for hub in self.updateHubs.values()] + tasks = [UpdateHubTask().setup(hub, self.updateHubCallback) + for hub in self.updateHubs.values()] self.tasks += tasks backgroundthread.BGThreader.addTasks(tasks) def showBusy(self, on=True): self.setProperty('busy', on and '1' or '') - def fullyRefreshHome(self, *args, **kwargs): - self.showSections() + def setDirty(self, *args, **kwargs): + self._reloadOnReinit = True + self.storeSpoilerSettings() + + def fullyRefreshHome(self, *args, section=None, **kwargs): + self.showSections(focus_section=section or home_section) self.backgroundSet = False - self.showHubs(HomeSection) + self.showHubs(section if section else home_section) + + def disableUpdates(self, *args, **kwargs): + util.LOG("Sleep event, stopping updates") + self._ignoreTick = True + + def enableUpdates(self, *args, **kwargs): + util.LOG("Wake event, resuming updates") + self._ignoreTick = False + + def refreshLastSection(self, *args, **kwargs): + if not xbmc.Player().isPlayingVideo(): + util.LOG("Refreshing last section after wake events") + self.showHubs(self.lastSection, force=True) + self.enableUpdates() @busy.dialog() - def serverRefresh(self): + def serverRefresh(self, section=None): backgroundthread.BGThreader.reset() if self.tasks: for task in self.tasks: @@ -828,11 +983,18 @@ def serverRefresh(self): with self.lock: self.setProperty('hub.focus', '') self.displayServerAndUser() + self.loadLibrarySettings() + self.loadHubSettings() if not plexapp.SERVERMANAGER.selectedServer: self.setFocusId(self.USER_BUTTON_ID) return False - self.fullyRefreshHome() + self.fullyRefreshHome(section=section) + if section is not None: + for mli in self.sectionList: + if mli.dataSource and mli.dataSource.key == section.key: + self.sectionList.selectItem(mli.pos()) + self.lastSection = mli.dataSource return True def hubItemClicked(self, hubControlID, auto_play=False): @@ -845,13 +1007,8 @@ def hubItemClicked(self, hubControlID, auto_play=False): return carryProps = None - if auto_play and self.hubControls: - # carry over some props to the new window as we might end up showing a resume dialog not rendering the - # underlying window. the new window class will invalidate the old one temporarily, though, as it seems - # and the properties vanish, resulting in all text2lines enabled hubs to lose their title2 labels - carryProps = dict( - ('hub.text2lines.4{0:02d}'.format(i), '1') for i, hubCtrl in enumerate(self.hubControls) if - hubCtrl.dataSource and self.HUBMAP[hubCtrl.dataSource.getCleanHubIdentifier()].get("text2lines")) + if auto_play: + carryProps = self.carriedProps try: command = opener.open(mli.dataSource, auto_play=auto_play, dialog_props=carryProps) @@ -898,6 +1055,240 @@ def processCommand(self, command): self.lastSection = mli.dataSource self.sectionChanged() + @property + def carriedProps(self): + # carry over some props to the new window as we might end up showing a dialog not rendering the + # underlying window. the new window class will invalidate the old one temporarily, though, as it seems + # and the properties vanish, resulting in all text2lines enabled hubs to lose their title2 labels + if self.hubControls: + return dict( + ('hub.text2lines.4{0:02d}'.format(i), '1') for i, hubCtrl in enumerate(self.hubControls) if + hubCtrl.dataSource and self.HUBMAP[hubCtrl.dataSource.getCleanHubIdentifier()].get("text2lines")) + + def sectionMenu(self): + item = self.sectionList.getSelectedItem() + if not item or not item.getProperty('item'): + return + + section = item.dataSource + choice = None + if not section.key: + # home section + sections = [playlists_section] + plexapp.SERVERMANAGER.selectedServer.library.sections() + options = [] + + if "order" in self.librarySettings and self.librarySettings["order"]: + options.append({'key': 'reset_order', 'display': T(33040, "Reset library order")}) + + for s in sections: + section_settings = self.librarySettings.get(s.key) + if section_settings and not section_settings.get("show", True): + options.append({'key': 'show', + 'section_id': s.key, + 'display': T(33029, "Show library: {}").format(s.title) + } + ) + if self.hubSettings: + for section_hub_key in self.ignoredHubs: + if not section_hub_key.startswith("None:"): + continue + + hub_title = section_hub_key + if plexapp.SERVERMANAGER.selectedServer.currentHubs: + hub_title = plexapp.SERVERMANAGER.selectedServer.currentHubs.get(section_hub_key, + section_hub_key) + options.append({'key': 'show', + 'hub_ident': section_hub_key, + 'display': T(33041, "Show hub: {}").format(hub_title) + } + ) + + if options: + choice = dropdown.showDropdown( + options, + pos=(660, 441), + close_direction='none', + set_dropdown_prop=False, + header=T(33034, "Library settings"), + select_index=0, + align_items="left", + dialog_props=self.carriedProps + ) + + else: + options = [] + + if section.locations: + for loc in section.locations: + source, target = section.getMappedPath(loc) + loc_is_mapped = source and target + options.append( + {'key': 'map', 'mapped': loc_is_mapped, 'path': loc, 'display': T(33026, + "Map path: {}").format(loc) + if not loc_is_mapped else T(33027, "Remove mapping: {}").format(target) + } + ) + + options.append({'key': 'hide', 'display': T(33028, "Hide library")}) + options.append({'key': 'move', 'display': T(33039, "Move")}) + + if self.hubSettings: + for section_hub_key in self.ignoredHubs: + if not section_hub_key.startswith("{}:".format(section.key)): + continue + + hub_title = section_hub_key + if plexapp.SERVERMANAGER.selectedServer.currentHubs: + hub_title = plexapp.SERVERMANAGER.selectedServer.currentHubs.get(section_hub_key, + section_hub_key) + options.append({'key': 'show', + 'hub_ident': section_hub_key, + 'display': T(33041, "Show hub: {}").format(hub_title) + } + ) + + choice = dropdown.showDropdown( + options, + pos=(660, 441), + close_direction='none', + set_dropdown_prop=False, + header=T(33030, 'Choose action for: {}').format(section.title), + select_index=0, + align_items="left", + dialog_props=self.carriedProps + ) + + if not choice: + return + + if choice["key"] == "map": + is_mapped = choice.get("mapped") + if is_mapped: + # show deletion + source, target = section.getMappedPath(choice["path"]) + section.deleteMapping(target) + return self.lastSection + + else: + # show fb + # select loc to map + d = xbmcgui.Dialog().browse(0, T(33031, "Select Kodi source for {}").format(choice["path"]), "files") + if not d: + return + pmm.addPathMapping(d, choice["path"]) + return self.lastSection + elif choice["key"] == "hide": + if section.key not in self.librarySettings: + self.librarySettings[section.key] = {} + self.librarySettings[section.key]['show'] = False + self.saveLibrarySettings() + return self.lastSection + elif choice["key"] == "show": + if "hub_ident" in choice: + util.DEBUG_LOG("AGA: %s %s" % (choice["hub_ident"], self.hubSettings)) + if choice["hub_ident"] in self.hubSettings: + self.hubSettings[choice["hub_ident"]]['show'] = True + self.saveHubSettings() + return self.lastSection + elif "section_id" in choice: + if choice["section_id"] in self.librarySettings: + self.librarySettings[choice["section_id"]]['show'] = True + self.saveLibrarySettings() + return self.lastSection + elif choice["key"] == "move": + self.sectionMover(item, "init") + elif choice["key"] == "reset_order": + if "order" in self.librarySettings: + del self.librarySettings["order"] + self.saveLibrarySettings() + return self.lastSection + + def hubMenu(self): + hub = self.currentHub + if not hub: + return + + section_hub_key = "{}:{}".format(self.lastSection.key, hub.hubIdentifier) + + hub_title = section_hub_key + if plexapp.SERVERMANAGER.selectedServer.currentHubs: + hub_title = plexapp.SERVERMANAGER.selectedServer.currentHubs.get(section_hub_key, + section_hub_key) + + options = [{'key': 'hide', 'display': "Hide Hub: {}".format(hub_title)}] + + choice = dropdown.showDropdown( + options, + pos=(660, 441), + close_direction='none', + set_dropdown_prop=False, + header=T(33030, 'Choose action for: {}').format(hub.title), + select_index=0, + align_items="left", + dialog_props=self.carriedProps + ) + + if not choice: + return + + elif choice["key"] == "hide": + if section_hub_key not in self.hubSettings: + self.hubSettings[section_hub_key] = {} + self.hubSettings[section_hub_key]['show'] = False + self.saveHubSettings() + return self.lastSection + + def sectionMover(self, item, action): + def stop_moving(reset=False): + # set everything to non-moving and re-insert home item + self.movingSection = False + self.setBoolProperty("moving", False) + item.setBoolProperty("moving", False) + homemli = kodigui.ManagedListItem(T(32332, 'Home'), data_source=home_section) + homemli.setProperty('is.home', '1') + homemli.setProperty('item', '1') + if reset: + if self.lastSelectedSectionPos is not None: + self.sectionList.moveItem(item, self.lastSelectedSectionPos) + self.lastSelectedSectionPos = None + self.sectionList.insertItem(0, homemli) + self.sectionList.selectItem(0) + self.sectionChanged() + + if action == "init": + self.movingSection = item + self.setBoolProperty("moving", True) + self.lastSelectedSectionPos = self.sectionList.getSelectedPos() - 1 + + # remove home item + self.sectionList.removeItem(0) + self.sectionList.setSelectedItem(item) + + item.setBoolProperty("moving", True) + + elif action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + stop_moving(reset=True) + + elif action in (xbmcgui.ACTION_MOVE_LEFT, xbmcgui.ACTION_MOVE_RIGHT): + direction = "left" if action == xbmcgui.ACTION_MOVE_LEFT else "right" + index = self.sectionList.getManagedItemPosition(item) + last_index = len(self.sectionList) - 1 + next_index = min(max(0, index - 1 if direction == "left" else index + 1), last_index) + if index == 0 and direction == "left": + next_index = last_index + self.sectionList.selectItem(last_index) + elif index == last_index and direction == "right": + next_index = 0 + self.sectionList.selectItem(0) + + self.sectionList.moveItem(item, next_index) + + elif action == xbmcgui.ACTION_SELECT_ITEM: + stop_moving() + # store section order + self.librarySettings["order"] = [i.dataSource.key for i in self.sectionList.items if i.dataSource] + self.saveLibrarySettings() + def checkSectionItem(self, force=False, action=None): item = self.sectionList.getSelectedItem() if not item: @@ -914,30 +1305,26 @@ def checkSectionItem(self, force=False, action=None): if item.getProperty('is.home'): self.storeLastBG() - if item.dataSource != self.lastSection: - self.sectionChanged() + if item.dataSource != self.lastSection or force: + self.sectionChanged(force=force) - def checkHubItem(self, controlID, actionID=None): + def checkHubItem(self, controlID, action=None): control = self.hubControls[controlID - 400] mli = control.getSelectedItem() is_valid_mli = mli and mli.getProperty('is.end') != '1' - is_last_item = is_valid_mli and control.isLastItem(mli) + + if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): + pos = control.getSelectedPos() + if pos is not None and pos > 0: + control.selectItem(0) + self.updateBackgroundFrom(control[0].dataSource) + return + return True if util.addonSettings.dynamicBackgrounds and is_valid_mli: self.updateBackgroundFrom(mli.dataSource) if not mli or not mli.getProperty('is.end') or mli.getProperty('is.updating') == '1': - if mli: - mlipos = control.getManagedItemPosition(mli) - - # in order to not round robin when the next chunk is loading, implement our own cheap round robining - # by storing the last selected item of the current control. if we've seen it twice, we need to wrap around - if not mli.getProperty('is.end') and is_last_item and actionID == xbmcgui.ACTION_MOVE_RIGHT: - if (controlID, mlipos) == self._lastSelectedItem: - control.selectItem(0) - self._lastSelectedItem = None - return - self._lastSelectedItem = (controlID, mlipos) return mli.setBoolProperty('is.updating', True) @@ -971,7 +1358,7 @@ def displayServerAndUser(self, **kwargs): def cleanTasks(self): self.tasks = [t for t in self.tasks if t] - def sectionChanged(self): + def sectionChanged(self, force=False): self.sectionChangeTimeout = time.time() + 0.5 # wait 2s at max if we're currently awaiting any hubs to reload @@ -983,16 +1370,22 @@ def sectionChanged(self): waited += 1 self.showBusy(False) + if force: + self.sectionChangeTimeout = None + self._sectionChanged(immediate=True) + return + if not self.sectionChangeThread or (self.sectionChangeThread and not self.sectionChangeThread.is_alive()): self.sectionChangeThread = threading.Thread(target=self._sectionChanged, name="sectionchanged") self.sectionChangeThread.start() - def _sectionChanged(self): - if not self.sectionChangeTimeout: - return - while not util.MONITOR.waitForAbort(0.1): - if time.time() >= self.sectionChangeTimeout: - break + def _sectionChanged(self, immediate=False): + if not immediate: + if not self.sectionChangeTimeout: + return + while not util.MONITOR.waitForAbort(0.1): + if time.time() >= self.sectionChangeTimeout: + break ds = self.sectionList.getSelectedItem().dataSource if self.lastSection == ds: @@ -1009,16 +1402,24 @@ def _sectionReallyChanged(self, section): util.DEBUG_LOG('Section changed ({0}): {1}'.format(section.key, repr(section.title))) self.showHubs(section) self.lastSection = section - #self.checkSectionItem(force=True) - def sectionHubsCallback(self, section, hubs): + # timing issue + cur_sel_ds = self.sectionList.getSelectedItem().dataSource + if self.lastSection != cur_sel_ds: + util.DEBUG_LOG("Section changed in the " + "meantime from {} to {}, re-running the section change".format( + section.key, + cur_sel_ds.key)) + self.checkSectionItem(force=True) + + def sectionHubsCallback(self, section, hubs, reselect_pos_dict=None): with self.lock: update = bool(self.sectionHubs.get(section.key)) self.sectionHubs[section.key] = hubs if self.lastSection == section: - self.showHubs(section, update=update) + self.showHubs(section, update=update, reselect_pos_dict=reselect_pos_dict) - def updateHubCallback(self, hub, items=None): + def updateHubCallback(self, hub, items=None, reselect_pos=None): with self.lock: for mli in self.sectionList: section = mli.dataSource @@ -1033,45 +1434,74 @@ def updateHubCallback(self, hub, items=None): for idx, ihub in enumerate(hubs): if ihub == hub: if self.lastSection == section: - util.DEBUG_LOG('Hub {0} updated - refreshing section: {1}'.format(hub.hubIdentifier, repr(section.title))) + util.DEBUG_LOG('Hub {0} updated - refreshing section: {1}'.format(hub.hubIdentifier, + repr(section.title))) hubs[idx] = hub - self.showHub(hub, items=items) + self.showHub(hub, items=items, reselect_pos=reselect_pos) return - def extendHubCallback(self, hub, items): - util.DEBUG_LOG('ExtendHub called: {0} [{1}]'.format(hub.hubIdentifier, len(hub.items))) - self.updateHubCallback(hub, items) + def extendHubCallback(self, hub, items, reselect_pos=None): + util.DEBUG_LOG('ExtendHub called: {0} [{1}] (reselect: {2})'.format(hub.hubIdentifier, len(hub.items), + reselect_pos)) + self.updateHubCallback(hub, items, reselect_pos=reselect_pos) - def showSections(self): + def showSections(self, focus_section=None): self.sectionHubs = {} items = [] - homemli = kodigui.ManagedListItem(T(32332, 'Home'), data_source=HomeSection) + homemli = kodigui.ManagedListItem(T(32332, 'Home'), data_source=home_section) homemli.setProperty('is.home', '1') homemli.setProperty('item', '1') items.append(homemli) - pl = plexapp.SERVERMANAGER.selectedServer.playlists() - if pl: - plli = kodigui.ManagedListItem('Playlists', thumbnailImage='script.plex/home/type/playlists.png', data_source=PlaylistsSection) - plli.setProperty('is.playlists', '1') - plli.setProperty('item', '1') - items.append(plli) + sections = [] + + if "playlists" not in self.librarySettings \ + or ("playlists" in self.librarySettings and self.librarySettings["playlists"].get("show", True)): + pl = plexapp.SERVERMANAGER.selectedServer.playlists() + if pl: + sections.append(playlists_section) try: - sections = plexapp.SERVERMANAGER.selectedServer.library.sections() + _sections = plexapp.SERVERMANAGER.selectedServer.library.sections() except plexnet.exceptions.BadRequest: self.setFocusId(self.SERVER_BUTTON_ID) util.messageDialog("Error", "Bad request") return + self.wantedSections = [] + for section in _sections: + if section.key in self.librarySettings and not self.librarySettings[section.key].get("show", True): + self.anyLibraryHidden = True + continue + sections.append(section) + self.wantedSections.append(section.key) + + # sort libraries + if "order" in self.librarySettings: + sections = sorted(sections, key=lambda s: self.librarySettings["order"].index(s.key) + if s.key in self.librarySettings["order"] else -1) + + # speedup if we don't have any hidden libraries + if not self.anyLibraryHidden: + self.wantedSections = None + if plexapp.SERVERMANAGER.selectedServer.hasHubs(): - self.tasks = [SectionHubsTask().setup(s, self.sectionHubsCallback) for s in [HomeSection, PlaylistsSection] + sections] + self.tasks = [SectionHubsTask().setup(s, self.sectionHubsCallback, self.wantedSections, self.ignoredHubs) + for s in [home_section] + sections] backgroundthread.BGThreader.addTasks(self.tasks) + show_pm_indicator = util.getSetting('path_mapping_indicators', True) for section in sections: - mli = kodigui.ManagedListItem(section.title, thumbnailImage='script.plex/home/type/{0}.png'.format(section.type), data_source=section) + mli = kodigui.ManagedListItem(section.title, + thumbnailImage='script.plex/home/type/{0}.png'.format(section.type), + data_source=section) mli.setProperty('item', '1') + if section == playlists_section: + mli.setProperty('is.playlists', '1') + mli.setThumbnailImage('script.plex/home/type/playlists.png') + if pmm.mapping and show_pm_indicator: + mli.setBoolProperty('is.mapped', section.isMapped) items.append(mli) self.bottomItem = len(items) - 1 @@ -1080,25 +1510,28 @@ def showSections(self): mli = kodigui.ManagedListItem() items.append(mli) - self.lastSection = HomeSection + self.lastSection = focus_section or home_section self.sectionList.reset() self.sectionList.addItems(items) - if items: - self.setFocusId(self.SECTION_LIST_ID) + if not focus_section: + if items: + self.setFocusId(self.SECTION_LIST_ID) + else: + self.setFocusId(self.SERVER_BUTTON_ID) else: - self.setFocusId(self.SERVER_BUTTON_ID) + self.setFocusId(self.SECTION_LIST_ID) - def showHubs(self, section=None, update=False): + def showHubs(self, section=None, update=False, force=False, reselect_pos_dict=None): self.setBoolProperty('no.content', False) if not update: self.setProperty('drawing', '1') try: - self._showHubs(section=section, update=update) + self._showHubs(section=section, update=update, force=force, reselect_pos_dict=reselect_pos_dict) finally: self.setProperty('drawing', '') - def _showHubs(self, section=None, update=False): + def _showHubs(self, section=None, update=False, force=False, reselect_pos_dict=None): if not update: self.clearHubs() @@ -1112,30 +1545,47 @@ def _showHubs(self, section=None, update=False): self.showBusy(True) hubs = self.sectionHubs.get(section.key) - if hubs is False: - self.showBusy(False) - self.setBoolProperty('no.content', True) - return + section_stale = False - if not hubs: - for task in self.tasks: - if task.section == section: - backgroundthread.BGThreader.moveToFront(task) - break + if not force: + if hubs is not None: + section_stale = time.time() - hubs.lastUpdated > HUBS_REFRESH_INTERVAL - if section.type != "home": + # hubs.invalid is True when the last hub update errored. if the hub is stale, refresh it, though + if hubs is not None and hubs.invalid and not section_stale: + util.DEBUG_LOG("Section fetch has failed: {}".format(section.key)) self.showBusy(False) self.setBoolProperty('no.content', True) - return + return + + if not hubs and not section_stale: + for task in self.tasks: + if task.section == section: + backgroundthread.BGThreader.moveToFront(task) + break - if time.time() - hubs.lastUpdated > HUBS_REFRESH_INTERVAL: - util.DEBUG_LOG('Section is stale: REFRESHING - update: {0}'.format(update)) + if section.type != "home": + self.showBusy(False) + self.setBoolProperty('no.content', True) + return + + if section_stale or force: + util.DEBUG_LOG('Section is stale: {0} REFRESHING - update: {1}, failed before: {2}'.format( + "Home" if section.key is None else section.key, update, "Unknown" if not hubs else hubs.invalid)) hubs.lastUpdated = time.time() self.cleanTasks() + # remember selected positions in hubs + is_home = section.key is None + _rp = {} + for hub in self.sectionHubs.get(section.key, []): + identifier = hub.getCleanHubIdentifier(is_home=is_home) + if identifier in self.HUBMAP: + _rp[identifier] = self.hubControls[self.HUBMAP[identifier]['index']].getSelectedPos() if not update: if section.key in self.sectionHubs: self.sectionHubs[section.key] = None - self.tasks.append(SectionHubsTask().setup(section, self.sectionHubsCallback)) + self.tasks.append(SectionHubsTask().setup(section, self.sectionHubsCallback, self.wantedSections, + reselect_pos_dict=_rp, ignore_hubs=self.ignoredHubs)) backgroundthread.BGThreader.addTask(self.tasks[-1]) return @@ -1154,7 +1604,8 @@ def _showHubs(self, section=None, update=False): skip[self.HUBMAP[identifier]['index']] = 1 - if self.showHub(hub, is_home=not section.key): + if self.showHub(hub, is_home=not section.key, + reselect_pos=reselect_pos_dict.get(identifier) if reselect_pos_dict else None): if hub.items: hasContent = True if self.HUBMAP[identifier].get('do_updates'): @@ -1183,7 +1634,7 @@ def _showHubs(self, section=None, update=False): finally: self.showBusy(False) - def showHub(self, hub, items=None, is_home=False): + def showHub(self, hub, items=None, is_home=False, reselect_pos=None): identifier = hub.getCleanHubIdentifier(is_home=is_home) if identifier in self.HUBMAP: @@ -1191,7 +1642,8 @@ def showHub(self, hub, items=None, is_home=False): identifier, len(hub.items), len(items) if items else None)) - self._showHub(hub, hubitems=items, **self.HUBMAP[identifier]) + self._showHub(hub, hubitems=items, reselect_pos=reselect_pos, identifier=identifier, + **self.HUBMAP[identifier]) return True else: util.DEBUG_LOG('UNHANDLED - Hub: {0} [{1}]({1})'.format(hub.hubIdentifier, identifier, len(hub.items))) @@ -1220,7 +1672,7 @@ def createSimpleListItem(self, obj, thumb_w, thumb_h): def createEpisodeListItem(self, obj, wide=False): mli = self.createGrandparentedListItem(obj, *self.THUMB_POSTER_DIM) if obj.index: - subtitle = u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), obj.parentIndex, T(32311, 'E'), obj.index) + subtitle = u'{0} \u2022 {1}'.format(T(32310, 'S').format(obj.parentIndex), T(32311, 'E').format(obj.index)) else: subtitle = obj.originallyAvailableAt.asDatetime('%m/%d/%y') @@ -1232,6 +1684,7 @@ def createEpisodeListItem(self, obj, wide=False): mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') if not obj.isWatched: mli.setProperty('unwatched', '1') + mli.setBoolProperty('watched', obj.isFullyWatched) return mli def createSeasonListItem(self, obj, wide=False): @@ -1240,6 +1693,7 @@ def createSeasonListItem(self, obj, wide=False): mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') if not obj.isWatched: mli.setProperty('unwatched.count', str(obj.unViewedLeafCount)) + mli.setBoolProperty('watched', obj.isFullyWatched) return mli def createMovieListItem(self, obj, wide=False): @@ -1247,6 +1701,7 @@ def createMovieListItem(self, obj, wide=False): mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/movie.png') if not obj.isWatched: mli.setProperty('unwatched', '1') + mli.setBoolProperty('watched', obj.isFullyWatched) return mli def createShowListItem(self, obj, wide=False): @@ -1254,6 +1709,7 @@ def createShowListItem(self, obj, wide=False): mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') if not obj.isWatched: mli.setProperty('unwatched.count', str(obj.unViewedLeafCount)) + mli.setBoolProperty('watched', obj.isFullyWatched) return mli def createAlbumListItem(self, obj, wide=False): @@ -1327,8 +1783,8 @@ def clearHubs(self): for control in self.hubControls: control.reset() - def _showHub(self, hub, hubitems=None, index=None, with_progress=False, with_art=False, ar16x9=False, - text2lines=False, **kwargs): + def _showHub(self, hub, hubitems=None, reselect_pos=None, identifier=None, index=None, with_progress=False, + with_art=False, ar16x9=False, text2lines=False, **kwargs): control = self.hubControls[index] control.dataSource = hub @@ -1344,11 +1800,23 @@ def _showHub(self, hub, hubitems=None, index=None, with_progress=False, with_art items = [] + check_spoilers = False for obj in hubitems or hub.items: if not self.backgroundSet: if self.updateBackgroundFrom(obj): self.backgroundSet = True - mli = self.createListItem(obj, wide=with_art) + + wide = with_art + no_spoilers = False + if obj.type == 'episode' and hub.hubIdentifier == "home.continue" and self.spoilerSetting != "off": + check_spoilers = True + obj._noSpoilers = no_spoilers = self.hideSpoilers(obj, use_cache=False) + + if obj.type == 'episode' and util.addonSettings.continueUseThumb and wide: + # with_art sets the wide parameter which includes the episode title + wide = no_spoilers in ("funwatched", "unwatched") and not self.noTitles + + mli = self.createListItem(obj, wide=wide) if mli: items.append(mli) @@ -1357,18 +1825,23 @@ def _showHub(self, hub, hubitems=None, index=None, with_progress=False, with_art mli.setProperty('progress', util.getProgressImage(mli.dataSource)) if with_art: for mli in items: - thumb = (util.addonSettings.continueUseThumb - and mli.dataSource.type == 'episode' - and mli.dataSource.thumb - ) \ - or mli.dataSource.art - mli.setThumbnailImage(thumb.asTranscodedImageURL(*self.THUMB_AR16X9_DIM)) + extra_opts = {} + thumb = mli.dataSource.art + # use episode thumbnail for in progress episodes + if mli.dataSource.type == 'episode' and util.addonSettings.continueUseThumb and check_spoilers: + # blur them if we don't want any spoilers and the episode hasn't been fully watched + if mli.dataSource._noSpoilers: + extra_opts = {"blur": util.addonSettings.episodeNoSpoilerBlur} + thumb = mli.dataSource.thumb + + mli.setThumbnailImage(thumb.asTranscodedImageURL(*self.THUMB_AR16X9_DIM, **extra_opts)) mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/movie16x9.png') if ar16x9: for mli in items: mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/movie16x9.png') - if hub.more.asBool(): + more = hub.more.asBool() + if more: end = kodigui.ManagedListItem('') end.setBoolProperty('is.end', True) items.append(end) @@ -1377,10 +1850,29 @@ def _showHub(self, hub, hubitems=None, index=None, with_progress=False, with_art end = control.size() - 1 control.replaceItem(end, items[0]) control.addItems(items[1:]) - control.selectItem(end) + if reselect_pos is None: + control.selectItem(end) else: control.replaceItems(items) + if reselect_pos is not None and reselect_pos > 0: + pos = reselect_pos + if pos < control.size() - (more and 1 or 0): + control.selectItem(pos) + else: + if more: + # re-extend the hub to its original size so we can reselect the position + # calculate how many pages we need to re-arrive at the last selected position + # fixme: someone check for an off-by-one please + size = max(math.ceil((pos + 2 - control.size()) / HUB_PAGE_SIZE), 1) * HUB_PAGE_SIZE + task = ExtendHubTask().setup(control.dataSource, self.extendHubCallback, + canceledCallback=lambda hub: mli.setBoolProperty('is.updating', False), + size=size, reselect_pos=pos) + self.tasks.append(task) + backgroundthread.BGThreader.addTask(task) + else: + control.selectItem(control.size() - 1) + def updateListItem(self, mli): if not mli or not mli.dataSource: # May have become invalid return @@ -1388,7 +1880,9 @@ def updateListItem(self, mli): obj = mli.dataSource if obj.type in ('episode', 'movie'): mli.setProperty('unwatched', not obj.isWatched and '1' or '') + mli.setProperty('watched', obj.isFullyWatched and '1' or '') elif obj.type in ('season', 'show', 'album'): + mli.setProperty('watched', obj.isFullyWatched and '1' or '') if obj.isWatched: mli.setProperty('unwatched.count', '') else: @@ -1424,6 +1918,7 @@ def onReachableServer(self, server=None, **kwargs): self.onNewServer() def onSelectedServerChange(self, **kwargs): + util.DEBUG_LOG("YEELLO") if self.serverRefresh(): self.setFocusId(self.SECTION_LIST_ID) self.changingServer = False @@ -1510,6 +2005,9 @@ def selectServer(self): def showUserMenu(self, mouse=False): items = [] if plexapp.ACCOUNT.isSignedIn: + if not len(plexapp.ACCOUNT.homeUsers) and not util.addonSettings.cacheHomeUsers: + plexapp.ACCOUNT.updateHomeUsers(refreshSubscription=True) + if len(plexapp.ACCOUNT.homeUsers) > 1: items.append(kodigui.ManagedListItem(T(32342, 'Switch User'), data_source='switch')) else: diff --git a/script.plexmod/lib/windows/info.py b/script.plexmod/lib/windows/info.py index d44f4991f..66631b7f2 100644 --- a/script.plexmod/lib/windows/info.py +++ b/script.plexmod/lib/windows/info.py @@ -1,11 +1,13 @@ from __future__ import absolute_import -from . import kodigui -from . import windowutils -from lib import util -from plexnet.video import Episode, Movie, Clip import os +from plexnet.video import Episode, Movie, Clip + +from lib import util +from . import kodigui +from . import windowutils + def split2len(s, n): def _f(s, n): @@ -33,6 +35,7 @@ def __init__(self, *args, **kwargs): self.title = kwargs.get('title') self.subTitle = kwargs.get('sub_title') self.thumb = kwargs.get('thumb') + self.thumb_opts = kwargs.get('thumb_opts', {}) self.thumbFallback = kwargs.get('thumb_fallback') self.info = kwargs.get('info') self.background = kwargs.get('background') @@ -155,7 +158,7 @@ def onFirstInit(self): self.setProperty('title.main', self.title) self.setProperty('title.sub', self.subTitle) self.setProperty('thumb.fallback', self.thumbFallback) - self.setProperty('thumb', self.thumb.asTranscodedImageURL(*self.thumbDim)) + self.setProperty('thumb', self.thumb.asTranscodedImageURL(*self.thumbDim, **self.thumb_opts)) self.setProperty('info', self.getVideoInfo()) self.setProperty('background', self.background) diff --git a/script.plexmod/lib/windows/kodigui.py b/script.plexmod/lib/windows/kodigui.py index 08e2e268d..8d5330735 100644 --- a/script.plexmod/lib/windows/kodigui.py +++ b/script.plexmod/lib/windows/kodigui.py @@ -1,18 +1,22 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import -from kodi_six import xbmc -from kodi_six import xbmcgui -import time + import threading +import time import traceback + +from kodi_six import xbmc +from kodi_six import xbmcgui +from plexnet import util as pnUtil from six.moves import range from six.moves import zip + from .. import util MONITOR = None -class BaseFunctions: +class BaseFunctions(object): xmlFile = '' path = '' theme = '' @@ -100,6 +104,8 @@ def setBoolProperty(self, key, boolean): class BaseWindow(xbmcgui.WindowXML, BaseFunctions): + __slots__ = ("_closing", "_winID", "started", "finishedInit", "dialogProps", "isOpen") + def __init__(self, *args, **kwargs): BaseFunctions.__init__(self) self._closing = False @@ -111,6 +117,8 @@ def __init__(self, *args, **kwargs): carryProps = kwargs.get("window_props", None) if carryProps: self.setProperties(list(carryProps.keys()), list(carryProps.values())) + self.setBoolProperty('use_alt_watched', util.getSetting('use_alt_watched', True)) + self.setBoolProperty('hide_aw_bg', util.getSetting('hide_aw_bg', False)) def onInit(self): global LAST_BG_URL @@ -229,6 +237,8 @@ def onClosed(self): class BaseDialog(xbmcgui.WindowXMLDialog, BaseFunctions): + __slots__ = ("_closing", "_winID", "started", "isOpen") + def __init__(self, *args, **kwargs): BaseFunctions.__init__(self) self._closing = False @@ -238,6 +248,8 @@ def __init__(self, *args, **kwargs): carryProps = kwargs.get("dialog_props", None) if carryProps: self.setProperties(list(carryProps.keys()), list(carryProps.values())) + self.setBoolProperty('use_alt_watched', util.getSetting('use_alt_watched', True)) + self.setBoolProperty('hide_aw_bg', util.getSetting('hide_aw_bg', False)) def onInit(self): self._winID = xbmcgui.getCurrentWindowDialogId() @@ -343,7 +355,16 @@ def __setattr__(self, key, value): class ManagedListItem(object): - def __init__(self, label='', label2='', iconImage='', thumbnailImage='', path='', data_source=None, properties=None): + __slots__ = ("_listItem", "dataSource", "properties", "label", "label2", "iconImage", "thumbnailImage", "path", + "_ID", "_manager", "_valid") + + PROPS = { + 'use_alt_watched': util.getSetting('use_alt_watched', True) and '1' or '', + 'hide_aw_bg': util.getSetting('hide_aw_bg', False) and '1' or '' + } + + def __init__(self, label='', label2='', iconImage='', thumbnailImage='', path='', data_source=None, + properties=None): self._listItem = xbmcgui.ListItem(label, label2, path=path) self._listItem.setArt({"thumb": thumbnailImage, "icon": iconImage}) self.dataSource = data_source @@ -356,6 +377,9 @@ def __init__(self, label='', label2='', iconImage='', thumbnailImage='', path='' self._ID = None self._manager = None self._valid = True + for k, v in self.PROPS.items(): + self.setProperty(k, v) + if properties: for k, v in properties.items(): self.setProperty(k, v) @@ -499,7 +523,19 @@ def onDestroy(self): pass +def watchMarkerSettingsChanged(*args, **kwargs): + ManagedListItem.PROPS['use_alt_watched'] = util.getSetting('use_alt_watched', True) and '1' or '' + ManagedListItem.PROPS['hide_aw_bg'] = util.getSetting('hide_aw_bg', False) and '1' or '' + + +pnUtil.APP.on('change:use_alt_watched', watchMarkerSettingsChanged) +pnUtil.APP.on('change:hide_aw_bg', watchMarkerSettingsChanged) + + class ManagedControlList(object): + __slots__ = ("controlID", "control", "items", "_sortKey", "_idCounter", "_maxViewIndex", "_properties", + "dataSource") + def __init__(self, window, control_id, max_view_index, data_source=None): self.controlID = control_id self.control = window.getControl(control_id) @@ -635,10 +671,24 @@ def getSelectedItem(self): return None return self.getListItem(pos) + def getSelectedPos(self): + pos = self.control.getSelectedPosition() + if not self.positionIsValid(pos): + pos = self.size() - 1 + + if pos < 0: + return None + return pos + def setSelectedItemByPos(self, pos): if self.positionIsValid(pos): self.control.selectItem(pos) + def setSelectedItem(self, item): + pos = self.getManagedItemPosition(item) + if self.positionIsValid(pos): + self.control.selectItem(pos) + def removeItem(self, index): old = self.items.pop(index) old.onDestroy() @@ -793,6 +843,8 @@ def newControl(self, window=None, control_id=None): class _MWBackground(ControlledWindow): + __slots__ = ("_multiWindow", "started") + def __init__(self, *args, **kwargs): self._multiWindow = kwargs.get('multi_window') self.started = False @@ -807,6 +859,8 @@ def onInit(self): class MultiWindow(object): + __slots__ = ("_windows", "_next", "_properties", "_current", "_allClosed", "exitCommand", "_currentOnAction") + def __init__(self, windows=None, default_window=None, **kwargs): self._windows = windows self._next = default_window or self._windows[0] @@ -1115,6 +1169,8 @@ def reset(self, close_win=None, init=None): class WindowProperty(): + __slots__ = ("win", "prop", "val", "end", "old") + def __init__(self, win, prop, val='1', end=None): self.win = win self.prop = prop @@ -1131,6 +1187,8 @@ def __exit__(self, exc_type, exc_value, traceback): class GlobalProperty(): + __slots__ = ("_addonID", "prop", "val", "end", "old") + def __init__(self, prop, val='1', end=None): from kodi_six import xbmcaddon self._addonID = xbmcaddon.Addon().getAddonInfo('id') diff --git a/script.plexmod/lib/windows/library.py b/script.plexmod/lib/windows/library.py index 2b9c77d98..951fc7c67 100644 --- a/script.plexmod/lib/windows/library.py +++ b/script.plexmod/lib/windows/library.py @@ -1,34 +1,33 @@ from __future__ import absolute_import + +import json import os import random -import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error -import json -import time import threading +import plexnet +import six +import six.moves.urllib.error +import six.moves.urllib.parse +import six.moves.urllib.request from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui +from plexnet import playqueue +from six.moves import range -from lib import util from lib import backgroundthread from lib import player - +from lib import util +from lib.util import T from . import busy -from . import subitems -from . import preplay -from . import search -import plexnet from . import dropdown +from . import kodigui from . import opener +from . import preplay +from . import search +from . import subitems from . import windowutils -from plexnet import playqueue - -from lib.util import T -import six -from six.moves import range - KEYS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' MOVE_SET = frozenset( @@ -983,6 +982,7 @@ def updateUnwatchedAndProgress(self, mli): mli.dataSource.reload() if mli.dataSource.isWatched: mli.setProperty('unwatched', '') + mli.setBoolProperty('watched', mli.dataSource.isFullyWatched) mli.setProperty('unwatched.count', '') else: if self.section.TYPE == 'show' or mli.dataSource.TYPE == 'show' or mli.dataSource.TYPE == 'season': @@ -1295,10 +1295,6 @@ def _chunkCallback(self, items, start): thumbDim = TYPE_KEYS.get(self.section.type, TYPE_KEYS['movie'])['thumb_dim'] artDim = TYPE_KEYS.get(self.section.type, TYPE_KEYS['movie']).get('art_dim', (256, 256)) - showUnwatched = False - if (self.section.TYPE in ('movie', 'show') and items[0].TYPE != 'collection') or (self.section.TYPE == 'collection' and items[0].TYPE in ('movie', 'show', 'episode')): # NOTE: A collection with Seasons doesn't have the leafCount/viewedLeafCount until you actually go into the season so we can't update the unwatched count here - showUnwatched = True - if ITEM_TYPE == 'episode': for offset, obj in enumerate(items): if not self.showPanelControl: @@ -1309,7 +1305,8 @@ def _chunkCallback(self, items, start): mli.dataSource = obj mli.setProperty('index', str(pos)) if obj.index: - subtitle = u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), obj.parentIndex, T(32311, 'E'), obj.index) + subtitle = u'{0} \u2022 {1}'.format(T(32310, 'S').format(obj.parentIndex), + T(32311, 'E').format(obj.index)) mli.setProperty('subtitle', subtitle) subtitle = "\n" + subtitle else: @@ -1324,6 +1321,8 @@ def _chunkCallback(self, items, start): mli.setProperty('art', obj.defaultArt.asTranscodedImageURL(*artDim)) if not obj.isWatched: mli.setProperty('unwatched', '1') + mli.setBoolProperty('watched', obj.isFullyWatched) + mli.setProperty('initialized', '1') else: mli.clear() if obj is False: @@ -1378,9 +1377,10 @@ def _chunkCallback(self, items, start): mli.setThumbnailImage(obj.defaultThumb.asTranscodedImageURL(*thumbDim)) mli.dataSource = obj mli.setProperty('summary', obj.get('summary')) + mli.setProperty('year', obj.get('year')) - if showUnwatched and obj.TYPE != 'collection': - if not obj.isDirectory(): + if obj.TYPE != 'collection': + if not obj.isDirectory() and obj.get('duration').asInt(): mli.setLabel2(util.durationToText(obj.fixedDuration())) mli.setProperty('art', obj.defaultArt.asTranscodedImageURL(*artDim)) if not obj.isWatched and obj.TYPE != "Directory": @@ -1388,6 +1388,9 @@ def _chunkCallback(self, items, start): mli.setProperty('unwatched.count', str(obj.unViewedLeafCount)) else: mli.setProperty('unwatched', '1') + elif obj.isFullyWatched and obj.TYPE != "Directory": + mli.setBoolProperty('watched', '1') + mli.setProperty('initialized', '1') mli.setProperty('progress', util.getProgressImage(obj)) else: diff --git a/script.plexmod/lib/windows/mixins.py b/script.plexmod/lib/windows/mixins.py index f35ac80fb..24bfeddbd 100644 --- a/script.plexmod/lib/windows/mixins.py +++ b/script.plexmod/lib/windows/mixins.py @@ -2,12 +2,14 @@ import math -from lib import util +from plexnet import util as pnUtil +from lib import util +from lib.data_cache import dcm +from lib.util import T +from . import busy from . import kodigui from . import optionsdialog -from . import busy -from lib.util import T class SeasonsMixin: @@ -64,6 +66,7 @@ def fillSeasons(self, show, update=False, seasonsFilter=None, selectSeason=None) mli.setProperty('index', str(idx)) mli.setProperty('thumb.fallback', 'script.plex/thumb_fallbacks/show.png') mli.setProperty('unwatched.count', not season.isWatched and str(season.unViewedLeafCount) or '') + mli.setBoolProperty('watched', season.isFullyWatched) if not season.isWatched: mli.setProperty('progress', util.getProgressImage(None, self.getSeasonProgress(show, season))) items.append(mli) @@ -81,9 +84,10 @@ def fillSeasons(self, show, update=False, seasonsFilter=None, selectSeason=None) class DeleteMediaMixin: def delete(self, item=None): + item = item or self.mediaItem button = optionsdialog.show( T(32326, 'Really delete?'), - T(32327, 'Are you sure you really want to delete this media?'), + T(33035, "Delete {}: {}?").format(type(item).__name__, item.defaultTitle), T(32328, 'Yes'), T(32329, 'No') ) @@ -91,16 +95,16 @@ def delete(self, item=None): if button != 0: return - if not self._delete(item=item or self.mediaItem): + if not self._delete(item=item): util.messageDialog(T(32330, 'Message'), T(32331, 'There was a problem while attempting to delete the media.')) return return True @busy.dialog() - def _delete(self, item): + def _delete(self, item, do_close=False): success = item.delete() - util.LOG('Media DELETE: {0} - {1}'.format(self.mediaItem, success and 'SUCCESS' or 'FAILED')) - if success: + util.LOG('Media DELETE: {0} - {1}'.format(item, success and 'SUCCESS' or 'FAILED')) + if success and do_close: self.doClose() return success @@ -137,3 +141,82 @@ def sanitize(src): 'script.plex/ratings/{0}.png'.format(sanitize(video.audienceRatingImage))) else: setProperty('rating', video.rating) + + +class SpoilersMixin(object): + def __init__(self, *args, **kwargs): + self._noSpoilers = None + self.spoilerSetting = "unwatched" + self.noTitles = False + self.spoilersAllowedFor = True + self.storeSpoilerSettings() + + def storeSpoilerSettings(self): + self.spoilerSetting = util.getSetting('no_episode_spoilers2', "unwatched") + self.noTitles = util.getSetting('no_unwatched_episode_titles', False) + self.spoilersAllowedFor = util.getSetting('spoilers_allowed_genres', True) + + @property + def noSpoilers(self): + return self.getNoSpoilers() + + def getCachedGenres(self, rating_key): + genres = dcm.getCacheData("show_genres", rating_key) + if genres: + return [pnUtil.AttributeDict(tag=g) for g in genres] + + def getNoSpoilers(self, item=None, show=None): + """ + when called without item or show, retains a global noSpoilers value, otherwise return dynamically based on item + or show + returns: "off" if spoilers unnecessary, otherwise "unwatched" or "funwatched" + """ + if not item and not show and self._noSpoilers is not None: + return self._noSpoilers + + if item and item.type != "episode": + return "off" + + nope = self.spoilerSetting + + if nope != "off" and self.spoilersAllowedFor: + # instead of making possibly multiple separate API calls to find genres for episode's shows, try to get + # a cached value instead + genres = [] + if item or show: + genres = self.getCachedGenres(item and item.grandparentRatingKey or show.ratingKey) + + if not genres: + show = getattr(self, "show_", show or (item and item.show()) or None) + if not show: + return "off" + + if not genres and show: + genres = show.genres() + + for g in genres: + if g.tag in util.SPOILER_ALLOWED_GENRES: + nope = "off" + break + + if item or show: + self._noSpoilers = nope + return self._noSpoilers + return nope + + def hideSpoilers(self, ep, fully_watched=None, watched=None, use_cache=True): + """ + returns boolean on whether we should hide spoilers for the given episode + """ + watched = watched if watched is not None else ep.isWatched + fullyWatched = fully_watched if fully_watched is not None else ep.isFullyWatched + nspoil = self.getNoSpoilers(item=ep if not use_cache else None) + return ((nspoil == 'funwatched' and not fullyWatched) or + (nspoil == 'unwatched' and not watched)) + + def getThumbnailOpts(self, ep, fully_watched=None, watched=None, hide_spoilers=None): + if self.getNoSpoilers(item=ep) == "off": + return {} + return (hide_spoilers if hide_spoilers is not None else + self.hideSpoilers(ep, fully_watched=fully_watched, watched=watched)) \ + and {"blur": util.addonSettings.episodeNoSpoilerBlur} or {} diff --git a/script.plexmod/lib/windows/musicplayer.py b/script.plexmod/lib/windows/musicplayer.py index 85d63afc2..58490298b 100644 --- a/script.plexmod/lib/windows/musicplayer.py +++ b/script.plexmod/lib/windows/musicplayer.py @@ -1,12 +1,13 @@ from __future__ import absolute_import + from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui -from . import currentplaylist -from . import opener from lib import player from lib import util +from . import currentplaylist +from . import kodigui +from . import opener def timeDisplay(ms): @@ -62,10 +63,7 @@ def onFirstInit(self): self.setupSeekbar() self.selectionBoxMax = self.SEEK_IMAGE_WIDTH - (self.selectionBoxHalf - 3) - player.PLAYER.on('starting.audio', self.onAudioStarting) - player.PLAYER.on('started.audio', self.onAudioStarted) - player.PLAYER.on('changed.audio', self.onAudioChanged) - + self.commonInit() self.updateProperties() self.play() self.setFocusId(406) @@ -75,23 +73,9 @@ def doClose(self, **kwargs): if self.playlist and self.playlist.isRemote: self.playlist.off('change', self.updateProperties) - player.PLAYER.off('starting.audio', self.onAudioStarting) - player.PLAYER.off('started.audio', self.onAudioStarted) - player.PLAYER.off('changed.audio', self.onAudioChanged) + self.commonDeinit() kodigui.ControlledWindow.doClose(self) - def onAudioStarting(self, *args, **kwargs): - util.setGlobalProperty('ignore_spinner', '1') - self.ignoreStopCommands = True - - def onAudioStarted(self, *args, **kwargs): - util.setGlobalProperty('ignore_spinner', '') - self.ignoreStopCommands = False - - def onAudioChanged(self, *args, **kwargs): - util.setGlobalProperty('ignore_spinner', '') - self.ignoreStopCommands = False - def onAction(self, action): if self.ignoreStopCommands and action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK, diff --git a/script.plexmod/lib/windows/opener.py b/script.plexmod/lib/windows/opener.py index 9ea161bf1..37ba37f32 100644 --- a/script.plexmod/lib/windows/opener.py +++ b/script.plexmod/lib/windows/opener.py @@ -1,9 +1,10 @@ from __future__ import absolute_import -from . import busy +import six from plexnet import playqueue, plexapp, plexlibrary + from lib import util -import six +from . import busy def open(obj, **kwargs): @@ -17,7 +18,7 @@ def open(obj, **kwargs): return handleOpen(photos.PhotoWindow, play_queue=obj, **kwargs) else: from . import videoplayer - videoplayer.play(play_queue=obj) + videoplayer.play(play_queue=obj, **kwargs) return '' elif isinstance(obj, six.string_types): key = obj diff --git a/script.plexmod/lib/windows/optionsdialog.py b/script.plexmod/lib/windows/optionsdialog.py index 317ee6eb4..e6e8f18bd 100644 --- a/script.plexmod/lib/windows/optionsdialog.py +++ b/script.plexmod/lib/windows/optionsdialog.py @@ -1,7 +1,7 @@ from __future__ import absolute_import -from . import kodigui from lib import util +from . import kodigui class OptionsDialog(kodigui.BaseDialog): diff --git a/script.plexmod/lib/windows/pagination.py b/script.plexmod/lib/windows/pagination.py index 474be481c..3e963dd62 100644 --- a/script.plexmod/lib/windows/pagination.py +++ b/script.plexmod/lib/windows/pagination.py @@ -1,7 +1,9 @@ from __future__ import absolute_import -from . import kodigui + from kodi_six import xbmcgui + from lib import util +from . import kodigui class MCLPaginator(object): @@ -271,4 +273,5 @@ def prepareListItem(self, data, mli): mli.setProperty('unwatched.count', str(mli.dataSource.unViewedLeafCount)) else: mli.setProperty('unwatched', not mli.dataSource.isWatched and '1' or '') + mli.setBoolProperty('watched', mli.dataSource.isFullyWatched) mli.setProperty('progress', util.getProgressImage(mli.dataSource)) diff --git a/script.plexmod/lib/windows/photos.py b/script.plexmod/lib/windows/photos.py index ef94ccaf6..fcfe9b1cf 100644 --- a/script.plexmod/lib/windows/photos.py +++ b/script.plexmod/lib/windows/photos.py @@ -1,20 +1,21 @@ from __future__ import absolute_import -import threading -import time + +import hashlib import os import shutil -import hashlib -import requests +import threading +import time -from kodi_six import xbmc, xbmcvfs +import requests +from kodi_six import xbmc from kodi_six import xbmcgui +from plexnet import plexapp, plexplayer, playqueue +from plexnet import util as plexnetUtil -from . import kodigui +from lib import util, colors from . import busy +from . import kodigui -from lib import util, colors -from plexnet import plexapp, plexplayer, playqueue -from plexnet import util as plexnetUtil class PhotoWindow(kodigui.BaseWindow): xmlFile = 'script-plex-photo.xml' diff --git a/script.plexmod/lib/windows/playbacksettings.py b/script.plexmod/lib/windows/playbacksettings.py index 5e614e1ae..b87060851 100644 --- a/script.plexmod/lib/windows/playbacksettings.py +++ b/script.plexmod/lib/windows/playbacksettings.py @@ -1,9 +1,8 @@ # coding=utf-8 -from lib import util -from lib.util import T - from plexnet.util import INTERFACE +from lib import util +from lib.util import T from . import dropdown diff --git a/script.plexmod/lib/windows/playerbackground.py b/script.plexmod/lib/windows/playerbackground.py index e34073b15..31ce2bfaa 100644 --- a/script.plexmod/lib/windows/playerbackground.py +++ b/script.plexmod/lib/windows/playerbackground.py @@ -1,7 +1,9 @@ from __future__ import absolute_import + import contextlib -from . import kodigui + from lib import util +from . import kodigui class PlayerBackground(kodigui.BaseWindow): diff --git a/script.plexmod/lib/windows/playersettings.py b/script.plexmod/lib/windows/playersettings.py index 51fbb5c1b..bea121edb 100644 --- a/script.plexmod/lib/windows/playersettings.py +++ b/script.plexmod/lib/windows/playersettings.py @@ -1,13 +1,13 @@ from __future__ import absolute_import + +import plexnet from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui -from lib import util from lib import metadata +from lib import util from lib.util import T - -import plexnet +from . import kodigui class VideoSettingsDialog(kodigui.BaseDialog, util.CronReceiver): diff --git a/script.plexmod/lib/windows/playlist.py b/script.plexmod/lib/windows/playlist.py index 087bb5c17..c5bfab5c4 100644 --- a/script.plexmod/lib/windows/playlist.py +++ b/script.plexmod/lib/windows/playlist.py @@ -1,25 +1,23 @@ from __future__ import absolute_import + import threading +import plexnet from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui +from six.moves import range +from lib import backgroundthread +from lib import player +from lib import util +from lib.util import T from . import busy -from . import videoplayer -from . import windowutils from . import dropdown -from . import search -import plexnet +from . import kodigui from . import opener - -from lib import colors -from lib import util -from lib import player -from lib import backgroundthread - -from lib.util import T -from six.moves import range +from . import search +from . import videoplayer +from . import windowutils PLAYLIST_PAGE_SIZE = 500 PLAYLIST_INITIAL_SIZE = 100 @@ -114,6 +112,8 @@ def onAction(self, action): try: if action in (xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_PREVIOUS_MENU): self.doClose() + elif self.playlist.playlistType == 'video' and action == xbmcgui.ACTION_CONTEXT_MENU: + return self.plItemPlaybackMenu() except: util.ERROR() @@ -140,10 +140,44 @@ def doClose(self): self.tasks.cancel() ChunkRequestTask.reset() + def plItemPlaybackMenu(self, select_choice='visit'): + mli = self.playlistListControl.getSelectedItem() + if not mli or not mli.dataSource: + return + + can_resume = mli.dataSource.viewOffset.asInt() + + options = [ + {'key': 'visit', 'display': T(33019, 'Visit Media Item')}, + {'key': 'play', 'display': T(33020, 'Play') if not can_resume else T(32317, 'Play from beginning')}, + ] + if can_resume: + options.append({'key': 'resume', 'display': T(32429, 'Resume from {0}').format( + util.timeDisplay(mli.dataSource.viewOffset.asInt()).lstrip('0').lstrip(':'))}) + + choice = dropdown.showDropdown( + options, + pos=(660, 441), + close_direction='none', + set_dropdown_prop=False, + header=T(33021, 'Choose action'), + select_index=2 if select_choice == 'resume' else 1 if util.addonSettings.playlistVisitMedia else 0 + ) + + if not choice: + return + + if choice['key'] == 'visit': + self.openItem(mli.dataSource) + elif choice['key'] == 'play': + self.playlistListClicked(resume=False, play=True) + elif choice['key'] == 'resume': + self.playlistListClicked(resume=True, play=True) + def searchButtonClicked(self): self.processCommand(search.dialog(self)) - def playlistListClicked(self, no_item=False, shuffle=False): + def playlistListClicked(self, no_item=False, shuffle=False, resume=None, play=False): if no_item: mli = None else: @@ -167,17 +201,20 @@ def playlistListClicked(self, no_item=False, shuffle=False): pq = plexnet.playqueue.createPlayQueueForItem(self.playlist, options=args) opener.open(pq) elif self.playlist.playlistType == 'video': - if not util.addonSettings.playlistVisitMedia: + if not util.addonSettings.playlistVisitMedia or play: + if resume is None and bool(mli.dataSource.viewOffset.asInt()): + return self.plItemPlaybackMenu(select_choice='resume') + if self.playlist.leafCount.asInt() <= PLAYLIST_INITIAL_SIZE: self.playlist.setShuffle(shuffle) self.playlist.setCurrent(mli and mli.pos() or 0) - videoplayer.play(play_queue=self.playlist) + videoplayer.play(play_queue=self.playlist, resume=resume) else: args = {'shuffle': shuffle} if mli: args['key'] = mli.dataSource.key pq = plexnet.playqueue.createPlayQueueForItem(self.playlist, options=args) - opener.open(pq) + opener.open(pq, resume=resume) else: if not mli: firstItem = 0 @@ -272,7 +309,8 @@ def createTrackListItem(self, mli, track): def createEpisodeListItem(self, mli, episode): label2 = u'{0} \u2022 {1}'.format( - episode.grandparentTitle, u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), episode.parentIndex, T(32311, 'E'), episode.index) + episode.grandparentTitle, u'{0} \u2022 {1}'.format(T(32310, 'S').format(episode.parentIndex), + T(32311, 'E').format(episode.index)) ) mli.setLabel2(label2) mli.setThumbnailImage(episode.thumb.asTranscodedImageURL(*self.LI_AR16X9_THUMB_DIM)) diff --git a/script.plexmod/lib/windows/playlists.py b/script.plexmod/lib/windows/playlists.py index 12d22bb1f..b2593a83d 100644 --- a/script.plexmod/lib/windows/playlists.py +++ b/script.plexmod/lib/windows/playlists.py @@ -1,17 +1,15 @@ from __future__ import absolute_import + from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui +from plexnet import plexapp +from lib import util from . import busy +from . import kodigui from . import playlist -from . import windowutils from . import search - -from lib import util -from lib import colors - -from plexnet import plexapp +from . import windowutils class PlaylistsWindow(kodigui.ControlledWindow, windowutils.UtilMixin): diff --git a/script.plexmod/lib/windows/preplay.py b/script.plexmod/lib/windows/preplay.py index 49a1b8747..e3f5a3dd1 100644 --- a/script.plexmod/lib/windows/preplay.py +++ b/script.plexmod/lib/windows/preplay.py @@ -2,29 +2,24 @@ from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui +from plexnet import plexplayer, media +from lib import metadata +from lib import util +from lib.util import T from . import busy -from . import opener +from . import dropdown from . import info -from . import videoplayer +from . import kodigui +from . import opener +from . import optionsdialog +from . import pagination from . import playersettings from . import search -from . import dropdown +from . import videoplayer from . import windowutils -from . import optionsdialog -from . import preplayutils -from . import pagination from .mixins import RatingsMixin -from plexnet import plexplayer, media - -from lib import util -from lib import metadata - -from lib.util import T - - VIDEO_RELOAD_KW = dict(includeExtras=1, includeExtrasCount=10, includeChapters=1, includeReviews=1) @@ -310,7 +305,7 @@ def mediaButtonClicked(self): def delete(self): button = optionsdialog.show( T(32326, 'Really delete?'), - T(32327, 'Are you sure you really want to delete this media?'), + T(33035, "Delete {}: {}?").format(type(self.video).__name__, self.video.defaultTitle), T(32328, 'Yes'), T(32329, 'No') ) @@ -528,6 +523,7 @@ def setInfo(self, skip_bg=False): self.setProperty('duration', util.durationToText(self.video.duration.asInt())) self.setProperty('summary', self.video.summary.strip().replace('\t', ' ')) self.setProperty('unwatched', not self.video.isWatched and '1' or '') + self.setBoolProperty('watched', self.video.isFullyWatched) directors = u' / '.join([d.tag for d in self.video.directors()][:3]) directorsLabel = len(self.video.directors) > 1 and T(32401, u'DIRECTORS').upper() or T(32383, u'DIRECTOR').upper() @@ -542,7 +538,7 @@ def setInfo(self, skip_bg=False): self.setProperty('content.rating', '') self.setProperty('thumb', self.video.defaultThumb.asTranscodedImageURL(*self.THUMB_POSTER_DIM)) self.setProperty('preview', self.video.thumb.asTranscodedImageURL(*self.PREVIEW_DIM)) - self.setProperty('info', u'{0} {1} {2} {3}'.format(T(32303, 'Season'), self.video.parentIndex, T(32304, 'Episode'), self.video.index)) + self.setProperty('info', u'{0} {1}'.format(T(32303, 'Season').format(self.video.parentIndex), T(32304, 'Episode').format(self.video.index))) self.setProperty('date', util.cleanLeadingZeros(self.video.originallyAvailableAt.asDatetime('%B %d, %Y'))) self.setProperty('related.header', T(32306, 'Related Shows')) elif self.video.type == 'movie': diff --git a/script.plexmod/lib/windows/preplayutils.py b/script.plexmod/lib/windows/preplayutils.py index 7d000622f..03ea300a6 100644 --- a/script.plexmod/lib/windows/preplayutils.py +++ b/script.plexmod/lib/windows/preplayutils.py @@ -1,7 +1,7 @@ from __future__ import absolute_import -from . import dropdown from lib.util import T +from . import dropdown def chooseVersion(video): diff --git a/script.plexmod/lib/windows/search.py b/script.plexmod/lib/windows/search.py index 2b4e2998c..47394643d 100644 --- a/script.plexmod/lib/windows/search.py +++ b/script.plexmod/lib/windows/search.py @@ -1,17 +1,17 @@ from __future__ import absolute_import -import time + import threading +import time from kodi_six import xbmcgui, xbmc +from plexnet import plexapp +from lib import util +from lib.kodijsonrpc import rpc from . import kodigui from . import opener from . import windowutils -from lib import util -from lib.kodijsonrpc import rpc - -from plexnet import plexapp class SearchDialog(kodigui.BaseDialog, windowutils.UtilMixin): xmlFile = 'script-plex-search.xml' diff --git a/script.plexmod/lib/windows/seekdialog.py b/script.plexmod/lib/windows/seekdialog.py index db1fe423d..f23528f6b 100644 --- a/script.plexmod/lib/windows/seekdialog.py +++ b/script.plexmod/lib/windows/seekdialog.py @@ -1,27 +1,25 @@ from __future__ import absolute_import + import re -import time import threading +import time +from collections import OrderedDict from kodi_six import xbmc from kodi_six import xbmcgui -from collections import OrderedDict - -import lib.cache -from . import kodigui -from . import playersettings -from . import dropdown -from . import busy from plexnet import plexapp - -from lib import util -from plexnet.videosession import VideoSessionInfo, ATTRIBUTE_TYPES as SESSION_ATTRIBUTE_TYPES from plexnet.exceptions import ServerNotOwned, NotFound +from plexnet.videosession import VideoSessionInfo, ATTRIBUTE_TYPES as SESSION_ATTRIBUTE_TYPES +from six.moves import range +import lib.cache +from lib import util from lib.kodijsonrpc import builtin - from lib.util import T -from six.moves import range +from . import busy +from . import dropdown +from . import kodigui +from . import playersettings KEY_MOVE_SET = frozenset( ( @@ -134,7 +132,7 @@ class SeekDialog(kodigui.BaseDialog): SKIP_STEPS = {"negative": [-10000], "positive": [30000]} def __init__(self, *args, **kwargs): - kodigui.BaseDialog.__init__(self, *args, **kwargs) + super(SeekDialog, self).__init__(*args, **kwargs) # fixme: heyo, there's a lot of disorder in here. self.handler = kwargs.get('handler') @@ -292,11 +290,22 @@ def markers(self): if not self._enableMarkerSkip: return None - if not self._markers and hasattr(self.handler.player.video, "markers"): + if self._markers is None and hasattr(self.handler.player.video, "markers"): markers = [] for marker in self.handler.player.video.markers: if marker.type in MARKERS: + # skip completely bad markers + if marker.startTimeOffset.asInt() > self.duration: + continue + + # skip intro markers that are too late + if marker.type == "intro" and \ + marker.startTimeOffset.asInt() > util.addonSettings.introMarkerMaxOffset * 1000: + util.DEBUG_LOG("Throwing away intro marker {}, as its start time offset is bigger than the" + " configured maximum".format(marker)) + continue + m = MARKERS[marker.type].copy() marker.startTimeOffset = marker.startTimeOffset.asInt() \ if not isinstance(marker.startTimeOffset, int) else marker.startTimeOffset @@ -340,10 +349,6 @@ def getCurrentMarkerDef(self, offset=None): marker.endTimeOffset = self.duration util.DEBUG_LOG("Fixing marker endTimeOffset for: {}".format(marker)) - # skip completely bad markers - if marker.startTimeOffset > self.duration: - continue - markerEndNegoff = FINAL_MARKER_NEGOFF if getattr(markerDef["marker"], "final", False) else 0 if startTimeOffset - MARKER_SHOW_NEGOFF <= off < marker.endTimeOffset - markerEndNegoff: @@ -387,6 +392,18 @@ def _onFirstInit(self): self.setBoolProperty('nav.repeat', showRepeat) self.setBoolProperty('nav.ffwdrwd', showFfwdRwd) self.setBoolProperty('nav.shuffle', showShuffle) + navPlaylist = util.getSetting('video_show_playlist', 'eponly') + self.setBoolProperty('nav.playlist', (navPlaylist == "eponly" and + (self.player.video.type == 'episode' or self.handler.playlist)) or + navPlaylist == "always") + + if not self.getProperty('nav.playlist'): + self.subtitleButtonLeft += self.NAVBAR_BTN_SIZE + + navPrevNext = util.getSetting('video_show_prevnext', 'eponly') + self.setBoolProperty('nav.prevnext', (navPrevNext == "eponly" and + (self.player.video.type == 'episode' or self.handler.playlist)) or + navPrevNext == "always") if showQuickSubs: self.subtitleButtonLeft += self.NAVBAR_BTN_SIZE * len( @@ -417,6 +434,7 @@ def setup(self, duration, meta, offset=0, bif_url=None, title='', title2='', cha this is called by our handler and occurs earlier than onFirstInit. """ util.DEBUG_LOG("SeekDialog: setup, keepMarkerDef={}".format(keepMarkerDef)) + self._duration = duration self.title = title self.title2 = title2 self.chapters = chapters or [] @@ -432,17 +450,9 @@ def setup(self, duration, meta, offset=0, bif_url=None, title='', title2='', cha self.killTimeKeeper() - navPlaylist = util.getSetting('video_show_playlist', 'eponly') - self.setBoolProperty('nav.playlist', (navPlaylist == "eponly" and self.player.video.type == 'episode') or - navPlaylist == "always") - if not self.getProperty('nav.playlist'): self.subtitleButtonLeft += self.NAVBAR_BTN_SIZE - navPrevNext = util.getSetting('video_show_prevnext', 'eponly') - self.setBoolProperty('nav.prevnext', (navPrevNext == "eponly" and self.player.video.type == 'episode') or - navPrevNext == "always") - if not self.getProperty('nav.prevnext'): self.subtitleButtonLeft += self.NAVBAR_BTN_SIZE @@ -479,7 +489,6 @@ def setup(self, duration, meta, offset=0, bif_url=None, title='', title2='', cha self.offset = 0 self.idleTime = None self.lastSubtitleNavAction = "forward" - self._duration = duration self._videoBelowOneHour = duration / 3600000 < 1 if self._videoBelowOneHour: self.timeFmtKodi = self.timeFmtKodi.replace("hh:", "") @@ -738,14 +747,14 @@ def onAction(self, action): self.hideOSD() return - if action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK): - if self._osdHideAnimationTimeout: + if action in (xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK, xbmcgui.ACTION_STOP): + if action != xbmcgui.ACTION_STOP and self._osdHideAnimationTimeout: if self._osdHideAnimationTimeout >= time.time(): return else: self._osdHideAnimationTimeout = None - if self.osdVisible(): + if action != xbmcgui.ACTION_STOP and self.osdVisible(): self.hideOSD() else: self.sendTimeline(state=self.player.STATE_STOPPED) @@ -1232,7 +1241,32 @@ def subtitleButtonClicked(self): else: util.setGlobalProperty("current_oshash", '', base='videoinfo.{0}') self.lastSubtitleNavAction = "download" + + # remove the Year info from the current video info tag for better OSS search results + t = self.player.getVideoInfoTag() + changed_info_tag = False + item = xbmcgui.ListItem() + item.setPath(self.player.getPlayingFile()) + if t: + util.DEBUG_LOG("GOGOBO: %s" % t.getSeason()) + year = t.getYear() + if year: + item.setInfo("video", {"year": 0}) + self.player.updateInfoTag(item) + changed_info_tag = year + builtin.ActivateWindow('SubtitleSearch') + # wait for the window to activate + while not xbmc.getCondVisibility('Window.IsActive(SubtitleSearch)'): + util.MONITOR.waitForAbort(0.1) + # wait for the window to close + while xbmc.getCondVisibility('Window.IsActive(SubtitleSearch)'): + util.MONITOR.waitForAbort(0.1) + + if changed_info_tag: + item.setInfo("video", {"year": changed_info_tag}) + self.player.updateInfoTag(item) + elif choice['key'] == 'delay': self.hideOSD() self.lastSubtitleNavAction = "delay" @@ -1361,14 +1395,25 @@ def updateProperties(self, **kwargs): self.setFocusId(self.MAIN_BUTTON_ID) self.fromSeek = 0 + v = self.player.video + is_show = v.type == 'episode' + self.setProperty('has.bif', self.bifURL and '1' or '') self.setProperty('video.title', self.title) self.setProperty('video.title2', self.title2) - self.setProperty('is.show', (self.player.video.type == 'episode') and '1' or '') + self.setProperty('is.show', is_show and '1' or '') self.setProperty('media.show_ends', self.showItemEndsInfo and '1' or '') self.setProperty('time.ends_label', self.showItemEndsLabel and (util.T(32543, 'Ends at')) or '') self.setBoolProperty('no.osd.hide_info', util.getSetting('no_spoilers', False)) + no_spoilers = util.getSetting('no_episode_spoilers2', "unwatched") + hide_title = False + if is_show and no_spoilers != "off" and util.getSetting('no_unwatched_episode_titles', False): + hide_title = ((no_spoilers == 'funwatched' and not v.isFullyWatched) or + (no_spoilers == 'unwatched' and not v.isWatched)) + + self.setBoolProperty('hide.title', hide_title) + if self.isDirectPlay: self.setProperty('time.fmt', self.timeFmtKodi) self.setProperty('time.fmt.ends', util.timeFormatKN.replace(":ss", "")) @@ -2143,10 +2188,14 @@ def playlistDialogVisible(self, value): self.setProperty('playlist.visible', '1' if value else '') def showPlaylistDialog(self): + created = False if not self.playlistDialog: self.playlistDialog = PlaylistDialog.create(show=False, handler=self.handler) + created = True self.playlistDialogVisible = True + if not created: + self.playlistDialog.updatePlayingItem() self.playlistDialog.doModal() self.resetTimeout() self.playlistDialogVisible = False @@ -2231,14 +2280,15 @@ def createListItem(self, pi): def createEpisodeListItem(self, episode): label2 = u'{0} \u2022 {1}'.format( episode.grandparentTitle, - u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), episode.parentIndex, T(32311, 'E'), episode.index) + u'{0} \u2022 {1}'.format(T(32310, 'S').format(episode.parentIndex), T(32311, 'E').format(episode.index)) ) mli = kodigui.ManagedListItem(episode.title, label2, thumbnailImage=episode.thumb.asTranscodedImageURL(*self.LI_AR16X9_THUMB_DIM), data_source=episode) mli.setProperty('track.duration', util.durationToShortText(episode.duration.asInt())) mli.setProperty('video', '1') - mli.setProperty('watched', episode.isWatched and '1' or '') + mli.setProperty('unwatched', not episode.isWatched and '1' or '') + mli.setProperty('watched', episode.isFullyWatched and '1' or '') return mli def createMovieListItem(self, movie): @@ -2247,7 +2297,8 @@ def createMovieListItem(self, movie): data_source=movie) mli.setProperty('track.duration', util.durationToShortText(movie.duration.asInt())) mli.setProperty('video', '1') - mli.setProperty('watched', movie.isWatched and '1' or '') + mli.setProperty('unwatched', not movie.isWatched and '1' or '') + mli.setProperty('watched', movie.isFullyWatched and '1' or '') return mli def playQueueCallback(self, **kwargs): diff --git a/script.plexmod/lib/windows/settings.py b/script.plexmod/lib/windows/settings.py index 5b1d8a011..339612bfb 100644 --- a/script.plexmod/lib/windows/settings.py +++ b/script.plexmod/lib/windows/settings.py @@ -1,17 +1,16 @@ from __future__ import absolute_import + +import sys + +import plexnet from kodi_six import xbmc from kodi_six import xbmcgui -from kodi_six import xbmcvfs import lib.cache -from . import kodigui -from . import windowutils - from lib import util from lib.util import T - -import plexnet -import sys +from . import kodigui +from . import windowutils class Setting(object): @@ -257,13 +256,33 @@ class Settings(object): T(32100, 'Skip user selection and pin entry on startup.') ), BoolSetting( - 'speedy_home_hubs2', T(33503, 'Use alternative hubs refresh'), False + 'use_alt_watched', T(33022, ''), True ).description( - T( - 33504, - "Refreshes all hubs for all libraries after an item's watch-state has changed, instead of " - "only those likely affected. Use this if you find a hub that doesn't update properly." + T(33023, "") + ), + BoolSetting( + 'hide_aw_bg', T(33024, ''), False + ).description( + T(33025, "") + ), + OptionsSetting( + 'no_episode_spoilers2', T(33006, ''), + 'unwatched', + ( + ('off', T(32481, '')), + ('unwatched', T(33010, '')), + ('funwatched', T(33011, '')), ) + ).description(T(33007, "")), + BoolSetting( + 'no_unwatched_episode_titles', T(33012, ''), True + ).description( + T(33013, "") + ), + BoolSetting( + 'spoilers_allowed_genres', T(33016, ''), True + ).description( + T(33017, "").format(", ".join('"{}"'.format(t) for t in util.SPOILER_ALLOWED_GENRES)) ), BoolSetting( 'hubs_use_new_continue_watching', T(32998, ''), False @@ -275,6 +294,11 @@ class Settings(object): ).description( T(32962, "Visually separate hubs horizontally using a thin line.") ), + BoolSetting( + 'path_mapping_indicators', T(33032, 'Show path mapping indicators'), True + ).description( + T(33033, "When path mapping is active for a library, display an indicator.") + ), BoolSetting( 'search_use_kodi_kbd', T(32955, 'Use Kodi keyboard for searching'), False ), @@ -393,14 +417,14 @@ class Settings(object): OptionsSetting( 'video_show_playlist', T(32936, 'Show playlist button'), 'eponly', ( - ('always', T(32035, 'Always')), ('eponly', T(32938, 'Only for Episodes')), + ('always', T(32035, 'Always')), ('eponly', T(32938, 'Only for Episodes/Playlists')), ('never', T(32033, 'Never')) ) ).description(T(32939, 'Only applies to video player UI')), OptionsSetting( 'video_show_prevnext', T(32937, 'Show prev/next button'), 'eponly', ( - ('always', T(32035, 'Always')), ('eponly', T(32938, 'Only for Episodes')), + ('always', T(32035, 'Always')), ('eponly', T(32938, 'Only for Episodes/Playlists')), ('never', T(32033, 'Never')) ) ).description(T(32939, 'Only applies to video player UI')), diff --git a/script.plexmod/lib/windows/signin.py b/script.plexmod/lib/windows/signin.py index 444933662..257f3361d 100644 --- a/script.plexmod/lib/windows/signin.py +++ b/script.plexmod/lib/windows/signin.py @@ -1,7 +1,9 @@ from __future__ import absolute_import + from kodi_six import xbmcgui -from . import kodigui + from lib import util +from . import kodigui class Background(kodigui.BaseWindow): diff --git a/script.plexmod/lib/windows/slidehshow.py b/script.plexmod/lib/windows/slidehshow.py index efb0b0df1..65eb27adf 100644 --- a/script.plexmod/lib/windows/slidehshow.py +++ b/script.plexmod/lib/windows/slidehshow.py @@ -1,10 +1,11 @@ -import time import random +import time -from . import kodigui +from plexnet import plexapp from lib import util -from plexnet import plexapp +from . import kodigui + class Slideshow(kodigui.BaseWindow, util.CronReceiver): xmlFile = 'script-plex-slideshow.xml' diff --git a/script.plexmod/lib/windows/subitems.py b/script.plexmod/lib/windows/subitems.py index 4cac3536a..6b7e800e2 100644 --- a/script.plexmod/lib/windows/subitems.py +++ b/script.plexmod/lib/windows/subitems.py @@ -1,30 +1,28 @@ from __future__ import absolute_import + import gc from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui +from plexnet import playlist -from lib import util from lib import metadata from lib import player - -from plexnet import playlist - +from lib import util +from lib.util import T from . import busy +from . import dropdown from . import episodes -from . import tracks -from . import opener from . import info +from . import kodigui from . import musicplayer -from . import videoplayer -from . import dropdown -from . import windowutils -from . import search +from . import opener from . import pagination from . import playbacksettings - -from lib.util import T +from . import search +from . import tracks +from . import videoplayer +from . import windowutils from .mixins import SeasonsMixin, DeleteMediaMixin, RatingsMixin @@ -404,7 +402,7 @@ def playButtonClicked(self, shuffle=False): pl = playlist.LocalPlaylist(items, self.mediaItem.getServer()) resume = False if not shuffle and self.mediaItem.type == 'show': - resume = self.getPlaylistResume(pl, items, self.mediaItem.title) + resume = self.getNextShowEp(pl, items, self.mediaItem.title) if resume is None: return @@ -487,7 +485,11 @@ def optionsButtonClicked(self, from_item=None): if self.delete(item): # cheap way of requesting a home hub refresh because of major deletion util.MONITOR.watchStatusChanged() - self.goHome() + self.initialized = False + self.setBoolProperty("initialized", False) + self.setup() + self.initialized = True + self.setFocusId(self.PLAY_BUTTON_ID) def roleClicked(self): mli = self.rolesListControl.getSelectedItem() diff --git a/script.plexmod/lib/windows/tracks.py b/script.plexmod/lib/windows/tracks.py index de7e511fd..b000a6b9b 100644 --- a/script.plexmod/lib/windows/tracks.py +++ b/script.plexmod/lib/windows/tracks.py @@ -1,21 +1,18 @@ from __future__ import absolute_import + from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui - -from lib import player -from lib import util - from plexnet import playlist +from lib import util +from lib.util import T from . import busy -from . import musicplayer from . import dropdown -from . import windowutils +from . import kodigui +from . import musicplayer from . import opener from . import search - -from lib.util import T +from . import windowutils class AlbumWindow(kodigui.ControlledWindow, windowutils.UtilMixin): diff --git a/script.plexmod/lib/windows/userselect.py b/script.plexmod/lib/windows/userselect.py index 12b475355..3175d562d 100644 --- a/script.plexmod/lib/windows/userselect.py +++ b/script.plexmod/lib/windows/userselect.py @@ -1,15 +1,14 @@ from __future__ import absolute_import + from kodi_six import xbmc from kodi_six import xbmcgui - -from . import kodigui -from . import dropdown -from . import busy - -from lib import util from plexnet import plexapp +from lib import util from lib.util import T +from . import busy +from . import dropdown +from . import kodigui class UserSelectWindow(kodigui.BaseWindow): diff --git a/script.plexmod/lib/windows/videoplayer.py b/script.plexmod/lib/windows/videoplayer.py index fc0269e1b..c2e547238 100644 --- a/script.plexmod/lib/windows/videoplayer.py +++ b/script.plexmod/lib/windows/videoplayer.py @@ -1,26 +1,25 @@ from __future__ import absolute_import -import time -import threading + import math +import threading +import time from kodi_six import xbmc from kodi_six import xbmcgui -from . import kodigui -from . import windowutils -from . import opener -from . import busy -from . import search -from . import dropdown -from . import pagination - -from lib import util -from lib import player from lib import colors from lib import kodijsonrpc - +from lib import player +from lib import util from lib.util import T - +from . import busy +from . import dropdown +from . import kodigui +from . import opener +from . import pagination +from . import search +from . import windowutils +from .mixins import SpoilersMixin PASSOUT_PROTECTION_DURATION_SECONDS = 7200 PASSOUT_LAST_VIDEO_DURATION_MILLIS = 1200000 @@ -44,17 +43,20 @@ def readyForPaging(self): def prepareListItem(self, data, mli): mli.setProperty('progress', util.getProgressImage(mli.dataSource)) mli.setProperty('unwatched', not mli.dataSource.isWatched and '1' or '') + mli.setProperty('watched', mli.dataSource.isFullyWatched and '1' or '') if data.type in 'episode': mli.setLabel2( - u'{0}{1} \u2022 {2}{3}'.format(T(32310, 'S'), data.parentIndex, T(32311, 'E'), data.index)) + u'{0} \u2022 {1}'.format(T(32310, 'S').format(data.parentIndex), T(32311, 'E').format(data.index))) else: mli.setLabel2(data.year) def createListItem(self, ondeck): title = ondeck.grandparentTitle or ondeck.title if ondeck.type == 'episode': - thumb = ondeck.thumb.asTranscodedImageURL(*self.parentWindow.ONDECK_DIM) + hide_spoilers = self.parentWindow.hideSpoilers(ondeck, use_cache=False) + thumb_opts = self.parentWindow.getThumbnailOpts(ondeck, hide_spoilers=hide_spoilers) + thumb = ondeck.thumb.asTranscodedImageURL(*self.parentWindow.ONDECK_DIM, **thumb_opts) else: thumb = ondeck.defaultArt.asTranscodedImageURL(*self.parentWindow.ONDECK_DIM) @@ -63,10 +65,13 @@ def createListItem(self, ondeck): return mli def getData(self, offset, amount): - return (self.parentWindow.prev or self.parentWindow.next).sectionOnDeck(offset=offset, limit=amount) + data = (self.parentWindow.prev or self.parentWindow.next).sectionOnDeck(offset=offset, limit=amount) + if self.parentWindow.next: + return list(filter(lambda x: x.ratingKey != self.parentWindow.next.ratingKey, data)) + return data -class VideoPlayerWindow(kodigui.ControlledWindow, windowutils.UtilMixin): +class VideoPlayerWindow(kodigui.ControlledWindow, windowutils.UtilMixin, SpoilersMixin): xmlFile = 'script-plex-video_player.xml' path = util.ADDON.getAddonInfo('path') theme = 'Main' @@ -97,6 +102,7 @@ class VideoPlayerWindow(kodigui.ControlledWindow, windowutils.UtilMixin): def __init__(self, *args, **kwargs): kodigui.ControlledWindow.__init__(self, *args, **kwargs) windowutils.UtilMixin.__init__(self) + SpoilersMixin.__init__(self, *args, **kwargs) self.playQueue = kwargs.get('play_queue') self.video = kwargs.get('video') self.resume = bool(kwargs.get('resume')) @@ -129,6 +135,9 @@ def doClose(self): def onFirstInit(self): player.PLAYER.on('session.ended', self.sessionEnded) player.PLAYER.on('av.started', self.playerPlaybackStarted) + player.PLAYER.on('starting.video', self.onVideoStarting) + player.PLAYER.on('started.video', self.onVideoStarted) + player.PLAYER.on('changed.video', self.onVideoChanged) player.PLAYER.on('post.play', self.postPlay) player.PLAYER.on('change.background', self.changeBackground) @@ -140,6 +149,16 @@ def onFirstInit(self): self.resetPassoutProtection() self.play(resume=self.resume) + def onVideoStarting(self, *args, **kwargs): + util.setGlobalProperty('ignore_spinner', '1') + + def onVideoStarted(self, *args, **kwargs): + util.setGlobalProperty('ignore_spinner', '') + + def onVideoChanged(self, *args, **kwargs): + #util.setGlobalProperty('ignore_spinner', '') + pass + def onReInit(self): self.setBackground() @@ -472,14 +491,26 @@ def getHubs(self): self.setProperty('has.next', '1') def setInfo(self): + hide_spoilers = False + if self.next and self.next.type == "episode": + hide_spoilers = self.hideSpoilers(self.next, use_cache=False) if self.next: self.setProperty( 'post.play.background', util.backgroundFromArt(self.next.art, width=self.width, height=self.height) ) - self.setProperty('info.title', self.next.title) + if self.next.type == "episode" and hide_spoilers: + if self.noTitles: + self.setProperty('info.title', + u'{0} \u2022 {1}'.format(T(32310, 'S').format(self.next.parentIndex), + T(32311, 'E').format(self.next.index))) + else: + self.setProperty('info.title', self.next.title) + self.setProperty('info.summary', T(33008, '')) + else: + self.setProperty('info.title', self.next.title) + self.setProperty('info.summary', self.next.summary) self.setProperty('info.duration', util.durationToText(self.next.duration.asInt())) - self.setProperty('info.summary', self.next.summary) if self.prev: self.setProperty( @@ -493,18 +524,25 @@ def setInfo(self): if self.prev.type == 'episode': self.setProperty('related.header', T(32306, 'Related Shows')) if self.next: - self.setProperty('next.thumb', self.next.thumb.asTranscodedImageURL(*self.NEXT_DIM)) - self.setProperty('info.date', util.cleanLeadingZeros(self.next.originallyAvailableAt.asDatetime('%B %d, %Y'))) + thumb_opts = {} + if hide_spoilers: + thumb_opts = self.getThumbnailOpts(self.next, hide_spoilers=hide_spoilers) + self.setProperty('next.thumb', self.next.thumb.asTranscodedImageURL(*self.NEXT_DIM, **thumb_opts)) + self.setProperty('info.date', + util.cleanLeadingZeros(self.next.originallyAvailableAt.asDatetime('%B %d, %Y'))) self.setProperty('next.title', self.next.grandparentTitle) self.setProperty( - 'next.subtitle', u'{0} {1} \u2022 {2} {3}'.format(T(32303, 'Season'), self.next.parentIndex, T(32304, 'Episode'), self.next.index) + 'next.subtitle', + u'{0} \u2022 {1}'.format(T(32303, 'Season').format(self.next.parentIndex), + T(32304, 'Episode').format(self.next.index)) ) if self.prev: self.setProperty('prev.thumb', self.prev.thumb.asTranscodedImageURL(*self.PREV_DIM)) self.setProperty('prev.title', self.prev.grandparentTitle) self.setProperty( - 'prev.subtitle', u'{0} {1} \u2022 {2} {3}'.format(T(32303, 'Season'), self.prev.parentIndex, T(32304, 'Episode'), self.prev.index) + 'prev.subtitle', u'{0} \u2022 {1}'.format(T(32303, 'Season').format(self.prev.parentIndex), + T(32304, 'Episode').format(self.prev.index)) ) self.setProperty('prev.info.date', util.cleanLeadingZeros(self.prev.originallyAvailableAt.asDatetime('%B %d, %Y'))) elif self.prev.type == 'movie': @@ -610,6 +648,9 @@ def play(video=None, play_queue=None, resume=False): player.PLAYER.off('session.ended', w.sessionEnded) player.PLAYER.off('post.play', w.postPlay) player.PLAYER.off('av.started', w.playerPlaybackStarted) + player.PLAYER.off('starting.video', w.onVideoStarting) + player.PLAYER.off('started.video', w.onVideoStarted) + player.PLAYER.off('changed.video', w.onVideoChanged) player.PLAYER.off('change.background', w.changeBackground) player.PLAYER.reset() command = w.exitCommand diff --git a/script.plexmod/lib/windows/windowutils.py b/script.plexmod/lib/windows/windowutils.py index 9914d8c87..edf5415e3 100644 --- a/script.plexmod/lib/windows/windowutils.py +++ b/script.plexmod/lib/windows/windowutils.py @@ -1,10 +1,9 @@ from __future__ import absolute_import -from lib import util -from . import opener -from . import dropdown +from lib import util from lib.util import T - +from . import dropdown +from . import opener HOME = None @@ -41,37 +40,50 @@ def showAudioPlayer(self, **kwargs): from . import musicplayer self.processCommand(opener.handleOpen(musicplayer.MusicPlayerWindow, **kwargs)) - def getPlaylistResume(self, pl, items, title): - resume = False + def getNextShowEp(self, pl, items, title): + revitems = list(reversed(items)) + in_progress = [i for i in revitems if i.get('viewOffset').asInt()] + if in_progress: + n = in_progress[0] + pl.setCurrent(n) + choice = dropdown.showDropdown( + options=[ + {'key': 'resume', 'display': T(32429, 'Resume from {0}').format( + util.timeDisplay(n.viewOffset.asInt()).lstrip('0').lstrip(':'))}, + {'key': 'play', 'display': T(32317, 'Play from beginning')} + ], + pos=(660, 441), + close_direction='none', + set_dropdown_prop=False, + header=u'{0} - {1} \u2022 {2}'.format(title, + T(32310, 'S').format(n.parentIndex), + T(32311, 'E').format(n.index)) + ) + + if not choice: + return None + + if choice['key'] == 'resume': + return True + return False + watched = False - for i in items: - if (watched and not i.isWatched) or i.get('viewOffset').asInt(): - if i.get('viewOffset'): - choice = dropdown.showDropdown( - options=[ - {'key': 'resume', 'display': T(32429, 'Resume from {0}').format(util.timeDisplay(i.viewOffset.asInt()).lstrip('0').lstrip(':'))}, - {'key': 'play', 'display': T(32317, 'Play from beginning')} - ], - pos=(660, 441), - close_direction='none', - set_dropdown_prop=False, - header=u'{0} - {1}{2} \u2022 {3}{4}'.format(title, T(32310, 'S'), i.parentIndex, T(32311, 'E'), i.index) - ) - - if not choice: - return None - - if choice['key'] == 'resume': - resume = True - - pl.setCurrent(i) - break - elif i.isWatched: + for (k, i) in enumerate(revitems): + if watched: + try: + pl.setCurrent(revitems[k-2]) + return False + except IndexError: + break + if i.get('viewCount').asInt() > 0: watched = True - else: - break - return resume + non_special = [i for i in revitems if i.get('parentIndex').asInt() and i.get('viewCount').asInt() == 0] + use = items[0] + if non_special: + use = non_special[-1] + pl.setCurrent(use) + return False def shutdownHome(): diff --git a/script.plexmod/resources/language/resource.language.de_de/strings.po b/script.plexmod/resources/language/resource.language.de_de/strings.po index 37a347e3d..d5ae2aa65 100644 --- a/script.plexmod/resources/language/resource.language.de_de/strings.po +++ b/script.plexmod/resources/language/resource.language.de_de/strings.po @@ -4,7 +4,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: POEditor.com\n" -"Project-Id-Version: PM4K\n" +"Project-Id-Version: PM4K / PlexMod for Kodi\n" "Language: de\n" #: @@ -95,7 +95,7 @@ msgstr "Qualität für entfernte Geräte" #: msgctxt "#32022" msgid "Online Quality" -msgstr "Online Qualität" +msgstr "Online-Qualität" #: msgctxt "#32023" @@ -115,7 +115,7 @@ msgstr "Direkte Wiedergabe erlauben" #: msgctxt "#32026" msgid "Allow Direct Stream" -msgstr "Direktes streamen erlauben" +msgstr "Direktes Streamen erlauben" #: msgctxt "#32027" @@ -130,18 +130,13 @@ msgstr "Immer" #: msgctxt "#32029" msgid "Only Image Formats" -msgstr "nur Bildformate" +msgstr "Nur Bildformate" #: msgctxt "#32030" msgid "Auto" msgstr "Automatisch" -#: -msgctxt "#32031" -msgid "Burn-in Subtitles" -msgstr "Untertitel einbrennen" - #: msgctxt "#32032" msgid "Allow Insecure Connections" @@ -185,17 +180,17 @@ msgstr "Automatisch nächsten Titel abspielen" #: msgctxt "#32040" msgid "Enable Subtitle Downloading" -msgstr "Untertitel download aktivieren" +msgstr "Untertitel-Download aktivieren" #: msgctxt "#32041" msgid "Enable Subtitle Downloading" -msgstr "Untertitel download aktivieren" +msgstr "Untertitel-Download aktivieren" #: msgctxt "#32042" msgid "Server Discovery (GDM)" -msgstr "Server Erkennung (GDM)" +msgstr "Server-Erkennung (GDM)" #: msgctxt "#32043" @@ -255,12 +250,12 @@ msgstr "Video" #: msgctxt "#32054" msgid "Addon Version" -msgstr "Erweiterung Version" +msgstr "Version der Erweiterung" #: msgctxt "#32055" msgid "Kodi Version" -msgstr "Kodi Version" +msgstr "Kodi-Version" #: msgctxt "#32056" @@ -270,7 +265,7 @@ msgstr "Bilschirmauflösung" #: msgctxt "#32057" msgid "Current Server Version" -msgstr "Aktuelle Server Version" +msgstr "Aktuelle Server-Version" #: msgctxt "#32058" @@ -287,41 +282,11 @@ msgctxt "#32060" msgid "Use Kodi audio channels" msgstr "Kodi-Audiokanäle verwenden" -#: -msgctxt "#32061" -msgid "When transcoding audio, target the audio channels set in Kodi." -msgstr "Beim Transkodieren von Audio werden die in Kodi eingestellten Audiokanäle verwendet." - -#: -msgctxt "#32062" -msgid "Transcode audio to AC3" -msgstr "Transkodiere Ton zu AC3" - -#: -msgctxt "#32063" -msgid "Transcode audio to AC3 in certain conditions (useful for passthrough)." -msgstr "Transkodiere Ton zu AC3 in bestimmten Umständen (nützlich für Passthrough)" - #: msgctxt "#32064" msgid "Treat DTS like AC3" msgstr "DTS wie AC3 behandeln" -#: -msgctxt "#32065" -msgid "When any of the force AC3 settings are enabled, treat DTS the same as AC3 (useful for Optical passthrough)" -msgstr "Wenn einer der AC3 Optionen aktiviert ist, wird DTS wie AC3 behandelt (nützlich für Optical Passthrough)" - - -msgctxt "#32066" -msgid "Force audio to AC3" -msgstr "Audio immer als AC3 erzwingen" - - -msgctxt "#32067" -msgid "Only force multichannel audio to AC3" -msgstr "Nur Mehrkanal-Audio als AC3 erzwingen" - #: msgctxt "#32100" msgid "Skip user selection and pin entry on startup." @@ -330,22 +295,22 @@ msgstr "Benutzerauswahl und Pin-Eingabe beim Start überspringen." #: msgctxt "#32101" msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." -msgstr "Falls aktiviert wird, sofern verfügbar, nachdem die Wiedergabe endet ein 'nächster Titel' automatisch nach 15 Sekunden gestartet." +msgstr "Falls die Option aktiviert und ein weiterer Titel verfügbar ist, wird dieser 15 Sekunden nach der aktuellen Wiedergabe gestartet." #: msgctxt "#32102" msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." -msgstr "Aktiviert 4K Wiedergabe per Hardware. Deaktivierung erzwingt Transcodierung." +msgstr "Aktiviert 4K-Wiedergabe per Hardware. Deaktivierung erzwingt Transcodierung." #: msgctxt "#32103" msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." -msgstr "Aktiviert HEVC/H265 Wiedergabe per Hardware. Deaktivierung erzwingt Transcodierung." +msgstr "Aktiviert HEVC/H265-Wiedergabe per Hardware. Deaktivierung erzwingt Transcodierung." #: msgctxt "#32104" msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" -msgstr "Wann soll zu Servern ohne 'sichere Verbindung' verbunden werden[CR]* [B]Nie[/B]: Niemals unsicher zu eine Server verbinden.[CR]* [B]Im selben Netzwerk[/B]: Im selben Netzwerk erlauben[CR]* [B]Immer[/B]: Im selben Netzwerk und bei entfernter Verbindung erlauben" +msgstr "Wann soll zu Servern ohne 'sichere Verbindung' verbunden werden?[CR][CR]* [B]Nie[/B]: Niemals unsicher zu eine Server verbinden.[CR]* [B]Im selben Netzwerk[/B]: Im selben Netzwerk erlauben[CR]* [B]Immer[/B]: Im selben Netzwerk und bei entfernter Verbindung erlauben" #: msgctxt "#32201" @@ -380,7 +345,7 @@ msgstr "Szene" #: msgctxt "#32207" msgid "Live Music Video" -msgstr "Live Musikvideo" +msgstr "Live-Musikvideo" #: msgctxt "#32208" @@ -422,16 +387,6 @@ msgctxt "#32302" msgid "Go to {0}" msgstr "Gehe zu {0}" -#: -msgctxt "#32303" -msgid "Season" -msgstr "Staffel" - -#: -msgctxt "#32304" -msgid "Episode" -msgstr "Folge" - #: msgctxt "#32305" msgid "Extras" @@ -445,7 +400,7 @@ msgstr "Ähnliche Serien" #: msgctxt "#32307" msgid "More" -msgstr "Film" +msgstr "Mehr" #: msgctxt "#32308" @@ -457,16 +412,6 @@ msgctxt "#32309" msgid "None" msgstr "Ohne" -#: -msgctxt "#32310" -msgid "S" -msgstr "S" - -#: -msgctxt "#32311" -msgid "E" -msgstr "E" - #: msgctxt "#32312" msgid "Unavailable" @@ -545,7 +490,7 @@ msgstr "Wirklich löschen?" #: msgctxt "#32327" msgid "Are you sure you really want to delete this media?" -msgstr "Soll diese Mediandatei wirklich gelöscht werden?" +msgstr "Soll diese Mediendatei wirklich gelöscht werden?" #: msgctxt "#32328" @@ -585,7 +530,7 @@ msgstr "Beenden bestätigen" #: msgctxt "#32335" msgid "Are you ready to exit Plex?" -msgstr "Bereit um Plex zu beenden?" +msgstr "Bereit, um Plex zu beenden?" #: msgctxt "#32336" @@ -615,7 +560,7 @@ msgstr "Verbindungstests laufen. Bitte warten." #: msgctxt "#32341" msgid "Server is not accessible. Please sign into your server and check your connection." -msgstr "Der Server ist nicht erreichbar. Bitte einloggen und Verbindung prüfen." +msgstr "Der Server ist nicht erreichbar. Bitte am Server einloggen und Verbindung prüfen." #: msgctxt "#32342" @@ -900,12 +845,12 @@ msgstr "Qualität" #: msgctxt "#32398" msgid "Kodi Video Settings" -msgstr "Kodi Bild Einstellungen" +msgstr "Kodi-Bildeinstellungen" #: msgctxt "#32399" msgid "Kodi Audio Settings" -msgstr "Kodi Ton Einstellungen" +msgstr "Kodi-Toneinstellungen" #: msgctxt "#32400" @@ -925,7 +870,7 @@ msgstr "Autor(in)" #: msgctxt "#32403" msgid "Writers" -msgstr "Autoren" +msgstr "Autor(inn)en" #: msgctxt "#32404" @@ -940,7 +885,7 @@ msgstr "Untertitel downloaden" #: msgctxt "#32406" msgid "Subtitle Delay" -msgstr "Untertitel Verzögerung" +msgstr "Untertitel-Verzögerung" #: msgctxt "#32407" @@ -950,7 +895,7 @@ msgstr "Nächster Untertitel" #: msgctxt "#32408" msgid "Disable Subtitles" -msgstr "Untertitel deaktiviren" +msgstr "Untertitel deaktivieren" #: msgctxt "#32409" @@ -960,7 +905,7 @@ msgstr "Untertitel aktivieren" #: msgctxt "#32410" msgid "Platform Version" -msgstr "Platform Version" +msgstr "Platform-Version" #: msgctxt "#32411" @@ -975,7 +920,7 @@ msgstr "Bearbeiten oder bereinigen" #: msgctxt "#32413" msgid "Edit IP address or clear the current setting?" -msgstr "IP Adresse bearbeiten oder die aktuellen Einstellungen bereinigen?" +msgstr "IP-Adresse bearbeiten oder die aktuellen Einstellungen bereinigen?" #: msgctxt "#32414" @@ -990,12 +935,12 @@ msgstr "Ändern" #: msgctxt "#32416" msgid "Enter IP Address" -msgstr "IP Adresse eingeben" +msgstr "IP-Adresse eingeben" #: msgctxt "#32417" msgid "Enter Port Number" -msgstr "Port Nummer eingeben" +msgstr "Port-Nummer eingeben" #: msgctxt "#32418" @@ -1080,7 +1025,7 @@ msgstr "Bereinigen" #: msgctxt "#32434" msgid "Searching..." -msgstr "Suche..." +msgstr "Suche ..." #: msgctxt "#32435" @@ -1142,6 +1087,7 @@ msgctxt "#32446" msgid "Stereo" msgstr "Stereo" +#. Depending on context, this could also be translated differently. Same with all the "none"s in the list #: msgctxt "#32447" msgid "None" @@ -1165,12 +1111,12 @@ msgstr "Version auswählen" #: msgctxt "#32451" msgid "Play Version..." -msgstr "Version abspielen..." +msgstr "Version abspielen ..." #: msgctxt "#32452" msgid "No Content available in this library" -msgstr "In dieser Bibliothek ist nichts vorhanden" +msgstr "Keine Inhalte in dieser Bibliothek vorhanden" #: msgctxt "#32453" @@ -1240,7 +1186,7 @@ msgstr "Skip-Schritte-Einstellung von Kodi benutzen" #: msgctxt "#32466" msgid "Automatically seek selected position after a delay" -msgstr "Automatisch verzögert zur ausgewählten Position springen" +msgstr "Nach Verzögerung automatisch zur ausgewählten Position springen" #: msgctxt "#32467" @@ -1277,6 +1223,7 @@ msgctxt "#32481" msgid "Off" msgstr "Aus" +#. What is going on here? #: msgctxt "#32482" msgid "%(percentage)s %%" @@ -1285,17 +1232,17 @@ msgstr "%(percentage)s %%" #: msgctxt "#32483" msgid "Hide Stream Info" -msgstr "Stream Info nicht anzeigen" +msgstr "Stream-Info nicht anzeigen" #: msgctxt "#32484" msgid "Show Stream Info" -msgstr "Stream Info anzeigen" +msgstr "Stream-Info anzeigen" #: msgctxt "#32485" msgid "Go back instantly with the previous menu action in scrolled views" -msgstr "Mit der Previous-Menu-Aktion In gescrollten Ansichten sofort zurückgehen" +msgstr "Mit 'Vorheriges Menü' in gescrollten Ansichten sofort zurückgehen" #: msgctxt "#32487" @@ -1325,12 +1272,7 @@ msgstr "Ordner" #: msgctxt "#32492" msgid "Kodi Subtitle Settings" -msgstr "Kodi Untertitel-Einstellungen" - -#: -msgctxt "#32493" -msgid "When a media file has a forced/foreign subtitle for a subtitle-enabled language, the Plex Media Server preselects it. This behaviour is usually not necessary and not configurable. This setting fixes that by ignoring the PMSs decision and selecting the same language without a forced flag if possible." -msgstr "Hat eine Mediendatei erzwungenge Untertitel für eine Sprache, bei der Untertitel erwünscht sind, wählt der Plex Media Server diesen standardmäßig aus. Das Verhalten ist normalerweise unerwünscht und nicht konfigurierbar. Diese Einstellung behebt das Problem, indem versucht wird, einen Untertitel der selben Sprache ohne Erzwungen-Markierung zu wählen." +msgstr "Kodi-Untertiteleinstellungen" #: msgctxt "#32495" @@ -1345,12 +1287,12 @@ msgstr "Abspann überspringen" #: msgctxt "#32500" msgid "Always show post-play screen (even for short videos)" -msgstr "Immer den Nachwiedergabe-Bildschirm anzeigen (auch bei kurzen Videos)" +msgstr "Immer den Nach-Wiedergabe-Bildschirm anzeigen (auch bei kurzen Videos)" #: msgctxt "#32501" msgid "Time-to-wait between videos on post-play" -msgstr "Wartezeit zwischen Videos bei Nachwiedergabe" +msgstr "Wartezeit zwischen Videos bei Nach-Wiedergabe" #: msgctxt "#32505" @@ -1360,18 +1302,13 @@ msgstr "Medien in der Video-Wiedergabeliste anzeigen, anstatt sie abzuspielen" #: msgctxt "#32521" msgid "Skip Intro Button Timeout" -msgstr "Zeitlimit für die Schaltfläche Intro überspringen" +msgstr "Zeitlimit für die Schaltfläche 'Intro überspringen'" #: msgctxt "#32522" msgid "Automatically Skip Intro" msgstr "Intro automatisch überspringen" -#: -msgctxt "#32523" -msgid "Automatically skip intros if available. Doesn't override enabled binge mode.\nCan be disabled/enabled per TV show." -msgstr "Automatisches Überspringen von Intros, falls vorhanden. Überschreibt aktivierten Binge-Modus nicht.\nKann pro Serie aktiviert/deaktiviert werden." - #: msgctxt "#32524" msgid "Set how long the skip intro button shows for." @@ -1380,22 +1317,17 @@ msgstr "Festlegen, wie lange die Schaltfläche zum Überspringen des Intros ange #: msgctxt "#32525" msgid "Skip Credits Button Timeout" -msgstr "Zeitlimit für die Schaltfläche Abspann überspringen" +msgstr "Zeitlimit für die Schaltfläche 'Abspann überspringen'" #: msgctxt "#32526" msgid "Automatically Skip Credits" -msgstr "Automatisches Überspringen von Abspann" - -#: -msgctxt "#32527" -msgid "Automatically skip credits if available. Doesn't override enabled binge mode.\nCan be disabled/enabled per TV show." -msgstr "Automatisches Überspringen von Abspann, falls vorhanden. Überschreibt aktivierten Binge-Modus nicht.\nKann pro Serie aktiviert/deaktiviert werden." +msgstr "Abspann automatisch überspringen" #: msgctxt "#32528" msgid "Set how long the skip credits button shows for." -msgstr "Festlegen, wie lange die Schaltfläche zum Überspringen des Abspann angezeigt werden soll." +msgstr "Festlegen, wie lange die Schaltfläche zum Überspringen des Abspanns angezeigt werden soll." #: msgctxt "#32540" @@ -1405,12 +1337,12 @@ msgstr "Im Player anzeigen, wann das aktuelle Video endet" #: msgctxt "#32541" msgid "Shows time left and at which time the media will end." -msgstr "Zeigt im Player an, wann und zu welchem Zeitpunkt das aktuelle Video endet." +msgstr "Zeigt verbleibende Restzeit und Uhrzeit, wann das Video endet, im Player an." #: msgctxt "#32542" msgid "Show \"Ends at\" label for the end-time as well" -msgstr "\"Endet um\"-Label für die Endzeit auch anzeigen" +msgstr "'Endet um'-Label für Ende des Abspielens anzeigen" #: msgctxt "#32543" @@ -1460,7 +1392,7 @@ msgstr "Inhaltsbewertung" #: msgctxt "#33107" msgid "By Critic Rating" -msgstr "Nach kritischer Bewertung" +msgstr "Nach Kritikerwertung" #: msgctxt "#33108" @@ -1475,7 +1407,7 @@ msgstr "Hintergrundfarbe" #: msgctxt "#33201" msgid "Specify solid Background Color instead of using media images" -msgstr "Hintergrundfarbe anstatt Bilder verwenden" +msgstr "Hintergrundfarbe anstatt Medienbildern verwenden" #: msgctxt "#33400" @@ -1485,646 +1417,1063 @@ msgstr "Altes Kompatibilitätsprofil verwenden" #: msgctxt "#33401" msgid "Uses the Chrome client profile instead of the custom one. Might fix rare issues with 3D playback." -msgstr "Benutzt das alte Chrome Client-Profil anstatt des angepassten. Könnte seltene Fehler beim Abspielen von 3D-Inhalten verhindern." +msgstr "Benutzt das alte Chrome-Client-Profil anstatt des angepassten. Könnte seltene Fehler beim Abspielen von 3D-Inhalten verhindern." #: -msgctxt "#32348" -msgid "movies" -msgstr "Filme" +msgctxt "#32031" +msgid "Burn-in Subtitles" +msgstr "Untertitel einbrennen" #: -msgctxt "#32466" -msgid "Automatically seek to the selected timeline position after a second" -msgstr "Nach Verzögerung automatisch zur aktuell gewählten Position springen" +msgctxt "#32061" +msgid "When transcoding audio, target the audio channels set in Kodi." +msgstr "Beim Transkodieren von Audio werden die in Kodi eingestellten Audiokanäle verwendet." +#: +msgctxt "#32062" +msgid "Transcode audio to AC3" +msgstr "Transkodiere Ton zu AC3" + +#: +msgctxt "#32063" +msgid "Transcode audio to AC3 in certain conditions (useful for passthrough)." +msgstr "Transkodiere Ton zu AC3 unter bestimmten Umständen (nützlich für Passthrough)" + +#: +msgctxt "#32065" +msgid "When any of the force AC3 settings are enabled, treat DTS the same as AC3 (useful for Optical passthrough)" +msgstr "Wenn eine der AC3-Optionen aktiviert ist, wird DTS wie AC3 behandelt (nützlich für Optical Passthrough)" + +#: +msgctxt "#32066" +msgid "Force audio to AC3" +msgstr "Audio immer als AC3 erzwingen" + +#: +msgctxt "#32067" +msgid "Only force multichannel audio to AC3" +msgstr "Nur Mehrkanal-Audio als AC3 erzwingen" + +#: +msgctxt "#32493" +msgid "When a media file has a forced/foreign subtitle for a subtitle-enabled language, the Plex Media Server preselects it. This behaviour is usually not necessary and not configurable. This setting fixes that by ignoring the PMSs decision and selecting the same language without a forced flag if possible." +msgstr "Hat eine Mediendatei erzwungenge Untertitel für eine Sprache, bei der Untertitel erwünscht sind, wählt der Plex Media Server diesen standardmäßig aus. Das Verhalten ist normalerweise unerwünscht und nicht konfigurierbar. Diese Einstellung behebt das Problem, indem versucht wird, einen Untertitel der selben Sprache ohne Erzwungen-Markierung zu wählen." + +#: +msgctxt "#32523" +msgid "Automatically skip intros if available. Doesn't override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Automatisches Überspringen vorhandener Intros. Überschreibt aktivierten Binge-Modus nicht.\n" +"Kann pro Serie aktiviert/deaktiviert werden." + +#: +msgctxt "#32527" +msgid "Automatically skip credits if available. Doesn't override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Automatisches Überspringen von vorhandenem Abspann. Überschreibt aktivierten Binge-Modus nicht.\n" +"Kann pro Serie aktiviert/deaktiviert werden." + +#: msgctxt "#33501" msgid "Video played threshold" msgstr "Video-abgespielt-Grenzwert" +#: msgctxt "#33502" msgid "Set this to the same value as your Plex server (Settings>Library>Video played threshold) to avoid certain pitfalls, Default: 90 %" -msgstr "Auf dem selben wert wie im Plex server setzen (Einstellungen>Mediathek>Video played threshold) um bestimmte Fehler zu umgehen, Standardwert: 90 %" +msgstr "Auf den selben Wert wie im Plex-Server setzen (unter Einstellungen > Mediathek zu finden), um bestimmte Fehler zu umgehen; Standardwert: 90 %" +#: msgctxt "#33503" msgid "Use alternative hubs refresh" msgstr "Alternative Aktualisierung der Hubs" +#: msgctxt "#33504" msgid "Refreshes all hubs for all libraries after an item's watch-state has changed, instead of only those likely affected. Use this if you find a hub that doesn't update properly." msgstr "Aktualisiert alle Hubs aller Bibliotheken, anstatt nur die, die möglicherweise zutreffend sind, nachdem sich der Abspielstatus eines Items geändert hat. Benutzen, wenn sich ein Hub nicht aktualisiert." +#: msgctxt "#33505" msgid "Show intro skip button early" -msgstr "Intro überspringen früher anzeigen" +msgstr "'Intro überspringen' früher anzeigen" +#: msgctxt "#33506" -msgid "Show the intro skip button from the start of a video with an intro marker. The auto-skipping setting applies. Doesn\'t override enabled binge mode.\nCan be disabled/enabled per TV show." -msgstr "Zeige den Intro-Überspringen-Knopf von Anfang an. Die Automatische-Intro-Überspringen-Einstellung wird angewandt. Überschreibt aktivierten Binge-Modus nicht.\nKann pro Serie aktiviert/deaktiviert werden." +msgid "Show the intro skip button from the start of a video with an intro marker. The auto-skipping setting applies. Doesn\\'t override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Zeige den 'Intro überspringen'-Knopf von Anfang an. Die 'Automatisch überspringen'-Einstellung wird weiterhin angewandt. Überschreibt aktivierten Binge-Modus nicht.\n" +"Kann pro Serie aktiviert/deaktiviert werden." +#: msgctxt "#33507" msgid "Enabled" msgstr "Aktiviert" +#: msgctxt "#33508" msgid "Disabled" msgstr "Deaktiviert" +#: msgctxt "#33509" msgid "Early intro skip threshold (default: < 60s/1m)" -msgstr "Frühes Intro-Überspringen Grenzwert (default: < 60s/1m)" +msgstr "Grenzwert für 'Früher Intro überspringen' (Standardwert < 60s)" +#: msgctxt "#33510" -msgid "When showing the intro skip button early, only do so if the intro starts within the first X seconds." -msgstr "Wenn der Into-Überspringen-Knopf früher angezeigt werden soll, nur anzeigen, wenn das Intro innerhalb der ersten X Sekunden startet." +msgid "When showing the intro skip button early, only do so if the intro occurs within the first X seconds." +msgstr "Wenn der 'Intro überspringen'-Knopf früher angezeigt werden soll, nur anzeigen, wenn das Intro innerhalb der ersten X Sekunden startet." +#: msgctxt "#33600" msgid "System" msgstr "System" +#: msgctxt "#33601" msgid "Show video chapters" msgstr "Video-Kapitel anzeigen" +#: msgctxt "#33602" msgid "If available, show video chapters from the video-file instead of the timeline-big-seek-steps." msgstr "Wenn verfügbar, Video-Kapitel aus der Video-Datei anstatt der Zeitleiste-Big-Seek-Schritte anzeigen." +#: msgctxt "#33603" msgid "Use virtual chapters" msgstr "Virtuelle Kapitel verwenden" +#: msgctxt "#33604" msgid "When the above is enabled and no video chapters are available, simulate them by using the markers identified by the Plex Server (Intro, Credits)." -msgstr "Wenn die obrige aktiviert ist und keine Video-Kapitel verfügbar sind, virtuelle Kapitel aus den Plex Server Markern (Intro, Abspann) erzeugen." +msgstr "Wenn die obige Option aktiviert ist und keine Video-Kapitel verfügbar sind, virtuelle Kapitel aus den Plex-Server-Markern (Intro, Abspann) erzeugen." +#: msgctxt "#33605" msgid "Video Chapters" msgstr "Video-Kapitel" +#: msgctxt "#33606" msgid "Virtual Chapters" msgstr "Virtuelle Kapitel" +#: msgctxt "#33607" msgid "Chapter {}" msgstr "Kapitel {}" +#: msgctxt "#33608" msgid "Intro" msgstr "Intro" +#: msgctxt "#33609" msgid "Credits" msgstr "Abspann" +#: msgctxt "#33610" msgid "Main" msgstr "Haupt" +#: msgctxt "#33611" msgid "Chapters" msgstr "Kapitel" +#: msgctxt "#33612" msgid "Markers" msgstr "Markierungen" +#: msgctxt "#33613" msgid "Kodi Buffer Size (MB)" msgstr "Kodi Puffergröße (MB)" +#: msgctxt "#33614" msgid "Set the Kodi Cache/Buffer size. Free: {} MB, Recommended: ~50 MB, Recommended max: {} MB, Default: 20 MB." msgstr "Setzt die Kodi Cache/Puffer Größe. Frei: {} MB, empfohlen: ~50 MB, empfohlenes Max.: {} MB, Default: 20 MB." +#: msgctxt "#33615" msgid "{time} left" msgstr "{time} übrig" +#: msgctxt "#33616" msgid "Addon Path" msgstr "Addon-Pfad" +#: msgctxt "#33617" msgid "Userdata/Profile Path" msgstr "Benutzerdaten-/Profilpfad" +#: msgctxt "#33618" msgid "TV binge-viewing mode" -msgstr "TV Binge-Viewing-Modus" +msgstr "TV-Binge-Viewing-Modus" +#: msgctxt "#33619" -msgid "Automatically skips episode intros, credits and tries to skip episode recaps. Doesn\'t skip the intro of the first episode of a season and doesn't skip the final credits of a show.\n\nCan be disabled/enabled per TV show.\nOverrides any setting below." -msgstr "Überspringt automatisch Intros und Abspänne von Episoden und versucht Recaps zu vermeiden. Überspringt das Intro der ersten Episode einer Staffel und den Abspann der letzten Episode einer Serie nicht.\n\nKann pro Serie aktiviert/deaktiviert werden.\nÜberschreibt jegliche Einstellung unterhalb dieser." +msgid "Automatically skips episode intros, credits and tries to skip episode recaps. Doesn\\'t skip the intro of the first episode of a season and doesn't skip the final credits of a show.\n" +"\n" +"Can be disabled/enabled per TV show.\n" +"Overrides any setting below." +msgstr "Überspringt automatisch Intros und Abspänne von Episoden und versucht Recaps zu vermeiden. Überspringt das Intro der ersten Episode einer Staffel und den Abspann der letzten Episode einer Serie nicht.\n" +"\n" +"Kann pro Serie aktiviert/deaktiviert werden.\n" +"Überschreibt jegliche Einstellung unterhalb dieser." +#: msgctxt "#33620" msgid "Plex requests timeout (seconds)" -msgstr "Plex HTTP Zeitlimit (Sekunden)" +msgstr "Plex-HTTP-Zeitlimit (Sekunden)" +#: msgctxt "#33621" -msgid "Set the (async and connection) timeout value of the Python requests library in seconds. Default: 5 seconds" -msgstr "Setzt das Zeitlimit für die Python Requests Bibliothek bei asynchronen Verbindungen und Verbindungsanfragen. Default: 5 Sekunden" +msgid "Set the (async and connection) timeout value of the Python requests library in seconds. Default: 5" +msgstr "Setzt das Zeitlimit für die Python-Requests-Bibliothek bei asynchronen Verbindungen und Verbindungsanfragen. Default: 5" +#: msgctxt "#33622" msgid "LAN reachability timeout (ms)" msgstr "LAN-Erreichbarkeits-Zeitlimit (ms)" +#: msgctxt "#33623" -msgid "When checking for Server-in-LAN reachability, use this timeout. Default: 10ms" +msgid "When checking for LAN reachability, use this timeout. Default: 10ms" msgstr "Wenn die lokale Serververbindung im LAN überprüft wird, benutze dieses Zeitlimit. Default: 10ms" +#: msgctxt "#33624" msgid "Network" msgstr "Netzwerk" +#: msgctxt "#33625" msgid "Smart LAN/local server discovery" -msgstr "Smartes LAN/lokale Server-Auffinden" +msgstr "Smartes LAN/lokale Server auffinden" +#: msgctxt "#33626" -msgid "Checks whether servers returned from Plex.tv are actually local/in your LAN. For specific setups (e.g. Docker) Plex.tv might not properly detect a local server.\n\nNOTE: Only works on Kodi 19 or above." -msgstr "Überprüft, ob von Plex.tv zurückgegebene Server tatsächlich lokal/in Deinem LAN sind. Für bestimmte Setups (z. B. Docker) könnte Plex.tv einen lokalen Servern nicht als solchen entdecken.\n\nACHTUNG: Funktioniert nur unter Kodi 19 oder neuer." +msgid "Checks whether servers returned from Plex.tv are actually local/in your LAN. For specific setups (e.g. Docker) Plex.tv might not properly detect a local server.\n" +"\n" +"NOTE: Only works on Kodi 19 or above." +msgstr "Überprüft, ob von Plex.tv zurückgegebene Server tatsächlich lokal/in Deinem LAN sind. Für bestimmte Setups (z. B. Docker) könnte Plex.tv einen lokalen Server nicht als solchen entdecken.\n" +"\n" +"ACHTUNG: Funktioniert nur mit Kodi 19 oder neuer." +#: msgctxt "#33627" msgid "Prefer LAN/local servers over security" msgstr "LAN/lokale Server bevorzugen" +#: msgctxt "#33628" msgid "Prioritizes local connections over secure ones. Needs the proper setting in \"Allow Insecure Connections\" and the Plex Server's \"Secure connections\" at \"Preferred\". Can be used to enforce manual servers." -msgstr "Priorisiert lokale Verbindungen über sichere. Benötigt die korrekte Einstellung in \"Unsichere Verbindung erlauben\" und die Plex Server Einstellung \"Sichere Verbindungen\" auf \"Bevorzugt\". Kann verwendet werden um manuelle Server zu forcieren." +msgstr "Priorisiert lokale Verbindungen über sichere. Benötigt die korrekte Einstellung in \"Unsichere Verbindung erlauben\" und die Plex-Server-Einstellung \"Sichere Verbindungen\". Kann verwendet werden, um manuelle Server zu forcieren." +#: msgctxt "#33629" msgid "Auto-skip intro/credits offset" msgstr "Auto-Überspringen-Versatz" +#: msgctxt "#33630" msgid "Intro/credits markers might be a little early in Plex. When auto skipping add (or subtract) this many seconds from the marker. This avoids cutting off content, while possibly skipping the marker a little late." -msgstr "Intro-/Abspann-Markierungen können ein wenig früh erscheinen in Plex. Wenn diese automatisch übersprungen werden sollen, addiere (oder subtrahiere) diese Menge an Sekunden. Das verhindert das verfrühte Abschneiden von Inhalten, kann aber zu etwas verspätetem Springen führen." +msgstr "Intro-/Abspann-Markierungen können zeitversetzt sein. Um passend automatisch zu überspringen, addiere (oder subtrahiere) die eingestellte Menge an Sekunden. Das verhindert das verfrühte Abschneiden von Inhalten, kann aber zu etwas verspätetem Springen führen." +#: msgctxt "#32631" msgid "Playback (user-specific)" msgstr "Wiedergabe (benutzerspezifisch)" +#: msgctxt "#33632" msgid "Server connectivity check timeout (seconds)" -msgstr "Server Konnektivitätscheck-Timeout (Sekunden)" +msgstr "Timeout für Server-Konnektivitäts-Check (Sekunden)" +#: msgctxt "#33633" msgid "Set the maximum amount of time a server connection has to answer a connectivity request. Default: 2.5" msgstr "Setzt die maximale Zeit, in der eine Serververbindung antworten muss. Voreinstellung: 2.5" +#: msgctxt "#33634" msgid "Combined Chapters" msgstr "Kombinierte Kapitel" +#: msgctxt "#33635" msgid "Final Credits" msgstr "Finaler Abspann" +#: msgctxt "#32700" msgid "Action on Sleep event" msgstr "Aktion bei Sleep-Ereignis" +#: msgctxt "#32701" msgid "When Kodi receives a sleep event from the system, run the following action." msgstr "Wenn Kodi ein Sleep-Ereignis vom System erhält, folgende Aktion ausführen." +#: msgctxt "#32702" msgid "Nothing" msgstr "Nichts" +#: msgctxt "#32703" msgid "Stop playback" msgstr "Abspielen stoppen" +#: msgctxt "#32704" msgid "Quit Kodi" msgstr "Kodi beenden" +#: msgctxt "#32705" msgid "CEC Standby" msgstr "CEC Standby" +#: msgctxt "#32800" msgid "Skipping intro" msgstr "Überspringe Intro" +#: msgctxt "#32801" msgid "Skipping credits" msgstr "Überspringe Abspann" +#: msgctxt "#32900" msgid "While playing back an item and seeking on the seekbar, automatically seek to the selected position after a delay instead of having to confirm the selection." msgstr "Wird während des Abspielens die Position auf der Zeitleiste verändert, automatisch nach einer Verzögerung auf die gewählte Position springen, ohne diese bestätigen zu müssen." +#: msgctxt "#32901" msgid "Seek delay in seconds." msgstr "Sprungverzögerung in Sekunden." +#: msgctxt "#32902" msgid "Kodi has its own skip step settings. Try to use them if they're configured instead of the default ones." -msgstr "Kodi besitzt seine eigenen Sprungeinstellungen. Versuche diese anstatt der standardmäßigen zu verwenden, sollten sie konfiguriert sein." +msgstr "Kodi besitzt seine eigenen Sprungeinstellungen. Versuche diese zu verwenden, sollten sie konfiguriert sein." +#: msgctxt "#32903" msgid "Use the above for seeking on the timeline as well." -msgstr "Benutze die obrige Einstellung auch für die Zeitleiste." +msgstr "Benutze die obige Einstellung auch für die Zeitleiste." +#: msgctxt "#32904" msgid "In seconds." msgstr "In Sekunden." +#: msgctxt "#32905" msgid "Cancel post-play timer by pressing OK/SELECT" -msgstr "Post-Play Timer durch OK/AUSWAHL abbrechen" +msgstr "Post-Play-Timer durch OK/AUSWAHL abbrechen" +#: msgctxt "#32906" msgid "Cancel skip marker timer with BACK" msgstr "Markierung überspringen durch Zurück-Taste abbrechen" +#: msgctxt "#32907" msgid "When auto-skipping a marker, allow cancelling the timer by pressing BACK." msgstr "Wenn eine Markierung mit einem Zeitgeber automatisch übersprungen wird, durch Zurück-Taste abbrechen." +#: msgctxt "#32908" msgid "Immediately skip marker with OK/SELECT" msgstr "Markierung sofort überspringen mit OK/AUSWAHL" +#: msgctxt "#32909" msgid "When auto-skipping a marker with a timer, allow skipping immediately by pressing OK/SELECT." msgstr "Wenn eine Markierung mit einem Zeitgeber automatisch übersprungen wird, durch OK/AUSWAHL-Taste sofort überspringen." +#: msgctxt "#32912" msgid "Show buffer-state on timeline" msgstr "Zeige Puffer-Stand auf Zeitachse" +#: msgctxt "#32913" msgid "Shows the current Kodi buffer/cache state on the video player timeline." -msgstr "Zeigt den aktuellen Kodi Puffer/Cache-Stand auf der Videoplayer Zeitachse." +msgstr "Zeigt den aktuellen Kodi-Puffer/Cache-Stand auf der Videoplayer-Zeitachse." +#: msgctxt "#32914" msgid "Loading" msgstr "Lädt" +#: msgctxt "#32915" msgid "Slow connection" msgstr "Langsame Verbindung" +#: msgctxt "#32916" msgid "Use with a wonky/slow connection, e.g. in a hotel room. Adjusts the UI to visually wait for item refreshes and waits for the buffer to fill when starting playback. Automatically sets readfactor=20, requires Kodi restart." -msgstr "Bei langsamer Verbindung benutzen, z.B. im Hotel. Passt die Oberfläche visuell an um auf Media Auffrischungen zu warten und füllt den Kodi Puffer vor dem Abspielen. Setzt automatisch Kodi Cache readfactor=20, benötigt einen Kodi Neustart." +msgstr "Bei langsamer Verbindung benutzen, z.B. im Hotel. Passt die Oberfläche visuell an, um auf Medien-Auffrischungen zu warten, und füllt den Kodi-Puffer vor dem Abspielen. Setzt automatisch Kodi-Cache readfactor=20. Benötigt einen Kodi-Neustart." +#: msgctxt "#32917" msgid "Couldn't fill buffer in time ({}s)" msgstr "Konnte den Puffer nicht schnell genug füllen ({} Sek.)" +#: msgctxt "#32918" msgid "Buffer wait timeout (seconds)" msgstr "Puffer-Wartezeit (Sekunden)" +#: msgctxt "#32919" msgid "When slow connection is enabled in the addon, wait this long for the buffer to fill. Default: 120 s" -msgstr "Wenn Langsame Verbindung im Addon aktiviert ist, warte so lange bis der Puffer gefüllt ist. Voreinstellung: 120 Sek." +msgstr "Wenn 'Langsame Verbindung' im Addon aktiviert ist, warte so lange, bis der Puffer gefüllt ist. Voreinstellung: 120 Sek." +#: msgctxt "#32920" msgid "Insufficient buffer wait (seconds)" -msgstr "Ungenügender Puffer Wartezeit (Sekunden)" +msgstr "Ungenügender-Puffer-Wartezeit (Sekunden)" +#: msgctxt "#32921" -msgid "When slow connection is enabled in the addon and the configured cache/buffer isn't big enough for us to determine its fill state, wait this long when starting playback. Default: 10 s" -msgstr "Wenn \"Langsame Verbindung\" im Addon aktiviert ist und der konfigurierte Puffer/Cache nicht groß genug ist, um seinen Füllstand zu ermitteln, wird so lange gewartet, bevor die Wiedergabe gestartet wird. Voreinstellung: 10 Sek." +msgid "When slow connection is enabled in the addon and the configured buffer isn't big enough for us to determine its fill state, wait this long when starting playback. Default: 10 s" +msgstr "Wenn 'Langsame Verbindung' im Addon aktiviert ist und der konfigurierte Puffer/Cache nicht groß genug ist, um seinen Füllstand zu ermitteln, wird so lange gewartet, bevor die Wiedergabe gestartet wird. Voreinstellung: 10 Sek." +#: msgctxt "#32922" msgid "Kodi Cache Readfactor" -msgstr "Kodi Puffer Readfactor" +msgstr "Kodi-Puffer/Cache-Readfactor" +#: msgctxt "#32923" msgid "Sets the Kodi cache readfactor value. Default: {0}, recommended: {1}. With \"Slow connection\" enabled this will be set to {2}, as otherwise the cache doesn't fill fast/aggressively enough." -msgstr "Setzt den Kodi Cache/Puffer readfactor Wert. Standard: {0}, Empfohlen: {1}. Bei aktivem \"Langsame Verbindung\" wird dies automatisch auf {2} gesetzt, da ansonsten der Cache nicht schnell/agressiv genug gefüllt wird." +msgstr "Setzt den Kodi-Cache/Puffer-Readfactor-Wert. Standard: {0}, Empfohlen: {1}. Bei aktivem 'Langsame Verbindung' wird dies automatisch auf {2} gesetzt, da ansonsten der Cache nicht schnell/agressiv genug gefüllt wird." +#: msgctxt "#32924" msgid "Minimize" msgstr "Minimieren" +#: msgctxt "#32925" msgid "Playback Settings" -msgstr "Abspieleinstell." +msgstr "Abspieleinstellungen" +#: msgctxt "#32926" msgid "Wrong pin entered!" msgstr "Falsche PIN eingegeben!" +#: msgctxt "#32927" msgid "Use episode thumbnails in continue hub" msgstr "Vorschaubild für Episoden im Fortsetzen-Hub verwenden" +#: msgctxt "#32928" msgid "Instead of using media artwork, use thumbnails for episodes in the continue hub on the home screen if available." msgstr "Verwende Vorschaubilder anstatt Media-Artwork für Episoden im Fortsetzen-Hub auf der Start-Ansicht." +#: msgctxt "#32929" msgid "Use legacy background fallback image" -msgstr "Veraltetes Ausweich-Hintergrundbild verwenden" +msgstr "Klassisches Ausweichhintergrundbild verwenden" +#: msgctxt "#32930" msgid "Previous Subtitle" msgstr "Vorheriger Untertitel" +#: msgctxt "#32931" msgid "Audio/Subtitles" msgstr "Audio/Untertitel" +#: msgctxt "#32932" msgid "Show subtitle quick-actions button" msgstr "Zeige Untertitel-Schnellaktionen-Knopf" +#: msgctxt "#32933" msgid "Show FFWD/RWD buttons" -msgstr "Zeige Vorspulen-Zurückspulen-Knopf" +msgstr "Zeige Vor-/Zurückspulen-Knopf" +#: msgctxt "#32934" msgid "Show repeat button" msgstr "Zeige Wiederholen-Knopf" +#: msgctxt "#32935" msgid "Show shuffle button" msgstr "Zeige Zufällige-Wiedergabe-Knopf" +#: msgctxt "#32936" msgid "Show playlist button" msgstr "Zeige Wiedergabeliste-Knopf" +#: msgctxt "#32937" msgid "Show prev/next button" msgstr "Zeige Vorheriger/Nächster-Knopf" -msgctxt "#32938" -msgid "Only for Episodes" -msgstr "Nur bei Episoden" - +#: msgctxt "#32939" msgid "Only applies to video player UI" -msgstr "Gilt nur für die Video Abspieloberfläche" +msgstr "Gilt nur für die Video-Abspieloberfläche" +#: msgctxt "#32940" msgid "Player UI" msgstr "Abspieloberfläche" +#: msgctxt "#32941" msgid "Forced subtitles fix" msgstr "Erzwungene Untertitel beheben" +#: msgctxt "#32942" msgid "Other seasons" msgstr "Weitere Staffeln" +#: msgctxt "#32943" msgid "Crossfade dynamic background art" msgstr "Dynamische Hintergrundbilder überblenden" +#: msgctxt "#32944" msgid "Burn-in SSA subtitles (DirectStream)" msgstr "SSA-Untertitel einbrennen (DirectStream)" +#: msgctxt "#32945" msgid "When Direct Streaming instruct the Plex Server to burn in SSA/ASS subtitles (thus transcoding the video stream). If disabled it will not touch the video stream, but will convert the subtitle to unstyled text." -msgstr "Wird Direct Streaming verwendet, den Plex Server dazu bringen, SSA/ASS-Untertitel einzubrennen (also den Video Stream zu transcoden). Wenn deaktiviert, wird dieser den Video Stream nicht anfassen, jedoch den Untertitel als reinen Text anzeigen." +msgstr "Wird Direct Streaming verwendet, den Plex-Server dazu bringen, SSA/ASS-Untertitel einzubrennen (mit Video-Stream-Transcode). Wenn deaktiviert, wird der Video-Stream nicht verändert, jedoch der Untertitel zu reinem Text konvertiert." +#: msgctxt "#32946" msgid "Stop video playback on idle after" msgstr "Bei Inaktivität Video stoppen nach" +#: msgctxt "#32947" msgid "Stop video playback on screensaver" msgstr "Video stoppen bei Bildschirmschoner" +#: msgctxt "#32948" msgid "Allow auto-skip when transcoding" msgstr "Überspringen beim Transkodieren erlauben" +#: msgctxt "#32949" msgid "When transcoding/DirectStreaming, allow auto-skip functionality." msgstr "Beim Transkodieren/DirectStream die automatische Überspringen-Funktionalität erlauben." +#: msgctxt "#32950" msgid "Use extended title for subtitles" msgstr "Erweiterten Titel für Untertitel verwenden" +#: msgctxt "#32951" msgid "When displaying subtitles use the extendedDisplayTitle Plex exposes." msgstr "Verwende erweiterte Namen wenn Untertitelnamen angezeigt werden." -msgctxt "#32952" -msgid "Dialog-Flackern beheben" -msgstr "" - +#: msgctxt "#32953" msgid "Reviews" msgstr "Kritik" +#: msgctxt "#32954" -msgid "Needs Kodi restart. WARNING: This will overwrite advancedsettings.xml!\n\nTo customize other cache/network-related values, copy \"script.plexmod/pm4k_cache_template.xml\" to profile folder and edit it to your liking. (See About section for the file paths)" -msgstr "Benötigt Kodi Neustart. ACHTUNG: Überschreibt advancedsettings.xml!\n\nUm weitere Cache-/Netzwerkbezogene Werte zu ändern, kopiere \"script.plexmod/pm4k_cache_template.xml\" in den Profilordner und editiere sie. (Für die Dateipfade schaue in die Über-Sektion)" +msgid "Needs Kodi restart. WARNING: This will overwrite advancedsettings.xml!\n" +"\n" +"To customize other cache/network-related values, copy \"script.plexmod/pm4k_cache_template.xml\" to profile folder and edit it to your liking. (See About section for the file paths)" +msgstr "Benötigt Kodi-Neustart. ACHTUNG: Überschreibt advancedsettings.xml!\n" +"\n" +"Um weitere Cache-/Netzwerkbezogene Werte zu ändern, kopiere \"script.plexmod/pm4k_cache_template.xml\" in den Profilordner und editiere sie. (Für die Dateipfade schaue in Abschnitt 'Über')" +#: msgctxt "#32955" msgid "Use Kodi keyboard for searching" msgstr "Kodi-Tastatur bei der Suche verwenden" +#: msgctxt "#32956" msgid "Poster resolution scaling %" msgstr "Poster Auflösungsskalierung %" +#: msgctxt "#32957" -msgid "In percent. Scales the resolution of all posters/thumbnails for better image quality. May impact PMS/PM4K performance, will increase the cache usage accordingly. Recommended: 200-300 % for big screens if your hardware can handle it. Needs addon restart." -msgstr "In Prozent. Skaliert die Auflösung aller Poster/Vorschaubilder für bessere Bildqualität. Kann die PMS/PM4K Performance beeinflussen, wird die Cache-Nutzung dementsprechend erhöhen. Empfohlen: 200-300 % für große Bildschirme, wenn die Hardware damit umgehen kann. Benötigt Addon-Neustart." +msgid "In percent. Scales the resolution of all posters/thumbnails for better image quality. May impact PMS/PM4K performance, will increase the cache usage accordingly. Recommended: 200-300 % for for big screens if your hardware can handle it. Needs addon restart." +msgstr "In Prozent. Skaliert die Auflösung aller Poster/Vorschaubilder für bessere Bildqualität. Kann die PMS/PM4K Performance beeinflussen; wird die Cache-Nutzung dementsprechend erhöhen. Empfohlen: 200-300 % für große Bildschirme, wenn die Hardware damit umgehen kann. Benötigt Addon-Neustart." +#: msgctxt "#32958" msgid "Calculate OpenSubtitles.com hash" -msgstr "OpenSubtitles.com Prüfsumme berechnen" +msgstr "OpenSubtitles.com-Prüfsumme berechnen" +#: msgctxt "#32959" msgid "When opening the subtitle download feature, automatically calculate the OpenSubtitles.com hash for the given file. Can improve search results, downloads 2*64 KB of the video file to calculate the hash." msgstr "Beim Öffnen der Untertitel-Herunterladen-Funktion die Prüfsumme der Datei für OpenSubtitles.com automatisch berechnen. Kann die Suchergebnisse verbessern, lädt 2*64 KB der Videodatei herunter um die Prüfsumme zu berechnen." +#: msgctxt "#32960" msgid "Similar Artists" msgstr "Ähnliche Künstler" +#: msgctxt "#32961" msgid "Show hub bifurcation lines" msgstr "Hub-Trennlinie anzeigen" +#: msgctxt "#32962" msgid "Visually separate hubs horizontally using a thin line." msgstr "Trennt Hubs visuell horizontal mit Hilfe einer dünnen Linie." +#: msgctxt "#32963" msgid "Wait between videos (s)" -msgstr "Zwischen Videos warten (s)" +msgstr "Zwischen Videos warten (in Sekunden)" +#: msgctxt "#32964" msgid "When playing back consecutive videos (e.g. TV shows), wait this long before starting the next one in the queue. Might fix compatibility issues with certain configurations." msgstr "Werden aufeinanderfolgende Videos abgespielt (z. B. Serien), so lange warten, bis das nächste Video in der Warteschlange abgespielt wird. Könnte Kompatibilitätsprobleme mit gewissen Konfigurationen beheben." +#: msgctxt "#32965" msgid "Quit Kodi on exit by default" -msgstr "Kodi beenden anstatt PM4K" +msgstr "Bei Beenden von PM4K auch Kodi beenden" +#: msgctxt "#32966" -msgid "When showing the addon exit confirmation, use \"Quit Kodi\" as default option. Can be dynamically switched using CONTEXT_MENU (often longpress SELECT)" -msgstr "Wenn die Addon-Beendigungsbestätigung angezeigt wird, \"Kodi beenden\" als Standardoption verwenden. Kann dynamisch mit CONTEXT_MENU (oft lange gedrücktes SELECT) getauscht werden." +msgid "When exiting the addon, use \"Quit Kodi\" as default option. Can be dynamically switched using CONTEXT_MENU (often longpress SELECT)" +msgstr "Wenn das Addon beendet wird, \"Kodi beenden\" als Standardoption verwenden. Kann dynamisch mit CONTEXT_MENU (oft lange gedrücktes SELECT) getauscht werden." +#: msgctxt "#32967" msgid "Kodi Colour Management" -msgstr "Kodi Farbeinstellungen" +msgstr "Kodi-Farbeinstellungen" +#: msgctxt "#32968" msgid "Kodi Resolution Settings" -msgstr "Kodi Auflösungseinstellungen" +msgstr "Kodi-Auflösungseinstellungen" +#: msgctxt "#32969" msgid "Always request all library media items at once" msgstr "Immer die vollständige Bibliothek laden" +#: msgctxt "#32970" msgid "Retrieve all media in library up front instead of fetching it in chunks as the user navigates through the library" msgstr "Alle Medieninhalte einer Bibliothek anfordern, anstatt diese gestückelt nachzuladen" +#: msgctxt "#32971" msgid "Library item-request chunk size" -msgstr "Bibliothek Anfrage-Blockgröße" +msgstr "Bibliotheksanfrage-Blockgröße" +#: msgctxt "#32972" msgid "Request this amount of media items per chunk request in library view (+6-30 depending on view mode; less can be less straining for the UI at first, but puts more strain on the server)" msgstr "Diese Anzahl an Medieninhalten pro gestückelter Anfrage in der Bibliothekenansicht laden (+6-30 abhängig von der Ansicht; weniger kann vorerst geringere UI-Last bedeuten, aber mehr Last beim Server erzeugen)" +#: msgctxt "#32973" msgid "Episodes: Skip Post Play screen" msgstr "Direkt zur nächsten Episode springen" +#: msgctxt "#32974" -msgid "When finishing an episode, don't show Post Play but go to the next one immediately.\nCan be disabled/enabled per TV show. Doesn't override enabled binge mode. Overrides the Post Play setting." -msgstr "Beim Beenden einer Episode nicht in die Post Play Ansicht gehen und stattdessen sofort zur nächsten Episode springen.\nCan be disabled/enabled per TV show. Überschreibt aktivierten Binge-Modus nicht. Überschreibt die \"Automatisch nächsten Titel abspielen\"-Einstellung" +msgid "When finishing an episode, don't show Post Play but go to the next one immediately.\n" +"Can be disabled/enabled per TV show. Doesn't override enabled binge mode. Overrides the Post Play setting." +msgstr "Beim Beenden einer Episode nicht in die Post-Play-Ansicht gehen und stattdessen sofort zur nächsten Episode springen.\n" +"Kann pro TV-Sendung eingestellt werden. Überschreibt aktivierten Binge-Modus nicht. Überschreibt die \"Automatisch nächsten Titel abspielen\"-Einstellung." +#: msgctxt "#32975" msgid "Delete Season" msgstr "Staffel löschen" +#: msgctxt "#32976" msgid "Adaptive" msgstr "Adaptiv" +#: msgctxt "#32977" msgid "Allow VC1" msgstr "VC1 zulassen" +#: msgctxt "#32978" msgid "Enable this if your hardware can handle VC1. Disable it to force transcoding." msgstr "Diese Option aktivieren, wenn die Hardware VC1 verarbeiten kann. Deaktivieren, um die Transkodierung zu erzwingen." +#: msgctxt "#32979" msgid "Allows the server to only transcode streams of a video that need transcoding, while streaming the others unaltered. If disabled, force the server to transcode everything not direct playable." msgstr "Erlaubt dem Server nur Streams eines Videos zu transkodieren, die dies benötigen, während die anderen unverändert übertragen werden. Ist dies deaktiviert, wird der Server dazu gezwungen, alles zu transkodieren, was nicht direkt abspielbar ist." +#: msgctxt "#32980" msgid "Refresh Users" -msgstr "Benutzer aktual." +msgstr "Benutzer aktualisieren" +#: msgctxt "#32981" msgid "Background worker count" msgstr "Anzahl Hintergrund-Worker" +#: msgctxt "#32982" msgid "Depending on how many cores your CPU has and how much it can handle, increasing this might improve certain situations. If you experience crashes or other annormalities, leave this at its default (3). Needs an addon restart." -msgstr "Je nachdem, wie viele Kerne Deine CPU hat und wie viel sie verarbeiten kann, kann eine höhere Zahl bestimmte Situationen verbessern. Solltest Du Abstürze oder andere Annomalien bemerken, stelle dies auf den Standardwert zurück (3). Benötigt einen Addon-Neustart." +msgstr "Je nachdem, wie viele Kerne Deine CPU hat und wie viel sie verarbeiten kann, kann eine höhere Zahl bestimmte Situationen verbessern. Solltest Du Abstürze oder andere Anomalien bemerken, stelle dies auf den Standardwert zurück (3). Benötigt einen Addon-Neustart." +#: msgctxt "#32983" msgid "Player Theme" msgstr "Player-Theme" +#: msgctxt "#32984" -msgid "Sets the player theme. Currently only customizes the playback control buttons. ATTENTION: [I]Might[/I] need an addon restart.\nIn order to customize this, copy one of the xml's in script.plexmod/resources/skins/Main/1080i/templates to addon_data/script.plexmod/templates/seek_dialog_buttons_custom.xml and adjust it to your liking, then select \"Custom\" as your theme." -msgstr "Wählt das Theme des Players. Verändert aktuell nur die Abspiel-Knöpfe. ACHTUNG: Ein Addon-Neustart [I]könnte[/I] notwendig sein.\nUm dies individuell anzupassen, kopiere eine der xml's aus script.plexmod/resources/skins/Main/1080i/templates nach addon_data/script.plexmod/templates/seek_dialog_buttons_custom.xml und passe es nach Deinen Ansprüchen an, danach \"Individualisiert\" als Theme wählen." +msgid "Sets the player theme. Currently only customizes the playback control buttons. ATTENTION: [I]Might[/I] need an addon restart.\n" +"In order to customize this, copy one of the xml's in script.plexmod/resources/skins/Main/1080i/templates to addon_data/script.plexmod/templates/seek_dialog_buttons_custom.xml and adjust it to your liking, then select \"Custom\" as your theme." +msgstr "Wählt das Theme des Players. Verändert aktuell nur die Abspiel-Knöpfe. ACHTUNG: Ein Addon-Neustart [I]könnte[/I] notwendig sein.\n" +"Um dies individuell anzupassen, kopiere eine der xml's aus script.plexmod/resources/skins/Main/1080i/templates nach addon_data/script.plexmod/templates/seek_dialog_buttons_custom.xml und passe es nach Deinen Ansprüchen an; danach \"Individualisiert\" als Theme wählen." +#: msgctxt "#32985" msgid "Modern" msgstr "Modern" +#: msgctxt "#32986" msgid "Modern (dotted)" msgstr "Modern (gepunktet)" +#: msgctxt "#32987" msgid "Classic" msgstr "Klassisch" +#: msgctxt "#32988" msgid "Custom" msgstr "Individualisiert" +#: msgctxt "#32989" msgid "Modern (colored)" msgstr "Modern (eingefärbt)" +#: msgctxt "#32990" msgid "Handle plex.direct mapping" -msgstr "plex.direct Zuordnung abwickeln" +msgstr "plex.direct-Zuordnung abwickeln" +#: msgctxt "#32991" msgid "Notify" msgstr "Benachrichtigen" +#: msgctxt "#32992" msgid "When using servers with a plex.direct connection (most of them), should we automatically adjust advancedsettings.xml to cope with plex.direct domains? If not, you might want to add plex.direct to your router's DNS rebind exemption list." msgstr "Wenn Server mit einer plex.direct Verbindung verwendet werden (die meisten), sollen wir automatisch die advancedsettings.xml anpassen? Wenn nicht, solltest Du plex.direct in die DNS Rebind Ausschlussliste Deines Routers eintragen." +#: msgctxt "#32993" -msgid "{} unhandled plex.direct connections found: {}" -msgstr "{} unbehandelte plex.direct Verbindungen gefunden" +msgid "{} unhandled plex.direct connections found" +msgstr "{} unbehandelte plex.direct-Verbindungen gefunden" +#: msgctxt "#32994" msgid "In order for PM4K to work properly, we need to add special handling for plex.direct connections. We've found {} new unhandled connections. Do you want us to write those to Kodi's advancedsettings.xml automatically? If not, you might want to add plex.direct to your router's DNS rebind exemption list. This can be changed in the settings as well." -msgstr "Damit PM4K korrekt funktioniert, müssen wir spezielles Handling für plex.direct Verbindungen einrichten. Es wurden {} neue unbehandelte Verbindungen gefunden. Sollen wir diese in Kodi's advancedsettings.xml eintragen? Wenn nicht, solltest Du plex.direct in die DNS Rebind Ausschlussliste Deines Routers eintragen. Dies kann später in den Einstellungen verändert werden." +msgstr "Damit PM4K korrekt funktioniert, müssen wir spezielles Handling für plex.direct-Verbindungen einrichten. Es wurden {} neue unbehandelte Verbindungen gefunden. Sollen wir diese in Kodis advancedsettings.xml eintragen? Wenn nicht, solltest Du plex.direct in die DNS-Rebind-Ausschlussliste Deines Routers eintragen. Dies kann später in den Einstellungen verändert werden." +#: msgctxt "#32995" msgid "Advancedsettings.xml modified (plex.direct mappings)" msgstr "Advancedsettings.xml modifiziert (plex.direct mappings)" +#: msgctxt "#32996" -msgid "The advancedsettings.xml file has been modified. Please restart Kodi for them to take effect." -msgstr "Die advancedsettings.xml-Datei wurde modifiziert. Bitte starte Kodi neu, damit die Änderungen in Effekt treten." +msgid "The advancedsettings.xml file has been modified. Please restart Kodi for the changes to apply." +msgstr "Die advancedsettings.xml-Datei wurde modifiziert. Bitte starte Kodi neu, damit die Änderungen angewandt werden." +#: msgctxt "#32997" msgid "OK" msgstr "OK" +#: msgctxt "#32998" msgid "Use new Continue Watching hub on Home" -msgstr "Neuen \"Fortsetzen\" Home-Hub verwenden" +msgstr "Neuen 'Weiterschauen'-Home-Hub verwenden" +#: msgctxt "#32999" msgid "Instead of separating Continue Watching and On Deck hubs, behave like the modern Plex clients, which combine those two types of hubs into one Continue Watching hub." -msgstr "Anstatt die separaten Fortsetzen und " +msgstr "Anstatt von separaten 'Fortsetzen' und 'Als nächstes'-Hubs, kombiniere beide in einen einzigen 'Weiterschauen'-Hub, wie bei anderen modernen Plex-Clients." +#: msgctxt "#33000" msgid "Enable path mapping" -msgstr "Path mapping aktivieren" +msgstr "Path-Mapping aktivieren" +#: msgctxt "#33001" msgid "Honor path_mapping.json in the addon_data/script.plexmod folder when DirectPlaying media. This can be used to stream using other techniques such as SMB/NFS/etc. instead of the default HTTP handler. path_mapping.example.json is included in the addon's main directory." -msgstr "Lese path_mapping.json im addon_data/script.plexmod Ordner wenn etwas DirectPlayed wird. Dies kann verwendet werden, um andere Techniken beim Streamen zu benutzen, wie z. B. SMB/NFS/etc., anstatt des HTTP handlers. path_mapping.example.json liegt im Hauptverzeichnis vom Addon." +msgstr "Bei DirectPlay von Videos, nutze path_mapping.json im addon_data/script.plexmod-Ordner. Dies kann verwendet werden, um andere Dateizugriff-Technologien zu benutzen, wie z. B. SMB/NFS/usw., anstatt des HTTP-Handlers. path_mapping.example.json liegt im Hauptverzeichnis vom Addon." +#: msgctxt "#33002" msgid "Verify mapped files exist" msgstr "Gemappte Dateien verifizieren" +#: msgctxt "#33003" msgid "When path mapping is enabled and we've successfully mapped a file, verify its existence." -msgstr "Wenn path mapping aktiviert ist und wir erfolgreich eine Datei gemappt haben, auch ihre Existenz verifizieren." +msgstr "Wenn Path-Mapping aktiviert ist und wir erfolgreich eine Datei gemappt haben, auch ihre Existenz verifizieren." +#: msgctxt "#33004" msgid "No spoilers without OSD" msgstr "Keine Spoiler ohne OSD" +#: msgctxt "#33005" msgid "When seeking without the OSD open, hide all time-related information from the user." msgstr "Wenn ohne OSD gesprungen wird, alle zeitrelevanten Informationen verstecken." + +#: +msgctxt "#33006" +msgid "No TV spoilers" +msgstr "Keine TV-Spoiler" + +#: +msgctxt "#33007" +msgid "When visiting an episode/season view, blur unwatched/unwatched+in-progress episode thumbnails, previews and redact summaries. When the Addon Setting \"Use episode thumbnails in continue hub\" is enabled, blur them as well." +msgstr "In der Episoden-/Staffelansicht Vorschaubilder nicht geschauter oder angefangener Episoden verschleiern und Zusammenfassungen zensieren. Wenn die Addon-Einstellung \"Vorschaubild für Episoden im Fortsetzen-Hub verwenden\" aktiviert ist, diese ebenfalls verschleiern." + +#: +msgctxt "#33008" +msgid "[Spoilers removed]" +msgstr "[Spoiler entfernt]" + +#: +msgctxt "#33009" +msgid "Blur amount for unwatched/in-progress episodes" +msgstr "Stärke der Verschleierung nicht geschauter Episoden" + +#: +msgctxt "#33010" +msgid "Unwatched" +msgstr "Nicht geschaut" + +#: +msgctxt "#33011" +msgid "Unwatched/in progress" +msgstr "Nicht geschaut/Angefangen" + +#: +msgctxt "#33012" +msgid "No unwatched episode titles" +msgstr "Keine Episodentitel für nicht geschaute Folgen" + +#: +msgctxt "#33013" +msgid "When the above is anything but \"off\", hide episode titles as well." +msgstr "Wenn die vorherige Einstellung nicht \"aus\" ist, Episodentitel ebenfalls zensieren." + +#: +msgctxt "#33014" +msgid "Ignore plex.direct docker hosts" +msgstr "plex.direct-Docker-Hosts ignorieren" + +#: +msgctxt "#33015" +msgid "When checking for plex.direct host mapping, ignore local Docker IPv4 addresses (172.16.0.0/12)." +msgstr "Wenn das plex.direct-Host-Mapping überprüft wird, lokale Docker-IPv4-Adressen ignorieren (172.16.0.0/12)." + +#: +msgctxt "#33016" +msgid "Allow TV spoilers for specific genres" +msgstr "Erlaube TV-Spoiler für bestimmte Genres" + +#: +msgctxt "#33017" +msgid "Overrides the above for: {}" +msgstr "Überschreibt die vorherigen Einstellungen für: {}" + +#: +msgctxt "#32303" +msgid "Season {}" +msgstr "Staffel {}" + +#: +msgctxt "#32304" +msgid "Episode {}" +msgstr "Folge {}" + +#: +msgctxt "#32310" +msgid "S{}" +msgstr "S{}" + +#: +msgctxt "#32311" +msgid "E{}" +msgstr "E{}" + +#: +msgctxt "#32938" +msgid "Only for Episodes/Playlists" +msgstr "Nur bei Episoden/Wiedergabelisten" + +#: +msgctxt "#33018" +msgid "Cache Plex Home users" +msgstr "Plex-Heimbenutzer zwischenspeichern" + +#: +msgctxt "#33019" +msgid "Visit media item" +msgstr "Mediendetails anschauen" + +#: +msgctxt "#33020" +msgid "Play" +msgstr "Abspielen" + +#: +msgctxt "#33021" +msgid "Choose action" +msgstr "Aktion wählen" + +#: +msgctxt "#33022" +msgid "Use modern inverted watched states" +msgstr "Modernen, invertierten Geschaut-Status benutzen" + +#: +msgctxt "#33023" +msgid "Instead of marking unwatched items, mark watched items with a checkmark (modern clients; default: off)" +msgstr "Anstatt nicht geschaute Elemente zu markieren, geschaute Elemente mit einem Haken markieren (moderne Clients; standard: aus)" + +#: +msgctxt "#33024" +msgid "Hide black backdrop in inverted watched states" +msgstr "Kein Hintergrund beim invertierten Geschaut-Status" + +#: +msgctxt "#33025" +msgid "When the above is enabled, hide the black backdrop of the watched state." +msgstr "Wenn die vorherige Option aktiviert ist, den schwarzen Hintergrund nicht darstellen." + +#: +msgctxt "#33026" +msgid "Map path: {}" +msgstr "Pfad zuordnen: {}" + +#: +msgctxt "#33027" +msgid "Remove mapping: {}" +msgstr "Zuordnung entfernen: {}" + +#: +msgctxt "#33028" +msgid "Hide library" +msgstr "Bibliothek verstecken" + +#: +msgctxt "#33029" +msgid "Show library: {}" +msgstr "Bibliothek anzeigen: {}" + +#: +msgctxt "#33030" +msgid "Choose action for: {}" +msgstr "Aktion wählen für: {}" + +#: +msgctxt "#33031" +msgid "Select Kodi source for {}" +msgstr "Kodi Quelle auswählen für {}" + +#: +msgctxt "#33032" +msgid "Show path mapping indicators" +msgstr "Pfadzuordnungs-Indikator anzeigen" + +#: +msgctxt "#33033" +msgid "When path mapping is active for a library, display an indicator." +msgstr "Wenn eine Pfadzuordnung für eine Bibliothek aktiv ist, einen Indikator anzeigen." + +#: +msgctxt "#33034" +msgid "Library settings" +msgstr "Bibliothek-Einstellungen" + + +#: +msgctxt "#33035" +msgid "Delete {}: {}?" +msgstr "{}: {} löschen?" + +#: +msgctxt "#33036" +msgid "Delete episode S{0:02d}E{1:02d} from {2}?" +msgstr "Episode S{0:02d}E{1:02d} von {2} löschen?" + +#: +msgctxt "#33037" +msgid "Maximum intro offset to consider" +msgstr "Maximales erwägtes Intro-Offset" + +#: +msgctxt "#33038" +msgid "When encountering an intro marker with a start time offset greater than this, ignore it (default: 600s/10m)" +msgstr "Wenn ein Intro-Marker mit einem Startzeitpunkt größer als diese Einstellung ist, diesen ignorieren (default: 600s/10m)" + +#: +msgctxt "#33039" +msgid "Move" +msgstr "Verschieben" + +#: +msgctxt "#33040" +msgid "Reset library order" +msgstr "Ordnung der Bibliotheken zurücksetzen" + +msgctxt "#33041" +msgid "Show hub: {}" +msgstr "Hub anzeigen: {}" diff --git a/script.plexmod/resources/language/resource.language.en_gb/strings.po b/script.plexmod/resources/language/resource.language.en_gb/strings.po index d942912c3..0b75fa76d 100644 --- a/script.plexmod/resources/language/resource.language.en_gb/strings.po +++ b/script.plexmod/resources/language/resource.language.en_gb/strings.po @@ -346,11 +346,11 @@ msgid "Go to {0}" msgstr "" msgctxt "#32303" -msgid "Season" +msgid "Season {}" msgstr "" msgctxt "#32304" -msgid "Episode" +msgid "Episode {}" msgstr "" msgctxt "#32305" @@ -374,11 +374,11 @@ msgid "None" msgstr "" msgctxt "#32310" -msgid "S" +msgid "S{}" msgstr "" msgctxt "#32311" -msgid "E" +msgid "E{}" msgstr "" msgctxt "#32312" @@ -1559,7 +1559,7 @@ msgid "Show prev/next button" msgstr "" msgctxt "#32938" -msgid "Only for Episodes" +msgid "Only for Episodes/Playlists" msgstr "" msgctxt "#32939" @@ -1614,10 +1614,6 @@ msgctxt "#32951" msgid "When displaying subtitles use the extendedDisplayTitle Plex exposes." msgstr "" -msgctxt "#32952" -msgid "Dialog flicker fix" -msgstr "" - msgctxt "#32953" msgid "Reviews" msgstr "" @@ -1829,3 +1825,147 @@ msgstr "" msgctxt "#33005" msgid "When seeking without the OSD open, hide all time-related information from the user." msgstr "" + +msgctxt "#33006" +msgid "No TV spoilers" +msgstr "" + +msgctxt "#33007" +msgid "When visiting an episode/season view, blur unwatched/unwatched+in-progress episode thumbnails, previews and redact summaries. When the Addon Setting \"Use episode thumbnails in continue hub\" is enabled, blur them as well." +msgstr "" + +msgctxt "#33008" +msgid "[Spoilers removed]" +msgstr "" + +msgctxt "#33009" +msgid "Blur amount for unwatched/in-progress episodes" +msgstr "" + +msgctxt "#33010" +msgid "Unwatched" +msgstr "" + +msgctxt "#33011" +msgid "Unwatched/in progress" +msgstr "" + +msgctxt "#33012" +msgid "No unwatched episode titles" +msgstr "" + +msgctxt "#33013" +msgid "When the above is anything but \"off\", hide episode titles as well." +msgstr "" + +msgctxt "#33014" +msgid "Ignore plex.direct docker hosts" +msgstr "" + +msgctxt "#33015" +msgid "When checking for plex.direct host mapping, ignore local Docker IPv4 addresses (172.16.0.0/12)." +msgstr "" + +msgctxt "#33016" +msgid "Allow TV spoilers for specific genres" +msgstr "" + +msgctxt "#33017" +msgid "Overrides the above for: {}" +msgstr "" + +msgctxt "#33018" +msgid "Cache Plex Home users" +msgstr "" + +msgctxt "#33019" +msgid "Visit media item" +msgstr "" + +msgctxt "#33020" +msgid "Play" +msgstr "" + +msgctxt "#33021" +msgid "Choose action" +msgstr "" + +msgctxt "#33022" +msgid "Use modern inverted watched states" +msgstr "" + +msgctxt "#33023" +msgid "Instead of marking unwatched items, mark watched items with a checkmark (modern clients; default: off)" +msgstr "" + +msgctxt "#33024" +msgid "Hide black backdrop in inverted watched states" +msgstr "" + +msgctxt "#33025" +msgid "When the above is enabled, hide the black backdrop of the watched state." +msgstr "" + +msgctxt "#33026" +msgid "Map path: {}" +msgstr "" + +msgctxt "#33027" +msgid "Remove mapping: {}" +msgstr "" + +msgctxt "#33028" +msgid "Hide library" +msgstr "" + +msgctxt "#33029" +msgid "Show library: {}" +msgstr "" + +msgctxt "#33030" +msgid "Choose action for: {}" +msgstr "" + +msgctxt "#33031" +msgid "Select Kodi source for {}" +msgstr "" + +msgctxt "#33032" +msgid "Show path mapping indicators" +msgstr "" + +msgctxt "#33033" +msgid "When path mapping is active for a library, display an indicator." +msgstr "" + +msgctxt "#33034" +msgid "Library settings" +msgstr "" + +msgctxt "#33035" +msgid "Delete {}: {}?" +msgstr "" + +msgctxt "#33036" +msgid "Delete episode S{0:02d}E{1:02d} from {2}?" +msgstr "" + +msgctxt "#33037" +msgid "Maximum intro offset to consider" +msgstr "" + +msgctxt "#33038" +msgid "When encountering an intro marker with a start time offset greater than this, ignore it (default: 600s/10m)" +msgstr "" + +msgctxt "#33039" +msgid "Move" +msgstr "" + +msgctxt "#33040" +msgid "Reset library order" +msgstr "" + +msgctxt "#33041" +msgid "Show hub: {}" +msgstr "" diff --git a/script.plexmod/resources/language/resource.language.es_es/strings.po b/script.plexmod/resources/language/resource.language.es_es/strings.po index ae77eb6a4..14a0bbe8a 100644 --- a/script.plexmod/resources/language/resource.language.es_es/strings.po +++ b/script.plexmod/resources/language/resource.language.es_es/strings.po @@ -1,1711 +1,2476 @@ -# XBMC Media Center language file msgid "" msgstr "" -"Project-Id-Version: XBMC-Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" -"POT-Creation-Date: 2013-12-12 22:56+0000\n" -"PO-Revision-Date: 2024-01-28 13:15+0100\n" -"Last-Translator: DeciBelioS\n" -"Language-Team: LANGUAGE\n" -"Language: es\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: Poedit 3.4.2\n" +"X-Generator: POEditor.com\n" +"Project-Id-Version: PM4K / PlexMod for Kodi\n" +"Language: es\n" +#: msgctxt "#32000" msgid "Main" msgstr "Principal" +#: msgctxt "#32001" msgid "Original" msgstr "Original" +#: msgctxt "#32002" msgid "20 Mbps 1080p" msgstr "20 Mbps 1080p" +#: msgctxt "#32003" msgid "12 Mbps 1080p" msgstr "12 Mbps 1080p" +#: msgctxt "#32004" msgid "10 Mbps 1080p" msgstr "10 Mbps 1080p" +#: msgctxt "#32005" msgid "8 Mbps 1080p" msgstr "8 Mbps 1080p" +#: msgctxt "#32006" msgid "4 Mbps 720p" msgstr "4 Mbps 720p" +#: msgctxt "#32007" msgid "3 Mbps 720p" msgstr "3 Mbps 720p" +#: msgctxt "#32008" msgid "2 Mbps 720p" msgstr "2 Mbps 720p" +#: msgctxt "#32009" msgid "1.5 Mbps 480p" msgstr "1.5 Mbps 480p" +#: msgctxt "#32010" msgid "720 kbps" msgstr "720 kbps" +#: msgctxt "#32011" msgid "320 kbps" msgstr "320 kbps" +#: msgctxt "#32012" msgid "208 kbps" msgstr "208 kbps" +#: msgctxt "#32013" msgid "96 kbps" msgstr "96 kbps" +#: msgctxt "#32014" msgid "64 kbps" msgstr "64 kbps" +#: msgctxt "#32020" msgid "Local Quality" msgstr "Calidad Local" +#: msgctxt "#32021" msgid "Remote Quality" -msgstr "Calidad Remoto" +msgstr "Calidad Remota" +#: msgctxt "#32022" msgid "Online Quality" -msgstr "Calidad Internet" +msgstr "Calidad en línea" +#: msgctxt "#32023" msgid "Transcode Format" msgstr "Formato transcodificación" +#: msgctxt "#32024" msgid "Debug Logging" -msgstr "Log Depuración" +msgstr "Log de Depuración" +#: msgctxt "#32025" msgid "Allow Direct Play" msgstr "Permitir reproducción directa" +#: msgctxt "#32026" msgid "Allow Direct Stream" msgstr "Permitir transmisión directa" +#: msgctxt "#32027" msgid "Force" msgstr "Forzar" +#: msgctxt "#32028" msgid "Always" msgstr "Siempre" +#: msgctxt "#32029" msgid "Only Image Formats" msgstr "Solo formatos de imagen" +#: msgctxt "#32030" msgid "Auto" msgstr "Auto" -msgctxt "#32031" -msgid "Burn-in Subtitles" -msgstr "Subtítulos quemados" - +#: msgctxt "#32032" msgid "Allow Insecure Connections" -msgstr "Permetir conexiones inseguras" +msgstr "Permitir conexiones inseguras" +#: msgctxt "#32033" msgid "Never" msgstr "Nunca" +#: msgctxt "#32034" msgid "On Same network" msgstr "En la misma red" +#: msgctxt "#32035" msgid "Always" msgstr "Siempre" +#: msgctxt "#32036" msgid "Allow 4K" msgstr "Permitir 4K" +#: msgctxt "#32037" msgid "Allow HEVC (h265)" -msgstr "Permetir HEVC (h265)" +msgstr "Permitir HEVC (h265)" +#: msgctxt "#32038" msgid "Automatically Sign In" -msgstr "Accesso automatico" +msgstr "Accesso automático" +#: msgctxt "#32039" msgid "Post Play Auto Play" msgstr "Reproducción automática posterior" +#: msgctxt "#32040" msgid "Enable Subtitle Downloading" msgstr "Activar la descarga de subtítulos" +#: msgctxt "#32041" msgid "Enable Subtitle Downloading" msgstr "Activar la descarga de subtítulos" +#: msgctxt "#32042" msgid "Server Discovery (GDM)" msgstr "Detección del Servidor (GDM)" +#: msgctxt "#32043" msgid "Start Plex On Kodi Startup" msgstr "Arrancar Plex al iniciar Kodi" +#: msgctxt "#32044" msgid "Connection 1 IP" -msgstr "IP Conexión 1" +msgstr "Conexión IP 1" +#: msgctxt "#32045" msgid "Connection 1 Port" msgstr "Puerto Conexión 1" +#: msgctxt "#32046" msgid "Connection 2 IP" -msgstr "IP Conexión 2" +msgstr "Conexión IP 2" +#: msgctxt "#32047" msgid "Connection 2 Port" msgstr "Puerto conexión 2" +#: msgctxt "#32048" msgid "Audio" msgstr "Audio" +#: msgctxt "#32049" msgid "Advanced" -msgstr "Avanzar" +msgstr "Avanzado" +#: msgctxt "#32050" msgid "Manual Servers" msgstr "Servidores manuales" +#: msgctxt "#32051" msgid "Privacy" msgstr "Privacidad" +#: msgctxt "#32052" msgid "About" msgstr "Acerca de" +#: msgctxt "#32053" msgid "Video" msgstr "Video" +#: msgctxt "#32054" msgid "Addon Version" -msgstr "Versión Add-on" +msgstr "Versión del Add-on" +#: msgctxt "#32055" msgid "Kodi Version" -msgstr "Versión Kodi" +msgstr "Versión de Kodi" +#: msgctxt "#32056" msgid "Screen Resolution" msgstr "Resolución de Pantalla" +#: msgctxt "#32057" msgid "Current Server Version" -msgstr "Versión del Servidor" +msgstr "Versión actual del Servidor" +#: msgctxt "#32058" msgid "Never exceed original audio codec" -msgstr "No superar nunca el códec de audio original" +msgstr "Nunca superar el códec de audio original" +#: msgctxt "#32059" msgid "When transcoding audio, never exceed the original audio bitrate or channel count on the same codec." msgstr "Cuando transcodifiques audio, nunca superes la tasa de bits o el número de canales del audio original en el mismo códec." +#: msgctxt "#32060" msgid "Use Kodi audio channels" msgstr "Utilizar los canales de audio de Kodi" -msgctxt "#32061" -msgid "When transcoding audio, target the audio channels set in Kodi." -msgstr "Al transcodificar audio, apunte a los canales de audio configurados en Kodi." - -msgctxt "#32062" -msgid "Transcode audio to AC3" -msgstr "Transcodificar audio a AC3" - -msgctxt "#32063" -msgid "Transcode audio to AC3 in certain conditions (useful for passthrough)." -msgstr "Transcodifica el audio a AC3 en determinadas condiciones (útil para passthrough)." - +#: msgctxt "#32064" msgid "Treat DTS like AC3" msgstr "Tratar DTS como AC3" -msgctxt "#32065" -msgid "When any of the force AC3 settings are enabled, treat DTS the same as AC3 (useful for Optical passthrough)" -msgstr "Cuando cualquiera de los ajustes de forzar AC3 está activado, trata DTS igual que AC3 (útil para el passthrough)" - -msgctxt "#32066" -msgid "Force audio to AC3" -msgstr "Forzar audio a AC3" - -msgctxt "#32067" -msgid "Only force multichannel audio to AC3" -msgstr "Forzar sólo el audio multicanal a AC3" - +#: msgctxt "#32100" msgid "Skip user selection and pin entry on startup." -msgstr "Omitir selección de usuario y PIN al iniciar." +msgstr "Omitir la selección de usuario y PIN al iniciar." +#: msgctxt "#32101" msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." msgstr "Si se activa, cuando acabe la reproducción y 'Siguiente Capítulo' esté disponible, se reproducirá automáticamente a los 15 segundos." +#: msgctxt "#32102" msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." -msgstr "Activa esto si se puede reproducir contenido 4K. Desactívalo para forzar la trasncodificación." +msgstr "Activa esto si tu Hardware soporta la reproducción de contenido 4K. Desactívalo para forzar la transcodificación." +#: msgctxt "#32103" msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." -msgstr "Activa esto si se puede reproducir HEVC/h265. Desactiva para forzar la trascodificación." +msgstr "Activa esto si tu Hardware soporta la reproducción HEVC/h265. Desactiva para forzar la transcodificación." +#: msgctxt "#32104" msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" -msgstr "Conectar a servidores con conexiones no seguras.[CR][CR]* [B]Nunca[/B]: Nunca conectarse a un servidor de forma no segura[CR]* [B]En la misma red[/B]: Permitir para la misma red[CR]* [B]Siempre[/B]: Permitir para todas las conexiones" +msgstr "Conectar a servidores con conexiones no seguras.[CR][CR]* [B]Nunca[/B]: Nunca conectarse a un servidor de forma no segura[CR]* [B]En la misma red[/B]: Permitir si está en la misma red[CR]* [B]Siempre[/B]: Permitir para todas las conexiones" +#: msgctxt "#32201" msgid "Trailer" msgstr "Tráiler" +#: msgctxt "#32202" msgid "Deleted Scene" msgstr "Escenas eliminadas" +#: msgctxt "#32203" msgid "Interview" msgstr "Entrevista" +#: msgctxt "#32204" msgid "Music Video" msgstr "Video musical" +#: msgctxt "#32205" msgid "Behind the Scenes" -msgstr "Detrás de las escenas" +msgstr "Detrás de escenas" +#: msgctxt "#32206" msgid "Scene" msgstr "Escena" +#: msgctxt "#32207" msgid "Live Music Video" -msgstr "Videos de música en vivo" +msgstr "Video musical en vivo" +#: msgctxt "#32208" msgid "Lyric Music Video" -msgstr "Videos de letras musicales" +msgstr "Video de letras musicales" +#: msgctxt "#32209" msgid "Concert" -msgstr "Conciertos" +msgstr "Concierto" +#: msgctxt "#32210" msgid "Featurette" msgstr "Featurette" +#: msgctxt "#32211" msgid "Short" msgstr "Cortos" +#: msgctxt "#32212" msgid "Other" msgstr "Otros" +#: msgctxt "#32300" msgid "Go to Album" msgstr "Ir a Album" +#: msgctxt "#32301" msgid "Go to Artist" msgstr "Ir a Artistas" +#: msgctxt "#32302" msgid "Go to {0}" msgstr "Ir a {0}" -msgctxt "#32303" -msgid "Season" -msgstr "Temporada" - -msgctxt "#32304" -msgid "Episode" -msgstr "Capítulo" - +#: msgctxt "#32305" msgid "Extras" msgstr "Extras" +#: msgctxt "#32306" msgid "Related Shows" msgstr "Series relacionadas" +#: msgctxt "#32307" msgid "More" msgstr "Más" +#: msgctxt "#32308" msgid "Available" msgstr "Disponible" +#: msgctxt "#32309" msgid "None" msgstr "Ninguno" -msgctxt "#32310" -msgid "S" -msgstr "S" - -msgctxt "#32311" -msgid "E" -msgstr "E" - +#: msgctxt "#32312" msgid "Unavailable" msgstr "No disponible" +#: msgctxt "#32313" msgid "This item is currently unavailable." msgstr "Este elemento no está disponible actualmente." +#: msgctxt "#32314" msgid "In Progress" msgstr "En curso" +#: msgctxt "#32315" msgid "Resume playback?" msgstr "¿Continuar reproducción?" +#: msgctxt "#32316" msgid "Resume" msgstr "Continuar" +#: msgctxt "#32317" msgid "Play from beginning" msgstr "Reproducir desde el principio" +#: msgctxt "#32318" msgid "Mark Unplayed" msgstr "Marcar como no visto" +#: msgctxt "#32319" msgid "Mark Played" msgstr "Marcar como visto" +#: msgctxt "#32320" msgid "Mark Season Unplayed" msgstr "Marca la Temporada como no vista" +#: msgctxt "#32321" msgid "Mark Season Played" msgstr "Marcar la Temporada como vista" +#: msgctxt "#32322" msgid "Delete" msgstr "Borrar" +#: msgctxt "#32323" msgid "Go To Show" msgstr "Ir a la Serie" +#: msgctxt "#32324" msgid "Go To {0}" msgstr "Ir a {0}" +#: msgctxt "#32325" msgid "Play Next" msgstr "Reproducir el siguiente" +#: msgctxt "#32326" msgid "Really Delete?" msgstr "¿Borrarlo de verdad?" +#: msgctxt "#32327" msgid "Are you sure you really want to delete this media?" msgstr "¿Seguro que quieres borrar este medio?" +#: msgctxt "#32328" msgid "Yes" msgstr "Sí" +#: msgctxt "#32329" msgid "No" msgstr "No" +#: msgctxt "#32330" msgid "Message" msgstr "Mensaje" +#: msgctxt "#32331" msgid "There was a problem while attempting to delete the media." msgstr "Hubo un problema al intentar borrar este medio." +#: msgctxt "#32332" msgid "Home" msgstr "Inicio" +#: msgctxt "#32333" msgid "Playlists" msgstr "Listas de reproducción" +#: msgctxt "#32334" msgid "Confirm Exit" msgstr "Confirmar salida" +#: msgctxt "#32335" msgid "Are you ready to exit Plex?" msgstr "¿Listo para salir de Plex?" +#: msgctxt "#32336" msgid "Exit" msgstr "Salir" +#: msgctxt "#32337" msgid "Cancel" msgstr "Cancelar" +#: msgctxt "#32338" msgid "No Servers Found" msgstr "Ningún servidor encontrado" +#: msgctxt "#32339" msgid "Server is not accessible" msgstr "Servidor no accessible" +#: msgctxt "#32340" msgid "Connection tests are in progress. Please wait." -msgstr "Tests de conexión en curso. Espere por favor." +msgstr "Pruebas de conexión en curso. Espere por favor." +#: msgctxt "#32341" msgid "Server is not accessible. Please sign into your server and check your connection." msgstr "Servidor no accessible. Por favor, comprueba la conexión de tu servidor." +#: msgctxt "#32342" msgid "Switch User" msgstr "Cambiar usuario" +#: msgctxt "#32343" msgid "Settings" msgstr "Configuración" +#: msgctxt "#32344" msgid "Sign Out" -msgstr "Desconectar" +msgstr "Cerrar sesión" +#: msgctxt "#32345" msgid "All" msgstr "Todo" +#: msgctxt "#32346" msgid "By Name" msgstr "Por Nombre" +#: msgctxt "#32347" msgid "Artists" msgstr "Artistas" +#: msgctxt "#32348" msgid "Movies" msgstr "Películas" +#: msgctxt "#32349" msgid "photos" msgstr "fotos" +#: msgctxt "#32350" msgid "Shows" msgstr "Series" +#: msgctxt "#32351" msgid "By Date Added" -msgstr "Por fecha" +msgstr "Por fecha de añadido" +#: msgctxt "#32352" msgid "Date Added" -msgstr "Fecha" +msgstr "Fecha de añadido" +#: msgctxt "#32353" msgid "By Release Date" msgstr "Por fecha de estreno" +#: msgctxt "#32354" msgid "Release Date" msgstr "Fecha de estreno" +#: msgctxt "#32355" msgid "By Date Viewed" -msgstr "Por fecha de visionado" +msgstr "Por fecha en la que se vio" +#: msgctxt "#32356" msgid "Date Viewed" -msgstr "Fecha de visionado" +msgstr "Fecha en la que se vio" +#: msgctxt "#32357" msgid "By Name" msgstr "Por nombre" +#: msgctxt "#32358" msgid "Name" msgstr "Nombre" +#: msgctxt "#32359" msgid "By Rating" msgstr "Por valoración" +#: msgctxt "#32360" msgid "Rating" msgstr "Valoración" +#: msgctxt "#32361" msgid "By Resolution" msgstr "Por Resolución" +#: msgctxt "#32362" msgid "Resolution" msgstr "Resolución" +#: msgctxt "#32363" msgid "By Duration" msgstr "Por Duración" +#: msgctxt "#32364" msgid "Duration" msgstr "Duración" +#: msgctxt "#32365" msgid "By First Aired" msgstr "Por primera emisión" +#: msgctxt "#32366" msgid "First Aired" msgstr "Primera emisión" +#: msgctxt "#32367" msgid "By Unplayed" msgstr "Por No Vistos" +#: msgctxt "#32368" msgid "Unplayed" -msgstr "Non visto" +msgstr "No visto" +#: msgctxt "#32369" msgid "By Date Played" msgstr "Por Fecha de Reproducción" +#: msgctxt "#32370" msgid "Date Played" msgstr "Fecha de Reproducción" +#: msgctxt "#32371" msgid "By Play Count" msgstr "Por Número de Reproducciones" +#: msgctxt "#32372" msgid "Play Count" msgstr "Número de Reproducciones" +#: msgctxt "#32373" msgid "By Date Taken" msgstr "Por Fecha de Captura" +#: msgctxt "#32374" msgid "Date Taken" msgstr "Fecha de Captura" +#: msgctxt "#32375" msgid "No filters available" -msgstr "Sin filtros disponbles" +msgstr "Sin filtros disponibles" +#: msgctxt "#32376" msgid "Clear Filter" msgstr "Quitar filtros" +#: msgctxt "#32377" msgid "Year" msgstr "Año" +#: msgctxt "#32378" msgid "Decade" msgstr "Década" +#: msgctxt "#32379" msgid "Genre" msgstr "Género" +#: msgctxt "#32380" msgid "Content Rating" msgstr "Clasificación por Edad" +#: msgctxt "#32381" msgid "Network" msgstr "Red" +#: msgctxt "#32382" msgid "Collection" msgstr "Colección" +#: msgctxt "#32383" msgid "Director" msgstr "Dirección" +#: msgctxt "#32384" msgid "Actor" -msgstr "Actores" +msgstr "Actor" +#: msgctxt "#32385" msgid "Country" msgstr "País" +#: msgctxt "#32386" msgid "Studio" msgstr "Estudio" +#: msgctxt "#32387" msgid "Labels" msgstr "Etiquetas" +#: msgctxt "#32388" msgid "Camera Make" msgstr "Marca de Cámara" +#: msgctxt "#32389" msgid "Camera Model" msgstr "Modelo de Cámera" +#: msgctxt "#32390" msgid "Aperture" msgstr "Apertura" +#: msgctxt "#32391" msgid "Shutter Speed" msgstr "Velocidad de apertura" +#: msgctxt "#32392" msgid "Lens" msgstr "Lente" +#: msgctxt "#32393" msgid "TV Shows" msgstr "Series de TV" +#: msgctxt "#32394" msgid "Music" msgstr "Música" +#: msgctxt "#32395" msgid "Audio" msgstr "Audio" +#: msgctxt "#32396" msgid "Subtitles" msgstr "Subtítulos" +#: msgctxt "#32397" msgid "Quality" msgstr "Calidad" +#: msgctxt "#32398" msgid "Kodi Video Settings" msgstr "Configuración de Video de Kodi" +#: msgctxt "#32399" msgid "Kodi Audio Settings" msgstr "Configuración de Audio de Kodi" +#: msgctxt "#32400" msgid "Go To Season" msgstr "Ir a Temporada" +#: msgctxt "#32401" msgid "Directors" msgstr "Dirección" +#: msgctxt "#32402" msgid "Writer" msgstr "Autor" +#: msgctxt "#32403" msgid "Writers" msgstr "Guionistas" +#: msgctxt "#32404" msgid "Related Movies" msgstr "Películas relacionadas" +#: msgctxt "#32405" msgid "Download Subtitles" msgstr "Descargar Subtítulos" +#: msgctxt "#32406" msgid "Subtitle Delay" msgstr "Retardo en Subtítulos" +#: msgctxt "#32407" msgid "Next Subtitle" msgstr "Siguiente Subtítulo" +#: msgctxt "#32408" msgid "Disable Subtitles" msgstr "Desactivar Subtítulos" +#: msgctxt "#32409" msgid "Enable Subtitles" msgstr "Activar Subtítulos" +#: msgctxt "#32410" msgid "Platform Version" msgstr "Versión de la Plataforma" +#: msgctxt "#32411" msgid "Unknown" msgstr "Desconocido" +#: msgctxt "#32412" msgid "Edit Or Clear" msgstr "Modificar o Borrar" +#: msgctxt "#32413" msgid "Edit IP address or clear the current setting?" -msgstr "¿Editar la direeción IP o borrar la configuración?" +msgstr "¿Editar la direción IP o borrar la configuración?" +#: msgctxt "#32414" msgid "Clear" msgstr "Borrar" +#: msgctxt "#32415" msgid "Edit" msgstr "Modificar" +#: msgctxt "#32416" msgid "Enter IP Address" msgstr "Introduce la Dirección IP" +#: msgctxt "#32417" msgid "Enter Port Number" msgstr "Introduce el Puerto" +#: msgctxt "#32418" msgid "Creator" msgstr "Creador" +#: msgctxt "#32419" msgid "Cast" msgstr "Elenco" +#: msgctxt "#32420" msgid "Disc" msgstr "Disco" +#: msgctxt "#32421" msgid "Sign Out" -msgstr "Desconectar" +msgstr "Cerrar sesión" +#: msgctxt "#32422" msgid "Exit" msgstr "Salir" +#: msgctxt "#32423" msgid "Shutdown" msgstr "Apagar" +#: msgctxt "#32424" msgid "Suspend" msgstr "Suspender" +#: msgctxt "#32425" msgid "Hibernate" msgstr "Hibernar" +#: msgctxt "#32426" msgid "Reboot" msgstr "Reiniciar" +#: msgctxt "#32427" msgid "Failed" msgstr "Fallo" +#: msgctxt "#32428" msgid "Login failed!" msgstr "¡El acceso falló!" +#: msgctxt "#32429" msgid "Resume from {0}" msgstr "Continuar desde {0}" +#: msgctxt "#32430" msgid "Discovery" msgstr "Descubrimiento" +#: msgctxt "#32431" msgid "Search" msgstr "Búsqueda" +#: msgctxt "#32432" msgid "Space" msgstr "Espacio" +#: msgctxt "#32433" msgid "Clear" msgstr "Borrar" +#: msgctxt "#32434" msgid "Searching..." msgstr "Buscando..." +#: msgctxt "#32435" msgid "No Results" msgstr "Sin resultados" +#: msgctxt "#32436" msgid "Paused" msgstr "En Pausa" +#: msgctxt "#32437" msgid "Welcome" msgstr "Bienvenido" +#: msgctxt "#32438" msgid "Previous" msgstr "Anterior" +#: msgctxt "#32439" msgid "Playing Next" msgstr "Reproducir el Siguiente" +#: msgctxt "#32440" msgid "On Deck" msgstr "En Portada" +#: msgctxt "#32441" msgid "Unknown" msgstr "Desconocido" +#: msgctxt "#32442" msgid "Embedded" msgstr "Integrado" +#: msgctxt "#32443" msgid "Forced" msgstr "Forzado" +#: msgctxt "#32444" msgid "Lyrics" msgstr "Letras" +#: msgctxt "#32445" msgid "Mono" msgstr "Mono" +#: msgctxt "#32446" msgid "Stereo" msgstr "Stereo" +#: msgctxt "#32447" msgid "None" msgstr "Ninguno" +#: msgctxt "#32448" msgid "Playback Failed!" msgstr "¡La reproducción falló!" +#: msgctxt "#32449" msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." -msgstr "No pude conectarme a plex.tv[CR]Comprueba la conexión y vuelve a intentarlo." +msgstr "No se pudo conectar a plex.tv[CR]Comprueba la conexión y vuelve a intentarlo." +#: msgctxt "#32450" msgid "Choose Version" msgstr "Elegir una Versión" +#: msgctxt "#32451" msgid "Play Version..." msgstr "Reproduce un Versión..." +#: msgctxt "#32452" msgid "No Content available in this library" msgstr "No hay contenido disponible en esta bilioteca" +#: msgctxt "#32453" msgid "Please add content and/or check that 'Include in dashboard' is enabled." -msgstr "Por favo, añade contenido y/o comprueba que 'Incluir en el dashboard' esté activado." +msgstr "Por favor, añade contenido y/o comprueba que 'Incluir en el dashboard' esté activado." +#: msgctxt "#32454" msgid "No Content available for this filter" msgstr "Sin contenido disponible por este filtro" +#: msgctxt "#32455" msgid "Please change change or remove the current filter" msgstr "Por favor, cambie o quite el filtro actual" +#: msgctxt "#32456" msgid "Show" msgstr "Serie" +#: msgctxt "#32457" msgid "By Show" msgstr "Por Serie" +#: msgctxt "#32458" msgid "Episodes" msgstr "Capítulo" +#: msgctxt "#32459" msgid "Offline Mode" msgstr "Modo Offline" +#: msgctxt "#32460" msgid "Sign In" -msgstr "Acceso" +msgstr "Iniciar sesión" +#: msgctxt "#32461" msgid "Albums" -msgstr "Albums" +msgstr "Álbumes" +#: msgctxt "#32462" msgid "Artist" msgstr "Artista" +#: msgctxt "#32463" msgid "By Artist" msgstr "Por Artista" +#: msgctxt "#32464" msgid "Player" msgstr "Reproductor" +#: msgctxt "#32465" msgid "Use skip step settings from Kodi" msgstr "Utilizar la configuración de salto de paso de Kodi" +#: msgctxt "#32466" msgid "Automatically seek selected position after a delay" msgstr "Búsqueda automática de la posición seleccionada tras un retardo" +#: msgctxt "#32467" msgid "User Interface" msgstr "Interfaz de usuario" +#: msgctxt "#32468" msgid "Show dynamic background art" msgstr "Mostrar arte de fondo dinámico" +#: msgctxt "#32469" msgid "Background art blur amount" msgstr "Cantidad de desenfoque del arte de fondo" +#: msgctxt "#32470" msgid "Background art opacity" msgstr "Opacidad del arte de fondo" +#: msgctxt "#32471" msgid "Use Plex/Kodi steps for timeline" msgstr "Utiliza los pasos de Plex/Kodi para la línea de tiempo" +#: msgctxt "#32480" msgid "Theme music" msgstr "Tema musical" +#: msgctxt "#32481" msgid "Off" msgstr "Apagado" +#: msgctxt "#32482" msgid "%(percentage)s %%" msgstr "%(percentage)s %%" +#: msgctxt "#32483" msgid "Hide Stream Info" msgstr "Ocultar mediainfo" +#: msgctxt "#32484" msgid "Show Stream Info" msgstr "Mostrar mediainfo" +#: msgctxt "#32485" msgid "Go back instantly with the previous menu action in scrolled views" msgstr "Retroceder instantáneamente con la acción del menú anterior en vistas desplazadas" +#: msgctxt "#32487" msgid "Seek Delay" msgstr "Retraso de búsqueda" +#: msgctxt "#32488" msgid "Screensaver" msgstr "Salvapantallas" +#: msgctxt "#32489" msgid "Quiz Mode" msgstr "Modo concurso" +#: msgctxt "#32490" msgid "Collections" msgstr "Colecciones" +#: msgctxt "#32491" msgid "Folders" msgstr "Carpetas" +#: msgctxt "#32492" msgid "Kodi Subtitle Settings" msgstr "Configuración de subtítulos de Kodi" -msgctxt "#32493" -msgid "When a media file has a forced/foreign subtitle for a subtitle-enabled language, the Plex Media Server preselects it. This behaviour is usually not necessary and not configurable. This setting fixes that by ignoring the PMSs decision and selecting the same language without a forced flag if possible." -msgstr "Cuando un archivo multimedia tiene un subtítulo forzado/extranjero para un idioma habilitado para subtítulos, el Plex Media Server lo preselecciona. Este comportamiento no suele ser necesario y no es configurable. Este ajuste lo soluciona ignorando la decisión del PMS y seleccionando el mismo idioma sin bandera forzada si es posible." - +#: msgctxt "#32495" msgid "Skip intro" msgstr "Saltar introducción" +#: msgctxt "#32496" msgid "Skip credits" msgstr "Saltar créditos" +#: msgctxt "#32500" msgid "Always show post-play screen (even for short videos)" -msgstr "Mostrar siempre la pantalla posterior a la reproducción (incluso para vídeos cortos)" +msgstr "Mostrar siempre la pantalla posterior a la reproducción (incluso para videos cortos)" +#: msgctxt "#32501" msgid "Time-to-wait between videos on post-play" -msgstr "Tiempo de espera entre vídeos en post-play" +msgstr "Tiempo de espera entre videos en post-play" +#: msgctxt "#32505" msgid "Visit media in video playlist instead of playing it" msgstr "Visitar medios en la lista de reproducción de vídeo en lugar de reproducirlos" +#: msgctxt "#32521" msgid "Skip Intro Button Timeout" msgstr "Tiempo de espera del botón de intro" +#: msgctxt "#32522" msgid "Automatically Skip Intro" msgstr "Saltar automáticamente la introducción" -msgctxt "#32523" -msgid "Automatically skip intros if available. Doesn't override enabled binge mode.\nCan be disabled/enabled per TV show." -msgstr "Salta automáticamente las intros si están disponibles. No anula el modo atracón activado.\nPuede desactivarse/activarse por programa de TV." - +#: msgctxt "#32524" msgid "Set how long the skip intro button shows for." msgstr "Establece el tiempo que se mostrará el botón de salto de introducción." +#: msgctxt "#32525" msgid "Skip Credits Button Timeout" msgstr "Salto del tiempo de espera del botón de créditos" +#: msgctxt "#32526" msgid "Automatically Skip Credits" msgstr "Saltar créditos automáticamente" -msgctxt "#32527" -msgid "Automatically skip credits if available. Doesn't override enabled binge mode.\nCan be disabled/enabled per TV show." -msgstr "Salta automáticamente los créditos si están disponibles. No anula el modo atracón activado.\nPuede desactivarse/activarse por programa de TV." - +#: msgctxt "#32528" msgid "Set how long the skip credits button shows for." msgstr "Establece el tiempo que se mostrará el botón de saltar créditos." +#: msgctxt "#32540" msgid "Show when the current video will end in player" msgstr "Mostrar cuándo terminará el vídeo actual en el reproductor" +#: msgctxt "#32541" msgid "Shows time left and at which time the media will end." msgstr "Muestra el tiempo restante y a qué hora terminará el medio." +#: msgctxt "#32542" msgid "Show \"Ends at\" label for the end-time as well" msgstr "Mostrar la etiqueta \"Finaliza en\" también para la hora de finalización" +#: msgctxt "#32543" msgid "Ends at" msgstr "Termina en" +#: msgctxt "#32601" msgid "Allow AV1" msgstr "Permitir AV1" +#: msgctxt "#32602" msgid "Enable this if your hardware can handle AV1. Disable it to force transcoding." msgstr "Actívelo si su hardware puede manejar AV1. Desactívalo para forzar la transcodificación." +#: msgctxt "#33101" msgid "By Audience Rating" msgstr "Por índice de audiencia" +#: msgctxt "#33102" msgid "Audience Rating" msgstr "Clasificación del público" +#: msgctxt "#33103" msgid "By my Rating" msgstr "Según mi valoración" +#: msgctxt "#33104" msgid "My Rating" msgstr "Mi valoración" +#: msgctxt "#33105" msgid "By Content Rating" msgstr "Por clasificación de contenidos" +#: msgctxt "#33106" msgid "Content Rating" msgstr "Clasificación del contenido" +#: msgctxt "#33107" msgid "By Critic Rating" msgstr "Por valoración crítica" +#: msgctxt "#33108" msgid "Critic Rating" msgstr "Valoración de la crítica" +#: msgctxt "#33200" msgid "Background Color" msgstr "Color de fondo" +#: msgctxt "#33201" msgid "Specify solid Background Color instead of using media images" msgstr "Especifique un color de fondo sólido en lugar de utilizar imágenes multimedia" +#: msgctxt "#33400" msgid "Use old compatibility profile" msgstr "Utilizar el antiguo perfil de compatibilidad" +#: msgctxt "#33401" msgid "Uses the Chrome client profile instead of the custom one. Might fix rare issues with 3D playback." msgstr "Utiliza el perfil de cliente de Chrome en lugar del personalizado. Podría solucionar problemas poco frecuentes con la reproducción 3D." +#: +msgctxt "#32031" +msgid "Burn-in Subtitles" +msgstr "Subtítulos quemados" + +#: +msgctxt "#32061" +msgid "When transcoding audio, target the audio channels set in Kodi." +msgstr "Al transcodificar audio, apunte a los canales de audio configurados en Kodi." + +#: +msgctxt "#32062" +msgid "Transcode audio to AC3" +msgstr "Transcodificar audio a AC3" + +#: +msgctxt "#32063" +msgid "Transcode audio to AC3 in certain conditions (useful for passthrough)." +msgstr "Transcodifica el audio a AC3 en determinadas condiciones (útil para passthrough)." + +#: +msgctxt "#32065" +msgid "When any of the force AC3 settings are enabled, treat DTS the same as AC3 (useful for Optical passthrough)" +msgstr "Cuando cualquiera de los ajustes de forzar AC3 está activado, trata DTS igual que AC3 (útil para el passthrough)" + +#: +msgctxt "#32066" +msgid "Force audio to AC3" +msgstr "Forzar audio a AC3" + +#: +msgctxt "#32067" +msgid "Only force multichannel audio to AC3" +msgstr "Forzar sólo el audio multicanal a AC3" + +#: +msgctxt "#32493" +msgid "When a media file has a forced/foreign subtitle for a subtitle-enabled language, the Plex Media Server preselects it. This behaviour is usually not necessary and not configurable. This setting fixes that by ignoring the PMSs decision and selecting the same language without a forced flag if possible." +msgstr "Cuando un archivo multimedia tiene un subtítulo forzado/extranjero para un idioma habilitado para subtítulos, el Plex Media Server lo preselecciona. Este comportamiento no suele ser necesario y no es configurable. Este ajuste lo soluciona ignorando la decisión del PMS y seleccionando el mismo idioma sin bandera forzada si es posible." + +#: +msgctxt "#32523" +msgid "Automatically skip intros if available. Doesn't override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Salta automáticamente las intros si están disponibles. No anula el modo maratón activado.\n" +"Puede desactivarse/activarse por programa de TV." + +#: +msgctxt "#32527" +msgid "Automatically skip credits if available. Doesn't override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Salta automáticamente los créditos si están disponibles. No anula el modo maratón activado.\n" +"Puede desactivarse/activarse por programa de TV." + +#: msgctxt "#33501" msgid "Video played threshold" msgstr "Umbral de reproducción de vídeo" +#: msgctxt "#33502" msgid "Set this to the same value as your Plex server (Settings>Library>Video played threshold) to avoid certain pitfalls, Default: 90 %" -msgstr "Ajústelo al mismo valor que su servidor Plex (Configuración>Biblioteca>Umbral de vídeo reproducido) para evitar ciertas trampas, Predeterminado: 90%" +msgstr "Ajústelo al mismo valor que su servidor Plex (Configuración>Biblioteca>Umbral de vídeo reproducido) para evitar ciertas caídas, Predeterminado: 90%" +#: msgctxt "#33503" msgid "Use alternative hubs refresh" -msgstr "Utilizar centros alternativos refrescar" +msgstr "Utilizar un método alternativo para refrescar los Hubs" +#: msgctxt "#33504" msgid "Refreshes all hubs for all libraries after an item's watch-state has changed, instead of only those likely affected. Use this if you find a hub that doesn't update properly." -msgstr "Actualiza todos los concentradores de todas las bibliotecas después de que el estado de vigilancia de un elemento haya cambiado, en lugar de sólo los probablemente afectados. Utilícelo si encuentra un concentrador que no se actualiza correctamente." +msgstr "Actualiza todos los Hubs de todas las bibliotecas después de que el estado de reproducción de un elemento haya cambiado, en lugar de sólo los probablemente afectados. Utilícelo si encuentra un Hub que no se actualiza correctamente." +#: msgctxt "#33505" msgid "Show intro skip button early" msgstr "Mostrar el botón de salto de introducción antes de tiempo" +#: msgctxt "#33506" -msgid "Show the intro skip button from the start of a video with an intro marker. The auto-skipping setting applies. Doesn\'t override enabled binge mode.\nCan be disabled/enabled per TV show." -msgstr "Mostrar el botón de salto de introducción desde el inicio de un vídeo con un marcador de introducción. Se aplica la configuración de salto automático. No anula el modo atracón activado.\nPuede desactivarse/activarse por programa de TV." +msgid "Show the intro skip button from the start of a video with an intro marker. The auto-skipping setting applies. Doesn\\'t override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Mostrar el botón de salto de introducción desde el inicio de un vídeo con un marcador de introducción. Se aplica la configuración de salto automático. No anula el modo maratón activado.\n" +"Puede desactivarse/activarse por programa de TV." +#: msgctxt "#33507" msgid "Enabled" msgstr "Activado" +#: msgctxt "#33508" msgid "Disabled" msgstr "Desactivado" +#: msgctxt "#33509" msgid "Early intro skip threshold (default: < 60s/1m)" msgstr "Umbral de salto de introducción temprana (por defecto: < 60s/1m)" +#: msgctxt "#33510" msgid "When showing the intro skip button early, only do so if the intro occurs within the first X seconds." -msgstr "Cuando muestre el botón de salto de introducción antes de tiempo, hágalo sólo si la introducción se produce en los primeros X segundos." +msgstr "Cuando se muestre el botón de salto de introducción antes de tiempo, hacerlo sólo si la introducción se produce en los primeros X segundos." +#: msgctxt "#33600" msgid "System" msgstr "Sistema" +#: msgctxt "#33601" msgid "Show video chapters" msgstr "Mostrar capítulos de vídeo" +#: msgctxt "#33602" msgid "If available, show video chapters from the video-file instead of the timeline-big-seek-steps." msgstr "Si está disponible, mostrar capítulos de vídeo del archivo de vídeo en lugar de la línea de tiempo-grandes-pasos-de-búsqueda." +#: msgctxt "#33603" msgid "Use virtual chapters" msgstr "Utilizar capítulos virtuales" +#: msgctxt "#33604" msgid "When the above is enabled and no video chapters are available, simulate them by using the markers identified by the Plex Server (Intro, Credits)." msgstr "Cuando lo anterior esté activado y no haya capítulos de vídeo disponibles, simúlelos utilizando los marcadores identificados por el Servidor Plex (Intro, Créditos)." +#: msgctxt "#33605" msgid "Video Chapters" msgstr "Capítulos de vídeo" +#: msgctxt "#33606" msgid "Virtual Chapters" msgstr "Capítulos virtuales" +#: msgctxt "#33607" msgid "Chapter {}" msgstr "Capítulo {}" +#: msgctxt "#33608" msgid "Intro" msgstr "Introducción" +#: msgctxt "#33609" msgid "Credits" msgstr "Créditos" +#: msgctxt "#33610" msgid "Main" msgstr "Principal" +#: msgctxt "#33611" msgid "Chapters" msgstr "Capítulos" +#: msgctxt "#33612" msgid "Markers" msgstr "Marcadores" +#: msgctxt "#33613" msgid "Kodi Buffer Size (MB)" msgstr "Tamaño del búfer de Kodi (MB)" +#: msgctxt "#33614" -msgid "Set the Kodi Cache/Buffer size. Free: {} MB, Recommended: ~100 MB, Recommended max: {} MB, Default: 20 MB." -msgstr "Establece el tamaño de la Caché/Buffer de Kodi. Libre: {} MB, Recomendado: ~100 MB, Máximo recomendado: {} MB, Por defecto: 20 MB." +msgid "Set the Kodi Cache/Buffer size. Free: {} MB, Recommended: ~50 MB, Recommended max: {} MB, Default: 20 MB." +msgstr "Colocar la Caché de Kodi/Tamaño de Buffer. Libre: {} MB, Recomendado: ~50 MB, Recomendado máximo: {} MB, Por defecto: 20 MB." +#: msgctxt "#33615" msgid "{time} left" msgstr "{time} restante" +#: msgctxt "#33616" msgid "Addon Path" msgstr "Ruta de Addon" +#: msgctxt "#33617" msgid "Userdata/Profile Path" -msgstr "Ruta de datos de usuario/perfil" +msgstr "Ruta Userdata/profile" +#: msgctxt "#33618" msgid "TV binge-viewing mode" -msgstr "Modo \"atracón\" de TV" +msgstr "Modo \"maratón\" de TV" +#: msgctxt "#33619" -msgid "Automatically skips episode intros, credits and tries to skip episode recaps. Doesn\'t skip the intro of the first episode of a season and doesn't skip the final credits of a show.\n\nCan be disabled/enabled per TV show.\nOverrides any setting below." -msgstr "Se salta automaticamente las intros de los episodios, los créditos e intenta saltarse los resúmenes de los episodios. No salta la intro del primer episodio de una temporada y no salta los créditos finales de un programa.\nPuede ser desactivado/activado por programa de TV.\nAnula cualquier configuración de abajo." - +msgid "Automatically skips episode intros, credits and tries to skip episode recaps. Doesn\\'t skip the intro of the first episode of a season and doesn't skip the final credits of a show.\n" +"\n" +"Can be disabled/enabled per TV show.\n" +"Overrides any setting below." +msgstr "Se salta automaticamente las intros de los episodios, los créditos e intenta saltarse los resúmenes de los episodios. No salta la intro del primer episodio de una temporada y no salta los créditos finales de un programa.\n" +"Puede ser desactivado/activado por programa de TV.\n" +"Anula cualquier configuración de abajo." + +#: msgctxt "#33620" msgid "Plex requests timeout (seconds)" msgstr "Tiempo de espera de las solicitudes de Plex (segundos)" +#: msgctxt "#33621" msgid "Set the (async and connection) timeout value of the Python requests library in seconds. Default: 5" msgstr "Establece el valor del tiempo de espera (asíncrono y de conexión) de la biblioteca de peticiones de Python en segundos. Predeterminado: 5" +#: msgctxt "#33622" msgid "LAN reachability timeout (ms)" -msgstr "Tiempo de espera de alcanzabilidad de LAN (ms)" +msgstr "Tiempo de espera de accesibilidad LAN (ms)" +#: msgctxt "#33623" msgid "When checking for LAN reachability, use this timeout. Default: 10ms" msgstr "Cuando compruebe la accesibilidad de la LAN, utilice este tiempo de espera. Por defecto: 10ms" +#: msgctxt "#33624" msgid "Network" msgstr "Red" +#: msgctxt "#33625" msgid "Smart LAN/local server discovery" msgstr "Detección inteligente de LAN/servidores locales" +#: msgctxt "#33626" -msgid "Checks whether servers returned from Plex.tv are actually local/in your LAN. For specific setups (e.g. Docker) Plex.tv might not properly detect a local server.\n\nNOTE: Only works on Kodi 19 or above." -msgstr "Comprueba si los servidores devueltos por Plex.tv son realmente locales en su LAN. Para configuraciones específicas (por ejemplo, Docker) Plex.tv podría no detectar correctamente un servidor local.\n\nNOTA: Sólo funciona en Kodi 19 o superior." - +msgid "Checks whether servers returned from Plex.tv are actually local/in your LAN. For specific setups (e.g. Docker) Plex.tv might not properly detect a local server.\n" +"\n" +"NOTE: Only works on Kodi 19 or above." +msgstr "Comprueba si los servidores devueltos por Plex.tv son realmente locales/ en su LAN. Para configuraciones específicas (por ejemplo, Docker) Plex.tv podría no detectar correctamente un servidor local.\n" +"\n" +"NOTA: Sólo funciona en Kodi 19 o superior." + +#: msgctxt "#33627" msgid "Prefer LAN/local servers over security" msgstr "Preferir los servidores LAN/locales a la seguridad" +#: msgctxt "#33628" msgid "Prioritizes local connections over secure ones. Needs the proper setting in \"Allow Insecure Connections\" and the Plex Server's \"Secure connections\" at \"Preferred\". Can be used to enforce manual servers." msgstr "Prioriza las conexiones locales sobre las seguras. Necesita la configuración adecuada en \"Permitir conexiones inseguras\" y las \"Conexiones seguras\" del servidor Plex en \"Preferidas\". Puede utilizarse para reforzar servidores manuales." +#: msgctxt "#33629" msgid "Auto-skip intro/credits offset" -msgstr "Desplazamiento automático de introducción/créditos" +msgstr "Intervalo de salto automático de introducción/créditos" +#: msgctxt "#33630" msgid "Intro/credits markers might be a little early in Plex. When auto skipping add (or subtract) this many seconds from the marker. This avoids cutting off content, while possibly skipping the marker a little late." msgstr "Los marcadores de introducción/créditos pueden ser un poco tempranos en Plex. Al saltar automáticamente, añada (o reste) esta cantidad de segundos al marcador. Esto evita cortar el contenido, mientras que posiblemente salta el marcador un poco tarde." +#: msgctxt "#32631" msgid "Playback (user-specific)" msgstr "Reproducción (específica del usuario)" +#: msgctxt "#33632" msgid "Server connectivity check timeout (seconds)" msgstr "Tiempo de espera de comprobación de conectividad del servidor (segundos)" +#: msgctxt "#33633" msgid "Set the maximum amount of time a server connection has to answer a connectivity request. Default: 2.5" msgstr "Establece la cantidad máxima de tiempo que una conexión de servidor tiene para responder a una solicitud de conectividad. Predeterminado: 2,5" +#: msgctxt "#33634" msgid "Combined Chapters" msgstr "Capítulos combinados" +#: msgctxt "#33635" msgid "Final Credits" msgstr "Créditos finales" +#: msgctxt "#32700" msgid "Action on Sleep event" msgstr "Acción sobre el evento de suspensión" +#: msgctxt "#32701" msgid "When Kodi receives a sleep event from the system, run the following action." msgstr "Cuando Kodi reciba un evento de suspensión del sistema, ejecuta la siguiente acción." +#: msgctxt "#32702" msgid "Nothing" msgstr "Nada" +#: msgctxt "#32703" msgid "Stop playback" msgstr "Detener la reproducción" +#: msgctxt "#32704" msgid "Quit Kodi" msgstr "Salir de Kodi" +#: msgctxt "#32705" msgid "CEC Standby" msgstr "CEC En espera" +#: msgctxt "#32800" msgid "Skipping intro" msgstr "Saltar introducción" +#: msgctxt "#32801" msgid "Skipping credits" msgstr "Saltar créditos" +#: msgctxt "#32900" msgid "While playing back an item and seeking on the seekbar, automatically seek to the selected position after a delay instead of having to confirm the selection." msgstr "Mientras se reproduce un elemento y se busca en la barra de búsqueda, se busca automáticamente la posición seleccionada tras un retardo en lugar de tener que confirmar la selección." +#: msgctxt "#32901" msgid "Seek delay in seconds." msgstr "Retraso de búsqueda en segundos." +#: msgctxt "#32902" msgid "Kodi has its own skip step settings. Try to use them if they're configured instead of the default ones." msgstr "Kodi tiene sus propios ajustes para saltar pasos. Intenta usarlos si están configurados en lugar de los predeterminados." +#: msgctxt "#32903" msgid "Use the above for seeking on the timeline as well." msgstr "Utilice lo anterior también para buscar en la línea de tiempo." +#: msgctxt "#32904" msgid "In seconds." msgstr "En segundos." +#: msgctxt "#32905" msgid "Cancel post-play timer by pressing OK/SELECT" msgstr "Cancelar el temporizador post-play pulsando OK/SELECCIONAR" +#: msgctxt "#32906" msgid "Cancel skip marker timer with BACK" msgstr "Cancelar el temporizador de salto de marcador con VOLVER" +#: msgctxt "#32907" msgid "When auto-skipping a marker, allow cancelling the timer by pressing BACK." msgstr "Cuando se salta automáticamente un marcador, permite cancelar el temporizador pulsando VOLVER." +#: msgctxt "#32908" msgid "Immediately skip marker with OK/SELECT" msgstr "Saltar inmediatamente el marcador con OK/SELECCIONAR" +#: msgctxt "#32909" msgid "When auto-skipping a marker with a timer, allow skipping immediately by pressing OK/SELECT." msgstr "Cuando se omita automáticamente un marcador con temporizador, permita la omisión inmediatamente pulsando OK/SELECCIONAR." +#: msgctxt "#32912" msgid "Show buffer-state on timeline" -msgstr "Mostrar el estado de la memoria intermedia en la línea de tiempo" +msgstr "Mostrar el estado del Buffer en la línea de tiempo" +#: msgctxt "#32913" msgid "Shows the current Kodi buffer/cache state on the video player timeline." msgstr "Muestra el estado actual del búfer/caché de Kodi en la línea de tiempo del reproductor de vídeo." +#: msgctxt "#32914" msgid "Loading" msgstr "Cargando" +#: msgctxt "#32915" msgid "Slow connection" msgstr "Conexión lenta" +#: msgctxt "#32916" msgid "Use with a wonky/slow connection, e.g. in a hotel room. Adjusts the UI to visually wait for item refreshes and waits for the buffer to fill when starting playback. Automatically sets readfactor=20, requires Kodi restart." msgstr "Utilícelo con una conexión lenta o inestable, por ejemplo, en una habitación de hotel. Ajusta la interfaz de usuario para esperar visualmente a que se actualicen los elementos y espera a que se llene el búfer al iniciar la reproducción. Establece automáticamente readfactor=20, requiere reiniciar Kodi." +#: msgctxt "#32917" msgid "Couldn't fill buffer in time ({}s)" msgstr "No se ha podido llenar el buffer a tiempo ({}s)" +#: msgctxt "#32918" msgid "Buffer wait timeout (seconds)" msgstr "Tiempo de espera del búfer (segundos)" +#: msgctxt "#32919" msgid "When slow connection is enabled in the addon, wait this long for the buffer to fill. Default: 120 s" msgstr "Cuando la conexión lenta está activada en el addon, espera este tiempo a que se llene el búfer. Por defecto: 120 s" +#: msgctxt "#32920" msgid "Insufficient buffer wait (seconds)" msgstr "Espera de búfer insuficiente (segundos)" +#: msgctxt "#32921" msgid "When slow connection is enabled in the addon and the configured buffer isn't big enough for us to determine its fill state, wait this long when starting playback. Default: 10 s" msgstr "Cuando la conexión lenta está activada en el addon y el búfer configurado no es lo suficientemente grande como para que podamos determinar su estado de llenado, espere este tiempo al iniciar la reproducción. Predeterminado: 10 s" +#: msgctxt "#32922" msgid "Kodi Cache Readfactor" -msgstr "Factor de lectura de la caché de Kodi" +msgstr "Factor de lectura (Readfactor) de la caché de Kodi" +#: msgctxt "#32923" msgid "Sets the Kodi cache readfactor value. Default: {0}, recommended: {1}. With \"Slow connection\" enabled this will be set to {2}, as otherwise the cache doesn't fill fast/aggressively enough." -msgstr "Establece el valor del factor de lectura de la caché de Kodi. Por defecto: {0}, recomendado: {1}. Con \"Conexión lenta\" activada, este valor será {2}, ya que de lo contrario la caché no se llena lo suficientemente rápido/agresivamente." +msgstr "Establece el valor del factor de lectura (Readfactor) de la caché de Kodi. Por defecto: {0}, recomendado: {1}. Con \"Conexión lenta\" activada, este valor será {2}, ya que de lo contrario la caché no se llena lo suficientemente rápido/agresivamente." +#: msgctxt "#32924" msgid "Minimize" msgstr "Minimizar" +#: msgctxt "#32925" msgid "Playback Settings" msgstr "Ajustes de reproducción" +#: msgctxt "#32926" msgid "Wrong pin entered!" msgstr "¡Pin introducido erróneo!" +#: msgctxt "#32927" msgid "Use episode thumbnails in continue hub" msgstr "Utilizar miniaturas de episodios en el hub de continuación" +#: msgctxt "#32928" msgid "Instead of using media artwork, use thumbnails for episodes in the continue hub on the home screen if available." msgstr "En lugar de utilizar ilustraciones multimedia, utiliza miniaturas de los episodios en el hub de continuación de la pantalla de inicio, si está disponible." +#: msgctxt "#32929" msgid "Use legacy background fallback image" msgstr "Utilizar la imagen de fondo anterior" +#: msgctxt "#32930" msgid "Previous Subtitle" msgstr "Subtítulos anteriores" +#: msgctxt "#32931" msgid "Audio/Subtitles" msgstr "Audio/Subtítulos" +#: msgctxt "#32932" msgid "Show subtitle quick-actions button" msgstr "Botón de acciones rápidas para mostrar subtítulos" +#: msgctxt "#32933" msgid "Show FFWD/RWD buttons" msgstr "Mostrar botones FFWD/RWD" +#: msgctxt "#32934" msgid "Show repeat button" msgstr "Mostrar botón de repetición" +#: msgctxt "#32935" msgid "Show shuffle button" msgstr "Botón de reproducción aleatoria" +#: msgctxt "#32936" msgid "Show playlist button" msgstr "Botón Mostrar lista de reproducción" +#: msgctxt "#32937" msgid "Show prev/next button" msgstr "Mostrar botón anterior/siguiente" -msgctxt "#32938" -msgid "Only for Episodes" -msgstr "Sólo para episodios" - +#: msgctxt "#32939" msgid "Only applies to video player UI" msgstr "Sólo se aplica a la interfaz de usuario del reproductor de vídeo" +#: msgctxt "#32940" msgid "Player UI" msgstr "Interfaz del reproductor" +#: msgctxt "#32941" msgid "Forced subtitles fix" msgstr "Corrección de subtítulos forzados" +#: msgctxt "#32942" msgid "Other seasons" msgstr "Otras temporadas" +#: msgctxt "#32943" msgid "Crossfade dynamic background art" -msgstr "Arte de fondo dinámico con fundido cruzado" +msgstr "Arte de fondo dinámico con Crossfade" +#: msgctxt "#32944" msgid "Burn-in SSA subtitles (DirectStream)" msgstr "Subtítulos SSA quemados (DirectStream)" +#: msgctxt "#32945" msgid "When Direct Streaming instruct the Plex Server to burn in SSA/ASS subtitles (thus transcoding the video stream). If disabled it will not touch the video stream, but will convert the subtitle to unstyled text." -msgstr "Cuando se hace Direct Streaming, ordena al Servidor Plex que grabe los subtítulos SSA/ASS (transcodificando así el flujo de vídeo). Si se desactiva no tocará el flujo de vídeo, pero convertirá los subtítulos en texto sin estilo." +msgstr "Cuando se hace Direct Streaming, ordena al Servidor Plex que grabe los subtítulos SSA/ASS (transcodificando así la transmisión del video). Si se desactiva, no tocará la transmisión del video, pero convertirá los subtítulos en texto sin estilo." +#: msgctxt "#32946" msgid "Stop video playback on idle after" msgstr "Detener la reproducción de vídeo en reposo después de" +#: msgctxt "#32947" msgid "Stop video playback on screensaver" msgstr "Detener la reproducción de vídeo en el salvapantallas" +#: msgctxt "#32948" msgid "Allow auto-skip when transcoding" msgstr "Permitir el salto automático al transcodificar" +#: msgctxt "#32949" msgid "When transcoding/DirectStreaming, allow auto-skip functionality." msgstr "Al transcodificar/transmitir directamente, permita la función de salto automático." +#: msgctxt "#32950" msgid "Use extended title for subtitles" msgstr "Utilizar el título ampliado para los subtítulos" +#: msgctxt "#32951" msgid "When displaying subtitles use the extendedDisplayTitle Plex exposes." msgstr "Cuando muestre subtítulos utilice el título de pantalla extendida que Plex expone." -msgctxt "#32952" -msgid "Dialog flicker fix" -msgstr "Corrección del parpadeo de los diálogos" - +#: msgctxt "#32953" msgid "Reviews" msgstr "Reseñas" +#: msgctxt "#32954" -msgid "Needs Kodi restart. WARNING: This will overwrite advancedsettings.xml!\n\nTo customize other cache/network-related values, copy \"script.plexmod/pm4k_cache_template.xml\" to profile folder and edit it to your liking. (See About section for the file paths)" -msgstr "Necesita reiniciar Kodi. ADVERTENCIA: ¡Esto sobrescribirá advancedsettings.xml!\n\nPara personalizar otros valores relacionados con la caché/red, copia \"script.plexmod/pm4k_cache_template.xml\" a la carpeta profile y edítalo a tu gusto. (Consulta la sección Acerca de para ver las rutas de los archivos)" - +msgid "Needs Kodi restart. WARNING: This will overwrite advancedsettings.xml!\n" +"\n" +"To customize other cache/network-related values, copy \"script.plexmod/pm4k_cache_template.xml\" to profile folder and edit it to your liking. (See About section for the file paths)" +msgstr "Necesita reiniciar Kodi. ADVERTENCIA: ¡Esto sobrescribirá advancedsettings.xml!\n" +"\n" +"Para personalizar otros valores relacionados con la caché/red, copia \"script.plexmod/pm4k_cache_template.xml\" a la carpeta profile y edítalo a tu gusto. (Consulta la sección Acerca de para ver las rutas de los archivos)" + +#: msgctxt "#32955" msgid "Use Kodi keyboard for searching" msgstr "Usa el teclado de Kodi para buscar" +#: msgctxt "#32956" msgid "Poster resolution scaling %" msgstr "Escalado de la resolución del póster %" +#: msgctxt "#32957" msgid "In percent. Scales the resolution of all posters/thumbnails for better image quality. May impact PMS/PM4K performance, will increase the cache usage accordingly. Recommended: 200-300 % for for big screens if your hardware can handle it. Needs addon restart." msgstr "En porcentaje. Escala la resolución de todos los pósters/miniaturas para una mejor calidad de imagen. Puede afectar al rendimiento de PMS/PM4K, aumentará el uso de caché en consecuencia. Recomendado: 200-300 % para pantallas grandes si tu hardware puede soportarlo. Necesita reiniciar el addon." +#: msgctxt "#32958" msgid "Calculate OpenSubtitles.com hash" msgstr "Calcular el hash de OpenSubtitles.com" +#: msgctxt "#32959" msgid "When opening the subtitle download feature, automatically calculate the OpenSubtitles.com hash for the given file. Can improve search results, downloads 2*64 KB of the video file to calculate the hash." msgstr "Al abrir la función de descarga de subtítulos, calcula automáticamente el hash de OpenSubtitles.com para el archivo dado. Puede mejorar los resultados de búsqueda, descarga 2*64 KB del archivo de vídeo para calcular el hash." +#: msgctxt "#32960" msgid "Similar Artists" msgstr "Artistas similares" +#: msgctxt "#32961" msgid "Show hub bifurcation lines" msgstr "Mostrar líneas de bifurcación del buje" +#: msgctxt "#32962" msgid "Visually separate hubs horizontally using a thin line." msgstr "Separe visualmente los cubos horizontalmente mediante una línea fina." +#: msgctxt "#32963" msgid "Wait between videos (s)" -msgstr "Espera entre vídeos (s)" +msgstr "Espera entre videos (s)" +#: msgctxt "#32964" msgid "When playing back consecutive videos (e.g. TV shows), wait this long before starting the next one in the queue. Might fix compatibility issues with certain configurations." -msgstr "Al reproducir vídeos consecutivos (por ejemplo, programas de TV), espere este tiempo antes de iniciar el siguiente de la cola. Podría solucionar problemas de compatibilidad con determinadas configuraciones." +msgstr "Al reproducir videos consecutivos (por ejemplo, programas de TV), espere este tiempo antes de iniciar el siguiente de la cola. Podría solucionar problemas de compatibilidad con determinadas configuraciones." +#: msgctxt "#32965" msgid "Quit Kodi on exit by default" -msgstr "Salir de Kodi al salir por defecto" +msgstr "Cerrar Kodi al salir por defecto" +#: msgctxt "#32966" msgid "When exiting the addon, use \"Quit Kodi\" as default option. Can be dynamically switched using CONTEXT_MENU (often longpress SELECT)" msgstr "Al salir del addon, usa \"Salir de Kodi\" como opción por defecto. Se puede cambiar dinámicamente usando CONTEXT_MENU (a menudo pulsando prolongadamente SELECCIONAR)" +#: msgctxt "#32967" msgid "Kodi Colour Management" msgstr "Gestión del color en Kodi" +#: msgctxt "#32968" msgid "Kodi Resolution Settings" msgstr "Ajustes de resolución de Kodi" +#: msgctxt "#32969" msgid "Always request all library media items at once" -msgstr "Solicite siempre todos los materiales de la biblioteca a la vez" +msgstr "Solicite siempre todos los medios de la biblioteca a la vez" +#: msgctxt "#32970" msgid "Retrieve all media in library up front instead of fetching it in chunks as the user navigates through the library" msgstr "Recuperar todos los medios de la biblioteca por adelantado en lugar de hacerlo por partes a medida que el usuario navega por la biblioteca" +#: msgctxt "#32971" msgid "Library item-request chunk size" msgstr "Tamaño del fragmento de solicitud de ítem de biblioteca" +#: msgctxt "#32972" msgid "Request this amount of media items per chunk request in library view (+6-30 depending on view mode; less can be less straining for the UI at first, but puts more strain on the server)" msgstr "Solicita esta cantidad de elementos multimedia por petición de chunk en la vista de biblioteca (+6-30 dependiendo del modo de vista; menos puede ser menos estresante para la interfaz de usuario al principio, pero pone más tensión en el servidor)" +#: msgctxt "#32973" msgid "Episodes: Skip Post Play screen" msgstr "Episodios: Saltar pantalla de reproducción" +#: msgctxt "#32974" -msgid "When finishing an episode, don't show Post Play but go to the next one immediately.\nCan be disabled/enabled per TV show. Doesn't override enabled binge mode. Overrides the Post Play setting." -msgstr "Al terminar un episodio, no muestra Post Play sino que pasa al siguiente inmediatamente.\nPuede desactivarse/activarse por programa de TV. No anula el modo atracón activado. Anula la configuración de Post Play." +msgid "When finishing an episode, don't show Post Play but go to the next one immediately.\n" +"Can be disabled/enabled per TV show. Doesn't override enabled binge mode. Overrides the Post Play setting." +msgstr "Al terminar un episodio, no muestra Post Play sino que pasa al siguiente inmediatamente.\n" +"Puede desactivarse/activarse por programa de TV. No anula el modo maratón activado. Anula la configuración de Post Play." +#: msgctxt "#32975" msgid "Delete Season" msgstr "Borrar temporada" + +#: +msgctxt "#32976" +msgid "Adaptive" +msgstr "Adaptable" + +#: +msgctxt "#32977" +msgid "Allow VC1" +msgstr "Permitir VC1" + +#: +msgctxt "#32978" +msgid "Enable this if your hardware can handle VC1. Disable it to force transcoding." +msgstr "Activa esto si tu Hardware puede manejar VC1. Desactiva esto para forzar la transcodificación." + +#: +msgctxt "#32979" +msgid "Allows the server to only transcode streams of a video that need transcoding, while streaming the others unaltered. If disabled, force the server to transcode everything not direct playable." +msgstr "Permitir al servidor solo transcodificar la reproducción de video que necesita de transcodificación, mientras se reproduce el resto sin cambios. Si se deshabilita, fuerza al servidor a transcodificar todo lo que no sea directamente reproducible." + +#. Refrescar Usuarios o Recargar Usuarios +#: +msgctxt "#32980" +msgid "Refresh Users" +msgstr "Volver a cargar usuarios" + +#. In this sentence Workers should not be translated to Trabajadores in Spanish because there's no real translation for it in the programming context. +#: +msgctxt "#32981" +msgid "Background worker count" +msgstr "Recuento de Workers en segundo plano" + +#: +msgctxt "#32982" +msgid "Depending on how many cores your CPU has and how much it can handle, increasing this might improve certain situations. If you experience crashes or other annormalities, leave this at its default (3). Needs an addon restart." +msgstr "Según cuántos núcleos tenga tu procesador y cuánto pueda manejar, incrementar esto podría mejorar ciertas situaciones. Si experimentas cierres repentinos u otros errores, déjalo con su configuración por defecto (3). Necesita un reinicio del Addon." + +#: +msgctxt "#32983" +msgid "Player Theme" +msgstr "Tema del reproductor" + +#: +msgctxt "#32984" +msgid "Sets the player theme. Currently only customizes the playback control buttons. ATTENTION: [I]Might[/I] need an addon restart.\n" +"In order to customize this, copy one of the xml's in script.plexmod/resources/skins/Main/1080i/templates to addon_data/script.plexmod/templates/seek_dialog_buttons_custom.xml and adjust it to your liking, then select \"Custom\" as your theme." +msgstr "Configura el tema del reproductor. Por ahora solo modifica los botones de control del reproductor. Atención: [I]Podría[/I] necesitar un reinicio del Addon. Para personalizarlo, copia uno de los xml's en script.plexmod/resources/skins/Main/1080i/templates a addon_data/script.plexmod/templates/seek_dialog_buttons_custom.xml y ajústalo a tu gusto, luego selecciona \"Perzonalizado\" como tema." + +#: +msgctxt "#32985" +msgid "Modern" +msgstr "Moderno" + +#: +msgctxt "#32986" +msgid "Modern (dotted)" +msgstr "Moderno (puntos)" + +#: +msgctxt "#32987" +msgid "Classic" +msgstr "Clásico" + +#: +msgctxt "#32988" +msgid "Custom" +msgstr "Perzonalizado" + +#: +msgctxt "#32989" +msgid "Modern (colored)" +msgstr "Moderno (coloreado)" + +#: +msgctxt "#32990" +msgid "Handle plex.direct mapping" +msgstr "Manejar el mapeo de plex.direct" + +#: +msgctxt "#32991" +msgid "Notify" +msgstr "Notificar" + +#. Haven't heard about an actual translation for "Rebind" in Spanish. These techie words are usually not translated in Spanish. +#: +msgctxt "#32992" +msgid "When using servers with a plex.direct connection (most of them), should we automatically adjust advancedsettings.xml to cope with plex.direct domains? If not, you might want to add plex.direct to your router's DNS rebind exemption list." +msgstr "Cuando se utilicen servidores con una conexión a plex.direct (la mayoría), ¿deberíamos ajustar advancedsettings.xml para lidiar con los dominios de plex.direct? Si no, podrías necesitar añadir plex.direct a la lista de excepción de DNS Rebind de tu router." + +#: +msgctxt "#32993" +msgid "{} unhandled plex.direct connections found" +msgstr "{} conexiones a plex.direct sin manejar encontradas" + +#: +msgctxt "#32994" +msgid "In order for PM4K to work properly, we need to add special handling for plex.direct connections. We've found {} new unhandled connections. Do you want us to write those to Kodi's advancedsettings.xml automatically? If not, you might want to add plex.direct to your router's DNS rebind exemption list. This can be changed in the settings as well." +msgstr "Para que PM4K funcione correctamente, necesitamos añadir un manejo especial para las conexiones a plex.direct. Se han encontrado {} nuevas conexiones sin manejar. ¿Quieres que las coloquemos en el archivo advancedsettings.xml de Kodi automáticamente? Si no, podrías necesitar añadir plex.direct a la lista de excepción de DNS Rebind de tu router. Esto también puede ser cambiado en los ajustes." + +#: +msgctxt "#32995" +msgid "Advancedsettings.xml modified (plex.direct mappings)" +msgstr "Advancedsettings.xml modificado (mapeos de plex.direct)" + +#: +msgctxt "#32996" +msgid "The advancedsettings.xml file has been modified. Please restart Kodi for the changes to apply." +msgstr "El archivo advancedsettings.xml ha sido modificado. Por favor renicia Kodi para que los cambios sean aplicados." + +#: +msgctxt "#32997" +msgid "OK" +msgstr "OK" + +#. Apartado was the best interpretation for Hub that I could think of +#: +msgctxt "#32998" +msgid "Use new Continue Watching hub on Home" +msgstr "Utilizar el nuevo apartado de Continuar Viendo en Inicio" + +#. Cartelera was the best interpretation for On Deck that I could think of +#: +msgctxt "#32999" +msgid "Instead of separating Continue Watching and On Deck hubs, behave like the modern Plex clients, which combine those two types of hubs into one Continue Watching hub." +msgstr "En lugar de separar los apartados de Continuar Viendo y Cartelera, comportarse como los clientes modernos de Plex, los cuales combinan estos dos apartados en uno solo de Continuar Viendo." + +#: +msgctxt "#33000" +msgid "Enable path mapping" +msgstr "Activar mapeo de rutas" + +#: +msgctxt "#33001" +msgid "Honor path_mapping.json in the addon_data/script.plexmod folder when DirectPlaying media. This can be used to stream using other techniques such as SMB/NFS/etc. instead of the default HTTP handler. path_mapping.example.json is included in the addon's main directory." +msgstr "Dar preferencia al archivo path_mapping.json en la carpeta addon_data/scrip.plexmod cuando haya una Reproducción Directa de medios (DirectPlay). Esto se puede usar para transmitir utilizando otras técnicas como SMB/NFS/etc. En lugar del manejo con HTTP por defecto. El archivo path_mapping.example.json se incluye en el directorio principal del Addon." + +#: +msgctxt "#33002" +msgid "Verify mapped files exist" +msgstr "Verificar que los archivos mapeados existan" + +#: +msgctxt "#33003" +msgid "When path mapping is enabled and we've successfully mapped a file, verify its existence." +msgstr "Cuando el Mapeo de Rutas está activo y se ha mapeado un archivo con éxito, verificar su existencia." + +#: +msgctxt "#33004" +msgid "No spoilers without OSD" +msgstr "No Spoilers sin el OSD" + +#: +msgctxt "#33005" +msgid "When seeking without the OSD open, hide all time-related information from the user." +msgstr "Cuando se adelanta o retrocede la reproducción sin el OSD abierto, oculta toda la información relacionada con el tiempo de reproducción al usuario." + +#: +msgctxt "#33006" +msgid "No TV spoilers" +msgstr "Sin Spoilers de TV" + +#: +msgctxt "#33007" +msgid "When visiting an episode/season view, blur unwatched/unwatched+in-progress episode thumbnails, previews and redact summaries. When the Addon Setting \"Use episode thumbnails in continue hub\" is enabled, blur them as well." +msgstr "Cuando se visita la vista de episodio/temporada, desenfocar las miniaturas de episodio de No vistos/No vistos+En progreso, vista previa, y redactar resúmenes. Cuando la opción del Addon \"Utilizar miniaturas de episodio en el apartado de Continuar\" está habilitada, desenfocarlas también." + +#: +msgctxt "#33008" +msgid "[Spoilers removed]" +msgstr "[Spoilers removidos]" + +#: +msgctxt "#33009" +msgid "Blur amount for unwatched/in-progress episodes" +msgstr "Cantidad de desenfoque para episodios No vistos/En progreso" + +#: +msgctxt "#33010" +msgid "Unwatched" +msgstr "No vistos" + +#: +msgctxt "#33011" +msgid "Unwatched/in progress" +msgstr "No vistos/En progreso" + +#: +msgctxt "#33012" +msgid "No unwatched episode titles" +msgstr "Títulos de Episodios no vistos" + +#: +msgctxt "#33013" +msgid "When the above is anything but \"off\", hide episode titles as well." +msgstr "Cuando lo de arriba es cualquier cosa menos \"Apagado\", ocultar los títulos de episodios también." + +#: +msgctxt "#33014" +msgid "Ignore plex.direct docker hosts" +msgstr "Ignorar los Hosts plex.direct de docker" + +#: +msgctxt "#33015" +msgid "When checking for plex.direct host mapping, ignore local Docker IPv4 addresses (172.16.0.0/12)." +msgstr "Cuando se verifica el mapeo de Host de plex.direct, ignorar las direcciones locales IPv4 de Docker (172.16.0.0/12)." + +#: +msgctxt "#33016" +msgid "Allow TV spoilers for specific genres" +msgstr "Permitir Spoilers de TV para géneros específicos" + +#: +msgctxt "#33017" +msgid "Overrides the above for: {}" +msgstr "Cambiar lo de arriba por: {}" + +#: +msgctxt "#32303" +msgid "Season {}" +msgstr "Temporada {}" + +#: +msgctxt "#32304" +msgid "Episode {}" +msgstr "Episodio {}" + +#: +msgctxt "#32310" +msgid "S{}" +msgstr "S{}" + +#: +msgctxt "#32311" +msgid "E{}" +msgstr "E{}" + +#: +msgctxt "#32938" +msgid "Only for Episodes/Playlists" +msgstr "Solo para Episodios/Listas de reproducción" + +#: +msgctxt "#33018" +msgid "Cache Plex Home users" +msgstr "Guardar en Caché los usuarios de Plex Home" + +#: +msgctxt "#33019" +msgid "Visit media item" +msgstr "Visitar un archivo de medio" + +#: +msgctxt "#33020" +msgid "Play" +msgstr "Reproducir" + +#: +msgctxt "#33021" +msgid "Choose action" +msgstr "Elegir acción" + +#: +msgctxt "#33022" +msgid "Use modern inverted watched states" +msgstr "Utilice estados observados invertidos modernos" + +#: +msgctxt "#33023" +msgid "Instead of marking unwatched items, mark watched items with a checkmark (modern clients; default: off)" +msgstr "En lugar de marcar los elementos no vistos, marcar los elementos vistos con una marca de verificación (clientes modernos; por defecto: desactivado)" + +#: +msgctxt "#33024" +msgid "Hide black backdrop in inverted watched states" +msgstr "Ocultar fondo negro en estados de vigilancia invertidos" + +#: +msgctxt "#33025" +msgid "When the above is enabled, hide the black backdrop of the watched state." +msgstr "Cuando se activa lo anterior, oculta el fondo negro del estado vigilado." + +#: +msgctxt "#33026" +msgid "Map path: {}" +msgstr "Asignación de rutas: {}" + +#: +msgctxt "#33027" +msgid "Remove mapping: {}" +msgstr "Quitar mapeo: {}" + +#: +msgctxt "#33028" +msgid "Hide library" +msgstr "Ocultar biblioteca" + +#: +msgctxt "#33029" +msgid "Show library: {}" +msgstr "Mostrar biblioteca: {}" + +#: +msgctxt "#33030" +msgid "Choose action for: {}" +msgstr "Elegir acción para: {}" + +#: +msgctxt "#33031" +msgid "Select Kodi source for {}" +msgstr "Seleccione la fuente Kodi para {}" + +#: +msgctxt "#33032" +msgid "Show path mapping indicators" +msgstr "Mostrar indicadores de asignación de rutas" + +#: +msgctxt "#33033" +msgid "When path mapping is active for a library, display an indicator." +msgstr "Cuando la asignación de rutas está activa para una biblioteca, muestra un indicador." + +#: +msgctxt "#33034" +msgid "Library settings" +msgstr "Configuración de la biblioteca" + + +#: +msgctxt "#33035" +msgid "Delete {}: {}?" +msgstr "Borrar {}: {}?" + +#: +msgctxt "#33036" +msgid "Delete episode S{0:02d}E{1:02d} from {2}?" +msgstr "¿Borrar episodio S{0:02d}E{1:02d} de {2}?" + +#: +msgctxt "#33037" +msgid "Maximum intro offset to consider" +msgstr "Desplazamiento de introducción máximo a considerar" + +#: +msgctxt "#33038" +msgid "When encountering an intro marker with a start time offset greater than this, ignore it (default: 600s/10m)" +msgstr "Cuando encuentre un marcador de introducción con un desfase de tiempo de inicio superior a este valor, ignórelo (por defecto: 600s/10m)" + +#: +msgctxt "#33039" +msgid "Move" +msgstr "Mover" + +#: +msgctxt "#33040" +msgid "Reset library order" +msgstr "Restablecer el orden de la biblioteca" diff --git a/script.plexmod/resources/language/resource.language.it_it/strings.po b/script.plexmod/resources/language/resource.language.it_it/strings.po index 50dee38bc..ddab8dc09 100644 --- a/script.plexmod/resources/language/resource.language.it_it/strings.po +++ b/script.plexmod/resources/language/resource.language.it_it/strings.po @@ -1,951 +1,2358 @@ -# XBMC Media Center language file msgid "" msgstr "" -"Project-Id-Version: XBMC-Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" -"POT-Creation-Date: 2013-12-12 22:56+0000\n" -"PO-Revision-Date: 2017-05-25 10:52+0200\n" -"Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"X-Generator: POEditor.com\n" +"Project-Id-Version: PM4K / PlexMod for Kodi\n" "Language: it\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Last-Translator: \n" -"X-Generator: Poedit 2.0.2\n" +#: msgctxt "#32000" msgid "Main" msgstr "Principale" +#: msgctxt "#32001" msgid "Original" msgstr "Originale" +#: msgctxt "#32002" msgid "20 Mbps 1080p" msgstr "20 Mbps 1080p" +#: msgctxt "#32003" msgid "12 Mbps 1080p" msgstr "12 Mbps 1080p" +#: msgctxt "#32004" msgid "10 Mbps 1080p" msgstr "10 Mbps 1080p" +#: msgctxt "#32005" msgid "8 Mbps 1080p" msgstr "8 Mbps 1080p" +#: msgctxt "#32006" msgid "4 Mbps 720p" msgstr "4 Mbps 720p" +#: msgctxt "#32007" msgid "3 Mbps 720p" msgstr "3 Mbps 720p" +#: msgctxt "#32008" msgid "2 Mbps 720p" msgstr "2 Mbps 720p" +#: msgctxt "#32009" msgid "1.5 Mbps 480p" msgstr "1.5 Mbps 480p" +#: msgctxt "#32010" msgid "720 kbps" msgstr "720 kbps" +#: msgctxt "#32011" msgid "320 kbps" msgstr "320 kbps" +#: msgctxt "#32012" msgid "208 kbps" msgstr "208 kbps" +#: msgctxt "#32013" msgid "96 kbps" msgstr "96 kbps" +#: msgctxt "#32014" msgid "64 kbps" msgstr "64 kbps" +#: msgctxt "#32020" msgid "Local Quality" msgstr "Qualità Locale" +#: msgctxt "#32021" msgid "Remote Quality" msgstr "Qualità Remota" +#: msgctxt "#32022" msgid "Online Quality" msgstr "Qualità Online" +#: msgctxt "#32023" msgid "Transcode Format" msgstr "Formato transcodifica" +#: msgctxt "#32024" msgid "Debug Logging" msgstr "Log di Debug" +#: msgctxt "#32025" msgid "Allow Direct Play" msgstr "Permetti Play Diretto" +#: msgctxt "#32026" msgid "Allow Direct Stream" msgstr "Permetti Stream Diretto" +#: msgctxt "#32027" msgid "Force" msgstr "Forza" +#: msgctxt "#32028" msgid "Always" msgstr "Sempre" +#: msgctxt "#32029" msgid "Only Image Formats" msgstr "Solo formati immagine" +#: msgctxt "#32030" msgid "Auto" msgstr "Auto" -msgctxt "#32031" -msgid "Burn Subtitles (Direct Play Only)" -msgstr "Sottotitoli (Solo Play Diretto)" - +#: msgctxt "#32032" msgid "Allow Insecure Connections" msgstr "Permetti connessioni non sicure" +#: msgctxt "#32033" msgid "Never" msgstr "Mai" +#: msgctxt "#32034" msgid "On Same network" msgstr "Sulla stessa rete" +#: msgctxt "#32035" msgid "Always" msgstr "Sempre" +#: msgctxt "#32036" msgid "Allow 4K" msgstr "Permetti 4K" +#: msgctxt "#32037" msgid "Allow HEVC (h265)" msgstr "Permetti HEVC (h265)" +#: msgctxt "#32038" msgid "Automatically Sign In" msgstr "Accesso (Sign In) automatico" +#: msgctxt "#32039" msgid "Post Play Auto Play" msgstr "Post Play Auto Play" +#: msgctxt "#32040" msgid "Enable Subtitle Downloading" msgstr "Abilita il download dei sottotitoli" +#: msgctxt "#32041" msgid "Enable Subtitle Downloading" msgstr "Abilita il download dei sottotitoli" +#: msgctxt "#32042" msgid "Server Discovery (GDM)" msgstr "Ricerca Server (GDM)" +#: msgctxt "#32043" msgid "Start Plex On Kodi Startup" msgstr "Esegui Plex all'avvio di Kodi" +#: msgctxt "#32044" msgid "Connection 1 IP" msgstr "IP connessione 1" +#: msgctxt "#32045" msgid "Connection 1 Port" msgstr "Porta connessione 1" +#: msgctxt "#32046" msgid "Connection 2 IP" msgstr "IP connessione 2" +#: msgctxt "#32047" msgid "Connection 2 Port" msgstr "Porta connessione 2" +#: msgctxt "#32048" msgid "Audio" msgstr "Audio" +#: msgctxt "#32049" msgid "Advanced" msgstr "Avanzate" +#: msgctxt "#32050" msgid "Manual Servers" msgstr "Server manuali" +#: msgctxt "#32051" msgid "Privacy" msgstr "Privacy" +#: msgctxt "#32052" msgid "About" -msgstr "Circa" +msgstr "Informazioni" +#: msgctxt "#32053" msgid "Video" msgstr "Video" +#: msgctxt "#32054" msgid "Addon Version" msgstr "Versione Addon" +#: msgctxt "#32055" msgid "Kodi Version" msgstr "Versione Kodi" +#: msgctxt "#32056" msgid "Screen Resolution" msgstr "Risoluzione schermo" +#: msgctxt "#32057" msgid "Current Server Version" msgstr "Versione Server attuale" +#: +msgctxt "#32058" +msgid "Never exceed original audio codec" +msgstr "Non superare il codec audio originale" + +#: +msgctxt "#32059" +msgid "When transcoding audio, never exceed the original audio bitrate or channel count on the same codec." +msgstr "Durante la transcodifica dell'audio, non superare mai il bitrate audio originale o il numero di canali sullo stesso codec." + +#: +msgctxt "#32060" +msgid "Use Kodi audio channels" +msgstr "Utilizza i canali audio Kodi" + +#: +msgctxt "#32064" +msgid "Treat DTS like AC3" +msgstr "Tratta DTS come AC3" + +#: msgctxt "#32100" msgid "Skip user selection and pin entry on startup." msgstr "All'avvio salta l'immissione del PIN e la selezione utente." +#: msgctxt "#32101" msgid "If enabled, when playback ends and there is a 'Next Up' item available, it will be automatically be played after a 15 second delay." msgstr "Se abilitato, quando la riproduzione finisce e un 'Titolo Successivo' è disponibile, sarà automaticamente riprodotto dopo un ritardo di 15 secondi." +#: msgctxt "#32102" msgid "Enable this if your hardware can handle 4K playback. Disable it to force transcoding." msgstr "Abilita se il tuo hardware supporta la riproduzione 4K. Disabilita per forzare la trascodifica." +#: msgctxt "#32103" msgid "Enable this if your hardware can handle HEVC/h265. Disable it to force transcoding." msgstr "Abilita se il tuo hardware supporta HEVC/h265. Disabilita per forzare la trascodifica." +#: msgctxt "#32104" msgid "When to connect to servers with no secure connections.[CR][CR]* [B]Never[/B]: Never connect to a server insecurely[CR]* [B]On Same Network[/B]: Allow if on the same network[CR]* [B]Always[/B]: Allow same network and remote connections" msgstr "Quando connettersi a Server con connessioni non sicure.[CR][CR]* [B]Mai[/B]: Mai connettersi a Server non sicuri[CR]* [B]Sulla stessa Rete[/B]: Permetti se nella stessa Rete[CR]* [B]Sempre[/B]: Permetti sulla stessa Rete e su Reti remote" +#: msgctxt "#32201" msgid "Trailer" msgstr "Trailer" +#: msgctxt "#32202" msgid "Deleted Scene" msgstr "Scene cancellate" +#: msgctxt "#32203" msgid "Interview" msgstr "Intervista" +#: msgctxt "#32204" msgid "Music Video" msgstr "Video musicali" +#: msgctxt "#32205" msgid "Behind the Scenes" msgstr "Dietro le scene" +#: msgctxt "#32206" msgid "Scene" msgstr "Scena" +#: msgctxt "#32207" msgid "Live Music Video" msgstr "Video musicali dal vivo" +#: msgctxt "#32208" msgid "Lyric Music Video" msgstr "Testi video musicali" +#: msgctxt "#32209" msgid "Concert" msgstr "Concerto" +#: msgctxt "#32210" msgid "Featurette" msgstr "Featurette" +#: msgctxt "#32211" msgid "Short" msgstr "Corto" +#: msgctxt "#32212" msgid "Other" msgstr "Altro" +#: msgctxt "#32300" msgid "Go to Album" msgstr "Vai all'Album" +#: msgctxt "#32301" msgid "Go to Artist" msgstr "Vai all'Artista" +#: msgctxt "#32302" msgid "Go to {0}" msgstr "Vai a {0}" -msgctxt "#32303" -msgid "Season" -msgstr "Stagione" - -msgctxt "#32304" -msgid "Episode" -msgstr "Episodio" - +#: msgctxt "#32305" msgid "Extras" msgstr "Extras" +#: msgctxt "#32306" msgid "Related Shows" msgstr "Serie correlate" +#: msgctxt "#32307" msgid "More" msgstr "Più" +#: msgctxt "#32308" msgid "Available" msgstr "Disponibile" +#: msgctxt "#32309" msgid "None" msgstr "Nessuno" -msgctxt "#32310" -msgid "S" -msgstr "S" - -msgctxt "#32311" -msgid "E" -msgstr "E" - +#: msgctxt "#32312" msgid "Unavailable" msgstr "Non disponibile" +#: msgctxt "#32313" msgid "This item is currently unavailable." msgstr "Questo elemento non è al momento diponibile" +#: msgctxt "#32314" msgid "In Progress" msgstr "In Corso" +#: msgctxt "#32315" msgid "Resume playback?" msgstr "Riprendere la riproduzione?" +#: msgctxt "#32316" msgid "Resume" msgstr "Riprendi" +#: msgctxt "#32317" msgid "Play from beginning" msgstr "Riproduci dall'inizio" +#: msgctxt "#32318" msgid "Mark Unplayed" msgstr "Marca come non visto" +#: msgctxt "#32319" msgid "Mark Played" msgstr "Marca come visto" +#: msgctxt "#32320" msgid "Mark Season Unplayed" msgstr "Marca la Stagione come non vista" +#: msgctxt "#32321" msgid "Mark Season Played" msgstr "Marca la Stagione come vista" +#: msgctxt "#32322" msgid "Delete" msgstr "Cancellato" +#: msgctxt "#32323" msgid "Go To Show" msgstr "Vai alla Serie" +#: msgctxt "#32324" msgid "Go To {0}" msgstr "Vai a {0}" +#: msgctxt "#32325" msgid "Play Next" msgstr "Riproduci il titolo succesivo" +#: msgctxt "#32326" msgid "Really Delete?" msgstr "Cancellare veramente?" +#: msgctxt "#32327" msgid "Are you sure you really want to delete this media?" msgstr "Sei sucuro che vuoi davvero cancellare questo media?" +#: msgctxt "#32328" msgid "Yes" msgstr "Sì" +#: msgctxt "#32329" msgid "No" msgstr "No" +#: msgctxt "#32330" msgid "Message" msgstr "Messaggio" +#: msgctxt "#32331" msgid "There was a problem while attempting to delete the media." msgstr "C'è stato un problema nella cancellazione del media." +#: msgctxt "#32332" msgid "Home" msgstr "Home" +#: msgctxt "#32333" msgid "Playlists" msgstr "Playlists" +#: msgctxt "#32334" msgid "Confirm Exit" msgstr "Conferma Uscita" +#: msgctxt "#32335" msgid "Are you ready to exit Plex?" msgstr "Sei pronto per uscire da Plex?" +#: msgctxt "#32336" msgid "Exit" msgstr "Esci" +#: msgctxt "#32337" msgid "Cancel" msgstr "Cancella" +#: msgctxt "#32338" msgid "No Servers Found" msgstr "Nessun Server trovato" +#: msgctxt "#32339" msgid "Server is not accessible" msgstr "Server non accessibile" +#: msgctxt "#32340" msgid "Connection tests are in progress. Please wait." msgstr "Test di connessione in corso. Per favore attenti." +#: msgctxt "#32341" msgid "Server is not accessible. Please sign into your server and check your connection." msgstr "Server non accessibile. Per favore fai il sign in nel Server a controlla la connessione." +#: msgctxt "#32342" msgid "Switch User" msgstr "Cambia utente" +#: msgctxt "#32343" msgid "Settings" msgstr "Impostazioni" +#: msgctxt "#32344" msgid "Sign Out" msgstr "Esci (Sign Out)" +#: msgctxt "#32345" msgid "All" msgstr "Tutto" +#: msgctxt "#32346" msgid "By Name" msgstr "Per Nome" +#: msgctxt "#32347" msgid "Artists" msgstr "Artisti" +#: msgctxt "#32348" -msgid "movies" -msgstr "film" +msgid "Movies" +msgstr "Film" +#: msgctxt "#32349" msgid "photos" msgstr "foto" +#: msgctxt "#32350" msgid "Shows" msgstr "Serie" +#: msgctxt "#32351" msgid "By Date Added" msgstr "Per data di aggiunta" +#: msgctxt "#32352" msgid "Date Added" msgstr "Data di aggiunta" +#: msgctxt "#32353" msgid "By Release Date" msgstr "Per data di uscita" +#: msgctxt "#32354" msgid "Release Date" msgstr "Data di uscita" +#: msgctxt "#32355" msgid "By Date Viewed" msgstr "Per data di già visto" +#: msgctxt "#32356" msgid "Date Viewed" msgstr "Data di già visto" +#: msgctxt "#32357" msgid "By Name" msgstr "Per nome" +#: msgctxt "#32358" msgid "Name" msgstr "Nome" +#: msgctxt "#32359" msgid "By Rating" msgstr "Per Valutazione" +#: msgctxt "#32360" msgid "Rating" msgstr "Valutazione" +#: msgctxt "#32361" msgid "By Resolution" msgstr "Per Risoluzione" +#: msgctxt "#32362" msgid "Resolution" msgstr "Risoluzione" +#: msgctxt "#32363" msgid "By Duration" msgstr "Per Durata" +#: msgctxt "#32364" msgid "Duration" msgstr "Durata" +#: msgctxt "#32365" msgid "By First Aired" msgstr "Per prima trasmissione" +#: msgctxt "#32366" msgid "First Aired" msgstr "Prima trasmissione" +#: msgctxt "#32367" msgid "By Unplayed" msgstr "Per Non visto" +#: msgctxt "#32368" msgid "Unplayed" msgstr "Non visto" +#: msgctxt "#32369" msgid "By Date Played" msgstr "Per data di riproduzione" +#: msgctxt "#32370" msgid "Date Played" msgstr "Data di riproduzione" +#: msgctxt "#32371" msgid "By Play Count" msgstr "Per numero di volte riprodotto" +#: msgctxt "#32372" msgid "Play Count" msgstr "Numero di volte riprodotto" +#: msgctxt "#32373" msgid "By Date Taken" msgstr "Per data di ripresa" +#: msgctxt "#32374" msgid "Date Taken" msgstr "Data di ripresa" +#: msgctxt "#32375" msgid "No filters available" msgstr "Nussun filtro disponibile" +#: msgctxt "#32376" msgid "Clear Filter" msgstr "Pulisci i filtri" +#: msgctxt "#32377" msgid "Year" msgstr "Anno" +#: msgctxt "#32378" msgid "Decade" msgstr "Decennio" +#: msgctxt "#32379" msgid "Genre" msgstr "Genere" +#: msgctxt "#32380" msgid "Content Rating" msgstr "Classificazione dei contenuti" +#: msgctxt "#32381" msgid "Network" msgstr "Rete" +#: msgctxt "#32382" msgid "Collection" msgstr "Collezione" +#: msgctxt "#32383" msgid "Director" msgstr "Regista" +#: msgctxt "#32384" msgid "Actor" msgstr "Attore" +#: msgctxt "#32385" msgid "Country" msgstr "Nazione" +#: msgctxt "#32386" msgid "Studio" msgstr "Studio" +#: msgctxt "#32387" msgid "Labels" msgstr "Etichette" +#: msgctxt "#32388" msgid "Camera Make" msgstr "Marca camera" +#: msgctxt "#32389" msgid "Camera Model" msgstr "Modello camera" +#: msgctxt "#32390" msgid "Aperture" msgstr "Apertura" +#: msgctxt "#32391" msgid "Shutter Speed" msgstr "Velocità di scatto" +#: msgctxt "#32392" msgid "Lens" msgstr "Lenti" +#: msgctxt "#32393" msgid "TV Shows" msgstr "Serie televisive" +#: msgctxt "#32394" msgid "Music" msgstr "Musica" +#: msgctxt "#32395" msgid "Audio" msgstr "Audio" +#: msgctxt "#32396" msgid "Subtitles" msgstr "Sottotitoli" +#: msgctxt "#32397" msgid "Quality" msgstr "Qualità" +#: msgctxt "#32398" msgid "Kodi Video Settings" msgstr "Impostazioni Video di Kodi" +#: msgctxt "#32399" msgid "Kodi Audio Settings" msgstr "Impostazioni Audio di Kodi" +#: msgctxt "#32400" msgid "Go To Season" msgstr "Vai alla Stagione" +#: msgctxt "#32401" msgid "Directors" msgstr "Registi" +#: msgctxt "#32402" msgid "Writer" msgstr "Autore" +#: msgctxt "#32403" msgid "Writers" msgstr "Autori" +#: msgctxt "#32404" msgid "Related Movies" msgstr "Film correlati" +#: msgctxt "#32405" msgid "Download Subtitles" msgstr "Scarica Sottotitoli" +#: msgctxt "#32406" msgid "Subtitle Delay" msgstr "Ritardo Sottotitolo" +#: msgctxt "#32407" msgid "Next Subtitle" msgstr "Sottotitolo successivo" +#: msgctxt "#32408" msgid "Disable Subtitles" msgstr "Disabilita sottotitoli" +#: msgctxt "#32409" msgid "Enable Subtitles" msgstr "Abilita Sottotitoli" +#: msgctxt "#32410" msgid "Platform Version" msgstr "Versione piattaforma" +#: msgctxt "#32411" msgid "Unknown" msgstr "Sconosciuto" +#: msgctxt "#32412" msgid "Edit Or Clear" msgstr "Modifica o Cancella" +#: msgctxt "#32413" msgid "Edit IP address or clear the current setting?" msgstr "Modificare l'indirizzo IP o cancellare le impostazioni correnti?" +#: msgctxt "#32414" msgid "Clear" msgstr "Cancella" +#: msgctxt "#32415" msgid "Edit" msgstr "Modifica" +#: msgctxt "#32416" msgid "Enter IP Address" msgstr "Inserisci l'indirizzo IP" +#: msgctxt "#32417" msgid "Enter Port Number" msgstr "Inserisci il numero della Porta" +#: msgctxt "#32418" msgid "Creator" msgstr "Creatore" +#: msgctxt "#32419" msgid "Cast" msgstr "Cast" +#: msgctxt "#32420" msgid "Disc" msgstr "Disc" +#: msgctxt "#32421" msgid "Sign Out" msgstr "Esci (Sign Out)" +#: msgctxt "#32422" msgid "Exit" msgstr "Esci" +#: msgctxt "#32423" msgid "Shutdown" msgstr "Spegni" +#: msgctxt "#32424" msgid "Suspend" msgstr "Sospenti" +#: msgctxt "#32425" msgid "Hibernate" msgstr "Iberna" +#: msgctxt "#32426" msgid "Reboot" msgstr "Riavvia" +#: msgctxt "#32427" msgid "Failed" msgstr "Fallito" +#: msgctxt "#32428" msgid "Login failed!" msgstr "Login fallita!" +#: msgctxt "#32429" msgid "Resume from {0}" msgstr "Riprendi da {0}" +#: msgctxt "#32430" msgid "Discovery" msgstr "Ricerca" +#: msgctxt "#32431" msgid "Search" msgstr "Cerca" +#: msgctxt "#32432" msgid "Space" msgstr "Spazio" +#: msgctxt "#32433" msgid "Clear" msgstr "Pulisci" +#: msgctxt "#32434" msgid "Searching..." msgstr "In ricerca..." +#: msgctxt "#32435" msgid "No Results" msgstr "Nessun risultato" +#: msgctxt "#32436" msgid "Paused" msgstr "In Pausa" +#: msgctxt "#32437" msgid "Welcome" msgstr "Benvenuto" +#: msgctxt "#32438" msgid "Previous" msgstr "Precedente" +#: msgctxt "#32439" msgid "Playing Next" msgstr "Titolo successivo" +#: msgctxt "#32440" msgid "On Deck" msgstr "Scoprire" +#: msgctxt "#32441" msgid "Unknown" msgstr "Sconosciuto" +#: msgctxt "#32442" msgid "Embedded" msgstr "Integrato" +#: msgctxt "#32443" msgid "Forced" msgstr "Forzato" +#: msgctxt "#32444" msgid "Lyrics" msgstr "Testi" +#: msgctxt "#32445" msgid "Mono" msgstr "Mono" +#: msgctxt "#32446" msgid "Stereo" msgstr "Stereo" +#: msgctxt "#32447" msgid "None" msgstr "Nessuno" +#: msgctxt "#32448" msgid "Playback Failed!" msgstr "Riproduzione fallita!" +#: msgctxt "#32449" msgid "Can't connect to plex.tv[CR]Check your internet connection and try again." msgstr "Impossibile connettersi a plex.tv[CR]Controlla la tua connessione ad Internet e riprova." +#: msgctxt "#32450" msgid "Choose Version" msgstr "Seleziona Versione" +#: msgctxt "#32451" msgid "Play Version..." msgstr "Versione in Play..." +#: msgctxt "#32452" msgid "No Content available in this library" msgstr "Nessun contenuto disponibile in questa libreria" +#: msgctxt "#32453" msgid "Please add content and/or check that 'Include in dashboard' is enabled." msgstr "Per favore aggiungi contenuti e/o controlla che 'Includi nella dashboard' è abilitato." +#: msgctxt "#32454" msgid "No Content available for this filter" msgstr "Nessun contenuto disponibile per questo filtro" +#: msgctxt "#32455" msgid "Please change change or remove the current filter" msgstr "Per favore cambia o rimuovi il filtro corrente" +#: msgctxt "#32456" msgid "Show" msgstr "Serie" +#: msgctxt "#32457" msgid "By Show" msgstr "Per Serie" +#: msgctxt "#32458" msgid "Episodes" msgstr "Episodi" +#: msgctxt "#32459" msgid "Offline Mode" msgstr "Modo Offline" +#: msgctxt "#32460" msgid "Sign In" msgstr "Accedi (Sign In)" +#: msgctxt "#32461" msgid "Albums" msgstr "Albums" +#: msgctxt "#32462" msgid "Artist" msgstr "Artista" +#: msgctxt "#32463" msgid "By Artist" msgstr "Per Artista" + +#: +msgctxt "#32464" +msgid "Player" +msgstr "Player" + +#: +msgctxt "#32465" +msgid "Use skip step settings from Kodi" +msgstr "Utilizza intervallo salta di Kodi" + +#: +msgctxt "#32466" +msgid "Automatically seek selected position after a delay" +msgstr "Ricerca automaticamente la posizione selezionata dopo un certo ritardo." + +#: +msgctxt "#32467" +msgid "User Interface" +msgstr "Interfaccia Utente" + +#: +msgctxt "#32468" +msgid "Show dynamic background art" +msgstr "Mostra poster dinamici in backgroud" + +#: +msgctxt "#32469" +msgid "Background art blur amount" +msgstr "Trasparenza poster in background" + +#: +msgctxt "#32470" +msgid "Background art opacity" +msgstr "Opacità poster in background" + +#: +msgctxt "#32471" +msgid "Use Plex/Kodi steps for timeline" +msgstr "Usa Plex/Kodi intervalli salta nella timeline" + +#: +msgctxt "#32480" +msgid "Theme music" +msgstr "Tema Musicale" + +#: +msgctxt "#32481" +msgid "Off" +msgstr "Off" + +#: +msgctxt "#32482" +msgid "%(percentage)s %%" +msgstr "%(percentage)s %%" + +#: +msgctxt "#32483" +msgid "Hide Stream Info" +msgstr "Nascondi Steam Info" + +#: +msgctxt "#32484" +msgid "Show Stream Info" +msgstr "Mostra Stream Info" + +#: +msgctxt "#32485" +msgid "Go back instantly with the previous menu action in scrolled views" +msgstr "Torna istantaneamente indietro con l'azione del menu precedente nelle visualizzazioni scorrevoli" + +#: +msgctxt "#32487" +msgid "Seek Delay" +msgstr "Ritardo di ricerca" + +#: +msgctxt "#32488" +msgid "Screensaver" +msgstr "Salvaschermo" + +#: +msgctxt "#32489" +msgid "Quiz Mode" +msgstr "Modalità Quiz" + +#: +msgctxt "#32490" +msgid "Collections" +msgstr "Collezioni" + +#: +msgctxt "#32491" +msgid "Folders" +msgstr "Cartelle" + +#: +msgctxt "#32492" +msgid "Kodi Subtitle Settings" +msgstr "Impostazioni sottotitoli di Kodi" + +#: +msgctxt "#32495" +msgid "Skip intro" +msgstr "Salta Intro" + +#: +msgctxt "#32496" +msgid "Skip credits" +msgstr "Salta Crediti" + +#: +msgctxt "#32500" +msgid "Always show post-play screen (even for short videos)" +msgstr "Mostra sempre la schermata di post-riproduzione (anche per video brevi)" + +#: +msgctxt "#32501" +msgid "Time-to-wait between videos on post-play" +msgstr "Tempo di attesa tra i video in post-riproduzione" + +#: +msgctxt "#32505" +msgid "Visit media in video playlist instead of playing it" +msgstr "Mostra i media nella playlist video anziché riprodurli" + +#: +msgctxt "#32521" +msgid "Skip Intro Button Timeout" +msgstr "Timeout del pulsante Salta Intro" + +#: +msgctxt "#32522" +msgid "Automatically Skip Intro" +msgstr "Salta automaticamente le Intro" + +#: +msgctxt "#32524" +msgid "Set how long the skip intro button shows for." +msgstr "Imposta per quanto tempo il pulsante Salta Intro viene visualizzato." + +#: +msgctxt "#32525" +msgid "Skip Credits Button Timeout" +msgstr "Timeout del pulsante Salta Crediti" + +#: +msgctxt "#32526" +msgid "Automatically Skip Credits" +msgstr "Salta automaticamente i Crediti" + +#: +msgctxt "#32528" +msgid "Set how long the skip credits button shows for." +msgstr "Imposta per quanto tempo il pulsante Salta Crediti viene visualizzato." + +#: +msgctxt "#32540" +msgid "Show when the current video will end in player" +msgstr "Mostra quando il video attuale finirà nel player" + +#: +msgctxt "#32541" +msgid "Shows time left and at which time the media will end." +msgstr "Mostra il tempo rimasto e a che ora il video finirà." + +#: +msgctxt "#32542" +msgid "Show \"Ends at\" label for the end-time as well" +msgstr "Mostra l'etichetta \"Termina alle\" anche per l'orario di fine" + +#: +msgctxt "#32543" +msgid "Ends at" +msgstr "Termina alle" + +#: +msgctxt "#32601" +msgid "Allow AV1" +msgstr "Abilita AV1" + +#: +msgctxt "#32602" +msgid "Enable this if your hardware can handle AV1. Disable it to force transcoding." +msgstr "Attiva questa opzione se il tuo hardware supporta AV1. Disattivala per forzare la transcodifica." + +#: +msgctxt "#33101" +msgid "By Audience Rating" +msgstr "Secondo Valutazione degli Spettatori" + +#: +msgctxt "#33102" +msgid "Audience Rating" +msgstr "Valutazione degli Spettatori" + +#: +msgctxt "#33103" +msgid "By my Rating" +msgstr "Secondo la valutazione personale" + +#: +msgctxt "#33104" +msgid "My Rating" +msgstr "Valutazione Personale" + +#: +msgctxt "#33105" +msgid "By Content Rating" +msgstr "Secondo Classificazione del Contenuto" + +#: +msgctxt "#33106" +msgid "Content Rating" +msgstr "Classificazione del Contenuto" + +#: +msgctxt "#33107" +msgid "By Critic Rating" +msgstr "Secondo la Valutazione della Critica" + +#: +msgctxt "#33108" +msgid "Critic Rating" +msgstr "Valutazione della Critica" + +#: +msgctxt "#33200" +msgid "Background Color" +msgstr "Colore di Sfondo" + +#: +msgctxt "#33201" +msgid "Specify solid Background Color instead of using media images" +msgstr "Scegli un Colore di Sfondo anziché utilizzare immagini multimediali." + +#: +msgctxt "#33400" +msgid "Use old compatibility profile" +msgstr "Utilizza il vecchio profilo di compatibilità." + +#: +msgctxt "#33401" +msgid "Uses the Chrome client profile instead of the custom one. Might fix rare issues with 3D playback." +msgstr "Utilizza il profilo del client Chrome invece di quello personalizzato.\n" +"Potrebbe risolvere i problemi con la riproduzione in 3D." + +#: +msgctxt "#32031" +msgid "Burn-in Subtitles" +msgstr "Sottotitoli Incisi" + +#: +msgctxt "#32061" +msgid "When transcoding audio, target the audio channels set in Kodi." +msgstr "Durante la transcodifica dell'audio, utilizza i canali audio impostati in Kodi." + +#: +msgctxt "#32062" +msgid "Transcode audio to AC3" +msgstr "Trascodifica audio in AC3" + +#: +msgctxt "#32063" +msgid "Transcode audio to AC3 in certain conditions (useful for passthrough)." +msgstr "Trascodifica l'audio in AC3 in determinate condizioni (utile per il passaggio diretto)." + +#: +msgctxt "#32065" +msgid "When any of the force AC3 settings are enabled, treat DTS the same as AC3 (useful for Optical passthrough)" +msgstr "Quando uno qualsiasi dei settaggi di forzatura AC3 è attivato, trattare il DTS allo stesso modo dell'AC3 (utile per il passthrough ottico)" + +#: +msgctxt "#32066" +msgid "Force audio to AC3" +msgstr "Forza l'audio in AC3" + +#: +msgctxt "#32067" +msgid "Only force multichannel audio to AC3" +msgstr "Permetti solo all'audio multicanale di essere forzato in AC3." + +#: +msgctxt "#32493" +msgid "When a media file has a forced/foreign subtitle for a subtitle-enabled language, the Plex Media Server preselects it. This behaviour is usually not necessary and not configurable. This setting fixes that by ignoring the PMSs decision and selecting the same language without a forced flag if possible." +msgstr "Quando un file multimediale ha un sottotitolo forzato/esterno per una lingua abilitata ai sottotitoli, il server multimediale Plex lo preseleziona. Questo comportamento di solito non è necessario e non è configurabile. Questa impostazione risolve il problema ignorando la decisione del server multimediale Plex e selezionando la stessa lingua senza il flag forzato, se possibile." + +#: +msgctxt "#32523" +msgid "Automatically skip intros if available. Doesn't override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Salta automaticamente le intro se disponibili. Non annulla la modalità maratona abilitata. Può essere disattivato/attivato per ogni serie TV." + +#: +msgctxt "#32527" +msgid "Automatically skip credits if available. Doesn't override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Salta automaticamente i crediti se disponibili. Non annulla la modalità maratona abilitata.\n" +"Può essere disattivato/attivato per ogni serie TV." + +#: +msgctxt "#33501" +msgid "Video played threshold" +msgstr "Soglia di riproduzione dei video" + +#: +msgctxt "#33502" +msgid "Set this to the same value as your Plex server (Settings>Library>Video played threshold) to avoid certain pitfalls, Default: 90 %" +msgstr "Imposta questo valore allo stesso valore del tuo server Plex (Impostazioni>Libreria>Soglia di riproduzione dei video) per evitare certi problemi, Predefinito: 90%" + +#: +msgctxt "#33503" +msgid "Use alternative hubs refresh" +msgstr "Utilizza l'aggiornamento degli hub alternativo" + +#: +msgctxt "#33504" +msgid "Refreshes all hubs for all libraries after an item's watch-state has changed, instead of only those likely affected. Use this if you find a hub that doesn't update properly." +msgstr "Aggiorna tutti gli hub per tutte le librerie dopo che lo stato di visione di un elemento è cambiato, invece di solo quelli interessati. Usa questa opzione se trovi un hub che non si aggiorna correttamente." + +#: +msgctxt "#33505" +msgid "Show intro skip button early" +msgstr "Mostra il pulsante di salto intro in anticipo" + +#: +msgctxt "#33506" +msgid "Show the intro skip button from the start of a video with an intro marker. The auto-skipping setting applies. Doesn\\'t override enabled binge mode.\n" +"Can be disabled/enabled per TV show." +msgstr "Mostra il pulsante di salto intro dall'inizio di un video con un indicatore di intro. L'impostazione di auto-salto si applica. Non annulla la modalità maratona abilitata. \n" +"Può essere disattivato/attivato per ogni serie TV." + +#: +msgctxt "#33507" +msgid "Enabled" +msgstr "Attivato" + +#: +msgctxt "#33508" +msgid "Disabled" +msgstr "Disattivato" + +#: +msgctxt "#33509" +msgid "Early intro skip threshold (default: < 60s/1m)" +msgstr "Soglia di salto anticipato delle Intro (predefinito: < 60s/1m)" + +#: +msgctxt "#33510" +msgid "When showing the intro skip button early, only do so if the intro occurs within the first X seconds." +msgstr "Quando si mostra il pulsante di salto intro anticipato, fallo solo se l'introduzione avviene entro i primi X secondi." + +#: +msgctxt "#33600" +msgid "System" +msgstr "Sistema" + +#: +msgctxt "#33601" +msgid "Show video chapters" +msgstr "Mostra capitoli video" + +#: +msgctxt "#33602" +msgid "If available, show video chapters from the video-file instead of the timeline-big-seek-steps." +msgstr "Se disponibili, mostra i capitoli video dal file video invece degli intervalli della timeline." + +#: +msgctxt "#33603" +msgid "Use virtual chapters" +msgstr "Usa capitoli virtuali" + +#: +msgctxt "#33604" +msgid "When the above is enabled and no video chapters are available, simulate them by using the markers identified by the Plex Server (Intro, Credits)." +msgstr "Quando quanto sopra è abilitato e non ci sono capitoli video disponibili, simulali utilizzando i marker identificati dal server Plex (Introduzione, Crediti)." + +#: +msgctxt "#33605" +msgid "Video Chapters" +msgstr "Capitoli Video" + +#: +msgctxt "#33606" +msgid "Virtual Chapters" +msgstr "Capitoli Virtuali" + +#: +msgctxt "#33607" +msgid "Chapter {}" +msgstr "Capitolo {}" + +#: +msgctxt "#33608" +msgid "Intro" +msgstr "Intro" + +#: +msgctxt "#33609" +msgid "Credits" +msgstr "Crediti" + +#: +msgctxt "#33610" +msgid "Main" +msgstr "Principale" + +#: +msgctxt "#33611" +msgid "Chapters" +msgstr "Capitoli" + +#: +msgctxt "#33612" +msgid "Markers" +msgstr "Indicatori" + +#: +msgctxt "#33613" +msgid "Kodi Buffer Size (MB)" +msgstr "Dimensione del buffer di Kodi (MB)" + +#: +msgctxt "#33614" +msgid "Set the Kodi Cache/Buffer size. Free: {} MB, Recommended: ~50 MB, Recommended max: {} MB, Default: 20 MB." +msgstr "Imposta la dimensione della cache/buffer di Kodi. Libero: {} MB, Consigliato: ~50 MB, Massimo consigliato: {} MB, Predefinito: 20 MB." + +#: +msgctxt "#33615" +msgid "{time} left" +msgstr "{time} rimanenti" + +#: +msgctxt "#33616" +msgid "Addon Path" +msgstr "Addon Path" + +#: +msgctxt "#33617" +msgid "Userdata/Profile Path" +msgstr "Userdata/Profile Path" + +#: +msgctxt "#33618" +msgid "TV binge-viewing mode" +msgstr "Modalità maratona TV" + +#: +msgctxt "#33619" +msgid "Automatically skips episode intros, credits and tries to skip episode recaps. Doesn\\'t skip the intro of the first episode of a season and doesn't skip the final credits of a show.\n" +"\n" +"Can be disabled/enabled per TV show.\n" +"Overrides any setting below." +msgstr "Modalità maratona TV: Salta automaticamente le intro degli episodi, i crediti e cerca di saltare i riassunti degli episodi. Non salta l'introduzione del primo episodio di una stagione e non salta i crediti finali di uno spettacolo. \n" +"\n" +"\n" +"Può essere disattivata/attivata per singoli spettacoli TV. Sovrascrive qualsiasi impostazione seguente." + +#: +msgctxt "#33620" +msgid "Plex requests timeout (seconds)" +msgstr "Timeout delle richieste Plex (secondi)" + +#: +msgctxt "#33621" +msgid "Set the (async and connection) timeout value of the Python requests library in seconds. Default: 5" +msgstr "Imposta il valore di timeout (asincrono e di connessione) della libreria delle richieste Python in secondi. Predefinito: 5" + +#: +msgctxt "#33622" +msgid "LAN reachability timeout (ms)" +msgstr "Timeout di raggiungibilità LAN (ms)" + +#: +msgctxt "#33623" +msgid "When checking for LAN reachability, use this timeout. Default: 10ms" +msgstr "Durante il controllo della raggiungibilità LAN, utilizza questo timeout. Predefinito: 10ms" + +#: +msgctxt "#33624" +msgid "Network" +msgstr "Rete" + +#: +msgctxt "#33625" +msgid "Smart LAN/local server discovery" +msgstr "Smart LAN/Locale server discovery" + +#: +msgctxt "#33626" +msgid "Checks whether servers returned from Plex.tv are actually local/in your LAN. For specific setups (e.g. Docker) Plex.tv might not properly detect a local server.\n" +"\n" +"NOTE: Only works on Kodi 19 or above." +msgstr "Verifica se i server restituiti da Plex.tv sono effettivamente locali/nella LAN. Per configurazioni specifiche (es. Docker), Plex.tv potrebbe non rilevare correttamente un server locale.\n" +"\n" +"NOTA: Funziona solo su Kodi 19 o versioni successive." + +#: +msgctxt "#33627" +msgid "Prefer LAN/local servers over security" +msgstr "Preferire server LAN/locali rispetto alla sicurezza." + +#: +msgctxt "#33628" +msgid "Prioritizes local connections over secure ones. Needs the proper setting in \"Allow Insecure Connections\" and the Plex Server's \"Secure connections\" at \"Preferred\". Can be used to enforce manual servers." +msgstr "Prioritizza le connessioni locali rispetto a quelle sicure. Richiede l'impostazione corretta di \"Consenti connessioni non sicure\" e le impostazioni del server Plex su \"Connessioni sicure\" impostate su \"Preferite\". Può essere utilizzato per imporre server manuali." + +#: +msgctxt "#33629" +msgid "Auto-skip intro/credits offset" +msgstr "Offset di auto-salto intro/crediti" + +#: +msgctxt "#33630" +msgid "Intro/credits markers might be a little early in Plex. When auto skipping add (or subtract) this many seconds from the marker. This avoids cutting off content, while possibly skipping the marker a little late." +msgstr "I marker dell'intro/crediti potrebbero essere un po' anticipati in Plex. Quando si salta automaticamente, aggiungi (o sottrai) questo numero di secondi dal marker. Questo evita di interrompere il contenuto, anche se potrebbe causare lo skipping del marker un po' in ritardo." + +#: +msgctxt "#32631" +msgid "Playback (user-specific)" +msgstr "Riproduzione (specifica dell'utente)" + +#: +msgctxt "#33632" +msgid "Server connectivity check timeout (seconds)" +msgstr "Timeout del controllo di connettività del server (secondi)" + +#: +msgctxt "#33633" +msgid "Set the maximum amount of time a server connection has to answer a connectivity request. Default: 2.5" +msgstr "Imposta il tempo massimo entro il quale una connessione al server deve rispondere a una richiesta di connettività. Predefinito: 2.5" + +#: +msgctxt "#33634" +msgid "Combined Chapters" +msgstr "Combina Capitoli" + +#: +msgctxt "#33635" +msgid "Final Credits" +msgstr "Crediti Finiali" + +#: +msgctxt "#32700" +msgid "Action on Sleep event" +msgstr "Azione in caso di evento di sospensione" + +#: +msgctxt "#32701" +msgid "When Kodi receives a sleep event from the system, run the following action." +msgstr "Quando Kodi riceve un evento di sospensione dal sistema, esegui l'azione seguente." + +#: +msgctxt "#32702" +msgid "Nothing" +msgstr "Niente" + +#: +msgctxt "#32703" +msgid "Stop playback" +msgstr "Interrompi la riproduzione." + +#: +msgctxt "#32704" +msgid "Quit Kodi" +msgstr "Esci da Kodi" + +#: +msgctxt "#32705" +msgid "CEC Standby" +msgstr "CEC Standby" + +#: +msgctxt "#32800" +msgid "Skipping intro" +msgstr "Salto dell'Intro" + +#: +msgctxt "#32801" +msgid "Skipping credits" +msgstr "Salto dei Crediti" + +#: +msgctxt "#32900" +msgid "While playing back an item and seeking on the seekbar, automatically seek to the selected position after a delay instead of having to confirm the selection." +msgstr "Durante la riproduzione di un elemento e navigando nella timeline, esegui automaticamente la ricerca nella posizione selezionata dopo un ritardo anziché dover confermare la selezione." + +#: +msgctxt "#32901" +msgid "Seek delay in seconds." +msgstr "Ritardo Intervallo Salta" + +#: +msgctxt "#32902" +msgid "Kodi has its own skip step settings. Try to use them if they're configured instead of the default ones." +msgstr "Kodi ha le sue impostazioni di intervalli salta. Prova a utilizzarle se sono configurate invece di quelle predefinite." + +#: +msgctxt "#32903" +msgid "Use the above for seeking on the timeline as well." +msgstr "Utilizza quanto sopra anche per cercare nella timeline." + +#: +msgctxt "#32904" +msgid "In seconds." +msgstr "In secondi." + +#: +msgctxt "#32905" +msgid "Cancel post-play timer by pressing OK/SELECT" +msgstr "Annulla il timer di post-riproduzione premendo OK/SELEZIONA" + +#: +msgctxt "#32906" +msgid "Cancel skip marker timer with BACK" +msgstr "Annulla il timer del marker di salto premendo INDIETRO." + +#: +msgctxt "#32907" +msgid "When auto-skipping a marker, allow cancelling the timer by pressing BACK." +msgstr "Quando si salta automaticamente un marker, consenti di annullare il timer premendo INDIETRO." + +#: +msgctxt "#32908" +msgid "Immediately skip marker with OK/SELECT" +msgstr "Salta immediatamente il marker premendo OK/SELEZIONA" + +#: +msgctxt "#32909" +msgid "When auto-skipping a marker with a timer, allow skipping immediately by pressing OK/SELECT." +msgstr "Quando si salta automaticamente un marker con un timer, consenti di saltare immediatamente premendo OK/SELEZIONA" + +#: +msgctxt "#32912" +msgid "Show buffer-state on timeline" +msgstr "Mostra lo stato del buffer nella timeline" + +#: +msgctxt "#32913" +msgid "Shows the current Kodi buffer/cache state on the video player timeline." +msgstr "Mostra lo stato corrente del buffer/cache di Kodi nella timeline del Player." + +#: +msgctxt "#32914" +msgid "Loading" +msgstr "Caricamento" + +#: +msgctxt "#32915" +msgid "Slow connection" +msgstr "Connessione lenta" + +#: +msgctxt "#32916" +msgid "Use with a wonky/slow connection, e.g. in a hotel room. Adjusts the UI to visually wait for item refreshes and waits for the buffer to fill when starting playback. Automatically sets readfactor=20, requires Kodi restart." +msgstr "Utilizzare con una connessione instabile/lenta, es. in una stanza d'albergo. Regola l'interfaccia utente per attendere visivamente il refresh degli elementi e attende che il buffer si riempia all'avvio della riproduzione. Imposta automaticamente readfactor=20, richiede il riavvio di Kodi." + +#: +msgctxt "#32917" +msgid "Couldn't fill buffer in time ({}s)" +msgstr "Impossibile riempire il buffer in tempo ({}s)" + +#: +msgctxt "#32918" +msgid "Buffer wait timeout (seconds)" +msgstr "Timeout di attesa del buffer (secondi)" + +#: +msgctxt "#32919" +msgid "When slow connection is enabled in the addon, wait this long for the buffer to fill. Default: 120 s" +msgstr "Quando la connessione lenta è abilitata nell'addon, attendi questo tempo per riempire il buffer. Predefinito: 120 s" + +#: +msgctxt "#32920" +msgid "Insufficient buffer wait (seconds)" +msgstr "Attesa del buffer insufficiente (secondi)" + +#: +msgctxt "#32921" +msgid "When slow connection is enabled in the addon and the configured buffer isn't big enough for us to determine its fill state, wait this long when starting playback. Default: 10 s" +msgstr "Quando la connessione lenta è abilitata nell'addon e il buffer configurato non è abbastanza grande per determinare il suo stato di riempimento, attendi questo tempo all'avvio della riproduzione. Predefinito: 10 s" + +#: +msgctxt "#32922" +msgid "Kodi Cache Readfactor" +msgstr "Kodi Cache Readfactor" + +#: +msgctxt "#32923" +msgid "Sets the Kodi cache readfactor value. Default: {0}, recommended: {1}. With \"Slow connection\" enabled this will be set to {2}, as otherwise the cache doesn't fill fast/aggressively enough." +msgstr "Imposta il valore di readfactor della cache di Kodi. Predefinito: {0}, consigliato: {1}. Con 'Connessione lenta' abilitata, questo verrà impostato su {2}, altrimenti la cache non si riempie abbastanza rapidamente/aggressivamente." + +#: +msgctxt "#32924" +msgid "Minimize" +msgstr "Minimizza" + +#: +msgctxt "#32925" +msgid "Playback Settings" +msgstr "Impostazioni di Riproduzione" + +#: +msgctxt "#32926" +msgid "Wrong pin entered!" +msgstr "Pin inserito errato!" + +#: +msgctxt "#32927" +msgid "Use episode thumbnails in continue hub" +msgstr "Utilizza le miniature degli episodi nel riquadro di continua a guardare" + +#: +msgctxt "#32928" +msgid "Instead of using media artwork, use thumbnails for episodes in the continue hub on the home screen if available." +msgstr "Se disponibili, utilizza le miniature degli episodi invece del poster nel riquadro di continua a guardare sulla schermata principale." + +#: +msgctxt "#32929" +msgid "Use legacy background fallback image" +msgstr "Utilizza l'immagine di fallback dello sfondo legacy" + +#: +msgctxt "#32930" +msgid "Previous Subtitle" +msgstr "Sottotitolo Precedente" + +#: +msgctxt "#32931" +msgid "Audio/Subtitles" +msgstr "Audio/Sottotitoli" + +#: +msgctxt "#32932" +msgid "Show subtitle quick-actions button" +msgstr "Mostra il pulsante delle azioni rapide dei sottotitoli" + +#: +msgctxt "#32933" +msgid "Show FFWD/RWD buttons" +msgstr "Mostra i pulsanti FFWD/RWD" + +#: +msgctxt "#32934" +msgid "Show repeat button" +msgstr "Mostra il pulsante Ripeti" + +#: +msgctxt "#32935" +msgid "Show shuffle button" +msgstr "Mostra il pulsante Casuale" + +#: +msgctxt "#32936" +msgid "Show playlist button" +msgstr "Mostra il pulsante Playlist" + +#: +msgctxt "#32937" +msgid "Show prev/next button" +msgstr "Mostra il pulsante prev/next" + +#: +msgctxt "#32938" +msgid "Only for Episodes" +msgstr "Solo per gli episodi" + +#: +msgctxt "#32939" +msgid "Only applies to video player UI" +msgstr "Si applica solo all'interfaccia del Player" + +#: +msgctxt "#32940" +msgid "Player UI" +msgstr "Interfaccia del Player" + +#: +msgctxt "#32941" +msgid "Forced subtitles fix" +msgstr "Fix sottotitoli forzati" + +#: +msgctxt "#32942" +msgid "Other seasons" +msgstr "Altre stagioni" + +#: +msgctxt "#32943" +msgid "Crossfade dynamic background art" +msgstr "Dissolvenza incrociata poster di sfondo" + +#: +msgctxt "#32944" +msgid "Burn-in SSA subtitles (DirectStream)" +msgstr "Sottotitoli SSA incisi (DirectStream)" + +#: +msgctxt "#32945" +msgid "When Direct Streaming instruct the Plex Server to burn in SSA/ASS subtitles (thus transcoding the video stream). If disabled it will not touch the video stream, but will convert the subtitle to unstyled text." +msgstr "Quando si esegue lo Streaming Diretto, istruisci il Server Plex a imprimere i sottotitoli SSA/ASS (trascodificando quindi lo stream video). Se disabilitato, non modificherà lo stream video, ma convertirà i sottotitoli in testo senza stile." + +#: +msgctxt "#32946" +msgid "Stop video playback on idle after" +msgstr "Interrompi la riproduzione video inattiva dopo" + +#: +msgctxt "#32947" +msgid "Stop video playback on screensaver" +msgstr "Interrompi la riproduzione video durante lo screensaver" + +#: +msgctxt "#32948" +msgid "Allow auto-skip when transcoding" +msgstr "Consenti auto-salto durante la trascodifica" + +#: +msgctxt "#32949" +msgid "When transcoding/DirectStreaming, allow auto-skip functionality." +msgstr "Durante la trascodifica/DirectStreaming, consenti la funzionalità di auto-salto." + +#: +msgctxt "#32950" +msgid "Use extended title for subtitles" +msgstr "Utilizza il titolo esteso per i sottotitoli" + +#: +msgctxt "#32951" +msgid "When displaying subtitles use the extendedDisplayTitle Plex exposes." +msgstr "Quando si visualizzano i sottotitoli, utilizza l'extendedDisplayTitle fornito da Plex." + +#: +msgctxt "#32953" +msgid "Reviews" +msgstr "Recensioni" + +#: +msgctxt "#32954" +msgid "Needs Kodi restart. WARNING: This will overwrite advancedsettings.xml!\n" +"\n" +"To customize other cache/network-related values, copy \"script.plexmod/pm4k_cache_template.xml\" to profile folder and edit it to your liking. (See About section for the file paths)" +msgstr "Necessita riavvio di Kodi. ATTENZIONE: Questo sovrascriverà il file advancedsettings.xml!\n" +"\n" +"Per personalizzare altri valori relativi alla cache/rete, copia \"script.plexmod/pm4k_cache_template.xml\" nella cartella del profilo e modificalo secondo le tue preferenze. (Consulta la sezione Informazioni per i percorsi dei file)" + +#: +msgctxt "#32955" +msgid "Use Kodi keyboard for searching" +msgstr "Utilizza la tastiera di Kodi per la ricerca" + +#: +msgctxt "#32956" +msgid "Poster resolution scaling %" +msgstr "Ridimensionamento della risoluzione dei poster %" + +#: +msgctxt "#32957" +msgid "In percent. Scales the resolution of all posters/thumbnails for better image quality. May impact PMS/PM4K performance, will increase the cache usage accordingly. Recommended: 200-300 % for for big screens if your hardware can handle it. Needs addon restart." +msgstr "In percentuale. Ridimensiona la risoluzione di tutti i poster/miniature per una migliore qualità dell'immagine. Potrebbe influire sulle prestazioni di PMS/PM4K, aumenterà di conseguenza l'utilizzo della cache. Consigliato: 200-300 % per schermi grandi se l'hardware lo supporta. Necessita riavvio dell'addon." + +#: +msgctxt "#32958" +msgid "Calculate OpenSubtitles.com hash" +msgstr "Calcola l'hash di OpenSubtitles.com" + +#: +msgctxt "#32959" +msgid "When opening the subtitle download feature, automatically calculate the OpenSubtitles.com hash for the given file. Can improve search results, downloads 2*64 KB of the video file to calculate the hash." +msgstr "Quando si apre la funzione di download dei sottotitoli, calcola automaticamente l'hash di OpenSubtitles.com per il file fornito. Può migliorare i risultati della ricerca, scarica 2*64 KB del file video per calcolare l'hash." + +#: +msgctxt "#32960" +msgid "Similar Artists" +msgstr "Artisti Simili" + +#: +msgctxt "#32961" +msgid "Show hub bifurcation lines" +msgstr "Mostra linee di biforcazione dell'hub" + +#: +msgctxt "#32962" +msgid "Visually separate hubs horizontally using a thin line." +msgstr "Separa visualmente gli hub orizzontalmente utilizzando una linea sottile." + +#: +msgctxt "#32963" +msgid "Wait between videos (s)" +msgstr "Attesa tra i video" + +#: +msgctxt "#32964" +msgid "When playing back consecutive videos (e.g. TV shows), wait this long before starting the next one in the queue. Might fix compatibility issues with certain configurations." +msgstr "Quando riproduci video consecutivi (es. serie TV), attendi questo tempo prima di avviare il successivo nella coda. Potrebbe risolvere problemi di compatibilità con determinate configurazioni." + +#: +msgctxt "#32965" +msgid "Quit Kodi on exit by default" +msgstr "Esci da Kodi all'uscita per impostazione predefinita" + +#: +msgctxt "#32966" +msgid "When exiting the addon, use \"Quit Kodi\" as default option. Can be dynamically switched using CONTEXT_MENU (often longpress SELECT)" +msgstr "All'uscita dall'addon, utilizza \"Esci da Kodi\" come opzione predefinita. Può essere cambiato dinamicamente utilizzando CONTEXT_MENU (spesso premendo a lungo SELECT)" + +#: +msgctxt "#32967" +msgid "Kodi Colour Management" +msgstr "Gestione del Colore di Kodi" + +#: +msgctxt "#32968" +msgid "Kodi Resolution Settings" +msgstr "Impostazioni di Risoluzione di Kodi" + +#: +msgctxt "#32969" +msgid "Always request all library media items at once" +msgstr "Richiedi sempre tutti gli elementi multimediali della libreria in una volta sola" + +#: +msgctxt "#32970" +msgid "Retrieve all media in library up front instead of fetching it in chunks as the user navigates through the library" +msgstr "Recupera tutti i media nella libreria anticipatamente invece di recuperarli man mano che l'utente naviga attraverso la libreria" + +#: +msgctxt "#32971" +msgid "Library item-request chunk size" +msgstr "Dimensione del blocco di richiesta degli elementi della libreria" + +#: +msgctxt "#32972" +msgid "Request this amount of media items per chunk request in library view (+6-30 depending on view mode; less can be less straining for the UI at first, but puts more strain on the server)" +msgstr "Richiedi questa quantità di elementi multimediali per ciascuna richiesta a blocchi nella visualizzazione della libreria (+6-30 a seconda della modalità di visualizzazione; meno può essere meno carico per l'interfaccia utente all'inizio, ma mette più carico sul server)" + +#: +msgctxt "#32973" +msgid "Episodes: Skip Post Play screen" +msgstr "Episodi: Salta la schermata di post-riproduzione" + +#: +msgctxt "#32974" +msgid "When finishing an episode, don't show Post Play but go to the next one immediately.\n" +"Can be disabled/enabled per TV show. Doesn't override enabled binge mode. Overrides the Post Play setting." +msgstr "Quando si termina un episodio, non mostrare la schermata di post-riproduzione ma passa immediatamente al successivo.\n" +"Può essere disattivato/attivato per ogni serie TV. Non annulla la modalità maratona abilitata. Sovrascrive l'impostazione di Post Play." + +#: +msgctxt "#32975" +msgid "Delete Season" +msgstr "Elimina Stagione" + +#: +msgctxt "#32976" +msgid "Adaptive" +msgstr "Adattivo" + +#: +msgctxt "#32977" +msgid "Allow VC1" +msgstr "Abilita VC1" + +#: +msgctxt "#32978" +msgid "Enable this if your hardware can handle VC1. Disable it to force transcoding." +msgstr "Attiva questa opzione se l'hardware supporta VC1. Disattivala per forzare la trascodifica." + +#: +msgctxt "#32979" +msgid "Allows the server to only transcode streams of a video that need transcoding, while streaming the others unaltered. If disabled, force the server to transcode everything not direct playable." +msgstr "Consente al server di transcodificare solo i flussi video che necessitano della transcodifica, mentre trasmette gli altri inalterati. Se disabilitato, forza il server a trascodificare tutto ciò che non è riproducibile direttamente." + +#: +msgctxt "#32980" +msgid "Refresh Users" +msgstr "Aggiorna Utenti" + +#: +msgctxt "#32981" +msgid "Background worker count" +msgstr "Numero di Background worker" + +#: +msgctxt "#32982" +msgid "Depending on how many cores your CPU has and how much it can handle, increasing this might improve certain situations. If you experience crashes or other annormalities, leave this at its default (3). Needs an addon restart." +msgstr "A seconda di quanti core ha la tua CPU e di quanto può gestire, aumentare questo valore potrebbe migliorare certe situazioni. Se riscontri crash o altre anomalie, lascia questo valore a default(3). Richiede un riavvio dell'addon." + +#: +msgctxt "#32983" +msgid "Player Theme" +msgstr "Tema del Player" + +#: +msgctxt "#32984" +msgid "Sets the player theme. Currently only customizes the playback control buttons. ATTENTION: [I]Might[/I] need an addon restart.\n" +"In order to customize this, copy one of the xml's in script.plexmod/resources/skins/Main/1080i/templates to addon_data/script.plexmod/templates/seek_dialog_buttons_custom.xml and adjust it to your liking, then select \"Custom\" as your theme." +msgstr "Imposta il tema del lettore. Attualmente personalizza solo i pulsanti di controllo della riproduzione. ATTENZIONE: [I]Potrebbe[/I] essere necessario riavviare l'addon. \n" +"Per personalizzarlo, copia uno degli xml in script.plexmod/resources/skins/Main/1080i/templates in addon_data/script.plexmod/templates/seek_dialog_buttons_custom.xml e modificalo secondo le tue preferenze, quindi seleziona \"Personalizzato\" come tema." + +#: +msgctxt "#32985" +msgid "Modern" +msgstr "Moderno" + +#: +msgctxt "#32986" +msgid "Modern (dotted)" +msgstr "Moderno (a puntini)" + +#: +msgctxt "#32987" +msgid "Classic" +msgstr "Classico" + +#: +msgctxt "#32988" +msgid "Custom" +msgstr "Custom" + +#: +msgctxt "#32989" +msgid "Modern (colored)" +msgstr "Moderno (colorato)" + +#: +msgctxt "#32990" +msgid "Handle plex.direct mapping" +msgstr "Gestisci la mappatura plex.direct" + +#: +msgctxt "#32991" +msgid "Notify" +msgstr "Notifiche" + +#: +msgctxt "#32992" +msgid "When using servers with a plex.direct connection (most of them), should we automatically adjust advancedsettings.xml to cope with plex.direct domains? If not, you might want to add plex.direct to your router's DNS rebind exemption list." +msgstr "Quando si utilizzano server con una connessione plex.direct (la maggior parte di essi), dovremmo regolare automaticamente il file advancedsettings.xml per gestire i domini plex.direct? Se non lo facciamo, potresti dover aggiungere plex.direct all'elenco di eccezioni del reindirizzamento DNS del router." + +#: +msgctxt "#32993" +msgid "{} unhandled plex.direct connections found" +msgstr "{} connessioni plex.direct non gestite trovate" + +#: +msgctxt "#32994" +msgid "In order for PM4K to work properly, we need to add special handling for plex.direct connections. We've found {} new unhandled connections. Do you want us to write those to Kodi's advancedsettings.xml automatically? If not, you might want to add plex.direct to your router's DNS rebind exemption list. This can be changed in the settings as well." +msgstr "Perché PM4K funzioni correttamente, è necessario aggiungere un trattamento speciale per le connessioni plex.direct. Abbiamo trovato {} nuove connessioni non gestite. Vuoi che le scriviamo automaticamente nel file advancedsettings.xml di Kodi? In alternativa, dovresti aggiungere plex.direct all'elenco di eccezioni del reindirizzamento DNS del router. Questo può essere cambiato anche nelle impostazioni." + +#: +msgctxt "#32995" +msgid "Advancedsettings.xml modified (plex.direct mappings)" +msgstr "Modificato il file advancedsettings.xml (mappature plex.direct)" + +#: +msgctxt "#32996" +msgid "The advancedsettings.xml file has been modified. Please restart Kodi for the changes to apply." +msgstr "Il file advancedsettings.xml è stato modificato. Si prega di riavviare Kodi affinché le modifiche abbiano effetto." + +#: +msgctxt "#32997" +msgid "OK" +msgstr "OK" + +#: +msgctxt "#32998" +msgid "Use new Continue Watching hub on Home" +msgstr "Usa il nuovo hub Continua a Guardare nella Schermata Principale" + +#: +msgctxt "#32999" +msgid "Instead of separating Continue Watching and On Deck hubs, behave like the modern Plex clients, which combine those two types of hubs into one Continue Watching hub." +msgstr "Piuttosto che separare i riquadri 'Continua a guardare' e 'In evidenza', comportati come i client Plex moderni, che combinano questi due tipi di riquadri in un unico riquadro 'Continua a guardare'." + +#: +msgctxt "#33000" +msgid "Enable path mapping" +msgstr "Abilita path mapping" + +#: +msgctxt "#33001" +msgid "Honor path_mapping.json in the addon_data/script.plexmod folder when DirectPlaying media. This can be used to stream using other techniques such as SMB/NFS/etc. instead of the default HTTP handler. path_mapping.example.json is included in the addon's main directory." +msgstr "Rispetta path_mapping.json nella cartella addon_data/script.plexmod quando riproduci direttamente i media. Questo può essere utilizzato per lo streaming utilizzando altre tecniche come SMB/NFS/ecc. invece dell'handler HTTP predefinito. È incluso un'esempio di path_mapping.json nella cartella principale dell'addon come path_mapping.example.json." + +#: +msgctxt "#33002" +msgid "Verify mapped files exist" +msgstr "Verifica che i file mappati esistano" + +#: +msgctxt "#33003" +msgid "When path mapping is enabled and we've successfully mapped a file, verify its existence." +msgstr "Quando il path mapping è abilitato e è stato mappato con successo un file, verifica la sua esistenza." + +#: +msgctxt "#33004" +msgid "No spoilers without OSD" +msgstr "Nessun spoiler senza OSD" + +#: +msgctxt "#33005" +msgid "When seeking without the OSD open, hide all time-related information from the user." +msgstr "Quando si cerca senza OSD aperto, nascondi tutte le informazioni relative al tempo dall'utente." + +#: +msgctxt "#33006" +msgid "No TV spoilers" +msgstr "No TV spoilers" + +#: +msgctxt "#33007" +msgid "When visiting an episode/season view, blur unwatched/unwatched+in-progress episode thumbnails, previews and redact summaries. When the Addon Setting \"Use episode thumbnails in continue hub\" is enabled, blur them as well." +msgstr "Quando si accede alla vista episodio/stagione, sfoca le miniature degli episodi non visti/o + in corso, anteprime e redige i riepiloghi. Quando l'impostazione dell'Addon \"Usa le miniature degli episodi nel riquadro continua a guardare\" è abilitata, sfoca anche loro." + +#: +msgctxt "#33008" +msgid "[Spoilers removed]" +msgstr "[Spoileri rimossi]" + +#: +msgctxt "#33009" +msgid "Blur amount for unwatched/in-progress episodes" +msgstr "Livello di sfocatura per gli episodi non visti/in corso" + +#: +msgctxt "#33010" +msgid "Unwatched" +msgstr "Non visti" + +#: +msgctxt "#33011" +msgid "Unwatched/in progress" +msgstr "Non visti/in corso" + +#: +msgctxt "#33012" +msgid "No unwatched episode titles" +msgstr "Nessun titolo di episodi non visti" + +#: +msgctxt "#33013" +msgid "When the above is anything but \"off\", hide episode titles as well." +msgstr "Quando quanto sopra non è impostato su \"Off\", nascondi anche i titoli degli episodi." + +#: +msgctxt "#33014" +msgid "Ignore plex.direct docker hosts" +msgstr "Ignora gli host docker di plex.direct" + +#: +msgctxt "#33015" +msgid "When checking for plex.direct host mapping, ignore local Docker IPv4 addresses (172.16.0.0/12)." +msgstr "Nel controllo della mappatura dell'host plex.direct, ignorare gli indirizzi IPv4 locali di Docker (172.16.0.0/12)." + +#: +msgctxt "#33016" +msgid "Allow TV spoilers for specific genres" +msgstr "Consenti spoiler TV per generi specifici" + +#: +msgctxt "#33017" +msgid "Overrides the above for: {}" +msgstr "Sovrascrive quanto sopra per: {}" + +#: +msgctxt "#32303" +msgid "Season {}" +msgstr "Stagione {}" + +#: +msgctxt "#32304" +msgid "Episode {}" +msgstr "Episodio {}" + +#: +msgctxt "#32310" +msgid "S{}" +msgstr "S{}" + +#: +msgctxt "#32311" +msgid "E{}" +msgstr "E{}" + diff --git a/script.plexmod/resources/language/resource.language.zh_cn/strings.po b/script.plexmod/resources/language/resource.language.zh_cn/strings.po index 46b8c93da..bb8975407 100644 --- a/script.plexmod/resources/language/resource.language.zh_cn/strings.po +++ b/script.plexmod/resources/language/resource.language.zh_cn/strings.po @@ -306,11 +306,11 @@ msgid "Go to {0}" msgstr "跳转到 {0}" msgctxt "#32303" -msgid "Season" +msgid "Season {}" msgstr "季数" msgctxt "#32304" -msgid "Episode" +msgid "Episode {}" msgstr "集数" msgctxt "#32305" @@ -334,11 +334,11 @@ msgid "None" msgstr "无" msgctxt "#32310" -msgid "S" +msgid "S{}" msgstr "" msgctxt "#32311" -msgid "E" +msgid "E{}" msgstr "" msgctxt "#32312" diff --git a/script.plexmod/resources/settings.xml b/script.plexmod/resources/settings.xml index 20ff630fa..2e4741a40 100644 --- a/script.plexmod/resources/settings.xml +++ b/script.plexmod/resources/settings.xml @@ -13,11 +13,6 @@ false - - 0 - false - - 0 true @@ -59,6 +54,11 @@ + + 0 + true + + @@ -205,6 +205,19 @@ false + + 0 + 600 + + 1 + 10 + 1800 + + + 33510 + false + + 0 true @@ -294,9 +307,21 @@ true + + 0 + 16 + + 0 + 1 + 256 + + + false + + 0 - true + false @@ -329,6 +354,11 @@ true + + 0 + true + + 0 10 diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown.xml index 8ace797b8..db0df65e7 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown.xml @@ -86,6 +86,8 @@ center center FFFFFFFF + true + 60 @@ -99,6 +101,8 @@ left center FFFFFFFF + true + 60 @@ -162,6 +166,8 @@ center center FF000000 + true + 60 @@ -175,6 +181,8 @@ left center FF000000 + true + 60 diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown_header.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown_header.xml index 3c623d851..1ca029371 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown_header.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-dropdown_header.xml @@ -108,6 +108,8 @@ center center FFFFFFFF + true + 60 @@ -120,6 +122,8 @@ left center FFFFFFFF + true + 60 @@ -133,6 +137,8 @@ left center FFFFFFFF + true + 60 @@ -196,6 +202,8 @@ center center FF000000 + true + 60 @@ -208,6 +216,8 @@ left center FF000000 + true + 60 @@ -221,6 +231,8 @@ left center FF000000 + true + 60 diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-episodes.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-episodes.xml index e1b9f72fc..fec9bfe66 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-episodes.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-episodes.xml @@ -291,12 +291,33 @@ scale - !String.IsEmpty(Container(400).ListItem.Property(unwatched)) + String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(Container(400).ListItem.Property(unwatched)) + String.IsEmpty(Container(400).ListItem.Property(watched)) 682 0 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(Container(400).ListItem.Property(watched)) + 667 + 0 + + 0 + 0 + 50 + 40 + String.IsEmpty(Window.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 17 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + @@ -660,12 +681,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 264 0 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 259 + 0 + + 0 + 0 + 40 + 32 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + false @@ -786,12 +828,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 264 0 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 259 + 0 + + 0 + 0 + 40 + 32 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + Control.HasFocus(400) @@ -945,26 +1008,26 @@ !String.IsEmpty(ListItem.Property(unwatched.count)) - 113 + 126 0 - 45 - 40 + 32 + 32 script.plex/white-square.png FF000000 - 114 + 127 0 - 44 - 39 + 31 + 31 script.plex/white-square.png FFCC7B19 - 114 + 128 0 - 44 - 39 + 31 + 31 font10 center center @@ -972,6 +1035,27 @@ + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 128 + 0 + + 0 + 0 + 30 + 30 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 9 + 9 + 12 + 12 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(progress)) 0 @@ -1045,28 +1129,28 @@ scale - !String.IsEmpty(ListItem.Property(unwatched.count)) + !String.IsEmpty(ListItem.Property(unwatched.count)) - 113 + 126 0 - 45 - 40 + 32 + 32 script.plex/white-square.png FF000000 - 114 + 127 0 - 44 - 39 + 31 + 31 script.plex/white-square.png FFCC7B19 - 114 + 128 0 - 44 - 39 + 31 + 31 font10 center center @@ -1074,6 +1158,27 @@ + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 128 + 0 + + 0 + 0 + 30 + 30 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 9 + 9 + 12 + 12 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(progress)) 0 @@ -1541,13 +1646,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1685,12 +1811,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-home.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-home.xml index d2caf4ced..34bb982c8 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-home.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-home.xml @@ -177,12 +177,11 @@ 200 Conditional - Conditional + Conditional--> -300 0 2430 240 - 101 203 204 400 @@ -232,6 +231,15 @@ script.plex/home/type/home.png keep + + !String.IsEmpty(ListItem.Property(is.mapped)) + 230 + 0 + 8 + 8 + script.plex/white-square-rounded-4r.png + FF666666 + @@ -271,6 +279,7 @@ script.plex/drop-shadow.png + String.IsEmpty(ListItem.Property(moving)) UnFocus 0 0 @@ -280,6 +289,7 @@ FF1F1F1F + String.IsEmpty(ListItem.Property(moving)) UnFocus 0 0 @@ -288,6 +298,26 @@ script.plex/white-square-rounded.png FFE5A00D + + !String.IsEmpty(ListItem.Property(moving)) + UnFocus + 0 + 0 + 238 + 117 + script.plex/white-square-rounded.png + 66777777 + + + !String.IsEmpty(ListItem.Property(moving)) + UnFocus + 0 + 0 + 238 + 117 + script.plex/white-square-rounded.png + 66777777 + !Control.HasFocus(101) @@ -306,6 +336,15 @@ $INFO[ListItem.Thumb] keep + + !String.IsEmpty(ListItem.Property(is.mapped)) + 230 + 0 + 8 + 8 + script.plex/white-square-rounded-4r.png + AAFFFFFFF + !String.IsEmpty(ListItem.Property(is.home)) @@ -379,6 +418,7 @@ 101 401 noop + noop 200 horizontal 4 @@ -453,20 +493,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -605,20 +664,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -722,6 +800,7 @@ 400 402 noop + noop 200 horizontal 4 @@ -819,12 +898,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -967,13 +1067,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1057,6 +1178,7 @@ 401 403 noop + noop 200 horizontal 4 @@ -1154,12 +1276,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1302,13 +1445,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1392,6 +1556,7 @@ 402 404 noop + noop 200 horizontal 4 @@ -1489,12 +1654,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1637,13 +1823,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1727,6 +1934,7 @@ 403 405 noop + noop 200 horizontal 4 @@ -1824,12 +2032,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1972,13 +2201,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -2062,6 +2312,7 @@ 404 406 noop + noop 200 horizontal 4 @@ -2320,6 +2571,7 @@ 405 407 noop + noop 200 horizontal 4 @@ -2394,20 +2646,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -2546,20 +2817,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -2663,6 +2953,7 @@ 406 408 noop + noop 200 horizontal 4 @@ -2760,12 +3051,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -2908,13 +3220,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -2998,6 +3331,7 @@ 407 409 noop + noop 200 horizontal 4 @@ -3095,12 +3429,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -3243,13 +3598,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -3333,6 +3709,7 @@ 408 410 noop + noop 200 horizontal 4 @@ -3592,6 +3969,7 @@ 409 411 noop + noop 200 horizontal 4 @@ -3851,6 +4229,7 @@ 410 412 noop + noop 200 horizontal 4 @@ -4110,6 +4489,7 @@ 411 420 noop + noop 200 horizontal 4 @@ -4369,6 +4749,7 @@ 412 421 noop + noop 200 horizontal 4 @@ -4628,6 +5009,7 @@ 420 422 noop + noop 200 horizontal 4 @@ -4887,6 +5269,7 @@ 421 413 noop + noop 200 horizontal 4 @@ -5146,6 +5529,7 @@ 422 414 noop + noop 200 horizontal 4 @@ -5243,12 +5627,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -5391,13 +5796,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -5481,6 +5907,7 @@ 413 415 noop + noop 200 horizontal 4 @@ -5578,12 +6005,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -5726,13 +6174,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -5816,6 +6285,7 @@ 414 416 noop + noop 200 horizontal 4 @@ -5913,12 +6383,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -6061,13 +6552,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -6151,6 +6663,7 @@ 415 417 noop + noop 200 horizontal 4 @@ -6248,12 +6761,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -6396,13 +6930,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -6485,6 +7040,7 @@ 416 418 noop + noop 200 horizontal 4 @@ -6559,20 +7115,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -6711,20 +7286,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -6827,6 +7421,7 @@ 417 419 noop + noop 200 horizontal 4 @@ -6901,20 +7496,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -7053,20 +7667,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -7169,6 +7802,7 @@ 418 423 noop + noop 200 horizontal 4 @@ -7243,20 +7877,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -7395,20 +8048,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -7511,6 +8183,7 @@ 419 423 noop + noop 200 horizontal 4 @@ -7585,20 +8258,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png @@ -7737,20 +8429,39 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 484 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png - !String.IsEmpty(ListItem.Property(unwatched.count)) - 481 + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 492 0 0 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + + + !String.IsEmpty(ListItem.Property(unwatched.count)) + + 481 + 0 51 39 script.plex/white-square.png diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9.xml index a6a892171..54dc87fb7 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-16x9.xml @@ -222,12 +222,24 @@ 24 - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 880 -3 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(initialized)) + String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(.ListItem.Property(unwatched.count)) + String.IsEmpty(ListItem.Property(progress)) + 895 + 0 + + 0 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -262,10 +274,20 @@ 72 font10 left - center FFFFFFFF + + !String.IsEmpty(ListItem.Property(year)) + 0 + 30 + 915 + 72 + font10 + left + FFFFFFFF + + @@ -289,12 +311,24 @@ 24 - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 880 -2 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(initialized)) + String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(unwatched.count)) + String.IsEmpty(ListItem.Property(progress)) + 895 + 0 + + 0 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -329,10 +363,20 @@ 72 font10 left - center FFFFFFFF + + !String.IsEmpty(ListItem.Property(year)) + 0 + 30 + 915 + 72 + font10 + left + FFFFFFFF + + @@ -368,12 +412,24 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 957 0 48 48 - script.plex/indicators/unwatched-rounded.png + special://profile/addon_data/script.plexmod/media/unwatched-rounded.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 951 + 8 + + 0 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -401,7 +457,7 @@ 60 - 0 + 4 0 0 @@ -409,10 +465,20 @@ 72 font12 left - center DF000000 + + !String.IsEmpty(ListItem.Property(year)) + 0 + 30 + 510 + 72 + font12 + left + DF000000 + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square.xml index 7dbc4b5ff..a5a063d82 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-listview-square.xml @@ -253,7 +253,7 @@ -3 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -333,7 +333,7 @@ -2 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -429,7 +429,7 @@ 0 48 48 - script.plex/indicators/unwatched-rounded.png + special://profile/addon_data/script.plexmod/media/unwatched-rounded.png !String.IsEmpty(ListItem.Property(unwatched.count)) diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-playlist.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-playlist.xml index 859d1bb04..392a7251d 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-playlist.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-playlist.xml @@ -247,7 +247,7 @@ -1 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png 226 @@ -402,7 +402,7 @@ -1 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png 226 @@ -585,7 +585,7 @@ 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png 313 diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-posters-small.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-posters-small.xml index 75d3eebd4..e2c887658 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-posters-small.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-posters-small.xml @@ -142,7 +142,7 @@ 2 152 - + 55 137 @@ -187,12 +187,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 115 0 29 29 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(initialized)) + String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(unwatched.count)) + String.IsEmpty(ListItem.Property(progress)) + 114 + 0 + + 0 + 0 + 30 + 30 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 9 + 9 + 12 + 12 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -226,7 +247,19 @@ - String.IsEmpty(ListItem.Property(subtitle)) + String.IsEmpty(ListItem.Property(subtitle)) + !String.IsEmpty(ListItem.Property(year)) + false + 0 + 218 + 144 + 72 + font10 + center + FFFFFFFF + + + + String.IsEmpty(ListItem.Property(subtitle)) + String.IsEmpty(ListItem.Property(year)) false 0 218 @@ -254,7 +287,7 @@ - + 55 137 @@ -312,12 +345,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 115 0 29 29 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(initialized)) + String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(unwatched.count)) + String.IsEmpty(ListItem.Property(progress)) + 114 + 0 + + 0 + 0 + 30 + 30 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 9 + 9 + 12 + 12 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -351,7 +405,19 @@ - String.IsEmpty(ListItem.Property(subtitle)) + String.IsEmpty(ListItem.Property(subtitle)) + !String.IsEmpty(ListItem.Property(year)) + true + 0 + 218 + 144 + 72 + font10 + center + FFFFFFFF + + + + String.IsEmpty(ListItem.Property(subtitle)) + String.IsEmpty(ListItem.Property(year)) true 0 218 @@ -368,7 +434,7 @@ 0 218 144 - 30 + 20 font10 center FFFFFFFF @@ -394,7 +460,7 @@ String.IsEqual(Window(10000).Property(script.plex.sort),titleSort) + Integer.IsGreater(Container(101).NumItems,0) + String.IsEmpty(Window.Property(drawing)) 151 - 1780 + 1810 150 20 920 diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-posters.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-posters.xml index 43154ee67..244bde2a9 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-posters.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-posters.xml @@ -187,12 +187,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 199 0 45 45 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(initialized)) + String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(unwatched.count)) + String.IsEmpty(ListItem.Property(progress)) + 198 + 0 + + 0 + 0 + 46 + 46 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 15 + 15 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -236,6 +257,18 @@ FFFFFFFF + + !String.IsEmpty(ListItem.Property(year)) + false + 0 + 396 + 244 + 72 + font10 + center + FFFFFFFF + + @@ -299,12 +332,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 199 0 45 45 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(initialized)) + String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(unwatched.count)) + String.IsEmpty(ListItem.Property(progress)) + 198 + 0 + + 0 + 0 + 46 + 46 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 15 + 15 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -348,6 +402,18 @@ FFFFFFFF + + !String.IsEmpty(ListItem.Property(year)) + false + 0 + 396 + 244 + 72 + font10 + center + FFFFFFFF + + Control.HasFocus(101) diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-pre_play.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-pre_play.xml index 167c6e4d8..d9c473958 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-pre_play.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-pre_play.xml @@ -198,12 +198,33 @@ scale - !String.IsEmpty(Window.Property(unwatched)) + String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(Window.Property(unwatched)) + String.IsEmpty(Window.Property(watched)) 359 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(Window.Property(use_alt_watched)) + !String.IsEmpty(Window.Property(watched)) + 367 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(Window.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + @@ -1032,13 +1053,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1176,12 +1218,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-seasons.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-seasons.xml index 2cf45910d..3cb4abcfd 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-seasons.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-seasons.xml @@ -411,26 +411,26 @@ !String.IsEmpty(ListItem.Property(unwatched.count)) - 113 + 126 0 - 45 - 40 + 32 + 32 script.plex/white-square.png FF000000 - 114 + 127 0 - 44 - 39 + 31 + 31 script.plex/white-square.png FFCC7B19 - 114 + 128 0 - 44 - 39 + 31 + 31 font10 center center @@ -438,6 +438,27 @@ + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 128 + 0 + + 0 + 0 + 30 + 30 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 9 + 9 + 12 + 12 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(progress)) 0 @@ -511,28 +532,28 @@ scale - !String.IsEmpty(ListItem.Property(unwatched.count)) + !String.IsEmpty(ListItem.Property(unwatched.count)) - 113 + 126 0 - 45 - 40 + 32 + 32 script.plex/white-square.png FF000000 - 114 + 127 0 - 44 - 39 + 31 + 31 script.plex/white-square.png FFCC7B19 - 114 + 128 0 - 44 - 39 + 31 + 31 font10 center center @@ -540,6 +561,27 @@ + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 128 + 0 + + 0 + 0 + 30 + 30 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 9 + 9 + 12 + 12 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(progress)) 0 @@ -982,13 +1024,34 @@ - !String.IsEmpty(ListItem.Property(unwatched)) - 196 - 0 - 48 - 48 - script.plex/indicators/unwatched.png - + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 196 + 0 + 48 + 48 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -1126,12 +1189,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog.xml new file mode 100644 index 000000000..de00fea50 --- /dev/null +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog.xml @@ -0,0 +1,1095 @@ + + + + 1 + 0 + 0 + + 100 + 800 + + + [!String.IsEmpty(Window.Property(show.OSD)) | Window.IsVisible(seekbar) | !String.IsEmpty(Window.Property(button.seek))] + !Window.IsVisible(osdvideosettings) + !Window.IsVisible(osdaudiosettings) + !Window.IsVisible(osdsubtitlesettings) + !Window.IsVisible(subtitlesearch) + !Window.IsActive(playerprocessinfo) + !Window.IsActive(selectdialog) + !Window.IsVisible(osdcmssettings) + Hidden + + String.IsEmpty(Window.Property(settings.visible)) + [Window.IsVisible(seekbar) | Window.IsVisible(videoosd) | Player.ShowInfo] + Hidden + 0 + 0 + + 0 + 0 + 1920 + 1080 + script.plex/player-fade.png + FF080808 + + + + + 0 + 0 + + 0 + 0 + 1920 + 140 + script.plex/white-square.png + A0000000 + + + String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD)) + 0 + 940 + 1920 + 140 + script.plex/white-square.png + A0000000 + + + + + 0 + 40 + + !String.IsEmpty(Window.Property(is.show)) + String.IsEmpty(Window.Property(hide.title)) + 60 + 0 + 1720 + 60 + font13 + left + center + FFFFFFFF + true + 15 + + + + !String.IsEmpty(Window.Property(is.show)) + !String.IsEmpty(Window.Property(hide.title)) + 60 + 0 + 1720 + 60 + font13 + left + center + FFFFFFFF + true + 15 + + + + String.IsEmpty(Window.Property(is.show)) + 60 + 0 + 1720 + 60 + font13 + left + center + FFFFFFFF + true + 15 + + + + 1860 + 0 + 300 + 60 + font12 + right + center + FFFFFFFF + + + + + + 0 + 965 + + !String.IsEmpty(Window.Property(direct.play)) + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 60 + 0 + 1000 + 60 + font13 + left + center + FFFFFFFF + + + + String.IsEmpty(Window.Property(direct.play)) + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 60 + 0 + 1000 + 60 + font13 + left + center + FFFFFFFF + + + + Player.IsTempo + 60 + 40 + 1000 + 60 + font13 + left + center + A0FFFFFF + + + + !String.IsEmpty(Window.Property(direct.play)) + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 1860 + 0 + 800 + 60 + font13 + right + center + FFFFFFFF + + + + String.IsEmpty(Window.Property(direct.play)) + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 1860 + 0 + 800 + 60 + font13 + right + center + FFFFFFFF + + + + !String.IsEmpty(Window.Property(media.show_ends)) + !String.IsEmpty(Window.Property(direct.play)) + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 1860 + 40 + 800 + 60 + font13 + right + center + A0FFFFFF + + + + !String.IsEmpty(Window.Property(media.show_ends)) + String.IsEmpty(Window.Property(direct.play)) + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 1860 + 40 + 800 + 60 + font13 + right + center + A0FFFFFF + + + + + + + 0 + 940 + + String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD)) + 0 + 0 + 1920 + 10 + script.plex/white-square.png + A0000000 + + + !String.IsEmpty(Window.Property(show.buffer)) + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 0 + 2 + 1 + 6 + script.plex/white-square.png + EE4E4842 + + + String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD)) + 0 + 2 + 1 + 6 + script.plex/white-square.png + FFAC5B00 + + + [Control.HasFocus(100) | !String.IsEmpty(Window.Property(button.seek))] + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 0 + 2 + 1 + 6 + script.plex/white-square.png + FFE5A00D + + + + + String.IsEmpty(Window.Property(show.OSD)) + 0 + 0 + 1920 + 1080 + - + - + + SetProperty(show.OSD,1) + + + + + 0 + 350 + !String.IsEmpty(Window.Property(show.PPI)) + String.IsEmpty(Window.Property(settings.visible)) + String.IsEmpty(Window.Property(playlist.visible)) + Visible + Hidden + + 10 + -220 + 10 + 420 + buttons/dialogbutton-nofo.png + + + 52 + -184 + 1786 + 350 + horizontal + 10 + + 0 + 0 + 793 + + 793 + 50 + bottom + + font14 + black + Player.HasVideo + + + 793 + 50 + bottom + + font14 + black + Player.HasVideo + + + 793 + 50 + bottom + + font14 + black + Player.HasVideo + + + 793 + 50 + bottom + + font14 + black + Player.HasVideo + + + 793 + 50 + bottom + + + font14 + black + + + 793 + 50 + bottom + + font14 + black + + + + 0 + 0 + 993 + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Status)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Mode)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Container)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Video)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + [!String.IsEmpty(Window.Property(ppi.Audio)) | !String.IsEmpty(Window.Property(ppi.Subtitles))] + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.User)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + String.IsEmpty(Window.Property(ppi.Buffered)) + + + 893 + 50 + bottom + + font14 + black + Player.HasVideo + !String.IsEmpty(Window.Property(ppi.Buffered)) + + + + + 52 + 120 + 1786 + 50 + bottom + + font14 + black + + + + !String.IsEmpty(Window.Property(show.OSD)) + !Window.IsVisible(osdvideosettings) + !Window.IsVisible(osdaudiosettings) + !Window.IsVisible(osdsubtitlesettings) + !Window.IsVisible(subtitlesearch) + !Window.IsActive(playerprocessinfo) + !Window.IsActive(selectdialog) + !Window.IsVisible(osdcmssettings) + Hidden + + !String.IsEmpty(Window.Property(has.bif)) + [Control.HasFocus(100) | Control.HasFocus(501) | !String.IsEmpty(Window.Property(button.seek))] + Visible + 0 + 752 + + 0 + 0 + 324 + 184 + script.plex/white-square.png + FF000000 + + + 2 + 2 + 320 + 180 + 10 + $INFO[Window.Property(bif.image)] + + + + + 406 + + 360 + 964 + 1200 + + 124 + center + 100 + -40 + horizontal + 200 + true + + !String.IsEmpty(Window.Property(nav.repeat)) + 125 + 101 + + + 0 + 0 + 125 + 101 + 100 + 402 + 412 + font12 + - + - + + + + !Control.HasFocus(401) + + !Playlist.IsRepeatOne + !Playlist.IsRepeat + String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/repeat.png + + + Playlist.IsRepeat | !String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/repeat.png + + + Playlist.IsRepeatOne | !String.IsEmpty(Window.Property(pq.repeat.one)) + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/repeat-one.png + + + + Control.HasFocus(401) + + !Playlist.IsRepeatOne + !Playlist.IsRepeat + String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/repeat.png + + + Playlist.IsRepeat | !String.IsEmpty(Window.Property(pq.repeat)) + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/repeat.png + + + Playlist.IsRepeatOne | !String.IsEmpty(Window.Property(pq.repeat.one)) + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/repeat-one.png + + + + + + !String.IsEmpty(Window.Property(has.playlist)) + !String.IsEmpty(Window.Property(nav.shuffle)) + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/shuffle.png + script.plex/buttons/player/modern/shuffle.png + !String.IsEmpty(Window.Property(pq.shuffled)) + script.plex/buttons/player/modern/shuffle.png + script.plex/buttons/player/modern/shuffle.png + + + + false + String.IsEmpty(Window.Property(has.playlist)) + !String.IsEmpty(Window.Property(nav.shuffle)) + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/shuffle.png + script.plex/buttons/shuffle.png + + + + + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/settings.png + script.plex/buttons/player/modern/settings.png + + + + + + !String.IsEmpty(Window.Property(pq.hasprev)) + !String.IsEmpty(Window.Property(nav.prevnext)) + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/next.png + script.plex/buttons/player/modern/next.png + + + + false + String.IsEmpty(Window.Property(pq.hasprev)) + !String.IsEmpty(Window.Property(nav.prevnext)) + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/next.png + script.plex/buttons/player/modern/next.png + + + + !String.IsEmpty(Window.Property(nav.ffwdrwd)) + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/skip-forward.png + script.plex/buttons/player/modern/skip-forward.png + + + + + 125 + 101 + + + 0 + 0 + 125 + 101 + 100 + 407 + 405 + font12 + - + - + + PlayerControl(Play) + + + !Control.HasFocus(406) + + !Player.Paused + !Player.Forwarding + !Player.Rewinding + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/pause.png + + + Player.Paused | Player.Forwarding | Player.Rewinding + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/play.png + + + + Control.HasFocus(406) + + !Player.Paused + !Player.Forwarding + !Player.Rewinding + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/pause.png + + + Player.Paused | Player.Forwarding | Player.Rewinding + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/play.png + + + + + + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/stop.png + script.plex/buttons/player/modern/stop.png + + + + !String.IsEmpty(Window.Property(nav.ffwdrwd)) + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/skip-forward.png + script.plex/buttons/player/modern/skip-forward.png + + + + !String.IsEmpty(Window.Property(pq.hasnext)) + !String.IsEmpty(Window.Property(nav.prevnext)) + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/next.png + script.plex/buttons/player/modern/next.png + + + + false + String.IsEmpty(Window.Property(pq.hasnext)) + !String.IsEmpty(Window.Property(nav.prevnext)) + 0 + 0 + 125 + 101 + script.plex/buttons/player/modern/next.png + script.plex/buttons/player/modern/next.png + + + + + + [!String.IsEmpty(Window.Property(pq.hasnext)) | !String.IsEmpty(Window.Property(pq.hasprev))] + !String.IsEmpty(Window.Property(nav.playlist)) + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/pqueue.png + script.plex/buttons/player/modern/pqueue.png + + + + false + String.IsEmpty(Window.Property(pq.hasnext)) + String.IsEmpty(Window.Property(pq.hasprev)) + !String.IsEmpty(Window.Property(nav.playlist)) + + 30 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/pqueue.png + script.plex/buttons/player/modern/pqueue.png + + + + !String.IsEmpty(Window.Property(nav.quick_subtitles)) + + 0 + 0 + 125 + 101 + font12 + script.plex/buttons/player/modern/subtitle.png + script.plex/buttons/player/modern/subtitle.png + + + + + + 0 + 940 + + + 0 + 0 + 1920 + 10 + 501 + 400 + - + - + + + + + Conditional + + + Conditional + + + String.IsEmpty(Window.Property(mouse.mode)) + String.IsEmpty(Window.Property(hide.bigseek)) + [Control.HasFocus(501) | Control.HasFocus(100)] + [!String.IsEmpty(Window.Property(show.chapters)) | String.IsEmpty(Window.Property(has.chapters))] + -8 + 917 + + -200 + 5 + 2320 + 6 + script.plex/white-square.png + A0000000 + String.IsEmpty(Window.Property(has.chapters)) + + + + 0 + -175 + 1928 + 200 + script.plex/white-square.png + A0000000 + !String.IsEmpty(Window.Property(has.chapters)) + + + 40 + -162 + auto + 20 + font10 + left + center + CC606060 + + !String.IsEmpty(Window.Property(has.chapters)) + !Control.HasFocus(501) + + + 40 + -162 + auto + 20 + font10 + left + center + FFFFFFFF + + !String.IsEmpty(Window.Property(has.chapters)) + Control.HasFocus(501) + + + + + 0 + 0 + 1928 + 16 + 100 + SetProperty(hide.bigseek,) + 200 + horizontal + 4 + + + + 0 + 0 + 16 + 16 + script.plex/indicators/seek-selection-marker.png + FF606060 + + + + + + + !Control.HasFocus(501) + 0 + 0 + 16 + 16 + script.plex/indicators/seek-selection-marker.png + FF606060 + + + Control.HasFocus(501) + 0 + 0 + 16 + 16 + script.plex/indicators/seek-selection-marker.png + FFE5A00D + + + + + + + + 40 + 0 + 178 + 100 + script.plex/thumb_fallbacks/movie16x9.png + scale + CC606060 + !Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + DDAAAAAA + !Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + script.plex/thumb_fallbacks/movie16x9.png + scale + FFAAAAAA + Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + FFAAAAAA + Control.HasFocus(501) + + + 40 + 120 + auto + 10 + font10 + center + center + CC606060 + + !Control.HasFocus(501) + + + 40 + 120 + auto + 10 + font10 + center + center + FFAAAAAA + + Control.HasFocus(501) + + + + + + + + Focus + + 40 + 0 + 178 + 100 + script.plex/thumb_fallbacks/movie16x9.png + scale + CC909090 + !Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + FF666666 + !Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + script.plex/thumb_fallbacks/movie16x9.png + scale + + Control.HasFocus(501) + + + 40 + 0 + 178 + 100 + $INFO[ListItem.Thumb] + scale + + Control.HasFocus(501) + + + 40 + 120 + auto + 10 + font10 + center + center + FFDDDDDD + + !Control.HasFocus(501) + + + 40 + 120 + auto + 10 + font10 + center + center + + + Control.HasFocus(501) + + + + + + + + [Control.HasFocus(100) | Control.HasFocus(501) | !String.IsEmpty(Window.Property(button.seek))] + [String.IsEmpty(Window.Property(no.osd.hide_info)) | !String.IsEmpty(Window.Property(show.OSD))] + 0 + 896 + + -50 + 0 + + Visible + 0 + 0 + 101 + 39 + script.plex/indicators/player-selection-time_box.png + D0000000 + + + 0 + 0 + 101 + 40 + font10 + center + center + FFFFFFFF + + + + + Visible + -6 + 39 + 15 + 7 + script.plex/indicators/player-selection-time_arrow.png + D0000000 + + + + + + 30 + 797 + 1670 + 143 + right + horizontal + + [!String.IsEmpty(Window.Property(show.markerSkip)) + String.IsEmpty(Window.Property(show.markerSkip_OSDOnly))] | [!String.IsEmpty(Window.Property(show.markerSkip_OSDOnly)) + !String.IsEmpty(Window.Property(show.OSD))] + Focus + UnFocus + + + + auto + 143 + center + 0 + 0 + script.plex/buttons/blank-focus.png + script.plex/buttons/blank.png + 70 + FF000000 + FF000000 + + + + + diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog_skeleton.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog_skeleton.xml index 6b50e6d43..259c25f5b 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog_skeleton.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-seek_dialog_skeleton.xml @@ -52,7 +52,7 @@ 0 40 - !String.IsEmpty(Window.Property(is.show)) + !String.IsEmpty(Window.Property(is.show)) + String.IsEmpty(Window.Property(hide.title)) 60 0 1720 @@ -65,6 +65,20 @@ 15 + + !String.IsEmpty(Window.Property(is.show)) + !String.IsEmpty(Window.Property(hide.title)) + 60 + 0 + 1720 + 60 + font13 + left + center + FFFFFFFF + true + 15 + + String.IsEmpty(Window.Property(is.show)) 60 @@ -631,6 +645,7 @@ + Focus 40 0 @@ -648,7 +663,7 @@ 100 $INFO[ListItem.Thumb] scale - FFAAAAAA + FF666666 !Control.HasFocus(501) @@ -679,7 +694,7 @@ font10 center center - FFAAAAAA + FFDDDDDD !Control.HasFocus(501) diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-settings.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-settings.xml index 8ea7e0dac..ffe5f0445 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-settings.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-settings.xml @@ -200,6 +200,7 @@ left center FFFFFFFF + true @@ -292,6 +293,7 @@ left center FF000000 + true @@ -303,6 +305,7 @@ right center FF000000 + true @@ -320,6 +323,7 @@ left center FFFFFFFF + true @@ -331,6 +335,7 @@ right center FFFFFFFF + true diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-video_current_playlist.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-video_current_playlist.xml index 796140288..e03c56823 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-video_current_playlist.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-video_current_playlist.xml @@ -110,12 +110,24 @@ scale - String.IsEmpty(ListItem.Property(watched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 895 -1 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 895 + 0 + + 0 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + 226 @@ -243,12 +255,24 @@ scale - String.IsEmpty(ListItem.Property(watched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 895 -1 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 895 + 0 + + 0 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + 226 @@ -405,12 +429,24 @@ scale - String.IsEmpty(ListItem.Property(watched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) + 951 + -1 + 35 + 35 + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) 951 0 - 48 - 48 - script.plex/indicators/unwatched.png + + 0 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + 313 diff --git a/script.plexmod/resources/skins/Main/1080i/script-plex-video_player.xml b/script.plexmod/resources/skins/Main/1080i/script-plex-video_player.xml index 6885b5188..3dc2de7e4 100644 --- a/script.plexmod/resources/skins/Main/1080i/script-plex-video_player.xml +++ b/script.plexmod/resources/skins/Main/1080i/script-plex-video_player.xml @@ -470,12 +470,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 264 0 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 259 + 0 + + 0 + 0 + 40 + 32 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + false @@ -596,12 +617,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 264 0 35 35 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 267 + 0 + + 0 + 0 + 32 + 32 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 8 + 8 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + false @@ -790,12 +832,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(ListItem.Property(watched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) @@ -934,12 +997,33 @@ - !String.IsEmpty(ListItem.Property(unwatched)) + String.IsEmpty(Window.Property(use_alt_watched)) +!String.IsEmpty(ListItem.Property(unwatched)) 196 0 48 48 - script.plex/indicators/unwatched.png + special://profile/addon_data/script.plexmod/media/unwatched.png + + + !String.IsEmpty(ListItem.Property(use_alt_watched)) + !String.IsEmpty(ListItem.Property(watched)) + 204 + 0 + + 0 + 0 + 40 + 40 + String.IsEmpty(ListItem.Property(hide_aw_bg)) + script.plex/white-square-bl-rounded_w.png + CC000000 + + + 12 + 12 + 16 + 16 + special://profile/addon_data/script.plexmod/media/watched.png + !String.IsEmpty(ListItem.Property(unwatched.count)) diff --git a/script.plexmod/resources/skins/Main/media/script.plex/indicators/watched.png b/script.plexmod/resources/skins/Main/media/script.plex/indicators/watched.png new file mode 100644 index 000000000..f12c806d6 Binary files /dev/null and b/script.plexmod/resources/skins/Main/media/script.plex/indicators/watched.png differ diff --git a/script.plexmod/resources/skins/Main/media/script.plex/white-square-bl-rounded.png b/script.plexmod/resources/skins/Main/media/script.plex/white-square-bl-rounded.png new file mode 100644 index 000000000..1ce032a36 Binary files /dev/null and b/script.plexmod/resources/skins/Main/media/script.plex/white-square-bl-rounded.png differ diff --git a/script.plexmod/resources/skins/Main/media/script.plex/white-square-bl-rounded_w.png b/script.plexmod/resources/skins/Main/media/script.plex/white-square-bl-rounded_w.png new file mode 100644 index 000000000..7ecb50bd4 Binary files /dev/null and b/script.plexmod/resources/skins/Main/media/script.plex/white-square-bl-rounded_w.png differ diff --git a/script.plexmod/resources/skins/Main/media/script.plex/white-square-tr-bl-rounded.png b/script.plexmod/resources/skins/Main/media/script.plex/white-square-tr-bl-rounded.png new file mode 100644 index 000000000..6547d64a8 Binary files /dev/null and b/script.plexmod/resources/skins/Main/media/script.plex/white-square-tr-bl-rounded.png differ diff --git a/script.service.checkpreviousepisode/addon.xml b/script.service.checkpreviousepisode/addon.xml index 0b7638d24..7ff8e12ec 100644 --- a/script.service.checkpreviousepisode/addon.xml +++ b/script.service.checkpreviousepisode/addon.xml @@ -1,5 +1,5 @@ - + @@ -16,9 +16,7 @@ https://forum.kodi.tv/showthread.php?tid=355464 https://kodi.wiki/view/Add-on:XBMC_Check_Previous_Episode https://github.com/bossanova808/script.service.checkpreviousepisode - v0.4.6 - - Ignore shows that have already been decided on (i.e. those with a non-zero resume point) - + v0.4.7 Add Window Property so skinners can dress up the dialog icon.png diff --git a/script.service.checkpreviousepisode/changelog.txt b/script.service.checkpreviousepisode/changelog.txt index 89b340b44..e7869bc3f 100644 --- a/script.service.checkpreviousepisode/changelog.txt +++ b/script.service.checkpreviousepisode/changelog.txt @@ -1,3 +1,6 @@ +v0.4.7 +- Add Window Property so skinners can dress up the dialog + v0.4.6 - Ignore shows that have already been decided on (i.e. those with a non-zero resume point) diff --git a/script.service.checkpreviousepisode/resources/lib/common.py b/script.service.checkpreviousepisode/resources/lib/common.py index a86a1eeec..6e7b9f1de 100644 --- a/script.service.checkpreviousepisode/resources/lib/common.py +++ b/script.service.checkpreviousepisode/resources/lib/common.py @@ -1,11 +1,23 @@ # -*- coding: utf-8 -*- + """ -Handy utility functions for Kodi Addons -By bossanova808 -Free in all senses.... -VERSION 0.2.4 2021-08-10 -(For Kodi Matrix & later) + +Handy utility functions & constants for Kodi Addons +For Kodi Matrix & later +By bossanova808 - freely released +VERSION 0.2.7 2024-04-19 + +Changelog: +0.2.7 - Fix getting the major Kodi version (& change float -> int), as it was failing on e.g. 'RC' being in the string apparently +0.2.6 - (SkinPatcher) - add float KODI_VERSION_FLOAT constant, alongside string KODI_VERSION +0.2.5 - (Skin) - move to storing copy of latest in bossanova808 repo and adding this mini changelog + +For latest version - ALWAYS COPY BACK ANY CHANGES, plus do changelog, and a version & date bump above: +https://github.com/bossanova808/repository.bossanova808/blob/main/latest-common/common.py + + """ + import sys import traceback @@ -27,6 +39,7 @@ LANGUAGE = ADDON.getLocalizedString PROFILE = xbmcvfs.translatePath(ADDON.getAddonInfo('profile')) KODI_VERSION = xbmc.getInfoLabel('System.BuildVersion') +KODI_VERSION_INT = int(KODI_VERSION.split(".")[0]) USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" HOME_WINDOW = xbmcgui.Window(10000) WEATHER_WINDOW = xbmcgui.Window(12600) @@ -51,6 +64,8 @@ """ unit_testing = False + +# Testing outside of Kodi if not xbmc.getUserAgent(): xbmc = None @@ -65,6 +80,7 @@ def log(message, exception_instance=None, level=None): print(f'EXCPT: {traceback.format_exc(exception_instance)}') +# Running inside of Kodi else: def log(message, exception_instance=None, level=xbmc.LOGDEBUG): @@ -192,7 +208,7 @@ def footprints(startup=True): """ if startup: log(f'Starting...', level=xbmc.LOGINFO) - log(f'Kodi Version: {KODI_VERSION}', level=xbmc.LOGINFO) + log(f'Kodi System.BuildVersion: {KODI_VERSION}, which is Kodi major version: {KODI_VERSION_INT}', level=xbmc.LOGINFO) log(f'Addon arguments: {ADDON_ARGUMENTS}', level=xbmc.LOGINFO) else: log(f'Exiting...', level=xbmc.LOGINFO) diff --git a/script.service.checkpreviousepisode/resources/lib/monitor.py b/script.service.checkpreviousepisode/resources/lib/monitor.py index b17d6c6d0..a8f67e03e 100644 --- a/script.service.checkpreviousepisode/resources/lib/monitor.py +++ b/script.service.checkpreviousepisode/resources/lib/monitor.py @@ -15,4 +15,3 @@ def onSettingsChanged(self): def onAbortRequested(self): log('onAbortRequested') - log("Abort Requested") \ No newline at end of file diff --git a/script.service.checkpreviousepisode/resources/lib/player.py b/script.service.checkpreviousepisode/resources/lib/player.py index d0b584dec..d098bfef3 100644 --- a/script.service.checkpreviousepisode/resources/lib/player.py +++ b/script.service.checkpreviousepisode/resources/lib/player.py @@ -125,7 +125,10 @@ def onAVStarted(self): log("Prior episode not watched! -> pausing playback") self.pause() + # Set a window property per Hitcher's request - https://forum.kodi.tv/showthread.php?tid=355464&pid=3191615#pid3191615 + HOME_WINDOW.setProperty("CheckPreviousEpisode", "MissingPreviousEpisode") result = xbmcgui.Dialog().select(LANGUAGE(32020), [LANGUAGE(32021), LANGUAGE(32022), LANGUAGE(32023)], preselect=0) + HOME_WINDOW.setProperty("CheckPreviousEpisode", "") # User has requested we ignore this particular show from now on... if result == 2: diff --git a/script.service.playbackresumer/addon.xml b/script.service.playbackresumer/addon.xml index 0e85d60b6..aaa1fde08 100644 --- a/script.service.playbackresumer/addon.xml +++ b/script.service.playbackresumer/addon.xml @@ -1,5 +1,5 @@ - + @@ -15,9 +15,7 @@ https://github.com/bossanova808/script.service.playbackresumer https://forum.kodi.tv/showthread.php?tid=355383 bossanova808@gmail.com - v2.0.5 - - Fix odd reported bug with resume points - + v2.0.6 - Add support for non-library videos icon.png diff --git a/script.service.playbackresumer/changelog.txt b/script.service.playbackresumer/changelog.txt index a92f823fd..916709d3e 100644 --- a/script.service.playbackresumer/changelog.txt +++ b/script.service.playbackresumer/changelog.txt @@ -1,3 +1,7 @@ +v2.0.6 + +- Add support for non library videos + v2.0.5 - Fix wierd bug with resume points: https://forum.kodi.tv/showthread.php?tid=355383&pid=3163480#pid3163480 diff --git a/script.service.playbackresumer/resources/lib/common.py b/script.service.playbackresumer/resources/lib/common.py index 8e75b7b50..6e7b9f1de 100644 --- a/script.service.playbackresumer/resources/lib/common.py +++ b/script.service.playbackresumer/resources/lib/common.py @@ -1,11 +1,23 @@ # -*- coding: utf-8 -*- + """ -Handy utility functions for Kodi Addons -By bossanova808 -Free in all senses.... -VERSION 0.2.3 2021-06-21 -(For Kodi Matrix & later) + +Handy utility functions & constants for Kodi Addons +For Kodi Matrix & later +By bossanova808 - freely released +VERSION 0.2.7 2024-04-19 + +Changelog: +0.2.7 - Fix getting the major Kodi version (& change float -> int), as it was failing on e.g. 'RC' being in the string apparently +0.2.6 - (SkinPatcher) - add float KODI_VERSION_FLOAT constant, alongside string KODI_VERSION +0.2.5 - (Skin) - move to storing copy of latest in bossanova808 repo and adding this mini changelog + +For latest version - ALWAYS COPY BACK ANY CHANGES, plus do changelog, and a version & date bump above: +https://github.com/bossanova808/repository.bossanova808/blob/main/latest-common/common.py + + """ + import sys import traceback @@ -13,6 +25,8 @@ import xbmcvfs import xbmcgui import xbmcaddon +import json + ADDON = xbmcaddon.Addon() ADDON_NAME = ADDON.getAddonInfo('name') @@ -25,6 +39,7 @@ LANGUAGE = ADDON.getLocalizedString PROFILE = xbmcvfs.translatePath(ADDON.getAddonInfo('profile')) KODI_VERSION = xbmc.getInfoLabel('System.BuildVersion') +KODI_VERSION_INT = int(KODI_VERSION.split(".")[0]) USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" HOME_WINDOW = xbmcgui.Window(10000) WEATHER_WINDOW = xbmcgui.Window(12600) @@ -49,6 +64,8 @@ """ unit_testing = False + +# Testing outside of Kodi if not xbmc.getUserAgent(): xbmc = None @@ -63,6 +80,7 @@ def log(message, exception_instance=None, level=None): print(f'EXCPT: {traceback.format_exc(exception_instance)}') +# Running inside of Kodi else: def log(message, exception_instance=None, level=xbmc.LOGDEBUG): @@ -105,9 +123,9 @@ def set_property(window, name, value=""): def get_property(window, name): """ Return the value of a window property - @param window: - @param name: - @return: + :param window: the Kodi window to get the property value from + :param name: the name of the property to get + :return: the value of the window property """ return window.getProperty(name) @@ -115,32 +133,33 @@ def get_property(window, name): def get_property_as_bool(window, name): """ Return the value of a window property as a boolean - @param window: - @param name: - @return: + :param window: the Kodi window to get the property value from + :param name: the name of the property to get + :return: the value of the window property in boolean form """ return window.getProperty(name).lower() == "true" def send_kodi_json(human_description, json_string): """ - Send a JSON command to Kodi, logging the human description, command, and result returned. + Send a JSON command to Kodi, logging the human description, command, and result as returned. :param human_description: Required. A human sensible description of what the command is aiming to do/retrieve. :param json_string: Required. The json command to send. + :return the json object loaded from the result string """ log(f'KODI JSON RPC command: {human_description} [{json_string}]') result = xbmc.executeJSONRPC(json_string) log(f'KODI JSON RPC result: {result}') - return result + return json.loads(result) def get_setting(setting): """ Helper function to get string type from settings - @param setting: - @return: setting value + :param setting: The addon setting to return + :return: the setting value """ return ADDON.getSetting(setting).strip() @@ -149,8 +168,8 @@ def get_setting_as_bool(setting): """ Helper function to get bool type from settings - @param setting: - @return: setting value as boolen + :param setting: The addon setting to return + :return: the setting value as boolean """ return get_setting(setting).lower() == "true" @@ -159,10 +178,10 @@ def notify(message, notification_type=xbmcgui.NOTIFICATION_ERROR, duration=5000) """ Send a notification to the user via the Kodi GUI - @param message: the message to send - @param notification_type: xbmcgui.NOTIFICATION_ERROR (default), xbmcgui.NOTIFICATION_WARNING, or xbmcgui.NOTIFICATION_INFO - @param duration: time to display notification in milliseconds, default 5000 - @return: None + :param message: the message to send + :param notification_type: xbmcgui.NOTIFICATION_ERROR (default), xbmcgui.NOTIFICATION_WARNING, or xbmcgui.NOTIFICATION_INFO + :param duration: time to display notification in milliseconds, default 5000 + :return: None """ dialog = xbmcgui.Dialog() @@ -171,6 +190,15 @@ def notify(message, notification_type=xbmcgui.NOTIFICATION_ERROR, duration=5000) notification_type, duration) + def is_playback_paused(): + """ + Helper function to return Kodi player state. + (Odd this is needed, it should be a testable state on Player really..) + + :return: boolean indicating player paused state + """ + return bool(xbmc.getCondVisibility("Player.Paused")) + def footprints(startup=True): """ @@ -180,7 +208,7 @@ def footprints(startup=True): """ if startup: log(f'Starting...', level=xbmc.LOGINFO) - log(f'Kodi Version: {KODI_VERSION}', level=xbmc.LOGINFO) + log(f'Kodi System.BuildVersion: {KODI_VERSION}, which is Kodi major version: {KODI_VERSION_INT}', level=xbmc.LOGINFO) log(f'Addon arguments: {ADDON_ARGUMENTS}', level=xbmc.LOGINFO) else: log(f'Exiting...', level=xbmc.LOGINFO) diff --git a/script.service.playbackresumer/resources/lib/player.py b/script.service.playbackresumer/resources/lib/player.py index 89cbff591..e203a4ef3 100644 --- a/script.service.playbackresumer/resources/lib/player.py +++ b/script.service.playbackresumer/resources/lib/player.py @@ -121,9 +121,9 @@ def update_resume_point(self, seconds): # Short circuits - # No library ID or weird library ID - if not Store.library_id or Store.library_id < 0: - log(f"No/invalid library id ({Store.library_id}) for {Store.currently_playing_file_path} so can't set a resume point") + # Weird library ID + if Store.library_id and Store.library_id < 0: + log(f"No/invalid library id ({Store.library_id}) for {Store.currently_playing_file_path}") return # Kodi doing its normal stopping thing if seconds == -2: @@ -150,52 +150,77 @@ def update_resume_point(self, seconds): # Log what we are doing if seconds == 0: - log(f'Removing resume point for {Store.type_of_video} id {Store.library_id}') + log(f'Removing resume point for: {Store.currently_playing_file_path}, type: {Store.type_of_video}, library id: {Store.library_id}') else: - log(f'Setting resume point for {Store.type_of_video} id {Store.library_id} to {seconds} seconds') + log(f'Setting resume point for: {Store.currently_playing_file_path}, type: {Store.type_of_video}, library id: {Store.library_id}, to: {seconds} seconds') # Determine the JSON-RPC setFooDetails method to use and what the library id name is based of the type of video + id_name = None if Store.type_of_video == 'episode': - method = 'SetEpisodeDetails' - get_method = 'GetEpisodeDetails' + method = 'VideoLibrary.SetEpisodeDetails' + get_method = 'VideoLibrary.GetEpisodeDetails' id_name = 'episodeid' elif Store.type_of_video == 'movie': - method = 'SetMovieDetails' - get_method = 'GetMovieDetails' + method = 'VideoLibrary.SetMovieDetails' + get_method = 'VideoLibrary.GetMovieDetails' id_name = 'movieid' elif Store.type_of_video == 'musicvideo': - method = 'SetMusicVideoDetails' - get_method = 'GetMusicVideoDetails' + method = 'VideoLibrary.SetMusicVideoDetails' + get_method = 'VideoLibrary.GetMusicVideoDetails' id_name = 'musicvideoid' else: - log(f'Can\'t update resume point as did not recognise type of video [{Store.type_of_video}]') - return + log(f'Did not recognise type of video [{Store.type_of_video}] - assume non-library video') + method = 'Files.SetFileDetails' + get_method = 'Files.GetFileDetails' - query = json.dumps({ + json_dict = { "jsonrpc": "2.0", "id": "setResumePoint", - "method": "VideoLibrary." + method, - "params": { + "method": method, + } + if id_name: + params = { id_name: Store.library_id, "resume": { "position": seconds, "total": Store.length_of_currently_playing_file } } - }) - send_kodi_json(f'Set resume point to {seconds}, total to {Store.length_of_currently_playing_file}', query) + else: + params = { + "file": Store.currently_playing_file_path, + "media": "video", + "resume": { + "position": seconds, + "total": Store.length_of_currently_playing_file + } + } + + json_dict['params'] = params + query = json.dumps(json_dict) + send_kodi_json(f'Set resume point for: {Store.currently_playing_file_path}, type: {Store.type_of_video}, id: {Store.library_id}, to: {seconds} seconds, total: {Store.length_of_currently_playing_file}', query) - # For debugging - let's retrieve and log the current resume point... - query = json.dumps({ + # For debugging - let's retrieve and log the current resume point to check it was actually set as intended... + json_dict = { "jsonrpc": "2.0", "id": "getResumePoint", - "method": "VideoLibrary." + get_method, - "params": { + "method": get_method, + } + if id_name: + params = { id_name: Store.library_id, "properties": ["resume"], } - }) - send_kodi_json(f'Check new resume point & total for id {Store.library_id}', query) + else: + params = { + "file": Store.currently_playing_file_path, + "media": "video", + "properties": ["resume"], + } + + json_dict['params'] = params + query = json.dumps(json_dict) + send_kodi_json(f'Check new resume point & total for: {Store.currently_playing_file_path}, type: {Store.type_of_video}, id: {Store.library_id}', query) def resume_if_was_playing(self): """ diff --git a/script.service.playbackresumer/resources/lib/store.py b/script.service.playbackresumer/resources/lib/store.py index 6b78e16c9..bc3e354b2 100644 --- a/script.service.playbackresumer/resources/lib/store.py +++ b/script.service.playbackresumer/resources/lib/store.py @@ -24,7 +24,7 @@ class Store: # Store the full path of the currently playing file currently_playing_file_path = '' # What type of video is it? episode, movie, musicvideo - type_of_video = 'unknown' + type_of_video = None # What is the library id of this video, if there is one? library_id = -1 # if the video was paused, at what time was it paused? @@ -194,18 +194,15 @@ def update_current_playing_file_path(filepath): json_response = json.loads(xbmc.executeJSONRPC(json.dumps(query))) log(f'JSON-RPC Files.GetFileDetails response: {json.dumps(json_response)}') - Store.type_of_video = 'unknown' - try: Store.type_of_video = json_response['result']['filedetails']['type'] - except: + except KeyError: Store.library_id = -1 - log(f'Error determining type of video; probably not in Kodi\'s library: {Store.currently_playing_file_path}') + log(f"ERROR: Kodi did not return even an 'unknown' file type for: {Store.currently_playing_file_path}") - if Store.type_of_video == 'episode' or Store.type_of_video == 'movie' or Store.type_of_video == 'musicvideo': + if Store.type_of_video in ['episode', 'movie', 'musicvideo']: Store.library_id = json_response['result']['filedetails']['id'] - log(f'The library id for this {Store.type_of_video} is {Store.library_id}') else: Store.library_id = None - log(f'Unsupported type of video {Store.type_of_video} for {Store.currently_playing_file_path}') + log(f'Kodi type: {Store.type_of_video}, library id: {Store.library_id}') \ No newline at end of file diff --git a/script.trakt/resources/language/resource.language.ar_sa/strings.po b/script.trakt/resources/language/resource.language.ar_sa/strings.po index 0c38005b5..ee8f80f81 100644 --- a/script.trakt/resources/language/resource.language.ar_sa/strings.po +++ b/script.trakt/resources/language/resource.language.ar_sa/strings.po @@ -5,17 +5,16 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2024-01-23 10:13+0000\n" -"Last-Translator: Christian Gade \n" -"Language-Team: Arabic (Saudi Arabia) \n" -"Language: ar_sa\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: Arabic (http://www.transifex.com/projects/p/xbmc-addons/language/ar/)\n" +"Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "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 5.3\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 && n%100<=99 ? 4 : 5;\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -25,7 +24,6 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" msgstr "عام" @@ -37,7 +35,7 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "التقييم" msgctxt "#32005" msgid "Rate Movie after watching" @@ -140,7 +138,7 @@ msgstr "" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr ":عادل" msgctxt "#32034" msgid "Good" diff --git a/script.trakt/resources/language/resource.language.en_au/strings.po b/script.trakt/resources/language/resource.language.en_au/strings.po index 783e06180..9b0fb17b0 100644 --- a/script.trakt/resources/language/resource.language.en_au/strings.po +++ b/script.trakt/resources/language/resource.language.en_au/strings.po @@ -8,13 +8,13 @@ msgstr "" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: en_au\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: English (Australia) (http://www.transifex.com/projects/p/xbmc-addons/language/en_AU/)\n" +"Language: en_AU\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" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,10 +24,9 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "General" # empty strings from id 32001 to 32002 msgctxt "#32003" @@ -36,7 +35,7 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Rating" msgctxt "#32005" msgid "Rate Movie after watching" @@ -106,7 +105,7 @@ msgstr "" msgctxt "#32024" msgid "Error" -msgstr "" +msgstr "Error" # empty string with id 32025 msgctxt "#32026" @@ -139,7 +138,7 @@ msgstr "" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Fair" msgctxt "#32034" msgid "Good" @@ -191,7 +190,7 @@ msgstr "" msgctxt "#32046" msgid "Movies" -msgstr "" +msgstr "Movies" msgctxt "#32047" msgid "Add new movies to Trakt collection" @@ -223,7 +222,7 @@ msgstr "" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Service" msgctxt "#32055" msgid "Sync collection on library update or cleaning" @@ -635,7 +634,7 @@ msgstr "" msgctxt "#32163" msgid "User" -msgstr "" +msgstr "User" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" diff --git a/script.trakt/resources/language/resource.language.en_nz/strings.po b/script.trakt/resources/language/resource.language.en_nz/strings.po index a7a99320c..ca9e9482a 100644 --- a/script.trakt/resources/language/resource.language.en_nz/strings.po +++ b/script.trakt/resources/language/resource.language.en_nz/strings.po @@ -5,17 +5,16 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2024-01-23 10:13+0000\n" -"Last-Translator: Christian Gade \n" -"Language-Team: English (New Zealand) \n" -"Language: en_nz\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: English (New Zealand) (http://www.transifex.com/projects/p/xbmc-addons/language/en_NZ/)\n" +"Language: en_NZ\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 5.3\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -25,7 +24,6 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" msgstr "General" @@ -37,158 +35,155 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Rating" msgctxt "#32005" msgid "Rate Movie after watching" -msgstr "" +msgstr "Rate Movie after watching" msgctxt "#32006" msgid "Rate TV show Episode after watching" -msgstr "" +msgstr "Rate TV show Episode after watching" msgctxt "#32008" msgid "Minimum percent watched to display rating dialog" -msgstr "" +msgstr "Minimum percent watched to display rating dialogue" msgctxt "#32009" msgid "Allow re-rating of media" -msgstr "" +msgstr "Allow re-rating of media" msgctxt "#32010" msgid "Default rating" -msgstr "" +msgstr "Default rating" -# Scrobbling Settings msgctxt "#32011" msgid "Scrobbling" -msgstr "" +msgstr "Scrobbling" msgctxt "#32012" msgid "Scrobble movies" -msgstr "" +msgstr "Scrobble movies" msgctxt "#32013" msgid "Scrobble TV show episodes" -msgstr "" +msgstr "Scrobble TV show episodes" msgctxt "#32014" msgid "Show notification on scrobble" -msgstr "" +msgstr "Show notification on scrobble" msgctxt "#32015" msgid "Trakt - Scrobbled successfully" -msgstr "" +msgstr "Trakt - Scrobbled successfully" msgctxt "#32016" msgid "Exclusions" -msgstr "" +msgstr "Exclusions" msgctxt "#32017" msgid "Exclude Live TV" -msgstr "" +msgstr "Exclude Live TV" msgctxt "#32018" msgid "Exclude HTTP sources" -msgstr "" +msgstr "Exclude HTTP sources" msgctxt "#32019" msgid "Exclude path" -msgstr "" +msgstr "Exclude path" msgctxt "#32020" msgid "Folder's path (including subfolders)" -msgstr "" +msgstr "Folder's path (including subfolders)" -# empty strings from id 32021 to 32022 msgctxt "#32023" msgid "Can not connect to Trakt" -msgstr "" +msgstr "Can not connect to Trakt" msgctxt "#32024" msgid "Error" msgstr "Error" -# empty string with id 32025 msgctxt "#32026" msgid "What Did You Think?" -msgstr "" +msgstr "What Did You Think?" msgctxt "#32027" msgid "Totally Ninja!" -msgstr "" +msgstr "Totally Ninja!" msgctxt "#32028" msgid "Weak Sauce :(" -msgstr "" +msgstr "Weak Sauce :(" msgctxt "#32029" msgid "Terrible" -msgstr "" +msgstr "Terrible" msgctxt "#32030" msgid "Bad" -msgstr "" +msgstr "Bad" msgctxt "#32031" msgid "Poor" -msgstr "" +msgstr "Poor" msgctxt "#32032" msgid "Meh" -msgstr "" +msgstr "Meh" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Fair" msgctxt "#32034" msgid "Good" -msgstr "" +msgstr "Good" msgctxt "#32035" msgid "Great" -msgstr "" +msgstr "Great" msgctxt "#32036" msgid "Superb" -msgstr "" +msgstr "Superb" msgctxt "#32037" msgid "Unrate this movie" -msgstr "" +msgstr "Unrate this movie" msgctxt "#32038" msgid "Unrate this show" -msgstr "" +msgstr "Unrate this show" msgctxt "#32039" msgid "Unrate this episode" -msgstr "" +msgstr "Unrate this episode" msgctxt "#32040" msgid "Trakt - Rating submitted successfully" -msgstr "" +msgstr "Trakt - Rating submitted successfully" msgctxt "#32041" msgid "Trakt - Already rated" -msgstr "" +msgstr "Trakt - Already rated" msgctxt "#32042" msgid "Trakt - Unrated successfully" -msgstr "" +msgstr "Trakt - Unrated successfully" msgctxt "#32043" msgid "Trakt - Already has the same rating" -msgstr "" +msgstr "Trakt - Already has the same rating" msgctxt "#32044" msgid "Trakt - Problem submitting rating" -msgstr "" +msgstr "Trakt - Problem submitting rating" msgctxt "#32045" msgid "Synchronize" -msgstr "" +msgstr "Synchronise" msgctxt "#32046" msgid "Movies" @@ -196,434 +191,431 @@ msgstr "Movies" msgctxt "#32047" msgid "Add new movies to Trakt collection" -msgstr "" +msgstr "Add new movies to Trakt collection" msgctxt "#32048" msgid "Add watched movies to Trakt history" -msgstr "" +msgstr "Add watched movies to Trakt history" msgctxt "#32049" msgid "Mark movies from Trakt history as watched in Kodi" -msgstr "" +msgstr "Mark movies from Trakt history as watched in Kodi" msgctxt "#32050" msgid "TV Episodes" -msgstr "" +msgstr "TV Episodes" msgctxt "#32051" msgid "Add new TV episodes to Trakt collection" -msgstr "" +msgstr "Add new TV episodes to Trakt collection" msgctxt "#32052" msgid "Add watched TV episodes to Trakt history" -msgstr "" +msgstr "Add watched TV episodes to Trakt history" msgctxt "#32053" msgid "Mark TV episodes from Trakt history as watched in Kodi" -msgstr "" +msgstr "Mark TV episodes from Trakt history as watched in Kodi" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Service" msgctxt "#32055" msgid "Sync collection on library update or cleaning" -msgstr "" +msgstr "Sync collection on library update or cleaning" msgctxt "#32056" msgid "Show sync notifications" -msgstr "" +msgstr "Show sync notifications" msgctxt "#32057" msgid "Remove deleted movies from Trakt collection" -msgstr "" +msgstr "Remove deleted movies from Trakt collection" msgctxt "#32058" msgid "Remove deleted TV episodes from Trakt collection" -msgstr "" +msgstr "Remove deleted TV episodes from Trakt collection" -# empty string with id 32059 msgctxt "#32060" msgid "Hide notifications during playback" -msgstr "" +msgstr "Hide notifications during playback" msgctxt "#32061" msgid "Sync started" -msgstr "" +msgstr "Sync started" msgctxt "#32062" msgid "Sync complete" -msgstr "" +msgstr "Sync complete" msgctxt "#32063" msgid "%i movie(s) will be added to Trakt collection" -msgstr "" +msgstr "%i movie(s) will be added to Trakt collection" msgctxt "#32064" msgid "%i movie playcount(s) will be updated on Trakt" -msgstr "" +msgstr "%i movie playcount(s) will be updated on Trakt" msgctxt "#32065" msgid "%i movie(s) playcount will be updated in Kodi" -msgstr "" +msgstr "%i movie(s) playcount will be updated in Kodi" msgctxt "#32066" msgid "Movie Sync Complete" -msgstr "" +msgstr "Movie Sync Complete" msgctxt "#32067" msgid "Going to add %i show(s) to Trakt collection" -msgstr "" +msgstr "Going to add %i show(s) to Trakt collection" msgctxt "#32068" msgid "Checking for episodes missing from Trakt collection" -msgstr "" +msgstr "Checking for episodes missing from Trakt collection" msgctxt "#32069" msgid "%i of %i show(s) have episodes added to Trakt collection" -msgstr "" +msgstr "%i of %i show(s) have episodes added to Trakt collection" msgctxt "#32070" msgid "Going to update %i show(s) missing watched status" -msgstr "" +msgstr "Going to update %i show(s) missing watched status" msgctxt "#32071" msgid "Checking watched episodes on Trakt" -msgstr "" +msgstr "Checking watched episodes on Trakt" msgctxt "#32072" msgid "%i show(s) had missing watched status" -msgstr "" +msgstr "%i show(s) had missing watched status" msgctxt "#32073" msgid "%i episodes are being updated" -msgstr "" +msgstr "%i episodes are being updated" msgctxt "#32074" msgid "Checking watched episodes on Kodi" -msgstr "" +msgstr "Checking watched episodes on Kodi" msgctxt "#32075" msgid "Episode Sync Complete" -msgstr "" +msgstr "Episode Sync Complete" msgctxt "#32076" msgid "%i movie(s) will be removed from Trakt collection" -msgstr "" +msgstr "%i movie(s) will be removed from Trakt collection" msgctxt "#32077" msgid "Cleaning Trakt TV show collection" -msgstr "" +msgstr "Cleaning Trakt TV show collection" msgctxt "#32078" msgid "episodes are being removed" -msgstr "" +msgstr "episodes are being removed" msgctxt "#32079" msgid "Loading movies from Kodi" -msgstr "" +msgstr "Loading movies from Kodi" msgctxt "#32080" msgid "Movies loaded from Kodi" -msgstr "" +msgstr "Movies loaded from Kodi" msgctxt "#32081" msgid "Retrieving movie collection from Trakt" -msgstr "" +msgstr "Retrieving movie collection from Trakt" msgctxt "#32082" msgid "Retrieving watched movies from Trakt" -msgstr "" +msgstr "Retrieving watched movies from Trakt" msgctxt "#32083" msgid "Retrieved movie data from Trakt" -msgstr "" +msgstr "Retrieved movie data from Trakt" msgctxt "#32084" msgid "Trakt movie collection is up to date, no movies to add" -msgstr "" +msgstr "Trakt movie collection is up to date, no movies to add" msgctxt "#32085" msgid "%i movie(s) were added to your Trakt collection" -msgstr "" +msgstr "%i movie(s) were added to your Trakt collection" msgctxt "#32086" msgid "Trakt movie playcounts are up to date" -msgstr "" +msgstr "Trakt movie playcounts are up to date" msgctxt "#32087" msgid "Playcounts updated for %i movie(s) on Trakt" -msgstr "" +msgstr "Playcounts updated for %i movie(s) on Trakt" msgctxt "#32088" msgid "Kodi movie playcounts are up to date" -msgstr "" +msgstr "Kodi movie playcounts are up to date" msgctxt "#32089" msgid "Updating %i of %i movie playcount(s) in Kodi" -msgstr "" +msgstr "Updating %i of %i movie playcount(s) in Kodi" msgctxt "#32090" msgid "Playcounts updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Playcounts updated for %i movie(s) in Kodi" msgctxt "#32091" msgid "Trakt movie collection is up to date, no movies removed" -msgstr "" +msgstr "Trakt movie collection is up to date, no movies removed" msgctxt "#32092" msgid "%i movie(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i movie(s) were removed from your Trakt collection" msgctxt "#32093" msgid "Updating %i of %i movie playcount(s) on Trakt" -msgstr "" +msgstr "Updating %i of %i movie playcount(s) on Trakt" msgctxt "#32094" msgid "Loading episode data from Kodi" -msgstr "" +msgstr "Loading episode data from Kodi" msgctxt "#32095" msgid "Loading shows from Kodi" -msgstr "" +msgstr "Loading shows from Kodi" msgctxt "#32096" msgid "Shows loaded from Kodi" -msgstr "" +msgstr "Shows loaded from Kodi" msgctxt "#32097" msgid "Parsing %i of %i episode data from Kodi" -msgstr "" +msgstr "Parsing %i of %i episode data from Kodi" msgctxt "#32098" msgid "Loaded episode data from Kodi" -msgstr "" +msgstr "Loaded episode data from Kodi" msgctxt "#32099" msgid "Loading episode data from Trakt" -msgstr "" +msgstr "Loading episode data from Trakt" msgctxt "#32100" msgid "Retrieving episode collection from Trakt" -msgstr "" +msgstr "Retrieving episode collection from Trakt" msgctxt "#32101" msgid "Retrieving watched episodes from Trakt" -msgstr "" +msgstr "Retrieving watched episodes from Trakt" msgctxt "#32102" msgid "Parsing episode data %i of %i from Trakt" -msgstr "" +msgstr "Parsing episode data %i of %i from Trakt" msgctxt "#32103" msgid "Retrieved episode data from Trakt" -msgstr "" +msgstr "Retrieved episode data from Trakt" msgctxt "#32104" msgid "Trakt episode collection is up to date, no episodes to add" -msgstr "" +msgstr "Trakt episode collection is up to date, no episodes to add" msgctxt "#32105" msgid "%i episode(s) were added to your Trakt collection" -msgstr "" +msgstr "%i episode(s) were added to your Trakt collection" msgctxt "#32106" msgid "Trakt episode playcounts are up to date" -msgstr "" +msgstr "Trakt episode playcounts are up to date" msgctxt "#32107" msgid "Kodi episode playcounts are up to date" -msgstr "" +msgstr "Kodi episode playcounts are up to date" msgctxt "#32108" msgid "Updating %i of %i episode playcount(s) in Kodi" -msgstr "" +msgstr "Updating %i of %i episode playcount(s) in Kodi" msgctxt "#32109" msgid "Playcounts updated for %i show(s) in Kodi" -msgstr "" +msgstr "Playcounts updated for %i show(s) in Kodi" msgctxt "#32110" msgid "Trakt episode collection is clean, no episodes to remove" -msgstr "" +msgstr "Trakt episode collection is clean, no episodes to remove" msgctxt "#32111" msgid "%i episode(s) are being removed from your Trakt collection" -msgstr "" +msgstr "%i episode(s) are being removed from your Trakt collection" msgctxt "#32112" msgid "%i episode(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i episode(s) were removed from your Trakt collection" msgctxt "#32113" msgid "Trakt - Marked as watched" -msgstr "" +msgstr "Trakt - Marked as watched" msgctxt "#32114" msgid "Trakt - Failed marking as watched" -msgstr "" +msgstr "Trakt - Failed marking as watched" msgctxt "#32115" msgid "%d episode(s) of '%s'" -msgstr "" +msgstr "%d episode(s) of '%s'" msgctxt "#32116" msgid "Enable debug mode" -msgstr "" +msgstr "Enable debug mode" msgctxt "#32117" msgid "Sync movie playback progress to Kodi" -msgstr "" +msgstr "Sync movie playback progress to Kodi" msgctxt "#32118" msgid "Sync episode playback progress to Kodi" -msgstr "" +msgstr "Sync episode playback progress to Kodi" msgctxt "#32119" msgid "Retrieving episode playback progress from Trakt" -msgstr "" +msgstr "Retrieving episode playback progress from Trakt" msgctxt "#32120" msgid "Parsing episode playback progress %i of %i from Trakt" -msgstr "" +msgstr "Parsing episode playback progress %i of %i from Trakt" msgctxt "#32121" msgid "Retrieved episode playback progress from Trakt" -msgstr "" +msgstr "Retrieved episode playback progress from Trakt" msgctxt "#32122" msgid "Retrieving movie playback progress from Trakt" -msgstr "" +msgstr "Retrieving movie playback progress from Trakt" msgctxt "#32123" msgid "Parsing movie playback progress %i of %i from Trakt" -msgstr "" +msgstr "Parsing movie playback progress %i of %i from Trakt" msgctxt "#32124" msgid "Retrieved movie playback progress from Trakt" -msgstr "" +msgstr "Retrieved movie playback progress from Trakt" msgctxt "#32125" msgid "Kodi movie playback progress is up to date" -msgstr "" +msgstr "Kodi movie playback progress is up to date" msgctxt "#32126" msgid "%i movie(s) playback progress will be updated in Kodi" -msgstr "" +msgstr "%i movie(s) playback progress will be updated in Kodi" msgctxt "#32127" msgid "Updating %i of %i movie(s) playback progress in Kodi" -msgstr "" +msgstr "Updating %i of %i movie(s) playback progress in Kodi" msgctxt "#32128" msgid "Playback progress updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Playback progress updated for %i movie(s) in Kodi" msgctxt "#32129" msgid "Kodi episode playback progress is up to date" -msgstr "" +msgstr "Kodi episode playback progress is up to date" msgctxt "#32130" msgid "Updating %i of %i episode(s) playback progress in Kodi" -msgstr "" +msgstr "Updating %i of %i episode(s) playback progress in Kodi" msgctxt "#32131" msgid "Playback progress updated for %i episode(s) in Kodi" -msgstr "" +msgstr "Playback progress updated for %i episode(s) in Kodi" msgctxt "#32132" msgid "Unrate this season" -msgstr "" +msgstr "Unrate this season" msgctxt "#32133" msgid "Manage Movie's Lists" -msgstr "" +msgstr "Manage Movie's Lists" msgctxt "#32134" msgid "Manage Show's Lists" -msgstr "" +msgstr "Manage Show's Lists" msgctxt "#32135" msgid "Remove from Watchlist" -msgstr "" +msgstr "Remove from Watchlist" msgctxt "#32136" msgid "Add to watchlist" -msgstr "" +msgstr "Add to watchlist" msgctxt "#32137" msgid "Rate this movie" -msgstr "" +msgstr "Rate this movie" msgctxt "#32138" msgid "Rate this show" -msgstr "" +msgstr "Rate this show" msgctxt "#32139" msgid "Rate this episode" -msgstr "" +msgstr "Rate this episode" msgctxt "#32140" msgid "Toggle watched" -msgstr "" +msgstr "Toggle watched" msgctxt "#32141" msgid "Manage all lists" -msgstr "" +msgstr "Manage all lists" msgctxt "#32142" msgid "Update all tags" -msgstr "" +msgstr "Update all tags" msgctxt "#32143" msgid "Synchronize library" -msgstr "" +msgstr "Synchronise library" msgctxt "#32144" msgid "How do I authorize the trakt addon to access my trakt.tv account?" -msgstr "" +msgstr "How do I authorise the trakt addon to access my trakt.tv account?" -# empty strings from id 32145 to 32146 msgctxt "#32147" msgid "Trakt.tv PIN Authorization Failed" -msgstr "" +msgstr "Trakt.tv PIN Authorisation Failed" -# empty string with id 32148 msgctxt "#32149" msgid "Rate this Season" -msgstr "" +msgstr "Rate this Season" msgctxt "#32150" msgid "You will be reminded in 24 hours" -msgstr "" +msgstr "You will be reminded in 24 hours" msgctxt "#32151" msgid "Use Addon Settings later if you change your mind" -msgstr "" +msgstr "Use Addon Settings later if you change your mind" msgctxt "#32152" msgid "Trakt Authorization Complete" -msgstr "" +msgstr "Trakt Authorisation Complete" msgctxt "#32153" msgid "Trakt Account Authorization" -msgstr "" +msgstr "Trakt Account Authorisation" msgctxt "#32154" msgid "Authorize" -msgstr "" +msgstr "Authorise" msgctxt "#32155" msgid "Remind Me Later" -msgstr "" +msgstr "Remind Me Later" msgctxt "#32156" msgid "No Thanks" -msgstr "" +msgstr "No Thanks" msgctxt "#32157" msgid "Account Authorization" -msgstr "" +msgstr "Account Authorisation" # empty string with id 32158 msgctxt "#32159" @@ -632,23 +624,23 @@ msgstr "" msgctxt "#32162" msgid "The trakt addon CAN NOT be used without authorizing it to access your trakt.tv account." -msgstr "" +msgstr "The trakt addon CAN NOT be used without authorising it to access your trakt.tv account." msgctxt "#32163" msgid "User" -msgstr "" +msgstr "User" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" -msgstr "" +msgstr "Fallback to Title/Year matching if necessary" msgctxt "#32165" msgid "Trakt - Added to watchlist" -msgstr "" +msgstr "Trakt - Added to watchlist" msgctxt "#32166" msgid "Trakt - Failed adding to watchlist" -msgstr "" +msgstr "Trakt - Failed adding to watchlist" msgctxt "#32167" msgid "Offset scrobble start by X minutes" @@ -769,3 +761,19 @@ msgstr "" msgctxt "#42191" msgid "Optional password needed to authenticate with the proxy." msgstr "" + +#~ msgctxt "#32003" +#~ msgid "Startup Delay" +#~ msgstr "Startup Delay" + +#~ msgctxt "#32159" +#~ msgid "Visit {0} or scan the QR Code below." +#~ msgstr "Visit {0} or scan the QR Code below." + +#~ msgctxt "#32160" +#~ msgid "Authorize the trakt addon to access your account." +#~ msgstr "Authorise the trakt addon to access your account." + +#~ msgctxt "#32161" +#~ msgid "Enter the PIN provided in the box below." +#~ msgstr "Enter the PIN provided in the box below." diff --git a/script.trakt/resources/language/resource.language.en_us/strings.po b/script.trakt/resources/language/resource.language.en_us/strings.po index 3f4f53c63..6b8b8e16a 100644 --- a/script.trakt/resources/language/resource.language.en_us/strings.po +++ b/script.trakt/resources/language/resource.language.en_us/strings.po @@ -8,13 +8,13 @@ msgstr "" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: en_us\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: English (US) (http://www.transifex.com/projects/p/xbmc-addons/language/en_US/)\n" +"Language: en_US\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" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,10 +24,9 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "General" # empty strings from id 32001 to 32002 msgctxt "#32003" @@ -36,593 +35,587 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Rating" msgctxt "#32005" msgid "Rate Movie after watching" -msgstr "" +msgstr "Rate Movie after watching" msgctxt "#32006" msgid "Rate TV show Episode after watching" -msgstr "" +msgstr "Rate TV show Episode after watching" msgctxt "#32008" msgid "Minimum percent watched to display rating dialog" -msgstr "" +msgstr "Minimum percent watched to display rating dialog" msgctxt "#32009" msgid "Allow re-rating of media" -msgstr "" +msgstr "Allow re-rating of media" msgctxt "#32010" msgid "Default rating" -msgstr "" +msgstr "Default rating" -# Scrobbling Settings msgctxt "#32011" msgid "Scrobbling" -msgstr "" +msgstr "Scrobbling" msgctxt "#32012" msgid "Scrobble movies" -msgstr "" +msgstr "Scrobble movies" msgctxt "#32013" msgid "Scrobble TV show episodes" -msgstr "" +msgstr "Scrobble TV show episodes" msgctxt "#32014" msgid "Show notification on scrobble" -msgstr "" +msgstr "Show notification on scrobble" msgctxt "#32015" msgid "Trakt - Scrobbled successfully" -msgstr "" +msgstr "Trakt - Scrobbled successfully" msgctxt "#32016" msgid "Exclusions" -msgstr "" +msgstr "Exclusions" msgctxt "#32017" msgid "Exclude Live TV" -msgstr "" +msgstr "Exclude Live TV" msgctxt "#32018" msgid "Exclude HTTP sources" -msgstr "" +msgstr "Exclude HTTP sources" msgctxt "#32019" msgid "Exclude path" -msgstr "" +msgstr "Exclude path" msgctxt "#32020" msgid "Folder's path (including subfolders)" -msgstr "" +msgstr "Folder's path (including subfolders)" -# empty strings from id 32021 to 32022 msgctxt "#32023" msgid "Can not connect to Trakt" -msgstr "" +msgstr "Can not connect to Trakt" msgctxt "#32024" msgid "Error" -msgstr "" +msgstr "Error" -# empty string with id 32025 msgctxt "#32026" msgid "What Did You Think?" -msgstr "" +msgstr "What Did You Think?" msgctxt "#32027" msgid "Totally Ninja!" -msgstr "" +msgstr "Totally Ninja!" msgctxt "#32028" msgid "Weak Sauce :(" -msgstr "" +msgstr "Weak Sauce :(" msgctxt "#32029" msgid "Terrible" -msgstr "" +msgstr "Terrible" msgctxt "#32030" msgid "Bad" -msgstr "" +msgstr "Bad" msgctxt "#32031" msgid "Poor" -msgstr "" +msgstr "Poor" msgctxt "#32032" msgid "Meh" -msgstr "" +msgstr "Meh" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Fair" msgctxt "#32034" msgid "Good" -msgstr "" +msgstr "Good" msgctxt "#32035" msgid "Great" -msgstr "" +msgstr "Great" msgctxt "#32036" msgid "Superb" -msgstr "" +msgstr "Superb" msgctxt "#32037" msgid "Unrate this movie" -msgstr "" +msgstr "Unrate this movie" msgctxt "#32038" msgid "Unrate this show" -msgstr "" +msgstr "Unrate this show" msgctxt "#32039" msgid "Unrate this episode" -msgstr "" +msgstr "Unrate this episode" msgctxt "#32040" msgid "Trakt - Rating submitted successfully" -msgstr "" +msgstr "Trakt - Rating submitted successfully" msgctxt "#32041" msgid "Trakt - Already rated" -msgstr "" +msgstr "Trakt - Already rated" msgctxt "#32042" msgid "Trakt - Unrated successfully" -msgstr "" +msgstr "Trakt - Unrated successfully" msgctxt "#32043" msgid "Trakt - Already has the same rating" -msgstr "" +msgstr "Trakt - Already has the same rating" msgctxt "#32044" msgid "Trakt - Problem submitting rating" -msgstr "" +msgstr "Trakt - Problem submitting rating" msgctxt "#32045" msgid "Synchronize" -msgstr "" +msgstr "Synchronize" msgctxt "#32046" msgid "Movies" -msgstr "" +msgstr "Movies" msgctxt "#32047" msgid "Add new movies to Trakt collection" -msgstr "" +msgstr "Add new movies to Trakt collection" msgctxt "#32048" msgid "Add watched movies to Trakt history" -msgstr "" +msgstr "Add watched movies to Trakt history" msgctxt "#32049" msgid "Mark movies from Trakt history as watched in Kodi" -msgstr "" +msgstr "Mark movies from Trakt history as watched in Kodi" msgctxt "#32050" msgid "TV Episodes" -msgstr "" +msgstr "TV Episodes" msgctxt "#32051" msgid "Add new TV episodes to Trakt collection" -msgstr "" +msgstr "Add new TV episodes to Trakt collection" msgctxt "#32052" msgid "Add watched TV episodes to Trakt history" -msgstr "" +msgstr "Add watched TV episodes to Trakt history" msgctxt "#32053" msgid "Mark TV episodes from Trakt history as watched in Kodi" -msgstr "" +msgstr "Mark TV episodes from Trakt history as watched in Kodi" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Service" msgctxt "#32055" msgid "Sync collection on library update or cleaning" -msgstr "" +msgstr "Sync collection on library update or cleaning" msgctxt "#32056" msgid "Show sync notifications" -msgstr "" +msgstr "Show sync notifications" msgctxt "#32057" msgid "Remove deleted movies from Trakt collection" -msgstr "" +msgstr "Remove deleted movies from Trakt collection" msgctxt "#32058" msgid "Remove deleted TV episodes from Trakt collection" -msgstr "" +msgstr "Remove deleted TV episodes from Trakt collection" -# empty string with id 32059 msgctxt "#32060" msgid "Hide notifications during playback" -msgstr "" +msgstr "Hide notifications during playback" msgctxt "#32061" msgid "Sync started" -msgstr "" +msgstr "Sync started" msgctxt "#32062" msgid "Sync complete" -msgstr "" +msgstr "Sync complete" msgctxt "#32063" msgid "%i movie(s) will be added to Trakt collection" -msgstr "" +msgstr "%i movie(s) will be added to Trakt collection" msgctxt "#32064" msgid "%i movie playcount(s) will be updated on Trakt" -msgstr "" +msgstr "%i movie playcount(s) will be updated on Trakt" msgctxt "#32065" msgid "%i movie(s) playcount will be updated in Kodi" -msgstr "" +msgstr "%i movie(s) playcount will be updated in Kodi" msgctxt "#32066" msgid "Movie Sync Complete" -msgstr "" +msgstr "Movie Sync Complete" msgctxt "#32067" msgid "Going to add %i show(s) to Trakt collection" -msgstr "" +msgstr "Going to add %i show(s) to Trakt collection" msgctxt "#32068" msgid "Checking for episodes missing from Trakt collection" -msgstr "" +msgstr "Checking for episodes missing from Trakt collection" msgctxt "#32069" msgid "%i of %i show(s) have episodes added to Trakt collection" -msgstr "" +msgstr "%i of %i show(s) have episodes added to Trakt collection" msgctxt "#32070" msgid "Going to update %i show(s) missing watched status" -msgstr "" +msgstr "Going to update %i show(s) missing watched status" msgctxt "#32071" msgid "Checking watched episodes on Trakt" -msgstr "" +msgstr "Checking watched episodes on Trakt" msgctxt "#32072" msgid "%i show(s) had missing watched status" -msgstr "" +msgstr "%i show(s) had missing watched status" msgctxt "#32073" msgid "%i episodes are being updated" -msgstr "" +msgstr "%i episodes are being updated" msgctxt "#32074" msgid "Checking watched episodes on Kodi" -msgstr "" +msgstr "Checking watched episodes on Kodi" msgctxt "#32075" msgid "Episode Sync Complete" -msgstr "" +msgstr "Episode Sync Complete" msgctxt "#32076" msgid "%i movie(s) will be removed from Trakt collection" -msgstr "" +msgstr "%i movie(s) will be removed from Trakt collection" msgctxt "#32077" msgid "Cleaning Trakt TV show collection" -msgstr "" +msgstr "Cleaning Trakt TV show collection" msgctxt "#32078" msgid "episodes are being removed" -msgstr "" +msgstr "episodes are being removed" msgctxt "#32079" msgid "Loading movies from Kodi" -msgstr "" +msgstr "Loading movies from Kodi" msgctxt "#32080" msgid "Movies loaded from Kodi" -msgstr "" +msgstr "Movies loaded from Kodi" msgctxt "#32081" msgid "Retrieving movie collection from Trakt" -msgstr "" +msgstr "Retrieving movie collection from Trakt" msgctxt "#32082" msgid "Retrieving watched movies from Trakt" -msgstr "" +msgstr "Retrieving watched movies from Trakt" msgctxt "#32083" msgid "Retrieved movie data from Trakt" -msgstr "" +msgstr "Retrieved movie data from Trakt" msgctxt "#32084" msgid "Trakt movie collection is up to date, no movies to add" -msgstr "" +msgstr "Trakt movie collection is up to date, no movies to add" msgctxt "#32085" msgid "%i movie(s) were added to your Trakt collection" -msgstr "" +msgstr "%i movie(s) were added to your Trakt collection" msgctxt "#32086" msgid "Trakt movie playcounts are up to date" -msgstr "" +msgstr "Trakt movie playcounts are up to date" msgctxt "#32087" msgid "Playcounts updated for %i movie(s) on Trakt" -msgstr "" +msgstr "Playcounts updated for %i movie(s) on Trakt" msgctxt "#32088" msgid "Kodi movie playcounts are up to date" -msgstr "" +msgstr "Kodi movie playcounts are up to date" msgctxt "#32089" msgid "Updating %i of %i movie playcount(s) in Kodi" -msgstr "" +msgstr "Updating %i of %i movie playcount(s) in Kodi" msgctxt "#32090" msgid "Playcounts updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Playcounts updated for %i movie(s) in Kodi" msgctxt "#32091" msgid "Trakt movie collection is up to date, no movies removed" -msgstr "" +msgstr "Trakt movie collection is up to date, no movies removed" msgctxt "#32092" msgid "%i movie(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i movie(s) were removed from your Trakt collection" msgctxt "#32093" msgid "Updating %i of %i movie playcount(s) on Trakt" -msgstr "" +msgstr "Updating %i of %i movie playcount(s) on Trakt" msgctxt "#32094" msgid "Loading episode data from Kodi" -msgstr "" +msgstr "Loading episode data from Kodi" msgctxt "#32095" msgid "Loading shows from Kodi" -msgstr "" +msgstr "Loading shows from Kodi" msgctxt "#32096" msgid "Shows loaded from Kodi" -msgstr "" +msgstr "Shows loaded from Kodi" msgctxt "#32097" msgid "Parsing %i of %i episode data from Kodi" -msgstr "" +msgstr "Parsing %i of %i episode data from Kodi" msgctxt "#32098" msgid "Loaded episode data from Kodi" -msgstr "" +msgstr "Loaded episode data from Kodi" msgctxt "#32099" msgid "Loading episode data from Trakt" -msgstr "" +msgstr "Loading episode data from Trakt" msgctxt "#32100" msgid "Retrieving episode collection from Trakt" -msgstr "" +msgstr "Retrieving episode collection from Trakt" msgctxt "#32101" msgid "Retrieving watched episodes from Trakt" -msgstr "" +msgstr "Retrieving watched episodes from Trakt" msgctxt "#32102" msgid "Parsing episode data %i of %i from Trakt" -msgstr "" +msgstr "Parsing episode data %i of %i from Trakt" msgctxt "#32103" msgid "Retrieved episode data from Trakt" -msgstr "" +msgstr "Retrieved episode data from Trakt" msgctxt "#32104" msgid "Trakt episode collection is up to date, no episodes to add" -msgstr "" +msgstr "Trakt episode collection is up to date, no episodes to add" msgctxt "#32105" msgid "%i episode(s) were added to your Trakt collection" -msgstr "" +msgstr "%i episode(s) were added to your Trakt collection" msgctxt "#32106" msgid "Trakt episode playcounts are up to date" -msgstr "" +msgstr "Trakt episode playcounts are up to date" msgctxt "#32107" msgid "Kodi episode playcounts are up to date" -msgstr "" +msgstr "Kodi episode playcounts are up to date" msgctxt "#32108" msgid "Updating %i of %i episode playcount(s) in Kodi" -msgstr "" +msgstr "Updating %i of %i episode playcount(s) in Kodi" msgctxt "#32109" msgid "Playcounts updated for %i show(s) in Kodi" -msgstr "" +msgstr "Playcounts updated for %i show(s) in Kodi" msgctxt "#32110" msgid "Trakt episode collection is clean, no episodes to remove" -msgstr "" +msgstr "Trakt episode collection is clean, no episodes to remove" msgctxt "#32111" msgid "%i episode(s) are being removed from your Trakt collection" -msgstr "" +msgstr "%i episode(s) are being removed from your Trakt collection" msgctxt "#32112" msgid "%i episode(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i episode(s) were removed from your Trakt collection" msgctxt "#32113" msgid "Trakt - Marked as watched" -msgstr "" +msgstr "Trakt - Marked as watched" msgctxt "#32114" msgid "Trakt - Failed marking as watched" -msgstr "" +msgstr "Trakt - Failed marking as watched" msgctxt "#32115" msgid "%d episode(s) of '%s'" -msgstr "" +msgstr "%d episode(s) of '%s'" msgctxt "#32116" msgid "Enable debug mode" -msgstr "" +msgstr "Enable debug mode" msgctxt "#32117" msgid "Sync movie playback progress to Kodi" -msgstr "" +msgstr "Sync movie playback progress to Kodi" msgctxt "#32118" msgid "Sync episode playback progress to Kodi" -msgstr "" +msgstr "Sync episode playback progress to Kodi" msgctxt "#32119" msgid "Retrieving episode playback progress from Trakt" -msgstr "" +msgstr "Retrieving episode playback progress from Trakt" msgctxt "#32120" msgid "Parsing episode playback progress %i of %i from Trakt" -msgstr "" +msgstr "Parsing episode playback progress %i of %i from Trakt" msgctxt "#32121" msgid "Retrieved episode playback progress from Trakt" -msgstr "" +msgstr "Retrieved episode playback progress from Trakt" msgctxt "#32122" msgid "Retrieving movie playback progress from Trakt" -msgstr "" +msgstr "Retrieving movie playback progress from Trakt" msgctxt "#32123" msgid "Parsing movie playback progress %i of %i from Trakt" -msgstr "" +msgstr "Parsing movie playback progress %i of %i from Trakt" msgctxt "#32124" msgid "Retrieved movie playback progress from Trakt" -msgstr "" +msgstr "Retrieved movie playback progress from Trakt" msgctxt "#32125" msgid "Kodi movie playback progress is up to date" -msgstr "" +msgstr "Kodi movie playback progress is up to date" msgctxt "#32126" msgid "%i movie(s) playback progress will be updated in Kodi" -msgstr "" +msgstr "%i movie(s) playback progress will be updated in Kodi" msgctxt "#32127" msgid "Updating %i of %i movie(s) playback progress in Kodi" -msgstr "" +msgstr "Updating %i of %i movie(s) playback progress in Kodi" msgctxt "#32128" msgid "Playback progress updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Playback progress updated for %i movie(s) in Kodi" msgctxt "#32129" msgid "Kodi episode playback progress is up to date" -msgstr "" +msgstr "Kodi episode playback progress is up to date" msgctxt "#32130" msgid "Updating %i of %i episode(s) playback progress in Kodi" -msgstr "" +msgstr "Updating %i of %i episode(s) playback progress in Kodi" msgctxt "#32131" msgid "Playback progress updated for %i episode(s) in Kodi" -msgstr "" +msgstr "Playback progress updated for %i episode(s) in Kodi" msgctxt "#32132" msgid "Unrate this season" -msgstr "" +msgstr "Unrate this season" msgctxt "#32133" msgid "Manage Movie's Lists" -msgstr "" +msgstr "Manage Movie's Lists" msgctxt "#32134" msgid "Manage Show's Lists" -msgstr "" +msgstr "Manage Show's Lists" msgctxt "#32135" msgid "Remove from Watchlist" -msgstr "" +msgstr "Remove from Watchlist" msgctxt "#32136" msgid "Add to watchlist" -msgstr "" +msgstr "Add to watchlist" msgctxt "#32137" msgid "Rate this movie" -msgstr "" +msgstr "Rate this movie" msgctxt "#32138" msgid "Rate this show" -msgstr "" +msgstr "Rate this show" msgctxt "#32139" msgid "Rate this episode" -msgstr "" +msgstr "Rate this episode" msgctxt "#32140" msgid "Toggle watched" -msgstr "" +msgstr "Toggle watched" msgctxt "#32141" msgid "Manage all lists" -msgstr "" +msgstr "Manage all lists" msgctxt "#32142" msgid "Update all tags" -msgstr "" +msgstr "Update all tags" msgctxt "#32143" msgid "Synchronize library" -msgstr "" +msgstr "Synchronize library" msgctxt "#32144" msgid "How do I authorize the trakt addon to access my trakt.tv account?" -msgstr "" +msgstr "How do I authorize the trakt addon to access my trakt.tv account?" -# empty strings from id 32145 to 32146 msgctxt "#32147" msgid "Trakt.tv PIN Authorization Failed" -msgstr "" +msgstr "Trakt.tv PIN Authorization Failed" -# empty string with id 32148 msgctxt "#32149" msgid "Rate this Season" -msgstr "" +msgstr "Rate this Season" msgctxt "#32150" msgid "You will be reminded in 24 hours" -msgstr "" +msgstr "You will be reminded in 24 hours" msgctxt "#32151" msgid "Use Addon Settings later if you change your mind" -msgstr "" +msgstr "Use Addon Settings later if you change your mind" msgctxt "#32152" msgid "Trakt Authorization Complete" -msgstr "" +msgstr "Trakt Authorization Complete" msgctxt "#32153" msgid "Trakt Account Authorization" -msgstr "" +msgstr "Trakt Account Authorization" msgctxt "#32154" msgid "Authorize" -msgstr "" +msgstr "Authorize" msgctxt "#32155" msgid "Remind Me Later" -msgstr "" +msgstr "Remind Me Later" msgctxt "#32156" msgid "No Thanks" -msgstr "" +msgstr "No Thanks" msgctxt "#32157" msgid "Account Authorization" -msgstr "" +msgstr "Account Authorization" # empty string with id 32158 msgctxt "#32159" @@ -631,23 +624,23 @@ msgstr "" msgctxt "#32162" msgid "The trakt addon CAN NOT be used without authorizing it to access your trakt.tv account." -msgstr "" +msgstr "The trakt addon CAN NOT be used without authorizing it to access your trakt.tv account." msgctxt "#32163" msgid "User" -msgstr "" +msgstr "User" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" -msgstr "" +msgstr "Fallback to Title/Year matching if necessary" msgctxt "#32165" msgid "Trakt - Added to watchlist" -msgstr "" +msgstr "Trakt - Added to watchlist" msgctxt "#32166" msgid "Trakt - Failed adding to watchlist" -msgstr "" +msgstr "Trakt - Failed adding to watchlist" msgctxt "#32167" msgid "Offset scrobble start by X minutes" @@ -768,3 +761,19 @@ msgstr "" msgctxt "#42191" msgid "Optional password needed to authenticate with the proxy." msgstr "" + +#~ msgctxt "#32003" +#~ msgid "Startup Delay" +#~ msgstr "Startup Delay" + +#~ msgctxt "#32159" +#~ msgid "Visit {0} or scan the QR Code below." +#~ msgstr "Visit {0} or scan the QR Code below." + +#~ msgctxt "#32160" +#~ msgid "Authorize the trakt addon to access your account." +#~ msgstr "Authorize the trakt addon to access your account." + +#~ msgctxt "#32161" +#~ msgid "Enter the PIN provided in the box below." +#~ msgstr "Enter the PIN provided in the box below." diff --git a/script.trakt/resources/language/resource.language.es_ar/strings.po b/script.trakt/resources/language/resource.language.es_ar/strings.po index af628655c..56b0aedb8 100644 --- a/script.trakt/resources/language/resource.language.es_ar/strings.po +++ b/script.trakt/resources/language/resource.language.es_ar/strings.po @@ -8,13 +8,13 @@ msgstr "" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: es_ar\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: Spanish (Argentina) (http://www.transifex.com/projects/p/xbmc-addons/language/es_AR/)\n" +"Language: es_AR\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" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,10 +24,9 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "General" # empty strings from id 32001 to 32002 msgctxt "#32003" @@ -36,7 +35,7 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Valoración" msgctxt "#32005" msgid "Rate Movie after watching" @@ -106,7 +105,7 @@ msgstr "" msgctxt "#32024" msgid "Error" -msgstr "" +msgstr "Error" # empty string with id 32025 msgctxt "#32026" @@ -139,7 +138,7 @@ msgstr "" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Bueno" msgctxt "#32034" msgid "Good" @@ -191,7 +190,7 @@ msgstr "" msgctxt "#32046" msgid "Movies" -msgstr "" +msgstr "Películas" msgctxt "#32047" msgid "Add new movies to Trakt collection" @@ -223,7 +222,7 @@ msgstr "" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Servicio" msgctxt "#32055" msgid "Sync collection on library update or cleaning" @@ -635,7 +634,7 @@ msgstr "" msgctxt "#32163" msgid "User" -msgstr "" +msgstr "Usuarios" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" diff --git a/script.trakt/resources/language/resource.language.es_mx/strings.po b/script.trakt/resources/language/resource.language.es_mx/strings.po index 821b45570..3d7120db1 100644 --- a/script.trakt/resources/language/resource.language.es_mx/strings.po +++ b/script.trakt/resources/language/resource.language.es_mx/strings.po @@ -5,16 +5,17 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" +"Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: es_mx\n" +"PO-Revision-Date: 2022-08-05 23:14+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Spanish (Mexico) \n" +"Language: es_MX\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.13\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,339 +25,338 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "General" # empty strings from id 32001 to 32002 msgctxt "#32003" msgid "Startup Delay (seconds)" -msgstr "" +msgstr "Retraso al iniciar (en segundos)" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Calificación" msgctxt "#32005" msgid "Rate Movie after watching" -msgstr "" +msgstr "Calificar película después de ver" msgctxt "#32006" msgid "Rate TV show Episode after watching" -msgstr "" +msgstr "Calificar serie después de ver" msgctxt "#32008" msgid "Minimum percent watched to display rating dialog" -msgstr "" +msgstr "Porcentaje mínimo visto para mostrar diálogo de calificación" msgctxt "#32009" msgid "Allow re-rating of media" -msgstr "" +msgstr "Permitir calificar nuevamente" msgctxt "#32010" msgid "Default rating" -msgstr "" +msgstr "Calificación por defecto" # Scrobbling Settings msgctxt "#32011" msgid "Scrobbling" -msgstr "" +msgstr "Seguimiento" msgctxt "#32012" msgid "Scrobble movies" -msgstr "" +msgstr "Dar seguimiento a películas" msgctxt "#32013" msgid "Scrobble TV show episodes" -msgstr "" +msgstr "Dar seguimiento a episodios" msgctxt "#32014" msgid "Show notification on scrobble" -msgstr "" +msgstr "Mostrar notificaciones al sincronizar" msgctxt "#32015" msgid "Trakt - Scrobbled successfully" -msgstr "" +msgstr "Trakt - Sincronizado exitosamnte" msgctxt "#32016" msgid "Exclusions" -msgstr "" +msgstr "Exclusiones" msgctxt "#32017" msgid "Exclude Live TV" -msgstr "" +msgstr "Excluir TV en vivo" msgctxt "#32018" msgid "Exclude HTTP sources" -msgstr "" +msgstr "Excluir fuentes HTTP" msgctxt "#32019" msgid "Exclude path" -msgstr "" +msgstr "Excluir ruta" msgctxt "#32020" msgid "Folder's path (including subfolders)" -msgstr "" +msgstr "Ruta a la carpeta (incluyendo subcarpetas)" # empty strings from id 32021 to 32022 msgctxt "#32023" msgid "Can not connect to Trakt" -msgstr "" +msgstr "No se pudo conectar con Trakt" msgctxt "#32024" msgid "Error" -msgstr "" +msgstr "Error" # empty string with id 32025 msgctxt "#32026" msgid "What Did You Think?" -msgstr "" +msgstr "¿Qué te pareció?" msgctxt "#32027" msgid "Totally Ninja!" -msgstr "" +msgstr "¡Increíble!" msgctxt "#32028" msgid "Weak Sauce :(" -msgstr "" +msgstr "De lo peor" msgctxt "#32029" msgid "Terrible" -msgstr "" +msgstr "Malísimo" msgctxt "#32030" msgid "Bad" -msgstr "" +msgstr "Malo" msgctxt "#32031" msgid "Poor" -msgstr "" +msgstr "Un poco pobre" msgctxt "#32032" msgid "Meh" -msgstr "" +msgstr "Ni bueno ni malo" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Tuvo buenos momentos" msgctxt "#32034" msgid "Good" -msgstr "" +msgstr "Bueno" msgctxt "#32035" msgid "Great" -msgstr "" +msgstr "Muy bueno" msgctxt "#32036" msgid "Superb" -msgstr "" +msgstr "Buenísimo" msgctxt "#32037" msgid "Unrate this movie" -msgstr "" +msgstr "Des-calificar esta película" msgctxt "#32038" msgid "Unrate this show" -msgstr "" +msgstr "Des-calificar esta serie" msgctxt "#32039" msgid "Unrate this episode" -msgstr "" +msgstr "Des-calificar este episodio" msgctxt "#32040" msgid "Trakt - Rating submitted successfully" -msgstr "" +msgstr "Trakt - Calificación enviada con éxito" msgctxt "#32041" msgid "Trakt - Already rated" -msgstr "" +msgstr "Trakt - Ya se ha calificado" msgctxt "#32042" msgid "Trakt - Unrated successfully" -msgstr "" +msgstr "Trakt - Des-calificado con éxito" msgctxt "#32043" msgid "Trakt - Already has the same rating" -msgstr "" +msgstr "Trakt - Misma calificación" msgctxt "#32044" msgid "Trakt - Problem submitting rating" -msgstr "" +msgstr "Trakt - Problemas al enviar la calificación" msgctxt "#32045" msgid "Synchronize" -msgstr "" +msgstr "Sincronizar" msgctxt "#32046" msgid "Movies" -msgstr "" +msgstr "Películas" msgctxt "#32047" msgid "Add new movies to Trakt collection" -msgstr "" +msgstr "Agregar nuevas películas a la colección de Trakt" msgctxt "#32048" msgid "Add watched movies to Trakt history" -msgstr "" +msgstr "Agregar películas vistas al historial de Trakt" msgctxt "#32049" msgid "Mark movies from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marcar películas del historial de Trakt como vistas en Kodi" msgctxt "#32050" msgid "TV Episodes" -msgstr "" +msgstr "Episodios" msgctxt "#32051" msgid "Add new TV episodes to Trakt collection" -msgstr "" +msgstr "Agrergar nuevos episodios a la colección de Trakt" msgctxt "#32052" msgid "Add watched TV episodes to Trakt history" -msgstr "" +msgstr "Agregar episodios vistos al historial de Trakt" msgctxt "#32053" msgid "Mark TV episodes from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marcar episodios del historial de Trakt como vistos en Kodi" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Servicio" msgctxt "#32055" msgid "Sync collection on library update or cleaning" -msgstr "" +msgstr "Sincronizar colección al limpiar o actualizar la biblioteca" msgctxt "#32056" msgid "Show sync notifications" -msgstr "" +msgstr "Mostrar notificaciones de sincronización" msgctxt "#32057" msgid "Remove deleted movies from Trakt collection" -msgstr "" +msgstr "Quitar películas eliminadas de la colección de Trakt" msgctxt "#32058" msgid "Remove deleted TV episodes from Trakt collection" -msgstr "" +msgstr "Quitar episodios eliminados de la colección de Trakt" # empty string with id 32059 msgctxt "#32060" msgid "Hide notifications during playback" -msgstr "" +msgstr "Ocultar notificaciones durante la reproducción" msgctxt "#32061" msgid "Sync started" -msgstr "" +msgstr "Sincronización iniciada" msgctxt "#32062" msgid "Sync complete" -msgstr "" +msgstr "Sincronización completada" msgctxt "#32063" msgid "%i movie(s) will be added to Trakt collection" -msgstr "" +msgstr "%i película(s) se agregará(n) a la colección de Trakt" msgctxt "#32064" msgid "%i movie playcount(s) will be updated on Trakt" -msgstr "" +msgstr "%i reproducción(es) de película se actualizará(n) en Trakt" msgctxt "#32065" msgid "%i movie(s) playcount will be updated in Kodi" -msgstr "" +msgstr "%i reproducciones de película(s) se actualizará(n) en Kodi" msgctxt "#32066" msgid "Movie Sync Complete" -msgstr "" +msgstr "Sincronización de películas completada" msgctxt "#32067" msgid "Going to add %i show(s) to Trakt collection" -msgstr "" +msgstr "Se agregará(n) %i serie(s) a la colección de Trakt" msgctxt "#32068" msgid "Checking for episodes missing from Trakt collection" -msgstr "" +msgstr "Verificando episodios faltantes en la colección de Trakt" msgctxt "#32069" msgid "%i of %i show(s) have episodes added to Trakt collection" -msgstr "" +msgstr "%i de %i serie(s) tienen episodios agregados a la colección de Trakt" msgctxt "#32070" msgid "Going to update %i show(s) missing watched status" -msgstr "" +msgstr "Se va a actualizar el estado de visualización faltante de la(s) serie(s) %i" msgctxt "#32071" msgid "Checking watched episodes on Trakt" -msgstr "" +msgstr "Verificando episodios vistos en Trakt" msgctxt "#32072" msgid "%i show(s) had missing watched status" -msgstr "" +msgstr "%i serie(s) tiene(n) estados de visualización faltantes" msgctxt "#32073" msgid "%i episodes are being updated" -msgstr "" +msgstr "%i episodios están siendo actualizados" msgctxt "#32074" msgid "Checking watched episodes on Kodi" -msgstr "" +msgstr "Verificando episodios vistos en Kodi" msgctxt "#32075" msgid "Episode Sync Complete" -msgstr "" +msgstr "Sincronización de episodios completada" msgctxt "#32076" msgid "%i movie(s) will be removed from Trakt collection" -msgstr "" +msgstr "%i película(s) se borrará(n) de la colección de Trakt" msgctxt "#32077" msgid "Cleaning Trakt TV show collection" -msgstr "" +msgstr "Limpiando colección de series de Trakt" msgctxt "#32078" msgid "episodes are being removed" -msgstr "" +msgstr "episodios están siendo borrados" msgctxt "#32079" msgid "Loading movies from Kodi" -msgstr "" +msgstr "Cargando películas de Kodi" msgctxt "#32080" msgid "Movies loaded from Kodi" -msgstr "" +msgstr "Películas de Kodi cargadas" msgctxt "#32081" msgid "Retrieving movie collection from Trakt" -msgstr "" +msgstr "Obteniendo colección de películas de Trakt" msgctxt "#32082" msgid "Retrieving watched movies from Trakt" -msgstr "" +msgstr "Obteniendo películas vistas de Trakt" msgctxt "#32083" msgid "Retrieved movie data from Trakt" -msgstr "" +msgstr "Obtenidos datos de películas de Trakt" msgctxt "#32084" msgid "Trakt movie collection is up to date, no movies to add" -msgstr "" +msgstr "La colección de películas de Trakt está actualizada, no hay películas que agregar" msgctxt "#32085" msgid "%i movie(s) were added to your Trakt collection" -msgstr "" +msgstr "%i película(s) ha(n) sido agregada(s) a tu colección de Trakt" msgctxt "#32086" msgid "Trakt movie playcounts are up to date" -msgstr "" +msgstr "Las reproducciones de películas de Trakt están al día" msgctxt "#32087" msgid "Playcounts updated for %i movie(s) on Trakt" -msgstr "" +msgstr "Reproducciones de %i película(s) actualizada(s) en Trakt" msgctxt "#32088" msgid "Kodi movie playcounts are up to date" -msgstr "" +msgstr "Las reproducciones de películas de Kodi están al día" msgctxt "#32089" msgid "Updating %i of %i movie playcount(s) in Kodi" @@ -380,11 +380,11 @@ msgstr "" msgctxt "#32094" msgid "Loading episode data from Kodi" -msgstr "" +msgstr "Cargando datos de episodios de Kodi" msgctxt "#32095" msgid "Loading shows from Kodi" -msgstr "" +msgstr "Cargando series desde Kodi" msgctxt "#32096" msgid "Shows loaded from Kodi" @@ -456,11 +456,11 @@ msgstr "" msgctxt "#32113" msgid "Trakt - Marked as watched" -msgstr "" +msgstr "Trakt - Marcado como visto" msgctxt "#32114" msgid "Trakt - Failed marking as watched" -msgstr "" +msgstr "Trakt - No se pudo marcar como visto" msgctxt "#32115" msgid "%d episode(s) of '%s'" @@ -468,19 +468,19 @@ msgstr "" msgctxt "#32116" msgid "Enable debug mode" -msgstr "" +msgstr "Activar modo de depuración" msgctxt "#32117" msgid "Sync movie playback progress to Kodi" -msgstr "" +msgstr "Sincronizar progreso de reproducción de película con Kodi" msgctxt "#32118" msgid "Sync episode playback progress to Kodi" -msgstr "" +msgstr "Sincronizar progreso de reproducción de episodio con Kodi" msgctxt "#32119" msgid "Retrieving episode playback progress from Trakt" -msgstr "" +msgstr "Obteniendo progreso de reproducción de episodio de Trakt" msgctxt "#32120" msgid "Parsing episode playback progress %i of %i from Trakt" @@ -747,7 +747,7 @@ msgstr "" msgctxt "#32189" msgid "Proxy port" -msgstr "" +msgstr "Puerto Proxy" msgctxt "#42189" msgid "Port of the proxy server." @@ -755,7 +755,7 @@ msgstr "" msgctxt "#32190" msgid "Username" -msgstr "" +msgstr "Nombre de usuario" msgctxt "#42190" msgid "Optional user name needed to authenticate with the proxy." @@ -763,8 +763,13 @@ msgstr "" msgctxt "#32191" msgid "Password" -msgstr "" +msgstr "Contraseña" msgctxt "#42191" msgid "Optional password needed to authenticate with the proxy." msgstr "" + +# empty strings from id 32001 to 32002 +#~ msgctxt "#32003" +#~ msgid "Startup Delay" +#~ msgstr "Retraso de inicio" diff --git a/script.trakt/resources/language/resource.language.fa_af/strings.po b/script.trakt/resources/language/resource.language.fa_af/strings.po index 55907ed1a..b97b12faf 100644 --- a/script.trakt/resources/language/resource.language.fa_af/strings.po +++ b/script.trakt/resources/language/resource.language.fa_af/strings.po @@ -8,13 +8,13 @@ msgstr "" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: fa_af\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: Persian (http://www.transifex.com/projects/p/xbmc-addons/language/fa/)\n" +"Language: fa\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" +"Plural-Forms: nplurals=1; plural=0;\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,10 +24,9 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "عمومی" # empty strings from id 32001 to 32002 msgctxt "#32003" diff --git a/script.trakt/resources/language/resource.language.fr_ca/strings.po b/script.trakt/resources/language/resource.language.fr_ca/strings.po index 5cf7efe48..6c3ce614c 100644 --- a/script.trakt/resources/language/resource.language.fr_ca/strings.po +++ b/script.trakt/resources/language/resource.language.fr_ca/strings.po @@ -7,14 +7,15 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: fr_ca\n" +"PO-Revision-Date: 2021-07-10 08:37+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: French (Canada) \n" +"Language: fr_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.7.1\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,10 +25,9 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "Général" # empty strings from id 32001 to 32002 msgctxt "#32003" @@ -36,593 +36,587 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Évaluation" msgctxt "#32005" msgid "Rate Movie after watching" -msgstr "" +msgstr "Évaluer le film après visualisation" msgctxt "#32006" msgid "Rate TV show Episode after watching" -msgstr "" +msgstr "Évaluer l'épisode d'émission télé après visualisation" msgctxt "#32008" msgid "Minimum percent watched to display rating dialog" -msgstr "" +msgstr "Pourcentage de visualisation minimum pour afficher la fenêtre d'évaluation" msgctxt "#32009" msgid "Allow re-rating of media" -msgstr "" +msgstr "Permettre la réévaluation du média" msgctxt "#32010" msgid "Default rating" -msgstr "" +msgstr "Évaluation par défaut" -# Scrobbling Settings msgctxt "#32011" msgid "Scrobbling" -msgstr "" +msgstr "Scrobblage" msgctxt "#32012" msgid "Scrobble movies" -msgstr "" +msgstr "Scrobbler les films" msgctxt "#32013" msgid "Scrobble TV show episodes" -msgstr "" +msgstr "Scrobbler les épisodes d'émissions télé" msgctxt "#32014" msgid "Show notification on scrobble" -msgstr "" +msgstr "Afficher une notification lors du scrobble" msgctxt "#32015" msgid "Trakt - Scrobbled successfully" -msgstr "" +msgstr "Trakt - Scrobblé avec succès" msgctxt "#32016" msgid "Exclusions" -msgstr "" +msgstr "Exclusions" msgctxt "#32017" msgid "Exclude Live TV" -msgstr "" +msgstr "Exclure la télé en direct" msgctxt "#32018" msgid "Exclude HTTP sources" -msgstr "" +msgstr "Exclure les sources HTTP" msgctxt "#32019" msgid "Exclude path" -msgstr "" +msgstr "Exclure le chemin" msgctxt "#32020" msgid "Folder's path (including subfolders)" -msgstr "" +msgstr "Chemin du dossier (incluant les sous-dossiers)" -# empty strings from id 32021 to 32022 msgctxt "#32023" msgid "Can not connect to Trakt" -msgstr "" +msgstr "Impossible de se connecter à Trakt" msgctxt "#32024" msgid "Error" -msgstr "" +msgstr "Erreur" -# empty string with id 32025 msgctxt "#32026" msgid "What Did You Think?" -msgstr "" +msgstr "Qu'en avez-vous pensé?" msgctxt "#32027" msgid "Totally Ninja!" -msgstr "" +msgstr "Complètement Ninja!" msgctxt "#32028" msgid "Weak Sauce :(" -msgstr "" +msgstr "Ben faible :(" msgctxt "#32029" msgid "Terrible" -msgstr "" +msgstr "Affreux" msgctxt "#32030" msgid "Bad" -msgstr "" +msgstr "Mauvais" msgctxt "#32031" msgid "Poor" -msgstr "" +msgstr "Pas fameux" msgctxt "#32032" msgid "Meh" -msgstr "" +msgstr "Bof" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Beau" msgctxt "#32034" msgid "Good" -msgstr "" +msgstr "Bon" msgctxt "#32035" msgid "Great" -msgstr "" +msgstr "Vraiment bon" msgctxt "#32036" msgid "Superb" -msgstr "" +msgstr "Superbe" msgctxt "#32037" msgid "Unrate this movie" -msgstr "" +msgstr "Ôter l'évaluation de ce film" msgctxt "#32038" msgid "Unrate this show" -msgstr "" +msgstr "Ôter l'évaluation de cette émission" msgctxt "#32039" msgid "Unrate this episode" -msgstr "" +msgstr "Ôter l'évaluation de cet épisode" msgctxt "#32040" msgid "Trakt - Rating submitted successfully" -msgstr "" +msgstr "Trakt - Évaluation envoyée avec succès" msgctxt "#32041" msgid "Trakt - Already rated" -msgstr "" +msgstr "Trakt - Déjà évalué" msgctxt "#32042" msgid "Trakt - Unrated successfully" -msgstr "" +msgstr "Trakt - Évaluation ôtée avec succès" msgctxt "#32043" msgid "Trakt - Already has the same rating" -msgstr "" +msgstr "Trakt - A déjà la même évaluation" msgctxt "#32044" msgid "Trakt - Problem submitting rating" -msgstr "" +msgstr "Trakt - Problème lors de l'envoi de l'évaluation" msgctxt "#32045" msgid "Synchronize" -msgstr "" +msgstr "Synchroniser" msgctxt "#32046" msgid "Movies" -msgstr "" +msgstr "Films" msgctxt "#32047" msgid "Add new movies to Trakt collection" -msgstr "" +msgstr "Ajouter de nouveaux films à la collection Trakt" msgctxt "#32048" msgid "Add watched movies to Trakt history" -msgstr "" +msgstr "Ajouter les films regardés à l'historique Trakt" msgctxt "#32049" msgid "Mark movies from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marquer les films de l'historique Trakt comme regardés dans Kodi" msgctxt "#32050" msgid "TV Episodes" -msgstr "" +msgstr "Épisodes télé" msgctxt "#32051" msgid "Add new TV episodes to Trakt collection" -msgstr "" +msgstr "Ajouter de nouveaux épisodes télé à la collection Trakt" msgctxt "#32052" msgid "Add watched TV episodes to Trakt history" -msgstr "" +msgstr "Ajouter les épisodes télé regardés à l'historique Trakt" msgctxt "#32053" msgid "Mark TV episodes from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marquer les épisodes télé de l'historique Trakt comme regardés dans Kodi" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Service" msgctxt "#32055" msgid "Sync collection on library update or cleaning" -msgstr "" +msgstr "Synchroniser la collection lors de la mise à jour ou du nettoyage de la vidéothèque" msgctxt "#32056" msgid "Show sync notifications" -msgstr "" +msgstr "Montrer les notifications de synchro" msgctxt "#32057" msgid "Remove deleted movies from Trakt collection" -msgstr "" +msgstr "Enlever les films supprimés de la collection Trakt" msgctxt "#32058" msgid "Remove deleted TV episodes from Trakt collection" -msgstr "" +msgstr "Enlever les émissions télé supprimées de la collection Trakt" -# empty string with id 32059 msgctxt "#32060" msgid "Hide notifications during playback" -msgstr "" +msgstr "Cacher les notifications lors de la lecture" msgctxt "#32061" msgid "Sync started" -msgstr "" +msgstr "Synchro lancée" msgctxt "#32062" msgid "Sync complete" -msgstr "" +msgstr "Synchro terminée" msgctxt "#32063" msgid "%i movie(s) will be added to Trakt collection" -msgstr "" +msgstr "%i film(s) sera/seront ajouté(s) à la collection Trakt" msgctxt "#32064" msgid "%i movie playcount(s) will be updated on Trakt" -msgstr "" +msgstr "%i compteur(s) de lecture sera/seront mis à jour sur Trakt" msgctxt "#32065" msgid "%i movie(s) playcount will be updated in Kodi" -msgstr "" +msgstr "%i compteur(s) de lecture sera/seront mis à jour dans Kodi" msgctxt "#32066" msgid "Movie Sync Complete" -msgstr "" +msgstr "Synchro des films terminée" msgctxt "#32067" msgid "Going to add %i show(s) to Trakt collection" -msgstr "" +msgstr "%i émission(s) va/vont être ajoutée(s) à la collection" msgctxt "#32068" msgid "Checking for episodes missing from Trakt collection" -msgstr "" +msgstr "Vérification des épisodes manquants dans la collection Trakt" msgctxt "#32069" msgid "%i of %i show(s) have episodes added to Trakt collection" -msgstr "" +msgstr "Les épisodes d'%i émission(s) sur %i ont été ajoutés la collection Trakt" msgctxt "#32070" msgid "Going to update %i show(s) missing watched status" -msgstr "" +msgstr "L'état de visionnement manquant d'%i émission(s) va être mis à jour" msgctxt "#32071" msgid "Checking watched episodes on Trakt" -msgstr "" +msgstr "Vérification des épisodes regardés sur Trakt" msgctxt "#32072" msgid "%i show(s) had missing watched status" -msgstr "" +msgstr "L'état de visionnement était manquant pour %i émission(s)" msgctxt "#32073" msgid "%i episodes are being updated" -msgstr "" +msgstr "%i épisode(s) est/sont mis à jour" msgctxt "#32074" msgid "Checking watched episodes on Kodi" -msgstr "" +msgstr "Vérification sur Kodi des épisodes regardés" msgctxt "#32075" msgid "Episode Sync Complete" -msgstr "" +msgstr "Synchro des épisodes terminée" msgctxt "#32076" msgid "%i movie(s) will be removed from Trakt collection" -msgstr "" +msgstr "%i film(s) sera/seront retiré(s) de la collection Trakt" msgctxt "#32077" msgid "Cleaning Trakt TV show collection" -msgstr "" +msgstr "Nettoyage de la collection d'émissions tété de Trakt" msgctxt "#32078" msgid "episodes are being removed" -msgstr "" +msgstr "épisodes en cours de retrait" msgctxt "#32079" msgid "Loading movies from Kodi" -msgstr "" +msgstr "Chargement des films de Kodi" msgctxt "#32080" msgid "Movies loaded from Kodi" -msgstr "" +msgstr "Les films ont été chargés de Kodi" msgctxt "#32081" msgid "Retrieving movie collection from Trakt" -msgstr "" +msgstr "Récupération de la collection de film de Trakt" msgctxt "#32082" msgid "Retrieving watched movies from Trakt" -msgstr "" +msgstr "Récupération des films regardés de Trakt" msgctxt "#32083" msgid "Retrieved movie data from Trakt" -msgstr "" +msgstr "Données de film récupérées sur Trakt" msgctxt "#32084" msgid "Trakt movie collection is up to date, no movies to add" -msgstr "" +msgstr "La collection de films de Trakt est à jour, aucun film à ajouter" msgctxt "#32085" msgid "%i movie(s) were added to your Trakt collection" -msgstr "" +msgstr "%i film(s) a/ont été ajouté(s) à votre collection Trakt" msgctxt "#32086" msgid "Trakt movie playcounts are up to date" -msgstr "" +msgstr "Les compteurs de lecture des films de Trakt sont à jour" msgctxt "#32087" msgid "Playcounts updated for %i movie(s) on Trakt" -msgstr "" +msgstr "Compteurs de lecture mis à jour sur Trakt pour %i film(s)" msgctxt "#32088" msgid "Kodi movie playcounts are up to date" -msgstr "" +msgstr "Les compteurs de lecture des films de Kodi sont à jour" msgctxt "#32089" msgid "Updating %i of %i movie playcount(s) in Kodi" -msgstr "" +msgstr "Mise à jour d'%i compteur(s) de lecture de film sur %i dans Kodi" msgctxt "#32090" msgid "Playcounts updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Compteurs de lecture mis à jour dans Kodi pour %i film(s)" msgctxt "#32091" msgid "Trakt movie collection is up to date, no movies removed" -msgstr "" +msgstr "La collection de films de Trakt est à jour, aucun film n'a été supprimé" msgctxt "#32092" msgid "%i movie(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i film(s) a/ont été retiré(s) de votre collection Trakt" msgctxt "#32093" msgid "Updating %i of %i movie playcount(s) on Trakt" -msgstr "" +msgstr "Mise à jour d'%i compteur(s) de lecture de film sur %i sur Trakt" msgctxt "#32094" msgid "Loading episode data from Kodi" -msgstr "" +msgstr "Chargement des données d'épisode de Kodi" msgctxt "#32095" msgid "Loading shows from Kodi" -msgstr "" +msgstr "Chargement des émissions de Kodi" msgctxt "#32096" msgid "Shows loaded from Kodi" -msgstr "" +msgstr "Émissions chargées à partir de Kodi" msgctxt "#32097" msgid "Parsing %i of %i episode data from Kodi" -msgstr "" +msgstr "Analyse des données d'%i épisode(s) sur %i de Kodi" msgctxt "#32098" msgid "Loaded episode data from Kodi" -msgstr "" +msgstr "Les données d'épisode ont été chargées de Kodi" msgctxt "#32099" msgid "Loading episode data from Trakt" -msgstr "" +msgstr "Chargement des données d'épisode de Trakt" msgctxt "#32100" msgid "Retrieving episode collection from Trakt" -msgstr "" +msgstr "Obtention de la collection d'épisodes de Trakt" msgctxt "#32101" msgid "Retrieving watched episodes from Trakt" -msgstr "" +msgstr "Obtention des épisodes regardés de Trakt" msgctxt "#32102" msgid "Parsing episode data %i of %i from Trakt" -msgstr "" +msgstr "Analyse des données d'%i épisode(s) sur %i de Trakt" msgctxt "#32103" msgid "Retrieved episode data from Trakt" -msgstr "" +msgstr "Données d'épisode récupérées sur Trakt" msgctxt "#32104" msgid "Trakt episode collection is up to date, no episodes to add" -msgstr "" +msgstr "La collection d'épisodes de Trakt est à jour, aucun épisode à ajouter" msgctxt "#32105" msgid "%i episode(s) were added to your Trakt collection" -msgstr "" +msgstr "%i épisode(s) a/ont été ajouté(s) à votre collection Trakt" msgctxt "#32106" msgid "Trakt episode playcounts are up to date" -msgstr "" +msgstr "Les compteurs de lecture des épisodes de Trakt sont à jour" msgctxt "#32107" msgid "Kodi episode playcounts are up to date" -msgstr "" +msgstr "Les compteurs de lecture des épisodes de Kodi sont à jour" msgctxt "#32108" msgid "Updating %i of %i episode playcount(s) in Kodi" -msgstr "" +msgstr "Mise à jour d'%i compteur(s) de lecture d'épisode sur %i dans Kodi" msgctxt "#32109" msgid "Playcounts updated for %i show(s) in Kodi" -msgstr "" +msgstr "Compteurs de lecture mis à jour dans Kodi pour %i épisode(s)" msgctxt "#32110" msgid "Trakt episode collection is clean, no episodes to remove" -msgstr "" +msgstr "La collection d'épisodes de Trakt est propre, aucun épisode à supprimer" msgctxt "#32111" msgid "%i episode(s) are being removed from your Trakt collection" -msgstr "" +msgstr "%i épisode(s) est/sont en cours de retrait de votre collection Trakt" msgctxt "#32112" msgid "%i episode(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i épisode(s) a/ont été retiré(s) de votre collection Trakt" msgctxt "#32113" msgid "Trakt - Marked as watched" -msgstr "" +msgstr "Trakt - Marqué comme regardé" msgctxt "#32114" msgid "Trakt - Failed marking as watched" -msgstr "" +msgstr "Trakt - Impossible de marquer comme regardé" msgctxt "#32115" msgid "%d episode(s) of '%s'" -msgstr "" +msgstr "%d épisode(s) sur %s" msgctxt "#32116" msgid "Enable debug mode" -msgstr "" +msgstr "Activer le mode de débogage" msgctxt "#32117" msgid "Sync movie playback progress to Kodi" -msgstr "" +msgstr "Synchroniser la progression de lecture des films vers Kodi" msgctxt "#32118" msgid "Sync episode playback progress to Kodi" -msgstr "" +msgstr "Synchroniser la progression de lecture des épisodes vers Kodi" msgctxt "#32119" msgid "Retrieving episode playback progress from Trakt" -msgstr "" +msgstr "Obtention de la progression de lecture des épisodes de Trakt" msgctxt "#32120" msgid "Parsing episode playback progress %i of %i from Trakt" -msgstr "" +msgstr "Analyse de la progression de lecture de %i sur %i épisode(s) de Trakt" msgctxt "#32121" msgid "Retrieved episode playback progress from Trakt" -msgstr "" +msgstr "La progression de lecture des épisodes a été récupéré de Trakt" msgctxt "#32122" msgid "Retrieving movie playback progress from Trakt" -msgstr "" +msgstr "Obtention de la progression de lecture des films de Trakt" msgctxt "#32123" msgid "Parsing movie playback progress %i of %i from Trakt" -msgstr "" +msgstr "Analyse de la progression de lecture de %i sur %i films(s) de Trakt" msgctxt "#32124" msgid "Retrieved movie playback progress from Trakt" -msgstr "" +msgstr "La progression de lecture des films a été récupéré de Trakt" msgctxt "#32125" msgid "Kodi movie playback progress is up to date" -msgstr "" +msgstr "Les progressions de lecture des films de Kodi sont à jour" msgctxt "#32126" msgid "%i movie(s) playback progress will be updated in Kodi" -msgstr "" +msgstr "La progression de lecture de %i film(s) sera/seront mis à jour dans Kodi" msgctxt "#32127" msgid "Updating %i of %i movie(s) playback progress in Kodi" -msgstr "" +msgstr "Mise à jour de la progression de lecture de %i de %i film(s) dans Kodi" msgctxt "#32128" msgid "Playback progress updated for %i movie(s) in Kodi" -msgstr "" +msgstr "La progression de lecture de %i film(s) à été mis à jour dans Kodi" msgctxt "#32129" msgid "Kodi episode playback progress is up to date" -msgstr "" +msgstr "La progression de lecture des épisodes est à jour dans Kodi" msgctxt "#32130" msgid "Updating %i of %i episode(s) playback progress in Kodi" -msgstr "" +msgstr "Mise à jour de la progression de lecture pour %i de %i épisode(s) dans Kodi" msgctxt "#32131" msgid "Playback progress updated for %i episode(s) in Kodi" -msgstr "" +msgstr "La progression de lecture à été mise à jour pour %i épisodes(s) dans Kodi" msgctxt "#32132" msgid "Unrate this season" -msgstr "" +msgstr "Ôter l'évaluation de cette saison" msgctxt "#32133" msgid "Manage Movie's Lists" -msgstr "" +msgstr "Gérer la liste des films" msgctxt "#32134" msgid "Manage Show's Lists" -msgstr "" +msgstr "Gérer la liste des émissions" msgctxt "#32135" msgid "Remove from Watchlist" -msgstr "" +msgstr "Supprimer de la liste de suivi" msgctxt "#32136" msgid "Add to watchlist" -msgstr "" +msgstr "Ajouter à la liste de suivi" msgctxt "#32137" msgid "Rate this movie" -msgstr "" +msgstr "Évaluer ce film" msgctxt "#32138" msgid "Rate this show" -msgstr "" +msgstr "Évaluer cette émission" msgctxt "#32139" msgid "Rate this episode" -msgstr "" +msgstr "Évaluer cet épisode" msgctxt "#32140" msgid "Toggle watched" -msgstr "" +msgstr "Activer/désactiver les regardés" msgctxt "#32141" msgid "Manage all lists" -msgstr "" +msgstr "Gérer toutes les listes" msgctxt "#32142" msgid "Update all tags" -msgstr "" +msgstr "Mettre à jour toutes les balises" msgctxt "#32143" msgid "Synchronize library" -msgstr "" +msgstr "Synchroniser la médiathèque" msgctxt "#32144" msgid "How do I authorize the trakt addon to access my trakt.tv account?" -msgstr "" +msgstr "Comment autoriser l'addiciel trakt à accéder à mon compte trakt.tv?" -# empty strings from id 32145 to 32146 msgctxt "#32147" msgid "Trakt.tv PIN Authorization Failed" -msgstr "" +msgstr "Trakt.tv - Échec de l'autorisation par NIP" -# empty string with id 32148 msgctxt "#32149" msgid "Rate this Season" -msgstr "" +msgstr "Évaluer cette saison" msgctxt "#32150" msgid "You will be reminded in 24 hours" -msgstr "" +msgstr "On vous le rappellera dans 24 heures" msgctxt "#32151" msgid "Use Addon Settings later if you change your mind" -msgstr "" +msgstr "Utilisez les paramètres d'addiciels ultérieurement si vous changez d'avis" msgctxt "#32152" msgid "Trakt Authorization Complete" -msgstr "" +msgstr "Trakt - Autorisation terminée" msgctxt "#32153" msgid "Trakt Account Authorization" -msgstr "" +msgstr "Trakt - Autorisation de compte" msgctxt "#32154" msgid "Authorize" -msgstr "" +msgstr "Autoriser" msgctxt "#32155" msgid "Remind Me Later" -msgstr "" +msgstr "Me le rappeler ultérieurement" msgctxt "#32156" msgid "No Thanks" -msgstr "" +msgstr "Non merci" msgctxt "#32157" msgid "Account Authorization" -msgstr "" +msgstr "Autorisation de compte" # empty string with id 32158 msgctxt "#32159" @@ -631,23 +625,23 @@ msgstr "" msgctxt "#32162" msgid "The trakt addon CAN NOT be used without authorizing it to access your trakt.tv account." -msgstr "" +msgstr "L'addiciel trakt NE PEUT PAS être utilisé sans qu'il ne soit autorisé à accéder à votre compte trakt.tv." msgctxt "#32163" msgid "User" -msgstr "" +msgstr "Utilisateur" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" -msgstr "" +msgstr "Se replier vers une concordance Titre/Année si nécessaire" msgctxt "#32165" msgid "Trakt - Added to watchlist" -msgstr "" +msgstr "Trakt - Ajouter à la liste de suivi" msgctxt "#32166" msgid "Trakt - Failed adding to watchlist" -msgstr "" +msgstr "Trakt - Échec d'ajout à la liste de suivi" msgctxt "#32167" msgid "Offset scrobble start by X minutes" @@ -768,3 +762,19 @@ msgstr "" msgctxt "#42191" msgid "Optional password needed to authenticate with the proxy." msgstr "" + +#~ msgctxt "#32003" +#~ msgid "Startup Delay" +#~ msgstr "Retard de démarrage" + +#~ msgctxt "#32159" +#~ msgid "Visit {0} or scan the QR Code below." +#~ msgstr "Visiter {0} ou lire le code QR ci-dessous." + +#~ msgctxt "#32160" +#~ msgid "Authorize the trakt addon to access your account." +#~ msgstr "Autorisez l'addiciel trakt à accéder à votre compte." + +#~ msgctxt "#32161" +#~ msgid "Enter the PIN provided in the box below." +#~ msgstr "Saisissez le NIP fourni dans la boîte ci-dessous." diff --git a/script.trakt/resources/language/resource.language.he_il/strings.po b/script.trakt/resources/language/resource.language.he_il/strings.po index e72129534..486941a5b 100644 --- a/script.trakt/resources/language/resource.language.he_il/strings.po +++ b/script.trakt/resources/language/resource.language.he_il/strings.po @@ -7,14 +7,15 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: he_il\n" +"PO-Revision-Date: 2021-03-20 15:56+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Hebrew (Israel) \n" +"Language: he_IL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && n % 10 == 0) ? 2 : 3));\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Weblate 4.5.1\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,10 +25,9 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "כללי" # empty strings from id 32001 to 32002 msgctxt "#32003" @@ -36,593 +36,587 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "דירוג" msgctxt "#32005" msgid "Rate Movie after watching" -msgstr "" +msgstr "דרג סרט לאחר צפייה" msgctxt "#32006" msgid "Rate TV show Episode after watching" -msgstr "" +msgstr "דרג פרק סדרה לאחר צפייה" msgctxt "#32008" msgid "Minimum percent watched to display rating dialog" -msgstr "" +msgstr "מינימום אחוזי צפייה כדי להציג מסך דירוג" msgctxt "#32009" msgid "Allow re-rating of media" -msgstr "" +msgstr "אפשר דירוג בשנית למדיה" msgctxt "#32010" msgid "Default rating" -msgstr "" +msgstr "דירוג ברירת מחדל" -# Scrobbling Settings msgctxt "#32011" msgid "Scrobbling" -msgstr "" +msgstr "Scrobbling" msgctxt "#32012" msgid "Scrobble movies" -msgstr "" +msgstr "Scrobble סרטים" msgctxt "#32013" msgid "Scrobble TV show episodes" -msgstr "" +msgstr "Scrobble פרקי סדרות" msgctxt "#32014" msgid "Show notification on scrobble" -msgstr "" +msgstr "הצג התראה בעת ביצוע Scrobble" msgctxt "#32015" msgid "Trakt - Scrobbled successfully" -msgstr "" +msgstr "Trakt - Scrobble הצליח" msgctxt "#32016" msgid "Exclusions" -msgstr "" +msgstr "הכללות" msgctxt "#32017" msgid "Exclude Live TV" -msgstr "" +msgstr "אל תכלול טלוויזיה חיה" msgctxt "#32018" msgid "Exclude HTTP sources" -msgstr "" +msgstr "אל תכלול מקורות HTTP" msgctxt "#32019" msgid "Exclude path" -msgstr "" +msgstr "אל תכלול נתיב" msgctxt "#32020" msgid "Folder's path (including subfolders)" -msgstr "" +msgstr "נתיב תיקיה (כולל תת-תיקיות)" -# empty strings from id 32021 to 32022 msgctxt "#32023" msgid "Can not connect to Trakt" -msgstr "" +msgstr "אין אפשרות להתחבר אל Trakt" msgctxt "#32024" msgid "Error" -msgstr "" +msgstr "שגיאה" -# empty string with id 32025 msgctxt "#32026" msgid "What Did You Think?" -msgstr "" +msgstr "מה חשבת?" msgctxt "#32027" msgid "Totally Ninja!" -msgstr "" +msgstr "מטורף לגמרי!" msgctxt "#32028" msgid "Weak Sauce :(" -msgstr "" +msgstr "על הפנים :(" msgctxt "#32029" msgid "Terrible" -msgstr "" +msgstr "נוראי" msgctxt "#32030" msgid "Bad" -msgstr "" +msgstr "רע" msgctxt "#32031" msgid "Poor" -msgstr "" +msgstr "חלש" msgctxt "#32032" msgid "Meh" -msgstr "" +msgstr "נחמד" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "בסדר" msgctxt "#32034" msgid "Good" -msgstr "" +msgstr "טוב" msgctxt "#32035" msgid "Great" -msgstr "" +msgstr "מעולה" msgctxt "#32036" msgid "Superb" -msgstr "" +msgstr "סוף הדרך" msgctxt "#32037" msgid "Unrate this movie" -msgstr "" +msgstr "הסר דירוג מסרט זה" msgctxt "#32038" msgid "Unrate this show" -msgstr "" +msgstr "הסר דירוג מסדרה זו" msgctxt "#32039" msgid "Unrate this episode" -msgstr "" +msgstr "הסר דירוג מפרק זה" msgctxt "#32040" msgid "Trakt - Rating submitted successfully" -msgstr "" +msgstr "Trakt - דירוג נשלח בהצלחה" msgctxt "#32041" msgid "Trakt - Already rated" -msgstr "" +msgstr "Trakt - כבר דורג" msgctxt "#32042" msgid "Trakt - Unrated successfully" -msgstr "" +msgstr "Trakt - הסרת דירוג הצליחה" msgctxt "#32043" msgid "Trakt - Already has the same rating" -msgstr "" +msgstr "Trakt - כבר יש את אותו דירוג" msgctxt "#32044" msgid "Trakt - Problem submitting rating" -msgstr "" +msgstr "Trakt - בעיה בשליחת דירוג" msgctxt "#32045" msgid "Synchronize" -msgstr "" +msgstr "סנכרון" msgctxt "#32046" msgid "Movies" -msgstr "" +msgstr "סרטים" msgctxt "#32047" msgid "Add new movies to Trakt collection" -msgstr "" +msgstr "הוסף סרטים חדשים לאוסף של Trakt" msgctxt "#32048" msgid "Add watched movies to Trakt history" -msgstr "" +msgstr "הוסף סרטים שנצפו להיסטוריה של Trakt" msgctxt "#32049" msgid "Mark movies from Trakt history as watched in Kodi" -msgstr "" +msgstr "סמן סרטים מהיסטוריה של Trakt כנצפו ב-Kodi" msgctxt "#32050" msgid "TV Episodes" -msgstr "" +msgstr "פרקי סדרה" msgctxt "#32051" msgid "Add new TV episodes to Trakt collection" -msgstr "" +msgstr "הוסף פרקי סדרה חדשים לאוסף של Trakt" msgctxt "#32052" msgid "Add watched TV episodes to Trakt history" -msgstr "" +msgstr "הוסף פרקי סדרה שנצפו להיסטוריה של Trakt" msgctxt "#32053" msgid "Mark TV episodes from Trakt history as watched in Kodi" -msgstr "" +msgstr "סמן פרקי סדרה מהיסטוריה של Trakt כנצפו ב-Kodi" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "שירות" msgctxt "#32055" msgid "Sync collection on library update or cleaning" -msgstr "" +msgstr "סנכרן אוסף בעדכון ספריה או ניקוי" msgctxt "#32056" msgid "Show sync notifications" -msgstr "" +msgstr "הצג התראות סנכרון" msgctxt "#32057" msgid "Remove deleted movies from Trakt collection" -msgstr "" +msgstr "הסר סרטים שנמחקו מהאוסף של Trakt" msgctxt "#32058" msgid "Remove deleted TV episodes from Trakt collection" -msgstr "" +msgstr "הסר פרקי סדרה שנמחקו מהאוסף של Trakt" -# empty string with id 32059 msgctxt "#32060" msgid "Hide notifications during playback" -msgstr "" +msgstr "הסתר התראות בזמן צפייה" msgctxt "#32061" msgid "Sync started" -msgstr "" +msgstr "סנכרון התחיל" msgctxt "#32062" msgid "Sync complete" -msgstr "" +msgstr "סנכרון הסתיים" msgctxt "#32063" msgid "%i movie(s) will be added to Trakt collection" -msgstr "" +msgstr "%i סרט(ים) יתווספו לאוסף של Trakt" msgctxt "#32064" msgid "%i movie playcount(s) will be updated on Trakt" -msgstr "" +msgstr "%i מספר(י) ניגון סרט יועדכנו ב-Trakt" msgctxt "#32065" msgid "%i movie(s) playcount will be updated in Kodi" -msgstr "" +msgstr "%i מספר ניגון סרט(ים) יועדכנו ב-trakt" msgctxt "#32066" msgid "Movie Sync Complete" -msgstr "" +msgstr "סנכרון סרט הסתיים" msgctxt "#32067" msgid "Going to add %i show(s) to Trakt collection" -msgstr "" +msgstr "מתכונן להוסיף %i סדרה(ות) לאוסף של Trakt" msgctxt "#32068" msgid "Checking for episodes missing from Trakt collection" -msgstr "" +msgstr "בודק פרקים שחסרים מהאוסף של Trakt" msgctxt "#32069" msgid "%i of %i show(s) have episodes added to Trakt collection" -msgstr "" +msgstr "%i מתוך %i סדרה(ות) יש פרקים שמתווספים לאוסף של Trakt" msgctxt "#32070" msgid "Going to update %i show(s) missing watched status" -msgstr "" +msgstr "מתכונן לעדכן %i סדרה(ות) סטטוס צפייה שחסרים" msgctxt "#32071" msgid "Checking watched episodes on Trakt" -msgstr "" +msgstr "בודק פרקים שנצפו ב- Trakt" msgctxt "#32072" msgid "%i show(s) had missing watched status" -msgstr "" +msgstr "ל- %i סדרה(ות) יש סטטוס צפייה שחסרים" msgctxt "#32073" msgid "%i episodes are being updated" -msgstr "" +msgstr "%i פרקים מתעדכנים כעת" msgctxt "#32074" msgid "Checking watched episodes on Kodi" -msgstr "" +msgstr "בודק פרקים שנצפו ב- Kodi" msgctxt "#32075" msgid "Episode Sync Complete" -msgstr "" +msgstr "סנכרון פרק הסתיים" msgctxt "#32076" msgid "%i movie(s) will be removed from Trakt collection" -msgstr "" +msgstr "%i סרט(ים) יוסרו מהאוסף של Trakt" msgctxt "#32077" msgid "Cleaning Trakt TV show collection" -msgstr "" +msgstr "מנקה את האוסף סדרות של Trakt" msgctxt "#32078" msgid "episodes are being removed" -msgstr "" +msgstr "פרקים נמחקים" msgctxt "#32079" msgid "Loading movies from Kodi" -msgstr "" +msgstr "טוען סרטים מ-Kodi" msgctxt "#32080" msgid "Movies loaded from Kodi" -msgstr "" +msgstr "סרטים נטענו מ-Kodi" msgctxt "#32081" msgid "Retrieving movie collection from Trakt" -msgstr "" +msgstr "מקבל אוסף סרטים מ-Trakt" msgctxt "#32082" msgid "Retrieving watched movies from Trakt" -msgstr "" +msgstr "מקבל סרטים שנצפו נ-Trakt" msgctxt "#32083" msgid "Retrieved movie data from Trakt" -msgstr "" +msgstr "התקבלו נתוני סרט מ-Trakt" msgctxt "#32084" msgid "Trakt movie collection is up to date, no movies to add" -msgstr "" +msgstr "אוסף הסרטים של Trakt מעודכן, אין סרטים להוסיף" msgctxt "#32085" msgid "%i movie(s) were added to your Trakt collection" -msgstr "" +msgstr "%i סרט(ים) התווספו לאוסף Trakt שלך" msgctxt "#32086" msgid "Trakt movie playcounts are up to date" -msgstr "" +msgstr "מספרי ניגון סרט מעודכנים ב-Trakt" msgctxt "#32087" msgid "Playcounts updated for %i movie(s) on Trakt" -msgstr "" +msgstr "מספרי ניגון עודכנו עבור %i סרט(ים) ב-Trakt" msgctxt "#32088" msgid "Kodi movie playcounts are up to date" -msgstr "" +msgstr "מספרי ניגון סרט מעודכנים ב-Kodi" msgctxt "#32089" msgid "Updating %i of %i movie playcount(s) in Kodi" -msgstr "" +msgstr "מעדכן %i מתוך %i מספר(י) ניגון סרט ב-Kodi" msgctxt "#32090" msgid "Playcounts updated for %i movie(s) in Kodi" -msgstr "" +msgstr "מספרי ניגון עודכנו עבור %i סרט(ים) ב-Kodi" msgctxt "#32091" msgid "Trakt movie collection is up to date, no movies removed" -msgstr "" +msgstr "אוסף הסרטים של Trakt מעודכן, אין סרטים להסיר" msgctxt "#32092" msgid "%i movie(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i סרט(ים) הוסרו מהאוסף Trakt שלך" msgctxt "#32093" msgid "Updating %i of %i movie playcount(s) on Trakt" -msgstr "" +msgstr "מעדכן %i מתוך %i מספר(י) ניגון סרט ב-Trakt" msgctxt "#32094" msgid "Loading episode data from Kodi" -msgstr "" +msgstr "טוען נתוני פרק מ-Kodi" msgctxt "#32095" msgid "Loading shows from Kodi" -msgstr "" +msgstr "טוען סדרות Kodi" msgctxt "#32096" msgid "Shows loaded from Kodi" -msgstr "" +msgstr "סדרות נטענו מ-Kodi" msgctxt "#32097" msgid "Parsing %i of %i episode data from Kodi" -msgstr "" +msgstr "מנתח %i מתוך %i נתוני פרק מ-Kodi" msgctxt "#32098" msgid "Loaded episode data from Kodi" -msgstr "" +msgstr "נטענו נתוני פרק מ-Kodi" msgctxt "#32099" msgid "Loading episode data from Trakt" -msgstr "" +msgstr "טוען נתוני פרק מ-Trakt" msgctxt "#32100" msgid "Retrieving episode collection from Trakt" -msgstr "" +msgstr "מקבל אוסף פרקים מ-Trakt" msgctxt "#32101" msgid "Retrieving watched episodes from Trakt" -msgstr "" +msgstr "מקבל פרקים שנצפו מ-Trakt" msgctxt "#32102" msgid "Parsing episode data %i of %i from Trakt" -msgstr "" +msgstr "מנתח %i מתוך %i נתוני פרק מ-Trakt" msgctxt "#32103" msgid "Retrieved episode data from Trakt" -msgstr "" +msgstr "התקבל נתוני פרק מ-Trakt" msgctxt "#32104" msgid "Trakt episode collection is up to date, no episodes to add" -msgstr "" +msgstr "אוסף הפרקים של Trakt מעודכן, אין סרטים להוסיף" msgctxt "#32105" msgid "%i episode(s) were added to your Trakt collection" -msgstr "" +msgstr "%i פרק(ים) התווספו לאוסף Trakt שלך" msgctxt "#32106" msgid "Trakt episode playcounts are up to date" -msgstr "" +msgstr "מספרי ניגון פרק מעודכנים ב-Trakt" msgctxt "#32107" msgid "Kodi episode playcounts are up to date" -msgstr "" +msgstr "מספרי ניגון פרק מעודכנים ב-Kodi" msgctxt "#32108" msgid "Updating %i of %i episode playcount(s) in Kodi" -msgstr "" +msgstr "מעדכן %i מתוך %i מספר(י) ניגון פרק ב-Kodi" msgctxt "#32109" msgid "Playcounts updated for %i show(s) in Kodi" -msgstr "" +msgstr "מספרי ניגון עודכנו עבור %i סדרה(ות) ב-Kodi" msgctxt "#32110" msgid "Trakt episode collection is clean, no episodes to remove" -msgstr "" +msgstr "אוסף הפרקים של Trakt מעודכן, אין סרטים להסיר" msgctxt "#32111" msgid "%i episode(s) are being removed from your Trakt collection" -msgstr "" +msgstr "%i פרק(ים) נמחקים כעת מהאוסף Trakt שלך" msgctxt "#32112" msgid "%i episode(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i פרק(ים) הוסרו מהאוסף Trakt שלך" msgctxt "#32113" msgid "Trakt - Marked as watched" -msgstr "" +msgstr "Trakt - סומנו כנצפו" msgctxt "#32114" msgid "Trakt - Failed marking as watched" -msgstr "" +msgstr "Trakt - נכשל בסימון כנצפו" msgctxt "#32115" msgid "%d episode(s) of '%s'" -msgstr "" +msgstr "%d פרק(ים) מתוך '%s'" msgctxt "#32116" msgid "Enable debug mode" -msgstr "" +msgstr "הפעל מצב ניפוי שגיאות" msgctxt "#32117" msgid "Sync movie playback progress to Kodi" -msgstr "" +msgstr "סנכרון תהליך צפיית סרט אל Kodi" msgctxt "#32118" msgid "Sync episode playback progress to Kodi" -msgstr "" +msgstr "סנכרן תהליך צפיית פרק אל Kodi" msgctxt "#32119" msgid "Retrieving episode playback progress from Trakt" -msgstr "" +msgstr "מקבל תהליך צפיית פרק מ-Trakt" msgctxt "#32120" msgid "Parsing episode playback progress %i of %i from Trakt" -msgstr "" +msgstr "מנתח תהליך צפיית פרק %i מתוך %i מ-Trakt" msgctxt "#32121" msgid "Retrieved episode playback progress from Trakt" -msgstr "" +msgstr "התקבל תהליך צפיית פרק מ-Trakt" msgctxt "#32122" msgid "Retrieving movie playback progress from Trakt" -msgstr "" +msgstr "מקבל תהליך צפיית סרט מ-Trakt" msgctxt "#32123" msgid "Parsing movie playback progress %i of %i from Trakt" -msgstr "" +msgstr "מנתח תהליך צפיית סרט %i מתוך %i מ-Trakt" msgctxt "#32124" msgid "Retrieved movie playback progress from Trakt" -msgstr "" +msgstr "התקבל תהליך צפיית סרט מ-Trakt" msgctxt "#32125" msgid "Kodi movie playback progress is up to date" -msgstr "" +msgstr "תהליך צפיית סרט ב-Kodi מעודכן" msgctxt "#32126" msgid "%i movie(s) playback progress will be updated in Kodi" -msgstr "" +msgstr "ל-%i סרט(ים) יעודכנו תהלך הצפייה" msgctxt "#32127" msgid "Updating %i of %i movie(s) playback progress in Kodi" -msgstr "" +msgstr "מעדכן תהליך צפייה %i מתוך %i סרט(ים)" msgctxt "#32128" msgid "Playback progress updated for %i movie(s) in Kodi" -msgstr "" +msgstr "תהליך צפייה עודכן ל-%i סרט(ים) ב-Kodi" msgctxt "#32129" msgid "Kodi episode playback progress is up to date" -msgstr "" +msgstr "תהליך צפיית פרק ב-Kodi מעודכן" msgctxt "#32130" msgid "Updating %i of %i episode(s) playback progress in Kodi" -msgstr "" +msgstr "מעדכן תהליך צפייה %i מתוך %i פרק(ים)" msgctxt "#32131" msgid "Playback progress updated for %i episode(s) in Kodi" -msgstr "" +msgstr "תהליך צפייה עודכן ל-%i פרק(ים) ב-Kodi" msgctxt "#32132" msgid "Unrate this season" -msgstr "" +msgstr "הסר דירוג מעונה זו" msgctxt "#32133" msgid "Manage Movie's Lists" -msgstr "" +msgstr "ניהול רשימות סרט" msgctxt "#32134" msgid "Manage Show's Lists" -msgstr "" +msgstr "ניהול רשימות סדרה" msgctxt "#32135" msgid "Remove from Watchlist" -msgstr "" +msgstr "הסר מרשימת צפייה" msgctxt "#32136" msgid "Add to watchlist" -msgstr "" +msgstr "הוסף לרשימת צפייה" msgctxt "#32137" msgid "Rate this movie" -msgstr "" +msgstr "דרג סרט זה" msgctxt "#32138" msgid "Rate this show" -msgstr "" +msgstr "דרג סדרה זו" msgctxt "#32139" msgid "Rate this episode" -msgstr "" +msgstr "דרג פרק זה" msgctxt "#32140" msgid "Toggle watched" -msgstr "" +msgstr "סמן כנצפה" msgctxt "#32141" msgid "Manage all lists" -msgstr "" +msgstr "נהל את כל הרשימות" msgctxt "#32142" msgid "Update all tags" -msgstr "" +msgstr "עדכן את כל התגיות" msgctxt "#32143" msgid "Synchronize library" -msgstr "" +msgstr "סנכרן ספריה" msgctxt "#32144" msgid "How do I authorize the trakt addon to access my trakt.tv account?" -msgstr "" +msgstr "איך אני מאשר גישה לתוסף Trakt לחשבון שלי ב-trakt.tv?" -# empty strings from id 32145 to 32146 msgctxt "#32147" msgid "Trakt.tv PIN Authorization Failed" -msgstr "" +msgstr "אישור קוד PIN של Trakt.tv נכשל" -# empty string with id 32148 msgctxt "#32149" msgid "Rate this Season" -msgstr "" +msgstr "דרג עונה זו" msgctxt "#32150" msgid "You will be reminded in 24 hours" -msgstr "" +msgstr "תקבל תזכורת בעוד 24 שעות" msgctxt "#32151" msgid "Use Addon Settings later if you change your mind" -msgstr "" +msgstr "השתמש בהגדרות תוסף מאוחר יותר עם תשנה את דעתך" msgctxt "#32152" msgid "Trakt Authorization Complete" -msgstr "" +msgstr "אישור Trakt הושלם" msgctxt "#32153" msgid "Trakt Account Authorization" -msgstr "" +msgstr "אישור חשבון Trakt" msgctxt "#32154" msgid "Authorize" -msgstr "" +msgstr "אישור" msgctxt "#32155" msgid "Remind Me Later" -msgstr "" +msgstr "תזכיר לי מאוחר יותר" msgctxt "#32156" msgid "No Thanks" -msgstr "" +msgstr "לא תודה" msgctxt "#32157" msgid "Account Authorization" -msgstr "" +msgstr "אישור חשבון" # empty string with id 32158 msgctxt "#32159" @@ -631,23 +625,23 @@ msgstr "" msgctxt "#32162" msgid "The trakt addon CAN NOT be used without authorizing it to access your trakt.tv account." -msgstr "" +msgstr "אין אפשרות להשתמש בתוסף Trakt ללא אישור גישה לחשבון שלך ב-trakt.tv." msgctxt "#32163" msgid "User" -msgstr "" +msgstr "משתמש" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" -msgstr "" +msgstr "השתמש בהתאמה של כותרת/שנה אם יש צורך" msgctxt "#32165" msgid "Trakt - Added to watchlist" -msgstr "" +msgstr "Trakt - התווסף לרשימת צפייה" msgctxt "#32166" msgid "Trakt - Failed adding to watchlist" -msgstr "" +msgstr "Trakt - הוספה לרשימת צפייה נכשלה" msgctxt "#32167" msgid "Offset scrobble start by X minutes" @@ -768,3 +762,19 @@ msgstr "" msgctxt "#42191" msgid "Optional password needed to authenticate with the proxy." msgstr "" + +#~ msgctxt "#32003" +#~ msgid "Startup Delay" +#~ msgstr "השהיית הפעלה" + +#~ msgctxt "#32159" +#~ msgid "Visit {0} or scan the QR Code below." +#~ msgstr "בקר ב- {0} או סרוק את קוד ה-QR למטה." + +#~ msgctxt "#32160" +#~ msgid "Authorize the trakt addon to access your account." +#~ msgstr "אשר את התוסף Trakt כדי לגשת אל החשבון שלך" + +#~ msgctxt "#32161" +#~ msgid "Enter the PIN provided in the box below." +#~ msgstr "הזן את קוד ה-PIN שקיבלת בקופסא למטה." diff --git a/script.trakt/resources/language/resource.language.nb_no/strings.po b/script.trakt/resources/language/resource.language.nb_no/strings.po index 5db1be9d5..4c93c1581 100644 --- a/script.trakt/resources/language/resource.language.nb_no/strings.po +++ b/script.trakt/resources/language/resource.language.nb_no/strings.po @@ -8,13 +8,13 @@ msgstr "" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: nb_no\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: Norwegian (http://www.transifex.com/projects/p/xbmc-addons/language/no/)\n" +"Language: no\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" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,10 +24,9 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "Generelt" # empty strings from id 32001 to 32002 msgctxt "#32003" @@ -36,198 +35,195 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Rangering/aldersgrense" msgctxt "#32005" msgid "Rate Movie after watching" -msgstr "" +msgstr "Gi vurdering etter å ha sett" msgctxt "#32006" msgid "Rate TV show Episode after watching" -msgstr "" +msgstr "Gi vurdering på Tv-program etter å ha sett" msgctxt "#32008" msgid "Minimum percent watched to display rating dialog" -msgstr "" +msgstr "Minimum prosent sett for å spørre om vurdering" msgctxt "#32009" msgid "Allow re-rating of media" -msgstr "" +msgstr "Tillat overskriving av vurdering" msgctxt "#32010" msgid "Default rating" -msgstr "" +msgstr "Standard vurdering" -# Scrobbling Settings msgctxt "#32011" msgid "Scrobbling" -msgstr "" +msgstr "Scrobbling" msgctxt "#32012" msgid "Scrobble movies" -msgstr "" +msgstr "Scrobble filmer" msgctxt "#32013" msgid "Scrobble TV show episodes" -msgstr "" +msgstr "Scrobble TV-programmer og episoder" msgctxt "#32014" msgid "Show notification on scrobble" -msgstr "" +msgstr "Vis scrobble-varsel" msgctxt "#32015" msgid "Trakt - Scrobbled successfully" -msgstr "" +msgstr "Trakt - Scrobble vellykket" msgctxt "#32016" msgid "Exclusions" -msgstr "" +msgstr "Unntak" msgctxt "#32017" msgid "Exclude Live TV" -msgstr "" +msgstr "Ekskluder Live TV" msgctxt "#32018" msgid "Exclude HTTP sources" -msgstr "" +msgstr "Ekskluder HTTP-kilder" msgctxt "#32019" msgid "Exclude path" -msgstr "" +msgstr "Ekskluder sti" msgctxt "#32020" msgid "Folder's path (including subfolders)" -msgstr "" +msgstr "Mappens sti (inkludert undermapper)" -# empty strings from id 32021 to 32022 msgctxt "#32023" msgid "Can not connect to Trakt" -msgstr "" +msgstr "Kunne ikke koble til Trakt" msgctxt "#32024" msgid "Error" -msgstr "" +msgstr "Feil" -# empty string with id 32025 msgctxt "#32026" msgid "What Did You Think?" -msgstr "" +msgstr "Hva synes du?" msgctxt "#32027" msgid "Totally Ninja!" -msgstr "" +msgstr "Helt ninja!" msgctxt "#32028" msgid "Weak Sauce :(" -msgstr "" +msgstr "Svak saus :(" msgctxt "#32029" msgid "Terrible" -msgstr "" +msgstr "Forferdelig" msgctxt "#32030" msgid "Bad" -msgstr "" +msgstr "Elendig" msgctxt "#32031" msgid "Poor" -msgstr "" +msgstr "Dårlig" msgctxt "#32032" msgid "Meh" -msgstr "" +msgstr "Meh" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Greit" msgctxt "#32034" msgid "Good" -msgstr "" +msgstr "Bra" msgctxt "#32035" msgid "Great" -msgstr "" +msgstr "Kjempebra" msgctxt "#32036" msgid "Superb" -msgstr "" +msgstr "Supert" msgctxt "#32037" msgid "Unrate this movie" -msgstr "" +msgstr "Fjern vurdering av denne filmen" msgctxt "#32038" msgid "Unrate this show" -msgstr "" +msgstr "Fjern vurdering av dette TV-programmet" msgctxt "#32039" msgid "Unrate this episode" -msgstr "" +msgstr "Fjern vurdering av denne episoden" msgctxt "#32040" msgid "Trakt - Rating submitted successfully" -msgstr "" +msgstr "Trakt - Vurdering ble lagt til" msgctxt "#32041" msgid "Trakt - Already rated" -msgstr "" +msgstr "Trakt - Allerede vurdert" msgctxt "#32042" msgid "Trakt - Unrated successfully" -msgstr "" +msgstr "Trakt - Vurdering fjernet" msgctxt "#32043" msgid "Trakt - Already has the same rating" -msgstr "" +msgstr "Trakt - Har allerede samme vurdering" msgctxt "#32044" msgid "Trakt - Problem submitting rating" -msgstr "" +msgstr "Trakt - Kunne ikke legge til vurdering" msgctxt "#32045" msgid "Synchronize" -msgstr "" +msgstr "Synkroniser" msgctxt "#32046" msgid "Movies" -msgstr "" +msgstr "Filmer" msgctxt "#32047" msgid "Add new movies to Trakt collection" -msgstr "" +msgstr "Legg til filmer i Trakt-samlingen" msgctxt "#32048" msgid "Add watched movies to Trakt history" -msgstr "" +msgstr "Legg til filmer markert sett i Trakt-historien" msgctxt "#32049" msgid "Mark movies from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marker filmer fra Trakt-historien som sett i Kodi" msgctxt "#32050" msgid "TV Episodes" -msgstr "" +msgstr "TV-Episoder" msgctxt "#32051" msgid "Add new TV episodes to Trakt collection" -msgstr "" +msgstr "Legg til TV-episoder i Trakt-samling" msgctxt "#32052" msgid "Add watched TV episodes to Trakt history" -msgstr "" +msgstr "Legg til TV-episoder markert sett i Trakt-historie" msgctxt "#32053" msgid "Mark TV episodes from Trakt history as watched in Kodi" -msgstr "" +msgstr "Merk TV-episoder fra Trakt-historie som sett i Kodi" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Tjeneste" msgctxt "#32055" msgid "Sync collection on library update or cleaning" -msgstr "" +msgstr "Synkroniser samling når biblioteket oppdateres eller renses" msgctxt "#32056" msgid "Show sync notifications" @@ -235,240 +231,239 @@ msgstr "" msgctxt "#32057" msgid "Remove deleted movies from Trakt collection" -msgstr "" +msgstr "Fjern slettede filmer fra Trakt-samling" msgctxt "#32058" msgid "Remove deleted TV episodes from Trakt collection" -msgstr "" +msgstr "Fjern slettede TV-episoder fra Trakt-samling" -# empty string with id 32059 msgctxt "#32060" msgid "Hide notifications during playback" -msgstr "" +msgstr "Skjul varslinger under avspilling" msgctxt "#32061" msgid "Sync started" -msgstr "" +msgstr "Synkronisering startet" msgctxt "#32062" msgid "Sync complete" -msgstr "" +msgstr "Synkronisering ferdig" msgctxt "#32063" msgid "%i movie(s) will be added to Trakt collection" -msgstr "" +msgstr "%i film(er) vil bli lagt til i Trakt-samlingen" msgctxt "#32064" msgid "%i movie playcount(s) will be updated on Trakt" -msgstr "" +msgstr "%i filmavspilling(er) vil bli oppdatert på Trakt" msgctxt "#32065" msgid "%i movie(s) playcount will be updated in Kodi" -msgstr "" +msgstr "%i filmavspilling(er) vil bli oppdatert i Kodi" msgctxt "#32066" msgid "Movie Sync Complete" -msgstr "" +msgstr "Synkronisering av filmer ferdig" msgctxt "#32067" msgid "Going to add %i show(s) to Trakt collection" -msgstr "" +msgstr "Legger til %i program(mer) til Trakt-samling" msgctxt "#32068" msgid "Checking for episodes missing from Trakt collection" -msgstr "" +msgstr "Sjekker etter manglende episoder i Trakt-samling" msgctxt "#32069" msgid "%i of %i show(s) have episodes added to Trakt collection" -msgstr "" +msgstr "%i av %i program(mer) har episoder lagt til i Trakt-samlingen" msgctxt "#32070" msgid "Going to update %i show(s) missing watched status" -msgstr "" +msgstr "Oppdaterer %i program(mer)s manglende sett-status" msgctxt "#32071" msgid "Checking watched episodes on Trakt" -msgstr "" +msgstr "Sjekker etter episoder markert sett på Trakt" msgctxt "#32072" msgid "%i show(s) had missing watched status" -msgstr "" +msgstr "%i program(mer) manglet sett-status" msgctxt "#32073" msgid "%i episodes are being updated" -msgstr "" +msgstr "%i episoder blir oppdatert" msgctxt "#32074" msgid "Checking watched episodes on Kodi" -msgstr "" +msgstr "Sjekker episoder markert sett i Kodi" msgctxt "#32075" msgid "Episode Sync Complete" -msgstr "" +msgstr "Synkronisering av episode ferdig" msgctxt "#32076" msgid "%i movie(s) will be removed from Trakt collection" -msgstr "" +msgstr "%i film(er) blir fjernet fra Trakt-samlingen" msgctxt "#32077" msgid "Cleaning Trakt TV show collection" -msgstr "" +msgstr "Renser TV-programsamling" msgctxt "#32078" msgid "episodes are being removed" -msgstr "" +msgstr "episoder fjernes" msgctxt "#32079" msgid "Loading movies from Kodi" -msgstr "" +msgstr "Laster filmer fra Kodi" msgctxt "#32080" msgid "Movies loaded from Kodi" -msgstr "" +msgstr "Filmer fra Kodi lastet" msgctxt "#32081" msgid "Retrieving movie collection from Trakt" -msgstr "" +msgstr "Henter film-samling fra Trakt" msgctxt "#32082" msgid "Retrieving watched movies from Trakt" -msgstr "" +msgstr "Henter filmer markert sett fra Trakt" msgctxt "#32083" msgid "Retrieved movie data from Trakt" -msgstr "" +msgstr "Hentet data om film fra Trakt" msgctxt "#32084" msgid "Trakt movie collection is up to date, no movies to add" -msgstr "" +msgstr "Film-samlingen på Trakt er oppdatert. Ingen filmer å legge til." msgctxt "#32085" msgid "%i movie(s) were added to your Trakt collection" -msgstr "" +msgstr "%i film(er) ble lagt til i Trakt-samlingen" msgctxt "#32086" msgid "Trakt movie playcounts are up to date" -msgstr "" +msgstr "Trakt filmavspillinger er oppdatert" msgctxt "#32087" msgid "Playcounts updated for %i movie(s) on Trakt" -msgstr "" +msgstr "Avspillinger oppdatert for %i film(er) på Trakt" msgctxt "#32088" msgid "Kodi movie playcounts are up to date" -msgstr "" +msgstr "Kodi filmavspillinger er oppdatert" msgctxt "#32089" msgid "Updating %i of %i movie playcount(s) in Kodi" -msgstr "" +msgstr "Oppdaterer %i av %i filmavspilling(er) i Kodi" msgctxt "#32090" msgid "Playcounts updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Avspillingsteller oppdatert for %i film(er) i Kodi" msgctxt "#32091" msgid "Trakt movie collection is up to date, no movies removed" -msgstr "" +msgstr "filmsamlingen på Trakt er oppdatert. Ingen filmer å fjerne" msgctxt "#32092" msgid "%i movie(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i film(er) ble fjernet fra Trakt-samlingen" msgctxt "#32093" msgid "Updating %i of %i movie playcount(s) on Trakt" -msgstr "" +msgstr "Oppdaterer %i av %i filmavspilling(er) på Trakt" msgctxt "#32094" msgid "Loading episode data from Kodi" -msgstr "" +msgstr "Laster data om episode fra Kodi" msgctxt "#32095" msgid "Loading shows from Kodi" -msgstr "" +msgstr "Laster TV-programmer fra Kodi" msgctxt "#32096" msgid "Shows loaded from Kodi" -msgstr "" +msgstr "TV-programmer lastet fra kodi" msgctxt "#32097" msgid "Parsing %i of %i episode data from Kodi" -msgstr "" +msgstr "Analyserer %i av %i episodedata fra Kodi" msgctxt "#32098" msgid "Loaded episode data from Kodi" -msgstr "" +msgstr "Lastet episode-data fra Kodi" msgctxt "#32099" msgid "Loading episode data from Trakt" -msgstr "" +msgstr "Laster episode-data fra Trakt" msgctxt "#32100" msgid "Retrieving episode collection from Trakt" -msgstr "" +msgstr "Henter episode-samling fra Trakt" msgctxt "#32101" msgid "Retrieving watched episodes from Trakt" -msgstr "" +msgstr "Henter episoder markert sett fra Trakt" msgctxt "#32102" msgid "Parsing episode data %i of %i from Trakt" -msgstr "" +msgstr "Analyserer episodedata %i av %i fra Trakt" msgctxt "#32103" msgid "Retrieved episode data from Trakt" -msgstr "" +msgstr "Henter episode-data fra Trakt" msgctxt "#32104" msgid "Trakt episode collection is up to date, no episodes to add" -msgstr "" +msgstr "episode-samling på Trakt er oppdatert. Ingen episoder å legge til." msgctxt "#32105" msgid "%i episode(s) were added to your Trakt collection" -msgstr "" +msgstr "%i episode(r) ble lagt til i Trakt-samlingen" msgctxt "#32106" msgid "Trakt episode playcounts are up to date" -msgstr "" +msgstr "Trakt episodeavspillinger er oppdatert" msgctxt "#32107" msgid "Kodi episode playcounts are up to date" -msgstr "" +msgstr "Kodi episodeavspillinger er oppdatert" msgctxt "#32108" msgid "Updating %i of %i episode playcount(s) in Kodi" -msgstr "" +msgstr "Oppdaterer %i av %i episodeavspilling(er) i Kodi" msgctxt "#32109" msgid "Playcounts updated for %i show(s) in Kodi" -msgstr "" +msgstr "Avspillinger oppdatert for %i program(mer) i Kodi" msgctxt "#32110" msgid "Trakt episode collection is clean, no episodes to remove" -msgstr "" +msgstr "episodesamlingen på Trakt er renset. Ingen episoder å fjerne." msgctxt "#32111" msgid "%i episode(s) are being removed from your Trakt collection" -msgstr "" +msgstr "%i episode(r) blir fjernet fra Trakt-samlingen" msgctxt "#32112" msgid "%i episode(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i episode(r) ble fjernet fra Trakt-samlingen" msgctxt "#32113" msgid "Trakt - Marked as watched" -msgstr "" +msgstr "Trakt - Markert som sett" msgctxt "#32114" msgid "Trakt - Failed marking as watched" -msgstr "" +msgstr "Trakt - Kunne ikke markere som sett" msgctxt "#32115" msgid "%d episode(s) of '%s'" -msgstr "" +msgstr "%d episode(r) av '%s'" msgctxt "#32116" msgid "Enable debug mode" -msgstr "" +msgstr "Aktiver feilsøkingsmodus" msgctxt "#32117" msgid "Sync movie playback progress to Kodi" @@ -635,7 +630,7 @@ msgstr "" msgctxt "#32163" msgid "User" -msgstr "" +msgstr "Bruker" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" @@ -768,3 +763,7 @@ msgstr "" msgctxt "#42191" msgid "Optional password needed to authenticate with the proxy." msgstr "" + +#~ msgctxt "#32003" +#~ msgid "Startup Delay" +#~ msgstr "Forsinkelse av oppstart" diff --git a/script.trakt/resources/language/resource.language.pt_br/strings.po b/script.trakt/resources/language/resource.language.pt_br/strings.po index 93c92862c..bd8c311ce 100644 --- a/script.trakt/resources/language/resource.language.pt_br/strings.po +++ b/script.trakt/resources/language/resource.language.pt_br/strings.po @@ -7,14 +7,15 @@ msgstr "" "Project-Id-Version: XBMC Addons\n" "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: pt_br\n" +"PO-Revision-Date: 2021-03-20 15:56+0000\n" +"Last-Translator: Christian Gade \n" +"Language-Team: Portuguese (Brazil) \n" +"Language: pt_BR\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.5.1\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -24,10 +25,9 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "" -# General Settings msgctxt "#32000" msgid "General" -msgstr "" +msgstr "Geral" # empty strings from id 32001 to 32002 msgctxt "#32003" @@ -36,593 +36,587 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Classificação" msgctxt "#32005" msgid "Rate Movie after watching" -msgstr "" +msgstr "Avaliar Filme após assistir" msgctxt "#32006" msgid "Rate TV show Episode after watching" -msgstr "" +msgstr "Avaliar o Episódio de TV após assistir" msgctxt "#32008" msgid "Minimum percent watched to display rating dialog" -msgstr "" +msgstr "Percentual mínimo de assistido para apresentar o diálogo de avaliação" msgctxt "#32009" msgid "Allow re-rating of media" -msgstr "" +msgstr "Permitir reavaliar a mídia" msgctxt "#32010" msgid "Default rating" -msgstr "" +msgstr "Avaliação Padrão" -# Scrobbling Settings msgctxt "#32011" msgid "Scrobbling" -msgstr "" +msgstr "Scrobbling" msgctxt "#32012" msgid "Scrobble movies" -msgstr "" +msgstr "Scrobbling de filmes" msgctxt "#32013" msgid "Scrobble TV show episodes" -msgstr "" +msgstr "Scrobble de episódios de seriados" msgctxt "#32014" msgid "Show notification on scrobble" -msgstr "" +msgstr "Mostrar notificação no scrobble" msgctxt "#32015" msgid "Trakt - Scrobbled successfully" -msgstr "" +msgstr "Trakt - Scrobbled com sucesso" msgctxt "#32016" msgid "Exclusions" -msgstr "" +msgstr "Exclusões" msgctxt "#32017" msgid "Exclude Live TV" -msgstr "" +msgstr "Excluir Tv ao Vivo" msgctxt "#32018" msgid "Exclude HTTP sources" -msgstr "" +msgstr "Excluir fontes HTTP" msgctxt "#32019" msgid "Exclude path" -msgstr "" +msgstr "Excluir caminho" msgctxt "#32020" msgid "Folder's path (including subfolders)" -msgstr "" +msgstr "Caminho das Pastas (incluindo subpastas)" -# empty strings from id 32021 to 32022 msgctxt "#32023" msgid "Can not connect to Trakt" -msgstr "" +msgstr "Não pude me conectar ao Trakt" msgctxt "#32024" msgid "Error" -msgstr "" +msgstr "Erro" -# empty string with id 32025 msgctxt "#32026" msgid "What Did You Think?" -msgstr "" +msgstr "O que você achou?" msgctxt "#32027" msgid "Totally Ninja!" -msgstr "" +msgstr "Ninja Total!" msgctxt "#32028" msgid "Weak Sauce :(" -msgstr "" +msgstr "Sem Sal :(" msgctxt "#32029" msgid "Terrible" -msgstr "" +msgstr "Terrível" msgctxt "#32030" msgid "Bad" -msgstr "" +msgstr "Ruim" msgctxt "#32031" msgid "Poor" -msgstr "" +msgstr "Fraco" msgctxt "#32032" msgid "Meh" -msgstr "" +msgstr "Meh" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Razoável" msgctxt "#32034" msgid "Good" -msgstr "" +msgstr "Bom" msgctxt "#32035" msgid "Great" -msgstr "" +msgstr "Excelente" msgctxt "#32036" msgid "Superb" -msgstr "" +msgstr "Soberbo" msgctxt "#32037" msgid "Unrate this movie" -msgstr "" +msgstr "Remover avaliação deste filme" msgctxt "#32038" msgid "Unrate this show" -msgstr "" +msgstr "Remover avaliação deste seriado" msgctxt "#32039" msgid "Unrate this episode" -msgstr "" +msgstr "Remover avaliação deste episódio" msgctxt "#32040" msgid "Trakt - Rating submitted successfully" -msgstr "" +msgstr "Trakt - Avaliação enviada com sucesso" msgctxt "#32041" msgid "Trakt - Already rated" -msgstr "" +msgstr "Trakt - Já avaliado" msgctxt "#32042" msgid "Trakt - Unrated successfully" -msgstr "" +msgstr "Trakt - Removido avaliação com sucesso" msgctxt "#32043" msgid "Trakt - Already has the same rating" -msgstr "" +msgstr "Trakt - Sempre usar a mesma avaliação" msgctxt "#32044" msgid "Trakt - Problem submitting rating" -msgstr "" +msgstr "Trakt - Problema submetendo avaliação" msgctxt "#32045" msgid "Synchronize" -msgstr "" +msgstr "Sincronize" msgctxt "#32046" msgid "Movies" -msgstr "" +msgstr "Filmes" msgctxt "#32047" msgid "Add new movies to Trakt collection" -msgstr "" +msgstr "Adicionar novos filmes para coleção no Trakt" msgctxt "#32048" msgid "Add watched movies to Trakt history" -msgstr "" +msgstr "Adicionar filmes assistidos no histórico do Trakt" msgctxt "#32049" msgid "Mark movies from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marcar filmes como assistido no Kodi, baseado no histórico do Trakt" msgctxt "#32050" msgid "TV Episodes" -msgstr "" +msgstr "Episódios de TV" msgctxt "#32051" msgid "Add new TV episodes to Trakt collection" -msgstr "" +msgstr "Adicionar novos episódios de TV para a coleção do Trakt" msgctxt "#32052" msgid "Add watched TV episodes to Trakt history" -msgstr "" +msgstr "Adicionar episódios de TV assistidos no histórico do Trakt" msgctxt "#32053" msgid "Mark TV episodes from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marcar episódios de TV como assistido no Kodi, baseado no histórico do Trakt" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Serviço" msgctxt "#32055" msgid "Sync collection on library update or cleaning" -msgstr "" +msgstr "Sincronizar coleção ao atualizar ou limpar coleção" msgctxt "#32056" msgid "Show sync notifications" -msgstr "" +msgstr "Mostrar notificações de sincronização" msgctxt "#32057" msgid "Remove deleted movies from Trakt collection" -msgstr "" +msgstr "Remover filmes deletados da coleção no Trakt" msgctxt "#32058" msgid "Remove deleted TV episodes from Trakt collection" -msgstr "" +msgstr "Remover episódios de TV da coleção no Trakt" -# empty string with id 32059 msgctxt "#32060" msgid "Hide notifications during playback" -msgstr "" +msgstr "Ocultar notificações durante reprodução" msgctxt "#32061" msgid "Sync started" -msgstr "" +msgstr "Sincronização iniciada" msgctxt "#32062" msgid "Sync complete" -msgstr "" +msgstr "Sincronização completada" msgctxt "#32063" msgid "%i movie(s) will be added to Trakt collection" -msgstr "" +msgstr "%i filme(s) serão adicionais em sua coleção no Trakt" msgctxt "#32064" msgid "%i movie playcount(s) will be updated on Trakt" -msgstr "" +msgstr "%i de reprodução(ões) do filme serão atualizadas no Trakt" msgctxt "#32065" msgid "%i movie(s) playcount will be updated in Kodi" -msgstr "" +msgstr "%i de visualização(ões) de filmes serão atualizadas no Kodi" msgctxt "#32066" msgid "Movie Sync Complete" -msgstr "" +msgstr "Sincronização de Filmes Completada" msgctxt "#32067" msgid "Going to add %i show(s) to Trakt collection" -msgstr "" +msgstr "Indo adicionar %i seriado(s) para sua coleção no Trakt" msgctxt "#32068" msgid "Checking for episodes missing from Trakt collection" -msgstr "" +msgstr "Verificando por episódios ausentes na coleção do Trakt" msgctxt "#32069" msgid "%i of %i show(s) have episodes added to Trakt collection" -msgstr "" +msgstr "%i de %i seriado(s) possuem episódios que foram adicionados a sua coleção no Trakt" msgctxt "#32070" msgid "Going to update %i show(s) missing watched status" -msgstr "" +msgstr "Indo atualizar %i seriado(s) com estatus de assistido ausente" msgctxt "#32071" msgid "Checking watched episodes on Trakt" -msgstr "" +msgstr "Verificando episódios assistidos no Trakt" msgctxt "#32072" msgid "%i show(s) had missing watched status" -msgstr "" +msgstr "%i seriado(s) estão com estatus de assistidos ausentes" msgctxt "#32073" msgid "%i episodes are being updated" -msgstr "" +msgstr "%i episódios estão sendo atualizados" msgctxt "#32074" msgid "Checking watched episodes on Kodi" -msgstr "" +msgstr "Verificando episódios assistidos no Kodi" msgctxt "#32075" msgid "Episode Sync Complete" -msgstr "" +msgstr "Sincronização de Episódios Completado" msgctxt "#32076" msgid "%i movie(s) will be removed from Trakt collection" -msgstr "" +msgstr "%i filme(s) irão ser removidos da coleção no Trakt" msgctxt "#32077" msgid "Cleaning Trakt TV show collection" -msgstr "" +msgstr "Limpando coleção de Seriados no Trakt" msgctxt "#32078" msgid "episodes are being removed" -msgstr "" +msgstr "episódios estão sendo removidos" msgctxt "#32079" msgid "Loading movies from Kodi" -msgstr "" +msgstr "Carregando filmes do Kodi" msgctxt "#32080" msgid "Movies loaded from Kodi" -msgstr "" +msgstr "Filmes carregados do Kodi" msgctxt "#32081" msgid "Retrieving movie collection from Trakt" -msgstr "" +msgstr "Recuperando coletâneas de filmes do Trakt" msgctxt "#32082" msgid "Retrieving watched movies from Trakt" -msgstr "" +msgstr "Recuperando filmes assistidos do Trakt" msgctxt "#32083" msgid "Retrieved movie data from Trakt" -msgstr "" +msgstr "Recuperando dados do filme via Trakt" msgctxt "#32084" msgid "Trakt movie collection is up to date, no movies to add" -msgstr "" +msgstr "coleção de filmes no Trakt se encontra atualizada, nenhum filme por adicionar" msgctxt "#32085" msgid "%i movie(s) were added to your Trakt collection" -msgstr "" +msgstr "%i filme(s) foram adicionados para sua coleção no Trakt" msgctxt "#32086" msgid "Trakt movie playcounts are up to date" -msgstr "" +msgstr "Número de visualizações de filmes está atualizada no Trakt" msgctxt "#32087" msgid "Playcounts updated for %i movie(s) on Trakt" -msgstr "" +msgstr "Número de visualizações atualizadas para %i filme(s) no Trakt" msgctxt "#32088" msgid "Kodi movie playcounts are up to date" -msgstr "" +msgstr "Número de visualizações de filmes está atualizada no Kodi" msgctxt "#32089" msgid "Updating %i of %i movie playcount(s) in Kodi" -msgstr "" +msgstr "Atualizando o número de visualizações para %i de %i filme(s) no Kodi" msgctxt "#32090" msgid "Playcounts updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Número de visualizações atualizado para %i filme(s) no Kodi" msgctxt "#32091" msgid "Trakt movie collection is up to date, no movies removed" -msgstr "" +msgstr "Coleção de filmes no Trakt se encontra atualizada, nenhum filme removido" msgctxt "#32092" msgid "%i movie(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i filme(s) foram removidos de sua coleção no Trakt" msgctxt "#32093" msgid "Updating %i of %i movie playcount(s) on Trakt" -msgstr "" +msgstr "Actualizando visualizações para %i de %i filme(s) no Trakt" msgctxt "#32094" msgid "Loading episode data from Kodi" -msgstr "" +msgstr "Carregando dados dos episódios do Kodi" msgctxt "#32095" msgid "Loading shows from Kodi" -msgstr "" +msgstr "Carregando shows do Kodi" msgctxt "#32096" msgid "Shows loaded from Kodi" -msgstr "" +msgstr "Shows carregados do Kodi" msgctxt "#32097" msgid "Parsing %i of %i episode data from Kodi" -msgstr "" +msgstr "Analisando %i de %i dados de episódios via Kodi" msgctxt "#32098" msgid "Loaded episode data from Kodi" -msgstr "" +msgstr "Carregando dados do episódio do Kodi" msgctxt "#32099" msgid "Loading episode data from Trakt" -msgstr "" +msgstr "Carregando dados do episódio via Trakt" msgctxt "#32100" msgid "Retrieving episode collection from Trakt" -msgstr "" +msgstr "Recuperando coleção de episódios via Trakt" msgctxt "#32101" msgid "Retrieving watched episodes from Trakt" -msgstr "" +msgstr "Recuperando episódios assistidos via Trakt" msgctxt "#32102" msgid "Parsing episode data %i of %i from Trakt" -msgstr "" +msgstr "Analisando dados dos episódios %i de %i via Trakt" msgctxt "#32103" msgid "Retrieved episode data from Trakt" -msgstr "" +msgstr "Recuperando dados do episódio via Trakt" msgctxt "#32104" msgid "Trakt episode collection is up to date, no episodes to add" -msgstr "" +msgstr "Coleção de episódios no Trakt se encontra atualizado, nenhum episódio por adicionar" msgctxt "#32105" msgid "%i episode(s) were added to your Trakt collection" -msgstr "" +msgstr "%i episódio(s) foram adicionados em sua coleção no Trakt" msgctxt "#32106" msgid "Trakt episode playcounts are up to date" -msgstr "" +msgstr "Número de visualizações de episódios está atualizada no Trakt" msgctxt "#32107" msgid "Kodi episode playcounts are up to date" -msgstr "" +msgstr "Número de visualizações de episódios está atualizada no Kodi" msgctxt "#32108" msgid "Updating %i of %i episode playcount(s) in Kodi" -msgstr "" +msgstr "Atualizando número de visualizações para %i de %i episódio(s) no Kodi" msgctxt "#32109" msgid "Playcounts updated for %i show(s) in Kodi" -msgstr "" +msgstr "Número de visualizações atualizado para %i episódio(s) no Kodi" msgctxt "#32110" msgid "Trakt episode collection is clean, no episodes to remove" -msgstr "" +msgstr "Coleção de episódios no Trakt está limpa, nenhum episódio para remover" msgctxt "#32111" msgid "%i episode(s) are being removed from your Trakt collection" -msgstr "" +msgstr "%i episódio(s) estão sendo removidos de sua coleção no Trakt" msgctxt "#32112" msgid "%i episode(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i episódio(s) foram removidos de sua coleção no Trakt" msgctxt "#32113" msgid "Trakt - Marked as watched" -msgstr "" +msgstr "Trakt - Marcado como assistido" msgctxt "#32114" msgid "Trakt - Failed marking as watched" -msgstr "" +msgstr "Trakt - Falhou marcando como assistido" msgctxt "#32115" msgid "%d episode(s) of '%s'" -msgstr "" +msgstr "%d episódio(s) de '%s'" msgctxt "#32116" msgid "Enable debug mode" -msgstr "" +msgstr "Ativar Modo Debug" msgctxt "#32117" msgid "Sync movie playback progress to Kodi" -msgstr "" +msgstr "Sincronizando progresso de reprodução dos filmes para o Kodi" msgctxt "#32118" msgid "Sync episode playback progress to Kodi" -msgstr "" +msgstr "Sincronizando progresso de reprodução dos seriados para o Kodi" msgctxt "#32119" msgid "Retrieving episode playback progress from Trakt" -msgstr "" +msgstr "Recebendo progresso da reprodução do episódio do Trakt" msgctxt "#32120" msgid "Parsing episode playback progress %i of %i from Trakt" -msgstr "" +msgstr "Analisando progresso da reprodução dos episiodios % i de % i do Trakt" msgctxt "#32121" msgid "Retrieved episode playback progress from Trakt" -msgstr "" +msgstr "Recebendo progresso da reprodução dos episódios do Trakt" msgctxt "#32122" msgid "Retrieving movie playback progress from Trakt" -msgstr "" +msgstr "Recebendo progresso da reprodução dos filmes do Trakt" msgctxt "#32123" msgid "Parsing movie playback progress %i of %i from Trakt" -msgstr "" +msgstr "Analisando progresso da reprodução dos filmes % i de % i do Trakt" msgctxt "#32124" msgid "Retrieved movie playback progress from Trakt" -msgstr "" +msgstr "Recebendo progresso da reprodução dos filmes do Trakt" msgctxt "#32125" msgid "Kodi movie playback progress is up to date" -msgstr "" +msgstr "O progresso de reprodução dos filmes está atualizado" msgctxt "#32126" msgid "%i movie(s) playback progress will be updated in Kodi" -msgstr "" +msgstr "Vão ser atualizados %i progresso(s) da reprodução para os filme(s) no Kodi" msgctxt "#32127" msgid "Updating %i of %i movie(s) playback progress in Kodi" -msgstr "" +msgstr "Atualizando progresso de reprodução dos filmes (%i de %i) no Kodi" msgctxt "#32128" msgid "Playback progress updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Progresso de reprodução atualizado para %i filme(s) no Kodi" msgctxt "#32129" msgid "Kodi episode playback progress is up to date" -msgstr "" +msgstr "O progresso de reprodução dos seriados está atualizado" msgctxt "#32130" msgid "Updating %i of %i episode(s) playback progress in Kodi" -msgstr "" +msgstr "Atualizando progresso de reprodução dos seriados (%i de %i) no Kodi" msgctxt "#32131" msgid "Playback progress updated for %i episode(s) in Kodi" -msgstr "" +msgstr "Progresso da reprodução atualizado para %i episódio(s) no Kodi" msgctxt "#32132" msgid "Unrate this season" -msgstr "" +msgstr "Remover avaliação desta temporada" msgctxt "#32133" msgid "Manage Movie's Lists" -msgstr "" +msgstr "Gerencie Listas de Filmes" msgctxt "#32134" msgid "Manage Show's Lists" -msgstr "" +msgstr "Gerencie Listas de Seriados" msgctxt "#32135" msgid "Remove from Watchlist" -msgstr "" +msgstr "Remover da Watchlist" msgctxt "#32136" msgid "Add to watchlist" -msgstr "" +msgstr "Adicionar para lista de por assistir" msgctxt "#32137" msgid "Rate this movie" -msgstr "" +msgstr "Avaliar este filme" msgctxt "#32138" msgid "Rate this show" -msgstr "" +msgstr "Avaliar este seriado" msgctxt "#32139" msgid "Rate this episode" -msgstr "" +msgstr "Avaliar este episódio" msgctxt "#32140" msgid "Toggle watched" -msgstr "" +msgstr "Alternar para assistido" msgctxt "#32141" msgid "Manage all lists" -msgstr "" +msgstr "Gerenciar todas as listas" msgctxt "#32142" msgid "Update all tags" -msgstr "" +msgstr "Atualizar todas as etiquetas" msgctxt "#32143" msgid "Synchronize library" -msgstr "" +msgstr "Sincronizar coleção" msgctxt "#32144" msgid "How do I authorize the trakt addon to access my trakt.tv account?" -msgstr "" +msgstr "Como posso autorizar o addon trakt para acessar minha conta trakt.tv?" -# empty strings from id 32145 to 32146 msgctxt "#32147" msgid "Trakt.tv PIN Authorization Failed" -msgstr "" +msgstr "PIN de Autorização do Trakt.tv Falhou" -# empty string with id 32148 msgctxt "#32149" msgid "Rate this Season" -msgstr "" +msgstr "Avaliar esta Temporada" msgctxt "#32150" msgid "You will be reminded in 24 hours" -msgstr "" +msgstr "Serás lembrado em 24 horas" msgctxt "#32151" msgid "Use Addon Settings later if you change your mind" -msgstr "" +msgstr "Use os Ajustes do Addon mais tarde, se você mudar de idéia" msgctxt "#32152" msgid "Trakt Authorization Complete" -msgstr "" +msgstr "Autorização Trakt Completada" msgctxt "#32153" msgid "Trakt Account Authorization" -msgstr "" +msgstr "Autorização na Conta Trakt" msgctxt "#32154" msgid "Authorize" -msgstr "" +msgstr "Autorizar" msgctxt "#32155" msgid "Remind Me Later" -msgstr "" +msgstr "Lembrar-me depois" msgctxt "#32156" msgid "No Thanks" -msgstr "" +msgstr "Não Obrigado" msgctxt "#32157" msgid "Account Authorization" -msgstr "" +msgstr "Autorização na Conta" # empty string with id 32158 msgctxt "#32159" @@ -631,23 +625,23 @@ msgstr "" msgctxt "#32162" msgid "The trakt addon CAN NOT be used without authorizing it to access your trakt.tv account." -msgstr "" +msgstr "O addon do trakt NÃO PODE ser usado sem o procedimento de autorização de acesso a sua conta no trakt.tv." msgctxt "#32163" msgid "User" -msgstr "" +msgstr "Usuário" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" -msgstr "" +msgstr "Retorno para Título/Ano correspondente se necessário" msgctxt "#32165" msgid "Trakt - Added to watchlist" -msgstr "" +msgstr "Trakt - Adicionado para lista de por assistir" msgctxt "#32166" msgid "Trakt - Failed adding to watchlist" -msgstr "" +msgstr "Trakt - Falhou ao adicionar para lista de por assistir" msgctxt "#32167" msgid "Offset scrobble start by X minutes" @@ -768,3 +762,19 @@ msgstr "" msgctxt "#42191" msgid "Optional password needed to authenticate with the proxy." msgstr "" + +#~ msgctxt "#32003" +#~ msgid "Startup Delay" +#~ msgstr "Atrasar ao Inicializar" + +#~ msgctxt "#32159" +#~ msgid "Visit {0} or scan the QR Code below." +#~ msgstr "Visite {0} ou escaneie o código QR abaixo." + +#~ msgctxt "#32160" +#~ msgid "Authorize the trakt addon to access your account." +#~ msgstr "Autorize o addon do trakt acessar sua conta." + +#~ msgctxt "#32161" +#~ msgid "Enter the PIN provided in the box below." +#~ msgstr "Entre com o PIN fornecido no campo abaixo." diff --git a/script.trakt/resources/language/resource.language.pt_pt/strings.po b/script.trakt/resources/language/resource.language.pt_pt/strings.po index 64e32aa34..d8171e62a 100644 --- a/script.trakt/resources/language/resource.language.pt_pt/strings.po +++ b/script.trakt/resources/language/resource.language.pt_pt/strings.po @@ -5,17 +5,17 @@ msgid "" msgstr "" "Project-Id-Version: XBMC Addons\n" -"Report-Msgid-Bugs-To: translations@kodi.tv\n" +"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2024-01-23 10:13+0000\n" +"PO-Revision-Date: 2021-03-20 15:56+0000\n" "Last-Translator: Christian Gade \n" "Language-Team: Portuguese (Portugal) \n" -"Language: pt_pt\n" +"Language: pt_PT\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 5.3\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Weblate 4.5.1\n" msgctxt "Addon Summary" msgid "TV and movie scrobbler for Trakt.tv" @@ -25,7 +25,6 @@ msgctxt "Addon Description" msgid "Automatically scrobble all TV episodes and movies you are watching to Trakt.tv! Keep a comprehensive history of everything you've watched and be part of a global community of TV and movie enthusiasts. Sign up for a free account at http://trakt.tv and get a ton of features:[CR][CR]- Automatically scrobble what you're watching[CR]- Mobile apps for iPhone, iPad, Android, and Windows Phone[CR]- Share what you're watching (in real time) and rating to facebook and twitter[CR]- Personalized calendar so you never miss a TV show[CR]- Follow your friends and people you're interesed in[CR]- Use watchlists so you don't forget to what to watch[CR]- Track your media collections and impress your friends[CR]- Create custom lists around any topics you choose[CR]- Easily track your TV show progress across all seasons and episodes[CR]- Track your progress against industry lists such as the IMDb Top 250[CR]- Discover new shows and movies based on your viewing habits[CR]- Widgets for your forum signature[CR][CR]What can this addon do?[CR][CR]- Automatically scrobble all TV episodes and movies you are watching[CR]- Sync your TV episode and movie collections to Trakt (triggered after a library update)[CR]- Auto clean your Trakt collection so that it matches up with Kodi[CR]- Keep watched statuses synced between Kodi and Trakt[CR]- Rate movies and episode after watching them[CR][CR]Special thanks to all who contributed to this plugin! Check the commit history and changelog to see these talented developers." msgstr "Automaticamente faça scrobble de filmes e séries que está a ver para o Trakt.tv! Mantenha um histórico de tudo o que visualizou e faça parte de uma comunidade de entusiastas de filmes e séries. Inscreva-se gratuitamente para uma conta em http://trakt.tv e receba uma tonelada de funcionalidades:[CR][CR]- Scrobble automático quando está a visualizar[CR]- Aplicações moveis para iPhone, iPad, Android, Windows Phone e Blackberry[CR]- Partilhe o que está a visualizar (em tempo real) e as suas classificações no facebook e twitter[CR]- Calendário personalizado de forma a nunca perder uma série[CR]- Siga os seus amigos e pessoas de interesse[CR]- Use listas para não esquecer o que ver[CR]- Mostre as suas bibliotecas de filmes e séries aos seus amigos[CR]- Crie listas personalizadas sobre os assuntos que quiser[CR]- Verifique que espisódios já visualizou e quais faltam ver[CR]- Veja que filmes tem do IMDB TOP 250[CR]- Descubra novos filmes e séries com base nos que já viu[CR]- Widgets para usar na assinatura de fóruns[CR][CR]O que pode este addon fazer?[CR]- Scrobble automático de todos os filmes e episódios de séries que está a ver[CR]- Sincronização dos filmes e episódios de séries vistos com o Trakt (após um update da biblioteca)[CR]- Limpeza automática do Trakt de forma a ficar igual ao Kodi[CR]- Manter as visualizações sincronizadas entre o Trakt e o Kodi[CR]- Classifique filmes e episódios após visualização[CR][CR]Um obrigado especial a todos os que contribuíram para este plugin! Veja o github e o changelog para ver quem são estes programadores talentosos." -# General Settings msgctxt "#32000" msgid "General" msgstr "Geral" @@ -37,158 +36,155 @@ msgstr "" msgctxt "#32004" msgid "Rating" -msgstr "" +msgstr "Classificação" msgctxt "#32005" msgid "Rate Movie after watching" -msgstr "" +msgstr "Classificar Filme após visualização" msgctxt "#32006" msgid "Rate TV show Episode after watching" -msgstr "" +msgstr "Classificar Episódio após visualização" msgctxt "#32008" msgid "Minimum percent watched to display rating dialog" -msgstr "" +msgstr "Percentagem mínima para aparecer o diálogo de classificação" msgctxt "#32009" msgid "Allow re-rating of media" -msgstr "" +msgstr "Permitir reclassificação" msgctxt "#32010" msgid "Default rating" -msgstr "" +msgstr "Classificação padrão" -# Scrobbling Settings msgctxt "#32011" msgid "Scrobbling" -msgstr "" +msgstr "Scrobbling" msgctxt "#32012" msgid "Scrobble movies" -msgstr "" +msgstr "Scrobble de filmes" msgctxt "#32013" msgid "Scrobble TV show episodes" -msgstr "" +msgstr "Scrobble de episódios de séries" msgctxt "#32014" msgid "Show notification on scrobble" -msgstr "" +msgstr "Mostrar notificação no scrobble" msgctxt "#32015" msgid "Trakt - Scrobbled successfully" -msgstr "" +msgstr "Trakt - Scrobbled com sucesso" msgctxt "#32016" msgid "Exclusions" -msgstr "" +msgstr "Exclusões" msgctxt "#32017" msgid "Exclude Live TV" -msgstr "" +msgstr "Excluir televisão em directo" msgctxt "#32018" msgid "Exclude HTTP sources" -msgstr "" +msgstr "Excluir fontes de HTTP" msgctxt "#32019" msgid "Exclude path" -msgstr "" +msgstr "Excluir directório" msgctxt "#32020" msgid "Folder's path (including subfolders)" -msgstr "" +msgstr "Caminho para as pastas (inclui sub-pastas)" -# empty strings from id 32021 to 32022 msgctxt "#32023" msgid "Can not connect to Trakt" -msgstr "" +msgstr "Sem ligação ao Trakt" msgctxt "#32024" msgid "Error" msgstr "Erro" -# empty string with id 32025 msgctxt "#32026" msgid "What Did You Think?" -msgstr "" +msgstr "O que achaste?" msgctxt "#32027" msgid "Totally Ninja!" -msgstr "" +msgstr "Excepcional!" msgctxt "#32028" msgid "Weak Sauce :(" -msgstr "" +msgstr "Intragável :(" msgctxt "#32029" msgid "Terrible" -msgstr "" +msgstr "Péssimo" msgctxt "#32030" msgid "Bad" -msgstr "" +msgstr "Mau" msgctxt "#32031" msgid "Poor" -msgstr "" +msgstr "Fraco" msgctxt "#32032" msgid "Meh" -msgstr "" +msgstr "Mais ou menos" msgctxt "#32033" msgid "Fair" -msgstr "" +msgstr "Razoável" msgctxt "#32034" msgid "Good" -msgstr "" +msgstr "Bom" msgctxt "#32035" msgid "Great" -msgstr "" +msgstr "Muito bom" msgctxt "#32036" msgid "Superb" -msgstr "" +msgstr "Soberbo" msgctxt "#32037" msgid "Unrate this movie" -msgstr "" +msgstr "Retirar a classificação a este filme" msgctxt "#32038" msgid "Unrate this show" -msgstr "" +msgstr "Retirar a classificação a esta série" msgctxt "#32039" msgid "Unrate this episode" -msgstr "" +msgstr "Retirar a classificação a este episódio" msgctxt "#32040" msgid "Trakt - Rating submitted successfully" -msgstr "" +msgstr "Trakt - Classificação submetida com sucesso" msgctxt "#32041" msgid "Trakt - Already rated" -msgstr "" +msgstr "Trakt - Já tinha sido classificado" msgctxt "#32042" msgid "Trakt - Unrated successfully" -msgstr "" +msgstr "Trakt - Retirada a classificação com sucesso" msgctxt "#32043" msgid "Trakt - Already has the same rating" -msgstr "" +msgstr "Trakt - Já tinha sido dada esta classificação" msgctxt "#32044" msgid "Trakt - Problem submitting rating" -msgstr "" +msgstr "Trakt - Ocorreu um problema ao submeter esta classificação" msgctxt "#32045" msgid "Synchronize" -msgstr "" +msgstr "Sincronizar" msgctxt "#32046" msgid "Movies" @@ -196,388 +192,387 @@ msgstr "Filmes" msgctxt "#32047" msgid "Add new movies to Trakt collection" -msgstr "" +msgstr "Adicionar novos filmes ao Trakt" msgctxt "#32048" msgid "Add watched movies to Trakt history" -msgstr "" +msgstr "Adicionar filmes marcado como vistos ao Trakt" msgctxt "#32049" msgid "Mark movies from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marcar filmes do histórico do Trakt como vistos no Kodi" msgctxt "#32050" msgid "TV Episodes" -msgstr "" +msgstr "Episódios de Séries" msgctxt "#32051" msgid "Add new TV episodes to Trakt collection" -msgstr "" +msgstr "Adicionar novos episódios à colecção do Trakt" msgctxt "#32052" msgid "Add watched TV episodes to Trakt history" -msgstr "" +msgstr "Adicionar episódios vistos ao histórico do Trakt" msgctxt "#32053" msgid "Mark TV episodes from Trakt history as watched in Kodi" -msgstr "" +msgstr "Marcar episódios do histórico do Trakt como vistos no Kodi" msgctxt "#32054" msgid "Service" -msgstr "" +msgstr "Serviço" msgctxt "#32055" msgid "Sync collection on library update or cleaning" -msgstr "" +msgstr "Sincronizar colecção ao actualizar ou limpar a biblioteca" msgctxt "#32056" msgid "Show sync notifications" -msgstr "" +msgstr "Mostrar notificações de sincronismo" msgctxt "#32057" msgid "Remove deleted movies from Trakt collection" -msgstr "" +msgstr "Remover filmes apagados da colecção do Trakt" msgctxt "#32058" msgid "Remove deleted TV episodes from Trakt collection" -msgstr "" +msgstr "Remover episódios apagados da colecção do Trakt" -# empty string with id 32059 msgctxt "#32060" msgid "Hide notifications during playback" -msgstr "" +msgstr "Omitir notificações durante a reprodução" msgctxt "#32061" msgid "Sync started" -msgstr "" +msgstr "Sincronização iniciada" msgctxt "#32062" msgid "Sync complete" -msgstr "" +msgstr "Sincronização concluída" msgctxt "#32063" msgid "%i movie(s) will be added to Trakt collection" -msgstr "" +msgstr "%i filme(s) serão adicionados à colecção do Trakt" msgctxt "#32064" msgid "%i movie playcount(s) will be updated on Trakt" -msgstr "" +msgstr "%i de reprodução(ões) do filme serão actualizadas no Trakt" msgctxt "#32065" msgid "%i movie(s) playcount will be updated in Kodi" -msgstr "" +msgstr "%i de visualização(ões) de filmes serão actualizadas no Kodi" msgctxt "#32066" msgid "Movie Sync Complete" -msgstr "" +msgstr "Sincronização de filmes concluída" msgctxt "#32067" msgid "Going to add %i show(s) to Trakt collection" -msgstr "" +msgstr "Vão ser adicionadas %i série(s) ao Trakt" msgctxt "#32068" msgid "Checking for episodes missing from Trakt collection" -msgstr "" +msgstr "A verificar os episódios que estão em falta na colecção do Trakt" msgctxt "#32069" msgid "%i of %i show(s) have episodes added to Trakt collection" -msgstr "" +msgstr "%i de %i série(s) têm episódios adicionados ao Trakt" msgctxt "#32070" msgid "Going to update %i show(s) missing watched status" -msgstr "" +msgstr "Vão ser actualizados os episódios marcado como vistos de %i série(s)" msgctxt "#32071" msgid "Checking watched episodes on Trakt" -msgstr "" +msgstr "A verificar episódios marcados como vistos no Trakt" msgctxt "#32072" msgid "%i show(s) had missing watched status" -msgstr "" +msgstr "%i série(s) não tinham sido marcada(s) como vista(s)" msgctxt "#32073" msgid "%i episodes are being updated" -msgstr "" +msgstr "%i episódios estão a ser actualizados" msgctxt "#32074" msgid "Checking watched episodes on Kodi" -msgstr "" +msgstr "A verificar episódios marcados como vistos no Kodi" msgctxt "#32075" msgid "Episode Sync Complete" -msgstr "" +msgstr "Sincronização de episódios concluída" msgctxt "#32076" msgid "%i movie(s) will be removed from Trakt collection" -msgstr "" +msgstr "%i filme(s) serão removidos do Trakt" msgctxt "#32077" msgid "Cleaning Trakt TV show collection" -msgstr "" +msgstr "A limpar as séries de TV da colecção do Trakt" msgctxt "#32078" msgid "episodes are being removed" -msgstr "" +msgstr "episódios estão a ser removidos" msgctxt "#32079" msgid "Loading movies from Kodi" -msgstr "" +msgstr "A carregar filmes do Kodi" msgctxt "#32080" msgid "Movies loaded from Kodi" -msgstr "" +msgstr "Filmes carregados do Kodi" msgctxt "#32081" msgid "Retrieving movie collection from Trakt" -msgstr "" +msgstr "Obter biblioteca de filmes do Trakt" msgctxt "#32082" msgid "Retrieving watched movies from Trakt" -msgstr "" +msgstr "Obter filmes marcados como vistos do Trakt" msgctxt "#32083" msgid "Retrieved movie data from Trakt" -msgstr "" +msgstr "Obter informação de filmes do Trakt" msgctxt "#32084" msgid "Trakt movie collection is up to date, no movies to add" -msgstr "" +msgstr "Biblioteca de filmes do Trakt está actualizada, sem filmes para adicionar." msgctxt "#32085" msgid "%i movie(s) were added to your Trakt collection" -msgstr "" +msgstr "%i filme(s) foram adicionados ao Trakt" msgctxt "#32086" msgid "Trakt movie playcounts are up to date" -msgstr "" +msgstr "Número de visualizações de filmes está actualizada no Trakt" msgctxt "#32087" msgid "Playcounts updated for %i movie(s) on Trakt" -msgstr "" +msgstr "Número de visualizações actualizadas para %i filme(s) no Trakt" msgctxt "#32088" msgid "Kodi movie playcounts are up to date" -msgstr "" +msgstr "Número de visualizações de filmes está actualizada no Kodi" msgctxt "#32089" msgid "Updating %i of %i movie playcount(s) in Kodi" -msgstr "" +msgstr "A actualizar o número de visualizações para %i de %i filme(s) no Kodi" msgctxt "#32090" msgid "Playcounts updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Número de visualizações actualizado para %i filme(s) no Kodi" msgctxt "#32091" msgid "Trakt movie collection is up to date, no movies removed" -msgstr "" +msgstr "A biblioteca de filmes no Trakt está actualizada, nenhum filme removido." msgctxt "#32092" msgid "%i movie(s) were removed from your Trakt collection" -msgstr "" +msgstr "%i filme(s) foram removidos da colecção do Trakt" msgctxt "#32093" msgid "Updating %i of %i movie playcount(s) on Trakt" -msgstr "" +msgstr "A actualizar visualizações para %i de %i filme(s) no Trakt" msgctxt "#32094" msgid "Loading episode data from Kodi" -msgstr "" +msgstr "A carregar episódios do Kodi" msgctxt "#32095" msgid "Loading shows from Kodi" -msgstr "" +msgstr "A carregar séries do Kodi" msgctxt "#32096" msgid "Shows loaded from Kodi" -msgstr "" +msgstr "Séries carregadas do Kodi" msgctxt "#32097" msgid "Parsing %i of %i episode data from Kodi" -msgstr "" +msgstr "A verificar dados de %i de %i episódios do Kodi" msgctxt "#32098" msgid "Loaded episode data from Kodi" -msgstr "" +msgstr "Informação de episódios carregada do Kodi" msgctxt "#32099" msgid "Loading episode data from Trakt" -msgstr "" +msgstr "Informação de episódios está a ser carregada do Trakt" msgctxt "#32100" msgid "Retrieving episode collection from Trakt" -msgstr "" +msgstr "Obter biblioteca de episódios do Trakt" msgctxt "#32101" msgid "Retrieving watched episodes from Trakt" -msgstr "" +msgstr "Obter episódios marcados como vistos do Trakt" msgctxt "#32102" msgid "Parsing episode data %i of %i from Trakt" -msgstr "" +msgstr "A verificar dados de %i de %i episódios do Trakt" msgctxt "#32103" msgid "Retrieved episode data from Trakt" -msgstr "" +msgstr "Obter dados do episódio do Trakt" msgctxt "#32104" msgid "Trakt episode collection is up to date, no episodes to add" -msgstr "" +msgstr "Biblioteca de episódios do Trakt está actualizada, sem episódios para adicionar." msgctxt "#32105" msgid "%i episode(s) were added to your Trakt collection" -msgstr "" +msgstr "%i episódio(s) foram adicionados ao Trakt" msgctxt "#32106" msgid "Trakt episode playcounts are up to date" -msgstr "" +msgstr "Número de visualizações de episódios está actualizada no Trakt" msgctxt "#32107" msgid "Kodi episode playcounts are up to date" -msgstr "" +msgstr "Número de visualizações de episódios está actualizada no Kodi" msgctxt "#32108" msgid "Updating %i of %i episode playcount(s) in Kodi" -msgstr "" +msgstr "A actualizar número de visualizações para %i de %i episódio(s) no Kodi" msgctxt "#32109" msgid "Playcounts updated for %i show(s) in Kodi" -msgstr "" +msgstr "Número de visualizações actualizado para %i episódio(s) no Kodi" msgctxt "#32110" msgid "Trakt episode collection is clean, no episodes to remove" -msgstr "" +msgstr "Biblioteca de episódios do Trakt está limpa, não há episódios para remover" msgctxt "#32111" msgid "%i episode(s) are being removed from your Trakt collection" -msgstr "" +msgstr "A remover %i episódio(s) do Trakt" msgctxt "#32112" msgid "%i episode(s) were removed from your Trakt collection" -msgstr "" +msgstr "Foram removidos %i episódio(s) do Trakt" msgctxt "#32113" msgid "Trakt - Marked as watched" -msgstr "" +msgstr "Trakt - Marcado como visto" msgctxt "#32114" msgid "Trakt - Failed marking as watched" -msgstr "" +msgstr "Trakt - Marcação como visto falhou" msgctxt "#32115" msgid "%d episode(s) of '%s'" -msgstr "" +msgstr "%d episódio(s) de '%s'" msgctxt "#32116" msgid "Enable debug mode" -msgstr "" +msgstr "Activar Modo de Depuração" msgctxt "#32117" msgid "Sync movie playback progress to Kodi" -msgstr "" +msgstr "A sincronizar progresso de reprodução dos filmes para o Kodi" msgctxt "#32118" msgid "Sync episode playback progress to Kodi" -msgstr "" +msgstr "A sincronizar progresso de reprodução das séries para o Kodi" msgctxt "#32119" msgid "Retrieving episode playback progress from Trakt" -msgstr "" +msgstr "A receber progresso da reprodução do episódio do Trakt" msgctxt "#32120" msgid "Parsing episode playback progress %i of %i from Trakt" -msgstr "" +msgstr "A analisar progresso da reprodução dos episiodios % i de % i do Trakt" msgctxt "#32121" msgid "Retrieved episode playback progress from Trakt" -msgstr "" +msgstr "A receber progresso da reprodução dos episódios do Trakt" msgctxt "#32122" msgid "Retrieving movie playback progress from Trakt" -msgstr "" +msgstr "A receber progresso da reprodução dos filmes do Trakt" msgctxt "#32123" msgid "Parsing movie playback progress %i of %i from Trakt" -msgstr "" +msgstr "A analisar progresso da reprodução dos filmes % i de % i do Trakt" msgctxt "#32124" msgid "Retrieved movie playback progress from Trakt" -msgstr "" +msgstr "A receber progresso da reprodução dos filmes do Trakt" msgctxt "#32125" msgid "Kodi movie playback progress is up to date" -msgstr "" +msgstr "O progresso de reprodução dos filmes está actualizado" msgctxt "#32126" msgid "%i movie(s) playback progress will be updated in Kodi" -msgstr "" +msgstr "Vão ser actualizados %i progresso(s) da reprodução para os filme(s) no Kodi" msgctxt "#32127" msgid "Updating %i of %i movie(s) playback progress in Kodi" -msgstr "" +msgstr "A actualizar progresso de reprodução dos filmes (%i de %i) no Kodi" msgctxt "#32128" msgid "Playback progress updated for %i movie(s) in Kodi" -msgstr "" +msgstr "Progresso de reprodução actualizado para %i filme(s) no Kodi" msgctxt "#32129" msgid "Kodi episode playback progress is up to date" -msgstr "" +msgstr "O progresso de reprodução das séries está actualizado" msgctxt "#32130" msgid "Updating %i of %i episode(s) playback progress in Kodi" -msgstr "" +msgstr "A actualizar progresso de reprodução das séries (%i de %i) no Kodi" msgctxt "#32131" msgid "Playback progress updated for %i episode(s) in Kodi" -msgstr "" +msgstr "Progresso da reprodução actualizado para %i episódio(s) no Kodi" msgctxt "#32132" msgid "Unrate this season" -msgstr "" +msgstr "Retira a classificação a esta temporada" msgctxt "#32133" msgid "Manage Movie's Lists" -msgstr "" +msgstr "Gerir Listas de Filmes" msgctxt "#32134" msgid "Manage Show's Lists" -msgstr "" +msgstr "Gerir Listas de Séries" msgctxt "#32135" msgid "Remove from Watchlist" -msgstr "" +msgstr "Remover da Watchlist" msgctxt "#32136" msgid "Add to watchlist" -msgstr "" +msgstr "Adicionar à Lista de Reprodução" msgctxt "#32137" msgid "Rate this movie" -msgstr "" +msgstr "Classifique este Filme" msgctxt "#32138" msgid "Rate this show" -msgstr "" +msgstr "Classifique esta Série" msgctxt "#32139" msgid "Rate this episode" -msgstr "" +msgstr "Classifique este Episódio" msgctxt "#32140" msgid "Toggle watched" -msgstr "" +msgstr "Alternar visto/por ver" msgctxt "#32141" msgid "Manage all lists" -msgstr "" +msgstr "Gerir Todas as Listas" msgctxt "#32142" msgid "Update all tags" -msgstr "" +msgstr "Actualizar Todas as Etiquetas" msgctxt "#32143" msgid "Synchronize library" -msgstr "" +msgstr "Sincronizar Biblioteca" msgctxt "#32144" msgid "How do I authorize the trakt addon to access my trakt.tv account?" @@ -611,19 +606,19 @@ msgstr "" msgctxt "#32154" msgid "Authorize" -msgstr "" +msgstr "Autorizar" msgctxt "#32155" msgid "Remind Me Later" -msgstr "" +msgstr "Lembrar Mais Tarde" msgctxt "#32156" msgid "No Thanks" -msgstr "" +msgstr "Não Obrigado" msgctxt "#32157" msgid "Account Authorization" -msgstr "" +msgstr "Autorização de Conta" # empty string with id 32158 msgctxt "#32159" @@ -636,7 +631,7 @@ msgstr "" msgctxt "#32163" msgid "User" -msgstr "" +msgstr "Utilizador" msgctxt "#32164" msgid "Fallback to Title/Year matching if necessary" @@ -644,11 +639,11 @@ msgstr "" msgctxt "#32165" msgid "Trakt - Added to watchlist" -msgstr "" +msgstr "Trakt - Adicionado à Watchlist" msgctxt "#32166" msgid "Trakt - Failed adding to watchlist" -msgstr "" +msgstr "Trakt - Falhou a Adicionar à Watchlist" msgctxt "#32167" msgid "Offset scrobble start by X minutes" @@ -769,3 +764,11 @@ msgstr "" msgctxt "#42191" msgid "Optional password needed to authenticate with the proxy." msgstr "" + +#~ msgctxt "#32003" +#~ msgid "Startup Delay" +#~ msgstr "Atrasar ao Iniciar" + +#~ msgctxt "#32159" +#~ msgid "Visit {0} or scan the QR Code below." +#~ msgstr "Visitar {0} ou digitalizar código QR abaixo." diff --git a/weather.multi/addon.xml b/weather.multi/addon.xml index 950382350..78c995af5 100644 --- a/weather.multi/addon.xml +++ b/weather.multi/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/weather.multi/changelog.txt b/weather.multi/changelog.txt index 9ce54b684..284e0731b 100644 --- a/weather.multi/changelog.txt +++ b/weather.multi/changelog.txt @@ -1,3 +1,15 @@ +v0.0.26 +- language update + +v0.0.25 +- reinit session with each new url + +v0.0.24 +- try multiple yahoo urls in order to get cookie + +v0.0.23 +- fix yahoo weather again + v0.0.22 - fix weatherbit ozone value could be none diff --git a/weather.multi/lib/weather.py b/weather.multi/lib/weather.py index d8a5c2cfb..87975c14a 100644 --- a/weather.multi/lib/weather.py +++ b/weather.multi/lib/weather.py @@ -3,7 +3,7 @@ from .providers import weatherbit from .providers import openweathermap -CURL = 'https://www.yahoo.com/?guccounter=2' +CURL = ['https://www.yahoo.com/', 'https://www.yahoo.com/?guccounter=1', 'https://www.yahoo.com/?guccounter=2', 'https://www.yahoo.com/?guccounter=', 'https://ca.yahoo.com/'] YURL = 'https://www.yahoo.com/news/weather/' LCURL = 'https://www.yahoo.com/news/_tdnews/api/resource/WeatherSearch;text=%s' FCURL = 'https://www.yahoo.com/news/_tdnews/api/resource/WeatherService;crumb={crumb};woeids=%5B{woeid}%5D' @@ -86,7 +86,6 @@ def get_location(self, mode): return location, locationid, locationlat, locationlon def get_ycreds(self): - ysess = requests.Session() ycookie = ADDON.getSettingString('ycookie') ycrumb = ADDON.getSettingString('ycrumb') ystamp = ADDON.getSettingString('ystamp') @@ -95,25 +94,34 @@ def get_ycreds(self): log('stamp from settings: %s' % ystamp) if ystamp == '' or (int(time.time()) - int(ystamp) > 31536000): # cookie expires after 1 year try: - retry = 0 - while (retry < 6) and (not self.MONITOR.abortRequested()): - response = ysess.get(CURL, headers=HEADERS, timeout=10) - if response.status_code == 200: + for URL in CURL: + ysess = requests.Session() + retry = 0 + while (retry < 6) and (not self.MONITOR.abortRequested()): + response = ysess.get(URL, headers=HEADERS, timeout=10) + if response.status_code == 200: + break + else: + self.MONITOR.waitForAbort(10) + retry += 1 + log('getting yahoo website failed') + if 'consent' in response.url: # EU users are asked for cookie consent + log('EU user') + token = re.search('csrfToken" value="(.*?)"', response.text, flags=re.DOTALL).group(1) + sessionid = re.search('sessionId" value="(.*?)"', response.text, flags=re.DOTALL).group(1) + redirect = re.search('originalDoneUrl" value="(.*?)"', response.text, flags=re.DOTALL).group(1) + log('EU token: %s' % token) + log('EU sessionid: %s' % sessionid) + log('EU redirect %s' % redirect) + DATA = {'csrfToken': token, 'sessionId': sessionid, 'originalDoneUrl': redirect, 'namespace': 'yahoo', 'reject': 'reject'} + response = ysess.post(response.url, headers=HEADERS, data=DATA) + log('cookies: %s' % str(response.cookies)) + if 'A3' in response.cookies: + ycookie = response.cookies['A3'] + break + elif 'A1' in response.cookies: + ycookie = response.cookies['A1'] break - else: - self.MONITOR.waitForAbort(10) - retry += 1 - log('getting yahoo website failed') - if 'consent' in response.url: # EU users are asked for cookie consent - token = re.search('csrfToken" value="(.*?)"', response.text, flags=re.DOTALL).group(1) - sessionid = re.search('sessionId" value="(.*?)"', response.text, flags=re.DOTALL).group(1) - redirect = re.search('originalDoneUrl" value="(.*?)"', response.text, flags=re.DOTALL).group(1) - DATA = {'csrfToken': token, 'sessionId': sessionid, 'originalDoneUrl': redirect, 'namespace': 'yahoo', 'reject': 'reject'} - response = ysess.post(response.url, headers=HEADERS, data=DATA) - try: - ycookie = response.cookies['A3'] - except: - ycookie = response.cookies['A1'] response = ysess.get(YURL, headers=HEADERS, cookies=dict(A3=ycookie), timeout=10) match = re.search('WeatherStore":{"crumb":"(.*?)","weathers', response.text, re.IGNORECASE) if not match: diff --git a/weather.multi/resources/language/resource.language.et_ee/strings.po b/weather.multi/resources/language/resource.language.et_ee/strings.po index f8e177a6b..0d24e7e05 100644 --- a/weather.multi/resources/language/resource.language.et_ee/strings.po +++ b/weather.multi/resources/language/resource.language.et_ee/strings.po @@ -7,15 +7,15 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2023-08-05 23:11+0000\n" -"Last-Translator: Toomas Tänava \n" +"PO-Revision-Date: 2024-03-28 06:13+0000\n" +"Last-Translator: rimasx \n" "Language-Team: Estonian \n" "Language: et_ee\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.18.2\n" +"X-Generator: Weblate 5.4\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" @@ -147,7 +147,7 @@ msgstr "Paduvihm" msgctxt "#32214" msgid "Freezing rain" -msgstr "Jäävihm" +msgstr "Jäine vihm" msgctxt "#32215" msgid "Light shower rain" @@ -199,15 +199,15 @@ msgstr "Sajuhood" msgctxt "#32227" msgid "Mist" -msgstr "Udu" +msgstr "Sumu" msgctxt "#32228" msgid "Smoke" -msgstr "Suitsuvine" +msgstr "Suits" msgctxt "#32229" msgid "Haze" -msgstr "Udu" +msgstr "Hägune" msgctxt "#32230" msgid "Sand/dust" @@ -247,183 +247,183 @@ msgstr "Teadmata sademed" msgctxt "#32251" msgid "Tornado" -msgstr "" +msgstr "Tornaado" msgctxt "#32252" msgid "Tropical Storm" -msgstr "" +msgstr "Troopiline torm" msgctxt "#32253" msgid "Hurricane" -msgstr "" +msgstr "Orkaan" msgctxt "#32254" msgid "Severe Thunderstorms" -msgstr "" +msgstr "Tugevad äikesetormid" msgctxt "#32255" msgid "Thunderstorms" -msgstr "" +msgstr "Äikesetormid" msgctxt "#32256" msgid "Mixed Rain and Snow" -msgstr "" +msgstr "Lumelörts ja vihm" msgctxt "#32257" msgid "Mixed Rain and Sleet" -msgstr "" +msgstr "Vihm ja lörts" msgctxt "#32258" msgid "Mixed Snow and Sleet" -msgstr "" +msgstr "Lumi ja lörts" msgctxt "#32259" msgid "Freezing Drizzle" -msgstr "" +msgstr "Külmavihm" msgctxt "#32260" msgid "Drizzle" -msgstr "" +msgstr "Uduvihm" msgctxt "#32261" msgid "Freezing Rain" -msgstr "" +msgstr "Jäävihm" msgctxt "#32262" msgid "Showers" -msgstr "" +msgstr "Hoovihm" msgctxt "#32263" msgid "Rain" -msgstr "" +msgstr "Vihm" msgctxt "#32264" msgid "Snow Flurries" -msgstr "" +msgstr "Lomehood" msgctxt "#32265" msgid "Light Snow Showers" -msgstr "" +msgstr "Kerged lumehood" msgctxt "#32266" msgid "Blowing Snow" -msgstr "" +msgstr "Hootine lumesadu" msgctxt "#32267" msgid "Snow" -msgstr "" +msgstr "Lumi" msgctxt "#32268" msgid "Hail" -msgstr "" +msgstr "Rahe" msgctxt "#32269" msgid "Sleet" -msgstr "" +msgstr "Lörts" msgctxt "#32270" msgid "Dust" -msgstr "" +msgstr "Tolm" msgctxt "#32271" msgid "Foggy" -msgstr "" +msgstr "Udune" msgctxt "#32272" msgid "Haze" -msgstr "" +msgstr "Hägu" msgctxt "#32273" msgid "Smoky" -msgstr "" +msgstr "Suitsuvine" msgctxt "#32274" msgid "Blustery" -msgstr "" +msgstr "Tormine" msgctxt "#32275" msgid "Windy" -msgstr "" +msgstr "Tuuline" msgctxt "#32276" msgid "Cold" -msgstr "" +msgstr "Külm" msgctxt "#32277" msgid "Cloudy" -msgstr "" +msgstr "Pilves" msgctxt "#32278" msgid "Mostly Cloudy" -msgstr "" +msgstr "Enamasti pilves" msgctxt "#32279" msgid "Partly Cloudy" -msgstr "" +msgstr "Osaliselt pilves" msgctxt "#32280" msgid "Clear" -msgstr "" +msgstr "Selge" msgctxt "#32281" msgid "Sunny" -msgstr "" +msgstr "Päikeseline" msgctxt "#32282" msgid "Fair" -msgstr "" +msgstr "Ilus" msgctxt "#32283" msgid "Mixed Rain and Hail" -msgstr "" +msgstr "Vihm ja rahe" msgctxt "#32284" msgid "Hot" -msgstr "" +msgstr "Palav" msgctxt "#32285" msgid "Isolated Thunderstorms" -msgstr "" +msgstr "Üksikud äikesetormid" msgctxt "#32286" msgid "Scattered Thunderstorms" -msgstr "" +msgstr "Hajutatud äikesetormid" msgctxt "#32287" msgid "Scattered Showers" -msgstr "" +msgstr "Hajutatud dušid" msgctxt "#32288" msgid "Heavy Rain" -msgstr "" +msgstr "Tugev vihm" msgctxt "#32289" msgid "Scattered Snow Showers" -msgstr "" +msgstr "Hajutatud lumehood" msgctxt "#32290" msgid "Heavy Snow" -msgstr "" +msgstr "Tugev lumesadu" msgctxt "#32291" msgid "Blizzard" -msgstr "" +msgstr "Tuisk" msgctxt "#32292" msgid "Not Available" -msgstr "" +msgstr "Pole saadaval" msgctxt "#32293" msgid "Scattered Showers" -msgstr "" +msgstr "Hajutatud vihmahood" msgctxt "#32294" msgid "Scattered Snow Showers" -msgstr "" +msgstr "Hajutatud lumehood" msgctxt "#32295" msgid "Scattered Thundershowers" -msgstr "" +msgstr "Hajutatud äikesevihmad" msgctxt "#32300" msgid "New Moon" diff --git a/weather.multi/resources/language/resource.language.fr_fr/strings.po b/weather.multi/resources/language/resource.language.fr_fr/strings.po index 9cd75665f..868ce74be 100644 --- a/weather.multi/resources/language/resource.language.fr_fr/strings.po +++ b/weather.multi/resources/language/resource.language.fr_fr/strings.po @@ -7,15 +7,15 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2023-01-01 16:16+0000\n" -"Last-Translator: skypichat \n" +"PO-Revision-Date: 2024-02-21 15:13+0000\n" +"Last-Translator: ludovik \n" "Language-Team: French (France) \n" "Language: fr_fr\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.15\n" +"X-Generator: Weblate 5.4\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" @@ -171,7 +171,7 @@ msgstr "Neige" msgctxt "#32220" msgid "Heavy snow" -msgstr "Beaucoup de neige" +msgstr "Neige abondante" msgctxt "#32221" msgid "Mix snow/rain" diff --git a/weather.multi/resources/language/resource.language.it_it/strings.po b/weather.multi/resources/language/resource.language.it_it/strings.po index 0bee46d4a..4c9cfb041 100644 --- a/weather.multi/resources/language/resource.language.it_it/strings.po +++ b/weather.multi/resources/language/resource.language.it_it/strings.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2023-12-12 06:11+0000\n" +"PO-Revision-Date: 2024-01-29 06:48+0000\n" "Last-Translator: Massimo Pissarello \n" "Language-Team: Italian \n" "Language: it_it\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.2.1\n" +"X-Generator: Weblate 5.3\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" @@ -223,7 +223,7 @@ msgstr "Nebbia gelata" msgctxt "#32233" msgid "Clear sky" -msgstr "Cielo limpido" +msgstr "Cielo sereno" msgctxt "#32234" msgid "Few clouds" diff --git a/weather.multi/resources/language/resource.language.nl_nl/strings.po b/weather.multi/resources/language/resource.language.nl_nl/strings.po index fbe7ffc0c..4f86169d1 100644 --- a/weather.multi/resources/language/resource.language.nl_nl/strings.po +++ b/weather.multi/resources/language/resource.language.nl_nl/strings.po @@ -7,15 +7,15 @@ msgstr "" "Project-Id-Version: Kodi add-ons\n" "Report-Msgid-Bugs-To: translations@kodi.tv\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2023-07-10 14:42+0000\n" -"Last-Translator: Natasha Ament-Teusink \n" +"PO-Revision-Date: 2024-01-29 06:48+0000\n" +"Last-Translator: Miniontoby \n" "Language-Team: Dutch \n" "Language: nl_nl\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.18.2\n" +"X-Generator: Weblate 5.3\n" msgctxt "Addon Summary" msgid "Weather forecast from several providers" @@ -399,7 +399,7 @@ msgstr "Zware regenval" msgctxt "#32289" msgid "Scattered Snow Showers" -msgstr "" +msgstr "Verspreide sneeuwbuien" msgctxt "#32290" msgid "Heavy Snow" @@ -419,11 +419,11 @@ msgstr "Verspreide Buien" msgctxt "#32294" msgid "Scattered Snow Showers" -msgstr "" +msgstr "Verspreide sneeuwbuien" msgctxt "#32295" msgid "Scattered Thundershowers" -msgstr "" +msgstr "Verspreide onweersbuien" msgctxt "#32300" msgid "New Moon"