diff options
350 files changed, 8964 insertions, 5548 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 28024af9fe..4ce8872d03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,7 +215,8 @@ endif() # find all folders containing addon.xml.in # used to define ADDON_XML_OUTPUTS, ADDON_XML_DEPENDS and ADDON_INSTALL_DATA # Function defined in ./cmake/scripts/common/Macros.cmake -find_addon_xml_in_files() +set(outputFilterRegex "addons/xbmc.json") +find_addon_xml_in_files(${outputFilterRegex}) # Compile Info add_custom_command(OUTPUT ${CORE_BUILD_DIR}/xbmc/CompileInfo.cpp @@ -227,6 +228,7 @@ add_custom_command(OUTPUT ${CORE_BUILD_DIR}/xbmc/CompileInfo.cpp -DARCH_DEFINES="${ARCH_DEFINES}" -DAPP_SCMID=${APP_SCMID} -DAPP_COPYRIGHT_YEARS=${APP_COPYRIGHT_YEARS} + -DAPP_BUILD_DATE=${APP_BUILD_DATE} -Dprefix=${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR} -P ${CMAKE_SOURCE_DIR}/cmake/scripts/common/GenerateVersionedFiles.cmake DEPENDS ${CMAKE_SOURCE_DIR}/version.txt @@ -488,6 +490,7 @@ if(VERBOSE) message(STATUS "BINARY: ${APP_NAME_LC}${APP_BINARY_SUFFIX}") message(STATUS "#---------------------------------------------#") message(STATUS "GIT_REV: ${APP_SCMID}") + message(STATUS "Build date: ${APP_BUILD_DATE}") message(STATUS "#---------------------------------------------#") message(STATUS "CPACK_GENERATOR : ${CPACK_GENERATOR}") message(STATUS "CPACK_SOURCE_GENERATOR: ${CPACK_SOURCE_GENERATOR}") diff --git a/addons/metadata.common.musicbrainz.org/addon.xml b/addons/metadata.common.musicbrainz.org/addon.xml index 70d133adc2..9ef1c2169b 100644 --- a/addons/metadata.common.musicbrainz.org/addon.xml +++ b/addons/metadata.common.musicbrainz.org/addon.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <addon id="metadata.common.musicbrainz.org" name="MusicBrainz Scraper Library" - version="2.2.0" + version="2.2.1" provider-name="Team Kodi"> <requires> <import addon="xbmc.metadata" version="2.1.0"/> diff --git a/addons/metadata.common.musicbrainz.org/musicbrainz.xml b/addons/metadata.common.musicbrainz.org/musicbrainz.xml index bdc4221676..95a88bbfd3 100644 --- a/addons/metadata.common.musicbrainz.org/musicbrainz.xml +++ b/addons/metadata.common.musicbrainz.org/musicbrainz.xml @@ -155,7 +155,7 @@ </GetMBAlbumRatingByMBID> <ParseMBAlbumRating dest="5"> <RegExp input="$$2" output="<details>\1</details>" dest="5"> - <RegExp input="$$1" output="<rating>\1</rating>" dest="2"> + <RegExp input="$$1" output="<rating max="5.0">\1</rating>" dest="2"> <expression noclean="1"></primary-type><rating votes-count="[^"]*">(\d)</expression> </RegExp> <expression noclean="1">(.+)</expression> diff --git a/addons/metadata.tvdb.com/addon.xml b/addons/metadata.tvdb.com/addon.xml deleted file mode 100644 index ad186db03d..0000000000 --- a/addons/metadata.tvdb.com/addon.xml +++ /dev/null @@ -1,127 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<addon id="metadata.tvdb.com" - name="The TVDB" - version="3.0.12" - provider-name="Team Kodi"> - <requires> - <import addon="xbmc.metadata" version="2.1.0"/> - <import addon="metadata.common.imdb.com" version="2.9.2"/> - </requires> - <extension point="xbmc.metadata.scraper.tvshows" - language="multi" - library="tvdb.xml" - cachepersistence="00:15"/> - <extension point="xbmc.addon.metadata"> - <summary lang="af">Gaan haal TV vertoning metadata vanaf TheTVDB.com</summary> - <summary lang="be">Fetch TV show metadata from TheTVDB.com</summary> - <summary lang="bg">Изтегля информация за ТВ Сериали от TheTVDB.com</summary> - <summary lang="ca">Obté les metadades de les sèries de televisió de TheTVDB.com</summary> - <summary lang="cs">Získat metadata televizního pořadu z TheTVDB.com</summary> - <summary lang="cy">Estyn metadata sioeau Teledu o TheTVDB.com</summary> - <summary lang="da">Hent metadata til TV-serier fra TheTVDB.com</summary> - <summary lang="de">Lade TV-Show-Metadaten von TheTVDB.com</summary> - <summary lang="el">Λήψη μετα-δεδομένων σειρών από το TVDB.com</summary> - <summary lang="en">Fetch TV show metadata from TheTVDB.com</summary> - <summary lang="en_NZ">Fetch TV show metadata from TheTVDB.com</summary> - <summary lang="en_US">Fetch TV show metadata from TheTVDB.com</summary> - <summary lang="es">Recuperar metadatos de series de TV en TheTVDB.com</summary> - <summary lang="es_AR">Recuperar metadatos de series de TV en TheTVDB.com</summary> - <summary lang="es_MX">Obtener metadata de Series desde TheTVDB.com</summary> - <summary lang="et">Hangi tv seriaalide metainfo TheTVDB.com-ist</summary> - <summary lang="fi">Nouda TV-ohjelmien tietoja TheTVDB.com -sivustolta</summary> - <summary lang="fr">Collecter les métadonnées des séries TV depuis TheTVDB.com</summary> - <summary lang="fr_CA">Récupérer les métadonnées pour les séries télé depuis TVDB.com</summary> - <summary lang="gl">Obter os metadatos das series de TV dende TheTVDB.com</summary> - <summary lang="he">הבא מידע </summary> - <summary lang="hi">द टी भी दी बी.कॉम से टी वी प्रदर्शन लाए</summary> - <summary lang="hr">Nabavi informacije za TV serije s TheTVDB.com</summary> - <summary lang="hu">TV műsor információk a TheTVDB.com-ról</summary> - <summary lang="id">Ambil metadata Serial TV dari TheTVDB.com</summary> - <summary lang="is">Sækja Sjónvarpsþátta lýsigögn frá TheTVDB.com</summary> - <summary lang="it">Scarica informazioni programma TV da TheTVDB.com</summary> - <summary lang="ja">TheTVDB.com からTV番組メタデータを取得</summary> - <summary lang="ka">სატელევიზიო გადაცემების მეტაინფორმაციის გადმოტანა TVDB.com-დან</summary> - <summary lang="ko">TheTVDB.com 에서 TV 쇼 정보 가져오기</summary> - <summary lang="lt">Parsiųsti TV šou (serialo) metaduomenis iš TheTVDB.com</summary> - <summary lang="mk">Превземи ТВ шоу метаподаток од TVDB.com</summary> - <summary lang="ms">Dapatkan data meta rancangan TV dari TheTVDB.com</summary> - <summary lang="my">TV show နှင့်ပတ်သက်သည့် အချက်အလက်များကို TheTVDB.com မှ ရယူရန်</summary> - <summary lang="nl">Seriemetadata ophalen van TheTVDB.com</summary> - <summary lang="no">Hent TV program data fra TheTVDB.com</summary> - <summary lang="pl">Pobieraj dane o serialach telewizyjnych z TheTVDB.com </summary> - <summary lang="pt">Obtenha metadados para séries TV a partir de TVDB.com</summary> - <summary lang="pt_BR">Obtenha dados dos seriados do TheTVDB.com</summary> - <summary lang="ro">Obţineţi datele despre seriale de la TheTVDB.com</summary> - <summary lang="ru">Загрузка информации о ТВ-шоу с TheTVDB.com</summary> - <summary lang="se">Skrapa för TV-seriemetadata från TVDB.com</summary> - <summary lang="sk">Získať metadáta o televíznej relácii zo stránky TheTVDB.com</summary> - <summary lang="sl">Prenesite informacije o TV serijah z TheTVDB.com</summary> - <summary lang="sq">Merr "metadata" mbi TV serialet nga TheTVDB.com</summary> - <summary lang="sv">Hämta TV-seriemetadata från TVDB.com</summary> - <summary lang="ta_IN">TheTVDB.com இருந்து தொலைக்காட்சி நிகழ்ச்சி மெட்டாடேட்டா எடுக்கபடுகின்றது</summary> - <summary lang="th">เรียกข้อมูลหลักของรายการทีวี จาก TheTVDB.com</summary> - <summary lang="tr">TV programı meta verilerini TheTVDB.com'dan al</summary> - <summary lang="uk">Отримання відомостей про серіали із TheTVDB.com</summary> - <summary lang="vi">Trình lấy TV show từ TheTVDB.com</summary> - <summary lang="zh">从 TheTVDB.com 获取电视剧集信息</summary> - <summary lang="zh_TW">從 TheTVDB.com 取得電視節目資訊</summary> - <description lang="af">TheTVDB.com is 'n TV Skraper. Die werf is 'n massiewe oop databasis wat deur enige iemand verander kan word en bevat vol meta data vir baie vertonings in verskillende tale. Alle inhoud en prente op die werf is bygedra deur sy gebruikers vir sy gebruikers en het 'n hoë standaard van kwaliteit. Die databasis skema en webruimte is oopbron onder die GPL.</description> - <description lang="be">TheTVDB.com is a TV Scraper. The site is a massive open database that can be modified by anybody and contains full meta data for many shows in different languages. All content and images on the site have been contributed by their users for users and have a high standard or quality. The database schema and website are open source under the GPL.</description> - <description lang="bg">TheTVDB.com предоставя информация за ТВ Сериали. Сайтът е масивна отворена база данни, която може да бъде променяна от всеки и съдържа пълни мета данни за много сериали на различни езици. Цялото съдържание и изображенията в сайта са предоставени от неговите потребители за други потребители и имат високо ниво на качество. Структурата на базата данни и уеб сайта са създадени с отворен код под GPL лиценз.</description> - <description lang="ca">TheTVDB.com és un raspador de TV. El lloc és una base de dades oberta massiva que pot ser modificat per qualsevol persona i conté metadades completes de molts programes en diferents idiomes. Tot el contingut i imatges en el lloc han estat aportat pels usuaris per als usuaris i tenen un alt nivell o qualitat. L'esquema de la base de dades i la pàgina web són de codi obert sota la llicència GPL.</description> - <description lang="cs">TheTVDB.com je zdroj metadat pro televizní pořady. Stránka je masivní otevřená databáze, kterou může kdokoliv upravovat a obsahuje veškerá metadata v různých jazycích k mnoha pořadům. Všechen obsah a obrázky jsou poskytnuty uživateli pro uživatele a mají vysokou kvalitu. Návrhový vzor databáze a webová stránka jsou svobodný software licencovaný pod GPL.</description> - <description lang="cy">Mae TheTVDB.com yn Grafwr Teledu. Mae'r wefan yn gronfa ddata anferthol agored y mae modd ei addasu gan unrhyw un ac yn cynnwys meta data llaw llawer o sioeau mewn ieithoedd gwahanol. Mae'r holl gynnwys a delweddau ar y wefan wedi ei gyfrannu gan eu defnyddwyr ac i safon uchel . Mae cynllun y gronfa ddata a'r wefan yn god agored o dan y GPL.</description> - <description lang="da">TheTVDB.com er en TV-scraper. Siden er en massiv åben database, som alle kan modificere, og den indeholder fyldestgørende metadata for mange serier på forskellige sprog. Alt indhold og alle billeder på siden er tilføjet af brugere og har en høj standard eller kvalitet. Databasens model og webside er open source under GPL.</description> - <description lang="de">TheTVDB.com ist ein Scraper für TV-Shows. Die Seite ist eine riesige, offene Datenbank, die von jedem angepasst werden kann und weitreichende Metadaten für viele TV-Shows, in verschiedenen Sprachen, enthält. Alle Inhalte und Bilder dieser Seite wurden von Benutzern für Benutzer zusammengetragen und folgen dabei dem hohen Standard für Qualität. Das Datenbankschema sowie die Webseite sind nach der GPL-Lizenvereinbarung OpenSource.</description> - <description lang="el">Το TVDB.com είναι ένα Scraper Τηλεόρασης. Η ιστοσελίδα είναι μία τεράστια ανοικτή βάση δεδομένων η οποία μπορεί να τροποποιηθεί από τον καθένα και περιέχει πλήρη μετα-δεδομένα για πολλές σειρές σε διάφορες γλώσσες. Όλο το περιεχόμενο και οι εικόνες στην ιστοσελίδα προέρχονται από τους χρήστες του, και έχουν υψηλά πρότυπα ποιότητας. Το σχήμα της βάσης δεδομένων και της ιστοσελίδας είναι ανοικτού κώδικα υπό το GPL.</description> - <description lang="en">TheTVDB.com is a TV Scraper. The site is a massive open database that can be modified by anybody and contains full meta data for many shows in different languages. All content and images on the site have been contributed by their users for users and have a high standard or quality. The database schema and website are open source under the GPL.</description> - <description lang="en_NZ">TheTVDB.com is a TV Scraper. The site is a massive open database that can be modified by anybody and contains full meta data for many shows in different languages. All content and images on the site have been contributed by their users for users and have a high standard or quality. The database schema and website are open source under the GPL.</description> - <description lang="en_US">TheTVDB.com is a TV Scraper. The site is a massive open database that can be modified by anybody and contains full meta data for many shows in different languages. All content and images on the site have been contributed by their users for users and have a high standard or quality. The database schema and website are open source under the GPL.</description> - <description lang="es">TheTVDB.com es un scraper de TV. El sitio es una enorme base de datos abierta que puede ser modificada por cualquiera y que contiene metadatos completos de muchas series en diferentes idiomas. Todos los contenidos e imágenes del sitio han sido aportados por sus usuarios y tienen una alta calidad. El esquema de base de datos y sitio web son de código abierto bajo la licencia GPL.</description> - <description lang="es_AR">TheTVDB.com es un scraper de TV. El sitio es una enorme base de datos abierta que puede ser modificada por cualquiera y que contiene metadatos completos de muchas series en diferentes idiomas. Todos los contenidos e imágenes del sitio han sido aportados por sus usuarios y tienen una alta calidad. El esquema de base de datos y sitio web son de código abierto bajo la licencia GPL.</description> - <description lang="es_MX">TheTVDB.com es un scraper de series de TV. Este sitio es una base de datos masiva y abierta que puede ser modicada por cualquiera y contiene metadata completa para muchas series en diferentes lenguajes. Todo el contenido e imágenes del sitio han sido contribuidos por sus usuarios para usuarios, los cuales tienen un alto estándar de calidad. El esquema de la base de datos y el sitio web son de código abierto bajo GPL.</description> - <description lang="et">TheTVDB.com on seriaalide kraabits. See leht on mahukas avatud andmebaas mida saavad täiendad kõik ja sisaldab palju metaandmeid suure hulga seriaalide kohta. Kõik sisu ja pildid lehel on kasutajate poolt sisestatud ning vastavad kõrgele kvaliteedile. TheTVDB.com andmebaasi struktuur ja kood on avaldatud GPLi all.</description> - <description lang="fi">TheTVDB.com on TV-ohjelmatietojen lataaja. Sivusto on massiivinen avoin tietokanta, jonka tietoja kaikki pystyy muokkaamaan ja se sisältää täydet tiedot monista TV-ohjelmista usealla eri kielellä. Kaikki sivuston sisältö ja kuvat on korkealaatuisia ja käyttäjien lahjoittamia. Tietokanta ja sivusto ovat GPL-lisenssin alaisia.</description> - <description lang="fr">TheTVDB.com est un collecteur TV. Le site est une immense base de données libre pouvant être modifiée par tout le monde et contenant toutes les informations de nombreuses séries en différentes langues. Les informations et images du site proviennent de contributions d'utilisateurs pour les usagers et sont d'excellentes qualités. Le schéma de la base de données et le site Web sont en open source sous licence GPL.</description> - <description lang="fr_CA">TheTVDB est un extracteur pour séries télé. Ce site est une énorme base de données ouverte qui peut être modifiée par n'importe qui et qui comprend des métadonnées complètes pour beaucoup de séries télé dans plusieurs langues. Tout le contenu et les images présentes sur le site ont été fournis par les utilisateurs et possèdent un haut niveau de qualité. La structure de la base de données et le site Web sont libres et sous licence GPL.</description> - <description lang="gl">TheTVDB.com é un Scraper de TV. O sitio é unha enorme base de datos aberta que calquera pode modificar e contén todos os metadatos de centos de series en diferentes idiomas. Todo o contido e imaxes do sitio foi proporcionado polos seus usuarios e amosa un grande estándar de calidade. O esquema da base de datos e o sitio web son de código aberto baixo licenza GPL.</description> - <description lang="he">TheTVDB.com הוא סקרייפר עבור תוכניות טלוויזיה. אתר זה הוא מסד נתונים פתוח עצום אשר כל אחד יכול לערוך ומכיל פרטים מלאים להרבה תוכניות טלוויזיה בשפות שונות. כל התכנים והתמונות באתר נתרמו ע"י המשתמשים שלה עבור משתמשים וישנו סטנדרט גבוה או איכות גבוהה. תכנית המסד נתונית והאתר הם בקוד פתוח תחת ה-GPL.</description> - <description lang="hi">टीभीडीबी एक टीभी स्क्रॅपर है.येह साइट एक बहुत बरा खुला डेटाबेस है जो किसी से भी रूपांतर्न किया जा सकता है और यह ह्र भासाओ मे सभी प्रदर्शन के लिए मीटा दाता रखता है.सभी सामग्री और चित्र यूज़र के लिए यूज़र का योगदान है और उच्च मानक या गुणवत्ता रखता है.डेटाबेस स्कीम और वेबसाइट जीपील् की अंतर्गत ओपन सोर्स है.</description> - <description lang="hr">TheTVDB.com je sakupljač informacija za TV programe. Stranica je ogromna otvorena baza podataka koju može bilo tko mijenjati i sadrži mnogo informacija za različite serije na različitim jezicima. Sav sadržaj i slike postavili su korisnici za ostale korisnike i visoke su kvalitete. Shema baze podataka i web stranice su otvorenog kôda pod GPL licencom.</description> - <description lang="hu">A TheTVDB.com egy TV műsor leolvasó. Az oldal egy hatalmas adatbázis amit bárki szabadon módosíthat és rengeteg TV műsor adatait tartalmazza különböző nyelveken. A minőségi tartalom és képanyag ezen az oldalon felhasználóktól származik más felhasználók számára. Az adatbázisstruktúra és a weblap nyílt forráskódú a GPL licenc alatt.</description> - <description lang="id">TheTVDB.com adalah pengais Serial TV. Situs ini adalah database yang sangat besar dan terbuka yang dapat dimodifikasi oleh semua orang dan mengandung meta data yang penuh untuk banyak Serial TV di bahasa yang berbeda. Semua konten dan gambar dalam situ ini dikontribusikan oleh penggunanay untuk pengguna dan memiliki standar dan kualitas tinggi. Skema database dan situs adalah open-source dengan lisensi GPL.</description> - <description lang="is">TheTVDB.com er sjónvarpsskafa.. Þessi veita er risastór opinn gagnagrunnur sem allir geta breytt og er með öll lýsigögn fyrir fullt af þáttum á mörgum tungumálum. Allt efni og myndir á veitunni er sett inn af notendum fyrir notendur og eru í háum staðli eða gæðum. Uppsetning gagnagrunnsins og vefsíðan eru 'open source under the GPL'</description> - <description lang="it">TheTVDB.com è uno scraper di programmi TV. Questo sito è un enorme database che può essere modificato da chiunque, e contiene tutte le informazioni di molti show in varie lingue. Tutti i contenuti e le immagini sul sito sono stati forniti dagli utenti, ed hanno un alto standard di qualità. Lo schema del database e il sito internet sono open source sotto licenza GPL.</description> - <description lang="ja">TheTVDB.com は TV スクレーパーです。本サイトは強力でオープンなデータベースで、誰もが追加修正可能です。テレビ番組のメタデータは多くの言語で提供されています。番組情報や画像データはユーザにより提供され、そのクオリティは非常に高いものです。データベーススキーマと web サイトは GPL ライセンスのオープンソースです。</description> - <description lang="ko">TheTVDB.com 은 TV 정보수집기입니다. 위 사이트는 이용자가 직접 수정할 수 있으며 다양한 언어의 완전한 메타 데이터를 포함하는 방대한 오픈 데이터베이스입니다. 사이트의 모든 콘텐츠와 이미지들은 사이트 이용자들이 다른 이용자들을 위해 제공한 것이며 높은 품질을 가지고 있습니다. 웹사이트와 데이터베이스 스키마는 GLP 오픈소스입니다.</description> - <description lang="lt">TheTVDB.com yra TV Scraper. Ši svetainė yra didžiulė atvira duomenų bazė, kuria gali pakeisti bet kas ir kurioje visa meta duomenis bazė daugelo šou įvairiomis kalbomis. Visas svetainės turinys atnaujinamas/papyldomasvartotojų ir turi aukštą kokybės standartą. Duomenų bazės ir svetainės yra atviro kodo pagal GPL standartą.</description> - <description lang="mk">TheTVDB.com is a TV Scraper. The site is a massive open database that can be modified by anybody and contains full meta data for many shows in different languages. All content and images on the site have been contributed by their users for users and have a high standard or quality. The database schema and website are open source under the GPL.</description> - <description lang="ms">TheTVDB.com adalah Pengikis TV. Laman tersebut merupakan pangkalan data terbuka yang amat besar dan boleh diubahsuai oleh sesiapa pun dan juga mengandungi data meta pelbagai rancangan dalam pelbagai bahasa. Semua kandungan dan imej di laman ini disumbang oleh pengguna mereka untuk pengguna mereka dan mempunyai piawaian dan kualiti yang amat tinggi. Skema pangkalan data dan laman adalah sumber terbuka dibawah GPL.</description> - <description lang="my">TheTVDB.com သည် TV Scraper ဖြစ်သည်။ database ထဲတွင် အချက်အလက်များစွာရှိနေပြီး မည်သူမဆို မည်သည့် ဘာသာစကားနှင့် မဆို ဝင်ရောက်ပြုပြင် နိုင်သည်။ အချက်အလက်များနှင့် ပုံများသည် ၎င်းတို့၏ အသုံးပြုသူများမှ အခြားအသုံးပြုသူများအတွက် ပံ့ပိုးထားသော အဆင်မြင့် အရေအသွေးများဖြစ်သည်။ website နှင့် database သည် open source GPL လိုင်စင် ကို အသုံးပြုထားသည်။</description> - <description lang="nl">TheTVDB.com is een seriescraper. De site is een gigantische open databank die iedereen kan aanpassen en uitbreiden, en biedt metadata aan voor TV-series in verschillende talen. Alle inhoud en afbeeldingen zijn afkomstig van gebruikers en moeten een grondige kwaliteitscontrole doorstaan. Het databankschema en de websitecode zijn vrijgegeven onder de open source GPL-licentie.</description> - <description lang="no">TheTVDB.com er en Tv Skraper. Siden er en massiv åpen database som kan endres av alle og inneholder data for mange forskjellige programmer på mange språk. Alt innholdet og bildene på siden er lagt til av brukere for brukere og har høy standard og kvalitet. Database skjemaet og websiden er åpen kildekode underlagt GPL.</description> - <description lang="pl">TheTVDB.com jest ekstraktorem informacji o serialach telewizyjnych. Serwis jest ogromną, wielojęzykową i otwartą bazą danych o serialach, którą może edytować każdy. Zawartość tego serwisu została stworzona przez użytkowników, dla użytkowników. Dostępne materiały są najwyższej jakości.</description> - <description lang="pt">O TheTVDB.com é um colector para séries TV. O site é uma gigantesca base de dados livre que pode ser alterada por qualquer pessoa e contém informação em várias línguas. Todos os conteúdos do site foram enviados por utilizadores e têm um elevado padrão de qualidade. A base de dados e o site funcionam sob uma licença GPL de software livre.</description> - <description lang="pt_BR">TheTVDB.com é um scraper de seriados. O site é um enorme banco de dados aberto que pode ser modificado por qualquer pessoa e contém metadados completos de muitos seriados em diferentes idiomas. Todos os conteúdos e imagens no site foram contribuições de usuários para usuários e têm um alto padrão de qualidade. O esquema do banco de dados e do site são de código aberto sob a licença GPL.</description> - <description lang="ro">TheTVDB.com este un colectore TV. Site-ul este o bază de date masivă, deschisă, ce poate fi modificată de oricine şi conţine date complete despre multe seriale în diferite limbi. Tot conţinutul site-ului a fost contribuit de către utilizatori pentru utilizatori şi are un standard de caliate înalt. Schema bazei de date şi site-ul au sursele libere sub licenţă GPL.</description> - <description lang="ru">TheTVDB.com — это инфоресурс для сериалов. Сайт представляет собой огромную открытую базу данных, в которую может вносить данные любой пользователь и которая содержит полные мета-данные для многих сериалов на различных языках. Всё содержимое и изображения на сайте были выложены его пользователями для других пользователей и имеют высокий уровень качества. Структура базы данных и веб-сайт созданы с открытым исходным кодом по лицензии GPL.</description> - <description lang="se">TVDB.com är en TV-skrapa. Sajten är en massiv öppen databas som kan ändras av vem som helst och innehåller full metadata för mängder av serier på olika språk. Allt innehåll och bilder på sajten har bidragits av användare för användare och har en hög standard eller kvalitet. Databasschemat och webbsidan är licensierat som GPL.</description> - <description lang="sk">TheTVDB.com je zdroj získavania dát ohľadom TV. Táto stránka je obrovskou otvorenou databázou, ktorú môže upravovať ktokoľvek a obsahuje úplne metadáta pre mnoho relácií v rôznych jazykoch. Všetok obsah a obrázky na stránke bol dodaný samotnými používateľmi pre používateľov a udržuje si vysoký štandard a kvalitu. Schéma databázy a webová stránka sú dostupné vo forme open source v súlade s licenciou GPL.</description> - <description lang="sl">TheTVDB.com je ponudnik informacij o TV serijah. Stran je masovna odprta baza podatkov, ki jo lahko dopolni kdorkoli, in vsebuje informacije o najrazličnejših TV serijah v več jezikih. Vsa vsebina in slike so bile dodane s strani uporabnikov in imajo visok nivo kvalitete. Shema baze in spletna stran sta odprtokodni pod GPL.</description> - <description lang="sq">TheTVDB.com është një "TV Scraper". Kjo faqe është nje bazë e të dhënave e hapur që mund të modifikohet nga si cili dhe përmbanë metadata për shumë seriale në gjuhë të ndryshme. Gjitha të dhënat dhe imazhet në këtë faqe janë kontribuar nga përdoruesit për përdoruesit dhe kanë një standard dhe kualitet të lartë. Skema e bazës së të dhënave dhe sajti i uebit janë open source nën liçensën GPL. </description> - <description lang="sv">TVDB.com är en TV-skrapa. Sajten är en massiv öppen databas som kan bli modifierad av vem som helst och innehåller all metadata för många serier på olika språk. Allt innehåll och bilder på sidan har bidragits av användare för användare och har hög standard eller kvalitet. Databasschemat och sidan är öppen källkod licensierat under GPL.</description> - <description lang="ta_IN">TheTVDB.com ஒரு தொலைக்காட்சி சுரண்டி. இந்த இணையத்தளத்தில் ஒரு பெரிய தரவுத்தளம் உள்ளது. இதில் எல்லா மொழிகளின் மேட்டாடேட்டா உள்ளது. அனைத்து தகவல்களும் படங்களும் அதன் பயனர்களின் சேகரிப்புஆகும். GPL லைசன்சில் உள்ளது.</description> - <description lang="th">TheTVDB.com เป็นตัวดึงข้อมูลทีวี เว็บไซต์เป็นฐานข้อมูลเปิดขนาดใหญ่ที่สามารถแก้ไขได้โดยทุกคนและมีข้อมูลขั้นสูงเต็มรูปแบบ สำหรับหลาย ๆ รายการ ในแต่ละภาษาที่แตกต่างกัน เนื้อหาและรูปภาพทั้งหมดในเว็บไซต์ ได้รับการสนับสนุนโดยผู้ใช้เพื่อผู้ใช้ มีคุณภาพและมาตรฐานที่สูง schemaของฐานข้อมูลและเว็บไซต์ได้เปิดภายใต้ GPL</description> - <description lang="tr">TheTVDB.com bir TV Scraper'dır. Bu site herkesin düzenleyebileceği büyük bir açık veritabanıdır ve farklı dillerdeki bir çok şov için bilgiler içerir. Sitedeki her resim ve içerik kullanıcılar tarafından kullanıcılar için karşılanır ve bunlar yüksek standart ve kaliteye sahiptir. Veritabanı şeması ve internet sitesi GPL lisansı altında açık kaynaklıdır.</description> - <description lang="uk">TheTVDB.com — джерело інформації про серіали. Це величезна база даних, що містить повні метадані про різні серіали багатьма мовами, яку може редагувати будь-хто. Увесь вміст і зображення на сайті, що відповідають найвищим стандартам якості, надали користувачі для користувачів. Схема бази даних і веб-сайт мають відкриті коди на умовах ліцензії GPL.</description> - <description lang="vi">TheTVDB.com là trình lấy dữ liệu TV show. Site chứa một số lượng khổng lồ cơ sở dữ liệu mở, có thể được thay đổi bởi mọi người và đầy đủ dữ liệu lớn các show trên nhiều ngôn ngữ. Tất cả nội dung và hình ảnh trên site này đều được đóng góp bởi toàn bộ người dùng của nó và có chất lượng cao. Mô hình cơ sở dữ liệu và website đều là mã nguồn mở được hỗ trợ bởi GPL.</description> - <description lang="zh">TheTVDB.com 是一个电视刮削器。该网站是一个巨大的开放式数据库,任何人都可以修改,包含多语言的许多电视剧集资料。网站设定了高品质标准,所有图片和内容都由用户提供。数据库结构和网站均在 GPL 许可下开源。</description> - <description lang="zh_TW">TheTVDB.com是一個電視節目。該網站是一個龐大並可以由任何人修改的開放性資料庫,並包含可以以多國語言顯示的完整的數據資料。所有內容和圖片都是經由用戶提供使用,有一定的標準或質量。數據庫架構和網站是在GPL下的開放性源碼。</description> - <platform>all</platform> - <license>GPL v2.0</license> - <forum></forum> - <website></website> - <email></email> - <source></source> - </extension> -</addon> diff --git a/addons/metadata.tvdb.com/changelog.txt b/addons/metadata.tvdb.com/changelog.txt deleted file mode 100644 index 6418f6b457..0000000000 --- a/addons/metadata.tvdb.com/changelog.txt +++ /dev/null @@ -1,172 +0,0 @@ -[B]3.0.12[/B] -- Fixed: DVD and Absolute episode ordering fixes - -[B]3.0.11[/B] -- Fixed: Use first aired episode date when firstAired field is missing (thx to Smeulf) - -[B]3.0.10[/B] -- Fixed: Use the year in the title as fallback when no firstAired field, to reduce mismatches - -[B]3.0.9[/B] -- Fixed: Character encoding fixes (part 2) - -[B]3.0.8[/B] -- Fixed: Character encoding fixes - -[B]3.0.7[/B] -- Fixed: Episode list changes - -[B]3.0.6[/B] -- Fixed: artwork won't be scraped (again) -- Fixed: Episode director/guest star mix-ups - -[B]3.0.5[/B] -- fixed: fanart preview - -[B]3.0.4[/B] -- fixed: artwork won't be scraped - -[B]3.0.3[/B] -- fixed: Spaces fix 2 - -[B]3.0.2[/B] -- fixed: Spaces removed from json regexes - -[B]3.0.1[/B] -- fixed: Uniqueids fixes - -[B]3.0.0[/B] -- Changed: Multiple ratings and uniqueids - -[B]2.0.5[/B] -- Fixed: Prevent language choices from interfering with IMDb ratings - -[B]2.0.4[/B] -- Fixed: Moved IMDb ratings to prevent clearing buffers before GetActors - -[B]2.0.3[/B] -- Fixed: IMDb series ratings -- Changed: Added the www back to the artwork URLs -- Changed: Turn fallback language on by default - -[B]2.0.2[/B] -- Fixed: Special episode placement -- Fixed: Episode thumbnails only when available -- Added: Use fallback language for artwork lookup - -[B]2.0.1[/B] -- Fixed: Backwards-compatibility code - -[B]2.0.0[/B] -- Updated: Complete rewrite for TVDB API 2.0 -- Added: Language fallback options -- Added: Merged DVD order split-episodes -- Added: Pseudo-absolute order for when not specified by TVDB - -[B]1.8.4[/B] -- Added: Runtime for tvshows - needs Krypton or newer - -[B]1.8.3[/B] -- Update author name - -[B]1.8.2[/B] -- Fixed: Runtime being zero in some cases - -[B]1.8.1[/B] -- removed unsupported languages - -[B]1.8.0[/B] -- added extra languages for selection -- changed language to a selection list - -[B]1.7.2[/B] -- Updated: handle artwork via GetArt chain - -[B]1.7.1[/B] -- Updated: language files from Transifex - -[B]1.7.0[/B] -- Added: Option to get IMDb episode and series rating when available - -[B]1.6.0[/B] -- Changed: Force selected language even if title on another language is being used for the search query - -[B]1.5.9[/B] -- Updated: language files from Transifex - -v1.5.8 -- Added: retrieve number of votes in GetDetails/GetEpisodeDetails - -v1.5.7 -- Fixed: append language to CreateSearchUrl cache file - -v1.5.6 -- Updated: language files from Transifex - -v1.5.4 -- Updated: language files from Transifex - -v1.5.3 -- Fixed: Language tag caching - round two (thx and credits to pgit) - -v1.5.2 -- Changed: Dropped the www from thetvdb URLs - -v1.5.1 -- Updated: Versioning for xbmc.metadata - -v1.5.0 -- Added: Language tag to caching (thx and credits to pgit) -- Added: Caching for search results (thx and credits to pgit) -- Removed: Poster preference as this is not needed for Frodo - -v1.4.5 -- Fixed: dvdorder setting won't apply in GetEpisodeDetails (thx and credits to scudlee) - -v1.4.4 -- Updated: language files from Transifex - -v1.4.3 -- Updated: language files from Transifex - -v1.4.2 -- Added: cache to GetTVDBId - -v1.4.1 -- Fixed: missing xml tag in GetTVDBId - -v1.4.0 -- Added: scraping of EpisodeID - -v1.3.1 -- Added: added back non-intentional removal of the imdb id lookup - -v1.3.0 -- Added: return the aspect attribute for thumb fields as banner or poster - -v1.2.4 -- Added: support for imdb url nfo's - -v1.2.3 -- Fixed: fixed broken scraping under certain circumtaces - -v1.2.2 -- Fixed: episodeguide url won't picked up sometimes - -v1.2.1 -- Fixed: won't parse longer search results - -v1.2.0 -- Added: episode runtime scraping - -v1.1.1 -- Fixed: episodeguide url won't picked up sometimes - -v1.1.0 -- Added: support decimals in episode numbers for DVD ordering - -v1.0.8 -- Fixed: fallback to other image languages if preferred doesn't exist - -v1.0.7 -- Fixed: season thumbs diff --git a/addons/metadata.tvdb.com/icon.png b/addons/metadata.tvdb.com/icon.png Binary files differdeleted file mode 100644 index 463f216567..0000000000 --- a/addons/metadata.tvdb.com/icon.png +++ /dev/null diff --git a/addons/metadata.tvdb.com/resources/language/Albanian/strings.po b/addons/metadata.tvdb.com/resources/language/Albanian/strings.po deleted file mode 100644 index c96718fa8b..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Albanian/strings.po +++ /dev/null @@ -1,37 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Albanian (http://www.transifex.com/projects/p/xbmc-addons/language/sq/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: sq\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Përdor rendin e \"DVD'së\"" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Përdor renditjen absolute (Sezon i veçantë)" - -msgctxt "#30002" -msgid "Enable Fanart" -msgstr "Aktivo \"Fanart'in\"" - -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Prefero Posterë" - -msgctxt "#30004" -msgid "Language" -msgstr "Gjuha" diff --git a/addons/metadata.tvdb.com/resources/language/Arabic/strings.po b/addons/metadata.tvdb.com/resources/language/Arabic/strings.po deleted file mode 100644 index c64fe11bcc..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Arabic/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Arabic (http://www.transifex.com/projects/p/xbmc-addons/language/ar/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ar\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 "#30004" -msgid "Language" -msgstr "اللغة" diff --git a/addons/metadata.tvdb.com/resources/language/Azerbaijani/strings.po b/addons/metadata.tvdb.com/resources/language/Azerbaijani/strings.po deleted file mode 100644 index 7cbc9e2907..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Azerbaijani/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Azerbaijani (http://www.transifex.com/projects/p/xbmc-addons/language/az/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: az\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -msgctxt "#30004" -msgid "Language" -msgstr "Dil" diff --git a/addons/metadata.tvdb.com/resources/language/Bosnian/strings.po b/addons/metadata.tvdb.com/resources/language/Bosnian/strings.po deleted file mode 100644 index e2ac6a9f14..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Bosnian/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Bosnian (http://www.transifex.com/projects/p/xbmc-addons/language/bs/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: bs\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" - -msgctxt "#30004" -msgid "Language" -msgstr "Jezik" diff --git a/addons/metadata.tvdb.com/resources/language/Faroese/strings.po b/addons/metadata.tvdb.com/resources/language/Faroese/strings.po deleted file mode 100644 index 25a5880d70..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Faroese/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Faroese (http://www.transifex.com/projects/p/xbmc-addons/language/fo/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fo\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -msgctxt "#30004" -msgid "Language" -msgstr "Mál" diff --git a/addons/metadata.tvdb.com/resources/language/Finnish/strings.po b/addons/metadata.tvdb.com/resources/language/Finnish/strings.po deleted file mode 100644 index 7ab1f4afad..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Finnish/strings.po +++ /dev/null @@ -1,37 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Finnish (http://www.transifex.com/projects/p/xbmc-addons/language/fi/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fi\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Käytä DVD järjestystä" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Käytä absoluuttista järjestystä (yksi tuotantokausi)" - -msgctxt "#30002" -msgid "Enable Fanart" -msgstr "Fanitaide käytössä" - -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Ensisijaisesti julisteet käytössä" - -msgctxt "#30004" -msgid "Language" -msgstr "Kieli" diff --git a/addons/metadata.tvdb.com/resources/language/Georgian/strings.po b/addons/metadata.tvdb.com/resources/language/Georgian/strings.po deleted file mode 100644 index ba1e5391a9..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Georgian/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Georgian (http://www.transifex.com/projects/p/xbmc-addons/language/ka/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ka\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -msgctxt "#30004" -msgid "Language" -msgstr "ენა" diff --git a/addons/metadata.tvdb.com/resources/language/Hindi (Devanagiri)/strings.po b/addons/metadata.tvdb.com/resources/language/Hindi (Devanagiri)/strings.po deleted file mode 100644 index 835d76e07d..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Hindi (Devanagiri)/strings.po +++ /dev/null @@ -1,37 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Hindi (Devanagiri) (http://www.transifex.com/projects/p/xbmc-addons/language/hi/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: hi\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -msgctxt "#30000" -msgid "Use DVD Order" -msgstr "डी भी डी ऑर्डर का प्रयोग ." - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "आब्सोल्यूट ऑर्डरिंग का प्रयोग करे (सिंगल सीज़न)" - -msgctxt "#30002" -msgid "Enable Fanart" -msgstr "फ़ानर्ट को एनेबल करे" - -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "पोस्टर्स को प्रिफर करे" - -msgctxt "#30004" -msgid "Language" -msgstr "बाशा" diff --git a/addons/metadata.tvdb.com/resources/language/Latvian/strings.po b/addons/metadata.tvdb.com/resources/language/Latvian/strings.po deleted file mode 100644 index b54bce9466..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Latvian/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Latvian (http://www.transifex.com/projects/p/xbmc-addons/language/lv/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: lv\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);\n" - -msgctxt "#30004" -msgid "Language" -msgstr "Valoda" diff --git a/addons/metadata.tvdb.com/resources/language/Maltese/strings.po b/addons/metadata.tvdb.com/resources/language/Maltese/strings.po deleted file mode 100644 index b3530c2d2e..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Maltese/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Maltese (http://www.transifex.com/projects/p/xbmc-addons/language/mt/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: mt\n" -"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3);\n" - -msgctxt "#30004" -msgid "Language" -msgstr "Lingwa" diff --git a/addons/metadata.tvdb.com/resources/language/Mongolian (Mongolia)/strings.po b/addons/metadata.tvdb.com/resources/language/Mongolian (Mongolia)/strings.po deleted file mode 100644 index e962f6e7f6..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Mongolian (Mongolia)/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Mongolian (Mongolia) (http://www.transifex.com/projects/p/xbmc-addons/language/mn_MN/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: mn_MN\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -msgctxt "#30004" -msgid "Language" -msgstr "Хэл" diff --git a/addons/metadata.tvdb.com/resources/language/Persian (Iran)/strings.po b/addons/metadata.tvdb.com/resources/language/Persian (Iran)/strings.po deleted file mode 100644 index 9d09cb0e42..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Persian (Iran)/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Persian (Iran) (http://www.transifex.com/projects/p/xbmc-addons/language/fa_IR/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fa_IR\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -msgctxt "#30004" -msgid "Language" -msgstr "زبان" diff --git a/addons/metadata.tvdb.com/resources/language/Persian/strings.po b/addons/metadata.tvdb.com/resources/language/Persian/strings.po deleted file mode 100644 index ac067621b3..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Persian/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Persian (http://www.transifex.com/projects/p/xbmc-addons/language/fa/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: fa\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -msgctxt "#30004" -msgid "Language" -msgstr "زبان" diff --git a/addons/metadata.tvdb.com/resources/language/Serbian (Cyrillic)/strings.po b/addons/metadata.tvdb.com/resources/language/Serbian (Cyrillic)/strings.po deleted file mode 100644 index 289eb2ff31..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Serbian (Cyrillic)/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Serbian (Cyrillic) (http://www.transifex.com/projects/p/xbmc-addons/language/sr_RS/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: sr_RS\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" - -msgctxt "#30004" -msgid "Language" -msgstr "Језик" diff --git a/addons/metadata.tvdb.com/resources/language/Serbian/strings.po b/addons/metadata.tvdb.com/resources/language/Serbian/strings.po deleted file mode 100644 index d81dbbb233..0000000000 --- a/addons/metadata.tvdb.com/resources/language/Serbian/strings.po +++ /dev/null @@ -1,21 +0,0 @@ -# Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com -# Addon Provider: XBMC Foundation -msgid "" -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: Kodi Translation Team\n" -"Language-Team: Serbian (http://www.transifex.com/projects/p/xbmc-addons/language/sr/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: sr\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" - -msgctxt "#30004" -msgid "Language" -msgstr "Jezik" diff --git a/addons/metadata.tvdb.com/resources/settings.xml b/addons/metadata.tvdb.com/resources/settings.xml deleted file mode 100644 index b636150f05..0000000000 --- a/addons/metadata.tvdb.com/resources/settings.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<settings> - <setting label="30000" type="bool" id="dvdorder" default="false" enable="!eq(1,true)" /> - <setting label="30001" type="bool" id="absolutenumber" default="false" enable="!eq(-1,true)" /> - <setting type="sep" /> - <setting label="30002" type="bool" id="fanart" default="true" /> - <setting type="sep" /> - <setting label="30004" type="select" id="language" values="cs|da|de|el|en|es|fi|fr|he|hr|hu|it|ja|ko|nl|no|pl|pt|ru|sl|sv|tr|zh" sort="yes" default="en" /> - <setting label="30007" type="bool" id="usefallbacklanguage1" subsetting="true" default="true"/> - <setting label="30008" type="select" id="fallbacklanguage" values="cs|da|de|el|en|es|fi|fr|he|hr|hu|it|ja|ko|nl|no|pl|pt|ru|sl|sv|tr|zh" subsetting="true" sort="yes" visible="eq(-1,true)" default="en" /> - <setting label="30005" type="labelenum" values="TheTVDB|IMDb" id="RatingS" default="TheTVDB"/> - <setting label="30006" type="bool" id="fallback" subsetting="true" visible="eq(-1,1)" default="true"/> - <setting label="30009" type="bool" id="alsoimdb" subsetting="true" visible="eq(-2,0)" default="false"/> -</settings> diff --git a/addons/metadata.tvdb.com/tvdb.xml b/addons/metadata.tvdb.com/tvdb.xml deleted file mode 100644 index 763fda8933..0000000000 --- a/addons/metadata.tvdb.com/tvdb.xml +++ /dev/null @@ -1,1140 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- should be self-explanatory --> -<scraper framework="1.1" date="2013-04-04"> - - <!-- input : $$1=nfo file --> - <!-- output: <url>*</url><id>*</id> --> - <NfoUrl dest="3" clearbuffers="no"> - <RegExp input="$$1" output="tt\1" dest="7"> - <expression clear="yes">imdb\....?/title/tt([0-9]*)</expression> - </RegExp> - <RegExp input="$$1" output="tt\1" dest="7"> - <expression>imdb\....?/title\?([0-9]*)</expression> - </RegExp> - <RegExp input="$$7" output="<details><url function="GetTVDBId" post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6"}|Content-Type=application/json</url></details>" dest="3"> - <expression>(?!^$)</expression> - </RegExp> - <RegExp input="$$1" output="\1" dest="6"> - <expression clear="yes">https?://(?:www\.)?thetvdb.com/(?:index\.php)?\?tab=series&id=([0-9]+)</expression> - </RegExp> - <RegExp input="$$6" output="<details><url function="NfoUrlAuth" post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6"}|Content-Type=application/json</url></details>" dest="3"> - <expression>(?!^$)</expression>> - </RegExp> - </NfoUrl> - <NfoUrlAuth dest="3" clearbuffers="no"> - <RegExp input="$$19" output="<details><url cache="$$6-$INFO[language].xml">https://api.thetvdb.com/series/$$6|Authorization=Bearer%20\1&accept-language=$INFO[language]</url><id>$$6</id></details>" dest="3"> - <RegExp input="$$1" output="\1" dest="19"> - <expression>"token":\s*?"(.*)"</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - </NfoUrlAuth> - <GetTVDBId dest="3" clearbuffers="no"> - <RegExp input="$$19" output="<details><url function="GetTVDBIdAuth" cache="search-$$7-$INFO[language].json">https://api.thetvdb.com/search/series?imdbId=$$7|Authorization=Bearer%20\1&accept-language=$INFO[language]</url></details>" dest="3"> - <RegExp input="$$1" output="\1" dest="19"> - <expression>"token":\s*?"(.*)"</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - </GetTVDBId> - <GetTVDBIdAuth dest="3" clearbuffers="no"> - <RegExp input="$$1" output="<details><url cache="\1-$INFO[language].xml">https://api.thetvdb.com/series/\1|Authorization=Bearer%20$$19&accept-language=$INFO[language]</url><id>\1</id></details>" dest="3"> - <expression>"id":\s*?(\d+),</expression> - </RegExp> - </GetTVDBIdAuth> - - <!-- input : $$1=query string --> - <!-- output: <url>*</url> --> - <CreateSearchUrl dest="3" clearbuffers="no"> - <RegExp input="" output="<url post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6"}|Content-Type=application/json</url>" dest="3"> - <expression/> - </RegExp> - <RegExp input="$$1" output="\1" dest="5"> - <expression noclean="1"/> - </RegExp> - </CreateSearchUrl> - <GetSearchResults dest="3" clearbuffers="no"> - <RegExp input="$$4" output="<results>\1</results>" dest="3"> - <RegExp input="$$1" output="\1" dest="19"> - <expression>"token":\s*?"(.*)"</expression> - </RegExp> - <RegExp input="$INFO[language]" output="\1" dest="16"> - <expression/> - </RegExp> - <RegExp input="" output="<url function="GetSearchResultsAuth" cache="search-$$5-$INFO[language].json">https://api.thetvdb.com/search/series?name=$$5|Authorization=Bearer%20$$19&accept-language=$INFO[language]</url>" dest="4"> - <expression noclean="1"/> - </RegExp> - <RegExp conditional="usefallbacklanguage1" input="$INFO[language]" output="<chain function="SwitchLanguage">$INFO[fallbacklanguage]</chain><url function="GetSearchResultsAuth" cache="search-$$5-$INFO[fallbacklanguage].json">https://api.thetvdb.com/search/series?name=$$5|Authorization=Bearer%20$$19&accept-language=$INFO[fallbacklanguage]</url>" dest="4+"> - <expression>^(?!\Q$INFO[fallbacklanguage]\E$)</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - </GetSearchResults> - - <SwitchLanguage dest="3" clearbuffers="no"> - <RegExp input="" output="<details><!-- $$1 --></details>" dest="3"> - <RegExp input="$$1" output="\1" dest="16"> - <expression/> - </RegExp> - <expression noclean="1"/> - </RegExp> - </SwitchLanguage> - - <!-- input : $$1=search html --> - <!-- input : $$2=search url --> - <!-- output: <results><entity><title>*</title><year>*</year><language>*</language><url>*</url><id>*</id></entity>*</results> --> - <GetSearchResultsAuth dest="6" clearbuffers="no"> - <RegExp input="$$1" output="<series><id>\3</id><seriesName>\4</seriesName><aliases>\1</aliases><firstAired>\2</firstAired><year>\5</year></series>" dest="4"> - <expression repeat="yes" fixchars="1,4">"aliases":\s*?\[([^]]*)\],\s*?"banner":\s*?"[^"]*",\s*?"firstAired":\s*?"([^"]*)",\s*?"id":\s*?(\d+),\s*?"network":\s*?"[^"]*",\s*?"overview":\s*?(?:"[^}]*"|null),\s*?"seriesName":\s*?"([^}]*?(?:\(([0-9]{4})\))?)",\s*?"slug":\s*?"[^"]*"</expression> - </RegExp> - <RegExp input="" output="" dest="6"> - <expression/> - </RegExp> - <XSLT input="<data>$$4</data>" output="\1" dest="6"> - <xsl:stylesheet version = "1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:output encoding="UTF-8" indent="yes"/> - - <xsl:variable name="notAllowedId">313081</xsl:variable> - - <xsl:template match="data"> - <results> - <xsl:apply-templates select="series[id!=$notAllowedId]"/> - <xsl:apply-templates select="series[id!=$notAllowedId]" mode="alias"/> - </results> - </xsl:template> - - <xsl:template match="series"> - <xsl:call-template name="entity"> - <xsl:with-param name="title" select="normalize-space(seriesName)"/> - </xsl:call-template> - </xsl:template> - - <xsl:template match="series" mode="alias"> - <xsl:call-template name="split-aliases"> - <xsl:with-param name="title-list" select="concat(normalize-space(aliases),', ')"/> - </xsl:call-template> - </xsl:template> - - <xsl:template name="split-aliases"> - <xsl:param name="title-list"/> - <xsl:variable name="first" select="substring-after(substring-before($title-list, '",'), '"')" /> - <xsl:variable name="remaining" select="substring-after($title-list, '",')" /> - <xsl:if test="$first!=''"> - <xsl:call-template name="entity"> - <xsl:with-param name="title" select="$first"/> - </xsl:call-template> - </xsl:if> - <xsl:if test="$remaining!=''"> - <xsl:call-template name="split-aliases"> - <xsl:with-param name="title-list" select="$remaining" /> - </xsl:call-template> - </xsl:if> - </xsl:template> - - <xsl:template name="entity"> - <xsl:param name="title"/> - <entity> - <title><xsl:value-of select="$title"/></title> - <year> - <xsl:choose> - <xsl:when test="firstAired!=''"><xsl:value-of select="substring(firstAired,1,4)"/></xsl:when> - <xsl:otherwise><xsl:value-of select="year"/></xsl:otherwise> - </xsl:choose> - </year> - <language>$$16</language> - <url><xsl:attribute name="cache"><xsl:value-of select="id"/>-$INFO[language].json</xsl:attribute>https://api.thetvdb.com/series/<xsl:value-of select="id"/>|Authorization=Bearer%20$$19&accept-language=$INFO[language]</url> - <id><xsl:value-of select="id"/></id> - </entity> - </xsl:template> - - </xsl:stylesheet> - </XSLT> - <RegExp input="$$6" output="\1" dest="6"> - <expression noclean="1" fixchars="1"/> - </RegExp> - </GetSearchResultsAuth> - - <!-- input : $$1=series html --> - <!-- input : $$2=id --> - <!-- input : $$3=series url --> - <!-- output: <details><title>*</title><plot>*</plot><id>*</id>...etc...<episodeguide>*</episodeguide></details> --> - <GetDetails dest="7" clearbuffers="no"> - <RegExp input="$$4" output="<?xml version="1.0" encoding="utf-8" standalone="yes"?><details>\1</details>" dest="7"> - <RegExp input="$$3" output="\1" dest="19"> - <expression>Authorization=Bearer%20(.+)&accept-language</expression> - </RegExp> - <RegExp input="" output="" dest="14"> - <expression clear="yes"/> - </RegExp> - <RegExp input="$$1" output="<uniqueid type="tvdb" default="true">\1</uniqueid>" dest="4"> - <expression clear="yes">"id":\s*?(\d+),</expression> - </RegExp> - <RegExp input="$$1" output="<uniqueid type="imdb">\1</uniqueid>" dest="4+"> - <expression>"imdbId":\s*?"(tt\d+)",</expression> - </RegExp> - <RegExp input="$$1" output="<title>\1</title>" dest="4+"> - <expression fixchars="1">"seriesName":\s*?"(.*)",\s*?"aliases"</expression> - </RegExp> - <RegExp conditional="usefallbacklanguage1" input="$$1" output="missingtitle|" dest="14"> - <expression clear="yes">"seriesName":\s*?null,\s*?"aliases"</expression> - </RegExp> - <RegExp input="$$1" output="<premiered>\1</premiered>" dest="4+"> - <expression>"firstAired":\s*?"([^"]+)",</expression> - </RegExp> - <RegExp input="$$1" output="<url function="GetPremieredFromFirstEp">https://api.thetvdb.com/series/$$2/episodes/query?airedSeason=1&airedEpisode=1|Authorization=Bearer%20$$19&amp;accept-language=$INFO[language]</url>" dest="4+"> - <expression>"firstAired":\s*?"",</expression> - </RegExp> - <RegExp input="$$1" output="<runtime>\1</runtime>" dest="4+"> - <expression>"runtime":\s*?"([^"]*)",</expression> - </RegExp> - <RegExp input="$$1" output="<studio>\1</studio>" dest="4+"> - <expression fixchars="1">"network":\s*?"([^"]*)",</expression> - </RegExp> - <RegExp input="$$7" output="<plot>\1</plot>" dest="4+"> - <RegExp input="$$6\r" output="\1\n" dest="7"> - <RegExp input="$$1" output="\1" dest="6"> - <expression clear="yes" noclean="1">"overview":\s*?"(.*)",\s*?"lastUpdated"</expression> - </RegExp> - <expression clear="yes" repeat="yes" fixchars="1">(.*?)\\r</expression> - </RegExp> - <expression noclean="1">(?!^$)(.*)</expression> - </RegExp> - <RegExp conditional="usefallbacklanguage1" input="$$1" output="missingplot|" dest="14+"> - <expression>"overview":\s*?null,\s*?"lastUpdated"</expression> - </RegExp> - <RegExp input="$$1" output="<mpaa>\1</mpaa>" dest="4+"> - <expression>"rating":\s*?"([^"]*)",</expression> - </RegExp> - <RegExp input="$$5" output="<genre>\1</genre>" dest="4+"> - <RegExp input="$$1" output="\1" dest="5"> - <expression clear="yes">"genre":\s*?\[([^]]*)\]</expression> - </RegExp> - <expression noclean="1" repeat="yes">"([^"]+)"</expression> - </RegExp> - <RegExp input="$INFO[language]" output="$$5" dest="4+"> - <RegExp input="$$14" output="<url function="GetFallbackDetails" cache="$$2-$INFO[fallbacklanguage].json">https://api.thetvdb.com/series/$$2|Authorization=Bearer%20$$19&accept-language=$INFO[fallbacklanguage]</url>" dest="5"> - <expression clear="yes">(?!^$)</expression> - </RegExp> - <expression>(?!^\Q$INFO[fallbacklanguage]\E$)</expression> - </RegExp> - <RegExp input="$$1" output="<chain function="GetActors">\1</chain>" dest="4+"> - <expression noclean="1">"id":\s*?(\d+),</expression> - </RegExp> - <RegExp input="$$1" output="<chain function="GetArt">\1</chain>" dest="4+"> - <expression noclean="1">"id":\s*?(\d+),</expression> - </RegExp> - <RegExp input="$$6" output="\1" dest="4+"> - <RegExp input="$$1" output="<value>\1</value>" dest="5"> - <expression clear="yes">"siteRating":\s*?(?:(\d+(?:\.\d)?)|null)</expression> - </RegExp> - <RegExp input="$$1" output="<votes>\1</votes>" dest="5+"> - <expression>"siteRatingCount":\s*?(?:(\d+)|null)\s*?}</expression> - </RegExp> - <RegExp input="$$1" output="\1" dest="8"> - <expression clear="yes">"imdbId":\s*?"(tt\d+)",</expression> - </RegExp> - <RegExp input="$INFO[RatingS]" output="default="true"" dest="9"> - <expression>TheTVDB</expression> - </RegExp> - <RegExp input="$INFO[RatingS]|$INFO[fallback]" output="<ratings><rating name="tvdb" $$9 >$$5</rating></ratings>" dest="6"> - <expression>TheTVDB|true</expression> - </RegExp> - <RegExp input="$$8|$INFO[RatingS]|default|$INFO[alsoimdb]" output="<chain function="GetIMDBRatingsById">$$8\1</chain>" dest="6+"> - <expression>^tt\d+\|(?:IMDb(\|default)|.*true$)</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - <RegExp input="$$1" output="<episodeguide><url post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6","id":\1}|Content-Type=application/json</url></episodeguide>" dest="4+"> - <expression noclean="1">"id":\s*?(\d+),</expression> - </RegExp> - <expression noclean="1" fixchars="1"/> - </RegExp> - </GetDetails> - <GetPremieredFromFirstEp dest="3" clearbuffers="no"> - <RegExp input="$$4" output="<details>\1</details>" dest="3"> - <RegExp input="$$1" output="<premiered>\1</premiered>" dest="4"> - <expression clear="yes">"firstAired":\s*?"([^"]+)"</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - </GetPremieredFromFirstEp> - <GetFallbackDetails dest="3" clearbuffers="no"> - <RegExp input="$$4" output="<details>\1</details>" dest="3"> - <RegExp input="$$14" output="$$5" dest="4"> - <RegExp input="$$1" output="<title>\1</title>" dest="5"> - <expression clear="yes" fixchars="1">"seriesName":\s*?"(.*)",\s*?"aliases"</expression> - </RegExp> - <expression clear="yes">missingtitle</expression> - </RegExp> - <RegExp input="$$14" output="$$5" dest="4+"> - <RegExp input="$$7" output="<plot>\1</plot>" dest="5"> - <RegExp input="$$6\r" output="\1\n" dest="7"> - <RegExp input="$$1" output="\1" dest="6"> - <expression clear="yes" noclean="1">"overview":\s*?"(.*)",\s*?"lastUpdated"</expression> - </RegExp> - <expression repeat="yes" fixchars="1">(.*?)\\r</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - <expression>missingplot</expression> - </RegExp> - <expression noclean="1" fixchars="1"/> - </RegExp> - </GetFallbackDetails> - <GetActors dest="3" clearbuffers="no"> - <RegExp input="$$1" output="<details><url function="ParseActors" cache="\1-actors.json">https://api.thetvdb.com/series/\1/actors|Authorization=Bearer%20$$19</url></details>" dest="3"> - <expression noclean="1"/> - </RegExp> - </GetActors> - <ParseActors dest="4"> - <RegExp input="$$5" output="<details>\1</details>" dest="4"> - <RegExp input="$$1" output="<actor><name>\1</name><role>\2</role><order>\3</order><thumb>http://www.thetvdb.com/banners/\4</thumb></actor>" dest="5"> - <expression repeat="yes" fixchars="1,2">"name":\s*?"([^}]+)",\s*?"role":\s*?"([^}]+)",\s*?"sortOrder":\s*?(\d+),\s*?"image":\s*?"([^"]+)",</expression> - </RegExp> - <RegExp input="$$1" output="<actor><name>\1</name><role>\2</role><order>\3</order></actor>" dest="5+"> - <expression repeat="yes" fixchars="1,2">"name":\s*?"([^}]+)",\s*?"role":\s*?"([^}]+)",\s*?"sortOrder":\s*?(\d+),\s*?"image":\s*?(?:""|null),</expression> - </RegExp> - <expression noclean="1" fixchars="1"/> - </RegExp> - </ParseActors> - <GetArt dest="3" clearbuffers="no"> - <RegExp input="$$4" output="<details>\1</details>" dest="3"> - <RegExp input="$$1" output="<url function="GetArtAuth" post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6","id":\1}|Content-Type=application/json" dest="4"> - <expression/> - </RegExp> - <RegExp input="$$1" output="\1" dest="18"> - <expression/> - </RegExp> - <expression noclean="1"/> - </RegExp> - </GetArt> - <GetArtAuth dest="3" clearbuffers="no"> - <RegExp input="$$4" output="<details>\1</details>" dest="3"> - <RegExp input="$$1" output="\1" dest="19"> - <expression>"token":\s*?"(.*)"</expression> - </RegExp> - <RegExp input="" output="" dest="10"> - <expression/> - </RegExp> - <RegExp input="" output="<url function="GetArtParams" cache="$$18-art-params.json">https://api.thetvdb.com/series/$$18/images/query/params|Authorization=Bearer%20$$19</url>" dest="4"> - <expression/> - </RegExp> - <RegExp input="" output="<chain function="ParseArt"></chain>" dest="4+"> - <expression/> - </RegExp> - <expression noclean="1"/> - </RegExp> - </GetArtAuth> - <GetArtParams dest="3" clearbuffers="no"> - <RegExp input="$$4" output="<details>\1</details>" dest="3"> - <RegExp input="$INFO[language]" output="\1" dest="16"> - <expression/> - </RegExp> - <RegExp input="$$1" output="<url function="LoadArt" cache="$$18-art-\1-$$16.json">https://api.thetvdb.com/series/$$18/images/query?keyType=\1|Authorization=Bearer%20$$19&accept-language=$$16</url>" dest="4"> - <expression clear="yes" repeat="yes">"keyType":\s*?"([^"]+)"</expression> - </RegExp> - <RegExp conditional="usefallbacklanguage1" input="$INFO[fallbacklanguage]" output="$$5" dest="4+"> - <RegExp input="" output="<chain function="SwitchLanguage">$INFO[fallbacklanguage]</chain>" dest="5"> - <expression noclean="1"/> - </RegExp> - <RegExp input="$$1" output="<url function="LoadArt" cache="$$18-art-\1-$INFO[fallbacklanguage].json">https://api.thetvdb.com/series/$$18/images/query?keyType=\1|Authorization=Bearer%20$$19&accept-language=$INFO[fallbacklanguage]</url>" dest="5+"> - <expression repeat="yes">"keyType":\s*?"([^"]+)"</expression> - </RegExp> - <expression>^(?!\Q$$16\E$|en$)</expression> - </RegExp> - <RegExp input="$$16" output="$$5" dest="4+"> - <RegExp input="" output="<chain function="SwitchLanguage">en</chain>" dest="5"> - <expression noclean="1"/> - </RegExp> - <RegExp input="$$1" output="<url function="LoadArt" cache="$$18-art-\1-en.json">https://api.thetvdb.com/series/$$18/images/query?keyType=\1|Authorization=Bearer%20$$19&accept-language=en</url>" dest="5+"> - <expression repeat="yes">"keyType":\s*?"([^"]+)"</expression> - </RegExp> - <expression>^(?!en)</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - </GetArtParams> - <LoadArt dest="3" clearbuffers="no"> - <RegExp input="$$1" output="<details><!-- $$16 \1 loaded --></details>" dest="3"> - <RegExp input="$$1" output="<Banner><id>\1</id><keyType>\2</keyType><subKey>\3</subKey><fileName>\4</fileName><resolution>\5</resolution><average>\6</average><thumbnail>\7</thumbnail><language>$$16</language></Banner>" dest="10+"> - <expression repeat="yes">"id":\s*?(\d+),\s*?"keyType":\s*?"([^"]+)",\s*?"subKey":\s*?"([^"]*)",\s*?"fileName":\s*?"([^"]+)","languageId":\s*?\d+,\s*?"resolution":\s*?"([^"]*)",\s*?"ratingsInfo":\s*?{\s*?"average":\s*?(?:([\d\.]+)|null),\s*?"count":\s*?\d+\s*?},\s*?"thumbnail":\s*?"([^"]*?)"</expression> - </RegExp> - <expression noclean="1">"keyType":\s*?"([^"]+)",</expression> - </RegExp> - </LoadArt> - <ParseArt dest="4" clearbuffers="no"> - <RegExp input="" output="" dest="4"> - <expression/> - </RegExp> - <XSLT input="<Banners>$$10</Banners>" output="\1" dest="4"> - <xsl:stylesheet version = "1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:output omit-xml-declaration="yes" indent="yes"/> - <xsl:strip-space elements="*"/> - <xsl:key name="BannersById" match="Banner" use="id"/> - - <xsl:template match="Banners"> - <details> - <fanart url="http://www.thetvdb.com/banners/"> - <xsl:apply-templates select="Banner[(keyType='fanart') and (generate-id()=generate-id(key('BannersById', id)[1]))]"> - <xsl:sort data-type="number" order="descending" select="average"/> - </xsl:apply-templates> - </fanart> - <xsl:apply-templates select="Banner[(keyType!='fanart') and (generate-id()=generate-id(key('BannersById', id)[1]))]"> - <xsl:sort data-type="number" order="ascending" select="(1 * number(keyType='poster')) - + (2 * number(keyType='series')) - + (3 * number(keyType='season')) - + (4 * number(keyType='seasonwide'))"/> - <xsl:sort data-type="number" order="ascending" select="(1 * number(subKey='graphical')) - + (2 * number(subKey='text')) - + (3 * number(subKey='blank')) - + (4 * number(subKey))"/> - <xsl:sort data-type="number" order="ascending" select="(1 * number(language='$INFO[language]')) - + (2 * number((language='$INFO[fallbacklanguage]') and ('$INFO[language]'!='$INFO[fallbacklanguage]'))) - + (3 * number((language!='$INFO[language]') and (language!='$INFO[fallbacklanguage]')))"/> - <xsl:sort data-type="number" order="descending" select="average"/> - </xsl:apply-templates> - <xsl:apply-templates select="Banner[((keyType='poster') or (keyType='series')) and (generate-id()=generate-id(key('BannersById', id)[1]))]" mode="allseasons"/> - </details> - </xsl:template> - - <xsl:template match="Banner[keyType='fanart']"> - <thumb> - <xsl:attribute name="dim"><xsl:value-of select="resolution"/></xsl:attribute> - <xsl:attribute name="preview">_cache/<xsl:value-of select="fileName"/></xsl:attribute> - <xsl:value-of select="fileName"/> - </thumb> - </xsl:template> - - <xsl:template match="Banner"> - <thumb> - <xsl:attribute name="aspect"> - <xsl:choose> - <xsl:when test="(keyType='poster') or (keyType='season')">poster</xsl:when> - <xsl:otherwise>banner</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:if test="(keyType='season') or (keyType='seasonwide')"> - <xsl:attribute name="type">season</xsl:attribute> - <xsl:attribute name="season"><xsl:value-of select="subKey"/></xsl:attribute> - </xsl:if> - <xsl:attribute name="language"><xsl:value-of select="language"/></xsl:attribute>http://www.thetvdb.com/banners/<xsl:value-of select="fileName"/> - </thumb> - </xsl:template> - - <xsl:template match="Banner" mode="allseasons"> - <thumb> - <xsl:attribute name="aspect"> - <xsl:choose> - <xsl:when test="(keyType='poster')">poster</xsl:when> - <xsl:otherwise>banner</xsl:otherwise> - </xsl:choose> - </xsl:attribute> - <xsl:attribute name="type">season</xsl:attribute> - <xsl:attribute name="season">-1</xsl:attribute> - <xsl:attribute name="language"><xsl:value-of select="language"/></xsl:attribute>http://www.thetvdb.com/banners/<xsl:value-of select="fileName"/></thumb> - </xsl:template> - - </xsl:stylesheet> - </XSLT> - </ParseArt> - - <!-- input : $$1=episodeguide html --> - <!-- input : $$2=episodeguide url --> - <!-- output: <episodeguide><episode><title>*</title><url>*</url><season>*</season><epnum>*</epnum><thumb>*</thumb><id>*</id><aired>*</aired></episode>*</episodeguide> !--> - <GetEpisodeList dest="3" clearbuffers="no"> - <RegExp input="$$5" output="<episodeguide>\1</episodeguide>" dest="3"> - <RegExp input="$$1" output="\1" dest="19"> - <expression clear="yes">"token":\s*?"(.*)"</expression> - </RegExp> - <RegExp input="$$2" output="\1" dest="18"> - <expression>"id":(\d+)}</expression> - </RegExp> - <RegExp input="$$19" output="<url function="GetEpisodeListAuth" cache="episodes-$$18-1-$INFO[language].json">https://api.thetvdb.com/series/$$18/episodes|Authorization=Bearer%20$$19&accept-language=$INFO[language]</url>" dest="5"> - <expression clear="yes">(?!^$)</expression> - </RegExp> - - <!-- Backwards-compatibility code. Scraper will still fail if/when the old URLs 404 (or similar), as this function just won't be run. --> - <RegExp input="$$2" output="<url function="GetEpisodeList" post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6","id":\1}|Content-Type=application/json</url>" dest="5"> - <expression>http://(?:www\.)?thetvdb\.com/api/.+/series/(\d+)/all/</expression> - </RegExp> - <RegExp input="$$2" output="https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6","id":\1}|Content-Type=application/json" dest="2"> - <expression>http://(?:www\.)?thetvdb\.com/api/.+/series/(\d+)/all/</expression> - </RegExp> - <expression noclean="1" fixchars="1"/> - </RegExp> - </GetEpisodeList> - <GetEpisodeListAuth dest="3" clearbuffers="no"> - <RegExp input="$$4" output="<episodeguide>\1</episodeguide>" dest="3"> - <RegExp input="$$1" output="<Data><last>\1</last></Data>" dest="5"> - <expression>"last":\s*?(\d+),</expression> - </RegExp> - <RegExp input="" output="" dest="4"> - <expression/> - </RegExp> - <RegExp input="" output="" dest="11"> - <expression/> - </RegExp> - <XSLT input="$$5" output="\1" dest="4"> - <xsl:stylesheet version = "1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:output omit-xml-declaration="yes" indent="yes"/> - <xsl:strip-space elements="*"/> - <xsl:template match="Data"> - <xsl:call-template name="generatelinks"> - <xsl:with-param name="current" select="'1'"/> - <xsl:with-param name="last" select="last"/> - </xsl:call-template> - <chain function="ParseEpisodeList"></chain> - </xsl:template> - <xsl:template name="generatelinks"> - <xsl:param name="current"/> - <xsl:param name="last"/> - <xsl:if test="$last>=$current"> - <url><xsl:attribute name="function">LoadEpisodeList</xsl:attribute><xsl:attribute name="cache">episodes-$$18-<xsl:value-of select="$current"/>-$INFO[language].json</xsl:attribute>https://api.thetvdb.com/series/$$18/episodes?page=<xsl:value-of select="$current"/>|Authorization=Bearer%20$$19&accept-language=$INFO[language]</url> - <xsl:call-template name="generatelinks"> - <xsl:with-param name="current" select="$current+1"/> - <xsl:with-param name="last" select="last"/> - </xsl:call-template> - </xsl:if> - </xsl:template> - - </xsl:stylesheet> - </XSLT> - <expression noclean="1" fixchars="1"/> - </RegExp> - </GetEpisodeListAuth> - <LoadEpisodeList dest="4" clearbuffers="no"> - <RegExp input="" output="<episodeguide></episodeguide>" dest="4"> - <RegExp input="$$1" output="<Episode><absolute_number>\9</absolute_number><EpisodeNumber>\3</EpisodeNumber><SeasonNumber>\2</SeasonNumber><DVD_episodenumber>\8</DVD_episodenumber><DVD_season>\7</DVD_season><EpisodeName>\4</EpisodeName><FirstAired>\5</FirstAired><id>\1</id><Overview>\6</Overview><filename>\10</filename></Episode>" dest="11+"> - <expression fixchars="4,6" repeat="yes">{"id":\s*?(\d+),"airedSeason":\s*?(\d+),"airedSeasonID":\s*?\d+,"airedEpisodeNumber":\s*?(\d+),"episodeName":\s*?(?:"([^}]*)"|null),"firstAired":\s*?(?:"([^"]*)"|null),[^{]*?\s*?"overview":\s*?(?:"([^}]*)"|null),"language":\s*?{[^}]+},[^{]*?,"dvdSeason":\s*?(?:(\d+)|null),"dvdEpisodeNumber":\s*?(?:([\d\.]+)|null),"dvdChapter":\s*?(?:\d+|null),"absoluteNumber":\s*?(?:(\d+)|null),"filename":(?:"([^"]*)"|null),</expression> - </RegExp> - <RegExp input="$$11" output="yes" dest="20"> - <expression clear="yes">(?!^$)</expression> - </RegExp> - <expression/> - </RegExp> - </LoadEpisodeList> - - <ParseEpisodeList dest="4" clearbuffers="no"> - <RegExp input="" output="" dest="4"> - <expression clear="yes"/> - </RegExp> - <RegExp input="" output="" dest="12"> - <expression clear="yes"/> - </RegExp> - <XSLT input="<Data>$$11</Data>" output="\1" dest="12"> - <xsl:stylesheet version = "1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:output omit-xml-declaration="yes" indent="yes"/> - <xsl:strip-space elements="*"/> - <xsl:key name="EpisodesBySeason" match="Episode" use="SeasonNumber"/> - <xsl:template match="Data"> - <xsl:if test="'$INFO[absolutenumber]'='true'"> - <xsl:variable name="season-list"> - <xsl:for-each select="//Episode[(SeasonNumber>0) and (generate-id() = generate-id(key('EpisodesBySeason', SeasonNumber)[1]))]"><xsl:sort select="SeasonNumber" data-type="number"/><xsl:value-of select="SeasonNumber"/>|</xsl:for-each> - </xsl:variable> - <xsl:call-template name="count-episodes"> - <xsl:with-param name="season-list" select="$season-list"/> - <xsl:with-param name="count-list" select="concat('|S', substring-before($season-list,'|'), '|0')"/> - </xsl:call-template> - </xsl:if> - </xsl:template> - <xsl:template name="count-episodes"> - <xsl:param name="season-list"/> - <xsl:param name="count-list"/> - <xsl:variable name="first" select="substring-before($season-list,'|')"/> - <xsl:variable name="remaining" select="substring-after($season-list,'|')"/> - <xsl:variable name="next" select="substring-before($remaining,'|')"/> - <xsl:variable name="currList" select="concat($count-list, '|S', $next, '|', string(count(//Episode[SeasonNumber=$first])+substring-after($count-list,concat('|S',$first,'|'))))"/> - <xsl:choose> - <xsl:when test="substring-after($remaining,'|')!=''"> - <xsl:call-template name="count-episodes"> - <xsl:with-param name="season-list" select="$remaining"/> - <xsl:with-param name="count-list" select="$currList"/> - </xsl:call-template> - </xsl:when> - <xsl:otherwise><xsl:value-of select="$currList"/>|</xsl:otherwise> - </xsl:choose> - </xsl:template> - </xsl:stylesheet> - </XSLT> - <XSLT input="<Data>$$11</Data>" output="\1" dest="4"> - <xsl:stylesheet version = "1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:output omit-xml-declaration="yes" indent="yes"/> - <xsl:strip-space elements="*"/> - <xsl:key name="EpisodesByDVDnumber" match="Episode" use="concat(DVD_season,',',substring-before(concat(DVD_episodenumber,'.'),'.'))"/> - <xsl:key name="EpisodesBySeason" match="Episode" use="SeasonNumber"/> - <xsl:variable name="title-divider" select="' / '"/> - - <xsl:variable name="SeasonCounts"> - <xsl:if test="'$INFO[absolutenumber]'='true'">$$12</xsl:if> - </xsl:variable> - - <xsl:template match="Data"> - <episodeguide> - <xsl:comment> Episode order: <xsl:choose><xsl:when test="'$INFO[dvdorder]'='true'">DVD </xsl:when><xsl:when test="'$INFO[absolutenumber]'='true'">Absolute </xsl:when><xsl:otherwise>Aired </xsl:otherwise></xsl:choose></xsl:comment> - <xsl:apply-templates select="Episode"/> - <xsl:if test="'$INFO[dvdorder]'='true'"> - <xsl:apply-templates select="Episode[(substring-after(DVD_episodenumber,'.')>0) and (generate-id() = generate-id(key('EpisodesByDVDnumber', concat(DVD_season,',',substring-before(DVD_episodenumber,'.')))[1]))]" mode="dvdmergedep"/> - </xsl:if> - </episodeguide> - </xsl:template> - - <xsl:template match="Episode"> - <episode> - <id><xsl:value-of select="id"/></id> - <title><xsl:value-of select="EpisodeName"/></title> - <aired><xsl:value-of select="FirstAired"/></aired> - <xsl:choose> - <xsl:when test="'$INFO[dvdorder]'!='true'"> - <xsl:choose> - <xsl:when test="('$INFO[absolutenumber]'='true') and ((SeasonNumber>0) or ((absolute_number!='') and (absolute_number!=0)))"> - <epnum> - <xsl:choose> - <xsl:when test="(absolute_number!='') and (absolute_number!=0)"><xsl:value-of select="absolute_number"/></xsl:when> - <xsl:otherwise><xsl:value-of select="substring-before(substring-after($SeasonCounts, concat('|S', SeasonNumber, '|')), '|') + EpisodeNumber"/></xsl:otherwise> - </xsl:choose> - </epnum> - <season>1</season> - </xsl:when> - <xsl:when test="('$INFO[absolutenumber]'='true') and (SeasonNumber=0)"><epnum><xsl:value-of select="EpisodeNumber"/></epnum><season>0</season></xsl:when> - <xsl:otherwise><epnum><xsl:value-of select="EpisodeNumber"/></epnum><season><xsl:value-of select="SeasonNumber"/></season></xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="((DVD_episodenumber!='') and (DVD_season!='')) and ((DVD_episodenumber!=0) or (DVD_season!=0))"> - <epnum><xsl:value-of select="DVD_episodenumber"/></epnum> - <season><xsl:value-of select="DVD_season"/></season> - </xsl:when> - <xsl:otherwise> - <epnum><xsl:value-of select="EpisodeNumber"/><xsl:if test="key('EpisodesByDVDnumber', concat(SeasonNumber,',',EpisodeNumber))">.<xsl:value-of select="count(key('EpisodesByDVDnumber', concat(SeasonNumber,',',EpisodeNumber))[(DVD_episodenumber!='') and number(substring-after(concat(DVD_episodenumber,'.0'),'.'))>0])+1"/></xsl:if></epnum> - <season><xsl:value-of select="SeasonNumber"/></season> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - <url post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6","id":<xsl:value-of select="id"/>}|Content-Type=application/json&accept-language=$INFO[language]</url> - </episode> - </xsl:template> - - <xsl:template match="Episode" mode="dvdmergedep"> - <xsl:variable name="mergedid"><xsl:for-each select="key('EpisodesByDVDnumber', concat(DVD_season,',',substring-before(DVD_episodenumber,'.')))"><xsl:sort select="substring-after(DVD_episodenumber,'.')" data-type="number"/><xsl:value-of select="id"/>|</xsl:for-each></xsl:variable> - <xsl:variable name="title"><xsl:for-each select="key('EpisodesByDVDnumber', concat(DVD_season,',',substring-before(DVD_episodenumber,'.')))"><xsl:sort select="substring-after(DVD_episodenumber,'.')" data-type="number"/><xsl:value-of select="concat(normalize-space(EpisodeName),$title-divider)"/></xsl:for-each></xsl:variable> - <xsl:variable name="mergedtitle"> - <xsl:call-template name="shrink-title"> - <xsl:with-param name="full-title" select="$title" /> - <xsl:with-param name="title-list" select="substring-after($title,$title-divider)" /> - <xsl:with-param name="test-title" select="substring(substring-before($title,$title-divider),1,string-length(substring-before($title,$title-divider))-4)" /> - </xsl:call-template> - </xsl:variable> - <episode> - <id><xsl:value-of select="substring($mergedid,1,string-length($mergedid)-1)"/></id> - <title><xsl:value-of select="$mergedtitle"/></title> - <aired><xsl:value-of select="FirstAired"/></aired> - <epnum><xsl:value-of select="substring-before(DVD_episodenumber,'.')"/></epnum> - <season><xsl:value-of select="DVD_season"/></season> - <url post="yes" cache="auth.json">https://api.thetvdb.com/login?{"apikey":"439DFEBA9D3059C6","id":<xsl:value-of select="$mergedid"/>}|Content-Type=application/json</url> - </episode> - </xsl:template> - - <xsl:template name="shrink-title"> - <xsl:param name="full-title"/> - <xsl:param name="title-list"/> - <xsl:param name="test-title"/> - <xsl:variable name="first" select="substring-before($title-list,$title-divider)"/> - <xsl:variable name="remaining" select="substring-after($title-list,$title-divider)"/> - <xsl:choose> - <xsl:when test="$test-title!=substring($first,1,string-length($first)-4)"><xsl:value-of select="substring($full-title,1,string-length($full-title)-string-length($title-divider))"/></xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="$remaining=''"><xsl:value-of select="$test-title"/></xsl:when> - <xsl:otherwise> - <xsl:call-template name="shrink-title"> - <xsl:with-param name="full-title" select="$full-title" /> - <xsl:with-param name="title-list" select="$remaining" /> - <xsl:with-param name="test-title" select="$test-title" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - </xsl:stylesheet> - </XSLT> - </ParseEpisodeList> - - <!-- input : $$1=episode html --> - <!-- input : $$2=id --> - <!-- input : $$3=episode url --> - <!-- output: <details><title>*</title><plot>*</plot><uniqueid>*</uniqueid><aired>*</aired><episode>*</episode><season>*</season></details> --> - <GetEpisodeDetails dest="4" clearbuffers="no"> - <RegExp input="$$5" output="<details>\1<chain function="ParseEpisodeDetails"></chain></details>" dest="4"> - <RegExp input="$$3" output="\1" dest="18"> - <expression>"id":(\d+)}</expression> - </RegExp> - <RegExp input="$$1" output="\1" dest="19"> - <expression>"token":\s*?"(.*)"</expression> - </RegExp> - <RegExp input="$$2|" output="<url function="GetEpisodeDetailsAuth" cache="episode-\1-$INFO[language].json">https://api.thetvdb.com/episodes/\1|Authorization=Bearer%20$$19&amp;accept-language=$INFO[language]</url>" dest="5"> - <expression noclean="1" repeat="yes">(\d+)\|</expression> - </RegExp> - <RegExp input="$$1" output="" dest="13"> - <expression clear="yes"/> - </RegExp> - <expression noclean="1"/> - </RegExp> - </GetEpisodeDetails> - <GetEpisodeDetailsAuth dest="4" clearbuffers="no"> - <RegExp input="$$5" output="<details>\1</details>" dest="4"> - <RegExp input="" output="" dest="14"> - <expression clear="yes"/> - </RegExp> - <RegExp input="$$1" output="<id>\1</id>" dest="10"> - <expression clear="yes">"id":\s*?(\d+),</expression> - </RegExp> - <RegExp input="$$1" output="\1" dest="17"> - <expression clear="yes">"id":\s*?(\d+),</expression> - </RegExp> - <RegExp input="$$1" output="<airedSeason>\1</airedSeason>" dest="10+"> - <expression>"airedSeason":\s*?(\d+),</expression> - </RegExp> - <RegExp input="$$1" output="<airedEpisodeNumber>\1</airedEpisodeNumber>" dest="10+"> - <expression>"airedEpisodeNumber":\s*?(\d+),</expression> - </RegExp> - <RegExp input="$$1" output="<episodeName>\1</episodeName>" dest="10+"> - <expression fixchars="1">"episodeName":\s*?"(.*)",\s*?"firstAired"</expression> - </RegExp> - <RegExp conditional="usefallbacklanguage1" input="$$1" output="missingtitle|" dest="14"> - <expression clear="yes">"episodeName":\s*?null,\s*?"firstAired"</expression> - </RegExp> - <RegExp input="$$1" output="<firstAired>\1</firstAired>" dest="10+"> - <expression>"firstAired":\s*?(?:"([^"]*)"|null),</expression> - </RegExp> - <RegExp input="$$7" output="<overview>\1</overview>" dest="10+"> - <RegExp input="$$6\r" output="\1\n" dest="7"> - <RegExp input="$$1" output="\1" dest="6"> - <expression clear="yes" noclean="1">"overview":\s*?"(.*)",\s*?"language"</expression> - </RegExp> - <expression clear="yes" repeat="yes" fixchars="1">(.*?)\\r</expression> - </RegExp> - <expression noclean="1">(?!^$)(.*)</expression> - </RegExp> - <RegExp conditional="usefallbacklanguage1" input="$$1" output="missingplot|" dest="14+"> - <expression fixchars="1">"overview":\s*?null,\s*?"language"</expression> - </RegExp> - <RegExp input="$$1" output="<dvdSeason>\1</dvdSeason>" dest="10+"> - <expression>"dvdSeason":\s*?(?:(\d+)|null),</expression> - </RegExp> - <RegExp input="$$1" output="<dvdEpisodeNumber>\1</dvdEpisodeNumber>" dest="10+"> - <expression>"dvdEpisodeNumber":\s*?(?:([\d\.]+)|null),</expression> - </RegExp> - <RegExp input="$$1" output="<absoluteNumber>\1</absoluteNumber>" dest="10+"> - <expression>"absoluteNumber":\s*?(?:(\d+)|null),</expression> - </RegExp> - <RegExp input="$$1" output="<airsAfterSeason>\1</airsAfterSeason>" dest="10+"> - <expression>"airsAfterSeason":\s*?(?:(\d+)|null),</expression> - </RegExp> - <RegExp input="$$1" output="<airsBeforeSeason>\1</airsBeforeSeason>" dest="10+"> - <expression>"airsBeforeSeason":\s*?(?:(\d+)|null),</expression> - </RegExp> - <RegExp input="$$1" output="<airsBeforeEpisode>\1</airsBeforeEpisode>" dest="10+"> - <expression>"airsBeforeEpisode":\s*?(?:(\d+)|null),</expression> - </RegExp> - <RegExp input="$$1" output="<siteRating>\1</siteRating>" dest="10+"> - <expression>"siteRating":\s*?(?:([\d\.]+)|null),</expression> - </RegExp> - <RegExp input="$$1" output="<siteRatingCount>\1</siteRatingCount>" dest="10+"> - <expression>"siteRatingCount":\s*?(?:(\d+)|null)\s*?}</expression> - </RegExp> - <RegExp input="$$1" output="<imdbId>\1</imdbId>" dest="10+"> - <expression fixchars="1">"imdbId":\s*?"(tt\d+)",</expression> - </RegExp> - <RegExp input="$$1" output="<filename>\1</filename>" dest="10+"> - <expression>"filename":\s*?(?:"([^"]*)"|null),</expression> - </RegExp> - <RegExp input="$$9," output="<credits>\1</credits>" dest="10+"> - <RegExp input="$$1" output="\1" dest="9"> - <expression clear="yes">"writers":\s*?\[([^]]*)\],</expression> - </RegExp> - <expression fixchars="1" repeat="yes">"([^"]*)",</expression> - </RegExp> - <RegExp input="$$9," output="<director>\1</director>" dest="10+"> - <RegExp input="$$1" output="\1" dest="9"> - <expression clear="yes">"directors":\s*?\[([^]]*)\],</expression> - </RegExp> - <expression fixchars="1" repeat="yes">"([^"]*)",</expression> - </RegExp> - <RegExp input="$$9," output="<actor><name>\1</name></actor>" dest="10+"> - <RegExp input="$$1" output="\1" dest="9"> - <expression clear="yes">"guestStars":\s*?\[\s*?"([^]]*)"\s*?\],</expression> - </RegExp> - <expression fixchars="1" repeat="yes">([^,"]+)[,"\s]+</expression> - </RegExp> - <RegExp input="$$9" output="\1" dest="13+"> - <RegExp input="$$14" output="<Episode>$$10</Episode>" dest="9"> - <expression clear="yes">^$</expression> - </RegExp> - <RegExp input="$INFO[language]" output="<Episode>$$10</Episode>" dest="9"> - <expression>^\Q$INFO[fallbacklanguage]\E$</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - <RegExp input="$INFO[language]" output="$$6" dest="5"> - <RegExp input="$$14" output="<url function="GetFallbackEpisodeDetails" cache="episode-$$17-$INFO[fallbacklanguage].json">https://api.thetvdb.com/episodes/$$17|Authorization=Bearer%20$$19&accept-language=$INFO[fallbacklanguage]</url>" dest="6"> - <expression clear="yes">(?!^$)</expression> - </RegExp> - <expression>(?!^\Q$INFO[fallbacklanguage]\E$)</expression> - </RegExp> - <expression noclean="1" fixchars="1"/> - </RegExp> - </GetEpisodeDetailsAuth> - <GetFallbackEpisodeDetails dest="3" clearbuffers="no"> - <RegExp input="$$4" output="<details></details>" dest="3"> - <RegExp input="$$14" output="$$5" dest="10+"> - <RegExp input="$$1" output="<episodeName>\1</episodeName>" dest="5"> - <expression clear="yes" fixchars="1">"episodeName":\s*?"(.*)",\s*?"firstAired"</expression> - </RegExp> - <expression>missingtitle</expression> - </RegExp> - <RegExp input="$$14" output="$$5" dest="10+"> - <RegExp input="$$7" output="<overview>\1</overview>" dest="5"> - <RegExp input="$$6\r" output="\1\n" dest="7"> - <RegExp input="$$1" output="\1" dest="6"> - <expression clear="yes" noclean="1">"overview":\s*?"(.*)",\s*?"language"</expression> - </RegExp> - <expression repeat="yes" fixchars="1">(.*?)\\r</expression> - </RegExp> - <expression noclean="1"/> - </RegExp> - <expression>missingplot</expression> - </RegExp> - <RegExp input="$$10" output="<Episode>\1</Episode>" dest="13+"> - <expression noclean="1"/> - </RegExp> - <expression noclean="1" fixchars="1"/> - </RegExp> - </GetFallbackEpisodeDetails> - <ParseEpisodeDetails dest="4" clearbuffers="no"> - <RegExp input="$$5" output="\1" dest="4"> - <RegExp input="$$1" output="" dest="5"> - <expression clear="yes"/> - </RegExp> - <XSLT input="<Data><current>$$13</current><all>$$11</all></Data>" output="\1" dest="5"> - <xsl:stylesheet version = "1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - <xsl:output indent="yes"/> - <xsl:strip-space elements="*"/> - <xsl:key name="EpisodesByDVDnumber" match="current/Episode" use="concat(dvdSeason,',',substring-before(concat(dvdEpisodeNumber,'.'),'.'))"/> - <xsl:variable name="SeasonCounts"> - <xsl:if test="'$INFO[absolutenumber]'='true'">$$12</xsl:if> - </xsl:variable> - - <xsl:variable name="episode-list" select="concat('$$2','|')" /> - <xsl:variable name="FirstEpisode" select="Data/current/Episode[id=substring-before($episode-list,'|')]" /> - <xsl:variable name="single-episode" select="substring-after($episode-list,'|')=''" /> - <xsl:variable name="AirsBeforeEpisode" select="Data/all/Episode[(SeasonNumber=$FirstEpisode/airsBeforeSeason) and (EpisodeNumber=$FirstEpisode/airsBeforeEpisode)]"/> - <xsl:variable name="AirsAfterEpisode" select="Data/all/Episode[(SeasonNumber=$FirstEpisode/airsAfterSeason + 1) and (EpisodeNumber=1)]"/> - <xsl:variable name="AfterSeasonCount" select="substring-before(substring-after($SeasonCounts, concat('|S', $FirstEpisode/airsAfterSeason + 1, '|')), '|')"/> - - <xsl:variable name="title-divider" select="' / '"/> - <xsl:variable name="plot-divider" select="' ---- '" /> - - <xsl:template match="*"/> - - <xsl:template match="Episode"/> - - <xsl:template match="Data"> - <xsl:apply-templates select="current"/> - </xsl:template> - - <xsl:template match="current"> - <details> - <title> - <xsl:choose> - <xsl:when test="$single-episode"><xsl:value-of select="$FirstEpisode/episodeName"/></xsl:when> - <xsl:otherwise> - <xsl:variable name="title"> - <xsl:call-template name="merge-details"> - <xsl:with-param name="list" select="$episode-list" /> - <xsl:with-param name="element" select="'episodeName'" /> - <xsl:with-param name="divider" select="$title-divider" /> - </xsl:call-template> - </xsl:variable> - <xsl:call-template name="shrink-title"> - <xsl:with-param name="full-title" select="$title" /> - <xsl:with-param name="title-list" select="substring-after(concat($title,$title-divider),$title-divider)" /> - <xsl:with-param name="test-title" select="substring(substring-before($title,$title-divider),1,string-length(substring-before($title,$title-divider))-4)" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </title> - <plot> - <xsl:choose> - <xsl:when test="$single-episode"><xsl:value-of select="$FirstEpisode/overview"/></xsl:when> - <xsl:otherwise> - <xsl:call-template name="merge-details"> - <xsl:with-param name="list" select="$episode-list" /> - <xsl:with-param name="element" select="'overview'" /> - <xsl:with-param name="divider" select="$plot-divider" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </plot> - <uniqueid type="tvdb" default="true"><xsl:value-of select="$FirstEpisode/id"/></uniqueid> - <xsl:if test="$FirstEpisode/imdbId!=''"><uniqueid type="imdb"><xsl:value-of select="$FirstEpisode/imdbId"/></uniqueid></xsl:if> - <aired><xsl:value-of select="$FirstEpisode/firstAired"/></aired> - <xsl:choose> - <xsl:when test="'$INFO[dvdorder]'!='true'"> - <xsl:choose> - <xsl:when test="('$INFO[absolutenumber]'='true') and (($FirstEpisode/airedSeason>0) or (($FirstEpisode/absoluteNumber!='') and ($FirstEpisode/absoluteNumber!=0)))"> - <episode> - <xsl:choose> - <xsl:when test="($FirstEpisode/absoluteNumber!='') and ($FirstEpisode/absoluteNumber!=0)"><xsl:value-of select="$FirstEpisode/absoluteNumber"/></xsl:when> - <xsl:otherwise><xsl:value-of select="substring-before(substring-after($SeasonCounts, concat('|S', $FirstEpisode/airedSeason, '|')), '|') + $FirstEpisode/airedEpisodeNumber"/></xsl:otherwise> - </xsl:choose> - </episode> - <season>1</season> - </xsl:when> - <xsl:when test="('$INFO[absolutenumber]'='true') and ($FirstEpisode/airedSeason=0)"> - <episode><xsl:value-of select="$FirstEpisode/airedEpisodeNumber"/></episode> - <season>0</season> - </xsl:when> - <xsl:otherwise> - <episode><xsl:value-of select="$FirstEpisode/airedEpisodeNumber"/></episode> - <season><xsl:value-of select="$FirstEpisode/airedSeason"/></season> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="(($FirstEpisode/dvdEpisodeNumber='') or ($FirstEpisode/dvdSeason='')) or (($FirstEpisode/dvdEpisodeNumber=0) and ($FirstEpisode/dvdSeason=0))"> - <episode><xsl:value-of select="$FirstEpisode/airedEpisodeNumber"/><xsl:if test="key('EpisodesByDVDnumber', concat($FirstEpisode/airedSeason,',',$FirstEpisode/airedEpisodeNumber))">.<xsl:value-of select="count(key('EpisodesByDVDnumber', concat($FirstEpisode/airedSeason,',',$FirstEpisode/airedEpisodeNumber))[(dvdEpisodeNumber!='') and number(substring-after(concat(dvdEpisodeNumber,'.0'),'.'))>0])+1"/></xsl:if></episode> - <season><xsl:value-of select="$FirstEpisode/airedSeason"/></season> - </xsl:when> - <xsl:otherwise> - <episode> - <xsl:choose> - <xsl:when test="$single-episode"><xsl:value-of select="$FirstEpisode/dvdEpisodeNumber"/></xsl:when> - <xsl:otherwise><xsl:value-of select="substring-before($FirstEpisode/dvdEpisodeNumber,'.')"/></xsl:otherwise> - </xsl:choose> - </episode> - <season><xsl:value-of select="$FirstEpisode/dvdSeason"/></season> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - <xsl:if test="$FirstEpisode/airedSeason=0"> - <xsl:choose> - <xsl:when test="'$INFO[dvdorder]'!='true'"> - <xsl:choose> - <xsl:when test="'$INFO[absolutenumber]'='true'"> - <xsl:if test="($FirstEpisode/airsBeforeSeason!='') or ($FirstEpisode/airsBeforeEpisode!='')"> - <displayepisode> - <xsl:choose> - <xsl:when test="$AirsBeforeEpisode and ($AirsBeforeEpisode/absoluteNumber!='')"><xsl:value-of select="$AirsBeforeEpisode/absoluteNumber"/></xsl:when> - <xsl:otherwise><xsl:value-of select="substring-before(substring-after($SeasonCounts, concat('|S', $AirsBeforeEpisode/SeasonNumber, '|')), '|') + $FirstEpisode/airsBeforeEpisode"/></xsl:otherwise> - </xsl:choose> - </displayepisode> - <displayseason>1</displayseason> - </xsl:if> - <xsl:if test="($FirstEpisode/airsAfterSeason!='') and ($AfterSeasonCount!='')"> - <displayepisode> - <xsl:choose> - <xsl:when test="$AirsAfterEpisode and ($AirsAfterEpisode/absoluteNumber!='')"><xsl:value-of select="$AirsAfterEpisode/absoluteNumber"/></xsl:when> - <xsl:otherwise><xsl:value-of select="$AfterSeasonCount + 1"/></xsl:otherwise> - </xsl:choose> - </displayepisode> - <displayseason>1</displayseason> - </xsl:if> - <xsl:if test="($FirstEpisode/airsAfterSeason!='') and ($AfterSeasonCount='')"> - <displayafterseason>1</displayafterseason> - </xsl:if> - </xsl:when> - <xsl:otherwise> - <displayepisode><xsl:value-of select="$FirstEpisode/airsBeforeEpisode"/></displayepisode> - <displayseason><xsl:value-of select="$FirstEpisode/airsBeforeSeason"/></displayseason> - <displayafterseason><xsl:value-of select="$FirstEpisode/airsAfterSeason"/></displayafterseason> - </xsl:otherwise> - </xsl:choose> - </xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="$AirsBeforeEpisode and ($AirsBeforeEpisode/dvdEpisodeNumber!='') and ($AirsBeforeEpisode/dvdSeason!='')"> - <displayepisode><xsl:value-of select="$AirsBeforeEpisode/dvdEpisodeNumber"/></displayepisode> - <displayseason><xsl:value-of select="$AirsBeforeEpisode/dvdSeason"/></displayseason> - </xsl:when> - <xsl:otherwise> - <displayepisode><xsl:value-of select="$FirstEpisode/airsBeforeEpisode"/></displayepisode> - <displayseason><xsl:value-of select="$FirstEpisode/airsBeforeSeason"/></displayseason> - </xsl:otherwise> - </xsl:choose> - <displayafterseason><xsl:value-of select="$FirstEpisode/airsAfterSeason"/></displayafterseason> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - <xsl:if test="('$INFO[RatingS]'='IMDb') or ('$INFO[alsoimdb]'='true')"> - <xsl:if test="$FirstEpisode/imdbId!=''"><chain function="GetIMDBRatingsById"><xsl:value-of select="$FirstEpisode/imdbId"/><xsl:if test="'$INFO[RatingS]'='IMDb'">|default</xsl:if></chain></xsl:if> - </xsl:if> - <xsl:if test="('$INFO[RatingS]'='TheTVDB') or ('$INFO[fallback]'='true')"> - <xsl:choose> - <xsl:when test="$single-episode"> - <ratings> - <rating> - <xsl:attribute name="name">tvdb</xsl:attribute> - <xsl:if test="'$INFO[RatingS]'='TheTVDB'"><xsl:attribute name="default">true</xsl:attribute></xsl:if> - <value><xsl:value-of select="$FirstEpisode/siteRating"/></value> - <votes><xsl:value-of select="$FirstEpisode/siteRatingCount"/></votes> - </rating> - </ratings> - </xsl:when> - <xsl:otherwise> - <xsl:call-template name="merge-rating"> - <xsl:with-param name="list" select="$episode-list" /> - <xsl:with-param name="rating" select="'0'" /> - <xsl:with-param name="votes" select="'0'" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:if> - <xsl:call-template name="split-details"> - <xsl:with-param name="list" select="$episode-list"/> - </xsl:call-template> - </details> - </xsl:template> - - <xsl:template name="merge-details"> - <xsl:param name="list"/> - <xsl:param name="element"/> - <xsl:param name="divider"/> - <xsl:variable name="first" select="substring-before($list, '|')" /> - <xsl:variable name="remaining" select="substring-after($list, '|')" /> - <xsl:if test="$first!=''"><xsl:value-of select="//Episode[id=$first]/child::*[name()=$element]"/><xsl:if test="$remaining!=''"><xsl:value-of select="$divider"/></xsl:if></xsl:if> - <xsl:if test="$remaining!=''"> - <xsl:call-template name="merge-details"> - <xsl:with-param name="list" select="$remaining" /> - <xsl:with-param name="element" select="$element" /> - <xsl:with-param name="divider" select="$divider" /> - </xsl:call-template> - </xsl:if> - </xsl:template> - - <xsl:template name="shrink-title"> - <xsl:param name="full-title"/> - <xsl:param name="title-list"/> - <xsl:param name="test-title"/> - <xsl:variable name="first" select="substring-before($title-list,$title-divider)"/> - <xsl:variable name="remaining" select="substring-after($title-list,$title-divider)"/> - <xsl:choose> - <xsl:when test="$test-title!=substring($first,1,string-length($first)-4)"><xsl:value-of select="$full-title"/></xsl:when> - <xsl:otherwise> - <xsl:choose> - <xsl:when test="$remaining=''"><xsl:value-of select="$test-title"/></xsl:when> - <xsl:otherwise> - <xsl:call-template name="shrink-title"> - <xsl:with-param name="full-title" select="$full-title" /> - <xsl:with-param name="title-list" select="$remaining" /> - <xsl:with-param name="test-title" select="$test-title" /> - </xsl:call-template> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <xsl:template name="merge-rating"> - <xsl:param name="list"/> - <xsl:param name="rating"/> - <xsl:param name="votes"/> - <xsl:variable name="first" select="substring-before($list, '|')" /> - <xsl:variable name="remaining" select="substring-after($list, '|')" /> - <xsl:variable name="currVotes" select="$votes + Episode[id=$first]/siteRatingCount" /> - <xsl:variable name="firstRating"> - <xsl:choose> - <xsl:when test="Episode[id=$first]/siteRating!=''"><xsl:value-of select="Episode[id=$first]/siteRating"/></xsl:when> - <xsl:otherwise>1</xsl:otherwise> - </xsl:choose> - </xsl:variable> - <xsl:variable name="currRating" select="$rating + ($firstRating * Episode[id=$first]/siteRatingCount)" /> - <xsl:choose> - <xsl:when test="$remaining!=''"> - <xsl:call-template name="merge-rating"> - <xsl:with-param name="list" select="$remaining" /> - <xsl:with-param name="rating" select="$currRating" /> - <xsl:with-param name="votes" select="$currVotes" /> - </xsl:call-template> - </xsl:when> - <xsl:otherwise> - <ratings> - <rating> - <xsl:attribute name="name">tvdb</xsl:attribute> - <xsl:if test="'$INFO[RatingS]'='TheTVDB'"><xsl:attribute name="default">true</xsl:attribute></xsl:if> - <xsl:if test="$currVotes>0"> - <value><xsl:value-of select="format-number($currRating div $currVotes,'#.#')"/></value> - </xsl:if> - <votes><xsl:value-of select="$currVotes"/></votes> - </rating> - </ratings> - </xsl:otherwise> - </xsl:choose> - </xsl:template> - - <xsl:template name="split-details"> - <xsl:param name="list"/> - <xsl:variable name="first" select="substring-before(normalize-space($list), '|')" /> - <xsl:variable name="remaining" select="substring-after(normalize-space($list), '|')" /> - <xsl:if test="$first!=''"><xsl:apply-templates select="Episode[id=$first]" mode="match"/></xsl:if> - <xsl:if test="$remaining!='' and $remaining!='|'"> - <xsl:call-template name="split-details"> - <xsl:with-param name="list" select="$remaining" /> - </xsl:call-template> - </xsl:if> - </xsl:template> - - <xsl:template match="Episode" mode="match"> - <xsl:if test="filename!=''"><thumb>http://www.thetvdb.com/banners/<xsl:value-of select="filename"/></thumb></xsl:if> - <xsl:for-each select="credits|director|actor"> - <xsl:copy-of select="."/> - </xsl:for-each> - </xsl:template> - - <xsl:template name="split"> - <xsl:param name="list"/> - <xsl:param name="element"/> - <xsl:variable name="first" select="substring-before(normalize-space($list), '|')" /> - <xsl:variable name="remaining" select="substring-after(normalize-space($list), '|')" /> - <xsl:if test="$first!=''"><xsl:element name="{$element}"><xsl:value-of select="$first"/></xsl:element></xsl:if> - <xsl:if test="$remaining!='' and $remaining!='|'"> - <xsl:call-template name="split"> - <xsl:with-param name="list" select="$remaining" /> - <xsl:with-param name="element" select="$element" /> - </xsl:call-template> - </xsl:if> - </xsl:template> - - </xsl:stylesheet> - </XSLT> - <expression noclean="1" fixchars="1"/> - </RegExp> - </ParseEpisodeDetails> - <GetIMDBRatingsById dest="5" clearbuffers="no"> - <RegExp input="$$1" output="<details><url cache="\1-main.html" function="ParseIMDBRatings">http://www.imdb.com/title/\1/|accept-language=en-us</url></details>" dest="5"> - <expression noclean="1">^(tt\d+)</expression> - </RegExp> - <RegExp input="$$1" output="default="true"" dest="3"> - <expression clear="yes">\|default$</expression> - </RegExp> - </GetIMDBRatingsById> - <ParseIMDBRatings dest="5" clearbuffers="no"> - <RegExp input="$$2" output="<details>\1</details>" dest="5"> - <RegExp input="$$1" output="<ratings><rating name="imdb" $$3><value>\2</value><votes>\1</votes></rating></ratings>" dest="2"> - <expression>"ratingCount":\s([0-9,]+),\s*"bestRating":\s"[^"]*",\s*"worstRating":\s"[^"]*",\s*"ratingValue":\s"([0-9.]+)</expression> - </RegExp> - <expression noclean="1" /> - </RegExp> - </ParseIMDBRatings> -</scraper> diff --git a/addons/metadata.tvshows.themoviedb.org/LICENSE.TXT b/addons/metadata.tvshows.themoviedb.org/LICENSE.TXT new file mode 100644 index 0000000000..47f7503cba --- /dev/null +++ b/addons/metadata.tvshows.themoviedb.org/LICENSE.TXT @@ -0,0 +1,287 @@ + + You may use, distribute and copy XBMC under the terms of GNU General + Public License version 2, which is displayed below. + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS +------------------------------------------------------------------------- diff --git a/addons/metadata.tvshows.themoviedb.org/addon.xml b/addons/metadata.tvshows.themoviedb.org/addon.xml new file mode 100644 index 0000000000..cbe0d753b6 --- /dev/null +++ b/addons/metadata.tvshows.themoviedb.org/addon.xml @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addon id="metadata.tvshows.themoviedb.org" + name="The Movie Database" + version="3.0.6" + provider-name="Team Kodi"> + <requires> + <import addon="xbmc.metadata" version="2.1.0"/> + <import addon="metadata.common.fanart.tv" version="3.1.0"/> + </requires> + <extension point="xbmc.metadata.scraper.tvshows" + language="en" + library="tmdb.xml"/> + <extension point="xbmc.addon.metadata"> + <summary lang="bg">Сваля инф. за ТВ Сериали от TMDB</summary> + <summary lang="cs">TMDb zdroj dat k seriálům </summary> + <summary lang="de">TMDB Fernsehserien Scraper</summary> + <summary lang="el">Scraper Τηλ. Σειρών του TMDb</summary> + <summary lang="en">TMDB TV show Scraper</summary> + <summary lang="en_US">TMDB TV show Scraper</summary> + <summary lang="es">Scraper de series TMDB</summary> + <summary lang="fr_CA">Extracteur de d'émissions télé TMDb</summary> + <summary lang="gl">Scraper serie de TV TMDB</summary> + <summary lang="he">סקרייפר סדרות TMDB</summary> + <summary lang="hr">TMDB sakupljač TV serija</summary> + <summary lang="hu">TMDB TV show Letöltő</summary> + <summary lang="id">Pengais Serial TV TMDB</summary> + <summary lang="is">TMDB TV skafa fyrir sjónvarpsefni</summary> + <summary lang="ko">TMDB TV 쇼 정보수집기</summary> + <summary lang="lt">TMDB TV laidų skreperis</summary> + <summary lang="nl">TMDB TV-serie scraper</summary> + <summary lang="pl">Ekstraktor serialowy TMDB</summary> + <summary lang="pt">Colector de filmes TMDb</summary> + <summary lang="pt_BR">Scraper de Seriados TMDb</summary> + <summary lang="ru">TMDB ТВ шоу инфоресурс</summary> + <summary lang="sv">TMDB TV-serie skrapa</summary> + <summary lang="zh">TMDB 剧集刮削器</summary> + <description lang="af">themoviedb.org is 'n verniet en oop fliek databasis. Dit is totaal gebruiker gedryf deur mense soos jy. TMDB word huidiglik deur miljoene mense elke maand gebruik, en met hulle kragtige API word dit ook deur baie gewilde media sentrums soos Kodi gebruik om Fliek Metadata, Plakkate en Ondersteunerkuns te onttrek om die gebruiker se ondervinding te verryk.</description> + <description lang="be">themoviedb.org is a free and open movie database. It's completely user driven by people like you. TMDb is currently used by millions of people every month and with their powerful API, it is also used by many popular media centers like Kodi to retrieve Movie Metadata, Posters and Fanart to enrich the user's experience.</description> + <description lang="bg">themoviedb.org е безплатна и отворена филмова база данни. Задвижва се изцяло от потребителите си, от хора като вас. Милиони хора по света всеки месец ползват TMDb. Благодарение на многофункционално API може да се ползва от най-различни и популярни медийни центрове като Kodi, които извличат метаданни, постери и фанарт за филмите с цел за красивото оформяне на интерфейса.</description> + <description lang="ca">themoviedb.org és una base de dades oberta i lliure. Es manté completament per usuaris, per gent com tu. TMDb s'utilitza actualment per milions de persones cada mes i amb la seva potent API també és utilitzada per molts centre media populas com l'Kodi per obtenir les meta-dades de pel·lícules, pósters i fanart per enriquir l'experiència d'usuari.</description> + <description lang="cs">themoviedb.org je otevřená a svobodná databáze filmů. Je řízena uživateli, tedy lidmi jako vy. TMDB je každý měsíc používána milióny lidí a se svým výborným API je také používano mnoha populárními mediálními centry jako je Kodi, k získávání metadat, plagátů a fanartu filmů pro obohacení uživatelského zážitku.</description> + <description lang="cy">Mae themoviedb.org yn gronfa ddata ffilmiau rhydd ac agored. Mae'n cael ei yrru gan ddefnyddwyr fel chi. Mae TMDb yn cael ei ddefnyddio gan filiynau o bobl bob mis a gyda'i API pwerus, mae'n cael ei ddefnyddio gan lawer o'r canolfannau cyfrwng fel Kodi i estyn metadata ffilmiau, posteri a chelf er mwyn cyfoethogi profiad defnyddwyr.</description> + <description lang="da">themoviedb.org er en fri og åben filmdatabase. Den er helt og aldeles brugerdrevet af folk som dig. TMDb bruges i dag af millioner af mennesker hver måned, og med deres kraftfulde API er den også brugt af mange populære mediecentre såsom Kodi til at hente metadata, plakater og fankunst til film, for at berige brugerens oplevelse.</description> + <description lang="de">TheMovieDB.org ist eine freie und offene Filmdatenbank. Sie wird von Benutzern wie dir angetrieben. TheMovieDB wird zur Zeit von millionen Nutzern jeden Monat genutzt und dank ihrer mächtigen API ist sie auch von vielen Media-Center, wie z.B. Kodi, implementiert, um Film-Metadaten, -Poster und -Fanarts zu beziehen, die das Benutzererlebnis verbessern.</description> + <description lang="el">Το themoviedb.org είναι μία δωρεάν και ανοικτή βάση δεδομένων ταινιών. Διαχειρίζεται πλήρως από ανθρώπους σαν και εσάς. Το TMDb χρησιμοποιείται από εκατομμύρια ανθρώπους κάθε μήνα, και με το πανίσχυρο API τους, χρησιμοποιείται και από πολλά δημοφιλή κέντρα πολυμέσων όπως το Kodi για να λαμβάνουν μετα-δεδομένα Ταινιών, Αφίσες και Fanart για εμπλουτισμό της εμπειρίας του χρήστη.</description> + <description lang="en">themoviedb.org is a free and open movie database. It's completely user driven by people like you. TMDb is currently used by millions of people every month and with their powerful API, it is also used by many popular media centers like Kodi to retrieve Movie Metadata, Posters and Fanart to enrich the user's experience.</description> + <description lang="en_NZ">themoviedb.org is a free and open movie database. It's completely user driven by people like you. TMDb is currently used by millions of people every month and with their powerful API, it is also used by many popular media centers like Kodi to retrieve Movie Metadata, Posters and Fanart to enrich the user's experience.</description> + <description lang="en_US">themoviedb.org is a free and open movie database. It's completely user driven by people like you. TMDb is currently used by millions of people every month and with their powerful API, it is also used by many popular media centers like Kodi to retrieve Movie Metadata, Posters and Fanart to enrich the user's experience.</description> + <description lang="es">themovieDB.org es una base de datos de películas gratuita y abierta. Es una página web que se basa en contenido subido por los usuarios. TMDb es usada diariamente por mucha gente gracias a su API, que es usada por más programas aparte de Kodi para descargar información de películas así como Posters o Fanart (Fondos de escritorio basados en películas usados en distintos skins) para enriquecer la experiencia de usar Kodi.</description> + <description lang="es_AR">themovieDB.org es una base de datos de películas gratuita y abierta. Está formada con contenido subido por usuarios como vos. TMDb es actualmente utilizada por millones de personas cada mes y, gracias a su poderosa API, es usada por muchos programas populares como Kodi para descargar Información de Películas, Posters y Fanart para enriquecer la experiencia de usar Kodi.</description> + <description lang="es_MX">themoviedb.org es una base de datos de películas gratis y abierta. Es completamente manejada por usuarios y personas como tu. Actualmente TMDb es usada por millones de personas cada mes, y dado a su poderosa API, es usada también por varios media centers populares como Kodi para obtener Metada de Películas, Posters y Fanarts, enriqueciendo de esta manera la experiencia del usuario.</description> + <description lang="et">themoviedb.org on tasuta ja vaba juurdepääsuga filmide andmebaas.See on täielikult koostatud sinu sarnaste inimeste poolt. TMDb on hetkel igapäevaselt kasutuses miljonite inimeste poolt ja seda kasutavad paljud populaarsed meediakeskused, nagu ka Kodi, filmiandmete, fännikunsti ja posterite leidmiseks.</description> + <description lang="fi">themoviedb.org on vapaa ja avoin elokuvatietokanta. Se on täysin käyttäjien ylläpitämä. TMDb:a käyttää miljoonat ihmiset joka kuukausi, sitä käytetään käyttäjäkokemuksen rikastuttamiseen monissa muissakin suosituissa Kodi:n kaltaisissa ohjelmissa lataamalla elokuvien tietoja, julisteita ja fanitaidetta.</description> + <description lang="fr">themoviedb.org est une base de données gratuite et libre d'accès de films. Elle est totalement gérée par les utilisateurs. TMDb est actuellement utilisée par des millions de personnes chaque mois et, grâce à ses puissantes fonctions et routines, elle est également utilisée par de nombreux Media Centers populaires comme Kodi aux fins de récupération des Métadonnées, Posters et Fanarts des films en vue d'améliorer l'expérience de l'utilisateur.</description> + <description lang="fr_CA">themoviedb.org est une base de données libre et ouverte. Elle est complètement gérée par des gens comme vous. TMDb est actuellement utilisée par des millions de personnes chaque mois et avec son API puissante, elle est également utilisée par de nombreux centres multimédias populaires comme Kodi pour récupérer les métadonnées des films, les affiches et le fanart afin d'enrichir l'expérience de l'utilisateur.</description> + <description lang="gl">themoviedb.org é una base de datos sobre filmes libre e aberta, impulsada por xente coma ti. Na actualidade TMDb é usada por millóns de persoas todos os meses, e grazas ó seu potente API, usado por algúns dos centros multimedia máis populares como Kodi para obter a información dos filmes, Posters e Fanart e así mellorar a experiencia do usuario.</description> + <description lang="he">themoviedb.org is a free and open movie database. It's completely user driven by people like you. TMDb is currently used by millions of people every month and with their powerful API, it is also used by many popular media centers like Kodi to retrieve Movie Metadata, Posters and Fanart to enrich the user's experience.</description> + <description lang="hr">themoviedb.org je besplatna i otvorena baza filmskih podataka. TMDb trenutno koriste milijuni ljudi svaki mjesec uz pomoću njegovog snažnog API-ja, isto tako se koristi u mnogim popularnim medijskim centrima poput Kodija, kako bi mogli sakupljati informacije o filmovima, filmske postere, omote filmova i na kraju obogatili korisničko iskustvo.</description> + <description lang="hu">A themoviedb.org egy ingyenes és nyílt filmadatbázis. Teljes egészében olyan felhasználók töltik fel, mint például Te. A TMDb-t havonta emberek milliói használják és a hatékony API-n keresztül számos népszerű média center is, mint például az Kodi a filmadatok, poszterek, fanartképek letöltésére.</description> + <description lang="id">themoviedb.org adalah database film yang gratis dan terbuka. Ini benar-benar digerakkan oleh orang-orang seperti Anda. TMDb saat ini digunakan oleh jutaan orang setiap bulannya dan dengan APInya yang digdaya, juga digunakan oleh beberapa pusat media seperti Kodi untuk mengambil Metadata Film, Poster dan Fanart untuk menperkaya pengalaman penggunanya.</description> + <description lang="is">themoviedb.org er frír og opinn gagnagrunnur. Hann er algjörlega rekinn af fólki eins og þér. TMBd er notaður af milljónum manna í hverjum mánuði og með öflugum forritaskilum þeirra (API), er hann líka notaður af mörgum vinsælum heimabíókerfum eins og Kodi til að ná í Ítarupplýsingar yfir Kvikmyndir, Veggspjöld og Fanart til að lífga upplifun notandans.</description> + <description lang="it">themoviedb.org è un database libero e aperto. E' gestito da utenti e persone come te. Viene usato correntemente da millioni di persone ogni mese e con le sue potenti API, è anche utilizzato da molti popolari media centers come Kodi per ottenere Metadati, Posters e Fanart di film per arricchire la loro esperienza utente.</description> + <description lang="ja">themoviedb.org は自由でオープンな映画データベースです。その運営は、完全にユーザ主導で行われています。TMDb は現在毎月何百万人もの人に利用されているほか、Kodi のようなメディアセンターも、TMDb のパワフルな API を介して映画メタデータ、ポスター、ファンアートを取得し、使い勝手を向上させるなどして使っています。</description> + <description lang="ko">themoviedb.org 는 전적으로 여러분 같은 이용자가 주도하는 무료 공개 영화 데이터베이스입니다. TMDb 는 현재 매월 수백만의 사람들이 강력한 API와 함께 사용하고 있을 뿐만 아니라 Kodi 같은 많은 미디어 센터가 영화 정보, 포스터, 팬아트를 가져와 풍성한 사용자 경험을 제공하는데 이용되고 있습니다.</description> + <description lang="lt">themoviedb.org yra nemokama ir atvira Filmų duomenų bazė. Jis remiamas ir skaitinamas tokių pat vartotojų kaip ir jūs. TMDb šiuo metu naudoja milijonai žmonių kiekvieną mėnesį, ir turi galingą API (informacinį centrą), taip pat naudojamas daug populiarių žiniasklaidos centrų. Pavyzdžiui Kodi gauti filmo(-ų) metaduomenis, plakatus ir FanArt siekiant praturtinti vartotojo patirtį.</description> + <description lang="mk">themoviedb.org is a free and open movie database. It's completely user driven by people like you. TMDb is currently used by millions of people every month and with their powerful API, it is also used by many popular media centers like Kodi to retrieve Movie Metadata, Posters and Fanart to enrich the user's experience.</description> + <description lang="ml">മൂവി ഡി ബി, എല്ലാവർക്കും കൈവക്കാവുന്ന ഒരു സൗജന്യ വിവരശേഖരമാണ്. ഇതുമൂലം ലോകം മുഴുവനും സിനിമാ പോസ്റ്ററുകൾ എല്ലവരും കാണുന്നു</description> + <description lang="ms">themoviedb.org adalah pangkalan data cakera terbuka. Ia sepenuhnya dipacu oleh individu seperti anda. TMDb buat masa ini diguna oleh berjuta-juta individu setiap bulan dan dengan API hebat mereka, ia juga digunakan oleh banyak pusat media popular seperti Kodi untuk mendapatkan Data Meta, Poster, Seni Peminat Cereka untuk memperkayakan pengalaman pengguna.</description> + <description lang="nl">Themoviedb.org is een vrije en open filmdatabank. Gebruikers zoals jij vormen de motor van deze site. Op dit moment gebruiken elke maand miljoenen mensen TMDb. De krachtige API van de site laat mediacenters zoals Kodi toe om metadata, posters en fanart op te halen en zo de gebruikerservaring te verrijken.</description> + <description lang="no">themoviedb.org er en gratis og åpen filmdatabase. Den drives helt og fullt av mennesker som deg. TMDb brukes av millioner av mennesker hver måned og med sitt gode API, brukes den også av mange popluære mediasenterløsninger som Kodi for å hente metadata for filmer, plakater og fanart for å gi en bedre brukeropplevelse.</description> + <description lang="pl">themoviedb.org jest wolną i otwartą filmową bazą danych, zarządzaną przez osoby takie jak Ty. Obecnie odwiedzają ją miliony osób miesięcznie, a dzięki dostępności interfejsu programistycznego jest używana przez wiele centrów multimedialnych takich jak Kodi, jako źródło informacji o filmach, plakatów i tapet.</description> + <description lang="pt">O themoviedb.org é uma base de dados de filmes livre e aberta. É actualizado inteiramente por pessoas como você e usado por milhões todos os meses. Com o poderoso motor de busca disponível, também se tornou no favorito para muitos programas de centro de média, como o popular Kodi, para obter informação, posters e fanart que enriquecem a experiência do utilizador.</description> + <description lang="pt_BR">O themoviedb.org é um banco de dados aberto e gratuito. É completamente operado por pessoas como você. O TMDb é atualmente usado por milhares de pessoas a cada mês e com sua poderosa API, é usado por muitas centrais de mídia populares como o Kodi para buscar metadados, cartazes e fanart de filmes para enriquecer a experiência do usuário.</description> + <description lang="ro">themoviedb.org este o bază de date de filme gratuită și deschisă. Este actualizată de oameni ca și tine. TMDb este curent folosită de milioane de oameni în fiecare lună și datorită API-ului puternic, este de asemena folosită de multe centre media populare ca Kodi pentru a obține informații despre filme, afișe și imagini produse de fani (Fanart) care îmbogățesc experiența utilizatorului.</description> + <description lang="ru">themoviedb.org — это бесплатная и открытая база данных фильмов. Она полностью поддерживается обычными людьми. В данный момент сайт TMDb используют миллионы людей каждый месяц, и благодаря мощному API его могут использовать различные популярные медиацентры, такие как Kodi, чтобы получать метаданные, постеры и фанарт для фильмов с целью красивого оформления интерфейса.</description> + <description lang="se">themoviedb.org är en fri och öppen filmdatabas. Det drivs helt av människor som dig. TMDb används av miljontals människor varje månad och med deras kraftfulla API, är det också använt av många populära mediacenter som Kodi för att hämta filmmetadata, omslag och fanart för att förgylla användarens upplevelse.</description> + <description lang="sk">themoviedb.org je voľná a otvorená databáza filmov. Je výlučne vedená užívateľmi ako si ty. TMDb je každý mesiac používaná miliónmi ľudí, a vďaka svojmu výkonnému API je veľmi populárna medzi 'media centrami' ako Kodi pre sťahovanie filmových metadát, plagátov a fanartov pre obohatenie zážitkov.</description> + <description lang="sl">themoviedb.org je brezplačna in prosta baza filmov. Je v celoti ustvarjena s strani uporabnikov kot ste vi. TMDB uporablja miljone ljudi in z njihovo močno API, jo lahko uporabljate tudi v multimedijskih centrih kot Kodi, s tem prenesete informacije o filmih, plakate in ozadja ter s tem popestrite uporabniško izkušnjo.</description> + <description lang="sv">themoviedb.org är en gratis och öppen filmdatabas. Den drivs helt av människor som du. TMDb används för närvarande av miljoner människor varje månad och med deras kraftfulla API används den även av många populära mediacenter som t.ex. Kodi för att hämta metadata om filmer, affischer och fanart för att berika användarens upplevelse.</description> + <description lang="ta_IN">themoviedb.org ஒரு இலவச மற்றும் திறந்த திரைப்பட தரவுத்தளம் ஆகும். இந்த தரவுத்தளம் முற்றிலும் பயனர் மக்களால் இயக்கப்படுகிறது. TMDb அவர்களது சக்திவாய்ந்த API இனால் தற்போது பல இலட்சக்கணக்கான மக்களால் ஒவ்வொரு மாதமும் பயன்படுத்தப்படுகிறது, இது Kodi போன்ற பல பிரபல ஊடக மையங்களில் பயனர் அனுபவத்தை மேம்படுத்த பயன்படுத்தப்படுகிறது.</description> + <description lang="th">themoviedb.org เป็นฐานข้อมูลภาพยนตร์ที่ฟรีและเปิดกว้าง. มันถูกขับเคลื่อนจากผู้ใช้ โดยคนเช่นคุณ. TMDb ปัจจุบันมีการใช้โดยคนนับล้านในแต่ละเดือน และมีประสิทธิภาพด้วย API ของพวกเขา , มันยังถูกใช้โดยหลายศูนย์สื่อที่นิยมเช่น Kodi เพื่อดึง อธิบายข้อมูลภาพยนตร์, โปสเตอร์และ แฟนอาร์ต เพื่อเพิ่มประสบการณ์ของผู้ใช้</description> + <description lang="tr">themoviedb.org ücretsiz ve herkese açık bir film veri tabanıdır. Tamamen kullanıcılar tarafından oluşturulmakta ve yönetilmektedir. TMDb her ay milyonlarca kullanıcı tarafından kullanılmakta ve güçlü API'si sayesinde Kodi gibi bir çok popüler medya merkezi tarafından Film Veritabanı, Poster ve Fanart bilgilerini kullanarak kullanıcı deneyimini zenginleştirmektedir.</description> + <description lang="uk">themoviedb.org - це безкоштовна і відкрита база даних фільмів. Вона повністю підтримується звичайними людьми. В даний момент сайт TMDb використовують мільйони людей кожен місяць, і завдяки потужному API, його можуть використовувати різні популярні медіацентри, такі як Kodi, щоб отримувати метадані, постери і фанарт для фільмів з метою оформлення інтерфейсу.</description> + <description lang="vi">themoviedb.org là cơ sở dữ liệu về phim ảnh mở và miễn phí. Nó hoàn toàn được kiểm soát bởi những người như bạn. TMDb hiện tại đang được sử dụng bởi hàng triệu người dùng hàng tháng và với sự hỗ trợ của bộ API mạnh mẽ nó cũng được sử dụng bởi những thiết bị giải trí cá nhân như Kodi cho việc lấy dữ liệu về Phim ảnh, Poster và Fanart để làm tăng trải nghiệm của người sử dụng</description> + <description lang="zh">themoviedb.org 是一个开放和自由的电影数据库。它完全由象你一样的用户来掌控。TMDb 每月为上百万用户提供服务,并通过强大的 API 界面为许多流行的媒体中心系统如 Kodi 提供电影资料、封面海报和同人画以丰富用户的体验。</description> + <description lang="zh_TW">themoviedb.org是一個免費和開放的電影資料庫。它是完全由與您一樣的廣大使用者來更新資訊。 TMDb目前擁有數以百萬計的使用人次並且有著強大的API,許多受歡迎的媒體中心平台像Kodi藉由TMDb獲取電影的數據資料庫,海報和影片資訊,以豐富使用者體驗。</description> + <platform>all</platform> + <license>GPL v2.0</license> + <forum>http://forum.xbmc.org/showthread.php?tid=200504</forum> + <website></website> + <email></email> + <source></source> + </extension> +</addon> diff --git a/addons/metadata.tvshows.themoviedb.org/changelog.txt b/addons/metadata.tvshows.themoviedb.org/changelog.txt new file mode 100644 index 0000000000..a84213c25c --- /dev/null +++ b/addons/metadata.tvshows.themoviedb.org/changelog.txt @@ -0,0 +1,74 @@ +[B]3.0.6[/B] +- Fixed: show overview + +[B]3.0.5[/B] +- Fixed scraping after API layout changes + +[B]3.0.4[/B] +- use https to access thetvdb.com + +[B]3.0.3[/B] +- fixed: scraping episodes with no air date + +[B]3.0.1[/B] +- fixed: typo causing season swapped with episode numbers (thanks tdf1970) + +[B]3.0.0[/B] +- added: extra artwork (clearlogo, clearart, landscape, etc.) from fanart.tv; bumped version for Leia + +[B]2.0.1[/B] +- changed: tmdb rating name + +[B]2.0.0[/B] +- added: some missing languages +- changed: bump version for Kodi v17 + +[B]1.4.0[/B] +added: uniqueids and ratings with their name (requires Kodi v17 or newer) -thanks phate89 + +[B]1.3.4[/B] +- Really fixed after API layout changes + +[B]1.3.3[/B] +- Fixed after API layout changes + +[B]1.3.2[/B] +- fixed: broken search results after API changes + +[B]1.3.1[/B] +- added: scraping of mpaa certifications + +[B]1.3.0[/B] +- Update + +[B]1.2.2[/B] +- Update author name + +[B]1.2.1[/B] +- fixed: broken search results after API changes + +[B]1.2.0[/B] +- added: scraping of ratings and votes + +[B]1.1.2[/B] +- fixed: broken search and art scraping + +[B]1.1.1[/B] +- fixed: scraping of episode names in certain languages + +[B]1.1.0[/B] +- added extra languages for selection +- changed language to a selection list + +[B]1.0.3[/B] +- updated language files from Transifex + +[B]1.0.2[/B] +- fixed: broken scraping + +[B]1.0.1[/B] +- updated language files from Transifex + +[B]1.0.0[/B] + +- Initial version diff --git a/addons/metadata.tvshows.themoviedb.org/icon.png b/addons/metadata.tvshows.themoviedb.org/icon.png Binary files differnew file mode 100644 index 0000000000..01337685ea --- /dev/null +++ b/addons/metadata.tvshows.themoviedb.org/icon.png diff --git a/addons/metadata.tvdb.com/resources/language/Afrikaans/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Afrikaans/strings.po index e2aae38344..c482a49c18 100644 --- a/addons/metadata.tvdb.com/resources/language/Afrikaans/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Afrikaans/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Gebruik DVD Orde" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Gebruik Absolute Ordening (Enkele Seisoen)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Stel Ondersteunerkuns in staat" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Verkies Plakkate" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Verkose Taal" -msgctxt "#30004" -msgid "Language" -msgstr "Taal" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Hou Oorspronklike Titel" diff --git a/addons/metadata.tvdb.com/resources/language/Esperanto/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Albanian/strings.po index 55fd377fce..b4101ef4b3 100644 --- a/addons/metadata.tvdb.com/resources/language/Esperanto/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Albanian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -9,13 +9,13 @@ msgstr "" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Kodi Translation Team\n" -"Language-Team: Esperanto (http://www.transifex.com/projects/p/xbmc-addons/language/eo/)\n" +"Language-Team: Albanian (http://www.transifex.com/projects/p/xbmc-addons/language/sq/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: eo\n" +"Language: sq\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -msgctxt "#30004" -msgid "Language" -msgstr "Lingvo" +msgctxt "#30000" +msgid "Enable Fanart" +msgstr "Aktivo \"Fanart'in\"" diff --git a/addons/metadata.tvdb.com/resources/language/Amharic/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Amharic/strings.po index e537a52246..5e8a316363 100644 --- a/addons/metadata.tvdb.com/resources/language/Amharic/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Amharic/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -16,6 +16,10 @@ msgstr "" "Language: am\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -msgctxt "#30004" -msgid "Language" -msgstr "ቋንቋ " +msgctxt "#30002" +msgid "Preferred Language" +msgstr "የተመረጠው ቋንቋ" + +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "ዋናውን አርእስት ጠብቅ " diff --git a/addons/metadata.tvdb.com/resources/language/Basque/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Basque/strings.po index 5b804c1cec..f2db18b5a2 100644 --- a/addons/metadata.tvdb.com/resources/language/Basque/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Basque/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -16,10 +16,6 @@ msgstr "" "Language: eu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -msgctxt "#30002" +msgctxt "#30000" msgid "Enable Fanart" msgstr "Gaitu Fanarta" - -msgctxt "#30004" -msgid "Language" -msgstr "Hizkuntza" diff --git a/addons/metadata.tvdb.com/resources/language/Belarusian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Belarusian/strings.po index 3112de70fd..7416d7870a 100644 --- a/addons/metadata.tvdb.com/resources/language/Belarusian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Belarusian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Use DVD Order" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Use Absolute Ordering (Single Season)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Enable Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Prefer Posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Пераважная мова" -msgctxt "#30004" -msgid "Language" -msgstr "Language" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Keep Original Title" diff --git a/addons/metadata.tvdb.com/resources/language/Bulgarian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Bulgarian/strings.po index 25402a3a72..6dffb49935 100644 --- a/addons/metadata.tvdb.com/resources/language/Bulgarian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Bulgarian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Ползвай последователността от DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Ползвай последователно номериране (един сезон)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Ползвай фанарт" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Предпочитай постерите" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Предпочитан език" -msgctxt "#30004" -msgid "Language" -msgstr "Език" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Запазвай оригиналното заглавие" diff --git a/addons/metadata.tvdb.com/resources/language/Burmese/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Burmese/strings.po index 6a07ea4d96..dcd1ad4acb 100644 --- a/addons/metadata.tvdb.com/resources/language/Burmese/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Burmese/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "DVD order ကို အသုံးပြုရန်" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Absolute Order ကို အသုံးပြုရန်" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Fanart ကို လုပ်ဆောင်ခွင့်" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "ပိုစတာ ပုံစံကို သဘောကျသည်" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "သင့်လျှော်သော ဘာသာစကား" -msgctxt "#30004" -msgid "Language" -msgstr "ဘာသာစကား" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "မူလခေါင်းစဉ်အတိုင်းထားမည်" diff --git a/addons/metadata.tvdb.com/resources/language/Catalan/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Catalan/strings.po index 37f8afc286..db397cf8d9 100644 --- a/addons/metadata.tvdb.com/resources/language/Catalan/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Catalan/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Utilitza l'ordre del DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Utilitza l'ordenament absolut (Temporada única)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Habilita el fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Dona preferència als pòsters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Idioma perferit" -msgctxt "#30004" -msgid "Language" -msgstr "Idioma" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Manté el títol original" diff --git a/addons/metadata.tvdb.com/resources/language/Chinese (Simple)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Chinese (Simple)/strings.po index fc6790f5ce..a5f46129a0 100644 --- a/addons/metadata.tvdb.com/resources/language/Chinese (Simple)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Chinese (Simple)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "使用 DVD 顺序" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "使用绝对顺序(单季)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "启用同人画" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "使用封面海报" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "首选语言" -msgctxt "#30004" -msgid "Language" -msgstr "语言" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "使用未翻译片名" diff --git a/addons/metadata.tvdb.com/resources/language/Chinese (Traditional)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Chinese (Traditional)/strings.po index 4dd4f263bf..227b9bca64 100644 --- a/addons/metadata.tvdb.com/resources/language/Chinese (Traditional)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Chinese (Traditional)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "使用 DVD 順序" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "使用原本的順序 (單季)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "啟用專輯資訊" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "下載海報" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "偏好的語言" -msgctxt "#30004" -msgid "Language" -msgstr "語言" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "保留原始標題" diff --git a/addons/metadata.tvdb.com/resources/language/Croatian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Croatian/strings.po index d11c05fab7..56487f8adb 100644 --- a/addons/metadata.tvdb.com/resources/language/Croatian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Croatian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "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" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Koristi DVD poredak" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Koristi potpuni poredak (Jedna sezona)" - -msgctxt "#30002" msgid "Enable Fanart" -msgstr "Omogući omote emisija" +msgstr "Omogući omote" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferiraj plakate" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Željeni jezik" -msgctxt "#30004" -msgid "Language" -msgstr "Jezik" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Zadrži izvorni naslov" diff --git a/addons/metadata.tvdb.com/resources/language/Czech/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Czech/strings.po index 2da15df2d4..8a03182452 100644 --- a/addons/metadata.tvdb.com/resources/language/Czech/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Czech/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Použít řazení jako na DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Použít absolutní řazení (pro jednu sérii)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Povolit Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Upřednostňovat plagáty" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Upřednostňovaný jazyk" -msgctxt "#30004" -msgid "Language" -msgstr "Jazyk" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Ponechat původní název" diff --git a/addons/metadata.tvdb.com/resources/language/Danish/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Danish/strings.po index 62061ad17e..f4d34aec61 100644 --- a/addons/metadata.tvdb.com/resources/language/Danish/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Danish/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Brug DVD rækkefølge" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Brug absolut rækkefølge (enkelt sæson)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Aktiver Fankunst" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Foretræk Plakater" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Foretrukket Sprog" -msgctxt "#30004" -msgid "Language" -msgstr "Sprog" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Behold original titel" diff --git a/addons/metadata.tvdb.com/resources/language/Dutch/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Dutch/strings.po index 26edbc0152..70d4afb2ac 100644 --- a/addons/metadata.tvdb.com/resources/language/Dutch/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Dutch/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "DVD-volgorde gebruiken" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Absolute volgorde gebruiken (Eén seizoen)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Fanart inschakelen" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Posters inschakelen" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Voorkeurstaal" -msgctxt "#30004" -msgid "Language" -msgstr "Taal" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Behoud originele titel" diff --git a/addons/metadata.tvdb.com/resources/language/English (New Zealand)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/English (New Zealand)/strings.po index 8cadb13662..462a259dbb 100644 --- a/addons/metadata.tvdb.com/resources/language/English (New Zealand)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/English (New Zealand)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Use DVD Order" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Use Absolute Ordering (Single Season)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Enable Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Prefer Posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Preferred Language" -msgctxt "#30004" -msgid "Language" -msgstr "Language" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Keep Original Title" diff --git a/addons/metadata.tvdb.com/resources/language/English (US)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/English (US)/strings.po index ac16d0b1c8..ed9b5db15a 100644 --- a/addons/metadata.tvdb.com/resources/language/English (US)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/English (US)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Use DVD Order" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Use Absolute Ordering (Single Season)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Enable Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Prefer Posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Preferred Language" -msgctxt "#30004" -msgid "Language" -msgstr "Language" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Keep Original Title" diff --git a/addons/metadata.tvdb.com/resources/language/English/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/English/strings.po index 705e48df98..0b985f3971 100644 --- a/addons/metadata.tvdb.com/resources/language/English/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/English/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,41 +17,25 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" +msgid "Enable Fanart" msgstr "" -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "" +#empty string with id 30001 msgctxt "#30002" -msgid "Enable Fanart" +msgid "Preferred Language" msgstr "" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "" - -msgctxt "#30004" -msgid "Language" -msgstr "" +#empty strings from id 30003 to 30004 msgctxt "#30005" -msgid "Get Default Rating from" +msgid "Keep Original Title" msgstr "" msgctxt "#30006" -msgid "Also get ratings from TheTVDB" +msgid "Get Artwork from themoviedb.org" msgstr "" msgctxt "#30007" -msgid "Use a fallback language for search and details" -msgstr "" - -msgctxt "#30008" -msgid "Fallback language" -msgstr "" - -msgctxt "#30009" -msgid "Also get ratings from IMDb" -msgstr "" +msgid "Get Extra Artwork from fanart.tv" +msgstr ""
\ No newline at end of file diff --git a/addons/metadata.tvdb.com/resources/language/Estonian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Estonian/strings.po index 123cb304fb..58e33bba98 100644 --- a/addons/metadata.tvdb.com/resources/language/Estonian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Estonian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Kasuta DVD järjestust" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Kasuta absoluutset järjestust (Üks hooaeg)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Võimalda fännikunst" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Eelista postreid" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Eelistatud keel" -msgctxt "#30004" -msgid "Language" -msgstr "Keel" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Säilita originaalne pealkiri" diff --git a/addons/metadata.tvdb.com/resources/language/Armenian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Finnish/strings.po index a0f672044e..93a3755487 100644 --- a/addons/metadata.tvdb.com/resources/language/Armenian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Finnish/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -9,13 +9,13 @@ msgstr "" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Kodi Translation Team\n" -"Language-Team: Armenian (http://www.transifex.com/projects/p/xbmc-addons/language/hy/)\n" +"Language-Team: Finnish (http://www.transifex.com/projects/p/xbmc-addons/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: hy\n" +"Language: fi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -msgctxt "#30004" -msgid "Language" -msgstr "Լեզու" +msgctxt "#30000" +msgid "Enable Fanart" +msgstr "Fanitaide käytössä" diff --git a/addons/metadata.tvdb.com/resources/language/French (Canada)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/French (Canada)/strings.po index 9f5f30321a..7d58cf42a7 100644 --- a/addons/metadata.tvdb.com/resources/language/French (Canada)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/French (Canada)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Utiliser l'ordre du DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Utiliser l'ordre absolue (une seule saison)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Activer le fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Affiches préférées" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Langue préférée" -msgctxt "#30004" -msgid "Language" -msgstr "Langue" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Conserver le titre original" diff --git a/addons/metadata.tvdb.com/resources/language/French/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/French/strings.po index 5435726db4..376e8f4cdb 100644 --- a/addons/metadata.tvdb.com/resources/language/French/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/French/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Utiliser l'ordre des DVDs" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Utiliser l'ordre absolu (Saison seule)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Activer les Fanarts" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Préférer les vignettes" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Langue préférée" -msgctxt "#30004" -msgid "Language" -msgstr "Langue" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Garder le titre original" diff --git a/addons/metadata.tvdb.com/resources/language/Galician/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Galician/strings.po index f54db7bea6..29d1738a6d 100644 --- a/addons/metadata.tvdb.com/resources/language/Galician/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Galician/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Empregar Orde do DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Usar Orde Absoluto (Só unha tempada)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Activar Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferir Pósters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Idioma Preferido" -msgctxt "#30004" -msgid "Language" -msgstr "Idioma" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Manter o Título Orixinal" diff --git a/addons/metadata.tvdb.com/resources/language/German/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/German/strings.po index 393a343d00..53e5d3a133 100644 --- a/addons/metadata.tvdb.com/resources/language/German/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/German/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Verwende DVD-Sortierung" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Verwende absolute Sortierung (einzelne Staffel)" - -msgctxt "#30002" msgid "Enable Fanart" -msgstr "Aktiviere Fanart" +msgstr "Fanart aktivieren" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Bevorzuge Poster" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Bevorzugte Sprache" -msgctxt "#30004" -msgid "Language" -msgstr "Sprache" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Verwende Original-Titel" diff --git a/addons/metadata.tvdb.com/resources/language/Greek/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Greek/strings.po index 7fe978b1db..a977b42312 100644 --- a/addons/metadata.tvdb.com/resources/language/Greek/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Greek/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Χρήση Αρίθμησης DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Χρήση Απόλυτης Αρίθμησης (Ένας Κύκλος)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Ενεργοποίηση Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Προτίμηση Αφισών" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Προτιμώμενη Γλώσσα" -msgctxt "#30004" -msgid "Language" -msgstr "Γλώσσα" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Διατήρηση Πρωτότυπου Τίτλου" diff --git a/addons/metadata.tvdb.com/resources/language/Hebrew/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Hebrew/strings.po index 4caa41576d..41c0ddc718 100644 --- a/addons/metadata.tvdb.com/resources/language/Hebrew/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Hebrew/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "השתמש בסדר קבצי DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "השתמש בסידור מוחלט (עונה יחידה)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "אפשר פאנארט" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "העדף פוסטרים" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "שפה מועדפת" -msgctxt "#30004" -msgid "Language" -msgstr "שפה" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "שמור על כותרת מקורית" diff --git a/addons/metadata.tvdb.com/resources/language/English (Australia)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Hindi (Devanagiri)/strings.po index 8b3aee351e..de0ad213b6 100644 --- a/addons/metadata.tvdb.com/resources/language/English (Australia)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Hindi (Devanagiri)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -9,13 +9,13 @@ msgstr "" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Kodi Translation Team\n" -"Language-Team: English (Australia) (http://www.transifex.com/projects/p/xbmc-addons/language/en_AU/)\n" +"Language-Team: Hindi (Devanagiri) (http://www.transifex.com/projects/p/xbmc-addons/language/hi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: en_AU\n" +"Language: hi\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -msgctxt "#30004" -msgid "Language" -msgstr "Language" +msgctxt "#30000" +msgid "Enable Fanart" +msgstr "फ़ानर्ट को एनेबल करे" diff --git a/addons/metadata.tvdb.com/resources/language/Hungarian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Hungarian/strings.po index 772d73c433..111da0a720 100644 --- a/addons/metadata.tvdb.com/resources/language/Hungarian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Hungarian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "DVD sorrend használata" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Abszolút sorrend használata (Egy évad esetén)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Fanartképek engedélyezése" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Poszterek előnyben részesítése" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Preferált nyelv" -msgctxt "#30004" -msgid "Language" -msgstr "Nyelv" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Eredeti filmcím megtartása" diff --git a/addons/metadata.tvdb.com/resources/language/Icelandic/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Icelandic/strings.po index bdaf81b37a..eecbb167bb 100644 --- a/addons/metadata.tvdb.com/resources/language/Icelandic/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Icelandic/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Nota DVD Uppröðun" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Nota ’Absolute Ordering' (Ein þáttaröð)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Virkja Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Nota Heldur Veggspjöld" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Æskilegt tungumál" -msgctxt "#30004" -msgid "Language" -msgstr "Tungumál" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Halda Upphaflegum Titli" diff --git a/addons/metadata.tvdb.com/resources/language/Indonesian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Indonesian/strings.po index b102f1c7bb..266464654a 100644 --- a/addons/metadata.tvdb.com/resources/language/Indonesian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Indonesian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Gunakan urutan DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Gunakan urutan absolut (Satu Musim)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Aktifkan Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Utamakan Poster" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Bahasa yang terutama" -msgctxt "#30004" -msgid "Language" -msgstr "Bahasa" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Pertahankan Judul Aslinya" diff --git a/addons/metadata.tvdb.com/resources/language/Italian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Italian/strings.po index bd32900504..fc7eeb05b7 100644 --- a/addons/metadata.tvdb.com/resources/language/Italian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Italian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Usa ordine DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Usa ordine assoluto (stagione singola)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Abilita Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferisci Posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Linguaggio preferito" -msgctxt "#30004" -msgid "Language" -msgstr "Lingua" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Mantieni Titolo Originale" diff --git a/addons/metadata.tvdb.com/resources/language/Japanese/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Japanese/strings.po index 15b9a9a9b4..a249114089 100644 --- a/addons/metadata.tvdb.com/resources/language/Japanese/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Japanese/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "DVD オーダーを使用" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "完全オーダーを使用 (単一シーズン)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "ファンアートを有効に" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "ポスターを使用" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "優先する言語" -msgctxt "#30004" -msgid "Language" -msgstr "言語" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "オリジナルタイトルを保持" diff --git a/addons/metadata.tvdb.com/resources/language/Korean/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Korean/strings.po index 75a6be307f..615e6094e6 100644 --- a/addons/metadata.tvdb.com/resources/language/Korean/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Korean/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "DVD 순서 사용" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "절대 순서 사용 (하나의 시즌)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "팬아트 사용" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "포스터 우선" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "선호 언어" -msgctxt "#30004" -msgid "Language" -msgstr "언어" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "원 제목 유지" diff --git a/addons/metadata.tvdb.com/resources/language/Lithuanian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Lithuanian/strings.po index 6ced77497e..446e37f3ba 100644 --- a/addons/metadata.tvdb.com/resources/language/Lithuanian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Lithuanian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Naudoti DVD Order" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Naudoti 'Absoliutus Užsakymas' (vienas sezonas)" - -msgctxt "#30002" msgid "Enable Fanart" -msgstr "Įjungti Fanart" +msgstr "Įjungti FanArt" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Pageidaujamas(-mi) Posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Pageidaujama kalba" -msgctxt "#30004" -msgid "Language" -msgstr "Kalba" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Išlaikyti originalų pavadinimą" diff --git a/addons/metadata.tvdb.com/resources/language/Macedonian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Macedonian/strings.po index e0592b3b84..5dbed3a421 100644 --- a/addons/metadata.tvdb.com/resources/language/Macedonian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Macedonian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Користи DVD верзија" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Користи апсолути верзии (единечна сесија)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Овозможи сликички" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Преферирај постери" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Посакуван јазик" -msgctxt "#30004" -msgid "Language" -msgstr "Јазик" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Задржи оригинален назив" diff --git a/addons/metadata.tvdb.com/resources/language/Malay/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Malay/strings.po index 9420de1395..53852cbb1f 100644 --- a/addons/metadata.tvdb.com/resources/language/Malay/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Malay/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Guna Tertib DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Gunakan Penertiban Mutlak (Satu Musim)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Benarkan Seni Peminat" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Utamakan Poster" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Bahasa Digemari" -msgctxt "#30004" -msgid "Language" -msgstr "Bahasa" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Kekalkan Tajuk Asal" diff --git a/addons/metadata.tvdb.com/resources/language/Malayalam/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Malayalam/strings.po index 9847548fec..b4acba6473 100644 --- a/addons/metadata.tvdb.com/resources/language/Malayalam/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Malayalam/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -16,6 +16,10 @@ msgstr "" "Language: ml\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -msgctxt "#30004" -msgid "Language" -msgstr "ഭാഷ" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "ഇഷ്ടപ്പെട്ട ഭാഷ" + +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "യഥാർത്ത പേര് നിലനിർത്തുക" diff --git a/addons/metadata.tvdb.com/resources/language/Norwegian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Norwegian/strings.po index 1839f61d53..8f049833fb 100644 --- a/addons/metadata.tvdb.com/resources/language/Norwegian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Norwegian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Bruk DVD sortering" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Bruk Absolutt sortering (Enkel Sesong)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Hent fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Foretrekke Postere" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Foretrukket språk" -msgctxt "#30004" -msgid "Language" -msgstr "Språk" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Bruk originaltittel" diff --git a/addons/metadata.tvdb.com/resources/language/Polish/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Polish/strings.po index 70d31ab2fa..cdcc5019fe 100644 --- a/addons/metadata.tvdb.com/resources/language/Polish/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Polish/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Używaj porządku DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Używaj absolutnego porządku (jeden sezon)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Używaj tapet" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferuj plakaty" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Preferowany język" -msgctxt "#30004" -msgid "Language" -msgstr "Język" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Zachowuj tytuł oryginalny" diff --git a/addons/metadata.tvdb.com/resources/language/Portuguese (Brazil)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Portuguese (Brazil)/strings.po index f29daa6d4b..0cb4f5002b 100644 --- a/addons/metadata.tvdb.com/resources/language/Portuguese (Brazil)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Portuguese (Brazil)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Usar a ordem do DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Usar ordenamento absoluto (Temporada Única)" - -msgctxt "#30002" msgid "Enable Fanart" -msgstr "Habilitar Fanart" +msgstr "Ativar Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferir Cartazes" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Idioma preferido" -msgctxt "#30004" -msgid "Language" -msgstr "Idioma" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Manter o título original" diff --git a/addons/metadata.tvdb.com/resources/language/Portuguese/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Portuguese/strings.po index 189389c481..c5a6cd9192 100644 --- a/addons/metadata.tvdb.com/resources/language/Portuguese/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Portuguese/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Usar ordem do DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Usar Ordem Absoluta (Temporada única)" - -msgctxt "#30002" msgid "Enable Fanart" -msgstr "Activar Fanart" +msgstr "Ativar Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferir posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Idioma preferido" -msgctxt "#30004" -msgid "Language" -msgstr "Idioma" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Manter Título Original" diff --git a/addons/metadata.tvdb.com/resources/language/Romanian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Romanian/strings.po index 1eb874c15d..3e81c784b8 100644 --- a/addons/metadata.tvdb.com/resources/language/Romanian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Romanian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Ordonare dupa DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Ordonare absolută (Un singur sezon)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Activează Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferă postere" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Limbă preferată" -msgctxt "#30004" -msgid "Language" -msgstr "Limbă" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Păstrează titlul original" diff --git a/addons/metadata.tvdb.com/resources/language/Russian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Russian/strings.po index 2872a8c998..ae1d45989f 100644 --- a/addons/metadata.tvdb.com/resources/language/Russian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Russian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "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" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Использовать порядок DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Использовать сквозную нумерацию (один сезон)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Использовать фанарт" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Предпочитать постеры" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Предпочтительный язык" -msgctxt "#30004" -msgid "Language" -msgstr "Язык" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Использовать оригинальные названия" diff --git a/addons/metadata.tvdb.com/resources/language/Slovak/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Slovak/strings.po index e4a00d7de6..85bf607c98 100644 --- a/addons/metadata.tvdb.com/resources/language/Slovak/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Slovak/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Používať usporiadanie podľa DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Použiť úplné usporiadanie (pre jednu sériu)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Povoliť umeleckú grafiku" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Uprednostňovať plagáty" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Uprednostňovaný jazyk" -msgctxt "#30004" -msgid "Language" -msgstr "Jazyk" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Ponechať pôvodný názov" diff --git a/addons/metadata.tvdb.com/resources/language/Slovenian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Slovenian/strings.po index afa65c2f8c..7eefca628e 100644 --- a/addons/metadata.tvdb.com/resources/language/Slovenian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Slovenian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Uporabi zaporedje DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Uporabi absolutno zaporedje (ena sezona)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Vključi grafike" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Uporabi plakate" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Privzet jezik" -msgctxt "#30004" -msgid "Language" -msgstr "Jezik" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Ohrani naslov izvirnika" diff --git a/addons/metadata.tvdb.com/resources/language/Spanish (Argentina)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Spanish (Argentina)/strings.po index 848d371807..2dbca4c799 100644 --- a/addons/metadata.tvdb.com/resources/language/Spanish (Argentina)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Spanish (Argentina)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Usar Orden del DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Usar Orden Absoluto (Temporada Única)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Descargar Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferir Posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Idioma Preferido" -msgctxt "#30004" -msgid "Language" -msgstr "Idioma" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Mantener Título Original" diff --git a/addons/metadata.tvdb.com/resources/language/Spanish (Mexico)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Spanish (Mexico)/strings.po index 0ab869b3eb..50e233ec04 100644 --- a/addons/metadata.tvdb.com/resources/language/Spanish (Mexico)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Spanish (Mexico)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Usar Orden de DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Usar Orden Absoluto (Una sola temporada)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Activar Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferir Posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Lenguaje Preferido" -msgctxt "#30004" -msgid "Language" -msgstr "Idioma" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Mantener Título Original" diff --git a/addons/metadata.tvdb.com/resources/language/Spanish/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Spanish/strings.po index 09b6b58574..87c4cf365a 100644 --- a/addons/metadata.tvdb.com/resources/language/Spanish/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Spanish/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Usar orden de DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Usar orden absoluto (Temporada única)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Descargar Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Preferir Posters" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Idioma preferido" -msgctxt "#30004" -msgid "Language" -msgstr "Idioma" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Mantener título original" diff --git a/addons/metadata.tvdb.com/resources/language/Swedish/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Swedish/strings.po index e75832f489..f20b6ab56b 100644 --- a/addons/metadata.tvdb.com/resources/language/Swedish/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Swedish/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Använd DVD-ordning" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Använd absolut ordning (singelsäsong)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Aktivera fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Föredra omslag" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Föredraget språk" -msgctxt "#30004" -msgid "Language" -msgstr "Språk" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Behåll orginaltitel" diff --git a/addons/metadata.tvdb.com/resources/language/Tamil (India)/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Tamil (India)/strings.po index 1fcf8cb728..1f2699d89f 100644 --- a/addons/metadata.tvdb.com/resources/language/Tamil (India)/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Tamil (India)/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "டிவிடி வரிசை பயன்படுத்து" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "தனி வரிசை (தனி சீசன்) பயன்படுத்து" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "விசிறிபடத்தை காண்பி" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "சுவரொட்டிகள் விருப்பு" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "விரும்பிய மொழி" -msgctxt "#30004" -msgid "Language" -msgstr "மொழி" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "அசல் தலைப்பை வைக்க" diff --git a/addons/metadata.tvdb.com/resources/language/Thai/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Thai/strings.po index 2b275112ae..de64a7fecf 100644 --- a/addons/metadata.tvdb.com/resources/language/Thai/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Thai/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "ใช้การเรียง ดีวีดี" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "ใช้การเรียงลำดับโดยสมบูรณ์ (ฤดูเดียว)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "เปิดใช้ แฟนอาร์ต" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "เลือกใช้ โปสเตอร์" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "ภาษา ที่ต้องการ" -msgctxt "#30004" -msgid "Language" -msgstr "ภาษา" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "คงไว้ซึ่ง ชื่อต้นฉบับ" diff --git a/addons/metadata.tvdb.com/resources/language/Turkish/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Turkish/strings.po index c7c0452dee..9d388729a2 100644 --- a/addons/metadata.tvdb.com/resources/language/Turkish/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Turkish/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "DVD Sıralama Kullan" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Mutlak Sıralama Kullan (Tek Sezon)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Fanart Etkinleştir" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Posterleri Tercih Et" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Tercih Edilen Dil" -msgctxt "#30004" -msgid "Language" -msgstr "Dil" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Özgün Başlığı Koru" diff --git a/addons/metadata.tvdb.com/resources/language/Ukrainian/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Ukrainian/strings.po index cffffabff2..9115d0bd7e 100644 --- a/addons/metadata.tvdb.com/resources/language/Ukrainian/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Ukrainian/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "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" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Використоввати порядок DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Наскрізна нумерація (один сезон)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Завантажувати фанарт" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Віддавати перевагу постерам" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Вибір мови" -msgctxt "#30004" -msgid "Language" -msgstr "Мова" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Зберігати оригінальну назву" diff --git a/addons/metadata.tvdb.com/resources/language/Uzbek/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Uzbek/strings.po index 37df393af9..5ba109b14d 100644 --- a/addons/metadata.tvdb.com/resources/language/Uzbek/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Uzbek/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -16,6 +16,6 @@ msgstr "" "Language: uz\n" "Plural-Forms: nplurals=1; plural=0;\n" -msgctxt "#30004" -msgid "Language" -msgstr "Til" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Afzal til" diff --git a/addons/metadata.tvdb.com/resources/language/Vietnamese/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Vietnamese/strings.po index fdffc92c59..5f26764419 100644 --- a/addons/metadata.tvdb.com/resources/language/Vietnamese/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Vietnamese/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Sử dụng DVD Order" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Sử dụng sắp đặt cố định (Theo Season)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Sử dụng Fanart" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Ưu tiên các poster" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Ưu tiên ngôn ngữ" -msgctxt "#30004" -msgid "Language" -msgstr "Ngôn ngữ" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Giữ nguyên tên phim gốc" diff --git a/addons/metadata.tvdb.com/resources/language/Welsh/strings.po b/addons/metadata.tvshows.themoviedb.org/resources/language/Welsh/strings.po index 1e9e4b2335..5288ca3a74 100644 --- a/addons/metadata.tvdb.com/resources/language/Welsh/strings.po +++ b/addons/metadata.tvshows.themoviedb.org/resources/language/Welsh/strings.po @@ -1,6 +1,6 @@ # Kodi Media Center language file -# Addon Name: The TVDB -# Addon id: metadata.tvdb.com +# Addon Name: The Movie Database +# Addon id: metadata.tvshows.themoviedb.org # Addon Provider: XBMC Foundation msgid "" msgstr "" @@ -17,21 +17,13 @@ msgstr "" "Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;\n" msgctxt "#30000" -msgid "Use DVD Order" -msgstr "Defnyddio Trefn DVD" - -msgctxt "#30001" -msgid "Use Absolute Ordering (Single Season)" -msgstr "Defnyddio Trefnu Absoliwt (Un Tymor)" - -msgctxt "#30002" msgid "Enable Fanart" msgstr "Galluogi Celf" -msgctxt "#30003" -msgid "Prefer Posters" -msgstr "Cyfeirio Cofnodwyr" +msgctxt "#30002" +msgid "Preferred Language" +msgstr "Dewis Iaith" -msgctxt "#30004" -msgid "Language" -msgstr "Iaith" +msgctxt "#30005" +msgid "Keep Original Title" +msgstr "Cadw'r Teitl Gwreiddiol" diff --git a/addons/metadata.tvshows.themoviedb.org/resources/settings.xml b/addons/metadata.tvshows.themoviedb.org/resources/settings.xml new file mode 100644 index 0000000000..c6cd65137e --- /dev/null +++ b/addons/metadata.tvshows.themoviedb.org/resources/settings.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<settings> + <setting label="30005" type="bool" id="keeporiginaltitle" default="false"/> + <setting label="30006" type="bool" id="tmdbart" default="true"/> + <setting label="30007" type="bool" id="fanarttvart" default="true"/> + <setting label="30002" type="select" values="bg|cs|da|de|ee|el|en|es|fa|fa-ir|fi|fr|fr-ca|he|hr|hu|it|ja|ko|nl|no|pl|pt|pt-br|ru|sl|sr|sv|tr|zh-cn|zh-tw" id="language" default="en"/> +</settings> diff --git a/addons/metadata.tvshows.themoviedb.org/tmdb.xml b/addons/metadata.tvshows.themoviedb.org/tmdb.xml new file mode 100644 index 0000000000..181a5b80d0 --- /dev/null +++ b/addons/metadata.tvshows.themoviedb.org/tmdb.xml @@ -0,0 +1,474 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scraper framework="1.1" date="2013-10-26"> + <CreateSearchUrl dest="3"> + <RegExp input="$$1" output="<url>http://api.themoviedb.org/3/search/tv?api_key=6a5be4999abf74eba1f9a8311294c267&amp;query=\1&amp;language=$INFO[language]&amp;append_to_response=credits,external_ids,images&amp;include_image_language=$INFO[language],en,null</url>" dest="3"> + <expression noclean="1" /> + </RegExp> + </CreateSearchUrl> + + <NfoUrl dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="<url function="GetTMDBId">http://api.themoviedb.org/3/find/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;external_source=imdb_id</url>" dest="5"> + <expression clear="yes" noclean="1">imdb....?/title/(tt[0-9]*)</expression> + </RegExp> + <RegExp input="$$1" output="<url function="GetTMDBId">http://api.themoviedb.org/3/find/tt\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;external_source=imdb_id</url>" dest="5"> + <expression noclean="1">imdb....?/Title\?([0-9]*)</expression> + </RegExp> + <RegExp input="$$1" output="<url function="GetTMDBId">http://api.themoviedb.org/3/find/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;external_source=tvdb_id</url>" dest="5"> + <expression noclean="1">http://(?:www\.)?thetvdb\.com/(?:index\.php)?\?tab=series&id=([0-9]+)</expression> + </RegExp> + <RegExp input="$$1" output="<url cache="tmdb-\1-$INFO[language].json">http://api.themoviedb.org/3/tv/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=content_ratings,credits,external_ids,images&amp;include_image_language=$INFO[language],en,null</url><id>\1</id>" dest="5"> + <expression noclean="1">themoviedb\.org/tv/([0-9]+)</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </NfoUrl> + <GetTMDBId dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$7" output="<url cache="tmdb-\1-$INFO[language].json">http://api.themoviedb.org/3/tv/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=content_ratings,credits,external_ids,images&amp;include_image_language=$INFO[language],en,null</url><id>\1</id>" dest="5"> + <RegExp input="$$1" output="\1" dest="7"> + <expression noclean="1">"tv_results":\[([^\]]+)\]</expression> + </RegExp> + <expression>"id":([0-9]+)</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetTMDBId> + + <GetSearchResults dest="8"> + <RegExp input="$$3" output="<results>\1</results>" dest="8"> + <RegExp input="$$1" output="<entity><title>\3</title><id>\1</id><year>\2</year><url cache="tmdb-\1-$INFO[language].json">http://api.themoviedb.org/3/tv/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=content_ratings,credits,external_ids,images&amp;include_image_language=$INFO[language],en,null</url></entity>" dest="3"> + <expression repeat="yes">"id":([0-9]*),.*?"first_air_date":"([0-9]+).*?"original_name":"([^"]*)"</expression> + </RegExp> + <RegExp input="$$1" output="<entity><title>\2</title><id>\1</id><url cache="tmdb-\1-$INFO[language].json">http://api.themoviedb.org/3/tv/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=content_ratings,credits,external_ids,images&amp;include_image_language=$INFO[language],en,null</url></entity>" dest="3+"> + <expression repeat="yes">"id":([0-9]*),.*?"first_air_date":null.*?"original_name":"([^"]*)"</expression> + </RegExp> + <RegExp input="$$1" output="<entity><title>\1</title><id>\2</id><year>\3</year><url cache="tmdb-\2-$INFO[language].json">http://api.themoviedb.org/3/tv/\2?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=content_ratings,credits,external_ids,images&amp;include_image_language=$INFO[language],en,null</url></entity>" dest="3+"> + <expression repeat="yes">original_name":"([^"]*)","id":([0-9]*),.*?"first_air_date":"([0-9]+).*?"</expression> + </RegExp> + <RegExp input="$$1" output="<entity><title>\1</title><id>\2</id><url cache="tmdb-\2-$INFO[language].json">http://api.themoviedb.org/3/tv/\2?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=content_ratings,credits,external_ids,images&amp;include_image_language=$INFO[language],en,null</url></entity>" dest="3+"> + <expression repeat="yes">original_name":"([^"]*)","id":([0-9]*),.*?"first_air_date":null.*?"</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetSearchResults> + + <GetDetails dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="\1" dest="7"> + <expression fixchars="1">"original_name":"([^"]*)</expression> + </RegExp> + <RegExp conditional="keeporiginaltitle" input="$$7" output="<title>\1</title>" dest="5"> + <expression/> + </RegExp> + <RegExp conditional="!keeporiginaltitle" input="$$1" output="<title>\1</title>" dest="5+"> + <expression fixchars="1">"name":"([^"]*)","next</expression> + </RegExp> + <RegExp input="$$7" output="<originaltitle>\1</originaltitle>" dest="5+"> + <expression/> + </RegExp> + <RegExp input="$$2" output="<id>\1</id><uniqueid type="tmdb" default="true">\1</uniqueid>" dest="5+"> + <expression/> + </RegExp> + <RegExp input="$$1" output="<year>\1</year>" dest="5+"> + <expression noclean="1">"first_air_date":"([0-9]+)-</expression> + </RegExp> + <RegExp input="$$1" output="<premiered>\1</premiered>" dest="5+"> + <expression noclean="1">"first_air_date":"([^"]*)</expression> + </RegExp> + <RegExp input="$$7" output="<studio>\1</studio>" dest="5+"> + <RegExp input="$$1" output="\1" dest="7"> + <expression clear="yes" noclean="1">"networks":\[([^\]]*)</expression> + </RegExp> + <expression trim="1" fixchars="1">"name":"([^"]*)</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="7"> + <expression clear="yes" noclean="1">"crew":\[([^\]]*)</expression> + </RegExp> + <RegExp input="$$7" output="<director>\1</director>" dest="5+"> + <expression repeat="yes" fixchars="1">"name":"([^"]*)","job":"Director"</expression> + </RegExp> + <RegExp input="$$7" output="<credits>\1</credits>" dest="5+"> + <expression repeat="yes" fixchars="1">"name":"([^"]*)","job":"Writer"</expression> + </RegExp> + <RegExp input="$$7" output="<ratings><rating name="themoviedb" default="true">\1</rating></ratings>" dest="5+"> + <RegExp input="$$1" output="<value>\1</value>" dest="7"> + <expression>"vote_average":([^"]*)</expression> + </RegExp> + <RegExp input="$$1" output="<votes>\1</votes>" dest="7+"> + <expression>"vote_count":([0-9]+)</expression> + </RegExp> + <expression noclean="1">(.+)</expression> + </RegExp> + <RegExp input="$$1" output="<mpaa>\1</mpaa>" dest="5+"> + <expression>"rating":"([^"]*)"</expression> + </RegExp> + <RegExp input="$$2" output="<chain function="GetCast">$$2</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$7" output="<genre>\1</genre>" dest="5+"> + <RegExp input="$$1" output="\1" dest="7"> + <expression clear="yes" noclean="1">"genres":\[([^\]]+)\]</expression> + </RegExp> + <expression repeat="yes" fixchars="1">"name":"([^"]*)</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="9"> + <expression clear="yes" fixchars="1">original_name":"[^"]*","overview":"(.+?)","popularity"</expression> + </RegExp> + <RegExp input="$$9" output="<plot>\1</plot>" dest="5+"> + <expression>(.+)</expression> + </RegExp> + <RegExp input="$$9" output="$$8" dest="5+"> + <RegExp input="$INFO[language]" output="<url function="ParseFallbackTMDBPlot" cache="tmdb-$$2-en.json">http://api.themoviedb.org/3/tv/$$2?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=en</url>" dest="8"> + <expression clear="yes">^(?!en).*</expression> + </RegExp> + <expression>^$</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="19"> + <expression>"tvdb_id":([^,]*),</expression> + </RegExp> + <RegExp input="$$19" output="<uniqueid type="tvdb" default="false">\1</uniqueid>" dest="5+"> + <expression/> + </RegExp> + <RegExp conditional="fanarttvart" input="$$19" output="<chain function="GetFanartTvArt">\1</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp conditional="tmdbart" input="$$2" output="<chain function="GetArt">$$2</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$3" output="<episodeguide><url cache="tmdb-$$2-$INFO[language].json">\1</url></episodeguide>" dest="5+"> + <expression>(.*)&append</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetDetails> + + <GetEpisodeList clearbuffers="no" dest="3"> + <RegExp input="$$4" output="<episodeguide>\1</episodeguide>" dest="3"> + <RegExp input="$$1" output="\1" dest="5"> + <expression>"id":([0-9]+),"in_production"</expression> + </RegExp> + <RegExp input="$$1" output="<url cache="tmdb-$$5-$INFO[language]-season-\1.json" function="GetSeasonEpisodeList">http://api.themoviedb.org/3/tv/$$5/season/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]</url>" dest="4"> + <expression repeat="yes">"season_number":([0-9]+)</expression> + </RegExp> + <expression noclean="1"/> + </RegExp> + </GetEpisodeList> + <GetSeasonEpisodeList clearbuffers="no" dest="3"> + <RegExp input="$$4" output="<episodeguide>\1</episodeguide>" dest="3"> + <RegExp input="$$1" output="\1" dest="6"> + <expression clear="yes">"season_number":([0-9]+)</expression> + </RegExp> + <RegExp input="$$1" output="<episode><title>\4</title><aired>\2</aired><epnum>\3</epnum><season>$$6</season><url cache="tmdb-$$5-$INFO[language]-episode-s$$6e\3.json">http://api.themoviedb.org/3/tv/$$5/season/$$6/episode/\3?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=credits,external_ids,images&amp;include_image_language=$INFO[language],en,null</url><id>$$5|$$6|\3</id></episode>" dest="4"> + <expression repeat="yes" clear="yes">"air_date":("([^"]+)"|null),"episode_number":([0-9]+),"id":[0-9]+,"name":"((?:[^"]|(?<=\\)")*)",</expression> + </RegExp> + <expression noclean="1"/> + </RegExp> + </GetSeasonEpisodeList> + + <GetEpisodeDetails dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="\1" dest="10"> + <expression>"season_number":([0-9]+)</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="11"> + <expression>"episode_number":([0-9]+)</expression> + </RegExp> + <RegExp input="$$2" output="\1" dest="6"> + <expression>([0-9]+)\|</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="9"> + <expression fixchars="1" clear="yes">"name":"([^\}]*?)","overview"</expression> + </RegExp> + <RegExp input="$$9" output="<title>\1</title>" dest="5"> + <expression>(.+)</expression> + </RegExp> + <RegExp input="$$9" output="$$8" dest="5+"> + <RegExp input="$INFO[language]" output="<url function="ParseFallbackTMDBEpisodeTitle" cache="tmdb-$$6-en-episode-s$$10e$$11.json">http://api.themoviedb.org/3/tv/$$6/season/$$10/episode/$$11?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=en</url>" dest="8"> + <expression clear="yes">^(?!en).*</expression> + </RegExp> + <expression>^$</expression> + </RegExp> + <RegExp input="$$10|$$11" output="<season>\1</season><episode>\2</episode>" dest="5+"> + <expression>([0-9]+)\|([0-9]+)</expression> + </RegExp> + <RegExp input="$$1" output="<aired>\1</aired>" dest="5+"> + <expression>"air_date":"([^"]*)"</expression> + </RegExp> + <RegExp input="$$1" output="<uniqueid type="tmdb" default="true">\1</uniqueid>" dest="5+"> + <expression>"id":([0-9]+),"production_code"</expression> + </RegExp> + <RegExp input="$$7" output="<ratings><rating name="tmdb" default="true">\1</rating></ratings>" dest="5+"> + <RegExp input="$$1" output="<value>\1</value>" dest="7"> + <expression>"vote_average":([^"]*)</expression> + </RegExp> + <RegExp input="$$1" output="<votes>\1</votes>" dest="7+"> + <expression>"vote_count":([0-9]+)</expression> + </RegExp> + <expression noclean="1">(.+)</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="9"> + <expression clear="yes" fixchars="1">"overview":"([^\{]+?)","id"</expression> + </RegExp> + <RegExp input="$$9" output="<plot>\1</plot>" dest="5+"> + <expression>(.+)</expression> + </RegExp> + <RegExp input="$$9" output="$$8" dest="5+"> + <RegExp input="$INFO[language]" output="<url function="ParseFallbackTMDBPlot" cache="tmdb-$$6-en-episode-s$$10e$$11.json">http://api.themoviedb.org/3/tv/$$6/season/$$10/episode/$$11?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=en</url>" dest="8"> + <expression clear="yes">^(?!en).*</expression> + </RegExp> + <expression>^$</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="7"> + <expression clear="yes" noclean="1">"crew":\[([^\]]*)</expression> + </RegExp> + <RegExp input="$$7" output="<director>\1</director>" dest="5+"> + <expression repeat="yes" fixchars="1">"name":"([^"]*)","department":"Directing"</expression> + </RegExp> + <RegExp input="$$7" output="<credits>\1</credits>" dest="5+"> + <expression repeat="yes" fixchars="1">"name":"([^"]*)","department":"Writing"</expression> + </RegExp> + <RegExp input="$$2" output="<chain function="GetCast">$$2</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$2" output="<chain function="GetEpisodeArt">$$2</chain>" dest="5+"> + <expression /> + </RegExp> + <expression noclean="1"/> + </RegExp> + </GetEpisodeDetails> + + <ParseFallbackTMDBPlot dest="4"> + <RegExp input="$$5" output="<details>\1</details>" dest="4"> + <RegExp input="$$1" output="<plot>\1</plot>" dest="5"> + <expression clear="yes" fixchars="1">original_name":"[^"]*","overview":"([^\{]*?)","(?:id|popularity)"</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </ParseFallbackTMDBPlot> + + <ParseFallbackTMDBEpisodeTitle dest="4"> + <RegExp input="$$5" output="<details>\1</details>" dest="4"> + <RegExp input="$$1" output="<title>\1</title>" dest="5"> + <expression fixchars="1" clear="yes">"name":"([^\}]*?)","overview"</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </ParseFallbackTMDBEpisodeTitle> + + <ParseTMDBBaseImageURL clearbuffers="no" dest="4"> + <RegExp input="$$5" output="<details>$$20</details>" dest="4"> + <RegExp input="$$1" output="\1" dest="20"> + <expression>"images":\{"base_url":"([^"]*)"</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </ParseTMDBBaseImageURL> + + <GetCast dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="<url function="ParseTMDBBaseImageURL" cache="tmdb-config.json">http://api.themoviedb.org/3/configuration?api_key=6a5be4999abf74eba1f9a8311294c267</url>" dest="5"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<url cache="tmdb-\1-$INFO[language].json" function="ParseCast">http://api.themoviedb.org/3/tv/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=credits</url>" dest="5+"> + <expression>^([0-9]+)$</expression> /> + </RegExp> + <RegExp input="$$1" output="<url cache="tmdb-\1-$INFO[language]-episode-s\2e\3.json" function="ParseCast">http://api.themoviedb.org/3/tv/\1/season/\2/episode/\3?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=credits</url>" dest="5+"> + <expression>^([0-9]+)\|([0-9]+)\|([0-9]+)$</expression> /> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetCast> + <ParseCast dest="4"> + <RegExp input="$$5" output="<details>\1</details>" dest="4"> + <RegExp input="$$1" output="\1" dest="7"> + <expression clear="yes" noclean="1">"cast":\[([^\]]+)\]</expression> + </RegExp> + <RegExp input="$$7" output="<actor><name>\2</name><role>\1</role><order>\4</order><thumb>$$20original\3</thumb></actor>" dest="5"> + <expression clear="yes" repeat="yes" fixchars="1,2">"character":"((?:[^"]|(?<=\\)")*)","credit_id":"[^"]*","id":[0-9]*,"name":"([^"]*)","gender":[^,]*,"profile_path":"([^"]*)","order":([0-9]*)</expression> + </RegExp> + <RegExp input="$$7" output="<actor><name>\2</name><role>\1</role><order>\3</order></actor>" dest="5+"> + <expression repeat="yes" fixchars="1,2">"character":"((?:[^"]|(?<=\\)")*)","credit_id":"[^"]*","id":[0-9]*,"name":"([^"]*)","gender":[^,]*,"profile_path":null,"order":([0-9]*)</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="7"> + <expression clear="yes" noclean="1">"guest_stars":\[([^\]]+)\]</expression> + </RegExp> + <RegExp input="$$7" output="<actor><name>\1</name><role>\2</role><thumb>$$20original\3</thumb></actor>" dest="5+"> + <expression repeat="yes" fixchars="1,2">"name":"([^"]*)","credit_id":"[^"]*","character":"((?:[^"]|(?<=\\)")*)","profile_path":"([^"]*)","order":[0-9]*</expression> + </RegExp> + <RegExp input="$$7" output="<actor><name>\2</name><role>\1</role></actor>" dest="5+"> + <expression repeat="yes" fixchars="1,2">"name":"([^"]*)","credit_id":"[^"]*","character":"((?:[^"]|(?<=\\)")*)","profile_path":null,"order":[0-9]*</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </ParseCast> + + <GetArt dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="<url function="ParseTMDBBaseImageURL" cache="tmdb-config.json">http://api.themoviedb.org/3/configuration?api_key=6a5be4999abf74eba1f9a8311294c267</url>" dest="5"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<url cache="tmdb-\1-$INFO[language].json" function="ParseArt">http://api.themoviedb.org/3/tv/\1?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=external_ids,images&amp;include_image_language=$INFO[language],en,null</url>" dest="5+"> + <expression /> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetArt> + <ParseArt clearbuffers="no" dest="4"> + <RegExp input="$$5" output="<details>\1</details>" dest="4"> + <RegExp input="$$1" output="\1" dest="7"> + <expression>"posters":\[([^\]]*)\]</expression> + </RegExp> + <RegExp input="$$7" output="<thumb aspect="poster">$$20original\1</thumb>" dest="5"> + <expression clear="yes" repeat="yes">"file_path":"([^"]*)","height":[0-9]+,"iso_639_1":"$INFO[language]"</expression> + </RegExp> + <RegExp input="$$7" output="<thumb aspect="poster">$$20original\1</thumb>" dest="5+"> + <expression repeat="yes">"file_path":"([^"]*)","height":[0-9]+,"iso_639_1":(?!"$INFO[language]")</expression> + </RegExp> + <RegExp input="$$8" output="<fanart url="$$20" >\1</fanart>" dest="5+"> + <RegExp input="$$7" output="<thumb dim="\3x\2" preview="w780\1">original\1</thumb>" dest="8"> + <RegExp input="$$1" output="\1" dest="7"> + <expression>"backdrops":\[([^\]]*)\]</expression> + </RegExp> + <expression repeat="yes">"file_path":"([^"]*)","height":([0-9]+)[^\}]*"width":([0-9]+)</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + <RegExp input="$$1" output="\1" dest="8"> + <expression>"id":([0-9]+),"in_production"</expression> + </RegExp> + <RegExp input="$$1" output="<chain function="GetSeasonArt">$$8|\1</chain>" dest="5+"> + <expression repeat="yes">"season_number":([0-9]+)</expression> + </RegExp> + <RegExp input="$$1" output="<chain function="GetTVDBWideBanners">\1</chain>" dest="5+"> + <expression>"tvdb_id":([0-9]+)</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </ParseArt> + <GetSeasonArt clearbuffers="no" dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="<url function="ParseTMDBBaseImageURL" cache="tmdb-config.json">http://api.themoviedb.org/3/configuration?api_key=6a5be4999abf74eba1f9a8311294c267</url>" dest="5"> + <expression>^([0-9]+)\|</expression> + </RegExp> + <RegExp input="$$1" output="\1" dest="10"> + <expression>\|([0-9]+)$</expression> + </RegExp> + <RegExp input="$$1" output="<url cache="tmdb-\1-$INFO[language]-season-\2.json" function="ParseSeasonArt">http://api.themoviedb.org/3/tv/\1/season/\2?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;append_to_response=images&amp;include_image_language=$INFO[language],en,null</url>" dest="5+"> + <expression>^([0-9]+)\|([0-9]+)$</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetSeasonArt> + <ParseSeasonArt dest="4"> + <RegExp input="$$5" output="<details>\1</details>" dest="4"> + <RegExp input="$$1" output="\1" dest="7"> + <expression clear="yes">"posters":\[([^\]]*)\]</expression> + </RegExp> + <RegExp input="$$7" output="<thumb aspect="poster" type="season" season="$$10">$$20original\1</thumb>" dest="5"> + <expression clear="yes" repeat="yes">"file_path":"([^"]*)","height":[0-9]+,"iso_639_1":"$INFO[language]"</expression> + </RegExp> + <RegExp input="$$7" output="<thumb aspect="poster" type="season" season="$$10">$$20original\1</thumb>" dest="5+"> + <expression repeat="yes">"file_path":"([^"]*)","height":[0-9]+,"iso_639_1":(?!"$INFO[language]")</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </ParseSeasonArt> + <GetEpisodeArt dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="<url function="ParseTMDBBaseImageURL" cache="tmdb-config.json">http://api.themoviedb.org/3/configuration?api_key=6a5be4999abf74eba1f9a8311294c267</url>" dest="5"> + <expression>^([0-9]+)\|</expression> + </RegExp> + <RegExp input="$$1" output="<url cache="tmdb-\1-$INFO[language]-episode-s\2e\3.json" function="ParseEpisodeArt">http://api.themoviedb.org/3/tv/\1/season/\2/episode/\3/images?api_key=6a5be4999abf74eba1f9a8311294c267&amp;language=$INFO[language]&amp;include_image_language=$INFO[language],en,null</url>" dest="5+"> + <expression>^([0-9]+)\|([0-9]+)\|([0-9]+)$</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetEpisodeArt> + <ParseEpisodeArt dest="4"> + <RegExp input="$$5" output="<details>\1</details>" dest="4"> + <RegExp input="$$7" output="<thumb>$$20original\1</thumb>" dest="5"> + <RegExp input="$$1" output="\1" dest="7"> + <expression clear="yes">"stills":\[([^\]]*)\]</expression> + </RegExp> + <expression repeat="yes">"file_path":"([^"]*)"</expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </ParseEpisodeArt> + + <GetTVDBWideBanners dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="<url function="ParseTVDBWideBanners" cache="tvdb-\1-banners.xml">https://thetvdb.com/api/439DFEBA9D3059C6/series/\1/banners.xml</url>" dest="5"> + <expression /> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetTVDBWideBanners> + <ParseTVDBWideBanners dest="4"> + <RegExp input="$$5" output="<details>\1</details>" dest="4"> + <RegExp input="$$1" output="\1" dest="3"> + <expression noclean="1"><Banners>(.*)</expression> + </RegExp> + <RegExp input="$$3" output="<thumb aspect="banner">https://thetvdb.com/banners/\1</thumb>" dest="5"> + <expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>graphical</BannerType2>[^<]*<Language>$INFO[language]</Language></expression> + </RegExp> + <RegExp input="$$3" output="<thumb aspect="banner">https://thetvdb.com/banners/\1</thumb>" dest="5+"> + <expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>graphical</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language></expression> + </RegExp> + <RegExp input="$$3" output="<thumb aspect="banner">https://thetvdb.com/banners/\1</thumb>" dest="5+"> + <expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>text</BannerType2>[^<]*<Language>$INFO[language]</Language></expression> + </RegExp> + <RegExp input="$$3" output="<thumb aspect="banner">https://thetvdb.com/banners/\1</thumb>" dest="5+"> + <expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>text</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language></expression> + </RegExp> + <RegExp input="$$3" output="<thumb aspect="banner">https://thetvdb.com/banners/\1</thumb>" dest="5+"> + <expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>blank</BannerType2>[^<]*<Language></Language></expression> + </RegExp> + <RegExp input="$$3" output="<thumb aspect="banner" type="season" season="\2">https://thetvdb.com/banners/\1</thumb>" dest="5+"> + <expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>seasonwide</BannerType2>[^<]*<Language>$INFO[language]</Language>[^<]*[^S]*Season>([0-9]+)</Season></expression> + </RegExp> + <RegExp input="$$3" output="<thumb aspect="banner" type="season" season="\3">https://thetvdb.com/banners/\1</thumb>" dest="5+"> + <expression repeat="yes"><BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>seasonwide</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language>[^<]*[^S]*Season>([0-9]+)</Season></expression> + </RegExp> + <expression noclean="1" /> + </RegExp> + </ParseTVDBWideBanners> + + <GetFanartTvArt dest="3"> + <RegExp input="$$5" output="<details>\1</details>" dest="3"> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowPosterByIdChain">\1::$INFO[language]</chain>" dest="5"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowBannerByIdChain">\1::$INFO[language]</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowLandscapeByIdChain">\1::$INFO[language]</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowClearlogoByIdChain">\1::$INFO[language]</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowClearartByIdChain">\1::$INFO[language]</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowFanartByIdChain">\1</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowCharacterartByIdChain">\1</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowSeasonposterByIdChain">\1::$INFO[language]</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowSeasonbannerByIdChain">\1::$INFO[language]</chain>" dest="5+"> + <expression /> + </RegExp> + <RegExp input="$$1" output="<chain function="GetFanartTvTvShowSeasonLandscapeByIdChain">\1::$INFO[language]</chain>" dest="5+"> + <expression /> + </RegExp> + <expression noclean="1" /> + </RegExp> + </GetFanartTvArt> + +</scraper> diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 51a400f154..b28cd82141 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -4818,7 +4818,13 @@ msgctxt "#10007" msgid "System information" msgstr "" -#empty strings from id 10008 to 10010 +#: xbmc/music/windows/GUIWindowMusicBase.cpp +#: xbmc/video/windows/GUIWindowVideoBase.cpp +msgctxt "#10008" +msgid "Play next" +msgstr "" + +#empty strings from id 10009 to 10010 #: xbmc/guilib/WindowIDs.h msgctxt "#10011" @@ -10914,11 +10920,7 @@ msgctxt "#19302" msgid "Do you want to record the selected programme or to switch to the current programme?" msgstr "" -#. pvr setting "Use simple timeshift OSD" value -#: system/settings/settings.xml -msgctxt "#19303" -msgid "Use simple timeshift OSD" -msgstr "" +#empty string with id 19303 #. Label for context menu entry to open settings dialog for a timer rule (read-only) #: xbmc/pvr/PVRContextMenus.cpp @@ -12727,6 +12729,7 @@ msgstr "" #: xbmc/media/MediaTypes.cpp #: addons/skin.estuary/xml/Variables.xml #: xbmc/view/GUIViewState.cpp +#: system/settings/settings.xml msgctxt "#20342" msgid "Movies" msgstr "" @@ -12738,6 +12741,7 @@ msgstr "" #: addons/skin.estuary/xml/SkinSettings.xml #: addons/skin.estuary/xml/Variables.xml #: xbmc/view/GUIViewState.cpp +#: system/settings/settings.xml msgctxt "#20343" msgid "TV shows" msgstr "" @@ -12873,7 +12877,7 @@ msgstr "" #: system/settings/settings.xml msgctxt "#20369" -msgid "Show plot for unwatched items" +msgid "Show information for unwatched items" msgstr "" msgctxt "#20370" @@ -14865,7 +14869,8 @@ msgctxt "#24041" msgid "Install from zip file" msgstr "" -#: xbmc/addons/GUIViewStateAddonBrowser.cpp +#. Used to show on addon list the current download process +#: xbmc/addons/GUIWindowAddonBrowser.cpp msgctxt "#24042" msgid "Downloading {0:d}%" msgstr "" @@ -14876,7 +14881,11 @@ msgctxt "#24043" msgid "Available updates" msgstr "" -#empty string with id 24044 +#. Used to show on addon list the current install process (shown after 24042) +#: xbmc/addons/GUIWindowAddonBrowser.cpp +msgctxt "#24044" +msgid "Installing {0:d}%" +msgstr "" #. Used as an event log description for add-ons failed to install from zip #: xbmc/addons/AddonInstaller.cpp @@ -18104,10 +18113,10 @@ msgctxt "#36140" msgid "Choose which temperature unit is used for displaying temperatures in the user interface." msgstr "" -#. Description of setting with label #20369 "Show plot for unwatched items" +#. Description of setting with label #20369 "Show information for unwatched items" #: system/settings/settings.xml msgctxt "#36141" -msgid "Show plot information for unwatched media in the video library." +msgid "Show information for unwatched media in the video library or hide them if not selected to prevent spoilers. Available options are 'Movie plot', 'Episode plot' and 'Episode thumb'." msgstr "" #. Description of setting with label #14106 "Speed unit" @@ -18632,18 +18641,13 @@ msgctxt "#36234" msgid "Duration of instant recordings when pressing the record button. This value will be taken into account if \"Instant recording action\" is set to \"Record for a fixed period of time\"" msgstr "" -#. help text for pvr setting "Use simple timeshift OSD" -#: system/settings/settings.xml -msgctxt "#36235" -msgid "Normal timeshift OSD always shows the complete timeshift buffer along with with the currently playing show, whereas the simple timeshift OSD only shows the currently playing show with no visual feedback how far in the timeshift buffer you can jump from the currently playing position." -msgstr "" +#empty string with id 36235 #: system/settings/settings.xml msgctxt "#36236" msgid "If set to a value greater than zero last watched time of channels will be stored the given amount of time after start of channel playback. Otherwise the last watched time will be stored immediately at start of channel playback." msgstr "" - #: system/settings/settings.xml msgctxt "#36237" msgid "Additional time to record before the scheduled start time to allow for minor broadcasting changes. Not supported by all add-ons and backends." @@ -19113,7 +19117,7 @@ msgstr "" #. Description of setting with label #21361 "Look for remote UPnP players" #: system/settings/settings.xml msgctxt "#36326" -msgid "Enable the UPnP control point. This allows you to stream media to any UPnP client and control it's playback." +msgid "Enable the UPnP control point. This allows you to stream media to any UPnP client and control its playback." msgstr "" #. Description of settings category with label #20187 "Control" @@ -20654,6 +20658,7 @@ msgid "Configure audio encoder settings such as quality and compression level" msgstr "" #: system/settings/rbp.xml +#: system/settings/android.xml msgctxt "#37026" msgid "Auto" msgstr "" @@ -20664,6 +20669,7 @@ msgid "540" msgstr "" #: system/settings/rbp.xml +#: system/settings/android.xml msgctxt "#37028" msgid "720" msgstr "" @@ -20674,6 +20680,7 @@ msgid "900" msgstr "" #: system/settings/rbp.xml +#: system/settings/android.xml msgctxt "#37030" msgid "Unlimited" msgstr "" @@ -20768,7 +20775,12 @@ msgctxt "#37045" msgid "Extract chapter thumbnails for presentation in the chapters / bookmarks dialogue. This might increase CPU load." msgstr "" -#empty strings from id 37046 to 38009 +#: system/settings/android.xml +msgctxt "#37046" +msgid "1080" +msgstr "" + +#empty strings from id 37047 to 38009 #: system/settings/rbp.xml msgctxt "#38010" @@ -21584,3 +21596,21 @@ msgstr "" msgctxt "#39113" msgid "Center Mix Level in dB relative to metadata or default (-3 dB)" msgstr "" + +#. Label for "show information for unwatched items" setting option +#: system/settings/settings.xml +msgctxt "#39114" +msgid "Episode thumb" +msgstr "" + +#. Label for "show information for unwatched items" setting option +#: system/settings/settings.xml +msgctxt "#39115" +msgid "Movie plot" +msgstr "" + +#. Label for "show information for unwatched items" setting option +#: system/settings/settings.xml +msgctxt "#39116" +msgid "Episode plot" +msgstr "" diff --git a/addons/screensaver.xbmc.builtin.dim/addon.xml b/addons/screensaver.xbmc.builtin.dim/addon.xml index 3053d9e8f3..3b0761063a 100644 --- a/addons/screensaver.xbmc.builtin.dim/addon.xml +++ b/addons/screensaver.xbmc.builtin.dim/addon.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <addon id="screensaver.xbmc.builtin.dim" name="Dim" - version="1.0.46" + version="1.0.49" provider-name="Team Kodi"> <extension point="xbmc.ui.screensaver" library=""/> <extension point="xbmc.addon.metadata"> diff --git a/addons/script.module.pil/icon.png b/addons/script.module.pil/icon.png Binary files differnew file mode 100644 index 0000000000..ca4c53adbf --- /dev/null +++ b/addons/script.module.pil/icon.png diff --git a/addons/script.module.pycryptodome/icon.png b/addons/script.module.pycryptodome/icon.png Binary files differnew file mode 100644 index 0000000000..ca4c53adbf --- /dev/null +++ b/addons/script.module.pycryptodome/icon.png diff --git a/addons/service.xbmc.versioncheck/addon.xml b/addons/service.xbmc.versioncheck/addon.xml index 1184bd71c5..e30d70bdd2 100644 --- a/addons/service.xbmc.versioncheck/addon.xml +++ b/addons/service.xbmc.versioncheck/addon.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <addon id="service.xbmc.versioncheck" name="Version Check" - version="0.3.27" + version="0.4.1" provider-name="Team Kodi"> <requires> <import addon="xbmc.python" version="2.1.0"/> diff --git a/addons/service.xbmc.versioncheck/resources/language/English/strings.po b/addons/service.xbmc.versioncheck/resources/language/English/strings.po index c8710afdd6..6746418c5c 100644 --- a/addons/service.xbmc.versioncheck/resources/language/English/strings.po +++ b/addons/service.xbmc.versioncheck/resources/language/English/strings.po @@ -111,3 +111,17 @@ msgstr "" msgctxt "#32035" msgid "It is recommended that you to upgrade to a newer version." msgstr "" + +#empty strings from id 32036 to 32039 + +msgctxt "#32040" +msgid "Your version %s of the Python cryptography module is too old. You need at least version 1.7." +msgstr "" + +msgctxt "#32041" +msgid "Please upgrade your operating system." +msgstr "" + +msgctxt "#32042" +msgid "For more information, see https://kodi.wiki/view/Linux" +msgstr "" diff --git a/addons/service.xbmc.versioncheck/resources/versions.txt b/addons/service.xbmc.versioncheck/resources/versions.txt index 6dea1f5242..5556b58198 100644 --- a/addons/service.xbmc.versioncheck/resources/versions.txt +++ b/addons/service.xbmc.versioncheck/resources/versions.txt @@ -397,6 +397,22 @@ "major": "18", "minor": "0", "tag": "beta", + "tagversion":"5", + "revision": "20181103-920e823249", + "addon_support": "yes" + }, + { + "major": "18", + "minor": "0", + "tag": "beta", + "tagversion":"4", + "revision": "20181023-c77874c5bf", + "addon_support": "yes" + }, + { + "major": "18", + "minor": "0", + "tag": "beta", "tagversion":"3", "revision": "20181002-c2e1b316f5", "addon_support": "yes" diff --git a/addons/service.xbmc.versioncheck/service.py b/addons/service.xbmc.versioncheck/service.py index 7f85bedefe..86bbdd5e53 100644 --- a/addons/service.xbmc.versioncheck/service.py +++ b/addons/service.xbmc.versioncheck/service.py @@ -19,8 +19,9 @@ import platform import xbmc +import xbmcgui import lib.common -from lib.common import log, dialog_yesno +from lib.common import log, dialog_yesno, localise from lib.common import upgrade_message as _upgrademessage from lib.common import upgrade_message2 as _upgrademessage2 @@ -102,9 +103,27 @@ def _versionchecklinux(packages): log("Unsupported platform %s" %platform.dist()[0]) sys.exit(0) - +# Python cryptography < 1.7 (still shipped with Ubuntu 16.04) has issues with +# pyOpenSSL integration, leading to all sorts of weird bugs - check here to save +# on some troubleshooting. This check may be removed in the future (when switching +# to Python3?) +# See https://github.com/pyca/pyopenssl/issues/542 +def _checkcryptography(): + ver = None + try: + import cryptography + ver = cryptography.__version__ + except: + # If the module is not found - no problem + return + + ver_parts = list(map(int, ver.split('.'))) + if len(ver_parts) < 2 or ver_parts[0] < 1 or (ver_parts[0] == 1 and ver_parts[1] < 7): + log('Python cryptography module version %s is too old, at least version 1.7 needed' % ver) + xbmcgui.Dialog().ok(ADDONNAME, localise(32040) % ver, localise(32041), localise(32042)) if (__name__ == "__main__"): + _checkcryptography() if ADDON.getSetting("versioncheck_enable") == "false": log("Disabled") else: diff --git a/addons/skin.estouchy/addon.xml b/addons/skin.estouchy/addon.xml index b095cf3b6b..7e403d9a52 100644 --- a/addons/skin.estouchy/addon.xml +++ b/addons/skin.estouchy/addon.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> -<addon id="skin.estouchy" version="2.0.17" name="Estouchy" provider-name="Team Kodi"> +<addon id="skin.estouchy" version="2.0.20" name="Estouchy" provider-name="Team Kodi"> <requires> - <import addon="xbmc.gui" version="5.13.0"/> + <import addon="xbmc.gui" version="5.14.0"/> </requires> <extension point="xbmc.gui.skin" debugging="false"> <res width="1280" height="960" aspect="4:3" folder="xml"/> diff --git a/addons/skin.estouchy/language/resource.language.fr_ca/strings.po b/addons/skin.estouchy/language/resource.language.fr_ca/strings.po index e889e82c24..daa142aee4 100644 --- a/addons/skin.estouchy/language/resource.language.fr_ca/strings.po +++ b/addons/skin.estouchy/language/resource.language.fr_ca/strings.po @@ -42,7 +42,7 @@ msgstr "Menu contextuel" msgctxt "#31009" msgid "Working..." -msgstr "Travail en cours..." +msgstr "Travail en cours…" msgctxt "#31011" msgid "Recent" @@ -194,7 +194,7 @@ msgstr "Valeur par défaut de l’habillage" msgctxt "#31391" msgid "Arial based" -msgstr "Basé sur Arial" +msgstr "D’après Arial" msgctxt "#31400" msgid "Change the skin · Set language and region · Change file listing options · Set up a screensaver" @@ -326,4 +326,4 @@ msgstr "Lorsque vous lisez de l’audio ou une vidéo, le titre de l’élément msgctxt "#31904" msgid "Now Playing Title..." -msgstr "Titre de la lecture en cours..." +msgstr "Titre de la lecture en cours…" diff --git a/addons/skin.estouchy/language/resource.language.nl_nl/strings.po b/addons/skin.estouchy/language/resource.language.nl_nl/strings.po index c095c2bdfe..45795f7375 100644 --- a/addons/skin.estouchy/language/resource.language.nl_nl/strings.po +++ b/addons/skin.estouchy/language/resource.language.nl_nl/strings.po @@ -46,7 +46,7 @@ msgstr "Bezig..." msgctxt "#31011" msgid "Recent" -msgstr "Recent" +msgstr "Recente" msgctxt "#31013" msgid "Movies" @@ -134,7 +134,7 @@ msgstr "Sluit afspeellijst" msgctxt "#31058" msgid "System music files" -msgstr "Systeem muziekbestanden" +msgstr "Systeemmuziekbestanden" msgctxt "#31059" msgid "Current playlist" @@ -250,7 +250,7 @@ msgstr "Achtergronden" msgctxt "#31551" msgid "Add-on Shortcut" -msgstr "Add-on snelkoppelingen" +msgstr "Add-on snelkoppeling" msgctxt "#31552" msgid "SYNC" diff --git a/addons/skin.estouchy/language/resource.language.sv_se/strings.po b/addons/skin.estouchy/language/resource.language.sv_se/strings.po index 7e5185a860..034861d990 100644 --- a/addons/skin.estouchy/language/resource.language.sv_se/strings.po +++ b/addons/skin.estouchy/language/resource.language.sv_se/strings.po @@ -270,7 +270,7 @@ msgstr "Konfigurera tv-inställningar · Ändra helskärmsinformation · Hantera msgctxt "#31556" msgid "Live TV" -msgstr "Live-tv" +msgstr "Live-TV" msgctxt "#31557" msgid "Hide video background" diff --git a/addons/skin.estouchy/xml/IncludesHomeRecentlyAdded.xml b/addons/skin.estouchy/xml/IncludesHomeRecentlyAdded.xml index 2818c81649..dc4675b43c 100644 --- a/addons/skin.estouchy/xml/IncludesHomeRecentlyAdded.xml +++ b/addons/skin.estouchy/xml/IncludesHomeRecentlyAdded.xml @@ -107,7 +107,7 @@ <texture border="5">thumb_focus.png</texture> </control> </focusedlayout> - <content target="movies" sortby="date" limit="10">videodb://recentlyaddedmovies/</content> + <content target="movies" limit="10">videodb://recentlyaddedmovies/</content> </control> <control type="panel" id="2200"> <visible>Library.HasContent(TVShows) + Container(9010).HasFocus(2)</visible> diff --git a/addons/skin.estuary/addon.xml b/addons/skin.estuary/addon.xml index 646c593548..469c22945b 100644 --- a/addons/skin.estuary/addon.xml +++ b/addons/skin.estuary/addon.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> -<addon id="skin.estuary" version="2.0.14" name="Estuary" provider-name="phil65, Ichabod Fletchman"> +<addon id="skin.estuary" version="2.0.17" name="Estuary" provider-name="phil65, Ichabod Fletchman"> <requires> - <import addon="xbmc.gui" version="5.13.0"/> + <import addon="xbmc.gui" version="5.14.0"/> </requires> <extension point="xbmc.gui.skin" debugging="false"> <res width="1920" height="1440" aspect="4:3" default="false" folder="xml" /> diff --git a/addons/skin.estuary/fonts/NotoSans-Bold.ttf b/addons/skin.estuary/fonts/NotoSans-Bold.ttf Binary files differindex d20d3629c8..032031f746 100644 --- a/addons/skin.estuary/fonts/NotoSans-Bold.ttf +++ b/addons/skin.estuary/fonts/NotoSans-Bold.ttf diff --git a/addons/skin.estuary/fonts/NotoSans-Regular.ttf b/addons/skin.estuary/fonts/NotoSans-Regular.ttf Binary files differindex bc49be7008..0d7289b914 100644 --- a/addons/skin.estuary/fonts/NotoSans-Regular.ttf +++ b/addons/skin.estuary/fonts/NotoSans-Regular.ttf diff --git a/addons/skin.estuary/fonts/Roboto-Thin.ttf b/addons/skin.estuary/fonts/Roboto-Thin.ttf Binary files differindex d69555029c..8be28191ed 100644 --- a/addons/skin.estuary/fonts/Roboto-Thin.ttf +++ b/addons/skin.estuary/fonts/Roboto-Thin.ttf diff --git a/addons/skin.estuary/fonts/heebo_licence.txt b/addons/skin.estuary/fonts/heebo_licence.txt new file mode 100644 index 0000000000..8930273e3a --- /dev/null +++ b/addons/skin.estuary/fonts/heebo_licence.txt @@ -0,0 +1,93 @@ +Copyright 2014 The Heebo Project Authors. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/addons/skin.estuary/fonts/mardoto_license.txt b/addons/skin.estuary/fonts/mardoto_license.txt new file mode 100644 index 0000000000..277e097abd --- /dev/null +++ b/addons/skin.estuary/fonts/mardoto_license.txt @@ -0,0 +1,219 @@ + + Copyright 2011 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ------------------------------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/addons/skin.estuary/language/resource.language.bg_bg/strings.po b/addons/skin.estuary/language/resource.language.bg_bg/strings.po index 9fb9bb7285..8a179af184 100644 --- a/addons/skin.estuary/language/resource.language.bg_bg/strings.po +++ b/addons/skin.estuary/language/resource.language.bg_bg/strings.po @@ -571,3 +571,7 @@ msgstr "Име на профила" msgctxt "#31166" msgid "Profile avatar" msgstr "Снимка на профила" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Анимиран фон" diff --git a/addons/skin.estuary/language/resource.language.cs_cz/strings.po b/addons/skin.estuary/language/resource.language.cs_cz/strings.po index 9dcc7e851f..31d32581f7 100644 --- a/addons/skin.estuary/language/resource.language.cs_cz/strings.po +++ b/addons/skin.estuary/language/resource.language.cs_cz/strings.po @@ -126,7 +126,7 @@ msgstr "Časový posun" msgctxt "#31028" msgid "Show fanart" -msgstr "Zobrazit fanouškovské umění" +msgstr "Zobrazit fanart" msgctxt "#31029" msgid "Last logged in" @@ -571,3 +571,7 @@ msgstr "Název profilu" msgctxt "#31166" msgid "Profile avatar" msgstr "Avatar profilu" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animovat pozadí" diff --git a/addons/skin.estuary/language/resource.language.en_us/strings.po b/addons/skin.estuary/language/resource.language.en_us/strings.po index 319f14fe07..220b8ddcf4 100644 --- a/addons/skin.estuary/language/resource.language.en_us/strings.po +++ b/addons/skin.estuary/language/resource.language.en_us/strings.po @@ -571,3 +571,7 @@ msgstr "Profile name" msgctxt "#31166" msgid "Profile avatar" msgstr "Profile avatar" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animate background" diff --git a/addons/skin.estuary/language/resource.language.es_es/strings.po b/addons/skin.estuary/language/resource.language.es_es/strings.po index be8323dba4..cd739a9dd0 100644 --- a/addons/skin.estuary/language/resource.language.es_es/strings.po +++ b/addons/skin.estuary/language/resource.language.es_es/strings.po @@ -571,3 +571,7 @@ msgstr "Nombre de perfil" msgctxt "#31166" msgid "Profile avatar" msgstr "Avatar de perfil" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animar fondo" diff --git a/addons/skin.estuary/language/resource.language.es_mx/strings.po b/addons/skin.estuary/language/resource.language.es_mx/strings.po index c0ec3b6ce2..62dc602e25 100644 --- a/addons/skin.estuary/language/resource.language.es_mx/strings.po +++ b/addons/skin.estuary/language/resource.language.es_mx/strings.po @@ -48,6 +48,10 @@ msgctxt "#31007" msgid "Unwatched movies" msgstr "Películas sin mirar" +msgctxt "#31008" +msgid "Enable category widgets" +msgstr "Habilitar categoría de widgets" + msgctxt "#31009" msgid "Download icons" msgstr "Download iconos" @@ -108,6 +112,10 @@ msgctxt "#31023" msgid "Viewtype" msgstr "Tipo de vista" +msgctxt "#31024" +msgid "Choose rating to display for media items" +msgstr "Escoger rating para mostrar para archivos multimedia" + msgctxt "#31025" msgid "No favourites found. You can add any item from media views to this list by using the context menu." msgstr "No se han encontrado favoritos. Puede agregar cualquier elemento de las vistas de medios a esta lista mediante el menú contextual." @@ -436,6 +444,14 @@ msgctxt "#31131" msgid "Choose skin fanart pack" msgstr "Elegir paquete de skin fanart" +msgctxt "#31132" +msgid "Select Program" +msgstr "Seleccionar programa" + +msgctxt "#31133" +msgid "Select Resolution" +msgstr "Seleccionar Resolución" + msgctxt "#31134" msgid "Remaining" msgstr "Restante" @@ -536,6 +552,26 @@ msgctxt "#31161" msgid "Numeric pad" msgstr "Teclado numérico" +msgctxt "#31162" +msgid "Play your personal games or download one of the many game add-ons from the official repository." +msgstr "Jugar tu juego personal o descarga uno de los muchos complementos de juegos desde el repositorio oficial." + +msgctxt "#31163" +msgid "Show Fanart background" +msgstr "Mostrar Fanart de fondo" + +msgctxt "#31164" +msgid "Choose kind of profile identification" +msgstr "Escoja el tipo de identificación de perfil" + msgctxt "#31165" msgid "Profile name" msgstr "Nombre de perfil" + +msgctxt "#31166" +msgid "Profile avatar" +msgstr "Avatar del perfil" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animar fondo" diff --git a/addons/skin.estuary/language/resource.language.fi_fi/strings.po b/addons/skin.estuary/language/resource.language.fi_fi/strings.po index bbbc589d4f..fc26ec9097 100644 --- a/addons/skin.estuary/language/resource.language.fi_fi/strings.po +++ b/addons/skin.estuary/language/resource.language.fi_fi/strings.po @@ -571,3 +571,7 @@ msgstr "Profiilin nimi" msgctxt "#31166" msgid "Profile avatar" msgstr "Profiilin kuva" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animoitu taustakuva" diff --git a/addons/skin.estuary/language/resource.language.fr_ca/strings.po b/addons/skin.estuary/language/resource.language.fr_ca/strings.po index 2a00fb1351..e3089acf9d 100644 --- a/addons/skin.estuary/language/resource.language.fr_ca/strings.po +++ b/addons/skin.estuary/language/resource.language.fr_ca/strings.po @@ -22,7 +22,7 @@ msgstr "Lecture en cours" msgctxt "#31001" msgid "Search..." -msgstr "Recherche..." +msgstr "Recherche…" msgctxt "#31002" msgid "Show media fanart as background" @@ -50,7 +50,7 @@ msgstr "Films non visionnés" msgctxt "#31008" msgid "Enable category widgets" -msgstr "Activer les widgets de catégories" +msgstr "Activer les gadgets logiciel de catégories" msgctxt "#31009" msgid "Download icons" @@ -198,7 +198,7 @@ msgstr "Proposé" msgctxt "#31050" msgid "Press [B]OK[/B] to stop" -msgstr "Peser sur [B]OK[/B] pour arrêter" +msgstr "Peser sur [B]Valider[/B] pour arrêter" msgctxt "#31052" msgid "filtered" @@ -206,7 +206,7 @@ msgstr "filtré" msgctxt "#31053" msgid "Arial based" -msgstr "Basé sur Arial" +msgstr "D’après Arial" msgctxt "#31054" msgid "Press [B]Left[/B] to rewind, or [B]Right[/B] to fast-forward" @@ -338,7 +338,7 @@ msgstr "Mur" msgctxt "#31103" msgid "Enter text here..." -msgstr "Saisir du texte ici..." +msgstr "Saisir du texte ici…" msgctxt "#31104" msgid "Your library is currently empty. In order to populate it with your personal media, enter \"Files\" section, add a media source and configure it. After the source has been added and indexed you will be able to browse your library." @@ -422,7 +422,7 @@ msgstr "Peser sur haut pour les informations sur les acteurs" msgctxt "#31126" msgid "Press OK to read plot" -msgstr "Peser sur OK pour lire l’intrigue" +msgstr "Peser sur Valider pour lire l’intrigue" msgctxt "#31127" msgid "Show icons" @@ -458,7 +458,7 @@ msgstr "Restant" msgctxt "#31136" msgid "Click here to see latest changes..." -msgstr "Cliquer ici pour visualiser les derniers changements..." +msgstr "Cliquer ici pour visualiser les derniers changements…" msgctxt "#31137" msgid "PVR info" @@ -522,7 +522,7 @@ msgstr "Aucun addiciel de ce type n’est installé. Utilisez le navigateur d’ msgctxt "#31154" msgid "Press OK to switch between locations" -msgstr "Pesez sur OK pour basculer entre les emplacements" +msgstr "Peser sur Valider pour basculer entre les emplacements" msgctxt "#31155" msgid "No bookmarks created yet." @@ -562,7 +562,7 @@ msgstr "Afficher le fanart en arrière-plan" msgctxt "#31164" msgid "Choose kind of profile identification" -msgstr "Choisir le type d’identification du profile" +msgstr "Choisir le genre d’identification du profil" msgctxt "#31165" msgid "Profile name" @@ -570,4 +570,8 @@ msgstr "Nom du profil" msgctxt "#31166" msgid "Profile avatar" -msgstr "Avatar du profile" +msgstr "Avatar du profil" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animer l’arrière-plan" diff --git a/addons/skin.estuary/language/resource.language.fr_fr/strings.po b/addons/skin.estuary/language/resource.language.fr_fr/strings.po index e6b3fce1ff..269883f17d 100644 --- a/addons/skin.estuary/language/resource.language.fr_fr/strings.po +++ b/addons/skin.estuary/language/resource.language.fr_fr/strings.po @@ -571,3 +571,7 @@ msgstr "Nom du profil" msgctxt "#31166" msgid "Profile avatar" msgstr "Avatar du profil" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animer l'arrière-plan" diff --git a/addons/skin.estuary/language/resource.language.hr_hr/strings.po b/addons/skin.estuary/language/resource.language.hr_hr/strings.po index ed0e9ce8b0..59394cc832 100644 --- a/addons/skin.estuary/language/resource.language.hr_hr/strings.po +++ b/addons/skin.estuary/language/resource.language.hr_hr/strings.po @@ -448,6 +448,10 @@ msgctxt "#31132" msgid "Select Program" msgstr "Odaberi program" +msgctxt "#31133" +msgid "Select Resolution" +msgstr "Odaberi razlučivost" + msgctxt "#31134" msgid "Remaining" msgstr "Preostalo" @@ -556,6 +560,18 @@ msgctxt "#31163" msgid "Show Fanart background" msgstr "Prikaži poster obožavatelja kao pozadinu" +msgctxt "#31164" +msgid "Choose kind of profile identification" +msgstr "Odaberi način identifikacije profila" + msgctxt "#31165" msgid "Profile name" msgstr "Naziv profila" + +msgctxt "#31166" +msgid "Profile avatar" +msgstr "Avatar profila" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animiraj pozadinu" diff --git a/addons/skin.estuary/language/resource.language.hu_hu/strings.po b/addons/skin.estuary/language/resource.language.hu_hu/strings.po index 1e1f70cc2c..97cfe16e70 100644 --- a/addons/skin.estuary/language/resource.language.hu_hu/strings.po +++ b/addons/skin.estuary/language/resource.language.hu_hu/strings.po @@ -560,6 +560,18 @@ msgctxt "#31163" msgid "Show Fanart background" msgstr "Illusztráció háttér megjelenítése" +msgctxt "#31164" +msgid "Choose kind of profile identification" +msgstr "Válassza ki a profil azonosítását" + msgctxt "#31165" msgid "Profile name" msgstr "Profil neve" + +msgctxt "#31166" +msgid "Profile avatar" +msgstr "Profil avatar" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animált háttér" diff --git a/addons/skin.estuary/language/resource.language.is_is/strings.po b/addons/skin.estuary/language/resource.language.is_is/strings.po index 7a69ca2284..cda4cf3cf1 100644 --- a/addons/skin.estuary/language/resource.language.is_is/strings.po +++ b/addons/skin.estuary/language/resource.language.is_is/strings.po @@ -571,3 +571,7 @@ msgstr "Nafn notanda" msgctxt "#31166" msgid "Profile avatar" msgstr "Notandatáknmynd" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Lifandi bakgrunnur" diff --git a/addons/skin.estuary/language/resource.language.lt_lt/strings.po b/addons/skin.estuary/language/resource.language.lt_lt/strings.po index 156d539d8e..8616f04b36 100644 --- a/addons/skin.estuary/language/resource.language.lt_lt/strings.po +++ b/addons/skin.estuary/language/resource.language.lt_lt/strings.po @@ -571,3 +571,7 @@ msgstr "Profilio vardas" msgctxt "#31166" msgid "Profile avatar" msgstr "Profilio avataras" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animuoti foną" diff --git a/addons/skin.estuary/language/resource.language.nl_nl/strings.po b/addons/skin.estuary/language/resource.language.nl_nl/strings.po index b16737bdc2..25bebba6a0 100644 --- a/addons/skin.estuary/language/resource.language.nl_nl/strings.po +++ b/addons/skin.estuary/language/resource.language.nl_nl/strings.po @@ -178,7 +178,7 @@ msgstr "Afspeellijstopties" msgctxt "#31043" msgid "Set the type and add rules to create a smart playlist. These playlists are dynamic and include all media items from your database which apply to your chosen rules." -msgstr "Stel het type in en voeg regels toe om een slimme afspeellijst te maken. Deze afspeellijsten zijn dynamisch en bevatten alle media items vanuit uw database die voldoen aan uw gekozen regels." +msgstr "Stel het type in en voeg regels toe om een slimme afspeellijst te maken. Deze afspeellijsten zijn dynamisch en bevatten alle media-items vanuit uw database die voldoen aan uw gekozen regels." msgctxt "#31044" msgid "Add group" @@ -571,3 +571,7 @@ msgstr "Profielnaam" msgctxt "#31166" msgid "Profile avatar" msgstr "Profielafbeelding" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Achtergrondanimatie" diff --git a/addons/skin.estuary/language/resource.language.sv_se/strings.po b/addons/skin.estuary/language/resource.language.sv_se/strings.po index 9fff27134a..0b917183d6 100644 --- a/addons/skin.estuary/language/resource.language.sv_se/strings.po +++ b/addons/skin.estuary/language/resource.language.sv_se/strings.po @@ -42,7 +42,7 @@ msgstr "Se i 2D" msgctxt "#31006" msgid "Random movies" -msgstr "Slumpvis urvalda filmer" +msgstr "Slumpvis utvalda filmer" msgctxt "#31007" msgid "Unwatched movies" @@ -66,11 +66,11 @@ msgstr "Mest spelade album" msgctxt "#31012" msgid "Random albums" -msgstr "Slumpvis urvalda album" +msgstr "Slumpvis utvalda album" msgctxt "#31013" msgid "Random artists" -msgstr "Slumpvis urvalda artister" +msgstr "Slumpvis utvalda artister" msgctxt "#31014" msgid "Unplayed albums" @@ -514,7 +514,7 @@ msgstr "Osedda musikvideor" msgctxt "#31152" msgid "Random music videos" -msgstr "Slumpvis urvalda musikvideor" +msgstr "Slumpvis utvalda musikvideor" msgctxt "#31153" msgid "You do not have any add-ons of this type installed. Enter the add-on browser to download add-ons created by our community." @@ -571,3 +571,7 @@ msgstr "Profilnamn" msgctxt "#31166" msgid "Profile avatar" msgstr "Profil avatar" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Animera bakgrund" diff --git a/addons/skin.estuary/language/resource.language.tr_tr/strings.po b/addons/skin.estuary/language/resource.language.tr_tr/strings.po index a94f1ae3f3..3a1ed339b6 100644 --- a/addons/skin.estuary/language/resource.language.tr_tr/strings.po +++ b/addons/skin.estuary/language/resource.language.tr_tr/strings.po @@ -448,6 +448,10 @@ msgctxt "#31132" msgid "Select Program" msgstr "Programı Seçiniz" +msgctxt "#31133" +msgid "Select Resolution" +msgstr "Çözünürlük seç" + msgctxt "#31134" msgid "Remaining" msgstr "Kalan" @@ -559,3 +563,11 @@ msgstr "Arka plan fanartını göster" msgctxt "#31165" msgid "Profile name" msgstr "Profil adı" + +msgctxt "#31166" +msgid "Profile avatar" +msgstr "Profil avatarı" + +msgctxt "#31167" +msgid "Animate background" +msgstr "Arka plana animasyon ekle" diff --git a/addons/skin.estuary/language/resource.language.zh_cn/strings.po b/addons/skin.estuary/language/resource.language.zh_cn/strings.po index ca6694f541..ac6b6c5efb 100644 --- a/addons/skin.estuary/language/resource.language.zh_cn/strings.po +++ b/addons/skin.estuary/language/resource.language.zh_cn/strings.po @@ -571,3 +571,7 @@ msgstr "用户配置名称" msgctxt "#31166" msgid "Profile avatar" msgstr "用户配置头像" + +msgctxt "#31167" +msgid "Animate background" +msgstr "动态背景" diff --git a/addons/skin.estuary/media/OverlaySpoiler.png b/addons/skin.estuary/media/OverlaySpoiler.png Binary files differnew file mode 100644 index 0000000000..f67af16bff --- /dev/null +++ b/addons/skin.estuary/media/OverlaySpoiler.png diff --git a/addons/skin.estuary/xml/AddonBrowser.xml b/addons/skin.estuary/xml/AddonBrowser.xml index dd211bcc78..8e243175b2 100644 --- a/addons/skin.estuary/xml/AddonBrowser.xml +++ b/addons/skin.estuary/xml/AddonBrowser.xml @@ -17,7 +17,9 @@ <visible>Control.IsVisible(55)</visible> <visible>Container.Content(addons) | Container.Content()</visible> <include>Visible_Left</include> - <include>ListThumbInfoPanel</include> + <include content="ListThumbInfoPanel"> + <param name="fallback_image" value="DefaultAddon.png" /> + </include> </control> <include content="TopBar"> <param name="breadcrumbs_label" value="$LOCALIZE[24001]" /> diff --git a/addons/skin.estuary/xml/EventLog.xml b/addons/skin.estuary/xml/EventLog.xml index 5a8e6b3f51..20294c9ab9 100644 --- a/addons/skin.estuary/xml/EventLog.xml +++ b/addons/skin.estuary/xml/EventLog.xml @@ -48,7 +48,7 @@ <left>160</left> <top>45</top> <right>20</right> - <height>60</height> + <height>80</height> <aligny>top</aligny> <textcolor>grey</textcolor> <label>$INFO[ListItem.Property(Event.Description)]</label> @@ -95,7 +95,7 @@ <left>160</left> <top>45</top> <right>20</right> - <height>60</height> + <height>80</height> <aligny>top</aligny> <label>$INFO[ListItem.Property(Event.Description)]</label> </control> diff --git a/addons/skin.estuary/xml/Home.xml b/addons/skin.estuary/xml/Home.xml index 3867952497..164b02aa82 100644 --- a/addons/skin.estuary/xml/Home.xml +++ b/addons/skin.estuary/xml/Home.xml @@ -791,6 +791,9 @@ <param name="visible" value="true"/> <param name="button2_label" value="$LOCALIZE[13391]"/> <param name="button2_onclick" value="EjectTray()"/> + <param name="button3_label" value="$LOCALIZE[600]"/> + <param name="button3_onclick" value="RipCD"/> + <param name="visible_3" value="String.IsEqual(System.DVDLabel,Audio-CD)"/> </include> </control> </control> diff --git a/addons/skin.estuary/xml/Includes_Home.xml b/addons/skin.estuary/xml/Includes_Home.xml index d8d50af843..d841926582 100644 --- a/addons/skin.estuary/xml/Includes_Home.xml +++ b/addons/skin.estuary/xml/Includes_Home.xml @@ -112,6 +112,7 @@ <param name="visible">true</param> <param name="visible_1">true</param> <param name="visible_2">true</param> + <param name="visible_3">false</param> <param name="button2_label">$LOCALIZE[31116]</param> <param name="button2_onclick">true</param> <definition> @@ -161,6 +162,18 @@ <texturenofocus border="40">buttons/dialogbutton-nofo.png</texturenofocus> <visible>$PARAM[visible_2]</visible> </control> + <control type="button" id="$PARAM[button_id]569"> + <width>auto</width> + <height>110</height> + <label>$PARAM[button3_label]</label> + <textoffsetx>40</textoffsetx> + <onclick>$PARAM[button3_onclick]</onclick> + <onclick>SetFocus(9000)</onclick> + <align>center</align> + <texturefocus border="23" colordiffuse="button_focus">buttons/dialogbutton-fo.png</texturefocus> + <texturenofocus border="40">buttons/dialogbutton-nofo.png</texturenofocus> + <visible>$PARAM[visible_3]</visible> + </control> </control> </control> </control> diff --git a/addons/skin.estuary/xml/MusicVisualisation.xml b/addons/skin.estuary/xml/MusicVisualisation.xml index 0df345c39f..3bbab7da63 100644 --- a/addons/skin.estuary/xml/MusicVisualisation.xml +++ b/addons/skin.estuary/xml/MusicVisualisation.xml @@ -32,7 +32,7 @@ </control> </control> <control type="group"> - <animation effect="fade" start="100" end="30" time="0" condition="!Skin.HasSetting(hide_background_fanart) + [!String.IsEmpty(Player.Art(fanart)) | Visualisation.Enabled | System.HasAddon(script.artistslideshow)]">Conditional</animation> + <animation effect="fade" start="100" end="30" time="0" condition="[!Skin.HasSetting(hide_background_fanart) + [!String.IsEmpty(Player.Art(fanart)) | System.HasAddon(script.artistslideshow)]] | Visualisation.Enabled">Conditional</animation> <include>ColoredBackgroundImages</include> </control> <control type="group"> diff --git a/addons/skin.estuary/xml/MyVideoNav.xml b/addons/skin.estuary/xml/MyVideoNav.xml index c910846d6b..ced8be1abd 100644 --- a/addons/skin.estuary/xml/MyVideoNav.xml +++ b/addons/skin.estuary/xml/MyVideoNav.xml @@ -48,7 +48,7 @@ <top>240</top> <width>525</width> <bottom>100</bottom> - <visible>!ListItem.IsCollection</visible> + <visible>![ListItem.IsCollection + String.IsEmpty(ListItem.Plot)]</visible> <label>$INFO[ListItem.Tagline,[I],[/I][CR][CR]]$INFO[ListItem.Plot][CR][CR]</label> <autoscroll delay="10000" time="3000" repeat="10000">Skin.HasSetting(autoscroll)</autoscroll> </control> diff --git a/addons/skin.estuary/xml/View_50_List.xml b/addons/skin.estuary/xml/View_50_List.xml index d5d0f05d65..c6d5d7a9e3 100644 --- a/addons/skin.estuary/xml/View_50_List.xml +++ b/addons/skin.estuary/xml/View_50_List.xml @@ -160,6 +160,7 @@ </definition> </include> <include name="ListThumbInfoPanel"> + <param name="fallback_image"></param> <param name="flip_bg">false</param> <definition> <control type="group"> @@ -175,7 +176,7 @@ <height>470</height> <aspectratio aligny="bottom">keep</aspectratio> <fadetime>300</fadetime> - <texture background="true">$VAR[IconWallThumbVar]</texture> + <texture fallback="$PARAM[fallback_image]" background="true">$VAR[IconWallThumbVar]</texture> <visible>!String.IsEqual(ListItem.DbType,episode)</visible> </control> <control type="image"> diff --git a/addons/skin.estuary/xml/View_51_Poster.xml b/addons/skin.estuary/xml/View_51_Poster.xml index e8edd19aa9..9fe79775d8 100644 --- a/addons/skin.estuary/xml/View_51_Poster.xml +++ b/addons/skin.estuary/xml/View_51_Poster.xml @@ -112,7 +112,7 @@ <autoscroll time="3000" delay="7000" repeat="5000">!System.HasActiveModalDialog + Skin.HasSetting(AutoScroll)</autoscroll> <label>$INFO[ListItem.Plot]</label> <shadowcolor>text_shadow</shadowcolor> - <visible>!ListItem.IsCollection</visible> + <visible>![ListItem.IsCollection + String.IsEmpty(ListItem.Plot)]</visible> </control> </control> </control> diff --git a/addons/xbmc.gui/addon.xml b/addons/xbmc.gui/addon.xml index c2e3a93a68..1d0f7bd7a6 100644 --- a/addons/xbmc.gui/addon.xml +++ b/addons/xbmc.gui/addon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<addon id="xbmc.gui" version="5.13.0" provider-name="Team Kodi"> +<addon id="xbmc.gui" version="5.14.0" provider-name="Team Kodi"> <backwards-compatibility abi="5.13.0"/> <requires> <import addon="xbmc.core" version="0.1.0"/> diff --git a/cmake/installdata/common/addons.txt b/cmake/installdata/common/addons.txt index c0ffb72b4b..13dbab39ec 100644 --- a/cmake/installdata/common/addons.txt +++ b/cmake/installdata/common/addons.txt @@ -40,5 +40,5 @@ addons/metadata.common.musicbrainz.org/* addons/metadata.common.theaudiodb.com/* addons/metadata.common.themoviedb.org/* addons/metadata.themoviedb.org/* -addons/metadata.tvdb.com/* +addons/metadata.tvshows.themoviedb.org/* addons/kodi.vfs/* diff --git a/cmake/modules/FindFreeType.cmake b/cmake/modules/FindFreeType.cmake index 8a3955552d..771819e902 100644 --- a/cmake/modules/FindFreeType.cmake +++ b/cmake/modules/FindFreeType.cmake @@ -19,7 +19,8 @@ endif() find_path(FREETYPE_INCLUDE_DIR NAMES freetype/freetype.h freetype.h PATHS ${PC_FREETYPE_INCLUDEDIR} - ${PC_FREETYPE_INCLUDE_DIRS}) + ${PC_FREETYPE_INCLUDE_DIRS} + PATH_SUFFIXES freetype2) find_library(FREETYPE_LIBRARY NAMES freetype freetype246MT PATHS ${PC_FREETYPE_LIBDIR}) diff --git a/cmake/modules/FindJsonSchemaBuilder.cmake b/cmake/modules/FindJsonSchemaBuilder.cmake index 14aa2f5113..094c2faaf8 100644 --- a/cmake/modules/FindJsonSchemaBuilder.cmake +++ b/cmake/modules/FindJsonSchemaBuilder.cmake @@ -3,24 +3,40 @@ # --------------------- # Finds the JsonSchemaBuilder # +# If WITH_JSONSCHEMABUILDER is defined and points to a directory, +# this path will be used to search for the JsonSchemaBuilder binary +# +# # This will define the following (imported) targets:: # # JsonSchemaBuilder::JsonSchemaBuilder - The JsonSchemaBuilder executable if(NOT TARGET JsonSchemaBuilder::JsonSchemaBuilder) - if(KODI_DEPENDSBUILD OR CMAKE_CROSSCOMPILING) + if(KODI_DEPENDSBUILD) + add_executable(JsonSchemaBuilder::JsonSchemaBuilder IMPORTED GLOBAL) + set_target_properties(JsonSchemaBuilder::JsonSchemaBuilder PROPERTIES + IMPORTED_LOCATION "${NATIVEPREFIX}/bin/JsonSchemaBuilder") + elseif(CORE_SYSTEM_NAME STREQUAL windowsstore) add_executable(JsonSchemaBuilder::JsonSchemaBuilder IMPORTED GLOBAL) - if(CORE_SYSTEM_NAME STREQUAL windows OR CORE_SYSTEM_NAME STREQUAL windowsstore) - set_target_properties(JsonSchemaBuilder::JsonSchemaBuilder PROPERTIES - IMPORTED_LOCATION "${DEPENDENCIES_DIR}/bin/json-rpc/JsonSchemaBuilder") + set_target_properties(JsonSchemaBuilder::JsonSchemaBuilder PROPERTIES + IMPORTED_LOCATION "${DEPENDENCIES_DIR}/bin/json-rpc/JsonSchemaBuilder") + else() + if(WITH_JSONSCHEMABUILDER) + get_filename_component(_jsbpath ${WITH_JSONSCHEMABUILDER} ABSOLUTE) + find_program(JSONSCHEMABUILDER_EXECUTABLE JsonSchemaBuilder PATHS ${_jsbpath}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(JsonSchemaBuilder DEFAULT_MSG JSONSCHEMABUILDER_EXECUTABLE) + if(JSONSCHEMABUILDER_FOUND) + add_executable(JsonSchemaBuilder::JsonSchemaBuilder IMPORTED GLOBAL) + set_target_properties(JsonSchemaBuilder::JsonSchemaBuilder PROPERTIES + IMPORTED_LOCATION "${JSONSCHEMABUILDER_EXECUTABLE}") + endif() + mark_as_advanced(JSONSCHEMABUILDER) else() - set_target_properties(JsonSchemaBuilder::JsonSchemaBuilder PROPERTIES - IMPORTED_LOCATION "${NATIVEPREFIX}/bin/JsonSchemaBuilder") + add_subdirectory(${CMAKE_SOURCE_DIR}/tools/depends/native/JsonSchemaBuilder build/jsonschemabuilder) + add_executable(JsonSchemaBuilder::JsonSchemaBuilder ALIAS JsonSchemaBuilder) + set_target_properties(JsonSchemaBuilder PROPERTIES FOLDER Tools) endif() - set_target_properties(JsonSchemaBuilder::JsonSchemaBuilder PROPERTIES FOLDER Tools) - else() - add_subdirectory(${CMAKE_SOURCE_DIR}/tools/depends/native/JsonSchemaBuilder build/jsonschemabuilder) - add_executable(JsonSchemaBuilder::JsonSchemaBuilder ALIAS JsonSchemaBuilder) - set_target_properties(JsonSchemaBuilder PROPERTIES FOLDER Tools) endif() endif() diff --git a/cmake/scripts/common/GenerateVersionedFiles.cmake b/cmake/scripts/common/GenerateVersionedFiles.cmake index 011f4956f1..1d324db9c5 100644 --- a/cmake/scripts/common/GenerateVersionedFiles.cmake +++ b/cmake/scripts/common/GenerateVersionedFiles.cmake @@ -15,7 +15,7 @@ endfunction() file(GLOB ADDON_XML_IN_FILE ${CORE_SOURCE_DIR}/addons/*/addon.xml.in) # remove 'xbmc.json', will be created from 'xbmc/interfaces/json-rpc/schema/CMakeLists.txt' -list(REMOVE_ITEM ADDON_XML_IN_FILE xbmc.json) +list(REMOVE_ITEM ADDON_XML_IN_FILE ${CORE_SOURCE_DIR}/addons/xbmc.json/addon.xml.in) foreach(loop_var ${ADDON_XML_IN_FILE}) list(GET loop_var 0 xml_name) diff --git a/cmake/scripts/common/Macros.cmake b/cmake/scripts/common/Macros.cmake index cf1f241b3e..eefd7c8803 100644 --- a/cmake/scripts/common/Macros.cmake +++ b/cmake/scripts/common/Macros.cmake @@ -623,6 +623,8 @@ function(core_find_git_rev stamp) # allow manual setting GIT_VERSION if(GIT_VERSION) set(${stamp} ${GIT_VERSION} PARENT_SCOPE) + string(TIMESTAMP APP_BUILD_DATE "%Y%m%d" UTC) + set(APP_BUILD_DATE ${APP_BUILD_DATE} PARENT_SCOPE) else() find_package(Git) if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git) @@ -653,12 +655,18 @@ function(core_find_git_rev stamp) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) string(REPLACE "\"" "" DATE ${DATE}) string(REPLACE "-" "" DATE ${DATE}) + + # build date + string(TIMESTAMP APP_BUILD_DATE "%Y%m%d" UTC) + set(APP_BUILD_DATE ${APP_BUILD_DATE} PARENT_SCOPE) else() if(EXISTS ${CMAKE_SOURCE_DIR}/BUILDDATE) file(STRINGS ${CMAKE_SOURCE_DIR}/BUILDDATE DATE LIMIT_INPUT 8) else() string(TIMESTAMP DATE "%Y%m%d" UTC) endif() + set(APP_BUILD_DATE ${DATE} PARENT_SCOPE) + if(EXISTS ${CMAKE_SOURCE_DIR}/VERSION) file(STRINGS ${CMAKE_SOURCE_DIR}/VERSION HASH LIMIT_INPUT 16) else() @@ -777,6 +785,12 @@ endmacro() # find all folders containing addon.xml.in and used to define # ADDON_XML_OUTPUTS, ADDON_XML_DEPENDS and ADDON_INSTALL_DATA macro(find_addon_xml_in_files) + set(filter ${ARGV0}) + + if(filter AND VERBOSE) + message(STATUS "find_addon_xml_in_files: filtering ${filter}") + endif() + file(GLOB ADDON_XML_IN_FILE ${CMAKE_SOURCE_DIR}/addons/*/addon.xml.in) foreach(loop_var ${ADDON_XML_IN_FILE}) list(GET loop_var 0 xml_name) @@ -785,7 +799,9 @@ macro(find_addon_xml_in_files) string(REPLACE "${CORE_SOURCE_DIR}/" "" xml_name ${xml_name}) list(APPEND ADDON_XML_DEPENDS "${CORE_SOURCE_DIR}/${xml_name}/addon.xml.in") - list(APPEND ADDON_XML_OUTPUTS "${CMAKE_BINARY_DIR}/${xml_name}/addon.xml") + if(filter AND NOT xml_name MATCHES ${filter}) + list(APPEND ADDON_XML_OUTPUTS "${CMAKE_BINARY_DIR}/${xml_name}/addon.xml") + endif() # Read content of add-on folder to have on install file(GLOB ADDON_FILES "${CORE_SOURCE_DIR}/${xml_name}/*") diff --git a/cmake/scripts/ios/Install.cmake b/cmake/scripts/ios/Install.cmake index f32c73f56f..7d8de72b9c 100644 --- a/cmake/scripts/ios/Install.cmake +++ b/cmake/scripts/ios/Install.cmake @@ -1,11 +1,26 @@ # IOS packaging -set(BUNDLE_RESOURCES ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/Default-568h@2x.png - ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/Default-667h@2x.png - ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/Default-736h@3x.png - ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/Default-Landscape-736h@3x.png - ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/Default-812h@3x.png - ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/Default-Landscape-812h@3x.png +set(BUNDLE_RESOURCES ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1100-Landscape-2436h@3x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1100-Portrait-2436h@3x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-1792h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2224h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2224h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2388h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2388h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2688h@3x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-1792h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2688h@3x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-568h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-700-568h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-700-Landscape@2x~ipad.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-700-Portrait@2x~ipad.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-700@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-800-667h@2x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-800-Landscape-736h@3x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-800-Portrait-736h@3x.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-Landscape@2x~ipad.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage-Portrait@2x~ipad.png + ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchImage@2x.png ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon29x29.png ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon29x29@2x.png ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon40x40.png diff --git a/docs/README.FreeBSD.md b/docs/README.FreeBSD.md index 7574f23a31..2a35a4db30 100644 --- a/docs/README.FreeBSD.md +++ b/docs/README.FreeBSD.md @@ -74,7 +74,7 @@ If you get a `package not found` type of message with the below command, remove Install build dependencies: ``` -sudo pkg install autoconf automake avahi-app binutils cmake curl dbus doxygen dri2proto dri3proto e2fsprogs-libuuid enca encodings flac flatbuffers font-util fontconfig freetype2 fribidi gawk gettext-tools giflib git glew glproto gmake gmp gnutls gperf gstreamer1-vaapi hal inputproto jpeg-turbo libaacs libass libbdplus libbluray libcapn libcdio libcec libedit libfmt libgcrypt libgpg-error libidn libinotify libmicrohttpd libnfs libogg libplist librtmp libtool libudev-devd libva libvdpau libvorbis libxslt lirc lzo2 m4 mesa-libs mysql57-client nasm openjdk8 p8-platform pkgconf python2 rapidjson samba46 shairplay sndio sqlite3 swig30 taglib tiff tinyxml xf86-input-keyboard xf86-input-mouse xf86vidmodeproto xorg-server xrandr zip +sudo pkg install autoconf automake avahi-app binutils cmake curl dbus doxygen e2fsprogs-libuuid enca encodings flac flatbuffers font-util fontconfig freetype2 fribidi gawk gettext-tools giflib git glew gmake gmp gnutls gperf gstreamer1-vaapi hal jpeg-turbo libaacs libass libbdplus libbluray libcapn libcdio libcec libedit libfmt libgcrypt libgpg-error libidn libinotify libmicrohttpd libnfs libogg libplist librtmp libtool libudev-devd libva libvdpau libvorbis libxslt lirc lzo2 m4 mesa-libs mysql57-client nasm openjdk8 p8-platform pkgconf python2 rapidjson samba46 shairplay sndio sqlite3 swig30 taglib tiff tinyxml xf86-input-keyboard xf86-input-mouse xorg-proto xorg-server xrandr zip ``` **WARNING:** Make sure you copy paste the entire line or you might receive an error or miss a few dependencies. diff --git a/docs/doxygen/Doxyfile.doxy b/docs/doxygen/Doxyfile.doxy index 514e942d6d..9115f3a19a 100644 --- a/docs/doxygen/Doxyfile.doxy +++ b/docs/doxygen/Doxyfile.doxy @@ -238,18 +238,18 @@ TAB_SIZE = 2 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = "table_start=<table width= 100% style= border bgcolor= 576f9f border= 0>" \ +ALIASES = "table_start=<table width=\"100%\" style=\"border\" bgcolor=\"576f9f\" border=\"0\">" \ "table_end=</table>" \ "table_h2_l{2}=<tr bgcolor= 576f9f><th width= 40% align=left>\1</th><th width= 60% align=left>\2</th></tr>" \ "table_row2_l{2}=<tr bgcolor=white><td width= 40% align=left>\1</td><td width= 60% align=left>\2</td></tr>" \ - "table_h3{3}=<tr bgcolor= 576f9f><th width= 30% align=left>\1</th><th width= 10% align=left>\2</th><th width= 60% align=left>\3</th></tr>" \ - "table_row3{3}=<tr bgcolor=white><td width= 30% align=left>\1</td><td width= 10% align=left>\2</td><td width= 60% align=left>\3</td></tr>" \ + "table_h3{3}=<tr bgcolor=576f9f><th width=30% align=left valign=middle><b>\1</b></th><th width=10% align=left valign=middle><b>\2</b></th><th width=60% align=left valign=middle><span><b>\3</b></span></th></tr>" \ + "table_row3{3}=\htmlonly<tr bgcolor=white><td width= 30% align=left>\endhtmlonly\1\htmlonly</td><td width= 10% align=left>\endhtmlonly\2\htmlonly</td><td width= 60% align=left>\endhtmlonly\3\htmlonly</td></tr>\endhtmlonly" \ "python_func{1}=\htmlonly <h4><code><span style=\"font-style: italic;\">Function: </span><span style=\"font-style: bold;\"><font color=31363b><big>\1</big></font></span></code></h4> \endhtmlonly" \ "python_func_with_rev{2}=\htmlonly <h4><code><span style=\"font-style: italic;\">Function: </span><span style=\"font-style: bold;\"><font color=31363b><big>\1</big></font></span></code><span style="float:right;"><small>\2</small></span></h4> \endhtmlonly" \ "python_class{1}=\htmlonly <h4><code><span style=\"font-style: italic;\">Class: </span><span style=\"font-style: bold;\"><font color=31363b><big>\1</big></font></span></code></h4> \endhtmlonly" \ "python_class_with_rev{2}=\htmlonly <h4><code><span style=\"font-style: italic;\">Class: </span><span style=\"font-style: bold;\"><font color=31363b><big>\1</big></font></span></code><span style="float:right;"><small>\2</small></span></h4> \endhtmlonly" \ "doc_header{1}=\htmlonly <h3><span style=\"text-decoration: underline;\"><span style=\"font-style: italic;\"><span style=\"color: rgb(102, 102, 102);\">\1</span></span></span></h3> \endhtmlonly" \ - "python_removed_function{3}=\htmlonly <dl class=\"reflist\"><dt>Member <a class="el" href=\"\2\">\1</a> (...)</dt><dd>\3</dd></dl>\endhtmlonly" \ + "python_removed_function{3}=\htmlonly <dl class=\"reflist\"><dt>Member <a class=\"el\" href=\"\2\">\1</a> (...)</dt><dd>\3</dd></dl>\endhtmlonly" \ "python_v12=\xrefitem python_v12 \"v12 Python API changes\" \"\"" \ "python_v13=\xrefitem python_v13 \"v13 Python API changes\" \"\"" \ "python_v14=\xrefitem python_v14 \"v14 Python API changes\" \"\"" \ diff --git a/project/Win32BuildSetup/genNsisInstaller.nsi b/project/Win32BuildSetup/genNsisInstaller.nsi index bba7eea574..67abeeac82 100644 --- a/project/Win32BuildSetup/genNsisInstaller.nsi +++ b/project/Win32BuildSetup/genNsisInstaller.nsi @@ -326,14 +326,14 @@ SectionEnd ;vs redist installer Section SectionGroup "Microsoft Visual C++ packages" SEC_VCREDIST -Section "VS2015 C++ re-distributable Package (${TARGET_ARCHITECTURE})" SEC_VCREDIST1 -DetailPrint "Running VS2015 re-distributable setup..." +Section "VS2017 C++ re-distributable Package (${TARGET_ARCHITECTURE})" SEC_VCREDIST1 +DetailPrint "Running VS2017 re-distributable setup..." SectionIn 1 2 #section is in install type Full - SetOutPath "$TEMP\vc2015" - File "${app_root}\..\..\BuildDependencies\downloads\vcredist\2015\vcredist_${TARGET_ARCHITECTURE}.exe" - ExecWait '"$TEMP\vc2015\vcredist_${TARGET_ARCHITECTURE}.exe" /install /quiet /norestart' $VSRedistSetupError - RMDir /r "$TEMP\vc2015" - DetailPrint "Finished VS2015 re-distributable setup" + SetOutPath "$TEMP\vc2017" + File "${app_root}\..\..\BuildDependencies\downloads\vcredist\2017\vcredist_${TARGET_ARCHITECTURE}.exe" + ExecWait '"$TEMP\vc2017\vcredist_${TARGET_ARCHITECTURE}.exe" /install /quiet /norestart' $VSRedistSetupError + RMDir /r "$TEMP\vc2017" + DetailPrint "Finished VS2017 re-distributable setup" SetOutPath "$INSTDIR" SectionEnd diff --git a/project/Win32BuildSetup/getdeploydependencies.bat b/project/Win32BuildSetup/getdeploydependencies.bat index d4a69de341..2054984505 100644 --- a/project/Win32BuildSetup/getdeploydependencies.bat +++ b/project/Win32BuildSetup/getdeploydependencies.bat @@ -8,11 +8,11 @@ echo Downloading from mirror %KODI_MIRROR% :: Following commands expect this script's parent directory to be the current directory, so make sure that's so PUSHD %~dp0 -if not exist ..\BuildDependencies\downloads\vcredist\2015 mkdir ..\BuildDependencies\downloads\vcredist\2015 +if not exist ..\BuildDependencies\downloads\vcredist\2017 mkdir ..\BuildDependencies\downloads\vcredist\2017 -if not exist ..\BuildDependencies\downloads\vcredist\2015\vcredist_%TARGET_ARCHITECTURE%.exe ( - echo Downloading vc140 redist... - ..\BuildDependencies\bin\wget --tries=5 --retry-connrefused --waitretry=2 -nv -O ..\BuildDependencies\downloads\vcredist\2015\vcredist_%TARGET_ARCHITECTURE%.exe %KODI_MIRROR%/build-deps/win32/vcredist/2015/vcredist_%TARGET_ARCHITECTURE%.exe +if not exist ..\BuildDependencies\downloads\vcredist\2017\vcredist_%TARGET_ARCHITECTURE%.exe ( + echo Downloading vc141 redist... + ..\BuildDependencies\bin\wget --tries=5 --retry-connrefused --waitretry=2 -nv -O ..\BuildDependencies\downloads\vcredist\2017\vcredist_%TARGET_ARCHITECTURE%.exe %KODI_MIRROR%/build-deps/win32/vcredist/2017/vcredist_%TARGET_ARCHITECTURE%.exe ) :: Restore the previous current directory POPD diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml index f0edcddbc1..aeb0cc6820 100644 --- a/system/addon-manifest.xml +++ b/system/addon-manifest.xml @@ -31,7 +31,7 @@ <addon>metadata.common.themoviedb.org</addon> <addon>metadata.local</addon> <addon>metadata.themoviedb.org</addon> - <addon>metadata.tvdb.com</addon> + <addon>metadata.tvshows.themoviedb.org</addon> <addon>repository.xbmc.org</addon> <addon>resource.images.weathericons.default</addon> <addon>resource.language.en_gb</addon> diff --git a/system/keymaps/joystick.xml b/system/keymaps/joystick.xml index b390f6c762..c4b50cd482 100644 --- a/system/keymaps/joystick.xml +++ b/system/keymaps/joystick.xml @@ -169,22 +169,38 @@ </FullscreenGame> <FullscreenLiveTV> <joystick profile="game.controller.default"> + <x>OSD</x> + <back>OSD</back> <guide>OSD</guide> + <start>Info</start> <up>ChannelUp</up> <down>ChannelDown</down> <left>StepBack</left> <right>StepForward</right> </joystick> </FullscreenLiveTV> + <TVGuide> + <joystick profile="game.controller.default"> + <back>Menu</back> + </joystick> + </TVGuide> <FullscreenRadio> <joystick profile="game.controller.default"> + <x>OSD</x> + <back>OSD</back> <guide>OSD</guide> + <start>Info</start> <up>ChannelUp</up> <down>ChannelDown</down> <left>StepBack</left> <right>StepForward</right> </joystick> </FullscreenRadio> + <RadioGuide> + <joystick profile="game.controller.default"> + <back>Menu</back> + </joystick> + </RadioGuide> <FullscreenInfo> <joystick profile="game.controller.default"> <b>Close</b> diff --git a/system/settings/android.xml b/system/settings/android.xml index 53d2c10650..f0a5e8f914 100644 --- a/system/settings/android.xml +++ b/system/settings/android.xml @@ -19,7 +19,7 @@ <options> <option label="37026">0</option> <!-- auto --> <option label="37028">720</option> <!-- 720 --> - <option label="37027">1080</option> <!-- 900 --> + <option label="37046">1080</option> <!-- 1080 --> <option label="37030">9999</option> <!-- unlimited --> </options> </constraints> diff --git a/system/settings/settings.xml b/system/settings/settings.xml index d83bc8d393..f87ac4b6f4 100755 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml @@ -968,10 +968,21 @@ <default>true</default> <control type="toggle" /> </setting> - <setting id="videolibrary.showunwatchedplots" type="boolean" label="20369" help="36141"> + <setting id="videolibrary.showunwatchedplots" type="list[integer]" label="20369" help="36141"> <level>0</level> - <default>true</default> - <control type="toggle" /> + <default>0,1,2</default> <!-- Show plot for both --> + <constraints> + <options> + <option label="39115">0</option> <!-- Show plot for unwatched movies only --> + <option label="39116">1</option> <!-- Show plot for unwatched tv show episodes only --> + <option label="39114">2</option> <!-- Show thumb for unwatched tv show episodes only --> + </options> + <delimiter>,</delimiter> + </constraints> + <control type="list" format="string"> + <multiselect>true</multiselect> + <hidevalue>false</hidevalue> + </control> </setting> <setting id="videolibrary.groupmoviesets" type="boolean" label="20458" help="36145"> <level>1</level> @@ -1200,7 +1211,7 @@ </setting> <setting id="scrapers.tvshowsdefault" type="addon" label="21414" help="36199"> <level>4</level> - <default>metadata.tvdb.com</default> + <default>metadata.tvshows.themoviedb.org</default> <constraints> <addontype>xbmc.metadata.scraper.tvshows</addontype> </constraints> @@ -1270,14 +1281,7 @@ </group> </category> <category id="pvrmenu" label="19181" help="36211"> - <group id="1" label="128"> - <setting id="pvrmenu.usesimpletimeshiftosd" type="boolean" label="19303" help="36235"> - <level>2</level> - <default>true</default> - <control type="toggle" /> - </setting> - </group> - <group id="2" label="14301"> + <group id="1" label="14301"> <setting id="pvrmenu.displaychannelinfo" type="integer" label="19178" help="36212"> <level>2</level> <default>5</default> @@ -1291,7 +1295,7 @@ </control> </setting> </group> - <group id="3" label="14302"> + <group id="2" label="14302"> <setting id="pvrmenu.iconpath" type="path" label="19018" help="36216"> <level>2</level> <default></default> diff --git a/tools/android/packaging/xbmc/src/Main.java.in b/tools/android/packaging/xbmc/src/Main.java.in index 214badd4d2..d5e6c88381 100644 --- a/tools/android/packaging/xbmc/src/Main.java.in +++ b/tools/android/packaging/xbmc/src/Main.java.in @@ -17,6 +17,7 @@ import android.view.View; import android.graphics.Color; import android.graphics.PixelFormat; import android.os.Handler; +import android.os.HandlerThread; import android.widget.RelativeLayout; import @APP_PACKAGE@.channels.util.TvUtil; diff --git a/tools/depends/native/m4-native/01-fix-ftbfs-with-glibc-2.28.patch b/tools/depends/native/m4-native/01-fix-ftbfs-with-glibc-2.28.patch new file mode 100644 index 0000000000..c10c1b2ba8 --- /dev/null +++ b/tools/depends/native/m4-native/01-fix-ftbfs-with-glibc-2.28.patch @@ -0,0 +1,117 @@ +From: Santiago Vila <sanvila@debian.org> +Subject: Fix FTBFS with glibc 2.28 +Bug-Debian: https://bugs.debian.org/915152 +X-Debian-version: 1.4.18-2 + +Based on this gnulib commit by Paul Eggert: + +https://lists.gnu.org/r/bug-gnulib/2018-03/msg00002.html + +--- a/lib/fflush.c ++++ b/lib/fflush.c +@@ -33,7 +33,7 @@ + #undef fflush + + +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + + /* Clear the stream's ungetc buffer, preserving the value of ftello (fp). */ + static void +@@ -72,7 +72,7 @@ + + #endif + +-#if ! (defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */) ++#if ! (defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */) + + # if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT + /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */ +@@ -148,7 +148,7 @@ + if (stream == NULL || ! freading (stream)) + return fflush (stream); + +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + + clear_ungetc_buffer_preserving_position (stream); + +--- a/lib/fpending.c ++++ b/lib/fpending.c +@@ -32,7 +32,7 @@ + /* Most systems provide FILE as a struct and the necessary bitmask in + <stdio.h>, because they need it for implementing getc() and putc() as + fast macros. */ +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + return fp->_IO_write_ptr - fp->_IO_write_base; + #elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ + /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */ +--- a/lib/fpurge.c ++++ b/lib/fpurge.c +@@ -62,7 +62,7 @@ + /* Most systems provide FILE as a struct and the necessary bitmask in + <stdio.h>, because they need it for implementing getc() and putc() as + fast macros. */ +-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + fp->_IO_read_end = fp->_IO_read_ptr; + fp->_IO_write_ptr = fp->_IO_write_base; + /* Avoid memory leak when there is an active ungetc buffer. */ +--- a/lib/freadahead.c ++++ b/lib/freadahead.c +@@ -25,7 +25,7 @@ + size_t + freadahead (FILE *fp) + { +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + if (fp->_IO_write_ptr > fp->_IO_write_base) + return 0; + return (fp->_IO_read_end - fp->_IO_read_ptr) +--- a/lib/freading.c ++++ b/lib/freading.c +@@ -31,7 +31,7 @@ + /* Most systems provide FILE as a struct and the necessary bitmask in + <stdio.h>, because they need it for implementing getc() and putc() as + fast macros. */ +-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + return ((fp->_flags & _IO_NO_WRITES) != 0 + || ((fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) == 0 + && fp->_IO_read_base != NULL)); +--- a/lib/fseeko.c ++++ b/lib/fseeko.c +@@ -47,7 +47,7 @@ + #endif + + /* These tests are based on fpurge.c. */ +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + if (fp->_IO_read_end == fp->_IO_read_ptr + && fp->_IO_write_ptr == fp->_IO_write_base + && fp->_IO_save_base == NULL) +@@ -123,7 +123,7 @@ + return -1; + } + +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + fp->_flags &= ~_IO_EOF_SEEN; + fp->_offset = pos; + #elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ +--- a/lib/stdio-impl.h ++++ b/lib/stdio-impl.h +@@ -18,6 +18,12 @@ + the same implementation of stdio extension API, except that some fields + have different naming conventions, or their access requires some casts. */ + ++/* Glibc 2.28 made _IO_IN_BACKUP private. For now, work around this ++ problem by defining it ourselves. FIXME: Do not rely on glibc ++ internals. */ ++#if !defined _IO_IN_BACKUP && defined _IO_EOF_SEEN ++# define _IO_IN_BACKUP 0x100 ++#endif + + /* BSD stdio derived implementations. */ + diff --git a/tools/depends/native/m4-native/Makefile b/tools/depends/native/m4-native/Makefile index 30bfea48d9..a4ffcc68d0 100644 --- a/tools/depends/native/m4-native/Makefile +++ b/tools/depends/native/m4-native/Makefile @@ -1,7 +1,7 @@ include ../../Makefile.include PREFIX=$(NATIVEPREFIX) PLATFORM=$(NATIVEPLATFORM) -DEPS= ../../Makefile.include Makefile osx_snprintf.patch +DEPS= ../../Makefile.include Makefile 01-fix-ftbfs-with-glibc-2.28.patch osx_snprintf.patch # lib name, version LIBNAME=m4 @@ -22,6 +22,7 @@ $(TARBALLS_LOCATION)/$(ARCHIVE): $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); patch -p1 -i ../01-fix-ftbfs-with-glibc-2.28.patch cd $(PLATFORM); patch -p1 -i ../osx_snprintf.patch cd $(PLATFORM); $(CONFIGURE) diff --git a/tools/depends/target/Makefile b/tools/depends/target/Makefile index 0c525401e6..493213d27c 100644 --- a/tools/depends/target/Makefile +++ b/tools/depends/target/Makefile @@ -119,6 +119,7 @@ waylandpp: wayland $(WAYLANDPP_DEPS) dbus: expat libinput: mtdev libevdev libevdev: libudev +taglib: $(ZLIB) .installed-$(PLATFORM): $(DEPENDS) touch $@ diff --git a/tools/depends/target/libandroidjni/Makefile b/tools/depends/target/libandroidjni/Makefile index eb1654539d..49dddbb530 100644 --- a/tools/depends/target/libandroidjni/Makefile +++ b/tools/depends/target/libandroidjni/Makefile @@ -3,7 +3,7 @@ DEPS= ../../Makefile.include Makefile # lib name, version LIBNAME=libandroidjni -VERSION=482232cc05102021e955e9d907b0047801fa47b4 +VERSION=aa12538cc5090d061d34b5fd7385d939ea82ce8b SOURCE=archive ARCHIVE=$(VERSION).tar.gz GIT_BASE_URL=https://github.com/xbmc diff --git a/tools/depends/target/libcec/Makefile b/tools/depends/target/libcec/Makefile index 71468e2a9a..89889ebb54 100644 --- a/tools/depends/target/libcec/Makefile +++ b/tools/depends/target/libcec/Makefile @@ -5,7 +5,7 @@ DEPS= ../../Makefile.include Makefile remove_git_info.patch LIBNAME=libcec VERSION_MAJOR=4 VERSION_MINOR=0 -VERSION_PATCH=1 +VERSION_PATCH=4 VERSION=$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) SOURCE=$(LIBNAME)-$(VERSION) diff --git a/tools/depends/target/sqlite3/Makefile b/tools/depends/target/sqlite3/Makefile index 2838a89f61..39e5334645 100644 --- a/tools/depends/target/sqlite3/Makefile +++ b/tools/depends/target/sqlite3/Makefile @@ -1,19 +1,18 @@ include ../../Makefile.include -DEPS= ../../Makefile.include Makefile fix-32bits-on-64bits.patch sqlite3.c.patch +DEPS= ../../Makefile.include Makefile sqlite3.c.patch # lib name, version LIBNAME=sqlite -VERSION=3140200 +VERSION=3260000 SOURCE=$(LIBNAME)-autoconf-$(VERSION) ARCHIVE=$(SOURCE).tar.gz # configuration settings export CXXFLAGS+=-DSQLITE_ENABLE_COLUMN_METADATA=1 export CFLAGS+=-DSQLITE_TEMP_STORE=3 -DSQLITE_DEFAULT_MMAP_SIZE=0x10000000 -export TCLLIBDIR=/dev/null CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) .; \ ./configure --prefix=$(PREFIX) --disable-shared \ - --enable-threadsafe --disable-tcl --disable-readline \ + --enable-threadsafe --disable-readline \ LIBDYLIB=$(PLATFORM)/.libs/lib$(LIBNAME)3.a @@ -25,9 +24,6 @@ $(TARBALLS_LOCATION)/$(ARCHIVE): $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) -ifeq ($(OS),android) - cd $(PLATFORM); patch -p0 < ../fix-32bits-on-64bits.patch -endif # seems MAP_POPULATE is broken on aarch64 ifneq ($(OS),android) cd $(PLATFORM); patch -p1 < ../sqlite3.c.patch diff --git a/tools/depends/target/sqlite3/fix-32bits-on-64bits.patch b/tools/depends/target/sqlite3/fix-32bits-on-64bits.patch deleted file mode 100644 index cf4d75be1b..0000000000 --- a/tools/depends/target/sqlite3/fix-32bits-on-64bits.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- sqlite3.c.orig 2014-11-19 13:14:16.633721369 +0100 -+++ sqlite3.c 2014-11-19 13:23:23.733711563 +0100 -@@ -25301,7 +25301,7 @@ - #if OS_VXWORKS - struct vxworksFileId *pId; /* Unique file ID for vxworks. */ - #else -- ino_t ino; /* Inode number */ -+ unsigned long long ino; /* Inode number */ - #endif - }; - diff --git a/tools/windows/packaging/uwp/kodi_temp_key.pfx b/tools/windows/packaging/uwp/kodi_temp_key.pfx Binary files differindex 697763b40b..268a41a2e4 100644 --- a/tools/windows/packaging/uwp/kodi_temp_key.pfx +++ b/tools/windows/packaging/uwp/kodi_temp_key.pfx diff --git a/version.txt b/version.txt index ffd0262ee2..9de48428cc 100644 --- a/version.txt +++ b/version.txt @@ -4,9 +4,9 @@ COPYRIGHT_YEARS 2005-2018 WEBSITE http://kodi.tv VERSION_MAJOR 18 VERSION_MINOR 0 -VERSION_TAG RC1 -VERSION_CODE 17.99.910 -ADDON_API 17.9.910 +VERSION_TAG RC4 +VERSION_CODE 17.99.940 +ADDON_API 17.9.940 APP_PACKAGE org.xbmc.kodi PACKAGE_IDENTITY XBMCFoundation.Kodi PACKAGE_PUBLISHER C62BD90A-CDD8-477F-96C3-B25992247B97 diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index 3f3f75a60a..c5cd3c7cad 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -450,7 +450,7 @@ bool CApplication::Create(const CAppParamParser ¶ms) // specialVersion = " (version for XXXX)"; #endif CLog::Log(LOGNOTICE, "Using %s %s x%d build%s", buildType.c_str(), CSysInfo::GetAppName().c_str(), g_sysinfo.GetXbmcBitness(), specialVersion.c_str()); - CLog::Log(LOGNOTICE, "%s compiled " __DATE__ " by %s for %s %s %d-bit %s (%s)", CSysInfo::GetAppName().c_str(), g_sysinfo.GetUsedCompilerNameAndVer().c_str(), g_sysinfo.GetBuildTargetPlatformName().c_str(), + CLog::Log(LOGNOTICE, "%s compiled %s by %s for %s %s %d-bit %s (%s)", CSysInfo::GetAppName().c_str(), CSysInfo::GetBuildDate(), g_sysinfo.GetUsedCompilerNameAndVer().c_str(), g_sysinfo.GetBuildTargetPlatformName().c_str(), g_sysinfo.GetBuildTargetCpuFamily().c_str(), g_sysinfo.GetXbmcBitness(), g_sysinfo.GetBuildTargetPlatformVersionDecoded().c_str(), g_sysinfo.GetBuildTargetPlatformVersion().c_str()); @@ -652,7 +652,6 @@ bool CApplication::CreateGUI() // If OS has no screen saver, use Kodi one by default screensaverModeSetting->SetDefault("screensaver.xbmc.builtin.dim"); } - CheckOSScreenSaverInhibitionSetting(); if (sav_res) CDisplaySettings::GetInstance().SetCurrentResolution(RES_DESKTOP, true); @@ -700,14 +699,6 @@ bool CApplication::InitWindow(RESOLUTION res) return true; } -bool CApplication::DestroyWindow() -{ - bool ret = CServiceBroker::GetWinSystem()->DestroyWindow(); - CServiceBroker::UnregisterWinSystem(); - m_pWinSystem.reset(); - return ret; -} - bool CApplication::Initialize() { #if defined(HAS_DVD_DRIVE) && !defined(TARGET_WINDOWS) // somehow this throws an "unresolved external symbol" on win32 @@ -870,6 +861,7 @@ bool CApplication::Initialize() CLog::Log(LOGNOTICE, "initialize done"); + CheckOSScreenSaverInhibitionSetting(); // reset our screensaver (starts timers etc.) ResetScreenSaver(); @@ -2443,10 +2435,7 @@ bool CApplication::Cleanup() CWinSystemBase *winSystem = CServiceBroker::GetWinSystem(); if (winSystem) - { winSystem->DestroyWindow(); - winSystem->DestroyWindowSystem(); - } if (m_pGUI) m_pGUI->GetWindowManager().DestroyWindows(); @@ -2490,6 +2479,14 @@ bool CApplication::Cleanup() m_pGUI.reset(); } + if (winSystem) + { + winSystem->DestroyWindowSystem(); + CServiceBroker::UnregisterWinSystem(); + winSystem = nullptr; + m_pWinSystem.reset(); + } + // Cleanup was called more than once on exit during my tests if (m_ServiceManager) { @@ -2811,6 +2808,7 @@ bool CApplication::PlayFile(CFileItem item, const std::string& player, bool bRes if(item.GetProperty("StartPercent").isString()) fallback = atof(item.GetProperty("StartPercent").asString().c_str()); options.startpercent = item.GetProperty("StartPercent").asDouble(fallback); + item.m_lStartOffset = 0; } options.starttime = CUtil::ConvertMilliSecsToSecs(item.m_lStartOffset); @@ -3369,6 +3367,7 @@ bool CApplication::ToggleDPMS(bool manual) m_dpmsIsActive = false; m_dpmsIsManual = false; SetRenderGUI(true); + CheckOSScreenSaverInhibitionSetting(); CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::GUI, "xbmc", "OnDPMSDeactivated"); return m_dpms->DisablePowerSaving(); } @@ -3379,6 +3378,7 @@ bool CApplication::ToggleDPMS(bool manual) m_dpmsIsActive = true; m_dpmsIsManual = manual; SetRenderGUI(false); + CheckOSScreenSaverInhibitionSetting(); CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::GUI, "xbmc", "OnDPMSActivated"); return true; } @@ -3491,7 +3491,10 @@ bool CApplication::WakeUpScreenSaver(bool bPowerOffKeyPressed /* = false */) void CApplication::CheckOSScreenSaverInhibitionSetting() { // Kodi screen saver overrides OS one: always inhibit OS screen saver then - if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SCREENSAVER_MODE).empty() && + // except when DPMS is active (inhibiting the screen saver then might also + // disable DPMS again) + if (!m_dpmsIsActive && + !CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_SCREENSAVER_MODE).empty() && CServiceBroker::GetWinSystem()->GetOSScreenSaver()) { if (!m_globalScreensaverInhibitor) @@ -3543,7 +3546,10 @@ void CApplication::CheckScreenSaverAndDPMS() if (haveIdleActivity && CServiceBroker::GetWinSystem()->GetOSScreenSaver()) { // Always inhibit OS screen saver during these kinds of activities - m_screensaverInhibitor = CServiceBroker::GetWinSystem()->GetOSScreenSaver()->CreateInhibitor(); + if (!m_screensaverInhibitor) + { + m_screensaverInhibitor = CServiceBroker::GetWinSystem()->GetOSScreenSaver()->CreateInhibitor(); + } } else if (m_screensaverInhibitor) { @@ -3557,7 +3563,7 @@ void CApplication::CheckScreenSaverAndDPMS() maybeScreensaver = false; } - if (m_screensaverActive && m_appPlayer.IsPlayingVideo() && !m_appPlayer.IsPaused()) + if (m_screensaverActive && haveIdleActivity) { WakeUpScreenSaverAndDPMS(); return; diff --git a/xbmc/Application.h b/xbmc/Application.h index 47c35504de..30cf6e7d32 100644 --- a/xbmc/Application.h +++ b/xbmc/Application.h @@ -150,7 +150,6 @@ public: bool CreateGUI(); bool InitWindow(RESOLUTION res = RES_INVALID); - bool DestroyWindow(); void StartServices(); void StopServices(); diff --git a/xbmc/CompileInfo.cpp.in b/xbmc/CompileInfo.cpp.in index eef78ba052..c47e6cc594 100644 --- a/xbmc/CompileInfo.cpp.in +++ b/xbmc/CompileInfo.cpp.in @@ -8,9 +8,9 @@ #include "CompileInfo.h" +#include <algorithm> #include <cstddef> #include <string> -#include <algorithm> int CCompileInfo::GetMajor() @@ -59,3 +59,14 @@ const char* CCompileInfo::GetCopyrightYears() { return "@APP_COPYRIGHT_YEARS@"; } + +std::string CCompileInfo::GetBuildDate() +{ + const std::string bdate = "@APP_BUILD_DATE@"; + if (!bdate.empty()) + { + std::string datestamp = bdate.substr(0, 4) + "-" + bdate.substr(4, 2) + "-" + bdate.substr(6, 2); + return datestamp; + } + return "1970-01-01"; +} diff --git a/xbmc/CompileInfo.h b/xbmc/CompileInfo.h index 855711e5f7..db3cfbe0f2 100644 --- a/xbmc/CompileInfo.h +++ b/xbmc/CompileInfo.h @@ -8,6 +8,8 @@ #pragma once +#include <string> + class CCompileInfo { public: @@ -19,4 +21,5 @@ public: static const char *GetSuffix(); // Git "Tag", e.g. alpha1 static const char* GetSCMID(); // Git Revision static const char* GetCopyrightYears(); + static std::string GetBuildDate(); }; diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp index 7b0c2dfc33..a56b0832ec 100644 --- a/xbmc/GUIInfoManager.cpp +++ b/xbmc/GUIInfoManager.cpp @@ -76,16 +76,136 @@ typedef struct int val; } infomap; -/// \page modules__General__List_of_gui_access List of GUI access messages +/// \page modules__infolabels_boolean_conditions Infolabels and Boolean conditions /// \tableofcontents /// -/// \section modules__General__List_of_gui_access_Description Description -/// Skins can use boolean conditions with the <b><visible></b> tag or with condition +/// \section modules__infolabels_boolean_conditions_Description Description +/// Skins can use boolean conditions with the <b>\<visible\></b> tag or with condition /// attributes. Scripts can read boolean conditions with /// <b>xbmc.getCondVisibility(condition)</b>. /// -/// Skins can use infolabels with <b>$INFO[infolabel]</b> or the <b><info></b> tag. Scripts +/// Skins can use infolabels with <b>$INFO[infolabel]</b> or the <b>\<info\></b> tag. Scripts /// can read infolabels with <b>xbmc.getInfoLabel('infolabel')</b>. +/// +/// @todo [docs] Improve the description and create links for functions +/// @todo [docs] Separate boolean conditions from infolabels +/// @todo [docs] Order items alphabetically within subsections for a better search experience +/// @todo [docs] Order subsections alphabetically +/// @todo [docs] Use links instead of bold values for infolabels/bools +/// so we can use a link to point users when providing help +/// + + +/// \page modules__infolabels_boolean_conditions +/// \section modules_list_infolabels_booleans List of Infolabels and Boolean conditions +/// \subsection modules__infolabels_boolean_conditions_GlobalBools Global +/// \table_start +/// \table_h3{ Labels, Type, Description } +/// \table_row3{ <b>`true`</b>, +/// \anchor Global_True +/// _boolean_, +/// @return Always evaluates to **true**. +/// <p> +/// } +/// \table_row3{ <b>`false`</b>, +/// \anchor Global_False +/// _boolean_, +/// @return Always evaluates to **false**. +/// <p> +/// } +/// \table_row3{ <b>`yes`</b>, +/// \anchor Global_Yes +/// _boolean_, +/// @return same as \link Global_True `true` \endlink. +/// <p> +/// } +/// \table_row3{ <b>`no`</b>, +/// \anchor Global_No +/// _boolean_, +/// @return same as \link Global_False `false` \endlink. +/// <p> +/// } +/// \table_end +/// +/// ----------------------------------------------------------------------------- + + +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_String String +/// \table_start +/// \table_h3{ Labels, Type, Description } +/// \table_row3{ <b>`String.IsEmpty(info)`</b>, +/// \anchor String_IsEmpty +/// _boolean_, +/// @return **True** if the info is empty. +/// @param info - infolabel +/// @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \, +/// \link ListItem_Genre `ListItem.Genre` \endlink. +/// Please note that string can also be a `$LOCALIZE[]`. +/// Also note that in a panelview or similar this only works on the focused item +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link String_IsEmpty `String.IsEmpty(info)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`String.IsEqual(info\,string)`</b>, +/// \anchor String_IsEqual +/// _boolean_, +/// @return **True** if the info is equal to the given string. +/// @param info - infolabel +/// @param string - comparison string +/// @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \, +/// \link ListItem_Genre `ListItem.Genre` \endlink. +/// Please note that string can also be a `$LOCALIZE[]`. +/// Also note that in a panelview or similar this only works on the focused item +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link String_IsEqual `String.IsEqual(info\,string)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`String.StartsWith(info\,substring)`</b>, +/// \anchor String_StartsWith +/// _boolean_, +/// @return **True** if the info starts with the given substring. +/// @param info - infolabel +/// @param substring - substring to check +/// @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \, +/// \link ListItem_Genre `ListItem.Genre` \endlink. +/// Please note that string can also be a `$LOCALIZE[]`. +/// Also note that in a panelview or similar this only works on the focused item +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link String_StartsWith `String.StartsWith(info\,substring)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`String.EndsWith(info\,substring)`</b>, +/// \anchor String_EndsWith +/// _boolean_, +/// @return **True** if the info ends with the given substring. +/// @param info - infolabel +/// @param substring - substring to check +/// @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \, +/// \link ListItem_Genre `ListItem.Genre` \endlink. +/// Please note that string can also be a `$LOCALIZE[]`. +/// Also note that in a panelview or similar this only works on the focused item +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link String_EndsWith `String.EndsWith(info\,substring)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`String.Contains(info\,substring)`</b>, +/// \anchor String_Contains +/// _boolean_, +/// @return **True** if the info contains the given substring. +/// @param info - infolabel +/// @param substring - substring to check +/// @note **Example of info:** \link ListItem_Title `ListItem.Title` \endlink \, +/// \link ListItem_Genre `ListItem.Genre` \endlink. +/// Please note that string can also be a `$LOCALIZE[]`. +/// Also note that in a panelview or similar this only works on the focused item +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link String_Contains `String.Contains(info\,substring)`\endlink +/// <p> +/// } +/// \table_end +/// +/// ----------------------------------------------------------------------------- const infomap string_bools[] = {{ "isempty", STRING_IS_EMPTY }, @@ -94,295 +214,420 @@ const infomap string_bools[] = {{ "isempty", STRING_IS_EMPTY }, { "endswith", STRING_ENDS_WITH }, { "contains", STRING_CONTAINS }}; + +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Integer Integer +/// \table_start +/// \table_h3{ Labels, Type, Description } +/// \table_row3{ <b>`Integer.IsEqual(info\,number)`</b>, +/// \anchor Integer_IsEqual +/// _boolean_, +/// @return **True** if the value of the infolabel is equal to the supplied number. +/// @param info - infolabel +/// @param number - number to compare +/// @note **Example:** `Integer.IsEqual(ListItem.Year\,2000)` +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Integer_IsEqual `Integer.IsEqual(info\,number)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Integer.IsGreater(info\,number)`</b>, +/// \anchor Integer_IsGreater +/// _boolean_, +/// @return **True** if the value of the infolabel is greater than to the supplied number. +/// @param info - infolabel +/// @param number - number to compare +/// @note **Example:** `Integer.IsGreater(ListItem.Year\,2000)` +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Integer_IsGreater `Integer.IsGreater(info\,number)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Integer.IsGreaterOrEqual(info\,number)`</b>, +/// \anchor Integer_IsGreaterOrEqual +/// _boolean_, +/// @return **True** if the value of the infolabel is greater or equal to the supplied number. +/// @param info - infolabel +/// @param number - number to compare +/// @note **Example:** `Integer.IsGreaterOrEqual(ListItem.Year\,2000)` +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Integer_IsGreaterOrEqual `Integer.IsGreaterOrEqual(info\,number)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Integer.IsLess(info\,number)`</b>, +/// \anchor Integer_IsLess +/// _boolean_, +/// @return **True** if the value of the infolabel is less than the supplied number. +/// @param info - infolabel +/// @param number - number to compare +/// @note **Example:** `Integer.IsLess(ListItem.Year\,2000)` +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Integer_IsLess `Integer.IsLess(info\,number)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Integer.IsLessOrEqual(info\,number)`</b>, +/// \anchor Integer_IsLessOrEqual +/// _boolean_, +/// @return **True** if the value of the infolabel is less or equal to the supplied number. +/// @param info - infolabel +/// @param number - number to compare +/// @note **Example:** `Integer.IsLessOrEqual(ListItem.Year\,2000)` +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Integer_IsLessOrEqual `Integer.IsLessOrEqual(info\,number)`\endlink +/// <p> +/// } +/// \table_end +/// +/// ----------------------------------------------------------------------------- + + const infomap integer_bools[] = {{ "isequal", INTEGER_IS_EQUAL }, { "isgreater", INTEGER_GREATER_THAN }, { "isgreaterorequal", INTEGER_GREATER_OR_EQUAL }, { "isless", INTEGER_LESS_THAN }, { "islessorequal", INTEGER_LESS_OR_EQUAL }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Player Player -/// @{ + +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Player Player /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Player.HasAudio`</b>, /// \anchor Player_HasAudio /// _boolean_, -/// Returns true if the player has an audio file. +/// @return **True** if the player has an audio file. +/// <p> /// } /// \table_row3{ <b>`Player.HasGame`</b>, /// \anchor Player_HasGame /// _boolean_, -/// Returns true if the player has a game file. +/// @return **True** if the player has a game file (RETROPLAYER). +/// <p><hr> +/// @skinning_v18 **[New Boolean Condition]** \link Player_HasGame `Player.HasGame`\endlink +/// <p> /// } /// \table_row3{ <b>`Player.HasMedia`</b>, /// \anchor Player_HasMedia /// _boolean_, -/// Returns true if the player has an audio or video file. +/// @return **True** if the player has an audio or video file. +/// <p> /// } /// \table_row3{ <b>`Player.HasVideo`</b>, /// \anchor Player_HasVideo /// _boolean_, -/// Returns true if the player has a video file. +/// @return **True** if the player has a video file. +/// <p> /// } /// \table_row3{ <b>`Player.Paused`</b>, /// \anchor Player_Paused /// _boolean_, -/// Returns true if the player is paused. +/// @return **True** if the player is paused. +/// <p> /// } /// \table_row3{ <b>`Player.Playing`</b>, /// \anchor Player_Playing /// _boolean_, -/// Returns true if the player is currently playing (ie not ffwding\, +/// @return **True** if the player is currently playing (i.e. not ffwding\, /// rewinding or paused.) +/// <p> /// } /// \table_row3{ <b>`Player.Rewinding`</b>, /// \anchor Player_Rewinding /// _boolean_, -/// Returns true if the player is rewinding. +/// @return **True** if the player is rewinding. +/// <p> /// } /// \table_row3{ <b>`Player.Rewinding2x`</b>, /// \anchor Player_Rewinding2x /// _boolean_, -/// Returns true if the player is rewinding at 2x. +/// @return **True** if the player is rewinding at 2x. +/// <p> /// } /// \table_row3{ <b>`Player.Rewinding4x`</b>, /// \anchor Player_Rewinding4x /// _boolean_, -/// Returns true if the player is rewinding at 4x. +/// @return **True** if the player is rewinding at 4x. +/// <p> /// } /// \table_row3{ <b>`Player.Rewinding8x`</b>, /// \anchor Player_Rewinding8x /// _boolean_, -/// Returns true if the player is rewinding at 8x. +/// @return **True** if the player is rewinding at 8x. +/// <p> /// } /// \table_row3{ <b>`Player.Rewinding16x`</b>, /// \anchor Player_Rewinding16x /// _boolean_, -/// Returns true if the player is rewinding at 16x. +/// @return **True** if the player is rewinding at 16x. +/// <p> /// } /// \table_row3{ <b>`Player.Rewinding32x`</b>, /// \anchor Player_Rewinding32x /// _boolean_, -/// Returns true if the player is rewinding at 32x. +/// @return **True** if the player is rewinding at 32x. +/// <p> /// } /// \table_row3{ <b>`Player.Forwarding`</b>, /// \anchor Player_Forwarding /// _boolean_, -/// Returns true if the player is fast forwarding. +/// @return **True** if the player is fast forwarding. +/// <p> /// } /// \table_row3{ <b>`Player.Forwarding2x`</b>, /// \anchor Player_Forwarding2x /// _boolean_, -/// Returns true if the player is fast forwarding at 2x. +/// @return **True** if the player is fast forwarding at 2x. +/// <p> /// } /// \table_row3{ <b>`Player.Forwarding4x`</b>, /// \anchor Player_Forwarding4x /// _boolean_, -/// Returns true if the player is fast forwarding at 4x. +/// @return **True** if the player is fast forwarding at 4x. +/// <p> /// } /// \table_row3{ <b>`Player.Forwarding8x`</b>, /// \anchor Player_Forwarding8x /// _boolean_, -/// Returns true if the player is fast forwarding at 8x. +/// @return **True** if the player is fast forwarding at 8x. +/// <p> /// } /// \table_row3{ <b>`Player.Forwarding16x`</b>, /// \anchor Player_Forwarding16x /// _boolean_, -/// Returns true if the player is fast forwarding at 16x. +/// @return **True** if the player is fast forwarding at 16x. +/// <p> /// } /// \table_row3{ <b>`Player.Forwarding32x`</b>, /// \anchor Player_Forwarding32x /// _boolean_, -/// Returns true if the player is fast forwarding at 32x. +/// @return **True** if the player is fast forwarding at 32x. +/// <p> /// } /// \table_row3{ <b>`Player.Caching`</b>, /// \anchor Player_Caching /// _boolean_, -/// Returns true if the player is current re-caching data (internet based +/// @return **True** if the player is current re-caching data (internet based /// video playback). +/// <p> /// } /// \table_row3{ <b>`Player.DisplayAfterSeek`</b>, /// \anchor Player_DisplayAfterSeek /// _boolean_, -/// Returns true for the first 2.5 seconds after a seek. +/// @return **True** for the first 2.5 seconds after a seek. +/// <p> /// } /// \table_row3{ <b>`Player.Seekbar`</b>, /// \anchor Player_Seekbar /// _integer_, -/// Returns amount of percent of one seek to other position +/// @return The percentage of one seek to other position. +/// <p> /// } /// \table_row3{ <b>`Player.Seeking`</b>, /// \anchor Player_Seeking /// _boolean_, -/// Returns true if a seek is in progress +/// @return **True** if a seek is in progress. +/// <p> /// } /// \table_row3{ <b>`Player.ShowTime`</b>, /// \anchor Player_ShowTime /// _boolean_, -/// Returns true if the user has requested the time to show (occurs in video -/// fullscreen) +/// @return **True** if the user has requested the time to show (occurs in video +/// fullscreen). +/// <p> /// } /// \table_row3{ <b>`Player.ShowInfo`</b>, /// \anchor Player_ShowInfo /// _boolean_, -/// Returns true if the user has requested the song info to show (occurs in -/// visualisation fullscreen and slideshow) -/// } -/// \table_row3{ <b>`Player.ShowCodec`</b>, -/// \anchor Player_ShowCodec -/// _boolean_, -/// Returns true if the user has requested the codec to show (occurs in -/// visualisation and video fullscreen) +/// @return **True** if the user has requested the song info to show (occurs in +/// visualisation fullscreen and slideshow). +/// <p> /// } /// \table_row3{ <b>`Player.Title`</b>, /// \anchor Player_Title /// _string_, -/// Returns the musicplayer title for audio and the videoplayer title for -/// videos. +/// @return The Musicplayer title for audio and the Videoplayer title for +/// video. +/// <p> /// } /// \table_row3{ <b>`Player.Muted`</b>, /// \anchor Player_Muted /// _boolean_, -/// Returns true if the volume is muted. +/// @return **True** if the volume is muted. +/// <p> /// } /// \table_row3{ <b>`Player.HasDuration`</b>, /// \anchor Player_HasDuration /// _boolean_, -/// Returns true if Media isn't a true stream +/// @return **True** if Media is not a true stream. +/// <p> /// } /// \table_row3{ <b>`Player.Passthrough`</b>, /// \anchor Player_Passthrough /// _boolean_, -/// Returns true if the player is using audio passthrough. +/// @return **True** if the player is using audio passthrough. +/// <p> /// } /// \table_row3{ <b>`Player.CacheLevel`</b>, /// \anchor Player_CacheLevel /// _string_, -/// Get the used cache level as string with an integer number +/// @return The used cache level as a string with an integer number. +/// <p> /// } /// \table_row3{ <b>`Player.Progress`</b>, /// \anchor Player_Progress /// _integer_, -/// Returns the progress position as percent +/// @return The progress position as percentage. +/// <p> /// } /// \table_row3{ <b>`Player.ProgressCache`</b>, /// \anchor Player_ProgressCache /// _integer_, -/// Returns how much of the file is cached above current play percentage +/// @return How much of the file is cached above current play percentage +/// <p> /// } /// \table_row3{ <b>`Player.Volume`</b>, /// \anchor Player_Volume /// _string_, -/// Returns the current player volume with the format `%2.1f dB` +/// @return The current player volume with the format `%2.1f` dB +/// <p> /// } /// \table_row3{ <b>`Player.SubtitleDelay`</b>, /// \anchor Player_SubtitleDelay /// _string_, -/// Return the used subtitle delay with the format `%2.3f s` +/// @return The used subtitle delay with the format `%2.3f` s +/// <p> /// } /// \table_row3{ <b>`Player.AudioDelay`</b>, /// \anchor Player_AudioDelay /// _string_, -/// Return the used audio delay with the format `%2.3f s` +/// @return The used audio delay with the format `%2.3f` s +/// <p> /// } /// \table_row3{ <b>`Player.Chapter`</b>, /// \anchor Player_Chapter /// _integer_, -/// Current chapter of current playing media +/// @return The current chapter of current playing media. +/// <p> /// } /// \table_row3{ <b>`Player.ChapterCount`</b>, /// \anchor Player_ChapterCount /// _integer_, -/// Total number of chapters of current playing media +/// @return The total number of chapters of current playing media. +/// <p> /// } /// \table_row3{ <b>`Player.ChapterName`</b>, /// \anchor Player_ChapterName /// _string_, -/// Return the name of currently used chapter if available +/// @return The name of currently used chapter if available. +/// <p> /// } /// \table_row3{ <b>`Player.Folderpath`</b>, /// \anchor Player_Folderpath /// _string_, -/// Returns the full path of the currently playing song or movie +/// @return The full path of the currently playing song or movie +/// <p> /// } /// \table_row3{ <b>`Player.FilenameAndPath`</b>, /// \anchor Player_FilenameAndPath /// _string_, -/// Returns the full path with filename of the currently playing song or movie +/// @return The full path with filename of the currently +/// playing song or movie +/// <p> /// } /// \table_row3{ <b>`Player.Filename`</b>, /// \anchor Player_Filename /// _string_, -/// Returns the filename of the currently playing media. +/// @return The filename of the currently playing media. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Player_Filename `Player.Filename`\endlink +/// <p> /// } /// \table_row3{ <b>`Player.IsInternetStream`</b>, /// \anchor Player_IsInternetStream /// _boolean_, -/// Returns true if the player is playing an internet stream. +/// @return **True** if the player is playing an internet stream. +/// <p> /// } /// \table_row3{ <b>`Player.PauseEnabled`</b>, /// \anchor Player_PauseEnabled /// _boolean_, -/// Returns true if played stream is paused +/// @return **True** if played stream is paused. +/// <p> /// } /// \table_row3{ <b>`Player.SeekEnabled`</b>, /// \anchor Player_SeekEnabled /// _boolean_, -/// Returns true if seek on playing is enabled +/// @return **True** if seek on playing is enabled. +/// <p> /// } /// \table_row3{ <b>`Player.ChannelPreviewActive`</b>, /// \anchor Player_ChannelPreviewActive /// _boolean_, -/// Returns true if pvr channel preview is active (used channel tag different -/// from played tag) +/// @return **True** if PVR channel preview is active (used +/// channel tag different from played tag) +/// <p> /// } /// \table_row3{ <b>`Player.TempoEnabled`</b>, /// \anchor Player_TempoEnabled /// _boolean_, -/// Returns true if player supports tempo (i.e. speed up/down normal playback speed) +/// @return **True** if player supports tempo (i.e. speed up/down normal +/// playback speed) +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Player_TempoEnabled `Player.TempoEnabled`\endlink +/// <p> /// } /// \table_row3{ <b>`Player.IsTempo`</b>, /// \anchor Player_IsTempo /// _boolean_, -/// Returns true if player has tempo (i.e. is playing with a playback speed higher or +/// @return **True** if player has tempo (i.e. is playing with a playback speed higher or /// lower than normal playback speed) +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Player_IsTempo `Player.IsTempo`\endlink +/// <p> /// } /// \table_row3{ <b>`Player.PlaySpeed`</b>, /// \anchor Player_PlaySpeed /// _string_, -/// Returns the player playback speed with the format %1.2f (1.00 means normal -/// playback speed). For Tempo\, the default range is 0.80 - 1.50 (it can be changed -/// in advanced settings). If `Player.PlaySpeed` returns a value different from 1.00 -/// and `Player.IsTempo` is false it means the player is in ff/rw mode. +/// @return The player playback speed with the format `%1.2f` (1.00 means normal +/// playback speed). +/// @note For Tempo\, the default range is 0.80 - 1.50 (it can be changed +/// in advanced settings). If \ref Player_PlaySpeed "Player.PlaySpeed" returns a value different from 1.00 +/// and \ref Player_IsTempo "Player.IsTempo" is false it means the player is in ff/rw mode. +/// <p> /// } /// \table_row3{ <b>`Player.HasResolutions`</b>, /// \anchor Player_HasResolutions /// _boolean_, -/// Returns true if the player is allowed to switch resolution and refresh rate +/// @return **True** if the player is allowed to switch resolution and refresh rate /// (i.e. if whitelist modes are configured in Kodi's System/Display settings) +/// <p><hr> +/// @skinning_v18 **[New Boolean Condition]** \link Player_HasResolutions `Player.HasResolutions`\endlink +/// <p> /// } /// \table_row3{ <b>`Player.HasPrograms`</b>, /// \anchor Player_HasPrograms /// _boolean_, -/// Returns true if the media file being played has programs\, i.e. groups of streams. -/// Ex: if a media file has multiple streams (quality\, channels\, etc) a program represents +/// @return **True** if the media file being played has programs\, i.e. groups of streams. +/// @note Ex: if a media file has multiple streams (quality\, channels\, etc) a program represents /// a particular stream combo. +/// <p> /// } /// \table_row3{ <b>`Player.FrameAdvance`</b>, /// \anchor Player_FrameAdvance /// _boolean_, -/// Returns true if player is in frame advance mode. Skins should hide seek bar -/// in this mode) +/// @return **True** if player is in frame advance mode. +/// @note Skins should hide seek bar in this mode +/// <p><hr> +/// @skinning_v18 **[New Boolean Condition]** \link Player_FrameAdvance `Player.FrameAdvance`\endlink +/// <p> /// } /// \table_row3{ <b>`Player.Icon`</b>, /// \anchor Player_Icon /// _string_, -/// Returns the thumbnail of the currently playing item. If no thumbnail image exists\, +/// @return The thumbnail of the currently playing item. If no thumbnail image exists\, /// the icon will be returned\, if available. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link Player_Icon `Player.Icon`\endlink +/// <p> /// } -/// \table_end -/// @} const infomap player_labels[] = {{ "hasmedia", PLAYER_HAS_MEDIA }, { "hasaudio", PLAYER_HAS_AUDIO }, { "hasvideo", PLAYER_HAS_VIDEO }, @@ -406,7 +651,6 @@ const infomap player_labels[] = {{ "hasmedia", PLAYER_HAS_MEDIA }, { "seekbar", PLAYER_SEEKBAR }, { "seeking", PLAYER_SEEKING }, { "showtime", PLAYER_SHOWTIME }, - { "showcodec", PLAYER_SHOWCODEC }, { "showinfo", PLAYER_SHOWINFO }, { "muted", PLAYER_MUTED }, { "hasduration", PLAYER_HASDURATION }, @@ -436,152 +680,109 @@ const infomap player_labels[] = {{ "hasmedia", PLAYER_HAS_MEDIA }, { "frameadvance", PLAYER_FRAMEADVANCE }, { "icon", PLAYER_ICON }}; -/// \page modules__General__List_of_gui_access -/// @{ -/// \table_start -/// \table_row3{ <b>`Player.Art(fanart)`</b>, -/// \anchor Player_Art_fanart -/// _string_, -/// Fanart Image of the currently playing episode's parent TV show -/// } -/// \table_row3{ <b>`Player.Art(thumb)`</b>, -/// \anchor Player_Art_thumb -/// _string_, -/// Returns the thumbnail image of the currently playing item. -/// } -/// \table_row3{ <b>`Player.Art(poster)`</b>, -/// \anchor Player_Art_poster -/// _string_, -/// Returns the poster of the currently playing movie. -/// } -/// \table_row3{ <b>`Player.Art(tvshow.poster)`</b>, -/// \anchor Player_Art_tvshowposter +/// \page modules__infolabels_boolean_conditions +/// \table_row3{ <b>`Player.Art(type)`</b>, +/// \anchor Player_Art_type /// _string_, -/// Returns the tv show poster of the currently playing episode's parent TV show. +/// @return The Image for the defined art type for the current playing ListItem. +/// @param type - The art type. The type is defined by scripts and scrappers and can have any value. +/// Common example values for type are: +/// - fanart +/// - thumb +/// - poster +/// - banner +/// - clearlogo +/// - tvshow.poster +/// - tvshow.banner +/// - etc +/// @todo get a way of centralize all random art strings used in core so we can point users to them +/// while still making it clear they can have any value. +/// <p> /// } -/// \table_row3{ <b>`Player.Art(tvshow.banner)`</b>, -/// \anchor Player_Art_tvshowbanner -/// _string_, -/// Returns the tv show banner of the currently playing episode's parent TV show. -/// } -/// \table_end -/// @} + + const infomap player_param[] = {{ "art", PLAYER_ITEM_ART }}; -/// \page modules__General__List_of_gui_access -/// @{ -/// \table_start +/// \page modules__infolabels_boolean_conditions /// \table_row3{ <b>`Player.SeekTime`</b>, /// \anchor Player_SeekTime /// _string_, -/// Time to which the user is seeking +/// @return The time to which the user is seeking. +/// <p> /// } -/// \table_row3{ <b>`Player.SeekOffset`</b>, -/// \anchor Player_SeekOffset -/// _string_, -/// Indicates the seek offset after a seek press (eg user presses -/// BigStepForward\, player.seekoffset returns +10:00) -/// } -/// \table_row3{ <b>`Player.SeekOffset(format)`</b>, +/// \table_row3{ <b>`Player.SeekOffset([format])`</b>, /// \anchor Player_SeekOffset_format /// _string_, -/// Returns hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The seek offset after a seek press in a given format. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> +/// @note **Example:** user presses BigStepForward\, player.seekoffset returns +10:00 +/// <p> /// } /// \table_row3{ <b>`Player.SeekStepSize`</b>, /// \anchor Player_SeekStepSize /// _string_, -/// Displays the seek step size. (v15 addition) -/// } -/// \table_row3{ <b>`Player.TimeRemaining`</b>, -/// \anchor Player_TimeRemaining -/// _string_, -/// Remaining time of current playing media +/// @return The seek step size. +/// <p> +/// <hr> +/// @skinning_v15 **[New Infolabel]** \link Player_SeekStepSize `Player.SeekStepSize`\endlink +/// <p> /// } -/// \table_row3{ <b>`Player.TimeRemaining(format)`</b>, +/// \table_row3{ <b>`Player.TimeRemaining([format])`</b>, /// \anchor Player_TimeRemaining_format /// _string_, -/// Returns hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The remaining time of current playing media in a given format. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`Player.TimeSpeed`</b>, /// \anchor Player_TimeSpeed /// _string_, -/// Both the time and the playspeed formatted up. eg 1:23 (2x) +/// @return The time and the playspeed formatted: "1:23 (2x)". +/// <p> /// } -/// \table_row3{ <b>`Player.Time`</b>, -/// \anchor Player_Time -/// _string_, -/// Elapsed time of current playing media -/// } -/// \table_row3{ <b>`Player.Time(format)`</b>, +/// \table_row3{ <b>`Player.Time([format])`</b>, /// \anchor Player_Time_format /// _string_, -/// Returns hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The elapsed time of current playing media in a given format. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } -/// \table_row3{ <b>`Player.Duration`</b>, -/// \anchor Player_Duration -/// _string_, -/// Total duration of the current playing media -/// } -/// \table_row3{ <b>`Player.Duration(format)`</b>, +/// \table_row3{ <b>`Player.Duration([format])`</b>, /// \anchor Player_Duration_format /// _string_, -/// Returns hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 -/// } -/// \table_row3{ <b>`Player.FinishTime`</b>, -/// \anchor Player_FinishTime -/// _string_, -/// Time playing media will end +/// @return The total duration of the current playing media in a given format. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } -/// \table_row3{ <b>`Player.FinishTime(format)`</b>, +/// \table_row3{ <b>`Player.FinishTime([format])`</b>, /// \anchor Player_FinishTime_format /// _string_, -/// Returns hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The time at which the playing media will end (in a specified format). +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } -/// \table_row3{ <b>`Player.StartTime`</b>, -/// \anchor Player_StartTime -/// _string_, -/// Time playing media began -/// } -/// \table_row3{ <b>`Player.StartTime(format)`</b>, +/// \table_row3{ <b>`Player.StartTime([format])`</b>, /// \anchor Player_StartTime_format /// _string_, -/// Returns hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 -/// } -/// \table_row3{ <b>`Player.SeekNumeric`</b>, -/// \anchor Player_SeekNumeric -/// _string_, -/// Time to which the user is seeking via numeric keys. +/// @return The time at which the playing media began (in a specified format). +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } -/// \table_row3{ <b>`Player.SeekNumeric(format)`</b>, +/// \table_row3{ <b>`Player.SeekNumeric([format])`</b>, /// \anchor Player_SeekNumeric_format /// _string_, -/// Returns hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The time at which the playing media began (in a specified format). +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } -/// \table_end -/// -/// ----------------------------------------------------------------------------- -/// @} const infomap player_times[] = {{ "seektime", PLAYER_SEEKTIME }, { "seekoffset", PLAYER_SEEKOFFSET }, { "seekstepsize", PLAYER_SEEKSTEPSIZE }, @@ -593,50 +794,175 @@ const infomap player_times[] = {{ "seektime", PLAYER_SEEKTIME }, { "starttime", PLAYER_START_TIME }, { "seeknumeric", PLAYER_SEEKNUMERIC } }; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Weather Weather -/// @{ + +/// \page modules__infolabels_boolean_conditions +/// \table_row3{ <b>`Player.Process(videohwdecoder)`</b>, +/// \anchor Player_Process_videohwdecoder +/// _boolean_, +/// @return **True** if the currently playing video is decoded in hardware. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Player_Process_videohwdecoder `Player.Process(videohwdecoder)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(videodecoder)`</b>, +/// \anchor Player_Process_videodecoder +/// _string_, +/// @return The videodecoder name of the currently playing video. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_videodecoder `Player.Process(videodecoder)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(deintmethod)`</b>, +/// \anchor Player_Process_deintmethod +/// _string_, +/// @return The deinterlace method of the currently playing video. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_deintmethod `Player.Process(deintmethod)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(pixformat)`</b>, +/// \anchor Player_Process_pixformat +/// _string_, +/// @return The pixel format of the currently playing video. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_pixformat `Player.Process(pixformat)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(videowidth)`</b>, +/// \anchor Player_Process_videowidth +/// _string_, +/// @return The width of the currently playing video. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_videowidth `Player.Process(videowidth)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(videoheight)`</b>, +/// \anchor Player_Process_videoheight +/// _string_, +/// @return The width of the currently playing video. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_videoheight `Player.Process(videoheight)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(videofps)`</b>, +/// \anchor Player_Process_videofps +/// _string_, +/// @return The video framerate of the currently playing video. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_videofps `Player.Process(videofps)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(videodar)`</b>, +/// \anchor Player_Process_videodar +/// _string_, +/// @return The display aspect ratio of the currently playing video. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_videodar `Player.Process(videodar)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(audiodecoder)`</b>, +/// \anchor Player_Process_audiodecoder +/// _string_, +/// @return The audiodecoder name of the currently playing item. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_videodar `Player.Process(audiodecoder)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(audiochannels)`</b>, +/// \anchor Player_Process_audiochannels +/// _string_, +/// @return The audiodecoder name of the currently playing item. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_audiochannels `Player.Process(audiochannels)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(audiosamplerate)`</b>, +/// \anchor Player_Process_audiosamplerate +/// _string_, +/// @return The samplerate of the currently playing item. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_audiosamplerate `Player.Process(audiosamplerate)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Player.Process(audiobitspersample)`</b>, +/// \anchor Player_Process_audiobitspersample +/// _string_, +/// @return The bits per sample of the currently playing item. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Player_Process_audiobitspersample `Player.Process(audiobitspersample)`\endlink +/// <p> +/// } +/// \table_end +/// +/// ----------------------------------------------------------------------------- + +const infomap player_process[] = +{ + { "videodecoder", PLAYER_PROCESS_VIDEODECODER }, + { "deintmethod", PLAYER_PROCESS_DEINTMETHOD }, + { "pixformat", PLAYER_PROCESS_PIXELFORMAT }, + { "videowidth", PLAYER_PROCESS_VIDEOWIDTH }, + { "videoheight", PLAYER_PROCESS_VIDEOHEIGHT }, + { "videofps", PLAYER_PROCESS_VIDEOFPS }, + { "videodar", PLAYER_PROCESS_VIDEODAR }, + { "videohwdecoder", PLAYER_PROCESS_VIDEOHWDECODER }, + { "audiodecoder", PLAYER_PROCESS_AUDIODECODER }, + { "audiochannels", PLAYER_PROCESS_AUDIOCHANNELS }, + { "audiosamplerate", PLAYER_PROCESS_AUDIOSAMPLERATE }, + { "audiobitspersample", PLAYER_PROCESS_AUDIOBITSPERSAMPLE } +}; + +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Weather Weather /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Weather.IsFetched`</b>, /// \anchor Weather_IsFetched /// _boolean_, -/// Returns true if the weather data has been downloaded. +/// @return **True** if the weather data has been downloaded. +/// <p> /// } /// \table_row3{ <b>`Weather.Conditions`</b>, /// \anchor Weather_Conditions /// _string_, -/// Current weather conditions as textual description – this is looked up in a background process. +/// @return The current weather conditions as textual description. +/// @note This is looked up in a background process. +/// <p> /// } /// \table_row3{ <b>`Weather.ConditionsIcon`</b>, /// \anchor Weather_ConditionsIcon /// _string_, -/// Current weather conditions as icon – this is looked up in a background process. +/// @return The current weather conditions as an icon. +/// @note This is looked up in a background process. +/// <p> /// } /// \table_row3{ <b>`Weather.Temperature`</b>, /// \anchor Weather_Temperature /// _string_, -/// Current weather temperature +/// @return The current weather temperature. +/// <p> /// } /// \table_row3{ <b>`Weather.Location`</b>, /// \anchor Weather_Location /// _string_, -/// City/town which the above two items are for +/// @return The city/town which the above two items are for. +/// <p> /// } -/// \table_row3{ <b>`Weather.fanartcode`</b>, +/// \table_row3{ <b>`Weather.Fanartcode`</b>, /// \anchor Weather_fanartcode /// _string_, -/// Current weather fanartcode. +/// @return The current weather fanartcode. +/// <p> /// } -/// \table_row3{ <b>`Weather.plugin`</b>, +/// \table_row3{ <b>`Weather.Plugin`</b>, /// \anchor Weather_plugin /// _string_, -/// Current weather plugin. +/// @return The current weather plugin. +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap weather[] = {{ "isfetched", WEATHER_IS_FETCHED }, { "conditions", WEATHER_CONDITIONS_TEXT }, // labels from here { "temperature", WEATHER_TEMPERATURE }, @@ -645,468 +971,614 @@ const infomap weather[] = {{ "isfetched", WEATHER_IS_FETCHED }, { "plugin", WEATHER_PLUGIN }, { "conditionsicon", WEATHER_CONDITIONS_ICON }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_System System -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_System System +/// @todo some values are hardcoded in the middle of the code - refactor to make it easier to track /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`System.AlarmLessOrEqual(alarmname\,seconds)`</b>, /// \anchor System_AlarmLessOrEqual /// _boolean_, -/// Returns true if the alarm with `alarmname` has less or equal to `seconds` -/// left. Standard use would be system.alarmlessorequal(shutdowntimer\,119)\, -/// which would return true when the shutdowntimer has less then 2 minutes +/// @return **True** if the alarm with `alarmname` has less or equal to `seconds` left. +/// @param alarmname - The name of the alarm. It can be one of the following: +/// - shutdowntimer +/// @param seconds - Time in seconds to compare with the alarm trigger event +/// @note **Example:** `System.Alarmlessorequal(shutdowntimer\,119)`\, +/// will return true when the shutdowntimer has less then 2 minutes /// left. +/// <p> /// } /// \table_row3{ <b>`System.HasNetwork`</b>, /// \anchor System_HasNetwork /// _boolean_, -/// Returns true if the ethernet cable is plugged in. +/// @return **True** if the Kodi host has a network available. +/// <p> /// } /// \table_row3{ <b>`System.HasMediadvd`</b>, /// \anchor System_HasMediadvd /// _boolean_, -/// Returns true if there is a CD or DVD in the DVD-ROM drive. +/// @return **True** if there is a CD or DVD in the DVD-ROM drive. +/// <p> /// } /// \table_row3{ <b>`System.DVDReady`</b>, /// \anchor System_DVDReady /// _boolean_, -/// Returns true if disc is ready to use. +/// @return **True** if the disc is ready to use. +/// <p> /// } /// \table_row3{ <b>`System.TrayOpen`</b>, /// \anchor System_TrayOpen /// _boolean_, -/// Returns true if discs tray is open +/// @return **True** if the disc tray is open. +/// <p> /// } /// \table_row3{ <b>`System.HasLocks`</b>, /// \anchor System_HasLocks /// _boolean_, -/// Returns true if system has an active lock mode. +/// @return **True** if the system has an active lock mode. +/// <p> /// } /// \table_row3{ <b>`System.IsMaster`</b>, /// \anchor System_IsMaster /// _boolean_, -/// Returns true if system is in master mode. +/// @return **True** if the system is in master mode. +/// <p> /// } /// \table_row3{ <b>`System.ShowExitButton`</b>, /// \anchor System_ShowExitButton /// _boolean_, -/// Returns true if the exit button should be shown (configurable via advanced settings). +/// @return **True** if the exit button should be shown (configurable via advanced settings). +/// <p> /// } /// \table_row3{ <b>`System.DPMSActive`</b>, /// \anchor System_DPMSActive /// _boolean_, -/// Returns true if DPMS (VESA Display Power Management Signaling) mode is active. -/// } -/// \table_row3{ <b>`System.IdleTime(time)`</b>, -/// \anchor System_IdleTime -/// _boolean_, -/// Returns true if Kodi has had no input for ?time? amount of seconds. +/// @return **True** if DPMS (VESA Display Power Management Signaling) mode is active. +/// <p> /// } /// \table_row3{ <b>`System.IsStandalone`</b>, /// \anchor System_IsStandalone /// _boolean_, -/// Returns true if Kodi is running in standalone mode. +/// @return **True** if Kodi is running in standalone mode. +/// <p> /// } /// \table_row3{ <b>`System.IsFullscreen`</b>, /// \anchor System_IsFullscreen /// _boolean_, -/// Returns true if Kodi is running fullscreen. +/// @return **True** if Kodi is running fullscreen. +/// <p> /// } /// \table_row3{ <b>`System.LoggedOn`</b>, /// \anchor System_LoggedOn /// _boolean_, -/// Returns true if a user is currently logged on under a profile +/// @return **True** if a user is currently logged on under a profile. +/// <p> /// } /// \table_row3{ <b>`System.HasLoginScreen`</b>, /// \anchor System_HasLoginScreen /// _boolean_, -/// Returns true if the profile login screen is enabled +/// @return **True** if the profile login screen is enabled. +/// <p> /// } /// \table_row3{ <b>`System.HasPVR`</b>, /// \anchor System_HasPVR /// _boolean_, -/// Returns true if PVR is supported from Kodi -/// \note normally always true +/// @return **True** if PVR is supported from Kodi. +/// @note normally always true +/// /// } -/// \table_row3{ <b>`System.HasPVRAddon(id)`</b>, +/// \table_row3{ <b>`System.HasPVRAddon`</b>, /// \anchor System_HasPVRAddon /// _boolean_, -/// Returns true if at least one pvr client addon is installed and enabled. +/// @return **True** if at least one pvr client addon is installed and enabled. +/// @param id - addon id of the PVR addon +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link System_HasPVRAddon `System.HasPVRAddon`\endlink +/// <p> /// } /// \table_row3{ <b>`System.HasCMS`</b>, /// \anchor System_HasCMS /// _boolean_, -/// Returns true if colour management is supported from Kodi -/// \note currently only supported for OpenGL +/// @return **True** if colour management is supported from Kodi. +/// @note currently only supported for OpenGL +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link System_HasCMS `System.HasCMS`\endlink +/// <p> /// } /// \table_row3{ <b>`System.HasActiveModalDialog`</b>, /// \anchor System_HasActiveModalDialog /// _boolean_, -/// Returns true if a modal dialog is active +/// @return **True** if a modal dialog is active. +/// <p><hr> +/// @skinning_v18 **[New Boolean Condition]** \link System_HasActiveModalDialog `System.HasActiveModalDialog`\endlink +/// <p> /// } /// \table_row3{ <b>`System.HasVisibleModalDialog`</b>, /// \anchor System_HasVisibleModalDialog /// _boolean_, -/// Returns true if a modal dialog is visible -/// } -/// \table_row3{ <b>`System.Time(startTime\,endTime)`</b>, -/// \anchor System_Time -/// _boolean_, -/// Returns true if the current system time is >= startTime and < endTime. -/// endTime is optional. Time must be specified in the format HH:mm\, using -/// a 24 hour clock. -/// } -/// \table_row3{ <b>`System.Date(startDate\,endDate)`</b>, -/// \anchor System_Date -/// _boolean_, -/// Returns true if the current system date is >= startDate and < endDate. -/// endDate is optional. Date must be specified in the format MM-DD. +/// @return **True** if a modal dialog is visible. +/// <p><hr> +/// @skinning_v18 **[New Boolean Condition]** \link System_HasVisibleModalDialog `System.HasVisibleModalDialog`\endlink +/// <p> /// } /// \table_row3{ <b>`System.Platform.Linux`</b>, /// \anchor System_PlatformLinux /// _boolean_, -/// Returns true if Kodi is running on a linux/unix based computer. +/// @return **True** if Kodi is running on a linux/unix based computer. +/// <p> /// } /// \table_row3{ <b>`System.Platform.Linux.RaspberryPi`</b>, /// \anchor System_PlatformLinuxRaspberryPi /// _boolean_, -/// Returns true if Kodi is running on a Raspberry Pi. +/// @return **True** if Kodi is running on a Raspberry Pi. +/// <p><hr> +/// @skinning_v13 **[New Boolean Condition]** \link System_PlatformLinuxRaspberryPi `System.Platform.Linux.RaspberryPi`\endlink +/// <p> /// } /// \table_row3{ <b>`System.Platform.Windows`</b>, /// \anchor System_PlatformWindows /// _boolean_, -/// Returns true if Kodi is running on a windows based computer. +/// @return **True** if Kodi is running on a windows based computer. +/// <p> /// } /// \table_row3{ <b>`System.Platform.UWP`</b>, /// \anchor System_PlatformUWP /// _boolean_, -/// Returns true if Kodi is running on Universal Windows Platform (UWP). +/// @return **True** if Kodi is running on Universal Windows Platform (UWP). +/// <p><hr> +/// @skinning_v18 **[New Boolean Condition]** \link System_PlatformUWP `System.Platform.UWP`\endlink +/// <p> /// } /// \table_row3{ <b>`System.Platform.OSX`</b>, /// \anchor System_PlatformOSX /// _boolean_, -/// Returns true if Kodi is running on an OSX based computer. +/// @return **True** if Kodi is running on an OSX based computer. +/// <p> /// } /// \table_row3{ <b>`System.Platform.IOS`</b>, /// \anchor System_PlatformIOS /// _boolean_, -/// Returns true if Kodi is running on an IOS device. +/// @return **True** if Kodi is running on an IOS device. +/// <p> /// } /// \table_row3{ <b>`System.Platform.Darwin`</b>, /// \anchor System_PlatformDarwin /// _boolean_, -/// Returns true if Kodi is running on an OSX or IOS system. -/// } -/// \table_row3{ <b>`System.Platform.ATV2`</b>, -/// \anchor System_PlatformATV2 -/// _boolean_, -/// Returns true if Kodi is running on an atv2. +/// @return **True** if Kodi is running on an OSX or IOS system. +/// <p> /// } /// \table_row3{ <b>`System.Platform.Android`</b>, /// \anchor System_PlatformAndroid /// _boolean_, -/// Returns true if Kodi is running on an android device. +/// @return **True** if Kodi is running on an android device. +/// <p> /// } /// \table_row3{ <b>`System.CanPowerDown`</b>, /// \anchor System_CanPowerDown /// _boolean_, -/// Returns true if Kodi can powerdown the system. +/// @return **True** if Kodi can powerdown the system. +/// <p> /// } /// \table_row3{ <b>`System.CanSuspend`</b>, /// \anchor System_CanSuspend /// _boolean_, -/// Returns true if Kodi can suspend the system. +/// @return **True** if Kodi can suspend the system. +/// <p> /// } /// \table_row3{ <b>`System.CanHibernate`</b>, /// \anchor System_CanHibernate /// _boolean_, -/// Returns true if Kodi can hibernate the system. +/// @return **True** if Kodi can hibernate the system. +/// <p> /// } /// \table_row3{ <b>`System.HasHiddenInput`</b>, /// \anchor System_HasHiddenInput /// _boolean_, -/// Return true when to osd keyboard/numeric dialog requests a +/// @return **True** when to osd keyboard/numeric dialog requests a /// password/pincode. +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \link System_HasHiddenInput `System.HasHiddenInput`\endlink +/// <p> /// } /// \table_row3{ <b>`System.CanReboot`</b>, /// \anchor System_CanReboot /// _boolean_, -/// Returns true if Kodi can reboot the system. +/// @return **True** if Kodi can reboot the system. +/// <p> /// } /// \table_row3{ <b>`System.ScreenSaverActive`</b>, /// \anchor System_ScreenSaverActive /// _boolean_, -/// Returns true if ScreenSaver is active. +/// @return **True** if ScreenSaver is active. +/// <p> /// } /// \table_row3{ <b>`System.IsInhibit`</b>, /// \anchor System_IsInhibit /// _boolean_, -/// Returns true when shutdown on idle is disabled. +/// @return **True** when shutdown on idle is disabled. +/// <p> /// } /// \table_row3{ <b>`System.HasShutdown`</b>, /// \anchor System_HasShutdown /// _boolean_, -/// Returns true when shutdown on idle is enabled. +/// @return **True** when shutdown on idle is enabled. +/// <p> /// } /// \table_row3{ <b>`System.Time`</b>, /// \anchor System_Time /// _string_, -/// Current time +/// @return The current time. +/// <p> /// } /// \table_row3{ <b>`System.Time(format)`</b>, /// \anchor System_Time_format /// _string_, -/// Returns hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The current time in a specified format. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> +/// } +/// \table_row3{ <b>`System.Time(startTime[\,endTime])`</b>, +/// \anchor System_Time +/// _boolean_, +/// @return **True** if the current system time is >= `startTime` and < `endTime` (if defined). +/// @param startTime - Start time +/// @param endTime - [opt] End time +/// <p> +/// @note Time must be specified in the format HH:mm\, using +/// a 24 hour clock. +/// <p> /// } /// \table_row3{ <b>`System.Date`</b>, /// \anchor System_Date /// _string_, -/// Current date +/// @return The current date. +/// <p><hr> +/// @skinning_v16 **[Infolabel Updated]** \link System_Date `System.Date`\endlink +/// will now return the full day and month names. old: sat\, jul 18 2015 +/// new: saturday\, july 18 2015 +/// <p> /// } /// \table_row3{ <b>`System.Date(format)`</b>, /// \anchor System_Date_format /// _string_, -/// Show current date using format\, available markings: d (day of month -/// 1-31)\, dd (day of month 01-31)\, ddd (short day of the week Mon-Sun)\, -/// DDD (long day of the week Monday-Sunday)\, m (month 1-12)\, mm (month -/// 01-12)\, mmm (short month name Jan-Dec)\, MMM (long month name January - -/// December)\, yy (2-digit year)\, yyyy (4-digit year). Added after dharma. +/// @return The current date using a specified format. +/// @param format - the format for the date. It can be one of the following +/// values: +/// - **d** - day of month (1-31) +/// - **dd** - day of month (01-31) +/// - **ddd** - short day of the week Mon-Sun +/// - **DDD** - long day of the week Monday-Sunday +/// - **m** - month (1-12) +/// - **mm** - month (01-12) +/// - **mmm** - short month name Jan-Dec +/// - **MMM** - long month name January-December +/// - **yy** - 2-digit year +/// - **yyyy** - 4-digit year +/// <p> +/// } +/// \table_row3{ <b>`System.Date(startDate[\,endDate])`</b>, +/// \anchor System_Date +/// _boolean_, +/// @return **True** if the current system date is >= `startDate` and < `endDate` (if defined). +/// @param startDate - The start date +/// @param endDate - [opt] The end date +/// @note Date must be specified in the format MM-DD or YY-MM-DD. +/// <p> /// } /// \table_row3{ <b>`System.AlarmPos`</b>, /// \anchor System_AlarmPos /// _string_, -/// Shutdown Timer position +/// @return The shutdown Timer position. +/// <p> /// } /// \table_row3{ <b>`System.BatteryLevel`</b>, /// \anchor System_BatteryLevel /// _string_, -/// Returns the remaining battery level in range 0-100 +/// @return The remaining battery level in range 0-100. +/// <p> /// } /// \table_row3{ <b>`System.FreeSpace`</b>, /// \anchor System_FreeSpace /// _string_, -/// Total Freespace on the drive +/// @return The total Freespace on the drive. +/// <p> /// } /// \table_row3{ <b>`System.UsedSpace`</b>, /// \anchor System_UsedSpace /// _string_, -/// Total Usedspace on the drive +/// @return The total Usedspace on the drive. +/// <p> /// } /// \table_row3{ <b>`System.TotalSpace`</b>, /// \anchor System_TotalSpace /// _string_, -/// Totalspace on the drive +/// @return The total space on the drive. +/// <p> /// } /// \table_row3{ <b>`System.UsedSpacePercent`</b>, /// \anchor System_UsedSpacePercent /// _string_, -/// Total Usedspace Percent on the drive +/// @return The total Usedspace Percent on the drive. +/// <p> /// } /// \table_row3{ <b>`System.FreeSpacePercent`</b>, /// \anchor System_FreeSpacePercent /// _string_, -/// Total Freespace Percent on the drive +/// @return The total Freespace Percent on the drive. +/// <p> /// } /// \table_row3{ <b>`System.CPUTemperature`</b>, /// \anchor System_CPUTemperature /// _string_, -/// Current CPU temperature +/// @return The current CPU temperature. +/// <p> /// } /// \table_row3{ <b>`System.CpuUsage`</b>, /// \anchor System_CpuUsage /// _string_, -/// Displays the cpu usage for each individual cpu core. +/// @return The the cpu usage for each individual cpu core. +/// <p> /// } /// \table_row3{ <b>`System.GPUTemperature`</b>, /// \anchor System_GPUTemperature /// _string_, -/// Current GPU temperature +/// @return The current GPU temperature. +/// <p> /// } /// \table_row3{ <b>`System.FanSpeed`</b>, /// \anchor System_FanSpeed /// _string_, -/// Current fan speed +/// @return The current fan speed. +/// <p> /// } /// \table_row3{ <b>`System.BuildVersion`</b>, /// \anchor System_BuildVersion /// _string_, -/// Version of build +/// @return The version of build. +/// <p> /// } /// \table_row3{ <b>`System.BuildVersionShort`</b>, /// \anchor System_BuildVersionShort /// _string_, -/// Shorter string with version of build +/// @return The shorter string with version of build. +/// <p> /// } /// \table_row3{ <b>`System.BuildDate`</b>, /// \anchor System_BuildDate /// _string_, -/// Date of build +/// @return The date of build. +/// <p> /// } /// \table_row3{ <b>`System.FriendlyName`</b>, /// \anchor System_FriendlyName /// _string_, -/// Returns the Kodi instance name. It will auto append (%hostname%) in case +/// @return The Kodi instance name. +/// @note It will auto append (%hostname%) in case /// the device name was not changed. eg. "Kodi (htpc)" +/// <p> /// } /// \table_row3{ <b>`System.FPS`</b>, /// \anchor System_FPS /// _string_, -/// Current rendering speed (frames per second) +/// @return The current rendering speed (frames per second). +/// <p> /// } /// \table_row3{ <b>`System.FreeMemory`</b>, /// \anchor System_FreeMemory /// _string_, -/// Amount of free memory in Mb +/// @return The amount of free memory in Mb. +/// <p> /// } /// \table_row3{ <b>`System.ScreenMode`</b>, /// \anchor System_ScreenMode /// _string_, -/// Screenmode (eg windowed / fullscreen) +/// @return The screenmode (eg windowed / fullscreen). +/// <p> /// } /// \table_row3{ <b>`System.ScreenWidth`</b>, /// \anchor System_ScreenWidth /// _string_, -/// Width of screen in pixels +/// @return The width of screen in pixels. +/// <p> /// } /// \table_row3{ <b>`System.ScreenHeight`</b>, /// \anchor System_ScreenHeight /// _string_, -/// Height of screen in pixels +/// @return The height of screen in pixels. +/// <p> /// } /// \table_row3{ <b>`System.StartupWindow`</b>, /// \anchor System_StartupWindow /// _string_, -/// The Window Kodi will load on startup +/// @return The Window Kodi will load on startup. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link System_StartupWindow `System.StartupWindow`\endlink +/// <p> /// } /// \table_row3{ <b>`System.CurrentWindow`</b>, /// \anchor System_CurrentWindow /// _string_, -/// Current Window we are in +/// @return The current Window in use. +/// <p> /// } /// \table_row3{ <b>`System.CurrentControl`</b>, /// \anchor System_CurrentControl /// _string_, -/// Current focused control +/// @return The current focused control +/// <p> /// } /// \table_row3{ <b>`System.CurrentControlId`</b>, /// \anchor System_CurrentControlId /// _string_, -/// ID of the currently focused control. +/// @return The ID of the currently focused control. +/// <p> /// } /// \table_row3{ <b>`System.DVDLabel`</b>, /// \anchor System_DVDLabel /// _string_, -/// Label of the disk in the DVD-ROM drive +/// @return the label of the disk in the DVD-ROM drive. +/// <p> /// } /// \table_row3{ <b>`System.KernelVersion`</b>, /// \anchor System_KernelVersion /// _string_, -/// System kernel version +/// @return The System kernel version. +/// <p> /// } /// \table_row3{ <b>`System.OSVersionInfo`</b>, /// \anchor System_OSVersionInfo /// _string_, -/// System name + kernel version +/// @return The system name + kernel version. +/// <p> /// } /// \table_row3{ <b>`System.Uptime`</b>, /// \anchor System_Uptime /// _string_, -/// System current uptime +/// @return The system current uptime. +/// <p> /// } /// \table_row3{ <b>`System.TotalUptime`</b>, /// \anchor System_TotalUptime /// _string_, -/// System total uptime +/// @return The system total uptime. +/// <p> /// } /// \table_row3{ <b>`System.CpuFrequency`</b>, /// \anchor System_CpuFrequency /// _string_, -/// System cpu frequency +/// @return The system cpu frequency. +/// <p> /// } /// \table_row3{ <b>`System.ScreenResolution`</b>, /// \anchor System_ScreenResolution /// _string_, -/// Screen resolution +/// @return The screen resolution. +/// <p> /// } /// \table_row3{ <b>`System.VideoEncoderInfo`</b>, /// \anchor System_VideoEncoderInfo /// _string_, -/// Video encoder info +/// @return The video encoder info. +/// <p> /// } /// \table_row3{ <b>`System.InternetState`</b>, /// \anchor System_InternetState /// _string_, -/// Will return the internet state\, connected or not connected and for -/// Conditional use: Connected->TRUE\, not Connected->FALSE\, do not use -/// to check status in a pythonscript since it is threaded. +/// @return The internet state: connected or not connected. +/// @warning Do not use to check status in a pythonscript since it is threaded. +/// <p> /// } /// \table_row3{ <b>`System.Language`</b>, /// \anchor System_Language /// _string_, -/// Returns the current language +/// @return the current language. +/// <p> /// } /// \table_row3{ <b>`System.ProfileName`</b>, /// \anchor System_ProfileName /// _string_, -/// Returns the user name of the currently logged in Kodi user +/// @return The user name of the currently logged in Kodi user +/// <p> /// } /// \table_row3{ <b>`System.ProfileThumb`</b>, /// \anchor System_ProfileThumb /// _string_, -/// Returns the thumbnail image of the currently logged in Kodi user +/// @return The thumbnail image of the currently logged in Kodi user +/// <p> /// } /// \table_row3{ <b>`System.ProfileCount`</b>, /// \anchor System_ProfileCount /// _string_, -/// Returns the number of defined profiles +/// @return The number of defined profiles. +/// <p> /// } /// \table_row3{ <b>`System.ProfileAutoLogin`</b>, /// \anchor System_ProfileAutoLogin /// _string_, -/// The profile Kodi will auto login to +/// @return The profile Kodi will auto login to. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link System_ProfileAutoLogin `System.ProfileAutoLogin`\endlink +/// <p> /// } /// \table_row3{ <b>`System.StereoscopicMode`</b>, /// \anchor System_StereoscopicMode /// _string_, -/// The prefered stereoscopic mode (settings > video > playback) +/// @return The prefered stereoscopic mode. +/// @note Configured in settings > video > playback). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link System_StereoscopicMode `System.StereoscopicMode`\endlink +/// <p> /// } /// \table_row3{ <b>`System.TemperatureUnits`</b>, /// \anchor System_TemperatureUnits /// _string_, -/// Returns Celsius or Fahrenheit symbol +/// @return the Celsius or the Fahrenheit symbol. +/// <p> /// } /// \table_row3{ <b>`System.Progressbar`</b>, /// \anchor System_Progressbar /// _string_, -/// Returns the percentage of the currently active progress. +/// @return The percentage of the currently active progress. +/// <p> /// } /// \table_row3{ <b>`System.GetBool(boolean)`</b>, /// \anchor System_GetBool /// _string_, -/// Returns the value of any standard system boolean setting. Will not work -/// with settings in advancedsettings.xml +/// @return The value of any standard system boolean setting. +/// @note Will not work with settings in advancedsettings.xml +/// <p> +/// } +/// \table_row3{ <b>`System.Memory(type)`</b>, +/// \anchor System_Memory +/// _string_, +/// @return The memory value depending on the requested type. +/// @param type - Can be one of the following: +/// - <b>free</b> +/// - <b>free.percent</b> +/// - <b>used</b> +/// - <b>used.percent</b> +/// - <b>total</b> +/// <p> /// } /// \table_row3{ <b>`System.AddonTitle(id)`</b>, /// \anchor System_AddonTitle /// _string_, -/// Returns the title of the addon with the given id +/// @return The title of the addon with the given id +/// @param id - the addon id +/// <p> /// } /// \table_row3{ <b>`System.AddonVersion(id)`</b>, /// \anchor System_AddonVersion /// _string_, -/// Returns the version of the addon with the given id +/// @return The version of the addon with the given id. +/// @param id - the addon id +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link System_AddonVersion `System.AddonVersion(id)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`System.AddonIcon(id)`</b>, +/// \anchor System_AddonVersion +/// _string_, +/// @return The icon of the addon with the given id. +/// @param id - the addon id +/// <p> +/// } +/// \table_row3{ <b>`System.IdleTime(time)`</b>, +/// \anchor System_IdleTime +/// _boolean_, +/// @return **True** if Kodi has had no input for `time` amount of seconds. +/// @param time - elapsed seconds to check for idle activity. +/// <p> /// } /// \table_row3{ <b>`System.PrivacyPolicy`</b>, /// \anchor System_PrivacyPolicy /// _string_, -/// Returns the official Kodi privacy policy +/// @return The official Kodi privacy policy. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link System_PrivacyPolicy `System.PrivacyPolicy`\endlink +/// <p> /// } -/// \table_end -/// @} const infomap system_labels[] = {{ "hasnetwork", SYSTEM_ETHERNET_LINK_ACTIVE }, { "hasmediadvd", SYSTEM_MEDIA_DVD }, { "dvdready", SYSTEM_DVDREADY }, @@ -1175,98 +1647,112 @@ const infomap system_labels[] = {{ "hasnetwork", SYSTEM_ETHERNET_LINK_ACT { "privacypolicy", SYSTEM_PRIVACY_POLICY }, { "haspvraddon", SYSTEM_HAS_PVR_ADDON }}; -/// \page modules__General__List_of_gui_access -/// @{ -/// \table_start +/// \page modules__infolabels_boolean_conditions /// \table_row3{ <b>`System.HasAddon(id)`</b>, /// \anchor System_HasAddon /// _boolean_, -/// Returns true if the specified addon is installed on the system. +/// @return **True** if the specified addon is installed on the system. +/// @param id - the addon id +/// <p> /// } /// \table_row3{ <b>`System.HasCoreId(id)`</b>, /// \anchor System_HasCoreId /// _boolean_, -/// Returns true if the cpu core with the given 'id' exists. +/// @return **True** if the CPU core with the given 'id' exists. +/// @param id - the id of the CPU core +/// <p> /// } /// \table_row3{ <b>`System.HasAlarm(alarm)`</b>, /// \anchor System_HasAlarm /// _boolean_, -/// Returns true if the system has the ?alarm? alarm set. +/// @return **True** if the system has the `alarm` alarm set. +/// @param alarm - the name of the alarm +/// <p> /// } /// \table_row3{ <b>`System.CoreUsage(id)`</b>, /// \anchor System_CoreUsage /// _string_, -/// Displays the usage of the cpu core with the given 'id' +/// @return the usage of the CPU core with the given 'id' +/// @param id - the id of the CPU core +/// <p> /// } /// \table_row3{ <b>`System.Setting(hidewatched)`</b>, /// \anchor System_Setting /// _boolean_, -/// Returns true if 'hide watched items' is selected. +/// @return **True** if 'hide watched items' is selected. +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap system_param[] = {{ "hasalarm", SYSTEM_HAS_ALARM }, { "hascoreid", SYSTEM_HAS_CORE_ID }, { "setting", SYSTEM_SETTING }, { "hasaddon", SYSTEM_HAS_ADDON }, { "coreusage", SYSTEM_GET_CORE_USAGE }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Network Network -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Network Network /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Network.IsDHCP`</b>, /// \anchor Network_IsDHCP /// _boolean_, -/// Network type is DHCP or FIXED +/// @return **True** if the network type is DHCP. +/// @note Network type can be either DHCP or FIXED +/// <p> /// } /// \table_row3{ <b>`Network.IPAddress`</b>, /// \anchor Network_IPAddress /// _string_, -/// The system's IP Address (formatted as IP: <ipaddress>) +/// @return The system's IP Address. e.g. 192.168.1.15 +/// <p> /// } /// \table_row3{ <b>`Network.LinkState`</b>, /// \anchor Network_LinkState /// _string_, -/// Network linkstate e.g. 10mbit/100mbit etc. +/// @return The network linkstate e.g. 10mbit/100mbit etc. +/// <p> /// } /// \table_row3{ <b>`Network.MacAddress`</b>, /// \anchor Network_MacAddress /// _string_, -/// The system's mac address +/// @return The system's MAC address. +/// <p> /// } /// \table_row3{ <b>`Network.SubnetMask`</b>, /// \anchor Network_SubnetMask /// _string_, -/// Network subnet mask +/// @return The network subnet mask. +/// <p> /// } /// \table_row3{ <b>`Network.GatewayAddress`</b>, /// \anchor Network_GatewayAddress /// _string_, -/// Network gateway address +/// @return The network gateway address. +/// <p> /// } /// \table_row3{ <b>`Network.DNS1Address`</b>, /// \anchor Network_DNS1Address /// _string_, -/// Network dns 1 address +/// @return The network DNS 1 address. +/// <p> /// } /// \table_row3{ <b>`Network.DNS2Address`</b>, /// \anchor Network_DNS2Address /// _string_, -/// Network dns 2 address +/// @return The network DNS 2 address. +/// <p> /// } /// \table_row3{ <b>`Network.DHCPAddress`</b>, /// \anchor Network_DHCPAddress /// _string_, -/// DHCP ip address +/// @return The DHCP IP address. +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap network_labels[] = {{ "isdhcp", NETWORK_IS_DHCP }, { "ipaddress", NETWORK_IP_ADDRESS }, //labels from here { "linkstate", NETWORK_LINK_STATE }, @@ -1277,377 +1763,715 @@ const infomap network_labels[] = {{ "isdhcp", NETWORK_IS_DHCP }, { "dns2address", NETWORK_DNS2_ADDRESS }, { "dhcpaddress", NETWORK_DHCP_ADDRESS }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_musicpartymode Music party mode -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_musicpartymode Music party mode /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`MusicPartyMode.Enabled`</b>, /// \anchor MusicPartyMode_Enabled /// _boolean_, -/// Returns true if Party Mode is enabled +/// @return **True** if Party Mode is enabled. +/// <p> /// } /// \table_row3{ <b>`MusicPartyMode.SongsPlayed`</b>, /// \anchor MusicPartyMode_SongsPlayed /// _string_, -/// Number of songs played during Party Mode +/// @return The number of songs played during Party Mode. +/// <p> /// } /// \table_row3{ <b>`MusicPartyMode.MatchingSongs`</b>, /// \anchor MusicPartyMode_MatchingSongs /// _string_, -/// Number of songs available to Party Mode +/// @return The number of songs available to Party Mode. +/// <p> /// } /// \table_row3{ <b>`MusicPartyMode.MatchingSongsPicked`</b>, /// \anchor MusicPartyMode_MatchingSongsPicked /// _string_, -/// Number of songs picked already for Party Mode +/// @return The number of songs picked already for Party Mode. +/// <p> /// } /// \table_row3{ <b>`MusicPartyMode.MatchingSongsLeft`</b>, /// \anchor MusicPartyMode_MatchingSongsLeft /// _string_, -/// Number of songs left to be picked from for Party Mode +/// @return The number of songs left to be picked from for Party Mode. +/// <p> /// } /// \table_row3{ <b>`MusicPartyMode.RelaxedSongsPicked`</b>, /// \anchor MusicPartyMode_RelaxedSongsPicked /// _string_, -/// Not currently used +/// @todo Not currently used +/// <p> /// } /// \table_row3{ <b>`MusicPartyMode.RandomSongsPicked`</b>, /// \anchor MusicPartyMode_RandomSongsPicked /// _string_, -/// Number of unique random songs picked during Party Mode +/// @return The number of unique random songs picked during Party Mode. +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap musicpartymode[] = {{ "enabled", MUSICPM_ENABLED }, { "songsplayed", MUSICPM_SONGSPLAYED }, { "matchingsongs", MUSICPM_MATCHINGSONGS }, { "matchingsongspicked", MUSICPM_MATCHINGSONGSPICKED }, { "matchingsongsleft", MUSICPM_MATCHINGSONGSLEFT }, - { "relaxedsongspicked",MUSICPM_RELAXEDSONGSPICKED }, + { "relaxedsongspicked", MUSICPM_RELAXEDSONGSPICKED }, { "randomsongspicked", MUSICPM_RANDOMSONGSPICKED }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_MusicPlayer Music player -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_MusicPlayer Music player /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`MusicPlayer.Offset(number).Exists`</b>, /// \anchor MusicPlayer_Offset /// _boolean_, -/// Returns true if the music players playlist has a song queued in +/// @return **True** if the music players playlist has a song queued in /// position (number). +/// @param number - song position +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Title`</b>, /// \anchor MusicPlayer_Title /// _string_, -/// Title of the currently playing song\, also available are -/// "MusicPlayer.offset(number).Title" offset is relative to the current -/// playing item and "MusicPlayer.Position(number).Title" position is relative -/// to the start of the playlist +/// @return The title of the currently playing song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).Title`</b>, +/// \anchor MusicPlayer_Offset_Title +/// _string_, +/// @return The title of the song which has an offset `number` with respect to the +/// current playing song. +/// @param number - the offset number with respect to the current playing song +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).Title`</b>, +/// \anchor MusicPlayer_Position_Title +/// _string_, +/// @return The title of the song which as an offset `number` with respect to the +/// start of the playlist. +/// @param number - the offset number with respect to the start of the playlist +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Album`</b>, /// \anchor MusicPlayer_Album /// _string_, -/// Album from which the current song is from\, also available are -/// "MusicPlayer.offset(number).Album" offset is relative to the current -/// playing item and "MusicPlayer.Position(number).Album" position is relative -/// to the start of the playlist +/// @return The album from which the current song is from. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).Album`</b>, +/// \anchor MusicPlayer_OffSet_Album +/// _string_, +/// @return The album from which the song with offset `number` with respect to +/// the current song is from. +/// @param number - the offset number with respect to the current playing song +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).Album`</b>, +/// \anchor MusicPlayer_Position_Album +/// _string_, +/// @return The album from which the song with offset `number` with respect to +/// the start of the playlist is from. +/// @param number - the offset number with respect to the start of the playlist +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Album_Mood)`</b>, /// \anchor MusicPlayer_Property_Album_Mood /// _string_, -/// Returns the moods of the currently playing Album +/// @return The moods of the currently playing Album +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Composer)`</b>, +/// \anchor MusicPlayer_Property_Role_Composer +/// _string_, +/// @return The name of the person who composed the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Composer `MusicPlayer.Property(Role.Composer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Conductor)`</b>, +/// \anchor MusicPlayer_Property_Role_Conductor +/// _string_, +/// @return The name of the person who conducted the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Conductor `MusicPlayer.Property(Role.Conductor)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Orchestra)`</b>, +/// \anchor MusicPlayer_Property_Role_Orchestra +/// _string_, +/// @return The name of the orchestra performing the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Orchestra `MusicPlayer.Property(Role.Orchestra)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Lyricist)`</b>, +/// \anchor MusicPlayer_Property_Role_Lyricist +/// _string_, +/// @return The name of the person who wrote the lyrics of the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Lyricist `MusicPlayer.Property(Role.Lyricist)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Remixer)`</b>, +/// \anchor MusicPlayer_Property_Role_Remixer +/// _string_, +/// @return The name of the person who remixed the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Remixer `MusicPlayer.Property(Role.Remixer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Arranger)`</b>, +/// \anchor MusicPlayer_Property_Role_Arranger +/// _string_, +/// @return The name of the person who arranged the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Arranger `MusicPlayer.Property(Role.Arranger)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Engineer)`</b>, +/// \anchor MusicPlayer_Property_Role_Engineer +/// _string_, +/// @return The name of the person who was the engineer of the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Engineer `MusicPlayer.Property(Role.Engineer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Producer)`</b>, +/// \anchor MusicPlayer_Property_Role_Producer +/// _string_, +/// @return The name of the person who produced the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Producer `MusicPlayer.Property(Role.Producer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.DJMixer)`</b>, +/// \anchor MusicPlayer_Property_Role_DJMixer +/// _string_, +/// @return The name of the dj who remixed the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_DJMixer `MusicPlayer.Property(Role.DJMixer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Role.Mixer)`</b>, +/// \anchor MusicPlayer_Property_Role_Mixer +/// _string_, +/// @return The name of the dj who remixed the selected song. +/// @todo So maybe rather than a row each have one entry for Role.XXXXX with composer\, arranger etc. as listed values +/// @note MusicPlayer.Property(Role.any_custom_role) also works\, +/// where any_custom_role could be an instrument violin or some other production activity e.g. sound engineer. +/// The roles listed (composer\, arranger etc.) are standard ones but there are many possible. +/// Music file tagging allows for the musicians and all other people involved in the recording to be added\, Kodi +/// will gathers and stores that data\, and it is availlable to GUI. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Property_Role_Mixer `MusicPlayer.Property(Role.Mixer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Property(Album_Mood)`</b>, +/// \anchor MusicPlayer_Property_Album_Mood +/// _string_, +/// @return the moods of the currently playing Album +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Album_Style)`</b>, /// \anchor MusicPlayer_Property_Album_Style /// _string_, -/// Returns the styles of the currently playing Album +/// @return the styles of the currently playing Album. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Album_Theme)`</b>, /// \anchor MusicPlayer_Property_Album_Theme /// _string_, -/// Returns the themes of the currently playing Album +/// @return The themes of the currently playing Album +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Album_Type)`</b>, /// \anchor MusicPlayer_Property_Album_Type /// _string_, -/// Returns the album type (e.g. compilation\, enhanced\, explicit lyrics) of the -/// currently playing album +/// @return The album type (e.g. compilation\, enhanced\, explicit lyrics) of the +/// currently playing album. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Album_Label)`</b>, /// \anchor MusicPlayer_Property_Album_Label /// _string_, -/// Returns the record label of the currently playing album +/// @return The record label of the currently playing album. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Album_Description)`</b>, /// \anchor MusicPlayer_Property_Album_Description /// _string_, -/// Returns a review of the currently playing album +/// @return A review of the currently playing album +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Artist`</b>, /// \anchor MusicPlayer_Artist /// _string_, -/// Artist(s) of current song\, also available are -/// "MusicPlayer.offset(number).Artist" offset is relative to the current -/// playing item and "MusicPlayer.Position(number).Artist" position is -/// relative to the start of the playlist +/// @return Artist(s) of current song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).Artist`</b>, +/// \anchor MusicPlayer_Offset_Artist +/// _string_, +/// @return Artist(s) of the song which has an offset `number` with respect +/// to the current playing song. +/// @param number - the offset of the song with respect to the current +/// playing song +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).Artist`</b>, +/// \anchor MusicPlayer_Position_Artist +/// _string_, +/// @return Artist(s) of the song which has an offset `number` with respect +/// to the start of the playlist. +/// @param number - the offset of the song with respect to +/// the start of the playlist +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.AlbumArtist`</b>, /// \anchor MusicPlayer_AlbumArtist /// _string_, -/// Album artist of the currently playing song +/// @return The album artist of the currently playing song. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Cover`</b>, /// \anchor MusicPlayer_Cover /// _string_, -/// Album cover of currently playing song +/// @return The album cover of currently playing song. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Sortname)`</b>, /// \anchor MusicPlayer_Property_Artist_Sortname /// _string_, -/// Sortname of the currently playing Artist +/// @return The sortname of the currently playing Artist. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link MusicPlayer_Property_Artist_Sortname `MusicPlayer.Property(Artist_Sortname)`\endlink +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Type)`</b>, /// \anchor MusicPlayer_Property_Artist_Type /// _string_, -/// Type of the currently playing Artist - person\, group\, orchestra\, choir etc. +/// @return The type of the currently playing Artist - person\, +/// group\, orchestra\, choir etc. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link MusicPlayer_Property_Artist_Type `MusicPlayer.Property(Artist_Type)`\endlink +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Gender)`</b>, /// \anchor MusicPlayer_Property_Artist_Gender /// _string_, -/// Gender of the currently playing Artist - male\, female\, other +/// @return The gender of the currently playing Artist - male\, +/// female\, other. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link MusicPlayer_Property_Artist_Gender `MusicPlayer.Property(Artist_Gender)`\endlink +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Disambiguation)`</b>, /// \anchor MusicPlayer_Property_Artist_Disambiguation /// _string_, -/// Brief description of the currently playing Artist that differentiates them -/// from others with the same name +/// @return A brief description of the currently playing Artist that differentiates them +/// from others with the same name. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link MusicPlayer_Property_Artist_Disambiguation `MusicPlayer.Property(Artist_Disambiguation)`\endlink +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Born)`</b>, /// \anchor MusicPlayer_Property_Artist_Born /// _string_, -/// Date of Birth of the currently playing Artist +/// @return The date of Birth of the currently playing Artist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Died)`</b>, /// \anchor MusicPlayer_Property_Artist_Died /// _string_, -/// Date of Death of the currently playing Artist +/// @return The date of Death of the currently playing Artist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Formed)`</b>, /// \anchor MusicPlayer_Property_Artist_Formed /// _string_, -/// Formation date of the currently playing Artist/Band +/// @return The Formation date of the currently playing Artist/Band. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Disbanded)`</b>, /// \anchor MusicPlayer_Property_Artist_Disbanded /// _string_, -/// Disbanding date of the currently playing Artist/Band +/// @return The disbanding date of the currently playing Artist/Band. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_YearsActive)`</b>, /// \anchor MusicPlayer_Property_Artist_YearsActive /// _string_, -/// Years the currently Playing artist has been active +/// @return The years the currently Playing artist has been active. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Instrument)`</b>, /// \anchor MusicPlayer_Property_Artist_Instrument /// _string_, -/// Instruments played by the currently playing artist +/// @return The instruments played by the currently playing artist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Description)`</b>, /// \anchor MusicPlayer_Property_Artist_Description /// _string_, -/// Returns a biography of the currently playing artist +/// @return A biography of the currently playing artist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Mood)`</b>, /// \anchor MusicPlayer_Property_Artist_Mood /// _string_, -/// Returns the moods of the currently playing artist +/// @return The moods of the currently playing artist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Style)`</b>, /// \anchor MusicPlayer_Property_Artist_Style /// _string_, -/// Returns the styles of the currently playing artist +/// @return The styles of the currently playing artist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(Artist_Genre)`</b>, /// \anchor MusicPlayer_Property_Artist_Genre /// _string_, -/// Returns the genre of the currently playing artist +/// @return The genre of the currently playing artist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Genre`</b>, /// \anchor MusicPlayer_Genre /// _string_, -/// Genre(s) of current song\, also available are -/// "MusicPlayer.offset(number).Genre" offset is relative to the current -/// playing item and "MusicPlayer.Position(number).Genre" position is -/// relative to the start of the playlist +/// @return The genre(s) of current song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).Genre`</b>, +/// \anchor MusicPlayer_OffSet_Genre +/// _string_, +/// @return The genre(s) of the song with an offset `number` with respect +/// to the current playing song. +/// @param number - the offset song number with respect to the current playing +/// song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).Genre`</b>, +/// \anchor MusicPlayer_Position_Genre +/// _string_, +/// @return The genre(s) of the song with an offset `number` with respect +/// to the start of the playlist. +/// @param number - the offset song number with respect to the start of the +/// playlist +/// song. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Lyrics`</b>, /// \anchor MusicPlayer_Lyrics /// _string_, -/// Lyrics of current song stored in ID tag info +/// @return The lyrics of current song stored in ID tag info. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Year`</b>, /// \anchor MusicPlayer_Year /// _string_, -/// Year of release of current song\, also available are -/// "MusicPlayer.offset(number).Year" offset is relative to the current -/// playing item and "MusicPlayer.Position(number).Year" position is -/// relative to the start of the playlist +/// @return The year of release of current song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).Year`</b>, +/// \anchor MusicPlayer_Offset_Year +/// _string_, +/// @return The year of release of the song with an offset `number` with +/// respect to the current playing song. +/// @param number - the offset numbet with respect to the current song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).Year`</b>, +/// \anchor MusicPlayer_Position_Year +/// _string_, +/// @return The year of release of the song with an offset `number` with +/// respect to the start of the playlist. +/// @param number - the offset numbet with respect to the start of the +/// playlist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Rating`</b>, /// \anchor MusicPlayer_Rating /// _string_, -/// Numeric Rating of current song\, also available are -/// "MusicPlayer.offset(number).Rating" offset is relative to the current -/// playing item and "MusicPlayer.Position(number).Rating" position is -/// relative to the start of the playlist +/// @return The numeric Rating of current song (1-10). +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).Rating`</b>, +/// \anchor MusicPlayer_OffSet_Rating +/// _string_, +/// @return The numeric Rating of song with an offset `number` with +/// respect to the current playing song. +/// @param number - the offset with respect to the current playing song +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).Rating`</b>, +/// \anchor MusicPlayer_Position_Rating +/// _string_, +/// @return The numeric Rating of song with an offset `number` with +/// respect to the start of the playlist. +/// @param number - the offset with respect to the start of the playlist +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.RatingAndVotes`</b>, /// \anchor MusicPlayer_RatingAndVotes /// _string_, -/// Returns the scraped rating and votes of currently playing song\, if it's in the database +/// @return The scraped rating and votes of currently playing song\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.UserRating`</b>, /// \anchor MusicPlayer_UserRating /// _string_, -/// Returns the scraped rating of the currently playing song +/// @return The scraped rating of the currently playing song (1-10). +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_UserRating `MusicPlayer.UserRating`\endlink +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Votes`</b>, /// \anchor MusicPlayer_Votes /// _string_, -/// Returns the scraped votes of currently playing song\, if it's in the database +/// @return The scraped votes of currently playing song\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.DiscNumber`</b>, /// \anchor MusicPlayer_DiscNumber /// _string_, -/// Disc Number of current song stored in ID tag info\, also available are -/// "MusicPlayer.offset(number).DiscNumber" offset is relative to the -/// current playing item and "MusicPlayer.Position(number).DiscNumber" -/// position is relative to the start of the playlist +/// @return The Disc Number of current song stored in ID tag info. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).DiscNumber`</b>, +/// \anchor MusicPlayer_Offset_DiscNumber +/// _string_, +/// @return The Disc Number of current song stored in ID tag info for the +/// song with an offset `number` with respect to the playing song. +/// @param number - The offset value for the song with respect to the +/// playing song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).DiscNumber`</b>, +/// \anchor MusicPlayer_Position_DiscNumber +/// _string_, +/// @return The Disc Number of current song stored in ID tag info for the +/// song with an offset `number` with respect to the start of the playlist. +/// @param number - The offset value for the song with respect to the +/// start of the playlist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Comment`</b>, /// \anchor MusicPlayer_Comment /// _string_, -/// Comment of current song stored in ID tag info\, also available are -/// "MusicPlayer.offset(number).Comment" offset is relative to the current -/// playing item and "MusicPlayer.Position(number).Comment" position is -/// relative to the start of the playlist +/// @return The Comment of current song stored in ID tag info. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).Comment`</b>, +/// \anchor MusicPlayer_Offset_Comment +/// _string_, +/// @return The Comment of current song stored in ID tag info for the +/// song with an offset `number` with respect to the playing song. +/// @param number - The offset value for the song with respect to the +/// playing song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).Comment`</b>, +/// \anchor MusicPlayer_Position_Comment +/// _string_, +/// @return The Comment of current song stored in ID tag info for the +/// song with an offset `number` with respect to the start of the playlist. +/// @param number - The offset value for the song with respect to the +/// start of the playlist. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Contributors`</b>, +/// \anchor MusicPlayer_Contributors +/// _string_, +/// @return The list of all people who've contributed to the currently playing song +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Contributors `MusicPlayer.Contributors`\endlink +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.ContributorAndRole`</b>, +/// \anchor MusicPlayer_ContributorAndRole +/// _string_, +/// @return The list of all people and their role who've contributed to the currently playing song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_ContributorAndRole `MusicPlayer.ContributorAndRole`\endlink +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Mood`</b>, /// \anchor MusicPlayer_Mood /// _string_, -/// Mood of the currently playing song +/// @return The mood of the currently playing song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_Mood `MusicPlayer.Mood`\endlink +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.PlaylistPlaying`</b>, /// \anchor MusicPlayer_PlaylistPlaying /// _boolean_, -/// Returns true if a playlist is currently playing +/// @return **True** if a playlist is currently playing. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Exists(relative\,position)`</b>, /// \anchor MusicPlayer_Exists /// _boolean_, -/// Returns true if the currently playing playlist has a song queued at the given position. -/// It is possible to define whether the position is relative or not\, default is false. +/// @return **True** if the currently playing playlist has a song queued at the given position. +/// @param relative - bool - If the position is relative +/// @param position - int - The position of the song +/// @note It is possible to define whether the position is relative or not\, default is false. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.HasPrevious`</b>, /// \anchor MusicPlayer_HasPrevious /// _boolean_, -/// Returns true if the music player has a a Previous Song in the Playlist. +/// @return **True** if the music player has a a Previous Song in the Playlist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.HasNext`</b>, /// \anchor MusicPlayer_HasNext /// _boolean_, -/// Returns true if the music player has a next song queued in the Playlist. +/// @return **True** if the music player has a next song queued in the Playlist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.PlayCount`</b>, /// \anchor MusicPlayer_PlayCount /// _integer_, -/// Returns the play count of currently playing song\, if it's in the database +/// @return The play count of currently playing song\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.LastPlayed`</b>, /// \anchor MusicPlayer_LastPlayed /// _string_, -/// Returns the last play date of currently playing song\, if it's in the database +/// @return The last play date of currently playing song\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.TrackNumber`</b>, /// \anchor MusicPlayer_TrackNumber /// _string_, -/// Track number of current song\, also available are -/// "MusicPlayer.offset(number).TrackNumber" offset is relative to the -/// current playing item and "MusicPlayer.Position(number).TrackNumber" -/// position is relative to the start of the playlist +/// @return The track number of current song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).TrackNumber`</b>, +/// \anchor MusicPlayer_Offset_TrackNumber +/// _string_, +/// @return The track number of the song with an offset `number` +/// with respect to the current playing song. +/// @param number - The offset number of the song with respect to the +/// playing song +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).TrackNumber`</b>, +/// \anchor MusicPlayer_Position_TrackNumber +/// _string_, +/// @return The track number of the song with an offset `number` +/// with respect to start of the playlist. +/// @param number - The offset number of the song with respect +/// to start of the playlist +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Duration`</b>, /// \anchor MusicPlayer_Duration /// _string_, -/// Duration of current song\, also available are -/// "MusicPlayer.offset(number).Duration" offset is relative to the -/// current playing item and "MusicPlayer.Position(number).Duration" -/// position is relative to the start of the playlist +/// @return The duration of the current song. +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.offset(number).Duration`</b>, +/// \anchor MusicPlayer_Offset_Duration +/// _string_, +/// @return The duration of the song with an offset `number` +/// with respect to the current playing song. +/// @param number - the offset number of the song with respect +/// to the current playing song +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.Position(number).Duration`</b>, +/// \anchor MusicPlayer_Position_Duration +/// _string_, +/// @return The duration of the song with an offset `number` +/// with respect to the start of the playlist. +/// @param number - the offset number of the song with respect +/// to the start of the playlist +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.BitRate`</b>, /// \anchor MusicPlayer_BitRate /// _string_, -/// Bitrate of current song +/// @return The bitrate of current song. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Channels`</b>, /// \anchor MusicPlayer_Channels /// _string_, -/// Number of channels of current song +/// @return The number of channels of current song. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.BitsPerSample`</b>, /// \anchor MusicPlayer_BitsPerSample /// _string_, -/// Number of bits per sample of current song +/// @return The number of bits per sample of current song. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.SampleRate`</b>, /// \anchor MusicPlayer_SampleRate /// _string_, -/// Samplerate of current song +/// @return The samplerate of current playing song. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Codec`</b>, /// \anchor MusicPlayer_Codec /// _string_, -/// Codec of current song +/// @return The codec of current playing song. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.PlaylistPosition`</b>, /// \anchor MusicPlayer_PlaylistPosition /// _string_, -/// Position of the current song in the current music playlist +/// @return The position of the current song in the current music playlist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.PlaylistLength`</b>, /// \anchor MusicPlayer_PlaylistLength /// _string_, -/// Total size of the current music playlist +/// @return The total size of the current music playlist. +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.ChannelName`</b>, /// \anchor MusicPlayer_ChannelName /// _string_, -/// Channel name of the radio programme that's currently playing (PVR). +/// @return The channel name of the radio programme that's currently playing (PVR). +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.ChannelNumberLabel`</b>, /// \anchor MusicPlayer_ChannelNumberLabel /// _string_, -/// Channel and subchannel number of the radio channel that's currently +/// @return The channel and subchannel number of the radio channel that's currently /// playing (PVR). +/// <p><hr> +/// @skinning_v14 **[New Infolabel]** \link MusicPlayer_ChannelNumberLabel `MusicPlayer.ChannelNumberLabel`\endlink +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.ChannelGroup`</b>, /// \anchor MusicPlayer_ChannelGroup /// _string_, -/// Channel group of the radio programme that's currently playing (PVR). +/// @return The channel group of the radio programme that's currently playing (PVR). +/// <p> /// } /// \table_row3{ <b>`MusicPlayer.Property(propname)`</b>, /// \anchor MusicPlayer_Property_Propname /// _string_, -/// Get a property of the currently playing item. +/// @return The requested property value of the currently playing item. +/// @param propname - The requested property +/// <p> +/// } +/// \table_row3{ <b>`MusicPlayer.DBID`</b>, +/// \anchor MusicPlayer_DBID +/// _string_, +/// @return The database id of the currently playing song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link MusicPlayer_DBID `MusicPlayer.DBID`\endlink +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap musicplayer[] = {{ "title", MUSICPLAYER_TITLE }, { "album", MUSICPLAYER_ALBUM }, { "artist", MUSICPLAYER_ARTIST }, @@ -1671,6 +2495,8 @@ const infomap musicplayer[] = {{ "title", MUSICPLAYER_TITLE }, { "votes", MUSICPLAYER_VOTES }, { "comment", MUSICPLAYER_COMMENT }, { "mood", MUSICPLAYER_MOOD }, + { "contributors", MUSICPLAYER_CONTRIBUTORS }, + { "contributorandrole", MUSICPLAYER_CONTRIBUTOR_AND_ROLE }, { "lyrics", MUSICPLAYER_LYRICS }, { "playlistplaying", MUSICPLAYER_PLAYLISTPLAYING }, { "exists", MUSICPLAYER_EXISTS }, @@ -1685,365 +2511,475 @@ const infomap musicplayer[] = {{ "title", MUSICPLAYER_TITLE }, { "property", MUSICPLAYER_PROPERTY }, }; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Videoplayer Video player -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Videoplayer Video player /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`VideoPlayer.UsingOverlays`</b>, /// \anchor VideoPlayer_UsingOverlays /// _boolean_, -/// Returns true if the video player is using the hardware overlays render -/// method. Useful\, as with hardware overlays you have no alpha blending to +/// @return **True** if the video player is using the hardware overlays render +/// method. +/// @note This is useful\, as with hardware overlays you have no alpha blending to /// the video image\, so shadows etc. need redoing\, or disabling. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.IsFullscreen`</b>, /// \anchor VideoPlayer_IsFullscreen /// _boolean_, -/// Returns true if the video player is in fullscreen mode. +/// @return **True** if the video player is in fullscreen mode. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.HasMenu`</b>, /// \anchor VideoPlayer_HasMenu /// _boolean_, -/// Returns true if the video player has a menu (ie is playing a DVD) +/// @return **True** if the video player has a menu (ie is playing a DVD). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.HasInfo`</b>, /// \anchor VideoPlayer_HasInfo /// _boolean_, -/// Returns true if the current playing video has information from the +/// @return **True** if the current playing video has information from the /// library or from a plugin (eg director/plot etc.) +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Content(parameter)`</b>, /// \anchor VideoPlayer_Content /// _boolean_, -/// Returns true if the current Video you are playing is contained in -/// corresponding Video Library sections.\n -/// The following values are accepted : -/// - files -/// - movies -/// - episodes -/// - musicvideos -/// - livetv +/// @return **True** if the current Video you are playing is contained in +/// corresponding Video Library sections. The following values are accepted: +/// - <b>files</b> +/// - <b>movies</b> +/// - <b>episodes</b> +/// - <b>musicvideos</b> +/// - <b>livetv</b> +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.HasSubtitles`</b>, /// \anchor VideoPlayer_HasSubtitles /// _boolean_, -/// Returns true if there are subtitles available for video. +/// @return **True** if there are subtitles available for video. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.HasTeletext`</b>, /// \anchor VideoPlayer_HasTeletext /// _boolean_, -/// Returns true if teletext is usable on played TV channel +/// @return **True** if teletext is usable on played TV channel. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.IsStereoscopic`</b>, /// \anchor VideoPlayer_IsStereoscopic /// _boolean_, -/// Returns true when the currently playing video is a 3D (stereoscopic) -/// video +/// @return **True** when the currently playing video is a 3D (stereoscopic) +/// video. +/// <p><hr> +/// @skinning_v13 **[New Boolean Condition]** \link VideoPlayer_IsStereoscopic `VideoPlayer.IsStereoscopic`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.SubtitlesEnabled`</b>, /// \anchor VideoPlayer_SubtitlesEnabled /// _boolean_, -/// Returns true if subtitles are turned on for video. +/// @return **True** if subtitles are turned on for video. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.HasEpg`</b>, /// \anchor VideoPlayer_HasEpg /// _boolean_, -/// Returns true if epg information is available for the currently playing +/// @return **True** if epg information is available for the currently playing /// programme (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.CanResumeLiveTV`</b>, /// \anchor VideoPlayer_CanResumeLiveTV /// _boolean_, -/// Returns true if a in-progress PVR recording is playing an the respective live TV channel is available +/// @return **True** if a in-progress PVR recording is playing an the respective +/// live TV channel is available. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Title`</b>, /// \anchor VideoPlayer_Title /// _string_, -/// Title of currently playing video. If it's in the database it will return -/// the database title\, else the filename +/// @return The title of currently playing video. +/// @note If it's in the database it will return the database title\, else the filename. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.OriginalTitle`</b>, /// \anchor VideoPlayer_OriginalTitle /// _string_, -/// Original title of currently playing video. If it's in the database +/// @return The original title of currently playing video. If it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.TVShowTitle`</b>, /// \anchor VideoPlayer_TVShowTitle /// _string_, -/// Title of currently playing episode's tvshow name +/// @return The title of currently playing episode's tvshow name. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Season`</b>, /// \anchor VideoPlayer_Season /// _string_, -/// Season number of the currently playing episode\, if it's in the database +/// @return The season number of the currently playing episode\, if it's in the database. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Season `VideoPlayer.Season`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Episode`</b>, /// \anchor VideoPlayer_Episode /// _string_, -/// Episode number of the currently playing episode +/// @return The episode number of the currently playing episode. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Episode `VideoPlayer.Episode`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Genre`</b>, /// \anchor VideoPlayer_Genre /// _string_, -/// Genre(s) of current movie\, if it's in the database +/// @return The genre(s) of current movie\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Director`</b>, /// \anchor VideoPlayer_Director /// _string_, -/// Director of current movie\, if it's in the database +/// @return The director of current movie\, if it's in the database. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Director `VideoPlayer.Director`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Country`</b>, /// \anchor VideoPlayer_Country /// _string_, -/// Production country of current movie\, if it's in the database +/// @return The production country of current movie\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Year`</b>, /// \anchor VideoPlayer_Year /// _string_, -/// Year of release of current movie\, if it's in the database +/// @return The year of release of current movie\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Cover`</b>, /// \anchor VideoPlayer_Cover /// _string_, -/// Cover of currently playing movie +/// @return The cover of currently playing movie. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Rating`</b>, /// \anchor VideoPlayer_Rating /// _string_, -/// Returns the scraped rating of current movie\, if it's in the database +/// @return The scraped rating of current movie\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.UserRating`</b>, /// \anchor VideoPlayer_UserRating /// _string_, -/// Returns the user rating of the currently playing item +/// @return The user rating of the currently playing item. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link VideoPlayer_UserRating `VideoPlayer.UserRating`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Votes`</b>, /// \anchor VideoPlayer_Votes /// _string_, -/// Returns the scraped votes of current movie\, if it's in the database +/// @return The scraped votes of current movie\, if it's in the database. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link VideoPlayer_Votes `VideoPlayer.Votes`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.RatingAndVotes`</b>, /// \anchor VideoPlayer_RatingAndVotes /// _string_, -/// Returns the scraped rating and votes of current movie\, if it's in the database +/// @return The scraped rating and votes of current movie\, if it's in the database +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.mpaa`</b>, /// \anchor VideoPlayer_mpaa /// _string_, -/// MPAA rating of current movie\, if it's in the database +/// @return The MPAA rating of current movie\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.IMDBNumber`</b>, /// \anchor VideoPlayer_IMDBNumber /// _string_, -/// The IMDb ID of the current movie\, if it's in the database +/// @return The IMDb ID of the current movie\, if it's in the database. +/// <p><hr> +/// @skinning_v15 **[New Infolabel]** \link VideoPlayer_IMDBNumber `VideoPlayer.IMDBNumber`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Top250`</b>, /// \anchor VideoPlayer_Top250 /// _string_, -/// IMDb Top250 position of the currently playing movie\, if it's in the database +/// @return The IMDb Top250 position of the currently playing movie\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.EpisodeName`</b>, /// \anchor VideoPlayer_EpisodeName /// _string_, -/// (PVR only) The name of the episode if the playing video is a TV Show\, -/// if it's in the database +/// @return The name of the episode if the playing video is a TV Show\, +/// if it's in the database (PVR). +/// <p><hr> +/// @skinning_v15 **[New Infolabel]** \link VideoPlayer_EpisodeName `VideoPlayer.EpisodeName`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.PlaylistPosition`</b>, /// \anchor VideoPlayer_PlaylistPosition /// _string_, -/// Position of the current song in the current video playlist +/// @return The position of the current song in the current video playlist. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.PlaylistLength`</b>, /// \anchor VideoPlayer_PlaylistLength /// _string_, -/// Total size of the current video playlist +/// @return The total size of the current video playlist. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Cast`</b>, /// \anchor VideoPlayer_Cast /// _string_, -/// A concatenated string of cast members of the current movie\, if it's in -/// the database +/// @return A concatenated string of cast members of the current movie\, if it's in +/// the database. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Cast `VideoPlayer.Cast`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.CastAndRole`</b>, /// \anchor VideoPlayer_CastAndRole /// _string_, -/// A concatenated string of cast members and roles of the current movie\, -/// if it's in the database +/// @return A concatenated string of cast members and roles of the current movie\, +/// if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Album`</b>, /// \anchor VideoPlayer_Album /// _string_, -/// Album from which the current Music Video is from\, if it's in the database +/// @return The album from which the current Music Video is from\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Artist`</b>, /// \anchor VideoPlayer_Artist /// _string_, -/// Artist(s) of current Music Video\, if it's in the database +/// @return The artist(s) of current Music Video\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Studio`</b>, /// \anchor VideoPlayer_Studio /// _string_, -/// Studio of current Music Video\, if it's in the database +/// @return The studio of current Music Video\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Writer`</b>, /// \anchor VideoPlayer_Writer /// _string_, -/// Name of Writer of current playing Video\, if it's in the database +/// @return The name of Writer of current playing Video\, if it's in the database. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link VideoPlayer_Writer `VideoPlayer.Writer`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Tagline`</b>, /// \anchor VideoPlayer_Tagline /// _string_, -/// Small Summary of current playing Video\, if it's in the database +/// @return The small Summary of current playing Video\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.PlotOutline`</b>, /// \anchor VideoPlayer_PlotOutline /// _string_, -/// Small Summary of current playing Video\, if it's in the database +/// @return The small Summary of current playing Video\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Plot`</b>, /// \anchor VideoPlayer_Plot /// _string_, -/// Complete Text Summary of current playing Video\, if it's in the database +/// @return The complete Text Summary of current playing Video\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Premiered`</b>, /// \anchor VideoPlayer_Premiered /// _string_, -/// Release or aired date of the currently playing episode\, show\, movie or EPG item\, if it's in the database +/// @return The release or aired date of the currently playing episode\, show\, movie or EPG item\, +/// if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.Trailer`</b>, /// \anchor VideoPlayer_Trailer /// _string_, -/// The path to the trailer of the currently playing movie\, if it's in the database +/// @return The path to the trailer of the currently playing movie\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.LastPlayed`</b>, /// \anchor VideoPlayer_LastPlayed /// _string_, -/// Last play date of current playing Video\, if it's in the database +/// @return The last play date of current playing Video\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.PlayCount`</b>, /// \anchor VideoPlayer_PlayCount /// _string_, -/// Playcount of current playing Video\, if it's in the database +/// @return The playcount of current playing Video\, if it's in the database. +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.VideoCodec`</b>, /// \anchor VideoPlayer_VideoCodec /// _string_, -/// Returns the video codec of the currently playing video (common values: see -/// \ref ListItem_VideoCodec "ListItem.VideoCodec") +/// @return The video codec of the currently playing video (common values: see +/// \ref ListItem_VideoCodec "ListItem.VideoCodec"). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.VideoResolution`</b>, /// \anchor VideoPlayer_VideoResolution /// _string_, -/// Returns the video resolution of the currently playing video (possible -/// values: see \ref ListItem_VideoResolution "ListItem.VideoResolution") +/// @return The video resolution of the currently playing video (possible +/// values: see \ref ListItem_VideoResolution "ListItem.VideoResolution"). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.VideoAspect`</b>, /// \anchor VideoPlayer_VideoAspect /// _string_, -/// Returns the aspect ratio of the currently playing video (possible values: -/// see \ref ListItem_VideoAspect "ListItem.VideoAspect") +/// @return The aspect ratio of the currently playing video (possible values: +/// see \ref ListItem_VideoAspect "ListItem.VideoAspect"). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.AudioCodec`</b>, /// \anchor VideoPlayer_AudioCodec /// _string_, -/// Returns the audio codec of the currently playing video\, optionally 'n' +/// @return The audio codec of the currently playing video\, optionally 'n' /// defines the number of the audiostream (common values: see -/// \ref ListItem_AudioCodec "ListItem.AudioCodec") +/// \ref ListItem_AudioCodec "ListItem.AudioCodec"). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.AudioChannels`</b>, /// \anchor VideoPlayer_AudioChannels /// _string_, -/// Returns the number of audio channels of the currently playing video -/// (possible values: see \ref ListItem_AudioChannels "ListItem.AudioChannels") +/// @return The number of audio channels of the currently playing video +/// (possible values: see \ref ListItem_AudioChannels "ListItem.AudioChannels"). +/// <p><hr> +/// @skinning_v16 **[Infolabel Updated]** \link VideoPlayer_AudioChannels `VideoPlayer.AudioChannels`\endlink +/// if a video contains no audio\, these infolabels will now return empty. +/// (they used to return 0) +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.AudioLanguage`</b>, /// \anchor VideoPlayer_AudioLanguage /// _string_, -/// Returns the language of the audio of the currently playing video(possible -/// values: see \ref ListItem_AudioLanguage "ListItem.AudioLanguage") +/// @return The language of the audio of the currently playing video(possible +/// values: see \ref ListItem_AudioLanguage "ListItem.AudioLanguage"). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link VideoPlayer_AudioLanguage `VideoPlayer.AudioLanguage`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.SubtitlesLanguage`</b>, /// \anchor VideoPlayer_SubtitlesLanguage /// _string_, -/// Returns the language of the subtitle of the currently playing video -/// (possible values: see \ref ListItem_SubtitleLanguage "ListItem.SubtitleLanguage") +/// @return The language of the subtitle of the currently playing video +/// (possible values: see \ref ListItem_SubtitleLanguage "ListItem.SubtitleLanguage"). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link VideoPlayer_SubtitlesLanguage `VideoPlayer.SubtitlesLanguage`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.StereoscopicMode`</b>, /// \anchor VideoPlayer_StereoscopicMode /// _string_, -/// Returns the stereoscopic mode of the currently playing video (possible -/// values: see \ref ListItem_StereoscopicMode "ListItem.StereoscopicMode") +/// @return The stereoscopic mode of the currently playing video (possible +/// values: see \ref ListItem_StereoscopicMode "ListItem.StereoscopicMode"). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link VideoPlayer_StereoscopicMode `VideoPlayer.StereoscopicMode`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.StartTime`</b>, /// \anchor VideoPlayer_StartTime /// _string_, -/// Start date and time of the currently playing epg event or recording (PVR). +/// @return The start date and time of the currently playing epg event or recording (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.EndTime`</b>, /// \anchor VideoPlayer_EndTime /// _string_, -/// End date and time of the currently playing epg event or recording (PVR). +/// @return The end date and time of the currently playing epg event or recording (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.NextTitle`</b>, /// \anchor VideoPlayer_NextTitle /// _string_, -/// Title of the programme that will be played next (PVR). +/// @return The title of the programme that will be played next (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.NextGenre`</b>, /// \anchor VideoPlayer_NextGenre /// _string_, -/// Genre of the programme that will be played next (PVR). +/// @return The genre of the programme that will be played next (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.NextPlot`</b>, /// \anchor VideoPlayer_NextPlot /// _string_, -/// Plot of the programme that will be played next (PVR). +/// @return The plot of the programme that will be played next (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.NextPlotOutline`</b>, /// \anchor VideoPlayer_NextPlotOutline /// _string_, -/// Plot outline of the programme that will be played next (PVR). +/// @return The plot outline of the programme that will be played next (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.NextStartTime`</b>, /// \anchor VideoPlayer_NextStartTime /// _string_, -/// Start time of the programme that will be played next (PVR). +/// @return The start time of the programme that will be played next (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.NextEndTime`</b>, /// \anchor VideoPlayer_NextEndTime /// _string_, -/// End time of the programme that will be played next (PVR). +/// @return The end time of the programme that will be played next (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.NextDuration`</b>, /// \anchor VideoPlayer_NextDuration /// _string_, -/// Duration of the programme that will be played next (PVR). +/// @return The duration of the programme that will be played next (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.ChannelName`</b>, /// \anchor VideoPlayer_ChannelName /// _string_, -/// Name of the currently tuned channel (PVR). +/// @return The name of the currently tuned channel (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.ChannelNumberLabel`</b>, /// \anchor VideoPlayer_ChannelNumberLabel /// _string_, -/// Channel and subchannel number of the tv channel that's currently playing (PVR). +/// @return The channel and subchannel number of the tv channel that's currently playing (PVR). +/// <p><hr> +/// @skinning_v14 **[New Infolabel]** \link VideoPlayer_ChannelNumberLabel `VideoPlayer.ChannelNumberLabel`\endlink +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.ChannelGroup`</b>, /// \anchor VideoPlayer_ChannelGroup /// _string_, -/// Group of the currently tuned channel (PVR). +/// @return The group of the currently tuned channel (PVR). +/// <p> /// } /// \table_row3{ <b>`VideoPlayer.ParentalRating`</b>, /// \anchor VideoPlayer_ParentalRating /// _string_, -/// Parental rating of the currently playing programme (PVR). +/// @return The parental rating of the currently playing programme (PVR). +/// <p> +/// } +/// \table_row3{ <b>`VideoPlayer.DBID`</b>, +/// \anchor VideoPlayer_DBID +/// _string_, +/// @return The database id of the currently playing video +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link VideoPlayer_DBID `VideoPlayer.DBID`\endlink +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap videoplayer[] = {{ "title", VIDEOPLAYER_TITLE }, { "genre", VIDEOPLAYER_GENRE }, { "country", VIDEOPLAYER_COUNTRY }, @@ -2110,71 +3046,54 @@ const infomap videoplayer[] = {{ "title", VIDEOPLAYER_TITLE }, { "canresumelivetv", VIDEOPLAYER_CAN_RESUME_LIVE_TV }, { "imdbnumber", VIDEOPLAYER_IMDBNUMBER }, { "episodename", VIDEOPLAYER_EPISODENAME }, - { "dbid", VIDEOPLAYER_DBID } + { "dbid", VIDEOPLAYER_DBID } }; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_RetroPlayer RetroPlayer -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_RetroPlayer RetroPlayer /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`RetroPlayer.VideoFilter`</b>, /// \anchor RetroPlayer_VideoFilter /// _string_, -/// Returns the video filter of the currently-playing game.\n +/// @return The video filter of the currently-playing game. /// The following values are possible: -/// - nearest (Nearest neighbor\, i.e. pixelate) -/// - linear (Bilinear filtering\, i.e. smooth blur) +/// - nearest (Nearest neighbor\, i.e. pixelate) +/// - linear (Bilinear filtering\, i.e. smooth blur) +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link RetroPlayer_VideoFilter `RetroPlayer.VideoFilter`\endlink +/// <p> /// } /// \table_row3{ <b>`RetroPlayer.StretchMode`</b>, /// \anchor RetroPlayer_StretchMode /// _string_, -/// Returns the stretch mode of the currently-playing game.\n +/// @return The stretch mode of the currently-playing game. /// The following values are possible: -/// - normal (Show the game normally) -/// - 4:3 (Stretch to a 4:3 aspect ratio) -/// - fullscreen (Stretch to the full viewing area) -/// - original (Shrink to the original resolution) +/// - normal (Show the game normally) +/// - 4:3 (Stretch to a 4:3 aspect ratio) +/// - fullscreen (Stretch to the full viewing area) +/// - original (Shrink to the original resolution) +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link RetroPlayer_StretchMode `RetroPlayer.StretchMode`\endlink +/// <p> /// } /// \table_row3{ <b>`RetroPlayer.VideoRotation`</b>, /// \anchor RetroPlayer_VideoRotation /// _integer_, -/// Returns the video rotation of the currently-playing game -/// in degrees counter-clockwise.\n +/// @return The video rotation of the currently-playing game +/// in degrees counter-clockwise. /// The following values are possible: -/// - 0 -/// - 90 (Shown in the GUI as 270 degrees) -/// - 180 -/// - 270 (Shown in the GUI as 90 degrees) -/// } -/// \table_row3{ <b>`ListItem.Property(Game.VideoFilter)`</b>, -/// \anchor ListItem_Property_Game_VideoFilter -/// _string_, -/// Returns the video filter of the list item representing a -/// gamewindow control.\n -/// See \link RetroPlayer_VideoFilter RetroPlayer.VideoFilter \endlink -/// for the possible values. -/// } -/// \table_row3{ <b>`ListItem.Property(Game.StretchMode)`</b>, -/// \anchor ListItem_Property_Game_StretchMode -/// _string_, -/// Returns the stretch mode of the list item representing a -/// gamewindow control.\n -/// See \link RetroPlayer_StretchMode RetroPlayer.StretchMode \endlink -/// for the possible values. -/// } -/// \table_row3{ <b>`ListItem.Property(Game.VideoRotation)`</b>, -/// \anchor ListItem_Property_Game_VideoRotation -/// _integer_, -/// Returns the video rotation of the list item representing a -/// gamewindow control.\n -/// See \link RetroPlayer_VideoRotation RetroPlayer.VideoRotation \endlink -/// for the possible values. +/// - 0 +/// - 90 (Shown in the GUI as 270 degrees) +/// - 180 +/// - 270 (Shown in the GUI as 90 degrees) +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link RetroPlayer_VideoRotation `RetroPlayer.VideoRotation`\endlink +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap retroplayer[] = { { "videofilter", RETROPLAYER_VIDEO_FILTER}, @@ -2182,115 +3101,132 @@ const infomap retroplayer[] = { "videorotation", RETROPLAYER_VIDEO_ROTATION}, }; -const infomap player_process[] = -{ - { "videodecoder", PLAYER_PROCESS_VIDEODECODER }, - { "deintmethod", PLAYER_PROCESS_DEINTMETHOD }, - { "pixformat", PLAYER_PROCESS_PIXELFORMAT }, - { "videowidth", PLAYER_PROCESS_VIDEOWIDTH }, - { "videoheight", PLAYER_PROCESS_VIDEOHEIGHT }, - { "videofps", PLAYER_PROCESS_VIDEOFPS }, - { "videodar", PLAYER_PROCESS_VIDEODAR }, - { "videohwdecoder", PLAYER_PROCESS_VIDEOHWDECODER }, - { "audiodecoder", PLAYER_PROCESS_AUDIODECODER }, - { "audiochannels", PLAYER_PROCESS_AUDIOCHANNELS }, - { "audiosamplerate", PLAYER_PROCESS_AUDIOSAMPLERATE }, - { "audiobitspersample", PLAYER_PROCESS_AUDIOBITSPERSAMPLE } -}; - -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Container Container -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Container Container /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Container(id).HasFiles`</b>, /// \anchor Container_HasFiles /// _boolean_, -/// Returns true if the container contains files (or current container if +/// @return **True** if the container contains files (or current container if /// id is omitted). +/// <p> /// } /// \table_row3{ <b>`Container(id).HasFolders`</b>, /// \anchor Container_HasFolders /// _boolean_, -/// Returns true if the container contains folders (or current container if +/// @return **True** if the container contains folders (or current container if /// id is omitted). +/// <p> /// } /// \table_row3{ <b>`Container(id).IsStacked`</b>, /// \anchor Container_IsStacked /// _boolean_, -/// Returns true if the container is currently in stacked mode (or current +/// @return **True** if the container is currently in stacked mode (or current /// container if id is omitted). +/// <p> /// } /// \table_row3{ <b>`Container.FolderPath`</b>, /// \anchor Container_FolderPath /// _string_, -/// Returns complete path of currently displayed folder +/// @return The complete path of currently displayed folder. +/// <p> /// } /// \table_row3{ <b>`Container.FolderName`</b>, /// \anchor Container_FolderName /// _string_, -/// Returns top most folder in currently displayed folder +/// @return The top most folder in currently displayed folder. +/// <p> /// } /// \table_row3{ <b>`Container.PluginName`</b>, /// \anchor Container_PluginName /// _string_, -/// Returns the current plugins base folder name +/// @return The current plugins base folder name. +/// <p> +/// } +/// \table_row3{ <b>`Container.PluginCategory`</b>, +/// \anchor Container_PluginCategory +/// _string_, +/// @return The current plugins category (set by the scripter). +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Container_PluginCategory `Container.PluginCategory`\endlink +/// <p> /// } /// \table_row3{ <b>`Container.Viewmode`</b>, /// \anchor Container_Viewmode /// _string_, -/// Returns the current viewmode (list\, icons etc.) +/// @return The current viewmode (list\, icons etc). +/// <p> /// } /// \table_row3{ <b>`Container.ViewCount`</b>, /// \anchor Container_ViewCount /// _integer_, -/// Returns the number of available skin view modes for the current container listing +/// @return The number of available skin view modes for the current container listing. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Container_ViewCount `Container.ViewCount`\endlink +/// <p> /// } /// \table_row3{ <b>`Container(id).Totaltime`</b>, /// \anchor Container_Totaltime /// _string_, -/// Returns the total time of all items in the current container +/// @return The total time of all items in the current container. +/// <p> /// } /// \table_row3{ <b>`Container(id).TotalWatched`</b>, /// \anchor Container_TotalWatched /// _string_, -/// Returns the number of watched items in the current container +/// @return The number of watched items in the container. +/// @param id - [opt] if not supplied the current container will be used. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link Container_TotalWatched `Container(id).TotalWatched`\endlink +/// <p> /// } /// \table_row3{ <b>`Container(id).TotalUnWatched`</b>, /// \anchor Container_TotalUnWatched /// _string_, -/// Returns the number of unwatched items in the current container +/// @return The number of unwatched items in the container. +/// @param id - [opt] if not supplied the current container will be used. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link Container_TotalUnWatched `Container(id).TotalUnWatched`\endlink +/// <p> /// } /// \table_row3{ <b>`Container.HasThumb`</b>, /// \anchor Container_HasThumb -/// _string_, -/// Returns true if the current container you are in has a thumb assigned -/// to it +/// _boolean_, +/// @return **True** if the current container you are in has a thumb assigned +/// to it. +/// <p> /// } /// \table_row3{ <b>`Container.SortMethod`</b>, /// \anchor Container_SortMethod -/// _string_, -/// Returns the current sort method (name\, year\, rating\, etc.) +/// _boolean_, +/// @return **True** the current sort method (name\, year\, rating\, etc). +/// <p> /// } /// \table_row3{ <b>`Container.SortOrder`</b>, /// \anchor Container_SortOrder /// _string_, -/// Returns the current sort order (Ascending/Descending) +/// @return The current sort order (Ascending/Descending). +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link Container_SortOrder `Container.SortOrder`\endlink +/// <p> /// } /// \table_row3{ <b>`Container.ShowPlot`</b>, /// \anchor Container_ShowPlot /// _string_, -/// Returns the TV Show plot of the current container and can be used at -/// season and episode level +/// @return The TV Show plot of the current container and can be used at +/// season and episode level. +/// <p> /// } /// \table_row3{ <b>`Container.ShowTitle`</b>, /// \anchor Container_ShowTitle /// _string_, -/// Returns the TV Show title of the current container and can be used at -/// season and episode level +/// @return The TV Show title of the current container and can be used at +/// season and episode level. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Container_ShowTitle `Container.ShowTitle`\endlink +/// <p> /// } -/// \table_end -/// @} const infomap mediacontainer[] = {{ "hasfiles", CONTAINER_HASFILES }, { "hasfolders", CONTAINER_HASFOLDERS }, { "isstacked", CONTAINER_STACKED }, @@ -2309,113 +3245,133 @@ const infomap mediacontainer[] = {{ "hasfiles", CONTAINER_HASFILES }, { "showplot", CONTAINER_SHOWPLOT }, { "showtitle", CONTAINER_SHOWTITLE }}; -/// \page modules__General__List_of_gui_access -/// @{ -/// \table_start +/// \page modules__infolabels_boolean_conditions /// \table_row3{ <b>`Container(id).OnNext`</b>, /// \anchor Container_OnNext /// _boolean_, -/// Returns true if the container with id (or current container if id is +/// @return **True** if the container with id (or current container if id is /// omitted) is moving to the next item. Allows views to be /// custom-designed (such as 3D coverviews etc.) +/// <p> /// } /// \table_row3{ <b>`Container(id).OnScrollNext`</b>, /// \anchor Container_OnScrollNext /// _boolean_, -/// Returns true if the container with id (or current container if id is -/// omitted) is scrolling to the next item. Differs from OnNext in that -/// OnNext triggers on movement even if there is no scroll involved. +/// @return **True** if the container with id (or current container if id is +/// omitted) is scrolling to the next item. Differs from \ref Container_OnNext "OnNext" in that +/// \ref Container_OnNext "OnNext" triggers on movement even if there is no scroll involved. +/// <p> /// } /// \table_row3{ <b>`Container(id).OnPrevious`</b>, /// \anchor Container_OnPrevious /// _boolean_, -/// Returns true if the container with id (or current container if id is +/// @return **True** if the container with id (or current container if id is /// omitted) is moving to the previous item. Allows views to be -/// custom-designed (such as 3D coverviews etc.) +/// custom-designed (such as 3D coverviews etc). +/// <p> /// } /// \table_row3{ <b>`Container(id).OnScrollPrevious`</b>, /// \anchor Container_OnScrollPrevious /// _boolean_, -/// Returns true if the container with id (or current container if id is -/// omitted) is scrolling to the previous item. Differs from OnPrevious in -/// that OnPrevious triggers on movement even if there is no scroll involved. +/// @return **True** if the container with id (or current container if id is +/// omitted) is scrolling to the previous item. Differs from \ref Container_OnPrevious "OnPrevious" in +/// that \ref Container_OnPrevious "OnPrevious" triggers on movement even if there is no scroll involved. +/// <p> /// } /// \table_row3{ <b>`Container(id).NumPages`</b>, /// \anchor Container_NumPages -/// _boolean_, -/// Number of pages in the container with given id. If no id is specified it +/// _integer_, +/// @return The number of pages in the container with given id. If no id is specified it /// grabs the current container. +/// <p> /// } /// \table_row3{ <b>`Container(id).NumItems`</b>, /// \anchor Container_NumItems -/// _boolean_, -/// Number of items in the container or grouplist with given id excluding parent folder item. If no id is -/// specified it grabs the current container. +/// _integer_, +/// @return The number of items in the container or grouplist with given id excluding parent folder item. +/// @note If no id is specified it grabs the current container. +/// <p> /// } /// \table_row3{ <b>`Container(id).NumAllItems`</b>, /// \anchor Container_NumAllItems -/// _boolean_, -/// Number of all items in the container or grouplist with given id including parent folder item. If no id is -/// specified it grabs the current container. +/// _integer_, +/// @return The number of all items in the container or grouplist with given id including parent folder item. +/// @note If no id is specified it grabs the current container. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link Container_NumAllItems `Container(id).NumAllItems`\endlink +/// <p> /// } /// \table_row3{ <b>`Container(id).NumNonFolderItems`</b>, /// \anchor Container_NumNonFolderItems -/// _boolean_, -/// Number of items in the container or grouplist with given id excluding all folder items (example: pvr -/// recordings folders\, parent ".." folder). If no id is specified it grabs the current container. +/// _integer_, +/// @return The Number of items in the container or grouplist with given id excluding all folder items. +/// @note **Example:** pvr recordings folders\, parent ".." folder). +/// If no id is specified it grabs the current container. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link Container_NumNonFolderItems `Container(id).NumNonFolderItems`\endlink +/// <p> /// } /// \table_row3{ <b>`Container(id).CurrentPage`</b>, /// \anchor Container_CurrentPage -/// _boolean_, -/// Current page in the container with given id. If no id is specified it -/// grabs the current container. +/// _string_, +/// @return THe current page in the container with given id. +/// @note If no id is specified it grabs the current container. +/// <p> /// } /// \table_row3{ <b>`Container(id).Scrolling`</b>, /// \anchor Container_Scrolling /// _boolean_, -/// Returns true if the user is currently scrolling through the container -/// with id (or current container if id is omitted). Note that this is -/// slightly delayed from the actual scroll start. Use -/// Container(id).OnScrollNext/OnScrollPrevious to trigger animations +/// @return **True** if the user is currently scrolling through the container +/// with id (or current container if id is omitted). +/// @note This is slightly delayed from the actual scroll start. Use +/// \ref Container_OnScrollNext "Container(id).OnScrollNext" or +/// \ref Container_OnScrollPrevious "Container(id).OnScrollPrevious" to trigger animations /// immediately on scroll. +/// <p> /// } /// \table_row3{ <b>`Container(id).HasNext`</b>, /// \anchor Container_HasNext /// _boolean_, -/// Returns true if the container or textbox with id (id) has a next page. +/// @return **True** if the container or textbox with id (id) has a next page. +/// <p> /// } /// \table_row3{ <b>`Container.HasParent`</b>, /// \anchor Container_HasParent /// _boolean_, -/// Return true when the container contains a parent ('..') item. +/// @return **True** when the container contains a parent ('..') item. +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \link Container_HasParent `Container.HasParent`\endlink +/// <p> /// } /// \table_row3{ <b>`Container(id).HasPrevious`</b>, /// \anchor Container_HasPrevious /// _boolean_, -/// Returns true if the container or textbox with id (id) has a previous page. +/// @return **True** if the container or textbox with id (id) has a previous page. +/// <p> /// } /// \table_row3{ <b>`Container.CanFilter`</b>, /// \anchor Container_CanFilter /// _boolean_, -/// Returns true when the current container can be filtered. +/// @return **True** when the current container can be filtered. +/// <p> /// } /// \table_row3{ <b>`Container.CanFilterAdvanced`</b>, /// \anchor Container_CanFilterAdvanced /// _boolean_, -/// Returns true when advanced filtering can be applied to the current container. +/// @return **True** when advanced filtering can be applied to the current container. +/// <p> /// } /// \table_row3{ <b>`Container.Filtered`</b>, /// \anchor Container_Filtered /// _boolean_, -/// Returns true when a mediafilter is applied to the current container. +/// @return **True** when a mediafilter is applied to the current container. +/// <p> /// } /// \table_row3{ <b>`Container(id).IsUpdating`</b>, /// \anchor Container_IsUpdating /// _boolean_, -/// Returns true if the container with dynamic list content is currently updating. +/// @return **True** if the container with dynamic list content is currently updating. /// } -/// \table_end -/// @} const infomap container_bools[] ={{ "onnext", CONTAINER_MOVE_NEXT }, { "onprevious", CONTAINER_MOVE_PREVIOUS }, { "onscrollnext", CONTAINER_SCROLL_NEXT }, @@ -2434,46 +3390,57 @@ const infomap container_bools[] ={{ "onnext", CONTAINER_MOVE_NEXT }, { "filtered", CONTAINER_FILTERED }, { "isupdating", CONTAINER_ISUPDATING }}; -/// \page modules__General__List_of_gui_access -/// @{ -/// \table_start +/// \page modules__infolabels_boolean_conditions /// \table_row3{ <b>`Container(id).Row`</b>, /// \anchor Container_Row /// _integer_, -/// Returns the row number of the focused position in a panel container. +/// @return The row number of the focused position in a panel container. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link Container_Row `Container(id).Row`\endlink +/// <p> /// } /// \table_row3{ <b>`Container(id).Column`</b>, /// \anchor Container_Column /// _integer_, -/// Returns the column number of the focused position in a panel container. +/// @return The column number of the focused position in a panel container. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link Container_Column `Container(id).Column`\endlink +/// <p> /// } /// \table_row3{ <b>`Container(id).Position`</b>, /// \anchor Container_Position /// _integer_, -/// Returns the current focused position of container / grouplist (id) as a +/// @return The current focused position of container / grouplist (id) as a /// numeric label. +/// <p><hr> +/// @skinning_v16 **[Infolabel Updated]** \link Container_Position `Container(id).Position`\endlink +/// now also returns the position for items inside a grouplist. +/// <p> /// } /// \table_row3{ <b>`Container(id).CurrentItem`</b>, /// \anchor Container_CurrentItem /// _integer_, -/// Current item in the container or grouplist with given id. If no id is -/// specified it grabs the current container. +/// @return The current item in the container or grouplist with given id. +/// @note If no id is specified it grabs the current container. +/// <p><hr> +/// @skinning_v15 **[New Infolabel]** \link Container_CurrentItem `Container(id).CurrentItem`\endlink +/// <p> /// } /// \table_row3{ <b>`Container(id).SubItem`</b>, /// \anchor Container_SubItem /// _integer_, -/// Sub item in the container or grouplist with given id. If no id is -/// specified it grabs the current container. +/// @return Sub-item in the container or grouplist with given id. +/// @note If no id is specified it grabs the current container. +/// <p> /// } /// \table_row3{ <b>`Container(id).HasFocus(item_number)`</b>, /// \anchor Container_HasFocus /// _boolean_, -/// Returns true if the container with id (or current container if id is +/// @return **True** if the container with id (or current container if id is /// omitted) has static content and is focused on the item with id /// item_number. +/// <p> /// } -/// \table_end -/// @} const infomap container_ints[] = {{ "row", CONTAINER_ROW }, { "column", CONTAINER_COLUMN }, { "position", CONTAINER_POSITION }, @@ -2481,1323 +3448,2172 @@ const infomap container_ints[] = {{ "row", CONTAINER_ROW }, { "subitem", CONTAINER_SUBITEM }, { "hasfocus", CONTAINER_HAS_FOCUS }}; -/// \page modules__General__List_of_gui_access -/// @{ -/// \table_start +/// \page modules__infolabels_boolean_conditions /// \table_row3{ <b>`Container.Property(addoncategory)`</b>, /// \anchor Container_Property_addoncategory /// _string_, -/// Returns the current add-on category +/// @return The current add-on category. +/// <p> /// } /// \table_row3{ <b>`Container.Property(reponame)`</b>, /// \anchor Container_Property_reponame /// _string_, -/// Returns the current add-on repository name +/// @return The current add-on repository name. +/// <p> /// } -/// \table_row3{ <b>`Container.Content(parameter)`</b>, +/// \table_row3{ <b>`Container.Content`</b>, /// \anchor Container_Content /// _string_, -/// Returns true if the current container you are in contains the following: -/// files\, songs\, artists\, albums\, movies\, tvshows\, -/// seasons\, episodes\, musicvideos\, genres\, years\, -/// actors\, playlists\, plugins\, studios\, directors\, -/// sets\, tags (Note: these currently only work in the Video and Music +/// @return The content of the current container. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link Container_Content `Container.Content`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Container(id).ListItem(offset).Property`</b>, +/// \anchor Container_ListItem_property +/// _string_, +/// @return the property of the ListItem with a given offset. +/// @param offset - The offset for the listitem. +/// @note `Property` has to be replaced with `Label`\, `Label2`\, `Icon` etc. +/// @note **Example:** `Container(50).Listitem(2).Label ` +/// <p> +/// } +/// \table_row3{ <b>`Container(id).ListItemNoWrap(offset).Property`</b>, +/// \anchor Container_ListItemNoWrap +/// _string_, +/// @return the same as \link Container_ListItem_property `Container(id).ListItem(offset).Property` \endlink +/// but it won't wrap. +/// @param offset - The offset for the listitem. +/// @note That means if the last item of a list is focused\, `ListItemNoWrap(1)` +/// will be empty while `ListItem(1)` will return the first item of the list. +/// `Property` has to be replaced with `Label`\, `Label2`\, `Icon` etc. +/// @note **Example:** `Container(50).ListitemNoWrap(1).Plot` +/// <p> +/// } +/// \table_row3{ <b>`Container(id).ListItemPosition(x).[infolabel]`</b>, +/// \anchor Container_ListItemPosition +/// _string_, +/// @return The infolabel for an item in a Container. +/// @param x - the position in the container relative to the cursor position. +/// @note **Example:** `Container(50).ListItemPosition(4).Genre` +/// <p> +/// } +/// \table_row3{ <b>`Container(id).ListItemAbsolute(x).[infolabel]`</b>, +/// \anchor Container_ListItemAbsolute +/// _string_, +/// @return The infolabel for an item in a Container. +/// @param x - the absolute position in the container. +/// @note **Example:** `Container(50).ListItemAbsolute(4).Genre` +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link Container_ListItemAbsolute `Container(id).ListItemAbsolute(x).[infolabel]`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Container.Content(parameter)`</b>, +/// \anchor Container_Content_parameter +/// _string_, +/// @return **True** if the current container you are in contains the following: +/// - <b>files</b> +/// - <b>songs</b> +/// - <b>artists</b> +/// - <b>albums</b> +/// - <b>movies</b> +/// - <b>tvshows</b> +/// - <b>seasons</b> +/// - <b>episodes</b> +/// - <b>musicvideos</b> +/// - <b>genres</b> +/// - <b>years</b> +/// - <b>actors</b> +/// - <b>playlists</b> +/// - <b>plugins</b> +/// - <b>studios</b> +/// - <b>directors</b> +/// - <b>sets</b> +/// - <b>tags</b> +/// @note These currently only work in the Video and Music /// Library or unless a Plugin has set the value) also available are /// Addons true when a list of add-ons is shown LiveTV true when a /// htsp (tvheadend) directory is shown +/// <p> /// } /// \table_row3{ <b>`Container.Art(type)`</b>, /// \anchor Container_Art /// _string_, -/// Returns the path to the art image file for the given type of the current container -/// Todo: list of all art types +/// @return The path to the art image file for the given type of the current container. +/// @param type - the art type to request. +/// @todo List of all art types +/// <p><hr> +/// @skinning_v16 **[Infolabel Updated]** \link Container_Art `Container.Art(type)`\endlink +/// <b>set.fanart</b> as possible type value. +/// @skinning_v15 **[New Infolabel]** \link Container_Art `Container.Art(type)`\endlink +/// <p> /// } -/// \table_end /// -/// ----------------------------------------------------------------------------- -/// @} const infomap container_str[] = {{ "property", CONTAINER_PROPERTY }, { "content", CONTAINER_CONTENT }, { "art", CONTAINER_ART }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_ListItem ListItem -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \table_row3{ <b>`Container.SortDirection(direction)`</b>, +/// \anchor Container_SortDirection +/// _boolean_, +/// @return **True** if the sort direction of a container equals direction. +/// @param direction - The direction to check. It can be: +/// - <b>ascending</b> +/// - <b>descending</b> +/// <p> +/// } +/// \table_end +/// +/// ----------------------------------------------------------------------------- + +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_ListItem ListItem /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`ListItem.Thumb`</b>, /// \anchor ListItem_Thumb /// _string_, -/// Returns the thumbnail (if it exists) of the currently selected item +/// @return The thumbnail (if it exists) of the currently selected item /// in a list or thumb control. /// @deprecated but still available\, returns -/// the same as `ListItem.Art(thumb)`.\par +/// the same as \ref ListItem_Art_Type "ListItem.Art(thumb)" +/// <p> /// } /// \table_row3{ <b>`ListItem.Icon`</b>, /// \anchor ListItem_Icon /// _string_, -/// Returns the thumbnail (if it exists) of the currently selected item in a list or thumb control. If no thumbnail image exists\, it will show the icon. +/// @return The thumbnail (if it exists) of the currently selected item in a list or thumb control. +/// @note If no thumbnail image exists\, it will show the icon. +/// <p> /// } /// \table_row3{ <b>`ListItem.ActualIcon`</b>, /// \anchor ListItem_ActualIcon /// _string_, -/// Returns the icon of the currently selected item in a list or thumb control. +/// @return The icon of the currently selected item in a list or thumb control. +/// <p> /// } /// \table_row3{ <b>`ListItem.Overlay`</b>, /// \anchor ListItem_Overlay /// _string_, -/// Returns the overlay icon status of the currently selected item in a list or thumb control. +/// @return The overlay icon status of the currently selected item in a list or thumb control. /// - compressed file -- OverlayRAR.png /// - watched -- OverlayWatched.png /// - unwatched -- OverlayUnwatched.png /// - locked -- OverlayLocked.png +/// <p> /// } /// \table_row3{ <b>`ListItem.IsFolder`</b>, /// \anchor ListItem_IsFolder /// _boolean_, -/// Returns whether the current ListItem is a folder +/// @return **True** if the current ListItem is a folder. +/// <p> /// } /// \table_row3{ <b>`ListItem.IsPlaying`</b>, /// \anchor ListItem_IsPlaying /// _boolean_, -/// Returns whether the current ListItem.* info labels and images are -/// currently Playing media +/// @return **True** if the current ListItem.* info labels and images are +/// currently Playing media. +/// <p> /// } /// \table_row3{ <b>`ListItem.IsResumable`</b>, /// \anchor ListItem_IsResumable /// _boolean_, -/// Returns true when the current ListItem has been partially played +/// @return **True** when the current ListItem has been partially played. +/// <p> /// } /// \table_row3{ <b>`ListItem.IsCollection`</b>, /// \anchor ListItem_IsCollection /// _boolean_, -/// Returns true when the current ListItem is a movie set +/// @return **True** when the current ListItem is a movie set. +/// <p><hr> +/// @skinning_v15 **[New Boolean Condition]** \link ListItem_IsCollection `ListItem.IsCollection`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.IsSelected`</b>, /// \anchor ListItem_IsSelected /// _boolean_, -/// Returns whether the current ListItem is selected (f.e. currently playing -/// in playlist window) +/// @return **True** if the current ListItem is selected (f.e. currently playing +/// in playlist window). +/// <p> /// } /// \table_row3{ <b>`ListItem.HasEpg`</b>, /// \anchor ListItem_HasEpg /// _boolean_, -/// Returns true when the selected programme has epg info (PVR) +/// @return **True** when the selected programme has epg info (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.HasTimer`</b>, /// \anchor ListItem_HasTimer /// _boolean_, -/// Returns true when a recording timer has been set for the selected -/// programme (PVR) +/// @return **True** when a recording timer has been set for the selected +/// programme (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.IsRecording`</b>, /// \anchor ListItem_IsRecording /// _boolean_, -/// Returns true when the selected programme is being recorded (PVR) +/// @return **True** when the selected programme is being recorded (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.IsEncrypted`</b>, /// \anchor ListItem_IsEncrypted /// _boolean_, -/// Returns true when the selected programme is encrypted (PVR) +/// @return **True** when the selected programme is encrypted (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.IsStereoscopic`</b>, /// \anchor ListItem_IsStereoscopic /// _boolean_, -/// Returns true when the selected video is a 3D (stereoscopic) video +/// @return **True** when the selected video is a 3D (stereoscopic) video. +/// <p><hr> +/// @skinning_v13 **[New Boolean Condition]** \link ListItem_IsStereoscopic `ListItem.IsStereoscopic`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(IsSpecial)`</b>, /// \anchor ListItem_Property_IsSpecial /// _boolean_, -/// Returns whether the current Season/Episode is a Special +/// @return **True** if the current Season/Episode is a Special. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(DateLabel)`</b>, /// \anchor ListItem_Property_DateLabel -/// _string_, -/// Can be used in the rulerlayout of the epggrid control. Will return true -/// if the item is a date label\, returns false if the item is a time label. +/// _boolean_, +/// @return **True** if the item is a date label\, returns false if the item is a time label. +/// @note Can be used in the rulerlayout of the epggrid control. +/// <p> /// } -/// \table_row3{ <b>`ListItem.Property(Addon.Enabled)`</b>, -/// \anchor ListItem_Property_AddonEnabled +/// \table_row3{ <b>`ListItem.Property(Addon.IsEnabled)`</b>, +/// \anchor ListItem_Property_AddonIsEnabled /// _boolean_, -/// Returns true when the selected addon is enabled (for use in the addon +/// @return **True** when the selected addon is enabled (for use in the addon /// info dialog only). +/// <p><hr> +/// @skinning_v17 **[Boolean Condition Updated]** \link ListItem_Property_AddonIsEnabled `ListItem.Property(Addon.IsEnabled)`\endlink +/// replaces `ListItem.Property(Addon.Enabled)`. +/// <p> /// } -/// \table_row3{ <b>`ListItem.Property(Addon.Installed)`</b>, -/// \anchor ListItem_Property_AddonInstalled +/// \table_row3{ <b>`ListItem.Property(Addon.IsInstalled)`</b>, +/// \anchor ListItem_Property_AddonIsInstalled /// _boolean_, -/// Returns true when the selected addon is installed (for use in the addon +/// @return **True** when the selected addon is installed (for use in the addon /// info dialog only). +/// <p><hr> +/// @skinning_v17 **[Boolean Condition Updated]** \link ListItem_Property_AddonIsInstalled `ListItem.Property(Addon.IsInstalled)`\endlink +/// replaces `ListItem.Property(Addon.Installed)`. +/// <p> /// } -/// \table_row3{ <b>`ListItem.Property(Addon.UpdateAvail)`</b>, -/// \anchor ListItem_Property_AddonUpdateAvail +/// \table_row3{ <b>`ListItem.Property(Addon.HasUpdate)`</b>, +/// \anchor ListItem_Property_AddonHasUpdate /// _boolean_, -/// Returns true when there's an update available for the selected addon. +/// @return **True** when there's an update available for the selected addon. +/// <p><hr> +/// @skinning_v17 **[Boolean Condition Updated]** \link ListItem_Property_AddonHasUpdate `ListItem.Property(Addon.HasUpdate)`\endlink +/// replaces `ListItem.Property(Addon.UpdateAvail)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.Label`</b>, /// \anchor ListItem_Label /// _string_, -/// Returns the left label of the currently selected item in a container +/// @return The left label of the currently selected item in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Label2`</b>, /// \anchor ListItem_Label2 /// _string_, -/// Returns the right label of the currently selected item in a container +/// @return The right label of the currently selected item in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Title`</b>, /// \anchor ListItem_Title /// _string_, -/// Returns the title of the currently selected song or movie in a container +/// @return The title of the currently selected song\, movie\, game in a container. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link ListItem_Title `ListItem.Title`\endlink extended +/// to support games +/// <p> /// } /// \table_row3{ <b>`ListItem.OriginalTitle`</b>, /// \anchor ListItem_OriginalTitle /// _string_, -/// Returns the original title of the currently selected movie in a container +/// @return The original title of the currently selected movie in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.SortLetter`</b>, /// \anchor ListItem_SortLetter /// _string_, -/// Returns the first letter of the current file in a container +/// @return The first letter of the current file in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.TrackNumber`</b>, /// \anchor ListItem_TrackNumber /// _string_, -/// Returns the track number of the currently selected song in a container +/// @return The track number of the currently selected song in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Artist`</b>, /// \anchor ListItem_Artist /// _string_, -/// Returns the artist of the currently selected song in a container +/// @return The artist of the currently selected song in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.AlbumArtist`</b>, /// \anchor ListItem_AlbumArtist /// _string_, -/// Returns the artist of the currently selected album in a list +/// @return The artist of the currently selected album in a list. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Sortname)`</b>, /// \anchor ListItem_Property_Artist_Sortname /// _string_, -/// Sortname of the currently selected Artist +/// @return The sortname of the currently selected Artist. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Property_Artist_Sortname `ListItem.Property(Artist_Sortname)`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Type)`</b>, /// \anchor ListItem_Property_Artist_Type /// _string_, -/// Type of the currently selected Artist - person\, group\, orchestra\, choir etc. +/// @return The type of the currently selected Artist - person\, group\, orchestra\, choir etc. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Property_Artist_Type `ListItem.Property(Artist_Type)`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Gender)`</b>, /// \anchor ListItem_Property_Artist_Gender /// _string_, -/// Gender of the currently selected Artist - male\, female\, other +/// @return The Gender of the currently selected Artist - male\, female\, other. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Property_Artist_Gender `ListItem.Property(Artist_Gender)`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Disambiguation)`</b>, /// \anchor ListItem_Property_Artist_Disambiguation /// _string_, -/// Brief description of the currently selected Artist that differentiates them -/// from others with the same name +/// @return A Brief description of the currently selected Artist that differentiates them +/// from others with the same name. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Property_Artist_Disambiguation `ListItem.Property(Artist_Disambiguation)`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Born)`</b>, /// \anchor ListItem_Property_Artist_Born /// _string_, -/// Date of Birth of the currently selected Artist +/// @return The date of Birth of the currently selected Artist. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Died)`</b>, /// \anchor ListItem_Property_Artist_Died /// _string_, -/// Date of Death of the currently selected Artist +/// @return The date of Death of the currently selected Artist. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Formed)`</b>, /// \anchor ListItem_Property_Artist_Formed /// _string_, -/// Formation date of the currently selected Band +/// @return The formation date of the currently selected Band. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Disbanded)`</b>, /// \anchor ListItem_Property_Artist_Disbanded /// _string_, -/// Disbanding date of the currently selected Band +/// @return The disbanding date of the currently selected Band. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_YearsActive)`</b>, /// \anchor ListItem_Property_Artist_YearsActive /// _string_, -/// Years the currently selected artist has been active +/// @return The years the currently selected artist has been active. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Instrument)`</b>, /// \anchor ListItem_Property_Artist_Instrument /// _string_, -/// Instruments played by the currently selected artist +/// @return The instruments played by the currently selected artist. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Description)`</b>, /// \anchor ListItem_Property_Artist_Description /// _string_, -/// Returns a biography of the currently selected artist +/// @return A biography of the currently selected artist. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Mood)`</b>, /// \anchor ListItem_Property_Artist_Mood /// _string_, -/// Returns the moods of the currently selected artist +/// @return The moods of the currently selected artist. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Style)`</b>, /// \anchor ListItem_Property_Artist_Style /// _string_, -/// Returns the styles of the currently selected artist +/// @return The styles of the currently selected artist. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Artist_Genre)`</b>, /// \anchor ListItem_Property_Artist_Genre /// _string_, -/// Returns the genre of the currently selected artist +/// @return The genre of the currently selected artist. +/// <p> /// } /// \table_row3{ <b>`ListItem.Album`</b>, /// \anchor ListItem_Album /// _string_, -/// Returns the album of the currently selected song in a container +/// @return The album of the currently selected song in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Album_Mood)`</b>, /// \anchor ListItem_Property_Album_Mood /// _string_, -/// Returns the moods of the currently selected Album +/// @return The moods of the currently selected Album. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Album_Style)`</b>, /// \anchor ListItem_Property_Album_Style /// _string_, -/// Returns the styles of the currently selected Album +/// @return The styles of the currently selected Album. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Album_Theme)`</b>, /// \anchor ListItem_Property_Album_Theme /// _string_, -/// Returns the themes of the currently selected Album +/// @return The themes of the currently selected Album. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Album_Type)`</b>, /// \anchor ListItem_Property_Album_Type /// _string_, -/// Returns the Album Type (e.g. compilation\, enhanced\, explicit lyrics) of -/// the currently selected Album +/// @return The Album Type (e.g. compilation\, enhanced\, explicit lyrics) of +/// the currently selected Album. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Album_Label)`</b>, /// \anchor ListItem_Property_Album_Label /// _string_, -/// Returns the record label of the currently selected Album +/// @return The record label of the currently selected Album. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Album_Description)`</b>, /// \anchor ListItem_Property_Album_Description /// _string_, -/// Returns a review of the currently selected Album +/// @return A review of the currently selected Album. +/// <p> /// } /// \table_row3{ <b>`ListItem.DiscNumber`</b>, /// \anchor ListItem_DiscNumber /// _string_, -/// Returns the disc number of the currently selected song in a container +/// @return The disc number of the currently selected song in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Year`</b>, /// \anchor ListItem_Year /// _string_, -/// Returns the year of the currently selected song\, album or movie in a -/// container +/// @return The year of the currently selected song\, album\, movie\, game in a +/// container. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link ListItem_Title `ListItem.Title`\endlink extended +/// to support games +/// <p> /// } /// \table_row3{ <b>`ListItem.Premiered`</b>, /// \anchor ListItem_Premiered /// _string_, -/// Returns the release/aired date of the currently selected episode\, show\, -/// movie or EPG item in a container +/// @return The release/aired date of the currently selected episode\, show\, +/// movie or EPG item in a container. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link ListItem_Premiered `ListItem.Premiered`\endlink +/// now also available for EPG items. +/// <p> /// } /// \table_row3{ <b>`ListItem.Genre`</b>, /// \anchor ListItem_Genre /// _string_, -/// Returns the genre of the currently selected song\, album or movie in a -/// container +/// @return The genre of the currently selected song\, album or movie in a +/// container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Contributors`</b>, /// \anchor ListItem_Contributors /// _string_, -/// List of all people who've contributed to the selected song +/// @return The list of all people who've contributed to the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Contributors `ListItem.Contributors`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.ContributorAndRole`</b>, /// \anchor ListItem_ContributorAndRole /// _string_, -/// List of all people and their role who've contributed to the selected song +/// @return The list of all people and their role who've contributed to the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_ContributorAndRole `ListItem.ContributorAndRole`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Director`</b>, /// \anchor ListItem_Director /// _string_, -/// Returns the director of the currently selected movie in a container +/// @return The director of the currently selected movie in a container. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link ListItem_Director `ListItem.Director`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`ListItem.Country`</b>, /// \anchor ListItem_Country /// _string_, -/// Returns the production country of the currently selected movie in a -/// container +/// @return The production country of the currently selected movie in a +/// container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Episode`</b>, /// \anchor ListItem_Episode /// _string_, -/// Returns the episode number value for the currently selected episode. It +/// @return The episode number value for the currently selected episode. It /// also returns the number of total\, watched or unwatched episodes for the /// currently selected tvshow or season\, based on the the current watched /// filter. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link ListItem_Episode `ListItem.Episode`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`ListItem.Season`</b>, /// \anchor ListItem_Season /// _string_, -/// Returns the season value for the currently selected tvshow +/// @return The season value for the currently selected tvshow. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link ListItem_Season `ListItem.Season`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`ListItem.TVShowTitle`</b>, /// \anchor ListItem_TVShowTitle /// _string_, -/// Returns the name value for the currently selected tvshow in the season and -/// episode depth of the video library +/// @return The name value for the currently selected tvshow in the season and +/// episode depth of the video library. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(TotalSeasons)`</b>, /// \anchor ListItem_Property_TotalSeasons /// _string_, -/// Returns the total number of seasons for the currently selected tvshow +/// @return The total number of seasons for the currently selected tvshow. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(TotalEpisodes)`</b>, /// \anchor ListItem_Property_TotalEpisodes /// _string_, -/// Returns the total number of episodes for the currently selected tvshow or -/// season +/// @return the total number of episodes for the currently selected tvshow or +/// season. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(WatchedEpisodes)`</b>, /// \anchor ListItem_Property_WatchedEpisodes /// _string_, -/// Returns the number of watched episodes for the currently selected tvshow -/// or season +/// @return The number of watched episodes for the currently selected tvshow +/// or season. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(UnWatchedEpisodes)`</b>, /// \anchor ListItem_Property_UnWatchedEpisodes /// _string_, -/// Returns the number of unwatched episodes for the currently selected tvshow -/// or season +/// @return The number of unwatched episodes for the currently selected tvshow +/// or season. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(NumEpisodes)`</b>, /// \anchor ListItem_Property_NumEpisodes /// _string_, -/// Returns the number of total\, watched or unwatched episodes for the +/// @return The number of total\, watched or unwatched episodes for the /// currently selected tvshow or season\, based on the the current watched filter. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureAperture`</b>, /// \anchor ListItem_PictureAperture /// _string_, -/// Returns the F-stop used to take the selected picture. This is the value of the -/// EXIF FNumber tag (hex code 0x829D). +/// @return The F-stop used to take the selected picture. +/// @note This is the value of the EXIF FNumber tag (hex code 0x829D). +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureAuthor`</b>, /// \anchor ListItem_PictureAuthor /// _string_, -/// Returns the name of the person involved in writing about the selected picture. -/// This is the value of the IPTC Writer tag (hex code 0x7A). +/// @return The name of the person involved in writing about the selected picture. +/// @note This is the value of the IPTC Writer tag (hex code 0x7A). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureAuthor `ListItem.PictureAuthor`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureByline`</b>, /// \anchor ListItem_PictureByline /// _string_, -/// Returns the name of the person who created the selected picture. This is -/// the value of the IPTC Byline tag (hex code 0x50). +/// @return The name of the person who created the selected picture. +/// @note This is the value of the IPTC Byline tag (hex code 0x50). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureByline `ListItem.PictureByline`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureBylineTitle`</b>, /// \anchor ListItem_PictureBylineTitle /// _string_, -/// Returns the title of the person who created the selected picture. This is -/// the value of the IPTC BylineTitle tag (hex code 0x55). +/// @return The title of the person who created the selected picture. +/// @note This is the value of the IPTC BylineTitle tag (hex code 0x55). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureBylineTitle `ListItem.PictureBylineTitle`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCamMake`</b>, /// \anchor ListItem_PictureCamMake /// _string_, -/// Returns the manufacturer of the camera used to take the selected picture. -/// This is the value of the EXIF Make tag (hex code 0x010F). +/// @return The manufacturer of the camera used to take the selected picture. +/// @note This is the value of the EXIF Make tag (hex code 0x010F). +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCamModel`</b>, /// \anchor ListItem_PictureCamModel /// _string_, -/// Returns the manufacturer's model name or number of the camera used to take -/// the selected picture. This is the value of the EXIF Model tag (hex code -/// 0x0110). +/// @return The manufacturer's model name or number of the camera used to take +/// the selected picture. +/// @note This is the value of the EXIF Model tag (hex code 0x0110). +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCaption`</b>, /// \anchor ListItem_PictureCaption /// _string_, -/// Returns a description of the selected picture. This is the value of the IPTC -/// Caption tag (hex code 0x78). +/// @return A description of the selected picture. +/// @note This is the value of the IPTC Caption tag (hex code 0x78). +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCategory`</b>, /// \anchor ListItem_PictureCategory /// _string_, -/// Returns the subject of the selected picture as a category code. This is the -/// value of the IPTC Category tag (hex code 0x0F). +/// @return The subject of the selected picture as a category code. +/// @note This is the value of the IPTC Category tag (hex code 0x0F). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureCategory `ListItem.PictureCategory`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCCDWidth`</b>, /// \anchor ListItem_PictureCCDWidth /// _string_, -/// Returns the width of the CCD in the camera used to take the selected -/// picture. This is calculated from three EXIF tags (0xA002 * 0xA210 -/// / 0xA20e). +/// @return The width of the CCD in the camera used to take the selected +/// picture. +/// @note This is calculated from three EXIF tags (0xA002 * 0xA210 / 0xA20e). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureCCDWidth `ListItem.PictureCCDWidth`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCity`</b>, /// \anchor ListItem_PictureCity /// _string_, -/// Returns the city where the selected picture was taken. This is the value of -/// the IPTC City tag (hex code 0x5A). +/// @return The city where the selected picture was taken. +/// @note This is the value of the IPTC City tag (hex code 0x5A). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureCity `ListItem.PictureCity`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureColour`</b>, /// \anchor ListItem_PictureColour /// _string_, -/// Returns whether the selected picture is "Colour" or "Black and White". +/// @return Whether the selected picture is "Colour" or "Black and White". +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureColour `ListItem.PictureColour`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureComment`</b>, /// \anchor ListItem_PictureComment /// _string_, -/// Returns a description of the selected picture. This is the value of the +/// @return A description of the selected picture. +/// @note This is the value of the /// EXIF User Comment tag (hex code 0x9286). This is the same value as /// \ref Slideshow_SlideComment "Slideshow.SlideComment". +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCopyrightNotice`</b>, /// \anchor ListItem_PictureCopyrightNotice /// _string_, -/// Returns the copyright notice of the selected picture. This is the value of -/// the IPTC Copyright tag (hex code 0x74). +/// @return The copyright notice of the selected picture. +/// @note This is the value of the IPTC Copyright tag (hex code 0x74). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureCopyrightNotice `ListItem.PictureCopyrightNotice`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCountry`</b>, /// \anchor ListItem_PictureCountry /// _string_, -/// Returns the full name of the country where the selected picture was taken. -/// This is the value of the IPTC CountryName tag (hex code 0x65). +/// @return The full name of the country where the selected picture was taken. +/// @note This is the value of the IPTC CountryName tag (hex code 0x65). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureCountry `ListItem.PictureCountry`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCountryCode`</b>, /// \anchor ListItem_PictureCountryCode /// _string_, -/// Returns the country code of the country where the selected picture was -/// taken. This is the value of the IPTC CountryCode tag (hex code 0x64). +/// @return The country code of the country where the selected picture was +/// taken. +/// @note This is the value of the IPTC CountryCode tag (hex code 0x64). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureCountryCode `ListItem.PictureCountryCode`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureCredit`</b>, /// \anchor ListItem_PictureCredit /// _string_, -/// Returns who provided the selected picture. This is the value of the IPTC -/// Credit tag (hex code 0x6E). +/// @return Who provided the selected picture. +/// @note This is the value of the IPTC Credit tag (hex code 0x6E). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureCredit `ListItem.PictureCredit`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureDate`</b>, /// \anchor ListItem_PictureDate /// _string_, -/// Returns the localized date of the selected picture. The short form of the -/// date is used. The value of the EXIF DateTimeOriginal tag (hex code 0x9003) +/// @return The localized date of the selected picture. The short form of the +/// date is used. +/// @note The value of the EXIF DateTimeOriginal tag (hex code 0x9003) /// is preferred. If the DateTimeOriginal tag is not found\, the value of /// DateTimeDigitized (hex code 0x9004) or of DateTime (hex code 0x0132) might /// be used. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureDate `ListItem.PictureDate`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureDatetime`</b>, /// \anchor ListItem_PictureDatetime /// _string_, -/// Returns the date/timestamp of the selected picture. The localized short form -/// of the date and time is used. The value of the EXIF DateTimeOriginal tag -/// (hex code 0x9003) is preferred. If the DateTimeOriginal tag is not found\, -/// the value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex code -/// 0x0132) might be used. +/// @return The date/timestamp of the selected picture. The localized short form +/// of the date and time is used. +/// @note The value of the EXIF DateTimeOriginal tag (hex code 0x9003) is preferred. +/// If the DateTimeOriginal tag is not found\, the value of DateTimeDigitized +/// (hex code 0x9004) or of DateTime (hex code 0x0132) might be used. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureDatetime `ListItem.PictureDatetime`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureDesc`</b>, /// \anchor ListItem_PictureDesc /// _string_, -/// Returns a short description of the selected picture. The SlideComment\, -/// EXIFComment\, or Caption values might contain a longer description. This -/// is the value of the EXIF ImageDescription tag (hex code 0x010E). +/// @return A short description of the selected picture. The SlideComment\, +/// EXIFComment\, or Caption values might contain a longer description. +/// @note This is the value of the EXIF ImageDescription tag (hex code 0x010E). +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureDigitalZoom`</b>, /// \anchor ListItem_PictureDigitalZoom /// _string_, -/// Returns the digital zoom ratio when the selected picture was taken. This -/// is the value of the EXIF DigitalZoomRatio tag (hex code 0xA404). +/// @return The digital zoom ratio when the selected picture was taken. +/// @note This is the value of the EXIF DigitalZoomRatio tag (hex code 0xA404). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureDigitalZoom `ListItem.PictureDigitalZoom`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureExpMode`</b>, /// \anchor ListItem_PictureExpMode /// _string_, -/// Returns the exposure mode of the selected picture. The possible values are -/// "Automatic"\, "Manual"\, and "Auto bracketing". This is the value of the -/// EXIF ExposureMode tag (hex code 0xA402). +/// @return The exposure mode of the selected picture. +/// The possible values are: +/// - <b>"Automatic"</b> +/// - <b>"Manual"</b> +/// - <b>"Auto bracketing"</b> +/// @note This is the value of the EXIF ExposureMode tag (hex code 0xA402). +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureExposure`</b>, /// \anchor ListItem_PictureExposure /// _string_, -/// Returns the class of the program used by the camera to set exposure when -/// the selected picture was taken. Values include "Manual"\, "Program -/// (Auto)"\, "Aperture priority (Semi-Auto)"\, "Shutter priority (semi-auto)"\, -/// etc. This is the value of the EXIF ExposureProgram tag (hex code 0x8822). +/// @return The class of the program used by the camera to set exposure when +/// the selected picture was taken. Values include: +/// - <b>"Manual"</b> +/// - <b>"Program (Auto)"</b> +/// - <b>"Aperture priority (Semi-Auto)"</b> +/// - <b>"Shutter priority (semi-auto)"</b> +/// - etc +/// @note This is the value of the EXIF ExposureProgram tag (hex code 0x8822). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureExposure `ListItem.PictureExposure`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureExposureBias`</b>, /// \anchor ListItem_PictureExposureBias /// _string_, -/// Returns the exposure bias of the selected picture. Typically this is a -/// number between -99.99 and 99.99. This is the value of the EXIF -/// ExposureBiasValue tag (hex code 0x9204). +/// @return The exposure bias of the selected picture. +/// Typically this is a number between -99.99 and 99.99. +/// @note This is the value of the EXIF ExposureBiasValue tag (hex code 0x9204). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureExposureBias `ListItem.PictureExposureBias`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureExpTime`</b>, /// \anchor ListItem_PictureExpTime /// _string_, -/// Returns the exposure time of the selected picture\, in seconds. This is the -/// value of the EXIF ExposureTime tag (hex code 0x829A). If the ExposureTime -/// tag is not found\, the ShutterSpeedValue tag (hex code 0x9201) might be -/// used. +/// @return The exposure time of the selected picture\, in seconds. +/// @note This is the value of the EXIF ExposureTime tag (hex code 0x829A). +/// If the ExposureTime tag is not found\, the ShutterSpeedValue tag (hex code 0x9201) +/// might be used. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureFlashUsed`</b>, /// \anchor ListItem_PictureFlashUsed /// _string_, -/// Returns the status of flash when the selected picture was taken. The value +/// @return The status of flash when the selected picture was taken. The value /// will be either "Yes" or "No"\, and might include additional information. -/// This is the value of the EXIF Flash tag (hex code 0x9209). +/// @note This is the value of the EXIF Flash tag (hex code 0x9209). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureFlashUsed `ListItem.PictureFlashUsed`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureFocalLen`</b>, /// \anchor ListItem_PictureFocalLen /// _string_, -/// Returns the lens focal length of the selected picture +/// @return The lens focal length of the selected picture. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureFocusDist`</b>, /// \anchor ListItem_PictureFocusDist /// _string_, -/// Returns the focal length of the lens\, in mm. This is the value of the EXIF -/// FocalLength tag (hex code 0x920A). +/// @return The focal length of the lens\, in mm. +/// @note This is the value of the EXIF FocalLength tag (hex code 0x920A). /// } /// \table_row3{ <b>`ListItem.PictureGPSLat`</b>, /// \anchor ListItem_PictureGPSLat /// _string_, -/// Returns the latitude where the selected picture was taken (degrees\, -/// minutes\, seconds North or South). This is the value of the EXIF -/// GPSInfo.GPSLatitude and GPSInfo.GPSLatitudeRef tags. +/// @return The latitude where the selected picture was taken (degrees\, +/// minutes\, seconds North or South). +/// @note This is the value of the EXIF GPSInfo.GPSLatitude and GPSInfo.GPSLatitudeRef tags. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureGPSLon`</b>, /// \anchor ListItem_PictureGPSLon /// _string_, -/// Returns the longitude where the selected picture was taken (degrees\, -/// minutes\, seconds East or West). This is the value of the EXIF -/// GPSInfo.GPSLongitude and GPSInfo.GPSLongitudeRef tags. +/// @return The longitude where the selected picture was taken (degrees\, +/// minutes\, seconds East or West). +/// @note This is the value of the EXIF GPSInfo.GPSLongitude and GPSInfo.GPSLongitudeRef tags. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureGPSAlt`</b>, /// \anchor ListItem_PictureGPSAlt /// _string_, -/// Returns the altitude in meters where the selected picture was taken. This -/// is the value of the EXIF GPSInfo.GPSAltitude tag. +/// @return The altitude in meters where the selected picture was taken. +/// @note This is the value of the EXIF GPSInfo.GPSAltitude tag. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureHeadline`</b>, /// \anchor ListItem_PictureHeadline /// _string_, -/// Returns a synopsis of the contents of the selected picture. This is the -/// value of the IPTC Headline tag (hex code 0x69). +/// @return A synopsis of the contents of the selected picture. +/// @note This is the value of the IPTC Headline tag (hex code 0x69). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureHeadline `ListItem.PictureHeadline`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureImageType`</b>, /// \anchor ListItem_PictureImageType /// _string_, -/// Returns the color components of the selected picture. This is the value of -/// the IPTC ImageType tag (hex code 0x82). +/// @return The color components of the selected picture. +/// @note This is the value of the IPTC ImageType tag (hex code 0x82). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureImageType `ListItem.PictureImageType`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureIPTCDate`</b>, /// \anchor ListItem_PictureIPTCDate /// _string_, -/// Returns the date when the intellectual content of the selected picture was -/// created\, rather than when the picture was created. This is the value of -/// the IPTC DateCreated tag (hex code 0x37). +/// @return The date when the intellectual content of the selected picture was +/// created\, rather than when the picture was created. +/// @note This is the value of the IPTC DateCreated tag (hex code 0x37). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureIPTCDate `ListItem.PictureIPTCDate`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureIPTCTime`</b>, /// \anchor ListItem_PictureIPTCTime /// _string_, -/// Returns the time when the intellectual content of the selected picture was -/// created\, rather than when the picture was created. This is the value of -/// the IPTC TimeCreated tag (hex code 0x3C). +/// @return The time when the intellectual content of the selected picture was +/// created\, rather than when the picture was created. +/// @note This is the value of the IPTC TimeCreated tag (hex code 0x3C). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureIPTCTime `ListItem.PictureIPTCTime`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureISO`</b>, /// \anchor ListItem_PictureISO /// _string_, -/// Returns the ISO speed of the camera when the selected picture was taken. -/// This is the value of the EXIF ISOSpeedRatings tag (hex code 0x8827). +/// @return The ISO speed of the camera when the selected picture was taken. +/// @note This is the value of the EXIF ISOSpeedRatings tag (hex code 0x8827). +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureKeywords`</b>, /// \anchor ListItem_PictureKeywords /// _string_, -/// Returns keywords assigned to the selected picture. This is the value of -/// the IPTC Keywords tag (hex code 0x19). +/// @return The keywords assigned to the selected picture. +/// @note This is the value of the IPTC Keywords tag (hex code 0x19). +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureLightSource`</b>, /// \anchor ListItem_PictureLightSource /// _string_, -/// Returns the kind of light source when the picture was taken. Possible -/// values include "Daylight"\, "Fluorescent"\, "Incandescent"\, etc. This is -/// the value of the EXIF LightSource tag (hex code 0x9208). +/// @return The kind of light source when the picture was taken. Possible +/// values include: +/// - <b>"Daylight"</b> +/// - <b>"Fluorescent"</b> +/// - <b>"Incandescent</b> +/// - etc +/// @note This is the value of the EXIF LightSource tag (hex code 0x9208). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureLightSource `ListItem.PictureLightSource`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureLongDate`</b>, /// \anchor ListItem_PictureLongDate /// _string_, -/// Returns only the localized date of the selected picture. The long form of -/// the date is used. The value of the EXIF DateTimeOriginal tag (hex code +/// @return Only the localized date of the selected picture. The long form of +/// the date is used. +/// @note The value of the EXIF DateTimeOriginal tag (hex code /// 0x9003) is preferred. If the DateTimeOriginal tag is not found\, the /// value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex code /// 0x0132) might be used. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureLongDate `ListItem.PictureLongDate`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureLongDatetime`</b>, /// \anchor ListItem_PictureLongDatetime /// _string_, -/// Returns the date/timestamp of the selected picture. The localized long -/// form of the date and time is used. The value of the EXIF DateTimeOriginal +/// @return The date/timestamp of the selected picture. The localized long +/// form of the date and time is used. +/// @note The value of the EXIF DateTimeOriginal /// tag (hex code 0x9003) is preferred. if the DateTimeOriginal tag is not /// found\, the value of DateTimeDigitized (hex code 0x9004) or of DateTime /// (hex code 0x0132) might be used. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureMeteringMode`</b>, /// \anchor ListItem_PictureMeteringMode /// _string_, -/// Returns the metering mode used when the selected picture was taken. The -/// possible values are "Center weight"\, "Spot"\, or "Matrix". This is the -/// value of the EXIF MeteringMode tag (hex code 0x9207). +/// @return The metering mode used when the selected picture was taken. The +/// possible values are: +/// - <b>"Center weight"</b> +/// - <b>"Spot"</b> +/// - <b>"Matrix"</b> +/// @note This is the value of the EXIF MeteringMode tag (hex code 0x9207). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureMeteringMode `ListItem.PictureMeteringMode`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureObjectName`</b>, /// \anchor ListItem_PictureObjectName /// _string_, -/// Returns a shorthand reference for the selected picture. This is the value -/// of the IPTC ObjectName tag (hex code 0x05). +/// @return A shorthand reference for the selected picture. +/// @note This is the value of the IPTC ObjectName tag (hex code 0x05). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureObjectName `ListItem.PictureObjectName`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureOrientation`</b>, /// \anchor ListItem_PictureOrientation /// _string_, -/// Returns the orientation of the selected picture. Possible values are "Top -/// Left"\, "Top Right"\, "Left Top"\, "Right Bottom"\, etc. This is the value -/// of the EXIF Orientation tag (hex code 0x0112). +/// @return The orientation of the selected picture. Possible values are: +/// - <b>"Top Left"</b> +/// - <b>"Top Right"</b> +/// - <b>"Left Top"</b> +/// - <b>"Right Bottom"</b> +/// - etc +/// @note This is the value of the EXIF Orientation tag (hex code 0x0112). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureOrientation `ListItem.PictureOrientation`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PicturePath`</b>, /// \anchor ListItem_PicturePath /// _string_, -/// Returns the filename and path of the selected picture +/// @return The filename and path of the selected picture. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureProcess`</b>, /// \anchor ListItem_PictureProcess /// _string_, -/// Returns the process used to compress the selected picture +/// @return The process used to compress the selected picture. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureProcess `ListItem.PictureProcess`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureReferenceService`</b>, /// \anchor ListItem_PictureReferenceService /// _string_, -/// Returns the Service Identifier of a prior envelope to which the selected -/// picture refers. This is the value of the IPTC ReferenceService tag -/// (hex code 0x2D). +/// @return The Service Identifier of a prior envelope to which the selected +/// picture refers. +/// @note This is the value of the IPTC ReferenceService tag (hex code 0x2D). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureReferenceService `ListItem.PictureReferenceService`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureResolution`</b>, /// \anchor ListItem_PictureResolution /// _string_, -/// Returns the dimensions of the selected picture +/// @return The dimensions of the selected picture. +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureSource`</b>, /// \anchor ListItem_PictureSource /// _string_, -/// Returns the original owner of the selected picture. This is the value of -/// the IPTC Source tag (hex code 0x73). +/// @return The original owner of the selected picture. +/// @note This is the value of the IPTC Source tag (hex code 0x73). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureSource `ListItem.PictureSource`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureSpecialInstructions`</b>, /// \anchor ListItem_PictureSpecialInstructions /// _string_, -/// Returns other editorial instructions concerning the use of the selected -/// picture. This is the value of the IPTC SpecialInstructions tag (hex -/// code 0x28). +/// @return Other editorial instructions concerning the use of the selected +/// picture. +/// @note This is the value of the IPTC SpecialInstructions tag (hex code 0x28). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureSpecialInstructions `ListItem.PictureSpecialInstructions`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureState`</b>, /// \anchor ListItem_PictureState /// _string_, -/// Returns the State/Province where the selected picture was taken. This is -/// the value of the IPTC ProvinceState tag (hex code 0x5F). +/// @return The State/Province where the selected picture was taken. +/// @note This is the value of the IPTC ProvinceState tag (hex code 0x5F). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureState `ListItem.PictureState`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureSublocation`</b>, /// \anchor ListItem_PictureSublocation /// _string_, -/// Returns the location within a city where the selected picture was taken - -/// might indicate the nearest landmark. This is the value of the IPTC -/// SubLocation tag (hex code 0x5C). +/// @return The location within a city where the selected picture was taken - +/// might indicate the nearest landmark. +/// @note This is the value of the IPTC SubLocation tag (hex code 0x5C). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureSublocation `ListItem.PictureSublocation`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureSupplementalCategories`</b>, /// \anchor ListItem_PictureSupplementalCategories /// _string_, -/// Returns supplemental category codes to further refine the subject of the -/// selected picture. This is the value of the IPTC SuppCategory tag (hex -/// code 0x14). +/// @return A supplemental category codes to further refine the subject of the +/// selected picture. +/// @note This is the value of the IPTC SuppCategory tag (hex code 0x14). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureSupplementalCategories `ListItem.PictureSupplementalCategories`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureTransmissionReference`</b>, /// \anchor ListItem_PictureTransmissionReference /// _string_, -/// Returns a code representing the location of original transmission of the -/// selected picture. This is the value of the IPTC TransmissionReference -/// tag (hex code 0x67). +/// @return A code representing the location of original transmission of the +/// selected picture. +/// @note This is the value of the IPTC TransmissionReference tag (hex code 0x67). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureTransmissionReference `ListItem.PictureTransmissionReference`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureUrgency`</b>, /// \anchor ListItem_PictureUrgency /// _string_, -/// Returns the urgency of the selected picture. Values are 1-9. The "1" is -/// most urgent. Some image management programs use urgency to indicate +/// @return The urgency of the selected picture. Values are 1-9. +/// @note The "1" is most urgent. Some image management programs use urgency to indicate /// picture rating\, where urgency "1" is 5 stars and urgency "5" is 1 star. /// Urgencies 6-9 are not used for rating. This is the value of the IPTC /// Urgency tag (hex code 0x0A). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureUrgency `ListItem.PictureUrgency`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PictureWhiteBalance`</b>, /// \anchor ListItem_PictureWhiteBalance /// _string_, -/// Returns the white balance mode set when the selected picture was taken. -/// The possible values are "Manual" and "Auto". This is the value of the -/// EXIF WhiteBalance tag (hex code 0xA403). +/// @return The white balance mode set when the selected picture was taken. +/// The possible values are: +/// - <b>"Manual"</b> +/// - <b>"Auto"</b> +/// @note This is the value of the EXIF WhiteBalance tag (hex code 0xA403). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_PictureWhiteBalance `ListItem.PictureWhiteBalance`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.FileName`</b>, /// \anchor ListItem_FileName /// _string_, -/// Returns the filename of the currently selected song or movie in a container +/// @return The filename of the currently selected song or movie in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Path`</b>, /// \anchor ListItem_Path /// _string_, -/// Returns the complete path of the currently selected song or movie in a -/// container +/// @return The complete path of the currently selected song or movie in a +/// container. +/// <p> /// } /// \table_row3{ <b>`ListItem.FolderName`</b>, /// \anchor ListItem_FolderName /// _string_, -/// Returns top most folder of the path of the currently selected song or -/// movie in a container +/// @return The top most folder of the path of the currently selected song or +/// movie in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.FolderPath`</b>, /// \anchor ListItem_FolderPath /// _string_, -/// Returns the complete path of the currently selected song or movie in a +/// @return The complete path of the currently selected song or movie in a /// container (without user details). +/// <p> /// } /// \table_row3{ <b>`ListItem.FileNameAndPath`</b>, /// \anchor ListItem_FileNameAndPath /// _string_, -/// Returns the full path with filename of the currently selected song or -/// movie in a container +/// @return The full path with filename of the currently selected song or +/// movie in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.FileExtension`</b>, /// \anchor ListItem_FileExtension /// _string_, -/// Returns the file extension (without leading dot) of the currently selected -/// item in a container +/// @return The file extension (without leading dot) of the currently selected +/// item in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Date`</b>, /// \anchor ListItem_Date /// _string_, -/// Returns the file date of the currently selected song or movie in a +/// @return The file date of the currently selected song or movie in a /// container / Aired date of an episode / Day\, start time and end time of -/// current selected TV programme (PVR) +/// current selected TV programme (PVR). +/// <p> +/// } +/// \table_row3{ <b>`ListItem.DateTime`</b>, +/// \anchor ListItem_DateTime +/// _string_, +/// @return The date and time a certain event happened (event log). +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link ListItem_DateTime `ListItem.DateTime`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.DateAdded`</b>, /// \anchor ListItem_DateAdded /// _string_, -/// Returns the date the currently selected item was added to the +/// @return The date the currently selected item was added to the /// library / Date and time of an event in the EventLog window. +/// <p> /// } /// \table_row3{ <b>`ListItem.Size`</b>, /// \anchor ListItem_Size /// _string_, -/// Returns the file size of the currently selected song or movie in a -/// container +/// @return The file size of the currently selected song or movie in a +/// container. +/// <p> /// } -/// \table_row3{ <b>`ListItem.Rating`</b>, +/// \table_row3{ <b>`ListItem.Rating([name])`</b>, /// \anchor ListItem_Rating /// _string_, -/// Returns the scraped rating of the currently selected movie in a container +/// @return The scraped rating of the currently selected item in a container (1-10). +/// @param name - [opt] you can specify the name of the scraper to retrieve a specific rating\, +/// for use in dialogvideoinfo.xml. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link ListItem_Rating `ListItem.Rating([name])`\endlink replaces +/// the old `ListItem.Ratings([name])` infolabel. +/// @skinning_v17 **[New Infolabel]** \link ListItem_Rating `ListItem.Ratings([name])`\endlink +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_Rating `ListItem.Ratings`\endlink +/// for songs it's now the scraped rating. +/// <p> /// } /// \table_row3{ <b>`ListItem.Set`</b>, /// \anchor ListItem_Set /// _string_, -/// Returns the name of the set the movie is part of +/// @return The name of the set the movie is part of. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Set `ListItem.Set`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.SetId`</b>, /// \anchor ListItem_SetId /// _string_, -/// Returns the id of the set the movie is part of +/// @return The id of the set the movie is part of. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_SetId `ListItem.SetId`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Status`</b>, +/// \anchor ListItem_Status +/// _string_, +/// @return One of the following status: +/// - <b>"returning series"</b> +/// - <b>"in production"</b> +/// - <b>"planned"</b> +/// - <b>"cancelled"</b> +/// - <b>"ended"</b> +/// <p> +/// @note For use with tv shows. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Status `ListItem.Status`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.EndTimeResume`</b>, +/// \anchor ListItem_EndTimeResume +/// _string_, +/// @return Returns the time a video will end if you resume it\, instead of playing it from the beginning. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_EndTimeResume `ListItem.EndTimeResume`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.UserRating`</b>, /// \anchor ListItem_UserRating /// _string_, -/// Returns the user rating of the currently selected item in a container +/// @return The user rating of the currently selected item in a container (1-10). +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_UserRating `ListItem.UserRating`\endlink +/// now available for albums/songs. +/// @skinning_v16 **[New Infolabel]** \link ListItem_UserRating `ListItem.UserRating`\endlink +/// <p> /// } -/// \table_row3{ <b>`ListItem.Votes`</b>, +/// \table_row3{ <b>`ListItem.Votes([name])`</b>, /// \anchor ListItem_Votes /// _string_, -/// Returns the scraped votes of the currently selected movie in a container +/// @return The scraped votes of the currently selected movie in a container. +/// @param name - [opt] you can specify the name of the scraper to retrieve specific votes\, +/// for use in `dialogvideoinfo.xml`. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_Votes `ListItem.Votes([name])`\endlink +/// add optional param <b>name</b> to specify the scrapper. +/// @skinning_v13 **[New Infolabel]** \link ListItem_Votes `ListItem.Votes`\endlink +/// <p> /// } -/// \table_row3{ <b>`ListItem.RatingAndVotes`</b>, +/// \table_row3{ <b>`ListItem.RatingAndVotes([name])`</b>, /// \anchor ListItem_RatingAndVotes /// _string_, -/// Returns the scraped rating and votes of the currently selected movie in a -/// container +/// @return The scraped rating and votes of the currently selected movie in a +/// container (1-10). +/// @param name - [opt] you can specify the name of the scraper to retrieve specific votes\, +/// for use in `dialogvideoinfo.xml`. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_RatingAndVotes `ListItem.RatingAndVotes([name])`\endlink +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_RatingAndVotes `ListItem.RatingAndVotes`\endlink +/// now available for albums/songs. +/// <p> /// } /// \table_row3{ <b>`ListItem.Mood`</b>, /// \anchor ListItem_Mood /// _string_, -/// Mood of the selected song +/// @return The mood of the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Mood `ListItem.Mood`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Mpaa`</b>, /// \anchor ListItem_Mpaa /// _string_, -/// Show the MPAA rating of the currently selected movie in a container +/// @return The MPAA rating of the currently selected movie in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.ProgramCount`</b>, /// \anchor ListItem_ProgramCount /// _string_, -/// Returns the number of times an xbe has been run from "my programs" +/// @return The number of times an xbe has been run from "my programs". +/// @todo description might be outdated +/// <p> /// } /// \table_row3{ <b>`ListItem.Duration`</b>, /// \anchor ListItem_Duration /// _string_, -/// Returns the duration of the currently selected item in a container -/// in the format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The duration of the currently selected item in a container +/// in the format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link ListItem_Duration `ListItem.Duration`\endlink will +/// return <b>hh:mm:ss</b> instead of the duration in minutes. +/// <p> /// } /// \table_row3{ <b>`ListItem.Duration(format)`</b>, -/// \anchor ListItem.Duration_format +/// \anchor ListItem_Duration_format /// _string_, -/// Returns the duration of the currently selected item in a container in -/// different formats: hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The duration of the currently selected item in a container in +/// different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`ListItem.DBTYPE`</b>, /// \anchor ListItem_DBTYPE /// _string_, -/// Returns the database type of the ListItem.DBID for videos (movie\, set\, +/// @return The database type of the \ref ListItem_DBID "ListItem.DBID" for videos (movie\, set\, /// genre\, actor\, tvshow\, season\, episode). It does not return any value -/// for the music library. Beware with season\, the "*all seasons" entry does +/// for the music library. +/// @note Beware with season\, the "*all seasons" entry does /// give a DBTYPE "season" and a DBID\, but you can't get the details of that /// entry since it's a virtual entry in the Video Library. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_DBTYPE `ListItem.DBTYPE`\endlink +/// now available in the music library. +/// <p> /// } /// \table_row3{ <b>`ListItem.DBID`</b>, /// \anchor ListItem_DBID /// _string_, -/// Returns the database id of the currently selected listitem in a container +/// @return The database id of the currently selected listitem in a container. +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Appearances`</b>, +/// \anchor ListItem_Appearances +/// _string_, +/// @return The number of movies featuring the selected actor / directed by the selected director. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Appearances `ListItem.Appearances`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Cast`</b>, /// \anchor ListItem_Cast /// _string_, -/// Returns a concatenated string of cast members of the currently selected -/// movie\, for use in dialogvideoinfo.xml +/// @return A concatenated string of cast members of the currently selected +/// movie\, for use in dialogvideoinfo.xml. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link ListItem_Cast `ListItem.Cast`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`ListItem.CastAndRole`</b>, /// \anchor ListItem_CastAndRole /// _string_, -/// Returns a concatenated string of cast members and roles of the currently -/// selected movie\, for use in dialogvideoinfo.xml +/// @return A concatenated string of cast members and roles of the currently +/// selected movie\, for use in dialogvideoinfo.xml. +/// <p> /// } /// \table_row3{ <b>`ListItem.Studio`</b>, /// \anchor ListItem_Studio /// _string_, -/// Studio of current selected Music Video in a container +/// @return The studio of current selected Music Video in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Top250`</b>, /// \anchor ListItem_Top250 /// _string_, -/// Returns the IMDb top250 position of the currently selected listitem in a +/// @return The IMDb top250 position of the currently selected listitem in a /// container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Trailer`</b>, /// \anchor ListItem_Trailer /// _string_, -/// Returns the full trailer path with filename of the currently selected -/// movie in a container +/// @return The full trailer path with filename of the currently selected +/// movie in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Writer`</b>, /// \anchor ListItem_Writer /// _string_, -/// Name of Writer of current Video in a container +/// @return The name of Writer of current Video in a container. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link ListItem_Writer `ListItem.Writer`\endlink +/// also supports EPG. +/// <p> /// } /// \table_row3{ <b>`ListItem.Tag`</b>, /// \anchor ListItem_Tag /// _string_, -/// Summary of current Video in a container +/// @return The summary of current Video in a container. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Tag `ListItem.Tag`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Tagline`</b>, /// \anchor ListItem_Tagline /// _string_, -/// Small Summary of current Video in a container +/// @return A Small Summary of current Video in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.PlotOutline`</b>, /// \anchor ListItem_PlotOutline /// _string_, -/// Small Summary of current Video in a container +/// @return A small Summary of current Video in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.Plot`</b>, /// \anchor ListItem_Plot /// _string_, -/// Complete Text Summary of Video in a container +/// @return The complete Text Summary of Video in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.IMDBNumber`</b>, /// \anchor ListItem_IMDBNumber /// _string_, -/// The IMDb ID of the selected Video in a container +/// @return The IMDb ID of the selected Video in a container. +/// <p><hr> +/// @skinning_v15 **[New Infolabel]** \link ListItem_IMDBNumber `ListItem.IMDBNumber`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.EpisodeName`</b>, /// \anchor ListItem_EpisodeName /// _string_, -/// (PVR only) The name of the episode if the selected EPG item is a TV Show +/// @return The name of the episode if the selected EPG item is a TV Show (PVR). +/// <p><hr> +/// @skinning_v15 **[New Infolabel]** \link ListItem_EpisodeName `ListItem.EpisodeName`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.PercentPlayed`</b>, /// \anchor ListItem_PercentPlayed /// _string_, -/// Returns percentage value [0-100] of how far the selected video has been -/// played +/// @return The percentage value [0-100] of how far the selected video has been +/// played. +/// <p> /// } /// \table_row3{ <b>`ListItem.LastPlayed`</b>, /// \anchor ListItem_LastPlayed /// _string_, -/// Last play date of Video in a container +/// @return The last play date of Video in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.PlayCount`</b>, /// \anchor ListItem_PlayCount /// _string_, -/// Playcount of Video in a container +/// @return The playcount of Video in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.ChannelName`</b>, /// \anchor ListItem_ChannelName /// _string_, -/// Name of current selected TV channel in a container +/// @return The name of current selected TV channel in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.VideoCodec`</b>, /// \anchor ListItem_VideoCodec /// _string_, -/// Returns the video codec of the currently selected video (common values: -/// 3iv2\, avc1\, div2\, div3\, divx\, divx 4\, dx50\, flv\, h264\, microsoft\, mp42\, -/// mp43\, mp4v\, mpeg1video\, mpeg2video\, mpg4\, rv40\, svq1\, svq3\, -/// theora\, vp6f\, wmv2\, wmv3\, wvc1\, xvid) +/// @return The video codec of the currently selected video. Common values: +/// - <b>3iv2</b> +/// - <b>avc1</b> +/// - <b>div2</b> +/// - <b>div3</b> +/// - <b>divx</b> +/// - <b>divx 4</b> +/// - <b>dx50</b> +/// - <b>flv</b> +/// - <b>h264</b> +/// - <b>microsoft</b> +/// - <b>mp42</b> +/// - <b>mp43</b> +/// - <b>mp4v</b> +/// - <b>mpeg1video</b> +/// - <b>mpeg2video</b> +/// - <b>mpg4</b> +/// - <b>rv40</b> +/// - <b>svq1</b> +/// - <b>svq3</b> +/// - <b>theora</b> +/// - <b>vp6f</b> +/// - <b>wmv2</b> +/// - <b>wmv3</b> +/// - <b>wvc1</b> +/// - <b>xvid</b> +/// - etc +/// <p> /// } /// \table_row3{ <b>`ListItem.VideoResolution`</b>, /// \anchor ListItem_VideoResolution /// _string_, -/// Returns the resolution of the currently selected video (possible values: -/// 480\, 576\, 540\, 720\, 1080\, 4K). Note that 540 usually means a widescreen +/// @return The resolution of the currently selected video. Possible values: +/// - <b>480</b> +/// - <b>576</b> +/// - <b>540</b> +/// - <b>720</b> +/// - <b>1080</b> +/// - <b>4K</b> +/// - <b>8K</b> +/// @note 540 usually means a widescreen /// format (around 960x540) while 576 means PAL resolutions (normally /// 720x576)\, therefore 540 is actually better resolution than 576. +/// <p><hr> +/// @skinning_v18 **[Updated Infolabel]** \link ListItem_VideoResolution ListItem.VideoResolution\endlink +/// added <b>8K</b> as a possible value. +/// <p> /// } /// \table_row3{ <b>`ListItem.VideoAspect`</b>, /// \anchor ListItem_VideoAspect /// _string_, -/// Returns the aspect ratio of the currently selected video (possible values: -/// 1.33\, 1.37\, 1.66\, 1.78\, 1.85\, 2.20\, 2.35\, 2.40\, 2.55\, 2.76) +/// @return The aspect ratio of the currently selected video. Possible values: +/// - <b>1.33</b> +/// - <b>1.37</b> +/// - <b>1.66</b> +/// - <b>1.78</b> +/// - <b>1.85</b> +/// - <b>2.20</b> +/// - <b>2.35</b> +/// - <b>2.40</b> +/// - <b>2.55</b> +/// - <b>2.76</b> +/// <p> /// } /// \table_row3{ <b>`ListItem.AudioCodec`</b>, /// \anchor ListItem_AudioCodec /// _string_, -/// Returns the audio codec of the currently selected video (common values: -/// aac\, ac3\, cook\, dca\, dtshd_hra\, dtshd_ma\, eac3\, mp1\, mp2\, mp3\, pcm_s16be\, pcm_s16le\, pcm_u8\, truehd\, vorbis\, wmapro\, wmav2) +/// @return The audio codec of the currently selected video. Common values: +/// - <b>aac</b> +/// - <b>ac3</b> +/// - <b>cook</b> +/// - <b>dca</b> +/// - <b>dtshd_hra</b> +/// - <b>dtshd_ma</b> +/// - <b>eac3</b> +/// - <b>mp1</b> +/// - <b>mp2</b> +/// - <b>mp3</b> +/// - <b>pcm_s16be</b> +/// - <b>pcm_s16le</b> +/// - <b>pcm_u8</b> +/// - <b>truehd</b> +/// - <b>vorbis</b> +/// - <b>wmapro</b> +/// - <b>wmav2</b> +/// <p> /// } /// \table_row3{ <b>`ListItem.AudioChannels`</b>, /// \anchor ListItem_AudioChannels /// _string_, -/// Returns the number of audio channels of the currently selected video -/// (possible values: 1\, 2\, 4\, 5\, 6\, 8\, 10) +/// @return The number of audio channels of the currently selected video. Possible values: +/// - <b>1</b> +/// - <b>2</b> +/// - <b>4</b> +/// - <b>5</b> +/// - <b>6</b> +/// - <b>8</b> +/// - <b>10</b> +/// <p><hr> +/// @skinning_v16 **[Infolabel Updated]** \link ListItem_AudioChannels `ListItem.AudioChannels`\endlink +/// if a video contains no audio\, these infolabels will now return empty. +/// (they used to return 0) +/// <p> /// } /// \table_row3{ <b>`ListItem.AudioLanguage`</b>, /// \anchor ListItem_AudioLanguage /// _string_, -/// Returns the audio language of the currently selected video (returns an -/// ISO 639-2 three character code\, e.g. eng\, epo\, deu) +/// @return The audio language of the currently selected video (an +/// ISO 639-2 three character code: e.g. eng\, epo\, deu) +/// <p> /// } /// \table_row3{ <b>`ListItem.SubtitleLanguage`</b>, /// \anchor ListItem_SubtitleLanguage /// _string_, -/// Returns the subtitle language of the currently selected video (returns an -/// ISO 639-2 three character code\, e.g. eng\, epo\, deu) +/// @return The subtitle language of the currently selected video (an +/// ISO 639-2 three character code: e.g. eng\, epo\, deu) +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(AudioCodec.[n])`</b>, /// \anchor ListItem_Property_AudioCodec /// _string_, -/// Returns the audio codec of the currently selected video\, 'n' defines the -/// number of the audiostream (values: see \ref ListItem_AudioCodec "ListItem.AudioCodec") +/// @return The audio codec of the currently selected video +/// @param n - the number of the audiostream (values: see \ref ListItem_AudioCodec "ListItem.AudioCodec") +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link ListItem_Property_AudioCodec `ListItem.Property(AudioCodec.[n])`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(AudioChannels.[n])`</b>, /// \anchor ListItem_Property_AudioChannels /// _string_, -/// Returns the number of audio channels of the currently selected video\, 'n' -/// defines the number of the audiostream (values: see +/// @return The number of audio channels of the currently selected video +/// @param n - the number of the audiostream (values: see /// \ref ListItem_AudioChannels "ListItem.AudioChannels") +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link ListItem_Property_AudioChannels `ListItem.Property(AudioChannels.[n])`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(AudioLanguage.[n])`</b>, /// \anchor ListItem_Property_AudioLanguage /// _string_, -/// Returns the audio language of the currently selected video\, 'n' defines -/// the number of the audiostream (values: see \ref ListItem_AudioLanguage "ListItem.AudioLanguage") +/// @return The audio language of the currently selected video +/// @param n - the number of the audiostream (values: see \ref ListItem_AudioLanguage "ListItem.AudioLanguage") +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link ListItem_Property_AudioLanguage `ListItem.Property(AudioLanguage.[n])`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(SubtitleLanguage.[n])`</b>, /// \anchor ListItem_Property_SubtitleLanguage /// _string_, -/// Returns the subtitle language of the currently selected video\, 'n' defines -/// the number of the subtitle (values: see \ref ListItem_SubtitleLanguage "ListItem.SubtitleLanguage") -/// } -/// \table_row3{ <b>`ListItem.Property(Addon.Name)`</b>, -/// \anchor ListItem_Property_AddonName -/// _string_, -/// Returns the name of the currently selected addon -/// } -/// \table_row3{ <b>`ListItem.Property(Addon.Version)`</b>, -/// \anchor ListItem_Property_AddonVersion -/// _string_, -/// Returns the version of the currently selected addon -/// } -/// \table_row3{ <b>`ListItem.Property(Addon.Summary)`</b>, -/// \anchor ListItem_Property_AddonSummary -/// _string_, -/// Returns a short description of the currently selected addon -/// } -/// \table_row3{ <b>`ListItem.Property(Addon.Description)`</b>, -/// \anchor ListItem_Property_AddonDescription -/// _string_, -/// Returns the full description of the currently selected addon -/// } -/// \table_row3{ <b>`ListItem.Property(Addon.Type)`</b>, -/// \anchor ListItem_Property_AddonType -/// _string_, -/// Returns the type (screensaver\, script\, skin\, etc...) of the currently -/// selected addon -/// } -/// \table_row3{ <b>`ListItem.Property(Addon.Creator)`</b>, -/// \anchor ListItem_Property_AddonCreator -/// _string_, -/// Returns the name of the author the currently selected addon +/// @return The subtitle language of the currently selected video +/// @param n - the number of the subtitle (values: see \ref ListItem_SubtitleLanguage "ListItem.SubtitleLanguage") +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link ListItem_Property_SubtitleLanguage `ListItem.Property(SubtitleLanguage.[n])`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Addon.Disclaimer)`</b>, /// \anchor ListItem_Property_AddonDisclaimer /// _string_, -/// Returns the disclaimer of the currently selected addon +/// @return The disclaimer of the currently selected addon. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Addon.Changelog)`</b>, /// \anchor ListItem_Property_AddonChangelog /// _string_, -/// Returns the changelog of the currently selected addon +/// @return The changelog of the currently selected addon. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Addon.ID)`</b>, /// \anchor ListItem_Property_AddonID /// _string_, -/// Returns the identifier of the currently selected addon +/// @return The identifier of the currently selected addon. +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Addon.Status)`</b>, /// \anchor ListItem_Property_AddonStatus /// _string_, -/// Returns the status of the currently selected addon +/// @return The status of the currently selected addon. +/// @todo missing reference in GuiInfoManager.cpp making it hard to track. +/// <p> /// } -/// \table_row3{ <b>`ListItem.Property(Addon.Broken)`</b>, -/// \anchor ListItem_Property_AddonBroken -/// _string_, -/// Returns a message when the addon is marked as broken in the repo +/// \table_row3{ <b>`ListItem.Property(Addon.Orphaned)`</b>, +/// \anchor ListItem_Property_AddonOrphaned +/// _boolean_, +/// @return **True** if the Addon is orphanad. +/// @todo missing reference in GuiInfoManager.cpp making it hard to track. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link ListItem_Property_AddonOrphaned `ListItem.Property(Addon.Orphaned)`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(Addon.Path)`</b>, /// \anchor ListItem_Property_AddonPath /// _string_, -/// Returns the path of the currently selected addon +/// @return The path of the currently selected addon. +/// <p> /// } /// \table_row3{ <b>`ListItem.StartTime`</b>, /// \anchor ListItem_StartTime /// _string_, -/// Start time of current selected TV programme in a container +/// @return The start time of current selected TV programme in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.EndTime`</b>, /// \anchor ListItem_EndTime /// _string_, -/// End time of current selected TV programme in a container +/// @return The end time of current selected TV programme in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.StartDate`</b>, /// \anchor ListItem_StartDate /// _string_, -/// Start date of current selected TV programme in a container +/// @return The start date of current selected TV programme in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.EndDate`</b>, /// \anchor ListItem_EndDate /// _string_, -/// End date of current selected TV programme in a container +/// @return The end date of current selected TV programme in a container. +/// <p> /// } /// \table_row3{ <b>`ListItem.NextTitle`</b>, /// \anchor ListItem_NextTitle /// _string_, -/// Title of the next item (PVR). +/// @return The title of the next item (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.NextGenre`</b>, /// \anchor ListItem_NextGenre /// _string_, -/// Genre of the next item (PVR). +/// @return The genre of the next item (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.NextPlot`</b>, /// \anchor ListItem_NextPlot /// _string_, -/// Plot of the next item (PVR). +/// @return The plot of the next item (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.NextPlotOutline`</b>, /// \anchor ListItem_NextPlotOutline /// _string_, -/// Plot outline of the next item (PVR). +/// @return The plot outline of the next item (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.NextStartTime`</b>, /// \anchor ListItem_NextStartTime /// _string_, -/// Start time of the next item (PVR). +/// @return The start time of the next item (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.NextEndTime`</b>, /// \anchor ListItem_NextEndTime /// _string_, -/// End of the next item (PVR). +/// @return The end of the next item (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.NextStartDate`</b>, /// \anchor ListItem_NextStartDate /// _string_, -/// Start date of the next item (PVR). +/// @return The start date of the next item (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.NextEndDate`</b>, /// \anchor ListItem_NextEndDate /// _string_, -/// End date of the next item (PVR). +/// @return The end date of the next item (PVR). +/// <p> +/// } +/// \table_row3{ <b>`ListItem.NextDuration`</b>, +/// \anchor ListItem_NextDuration +/// _string_, +/// @return The duration of the next item (PVR) in the format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_NextDuration `ListItem.NextDuration`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.NextDuration(format)`</b>, +/// \anchor ListItem_NextDuration_format +/// _string_, +/// @return The duration of the next item (PVR) in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_NextDuration_format `ListItem.NextDuration(format)`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.ChannelGroup`</b>, /// \anchor ListItem_ChannelGroup /// _string_, -/// Channel group of the selected item (PVR). +/// @return The channel group of the selected item (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.ChannelNumberLabel`</b>, /// \anchor ListItem_ChannelNumberLabel /// _string_, -/// Channel and subchannel number of the currently selected channel that's +/// @return The channel and subchannel number of the currently selected channel that's /// currently playing (PVR). +/// <p><hr> +/// @skinning_v14 **[New Infolabel]** \link ListItem_ChannelNumberLabel `ListItem.ChannelNumberLabel`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Progress`</b>, /// \anchor ListItem_Progress /// _string_, -/// Part of the programme that's been played (PVR). +/// @return The part of the programme that's been played (PVR). +/// <p> /// } /// \table_row3{ <b>`ListItem.StereoscopicMode`</b>, /// \anchor ListItem_StereoscopicMode /// _string_, -/// Returns the stereomode of the selected video (i.e. mono\, -/// split_vertical\, split_horizontal\, row_interleaved\, -/// anaglyph_cyan_red\, anaglyph_green_magenta) +/// @return The stereomode of the selected video: +/// - <b>mono</b> +/// - <b>split_vertical</b> +/// - <b>split_horizontal</b> +/// - <b>row_interleaved</b> +/// - <b>anaglyph_cyan_red</b> +/// - <b>anaglyph_green_magenta</b> +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link ListItem_StereoscopicMode `ListItem.StereoscopicMode`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.HasTimerSchedule`</b>, /// \anchor ListItem_HasTimerSchedule /// _boolean_, -/// Whether the item was scheduled by a timer rule (PVR). (v16 addition) +/// @return **True** if the item was scheduled by a timer rule (PVR). +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \ref ListItem_HasTimerSchedule "ListItem.HasTimerSchedule" +/// <p> /// } /// \table_row3{ <b>`ListItem.HasRecording`</b>, /// \anchor ListItem_HasRecording /// _boolean_, -/// Returns true if a given epg tag item currently gets recorded or has been recorded +/// @return **True** if a given epg tag item currently gets recorded or has been recorded. +/// <p> /// } /// \table_row3{ <b>`ListItem.TimerHasError`</b>, /// \anchor ListItem_TimerHasError /// _boolean_, -/// Whether the item has a timer and it won't be recorded because of an error (PVR). (v17 addition) +/// @return **True** if the item has a timer and it won't be recorded because of an error (PVR). +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \ref ListItem_TimerHasError "ListItem.TimerHasError" +/// <p> /// } /// \table_row3{ <b>`ListItem.TimerHasConflict`</b>, /// \anchor ListItem_TimerHasConflict /// _boolean_, -/// Whether the item has a timer and it won't be recorded because of a conflict (PVR). (v17 addition) +/// @return **True** if the item has a timer and it won't be recorded because of a conflict (PVR). +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \ref ListItem_TimerHasConflict "ListItem.TimerHasConflict" +/// <p> /// } /// \table_row3{ <b>`ListItem.TimerIsActive`</b>, /// \anchor ListItem_TimerIsActive /// _boolean_, -/// Whether the item has a timer that will be recorded\, i.e. the timer is enabled (PVR). (v17 addition) +/// @return **True** if the item has a timer that will be recorded\, i.e. the timer is enabled (PVR). +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \ref ListItem_TimerIsActive "ListItem.TimerIsActive" +/// <p> /// } /// \table_row3{ <b>`ListItem.Comment`</b>, /// \anchor ListItem_Comment /// _string_, -/// Comment assigned to the item (PVR/MUSIC). +/// @return The comment assigned to the item (PVR/MUSIC). +/// <p> /// } /// \table_row3{ <b>`ListItem.TimerType`</b>, /// \anchor ListItem_TimerType /// _string_, -/// Returns the type of the PVR timer / timer rule item as a human readable string +/// @return The type of the PVR timer / timer rule item as a human readable string. +/// <p> /// } /// \table_row3{ <b>`ListItem.EpgEventTitle`</b>, /// \anchor ListItem_EpgEventTitle /// _string_, -/// Returns the title of the epg event associated with the item\, if any +/// @return The title of the epg event associated with the item\, if any. +/// <p> /// } /// \table_row3{ <b>`ListItem.EpgEventIcon`</b>, /// \anchor ListItem_EpgEventIcon /// _string_, -/// Returns the thumbnail for the epg event associated with the item (if it exists) +/// @return The thumbnail for the EPG event associated with the item (if it exists). +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_EpgEventIcon `ListItem.EpgEventIcon`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.InProgress`</b>, /// \anchor ListItem_InProgress /// _boolean_, -/// Returns true if the epg event item is currently active (time-wise) +/// @return **True** if the EPG event item is currently active (time-wise). +/// <p> /// } /// \table_row3{ <b>`ListItem.IsParentFolder`</b>, /// \anchor ListItem_IsParentFolder /// _boolean_, -/// Returns true if the current list item is the goto parent folder '..' +/// @return **True** if the current list item is the goto parent folder '..'. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link ListItem_IsParentFolder `ListItem.IsParentFolder`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonName`</b>, /// \anchor ListItem_AddonName /// _string_, -/// Returns the name of the currently selected addon +/// @return The name of the currently selected addon. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonName `ListItem.AddonName`\endlink +/// replaces `ListItem.Property(Addon.Name)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonVersion`</b>, /// \anchor ListItem_AddonVersion /// _string_, -/// Returns the version of the currently selected addon +/// @return The version of the currently selected addon. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonVersion `ListItem.AddonVersion`\endlink +/// replaces `ListItem.Property(Addon.Version)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonCreator`</b>, /// \anchor ListItem_AddonCreator /// _string_, -/// Returns the name of the author the currently selected addon +/// @return The name of the author the currently selected addon. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonCreator `ListItem.AddonCreator`\endlink +/// replaces `ListItem.Property(Addon.Creator)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonSummary`</b>, /// \anchor ListItem_AddonSummary /// _string_, -/// Returns a short description of the currently selected addon +/// @return A short description of the currently selected addon. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonSummary `ListItem.AddonSummary`\endlink +/// replaces `ListItem.Property(Addon.Summary)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonDescription`</b>, /// \anchor ListItem_AddonDescription /// _string_, -/// Returns the full description of the currently selected addon +/// @return The full description of the currently selected addon. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonDescription `ListItem.AddonDescription`\endlink +/// replaces `ListItem.Property(Addon.Description)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonDisclaimer`</b>, /// \anchor ListItem_AddonDisclaimer /// _string_, -/// Returns the disclaimer of the currently selected addon +/// @return The disclaimer of the currently selected addon. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonDisclaimer `ListItem.AddonDisclaimer`\endlink +/// replaces `ListItem.Property(Addon.Disclaimer)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonBroken`</b>, /// \anchor ListItem_AddonBroken /// _string_, -/// Returns a message when the addon is marked as broken in the repo +/// @return A message when the addon is marked as broken in the repo. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonBroken `ListItem.AddonBroken`\endlink +/// replaces `ListItem.Property(Addon.Broken)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonType`</b>, /// \anchor ListItem_AddonType /// _string_, -/// Returns the type (screensaver\, script\, skin\, etc...) of the currently selected addon +/// @return The type (screensaver\, script\, skin\, etc...) of the currently selected addon. +/// <p><hr> +/// @skinning_v17 **[Infolabel Updated]** \link ListItem_AddonType `ListItem.AddonType`\endlink +/// replaces `ListItem.Property(Addon.Type)`. +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonInstallDate`</b>, /// \anchor ListItem_AddonInstallDate /// _string_, -/// Returns the date the addon was installed +/// @return The date the addon was installed. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_AddonInstallDate `ListItem.AddonInstallDate`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonLastUpdated`</b>, /// \anchor ListItem_AddonLastUpdated /// _string_, -/// Returns the date the addon was last updated +/// @return The date the addon was last updated. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_AddonLastUpdated `ListItem.AddonLastUpdated`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.AddonLastUsed`</b>, /// \anchor ListItem_AddonLastUsed /// _string_, -/// Returns the date the addon was used last +/// @return The date the addon was used last. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_AddonLastUsed `ListItem.AddonLastUsed`\endlink +/// <p> /// } -// \table_row3{ <b>`ListItem.AddonOrigin`</b>, +/// \table_row3{ <b>`ListItem.AddonNews`</b>, +/// \anchor ListItem_AddonNews +/// _string_, +/// @return A brief changelog\, taken from the addons' `addon.xml` file. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_AddonNews `ListItem.AddonNews`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.AddonSize`</b>, +/// \anchor ListItem_AddonSize +/// _string_, +/// @return The filesize of the addon. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_AddonSize `ListItem.AddonSize`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.AddonOrigin`</b>, /// \anchor ListItem_AddonOrigin /// _string_, -/// Name of the repository the add-on originates from. +/// @return The name of the repository the add-on originates from. +/// <p> /// } /// \table_row3{ <b>`ListItem.ExpirationDate`</b>, /// \anchor ListItem_ExpirationDate /// _string_, -/// Expiration date of the selected item in a container\, empty string if not supported +/// @return The expiration date of the selected item in a container\, empty string if not supported. +/// <p> /// } /// \table_row3{ <b>`ListItem.ExpirationTime`</b>, /// \anchor ListItem_ExpirationTime /// _string_, -/// Expiration time of the selected item in a container\, empty string if not supported +/// @return The expiration time of the selected item in a container\, empty string if not supported +/// <p> /// } /// \table_row3{ <b>`ListItem.Art(type)`</b>, /// \anchor ListItem_Art_Type /// _string_, -/// Get a particular art type for an item. +/// @return A particular art type for an item. +/// @param type - the art type. It can be any value (set by scripts and scrappers). Common values: +/// - <b>clearart</b> - the clearart (if it exists) of the currently selected movie or tv show. +/// - <b>clearlogo</b> - the clearlogo (if it exists) of the currently selected movie or tv show. +/// - <b>landscape</b> - the 16:9 landscape (if it exists) of the currently selected item. +/// - <b>thumb</b> - the thumbnail of the currently selected item. +/// - <b>poster</b> - the poster of the currently selected movie or tv show. +/// - <b>banner</b> - the banner of the currently selected tv show. +/// - <b>fanart</b> - the fanart image of the currently selected item. +/// - <b>set.fanart</b> - the fanart image of the currently selected movieset. +/// - <b>tvshow.poster</b> - the tv show poster of the parent container. +/// - <b>tvshow.banner</b> - the tv show banner of the parent container. +/// - <b>tvshow.clearlogo</b> - the tv show clearlogo (if it exists) of the parent container. +/// - <b>tvshow.landscape</b> - the tv show landscape (if it exists) of the parent container. +/// - <b>tvshow.clearart</b> - the tv show clearart (if it exists) of the parent container. +/// - <b>season.poster</b> - the season poster of the currently selected season. (Only available in DialogVideoInfo.xml). +/// - <b>season.banner</b> - the season banner of the currently selected season. (Only available in DialogVideoInfo.xml). +/// - <b>season.fanart</b> - the fanart image of the currently selected season. (Only available in DialogVideoInfo.xml) +/// - <b>artist.thumb</b> - the artist thumb of an album or song item. +/// - <b>artist.fanart</b> - the artist fanart of an album or song item. +/// - <b>album.thumb</b> - the album thumb (cover) of a song item. +/// - <b>artist[n].*</b> - in case a song has multiple artists\, a digit is added to the art type for the 2nd artist onwards +/// e.g `Listitem.Art(artist1.thumb)` gives the thumb of the 2nd artist of a song. +/// - <b>albumartist[n].*</b> - n case a song has multiple album artists\, a digit is added to the art type for the 2nd artist +/// onwards e.g `Listitem.Art(artist1.thumb)` gives the thumb of the 2nd artist of a song. +/// <p> +/// @todo Find a better way of finding the art types instead of manually defining them here. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link ListItem_Art_Type `ListItem.Art(type)`\endlink add <b>artist[n].*</b> and +/// <b>albumartist[n].*</b> as possible targets for <b>type</b> +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Platform`</b>, +/// \anchor ListItem_Platform +/// _string_, +/// @return The game platform (e.g. "Atari 2600") (RETROPLAYER). +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Platform `ListItem.Platform`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Genres`</b>, +/// \anchor ListItem_Genres +/// _string_, +/// @return The game genres (e.g. "["Action"\,"Strategy"]") (RETROPLAYER). +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Genres `ListItem.Genres`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Publisher`</b>, +/// \anchor ListItem_Publisher +/// _string_, +/// @return The game publisher (e.g. "Nintendo") (RETROPLAYER). +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Publisher `ListItem.Publisher`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Developer`</b>, +/// \anchor ListItem_Developer +/// _string_, +/// @return The game developer (e.g. "Square") (RETROPLAYER). +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Developer `ListItem.Developer`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Overview`</b>, +/// \anchor ListItem_Overview +/// _string_, +/// @return The game overview/summary (RETROPLAYER). +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Overview `ListItem.Overview`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.GameClient`</b>, +/// \anchor ListItem_GameClient +/// _string_, +/// @return The add-on ID of the game client (a.k.a. emulator) to use for playing the game +/// (e.g. game.libretro.fceumm) (RETROPLAYER). +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_GameClient `ListItem.GameClient`\endlink +/// <p> /// } /// \table_row3{ <b>`ListItem.Property(propname)`</b>, /// \anchor ListItem_Property_Propname /// _string_, -/// Get a property of an item. +/// @return The requested property of a ListItem. +/// @param propname - the property requested +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Composer)`</b>, +/// \anchor ListItem_Property_Role_Composer +/// _string_, +/// @return The name of the person who composed the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Composer `ListItem.Property(Role.Composer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Conductor)`</b>, +/// \anchor ListItem_Property_Role_Conductor +/// _string_, +/// @return The name of the person who conducted the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Conductor `ListItem.Property(Role.Conductor)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Orchestra)`</b>, +/// \anchor ListItem_Property_Role_Orchestra +/// _string_, +/// @return The name of the orchestra performing the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Orchestra `ListItem.Property(Role.Orchestra)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Lyricist)`</b>, +/// \anchor ListItem_Property_Role_Lyricist +/// _string_, +/// @return The name of the person who wrote the lyrics of the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Lyricist `ListItem.Property(Role.Lyricist)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Remixer)`</b>, +/// \anchor ListItem_Property_Role_Remixer +/// _string_, +/// @return The name of the person who remixed the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Remixer `ListItem.Property(Role.Remixer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Arranger)`</b>, +/// \anchor ListItem_Property_Role_Arranger +/// _string_, +/// @return The name of the person who arranged the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Arranger `ListItem.Property(Role.Arranger)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Engineer)`</b>, +/// \anchor ListItem_Property_Role_Engineer +/// _string_, +/// @return The name of the person who was the engineer of the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Engineer `ListItem.Property(Role.Engineer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Producer)`</b>, +/// \anchor ListItem_Property_Role_Producer +/// _string_, +/// @return The name of the person who produced the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_Producer `ListItem.Property(Role.Producer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.DJMixer)`</b>, +/// \anchor ListItem_Property_Role_DJMixer +/// _string_, +/// @return The name of the dj who remixed the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_DJMixer `ListItem.Property(Role.DJMixer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Role.Mixer)`</b>, +/// \anchor ListItem_Property_Role_Mixer +/// _string_, +/// @return The name of the person who mixed the selected song. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link ListItem_Property_Role_DJMixer `ListItem.Property(Role.DJMixer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Game.VideoFilter)`</b>, +/// \anchor ListItem_Property_Game_VideoFilter +/// _string_, +/// @return The video filter of the list item representing a +/// gamewindow control (RETROPLAYER). +/// See \link RetroPlayer_VideoFilter RetroPlayer.VideoFilter \endlink +/// for the possible values. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Property_Game_VideoFilter `ListItem.Property(Game.VideoFilter)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Game.StretchMode)`</b>, +/// \anchor ListItem_Property_Game_StretchMode +/// _string_, +/// @return The stretch mode of the list item representing a +/// gamewindow control (RETROPLAYER). +/// See \link RetroPlayer_StretchMode RetroPlayer.StretchMode \endlink +/// for the possible values. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Property_Game_StretchMode `ListItem.Property(Game.StretchMode)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`ListItem.Property(Game.VideoRotation)`</b>, +/// \anchor ListItem_Property_Game_VideoRotation +/// _integer_, +/// @return The video rotation of the list item representing a +/// gamewindow control (RETROPLAYER). +/// See \link RetroPlayer_VideoRotation RetroPlayer.VideoRotation \endlink +/// for the possible values. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link ListItem_Property_Game_VideoRotation `ListItem.Property(Game.VideoRotation)`\endlink +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap listitem_labels[]= {{ "thumb", LISTITEM_THUMB }, { "icon", LISTITEM_ICON }, { "actualicon", LISTITEM_ACTUAL_ICON }, @@ -3936,6 +5752,7 @@ const infomap listitem_labels[]= {{ "thumb", LISTITEM_THUMB }, { "nextendtime", LISTITEM_NEXT_ENDTIME }, { "nextstartdate", LISTITEM_NEXT_STARTDATE }, { "nextenddate", LISTITEM_NEXT_ENDDATE }, + { "nextduration", LISTITEM_NEXT_DURATION }, { "channelname", LISTITEM_CHANNEL_NAME }, { "channelnumberlabel", LISTITEM_CHANNEL_NUMBER }, { "channelgroup", LISTITEM_CHANNEL_GROUP }, @@ -3981,275 +5798,389 @@ const infomap listitem_labels[]= {{ "thumb", LISTITEM_THUMB }, { "property", LISTITEM_PROPERTY }, }; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Visualisation Visualisation -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Visualisation Visualisation /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Visualisation.Enabled`</b>, /// \anchor Visualisation_Enabled /// _boolean_, -/// Returns true if any visualisation has been set in settings (so not None). +/// @return **True** if any visualisation has been set in settings (so not None). +/// <p> /// } /// \table_row3{ <b>`Visualisation.HasPresets`</b>, /// \anchor Visualisation_HasPresets /// _boolean_, -/// Returns true if the visualisation has built in presets. +/// @return **True** if the visualisation has built in presets. +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \link Visualisation_HasPresets `Visualisation.HasPresets`\endlink +/// <p> /// } /// \table_row3{ <b>`Visualisation.Locked`</b>, /// \anchor Visualisation_Locked /// _boolean_, -/// Returns true if the current visualisation preset is locked (eg in Milkdrop.) +/// @return **True** if the current visualisation preset is locked (e.g. in Milkdrop). +/// <p> /// } /// \table_row3{ <b>`Visualisation.Preset`</b>, /// \anchor Visualisation_Preset /// _string_, -/// Returns the current preset of the visualisation. +/// @return The current preset of the visualisation. +/// <p> /// } /// \table_row3{ <b>`Visualisation.Name`</b>, /// \anchor Visualisation_Name /// _string_, -/// Returns the name of the visualisation. +/// @return the name of the visualisation. +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap visualisation[] = {{ "locked", VISUALISATION_LOCKED }, { "preset", VISUALISATION_PRESET }, { "haspresets", VISUALISATION_HAS_PRESETS }, { "name", VISUALISATION_NAME }, { "enabled", VISUALISATION_ENABLED }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Fanart Fanart -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Fanart Fanart /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Fanart.Color1`</b>, /// \anchor Fanart_Color1 /// _string_, -/// Returns the first of three colors included in the currently selected -/// Fanart theme for the parent TV Show. Colors are arranged Lightest to -/// Darkest. +/// @return The first of three colors included in the currently selected +/// Fanart theme for the parent TV Show. +/// @note Colors are arranged Lightest to Darkest. +/// <p> /// } /// \table_row3{ <b>`Fanart.Color2`</b>, /// \anchor Fanart_Color2 /// _string_, -/// Returns the second of three colors included in the currently selected -/// Fanart theme for the parent TV Show. Colors are arranged Lightest to -/// Darkest. +/// @return The second of three colors included in the currently selected +/// Fanart theme for the parent TV Show. +/// @note Colors are arranged Lightest to Darkest. +/// <p> /// } /// \table_row3{ <b>`Fanart.Color3`</b>, /// \anchor Fanart_Color3 /// _string_, -/// Returns the third of three colors included in the currently selected -/// Fanart theme for the parent TV Show. Colors are arranged Lightest to -/// Darkest. +/// @return The third of three colors included in the currently selected +/// Fanart theme for the parent TV Show. +/// @note Colors are arranged Lightest to Darkest. +/// <p> /// } /// \table_row3{ <b>`Fanart.Image`</b>, /// \anchor Fanart_Image /// _string_, -/// Returns the fanart image\, if any +/// @return The fanart image\, if any +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap fanart_labels[] = {{ "color1", FANART_COLOR1 }, { "color2", FANART_COLOR2 }, { "color3", FANART_COLOR3 }, { "image", FANART_IMAGE }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Skin Skin -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Skin Skin /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Skin.CurrentTheme`</b>, /// \anchor Skin_CurrentTheme /// _string_, -/// Returns the current selected skin theme. +/// @return The current selected skin theme. +/// <p> /// } /// \table_row3{ <b>`Skin.CurrentColourTheme`</b>, /// \anchor Skin_CurrentColourTheme /// _string_, -/// Returns the current selected colour theme of the skin. +/// @return the current selected colour theme of the skin. +/// <p> /// } /// \table_row3{ <b>`Skin.AspectRatio`</b>, /// \anchor Skin_AspectRatio /// _string_, -/// Returns the closest aspect ratio match using the resolution info from the skin's addon.xml file. +/// @return The closest aspect ratio match using the resolution info from the skin's `addon.xml` file. +/// <p> /// } /// \table_row3{ <b>`Skin.Font`</b>, /// \anchor Skin_Font /// _string_, -/// Returns the current fontset from Font.xml. +/// @return the current fontset from `Font.xml`. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link Skin_Font `Skin.Font`\endlink +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap skin_labels[] = {{ "currenttheme", SKIN_THEME }, { "currentcolourtheme",SKIN_COLOUR_THEME }, { "aspectratio", SKIN_ASPECT_RATIO}, { "font", SKIN_FONT}}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Window Window -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Window Window /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Window.IsMedia`</b>, /// \anchor Window_IsMedia /// _boolean_, -/// Returns true if this window is a media window (programs\, music\, video\, +/// @return **True** if this window is a media window (programs\, music\, video\, /// scripts\, pictures) +/// <p> /// } /// \table_row3{ <b>`Window.Is(window)`</b>, /// \anchor Window_Is /// _boolean_, -/// Returns true if the window with the given name is the window which is currently rendered. -/// Useful in xml files that are shared between multiple windows or dialogs. +/// @return **True** if the window with the given name is the window which is currently rendered. +/// @param window - the name of the window +/// @note Useful in xml files that are shared between multiple windows or dialogs. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \ref Window_Is "Window.Is(window)" +/// <p> /// } /// \table_row3{ <b>`Window.IsActive(window)`</b>, /// \anchor Window_IsActive /// _boolean_, -/// Returns true if the window with id or title _window_ is active -/// (excludes fade out time on dialogs) +/// @return **True** if the window with id or title _window_ is active +/// @param window - the id or name of the window +/// @note Excludes fade out time on dialogs +/// <p> /// } /// \table_row3{ <b>`Window.IsVisible(window)`</b>, /// \anchor Window_IsVisible /// _boolean_, -/// Returns true if the window is visible (includes fade out time on dialogs) +/// @return **True** if the window is visible +/// @note Includes fade out time on dialogs +/// <p> /// } /// \table_row3{ <b>`Window.IsTopmost(window)`</b>, /// \anchor Window_IsTopmost /// _boolean_, -/// Returns true if the window with id or title _window_ is on top of the -/// window stack (excludes fade out time on dialogs) -/// @deprecated use `Window.IsDialogTopmost(dialog)` instead \par +/// @return **True** if the window with id or title _window_ is on top of the +/// window stack. +/// @param window - the id or name of the window +/// @note Excludes fade out time on dialogs +/// @deprecated use \ref Window_IsDialogTopmost "Window.IsDialogTopmost(dialog)" instead +/// <p> /// } /// \table_row3{ <b>`Window.IsDialogTopmost(dialog)`</b>, /// \anchor Window_IsDialogTopmost /// _boolean_, -/// Returns true if the dialog with id or title _dialog_ is on top of the -/// dialog stack (excludes fade out time on dialogs) +/// @return **True** if the dialog with id or title _dialog_ is on top of the +/// dialog stack. +/// @param window - the id or name of the window +/// @note Excludes fade out time on dialogs +/// <p> /// } /// \table_row3{ <b>`Window.IsModalDialogTopmost(dialog)`</b>, /// \anchor Window_IsModalDialogTopmost /// _boolean_, -/// Returns true if the dialog with id or title _dialog_ is on top of the -/// modal dialog stack (excludes fade out time on dialogs) +/// @return **True** if the dialog with id or title _dialog_ is on top of the +/// modal dialog stack +/// @note Excludes fade out time on dialogs +/// <p> /// } /// \table_row3{ <b>`Window.Previous(window)`</b>, /// \anchor Window_Previous /// _boolean_, -/// Returns true if the window with id or title _window_ is being moved from. -/// Only valid while windows are changing. +/// @return **True** if the window with id or title _window_ is being moved from. +/// @param window - the window id or title +/// @note Only valid while windows are changing. +/// <p> /// } /// \table_row3{ <b>`Window.Next(window)`</b>, /// \anchor Window_Next /// _boolean_, -/// Returns true if the window with id or title _window_ is being moved to. -/// Only valid while windows are changing. +/// @return **True** if the window with id or title _window_ is being moved to. +/// @param window - the window id or title +/// @note Only valid while windows are changing. +/// <p> +/// } +/// \table_row3{ <b>`Window.Property(Addon.ID)`</b>, +/// \anchor Window_Property_AddonId +/// _string_, +/// @return The id of the selected addon\, in `DialogAddonSettings.xml`. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link Window_Property_AddonId `Window.Property(Addon.ID)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Window([window]).Property(key)`</b>, +/// \anchor Window_Window_Property_key +/// _string_, +/// @return A window property. +/// @param window - [opt] window id or name. +/// @param key - any value. +/// <p> +/// } +/// \table_row3{ <b>`Window(AddonBrowser).Property(Updated)`</b>, +/// \anchor Window_Addonbrowser_Property_Updated +/// _string_, +/// @return The date and time the addon repo was last checked for updates. +/// @todo move to a future window document. +/// <p><hr> +/// @skinning_v15 **[New Infolabel]** \link Window_Addonbrowser_Property_Updated `Window(AddonBrowser).Property(Updated)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Window(Weather).Property(property)`</b>, +/// \anchor Window_Weather_Property +/// _string_, +/// @return The property for the weather window. +/// @param property - The requested property. The following are available: +/// - Current.ConditionIcon +/// - Day[0-6].OutlookIcon +/// - Current.FanartCode +/// - Day[0-6].FanartCode +/// - WeatherProviderLogo +/// - Daily.%i.OutlookIcon +/// - 36Hour.%i.OutlookIcon +/// - Weekend.%i.OutlookIcon +/// - Hourly.%i.OutlookIcon +/// @todo move to a future window document. +/// <p><hr> +/// @skinning_v16 **[Updated infolabel]** \link Window_Weather_Property `Window(Weather).Property(property)`\endlink +/// For skins that support extended weather info\, the following infolabels have been changed: +/// - Daily.%i.OutlookIcon +/// - 36Hour.%i.OutlookIcon +/// - Weekend.%i.OutlookIcon +/// - Hourly.%i.OutlookIcon +/// +/// previously the openweathermap addon would provide the full\, hardcoded path to the icon +/// ie. `resource://resource.images.weathericons.default/28.png` +/// to make it easier for skins to work with custom icon sets\, it now will return the filename only +/// i.e. 28.png +/// @skinning_v13 **[Infolabel Updated]** \link Window_Weather_Property `Window(Weather).Property(property)`\endlink +/// added `WeatherProviderLogo` propertu - weather provider logo (for weather addons that support it). +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap window_bools[] = {{ "ismedia", WINDOW_IS_MEDIA }, { "is", WINDOW_IS }, { "isactive", WINDOW_IS_ACTIVE }, { "isvisible", WINDOW_IS_VISIBLE }, - { "istopmost", WINDOW_IS_DIALOG_TOPMOST }, // deprecated, remove in v19 + { "istopmost", WINDOW_IS_DIALOG_TOPMOST }, //! @deprecated, remove in v19 { "isdialogtopmost", WINDOW_IS_DIALOG_TOPMOST }, { "ismodaldialogtopmost", WINDOW_IS_MODAL_DIALOG_TOPMOST }, { "previous", WINDOW_PREVIOUS }, { "next", WINDOW_NEXT }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Control Control -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Control Control /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Control.HasFocus(id)`</b>, /// \anchor Control_HasFocus /// _boolean_, -/// Returns true if the currently focused control has id "id". +/// @return **True** if the currently focused control has id "id". +/// @param id - The id of the control +/// <p> /// } /// \table_row3{ <b>`Control.IsVisible(id)`</b>, /// \anchor Control_IsVisible /// _boolean_, -/// Returns true if the control with id "id" is visible. +/// @return **True** if the control with id "id" is visible. +/// @param id - The id of the control +/// <p> /// } /// \table_row3{ <b>`Control.IsEnabled(id)`</b>, /// \anchor Control_IsEnabled /// _boolean_, -/// Returns true if the control with id "id" is enabled. +/// @return **True** if the control with id "id" is enabled. +/// @param id - The id of the control +/// <p> /// } /// \table_row3{ <b>`Control.GetLabel(id)[.index()]`</b>, /// \anchor Control_GetLabel /// _string_, -/// Returns the label value or texture name of the control with the given id. -/// Optionally you can specify index(1) to retrieve label2 from an Edit +/// @return The label value or texture name of the control with the given id. +/// @param id - The id of the control +/// @param index - [opt] Optionally you can specify index(1) to retrieve label2 from an Edit /// control. +/// <p><hr> +/// @skinning_v15 **[Infolabel Updated]** \link Control_GetLabel `Control.GetLabel(id)`\endlink +/// added index parameter - allows skinner to retrieve label2 of a control. Only edit controls are supported. +/// ** Example** : `Control.GetLabel(999).index(1)` where: +/// - index(0) = label +/// - index(1) = label2 +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap control_labels[] = {{ "hasfocus", CONTROL_HAS_FOCUS }, { "isvisible", CONTROL_IS_VISIBLE }, { "isenabled", CONTROL_IS_ENABLED }, { "getlabel", CONTROL_GET_LABEL }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Playlist Playlist -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Playlist Playlist /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Playlist.Length(media)`</b>, /// \anchor Playlist_Length /// _integer_, -/// Total size of the current playlist. optional parameter media is either +/// @return The total size of the current playlist. +/// @param media - [opt] mediatype with is either /// video or music. +/// <p> /// } /// \table_row3{ <b>`Playlist.Position(media)`</b>, /// \anchor Playlist_Position /// _integer_, -/// Position of the current item in the current playlist. optional parameter -/// media is either video or music. +/// @return The position of the current item in the current playlist. +/// @param media - [opt] mediatype with is either +/// video or music. +/// <p> /// } /// \table_row3{ <b>`Playlist.Random`</b>, /// \anchor Playlist_Random /// _integer_, -/// Returns string ID's 590 (Randomize Play Enabled) or 591 (Disabled) +/// @return String ID for the random mode: +/// - **16041** (On) +/// - **591** (Off) +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link Playlist_Random `Playlist.Random`\endlink will +/// now return **On/Off** +/// <p> /// } /// \table_row3{ <b>`Playlist.Repeat`</b>, /// \anchor Playlist_Repeat /// _integer_, -/// Returns string ID's 592 (Repeat One)\, 593 (Repeat All)\, or 594 (Repeat Off) +/// @return The String Id for the repeat mode. It can be one of the following +/// values: +/// - **592** (Repeat One) +/// - **593** (Repeat All) +/// - **594** (Repeat Off) +/// <p> /// } /// \table_row3{ <b>`Playlist.IsRandom`</b>, /// \anchor Playlist_IsRandom /// _boolean_, -/// Returns true if the player is in random mode. +/// @return **True** if the player is in random mode. +/// <p> /// } /// \table_row3{ <b>`Playlist.IsRepeat`</b>, /// \anchor Playlist_IsRepeat /// _boolean_, -/// Returns true if the player is in repeat all mode. +/// @return **True** if the player is in repeat all mode. +/// <p> /// } /// \table_row3{ <b>`Playlist.IsRepeatOne`</b>, /// \anchor Playlist_IsRepeatOne /// _boolean_, -/// Returns true if the player is in repeat one mode. +/// @return **True** if the player is in repeat one mode. +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap playlist[] = {{ "length", PLAYLIST_LENGTH }, { "position", PLAYLIST_POSITION }, { "random", PLAYLIST_RANDOM }, @@ -4258,395 +6189,542 @@ const infomap playlist[] = {{ "length", PLAYLIST_LENGTH }, { "isrepeat", PLAYLIST_ISREPEAT }, { "isrepeatone", PLAYLIST_ISREPEATONE }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_Pvr Pvr -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Pvr Pvr /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`PVR.IsRecording`</b>, /// \anchor PVR_IsRecording /// _boolean_, -/// Returns true when the system is recording a tv or radio programme. +/// @return **True** when the system is recording a tv or radio programme. +/// <p> /// } /// \table_row3{ <b>`PVR.HasTimer`</b>, /// \anchor PVR_HasTimer /// _boolean_, -/// Returns true when a recording timer is active. +/// @return **True** when a recording timer is active. +/// <p> /// } /// \table_row3{ <b>`PVR.HasTVChannels`</b>, /// \anchor PVR_HasTVChannels /// _boolean_, -/// Returns true if there are TV channels available +/// @return **True** if there are TV channels available. +/// <p> /// } /// \table_row3{ <b>`PVR.HasRadioChannels`</b>, /// \anchor PVR_HasRadioChannels /// _boolean_, -/// Returns true if there are radio channels available +/// @return **True** if there are radio channels available. +/// <p> /// } /// \table_row3{ <b>`PVR.HasNonRecordingTimer`</b>, /// \anchor PVR_HasNonRecordingTimer /// _boolean_, -/// Returns true if there are timers present who currently not do recording +/// @return **True** if there are timers present who currently not do recording. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendName`</b>, /// \anchor PVR_BackendName /// _string_, -/// Name of the backend being used +/// @return The name of the backend being used. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendVersion`</b>, /// \anchor PVR_BackendVersion /// _string_, -/// Version of the backend that's being used +/// @return The version of the backend that's being used. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendHost`</b>, /// \anchor PVR_BackendHost /// _string_, -/// Backend hostname +/// @return The backend hostname. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendDiskSpace`</b>, /// \anchor PVR_BackendDiskSpace /// _string_, -/// Available diskspace on the backend as string with size +/// @return The available diskspace on the backend as string with size. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendDiskSpaceProgr`</b>, /// \anchor PVR_BackendDiskSpaceProgr /// _integer_, -/// Available diskspace on the backend as percent value +/// @return The available diskspace on the backend as percent value. +/// <p><hr> +/// @skinning_v14 **[New Infolabel]** \link PVR_BackendDiskSpaceProgr `PVR.BackendDiskSpaceProgr`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.BackendChannels`</b>, /// \anchor PVR_BackendChannels /// _string (integer)_, -/// Number of available channels the backend provides +/// @return The number of available channels the backend provides. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendTimers`</b>, /// \anchor PVR_BackendTimers /// _string (integer)_, -/// Number of timers set for the backend +/// @return The number of timers set for the backend. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendRecordings`</b>, /// \anchor PVR_BackendRecordings /// _string (integer)_, -/// Number of recording available on the backend +/// @return The number of recordings available on the backend. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendDeletedRecordings`</b>, /// \anchor PVR_BackendDeletedRecordings /// _string (integer)_, -/// Number of deleted recording present on the backend +/// @return The number of deleted recordings present on the backend. +/// <p> /// } /// \table_row3{ <b>`PVR.BackendNumber`</b>, /// \anchor PVR_BackendNumber /// _string_, -/// Backend number +/// @return The backend number. +/// <p> /// } /// \table_row3{ <b>`PVR.TotalDiscSpace`</b>, /// \anchor PVR_TotalDiscSpace /// _string_, -/// Total diskspace available for recordings +/// @return The total diskspace available for recordings. +/// <p> /// } /// \table_row3{ <b>`PVR.NextTimer`</b>, /// \anchor PVR_NextTimer /// _boolean_, -/// Next timer date +/// @return The next timer date. +/// <p> /// } /// \table_row3{ <b>`PVR.IsPlayingTV`</b>, /// \anchor PVR_IsPlayingTV /// _boolean_, -/// Returns true when live tv is being watched. +/// @return **True** when live tv is being watched. +/// <p> /// } /// \table_row3{ <b>`PVR.IsPlayingRadio`</b>, /// \anchor PVR_IsPlayingRadio /// _boolean_, -/// Returns true when live radio is being listened to. +/// @return **True** when live radio is being listened to. +/// <p> /// } /// \table_row3{ <b>`PVR.IsPlayingRecording`</b>, /// \anchor PVR_IsPlayingRecording /// _boolean_, -/// Returns true when a recording is being watched. +/// @return **True** when a recording is being watched. +/// <p> /// } /// \table_row3{ <b>`PVR.IsPlayingEpgTag`</b>, /// \anchor PVR_IsPlayingEpgTag /// _boolean_, -/// Returns true when an epg tag is being watched. +/// @return **True** when an epg tag is being watched. +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventProgress`</b>, /// \anchor PVR_EpgEventProgress /// _integer_, -/// Returns the percentage complete of the currently playing epg event +/// @return The percentage complete of the currently playing epg event. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link PVR_EpgEventProgress `PVR.EpgEventProgress`\endlink replaces +/// the old `PVR.Progress` infolabel. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamClient`</b>, /// \anchor PVR_ActStreamClient /// _string_, -/// Stream client name +/// @return The stream client name. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamDevice`</b>, /// \anchor PVR_ActStreamDevice /// _string_, -/// Stream device name +/// @return The stream device name. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamStatus`</b>, /// \anchor PVR_ActStreamStatus /// _string_, -/// Status of the stream +/// @return The status of the stream. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamSignal`</b>, /// \anchor PVR_ActStreamSignal /// _string_, -/// Signal quality of the stream +/// @return The signal quality of the stream. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamSnr`</b>, /// \anchor PVR_ActStreamSnr /// _string_, -/// Signal to noise ratio of the stream +/// @return The signal to noise ratio of the stream. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamBer`</b>, /// \anchor PVR_ActStreamBer /// _string_, -/// Bit error rate of the stream +/// @return The bit error rate of the stream. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamUnc`</b>, /// \anchor PVR_ActStreamUnc /// _string_, -/// UNC value of the stream +/// @return The UNC value of the stream. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamProgrSignal`</b>, /// \anchor PVR_ActStreamProgrSignal /// _integer_, -/// Signal quality of the programme +/// @return The signal quality of the programme. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamProgrSnr`</b>, /// \anchor PVR_ActStreamProgrSnr /// _integer_, -/// Signal to noise ratio of the programme +/// @return The signal to noise ratio of the programme. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamIsEncrypted`</b>, /// \anchor PVR_ActStreamIsEncrypted /// _boolean_, -/// Returns true when channel is encrypted on source +/// @return **True** when channel is encrypted on source. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamEncryptionName`</b>, /// \anchor PVR_ActStreamEncryptionName /// _string_, -/// Encryption used on the stream +/// @return The encryption used on the stream. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamServiceName`</b>, /// \anchor PVR_ActStreamServiceName /// _string_, -/// Returns the service name of played channel if available +/// @return The service name of played channel if available. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamMux`</b>, /// \anchor PVR_ActStreamMux /// _string_, -/// Returns the multiplex type of played channel if available +/// @return The multiplex type of played channel if available. +/// <p> /// } /// \table_row3{ <b>`PVR.ActStreamProviderName`</b>, /// \anchor PVR_ActStreamProviderName /// _string_, -/// Returns the provider name of the played channel if available +/// @return The provider name of the played channel if available. +/// <p> /// } /// \table_row3{ <b>`PVR.IsTimeShift`</b>, /// \anchor PVR_IsTimeShift /// _boolean_, -/// Returns true when for channel is timeshift available +/// @return **True** when for channel is timeshift available. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftProgress`</b>, /// \anchor PVR_TimeShiftProgress /// _integer_, -/// Returns the position of currently timeshifted title on TV as integer +/// @return The position of currently timeshifted title on TV as integer. +/// <p> /// } /// \table_row3{ <b>`PVR.NowRecordingTitle`</b>, /// \anchor PVR_NowRecordingTitle /// _string_, -/// Title of the programme being recorded +/// @return The title of the programme being recorded. +/// <p> /// } /// \table_row3{ <b>`PVR.NowRecordingDateTime`</b>, /// \anchor PVR_NowRecordingDateTime /// _Date/Time string_, -/// Start date and time of the current recording +/// @return The start date and time of the current recording. +/// <p> /// } /// \table_row3{ <b>`PVR.NowRecordingChannel`</b>, /// \anchor PVR_NowRecordingChannel /// _string_, -/// Channel name of the current recording +/// @return The channel name of the current recording. +/// <p> /// } /// \table_row3{ <b>`PVR.NowRecordingChannelIcon`</b>, /// \anchor PVR_NowRecordingChannelIcon /// _string_, -/// Icon of the current recording channel +/// @return The icon of the current recording channel. +/// <p> /// } /// \table_row3{ <b>`PVR.NextRecordingTitle`</b>, /// \anchor PVR_NextRecordingTitle /// _string_, -/// Title of the next programme that will be recorded +/// @return The title of the next programme that will be recorded. +/// <p> /// } /// \table_row3{ <b>`PVR.NextRecordingDateTime`</b>, /// \anchor PVR_NextRecordingDateTime /// _Date/Time string_, -/// Start date and time of the next recording +/// @return The start date and time of the next recording. +/// <p> /// } /// \table_row3{ <b>`PVR.NextRecordingChannel`</b>, /// \anchor PVR_NextRecordingChannel /// _string_, -/// Channel name of the next recording +/// @return The channel name of the next recording. +/// <p> /// } /// \table_row3{ <b>`PVR.NextRecordingChannelIcon`</b>, /// \anchor PVR_NextRecordingChannelIcon /// _string_, -/// Icon of the next recording channel +/// @return The icon of the next recording channel. +/// <p> /// } /// \table_row3{ <b>`PVR.TVNowRecordingTitle`</b>, /// \anchor PVR_TVNowRecordingTitle /// _string_, -/// Title of the tv programme being recorded +/// @return The title of the tv programme being recorded. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_TVNowRecordingTitle `PVR.TVNowRecordingTitle`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TVNowRecordingDateTime`</b>, /// \anchor PVR_TVNowRecordingDateTime /// _Date/Time string_, -/// Start date and time of the current tv recording +/// @return The start date and time of the current tv recording. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_TVNowRecordingDateTime `PVR.TVNowRecordingDateTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TVNowRecordingChannel`</b>, /// \anchor PVR_TVNowRecordingChannel /// _string_, -/// Channel name of the current tv recording +/// @return The channel name of the current tv recording. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_TVNowRecordingChannel `PVR.TVNowRecordingChannel`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TVNowRecordingChannelIcon`</b>, /// \anchor PVR_TVNowRecordingChannelIcon /// _string_, -/// Icon of the current recording TV channel +/// @return The icon of the current recording TV channel. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_TVNowRecordingChannelIcon `PVR.TVNowRecordingChannelIcon`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TVNextRecordingTitle`</b>, /// \anchor PVR_TVNextRecordingTitle /// _string_, -/// Title of the next tv programme that will be recorded +/// @return The title of the next tv programme that will be recorded. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_TVNextRecordingTitle `PVR.TVNextRecordingTitle`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TVNextRecordingDateTime`</b>, /// \anchor PVR_TVNextRecordingDateTime /// _Date/Time string_, -/// Start date and time of the next tv recording +/// @return The start date and time of the next tv recording. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_TVNextRecordingDateTime `PVR.TVNextRecordingDateTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TVNextRecordingChannel`</b>, /// \anchor PVR_TVNextRecordingChannel /// _string_, -/// Channel name of the next tv recording +/// @return The channel name of the next tv recording. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_TVNextRecordingChannel `PVR.TVNextRecordingChannel`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TVNextRecordingChannelIcon`</b>, /// \anchor PVR_TVNextRecordingChannelIcon -/// , -/// Icon of the next recording tv channel +/// _string_, +/// @return The icon of the next recording tv channel. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_TVNextRecordingChannelIcon `PVR.TVNextRecordingChannelIcon`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.RadioNowRecordingTitle`</b>, /// \anchor PVR_RadioNowRecordingTitle /// _string_, -/// Title of the radio programme being recorded +/// @return The title of the radio programme being recorded. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_RadioNowRecordingTitle `PVR.RadioNowRecordingTitle`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.RadioNowRecordingDateTime`</b>, /// \anchor PVR_RadioNowRecordingDateTime /// _Date/Time string_, -/// Start date and time of the current radio recording +/// @return The start date and time of the current radio recording. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_RadioNowRecordingDateTime `PVR.RadioNowRecordingDateTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.RadioNowRecordingChannel`</b>, /// \anchor PVR_RadioNowRecordingChannel /// _string_, -/// Channel name of the current radio recording +/// @return The channel name of the current radio recording. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_RadioNowRecordingChannel `PVR.RadioNowRecordingChannel`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.RadioNowRecordingChannelIcon`</b>, /// \anchor PVR_RadioNowRecordingChannelIcon /// _string_, -/// Icon of the current recording radio channel +/// @return The icon of the current recording radio channel. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_RadioNowRecordingChannelIcon `PVR.RadioNowRecordingChannelIcon`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.RadioNextRecordingTitle`</b>, /// \anchor PVR_RadioNextRecordingTitle /// _string_, -/// Title of the next radio programme that will be recorded +/// @return The title of the next radio programme that will be recorded. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_RadioNextRecordingTitle `PVR.RadioNextRecordingTitle`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.RadioNextRecordingDateTime`</b>, /// \anchor PVR_RadioNextRecordingDateTime /// _Date/Time string_, -/// Start date and time of the next radio recording +/// @return The start date and time of the next radio recording. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_RadioNextRecordingDateTime `PVR.RadioNextRecordingDateTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.RadioNextRecordingChannel`</b>, /// \anchor PVR_RadioNextRecordingChannel /// _string_, -/// Channel name of the next radio recording +/// @return The channel name of the next radio recording. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_RadioNextRecordingChannel `PVR.RadioNextRecordingChannel`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.RadioNextRecordingChannelIcon`</b>, /// \anchor PVR_RadioNextRecordingChannelIcon /// _string_, -/// Icon of the next recording radio channel +/// @return The icon of the next recording radio channel. +/// <p><hr> +/// @skinning_v17 **[New Infolabel]** \link PVR_RadioNextRecordingChannelIcon `PVR.RadioNextRecordingChannelIcon`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.IsRecordingTV`</b>, /// \anchor PVR_IsRecordingTV /// _boolean_, -/// Returns true when the system is recording a tv programme. +/// @return **True** when the system is recording a tv programme. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link PVR_IsRecordingTV `PVR.IsRecordingTV`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.HasTVTimer`</b>, /// \anchor PVR_HasTVTimer /// _boolean_, -/// Returns true if at least one tv timer is active. +/// @return **True** if at least one tv timer is active. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link PVR_HasTVTimer `PVR.HasTVTimer`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.HasNonRecordingTVTimer`</b>, /// \anchor PVR_HasNonRecordingTVTimer /// _boolean_, -/// Returns true if there are tv timers present who currently not do recording +/// @return **True** if there are tv timers present who currently not do recording. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link PVR_HasNonRecordingTVTimer `PVR.HasNonRecordingTVTimer`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.IsRecordingRadio`</b>, /// \anchor PVR_IsRecordingRadio /// _boolean_, -/// Returns true when the system is recording a radio programme. +/// @return **True** when the system is recording a radio programme. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link PVR_IsRecordingRadio `PVR.IsRecordingRadio`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.HasRadioTimer`</b>, /// \anchor PVR_HasRadioTimer /// _boolean_, -/// Returns true if at least one radio timer is active. +/// @return **True** if at least one radio timer is active. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link PVR_HasRadioTimer `PVR.HasRadioTimer`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.HasNonRecordingRadioTimer`</b>, /// \anchor PVR_HasNonRecordingRadioTimer /// _boolean_, -/// Returns true if there are radio timers present who currently not do recording +/// @return **True** if there are radio timers present who currently not do recording. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link PVR_HasNonRecordingRadioTimer `PVR.HasRadioTimer`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.ChannelNumberInput`</b>, /// \anchor PVR_ChannelNumberInput /// _string_, -/// Returns the currently entered channel number while in numeric channel input mode\, an empty string otherwise +/// @return The currently entered channel number while in numeric channel input mode\, an empty string otherwise. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_ChannelNumberInput `PVR.ChannelNumberInput`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.CanRecordPlayingChannel`</b>, /// \anchor PVR_CanRecordPlayingChannel /// _boolean_, -/// Returns true if PVR is currently playing a channel and if this channel can be recorded. +/// @return **True** if PVR is currently playing a channel and if this channel can be recorded. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link PVR_CanRecordPlayingChannel `PVR.CanRecordPlayingChannel`\endlink replaces +/// the old `Player.CanRecord` infolabel. +/// <p> /// } /// \table_row3{ <b>`PVR.IsRecordingPlayingChannel`</b>, /// \anchor PVR_IsRecordingPlayingChannel /// _boolean_, -/// Returns true if PVR is currently playing a channel and if this channel is currently recorded. +/// @return **True** if PVR is currently playing a channel and if this channel is currently recorded. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link PVR_IsRecordingPlayingChannel `PVR.IsRecordingPlayingChannel`\endlink replaces +/// the old `Player.Recording` infolabel. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressPlayPos`</b>, /// \anchor PVR_TimeshiftProgressPlayPos /// _integer_, -/// Returns the percentage of the current play position within the PVR timeshift progress. +/// @return The percentage of the current play position within the PVR timeshift progress. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressPlayPos `PVR.TimeshiftProgressPlayPos`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressEpgStart`</b>, /// \anchor PVR_TimeshiftProgressEpgStart /// _integer_, -/// Returns the percentage of the start of the currently playing epg event within the PVR timeshift progress. +/// @return The percentage of the start of the currently playing epg event within the PVR timeshift progress. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressEpgStart `PVR.TimeshiftProgressEpgStart`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressEpgEnd`</b>, /// \anchor PVR_TimeshiftProgressEpgEnd /// _integer_, -/// Returns the percentage of the end of the currently playing epg event within the PVR timeshift progress. +/// @return The percentage of the end of the currently playing epg event within the PVR timeshift progress. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressEpgEnd `PVR.TimeshiftProgressEpgEnd`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressBufferStart`</b>, /// \anchor PVR_TimeshiftProgressBufferStart /// _integer_, -/// Returns the percentage of the start of the timeshift buffer within the PVR timeshift progress. +/// @return The percentage of the start of the timeshift buffer within the PVR timeshift progress. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressBufferStart `PVR.TimeshiftProgressBufferStart`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressBufferEnd`</b>, /// \anchor PVR_TimeshiftProgressBufferEnd /// _integer_, -/// Returns the percentage of the end of the timeshift buffer within the PVR timeshift progress. +/// @return The percentage of the end of the timeshift buffer within the PVR timeshift progress. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressBufferEnd `PVR.TimeshiftProgressBufferEnd`\endlink +/// <p> +/// } +/// \table_row3{ <b>`PVR.EpgEventIcon`</b>, +/// \anchor PVR_EpgEventIcon +/// _string_, +/// @return The icon of the currently playing epg event\, if any. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_EpgEventIcon `PVR_EpgEventIcon`\endlink +/// <p> /// } -/// \table_end /// -/// ----------------------------------------------------------------------------- -/// @} const infomap pvr[] = {{ "isrecording", PVR_IS_RECORDING }, { "hastimer", PVR_HAS_TIMER }, { "hastvchannels", PVR_HAS_TV_CHANNELS }, @@ -4722,204 +6800,224 @@ const infomap pvr[] = {{ "isrecording", PVR_IS_RECORDING { "timeshiftprogressepgstart", PVR_TIMESHIFT_PROGRESS_EPG_START }, { "timeshiftprogressepgend", PVR_TIMESHIFT_PROGRESS_EPG_END }, { "timeshiftprogressbufferstart", PVR_TIMESHIFT_PROGRESS_BUFFER_START }, - { "timeshiftprogressbufferend", PVR_TIMESHIFT_PROGRESS_BUFFER_END }}; + { "timeshiftprogressbufferend", PVR_TIMESHIFT_PROGRESS_BUFFER_END }, + { "epgeventicon", PVR_EPG_EVENT_ICON }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_PvrTimes PvrTimes -/// @{ -/// \table_start -/// \table_h3{ Labels, Type, Description } -/// \table_row3{ <b>`PVR.EpgEventIcon`</b>, -/// \anchor PVR_EpgEventIcon -/// _string_, -/// Returns the icon of the currently playing epg event, if any. -/// } +/// \page modules__infolabels_boolean_conditions /// \table_row3{ <b>`PVR.EpgEventDuration`</b>, /// \anchor PVR_EpgEventDuration /// _string_, -/// Returns the duration of the currently playing epg event in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The duration of the currently playing epg event in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link PVR_EpgEventDuration `PVR.EpgEventDuration`\endlink replaces +/// the old `PVR.Duration` infolabel. +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventDuration(format)`</b>, /// \anchor PVR_EpgEventDuration_format /// _string_, -/// Returns the duration of the currently playing epg event in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The duration of the currently playing EPG event in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventElapsedTime`</b>, /// \anchor PVR_EpgEventElapsedTime /// _string_, -/// Returns the time of the current position of the currently playing epg event in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return the time of the current position of the currently playing epg event in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[Infolabel Updated]** \link PVR_EpgEventElapsedTime `PVR.EpgEventElapsedTime`\endlink replaces +/// the old `PVR.Time` infolabel. +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventElapsedTime(format)`</b>, /// \anchor PVR_EpgEventElapsedTime_format /// _string_, -/// Returns the time of the current position of the currently playing epg event in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The time of the current position of the currently playing epg event in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventRemainingTime`</b>, /// \anchor PVR_EpgEventRemainingTime /// _string_, -/// Returns the remaining time for currently playing epg event in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The remaining time for currently playing epg event in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_EpgEventRemainingTime `PVR.EpgEventRemainingTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventRemainingTime(format)`</b>, /// \anchor PVR_EpgEventRemainingTime_format /// _string_, -/// Returns the remaining time for currently playing epg event in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The remaining time for currently playing epg event in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventSeekTime`</b>, /// \anchor PVR_EpgEventSeekTime /// _string_, -/// Returns the time the user is seeking within the currently playing epg event in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The time the user is seeking within the currently playing epg event in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_EpgEventSeekTime `PVR.EpgEventSeekTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventSeekTime(format)`</b>, /// \anchor PVR_EpgEventSeekTime_format /// _string_, -/// Returns the time the user is seeking within the currently playing epg event in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The time the user is seeking within the currently playing epg event in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventFinishTime`</b>, /// \anchor PVR_EpgEventFinishTime /// _string_, -/// Returns the time the currently playing epg event will end in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The time the currently playing epg event will end in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_EpgEventFinishTime `PVR.EpgEventFinishTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.EpgEventFinishTime(format)`</b>, /// \anchor PVR_EpgEventFinishTime_format /// _string_, -/// Returns the time the currently playing epg event will end in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// Returns the time the currently playing epg event will end in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftStart`</b>, /// \anchor PVR_TimeShiftStart /// _string_, -/// Returns the start time of the timeshift buffer in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The start time of the timeshift buffer in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftStart(format)`</b>, /// \anchor PVR_TimeShiftStart_format /// _string_, -/// Returns the start time of the timeshift buffer in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// Returns the start time of the timeshift buffer in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftEnd`</b>, /// \anchor PVR_TimeShiftEnd /// _string_, -/// Returns the end time of the timeshift buffer in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The end time of the timeshift buffer in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftEnd(format)`</b>, /// \anchor PVR_TimeShiftEnd_format /// _string_, -/// Returns the end time of the timeshift buffer in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The end time of the timeshift buffer in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftCur`</b>, /// \anchor PVR_TimeShiftCur /// _string_, -/// Returns the current playback time within the timeshift buffer in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The current playback time within the timeshift buffer in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftCur(format)`</b>, /// \anchor PVR_TimeShiftCur_format /// _string_, -/// Returns the current playback time within the timeshift buffer in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). When 12 hour clock is used -/// (xx) will return AM/PM. Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// Returns the current playback time within the timeshift buffer in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftOffset`</b>, /// \anchor PVR_TimeShiftOffset /// _string_, -/// Returns the delta of timeshifted time to actual time in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The delta of timeshifted time to actual time in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeShiftOffset(format)`</b>, /// \anchor PVR_TimeShiftOffset_format /// _string_, -/// Returns the delta of timeshifted time to actual time in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// Returns the delta of timeshifted time to actual time in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressDuration`</b>, /// \anchor PVR_TimeshiftProgressDuration /// _string_, -/// Returns the duration of the PVR timeshift progress in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return the duration of the PVR timeshift progress in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressDuration `PVR.TimeshiftProgressDuration`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressDuration(format)`</b>, /// \anchor PVR_TimeshiftProgressDuration_format /// _string_, -/// Returns the duration of the PVR timeshift progress in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The duration of the PVR timeshift progress in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressStartTime`</b>, /// \anchor PVR_TimeshiftProgressStartTime /// _string_, -/// Returns the start time of the PVR timeshift progress in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The start time of the PVR timeshift progress in the +/// format <b>hh:mm:ss</b>. +/// @note <b>hh:</b> will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressStartTime `PVR.TimeshiftProgressStartTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressStartTime(format)`</b>, /// \anchor PVR_TimeshiftProgressStartTime_format /// _string_, -/// Returns the start time of the PVR timeshift progress in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The start time of the PVR timeshift progress in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressEndTime`</b>, /// \anchor PVR_TimeshiftProgressEndTime /// _string_, -/// Returns the end time of the PVR timeshift progress in the -/// format hh:mm:ss. hh: will be omitted if hours value is zero. +/// @return The end time of the PVR timeshift progress in the +/// format <b>hh:mm:ss</b>. +/// @note hh: will be omitted if hours value is zero. +/// <p><hr> +/// @skinning_v18 **[New Infolabel]** \link PVR_TimeshiftProgressEndTime `PVR.TimeshiftProgressEndTime`\endlink +/// <p> /// } /// \table_row3{ <b>`PVR.TimeshiftProgressEndTime(format)`</b>, /// \anchor PVR_TimeshiftProgressEndTime_format /// _string_, -/// Returns the end time of the PVR timeshift progress in different formats: -/// Hours (hh)\, minutes (mm) or seconds (ss). -/// Also supported: (hh:mm)\, (mm:ss)\, (hh:mm:ss)\, (h:mm:ss). -/// Added with Leia: (secs)\, (mins)\, (hours) for total time values and (m). -/// Example: 3661 seconds => h=1\, hh=01\, m=1\, mm=01\, ss=01\, hours=1\, mins=61\, secs=3661 +/// @return The end time of the PVR timeshift progress in different formats. +/// @param format [opt] The format of the return time value. +/// See \ref TIME_FORMAT for the list of possible values. +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} -const infomap pvr_times[] = {{ "epgeventicon", PVR_EPG_EVENT_ICON }, - { "epgeventduration", PVR_EPG_EVENT_DURATION }, +const infomap pvr_times[] = {{ "epgeventduration", PVR_EPG_EVENT_DURATION }, { "epgeventelapsedtime", PVR_EPG_EVENT_ELAPSED_TIME }, { "epgeventremainingtime", PVR_EPG_EVENT_REMAINING_TIME }, { "epgeventfinishtime", PVR_EPG_EVENT_FINISH_TIME }, @@ -4932,105 +7030,150 @@ const infomap pvr_times[] = {{ "epgeventicon", PVR_EPG_EVENT_ICON { "timeshiftprogressstarttime", PVR_TIMESHIFT_PROGRESS_START_TIME }, { "timeshiftprogressendtime", PVR_TIMESHIFT_PROGRESS_END_TIME }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_RDS Radio RDS -/// \note Only be supported on PVR Radio where the related add-on client can -/// bring it. -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_RDS RDS +/// @note Only supported if both the PVR backend and the Kodi client support RDS. +/// /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`RDS.HasRds`</b>, /// \anchor RDS_HasRds /// _boolean_, -/// Returns true if RDS is present +/// @return **True** if RDS is present. +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \link RDS_HasRds `RDS.HasRds`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.HasRadioText`</b>, /// \anchor RDS_HasRadioText /// _boolean_, -/// Returns true if RDS contains also Radiotext +/// @return **True** if RDS contains also Radiotext. +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \link RDS_HasRadioText `RDS.HasRadioText`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.HasRadioTextPlus`</b>, /// \anchor RDS_HasRadioTextPlus /// _boolean_, -/// Returns true if RDS with Radiotext contains also the plus information +/// @return **True** if RDS with Radiotext contains also the plus information. +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \link RDS_HasRadioTextPlus `RDS.HasRadioTextPlus`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.HasHotline`</b>, /// \anchor RDS_HasHotline /// _boolean_, -/// Returns true if a hotline phone number is present\n -/// (Only be available on RadiotextPlus) +/// @return **True** if a hotline phone number is present. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \link RDS_HasHotline `RDS.HasHotline`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.HasStudio`</b>, /// \anchor RDS_HasStudio /// _boolean_, -/// Returns true if a studio name is present\n -/// (Only be available on RadiotextPlus) +/// @return **True** if a studio name is present. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Boolean Condition]** \link RDS_HasStudio `RDS.HasStudio`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.AudioLanguage`</b>, /// \anchor RDS_AudioLanguage /// _string_, -/// The from RDS reported audio language of channel +/// @return The RDS reported audio language of the channel. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_AudioLanguage `RDS.AudioLanguage`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.ChannelCountry`</b>, /// \anchor RDS_ChannelCountry /// _string_, -/// Country where the radio channel is sended +/// @return The country where the radio channel is broadcasted. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_ChannelCountry `RDS.ChannelCountry`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.GetLine(number)`</b>, /// \anchor RDS_GetLine /// _string_, -/// Returns the last sended RDS text messages on given number\, 0 is the +/// @return The last sent RDS text messages on given number. +/// @param number - given number for RDS\, 0 is the /// last and 4 rows are supported (0-3) +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_GetLine `RDS.GetLine(number)`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.Title`</b>, /// \anchor RDS_Title /// _string_, -/// Title of item; e.g. track title of an album\n -/// (Only be available on RadiotextPlus) +/// @return The title of item; e.g. track title of an album. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_Title `RDS.Title`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.Artist`</b>, /// \anchor RDS_Artist /// _string_, -/// A person or band/collective generally considered responsible for the work\n -/// (Only be available on RadiotextPlus) +/// @return A person or band/collective generally considered responsible for the work. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_Artist `RDS.Artist`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.Band`</b>, /// \anchor RDS_Band /// _string_, -/// Band/orchestra/accompaniment/musician\n -/// (Only be available on RadiotextPlus) +/// @return The band/orchestra/musician. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_Band `RDS.Band`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.Composer`</b>, /// \anchor RDS_Composer /// _string_, -/// Name of the original composer/author\n -/// (Only be available on RadiotextPlus) +/// @return The name of the original composer/author. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_Composer `RDS.Composer`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.Conductor`</b>, /// \anchor RDS_Conductor /// _string_, -/// The artist(s) who performed the work. In classical music this would be -/// the conductor\n -/// (Only be available on RadiotextPlus) +/// @return The artist(s) who performed the work. In classical music this would be +/// the conductor. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_Conductor `RDS.Conductor`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.Album`</b>, /// \anchor RDS_Album /// _string_, -/// The collection name to which this track belongs\n -/// (Only be available on RadiotextPlus) +/// @return The album of the song. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_Album `RDS.Album`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.TrackNumber`</b>, /// \anchor RDS_TrackNumber /// _string_, -/// The track number of the item on the album on which it was originally -/// released.\n -/// (Only be available on RadiotextPlus) +/// @return The track number of the item on the album on which it was originally +/// released. +/// @note Only be available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_TrackNumber `RDS.TrackNumber`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.RadioStyle`</b>, /// \anchor RDS_RadioStyle /// _string_, -/// The from radio channel used style of currently played part\, is always -/// updated on changed\, e.g "popmusic" to "news" or "weather"... +/// @return The style of current played radio channel\, it is always +/// updated once the style changes\, e.g "popmusic" to "news" or "weather"... /// | RDS | RBDS | /// |:------------------------|:------------------------| /// | none | none | @@ -5067,187 +7210,276 @@ const infomap pvr_times[] = {{ "epgeventicon", PVR_EPG_EVENT_ICON /// | alarm-alarm | alarm-alarm | /// @note "alarm-alarm" is normally not used from radio stations\, is thought /// to inform about horrible messages who are needed asap to all people. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_RadioStyle `RDS.RadioStyle`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.Comment`</b>, /// \anchor RDS_Comment /// _string_, -/// Radio station comment string if available\n -/// (Only be available on RadiotextPlus) +/// @return The radio station comment string if available. +/// @note Only available on RadiotextPlus) +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_Comment `RDS.Comment`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoNews`</b>, /// \anchor RDS_InfoNews /// _string_, -/// Message / headline (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The message / headline (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoNews `RDS.InfoNews`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoNewsLocal`</b>, /// \anchor RDS_InfoNewsLocal /// _string_, -/// Local information news sended from radio channel (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The local information news sended from radio channel (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoNewsLocal `RDS.InfoNewsLocal`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoStock`</b>, /// \anchor RDS_InfoStock /// _string_, -/// Quote information; either as one part or as several distinct parts: -/// "name 99latest value 99change 99high 99low 99volume" (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The stock information; either as one part or as several distinct parts: +/// "name 99latest value 99change 99high 99low 99volume" (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoStock `RDS.InfoStock`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoStockSize`</b>, /// \anchor RDS_InfoStockSize /// _string_, -/// Number of rows present in stock information\n -/// (Only be available on RadiotextPlus) +/// @return The number of rows present in stock information. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoStockSize `RDS.InfoStockSize`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoSport`</b>, /// \anchor RDS_InfoSport /// _string_, -/// Result of a game; either as one part or as several distinct parts: -/// "match 99result"\, e.g. "Bayern München : Borussia 995:5" (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The result of a match; either as one part or as several distinct parts: +/// "match 99result"\, e.g. "Bayern München : Borussia 995:5" (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoSport `RDS.InfoSport`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoSportSize`</b>, /// \anchor RDS_InfoSportSize /// _string_, -/// Number of rows present in sport information\n -/// (Only be available on RadiotextPlus) +/// @return The number of rows present in sport information. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoSportSize `RDS.InfoSportSize`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoLottery`</b>, /// \anchor RDS_InfoLottery /// _string_, -/// Raffle / lottery: "key word 99values" (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The raffle / lottery: "key word 99values" (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoLottery `RDS.InfoLottery`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoLotterySize`</b>, /// \anchor RDS_InfoLotterySize /// _string_, -/// Number of rows present in lottery information\n -/// (Only be available on RadiotextPlus) +/// @return The number of rows present in lottery information. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoLotterySize `RDS.InfoLotterySize`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoWeather`</b>, /// \anchor RDS_InfoWeather /// _string_, -/// Weather informations sended from radio channel (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The weather information (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoWeather `RDS.InfoWeather`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoWeatherSize`</b>, /// \anchor RDS_InfoWeatherSize /// _string_, -/// Number of rows present in weather information\n -/// (Only be available on RadiotextPlus) +/// @return The number of rows present in weather information. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoWeatherSize `RDS.InfoWeatherSize`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoCinema`</b>, /// \anchor RDS_InfoCinema /// _string_, -/// Information about movies in cinema (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The information about movies in cinema (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoCinema `RDS.InfoCinema`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoCinemaSize`</b>, /// \anchor RDS_InfoCinemaSize /// _string_, -/// Number of rows present in cinema information\n -/// (Only be available on RadiotextPlus) +/// @return The number of rows present in cinema information. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoCinemaSize `RDS.InfoCinemaSize`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoHoroscope`</b>, /// \anchor RDS_InfoHoroscope /// _string_, -/// Horoscope; either as one part or as two distinct parts: -/// "key word 99text"\, e.g. "sign of the zodiac 99blablabla" (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The horoscope; either as one part or as two distinct parts: +/// "key word 99text"\, e.g. "sign of the zodiac 99blablabla" (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoHoroscope `RDS.InfoHoroscope`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoHoroscopeSize`</b>, /// \anchor RDS_InfoHoroscopeSize /// _string_, -/// Number of rows present in horoscope information\n -/// (Only be available on RadiotextPlus) +/// @return The Number of rows present in horoscope information. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoHoroscopeSize `RDS.InfoHoroscopeSize`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoOther`</b>, /// \anchor RDS_InfoOther /// _string_, -/// Other information\, not especially specified: "key word 99info" (if available)\n -/// (Only be available on RadiotextPlus) +/// @return Other information\, not especially specified: "key word 99info" (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoOther `RDS.InfoOther`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.InfoOtherSize`</b>, /// \anchor RDS_InfoOtherSize /// _string_, -/// Number of rows present with other informations\n -/// (Only be available on RadiotextPlus) +/// @return The number of rows present with other information. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_InfoOtherSize `RDS.InfoOtherSize`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.ProgStation`</b>, /// \anchor RDS_ProgStation /// _string_, -/// Name of the radio channel -/// @note becomes also be set from epg if from RDS not available +/// @return The name of the radio channel. +/// @note becomes also set from epg if it is not available from RDS +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_ProgStation `RDS.ProgStation`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.ProgNow`</b>, /// \anchor RDS_ProgNow /// _string_, -/// Now played program name +/// @return The now playing program name. /// @note becomes also be set from epg if from RDS not available +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_ProgNow `RDS.ProgNow`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.ProgNext`</b>, /// \anchor RDS_ProgNext /// _string_, -/// Next played program name (if available) +/// @return The next played program name (if available). /// @note becomes also be set from epg if from RDS not available +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_ProgNext `RDS.ProgNext`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.ProgHost`</b>, /// \anchor RDS_ProgHost /// _string_, -/// Name of the host of the radio show +/// @return The name of the host of the radio show. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_ProgHost `RDS.ProgHost`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.ProgEditStaff`</b>, /// \anchor RDS_ProgEditStaff /// _string_, -/// Name of the editorial staff; e.g. name of editorial journalist\n -/// (Only be available on RadiotextPlus) +/// @return The name of the editorial staff; e.g. name of editorial journalist. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_ProgEditStaff `RDS.ProgEditStaff`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.ProgHomepage`</b>, /// \anchor RDS_ProgHomepage /// _string_, -/// Link to radio station homepage\n -/// (Only be available on RadiotextPlus) +/// @return The Link to radio station homepage +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_ProgHomepage `RDS.ProgHomepage`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.ProgStyle`</b>, /// \anchor RDS_ProgStyle /// _string_, -/// Human readable string about radiostyle defined from RDS or RBDS +/// @return A human readable string about radiostyle defined from RDS or RBDS. +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_ProgStyle `RDS.ProgStyle`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.PhoneHotline`</b>, /// \anchor RDS_PhoneHotline /// _string_, -/// The telephone number of the radio station's hotline\n -/// (Only be available on RadiotextPlus) +/// @return The telephone number of the radio station's hotline. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_PhoneHotline `RDS.PhoneHotline`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.PhoneStudio`</b>, /// \anchor RDS_PhoneStudio /// _string_, -/// The telephone number of the radio station's studio\n -/// (Only be available on RadiotextPlus) +/// @return The telephone number of the radio station's studio. +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_PhoneStudio `RDS.PhoneStudio`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.SmsStudio`</b>, /// \anchor RDS_SmsStudio /// _string_, -/// The sms number of the radio stations studio (to send directly a sms to -/// the studio) (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The sms number of the radio stations studio (to send directly a sms to +/// the studio) (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_SmsStudio `RDS.SmsStudio`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.EmailHotline`</b>, /// \anchor RDS_EmailHotline /// _string_, -/// The email address of the radio stations hotline (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The email address of the radio stations hotline (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_EmailHotline `RDS.EmailHotline`\endlink +/// <p> /// } /// \table_row3{ <b>`RDS.EmailStudio`</b>, /// \anchor RDS_EmailStudio /// _string_, -/// The email address of the radio stations studio (if available)\n -/// (Only be available on RadiotextPlus) +/// @return The email address of the radio station's studio (if available). +/// @note Only available on RadiotextPlus +/// <p><hr> +/// @skinning_v16 **[New Infolabel]** \link RDS_EmailStudio `RDS.EmailStudio`\endlink +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap rds[] = {{ "hasrds", RDS_HAS_RDS }, { "hasradiotext", RDS_HAS_RADIOTEXT }, { "hasradiotextplus", RDS_HAS_RADIOTEXT_PLUS }, @@ -5294,428 +7526,596 @@ const infomap rds[] = {{ "hasrds", RDS_HAS_RDS }, { "hashotline", RDS_HAS_HOTLINE_DATA }, { "hasstudio", RDS_HAS_STUDIO_DATA }}; -/// \page modules__General__List_of_gui_access -/// \section modules__General__List_of_gui_access_slideshow Slideshow -/// @{ +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_slideshow Slideshow /// \table_start /// \table_h3{ Labels, Type, Description } /// \table_row3{ <b>`Slideshow.IsActive`</b>, /// \anchor Slideshow_IsActive /// _boolean_, -/// Returns true if the picture slideshow is running +/// @return **True** if the picture slideshow is running. +/// <p> /// } /// \table_row3{ <b>`Slideshow.IsPaused`</b>, /// \anchor Slideshow_IsPaused /// _boolean_, -/// Returns true if the picture slideshow is paused +/// @return **True** if the picture slideshow is paused. +/// <p> /// } /// \table_row3{ <b>`Slideshow.IsRandom`</b>, /// \anchor Slideshow_IsRandom /// _boolean_, -/// Returns true if the picture slideshow is in random mode +/// @return **True** if the picture slideshow is in random mode. +/// <p> /// } /// \table_row3{ <b>`Slideshow.IsVideo`</b>, /// \anchor Slideshow_IsVideo /// _boolean_, -/// Returns true if the picture slideshow is playing a video +/// @return **True** if the picture slideshow is playing a video. +/// <p><hr> +/// @skinning_v13 **[New Boolean Condition]** \link Slideshow_IsVideo `Slideshow.IsVideo`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Altitude`</b>, /// \anchor Slideshow_Altitude /// _string_, -/// Shows the altitude in meters where the current picture was taken. This -/// is the value of the EXIF GPSInfo.GPSAltitude tag. +/// @return The altitude in meters where the current picture was taken. +/// @note This is the value of the EXIF GPSInfo.GPSAltitude tag. +/// <p> /// } /// \table_row3{ <b>`Slideshow.Aperture`</b>, /// \anchor Slideshow_Aperture /// _string_, -/// Shows the F-stop used to take the current picture. This is the value of -/// the EXIF FNumber tag (hex code 0x829D). +/// @return The F-stop used to take the current picture. +/// @note This is the value of the EXIF FNumber tag (hex code 0x829D). +/// <p> /// } /// \table_row3{ <b>`Slideshow.Author`</b>, /// \anchor Slideshow_Author /// _string_, -/// Shows the name of the person involved in writing about the current -/// picture. This is the value of the IPTC Writer tag (hex code 0x7A). +/// @return The name of the person involved in writing about the current +/// picture. +/// @note This is the value of the IPTC Writer tag (hex code 0x7A). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Author `Slideshow.Author`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Byline`</b>, /// \anchor Slideshow_Byline /// _string_, -/// Shows the name of the person who created the current picture. This is -/// the value of the IPTC Byline tag (hex code 0x50). +/// @return The name of the person who created the current picture. +/// @note This is the value of the IPTC Byline tag (hex code 0x50). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Byline `Slideshow.Byline`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.BylineTitle`</b>, /// \anchor Slideshow_BylineTitle /// _string_, -/// Shows the title of the person who created the current picture. This is -/// the value of the IPTC BylineTitle tag (hex code 0x55). +/// @return The title of the person who created the current picture. +/// @note This is the value of the IPTC BylineTitle tag (hex code 0x55). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_BylineTitle `Slideshow.BylineTitle`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.CameraMake`</b>, /// \anchor Slideshow_CameraMake /// _string_, -/// Shows the manufacturer of the camera used to take the current picture. -/// This is the value of the EXIF Make tag (hex code 0x010F). +/// @return The manufacturer of the camera used to take the current picture. +/// @note This is the value of the EXIF Make tag (hex code 0x010F). +/// <p> /// } /// \table_row3{ <b>`Slideshow.CameraModel`</b>, /// \anchor Slideshow_CameraModel /// _string_, -/// Shows the manufacturer's model name or number of the camera used to take -/// the current picture. This is the value of the EXIF Model tag (hex code -/// 0x0110). +/// @return The manufacturer's model name or number of the camera used to take +/// the current picture. +/// @note This is the value of the EXIF Model tag (hex code 0x0110). +/// <p> /// } /// \table_row3{ <b>`Slideshow.Caption`</b>, /// \anchor Slideshow_Caption /// _string_, -/// Shows a description of the current picture. This is the value of the -/// IPTC Caption tag (hex code 0x78). +/// @return A description of the current picture. +/// @note This is the value of the IPTC Caption tag (hex code 0x78). +/// <p> /// } /// \table_row3{ <b>`Slideshow.Category`</b>, /// \anchor Slideshow_Category /// _string_, -/// Shows the subject of the current picture as a category code. This is the -/// value of the IPTC Category tag (hex code 0x0F). +/// @return The subject of the current picture as a category code. +/// @note This is the value of the IPTC Category tag (hex code 0x0F). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Category `Slideshow.Category`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.CCDWidth`</b>, /// \anchor Slideshow_CCDWidth /// _string_, -/// Shows the width of the CCD in the camera used to take the current -/// picture. This is calculated from three EXIF tags (0xA002 * 0xA210 / 0xA20e). +/// @return The width of the CCD in the camera used to take the current +/// picture. +/// @note This is calculated from three EXIF tags (0xA002 * 0xA210 / 0xA20e). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_CCDWidth `Slideshow.CCDWidth`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.City`</b>, /// \anchor Slideshow_City /// _string_, -/// Shows the city where the current picture was taken. This is the value of -/// the IPTC City tag (hex code 0x5A). +/// @return The city where the current picture was taken. +/// @note This is the value of the IPTC City tag (hex code 0x5A). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_City `Slideshow.City`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Colour`</b>, /// \anchor Slideshow_Colour /// _string_, -/// Shows whether the current picture is "Colour" or "Black and White". +/// @return the colour of the picture. It can have one of the following values: +/// - <b>"Colour"</b> +/// - <b>"Black and White"</b> +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Colour `Slideshow.Colour`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.CopyrightNotice`</b>, /// \anchor Slideshow_CopyrightNotice /// _string_, -/// Shows the copyright notice of the current picture. This is the value of -/// the IPTC Copyright tag (hex code 0x74). +/// @return The copyright notice of the current picture. +/// @note This is the value of the IPTC Copyright tag (hex code 0x74). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_CopyrightNotice `Slideshow.CopyrightNotice`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Country`</b>, /// \anchor Slideshow_Country /// _string_, -/// Shows the full name of the country where the current picture was taken. -/// This is the value of the IPTC CountryName tag (hex code 0x65). +/// @return The full name of the country where the current picture was taken. +/// @note This is the value of the IPTC CountryName tag (hex code 0x65). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Country `Slideshow.Country`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.CountryCode`</b>, /// \anchor Slideshow_CountryCode /// _string_, -/// Shows the country code of the country where the current picture was -/// taken. This is the value of the IPTC CountryCode tag (hex code 0x64). +/// @return The country code of the country where the current picture was +/// taken. +/// @note This is the value of the IPTC CountryCode tag (hex code 0x64). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_CountryCode `Slideshow.CountryCode`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Credit`</b>, /// \anchor Slideshow_Credit /// _string_, -/// Shows who provided the current picture. This is the value of the IPTC -/// Credit tag (hex code 0x6E). +/// @return Who provided the current picture. +/// @note This is the value of the IPTC Credit tag (hex code 0x6E). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Credit `Slideshow.Credit`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.DigitalZoom`</b>, /// \anchor Slideshow_DigitalZoom /// _string_, -/// Shows the digital zoom ratio when the current picture was taken. This is -/// the value of the EXIF .DigitalZoomRatio tag (hex code 0xA404). +/// @return The digital zoom ratio when the current picture was taken. +/// @note This is the value of the EXIF .DigitalZoomRatio tag (hex code 0xA404). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_DigitalZoom `Slideshow.DigitalZoom`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.EXIFComment`</b>, /// \anchor Slideshow_EXIFComment /// _string_, -/// Shows a description of the current picture. This is the value of the -/// EXIF User Comment tag (hex code 0x9286). This is the same value as -/// Slideshow.SlideComment. +/// @return A description of the current picture. +/// @note This is the value of the EXIF User Comment tag (hex code 0x9286). +/// This is the same value as \ref Slideshow_SlideComment "Slideshow.SlideComment". +/// <p> /// } /// \table_row3{ <b>`Slideshow.EXIFDate`</b>, /// \anchor Slideshow_EXIFDate /// _string_, -/// Shows the localized date of the current picture. The short form of the -/// date is used. The value of the EXIF DateTimeOriginal tag (hex code +/// @return The localized date of the current picture. The short form of the +/// date is used. +/// @note The value of the EXIF DateTimeOriginal tag (hex code /// 0x9003) is preferred. If the DateTimeOriginal tag is not found\, the /// value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex code /// 0x0132) might be used. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_EXIFDate `Slideshow.EXIFDate`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.EXIFDescription`</b>, /// \anchor Slideshow_EXIFDescription /// _string_, -/// Shows a short description of the current picture. The SlideComment\, -/// EXIFComment or Caption values might contain a longer description. This -/// is the value of the EXIF ImageDescription tag (hex code 0x010E). +/// @return A short description of the current picture. The SlideComment\, +/// EXIFComment or Caption values might contain a longer description. +/// @note This is the value of the EXIF ImageDescription tag (hex code 0x010E). +/// <p> /// } /// \table_row3{ <b>`Slideshow.EXIFSoftware`</b>, /// \anchor Slideshow_EXIFSoftware /// _string_, -/// Shows the name and version of the firmware used by the camera that took -/// the current picture. This is the value of the EXIF Software tag (hex -/// code 0x0131). +/// @return The name and version of the firmware used by the camera that took +/// the current picture. +/// @note This is the value of the EXIF Software tag (hex code 0x0131). +/// <p> /// } /// \table_row3{ <b>`Slideshow.EXIFTime`</b>, /// \anchor Slideshow_EXIFTime /// _string_, -/// Shows the date/timestamp of the current picture. The localized short -/// form of the date and time is used. The value of the EXIF -/// DateTimeOriginal tag (hex code 0x9003) is preferred. If the -/// DateTimeOriginal tag is not found\, the value of DateTimeDigitized (hex -/// code 0x9004) or of DateTime (hex code 0x0132) might be used. +/// @return The date/timestamp of the current picture. The localized short +/// form of the date and time is used. +/// @note The value of the EXIF DateTimeOriginal tag (hex code 0x9003) is +/// preferred. If the DateTimeOriginal tag is not found\, the value of +/// DateTimeDigitized (hex code 0x9004) or of DateTime (hex code 0x0132) +/// might be used. +/// <p> /// } /// \table_row3{ <b>`Slideshow.Exposure`</b>, /// \anchor Slideshow_Exposure /// _string_, -/// Shows the class of the program used by the camera to set exposure when -/// the current picture was taken. Values include "Manual"\, -/// "Program (Auto)"\, "Aperture priority (Semi-Auto)"\, "Shutter priority -/// (semi-auto)"\, etc. This is the value of the EXIF ExposureProgram tag +/// @return The class of the program used by the camera to set exposure when +/// the current picture was taken. Values include: +/// - <b>"Manual"</b> +/// - <b>"Program (Auto)"</b> +/// - <b>"Aperture priority (Semi-Auto)"</b> +/// - <b>"Shutter priority (semi-auto)"</b> +/// - etc... +/// @note This is the value of the EXIF ExposureProgram tag /// (hex code 0x8822). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Exposure `Slideshow.Exposure`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.ExposureBias`</b>, /// \anchor Slideshow_ExposureBias /// _string_, -/// Shows the exposure bias of the current picture. Typically this is a -/// number between -99.99 and 99.99. This is the value of the EXIF -/// ExposureBiasValue tag (hex code 0x9204). +/// @return The exposure bias of the current picture. Typically this is a +/// number between -99.99 and 99.99. +/// @note This is the value of the EXIF ExposureBiasValue tag (hex code 0x9204). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_ExposureBias `Slideshow.ExposureBias`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.ExposureMode`</b>, /// \anchor Slideshow_ExposureMode /// _string_, -/// Shows the exposure mode of the current picture. The possible values are -/// "Automatic"\, "Manual"\, and "Auto bracketing". This is the value of the -/// EXIF ExposureMode tag (hex code 0xA402). +/// @return The exposure mode of the current picture. The possible values are: +/// - <b>"Automatic"</b> +/// - <b>"Manual"</b> +/// - <b>"Auto bracketing"</b> +/// @note This is the value of the EXIF ExposureMode tag (hex code 0xA402). +/// <p> /// } /// \table_row3{ <b>`Slideshow.ExposureTime`</b>, /// \anchor Slideshow_ExposureTime /// _string_, -/// Shows the exposure time of the current picture\, in seconds. This is the -/// value of the EXIF ExposureTime tag (hex code 0x829A). If the -/// ExposureTime tag is not found\, the ShutterSpeedValue tag (hex code +/// @return The exposure time of the current picture\, in seconds. +/// @note This is the value of the EXIF ExposureTime tag (hex code 0x829A). +/// If the ExposureTime tag is not found\, the ShutterSpeedValue tag (hex code /// 0x9201) might be used. +/// <p> /// } /// \table_row3{ <b>`Slideshow.Filedate`</b>, /// \anchor Slideshow_Filedate /// _string_, -/// Shows the file date of the current picture +/// @return The file date of the current picture. +/// <p> /// } /// \table_row3{ <b>`Slideshow.Filename`</b>, /// \anchor Slideshow_Filename /// _string_, -/// Shows the file name of the current picture +/// @return The file name of the current picture. +/// <p> /// } /// \table_row3{ <b>`Slideshow.Filesize`</b>, /// \anchor Slideshow_Filesize /// _string_, -/// Shows the file size of the current picture +/// @return The file size of the current picture. +/// <p> /// } /// \table_row3{ <b>`Slideshow.FlashUsed`</b>, /// \anchor Slideshow_FlashUsed /// _string_, -/// Shows the status of flash when the current picture was taken. The value -/// will be either "Yes" or "No"\, and might include additional information. -/// This is the value of the EXIF Flash tag (hex code 0x9209). +/// @return The status of flash when the current picture was taken. The value +/// will be either <b>"Yes"</b> or <b>"No"</b>\, and might include additional information. +/// @note This is the value of the EXIF Flash tag (hex code 0x9209). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_FlashUsed `Slideshow.FlashUsed`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.FocalLength`</b>, /// \anchor Slideshow_FocalLength /// _string_, -/// Shows the focal length of the lens\, in mm. This is the value of the EXIF -/// FocalLength tag (hex code 0x920A). +/// @return The focal length of the lens\, in mm. +/// @note This is the value of the EXIF FocalLength tag (hex code 0x920A). +/// <p> /// } /// \table_row3{ <b>`Slideshow.FocusDistance`</b>, /// \anchor Slideshow_FocusDistance /// _string_, -/// Shows the distance to the subject\, in meters. This is the value of the -/// EXIF SubjectDistance tag (hex code 0x9206). +/// @return The distance to the subject\, in meters. +/// @note This is the value of the EXIF SubjectDistance tag (hex code 0x9206). +/// <p> /// } /// \table_row3{ <b>`Slideshow.Headline`</b>, /// \anchor Slideshow_Headline /// _string_, -/// Shows a synopsis of the contents of the current picture. This is the -/// value of the IPTC Headline tag (hex code 0x69). +/// @return A synopsis of the contents of the current picture. +/// @note This is the value of the IPTC Headline tag (hex code 0x69). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Headline `Slideshow.Headline`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.ImageType`</b>, /// \anchor Slideshow_ImageType /// _string_, -/// Shows the color components of the current picture. This is the value of -/// the IPTC ImageType tag (hex code 0x82). +/// @return The color components of the current picture. +/// @note This is the value of the IPTC ImageType tag (hex code 0x82). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_ImageType `Slideshow.ImageType`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.IPTCDate`</b>, /// \anchor Slideshow_IPTCDate /// _string_, -/// Shows the date when the intellectual content of the current picture was -/// created\, rather than when the picture was created. This is the value of -/// the IPTC DateCreated tag (hex code 0x37). +/// @return The date when the intellectual content of the current picture was +/// created\, rather than when the picture was created. +/// @note This is the value of the IPTC DateCreated tag (hex code 0x37). +/// <p> /// } /// \table_row3{ <b>`Slideshow.ISOEquivalence`</b>, /// \anchor Slideshow_ISOEquivalence /// _string_, -/// Shows the ISO speed of the camera when the current picture was taken. -/// This is the value of the EXIF ISOSpeedRatings tag (hex code 0x8827). +/// @return The ISO speed of the camera when the current picture was taken. +/// @note This is the value of the EXIF ISOSpeedRatings tag (hex code 0x8827). +/// <p> /// } /// \table_row3{ <b>`Slideshow.Keywords`</b>, /// \anchor Slideshow_Keywords /// _string_, -/// Shows keywords assigned to the current picture. This is the value of the -/// IPTC Keywords tag (hex code 0x19). +/// @return The keywords assigned to the current picture. +/// @note This is the value of the IPTC Keywords tag (hex code 0x19). +/// <p> /// } /// \table_row3{ <b>`Slideshow.Latitude`</b>, /// \anchor Slideshow_Latitude /// _string_, -/// Shows the latitude where the current picture was taken (degrees\, -/// minutes\, seconds North or South). This is the value of the EXIF -/// GPSInfo.GPSLatitude and GPSInfo.GPSLatitudeRef tags. +/// @return The latitude where the current picture was taken (degrees\, +/// minutes\, seconds North or South). +/// @note This is the value of the EXIF GPSInfo.GPSLatitude and +/// GPSInfo.GPSLatitudeRef tags. +/// <p> /// } /// \table_row3{ <b>`Slideshow.LightSource`</b>, /// \anchor Slideshow_LightSource /// _string_, -/// Shows the kind of light source when the picture was taken. Possible -/// values include "Daylight"\, "Fluorescent"\, "Incandescent"\, etc. This is -/// the value of the EXIF LightSource tag (hex code 0x9208). +/// @return The kind of light source when the picture was taken. Possible +/// values include: +/// - <b>"Daylight"</b> +/// - <b>"Fluorescent"</b> +/// - <b>"Incandescent"</b> +/// - etc... +/// @note This is the value of the EXIF LightSource tag (hex code 0x9208). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_LightSource `Slideshow.LightSource`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.LongEXIFDate`</b>, /// \anchor Slideshow_LongEXIFDate /// _string_, -/// Shows only the localized date of the current picture. The long form of -/// the date is used. The value of the EXIF DateTimeOriginal tag (hex code +/// @return Only the localized date of the current picture. The long form of +/// the date is used. +/// @note The value of the EXIF DateTimeOriginal tag (hex code /// 0x9003) is preferred. If the DateTimeOriginal tag is not found\, the /// value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex code /// 0x0132) might be used. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_LongEXIFDate `Slideshow.LongEXIFDate`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.LongEXIFTime`</b>, /// \anchor Slideshow_LongEXIFTime /// _string_, -/// Shows the date/timestamp of the current picture. The localized long form -/// of the date and time is used. The value of the EXIF DateTimeOriginal tag +/// @return The date/timestamp of the current picture. The localized long form +/// of the date and time is used. +/// @note The value of the EXIF DateTimeOriginal tag /// (hex code 0x9003) is preferred. if the DateTimeOriginal tag is not found\, /// the value of DateTimeDigitized (hex code 0x9004) or of DateTime (hex /// code 0x0132) might be used. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_LongEXIFTime `Slideshow.LongEXIFTime`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Longitude`</b>, /// \anchor Slideshow_Longitude /// _string_, -/// Shows the longitude where the current picture was taken (degrees\, -/// minutes\, seconds East or West). This is the value of the EXIF -/// GPSInfo.GPSLongitude and GPSInfo.GPSLongitudeRef tags. +/// @return The longitude where the current picture was taken (degrees\, +/// minutes\, seconds East or West). +/// @note This is the value of the EXIF GPSInfo.GPSLongitude and +/// GPSInfo.GPSLongitudeRef tags. +/// <p> /// } /// \table_row3{ <b>`Slideshow.MeteringMode`</b>, /// \anchor Slideshow_MeteringMode /// _string_, -/// Shows the metering mode used when the current picture was taken. The -/// possible values are "Center weight"\, "Spot"\, or "Matrix". This is the -/// value of the EXIF MeteringMode tag (hex code 0x9207). +/// @return The metering mode used when the current picture was taken. The +/// possible values are: +/// - <b>"Center weight"</b> +/// - <b>"Spot"</b> +/// - <b>"Matrix"</b> +/// @note This is the value of the EXIF MeteringMode tag (hex code 0x9207). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_MeteringMode `Slideshow.MeteringMode`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.ObjectName`</b>, /// \anchor Slideshow_ObjectName /// _string_, -/// Shows a shorthand reference for the current picture. This is the value -/// of the IPTC ObjectName tag (hex code 0x05). +/// @return a shorthand reference for the current picture. +/// @note This is the value of the IPTC ObjectName tag (hex code 0x05). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_ObjectName `Slideshow.ObjectName`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Orientation`</b>, /// \anchor Slideshow_Orientation /// _string_, -/// Shows the orientation of the current picture. Possible values are "Top -/// Left"\, "Top Right"\, "Left Top"\, "Right Bottom"\, etc. This is the value -/// of the EXIF Orientation tag (hex code 0x0112). +/// @return The orientation of the current picture. Possible values are: +/// - <b>"Top Left"</b> +/// - <b>"Top Right"</b> +/// - <b>"Left Top"</b> +/// - <b>"Right Bottom"</b> +/// - etc... +/// @note This is the value of the EXIF Orientation tag (hex code 0x0112). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Orientation `Slideshow.Orientation`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Path`</b>, /// \anchor Slideshow_Path /// _string_, -/// Shows the file path of the current picture +/// @return The file path of the current picture. +/// <p> /// } /// \table_row3{ <b>`Slideshow.Process`</b>, /// \anchor Slideshow_Process /// _string_, -/// Shows the process used to compress the current picture +/// @return The process used to compress the current picture. +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Process `Slideshow.Process`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.ReferenceService`</b>, /// \anchor Slideshow_ReferenceService /// _string_, -/// Shows the Service Identifier of a prior envelope to which the current -/// picture refers. This is the value of the IPTC ReferenceService tag (hex -/// code 0x2D). +/// @return The Service Identifier of a prior envelope to which the current +/// picture refers. +/// @note This is the value of the IPTC ReferenceService tag (hex code 0x2D). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_ReferenceService `Slideshow.ReferenceService`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Resolution`</b>, /// \anchor Slideshow_Resolution /// _string_, -/// Shows the dimensions of the current picture (Width x Height) +/// @return The dimensions of the current picture (Width x Height) +/// <p> /// } /// \table_row3{ <b>`Slideshow.SlideComment`</b>, /// \anchor Slideshow_SlideComment /// _string_, -/// Shows a description of the current picture. This is the value of the -/// EXIF User Comment tag (hex code 0x9286). This is the same value as -/// Slideshow.EXIFComment. +/// @return A description of the current picture. +/// @note This is the value of the EXIF User Comment tag (hex code 0x9286). +/// This is the same value as \ref Slideshow_EXIFComment "Slideshow.EXIFComment". +/// <p> /// } /// \table_row3{ <b>`Slideshow.SlideIndex`</b>, /// \anchor Slideshow_SlideIndex /// _string_, -/// Shows the slide index of the current picture +/// @return The slide index of the current picture. +/// <p> /// } /// \table_row3{ <b>`Slideshow.Source`</b>, /// \anchor Slideshow_Source /// _string_, -/// Shows the original owner of the current picture. This is the value of -/// the IPTC Source tag (hex code 0x73). +/// @return The original owner of the current picture. +/// @note This is the value of the IPTC Source tag (hex code 0x73). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Source `Slideshow.Source`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.SpecialInstructions`</b>, /// \anchor Slideshow_SpecialInstructions /// _string_, -/// Shows other editorial instructions concerning the use of the current -/// picture. This is the value of the IPTC SpecialInstructions tag (hex -/// code 0x28). +/// @return Other editorial instructions concerning the use of the current +/// picture. +/// @note This is the value of the IPTC SpecialInstructions tag (hex code 0x28). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_SpecialInstructions `Slideshow.SpecialInstructions`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.State`</b>, /// \anchor Slideshow_State /// _string_, -/// Shows the State/Province where the current picture was taken. This is -/// the value of the IPTC ProvinceState tag (hex code 0x5F). +/// @return The State/Province where the current picture was taken. +/// @note This is the value of the IPTC ProvinceState tag (hex code 0x5F). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_State `Slideshow.State`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Sublocation`</b>, /// \anchor Slideshow_Sublocation /// _string_, -/// Shows the location within a city where the current picture was taken - -/// might indicate the nearest landmark. This is the value of the IPTC -/// SubLocation tag (hex code 0x5C). +/// @return The location within a city where the current picture was taken - +/// might indicate the nearest landmark. +/// @note This is the value of the IPTC SubLocation tag (hex code 0x5C). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Sublocation `Slideshow.Sublocation`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.SupplementalCategories`</b>, /// \anchor Slideshow_SupplementalCategories /// _string_, -/// Shows supplemental category codes to further refine the subject of the -/// current picture. This is the value of the IPTC SuppCategory tag (hex +/// @return The supplemental category codes to further refine the subject of the +/// current picture. +/// @note This is the value of the IPTC SuppCategory tag (hex /// code 0x14). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_SupplementalCategories `Slideshow.SupplementalCategories`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.TimeCreated`</b>, /// \anchor Slideshow_TimeCreated /// _string_, -/// Shows the time when the intellectual content of the current picture was -/// created\, rather than when the picture was created. This is the value of -/// the IPTC TimeCreated tag (hex code 0x3C). +/// @return The time when the intellectual content of the current picture was +/// created\, rather than when the picture was created. +/// @note This is the value of the IPTC TimeCreated tag (hex code 0x3C). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_TimeCreated `Slideshow.TimeCreated`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.TransmissionReference`</b>, /// \anchor Slideshow_TransmissionReference /// _string_, -/// Shows a code representing the location of original transmission of the -/// current picture. This is the value of the IPTC TransmissionReference tag +/// @return A code representing the location of original transmission of the +/// current picture. +/// @note This is the value of the IPTC TransmissionReference tag /// (hex code 0x67). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_TransmissionReference `Slideshow.TransmissionReference`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.Urgency`</b>, /// \anchor Slideshow_Urgency /// _string_, -/// Shows the urgency of the current picture. Values are 1-9. The 1 is most -/// urgent. Some image management programs use urgency to indicate picture +/// @return The urgency of the current picture. Values are 1-9. The 1 is most +/// urgent. +/// @note Some image management programs use urgency to indicate picture /// rating\, where urgency 1 is 5 stars and urgency 5 is 1 star. Urgencies /// 6-9 are not used for rating. This is the value of the IPTC Urgency tag /// (hex code 0x0A). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_Urgency `Slideshow.Urgency`\endlink +/// <p> /// } /// \table_row3{ <b>`Slideshow.WhiteBalance`</b>, /// \anchor Slideshow_WhiteBalance /// _string_, -/// Shows the white balance mode set when the current picture was taken. -/// The possible values are "Manual" and "Auto". This is the value of the -/// EXIF WhiteBalance tag (hex code 0xA403). +/// @return The white balance mode set when the current picture was taken. +/// The possible values are: +/// - <b>"Manual"</b> +/// - <b>"Auto"</b> +/// <p> +/// @note This is the value of the EXIF WhiteBalance tag (hex code 0xA403). +/// <p><hr> +/// @skinning_v13 **[New Infolabel]** \link Slideshow_WhiteBalance `Slideshow.WhiteBalance`\endlink +/// <p> /// } /// \table_end /// /// ----------------------------------------------------------------------------- -/// @} const infomap slideshow[] = {{ "ispaused", SLIDESHOW_ISPAUSED }, { "isactive", SLIDESHOW_ISACTIVE }, { "isvideo", SLIDESHOW_ISVIDEO }, @@ -5782,8 +8182,249 @@ const infomap slideshow[] = {{ "ispaused", SLIDESHOW_ISPAUSED { "imagetype", SLIDESHOW_IPTC_IMAGETYPE }, }; +/// \page modules__infolabels_boolean_conditions +/// \subsection modules__infolabels_boolean_conditions_Library Library +/// @todo Make this annotate an array of infobools/labels to make it easier to track +/// \table_start +/// \table_h3{ Labels, Type, Description } +/// \table_row3{ <b>`Library.IsScanning`</b>, +/// \anchor Library_IsScanning +/// _boolean_, +/// @return **True** if the library is being scanned. +/// <p> +/// } +/// \table_row3{ <b>`Library.IsScanningVideo`</b>, +/// \anchor Library_IsScanningVideo +/// _boolean_, +/// @return **True** if the video library is being scanned. +/// <p> +/// } +/// \table_row3{ <b>`Library.IsScanningMusic`</b>, +/// \anchor Library_IsScanningMusic +/// _boolean_, +/// @return **True** if the music library is being scanned. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(music)`</b>, +/// \anchor Library_HasContent_Music +/// _boolean_, +/// @return **True** if the library has music content. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(video)`</b>, +/// \anchor Library_HasContent_Video +/// _boolean_, +/// @return **True** if the library has video content. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(movies)`</b>, +/// \anchor Library_HasContent_Movies +/// _boolean_, +/// @return **True** if the library has movies. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(tvshows)`</b>, +/// \anchor Library_HasContent_TVShows +/// _boolean_, +/// @return **True** if the library has tvshows. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(musicvideos)`</b>, +/// \anchor Library_HasContent_MusicVideos +/// _boolean_, +/// @return **True** if the library has music videos. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(moviesets)`</b>, +/// \anchor Library_HasContent_MovieSets +/// _boolean_, +/// @return **True** if the library has movie sets. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(singles)`</b>, +/// \anchor Library_HasContent_Singles +/// _boolean_, +/// @return **True** if the library has singles. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(compilations)`</b>, +/// \anchor Library_HasContent_Compilations +/// _boolean_, +/// @return **True** if the library has compilations. +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Composer)`</b>, +/// \anchor Library_HasContent_Role_Composer +/// _boolean_, +/// @return **True** if there are songs in the library which have composers. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Composer `Library.HasContent(Role.Composer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Conductor)`</b>, +/// \anchor Library_HasContent_Role_Conductor +/// _boolean_, +/// @return **True** if there are songs in the library which have a conductor. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Conductor `Library.HasContent(Role.Conductor)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Orchestra)`</b>, +/// \anchor Library_HasContent_Role_Orchestra +/// _boolean_, +/// @return **True** if there are songs in the library which have an orchestra. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Orchestra `Library.HasContent(Role.Orchestra)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Lyricist)`</b>, +/// \anchor Library_HasContent_Role_Lyricist +/// _boolean_, +/// @return **True** if there are songs in the library which have a lyricist. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Lyricist `Library.HasContent(Role.Lyricist)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Remixer)`</b>, +/// \anchor Library_HasContent_Role_Remixer +/// _boolean_, +/// @return **True** if there are songs in the library which have a remixer. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Remixer `Library.HasContent(Role.Remixer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Arranger)`</b>, +/// \anchor Library_HasContent_Role_Remixer +/// _boolean_, +/// @return **True** if there are songs in the library which have an arranger. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Remixer `Library.HasContent(Role.Arranger)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Engineer)`</b>, +/// \anchor Library_HasContent_Role_Engineer +/// _boolean_, +/// @return **True** if there are songs in the library which have an engineer. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Engineer `Library.HasContent(Role.Engineer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Producer)`</b>, +/// \anchor Library_HasContent_Role_Producer +/// _boolean_, +/// @return **True** if there are songs in the library which have an producer. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Producer `Library.HasContent(Role.Producer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.DJMixer)`</b>, +/// \anchor Library_HasContent_Role_DJMixer +/// _boolean_, +/// @return **True** if there are songs in the library which have a DJMixer. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_DJMixer `Library.HasContent(Role.DJMixer)`\endlink +/// <p> +/// } +/// \table_row3{ <b>`Library.HasContent(Role.Mixer)`</b>, +/// \anchor Library_HasContent_Role_Mixer +/// _boolean_, +/// @return **True** if there are songs in the library which have a mixer. +/// <p><hr> +/// @skinning_v17 **[New Boolean Condition]** \link Library_HasContent_Role_Mixer `Library.HasContent(Role.Mixer)`\endlink +/// <p> +/// } +/// \table_end +/// +/// ----------------------------------------------------------------------------- + + +/// \page modules__infolabels_boolean_conditions +/// \section modules_rm_infolabels_booleans Additional revision history for Infolabels and Boolean Conditions +/// <hr> +/// \subsection modules_rm_infolabels_booleans_v18 Kodi v18 (Leia) +/// +/// @skinning_v18 **[Removed Infolabels]** The following infolabels have been removed: +/// - `Listitem.Property(artistthumbs)`, `Listitem.Property(artistthumb)` - use +/// \link ListItem_Art_Type `ListItem.Art(type)`\endlink with <b>albumartist[n].*</b> or <b>artist[n].*</b> as <b>type</b> +/// - `ADSP.ActiveStreamType` +/// - `ADSP.DetectedStreamType` +/// - `ADSP.MasterName` +/// - `ADSP.MasterInfo` +/// - `ADSP.MasterOwnIcon` +/// - `ADSP.MasterOverrideIcon` +/// - `ListItem.ChannelNumber`, `ListItem.SubChannelNumber`, `MusicPlayer.ChannelNumber`, +/// `MusicPlayer.SubChannelNumber`, `VideoPlayer.ChannelNumber`, +/// `VideoPlayer.SubChannelNumber`. Please use the following alternatives +/// \link ListItem_ChannelNumberLabel `ListItem.ChannelNumberLabel` \endlink, +/// \link MusicPlayer_ChannelNumberLabel `MusicPlayer.ChannelNumberLabel` \endlink +/// \link VideoPlayer_ChannelNumberLabel `VideoPlayer.ChannelNumberLabel` \endlink from now on. +/// +/// @skinning_v18 **[Removed Boolean Conditions]** The following infobools have been removed: +/// - `System.HasModalDialog` - use \link System_HasActiveModalDialog `System.HasActiveModalDialog` \endlink and +/// \link System_HasVisibleModalDialog `System.HasVisibleModalDialog`\endlink instead +/// - `StringCompare()` - use \link String_IsEqual `String.IsEqual(info,string)`\endlink instead +/// - `SubString()` - use \link String_Contains `String.Contains(info,substring)`\endlink instead +/// - `IntegerGreaterThan()` - use \link Integer_IsGreater `Integer.IsGreater(info,number)`\endlink instead +/// - `IsEmpty()` - use \link String_IsEmpty `String.IsEmpty(info)`\endlink instead +/// - `System.HasADSP` +/// - `ADSP.IsActive` +/// - `ADSP.HasInputResample` +/// - `ADSP.HasPreProcess` +/// - `ADSP.HasMasterProcess` +/// - `ADSP.HasPostProcess` +/// - `ADSP.HasOutputResample` +/// - `ADSP.MasterActive` +/// <hr> +/// \subsection modules_rm_infolabels_booleans_v17 Kodi v17 (Krypton) +/// @skinning_v17 **[Removed Infolabels]** The following infolabels have been removed: +/// - `ListItem.StarRating` - use the other ratings instead. +/// +/// @skinning_v17 **[Removed Boolean Conditions]** The following infobools have been removed: +/// - `on` - use `true` instead +/// - `off` - use `false` instead +/// - `Player.ShowCodec` +/// - `System.GetBool(pvrmanager.enabled)` +/// <hr> +/// \subsection modules_rm_infolabels_booleans_v16 Kodi v16 (Jarvis) +/// @skinning_v16 **[New Boolean Conditions]** The following infobools were added: +/// - `System.HasADSP` +/// - `ADSP.IsActive` +/// - `ADSP.HasInputResample` +/// - `ADSP.HasPreProcess` +/// - `ADSP.HasMasterProcess` +/// - `ADSP.HasPostProcess` +/// - `ADSP.HasOutputResample` +/// - `ADSP.MasterActive` +/// - `System.HasModalDialog` +/// +/// @skinning_v16 **[New Infolabels]** The following infolabels were added: +/// - `ADSP.ActiveStreamType` +/// - `ADSP.DetectedStreamType` +/// - `ADSP.MasterName` +/// - `ADSP.MasterInfo` +/// - `ADSP.MasterOwnIcon` +/// - `ADSP.MasterOverrideIcon` +/// +/// @skinning_v16 **[Removed Boolean Conditions]** The following infobols were removed: +/// - `System.Platform.ATV2` + +/// <hr> +/// \subsection modules_rm_infolabels_booleans_v15 Kodi v15 (Isengard) +/// <hr> +/// \subsection modules_rm_infolabels_booleans_v14 Kodi v14 (Helix) +/// @skinning_v14 **[New Infolabels]** The following infolabels were added: +/// - `ListItem.SubChannelNumber` +/// - `MusicPlayer.SubChannelNumber` +/// - `VideoPlayer.SubChannelNumber` +/// +/// <hr> +/// \subsection modules_rm_infolabels_booleans_v13 XBMC v13 (Gotham) +/// @skinning_v13 **[Removed Infolabels]** The following infolabels were removed: +/// - `Network.SubnetAddress` +/// +/// <hr> // Crazy part, to use tableofcontents must it be on end -/// \page modules__General__List_of_gui_access +/// \page modules__infolabels_boolean_conditions /// \tableofcontents CGUIInfoManager::Property::Property(const std::string &property, const std::string ¶meters) @@ -6433,7 +9074,7 @@ int CGUIInfoManager::TranslateListItem(const Property& cat, const Property& prop { data3 = prop.param(); } - else if (prop.name == "duration") + else if (prop.name == "duration" || prop.name == "nextduration") { data4 = TranslateTimeFormat(prop.param()); } @@ -6713,7 +9354,7 @@ bool CGUIInfoManager::GetMultiInfoBool(const CGUIInfo &info, int contextWindow, else value = GetImage(info.GetData1(), contextWindow); - // Handle the case when a value contains time separator (:). This makes IntegerGreaterThan + // Handle the case when a value contains time separator (:). This makes Integer.IsGreater // useful for Player.Time* members without adding a separate set of members returning time in seconds if (value.find_first_of( ':' ) != value.npos) integer = StringUtils::TimeStringToSeconds(value); @@ -6872,7 +9513,7 @@ void CGUIInfoManager::SetCurrentItem(const CFileItem &item) SetChanged(); NotifyObservers(ObservableMessageCurrentItem); - // todo this should be handled by one of the observers above and forwarded + // @todo this should be handled by one of the observers above and forwarded CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::Info, "xbmc", "OnChanged"); } diff --git a/xbmc/XBDateTime.cpp b/xbmc/XBDateTime.cpp index f359a8cf67..b006134794 100644 --- a/xbmc/XBDateTime.cpp +++ b/xbmc/XBDateTime.cpp @@ -1056,15 +1056,19 @@ bool CDateTime::SetFromDBDate(const std::string &date) bool CDateTime::SetFromDBTime(const std::string &time) { - if (time.size() < 8) + if (time.size() < 5) return false; - // assumes format: - // HH:MM:SS - int hour, minute, second; + int hour; + int minute; + + int second = 0; + // HH:MM or HH:MM:SS hour = atoi(time.substr(0, 2).c_str()); minute = atoi(time.substr(3, 2).c_str()); - second = atoi(time.substr(6, 2).c_str()); + // HH:MM:SS + if (time.size() == 8) + second = atoi(time.substr(6, 2).c_str()); return SetTime(hour, minute, second); } diff --git a/xbmc/XBDateTime.h b/xbmc/XBDateTime.h index 510f99dd32..d1566f86c5 100644 --- a/xbmc/XBDateTime.h +++ b/xbmc/XBDateTime.h @@ -16,25 +16,54 @@ Note the use of bitmasking, e.g. TIME_FORMAT_HH_MM_SS = TIME_FORMAT_HH | TIME_FORMAT_MM | TIME_FORMAT_SS \sa StringUtils::SecondsToTimeString + \note For InfoLabels use the equivalent value listed (bold) + on the description of each enum value. + \note<b>Example:</b> 3661 seconds => h=1, hh=01, m=1, mm=01, ss=01, hours=1, mins=61, secs=3661 + <p><hr> + @skinning_v18 **[Infolabels Updated]** Added <b>secs</b>, <b>mins</b>, <b>hours</b> (total time) and **m** as possible formats for + InfoLabels that support the definition of a time format. Examples are: + - \link Player_SeekOffset_format `Player.SeekOffset(format)`\endlink + - \link Player_TimeRemaining_format `Player.TimeRemaining(format)`\endlink + - \link Player_Time_format `Player.Time(format)`\endlink + - \link Player_Duration_format `Player.Duration(format)`\endlink + - \link Player_FinishTime_format `Player.FinishTime(format)`\endlink + - \link Player_StartTime_format `Player.StartTime(format)` \endlink + - \link Player_SeekNumeric_format `Player.SeekNumeric(format)`\endlink + - \link ListItem_Duration_format `ListItem.Duration(format)`\endlink + - \link PVR_EpgEventDuration_format `PVR.EpgEventDuration(format)`\endlink + - \link PVR_EpgEventElapsedTime_format `PVR.EpgEventElapsedTime(format)`\endlink + - \link PVR_EpgEventRemainingTime_format `PVR.EpgEventRemainingTime(format)`\endlink + - \link PVR_EpgEventSeekTime_format `PVR.EpgEventSeekTime(format)`\endlink + - \link PVR_EpgEventFinishTime_format `PVR.EpgEventFinishTime(format)`\endlink + - \link PVR_TimeShiftStart_format `PVR.TimeShiftStart(format)`\endlink + - \link PVR_TimeShiftEnd_format `PVR.TimeShiftEnd(format)`\endlink + - \link PVR_TimeShiftCur_format `PVR.TimeShiftCur(format)`\endlink + - \link PVR_TimeShiftOffset_format `PVR.TimeShiftOffset(format)`\endlink + - \link PVR_TimeshiftProgressDuration_format `PVR.TimeshiftProgressDuration(format)`\endlink + - \link PVR_TimeshiftProgressEndTime `PVR.TimeshiftProgressEndTime`\endlink + - \link PVR_TimeshiftProgressEndTime_format `PVR.TimeshiftProgressEndTime(format)`\endlink + - \link ListItem_NextDuration_format `ListItem.NextDuration(format)` \endlink + <p> */ -enum TIME_FORMAT { TIME_FORMAT_GUESS = 0, - TIME_FORMAT_SS = 1, - TIME_FORMAT_MM = 2, - TIME_FORMAT_MM_SS = 3, - TIME_FORMAT_HH = 4, - TIME_FORMAT_HH_SS = 5, // not particularly useful - TIME_FORMAT_HH_MM = 6, - TIME_FORMAT_HH_MM_SS = 7, - TIME_FORMAT_XX = 8, // AM/PM - TIME_FORMAT_HH_MM_XX = 14, - TIME_FORMAT_HH_MM_SS_XX = 15, - TIME_FORMAT_H = 16, - TIME_FORMAT_H_MM_SS = 19, - TIME_FORMAT_H_MM_SS_XX = 27, - TIME_FORMAT_SECS = 32, - TIME_FORMAT_MINS = 64, - TIME_FORMAT_HOURS = 128, - TIME_FORMAT_M = 256 }; +enum TIME_FORMAT { TIME_FORMAT_GUESS = 0, ///< usually used as the fallback value if the format value is empty + TIME_FORMAT_SS = 1, ///< <b>ss</b> - seconds only + TIME_FORMAT_MM = 2, ///< <b>mm</b> - minutes only (2-digit) + TIME_FORMAT_MM_SS = 3, ///< <b>mm:ss</b> - minutes and seconds + TIME_FORMAT_HH = 4, ///< <b>hh</b> - hours only (2-digit) + TIME_FORMAT_HH_SS = 5, ///< <b>hh:ss</b> - hours and seconds (this is not particularly useful) + TIME_FORMAT_HH_MM = 6, ///< <b>hh:mm</b> - hours and minutes + TIME_FORMAT_HH_MM_SS = 7, ///< <b>hh:mm:ss</b> - hours, minutes and seconds + TIME_FORMAT_XX = 8, ///< <b>xx</b> - returns AM/PM for a 12-hour clock + TIME_FORMAT_HH_MM_XX = 14, ///< <b>hh:mm xx</b> - returns hours and minutes in a 12-hour clock format (AM/PM) + TIME_FORMAT_HH_MM_SS_XX = 15, ///< <b>hh:mm:ss xx</b> - returns hours (2-digit), minutes and seconds in a 12-hour clock format (AM/PM) + TIME_FORMAT_H = 16, ///< <b>h</b> - hours only (1-digit) + TIME_FORMAT_H_MM_SS = 19, ///< <b>hh:mm:ss</b> - hours, minutes and seconds + TIME_FORMAT_H_MM_SS_XX = 27, ///< <b>hh:mm:ss xx</b> - returns hours (1-digit), minutes and seconds in a 12-hour clock format (AM/PM) + TIME_FORMAT_SECS = 32, ///< <b>secs</b> - total time in seconds + TIME_FORMAT_MINS = 64, ///< <b>mins</b> - total time in minutes + TIME_FORMAT_HOURS = 128, ///< <b>hours</b> - total time in hours + TIME_FORMAT_M = 256 ///< <b>m</b> - minutes only (1-digit) + }; class CDateTime; diff --git a/xbmc/addons/AddonInfo.h b/xbmc/addons/AddonInfo.h index d29ee611c0..a476e422e9 100644 --- a/xbmc/addons/AddonInfo.h +++ b/xbmc/addons/AddonInfo.h @@ -133,7 +133,6 @@ namespace ADDON const CDateTime& LastUsed() const { return m_lastUsed; } const std::string& Origin() const { return m_origin; } uint64_t PackageSize() const { return m_packageSize; } - const std::string& Language() const { return m_language; } const InfoMap& ExtraInfo() const { return m_extrainfo; } bool MeetsVersion(const AddonVersion &version) const; @@ -174,7 +173,6 @@ namespace ADDON CDateTime m_lastUsed; std::string m_origin; uint64_t m_packageSize = 0; - std::string m_language; std::string m_libname; InfoMap m_extrainfo; }; diff --git a/xbmc/addons/AddonInstaller.cpp b/xbmc/addons/AddonInstaller.cpp index 28bce5c1e9..e97cc22e5b 100644 --- a/xbmc/addons/AddonInstaller.cpp +++ b/xbmc/addons/AddonInstaller.cpp @@ -85,7 +85,8 @@ void CAddonInstaller::OnJobProgress(unsigned int jobID, unsigned int progress, u if (i != m_downloadJobs.end()) { // update job progress - i->second.progress = progress; + i->second.progress = 100 / total * progress; + i->second.downloadFinshed = std::string(job->GetType()) == CAddonInstallJob::TYPE_INSTALL; CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM); msg.SetStringParam(i->first); lock.Leave(); @@ -120,13 +121,14 @@ void CAddonInstaller::GetInstallList(VECADDONS &addons) const } } -bool CAddonInstaller::GetProgress(const std::string &addonID, unsigned int &percent) const +bool CAddonInstaller::GetProgress(const std::string& addonID, unsigned int& percent, bool& downloadFinshed) const { CSingleLock lock(m_critSection); JobMap::const_iterator i = m_downloadJobs.find(addonID); if (i != m_downloadJobs.end()) { percent = i->second.progress; + downloadFinshed = i->second.downloadFinshed; return true; } return false; @@ -485,6 +487,8 @@ bool CAddonInstallJob::GetAddon(const std::string& addonID, RepositoryPtr& repo, bool CAddonInstallJob::DoWork() { + m_currentType = CAddonInstallJob::TYPE_DOWNLOAD; + SetTitle(StringUtils::Format(g_localizeStrings.Get(24057).c_str(), m_addon->Name().c_str())); SetProgress(0); @@ -505,9 +509,6 @@ bool CAddonInstallJob::DoWork() // packages folder, then extracting from the local .zip package into the addons folder // Both these functions are achieved by "copying" using the vfs. - std::string dest = "special://home/addons/packages/"; - std::string package = URIUtils::AddFileToFolder("special://home/addons/packages/", - URIUtils::GetFileName(m_addon->Path())); if (!m_repo && URIUtils::HasSlashAtEnd(m_addon->Path())) { // passed in a folder - all we need do is copy it across installFrom = m_addon->Path(); @@ -537,6 +538,18 @@ bool CAddonInstallJob::DoWork() return false; } + std::string packageOriginalPath, packageFileName; + URIUtils::Split(path, packageOriginalPath, packageFileName); + // Use ChangeBasePath so the URL is decoded if necessary + const std::string packagePath = "special://home/addons/packages/"; + //!@todo fix design flaw in file copying: We use CFileOperationJob to download the package from the internet + // to the local cache. It tries to be "smart" and decode the URL. But it never tells us what the result is, + // so if we try for example to download "http://localhost/a+b.zip" the result ends up in "a b.zip". + // First bug is that it actually decodes "+", which is not necessary except in query parts. Second bug + // is that we cannot know that it does this and what the result is so the package will not be found without + // using ChangeBasePath here (which is the same function the copying code uses and performs the translation). + std::string package = URIUtils::ChangeBasePath(packageOriginalPath, packageFileName, packagePath); + // check that we don't already have a valid copy if (!hash.Empty()) { @@ -554,7 +567,7 @@ bool CAddonInstallJob::DoWork() // zip passed in - download + extract if (!CFile::Exists(package)) { - if (!DownloadPackage(path, dest)) + if (!DownloadPackage(path, packagePath)) { CFile::Delete(package); @@ -602,6 +615,8 @@ bool CAddonInstallJob::DoWork() } } + m_currentType = CAddonInstallJob::TYPE_INSTALL; + // run any pre-install functions ADDON::OnPreInstall(m_addon); @@ -708,7 +723,7 @@ bool CAddonInstallJob::Install(const std::string &installFrom, const RepositoryP SetText(g_localizeStrings.Get(24079)); auto deps = m_addon->GetDependencies(); - unsigned int totalSteps = static_cast<unsigned int>(deps.size()); + unsigned int totalSteps = static_cast<unsigned int>(deps.size()) + 1; if (ShouldCancel(0, totalSteps)) return false; @@ -780,7 +795,7 @@ bool CAddonInstallJob::Install(const std::string &installFrom, const RepositoryP } SetText(g_localizeStrings.Get(24086)); - SetProgress(0); + SetProgress(static_cast<unsigned int>(100.0 * (totalSteps - 1.0) / totalSteps)); CFilesystemInstaller fsInstaller; if (!fsInstaller.InstallToFilesystem(installFrom, m_addon->ID())) diff --git a/xbmc/addons/AddonInstaller.h b/xbmc/addons/AddonInstaller.h index e738d398d8..1e0b56edc6 100644 --- a/xbmc/addons/AddonInstaller.h +++ b/xbmc/addons/AddonInstaller.h @@ -27,7 +27,7 @@ public: bool IsDownloading() const; void GetInstallList(ADDON::VECADDONS &addons) const; - bool GetProgress(const std::string &addonID, unsigned int &percent) const; + bool GetProgress(const std::string& addonID, unsigned int& percent, bool& downloadFinshed) const; bool Cancel(const std::string &addonID); /*! \brief Installs the addon while showing a modal progress dialog @@ -93,13 +93,11 @@ public: class CDownloadJob { public: - explicit CDownloadJob(unsigned int id) - { - jobID = id; - progress = 0; - } + explicit CDownloadJob(unsigned int id) : jobID(id) { } + unsigned int jobID; - unsigned int progress; + unsigned int progress = 0; + bool downloadFinshed = false; }; typedef std::map<std::string, CDownloadJob> JobMap; @@ -146,6 +144,16 @@ public: bool DoWork() override; + static constexpr const char* TYPE_DOWNLOAD = "DOWNLOAD"; + static constexpr const char* TYPE_INSTALL = "INSTALL"; + /*! + * \brief Returns the current processing type in the installation job + * + * \return The current processing type as string, can be \ref TYPE_DOWNLOAD or + * \ref TYPE_INSTALL + */ + const char* GetType() const override { return m_currentType; } + /*! \brief Find the add-on and its repository for the given add-on ID * \param addonID ID of the add-on to find * \param[out] repo the repository to use @@ -173,6 +181,7 @@ private: ADDON::RepositoryPtr m_repo; bool m_isUpdate; bool m_isAutoUpdate; + const char* m_currentType = TYPE_DOWNLOAD; }; class CAddonUnInstallJob : public CFileOperationJob diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp index 6fd677fcc3..4d6e27e3d9 100644 --- a/xbmc/addons/AddonManager.cpp +++ b/xbmc/addons/AddonManager.cpp @@ -20,7 +20,10 @@ #include "utils/URIUtils.h" #include "utils/XMLUtils.h" +#include <algorithm> #include <array> +#include <set> +#include <utility> using namespace XFILE; @@ -688,17 +691,28 @@ bool CAddonMgr::FindAddons() //Sync with db { - std::set<std::string> installed; + std::set<std::pair<std::string, std::string>> installed; cp_status_t status; int n; cp_plugin_info_t** cp_addons = cp_get_plugins_info(m_cp_context, &status, &n); for (int i = 0; i < n; ++i) { - CLog::Log(LOGNOTICE, "ADDON: %s v%s installed", cp_addons[i]->identifier, cp_addons[i]->version); - installed.insert(cp_addons[i]->identifier); + installed.emplace(cp_addons[i]->identifier, cp_addons[i]->version ? cp_addons[i]->version : ""); } cp_release_info(m_cp_context, cp_addons); - m_database.SyncInstalled(installed, m_systemAddons, m_optionalAddons); + // Log separately so list is sorted + for (const auto& installedAddon : installed) + { + CLog::Log(LOGNOTICE, "ADDON: {} v{} installed", installedAddon.first, installedAddon.second); + } + + std::set<std::string> installedIdentifiers; + std::transform( + installed.cbegin(), installed.cend(), + std::inserter(installedIdentifiers, installedIdentifiers.begin()), + [](const decltype(installed)::value_type& p) { return p.first; } + ); + m_database.SyncInstalled(installedIdentifiers, m_systemAddons, m_optionalAddons); } // Reload caches diff --git a/xbmc/addons/GUIDialogAddonInfo.cpp b/xbmc/addons/GUIDialogAddonInfo.cpp index 00c44ec16c..fceabd9201 100644 --- a/xbmc/addons/GUIDialogAddonInfo.cpp +++ b/xbmc/addons/GUIDialogAddonInfo.cpp @@ -471,12 +471,21 @@ bool CGUIDialogAddonInfo::ShowDependencyList(const std::vector<ADDON::Dependency CFileItemList items; for (auto& it : deps) { - AddonPtr dep_addon, local_addon; + AddonPtr dep_addon, local_addon, info_addon; + // Find add-on in repositories CServiceBroker::GetAddonMgr().FindInstallableById(it.id, dep_addon); + // Find add-on in local installation CServiceBroker::GetAddonMgr().GetAddon(it.id, local_addon); - if (dep_addon) + + // All combinations of dep_addon and local_addon validity are possible and information + // must be displayed even when there is no dep_addon. + // info_addon is the add-on to take the information to display (name, icon) from. The + // version in the repository is preferred because it might contain more recent data. + info_addon = dep_addon ? dep_addon : local_addon; + + if (info_addon) { - CFileItemPtr item(new CFileItem(dep_addon->Name())); + CFileItemPtr item(new CFileItem(info_addon->Name())); std::stringstream str; str << it.id << " " << it.requiredVersion.asString(); if ((it.optional && !local_addon) || (!it.optional && local_addon)) @@ -489,7 +498,7 @@ bool CGUIDialogAddonInfo::ShowDependencyList(const std::vector<ADDON::Dependency g_localizeStrings.Get(39018).c_str()); item->SetLabel2(str.str()); - item->SetIconImage(dep_addon->Icon()); + item->SetIconImage(info_addon->Icon()); item->SetProperty("addon_id", it.id); items.Add(item); } diff --git a/xbmc/addons/GUIWindowAddonBrowser.cpp b/xbmc/addons/GUIWindowAddonBrowser.cpp index 3d5a85fbab..4bc272da81 100644 --- a/xbmc/addons/GUIWindowAddonBrowser.cpp +++ b/xbmc/addons/GUIWindowAddonBrowser.cpp @@ -313,9 +313,10 @@ void CGUIWindowAddonBrowser::UpdateStatus(const CFileItemPtr& item) return; unsigned int percent; - if (CAddonInstaller::GetInstance().GetProgress(item->GetProperty("Addon.ID").asString(), percent)) + bool downloadFinshed; + if (CAddonInstaller::GetInstance().GetProgress(item->GetProperty("Addon.ID").asString(), percent, downloadFinshed)) { - std::string progress = StringUtils::Format(g_localizeStrings.Get(24042).c_str(), percent); + std::string progress = StringUtils::Format(!downloadFinshed ? g_localizeStrings.Get(24042) : g_localizeStrings.Get(24044), percent); item->SetProperty("Addon.Status", progress); item->SetProperty("Addon.Downloading", true); } diff --git a/xbmc/addons/Repository.cpp b/xbmc/addons/Repository.cpp index 2d50e57b93..9c97aaac19 100644 --- a/xbmc/addons/Repository.cpp +++ b/xbmc/addons/Repository.cpp @@ -170,11 +170,11 @@ CRepository::CRepository(CAddonInfo addonInfo, DirList dirs) CURL datadir(dir.datadir); if (datadir.IsProtocol("http")) { - CLog::Log(LOGWARNING, "Repository {} uses plain HTTP for add-on downloads - this is insecure and will make your Kodi installation vulnerable to attacks if enabled!", Name()); + CLog::Log(LOGWARNING, "Repository add-on {} uses plain HTTP for add-on downloads in path {} - this is insecure and will make your Kodi installation vulnerable to attacks if enabled!", ID(), datadir.GetRedacted()); } else if (datadir.IsProtocol("https") && datadir.HasProtocolOption("verifypeer") && datadir.GetProtocolOption("verifypeer") == "false") { - CLog::Log(LOGWARNING, "Repository {} disabled peer verification for add-on downloads - this is insecure and will make your Kodi installation vulnerable to attacks if enabled!", Name()); + CLog::Log(LOGWARNING, "Repository add-on {} disabled peer verification for add-on downloads in path {} - this is insecure and will make your Kodi installation vulnerable to attacks if enabled!", ID(), datadir.GetRedacted()); } } } diff --git a/xbmc/addons/kodi-addon-dev-kit/doxygen/Modules/modules_general.dox b/xbmc/addons/kodi-addon-dev-kit/doxygen/Modules/modules_general.dox index 481a0db8d6..f7e04ca269 100644 --- a/xbmc/addons/kodi-addon-dev-kit/doxygen/Modules/modules_general.dox +++ b/xbmc/addons/kodi-addon-dev-kit/doxygen/Modules/modules_general.dox @@ -3,6 +3,6 @@ \page general_parts General Development parts \brief \doc_header{ General Add-On Development parts } -\subpage modules__General__List_of_gui_access +\subpage modules__infolabels_boolean_conditions \subpage page_List_of_built_in_functions */ diff --git a/xbmc/addons/settings/AddonSettings.cpp b/xbmc/addons/settings/AddonSettings.cpp index caaa117912..4fa4445e3d 100644 --- a/xbmc/addons/settings/AddonSettings.cpp +++ b/xbmc/addons/settings/AddonSettings.cpp @@ -430,11 +430,10 @@ bool CAddonSettings::ParseSettingVersion(const CXBMCTinyXML& doc, uint32_t& vers return true; } -std::shared_ptr<CSettingGroup> CAddonSettings::ParseOldSettingElement(const TiXmlElement* categoryElement, std::shared_ptr<CSettingCategory> category, std::set<std::string>& actionSettings) +std::shared_ptr<CSettingGroup> CAddonSettings::ParseOldSettingElement(const TiXmlElement* categoryElement, std::shared_ptr<CSettingCategory> category, std::set<std::string>& actionSettings, std::set<std::string>& settingIds) { // build a vector of settings from the same category std::vector<std::shared_ptr<const CSetting>> categorySettings; - std::set<std::string> settingIds; // prepare for settings with enable/visible conditions struct SettingWithConditions { @@ -593,9 +592,11 @@ std::shared_ptr<CSettingGroup> CAddonSettings::ParseOldSettingElement(const TiXm // turn the setting into a reference setting setting = std::make_shared<CSettingReference>(settingId, GetSettingsManager()); } - - // add the setting's identifier to the list of all identifiers - settingIds.insert(setting->GetId()); + else + { + // add the setting's identifier to the list of all identifiers + settingIds.insert(setting->GetId()); + } // add the setting to the list of settings from the same category categorySettings.push_back(setting); @@ -646,7 +647,7 @@ std::shared_ptr<CSettingGroup> CAddonSettings::ParseOldSettingElement(const TiXm return group; } -std::shared_ptr<CSettingCategory> CAddonSettings::ParseOldCategoryElement(uint32_t &categoryId, const TiXmlElement * categoryElement, std::set<std::string> &actionSettings) +std::shared_ptr<CSettingCategory> CAddonSettings::ParseOldCategoryElement(uint32_t &categoryId, const TiXmlElement * categoryElement, std::set<std::string> &actionSettings, std::set<std::string> &settingIds) { // create the category auto category = std::make_shared<CSettingCategory>(StringUtils::Format("category%u", categoryId), GetSettingsManager()); @@ -658,7 +659,7 @@ std::shared_ptr<CSettingCategory> CAddonSettings::ParseOldCategoryElement(uint32 category->SetLabel(categoryLabel); // prepare a setting group - auto group = ParseOldSettingElement(categoryElement, category, actionSettings); + auto group = ParseOldSettingElement(categoryElement, category, actionSettings, settingIds); // add the group to the category category->AddGroup(group); @@ -680,14 +681,16 @@ bool CAddonSettings::InitializeFromOldSettingDefinitions(const CXBMCTinyXML& doc uint32_t categoryId = 0; std::set<std::string> actionSettings; + // Settings id set + std::set<std::string> settingIds; // Special case for no category settings - section->AddCategory(ParseOldCategoryElement(categoryId, root, actionSettings)); + section->AddCategory(ParseOldCategoryElement(categoryId, root, actionSettings, settingIds)); const TiXmlElement *categoryElement = root->FirstChildElement("category"); while (categoryElement != nullptr) { - section->AddCategory(ParseOldCategoryElement(categoryId, categoryElement, actionSettings)); + section->AddCategory(ParseOldCategoryElement(categoryId, categoryElement, actionSettings, settingIds)); // look for the next category categoryElement = categoryElement->NextSiblingElement("category"); @@ -1316,20 +1319,21 @@ bool CAddonSettings::ParseOldLabel(const TiXmlElement* element, const std::strin labelId = -1; if (element == nullptr) return false; + + // label value as a string + std::string labelString; + element->QueryStringAttribute("label", &labelString); - // try to parse the label as a translation number - if (element->QueryIntAttribute("label", &labelId) == TIXML_SUCCESS && labelId >= 0) - return true; - std::string labelString; + // try to parse the label as a pure number, i.e. a localized string + char *endptr; + labelId = std::strtol(labelString.c_str(), &endptr, 10); + if (endptr == nullptr || *endptr == '\0') + return true; - // try to parse the label as a string - const auto labelStringPtr = element->Attribute("label"); - if (labelStringPtr != nullptr) - labelString = labelStringPtr; - bool parsed = !labelString.empty(); // as a last resort use the setting's identifier as a label + bool parsed = !labelString.empty(); if (!parsed) labelString = settingId; diff --git a/xbmc/addons/settings/AddonSettings.h b/xbmc/addons/settings/AddonSettings.h index d4f52b82e8..fbf546a85a 100644 --- a/xbmc/addons/settings/AddonSettings.h +++ b/xbmc/addons/settings/AddonSettings.h @@ -74,9 +74,9 @@ namespace ADDON bool ParseSettingVersion(const CXBMCTinyXML& doc, uint32_t& version) const; - std::shared_ptr<CSettingGroup> ParseOldSettingElement(const TiXmlElement *categoryElement, std::shared_ptr<CSettingCategory> category, std::set<std::string>& actionSettings); + std::shared_ptr<CSettingGroup> ParseOldSettingElement(const TiXmlElement *categoryElement, std::shared_ptr<CSettingCategory> category, std::set<std::string>& actionSettings, std::set<std::string>& settingIds); - std::shared_ptr<CSettingCategory> ParseOldCategoryElement(uint32_t &categoryId, const TiXmlElement * categoryElement, std::set<std::string> &actionSettings); + std::shared_ptr<CSettingCategory> ParseOldCategoryElement(uint32_t &categoryId, const TiXmlElement * categoryElement, std::set<std::string> &actionSettings, std::set<std::string>& settingIds); bool InitializeFromOldSettingDefinitions(const CXBMCTinyXML& doc); std::shared_ptr<CSetting> InitializeFromOldSettingAction(std::string settingId, const TiXmlElement *settingElement, const std::string& defaultValue); diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp index 8362851119..b8b3be7c72 100644 --- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp +++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp @@ -171,33 +171,21 @@ jni::CJNIAudioTrack *CAESinkAUDIOTRACK::CreateAudioTrack(int stream, int sampleR try { - if (CJNIBase::GetSDKVersion() >= 21) - { - CJNIAudioAttributesBuilder attrBuilder; - attrBuilder.setUsage(CJNIAudioAttributes::USAGE_MEDIA); - attrBuilder.setContentType(CJNIAudioAttributes::CONTENT_TYPE_MUSIC); - attrBuilder.setLegacyStreamType(CJNIAudioManager::STREAM_MUSIC); - - CJNIAudioFormatBuilder fmtBuilder; - fmtBuilder.setChannelMask(channelMask); - fmtBuilder.setEncoding(encoding); - fmtBuilder.setSampleRate(sampleRate); - - jniAt = new CJNIAudioTrack(attrBuilder.build(), - fmtBuilder.build(), - bufferSize, - CJNIAudioTrack::MODE_STREAM, - CJNIAudioManager::AUDIO_SESSION_ID_GENERATE); - } - else - { - jniAt = new CJNIAudioTrack(stream, - sampleRate, - channelMask, - encoding, - bufferSize, - CJNIAudioTrack::MODE_STREAM); - } + CJNIAudioAttributesBuilder attrBuilder; + attrBuilder.setUsage(CJNIAudioAttributes::USAGE_MEDIA); + attrBuilder.setContentType(CJNIAudioAttributes::CONTENT_TYPE_MUSIC); + attrBuilder.setLegacyStreamType(CJNIAudioManager::STREAM_MUSIC); + + CJNIAudioFormatBuilder fmtBuilder; + fmtBuilder.setChannelMask(channelMask); + fmtBuilder.setEncoding(encoding); + fmtBuilder.setSampleRate(sampleRate); + + jniAt = new CJNIAudioTrack(attrBuilder.build(), + fmtBuilder.build(), + bufferSize, + CJNIAudioTrack::MODE_STREAM, + CJNIAudioManager::AUDIO_SESSION_ID_GENERATE); } catch (const std::invalid_argument& e) { diff --git a/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp b/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp index aea3242ad0..5546f6ecdc 100644 --- a/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp +++ b/xbmc/cores/DllLoader/exports/emu_msvcrt.cpp @@ -2043,66 +2043,6 @@ extern "C" #endif } -#if _MSC_VER < 1900 - int dll_filbuf(FILE *fp) - { - if (fp == NULL) - return EOF; - - if(IS_STD_STREAM(fp)) - return EOF; - - CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(fp); - if (pFile) - { - unsigned char data; - if(pFile->Read(&data, 1) == 1) - { - pFile->Seek(-1, SEEK_CUR); - return (int)data; - } - else - return EOF; - } -#ifdef TARGET_POSIX - return EOF; -#else - return _filbuf(fp); -#endif - } - - int dll_flsbuf(int data, FILE *fp) - { - if (fp == NULL) - return EOF; - - if(IS_STDERR_STREAM(fp) || IS_STDOUT_STREAM(fp)) - { - CLog::Log(LOGDEBUG, "dll_flsbuf() - %c", data); - return data; - } - - if(IS_STD_STREAM(fp)) - return EOF; - - CFile* pFile = g_emuFileWrapper.GetFileXbmcByStream(fp); - if (pFile) - { - pFile->Flush(); - unsigned char c = (unsigned char)data; - if(pFile->Write(&c, 1) == 1) - return data; - else - return EOF; - } -#ifdef TARGET_POSIX - return EOF; -#else - return _flsbuf(data, fp); -#endif - } - -#endif // this needs to be wrapped, since dll's have their own file // descriptor list, but we always use app's list with our wrappers int __cdecl dll_open_osfhandle(intptr_t _OSFileHandle, int _Flags) diff --git a/xbmc/cores/DllLoader/exports/emu_msvcrt.h b/xbmc/cores/DllLoader/exports/emu_msvcrt.h index 7319240036..eb30c44f09 100644 --- a/xbmc/cores/DllLoader/exports/emu_msvcrt.h +++ b/xbmc/cores/DllLoader/exports/emu_msvcrt.h @@ -151,11 +151,6 @@ extern "C" #endif int dll_setvbuf(FILE *stream, char *buf, int type, size_t size); -#if _MSC_VER < 1900 - int dll_filbuf(FILE *fp); - int dll_flsbuf(int data, FILE*fp); -#endif - #if defined(TARGET_ANDROID) volatile int * __cdecl dll_errno(void); #elif defined(TARGET_POSIX) diff --git a/xbmc/cores/DllLoader/ldt_keeper.c b/xbmc/cores/DllLoader/ldt_keeper.c index def83a01dd..0e6bc81bf7 100644 --- a/xbmc/cores/DllLoader/ldt_keeper.c +++ b/xbmc/cores/DllLoader/ldt_keeper.c @@ -49,16 +49,11 @@ #ifdef __cplusplus extern "C" { #endif -/* declare modify_ldt with the _syscall3 macro for older glibcs */ -#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)) -_syscall3( int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount ); -#else #if defined(TARGET_ANDROID) && defined(__i386__) && !defined(modify_ldt) #define modify_ldt(a,b,c) syscall( __NR_modify_ldt, a, b, c); #else int modify_ldt(int func, void *ptr, unsigned long bytecount); #endif -#endif #ifdef __cplusplus } #endif diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp index 348a1dc1bb..82bf70596b 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AMLCodec.cpp @@ -2206,8 +2206,8 @@ void CAMLCodec::SetVideoZoom(const float zoom) void CAMLCodec::SetVideoContrast(const int contrast) { // input contrast range is 0 to 100 with default of 50. - // output contrast range is -255 to 255 with default of 0. - int aml_contrast = (255 * (contrast - 50)) / 50; + // output contrast range is -127 to 127 with default of 0. + int aml_contrast = (127 * (contrast - 50)) / 50; SysfsUtils::SetInt("/sys/class/video/contrast", aml_contrast); } void CAMLCodec::SetVideoBrightness(const int brightness) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.cpp index b86f820ef5..06fe701c66 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/AddonVideoCodec.cpp @@ -32,7 +32,6 @@ CAddonVideoCodec::CAddonVideoCodec(CProcessInfo &processInfo, ADDON::BinaryAddon CLog::Log(LOGERROR, "CInputStreamAddon: Failed to create add-on instance for '%s'", addonInfo->ID().c_str()); return; } - m_processInfo.SetVideoDecoderName(GetName(), false); } CAddonVideoCodec::~CAddonVideoCodec() @@ -142,7 +141,10 @@ bool CAddonVideoCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) if (!CopyToInitData(initData, hints)) return false; - return m_struct.toAddon.open(&m_struct, &initData); + bool ret = m_struct.toAddon.open(&m_struct, &initData); + m_processInfo.SetVideoDecoderName(GetName(), false); + + return ret; } bool CAddonVideoCodec::Reconfigure(CDVDStreamInfo &hints) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp index c725dbc04d..3588eeda89 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp @@ -340,9 +340,11 @@ CDVDVideoCodecAndroidMediaCodec::CDVDVideoCodecAndroidMediaCodec(CProcessInfo &p , m_OutputDuration(0) , m_fpsDuration(0) , m_lastPTS(-1) +, m_dtsShift(DVD_NOPTS_VALUE) , m_bitstream(nullptr) , m_render_surface(surface_render) , m_mpeg2_sequence(nullptr) +, m_useDTSforPTS(false) { m_videobuffer.Reset(); } @@ -416,6 +418,8 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio m_codecControlFlags = 0; m_hints = hints; m_indexInputBuffer = -1; + m_dtsShift = DVD_NOPTS_VALUE; + m_useDTSforPTS = false; CLog::Log(LOGDEBUG, LOGVIDEO, "CDVDVideoCodecAndroidMediaCodec::Open hints: fpsrate %d / fpsscale %d\n", m_hints.fpsrate, m_hints.fpsscale); CLog::Log(LOGDEBUG, LOGVIDEO, "CDVDVideoCodecAndroidMediaCodec::Open hints: CodecID %d \n", m_hints.codec); @@ -436,13 +440,13 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio m_mpeg2_sequence->ratio = m_hints.aspect; m_mpeg2_sequence->fps_scale = m_hints.fpsscale; m_mpeg2_sequence->fps_rate = m_hints.fpsrate; + m_useDTSforPTS = true; m_formatname = "amc-mpeg2"; break; case AV_CODEC_ID_MPEG4: - if (hints.width <= 800) - goto FAIL; m_mime = "video/mp4v-es"; m_formatname = "amc-mpeg4"; + m_useDTSforPTS = true; break; case AV_CODEC_ID_H263: m_mime = "video/3gpp"; @@ -711,6 +715,11 @@ bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptio if (!ConfigureMediaCodec()) goto FAIL; + if (m_codecname.find("OMX", 0, 3) == 0) + m_invalidPTSValue = AV_NOPTS_VALUE; + else + m_invalidPTSValue = 0; + CLog::Log(LOGINFO, "CDVDVideoCodecAndroidMediaCodec:: " "Open Android MediaCodec %s", m_codecname.c_str()); @@ -898,11 +907,17 @@ bool CDVDVideoCodecAndroidMediaCodec::AddData(const DemuxPacket &packet) // Do not try to pass pts as a unioned double/int64_t, // some android devices will diddle with presentationTimeUs // and you will get NaN back and VideoPlayerVideo will barf. - int64_t presentationTimeUs = 0; + if (m_dtsShift == DVD_NOPTS_VALUE) + m_dtsShift = (dts == DVD_NOPTS_VALUE) ? 0 : dts; + + int64_t presentationTimeUs = m_invalidPTSValue; if (pts != DVD_NOPTS_VALUE) - presentationTimeUs = pts; - else if (dts != DVD_NOPTS_VALUE) - presentationTimeUs = dts; + { + presentationTimeUs = (pts - m_dtsShift); + m_useDTSforPTS = false; + } + else if (m_useDTSforPTS && dts != DVD_NOPTS_VALUE) + presentationTimeUs = (dts - m_dtsShift); int flags = 0; int offset = 0; @@ -1038,6 +1053,7 @@ void CDVDVideoCodecAndroidMediaCodec::FlushInternal() // new ones to match the number of output buffers m_OutputDuration = 0; m_lastPTS = -1; + m_dtsShift = DVD_NOPTS_VALUE; } bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) @@ -1133,6 +1149,7 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void) if (pts != AV_NOPTS_VALUE) { m_videobuffer.pts = pts; + m_videobuffer.pts += m_dtsShift; if (m_lastPTS >= 0 && pts > m_lastPTS) m_OutputDuration += pts - m_lastPTS; m_lastPTS = pts; diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h index 7745b376bf..4f1cab8e88 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h @@ -171,6 +171,8 @@ protected: uint32_t m_OutputDuration, m_fpsDuration; int64_t m_lastPTS; + int64_t m_invalidPTSValue = 0; + double m_dtsShift; static std::atomic<bool> m_InstanceGuard; @@ -182,6 +184,7 @@ protected: mpeg2_sequence *m_mpeg2_sequence; int m_src_offset[4]; int m_src_stride[4]; + bool m_useDTSforPTS; // CJNISurfaceHolderCallback interface public: diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp index 585716704a..dca8ddf7d7 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp @@ -552,7 +552,9 @@ bool CDXVAContext::CreateSurfaces(const D3D11_VIDEO_DECODER_DESC &format, const vdovDesc.DecodeProfile = format.Guid; vdovDesc.Texture2D.ArraySlice = 0; vdovDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D; - float clearColor[] = { 0.0625f, 0.5f, 0.5f, 1.0f }; // black color in YUV + // For video views with YUV or YCbBr formats, ClearView doesn't + // convert color values but assumes UINT texture format + float clearColor[] = { 16.f, 127.f, 127.f, 255.f }; // black color in YUV size_t i; for (i = 0; i < count; ++i) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp index f17e509417..63d4c573be 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp @@ -720,10 +720,6 @@ CDVDVideoCodec::VCReturn CMMALVideo::GetPicture(VideoPicture* picture) bool drain = (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN) ? true : false; bool send_eos = drain && !m_got_eos && m_packet_num_eos != m_packet_num; - if (picture->videoBuffer) - picture->videoBuffer->Release(); - picture->videoBuffer = nullptr; - // we don't get an EOS response if no packets have been sent if (!drain) m_got_eos = false; @@ -799,6 +795,8 @@ CDVDVideoCodec::VCReturn CMMALVideo::GetPicture(VideoPicture* picture) if (ret == CDVDVideoCodec::VC_PICTURE) { assert(buffer && buffer->mmal_buffer); + if (picture->videoBuffer) + picture->videoBuffer->Release(); picture->videoBuffer = dynamic_cast<CVideoBuffer*>(buffer); assert(picture->videoBuffer); picture->color_range = 0; diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp index 6ce18e26e4..730500fab6 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp @@ -58,6 +58,16 @@ const std::string SETTING_VIDEOPLAYER_USEVAAPIVP8 = "videoplayer.usevaapivp8"; const std::string SETTING_VIDEOPLAYER_USEVAAPIVP9 = "videoplayer.usevaapivp9"; const std::string SETTING_VIDEOPLAYER_PREFERVAAPIRENDER = "videoplayer.prefervaapirender"; +void VAAPI::VaErrorCallback(void *user_context, const char *message) +{ + CLog::Log(LOGERROR, "libva error: {}", message); +} + +void VAAPI::VaInfoCallback(void *user_context, const char *message) +{ + CLog::Log(LOGDEBUG, "libva info: {}", message); +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -188,6 +198,11 @@ bool CVAAPIContext::CreateContext() return false; } +#if VA_CHECK_VERSION(1, 0, 0) + vaSetErrorCallback(m_display, VaErrorCallback, nullptr); + vaSetInfoCallback(m_display, VaInfoCallback, nullptr); +#endif + int major_version, minor_version; if (!CheckSuccess(vaInitialize(m_display, &major_version, &minor_version))) { @@ -211,6 +226,11 @@ void CVAAPIContext::DestroyContext() delete[] m_profiles; if (m_display) CheckSuccess(vaTerminate(m_display)); + +#if VA_CHECK_VERSION(1, 0, 0) + vaSetErrorCallback(m_display, nullptr, nullptr); + vaSetInfoCallback(m_display, nullptr, nullptr); +#endif } void CVAAPIContext::QueryCaps() diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h index 1ab751fe54..73e4d98308 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h @@ -38,6 +38,9 @@ class CProcessInfo; namespace VAAPI { +void VaErrorCallback(void *user_context, const char *message); +void VaInfoCallback(void *user_context, const char *message); + //----------------------------------------------------------------------------- // VAAPI data structs //----------------------------------------------------------------------------- diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp index ac6e04b548..f999fa679f 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp @@ -639,13 +639,16 @@ void CDVDDemuxClient::OpenStream(int id) { // OpenStream may change some parameters // in this case we need to reset our stream properties - if (m_IDemux && m_IDemux->OpenStream(id)) + if (m_IDemux) { + bool bOpenStream = m_IDemux->OpenStream(id); + CDemuxStream *stream(m_IDemux->GetStream(id)); if (stream && stream->type == STREAM_VIDEO) m_videoStreamPlaying = id; - SetStreamProps(stream, m_streams, true); + if (bOpenStream) + SetStreamProps(stream, m_streams, true); } } diff --git a/xbmc/cores/VideoPlayer/Edl.cpp b/xbmc/cores/VideoPlayer/Edl.cpp index 900a0ffcde..09023321c9 100644 --- a/xbmc/cores/VideoPlayer/Edl.cpp +++ b/xbmc/cores/VideoPlayer/Edl.cpp @@ -89,11 +89,10 @@ bool CEdl::ReadEditDecisionLists(const CFileItem& fileItem, const float fFrameRa */ const std::string strMovie = fileItem.GetDynPath(); if ((URIUtils::IsHD(strMovie) || URIUtils::IsOnLAN(strMovie)) && - !fileItem.IsPVRRecording() && !URIUtils::IsInternetStream(strMovie)) { CLog::Log(LOGDEBUG, "%s - Checking for edit decision lists (EDL) on local drive or remote share for: %s", - __FUNCTION__, strMovie.c_str()); + __FUNCTION__, CURL::GetRedacted(strMovie).c_str()); /* * Read any available file format until a valid EDL related file is found. @@ -117,14 +116,14 @@ bool CEdl::ReadEditDecisionLists(const CFileItem& fileItem, const float fFrameRa else if (fileItem.IsPVRRecording()) { CLog::Log(LOGDEBUG, "%s - Checking for edit decision list (EDL) for PVR recording: %s", - __FUNCTION__, strMovie.c_str()); + __FUNCTION__, CURL::GetRedacted(strMovie).c_str()); bFound = ReadPvr(fileItem); } else if (fileItem.IsEPG()) { CLog::Log(LOGDEBUG, "%s - Checking for edit decision list (EDL) for EPG entry: %s", - __FUNCTION__, strMovie.c_str()); + __FUNCTION__, CURL::GetRedacted(strMovie).c_str()); bFound = ReadPvr(fileItem); } @@ -146,7 +145,7 @@ bool CEdl::ReadEdl(const std::string& strMovie, const float fFramesPerSecond) CFile edlFile; if (!edlFile.Open(edlFilename)) { - CLog::Log(LOGERROR, "%s - Could not open EDL file: %s", __FUNCTION__, edlFilename.c_str()); + CLog::Log(LOGERROR, "%s - Could not open EDL file: %s", __FUNCTION__, CURL::GetRedacted(edlFilename).c_str()); return false; } @@ -158,7 +157,7 @@ bool CEdl::ReadEdl(const std::string& strMovie, const float fFramesPerSecond) { // Log any errors from previous run in the loop if (bError) - CLog::Log(LOGWARNING, "%s - Error on line %i in EDL file: %s", __FUNCTION__, iLine, edlFilename.c_str()); + CLog::Log(LOGWARNING, "%s - Error on line %i in EDL file: %s", __FUNCTION__, iLine, CURL::GetRedacted(edlFilename).c_str()); bError = false; @@ -248,7 +247,7 @@ bool CEdl::ReadEdl(const std::string& strMovie, const float fFramesPerSecond) if (!AddCut(cut)) { CLog::Log(LOGWARNING, "%s - Error adding cut from line %i in EDL file: %s", __FUNCTION__, - iLine, edlFilename.c_str()); + iLine, CURL::GetRedacted(edlFilename).c_str()); continue; } break; @@ -257,7 +256,7 @@ bool CEdl::ReadEdl(const std::string& strMovie, const float fFramesPerSecond) if (!AddCut(cut)) { CLog::Log(LOGWARNING, "%s - Error adding mute from line %i in EDL file: %s", __FUNCTION__, - iLine, edlFilename.c_str()); + iLine, CURL::GetRedacted(edlFilename).c_str()); continue; } break; @@ -265,7 +264,7 @@ bool CEdl::ReadEdl(const std::string& strMovie, const float fFramesPerSecond) if (!AddSceneMarker(cut.end)) { CLog::Log(LOGWARNING, "%s - Error adding scene marker from line %i in EDL file: %s", - __FUNCTION__, iLine, edlFilename.c_str()); + __FUNCTION__, iLine, CURL::GetRedacted(edlFilename).c_str()); continue; } break; @@ -274,32 +273,32 @@ bool CEdl::ReadEdl(const std::string& strMovie, const float fFramesPerSecond) if (!AddCut(cut)) { CLog::Log(LOGWARNING, "%s - Error adding commercial break from line %i in EDL file: %s", - __FUNCTION__, iLine, edlFilename.c_str()); + __FUNCTION__, iLine, CURL::GetRedacted(edlFilename).c_str()); continue; } break; default: CLog::Log(LOGWARNING, "%s - Invalid action on line %i in EDL file: %s", __FUNCTION__, iLine, - edlFilename.c_str()); + CURL::GetRedacted(edlFilename).c_str()); continue; } } if (bError) // Log last line warning, if there was one, since while loop will have terminated. - CLog::Log(LOGWARNING, "%s - Error on line %i in EDL file: %s", __FUNCTION__, iLine, edlFilename.c_str()); + CLog::Log(LOGWARNING, "%s - Error on line %i in EDL file: %s", __FUNCTION__, iLine, CURL::GetRedacted(edlFilename).c_str()); edlFile.Close(); if (HasCut() || HasSceneMarker()) { CLog::Log(LOGDEBUG, "{0} - Read {1} cuts and {2} scene markers in EDL file: {3}", __FUNCTION__, - m_vecCuts.size(), m_vecSceneMarkers.size(), edlFilename.c_str()); + m_vecCuts.size(), m_vecSceneMarkers.size(), CURL::GetRedacted(edlFilename).c_str()); return true; } else { CLog::Log(LOGDEBUG, "%s - No cuts or scene markers found in EDL file: %s", __FUNCTION__, - edlFilename.c_str()); + CURL::GetRedacted(edlFilename).c_str()); return false; } } @@ -315,7 +314,7 @@ bool CEdl::ReadComskip(const std::string& strMovie, const float fFramesPerSecond CFile comskipFile; if (!comskipFile.Open(comskipFilename)) { - CLog::Log(LOGERROR, "%s - Could not open Comskip file: %s", __FUNCTION__, comskipFilename.c_str()); + CLog::Log(LOGERROR, "%s - Could not open Comskip file: %s", __FUNCTION__, CURL::GetRedacted(comskipFilename).c_str()); return false; } @@ -324,7 +323,7 @@ bool CEdl::ReadComskip(const std::string& strMovie, const float fFramesPerSecond && strncmp(szBuffer, COMSKIP_HEADER, strlen(COMSKIP_HEADER)) != 0) // Line 1. { CLog::Log(LOGERROR, "%s - Invalid Comskip file: %s. Error reading line 1 - expected '%s' at start.", - __FUNCTION__, comskipFilename.c_str(), COMSKIP_HEADER); + __FUNCTION__, CURL::GetRedacted(comskipFilename).c_str(), COMSKIP_HEADER); comskipFile.Close(); return false; } @@ -367,19 +366,19 @@ bool CEdl::ReadComskip(const std::string& strMovie, const float fFramesPerSecond if (!bValid) { CLog::Log(LOGERROR, "%s - Invalid Comskip file: %s. Error on line %i. Clearing any valid commercial breaks found.", - __FUNCTION__, comskipFilename.c_str(), iLine); + __FUNCTION__, CURL::GetRedacted(comskipFilename).c_str(), iLine); Clear(); return false; } else if (HasCut()) { CLog::Log(LOGDEBUG, "{0} - Read {1} commercial breaks from Comskip file: {2}", __FUNCTION__, m_vecCuts.size(), - comskipFilename.c_str()); + CURL::GetRedacted(comskipFilename).c_str()); return true; } else { - CLog::Log(LOGDEBUG, "%s - No commercial breaks found in Comskip file: %s", __FUNCTION__, comskipFilename.c_str()); + CLog::Log(LOGDEBUG, "%s - No commercial breaks found in Comskip file: %s", __FUNCTION__, CURL::GetRedacted(comskipFilename).c_str()); return false; } } @@ -400,7 +399,7 @@ bool CEdl::ReadVideoReDo(const std::string& strMovie) CFile videoReDoFile; if (!videoReDoFile.Open(videoReDoFilename)) { - CLog::Log(LOGERROR, "%s - Could not open VideoReDo file: %s", __FUNCTION__, videoReDoFilename.c_str()); + CLog::Log(LOGERROR, "%s - Could not open VideoReDo file: %s", __FUNCTION__, CURL::GetRedacted(videoReDoFilename).c_str()); return false; } @@ -409,7 +408,7 @@ bool CEdl::ReadVideoReDo(const std::string& strMovie) && strncmp(szBuffer, VIDEOREDO_HEADER, strlen(VIDEOREDO_HEADER)) != 0) { CLog::Log(LOGERROR, "%s - Invalid VideoReDo file: %s. Error reading line 1 - expected %s. Only version 2 files are supported.", - __FUNCTION__, videoReDoFilename.c_str(), VIDEOREDO_HEADER); + __FUNCTION__, CURL::GetRedacted(videoReDoFilename).c_str(), VIDEOREDO_HEADER); videoReDoFile.Close(); return false; } @@ -457,20 +456,20 @@ bool CEdl::ReadVideoReDo(const std::string& strMovie) if (!bValid) { CLog::Log(LOGERROR, "%s - Invalid VideoReDo file: %s. Error in line %i. Clearing any valid cuts or scenes found.", - __FUNCTION__, videoReDoFilename.c_str(), iLine); + __FUNCTION__, CURL::GetRedacted(videoReDoFilename).c_str(), iLine); Clear(); return false; } else if (HasCut() || HasSceneMarker()) { CLog::Log(LOGDEBUG, "{0} - Read {1} cuts and {2} scene markers in VideoReDo file: {3}", __FUNCTION__, - m_vecCuts.size(), m_vecSceneMarkers.size(), videoReDoFilename.c_str()); + m_vecCuts.size(), m_vecSceneMarkers.size(), CURL::GetRedacted(videoReDoFilename).c_str()); return true; } else { CLog::Log(LOGDEBUG, "%s - No cuts or scene markers found in VideoReDo file: %s", __FUNCTION__, - videoReDoFilename.c_str()); + CURL::GetRedacted(videoReDoFilename).c_str()); return false; } } @@ -486,14 +485,14 @@ bool CEdl::ReadBeyondTV(const std::string& strMovie) CXBMCTinyXML xmlDoc; if (!xmlDoc.LoadFile(beyondTVFilename)) { - CLog::Log(LOGERROR, "%s - Could not load Beyond TV file: %s. %s", __FUNCTION__, beyondTVFilename.c_str(), + CLog::Log(LOGERROR, "%s - Could not load Beyond TV file: %s. %s", __FUNCTION__, CURL::GetRedacted(beyondTVFilename).c_str(), xmlDoc.ErrorDesc()); return false; } if (xmlDoc.Error()) { - CLog::Log(LOGERROR, "%s - Could not parse Beyond TV file: %s. %s", __FUNCTION__, beyondTVFilename.c_str(), + CLog::Log(LOGERROR, "%s - Could not parse Beyond TV file: %s. %s", __FUNCTION__, CURL::GetRedacted(beyondTVFilename).c_str(), xmlDoc.ErrorDesc()); return false; } @@ -502,7 +501,7 @@ bool CEdl::ReadBeyondTV(const std::string& strMovie) if (!pRoot || strcmp(pRoot->Value(), "cutlist")) { CLog::Log(LOGERROR, "%s - Invalid Beyond TV file: %s. Expected root node to be <cutlist>", __FUNCTION__, - beyondTVFilename.c_str()); + CURL::GetRedacted(beyondTVFilename).c_str()); return false; } @@ -540,20 +539,20 @@ bool CEdl::ReadBeyondTV(const std::string& strMovie) if (!bValid) { CLog::Log(LOGERROR, "%s - Invalid Beyond TV file: %s. Clearing any valid commercial breaks found.", __FUNCTION__, - beyondTVFilename.c_str()); + CURL::GetRedacted(beyondTVFilename).c_str()); Clear(); return false; } else if (HasCut()) { CLog::Log(LOGDEBUG, "{0} - Read {1} commercial breaks from Beyond TV file: {2}", __FUNCTION__, m_vecCuts.size(), - beyondTVFilename.c_str()); + CURL::GetRedacted(beyondTVFilename).c_str()); return true; } else { CLog::Log(LOGDEBUG, "%s - No commercial breaks found in Beyond TV file: %s", __FUNCTION__, - beyondTVFilename.c_str()); + CURL::GetRedacted(beyondTVFilename).c_str()); return false; } } @@ -563,7 +562,7 @@ bool CEdl::ReadPvr(const CFileItem &fileItem) const std::string strMovie = fileItem.GetDynPath(); if (!CServiceBroker::GetPVRManager().IsStarted()) { - CLog::Log(LOGERROR, "%s - PVR Manager not started, cannot read Edl for %s", __FUNCTION__, strMovie.c_str()); + CLog::Log(LOGERROR, "%s - PVR Manager not started, cannot read Edl for %s", __FUNCTION__, CURL::GetRedacted(strMovie).c_str()); return false; } @@ -581,7 +580,7 @@ bool CEdl::ReadPvr(const CFileItem &fileItem) } else { - CLog::Log(LOGERROR, "%s - Unknown file item type : %s", __FUNCTION__, strMovie.c_str()); + CLog::Log(LOGERROR, "%s - Unknown file item type : %s", __FUNCTION__, CURL::GetRedacted(strMovie).c_str()); return false; } @@ -618,13 +617,13 @@ bool CEdl::ReadPvr(const CFileItem &fileItem) { CLog::Log(LOGDEBUG, "%s - Added break [%s - %s] found in PVRRecording for: %s.", __FUNCTION__, MillisecondsToTimeString(cut.start).c_str(), - MillisecondsToTimeString(cut.end).c_str(), strMovie.c_str()); + MillisecondsToTimeString(cut.end).c_str(), CURL::GetRedacted(strMovie).c_str()); } else { CLog::Log(LOGERROR, "%s - Invalid break [%s - %s] found in PVRRecording for: %s. Continuing anyway.", __FUNCTION__, MillisecondsToTimeString(cut.start).c_str(), - MillisecondsToTimeString(cut.end).c_str(), strMovie.c_str()); + MillisecondsToTimeString(cut.end).c_str(), CURL::GetRedacted(strMovie).c_str()); } } diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp index 391703dd77..200b53c100 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp @@ -813,7 +813,7 @@ bool CVideoPlayer::OpenInputStream() { // find any available external subtitles std::vector<std::string> filenames; - CUtil::ScanForExternalSubtitles(m_item.GetPath(), filenames); + CUtil::ScanForExternalSubtitles(m_item.GetDynPath(), filenames); // load any subtitles from file item std::string key("subtitle:1"); @@ -1809,10 +1809,10 @@ bool CVideoPlayer::GetCachingTimes(double& level, double& delay, double& offset) if (!m_pInputStream->GetCacheStatus(&status)) return false; - uint64_t &cached = status.forward; - unsigned &currate = status.currate; - unsigned &maxrate = status.maxrate; - float &cache_level = status.level; + const uint64_t &cached = status.forward; + const unsigned &currate = status.currate; + const unsigned &maxrate = status.maxrate; + const bool &lowspeed = status.lowspeed; int64_t length = m_pInputStream->GetLength(); int64_t remain = length - m_pInputStream->Seek(0, SEEK_CUR); @@ -1837,13 +1837,7 @@ bool CVideoPlayer::GetCachingTimes(double& level, double& delay, double& offset) delay = cache_left - play_left; - /* NOTE: We can only reliably test for low readrate, when the cache is not - * already *near* full. This is because as soon as it's full the average- - * rate will become approximately the current-rate which can flag false - * low read-rate conditions. To work around this we don't check the currate at 100% - * but between 80% and 90% - */ - if (cache_level > 0.8 && cache_level < 0.9 && currate < maxrate) + if (lowspeed) { CLog::Log(LOGDEBUG, "Readrate %u is too low with %u required", currate, maxrate); level = -1.0; /* buffer is full & our read rate is too low */ @@ -3677,6 +3671,8 @@ bool CVideoPlayer::OpenAudioStream(CDVDStreamInfo& hint, bool reset) if (!player->OpenStream(hint)) return false; + player->SendMessage(new CDVDMsgBool(CDVDMsg::GENERAL_PAUSE, m_displayLost), 1); + static_cast<IDVDStreamPlayerAudio*>(player)->SetSpeed(m_streamPlayerSpeed); m_CurrentAudio.syncState = IDVDStreamPlayer::SYNC_STARTING; m_CurrentAudio.packets = 0; @@ -3766,6 +3762,8 @@ bool CVideoPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset) if (!player->OpenStream(hint)) return false; + player->SendMessage(new CDVDMsgBool(CDVDMsg::GENERAL_PAUSE, m_displayLost), 1); + // look for any EDL files m_Edl.Clear(); if (hint.fpsrate > 0 && hint.fpsscale > 0) @@ -4446,6 +4444,8 @@ bool CVideoPlayer::OnAction(const CAction &action) } } + pMenus.reset(); + switch (action.GetID()) { case ACTION_NEXT_ITEM: @@ -5018,6 +5018,9 @@ void CVideoPlayer::OnLostDisplay() void CVideoPlayer::OnResetDisplay() { + if (!m_displayLost) + return; + CLog::Log(LOGNOTICE, "VideoPlayer: OnResetDisplay received"); m_VideoPlayerAudio->SendMessage(new CDVDMsgBool(CDVDMsg::GENERAL_PAUSE, false), 1); m_VideoPlayerVideo->SendMessage(new CDVDMsgBool(CDVDMsg::GENERAL_PAUSE, false), 1); diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp index 6202e66dab..99e0356121 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp @@ -172,11 +172,12 @@ CMMALPool::~CMMALPool() CLog::Log(LOGERROR, "%s::%s Failed to disable component %s (status=%x %s)", CLASSNAME, __func__, m_component->name, status, mmal_status_to_string(status)); } + mmal_port_pool_destroy(port, m_mmal_pool); + if (m_component) mmal_component_destroy(m_component); m_component = nullptr; - mmal_port_pool_destroy(port, m_mmal_pool); m_mmal_pool = nullptr; for (auto buf : m_all) { diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.cpp index fe5fa42b3f..c545374a54 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererAML.cpp @@ -119,6 +119,7 @@ bool CRendererAML::Supports(ERENDERFEATURE feature) feature == RENDERFEATURE_CONTRAST || feature == RENDERFEATURE_BRIGHTNESS || feature == RENDERFEATURE_NONLINSTRETCH || + feature == RENDERFEATURE_VERTICAL_SHIFT || feature == RENDERFEATURE_STRETCH || feature == RENDERFEATURE_PIXEL_RATIO || feature == RENDERFEATURE_ROTATION) diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp index 24fef46672..295b269c82 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIME.cpp @@ -38,7 +38,7 @@ CBaseRenderer* CRendererDRMPRIME::Create(CVideoBuffer* buffer) CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(SETTING_VIDEOPLAYER_USEPRIMERENDERER) == 0) { CWinSystemGbm* winSystem = dynamic_cast<CWinSystemGbm*>(CServiceBroker::GetWinSystem()); - if (winSystem && winSystem->GetDrm()->GetPrimaryPlane()->plane && + if (winSystem && winSystem->GetDrm()->GetVideoPlane()->plane && std::dynamic_pointer_cast<CDRMAtomic>(winSystem->GetDrm())) return new CRendererDRMPRIME(); } @@ -49,7 +49,7 @@ CBaseRenderer* CRendererDRMPRIME::Create(CVideoBuffer* buffer) void CRendererDRMPRIME::Register() { CWinSystemGbm* winSystem = dynamic_cast<CWinSystemGbm*>(CServiceBroker::GetWinSystem()); - if (winSystem && winSystem->GetDrm()->GetPrimaryPlane()->plane && + if (winSystem && winSystem->GetDrm()->GetVideoPlane()->plane && std::dynamic_pointer_cast<CDRMAtomic>(winSystem->GetDrm())) { CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(SETTING_VIDEOPLAYER_USEPRIMERENDERER)->SetVisible(true); diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp index a335551ae5..1e7acae2c1 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/VideoLayerBridgeDRMPRIME.cpp @@ -28,7 +28,7 @@ CVideoLayerBridgeDRMPRIME::~CVideoLayerBridgeDRMPRIME() void CVideoLayerBridgeDRMPRIME::Disable() { // disable video plane - struct plane* plane = m_DRM->GetPrimaryPlane(); + struct plane* plane = m_DRM->GetVideoPlane(); m_DRM->AddProperty(plane, "FB_ID", 0); m_DRM->AddProperty(plane, "CRTC_ID", 0); } @@ -129,7 +129,7 @@ void CVideoLayerBridgeDRMPRIME::Unmap(CVideoBufferDRMPRIME* buffer) void CVideoLayerBridgeDRMPRIME::Configure(CVideoBufferDRMPRIME* buffer) { - struct plane* plane = m_DRM->GetPrimaryPlane(); + struct plane* plane = m_DRM->GetVideoPlane(); if (m_DRM->SupportsProperty(plane, "COLOR_ENCODING") && m_DRM->SupportsProperty(plane, "COLOR_RANGE")) { @@ -146,7 +146,7 @@ void CVideoLayerBridgeDRMPRIME::SetVideoPlane(CVideoBufferDRMPRIME* buffer, cons return; } - struct plane* plane = m_DRM->GetPrimaryPlane(); + struct plane* plane = m_DRM->GetVideoPlane(); m_DRM->AddProperty(plane, "FB_ID", buffer->m_fb_id); m_DRM->AddProperty(plane, "CRTC_ID", m_DRM->GetCrtc()->crtc->crtc_id); m_DRM->AddProperty(plane, "SRC_X", 0); @@ -164,7 +164,11 @@ void CVideoLayerBridgeDRMPRIME::UpdateVideoPlane() if (!m_buffer || !m_buffer->m_fb_id) return; - struct plane* plane = m_DRM->GetPrimaryPlane(); + // release the buffer that is no longer presented on screen + Release(m_prev_buffer); + m_prev_buffer = nullptr; + + struct plane* plane = m_DRM->GetVideoPlane(); m_DRM->AddProperty(plane, "FB_ID", m_buffer->m_fb_id); m_DRM->AddProperty(plane, "CRTC_ID", m_DRM->GetCrtc()->crtc->crtc_id); } diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGL.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGL.cpp index 7750b51644..acb8728ac3 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGL.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/LinuxRendererGL.cpp @@ -558,6 +558,9 @@ void CLinuxRendererGL::DrawBlackBars() glUniform4f(uniCol, m_clearColour / 255.0f, m_clearColour / 255.0f, m_clearColour / 255.0f, 1.0f); + int osWindowWidth = CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth(); + int osWindowHeight = CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight(); + //top quad if (m_destRect.y1 > 0.0) { @@ -565,10 +568,10 @@ void CLinuxRendererGL::DrawBlackBars() vertices[quad].x = 0.0; vertices[quad].y = 0.0; vertices[quad].z = 0; - vertices[quad+1].x = m_viewRect.Width(); + vertices[quad+1].x = osWindowWidth; vertices[quad+1].y = 0; vertices[quad+1].z = 0; - vertices[quad+2].x = m_viewRect.Width(); + vertices[quad+2].x = osWindowWidth; vertices[quad+2].y = m_destRect.y1; vertices[quad+2].z = 0; vertices[quad+3] = vertices[quad+2]; @@ -580,21 +583,21 @@ void CLinuxRendererGL::DrawBlackBars() } // bottom quad - if (m_destRect.y2 < m_viewRect.Height()) + if (m_destRect.y2 < osWindowHeight) { GLubyte quad = count; vertices[quad].x = 0.0; vertices[quad].y = m_destRect.y2; vertices[quad].z = 0; - vertices[quad+1].x = m_viewRect.Width(); + vertices[quad+1].x = osWindowWidth; vertices[quad+1].y = m_destRect.y2; vertices[quad+1].z = 0; - vertices[quad+2].x = m_viewRect.Width(); - vertices[quad+2].y = m_viewRect.Height(); + vertices[quad+2].x = osWindowWidth; + vertices[quad+2].y = osWindowHeight; vertices[quad+2].z = 0; vertices[quad+3] = vertices[quad+2]; vertices[quad+4].x = 0; - vertices[quad+4].y = m_viewRect.Height(); + vertices[quad+4].y = osWindowHeight; vertices[quad+4].z = 0; vertices[quad+5] = vertices[quad]; count += 6; @@ -622,16 +625,16 @@ void CLinuxRendererGL::DrawBlackBars() } // right quad - if (m_destRect.x2 < m_viewRect.Width()) + if (m_destRect.x2 < osWindowWidth) { GLubyte quad = count; vertices[quad].x = m_destRect.x2; vertices[quad].y = m_destRect.y1; vertices[quad].z = 0; - vertices[quad+1].x = m_viewRect.Width(); + vertices[quad+1].x = osWindowWidth; vertices[quad+1].y = m_destRect.y1; vertices[quad+1].z = 0; - vertices[quad+2].x = m_viewRect.Width(); + vertices[quad+2].x = osWindowWidth; vertices[quad+2].y = m_destRect.y2; vertices[quad+2].z = 0; vertices[quad+3] = vertices[quad+2]; diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRenderer.cpp index 2599880337..7b40cfce27 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRenderer.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRenderer.cpp @@ -331,6 +331,11 @@ void CRenderer::SetVideoRect(CRect &source, CRect &dest, CRect &view) m_rv = view; } +void CRenderer::SetStereoMode(const std::string &stereomode) +{ + m_stereomode = stereomode; +} + COverlay* CRenderer::Convert(CDVDOverlaySSA* o, double pts) { // libass render in a target area which named as frame. the frame size may bigger than video size, @@ -343,7 +348,19 @@ COverlay* CRenderer::Convert(CDVDOverlaySSA* o, double pts) int targetWidth = m_rv.Width(); int targetHeight = m_rv.Height(); int useMargin; - + // Render subtitle of half-sbs and half-ou video in full screen, not in half screen + if (m_stereomode == "left_right" || m_stereomode == "right_left") + { + // only half-sbs video, sbs video don't need to change source size + if (static_cast<double>(sourceWidth) / sourceHeight < 1.2) + sourceWidth = m_rs.Width() * 2; + } + else if (m_stereomode == "top_bottom" || m_stereomode == "bottom_top") + { + // only half-ou video, ou video don't need to change source size + if (static_cast<double>(sourceWidth) / sourceHeight > 2.5) + sourceHeight = m_rs.Height() * 2; + } int subalign = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_SUBTITLES_ALIGN); if(subalign == SUBTITLE_ALIGN_BOTTOM_OUTSIDE || subalign == SUBTITLE_ALIGN_TOP_OUTSIDE diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRenderer.h index bb98f51015..52ef213357 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRenderer.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/OverlayRenderer.h @@ -75,6 +75,7 @@ namespace OVERLAY { void Release(int idx); bool HasOverlay(int idx); void SetVideoRect(CRect &source, CRect &dest, CRect &view); + void SetStereoMode(const std::string &stereomode); protected: @@ -103,5 +104,6 @@ namespace OVERLAY { static unsigned int m_textureid; CRect m_rv, m_rs, m_rd; std::string m_font, m_fontBorder; + std::string m_stereomode; }; } diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp index 85930599f6..4d8e07b385 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp @@ -224,6 +224,7 @@ bool CRenderManager::Configure() m_renderDebug = false; m_clockSync.Reset(); m_dvdClock.SetVsyncAdjust(0); + m_overlays.SetStereoMode(m_stereomode); m_renderState = STATE_CONFIGURED; diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderBuffer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderBuffer.cpp index 7fdafe2f2d..a85da3735b 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderBuffer.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderBuffer.cpp @@ -85,6 +85,7 @@ void CRenderBuffer::Release() m_activePlanes = 0; texBits = 8; bits = 8; + m_locked = false; m_planes[0] = nullptr; m_planes[1] = nullptr; diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp index 56f3c90f20..068da182df 100644 --- a/xbmc/cores/omxplayer/OMXAudio.cpp +++ b/xbmc/cores/omxplayer/OMXAudio.cpp @@ -1312,7 +1312,7 @@ float COMXAudio::GetCacheTotal() } //*********************************************************************************************** -unsigned int COMXAudio::GetChunkLen() +unsigned int COMXAudio::GetChunkLen() const { return m_ChunkLen; } diff --git a/xbmc/cores/omxplayer/OMXAudio.h b/xbmc/cores/omxplayer/OMXAudio.h index 42d96c11a3..06ebb49174 100644 --- a/xbmc/cores/omxplayer/OMXAudio.h +++ b/xbmc/cores/omxplayer/OMXAudio.h @@ -71,7 +71,7 @@ typedef struct tWAVEFORMATEXTENSIBLE class COMXAudio { public: - unsigned int GetChunkLen(); + unsigned int GetChunkLen() const; float GetDelay(); float GetCacheTime(); float GetCacheTotal(); @@ -101,7 +101,7 @@ public: void SetCodingType(AEAudioFormat format); static void PrintChannels(OMX_AUDIO_CHANNELTYPE eChannelMapping[]); - void PrintPCM(OMX_AUDIO_PARAM_PCMMODETYPE *pcm, std::string direction); + static void PrintPCM(OMX_AUDIO_PARAM_PCMMODETYPE *pcm, std::string direction); void UpdateAttenuation(); bool BadState() const { return !m_Initialized; }; diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp index aa3a8bdfd8..fa7696cad9 100644 --- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp +++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp @@ -278,28 +278,28 @@ void COMXAudioCodecOMX::Reset() m_iBufferOutputUsed = 0; } -int COMXAudioCodecOMX::GetChannels() +int COMXAudioCodecOMX::GetChannels() const { if (!m_pCodecContext) return 0; return m_pCodecContext->channels; } -int COMXAudioCodecOMX::GetSampleRate() +int COMXAudioCodecOMX::GetSampleRate() const { if (!m_pCodecContext) return 0; return m_pCodecContext->sample_rate; } -int COMXAudioCodecOMX::GetBitsPerSample() +int COMXAudioCodecOMX::GetBitsPerSample() const { if (!m_pCodecContext) return 0; return m_desiredSampleFormat == AV_SAMPLE_FMT_S16 ? 16 : 32; } -int COMXAudioCodecOMX::GetBitRate() +int COMXAudioCodecOMX::GetBitRate() const { if (!m_pCodecContext) return 0; diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h index 7a8bf739d7..5b38b7142a 100644 --- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h +++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h @@ -31,14 +31,14 @@ public: int Decode(unsigned char* pData, int iSize, double dts, double pts); int GetData(unsigned char** dst, double &dts, double &pts); void Reset(); - int GetChannels(); + int GetChannels() const; void BuildChannelMap(); CAEChannelInfo GetChannelMap(); - int GetSampleRate(); - int GetBitsPerSample(); + int GetSampleRate() const; + int GetBitsPerSample() const; static const char* GetName() { return "FFmpeg"; } - int GetBitRate(); - unsigned int GetFrameSize() { return m_frameSize; } + int GetBitRate() const; + unsigned int GetFrameSize() const { return m_frameSize; } protected: CProcessInfo &m_processInfo; diff --git a/xbmc/cores/omxplayer/OMXImage.h b/xbmc/cores/omxplayer/OMXImage.h index dcbebd8a80..55c85bd6a8 100644 --- a/xbmc/cores/omxplayer/OMXImage.h +++ b/xbmc/cores/omxplayer/OMXImage.h @@ -81,12 +81,12 @@ public: COMXImageFile(); virtual ~COMXImageFile(); bool ReadFile(const std::string& inputFile, int orientation = 0); - int GetOrientation() { return m_orientation; }; - unsigned int GetWidth() { return m_width; }; - unsigned int GetHeight() { return m_height; }; - unsigned long GetImageSize() { return m_image_size; }; - const uint8_t *GetImageBuffer() { return (const uint8_t *)m_image_buffer; }; - const char *GetFilename() { return m_filename.c_str(); }; + int GetOrientation() const { return m_orientation; }; + unsigned int GetWidth() const { return m_width; }; + unsigned int GetHeight() const { return m_height; }; + unsigned long GetImageSize() const { return m_image_size; }; + const uint8_t *GetImageBuffer() const { return (const uint8_t *)m_image_buffer; }; + const char *GetFilename() const { return m_filename.c_str(); }; protected: OMX_IMAGE_CODINGTYPE GetCodingType(unsigned int &width, unsigned int &height, int orientation); uint8_t *m_image_buffer; @@ -106,9 +106,9 @@ public: // Required overrides void Close(); bool Decode(const uint8_t *data, unsigned size, unsigned int width, unsigned int height, unsigned stride, void *pixels); - unsigned int GetDecodedWidth() { return (unsigned int)m_decoded_format.format.image.nFrameWidth; }; - unsigned int GetDecodedHeight() { return (unsigned int)m_decoded_format.format.image.nFrameHeight; }; - unsigned int GetDecodedStride() { return (unsigned int)m_decoded_format.format.image.nStride; }; + unsigned int GetDecodedWidth() const { return (unsigned int)m_decoded_format.format.image.nFrameWidth; }; + unsigned int GetDecodedHeight() const { return (unsigned int)m_decoded_format.format.image.nFrameHeight; }; + unsigned int GetDecodedStride() const { return (unsigned int)m_decoded_format.format.image.nStride; }; protected: bool HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, unsigned int resize_stride); // Components diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp index c3bb5377c1..93f41e7491 100644 --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp @@ -310,6 +310,13 @@ void OMXPlayerVideo::Output(double pts, bool bDropPacket) omvb->m_state = MMAL::MMALStateBypass; picture.videoBuffer = omvb; + if (m_processInfo.GetVideoStereoMode() != GetStereoMode()) + { + m_processInfo.SetVideoStereoMode(picture.stereoMode); + // signal about changes in video parameters + m_messageParent.Put(new CDVDMsg(CDVDMsg::PLAYER_AVCHANGE)); + } + m_renderManager.AddVideoPicture(picture, m_bAbortOutput, EINTERLACEMETHOD::VS_INTERLACEMETHOD_NONE, (m_syncState == ESyncState::SYNC_STARTING)); } @@ -662,20 +669,20 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec if (stereoMode == "left_right") { - video_stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL; + video_stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL; } else if (stereoMode == "right_left") { - video_stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL; + video_stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL; stereo_invert = true; } else if (stereoMode == "top_bottom") { - video_stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL; + video_stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL; } else if (stereoMode == "bottom_top") { - video_stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL; + video_stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL; stereo_invert = true; } diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h index ce0facb317..f741a7d66d 100644 --- a/xbmc/cores/omxplayer/OMXVideo.h +++ b/xbmc/cores/omxplayer/OMXVideo.h @@ -55,7 +55,7 @@ public: int Decode(uint8_t *pData, int iSize, double dts, double pts, bool &settings_changed); void Reset(void); void SetDropState(bool bDrop); - std::string GetDecoderName() { return m_video_codec_name; }; + std::string GetDecoderName() const { return m_video_codec_name; }; void SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode, bool stereo_invert); int GetInputBufferSize(); bool GetPlayerInfo(double &match, double &phase, double &pll); diff --git a/xbmc/dialogs/GUIDialogContextMenu.h b/xbmc/dialogs/GUIDialogContextMenu.h index 69f7e19312..3e8194aa30 100644 --- a/xbmc/dialogs/GUIDialogContextMenu.h +++ b/xbmc/dialogs/GUIDialogContextMenu.h @@ -94,6 +94,7 @@ enum CONTEXT_BUTTON { CONTEXT_BUTTON_CANCELLED = 0, CONTEXT_BUTTON_EDIT_SORTTITLE, CONTEXT_BUTTON_DELETE_ALL, CONTEXT_BUTTON_HELP, + CONTEXT_BUTTON_PLAY_NEXT, }; class CContextButtons : public std::vector< std::pair<size_t, std::string> > diff --git a/xbmc/filesystem/DirectoryFactory.cpp b/xbmc/filesystem/DirectoryFactory.cpp index 644a4d661f..580d2dae62 100644 --- a/xbmc/filesystem/DirectoryFactory.cpp +++ b/xbmc/filesystem/DirectoryFactory.cpp @@ -137,30 +137,26 @@ IDirectory* CDirectoryFactory::Create(const CURL& url) if (CWinLibraryDirectory::IsValid(url)) return new CWinLibraryDirectory(); #endif - bool networkAvailable = CServiceBroker::GetNetwork().IsAvailable(); - if (networkAvailable) - { - if (url.IsProtocol("ftp") || url.IsProtocol("ftps")) return new CFTPDirectory(); - if (url.IsProtocol("http") || url.IsProtocol("https")) return new CHTTPDirectory(); - if (url.IsProtocol("dav") || url.IsProtocol("davs")) return new CDAVDirectory(); + if (url.IsProtocol("ftp") || url.IsProtocol("ftps")) return new CFTPDirectory(); + if (url.IsProtocol("http") || url.IsProtocol("https")) return new CHTTPDirectory(); + if (url.IsProtocol("dav") || url.IsProtocol("davs")) return new CDAVDirectory(); #ifdef HAS_FILESYSTEM_SMB #ifdef TARGET_WINDOWS - if (url.IsProtocol("smb")) return new CWin32SMBDirectory(); + if (url.IsProtocol("smb")) return new CWin32SMBDirectory(); #else - if (url.IsProtocol("smb")) return new CSMBDirectory(); + if (url.IsProtocol("smb")) return new CSMBDirectory(); #endif #endif #ifdef HAS_UPNP - if (url.IsProtocol("upnp")) return new CUPnPDirectory(); + if (url.IsProtocol("upnp")) return new CUPnPDirectory(); #endif - if (url.IsProtocol("rss") || url.IsProtocol("rsss")) return new CRSSDirectory(); + if (url.IsProtocol("rss") || url.IsProtocol("rsss")) return new CRSSDirectory(); #ifdef HAS_ZEROCONF - if (url.IsProtocol("zeroconf")) return new CZeroconfDirectory(); + if (url.IsProtocol("zeroconf")) return new CZeroconfDirectory(); #endif #ifdef HAS_FILESYSTEM_NFS - if (url.IsProtocol("nfs")) return new CNFSDirectory(); + if (url.IsProtocol("nfs")) return new CNFSDirectory(); #endif - } if (url.IsProtocol("pvr")) return new CPVRDirectory(); @@ -174,7 +170,7 @@ IDirectory* CDirectoryFactory::Create(const CURL& url) } } - CLog::Log(LOGWARNING, "%s - %sunsupported protocol(%s) in %s", __FUNCTION__, networkAvailable ? "" : "Network down or ", url.GetProtocol().c_str(), url.GetRedacted().c_str() ); + CLog::Log(LOGWARNING, "%s - unsupported protocol(%s) in %s", __FUNCTION__, url.GetProtocol().c_str(), url.GetRedacted().c_str() ); return NULL; } diff --git a/xbmc/filesystem/FileCache.cpp b/xbmc/filesystem/FileCache.cpp index 5edef2a702..97fed32d07 100644 --- a/xbmc/filesystem/FileCache.cpp +++ b/xbmc/filesystem/FileCache.cpp @@ -94,6 +94,9 @@ CFileCache::CFileCache(const unsigned int flags) , m_writeRate(0) , m_writeRateActual(0) , m_forwardCacheSize(0) + , m_forward(0) + , m_bFilling(false) + , m_bLowSpeedDetected(false) , m_fileSize(0) , m_flags(flags) { @@ -106,6 +109,9 @@ CFileCache::CFileCache(CCacheStrategy *pCache, bool bDeleteCache /* = true */) , m_writeRate(0) , m_writeRateActual(0) , m_forwardCacheSize(0) + , m_forward(0) + , m_bFilling(false) + , m_bLowSpeedDetected(false) { m_pCache = pCache; m_bDeleteCache = bDeleteCache; @@ -220,6 +226,9 @@ bool CFileCache::Open(const CURL& url) m_writePos = 0; m_writeRate = 1024 * 1024; m_writeRateActual = 0; + m_forward = 0; + m_bFilling = true; + m_bLowSpeedDetected = false; m_seekEvent.Reset(); m_seekEnded.Reset(); @@ -279,6 +288,12 @@ void CFileCache::Process() average.Reset(m_writePos, bCompleteReset); // Can only recalculate new average from scratch after a full reset (empty cache) limiter.Reset(m_writePos); m_nSeekResult = m_seekPos; + if (bCompleteReset) + { + m_forward = 0; + m_bFilling = true; + m_bLowSpeedDetected = false; + } } m_seekEnded.Set(); @@ -401,6 +416,28 @@ void CFileCache::Process() // under estimate write rate by a second, to // avoid uncertainty at start of caching m_writeRateActual = average.Rate(m_writePos, 1000); + + // Update forward cache size + m_forward = m_pCache->WaitForData(0, 0); + + // NOTE: Hysteresis (20-80%) for filling-logic + const float level = (m_forwardCacheSize == 0) ? 0.0 : (float) m_forward / m_forwardCacheSize; + if (level > 0.8f) + { + /* NOTE: We can only reliably test for low speed condition, when the cache is *really* + * filling. This is because as soon as it's full the average- + * rate will become approximately the current-rate which can flag false + * low read-rate conditions. + */ + if (m_bFilling && m_writeRateActual < m_writeRate) + m_bLowSpeedDetected = true; + + m_bFilling = false; + } + else if (level < 0.2f) + { + m_bFilling = true; + } } } @@ -569,10 +606,11 @@ int CFileCache::IoControl(EIoControl request, void* param) if (request == IOCTRL_CACHE_STATUS) { SCacheStatus* status = (SCacheStatus*)param; - status->forward = m_pCache->WaitForData(0, 0); - status->level = (m_forwardCacheSize == 0) ? 0.0 : (float) status->forward / m_forwardCacheSize; + status->forward = m_forward; status->maxrate = m_writeRate; status->currate = m_writeRateActual; + status->lowspeed = m_bLowSpeedDetected; + m_bLowSpeedDetected = false; // Reset flag return 0; } diff --git a/xbmc/filesystem/FileCache.h b/xbmc/filesystem/FileCache.h index 1663b4c773..918c2cd01a 100644 --- a/xbmc/filesystem/FileCache.h +++ b/xbmc/filesystem/FileCache.h @@ -71,6 +71,9 @@ namespace XFILE unsigned m_writeRate; unsigned m_writeRateActual; int64_t m_forwardCacheSize; + int64_t m_forward; + bool m_bFilling; + bool m_bLowSpeedDetected; std::atomic<int64_t> m_fileSize; unsigned int m_flags; CCriticalSection m_sync; diff --git a/xbmc/filesystem/FileFactory.cpp b/xbmc/filesystem/FileFactory.cpp index 35b320d227..5b67eb0ced 100644 --- a/xbmc/filesystem/FileFactory.cpp +++ b/xbmc/filesystem/FileFactory.cpp @@ -129,32 +129,28 @@ IFile* CFileFactory::CreateLoader(const CURL& url) else if (CWinLibraryFile::IsValid(url)) return new CWinLibraryFile(); #endif - bool networkAvailable = CServiceBroker::GetNetwork().IsAvailable(); - if (networkAvailable) - { - if (url.IsProtocol("ftp") - || url.IsProtocol("ftps") - || url.IsProtocol("rss") - || url.IsProtocol("rsss") - || url.IsProtocol("http") - || url.IsProtocol("https")) return new CCurlFile(); - else if (url.IsProtocol("dav") || url.IsProtocol("davs")) return new CDAVFile(); - else if (url.IsProtocol("shout")) return new CShoutcastFile(); + if (url.IsProtocol("ftp") + || url.IsProtocol("ftps") + || url.IsProtocol("rss") + || url.IsProtocol("rsss") + || url.IsProtocol("http") + || url.IsProtocol("https")) return new CCurlFile(); + else if (url.IsProtocol("dav") || url.IsProtocol("davs")) return new CDAVFile(); + else if (url.IsProtocol("shout")) return new CShoutcastFile(); #ifdef HAS_FILESYSTEM_SMB #ifdef TARGET_WINDOWS - else if (url.IsProtocol("smb")) return new CWin32SMBFile(); + else if (url.IsProtocol("smb")) return new CWin32SMBFile(); #else - else if (url.IsProtocol("smb")) return new CSMBFile(); + else if (url.IsProtocol("smb")) return new CSMBFile(); #endif #endif #ifdef HAS_FILESYSTEM_NFS - else if (url.IsProtocol("nfs")) return new CNFSFile(); + else if (url.IsProtocol("nfs")) return new CNFSFile(); #endif #ifdef HAS_UPNP - else if (url.IsProtocol("upnp")) return new CUPnPFile(); + else if (url.IsProtocol("upnp")) return new CUPnPFile(); #endif - } - CLog::Log(LOGWARNING, "%s - %sunsupported protocol(%s) in %s", __FUNCTION__, networkAvailable ? "" : "Network down or ", url.GetProtocol().c_str(), url.GetRedacted().c_str()); + CLog::Log(LOGWARNING, "%s - unsupported protocol(%s) in %s", __FUNCTION__, url.GetProtocol().c_str(), url.GetRedacted().c_str()); return NULL; } diff --git a/xbmc/filesystem/IFileTypes.h b/xbmc/filesystem/IFileTypes.h index 7470b15cfb..6817752ccd 100644 --- a/xbmc/filesystem/IFileTypes.h +++ b/xbmc/filesystem/IFileTypes.h @@ -51,7 +51,7 @@ struct SCacheStatus uint64_t forward; /**< number of bytes cached forward of current position */ unsigned maxrate; /**< maximum number of bytes per second cache is allowed to fill */ unsigned currate; /**< average read rate from source file since last position change */ - float level; /**< cache level (0.0 - 1.0) */ + bool lowspeed; /**< cache low speed condition detected? */ }; typedef enum { diff --git a/xbmc/games/addons/input/GameClientInput.cpp b/xbmc/games/addons/input/GameClientInput.cpp index 8f40f81a78..8bb4d27a0d 100644 --- a/xbmc/games/addons/input/GameClientInput.cpp +++ b/xbmc/games/addons/input/GameClientInput.cpp @@ -630,6 +630,19 @@ CGameClientInput::PortMap CGameClientInput::MapJoysticks(const PERIPHERALS::Peri //! @todo Preserve existing joystick ports + // Sort by order of last button press + PERIPHERALS::PeripheralVector sortedJoysticks = peripheralJoysticks; + std::sort(sortedJoysticks.begin(), sortedJoysticks.end(), + [](const PERIPHERALS::PeripheralPtr &lhs, const PERIPHERALS::PeripheralPtr &rhs) + { + if (lhs->LastActive().IsValid() && !rhs->LastActive().IsValid()) + return true; + if (!lhs->LastActive().IsValid() && rhs->LastActive().IsValid()) + return false; + + return lhs->LastActive() > rhs->LastActive(); + }); + unsigned int i = 0; for (const auto &it : gameClientjoysticks) { @@ -642,7 +655,7 @@ CGameClientInput::PortMap CGameClientInput::MapJoysticks(const PERIPHERALS::Peri break; // Dereference iterators - const PERIPHERALS::PeripheralPtr &peripheralJoystick = peripheralJoysticks[i++]; + const PERIPHERALS::PeripheralPtr &peripheralJoystick = sortedJoysticks[i++]; const std::unique_ptr<CGameClientJoystick> &gameClientJoystick = it.second; // Map input provider to input handler diff --git a/xbmc/games/dialogs/GUIDialogSelectGameClient.cpp b/xbmc/games/dialogs/GUIDialogSelectGameClient.cpp index 9269e92dff..f15110aef5 100644 --- a/xbmc/games/dialogs/GUIDialogSelectGameClient.cpp +++ b/xbmc/games/dialogs/GUIDialogSelectGameClient.cpp @@ -57,6 +57,7 @@ std::string CGUIDialogSelectGameClient::ShowAndGetGameClient(const std::string & { // Turn the addons into items CFileItemList items; + CFileItemList installableItems; for (const auto &candidate : candidates) { CFileItemPtr item(XFILE::CAddonsDirectory::FileItemFromAddon(candidate, candidate->ID())); @@ -68,9 +69,12 @@ std::string CGUIDialogSelectGameClient::ShowAndGetGameClient(const std::string & for (const auto &addon : installable) { CFileItemPtr item(XFILE::CAddonsDirectory::FileItemFromAddon(addon, addon->ID())); - items.Add(std::move(item)); + installableItems.Add(std::move(item)); } items.Sort(SortByLabel, SortOrderAscending); + installableItems.Sort(SortByLabel, SortOrderAscending); + + items.Append(installableItems); dialog->SetItems(items); diff --git a/xbmc/guilib/GUIFadeLabelControl.cpp b/xbmc/guilib/GUIFadeLabelControl.cpp index ea7455058c..3eaa2c5e5d 100644 --- a/xbmc/guilib/GUIFadeLabelControl.cpp +++ b/xbmc/guilib/GUIFadeLabelControl.cpp @@ -87,12 +87,14 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d m_scrollInfo.Reset(); m_fadeAnim.ResetAnimation(); } + MarkDirtyRegion(); } if (m_currentLabel != m_lastLabel) { // new label - reset scrolling m_scrollInfo.Reset(); m_fadeAnim.QueueAnimation(ANIM_PROCESS_REVERSE); m_lastLabel = m_currentLabel; + MarkDirtyRegion(); } if (m_infoLabels.size() > 1 || !m_shortText) diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp index acad2fcb76..906db44dad 100644 --- a/xbmc/guilib/GUIFontTTF.cpp +++ b/xbmc/guilib/GUIFontTTF.cpp @@ -352,6 +352,11 @@ void CGUIFontTTFBase::End() void CGUIFontTTFBase::DrawTextInternal(float x, float y, const std::vector<UTILS::Color> &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling) { + if (text.empty()) + { + return; + } + Begin(); uint32_t rawAlignment = alignment; diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp index db51eb4bdd..f87afae0af 100644 --- a/xbmc/guilib/GUIFontTTFGL.cpp +++ b/xbmc/guilib/GUIFontTTFGL.cpp @@ -23,6 +23,8 @@ #endif #include "rendering/MatrixGL.h" +#include <cassert> + // stuff for freetype #include <ft2build.h> #include FT_FREETYPE_H @@ -280,6 +282,9 @@ void CGUIFontTTFGL::LastEnd() CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vertices) const { + assert(!vertices.empty()); + assert(vertices.size() % 4 == 0); + // Generate a unique buffer object name and put it in bufferHandle GLuint bufferHandle; glGenBuffers(1, &bufferHandle); @@ -288,7 +293,7 @@ CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vert // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER // binding point (i.e. our buffer object) and initialise it from the // specified client-side pointer - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof (SVertex), &vertices[0], GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof (SVertex), vertices.data(), GL_STATIC_DRAW); // Unbind GL_ARRAY_BUFFER glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/xbmc/guilib/Shader.cpp b/xbmc/guilib/Shader.cpp index fc8095e75a..7cf820e52e 100644 --- a/xbmc/guilib/Shader.cpp +++ b/xbmc/guilib/Shader.cpp @@ -11,6 +11,7 @@ #include "filesystem/File.h" #include "utils/log.h" #include "utils/GLUtils.h" +#include "utils/StringUtils.h" #include "rendering/RenderSystem.h" #ifdef HAS_GLES @@ -51,6 +52,9 @@ bool CShader::LoadSource(const std::string& filename, const std::string& prefix) pos = versionPos + 1; } m_source.insert(pos, prefix); + + m_filenames = filename; + return true; } @@ -72,6 +76,9 @@ bool CShader::AppendSource(const std::string& filename) } getline(file, temp, '\0'); m_source.append(temp); + + m_filenames.append(" " + filename); + return true; } @@ -102,9 +109,27 @@ bool CShader::InsertSource(const std::string& filename, const std::string& loc) m_source.insert(locPos, temp); + m_filenames.append(" " + filename); + return true; } +std::string CShader::GetSourceWithLineNumbers() const +{ + int i{1}; + auto lines = StringUtils::Split(m_source, "\n"); + for (auto& line : lines) + { + line.insert(0, StringUtils::Format("%3d: ", i)); + i++; + } + + auto output = StringUtils::Join(lines, "\n"); + + return output; +} + + ////////////////////////////////////////////////////////////////////// // CGLSLVertexShader ////////////////////////////////////////////////////////////////////// @@ -254,7 +279,8 @@ bool CGLSLShaderProgram::CompileAndLink() // compiled vertex shader if (!m_pVP->Compile()) { - CLog::Log(LOGERROR, "GL: Error compiling vertex shader"); + CLog::Log(LOGERROR, "GL: Error compiling vertex shader: {}", m_pVP->GetName()); + CLog::Log(LOGDEBUG, "GL: vertex shader source:\n{}", m_pVP->GetSourceWithLineNumbers()); return false; } @@ -262,7 +288,8 @@ bool CGLSLShaderProgram::CompileAndLink() if (!m_pFP->Compile()) { m_pVP->Free(); - CLog::Log(LOGERROR, "GL: Error compiling fragment shader"); + CLog::Log(LOGERROR, "GL: Error compiling fragment shader: {}", m_pFP->GetName()); + CLog::Log(LOGDEBUG, "GL: fragment shader source:\n{}", m_pFP->GetSourceWithLineNumbers()); return false; } diff --git a/xbmc/guilib/Shader.h b/xbmc/guilib/Shader.h index d689b1b239..a0228cd175 100644 --- a/xbmc/guilib/Shader.h +++ b/xbmc/guilib/Shader.h @@ -32,11 +32,17 @@ namespace Shaders { virtual bool InsertSource(const std::string& filename, const std::string& loc); bool OK() const { return m_compiled; } + std::string GetName() const { return m_filenames; } + std::string GetSourceWithLineNumbers() const; + protected: std::string m_source; std::string m_lastLog; std::vector<std::string> m_attr; bool m_compiled = false; + + private: + std::string m_filenames; }; diff --git a/xbmc/guilib/guiinfo/GUIInfoLabels.h b/xbmc/guilib/guiinfo/GUIInfoLabels.h index f92c63d56d..4930662cda 100644 --- a/xbmc/guilib/guiinfo/GUIInfoLabels.h +++ b/xbmc/guilib/guiinfo/GUIInfoLabels.h @@ -35,7 +35,7 @@ #define PLAYER_TIME 27 #define PLAYER_TIME_REMAINING 28 #define PLAYER_DURATION 29 -#define PLAYER_SHOWCODEC 30 +// unused 30 #define PLAYER_SHOWINFO 31 #define PLAYER_VOLUME 32 #define PLAYER_MUTED 33 diff --git a/xbmc/guilib/guiinfo/VideoGUIInfo.cpp b/xbmc/guilib/guiinfo/VideoGUIInfo.cpp index e13a10b956..35f71e4fc5 100644 --- a/xbmc/guilib/guiinfo/VideoGUIInfo.cpp +++ b/xbmc/guilib/guiinfo/VideoGUIInfo.cpp @@ -22,6 +22,7 @@ #include "guilib/StereoscopicsManager.h" #include "guilib/WindowIDs.h" #include "settings/AdvancedSettings.h" +#include "settings/lib/Setting.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/StringUtils.h" @@ -330,18 +331,27 @@ bool CVideoGUIInfo::GetLabel(std::string& value, const CFileItem *item, int cont } break; case LISTITEM_PLOT: - if (tag->m_type != MediaTypeTvShow && - tag->m_type != MediaTypeVideoCollection && - tag->GetPlayCount() == 0 && - !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS)) { - value = g_localizeStrings.Get(20370); - } - else - { - value = tag->m_strPlot; + std::shared_ptr<CSettingList> setting(std::dynamic_pointer_cast<CSettingList>( + CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS))); + if (tag->m_type != MediaTypeTvShow && + tag->m_type != MediaTypeVideoCollection && + tag->GetPlayCount() == 0 && + setting && + ( + (tag->m_type == MediaTypeMovie && (!setting->FindIntInList(CSettings::VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_MOVIES))) || + (tag->m_type == MediaTypeEpisode && (!setting->FindIntInList(CSettings::VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_TVSHOWEPISODES))) + ) + ) + { + value = g_localizeStrings.Get(20370); + } + else + { + value = tag->m_strPlot; + } + return true; } - return true; case LISTITEM_STATUS: value = tag->m_strStatus; return true; diff --git a/xbmc/input/actions/ActionIDs.h b/xbmc/input/actions/ActionIDs.h index 12a5334e67..cf8a4846ed 100644 --- a/xbmc/input/actions/ActionIDs.h +++ b/xbmc/input/actions/ActionIDs.h @@ -268,6 +268,7 @@ #define ACTION_TOGGLE_FONT 249 //!< Toggle font. Used in TextViewer dialog #define ACTION_VIDEO_NEXT_STREAM 250 //!< Cycle video streams. Used in videofullscreen. +#define ACTION_QUEUE_ITEM_NEXT 251 //!< used to queue an item to the next position in the playlist // Voice actions #define ACTION_VOICE_RECOGNIZE 300 diff --git a/xbmc/input/actions/ActionTranslator.cpp b/xbmc/input/actions/ActionTranslator.cpp index e189321d32..018ae00960 100644 --- a/xbmc/input/actions/ActionTranslator.cpp +++ b/xbmc/input/actions/ActionTranslator.cpp @@ -63,6 +63,7 @@ static const std::map<ActionName, ActionID> ActionMappings = { "zoomin" , ACTION_ZOOM_IN }, { "playlist" , ACTION_SHOW_PLAYLIST }, { "queue" , ACTION_QUEUE_ITEM }, + { "playnext" , ACTION_QUEUE_ITEM_NEXT }, { "zoomnormal" , ACTION_ZOOM_LEVEL_NORMAL }, { "zoomlevel1" , ACTION_ZOOM_LEVEL_1 }, { "zoomlevel2" , ACTION_ZOOM_LEVEL_2 }, diff --git a/xbmc/interfaces/builtins/PlayerBuiltins.cpp b/xbmc/interfaces/builtins/PlayerBuiltins.cpp index 567f4edc1a..dabb959e65 100644 --- a/xbmc/interfaces/builtins/PlayerBuiltins.cpp +++ b/xbmc/interfaces/builtins/PlayerBuiltins.cpp @@ -551,10 +551,14 @@ static int Seek(const std::vector<std::string>& params) /// | Partymode(video) ** | Toggles video partymode | none | | /// | Partymode(path to .xsp) | Partymode for *.xsp-file | Partymode for *.xsp-file | | /// | ShowVideoMenu | Shows the DVD/BR menu if available | none | | +/// | FrameAdvance(n) *** | Advance video by _n_ frames | none | Kodi v18 | /// <br> /// '*' = For these controls\, the PlayerControl built-in function can make use of the 'notify'-parameter. For example: PlayerControl(random\, notify) +/// <br> /// '**' = If no argument is given for 'partymode'\, the control will default to music. /// <br> +/// '***' = This only works if the player is paused. +/// <br> /// @param[in] control Control to execute. /// @param[in] param "notify" to notify user (optional\, certain controls). /// diff --git a/xbmc/interfaces/json-rpc/PVROperations.cpp b/xbmc/interfaces/json-rpc/PVROperations.cpp index 964ef456d6..9442fa443d 100644 --- a/xbmc/interfaces/json-rpc/PVROperations.cpp +++ b/xbmc/interfaces/json-rpc/PVROperations.cpp @@ -216,7 +216,7 @@ JSONRPC_STATUS CPVROperations::Record(const std::string &method, ITransportLayer if (toggle) { - if (!CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(pChannel, pChannel->IsRecording())) + if (!CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(pChannel, !pChannel->IsRecording())) return FailedToExecute; } diff --git a/xbmc/interfaces/json-rpc/schema/version.txt b/xbmc/interfaces/json-rpc/schema/version.txt index 501d3e2821..d7bfa651e6 100644 --- a/xbmc/interfaces/json-rpc/schema/version.txt +++ b/xbmc/interfaces/json-rpc/schema/version.txt @@ -1 +1 @@ -JSONRPC_VERSION 9.7.2 +JSONRPC_VERSION 10.0.1 diff --git a/xbmc/interfaces/legacy/ModuleXbmcvfs.h b/xbmc/interfaces/legacy/ModuleXbmcvfs.h index c4576e65fc..3e4f2508aa 100644 --- a/xbmc/interfaces/legacy/ModuleXbmcvfs.h +++ b/xbmc/interfaces/legacy/ModuleXbmcvfs.h @@ -74,7 +74,7 @@ namespace XBMCAddon /// .. /// ~~~~~~~~~~~~~ /// - deleteFile(...); + delete(...); #else bool deleteFile(const String& file); #endif diff --git a/xbmc/interfaces/legacy/Monitor.h b/xbmc/interfaces/legacy/Monitor.h index 752f658e17..9913faa480 100644 --- a/xbmc/interfaces/legacy/Monitor.h +++ b/xbmc/interfaces/legacy/Monitor.h @@ -144,6 +144,8 @@ namespace XBMCAddon /// /// @note Will be called when library clean has ended and return video or /// music to indicate which library is being scanned + /// + /// ///----------------------------------------------------------------------- /// @python_v14 New function added. /// @@ -164,6 +166,8 @@ namespace XBMCAddon /// /// @note Will be called when library clean has ended and return video or /// music to indicate which library has been scanned + /// + /// ///----------------------------------------------------------------------- /// @python_v14 New function added. /// @@ -209,6 +213,8 @@ namespace XBMCAddon /// /// @note Will be called when library clean has ended and return video or /// music to indicate which library has been cleaned + /// + /// ///----------------------------------------------------------------------- /// @python_v14 New function added. /// @@ -229,6 +235,8 @@ namespace XBMCAddon /// /// @note Will be called when library clean has ended and return video or /// music to indicate which library has been finished + /// + /// ///----------------------------------------------------------------------- /// @python_v14 New function added. /// @@ -261,6 +269,8 @@ namespace XBMCAddon /// @param data JSON-encoded data of the notification /// /// @note Will be called when Kodi receives or sends a notification + /// + /// ///----------------------------------------------------------------------- /// @python_v13 New function added. /// @@ -280,9 +290,12 @@ namespace XBMCAddon /// /// @param timeout [opt] float - timeout in seconds. /// Default: no timeout. + /// /// @return True when abort have been requested, /// False if a timeout is given and the /// operation times out. + /// + /// ///----------------------------------------------------------------------- /// @python_v14 New function added. /// @@ -298,6 +311,8 @@ namespace XBMCAddon /// Returns True if abort has been requested. /// /// @return True if requested + /// + /// ///----------------------------------------------------------------------- /// @python_v14 New function added. /// diff --git a/xbmc/interfaces/legacy/Stat.h b/xbmc/interfaces/legacy/Stat.h index 5eace1da38..9b857395ca 100644 --- a/xbmc/interfaces/legacy/Stat.h +++ b/xbmc/interfaces/legacy/Stat.h @@ -160,13 +160,13 @@ namespace XBMCAddon #ifdef DOXYGEN_SHOULD_USE_THIS /// /// \ingroup python_stat - /// @brief \python_func{ atime() } + /// @brief \python_func{ st_atime() } ///----------------------------------------------------------------------- /// To get time of last access. /// /// @return st_atime /// - atime(); + st_atime(); #else inline long long atime() { return st.st_atime; }; //names st_atime/st_mtime/st_ctime are used by sys/stat.h #endif @@ -174,13 +174,13 @@ namespace XBMCAddon #ifdef DOXYGEN_SHOULD_USE_THIS /// /// \ingroup python_stat - /// @brief \python_func{ mtime() } + /// @brief \python_func{ st_mtime() } ///----------------------------------------------------------------------- /// To get time of last modification. /// /// @return st_mtime /// - mtime(); + st_mtime(); #else inline long long mtime() { return st.st_mtime; }; #endif @@ -188,13 +188,13 @@ namespace XBMCAddon #ifdef DOXYGEN_SHOULD_USE_THIS /// /// \ingroup python_stat - /// @brief \python_func{ ctime() } + /// @brief \python_func{ st_ctime() } ///----------------------------------------------------------------------- /// To get time of last status change. /// /// @return st_ctime /// - ctime(); + st_ctime(); #else inline long long ctime() { return st.st_ctime; }; #endif diff --git a/xbmc/listproviders/DirectoryProvider.cpp b/xbmc/listproviders/DirectoryProvider.cpp index b7273209b8..7fcaf8b52c 100644 --- a/xbmc/listproviders/DirectoryProvider.cpp +++ b/xbmc/listproviders/DirectoryProvider.cpp @@ -255,7 +255,8 @@ void CDirectoryProvider::Announce(ANNOUNCEMENT::AnnouncementFlag flag, const cha if (strcmp(message, "OnScanFinished") == 0 || strcmp(message, "OnCleanFinished") == 0 || strcmp(message, "OnUpdate") == 0 || - strcmp(message, "OnRemove") == 0) + strcmp(message, "OnRemove") == 0 || + strcmp(message, "OnRefresh") == 0) m_updateState = INVALIDATED; } } diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp index c9468e7db8..96035f7542 100644 --- a/xbmc/music/MusicDatabase.cpp +++ b/xbmc/music/MusicDatabase.cpp @@ -867,7 +867,7 @@ int CMusicDatabase::AddAlbum(const std::string& strAlbum, const std::string& str stored for it. Most values here should be the same across all songs anyway, but it does mean that if there's any inconsistencies then only the last folders information will be taken. - We make sure we clear out the link tables (album artists, album genres) and we reset + We make sure we clear out the link tables (album artists, album sources) and we reset the last scraped time to make sure that online metadata is re-fetched. */ int idAlbum = m_pDS->fv("idAlbum").get_asInt(); m_pDS->close(); @@ -896,6 +896,7 @@ int CMusicDatabase::AddAlbum(const std::string& strAlbum, const std::string& str idAlbum); m_pDS->exec(strSQL); DeleteAlbumArtistsByAlbum(idAlbum); + DeleteAlbumSources(idAlbum); return idAlbum; } } @@ -8049,6 +8050,11 @@ bool CMusicDatabase::AddAlbumSources(int idAlbum, const std::string& strPath) return false; } +bool CMusicDatabase::DeleteAlbumSources(int idAlbum) +{ + return ExecuteQuery(PrepareSQL("DELETE FROM album_source WHERE idAlbum = %i", idAlbum)); +} + bool CMusicDatabase::CheckSources(VECSOURCES& sources) { if (sources.empty()) diff --git a/xbmc/music/MusicDatabase.h b/xbmc/music/MusicDatabase.h index 39369173ff..8acaf08b2e 100644 --- a/xbmc/music/MusicDatabase.h +++ b/xbmc/music/MusicDatabase.h @@ -354,6 +354,7 @@ public: int GetSourceFromPath(const std::string& strPath); bool AddAlbumSource(int idAlbum, int idSource); bool AddAlbumSources(int idAlbum, const std::string& strPath); + bool DeleteAlbumSources(int idAlbum); bool GetSources(CFileItemList& items); bool GetSourcesByArtist(int idArtist, CFileItem* item); diff --git a/xbmc/music/tags/TagLoaderTagLib.cpp b/xbmc/music/tags/TagLoaderTagLib.cpp index 6e7fada382..d4813dafeb 100644 --- a/xbmc/music/tags/TagLoaderTagLib.cpp +++ b/xbmc/music/tags/TagLoaderTagLib.cpp @@ -397,8 +397,8 @@ bool CTagLoaderTagLib::ParseTag(ID3v2::Tag *id3v2, EmbeddedArt *art, MUSIC_INFO: // Loop through any UFID frames and set them for (ID3v2::FrameList::ConstIterator ut = it->second.begin(); ut != it->second.end(); ++ut) { - auto ufid = reinterpret_cast<ID3v2::UniqueFileIdentifierFrame*> (*ut); - if (ufid->owner() == "http://musicbrainz.org") + auto ufid = dynamic_cast<ID3v2::UniqueFileIdentifierFrame*> (*ut); + if (ufid && ufid->owner() == "http://musicbrainz.org") { // MusicBrainz pads with a \0, but the spec requires binary, be cautious char cUfid[64]; diff --git a/xbmc/music/windows/GUIWindowMusicBase.cpp b/xbmc/music/windows/GUIWindowMusicBase.cpp index 1ae068deae..cb27b0c6a3 100644 --- a/xbmc/music/windows/GUIWindowMusicBase.cpp +++ b/xbmc/music/windows/GUIWindowMusicBase.cpp @@ -115,7 +115,8 @@ bool CGUIWindowMusicBase::OnBack(int actionID) Other Controls: - The container controls\n Have the following actions in message them clicking on them. - - #ACTION_QUEUE_ITEM - add selected item to playlist + - #ACTION_QUEUE_ITEM - add selected item to end of playlist + - #ACTION_QUEUE_ITEM_NEXT - add selected item to next pos in playlist - #ACTION_SHOW_INFO - retrieve album info from the internet - #ACTION_SELECT_ITEM - Item has been selected. Overwrite OnClick() to react on it */ @@ -190,6 +191,10 @@ bool CGUIWindowMusicBase::OnMessage(CGUIMessage& message) { OnQueueItem(iItem); } + else if (iAction == ACTION_QUEUE_ITEM_NEXT) + { + OnQueueItem(iItem, true); + } else if (iAction == ACTION_SHOW_INFO) { OnItemInfo(iItem); @@ -347,7 +352,7 @@ void CGUIWindowMusicBase::RetrieveMusicInfo() /// \brief Add selected list/thumb control item to playlist and start playing /// \param iItem Selected Item in list/thumb control -void CGUIWindowMusicBase::OnQueueItem(int iItem) +void CGUIWindowMusicBase::OnQueueItem(int iItem, bool first) { // Determine the proper list to queue this element int playlist = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist(); @@ -386,7 +391,10 @@ void CGUIWindowMusicBase::OnQueueItem(int iItem) return; } - CServiceBroker::GetPlaylistPlayer().Add(playlist, queuedItems); + if (first && g_application.GetAppPlayer().IsPlaying()) + CServiceBroker::GetPlaylistPlayer().Insert(playlist, queuedItems, CServiceBroker::GetPlaylistPlayer().GetCurrentSong()+1); + else + CServiceBroker::GetPlaylistPlayer().Add(playlist, queuedItems); if (CServiceBroker::GetPlaylistPlayer().GetPlaylist(playlist).size() && !g_application.GetAppPlayer().IsPlaying()) { if (m_guiState.get()) @@ -519,6 +527,7 @@ void CGUIWindowMusicBase::GetContextButtons(int itemNumber, CContextButtons &but if (item->CanQueue() && !item->IsAddonsPath() && !item->IsScript()) { buttons.Add(CONTEXT_BUTTON_QUEUE_ITEM, 13347); //queue + buttons.Add(CONTEXT_BUTTON_PLAY_NEXT, 10008); //play next // allow a folder to be ad-hoc queued and played by the default player if (item->m_bIsFolder || (item->IsPlayList() && @@ -608,6 +617,10 @@ bool CGUIWindowMusicBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) OnQueueItem(itemNumber); return true; + case CONTEXT_BUTTON_PLAY_NEXT: + OnQueueItem(itemNumber, true); + return true; + case CONTEXT_BUTTON_INFO: OnItemInfo(itemNumber); return true; diff --git a/xbmc/music/windows/GUIWindowMusicBase.h b/xbmc/music/windows/GUIWindowMusicBase.h index 0dec4e6888..61864c691c 100644 --- a/xbmc/music/windows/GUIWindowMusicBase.h +++ b/xbmc/music/windows/GUIWindowMusicBase.h @@ -83,7 +83,7 @@ protected: void RetrieveMusicInfo(); void OnItemInfo(int iItem); void OnItemInfoAll(const std::string strPath, bool refresh = false); - virtual void OnQueueItem(int iItem); + virtual void OnQueueItem(int iItem, bool first = false); enum ALLOW_SELECTION { SELECTION_ALLOWED = 0, SELECTION_AUTO, SELECTION_FORCED }; void OnRipTrack(int iItem); diff --git a/xbmc/music/windows/GUIWindowMusicPlaylistEditor.cpp b/xbmc/music/windows/GUIWindowMusicPlaylistEditor.cpp index 6b9434e066..a85275f4d4 100644 --- a/xbmc/music/windows/GUIWindowMusicPlaylistEditor.cpp +++ b/xbmc/music/windows/GUIWindowMusicPlaylistEditor.cpp @@ -199,7 +199,7 @@ void CGUIWindowMusicPlaylistEditor::PlayItem(int iItem) CGUIWindowMusicBase::PlayItem(iItem); } -void CGUIWindowMusicPlaylistEditor::OnQueueItem(int iItem) +void CGUIWindowMusicPlaylistEditor::OnQueueItem(int iItem, bool) { if (iItem < 0 || iItem >= m_vecItems->Size()) return; diff --git a/xbmc/music/windows/GUIWindowMusicPlaylistEditor.h b/xbmc/music/windows/GUIWindowMusicPlaylistEditor.h index b64d724612..97f27a0242 100644 --- a/xbmc/music/windows/GUIWindowMusicPlaylistEditor.h +++ b/xbmc/music/windows/GUIWindowMusicPlaylistEditor.h @@ -28,7 +28,7 @@ protected: void OnPrepareFileItems(CFileItemList &items) override; void GetContextButtons(int itemNumber, CContextButtons &buttons) override; bool OnContextButton(int itemNumber, CONTEXT_BUTTON button) override; - void OnQueueItem(int iItem) override; + void OnQueueItem(int iItem, bool) override; std::string GetStartFolder(const std::string &dir) override { return ""; }; void OnPlaylistContext(); diff --git a/xbmc/peripherals/devices/Peripheral.h b/xbmc/peripherals/devices/Peripheral.h index e7aa673925..c083ff11c9 100644 --- a/xbmc/peripherals/devices/Peripheral.h +++ b/xbmc/peripherals/devices/Peripheral.h @@ -17,6 +17,7 @@ #include "input/keyboard/interfaces/IKeyboardInputProvider.h" #include "input/mouse/interfaces/IMouseInputProvider.h" #include "peripherals/PeripheralTypes.h" +#include "XBDateTime.h" class TiXmlDocument; class CSetting; @@ -230,6 +231,13 @@ namespace PERIPHERALS virtual IKeymap *GetKeymap(const std::string &controllerId) { return nullptr; } + /*! + * \brief Return the last time this peripheral was active + * + * \return The time of last activation, or invalid if unknown/never active + */ + virtual CDateTime LastActive() { return CDateTime(); } + protected: virtual void ClearSettings(void); diff --git a/xbmc/peripherals/devices/PeripheralJoystick.cpp b/xbmc/peripherals/devices/PeripheralJoystick.cpp index 68c85e1d56..1516dcbf9d 100644 --- a/xbmc/peripherals/devices/PeripheralJoystick.cpp +++ b/xbmc/peripherals/devices/PeripheralJoystick.cpp @@ -199,6 +199,8 @@ bool CPeripheralJoystick::OnButtonMotion(unsigned int buttonIndex, bool bPressed if (bPressed && !g_application.IsAppFocused()) return false; + m_lastActive = CDateTime::GetCurrentDateTime(); + CSingleLock lock(m_handlerMutex); // Process promiscuous handlers @@ -240,6 +242,8 @@ bool CPeripheralJoystick::OnHatMotion(unsigned int hatIndex, HAT_STATE state) if (state != HAT_STATE::NONE && !g_application.IsAppFocused()) return false; + m_lastActive = CDateTime::GetCurrentDateTime(); + CSingleLock lock(m_handlerMutex); // Process promiscuous handlers @@ -317,6 +321,9 @@ bool CPeripheralJoystick::OnAxisMotion(unsigned int axisIndex, float position) } } + if (bHandled) + m_lastActive = CDateTime::GetCurrentDateTime(); + return bHandled; } diff --git a/xbmc/peripherals/devices/PeripheralJoystick.h b/xbmc/peripherals/devices/PeripheralJoystick.h index b944c3990c..aeb2c72a82 100644 --- a/xbmc/peripherals/devices/PeripheralJoystick.h +++ b/xbmc/peripherals/devices/PeripheralJoystick.h @@ -52,6 +52,7 @@ namespace PERIPHERALS void UnregisterJoystickDriverHandler(KODI::JOYSTICK::IDriverHandler* handler) override; KODI::JOYSTICK::IDriverReceiver* GetDriverReceiver() override { return this; } IKeymap *GetKeymap(const std::string &controllerId) override; + CDateTime LastActive() override { return m_lastActive; } bool OnButtonMotion(unsigned int buttonIndex, bool bPressed); bool OnHatMotion(unsigned int hatIndex, KODI::JOYSTICK::HAT_STATE state); @@ -122,5 +123,6 @@ namespace PERIPHERALS std::unique_ptr<KODI::JOYSTICK::CDeadzoneFilter> m_deadzoneFilter; std::vector<DriverHandler> m_driverHandlers; CCriticalSection m_handlerMutex; + CDateTime m_lastActive; }; } diff --git a/xbmc/peripherals/devices/PeripheralKeyboard.cpp b/xbmc/peripherals/devices/PeripheralKeyboard.cpp index 70d092ad66..c2fa215859 100644 --- a/xbmc/peripherals/devices/PeripheralKeyboard.cpp +++ b/xbmc/peripherals/devices/PeripheralKeyboard.cpp @@ -75,6 +75,8 @@ void CPeripheralKeyboard::UnregisterKeyboardDriverHandler(KODI::KEYBOARD::IKeybo bool CPeripheralKeyboard::OnKeyPress(const CKey& key) { + m_lastActive = CDateTime::GetCurrentDateTime(); + CSingleLock lock(m_mutex); bool bHandled = false; diff --git a/xbmc/peripherals/devices/PeripheralKeyboard.h b/xbmc/peripherals/devices/PeripheralKeyboard.h index 3d3dfd442e..fe9b58c7ec 100644 --- a/xbmc/peripherals/devices/PeripheralKeyboard.h +++ b/xbmc/peripherals/devices/PeripheralKeyboard.h @@ -28,6 +28,7 @@ namespace PERIPHERALS bool InitialiseFeature(const PeripheralFeature feature) override; void RegisterKeyboardDriverHandler(KODI::KEYBOARD::IKeyboardDriverHandler* handler, bool bPromiscuous) override; void UnregisterKeyboardDriverHandler(KODI::KEYBOARD::IKeyboardDriverHandler* handler) override; + CDateTime LastActive() override { return m_lastActive; } // implementation of IKeyboardDriverHandler bool OnKeyPress(const CKey& key) override; @@ -42,5 +43,6 @@ namespace PERIPHERALS std::vector<KeyboardHandle> m_keyboardHandlers; CCriticalSection m_mutex; + CDateTime m_lastActive; }; } diff --git a/xbmc/peripherals/devices/PeripheralMouse.cpp b/xbmc/peripherals/devices/PeripheralMouse.cpp index 61d4172bb1..5abcdd97a3 100644 --- a/xbmc/peripherals/devices/PeripheralMouse.cpp +++ b/xbmc/peripherals/devices/PeripheralMouse.cpp @@ -93,11 +93,16 @@ bool CPeripheralMouse::OnPosition(int x, int y) } } + if (bHandled) + m_lastActive = CDateTime::GetCurrentDateTime(); + return bHandled; } bool CPeripheralMouse::OnButtonPress(MOUSE::BUTTON_ID button) { + m_lastActive = CDateTime::GetCurrentDateTime(); + CSingleLock lock(m_mutex); bool bHandled = false; diff --git a/xbmc/peripherals/devices/PeripheralMouse.h b/xbmc/peripherals/devices/PeripheralMouse.h index 9610e159c4..6b21a426d5 100644 --- a/xbmc/peripherals/devices/PeripheralMouse.h +++ b/xbmc/peripherals/devices/PeripheralMouse.h @@ -28,6 +28,7 @@ namespace PERIPHERALS bool InitialiseFeature(const PeripheralFeature feature) override; void RegisterMouseDriverHandler(KODI::MOUSE::IMouseDriverHandler* handler, bool bPromiscuous) override; void UnregisterMouseDriverHandler(KODI::MOUSE::IMouseDriverHandler* handler) override; + CDateTime LastActive() override { return m_lastActive; } // implementation of IMouseDriverHandler bool OnPosition(int x, int y) override; @@ -43,5 +44,6 @@ namespace PERIPHERALS std::vector<MouseHandle> m_mouseHandlers; CCriticalSection m_mutex; + CDateTime m_lastActive; }; } diff --git a/xbmc/platform/android/activity/AndroidKey.cpp b/xbmc/platform/android/activity/AndroidKey.cpp index 5cc7b8b9d3..1d5f17e82f 100644 --- a/xbmc/platform/android/activity/AndroidKey.cpp +++ b/xbmc/platform/android/activity/AndroidKey.cpp @@ -312,6 +312,10 @@ bool CAndroidKey::onKeyboardEvent(AInputEvent *event) void CAndroidKey::XBMC_Key(uint8_t code, uint16_t key, uint16_t modifiers, uint16_t unicode, bool up) { + CWinSystemAndroid* winSystem(dynamic_cast<CWinSystemAndroid*>(CServiceBroker::GetWinSystem())); + if (!winSystem) + return; + XBMC_Event newEvent; memset(&newEvent, 0, sizeof(newEvent)); @@ -323,5 +327,5 @@ void CAndroidKey::XBMC_Key(uint8_t code, uint16_t key, uint16_t modifiers, uint1 newEvent.key.keysym.mod = (XBMCMod)modifiers; //CXBMCApp::android_printf("XBMC_Key(%u, %u, 0x%04X, %d)", code, key, modifiers, up); - dynamic_cast<CWinSystemAndroid*>(CServiceBroker::GetWinSystem())->MessagePush(&newEvent); + winSystem->MessagePush(&newEvent); } diff --git a/xbmc/platform/android/activity/XBMCApp.cpp b/xbmc/platform/android/activity/XBMCApp.cpp index 6cbe39094c..2869919498 100644 --- a/xbmc/platform/android/activity/XBMCApp.cpp +++ b/xbmc/platform/android/activity/XBMCApp.cpp @@ -565,6 +565,14 @@ void CXBMCApp::SetRefreshRate(float rate) if (rate < 1.0) return; + CJNIWindow window = getWindow(); + if (window) + { + CJNIWindowManagerLayoutParams params = window.getAttributes(); + if (fabs(params.getpreferredRefreshRate() - rate) <= 0.001) + return; + } + m_refreshRate = rate; m_displayChangeEvent.Reset(); @@ -579,6 +587,15 @@ void CXBMCApp::SetDisplayMode(int mode, float rate) if (mode < 1.0) return; + CJNIWindow window = getWindow(); + if (window) + { + CJNIWindowManagerLayoutParams params = window.getAttributes(); + CLog::Log(LOGDEBUG, "XXX %d %d", params.getpreferredDisplayModeId(), mode); + if (params.getpreferredDisplayModeId() == mode) + return; + } + m_displayChangeEvent.Reset(); std::map<std::string, CVariant> vmap; @@ -1003,8 +1020,14 @@ void CXBMCApp::onReceive(CJNIIntent intent) m_hdmiPlugged = newstate; if (m_hdmiPlugged != m_hdmiReportedState) { - dynamic_cast<CWinSystemAndroid*>(CServiceBroker::GetWinSystem())->SetHDMIState(m_hdmiPlugged); - m_hdmiReportedState = m_hdmiPlugged; + if (g_application.IsInitialized()) + { + CWinSystemBase* winSystem = CServiceBroker::GetWinSystem(); + if (winSystem && dynamic_cast<CWinSystemAndroid*>(winSystem)) + dynamic_cast<CWinSystemAndroid*>(winSystem)->SetHDMIState(m_hdmiPlugged); + + m_hdmiReportedState = m_hdmiPlugged; + } } } } diff --git a/xbmc/platform/android/peripherals/AndroidJoystickState.cpp b/xbmc/platform/android/peripherals/AndroidJoystickState.cpp index 39e53cb91f..293f2ee113 100644 --- a/xbmc/platform/android/peripherals/AndroidJoystickState.cpp +++ b/xbmc/platform/android/peripherals/AndroidJoystickState.cpp @@ -162,6 +162,11 @@ bool CAndroidJoystickState::Initialize(const CJNIViewInputDevice& inputDevice) m_buttons.push_back({ { AKEYCODE_BUTTON_R2 } }); m_buttons.push_back({ { AKEYCODE_BUTTON_THUMBL } }); m_buttons.push_back({ { AKEYCODE_BUTTON_THUMBR } }); + m_buttons.push_back({ { AKEYCODE_DPAD_UP } }); + m_buttons.push_back({ { AKEYCODE_DPAD_RIGHT } }); + m_buttons.push_back({ { AKEYCODE_DPAD_DOWN } }); + m_buttons.push_back({ { AKEYCODE_DPAD_LEFT } }); + m_buttons.push_back({ { AKEYCODE_DPAD_CENTER} }); // check if there are no buttons or axes at all if (GetButtonCount() == 0 && GetAxisCount() == 0) diff --git a/xbmc/platform/darwin/DarwinUtils.mm b/xbmc/platform/darwin/DarwinUtils.mm index 75a5559c3f..854f7267d2 100644 --- a/xbmc/platform/darwin/DarwinUtils.mm +++ b/xbmc/platform/darwin/DarwinUtils.mm @@ -81,16 +81,23 @@ enum iosPlatform iPhoneSE, iPhone7, iPhone8, + iPhoneXR, iPadAir2Wifi, iPadAir2Cellular, iPadPro9_7InchWifi, iPadPro9_7InchCellular, + iPad6thGeneration9_7InchWifi, + iPad6thGeneration9_7InchCellular, iPadPro12_9InchWifi, iPadPro12_9InchCellular, iPadPro2_12_9InchWifi, iPadPro2_12_9InchCellular, + iPadPro3_12_9InchWifi, + iPadPro3_12_9InchCellular, iPadPro_10_5InchWifi, iPadPro_10_5InchCellular, + iPadPro11InchWifi, + iPadPro11InchCellular, iPadMini3Wifi, iPadMini3Cellular, iPadMini4Wifi, @@ -100,6 +107,8 @@ enum iosPlatform iPhone7Plus, iPhone8Plus, iPhoneX, + iPhoneXS, + iPhoneXSMax, }; // platform strings are based on http://theiphonewiki.com/wiki/Models @@ -163,6 +172,9 @@ enum iosPlatform getIosPlatform() else if (devStr == "iPhone10,4") eDev = iPhone8; else if (devStr == "iPhone10,5") eDev = iPhone8Plus; else if (devStr == "iPhone10,6") eDev = iPhoneX; + else if (devStr == "iPhone11,2") eDev = iPhoneXS; + else if (devStr == "iPhone11,6") eDev = iPhoneXSMax; + else if (devStr == "iPhone11,8") eDev = iPhoneXR; else if (devStr == "iPod1,1") eDev = iPodTouch1G; else if (devStr == "iPod2,1") eDev = iPodTouch2G; else if (devStr == "iPod3,1") eDev = iPodTouch3G; @@ -207,6 +219,16 @@ enum iosPlatform getIosPlatform() else if (devStr == "iPad7,2") eDev = iPadPro2_12_9InchCellular; else if (devStr == "iPad7,3") eDev = iPadPro_10_5InchWifi; else if (devStr == "iPad7,4") eDev = iPadPro_10_5InchCellular; + else if (devStr == "iPad7,5") eDev = iPad6thGeneration9_7InchWifi; + else if (devStr == "iPad7,6") eDev = iPad6thGeneration9_7InchCellular; + else if (devStr == "iPad8,1") eDev = iPadPro11InchWifi; + else if (devStr == "iPad8,2") eDev = iPadPro11InchWifi; + else if (devStr == "iPad8,3") eDev = iPadPro11InchCellular; + else if (devStr == "iPad8,4") eDev = iPadPro11InchCellular; + else if (devStr == "iPad8,5") eDev = iPadPro3_12_9InchWifi; + else if (devStr == "iPad8,6") eDev = iPadPro3_12_9InchWifi; + else if (devStr == "iPad8,7") eDev = iPadPro3_12_9InchCellular; + else if (devStr == "iPad8,8") eDev = iPadPro3_12_9InchCellular; else if (devStr == "AppleTV2,1") eDev = AppleTV2; else if (devStr == "AppleTV5,3") eDev = AppleTV4; else if (devStr == "AppleTV6,2") eDev = AppleTV4K; diff --git a/xbmc/platform/darwin/ios/Info.plist.in b/xbmc/platform/darwin/ios/Info.plist.in index 9408ec57bc..c43a0e89ac 100644 --- a/xbmc/platform/darwin/ios/Info.plist.in +++ b/xbmc/platform/darwin/ios/Info.plist.in @@ -74,65 +74,176 @@ <key>UILaunchImages</key> <array> <dict> + <key>UILaunchImageOrientation</key> + <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-1200-Portrait-2224h</string> <key>UILaunchImageSize</key> - <string>{375, 667}</string> + <string>{834, 1112}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>12.0</string> + </dict> + <dict> + <key>UILaunchImageOrientation</key> + <string>Landscape</string> <key>UILaunchImageName</key> - <string>Default-667h</string> + <string>LaunchImage-1200-Landscape-2224h</string> + <key>UILaunchImageSize</key> + <string>{834, 1112}</string> <key>UILaunchImageMinimumOSVersion</key> - <string>8.0</string> + <string>12.0</string> + </dict> + <dict> <key>UILaunchImageOrientation</key> <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-1200-Portrait-2388h</string> + <key>UILaunchImageSize</key> + <string>{834, 1194}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>12.0</string> </dict> <dict> + <key>UILaunchImageOrientation</key> + <string>Landscape</string> + <key>UILaunchImageName</key> + <string>LaunchImage-1200-Landscape-2388h</string> <key>UILaunchImageSize</key> - <string>{414, 736}</string> + <string>{834, 1194}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>12.0</string> + </dict> + + <dict> + <key>UILaunchImageOrientation</key> + <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-1200-Portrait-2688h</string> + <key>UILaunchImageSize</key> + <string>{414, 896}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>12.0</string> + </dict> + <dict> + <key>UILaunchImageOrientation</key> + <string>Landscape</string> <key>UILaunchImageName</key> - <string>Default-736h</string> + <string>LaunchImage-1200-Landscape-2688h</string> + <key>UILaunchImageSize</key> + <string>{414, 896}</string> <key>UILaunchImageMinimumOSVersion</key> - <string>8.0</string> + <string>12.0</string> + </dict> + <dict> <key>UILaunchImageOrientation</key> <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-1200-Portrait-1792h</string> + <key>UILaunchImageSize</key> + <string>{414, 896}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>12.0</string> </dict> <dict> + <key>UILaunchImageOrientation</key> + <string>Landscape</string> + <key>UILaunchImageName</key> + <string>LaunchImage-1200-Landscape-1792h</string> <key>UILaunchImageSize</key> - <string>{414, 736}</string> + <string>{414, 896}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>12.0</string> + </dict> + <dict> + <key>UILaunchImageOrientation</key> + <string>Portrait</string> <key>UILaunchImageName</key> - <string>Default-Landscape-736h</string> + <string>LaunchImage-1100-Portrait-2436h</string> + <key>UILaunchImageSize</key> + <string>{375, 812}</string> <key>UILaunchImageMinimumOSVersion</key> - <string>8.0</string> + <string>11.0</string> + </dict> + <dict> <key>UILaunchImageOrientation</key> <string>Landscape</string> + <key>UILaunchImageName</key> + <string>LaunchImage-1100-Landscape-2436h</string> + <key>UILaunchImageSize</key> + <string>{375, 812}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>11.0</string> </dict> <dict> + <key>UILaunchImageOrientation</key> + <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-800-Portrait-736h</string> <key>UILaunchImageSize</key> - <string>{320, 568}</string> + <string>{414, 736}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>8.0</string> + </dict> + <dict> + <key>UILaunchImageOrientation</key> + <string>Landscape</string> <key>UILaunchImageName</key> - <string>Default-568h</string> + <string>LaunchImage-800-Landscape-736h</string> + <key>UILaunchImageSize</key> + <string>{414, 736}</string> <key>UILaunchImageMinimumOSVersion</key> <string>8.0</string> + </dict> + <dict> + <key>UILaunchImageOrientation</key> + <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-800-667h</string> + <key>UILaunchImageSize</key> + <string>{375, 667}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>8.0</string> + </dict> + <dict> + <key>UILaunchImageOrientation</key> + <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-700</string> + <key>UILaunchImageSize</key> + <string>{320, 480}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>7.0</string> + </dict> + <dict> + <key>UILaunchImageOrientation</key> + <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-700-568h</string> + <key>UILaunchImageSize</key> + <string>{320, 568}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>7.0</string> + </dict> + <dict> <key>UILaunchImageOrientation</key> <string>Portrait</string> + <key>UILaunchImageName</key> + <string>LaunchImage-700-Portrait</string> + <key>UILaunchImageSize</key> + <string>{768, 1024}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>7.0</string> + </dict> + <dict> + <key>UILaunchImageOrientation</key> + <string>Landscape</string> + <key>UILaunchImageName</key> + <string>LaunchImage-700-Landscape</string> + <key>UILaunchImageSize</key> + <string>{768, 1024}</string> + <key>UILaunchImageMinimumOSVersion</key> + <string>7.0</string> </dict> - <dict> - <key>UILaunchImageSize</key> - <string>{375, 812}</string> - <key>UILaunchImageName</key> - <string>Default-812h</string> - <key>UILaunchImageMinimumOSVersion</key> - <string>9.0</string> - <key>UILaunchImageOrientation</key> - <string>Portrait</string> - </dict> - <dict> - <key>UILaunchImageSize</key> - <string>{375, 812}</string> - <key>UILaunchImageName</key> - <string>Default-Landscape-812h</string> - <key>UILaunchImageMinimumOSVersion</key> - <string>9.0</string> - <key>UILaunchImageOrientation</key> - <string>Landscape</string> - </dict> </array> <key>UIDeviceFamily</key> <array> diff --git a/xbmc/platform/darwin/ios/Default-Landscape-812h@3x.png b/xbmc/platform/darwin/ios/LaunchImage-1100-Landscape-2436h@3x.png Binary files differindex b05f0a8a5a..b05f0a8a5a 100644 --- a/xbmc/platform/darwin/ios/Default-Landscape-812h@3x.png +++ b/xbmc/platform/darwin/ios/LaunchImage-1100-Landscape-2436h@3x.png diff --git a/xbmc/platform/darwin/ios/Default-812h@3x.png b/xbmc/platform/darwin/ios/LaunchImage-1100-Portrait-2436h@3x.png Binary files differindex 3248694b67..3248694b67 100644 --- a/xbmc/platform/darwin/ios/Default-812h@3x.png +++ b/xbmc/platform/darwin/ios/LaunchImage-1100-Portrait-2436h@3x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-1792h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-1792h@2x.png Binary files differnew file mode 100644 index 0000000000..e19f744f10 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-1792h@2x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2224h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2224h@2x.png Binary files differnew file mode 100644 index 0000000000..b546b2cd6a --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2224h@2x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2388h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2388h@2x.png Binary files differnew file mode 100644 index 0000000000..cf94b66656 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2388h@2x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2688h@3x.png b/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2688h@3x.png Binary files differnew file mode 100644 index 0000000000..c5b455355f --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-1200-Landscape-2688h@3x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-1792h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-1792h@2x.png Binary files differnew file mode 100644 index 0000000000..a7f64cd697 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-1792h@2x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2224h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2224h@2x.png Binary files differnew file mode 100644 index 0000000000..f477575770 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2224h@2x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2388h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2388h@2x.png Binary files differnew file mode 100644 index 0000000000..98c79b7389 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2388h@2x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2688h@3x.png b/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2688h@3x.png Binary files differnew file mode 100644 index 0000000000..77c55d7c5e --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-1200-Portrait-2688h@3x.png diff --git a/xbmc/platform/darwin/ios/Default-568h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-568h@2x.png Binary files differindex 7dcb0e7125..7dcb0e7125 100644 --- a/xbmc/platform/darwin/ios/Default-568h@2x.png +++ b/xbmc/platform/darwin/ios/LaunchImage-568h@2x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-700-568h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-700-568h@2x.png Binary files differnew file mode 100644 index 0000000000..7dcb0e7125 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-700-568h@2x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-700-Landscape@2x~ipad.png b/xbmc/platform/darwin/ios/LaunchImage-700-Landscape@2x~ipad.png Binary files differnew file mode 100644 index 0000000000..a344aba267 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-700-Landscape@2x~ipad.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-700-Portrait@2x~ipad.png b/xbmc/platform/darwin/ios/LaunchImage-700-Portrait@2x~ipad.png Binary files differnew file mode 100644 index 0000000000..93e9e7ea58 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-700-Portrait@2x~ipad.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-700@2x.png b/xbmc/platform/darwin/ios/LaunchImage-700@2x.png Binary files differnew file mode 100644 index 0000000000..d93013028d --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-700@2x.png diff --git a/xbmc/platform/darwin/ios/Default-667h@2x.png b/xbmc/platform/darwin/ios/LaunchImage-800-667h@2x.png Binary files differindex 57a786dcd7..57a786dcd7 100644 --- a/xbmc/platform/darwin/ios/Default-667h@2x.png +++ b/xbmc/platform/darwin/ios/LaunchImage-800-667h@2x.png diff --git a/xbmc/platform/darwin/ios/Default-Landscape-736h@3x.png b/xbmc/platform/darwin/ios/LaunchImage-800-Landscape-736h@3x.png Binary files differindex e99ea0a070..e99ea0a070 100644 --- a/xbmc/platform/darwin/ios/Default-Landscape-736h@3x.png +++ b/xbmc/platform/darwin/ios/LaunchImage-800-Landscape-736h@3x.png diff --git a/xbmc/platform/darwin/ios/Default-736h@3x.png b/xbmc/platform/darwin/ios/LaunchImage-800-Portrait-736h@3x.png Binary files differindex b1cc794440..f3049c2b58 100644 --- a/xbmc/platform/darwin/ios/Default-736h@3x.png +++ b/xbmc/platform/darwin/ios/LaunchImage-800-Portrait-736h@3x.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-Landscape@2x~ipad.png b/xbmc/platform/darwin/ios/LaunchImage-Landscape@2x~ipad.png Binary files differnew file mode 100644 index 0000000000..a344aba267 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-Landscape@2x~ipad.png diff --git a/xbmc/platform/darwin/ios/LaunchImage-Portrait@2x~ipad.png b/xbmc/platform/darwin/ios/LaunchImage-Portrait@2x~ipad.png Binary files differnew file mode 100644 index 0000000000..00fedc6dc0 --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage-Portrait@2x~ipad.png diff --git a/xbmc/platform/darwin/ios/LaunchImage@2x.png b/xbmc/platform/darwin/ios/LaunchImage@2x.png Binary files differnew file mode 100644 index 0000000000..d93013028d --- /dev/null +++ b/xbmc/platform/darwin/ios/LaunchImage@2x.png diff --git a/xbmc/platform/darwin/osx/storage/DarwinStorageProvider.cpp b/xbmc/platform/darwin/osx/storage/DarwinStorageProvider.cpp index 279b0758a7..c69d42aa62 100644 --- a/xbmc/platform/darwin/osx/storage/DarwinStorageProvider.cpp +++ b/xbmc/platform/darwin/osx/storage/DarwinStorageProvider.cpp @@ -340,23 +340,17 @@ bool CDarwinStorageProvider::Eject(const std::string& mountpath) bool CDarwinStorageProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback) { - bool changed = !m_mountsToNotify.empty() || !m_unmountsToNotify.empty(); - - if (callback) + // Note: If we find a way to only notify kodi user initiated mounts/unmounts we + // could do this here, but currently we can't distinguish this and popups + // for system initiated mounts/unmounts (like done by Time Machine automatic + // backups) are very confusing and annoying. + bool bChanged = !m_mountsToNotify.empty() || !m_unmountsToNotify.empty(); + if (bChanged) { - for (const auto& mountToNotify : m_mountsToNotify) - { - callback->OnStorageAdded(mountToNotify.first, mountToNotify.second); - } m_mountsToNotify.clear(); - - for (const auto& unmountToNotify : m_unmountsToNotify) - { - callback->OnStorageSafelyRemoved(unmountToNotify.first); - } m_unmountsToNotify.clear(); } - return changed; + return bChanged; } void CDarwinStorageProvider::VolumeMountNotification(const char* label, const char* mountpoint) diff --git a/xbmc/platform/linux/input/LibInputHandler.cpp b/xbmc/platform/linux/input/LibInputHandler.cpp index c7dbac7d43..d2e93d308b 100644 --- a/xbmc/platform/linux/input/LibInputHandler.cpp +++ b/xbmc/platform/linux/input/LibInputHandler.cpp @@ -181,6 +181,9 @@ void CLibInputHandler::ProcessEvent(libinput_event *ev) case LIBINPUT_EVENT_POINTER_MOTION: m_pointer->ProcessMotion(libinput_event_get_pointer_event(ev)); break; + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: + m_pointer->ProcessMotionAbsolute(libinput_event_get_pointer_event(ev)); + break; case LIBINPUT_EVENT_POINTER_AXIS: m_pointer->ProcessAxis(libinput_event_get_pointer_event(ev)); break; diff --git a/xbmc/platform/linux/input/LibInputPointer.cpp b/xbmc/platform/linux/input/LibInputPointer.cpp index 82c1a25471..591a5c6fd0 100644 --- a/xbmc/platform/linux/input/LibInputPointer.cpp +++ b/xbmc/platform/linux/input/LibInputPointer.cpp @@ -96,6 +96,23 @@ void CLibInputPointer::ProcessMotion(libinput_event_pointer *e) appPort->OnEvent(event); } +void CLibInputPointer::ProcessMotionAbsolute(libinput_event_pointer *e) +{ + m_pos.X = static_cast<int>(libinput_event_pointer_get_absolute_x_transformed(e, CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth())); + m_pos.Y = static_cast<int>(libinput_event_pointer_get_absolute_y_transformed(e, CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight())); + + XBMC_Event event; + event.type = XBMC_MOUSEMOTION; + event.motion.x = static_cast<uint16_t>(m_pos.X); + event.motion.y = static_cast<uint16_t>(m_pos.Y); + + CLog::Log(LOGDEBUG, "CLibInputPointer::%s - event.type: %i, event.motion.x: %i, event.motion.y: %i", __FUNCTION__, event.type, event.motion.x, event.motion.y); + + std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort(); + if (appPort) + appPort->OnEvent(event); +} + void CLibInputPointer::ProcessAxis(libinput_event_pointer *e) { unsigned char scroll = 0; diff --git a/xbmc/platform/linux/input/LibInputPointer.h b/xbmc/platform/linux/input/LibInputPointer.h index aa7c8b90a3..608b438abe 100644 --- a/xbmc/platform/linux/input/LibInputPointer.h +++ b/xbmc/platform/linux/input/LibInputPointer.h @@ -24,6 +24,7 @@ public: void ProcessButton(libinput_event_pointer *e); void ProcessMotion(libinput_event_pointer *e); + void ProcessMotionAbsolute(libinput_event_pointer *e); void ProcessAxis(libinput_event_pointer *e); private: diff --git a/xbmc/platform/linux/powermanagement/LogindUPowerSyscall.cpp b/xbmc/platform/linux/powermanagement/LogindUPowerSyscall.cpp index 120429ecee..9e65e939fc 100644 --- a/xbmc/platform/linux/powermanagement/LogindUPowerSyscall.cpp +++ b/xbmc/platform/linux/powermanagement/LogindUPowerSyscall.cpp @@ -121,7 +121,37 @@ bool CLogindUPowerSyscall::HasLogind() // recommended method by systemd devs. The seats directory // doesn't exist unless logind created it and therefore is running. // see also https://mail.gnome.org/archives/desktop-devel-list/2013-March/msg00092.html - return (access("/run/systemd/seats/", F_OK) >= 0); + if (access("/run/systemd/seats/", F_OK) >= 0) + return true; + + // on some environments "/run/systemd/seats/" doesn't exist, e.g. on flatpak. Try DBUS instead. + CDBusMessage message(LOGIND_DEST, LOGIND_PATH, LOGIND_IFACE, "ListSeats"); + DBusMessage *reply = message.SendSystem(); + if (!reply) + return false; + + DBusMessageIter arrIter; + if (dbus_message_iter_init(reply, &arrIter) && dbus_message_iter_get_arg_type(&arrIter) == DBUS_TYPE_ARRAY) + { + DBusMessageIter structIter; + dbus_message_iter_recurse(&arrIter, &structIter); + if (dbus_message_iter_get_arg_type(&structIter) == DBUS_TYPE_STRUCT) + { + DBusMessageIter strIter; + dbus_message_iter_recurse(&structIter, &strIter); + if (dbus_message_iter_get_arg_type(&strIter) == DBUS_TYPE_STRING) + { + char *seat; + dbus_message_iter_get_basic(&strIter, &seat); + if (StringUtils::StartsWith(seat, "seat")) + { + CLog::Log(LOGDEBUG, "LogindUPowerSyscall::HasLogind - found seat: {}", seat); + return true; + } + } + } + } + return false; } bool CLogindUPowerSyscall::LogindSetPowerState(const char *state) diff --git a/xbmc/pvr/PVRGUITimerInfo.cpp b/xbmc/pvr/PVRGUITimerInfo.cpp index aca62b8f1f..12b8870bfc 100644 --- a/xbmc/pvr/PVRGUITimerInfo.cpp +++ b/xbmc/pvr/PVRGUITimerInfo.cpp @@ -56,14 +56,19 @@ bool CPVRGUITimerInfo::TimerInfoToggle() return true; } - if ((int) (XbmcThreads::SystemClockMillis() - m_iTimerInfoToggleStart) > CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRInfoToggleInterval) + if (static_cast<int>(XbmcThreads::SystemClockMillis() - m_iTimerInfoToggleStart) > + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRInfoToggleInterval) { unsigned int iPrevious = m_iTimerInfoToggleCurrent; unsigned int iBoundary = m_iRecordingTimerAmount > 0 ? m_iRecordingTimerAmount : m_iTimerAmount; if (++m_iTimerInfoToggleCurrent > iBoundary - 1) m_iTimerInfoToggleCurrent = 0; - return m_iTimerInfoToggleCurrent != iPrevious; + if (m_iTimerInfoToggleCurrent != iPrevious) + { + m_iTimerInfoToggleStart = XbmcThreads::SystemClockMillis(); + return true; + } } return false; diff --git a/xbmc/pvr/PVRGUITimesInfo.cpp b/xbmc/pvr/PVRGUITimesInfo.cpp index 228f05bb23..402b390237 100644 --- a/xbmc/pvr/PVRGUITimesInfo.cpp +++ b/xbmc/pvr/PVRGUITimesInfo.cpp @@ -166,7 +166,7 @@ void CPVRGUITimesInfo::UpdateTimeshiftProgressData() time_t start = 0; m_playingEpgTag->StartAsUTC().GetAsTime(start); if (start < m_iTimeshiftStartTime || - CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRMENU_USESIMPLETIMESHIFTOSD)) + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRTimeshiftSimpleOSD) { // playing event started before start of ts buffer or simple ts osd to be used m_iTimeshiftProgressStartTime = start; @@ -189,7 +189,7 @@ void CPVRGUITimesInfo::UpdateTimeshiftProgressData() time_t end = 0; m_playingEpgTag->EndAsUTC().GetAsTime(end); if (end > m_iTimeshiftEndTime || - CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRMENU_USESIMPLETIMESHIFTOSD)) + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRTimeshiftSimpleOSD) { // playing event will end after end of ts buffer or simple ts osd to be used m_iTimeshiftProgressEndTime = end; diff --git a/xbmc/pvr/channels/PVRChannel.cpp b/xbmc/pvr/channels/PVRChannel.cpp index d932e97d8c..173100c0ea 100644 --- a/xbmc/pvr/channels/PVRChannel.cpp +++ b/xbmc/pvr/channels/PVRChannel.cpp @@ -624,7 +624,7 @@ void CPVRChannel::ToSortable(SortItem& sortable, Field field) const if (field == FieldChannelName) sortable[FieldChannelName] = m_strChannelName; else if (field == FieldChannelNumber) - sortable[FieldChannelNumber] = m_channelNumber.FormattedChannelNumber(); + sortable[FieldChannelNumber] = m_channelNumber.SortableChannelNumber(); else if (field == FieldLastPlayed) { const CDateTime lastWatched(m_iLastWatched); diff --git a/xbmc/pvr/channels/PVRChannelNumber.cpp b/xbmc/pvr/channels/PVRChannelNumber.cpp index fd17bf1375..0f8d6a0bea 100644 --- a/xbmc/pvr/channels/PVRChannelNumber.cpp +++ b/xbmc/pvr/channels/PVRChannelNumber.cpp @@ -16,8 +16,21 @@ const char CPVRChannelNumber::SEPARATOR = '.'; std::string CPVRChannelNumber::FormattedChannelNumber() const { + return ToString(SEPARATOR); +} + +std::string CPVRChannelNumber::SortableChannelNumber() const +{ + // Note: The subchannel separator is a character that does not work for a + // SortItem (at least not on all platforms). See SortUtils::Sort for + // details. Only numbers, letters and the blank are safe to use. + return ToString(' '); +} + +std::string CPVRChannelNumber::ToString(char separator) const +{ if (m_iSubChannelNumber == 0) return StringUtils::Format("%u", m_iChannelNumber); else - return StringUtils::Format("%u%c%u", m_iChannelNumber, SEPARATOR, m_iSubChannelNumber); + return StringUtils::Format("%u%c%u", m_iChannelNumber, separator, m_iSubChannelNumber); } diff --git a/xbmc/pvr/channels/PVRChannelNumber.h b/xbmc/pvr/channels/PVRChannelNumber.h index de5483348f..b4ed1a4d6c 100644 --- a/xbmc/pvr/channels/PVRChannelNumber.h +++ b/xbmc/pvr/channels/PVRChannelNumber.h @@ -73,7 +73,15 @@ namespace PVR */ std::string FormattedChannelNumber() const; + /*! + * @brief Get a string representation for the channel number that can be used for SortItems. + * @return The sortable string in the form <channel> <subchannel>. + */ + std::string SortableChannelNumber() const; + private: + std::string ToString(char separator) const; + unsigned int m_iChannelNumber = 0; unsigned int m_iSubChannelNumber = 0; }; diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp index b4ad7614d0..a6b592c737 100644 --- a/xbmc/pvr/epg/EpgInfoTag.cpp +++ b/xbmc/pvr/epg/EpgInfoTag.cpp @@ -185,7 +185,7 @@ void CPVREpgInfoTag::ToSortable(SortItem& sortable, Field field) const sortable[FieldChannelName] = m_channel->ChannelName(); break; case FieldChannelNumber: - sortable[FieldChannelNumber] = m_channel->ChannelNumber().FormattedChannelNumber(); + sortable[FieldChannelNumber] = m_channel->ChannelNumber().SortableChannelNumber(); break; case FieldLastPlayed: { diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp index 871da80593..b50f68e0d7 100644 --- a/xbmc/pvr/recordings/PVRRecording.cpp +++ b/xbmc/pvr/recordings/PVRRecording.cpp @@ -302,8 +302,12 @@ bool CPVRRecording::SetResumePoint(double timeInSeconds, double totalTimeInSecon CBookmark CPVRRecording::GetResumePoint() const { const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId); - if (client && client->GetClientCapabilities().SupportsRecordingsLastPlayedPosition()) + if (client && client->GetClientCapabilities().SupportsRecordingsLastPlayedPosition() && + m_resumePointRefetchTimeout.IsTimePast()) { + // @todo: root cause should be fixed. details: https://github.com/xbmc/xbmc/pull/14961 + m_resumePointRefetchTimeout.Set(10000); // update resume point from backend at most every 10 secs + int pos = -1; client->GetRecordingLastPlayedPosition(*this, pos); diff --git a/xbmc/pvr/recordings/PVRRecording.h b/xbmc/pvr/recordings/PVRRecording.h index 90ae6f521d..72e57eda8e 100644 --- a/xbmc/pvr/recordings/PVRRecording.h +++ b/xbmc/pvr/recordings/PVRRecording.h @@ -29,6 +29,7 @@ #include "XBDateTime.h" #include "addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h" +#include "threads/SystemClock.h" #include "video/VideoInfoTag.h" #include "pvr/PVRTypes.h" @@ -320,6 +321,7 @@ namespace PVR bool m_bRadio; /*!< radio or tv recording */ int m_iGenreType = 0; /*!< genre type */ int m_iGenreSubType = 0; /*!< genre subtype */ + mutable XbmcThreads::EndTime m_resumePointRefetchTimeout; void UpdatePath(void); }; diff --git a/xbmc/rendering/dx/DeviceResources.cpp b/xbmc/rendering/dx/DeviceResources.cpp index 669c5e7682..bdb2fafc9c 100644 --- a/xbmc/rendering/dx/DeviceResources.cpp +++ b/xbmc/rendering/dx/DeviceResources.cpp @@ -195,13 +195,14 @@ bool DX::DeviceResources::SetFullScreen(bool fullscreen, RESOLUTION_INFO& res) critical_section::scoped_lock lock(m_criticalSection); - CLog::LogF(LOGDEBUG, "switching to/from fullscreen (%f x %f)", m_outputSize.Width, - m_outputSize.Height); - BOOL bFullScreen; - bool recreate = m_stereoEnabled != (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() == RENDER_STEREO_MODE_HARDWAREBASED); - m_swapChain->GetFullscreenState(&bFullScreen, nullptr); + + CLog::LogF(LOGDEBUG, "switching from %s(%.0f x %.0f) to %s(%d x %d)", + bFullScreen ? "fullscreen " : "", m_outputSize.Width, m_outputSize.Height, + fullscreen ? "fullscreen " : "", res.iWidth, res.iHeight); + + bool recreate = m_stereoEnabled != (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() == RENDER_STEREO_MODE_HARDWAREBASED); if (!!bFullScreen && !fullscreen) { CLog::LogF(LOGDEBUG, "switching to windowed"); @@ -257,7 +258,15 @@ bool DX::DeviceResources::SetFullScreen(bool fullscreen, RESOLUTION_INFO& res) recreate |= SUCCEEDED(m_swapChain->SetFullscreenState(true, pOutput.Get())); m_swapChain->GetFullscreenState(&bFullScreen, nullptr); } - recreate |= SUCCEEDED(m_swapChain->ResizeTarget(¤tMode)); + bool resized = SUCCEEDED(m_swapChain->ResizeTarget(¤tMode)); + if (resized) + { + // some system doesn't inform windowing about desktop size changes + // so we have to change output size before resizing buffers + m_outputSize.Width = static_cast<float>(currentMode.Width); + m_outputSize.Height = static_cast<float>(currentMode.Height); + } + recreate |= resized; } } if (!bFullScreen) @@ -276,7 +285,7 @@ bool DX::DeviceResources::SetFullScreen(bool fullscreen, RESOLUTION_INFO& res) CLog::LogF(LOGDEBUG, "switching done."); - return true; + return recreate; } // Configures resources that don't depend on the Direct3D device. @@ -516,16 +525,20 @@ void DX::DeviceResources::ResizeBuffers() DXGI_SWAP_CHAIN_DESC1 scDesc = { 0 }; if (m_swapChain) { + BOOL bFullcreen = 0; + m_swapChain->GetFullscreenState(&bFullcreen, nullptr); + if (!!bFullcreen) + { + windowed = false; + } + // check if swapchain needs to be recreated m_swapChain->GetDesc1(&scDesc); if ((scDesc.Stereo == TRUE) != bHWStereoEnabled) { // check fullscreen state and go to windowing if necessary - BOOL bFullcreen; - m_swapChain->GetFullscreenState(&bFullcreen, nullptr); if (!!bFullcreen) { - windowed = false; // will create fullscreen swapchain m_swapChain->SetFullscreenState(false, nullptr); // mandatory before releasing swapchain } @@ -544,7 +557,7 @@ void DX::DeviceResources::ResizeBuffers() lround(m_outputSize.Width), lround(m_outputSize.Height), scDesc.Format, - 0 + windowed ? 0 : DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH ); if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) @@ -569,7 +582,7 @@ void DX::DeviceResources::ResizeBuffers() swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 3 * (1 + bHWStereoEnabled); swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - swapChainDesc.Flags = 0; + swapChainDesc.Flags = windowed ? 0 : DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; diff --git a/xbmc/rendering/gl/RenderSystemGL.cpp b/xbmc/rendering/gl/RenderSystemGL.cpp index 0d83f858e5..94846c4a62 100644 --- a/xbmc/rendering/gl/RenderSystemGL.cpp +++ b/xbmc/rendering/gl/RenderSystemGL.cpp @@ -48,21 +48,25 @@ bool CRenderSystemGL::InitRenderSystem() if (m_RenderVersionMajor > 3 || (m_RenderVersionMajor == 3 && m_RenderVersionMinor >= 2)) { - GLint n; + GLint n = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &n); if (n > 0) { GLint i; for (i = 0; i < n; i++) { - m_RenderExtensions += (const char*)glGetStringi(GL_EXTENSIONS, i); + m_RenderExtensions += (const char*) glGetStringi(GL_EXTENSIONS, i); m_RenderExtensions += " "; } } } else { - m_RenderExtensions += (const char*) glGetString(GL_EXTENSIONS); + auto extensions = (const char*) glGetString(GL_EXTENSIONS); + if (extensions) + { + m_RenderExtensions += extensions; + } } m_RenderExtensions += " "; @@ -111,6 +115,9 @@ bool CRenderSystemGL::InitRenderSystem() bool CRenderSystemGL::ResetRenderSystem(int width, int height) { + if (!m_bRenderCreated) + return false; + m_width = width; m_height = height; diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp index 54669aa7ca..60eecd2d59 100644 --- a/xbmc/rendering/gles/RenderSystemGLES.cpp +++ b/xbmc/rendering/gles/RenderSystemGLES.cpp @@ -9,10 +9,11 @@ #include "guilib/DirtyRegion.h" #include "windowing/GraphicContext.h" #include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" #include "RenderSystemGLES.h" #include "rendering/MatrixGL.h" -#include "utils/log.h" #include "utils/GLUtils.h" +#include "utils/log.h" #include "utils/TimeUtils.h" #include "utils/SystemInfo.h" #include "utils/MathUtils.h" @@ -20,6 +21,10 @@ #include "XTimeUtils.h" #endif +#if defined(TARGET_LINUX) +#include "utils/EGLUtils.h" +#endif + CRenderSystemGLES::CRenderSystemGLES() : CRenderSystemBase() { @@ -36,9 +41,7 @@ bool CRenderSystemGLES::InitRenderSystem() glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); m_maxTextureSize = maxTextureSize; - m_bVSync = false; - m_iVSyncMode = 0; - m_bVsyncInit = false; + // Get the GLES version number m_RenderVersionMajor = 0; m_RenderVersionMinor = 0; @@ -73,6 +76,30 @@ bool CRenderSystemGLES::InitRenderSystem() m_RenderExtensions += " "; +//! @todo remove TARGET_RASPBERRY_PI when Raspberry Pi updates their GL headers +#if defined(GL_KHR_debug) && defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI) + if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_openGlDebugging) + { + if (IsExtSupported("GL_KHR_debug")) + { + auto glDebugMessageCallback = CEGLUtils::GetRequiredProcAddress<PFNGLDEBUGMESSAGECALLBACKKHRPROC>("glDebugMessageCallbackKHR"); + auto glDebugMessageControl = CEGLUtils::GetRequiredProcAddress<PFNGLDEBUGMESSAGECONTROLKHRPROC>("glDebugMessageControlKHR"); + + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); + glDebugMessageCallback(KODI::UTILS::GL::GlErrorCallback, nullptr); + + // ignore shader compilation information + glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER_KHR, GL_DEBUG_TYPE_OTHER_KHR, GL_DONT_CARE, 0, nullptr, GL_FALSE); + + CLog::Log(LOGDEBUG, "OpenGL(ES): debugging enabled"); + } + else + { + CLog::Log(LOGDEBUG, "OpenGL(ES): debugging requested but the required extension isn't available (GL_KHR_debug)"); + } + } +#endif + LogGraphicsInfo(); m_bRenderCreated = true; @@ -210,7 +237,7 @@ void CRenderSystemGLES::PresentRender(bool rendered, bool videoLayer) void CRenderSystemGLES::SetVSync(bool enable) { - if (m_bVSync==enable && m_bVsyncInit == true) + if (m_bVsyncInit) return; if (!m_bRenderCreated) @@ -221,20 +248,9 @@ void CRenderSystemGLES::SetVSync(bool enable) else CLog::Log(LOGINFO, "GLES: Disabling VSYNC"); - m_iVSyncMode = 0; - m_iVSyncErrors = 0; - m_bVSync = enable; - m_bVsyncInit = true; + m_bVsyncInit = true; SetVSyncImpl(enable); - - if (!enable) - return; - - if (!m_iVSyncMode) - CLog::Log(LOGERROR, "GLES: Vertical Blank Syncing unsupported"); - else - CLog::Log(LOGINFO, "GLES: Selected vsync mode %d", m_iVSyncMode); } void CRenderSystemGLES::CaptureStateBlock() diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h index c7ddbc606d..19603437c9 100644 --- a/xbmc/rendering/gles/RenderSystemGLES.h +++ b/xbmc/rendering/gles/RenderSystemGLES.h @@ -91,11 +91,9 @@ protected: virtual void PresentRenderImpl(bool rendered) = 0; void CalculateMaxTexturesize(); - int m_iVSyncMode; - int m_iVSyncErrors; - bool m_bVsyncInit; - int m_width; - int m_height; + bool m_bVsyncInit{false}; + int m_width; + int m_height; std::string m_RenderExtensions; diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp index 1da4b9cdf9..f3931613ed 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -386,6 +386,7 @@ void CAdvancedSettings::Initialize() m_bPVRAutoScanIconsUserSet = false; m_iPVRNumericChannelSwitchTimeout = 2000; m_iPVRTimeshiftThreshold = 10; + m_bPVRTimeshiftSimpleOSD = true; m_cacheMemSize = 1024 * 1024 * 20; m_cacheBufferMode = CACHE_BUFFER_MODE_INTERNET; // Default (buffer all internet streams/filesystems) @@ -433,6 +434,8 @@ void CAdvancedSettings::Initialize() m_extraLogEnabled = false; m_extraLogLevels = 0; + m_openGlDebugging = false; + m_userAgent = g_sysinfo.GetUserAgent(); m_initialized = true; @@ -565,6 +568,12 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) XMLUtils::GetBoolean(pElement, "omxdecodestartwithvalidframe", m_omxDecodeStartWithValidFrame); } + pElement = pRootElement->FirstChildElement("x11"); + if (pElement) + { + XMLUtils::GetBoolean(pElement, "omlsync", m_omlSync); + } + pElement = pRootElement->FirstChildElement("video"); if (pElement) { @@ -1117,6 +1126,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) XMLUtils::GetBoolean(pPVR, "autoscaniconsuserset", m_bPVRAutoScanIconsUserSet); XMLUtils::GetInt(pPVR, "numericchannelswitchtimeout", m_iPVRNumericChannelSwitchTimeout, 50, 60000); XMLUtils::GetInt(pPVR, "timeshiftthreshold", m_iPVRTimeshiftThreshold, 0, 60); + XMLUtils::GetBoolean(pPVR, "timeshiftsimpleosd", m_bPVRTimeshiftSimpleOSD); } TiXmlElement* pDatabase = pRootElement->FirstChildElement("videodatabase"); @@ -1229,6 +1239,8 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) m_seekSteps.push_back(atoi((*it).c_str())); } + XMLUtils::GetBoolean(pRootElement, "opengldebugging", m_openGlDebugging); + // load in the settings overrides CServiceBroker::GetSettingsComponent()->GetSettings()->LoadHidden(pRootElement); } diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h index 2c353d476b..1df75ad562 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h @@ -135,6 +135,8 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler bool m_omxDecodeStartWithValidFrame; + bool m_omlSync = false; + float m_videoSubsDelayRange; float m_videoAudioDelayRange; bool m_videoUseTimeSeeking; @@ -332,6 +334,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler bool m_bPVRAutoScanIconsUserSet; /*!< @brief mark channel icons populated by auto scan as "user set" */ int m_iPVRNumericChannelSwitchTimeout; /*!< @brief time in msecs after that a channel switch occurs after entering a channel number, if confirmchannelswitch is disabled */ int m_iPVRTimeshiftThreshold; /*!< @brief time diff between current playing time and timeshift buffer end, in seconds, before a playing stream is displayed as timeshifting. */ + bool m_bPVRTimeshiftSimpleOSD; /*!< @brief use simple timeshift OSD (with progress only for the playing event instead of progress for the whole ts buffer). */ DatabaseSettings m_databaseMusic; // advanced music database setup DatabaseSettings m_databaseVideo; // advanced video database setup DatabaseSettings m_databaseTV; // advanced tv database setup @@ -381,6 +384,8 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler False to show at the bottom of video (default) */ bool m_videoAssFixedWorks; + bool m_openGlDebugging; + std::string m_userAgent; private: diff --git a/xbmc/settings/DisplaySettings.cpp b/xbmc/settings/DisplaySettings.cpp index 55985f5f56..a5c00dd05e 100644 --- a/xbmc/settings/DisplaySettings.cpp +++ b/xbmc/settings/DisplaySettings.cpp @@ -329,10 +329,16 @@ bool CDisplaySettings::OnSettingChanging(std::shared_ptr<const CSetting> setting return true; } -#if defined(HAVE_X11) +#if defined(HAVE_X11) || defined(TARGET_WINDOWS_DESKTOP) else if (settingId == CSettings::SETTING_VIDEOSCREEN_BLANKDISPLAYS) { - CServiceBroker::GetWinSystem()->UpdateResolutions(); + auto winSystem = CServiceBroker::GetWinSystem(); +#if defined(HAVE_X11) + winSystem->UpdateResolutions(); +#elif defined(TARGET_WINDOWS_DESKTOP) + CGraphicContext& gfxContext = winSystem->GetGfxContext(); + gfxContext.SetVideoResolution(gfxContext.GetVideoResolution(), true); +#endif } #endif @@ -566,6 +572,12 @@ void CDisplaySettings::UpdateCalibrations() } } +void CDisplaySettings::ClearCalibrations() +{ + CSingleLock lock(m_critical); + m_calibrations.clear(); +} + DisplayMode CDisplaySettings::GetCurrentDisplayMode() const { if (GetCurrentResolution() == RES_WINDOW) diff --git a/xbmc/settings/DisplaySettings.h b/xbmc/settings/DisplaySettings.h index 75160cb42d..d525c995d8 100644 --- a/xbmc/settings/DisplaySettings.h +++ b/xbmc/settings/DisplaySettings.h @@ -71,6 +71,7 @@ public: void ApplyCalibrations(); void UpdateCalibrations(); + void ClearCalibrations(); void ClearCustomResolutions(); float GetZoomAmount() const { return m_zoomAmount; } diff --git a/xbmc/settings/MediaSettings.cpp b/xbmc/settings/MediaSettings.cpp index 69d3888ae7..8cccd71c4d 100644 --- a/xbmc/settings/MediaSettings.cpp +++ b/xbmc/settings/MediaSettings.cpp @@ -17,14 +17,17 @@ #include "dialogs/GUIDialogFileBrowser.h" #include "settings/dialogs/GUIDialogLibExportSettings.h" #include "guilib/LocalizeStrings.h" +#include "interfaces/AnnouncementManager.h" #include "interfaces/builtins/Builtins.h" #include "music/MusicDatabase.h" #include "music/MusicLibraryQueue.h" #include "messaging/helpers/DialogHelper.h" +#include "ServiceBroker.h" #include "settings/lib/Setting.h" #include "settings/Settings.h" #include "storage/MediaManager.h" #include "threads/SingleLock.h" +#include "utils/log.h" #include "utils/StringUtils.h" #include "utils/XBMCTinyXML.h" #include "utils/XMLUtils.h" @@ -343,6 +346,15 @@ void CMediaSettings::OnSettingAction(std::shared_ptr<const CSetting> setting) } } +void CMediaSettings::OnSettingChanged(std::shared_ptr<const CSetting> setting) +{ + if (setting == nullptr) + return; + + if (setting->GetId() == CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS) + CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnRefresh"); +} + int CMediaSettings::GetWatchedMode(const std::string &content) const { CSingleLock lock(m_critical); diff --git a/xbmc/settings/MediaSettings.h b/xbmc/settings/MediaSettings.h index 3ab6302344..93f480359e 100644 --- a/xbmc/settings/MediaSettings.h +++ b/xbmc/settings/MediaSettings.h @@ -39,6 +39,7 @@ public: bool Save(TiXmlNode *settings) const override; void OnSettingAction(std::shared_ptr<const CSetting> setting) override; + void OnSettingChanged(std::shared_ptr<const CSetting> setting) override; void OnSettingsLoaded() override; const CVideoSettings& GetDefaultVideoSettings() const { return m_defaultVideoSettings; } diff --git a/xbmc/settings/SettingDateTime.h b/xbmc/settings/SettingDateTime.h index 73d1b78055..5d05fa4d73 100644 --- a/xbmc/settings/SettingDateTime.h +++ b/xbmc/settings/SettingDateTime.h @@ -10,6 +10,7 @@ #include "XBDateTime.h" #include "settings/lib/Setting.h" +#include "utils/TimeUtils.h" class CSettingDate : public CSettingString { @@ -40,5 +41,5 @@ public: bool CheckValidity(const std::string &value) const override; CDateTime GetTime() const { return CDateTime::FromDBTime(GetValue()); } - bool SetTime(const CDateTime& time) { return SetValue(time.GetAsDBTime()); } + bool SetTime(const CDateTime& time) { return SetValue(CTimeUtils::WithoutSeconds(time.GetAsDBTime())); } }; diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp index 0f50e170c4..b299b73fac 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp @@ -201,7 +201,6 @@ const std::string CSettings::SETTING_PVRMANAGER_GROUPMANAGER = "pvrmanager.group const std::string CSettings::SETTING_PVRMANAGER_CHANNELSCAN = "pvrmanager.channelscan"; const std::string CSettings::SETTING_PVRMANAGER_RESETDB = "pvrmanager.resetdb"; const std::string CSettings::SETTING_PVRMENU_DISPLAYCHANNELINFO = "pvrmenu.displaychannelinfo"; -const std::string CSettings::SETTING_PVRMENU_USESIMPLETIMESHIFTOSD = "pvrmenu.usesimpletimeshiftosd"; const std::string CSettings::SETTING_PVRMENU_ICONPATH = "pvrmenu.iconpath"; const std::string CSettings::SETTING_PVRMENU_SEARCHICONS = "pvrmenu.searchicons"; const std::string CSettings::SETTING_EPG_PAST_DAYSTODISPLAY = "epg.pastdaystodisplay"; @@ -834,6 +833,7 @@ void CSettings::InitializeISettingCallbacks() settingSet.insert(CSettings::SETTING_VIDEOLIBRARY_CLEANUP); settingSet.insert(CSettings::SETTING_VIDEOLIBRARY_IMPORT); settingSet.insert(CSettings::SETTING_VIDEOLIBRARY_EXPORT); + settingSet.insert(CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS); GetSettingsManager()->RegisterCallback(&CMediaSettings::GetInstance(), settingSet); settingSet.clear(); @@ -844,6 +844,7 @@ void CSettings::InitializeISettingCallbacks() settingSet.insert(CSettings::SETTING_VIDEOSCREEN_PREFEREDSTEREOSCOPICMODE); settingSet.insert(CSettings::SETTING_VIDEOSCREEN_3DLUT); settingSet.insert(CSettings::SETTING_VIDEOSCREEN_DISPLAYPROFILE); + settingSet.insert(CSettings::SETTING_VIDEOSCREEN_BLANKDISPLAYS); GetSettingsManager()->RegisterCallback(&CDisplaySettings::GetInstance(), settingSet); settingSet.clear(); diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h index 29536d40af..95baba2a7e 100644 --- a/xbmc/settings/Settings.h +++ b/xbmc/settings/Settings.h @@ -161,7 +161,6 @@ public: static const std::string SETTING_PVRMANAGER_CHANNELSCAN; static const std::string SETTING_PVRMANAGER_RESETDB; static const std::string SETTING_PVRMENU_DISPLAYCHANNELINFO; - static const std::string SETTING_PVRMENU_USESIMPLETIMESHIFTOSD; static const std::string SETTING_PVRMENU_ICONPATH; static const std::string SETTING_PVRMENU_SEARCHICONS; static const std::string SETTING_EPG_PAST_DAYSTODISPLAY; @@ -374,6 +373,10 @@ public: static const std::string SETTING_SOURCE_VIDEOS; static const std::string SETTING_SOURCE_MUSIC; static const std::string SETTING_SOURCE_PICTURES; + // values for SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS + static const int VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_MOVIES = 0; + static const int VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_TVSHOWEPISODES = 1; + static const int VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE = 2; /*! \brief Creates a new settings wrapper around a new settings manager. diff --git a/xbmc/settings/windows/GUIControlSettings.cpp b/xbmc/settings/windows/GUIControlSettings.cpp index 78eb03691e..90d205bce1 100644 --- a/xbmc/settings/windows/GUIControlSettings.cpp +++ b/xbmc/settings/windows/GUIControlSettings.cpp @@ -648,14 +648,7 @@ bool CGUIControlButtonSetting::OnClick() SYSTEMTIME systemtime; settingTime->GetTime().GetAsSystemTime(systemtime); - /* TODO - if (value.size() >= 5) - { - // assumes HH:MM - systemtime.wHour = atoi(value.substr(0, 2).c_str()); - systemtime.wMinute = atoi(value.substr(3, 2).c_str()); - } - */ + if (CGUIDialogNumeric::ShowAndGetTime(systemtime, Localize(buttonControl->GetHeading()))) SetValid(settingTime->SetTime(CDateTime(systemtime))); } diff --git a/xbmc/storage/DetectDVDType.cpp b/xbmc/storage/DetectDVDType.cpp index 63298390b8..b2baa16303 100644 --- a/xbmc/storage/DetectDVDType.cpp +++ b/xbmc/storage/DetectDVDType.cpp @@ -328,6 +328,11 @@ DWORD CDetectDVDMedia::GetTrayState() } laststatus = status; m_cdio->cdio_destroy(cdio); + + if (status == DRIVER_OP_UNSUPPORTED) + { + return DRIVE_NONE; + } } else return DRIVE_NOT_READY; diff --git a/xbmc/utils/EGLUtils.cpp b/xbmc/utils/EGLUtils.cpp index 27a0567f96..25d93985a6 100644 --- a/xbmc/utils/EGLUtils.cpp +++ b/xbmc/utils/EGLUtils.cpp @@ -17,6 +17,8 @@ #include <EGL/eglext.h> +#include <map> + namespace { //! @todo remove when Raspberry Pi updates their EGL headers @@ -34,7 +36,7 @@ namespace #endif #define X(VAL) std::make_pair(VAL, #VAL) -std::array<std::pair<EGLint, const char*>, 32> eglAttributes = +std::map<EGLint, const char*> eglAttributes = { // please keep attributes in accordance to: // https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglGetConfigAttrib.xhtml @@ -71,8 +73,64 @@ std::array<std::pair<EGLint, const char*>, 32> eglAttributes = X(EGL_TRANSPARENT_GREEN_VALUE), X(EGL_TRANSPARENT_BLUE_VALUE) }; + +std::map<EGLenum, const char*> eglErrors = +{ + // please keep errors in accordance to: + // https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglGetError.xhtml + X(EGL_SUCCESS), + X(EGL_NOT_INITIALIZED), + X(EGL_BAD_ACCESS), + X(EGL_BAD_ALLOC), + X(EGL_BAD_ATTRIBUTE), + X(EGL_BAD_CONFIG), + X(EGL_BAD_CONTEXT), + X(EGL_BAD_CURRENT_SURFACE), + X(EGL_BAD_DISPLAY), + X(EGL_BAD_MATCH), + X(EGL_BAD_NATIVE_PIXMAP), + X(EGL_BAD_NATIVE_WINDOW), + X(EGL_BAD_PARAMETER), + X(EGL_BAD_SURFACE), + X(EGL_CONTEXT_LOST), +}; + +std::map<EGLint, const char*> eglErrorType = +{ +//! @todo remove when Raspberry Pi updates their EGL headers +#if !defined(TARGET_RASPBERRY_PI) + X(EGL_DEBUG_MSG_CRITICAL_KHR), + X(EGL_DEBUG_MSG_ERROR_KHR), + X(EGL_DEBUG_MSG_WARN_KHR), + X(EGL_DEBUG_MSG_INFO_KHR), +#endif +}; #undef X + +} // namespace + +//! @todo remove when Raspberry Pi updates their EGL headers +#if !defined(TARGET_RASPBERRY_PI) +void EglErrorCallback(EGLenum error, const char *command, EGLint messageType, EGLLabelKHR threadLabel, EGLLabelKHR objectLabel, const char* message) +{ + std::string errorStr; + std::string typeStr; + + auto eglError = eglErrors.find(error); + if (eglError != eglErrors.end()) + { + errorStr = eglError->second; + } + + auto eglType = eglErrorType.find(messageType); + if (eglType != eglErrorType.end()) + { + typeStr = eglType->second; + } + + CLog::Log(LOGDEBUG, "EGL Debugging:\nError: {}\nCommand: {}\nType: {}\nMessage: {}", errorStr, command, typeStr, message); } +#endif std::set<std::string> CEGLUtils::GetClientExtensions() { @@ -112,7 +170,16 @@ bool CEGLUtils::HasClientExtension(const std::string& name) void CEGLUtils::LogError(const std::string& what) { - CLog::Log(LOGERROR, "%s (EGL error %d)", what.c_str(), eglGetError()); + EGLenum error = eglGetError(); + std::string errorStr = StringUtils::Format("0x%04X", error); + + auto eglError = eglErrors.find(error); + if (eglError != eglErrors.end()) + { + errorStr = eglError->second; + } + + CLog::Log(LOGERROR, "{} ({})", what.c_str(), errorStr); } CEGLContextUtils::CEGLContextUtils() @@ -122,6 +189,22 @@ CEGLContextUtils::CEGLContextUtils() CEGLContextUtils::CEGLContextUtils(EGLenum platform, std::string const& platformExtension) : m_platform{platform} { +//! @todo remove when Raspberry Pi updates their EGL headers +#if !defined(TARGET_RASPBERRY_PI) + if (CEGLUtils::HasClientExtension("EGL_KHR_debug")) + { + auto eglDebugMessageControl = CEGLUtils::GetRequiredProcAddress<PFNEGLDEBUGMESSAGECONTROLKHRPROC>("eglDebugMessageControlKHR"); + + EGLAttrib eglDebugAttribs[] = {EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, + EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, + EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, + EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, + EGL_NONE}; + + eglDebugMessageControl(EglErrorCallback, eglDebugAttribs); + } +#endif + m_platformSupported = CEGLUtils::HasClientExtension("EGL_EXT_platform_base") && CEGLUtils::HasClientExtension(platformExtension); } @@ -321,6 +404,15 @@ bool CEGLContextUtils::CreateContext(CEGLAttributesVec contextAttribs) if (CEGLUtils::HasExtension(m_eglDisplay, "EGL_IMG_context_priority")) contextAttribs.Add({{EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG}}); +//! @todo remove when Raspberry Pi updates their EGL headers +#if !defined(TARGET_RASPBERRY_PI) + if (CEGLUtils::HasExtension(m_eglDisplay, "EGL_KHR_create_context") && + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_openGlDebugging) + { + contextAttribs.Add({{EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR}}); + } +#endif + m_eglContext = eglCreateContext(m_eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttribs.Get()); diff --git a/xbmc/utils/GLUtils.cpp b/xbmc/utils/GLUtils.cpp index e7376c0396..e381fd6bc9 100644 --- a/xbmc/utils/GLUtils.cpp +++ b/xbmc/utils/GLUtils.cpp @@ -7,47 +7,148 @@ */ #include "GLUtils.h" + #include "log.h" #include "ServiceBroker.h" #include "settings/AdvancedSettings.h" #include "settings/SettingsComponent.h" +#include "rendering/MatrixGL.h" #include "rendering/RenderSystem.h" +#include "utils/StringUtils.h" + +#include <map> +#include <utility> + +namespace +{ + +#define X(VAL) std::make_pair(VAL, #VAL) +std::map<GLenum, const char*> glErrors = +{ + // please keep attributes in accordance to: + // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetError.xhtml + X(GL_NO_ERROR), + X(GL_INVALID_ENUM), + X(GL_INVALID_VALUE), + X(GL_INVALID_OPERATION), + X(GL_INVALID_FRAMEBUFFER_OPERATION), + X(GL_OUT_OF_MEMORY), +#if defined(HAS_GL) + X(GL_STACK_UNDERFLOW), + X(GL_STACK_OVERFLOW), +#endif +}; + +std::map<GLenum, const char*> glErrorSource = +{ +//! @todo remove TARGET_RASPBERRY_PI when Raspberry Pi updates their GL headers +#if defined(HAS_GLES) && defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI) + X(GL_DEBUG_SOURCE_API_KHR), + X(GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR), + X(GL_DEBUG_SOURCE_SHADER_COMPILER_KHR), + X(GL_DEBUG_SOURCE_THIRD_PARTY_KHR), + X(GL_DEBUG_SOURCE_APPLICATION_KHR), + X(GL_DEBUG_SOURCE_OTHER_KHR), +#endif +}; + +std::map<GLenum, const char*> glErrorType = +{ +//! @todo remove TARGET_RASPBERRY_PI when Raspberry Pi updates their GL headers +#if defined(HAS_GLES) && defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI) + X(GL_DEBUG_TYPE_ERROR_KHR), + X(GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR), + X(GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR), + X(GL_DEBUG_TYPE_PORTABILITY_KHR), + X(GL_DEBUG_TYPE_PERFORMANCE_KHR), + X(GL_DEBUG_TYPE_OTHER_KHR), + X(GL_DEBUG_TYPE_MARKER_KHR), +#endif +}; + +std::map<GLenum, const char*> glErrorSeverity = +{ +//! @todo remove TARGET_RASPBERRY_PI when Raspberry Pi updates their GL headers +#if defined(HAS_GLES) && defined(TARGET_LINUX) && !defined(TARGET_RASPBERRY_PI) + X(GL_DEBUG_SEVERITY_HIGH_KHR), + X(GL_DEBUG_SEVERITY_MEDIUM_KHR), + X(GL_DEBUG_SEVERITY_LOW_KHR), + X(GL_DEBUG_SEVERITY_NOTIFICATION_KHR), +#endif +}; +#undef X + +} // namespace -void _VerifyGLState(const char* szfile, const char* szfunction, int lineno){ -#if defined(HAS_GL) && defined(_DEBUG) -#define printMatrix(matrix) \ - { \ - for (int ixx = 0 ; ixx<4 ; ixx++) \ - { \ - CLog::Log(LOGDEBUG, "% 3.3f % 3.3f % 3.3f % 3.3f ", \ - matrix[ixx*4], matrix[ixx*4+1], matrix[ixx*4+2], \ - matrix[ixx*4+3]); \ - } \ +void KODI::UTILS::GL::GlErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) +{ + std::string sourceStr; + std::string typeStr; + std::string severityStr; + + auto glSource = glErrorSource.find(source); + if (glSource != glErrorSource.end()) + { + sourceStr = glSource->second; } - if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_logLevel < LOG_LEVEL_DEBUG_FREEMEM) - return; + + auto glType = glErrorType.find(type); + if (glType != glErrorType.end()) + { + typeStr = glType->second; + } + + auto glSeverity = glErrorSeverity.find(severity); + if (glSeverity != glErrorSeverity.end()) + { + severityStr = glSeverity->second; + } + + CLog::Log(LOGDEBUG, "OpenGL(ES) Debugging:\nSource: {}\nType: {}\nSeverity: {}\nID: {}\nMessage: {}", sourceStr, typeStr, severityStr, id, message); +} + +static void PrintMatrix(const GLfloat* matrix, std::string matrixName) +{ + CLog::Log(LOGDEBUG, "{}:\n{:> 10.3f} {:> 10.3f} {:> 10.3f} {:> 10.3f}\n{:> 10.3f} {:> 10.3f} {:> 10.3f} {:> 10.3f}\n{:> 10.3f} {:> 10.3f} {:> 10.3f} {:> 10.3f}\n{:> 10.3f} {:> 10.3f} {:> 10.3f} {:> 10.3f}", + matrixName, + matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4], matrix[5], matrix[6], matrix[7], + matrix[8], matrix[9], matrix[10], matrix[11], + matrix[12], matrix[13], matrix[14], matrix[15]); +} + +void _VerifyGLState(const char* szfile, const char* szfunction, int lineno) +{ GLenum err = glGetError(); - if (err==GL_NO_ERROR) + if (err == GL_NO_ERROR) + { return; - CLog::Log(LOGERROR, "GL ERROR: %s\n", gluErrorString(err)); + } + + auto error = glErrors.find(err); + if (error != glErrors.end()) + { + CLog::Log(LOGERROR, "GL(ES) ERROR: {}", error->second); + } + if (szfile && szfunction) - CLog::Log(LOGERROR, "In file:%s function:%s line:%d", szfile, szfunction, lineno); - GLboolean bools[16]; + { + CLog::Log(LOGERROR, "In file: {} function: {} line: {}", szfile, szfunction, lineno); + } + + GLboolean scissors; + glGetBooleanv(GL_SCISSOR_TEST, &scissors); + CLog::Log(LOGDEBUG, "Scissor test enabled: {}", scissors == GL_TRUE ? "True" : "False"); + GLfloat matrix[16]; glGetFloatv(GL_SCISSOR_BOX, matrix); - CLog::Log(LOGDEBUG, "Scissor box: %f, %f, %f, %f", matrix[0], matrix[1], matrix[2], matrix[3]); - glGetBooleanv(GL_SCISSOR_TEST, bools); - CLog::Log(LOGDEBUG, "Scissor test enabled: %d", (int)bools[0]); + CLog::Log(LOGDEBUG, "Scissor box: {}, {}, {}, {}", matrix[0], matrix[1], matrix[2], matrix[3]); + glGetFloatv(GL_VIEWPORT, matrix); - CLog::Log(LOGDEBUG, "Viewport: %f, %f, %f, %f", matrix[0], matrix[1], matrix[2], matrix[3]); - glGetFloatv(GL_PROJECTION_MATRIX, matrix); - CLog::Log(LOGDEBUG, "Projection Matrix:"); - printMatrix(matrix); - glGetFloatv(GL_MODELVIEW_MATRIX, matrix); - CLog::Log(LOGDEBUG, "Modelview Matrix:"); - printMatrix(matrix); -// abort(); -#endif + CLog::Log(LOGDEBUG, "Viewport: {}, {}, {}, {}", matrix[0], matrix[1], matrix[2], matrix[3]); + + PrintMatrix(glMatrixProject.Get(), "Projection Matrix"); + PrintMatrix(glMatrixModview.Get(), "Modelview Matrix"); } void LogGraphicsInfo() diff --git a/xbmc/utils/GLUtils.h b/xbmc/utils/GLUtils.h index afacfe8e05..2dea0673b0 100644 --- a/xbmc/utils/GLUtils.h +++ b/xbmc/utils/GLUtils.h @@ -21,6 +21,19 @@ #include "system_gl.h" +namespace KODI +{ +namespace UTILS +{ +namespace GL +{ + +void GlErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); + +} +} +} + void _VerifyGLState(const char* szfile, const char* szfunction, int lineno); #if defined(GL_DEBUGGING) && (defined(HAS_GL) || defined(HAS_GLES)) #define VerifyGLState() _VerifyGLState(__FILE__, __FUNCTION__, __LINE__) diff --git a/xbmc/utils/SaveFileStateJob.cpp b/xbmc/utils/SaveFileStateJob.cpp index 85571ab124..ca70e0a43d 100644 --- a/xbmc/utils/SaveFileStateJob.cpp +++ b/xbmc/utils/SaveFileStateJob.cpp @@ -35,6 +35,8 @@ void CSaveFileState::DoWork(CFileItem& item, if (item.HasVideoInfoTag() && StringUtils::StartsWith(item.GetVideoInfoTag()->m_strFileNameAndPath, "removable://")) progressTrackingFile = item.GetVideoInfoTag()->m_strFileNameAndPath; // this variable contains removable:// suffixed by disc label+uniqueid or is empty if label not uniquely identified + else if (item.HasVideoInfoTag() && item.IsVideoDb()) + progressTrackingFile = item.GetVideoInfoTag()->m_strFileNameAndPath; // we need the file url of the video db item to create the bookmark else if (item.HasProperty("original_listitem_url")) { // only use original_listitem_url for Python, UPnP and Bluray sources diff --git a/xbmc/utils/Screenshot.cpp b/xbmc/utils/Screenshot.cpp index 24580ed232..0616e24a18 100644 --- a/xbmc/utils/Screenshot.cpp +++ b/xbmc/utils/Screenshot.cpp @@ -234,33 +234,19 @@ void CScreenShot::TakeScreenshot(const std::string &filename, bool sync) void CScreenShot::TakeScreenshot() { - static bool savingScreenshots = false; - static std::vector<std::string> screenShots; - bool promptUser = false; - std::string strDir; - - // check to see if we have a screenshot folder yet std::shared_ptr<CSettingPath> screenshotSetting = std::static_pointer_cast<CSettingPath>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_DEBUG_SCREENSHOTPATH)); - if (screenshotSetting != NULL) - { - strDir = screenshotSetting->GetValue(); - if (strDir.empty()) - { - if (CGUIControlButtonSetting::GetPath(screenshotSetting, &g_localizeStrings)) - strDir = screenshotSetting->GetValue(); - } - } + if (!screenshotSetting) + return; + std::string strDir = screenshotSetting->GetValue(); if (strDir.empty()) { - strDir = "special://temp/"; - if (!savingScreenshots) - { - promptUser = true; - savingScreenshots = true; - screenShots.clear(); - } + if (!CGUIControlButtonSetting::GetPath(screenshotSetting, &g_localizeStrings)) + return; + + strDir = screenshotSetting->GetValue(); } + URIUtils::RemoveSlashAtEnd(strDir); if (!strDir.empty()) @@ -270,32 +256,6 @@ void CScreenShot::TakeScreenshot() if (!file.empty()) { TakeScreenshot(file, false); - if (savingScreenshots) - screenShots.push_back(file); - if (promptUser) - { // grab the real directory - std::string newDir; - if (screenshotSetting != NULL) - { - newDir = screenshotSetting->GetValue(); - if (newDir.empty()) - { - if (CGUIControlButtonSetting::GetPath(screenshotSetting, &g_localizeStrings)) - newDir = screenshotSetting->GetValue(); - } - } - - if (!newDir.empty()) - { - for (unsigned int i = 0; i < screenShots.size(); i++) - { - std::string file = CUtil::GetNextFilename(URIUtils::AddFileToFolder(newDir, "screenshot%03d.png"), 999); - CFile::Copy(screenShots[i], file); - } - screenShots.clear(); - } - savingScreenshots = false; - } } else { diff --git a/xbmc/utils/SystemInfo.cpp b/xbmc/utils/SystemInfo.cpp index cf6519a4eb..df5e043a3a 100644 --- a/xbmc/utils/SystemInfo.cpp +++ b/xbmc/utils/SystemInfo.cpp @@ -1243,7 +1243,7 @@ std::string CSysInfo::GetVersion() std::string CSysInfo::GetBuildDate() { - return StringUtils::Format("%s", __DATE__); + return CCompileInfo::GetBuildDate(); } bool CSysInfo::HasVideoToolBoxDecoder() diff --git a/xbmc/utils/TimeUtils.cpp b/xbmc/utils/TimeUtils.cpp index 26a728d713..16d75b9fe6 100644 --- a/xbmc/utils/TimeUtils.cpp +++ b/xbmc/utils/TimeUtils.cpp @@ -94,3 +94,8 @@ CDateTime CTimeUtils::GetLocalTime(time_t time) return result; } + +std::string CTimeUtils::WithoutSeconds(const std::string hhmmss) +{ + return hhmmss.substr(0, 5); +} diff --git a/xbmc/utils/TimeUtils.h b/xbmc/utils/TimeUtils.h index 87ed08fccf..55e4de5a21 100644 --- a/xbmc/utils/TimeUtils.h +++ b/xbmc/utils/TimeUtils.h @@ -10,6 +10,7 @@ #include <stdint.h> #include <time.h> +#include <string> class CDateTime; @@ -19,10 +20,25 @@ int64_t CurrentHostFrequency(void); class CTimeUtils { public: - static void UpdateFrameTime(bool flip); ///< update the frame time. Not threadsafe - static unsigned int GetFrameTime(); ///< returns the frame time in MS. Not threadsafe + + /*! + * @brief Update the time frame + * @note Not threadsafe + */ + static void UpdateFrameTime(bool flip); + + /*! + * @brief Returns the frame time in MS + * @note Not threadsafe + */ + static unsigned int GetFrameTime(); static CDateTime GetLocalTime(time_t time); - + + /*! + * @brief Returns a time string without seconds, i.e: HH:MM + * @param hhmmss Time string in the format HH:MM:SS + */ + static std::string WithoutSeconds(const std::string hhmmss); private: static unsigned int frameTime; }; diff --git a/xbmc/utils/URIUtils.cpp b/xbmc/utils/URIUtils.cpp index db0ececd30..f0d3744dbe 100644 --- a/xbmc/utils/URIUtils.cpp +++ b/xbmc/utils/URIUtils.cpp @@ -598,6 +598,18 @@ bool URIUtils::IsRemote(const std::string& strFile) if (IsSourcesPath(strFile)) return false; + + if (IsVideoDb(strFile) || IsMusicDb(strFile)) + return false; + + if (IsLibraryFolder(strFile)) + return false; + + if (IsPlugin(strFile)) + return false; + + if (IsAndroidApp(strFile)) + return false; if (!url.IsLocal()) return true; diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp index 2553d72f19..3692c97ed1 100644 --- a/xbmc/utils/test/TestSystemInfo.cpp +++ b/xbmc/utils/test/TestSystemInfo.cpp @@ -13,11 +13,6 @@ #include "gtest/gtest.h" -#ifdef TARGET_WINDOWS_STORE -#include <algorithm> -using namespace Windows::Storage; -#endif - class TestSystemInfo : public testing::Test { protected: @@ -305,18 +300,7 @@ TEST_F(TestSystemInfo, GetDiskSpace) #ifdef TARGET_WINDOWS using KODI::PLATFORM::WINDOWS::FromW; wchar_t sysDrive[300]; -#if defined(TARGET_WINDOWS_STORE) - DWORD res = 0; - auto values = ApplicationData::Current->LocalSettings->Values; - if (values->HasKey(L"SystemDrive")) - { - auto value = safe_cast<Platform::String^>(values->Lookup(L"SystemDrive")); - wcscpy_s(sysDrive, value->Data()); - res = value->Length(); - } -#else DWORD res = GetEnvironmentVariableW(L"SystemDrive", sysDrive, sizeof(sysDrive) / sizeof(wchar_t)); -#endif std::string sysDriveLtr; if (res != 0 && res <= sizeof(sysDrive) / sizeof(wchar_t)) sysDriveLtr.assign(FromW(sysDrive), 0, 1); diff --git a/xbmc/utils/test/TestURIUtils.cpp b/xbmc/utils/test/TestURIUtils.cpp index 0631900075..c96c8d31a1 100644 --- a/xbmc/utils/test/TestURIUtils.cpp +++ b/xbmc/utils/test/TestURIUtils.cpp @@ -378,6 +378,11 @@ TEST_F(TestURIUtils, IsRemote) EXPECT_TRUE(URIUtils::IsRemote("https://path/to/file")); EXPECT_FALSE(URIUtils::IsRemote("addons://user/")); EXPECT_FALSE(URIUtils::IsRemote("sources://video/")); + EXPECT_FALSE(URIUtils::IsRemote("videodb://movies/titles")); + EXPECT_FALSE(URIUtils::IsRemote("musicdb://genres/")); + EXPECT_FALSE(URIUtils::IsRemote("library://video/")); + EXPECT_FALSE(URIUtils::IsRemote("androidapp://app")); + EXPECT_FALSE(URIUtils::IsRemote("plugin://plugin.video.id")); } TEST_F(TestURIUtils, IsSmb) diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp index 13c6aab5ce..8c5a6c60a3 100644 --- a/xbmc/video/VideoDatabase.cpp +++ b/xbmc/video/VideoDatabase.cpp @@ -5379,11 +5379,56 @@ void CVideoDatabase::UpdateTables(int iVersion) if (iVersion < 112) m_pDS->exec("ALTER TABLE settings ADD CenterMixLevel integer"); + + if (iVersion < 113) + { + // fb9c25f5 and e5f6d204 changed the behavior of path splitting for plugin URIs (previously it would only use the root) + // Re-split paths for plugin files in order to maintain watched state etc. + m_pDS->query("SELECT files.idFile, files.strFilename, path.strPath FROM files LEFT JOIN path ON files.idPath = path.idPath WHERE files.strFilename LIKE 'plugin://%'"); + while (!m_pDS->eof()) + { + std::string path, fn; + SplitPath(m_pDS->fv(1).get_asString(), path, fn); + if (path != m_pDS->fv(2).get_asString()) + { + int pathid = -1; + m_pDS2->query(PrepareSQL("SELECT idPath FROM path WHERE strPath='%s'", path.c_str())); + if (!m_pDS2->eof()) + pathid = m_pDS2->fv(0).get_asInt(); + m_pDS2->close(); + if (pathid < 0) + { + std::string parent = URIUtils::GetParentPath(path); + int parentid = -1; + m_pDS2->query(PrepareSQL("SELECT idPath FROM path WHERE strPath='%s'", parent.c_str())); + if (!m_pDS2->eof()) + parentid = m_pDS2->fv(0).get_asInt(); + m_pDS2->close(); + if (parentid < 0) + { + m_pDS2->exec(PrepareSQL("INSERT INTO path (strPath) VALUES ('%s')", parent.c_str())); + parentid = (int)m_pDS2->lastinsertid(); + } + m_pDS2->exec(PrepareSQL("INSERT INTO path (strPath, idParentPath) VALUES ('%s', %i)", path.c_str(), parentid)); + pathid = (int)m_pDS2->lastinsertid(); + } + m_pDS2->query(PrepareSQL("SELECT idFile FROM files WHERE strFileName='%s' AND idPath=%i", fn.c_str(), pathid)); + bool exists = !m_pDS2->eof(); + m_pDS2->close(); + if (exists) + m_pDS2->exec(PrepareSQL("DELETE FROM files WHERE idFile=%i", m_pDS->fv(0).get_asInt())); + else + m_pDS2->exec(PrepareSQL("UPDATE files SET idPath=%i WHERE idFile=%i", pathid, m_pDS->fv(0).get_asInt())); + } + m_pDS->next(); + } + m_pDS->close(); + } } int CVideoDatabase::GetSchemaVersion() const { - return 112; + return 113; } bool CVideoDatabase::LookupByFolders(const std::string &path, bool shows) diff --git a/xbmc/video/VideoInfoTag.cpp b/xbmc/video/VideoInfoTag.cpp index 31cf7b969c..562dfbb761 100644 --- a/xbmc/video/VideoInfoTag.cpp +++ b/xbmc/video/VideoInfoTag.cpp @@ -215,7 +215,7 @@ bool CVideoInfoTag::Save(TiXmlNode *node, const std::string &tag, bool savePathI { TiXmlElement set("set"); XMLUtils::SetString(&set, "name", m_set.title); - if (m_set.overview.empty()) + if (!m_set.overview.empty()) XMLUtils::SetString(&set, "overview", m_set.overview); movie->InsertEndChild(set); } diff --git a/xbmc/video/VideoThumbLoader.cpp b/xbmc/video/VideoThumbLoader.cpp index 6000f65294..28dd92e477 100644 --- a/xbmc/video/VideoThumbLoader.cpp +++ b/xbmc/video/VideoThumbLoader.cpp @@ -24,6 +24,7 @@ #include "GUIUserMessages.h" #include "music/MusicDatabase.h" #include "settings/AdvancedSettings.h" +#include "settings/lib/Setting.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "cores/VideoSettings.h" @@ -349,6 +350,19 @@ bool CVideoThumbLoader::LoadItemCached(CFileItem* pItem) SetArt(*pItem, artwork); } + // hide thumb if episode is unwatched + std::shared_ptr<CSettingList> setting(std::dynamic_pointer_cast<CSettingList>( + CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS))); + if (pItem->HasArt("thumb") && pItem->HasVideoInfoTag() && + pItem->GetVideoInfoTag()->m_type == MediaTypeEpisode && + pItem->GetVideoInfoTag()->GetPlayCount() == 0 && + setting && + !setting->FindIntInList(CSettings::VIDEOLIBRARY_THUMB_SHOW_UNWATCHED_EPISODE) + ) + { + pItem->SetArt("thumb", "OverlaySpoiler.png"); + } + m_videoDatabase->Close(); return true; diff --git a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp index dc4eb84b19..091472544b 100644 --- a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp @@ -33,6 +33,7 @@ #include "storage/MediaManager.h" #include "profiles/ProfileManager.h" #include "settings/AdvancedSettings.h" +#include "settings/lib/Setting.h" #include "settings/MediaSourceSettings.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" @@ -376,9 +377,17 @@ void CGUIDialogVideoInfo::SetMovie(const CFileItem *item) void CGUIDialogVideoInfo::Update() { // setup plot text area + std::shared_ptr<CSettingList> setting(std::dynamic_pointer_cast<CSettingList>( + CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS))); std::string strTmp = m_movieItem->GetVideoInfoTag()->m_strPlot; if (m_movieItem->GetVideoInfoTag()->m_type != MediaTypeTvShow) - if (m_movieItem->GetVideoInfoTag()->GetPlayCount() == 0 && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS)) + if (m_movieItem->GetVideoInfoTag()->GetPlayCount() == 0 && + setting && + ( + (m_movieItem->GetVideoInfoTag()->m_type == MediaTypeMovie && (!setting->FindIntInList(CSettings::VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_MOVIES))) || + (m_movieItem->GetVideoInfoTag()->m_type == MediaTypeEpisode && (!setting->FindIntInList(CSettings::VIDEOLIBRARY_PLOTS_SHOW_UNWATCHED_TVSHOWEPISODES))) + ) + ) strTmp = g_localizeStrings.Get(20370); StringUtils::Trim(strTmp); diff --git a/xbmc/video/windows/GUIWindowVideoBase.cpp b/xbmc/video/windows/GUIWindowVideoBase.cpp index ae6022fa08..ce086ea081 100644 --- a/xbmc/video/windows/GUIWindowVideoBase.cpp +++ b/xbmc/video/windows/GUIWindowVideoBase.cpp @@ -140,6 +140,11 @@ bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message) OnQueueItem(iItem); return true; } + else if (iAction == ACTION_QUEUE_ITEM_NEXT) + { + OnQueueItem(iItem, true); + return true; + } else if (iAction == ACTION_SHOW_INFO) { return OnItemInfo(iItem); @@ -411,7 +416,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItemPtr item, const ScraperPtr &info2, b return listNeedsUpdating; } -void CGUIWindowVideoBase::OnQueueItem(int iItem) +void CGUIWindowVideoBase::OnQueueItem(int iItem, bool first) { // Determine the proper list to queue this element int playlist = CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist(); @@ -442,7 +447,10 @@ void CGUIWindowVideoBase::OnQueueItem(int iItem) return; } - CServiceBroker::GetPlaylistPlayer().Add(playlist, queuedItems); + if (first && g_application.GetAppPlayer().IsPlaying()) + CServiceBroker::GetPlaylistPlayer().Insert(playlist, queuedItems, CServiceBroker::GetPlaylistPlayer().GetCurrentSong()+1); + else + CServiceBroker::GetPlaylistPlayer().Add(playlist, queuedItems); CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(playlist); // video does not auto play on queue like music m_viewControl.SetSelectedItem(iItem + 1); @@ -837,6 +845,7 @@ void CGUIWindowVideoBase::GetContextButtons(int itemNumber, CContextButtons &but && !m_vecItems->IsSourcesPath()) { buttons.Add(CONTEXT_BUTTON_QUEUE_ITEM, 13347); // Add to Playlist + buttons.Add(CONTEXT_BUTTON_PLAY_NEXT, 10008); // Play next } } @@ -975,6 +984,10 @@ bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) OnQueueItem(itemNumber); return true; + case CONTEXT_BUTTON_PLAY_NEXT: + OnQueueItem(itemNumber, true); + return true; + case CONTEXT_BUTTON_PLAY_ITEM: PlayItem(itemNumber); return true; diff --git a/xbmc/video/windows/GUIWindowVideoBase.h b/xbmc/video/windows/GUIWindowVideoBase.h index c0330a5112..0a67127174 100644 --- a/xbmc/video/windows/GUIWindowVideoBase.h +++ b/xbmc/video/windows/GUIWindowVideoBase.h @@ -85,7 +85,7 @@ protected: void GetContextButtons(int itemNumber, CContextButtons &buttons) override; bool OnContextButton(int itemNumber, CONTEXT_BUTTON button) override; - virtual void OnQueueItem(int iItem); + virtual void OnQueueItem(int iItem, bool first = false); virtual void OnDeleteItem(CFileItemPtr pItem); void OnDeleteItem(int iItem) override; virtual void DoSearch(const std::string& strSearch, CFileItemList& items) {}; diff --git a/xbmc/windowing/X11/GLContext.h b/xbmc/windowing/X11/GLContext.h index fdb17e5f76..a3d24b02e1 100644 --- a/xbmc/windowing/X11/GLContext.h +++ b/xbmc/windowing/X11/GLContext.h @@ -34,4 +34,7 @@ public: std::string m_extensions; Display *m_dpy; + +protected: + bool m_omlSync = false; }; diff --git a/xbmc/windowing/X11/GLContextEGL.cpp b/xbmc/windowing/X11/GLContextEGL.cpp index b8d0ff85eb..272cd96214 100644 --- a/xbmc/windowing/X11/GLContextEGL.cpp +++ b/xbmc/windowing/X11/GLContextEGL.cpp @@ -18,6 +18,9 @@ #include "GLContextEGL.h" #include "utils/log.h" #include <EGL/eglext.h> +#include "ServiceBroker.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" #define EGL_NO_CONFIG (EGLConfig)0 @@ -30,6 +33,12 @@ CGLContextEGL::CGLContextEGL(Display *dpy) : CGLContext(dpy) m_eglConfig = EGL_NO_CONFIG; eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT"); + + CSettingsComponent *settings = CServiceBroker::GetSettingsComponent(); + if (settings) + { + m_omlSync = settings->GetAdvancedSettings()->m_omlSync; + } } CGLContextEGL::~CGLContextEGL() @@ -424,6 +433,7 @@ void CGLContextEGL::SwapBuffers() if ((msc1 - m_sync.msc1) > 2) { m_sync.cont = 0; + CLog::Log(LOGDEBUG, "CGLContextEGL::SwapBuffers: sync reset"); } // we want to block in SwapBuffers @@ -439,22 +449,29 @@ void CGLContextEGL::SwapBuffers() { m_sync.interval = (ust1 - m_sync.ust1) / (msc1 - m_sync.msc1); m_sync.cont++; + CLog::Log(LOGDEBUG, "CGLContextEGL::SwapBuffers: sync interval: %ld", m_sync.interval); } } - else if ((m_sync.cont == 5) && (msc2 == msc1)) + else if (m_sync.cont == 5 && m_omlSync) { - // if no vertical retrace has occurred in eglSwapBuffers, - // sleep until next vertical retrace - uint64_t lastIncrement = (now / 1000 - ust2); - if (lastIncrement > m_sync.interval) + CLog::Log(LOGDEBUG, "CGLContextEGL::SwapBuffers: sync check blocking"); + + if (msc2 == msc1) { - lastIncrement = m_sync.interval; - CLog::Log(LOGWARNING, "CGLContextEGL::SwapBuffers: last msc time greater than interval"); + // if no vertical retrace has occurred in eglSwapBuffers, + // sleep until next vertical retrace + uint64_t lastIncrement = (now / 1000 - ust2); + if (lastIncrement > m_sync.interval) + { + lastIncrement = m_sync.interval; + CLog::Log(LOGWARNING, "CGLContextEGL::SwapBuffers: last msc time greater than interval"); + } + uint64_t sleeptime = m_sync.interval - lastIncrement; + usleep(sleeptime); + m_sync.cont++; + msc2++; + CLog::Log(LOGDEBUG, "CGLContextEGL::SwapBuffers: sync sleep: %ld", sleeptime); } - uint64_t sleeptime = m_sync.interval - lastIncrement; - usleep(sleeptime); - m_sync.cont++; - msc2++; } else if ((m_sync.cont > 5) && (msc2 == m_sync.msc2)) { diff --git a/xbmc/windowing/X11/WinSystemX11GLContext.cpp b/xbmc/windowing/X11/WinSystemX11GLContext.cpp index 4432fa5251..b4a6387f7b 100644 --- a/xbmc/windowing/X11/WinSystemX11GLContext.cpp +++ b/xbmc/windowing/X11/WinSystemX11GLContext.cpp @@ -211,13 +211,15 @@ bool CWinSystemX11GLContext::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res bool CWinSystemX11GLContext::DestroyWindowSystem() { - m_pGLContext->Destroy(); + if (m_pGLContext) + m_pGLContext->Destroy(); return CWinSystemX11::DestroyWindowSystem(); } bool CWinSystemX11GLContext::DestroyWindow() { - m_pGLContext->Detach(); + if (m_pGLContext) + m_pGLContext->Detach(); return CWinSystemX11::DestroyWindow(); } @@ -296,7 +298,7 @@ bool CWinSystemX11GLContext::RefreshGLContext(bool force) return true; } } - else if (gli != "EGL") + else if (gli == "EGL_PB") { success = m_pGLContext->CreatePB(); if (success) diff --git a/xbmc/windowing/amlogic/WinSystemAmlogicGLESContext.cpp b/xbmc/windowing/amlogic/WinSystemAmlogicGLESContext.cpp index 470db99f5f..076f7718f0 100644 --- a/xbmc/windowing/amlogic/WinSystemAmlogicGLESContext.cpp +++ b/xbmc/windowing/amlogic/WinSystemAmlogicGLESContext.cpp @@ -102,10 +102,8 @@ bool CWinSystemAmlogicGLESContext::SetFullScreen(bool fullScreen, RESOLUTION_INF void CWinSystemAmlogicGLESContext::SetVSyncImpl(bool enable) { - m_iVSyncMode = enable ? 10:0; if (!m_pGLContext.SetVSync(enable)) { - m_iVSyncMode = 0; CLog::Log(LOGERROR, "%s,Could not set egl vsync", __FUNCTION__); } } diff --git a/xbmc/windowing/android/AndroidUtils.cpp b/xbmc/windowing/android/AndroidUtils.cpp index aee6065379..372fb71023 100644 --- a/xbmc/windowing/android/AndroidUtils.cpp +++ b/xbmc/windowing/android/AndroidUtils.cpp @@ -23,8 +23,12 @@ #include "windowing/GraphicContext.h" #include "utils/log.h" + #include "settings/Settings.h" +#include "settings/DisplaySettings.h" #include "settings/SettingsComponent.h" +#include "settings/lib/SettingsManager.h" + #include "ServiceBroker.h" #include "utils/StringUtils.h" #include "utils/SysfsUtils.h" @@ -118,6 +122,8 @@ static void fetchDisplayModes() } } +const std::string CAndroidUtils::SETTING_LIMITGUI = "videoscreen.limitgui"; + CAndroidUtils::CAndroidUtils() { std::string displaySize; @@ -153,7 +159,7 @@ CAndroidUtils::CAndroidUtils() } CLog::Log(LOGDEBUG, "CAndroidUtils: maximum/current resolution: %dx%d", m_width, m_height); - int limit = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt("videoscreen.limitgui"); + int limit = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CAndroidUtils::SETTING_LIMITGUI); switch (limit) { case 0: // auto @@ -181,6 +187,10 @@ CAndroidUtils::CAndroidUtils() break; } CLog::Log(LOGDEBUG, "CAndroidUtils: selected resolution: %dx%d", m_width, m_height); + + CServiceBroker::GetSettingsComponent()->GetSettings()->GetSettingsManager()->RegisterCallback(this, { + CAndroidUtils::SETTING_LIMITGUI + }); } CAndroidUtils::~CAndroidUtils() @@ -258,6 +268,7 @@ bool CAndroidUtils::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions) { res.iWidth = std::min(res.iWidth, m_width); res.iHeight = std::min(res.iHeight, m_height); + res.iSubtitles = static_cast<int>(0.965 * res.iHeight); } resolutions.push_back(res); } @@ -302,3 +313,11 @@ bool CAndroidUtils::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions) } return false; } + +void CAndroidUtils::OnSettingChanged(std::shared_ptr<const CSetting> setting) +{ + const std::string &settingId = setting->GetId(); + /* Calibration (overscan / subtitles) are based on GUI size -> reset required */ + if (settingId == CAndroidUtils::SETTING_LIMITGUI) + CDisplaySettings::GetInstance().ClearCalibrations(); +} diff --git a/xbmc/windowing/android/AndroidUtils.h b/xbmc/windowing/android/AndroidUtils.h index 23a5c3deb2..e006ff1f41 100644 --- a/xbmc/windowing/android/AndroidUtils.h +++ b/xbmc/windowing/android/AndroidUtils.h @@ -13,9 +13,10 @@ #include <androidjni/Display.h> +#include "settings/lib/ISettingCallback.h" #include "windowing/Resolution.h" -class CAndroidUtils +class CAndroidUtils : public ISettingCallback { public: CAndroidUtils(); @@ -24,6 +25,10 @@ public: virtual bool SetNativeResolution(const RESOLUTION_INFO &res); virtual bool ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions); + // Implementation of ISettingCallback + static const std::string SETTING_LIMITGUI; + void OnSettingChanged(std::shared_ptr<const CSetting> setting) override; + protected: mutable int m_width; mutable int m_height; diff --git a/xbmc/windowing/android/WinSystemAndroid.cpp b/xbmc/windowing/android/WinSystemAndroid.cpp index 986ffda373..d08e3e1cb2 100644 --- a/xbmc/windowing/android/WinSystemAndroid.cpp +++ b/xbmc/windowing/android/WinSystemAndroid.cpp @@ -170,9 +170,7 @@ void CWinSystemAndroid::UpdateResolutions() CServiceBroker::GetWinSystem()->GetGfxContext().ResetOverscan(resolutions[i]); CDisplaySettings::GetInstance().GetResolutionInfo(res_index) = resolutions[i]; - if(resDesktop.iWidth == resolutions[i].iWidth && - resDesktop.iHeight == resolutions[i].iHeight && - resDesktop.iScreenWidth == resolutions[i].iScreenWidth && + if (resDesktop.iScreenWidth == resolutions[i].iScreenWidth && resDesktop.iScreenHeight == resolutions[i].iScreenHeight && (resDesktop.dwFlags & D3DPRESENTFLAG_MODEMASK) == (resolutions[i].dwFlags & D3DPRESENTFLAG_MODEMASK) && fabs(resDesktop.fRefreshRate - resolutions[i].fRefreshRate) < FLT_EPSILON) diff --git a/xbmc/windowing/gbm/DRMAtomic.cpp b/xbmc/windowing/gbm/DRMAtomic.cpp index f8d881b6b0..0299fc9caa 100644 --- a/xbmc/windowing/gbm/DRMAtomic.cpp +++ b/xbmc/windowing/gbm/DRMAtomic.cpp @@ -52,22 +52,22 @@ void CDRMAtomic::DrmAtomicCommit(int fb_id, int flags, bool rendered, bool video if (rendered) { - AddProperty(m_overlay_plane, "FB_ID", fb_id); - AddProperty(m_overlay_plane, "CRTC_ID", m_crtc->crtc->crtc_id); - AddProperty(m_overlay_plane, "SRC_X", 0); - AddProperty(m_overlay_plane, "SRC_Y", 0); - AddProperty(m_overlay_plane, "SRC_W", m_width << 16); - AddProperty(m_overlay_plane, "SRC_H", m_height << 16); - AddProperty(m_overlay_plane, "CRTC_X", 0); - AddProperty(m_overlay_plane, "CRTC_Y", 0); - AddProperty(m_overlay_plane, "CRTC_W", m_mode->hdisplay); - AddProperty(m_overlay_plane, "CRTC_H", m_mode->vdisplay); + AddProperty(m_gui_plane, "FB_ID", fb_id); + AddProperty(m_gui_plane, "CRTC_ID", m_crtc->crtc->crtc_id); + AddProperty(m_gui_plane, "SRC_X", 0); + AddProperty(m_gui_plane, "SRC_Y", 0); + AddProperty(m_gui_plane, "SRC_W", m_width << 16); + AddProperty(m_gui_plane, "SRC_H", m_height << 16); + AddProperty(m_gui_plane, "CRTC_X", 0); + AddProperty(m_gui_plane, "CRTC_Y", 0); + AddProperty(m_gui_plane, "CRTC_W", m_mode->hdisplay); + AddProperty(m_gui_plane, "CRTC_H", m_mode->vdisplay); } else if (videoLayer && !CServiceBroker::GetGUI()->GetWindowManager().HasVisibleControls()) { // disable gui plane when video layer is active and gui has no visible controls - AddProperty(m_overlay_plane, "FB_ID", 0); - AddProperty(m_overlay_plane, "CRTC_ID", 0); + AddProperty(m_gui_plane, "FB_ID", 0); + AddProperty(m_gui_plane, "CRTC_ID", 0); } auto ret = drmModeAtomicCommit(m_fd, m_req, flags | DRM_MODE_ATOMIC_TEST_ONLY, nullptr); @@ -101,9 +101,9 @@ void CDRMAtomic::FlipPage(struct gbm_bo *bo, bool rendered, bool videoLayer) if (rendered) { if (videoLayer) - m_overlay_plane->SetFormat(CDRMUtils::FourCCWithAlpha(m_overlay_plane->GetFormat())); + m_gui_plane->SetFormat(CDRMUtils::FourCCWithAlpha(m_gui_plane->GetFormat())); else - m_overlay_plane->SetFormat(CDRMUtils::FourCCWithoutAlpha(m_overlay_plane->GetFormat())); + m_gui_plane->SetFormat(CDRMUtils::FourCCWithoutAlpha(m_gui_plane->GetFormat())); drm_fb = CDRMUtils::DrmFbGetFromBo(bo); if (!drm_fb) diff --git a/xbmc/windowing/gbm/DRMUtils.cpp b/xbmc/windowing/gbm/DRMUtils.cpp index 215f696e17..df46ad4bdc 100644 --- a/xbmc/windowing/gbm/DRMUtils.cpp +++ b/xbmc/windowing/gbm/DRMUtils.cpp @@ -29,8 +29,8 @@ CDRMUtils::CDRMUtils() : m_connector(new connector) , m_encoder(new encoder) , m_crtc(new crtc) - , m_primary_plane(new plane) - , m_overlay_plane(new plane) + , m_video_plane(new plane) + , m_gui_plane(new plane) { } @@ -73,7 +73,7 @@ drm_fb * CDRMUtils::DrmFbGetFromBo(struct gbm_bo *bo) struct drm_fb *fb = static_cast<drm_fb *>(gbm_bo_get_user_data(bo)); if(fb) { - if (m_overlay_plane->GetFormat() == fb->format) + if (m_gui_plane->GetFormat() == fb->format) return fb; else DrmFbDestroyCallback(bo, gbm_bo_get_user_data(bo)); @@ -82,7 +82,7 @@ drm_fb * CDRMUtils::DrmFbGetFromBo(struct gbm_bo *bo) struct drm_fb *fb = new drm_fb; fb->bo = bo; - fb->format = m_overlay_plane->GetFormat(); + fb->format = m_gui_plane->GetFormat(); uint32_t width, height, @@ -365,8 +365,8 @@ drmModePlanePtr CDRMUtils::FindPlane(drmModePlaneResPtr resources, int crtc_inde case KODI_GUI_PLANE: { uint32_t plane_id = 0; - if (m_primary_plane->plane) - plane_id = m_primary_plane->plane->plane_id; + if (m_video_plane->plane) + plane_id = m_video_plane->plane->plane_id; if (plane->plane_id != plane_id && (plane_id == 0 || SupportsFormat(plane, DRM_FORMAT_ARGB8888)) && @@ -383,8 +383,8 @@ drmModePlanePtr CDRMUtils::FindPlane(drmModePlaneResPtr resources, int crtc_inde case KODI_GUI_10_PLANE: { uint32_t plane_id = 0; - if (m_primary_plane->plane) - plane_id = m_primary_plane->plane->plane_id; + if (m_video_plane->plane) + plane_id = m_video_plane->plane->plane_id; if (plane->plane_id != plane_id && (plane_id == 0 || SupportsFormat(plane, DRM_FORMAT_ARGB2101010)) && @@ -423,48 +423,48 @@ bool CDRMUtils::FindPlanes() return false; } - m_primary_plane->plane = FindPlane(plane_resources, m_crtc_index, KODI_VIDEO_PLANE); - m_overlay_plane->plane = FindPlane(plane_resources, m_crtc_index, KODI_GUI_10_PLANE); + m_video_plane->plane = FindPlane(plane_resources, m_crtc_index, KODI_VIDEO_PLANE); + m_gui_plane->plane = FindPlane(plane_resources, m_crtc_index, KODI_GUI_10_PLANE); /* fallback to 8bit plane if 10bit plane doesn't exist */ - if (m_overlay_plane->plane == nullptr) + if (m_gui_plane->plane == nullptr) { - drmModeFreePlane(m_overlay_plane->plane); - m_overlay_plane->plane = FindPlane(plane_resources, m_crtc_index, KODI_GUI_PLANE); - m_overlay_plane->SetFormat(DRM_FORMAT_XRGB8888); + drmModeFreePlane(m_gui_plane->plane); + m_gui_plane->plane = FindPlane(plane_resources, m_crtc_index, KODI_GUI_PLANE); + m_gui_plane->SetFormat(DRM_FORMAT_XRGB8888); } drmModeFreePlaneResources(plane_resources); - // primary plane may not be available - if (m_primary_plane->plane) + // video plane may not be available + if (m_video_plane->plane) { - if (!GetProperties(m_fd, m_primary_plane->plane->plane_id, DRM_MODE_OBJECT_PLANE, m_primary_plane)) + if (!GetProperties(m_fd, m_video_plane->plane->plane_id, DRM_MODE_OBJECT_PLANE, m_video_plane)) { - CLog::Log(LOGERROR, "CDRMUtils::%s - could not get primary plane %u properties: %s", __FUNCTION__, m_primary_plane->plane->plane_id, strerror(errno)); + CLog::Log(LOGERROR, "CDRMUtils::%s - could not get video plane %u properties: %s", __FUNCTION__, m_video_plane->plane->plane_id, strerror(errno)); return false; } - if (!FindModifiersForPlane(m_primary_plane)) + if (!FindModifiersForPlane(m_video_plane)) { - CLog::Log(LOGDEBUG, "CDRMUtils::%s - no drm modifiers present for the primary plane", __FUNCTION__); + CLog::Log(LOGDEBUG, "CDRMUtils::%s - no drm modifiers present for the video plane", __FUNCTION__); } } - // overlay plane should always be available - if (!GetProperties(m_fd, m_overlay_plane->plane->plane_id, DRM_MODE_OBJECT_PLANE, m_overlay_plane)) + // gui plane should always be available + if (!GetProperties(m_fd, m_gui_plane->plane->plane_id, DRM_MODE_OBJECT_PLANE, m_gui_plane)) { - CLog::Log(LOGERROR, "CDRMUtils::%s - could not get overlay plane %u properties: %s", __FUNCTION__, m_overlay_plane->plane->plane_id, strerror(errno)); + CLog::Log(LOGERROR, "CDRMUtils::%s - could not get gui plane %u properties: %s", __FUNCTION__, m_gui_plane->plane->plane_id, strerror(errno)); return false; } - if (!FindModifiersForPlane(m_overlay_plane)) + if (!FindModifiersForPlane(m_gui_plane)) { - CLog::Log(LOGDEBUG, "CDRMUtils::%s - no drm modifiers present for the overlay plane", __FUNCTION__); - m_overlay_plane->modifiers_map.emplace(DRM_FORMAT_ARGB8888, std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}); - m_overlay_plane->modifiers_map.emplace(DRM_FORMAT_XRGB8888, std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}); - m_overlay_plane->modifiers_map.emplace(DRM_FORMAT_ARGB2101010, std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}); - m_overlay_plane->modifiers_map.emplace(DRM_FORMAT_XRGB2101010, std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}); + CLog::Log(LOGDEBUG, "CDRMUtils::%s - no drm modifiers present for the gui plane", __FUNCTION__); + m_gui_plane->modifiers_map.emplace(DRM_FORMAT_ARGB8888, std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}); + m_gui_plane->modifiers_map.emplace(DRM_FORMAT_XRGB8888, std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}); + m_gui_plane->modifiers_map.emplace(DRM_FORMAT_ARGB2101010, std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}); + m_gui_plane->modifiers_map.emplace(DRM_FORMAT_XRGB2101010, std::vector<uint64_t>{DRM_FORMAT_MOD_LINEAR}); } return true; @@ -711,15 +711,15 @@ void CDRMUtils::DestroyDrm() delete m_crtc; m_crtc = nullptr; - drmModeFreePlane(m_primary_plane->plane); - FreeProperties(m_primary_plane); - delete m_primary_plane; - m_primary_plane = nullptr; + drmModeFreePlane(m_video_plane->plane); + FreeProperties(m_video_plane); + delete m_video_plane; + m_video_plane = nullptr; - drmModeFreePlane(m_overlay_plane->plane); - FreeProperties(m_overlay_plane); - delete m_overlay_plane; - m_overlay_plane = nullptr; + drmModeFreePlane(m_gui_plane->plane); + FreeProperties(m_gui_plane); + delete m_gui_plane; + m_gui_plane = nullptr; } RESOLUTION_INFO CDRMUtils::GetResolutionInfo(drmModeModeInfoPtr mode) diff --git a/xbmc/windowing/gbm/DRMUtils.h b/xbmc/windowing/gbm/DRMUtils.h index 9ca6777d24..6d6275d31b 100644 --- a/xbmc/windowing/gbm/DRMUtils.h +++ b/xbmc/windowing/gbm/DRMUtils.h @@ -104,10 +104,10 @@ public: std::string GetModule() const { return m_module; } int GetFileDescriptor() const { return m_fd; } int GetRenderNodeFileDescriptor() const { return m_renderFd; } - struct plane* GetPrimaryPlane() const { return m_primary_plane; } - struct plane* GetOverlayPlane() const { return m_overlay_plane; } - std::vector<uint64_t> *GetPrimaryPlaneModifiersForFormat(uint32_t format) { return &m_primary_plane->modifiers_map[format]; } - std::vector<uint64_t> *GetOverlayPlaneModifiersForFormat(uint32_t format) { return &m_overlay_plane->modifiers_map[format]; } + struct plane* GetVideoPlane() const { return m_video_plane; } + struct plane* GetGuiPlane() const { return m_gui_plane; } + std::vector<uint64_t> *GetVideoPlaneModifiersForFormat(uint32_t format) { return &m_video_plane->modifiers_map[format]; } + std::vector<uint64_t> *GetGuiPlaneModifiersForFormat(uint32_t format) { return &m_gui_plane->modifiers_map[format]; } struct crtc* GetCrtc() const { return m_crtc; } virtual RESOLUTION_INFO GetCurrentMode(); @@ -132,8 +132,8 @@ protected: struct connector *m_connector = nullptr; struct encoder *m_encoder = nullptr; struct crtc *m_crtc = nullptr; - struct plane *m_primary_plane = nullptr; - struct plane *m_overlay_plane = nullptr; + struct plane *m_video_plane = nullptr; + struct plane *m_gui_plane = nullptr; drmModeModeInfo *m_mode = nullptr; int m_width = 0; diff --git a/xbmc/windowing/gbm/WinSystemGbmEGLContext.cpp b/xbmc/windowing/gbm/WinSystemGbmEGLContext.cpp index 917f640ccf..cb453a541f 100644 --- a/xbmc/windowing/gbm/WinSystemGbmEGLContext.cpp +++ b/xbmc/windowing/gbm/WinSystemGbmEGLContext.cpp @@ -32,15 +32,15 @@ bool CWinSystemGbmEGLContext::InitWindowSystemEGL(EGLint renderableType, EGLint return false; } - uint32_t visualId = m_DRM->GetOverlayPlane()->GetFormat(); + uint32_t visualId = m_DRM->GetGuiPlane()->GetFormat(); // prefer alpha visual id, fallback to non-alpha visual id if (!m_eglContext.ChooseConfig(renderableType, CDRMUtils::FourCCWithAlpha(visualId)) && !m_eglContext.ChooseConfig(renderableType, CDRMUtils::FourCCWithoutAlpha(visualId))) { // fallback to 8bit format if no EGL config was found for 10bit - m_DRM->GetOverlayPlane()->useFallbackFormat = true; - visualId = m_DRM->GetOverlayPlane()->GetFormat(); + m_DRM->GetGuiPlane()->useFallbackFormat = true; + visualId = m_DRM->GetGuiPlane()->GetFormat(); if (!m_eglContext.ChooseConfig(renderableType, CDRMUtils::FourCCWithAlpha(visualId)) && !m_eglContext.ChooseConfig(renderableType, CDRMUtils::FourCCWithoutAlpha(visualId))) @@ -76,7 +76,7 @@ bool CWinSystemGbmEGLContext::CreateNewWindow(const std::string& name, } uint32_t format = m_eglContext.GetConfigAttrib(EGL_NATIVE_VISUAL_ID); - std::vector<uint64_t> *modifiers = m_DRM->GetOverlayPlaneModifiersForFormat(format); + std::vector<uint64_t> *modifiers = m_DRM->GetGuiPlaneModifiersForFormat(format); if (!m_GBM->CreateSurface(res.iWidth, res.iHeight, format, modifiers->data(), modifiers->size())) { diff --git a/xbmc/windowing/osx/WinEventsSDL.cpp b/xbmc/windowing/osx/WinEventsSDL.cpp index d1b7392cb4..745292814d 100644 --- a/xbmc/windowing/osx/WinEventsSDL.cpp +++ b/xbmc/windowing/osx/WinEventsSDL.cpp @@ -50,6 +50,9 @@ bool CWinEventsSDL::MessagePump() else if (event.active.state & SDL_APPINPUTFOCUS) { g_application.m_AppFocused = event.active.gain != 0; + std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort(); + if (appPort) + appPort->SetRenderGUI(event.active.gain != 0); CServiceBroker::GetWinSystem()->NotifyAppFocusChange(g_application.m_AppFocused); } break; diff --git a/xbmc/windowing/osx/WinSystemIOS.h b/xbmc/windowing/osx/WinSystemIOS.h index 8617cc665d..d29cc13b5b 100644 --- a/xbmc/windowing/osx/WinSystemIOS.h +++ b/xbmc/windowing/osx/WinSystemIOS.h @@ -37,7 +37,7 @@ public: void UpdateResolutions() override; bool CanDoWindowed() override { return false; } - void ShowOSMouse(bool show) override; + void ShowOSMouse(bool show) override {} bool HasCursor() override; void NotifyAppActiveChange(bool bActivated) override; @@ -70,13 +70,12 @@ public: protected: void PresentRenderImpl(bool rendered) override; - void SetVSyncImpl(bool enable) override; + void SetVSyncImpl(bool enable) override {} void *m_glView; // EAGLView opaque void *m_WorkingContext; // shared EAGLContext opaque bool m_bWasFullScreenBeforeMinimize; std::string m_eglext; - int m_iVSyncErrors; CCriticalSection m_resourceSection; std::vector<IDispResource*> m_resources; bool m_bIsBackgrounded; diff --git a/xbmc/windowing/osx/WinSystemIOS.mm b/xbmc/windowing/osx/WinSystemIOS.mm index 0c5c6d9a58..4a45799203 100644 --- a/xbmc/windowing/osx/WinSystemIOS.mm +++ b/xbmc/windowing/osx/WinSystemIOS.mm @@ -72,7 +72,7 @@ std::unique_ptr<CWinSystemBase> CWinSystemBase::CreateWinSystem() int CWinSystemIOS::GetDisplayIndexFromSettings() { std::string currentScreen = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_VIDEOSCREEN_MONITOR); - + int screenIdx = 0; if (currentScreen == CONST_EXTERNAL) { @@ -86,13 +86,12 @@ int CWinSystemIOS::GetDisplayIndexFromSettings() MoveToTouchscreen(); } } - + return screenIdx; } CWinSystemIOS::CWinSystemIOS() : CWinSystemBase() { - m_iVSyncErrors = 0; m_bIsBackgrounded = false; m_pDisplayLink = new CADisplayLinkWrapper; m_pDisplayLink->callbackClass = [[IOSDisplayLinkCallback alloc] init]; @@ -266,9 +265,9 @@ void CWinSystemIOS::UpdateResolutions() UpdateDesktopResolution(CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP), w, h, fps, 0); CDisplaySettings::GetInstance().GetResolutionInfo(RES_DESKTOP).strOutput = screenIdx == 0 ? CONST_TOUCHSCREEN : CONST_EXTERNAL; } - + CDisplaySettings::GetInstance().ClearCustomResolutions(); - + //now just fill in the possible resolutions for the attached screens //and push to the resolution info vector FillInVideoModes(screenIdx); @@ -291,7 +290,7 @@ void CWinSystemIOS::FillInVideoModes(int screenIdx) { w = mode.size.width; h = mode.size.height; - + if (screenIdx == 0) { res.strOutput = CONST_TOUCHSCREEN; @@ -300,7 +299,7 @@ void CWinSystemIOS::FillInVideoModes(int screenIdx) { res.strOutput = CONST_EXTERNAL; } - + UpdateDesktopResolution(res, w, h, refreshrate, 0); CLog::Log(LOGNOTICE, "Found possible resolution for display %d with %d x %d\n", screenIdx, w, h); @@ -422,24 +421,6 @@ void CWinSystemIOS::PresentRenderImpl(bool rendered) [g_xbmcController presentFramebuffer]; } -void CWinSystemIOS::SetVSyncImpl(bool enable) -{ - #if 0 - // set swapinterval if possible - void *eglSwapInterval; - eglSwapInterval = dlsym( RTLD_DEFAULT, "eglSwapInterval" ); - if ( eglSwapInterval ) - { - ((void(*)(int))eglSwapInterval)( 1 ) ; - } - #endif - m_iVSyncMode = 10; -} - -void CWinSystemIOS::ShowOSMouse(bool show) -{ -} - bool CWinSystemIOS::HasCursor() { // apple touch devices diff --git a/xbmc/windowing/rpi/WinSystemRpiGLESContext.cpp b/xbmc/windowing/rpi/WinSystemRpiGLESContext.cpp index da97b4ec81..a949c85e8b 100644 --- a/xbmc/windowing/rpi/WinSystemRpiGLESContext.cpp +++ b/xbmc/windowing/rpi/WinSystemRpiGLESContext.cpp @@ -125,10 +125,8 @@ bool CWinSystemRpiGLESContext::SetFullScreen(bool fullScreen, RESOLUTION_INFO& r void CWinSystemRpiGLESContext::SetVSyncImpl(bool enable) { - m_iVSyncMode = enable ? 10:0; if (!m_pGLContext.SetVSync(enable)) { - m_iVSyncMode = 0; CLog::Log(LOGERROR, "%s,Could not set egl vsync", __FUNCTION__); } } diff --git a/xbmc/windowing/wayland/CMakeLists.txt b/xbmc/windowing/wayland/CMakeLists.txt index f7cbd30b16..1a68845ecc 100644 --- a/xbmc/windowing/wayland/CMakeLists.txt +++ b/xbmc/windowing/wayland/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES Connection.cpp OSScreenSaverIdleInhibitUnstableV1.cpp Registry.cpp Seat.cpp + SeatInputProcessing.cpp SeatSelection.cpp ShellSurface.cpp ShellSurfaceWlShell.cpp @@ -35,6 +36,7 @@ set(HEADERS Connection.h OSScreenSaverIdleInhibitUnstableV1.h Registry.h Seat.h + SeatInputProcessing.h SeatSelection.h ShellSurface.h ShellSurfaceWlShell.h diff --git a/xbmc/windowing/wayland/InputProcessorKeyboard.cpp b/xbmc/windowing/wayland/InputProcessorKeyboard.cpp index d9de97c11e..db6ece37ef 100644 --- a/xbmc/windowing/wayland/InputProcessorKeyboard.cpp +++ b/xbmc/windowing/wayland/InputProcessorKeyboard.cpp @@ -8,13 +8,10 @@ #include "InputProcessorKeyboard.h" -#include <unistd.h> - #include <cassert> #include <limits> #include "utils/log.h" -#include "platform/posix/utils/FileHandle.h" using namespace KODI::WINDOWING::WAYLAND; @@ -24,74 +21,77 @@ namespace constexpr int WL_KEYBOARD_XKB_CODE_OFFSET{8}; } -CInputProcessorKeyboard::CInputProcessorKeyboard(wayland::keyboard_t const& keyboard, IInputHandlerKeyboard& handler) -: m_keyboard{keyboard}, m_handler{handler}, m_keyRepeatTimer{std::bind(&CInputProcessorKeyboard::KeyRepeatTimeout, this)} +CInputProcessorKeyboard::CInputProcessorKeyboard(IInputHandlerKeyboard& handler) +: m_handler{handler}, m_keyRepeatTimer{std::bind(&CInputProcessorKeyboard::KeyRepeatTimeout, this)} { - m_keyboard.on_enter() = [this](std::uint32_t, wayland::surface_t, wayland::array_t) - { - m_handler.OnKeyboardEnter(); - }; - m_keyboard.on_leave() = [this](std::uint32_t, wayland::surface_t) - { - m_keyRepeatTimer.Stop(); - m_handler.OnKeyboardLeave(); - }; - m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay) - { - CLog::Log(LOGDEBUG, "Key repeat rate: %d cps, delay %d ms", rate, delay); - // rate is in characters per second, so convert to msec interval - m_keyRepeatInterval = (rate != 0) ? static_cast<int> (1000.0f / rate) : 0; - m_keyRepeatDelay = delay; - }; - m_keyboard.on_keymap() = [this](wayland::keyboard_keymap_format format, int fd, std::uint32_t size) +} + +void CInputProcessorKeyboard::OnKeyboardKeymap(CSeat* seat, wayland::keyboard_keymap_format format, std::string const &keymap) +{ + if (format != wayland::keyboard_keymap_format::xkb_v1) { - KODI::UTILS::POSIX::CFileHandle fdGuard{fd}; + CLog::Log(LOGWARNING, "Wayland compositor sent keymap in format %u, but we only understand xkbv1 - keyboard input will not work", static_cast<unsigned int>(format)); + return; + } - if (format != wayland::keyboard_keymap_format::xkb_v1) + m_keyRepeatTimer.Stop(); + + try + { + if (!m_xkbContext) { - CLog::Log(LOGWARNING, "Wayland compositor sent keymap in format %u, but we only understand xkbv1 - keyboard input will not work", - static_cast<unsigned int>(format)); - return; + // Lazily initialize XkbcommonContext + m_xkbContext.reset(new CXkbcommonContext); } - m_keyRepeatTimer.Stop(); + m_keymap = m_xkbContext->KeymapFromString(keymap); + } + catch(std::exception const& e) + { + CLog::Log(LOGERROR, "Could not parse keymap from compositor: %s - continuing without keymap", e.what()); + } +} - try - { - if (!m_xkbContext) - { - // Lazily initialize XkbcommonContext - m_xkbContext.reset(new CXkbcommonContext); - } +void CInputProcessorKeyboard::OnKeyboardEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys) +{ + m_handler.OnKeyboardEnter(); +} - m_keymap = m_xkbContext->KeymapFromSharedMemory(fd, size); - } - catch(std::exception const& e) - { - CLog::Log(LOGERROR, "Could not parse keymap from compositor: %s - continuing without keymap", e.what()); - } - }; - m_keyboard.on_key() = [this](std::uint32_t, std::uint32_t, std::uint32_t key, wayland::keyboard_key_state state) +void CInputProcessorKeyboard::OnKeyboardLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) +{ + m_keyRepeatTimer.Stop(); + m_handler.OnKeyboardLeave(); +} + +void CInputProcessorKeyboard::OnKeyboardKey(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state) +{ + if (!m_keymap) { - if (!m_keymap) - { - CLog::Log(LOGWARNING, "Key event for code %u without valid keymap, ignoring", key); - return; - } + CLog::Log(LOGWARNING, "Key event for code %u without valid keymap, ignoring", key); + return; + } - ConvertAndSendKey(key, state == wayland::keyboard_key_state::pressed); - }; - m_keyboard.on_modifiers() = [this](std::uint32_t, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) + ConvertAndSendKey(key, state == wayland::keyboard_key_state::pressed); +} + +void CInputProcessorKeyboard::OnKeyboardModifiers(CSeat* seat, std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) +{ + if (!m_keymap) { - if (!m_keymap) - { - CLog::Log(LOGWARNING, "Modifier event without valid keymap, ignoring"); - return; - } + CLog::Log(LOGWARNING, "Modifier event without valid keymap, ignoring"); + return; + } - m_keyRepeatTimer.Stop(); - m_keymap->UpdateMask(modsDepressed, modsLatched, modsLocked, group); - }; + m_keyRepeatTimer.Stop(); + m_keymap->UpdateMask(modsDepressed, modsLatched, modsLocked, group); +} + +void CInputProcessorKeyboard::OnKeyboardRepeatInfo(CSeat* seat, std::int32_t rate, std::int32_t delay) +{ + CLog::Log(LOGDEBUG, "Key repeat rate: %d cps, delay %d ms", rate, delay); + // rate is in characters per second, so convert to msec interval + m_keyRepeatInterval = (rate != 0) ? static_cast<int> (1000.0f / rate) : 0; + m_keyRepeatDelay = delay; } void CInputProcessorKeyboard::ConvertAndSendKey(std::uint32_t scancode, bool pressed) diff --git a/xbmc/windowing/wayland/InputProcessorKeyboard.h b/xbmc/windowing/wayland/InputProcessorKeyboard.h index 74051a6636..81eed5874b 100644 --- a/xbmc/windowing/wayland/InputProcessorKeyboard.h +++ b/xbmc/windowing/wayland/InputProcessorKeyboard.h @@ -12,9 +12,8 @@ #include <cstdint> #include <memory> -#include <wayland-client-protocol.hpp> - #include "input/XBMC_keysym.h" +#include "Seat.h" #include "threads/Timer.h" #include "windowing/XBMC_events.h" #include "XkbcommonKeymap.h" @@ -35,10 +34,17 @@ public: virtual ~IInputHandlerKeyboard() = default; }; -class CInputProcessorKeyboard +class CInputProcessorKeyboard final : public IRawInputHandlerKeyboard { public: - CInputProcessorKeyboard(wayland::keyboard_t const& keyboard, IInputHandlerKeyboard& handler); + CInputProcessorKeyboard(IInputHandlerKeyboard& handler); + + void OnKeyboardKeymap(CSeat* seat, wayland::keyboard_keymap_format format, std::string const& keymap) override; + void OnKeyboardEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys) override; + void OnKeyboardLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) override; + void OnKeyboardKey(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state) override; + void OnKeyboardModifiers(CSeat* seat, std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) override; + void OnKeyboardRepeatInfo(CSeat* seat, std::int32_t rate, std::int32_t delay) override; private: CInputProcessorKeyboard(CInputProcessorKeyboard const& other) = delete; @@ -48,7 +54,6 @@ private: XBMC_Event SendKey(unsigned char scancode, XBMCKey key, std::uint16_t unicodeCodepoint, bool pressed); void KeyRepeatTimeout(); - wayland::keyboard_t m_keyboard; IInputHandlerKeyboard& m_handler; std::unique_ptr<CXkbcommonContext> m_xkbContext; diff --git a/xbmc/windowing/wayland/InputProcessorPointer.cpp b/xbmc/windowing/wayland/InputProcessorPointer.cpp index d81f7f0972..5114071614 100644 --- a/xbmc/windowing/wayland/InputProcessorPointer.cpp +++ b/xbmc/windowing/wayland/InputProcessorPointer.cpp @@ -37,73 +37,70 @@ int WaylandToXbmcButton(std::uint32_t button) } -CInputProcessorPointer::CInputProcessorPointer(wayland::pointer_t const& pointer, wayland::surface_t const& surface, IInputHandlerPointer& handler) -: m_pointer{pointer}, m_surface{surface}, m_handler{handler} +CInputProcessorPointer::CInputProcessorPointer(wayland::surface_t const& surface, IInputHandlerPointer& handler) +: m_surface{surface}, m_handler{handler} { - m_pointer.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) - { - if (surface == m_surface) - { - m_pointerOnSurface = true; - m_handler.OnPointerEnter(m_pointer, serial); - SetMousePosFromSurface({surfaceX, surfaceY}); - SendMouseMotion(); - } - }; - m_pointer.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface) +} + +void CInputProcessorPointer::OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) +{ + if (surface == m_surface) { - if (m_pointerOnSurface) - { - m_handler.OnPointerLeave(); - m_pointerOnSurface = false; - } - }; - m_pointer.on_motion() = [this](std::uint32_t time, double surfaceX, double surfaceY) + m_pointerOnSurface = true; + m_handler.OnPointerEnter(seat->GetGlobalName(), serial); + SetMousePosFromSurface({surfaceX, surfaceY}); + SendMouseMotion(); + } +} + +void CInputProcessorPointer::OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) +{ + if (m_pointerOnSurface) { - if (m_pointerOnSurface) - { - SetMousePosFromSurface({surfaceX, surfaceY}); - SendMouseMotion(); - } - }; - m_pointer.on_button() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) + m_handler.OnPointerLeave(); + m_pointerOnSurface = false; + } +} + +void CInputProcessorPointer::OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY) +{ + if (m_pointerOnSurface) { - if (m_pointerOnSurface) - { - int xbmcButton = WaylandToXbmcButton(button); - if (xbmcButton < 0) - { - // Button is unmapped - return; - } - - bool pressed = (state == wayland::pointer_button_state::pressed); - SendMouseButton(xbmcButton, pressed); - } - }; - m_pointer.on_axis() = [this](std::uint32_t, wayland::pointer_axis, double value) + SetMousePosFromSurface({surfaceX, surfaceY}); + SendMouseMotion(); + } +} + +void CInputProcessorPointer::OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) +{ + if (m_pointerOnSurface) { - if (m_pointerOnSurface) + int xbmcButton = WaylandToXbmcButton(button); + if (xbmcButton < 0) { - // For axis events we only care about the vector direction - // and not the scalar magnitude. Every axis event callback - // generates one scroll button event for XBMC - - // Negative is up - auto xbmcButton = static_cast<unsigned char> ((value < 0.0) ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN); - // Simulate a single click of the wheel-equivalent "button" - SendMouseButton(xbmcButton, true); - SendMouseButton(xbmcButton, false); + // Button is unmapped + return; } - }; - // Wayland groups pointer events, but right now there is no benefit in - // treating them in groups. The main use case for doing so seems to be - // multi-axis (i.e. diagnoal) scrolling, but we do not support this anyway. - /*m_pointer.on_frame() = [this]() - { + bool pressed = (state == wayland::pointer_button_state::pressed); + SendMouseButton(xbmcButton, pressed); + } +} - };*/ +void CInputProcessorPointer::OnPointerAxis(CSeat* seat, std::uint32_t time, wayland::pointer_axis axis, double value) +{ + if (m_pointerOnSurface) + { + // For axis events we only care about the vector direction + // and not the scalar magnitude. Every axis event callback + // generates one scroll button event for XBMC + + // Negative is up + auto xbmcButton = static_cast<unsigned char> ((value < 0.0) ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN); + // Simulate a single click of the wheel-equivalent "button" + SendMouseButton(xbmcButton, true); + SendMouseButton(xbmcButton, false); + } } std::uint16_t CInputProcessorPointer::ConvertMouseCoordinate(double coord) const @@ -128,4 +125,4 @@ void CInputProcessorPointer::SendMouseButton(unsigned char button, bool pressed) XBMC_Event event{static_cast<unsigned char> (pressed ? XBMC_MOUSEBUTTONDOWN : XBMC_MOUSEBUTTONUP)}; event.button = {button, m_pointerPosition.x, m_pointerPosition.y}; m_handler.OnPointerEvent(event); -}
\ No newline at end of file +} diff --git a/xbmc/windowing/wayland/InputProcessorPointer.h b/xbmc/windowing/wayland/InputProcessorPointer.h index 20ab2e4a07..afae6d2176 100644 --- a/xbmc/windowing/wayland/InputProcessorPointer.h +++ b/xbmc/windowing/wayland/InputProcessorPointer.h @@ -14,6 +14,7 @@ #include "input/XBMC_keysym.h" #include "utils/Geometry.h" +#include "Seat.h" #include "windowing/XBMC_events.h" namespace KODI @@ -26,18 +27,25 @@ namespace WAYLAND class IInputHandlerPointer { public: - virtual void OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) {}; - virtual void OnPointerLeave() {}; + virtual void OnPointerEnter(std::uint32_t seatGlobalName, std::uint32_t serial) {} + virtual void OnPointerLeave() {} virtual void OnPointerEvent(XBMC_Event& event) = 0; - virtual ~IInputHandlerPointer() = default; +protected: + ~IInputHandlerPointer() {} }; -class CInputProcessorPointer +class CInputProcessorPointer final : public IRawInputHandlerPointer { public: - CInputProcessorPointer(wayland::pointer_t const& pointer, wayland::surface_t const& surface, IInputHandlerPointer& handler); + CInputProcessorPointer(wayland::surface_t const& surface, IInputHandlerPointer& handler); void SetCoordinateScale(std::int32_t scale) { m_coordinateScale = scale; } + void OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) override; + void OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) override; + void OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY) override; + void OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) override; + void OnPointerAxis(CSeat* seat, std::uint32_t time, wayland::pointer_axis axis, double value) override; + private: CInputProcessorPointer(CInputProcessorPointer const& other) = delete; CInputProcessorPointer& operator=(CInputProcessorPointer const& other) = delete; @@ -47,7 +55,6 @@ private: void SendMouseMotion(); void SendMouseButton(unsigned char button, bool pressed); - wayland::pointer_t m_pointer; wayland::surface_t m_surface; IInputHandlerPointer& m_handler; diff --git a/xbmc/windowing/wayland/InputProcessorTouch.cpp b/xbmc/windowing/wayland/InputProcessorTouch.cpp index 3fa3a559da..8f1208b9d9 100644 --- a/xbmc/windowing/wayland/InputProcessorTouch.cpp +++ b/xbmc/windowing/wayland/InputProcessorTouch.cpp @@ -12,76 +12,81 @@ using namespace KODI::WINDOWING::WAYLAND; -CInputProcessorTouch::CInputProcessorTouch(wayland::touch_t const& touch, wayland::surface_t const& surface) -: m_touch{touch}, m_surface{surface} +CInputProcessorTouch::CInputProcessorTouch(wayland::surface_t const& surface) +: m_surface{surface} { - m_touch.on_down() = [this](std::uint32_t, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) +} + +void CInputProcessorTouch::OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) +{ + if (surface != m_surface) { - if (surface != m_surface) - { - return; - } + return; + } - // Find free Kodi pointer number - int kodiPointer{-1}; - // Not optimal, but irrelevant for the small number of iterations - for (int testPointer{0}; testPointer < CGenericTouchInputHandler::MAX_POINTERS; testPointer++) + // Find free Kodi pointer number + int kodiPointer{-1}; + // Not optimal, but irrelevant for the small number of iterations + for (int testPointer{0}; testPointer < CGenericTouchInputHandler::MAX_POINTERS; testPointer++) + { + if (std::all_of(m_touchPoints.cbegin(), m_touchPoints.cend(), + [=](decltype(m_touchPoints)::value_type const& pair) + { + return (pair.second.kodiPointerNumber != testPointer); + })) { - if (std::all_of(m_touchPoints.cbegin(), m_touchPoints.cend(), - [=](decltype(m_touchPoints)::value_type const& pair) - { - return (pair.second.kodiPointerNumber != testPointer); - })) - { - kodiPointer = testPointer; - break; - } + kodiPointer = testPointer; + break; } + } - if (kodiPointer != -1) - { - auto it = m_touchPoints.emplace(std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(time, kodiPointer, x * m_coordinateScale, y * m_coordinateScale, 0.0f)).first; - SendTouchPointEvent(TouchInputDown, it->second); - } - }; - m_touch.on_up() = [this](std::uint32_t, std::uint32_t time, std::int32_t id) + if (kodiPointer != -1) { - auto it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) - { - auto& point = it->second; - point.lastEventTime = time; - SendTouchPointEvent(TouchInputUp, point); - m_touchPoints.erase(it); - } - }; - m_touch.on_motion() = [this](std::uint32_t time, std::int32_t id, double x, double y) + auto it = m_touchPoints.emplace(std::piecewise_construct, std::forward_as_tuple(id), std::forward_as_tuple(time, kodiPointer, x * m_coordinateScale, y * m_coordinateScale, 0.0f)).first; + SendTouchPointEvent(TouchInputDown, it->second); + } +} + +void CInputProcessorTouch::OnTouchUp(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::int32_t id) +{ + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) { - auto it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) - { - auto& point = it->second; - point.x = x * m_coordinateScale; - point.y = y * m_coordinateScale; - point.lastEventTime = time; - SendTouchPointEvent(TouchInputMove, point); - } - }; - m_touch.on_cancel() = [this]() + auto& point = it->second; + point.lastEventTime = time; + SendTouchPointEvent(TouchInputUp, point); + m_touchPoints.erase(it); + } +} + +void CInputProcessorTouch::OnTouchMotion(CSeat* seat, std::uint32_t time, std::int32_t id, double x, double y) +{ + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) { - AbortTouches(); - }; - m_touch.on_shape() = [this](std::int32_t id, double major, double minor) + auto& point = it->second; + point.x = x * m_coordinateScale; + point.y = y * m_coordinateScale; + point.lastEventTime = time; + SendTouchPointEvent(TouchInputMove, point); + } +} + +void CInputProcessorTouch::OnTouchCancel(CSeat* seat) +{ + AbortTouches(); +} + +void CInputProcessorTouch::OnTouchShape(CSeat* seat, std::int32_t id, double major, double minor) +{ + auto it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) { - auto it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) - { - auto& point = it->second; - // Kodi only supports size without shape, so use average of both axes - point.size = ((major + minor) / 2.0) * m_coordinateScale; - UpdateTouchPoint(point); - } - }; + auto& point = it->second; + // Kodi only supports size without shape, so use average of both axes + point.size = ((major + minor) / 2.0) * m_coordinateScale; + UpdateTouchPoint(point); + } } CInputProcessorTouch::~CInputProcessorTouch() noexcept diff --git a/xbmc/windowing/wayland/InputProcessorTouch.h b/xbmc/windowing/wayland/InputProcessorTouch.h index 63f589600d..a71d88d455 100644 --- a/xbmc/windowing/wayland/InputProcessorTouch.h +++ b/xbmc/windowing/wayland/InputProcessorTouch.h @@ -14,6 +14,7 @@ #include <wayland-client-protocol.hpp> #include "input/touch/ITouchInputHandler.h" +#include "Seat.h" namespace KODI { @@ -27,13 +28,19 @@ namespace WAYLAND * * Events go directly to \ref CGenericTouchInputHandler, so no callbacks here */ -class CInputProcessorTouch +class CInputProcessorTouch final : public IRawInputHandlerTouch { public: - CInputProcessorTouch(wayland::touch_t const& touch, wayland::surface_t const& surface); + CInputProcessorTouch(wayland::surface_t const& surface); ~CInputProcessorTouch() noexcept; void SetCoordinateScale(std::int32_t scale) { m_coordinateScale = scale; } + void OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) override; + void OnTouchUp(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::int32_t id) override; + void OnTouchMotion(CSeat* seat, std::uint32_t time, std::int32_t id, double x, double y) override; + void OnTouchCancel(CSeat* seat) override; + void OnTouchShape(CSeat* seat, std::int32_t id, double major, double minor) override; + private: CInputProcessorTouch(CInputProcessorTouch const& other) = delete; CInputProcessorTouch& operator=(CInputProcessorTouch const& other) = delete; @@ -57,7 +64,6 @@ private: void UpdateTouchPoint(TouchPoint const& point); void AbortTouches(); - wayland::touch_t m_touch; wayland::surface_t m_surface; std::int32_t m_coordinateScale{1}; diff --git a/xbmc/windowing/wayland/Seat.cpp b/xbmc/windowing/wayland/Seat.cpp index 621fea0099..601cc3d433 100644 --- a/xbmc/windowing/wayland/Seat.cpp +++ b/xbmc/windowing/wayland/Seat.cpp @@ -8,6 +8,11 @@ #include "Seat.h" +#include <cassert> +#include <unistd.h> + +#include "platform/posix/utils/FileHandle.h" +#include "platform/posix/utils/Mmap.h" #include "utils/log.h" using namespace KODI::WINDOWING::WAYLAND; @@ -20,55 +25,54 @@ namespace * Handle change of availability of a wl_seat input capability * * This checks whether the capability is currently available with the wl_seat - * and whether it was bound to a processor. If there is a mismatch between - * these two, the processor is destroyed if a capability was removed or created + * and whether it was bound to a protocol object. If there is a mismatch between + * these two, the protocol proxy is released if a capability was removed or bound * if a capability was added. * - * \param handler CSeat instance * \param caps new capabilities * \param cap capability to check for + * \param seatName human-readable name of the seat for log messages * \param capName human-readable name of the capability for log messages - * \param processor reference to a smart pointer that holds the - * processor corresponding to the capability + * \param proxy proxy object that should be filled with a new instance or reset * \param instanceProvider function that functions as factory for the Wayland * protocol instance if the capability has been added - * \param onNewCapability function that is called after setting the new capability - * instance when it was added */ -template<typename T, typename ProcessorPtrT, typename InstanceProviderT, typename OnNewCapabilityT> -void HandleCapabilityChange(CSeat* handler, - wayland::seat_capability caps, +template<typename T, typename InstanceProviderT> +bool HandleCapabilityChange(wayland::seat_capability caps, wayland::seat_capability cap, - std::string const & capName, - ProcessorPtrT& processor, - InstanceProviderT instanceProvider, - OnNewCapabilityT onNewCapability) + std::string const& seatName, + std::string const& capName, + T& proxy, + InstanceProviderT instanceProvider) { bool hasCapability = caps & cap; - if ((!!processor) != hasCapability) + if ((!!proxy) != hasCapability) { // Capability changed if (hasCapability) { // The capability was added - CLog::Log(LOGDEBUG, "Wayland seat %s gained capability %s", handler->GetName().c_str(), capName.c_str()); - onNewCapability(instanceProvider()); + CLog::Log(LOGDEBUG, "Wayland seat {} gained capability {}", seatName, capName); + proxy = instanceProvider(); + return true; } else { // The capability was removed - CLog::Log(LOGDEBUG, "Wayland seat %s lost capability %s", handler->GetName().c_str(), capName.c_str()); - processor.reset(); + CLog::Log(LOGDEBUG, "Wayland seat {} lost capability {}", seatName, capName); + proxy.proxy_release(); } } + + return false; } } -CSeat::CSeat(std::uint32_t globalName, wayland::seat_t const& seat, wayland::surface_t const& inputSurface, CConnection& connection, IInputHandler& handler) -: m_globalName{globalName}, m_seat{seat}, m_inputSurface{inputSurface}, m_handler{handler}, m_selection{connection, seat} +CSeat::CSeat(std::uint32_t globalName, wayland::seat_t const& seat, CConnection& connection) +: m_globalName{globalName}, m_seat{seat}, m_selection{connection, seat} { m_seat.on_name() = [this](std::string name) { @@ -79,96 +83,194 @@ CSeat::CSeat(std::uint32_t globalName, wayland::seat_t const& seat, wayland::sur CSeat::~CSeat() noexcept = default; -void CSeat::HandleOnCapabilities(wayland::seat_capability caps) +void CSeat::AddRawInputHandlerKeyboard(KODI::WINDOWING::WAYLAND::IRawInputHandlerKeyboard *rawKeyboardHandler) { - HandleCapabilityChange<wayland::pointer_t> - (this, - caps, - wayland::seat_capability::pointer, - "pointer", - m_pointer, - std::bind(&wayland::seat_t::get_pointer, &m_seat), - std::bind(&CSeat::HandlePointerCapability, this, _1)); - HandleCapabilityChange<wayland::keyboard_t> - (this, - caps, - wayland::seat_capability::keyboard, - "keyboard", - m_keyboard, - std::bind(&wayland::seat_t::get_keyboard, &m_seat), - std::bind(&CSeat::HandleKeyboardCapability, this, _1)); - HandleCapabilityChange<wayland::touch_t> - (this, - caps, - wayland::seat_capability::touch, - "touch", - m_touch, - std::bind(&wayland::seat_t::get_touch, &m_seat), - std::bind(&CSeat::HandleTouchCapability, this, _1)); + assert(rawKeyboardHandler); + m_rawKeyboardHandlers.emplace(rawKeyboardHandler); } -void CSeat::HandlePointerCapability(wayland::pointer_t const& pointer) +void CSeat::RemoveRawInputHandlerKeyboard(KODI::WINDOWING::WAYLAND::IRawInputHandlerKeyboard *rawKeyboardHandler) { - m_pointer.reset(new CInputProcessorPointer(pointer, m_inputSurface, static_cast<IInputHandlerPointer&> (*this))); - UpdateCoordinateScale(); + m_rawKeyboardHandlers.erase(rawKeyboardHandler); } -void CSeat::OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) +void CSeat::AddRawInputHandlerPointer(IRawInputHandlerPointer* rawPointerHandler) { - m_handler.OnSetCursor(pointer, serial); - m_handler.OnEnter(m_globalName, InputType::POINTER); + assert(rawPointerHandler); + m_rawPointerHandlers.emplace(rawPointerHandler); } -void CSeat::OnPointerLeave() +void CSeat::RemoveRawInputHandlerPointer(KODI::WINDOWING::WAYLAND::IRawInputHandlerPointer *rawPointerHandler) { - m_handler.OnLeave(m_globalName, InputType::POINTER); + m_rawPointerHandlers.erase(rawPointerHandler); } -void CSeat::OnPointerEvent(XBMC_Event& event) +void CSeat::AddRawInputHandlerTouch(IRawInputHandlerTouch* rawTouchHandler) { - m_handler.OnEvent(m_globalName, InputType::POINTER, event); + assert(rawTouchHandler); + m_rawTouchHandlers.emplace(rawTouchHandler); } -void CSeat::HandleKeyboardCapability(wayland::keyboard_t const& keyboard) +void CSeat::RemoveRawInputHandlerTouch(KODI::WINDOWING::WAYLAND::IRawInputHandlerTouch *rawTouchHandler) { - m_keyboard.reset(new CInputProcessorKeyboard(keyboard, static_cast<IInputHandlerKeyboard&> (*this))); + m_rawTouchHandlers.erase(rawTouchHandler); } -void CSeat::OnKeyboardEnter() +void CSeat::HandleOnCapabilities(wayland::seat_capability caps) { - m_handler.OnEnter(m_globalName, InputType::KEYBOARD); + if (HandleCapabilityChange(caps, wayland::seat_capability::keyboard, GetName(), "keyboard", m_keyboard, std::bind(&wayland::seat_t::get_keyboard, m_seat))) + { + HandleKeyboardCapability(); + } + if (HandleCapabilityChange(caps, wayland::seat_capability::pointer, GetName(), "pointer", m_pointer, std::bind(&wayland::seat_t::get_pointer, m_seat))) + { + HandlePointerCapability(); + } + if (HandleCapabilityChange(caps, wayland::seat_capability::touch, GetName(), "touch", m_touch, std::bind(&wayland::seat_t::get_touch, m_seat))) + { + HandleTouchCapability(); + } } -void CSeat::OnKeyboardLeave() +void CSeat::SetCursor(std::uint32_t serial, wayland::surface_t const &surface, std::int32_t hotspotX, std::int32_t hotspotY) { - m_handler.OnLeave(m_globalName, InputType::KEYBOARD); + if (m_pointer) + { + m_pointer.set_cursor(serial, surface, hotspotX, hotspotY); + } } -void CSeat::OnKeyboardEvent(XBMC_Event& event) +void CSeat::HandleKeyboardCapability() { - m_handler.OnEvent(m_globalName, InputType::KEYBOARD, event); + m_keyboard.on_keymap() = [this](wayland::keyboard_keymap_format format, int fd, std::uint32_t size) + { + KODI::UTILS::POSIX::CFileHandle fdGuard{fd}; + KODI::UTILS::POSIX::CMmap mmap{nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0}; + std::string keymap{static_cast<const char*> (mmap.Data()), size}; + for (auto handler : m_rawKeyboardHandlers) + { + handler->OnKeyboardKeymap(this, format, keymap); + } + }; + m_keyboard.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys) + { + for (auto handler : m_rawKeyboardHandlers) + { + handler->OnKeyboardEnter(this, serial, surface, keys); + } + }; + m_keyboard.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface) + { + for (auto handler : m_rawKeyboardHandlers) + { + handler->OnKeyboardLeave(this, serial, surface); + } + }; + m_keyboard.on_key() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state) + { + for (auto handler : m_rawKeyboardHandlers) + { + handler->OnKeyboardKey(this, serial, time, key, state); + } + }; + m_keyboard.on_modifiers() = [this](std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) + { + for (auto handler : m_rawKeyboardHandlers) + { + handler->OnKeyboardModifiers(this, serial, modsDepressed, modsLatched, modsLocked, group); + } + }; + m_keyboard.on_repeat_info() = [this](std::int32_t rate, std::int32_t delay) + { + for (auto handler : m_rawKeyboardHandlers) + { + handler->OnKeyboardRepeatInfo(this, rate, delay); + } + }; } -void CSeat::HandleTouchCapability(wayland::touch_t const& touch) -{ - m_touch.reset(new CInputProcessorTouch(touch, m_inputSurface)); - UpdateCoordinateScale(); -} -void CSeat::SetCoordinateScale(std::int32_t scale) +void CSeat::HandlePointerCapability() { - m_coordinateScale = scale; - UpdateCoordinateScale(); + m_pointer.on_enter() = [this](std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) + { + for (auto handler : m_rawPointerHandlers) + { + handler->OnPointerEnter(this, serial, surface, surfaceX, surfaceY); + } + }; + m_pointer.on_leave() = [this](std::uint32_t serial, wayland::surface_t surface) + { + for (auto handler : m_rawPointerHandlers) + { + handler->OnPointerLeave(this, serial, surface); + } + }; + m_pointer.on_motion() = [this](std::uint32_t time, double surfaceX, double surfaceY) + { + for (auto handler : m_rawPointerHandlers) + { + handler->OnPointerMotion(this, time, surfaceX, surfaceY); + } + }; + m_pointer.on_button() = [this](std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) + { + for (auto handler : m_rawPointerHandlers) + { + handler->OnPointerButton(this, serial, time, button, state); + } + }; + m_pointer.on_axis() = [this](std::uint32_t time, wayland::pointer_axis axis, double value) + { + for (auto handler : m_rawPointerHandlers) + { + handler->OnPointerAxis(this, time, axis, value); + } + }; + // Wayland groups pointer events, but right now there is no benefit in + // treating them in groups. The main use case for doing so seems to be + // multi-axis (i.e. diagnoal) scrolling, but we do not support this anyway. + /*m_pointer.on_frame() = [this]() + { + + };*/ } -void CSeat::UpdateCoordinateScale() +void CSeat::HandleTouchCapability() { - if (m_pointer) + m_touch.on_down() = [this](std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) { - m_pointer->SetCoordinateScale(m_coordinateScale); - } - if (m_touch) + for (auto handler : m_rawTouchHandlers) + { + handler->OnTouchDown(this, serial, time, surface, id, x, y); + } + }; + m_touch.on_up() = [this](std::uint32_t serial, std::uint32_t time, std::int32_t id) { - m_touch->SetCoordinateScale(m_coordinateScale); - } + for (auto handler : m_rawTouchHandlers) + { + handler->OnTouchUp(this, serial, time, id); + } + }; + m_touch.on_motion() = [this](std::uint32_t time, std::int32_t id, double x, double y) + { + for (auto handler : m_rawTouchHandlers) + { + handler->OnTouchMotion(this, time, id, x, y); + } + }; + m_touch.on_cancel() = [this]() + { + for (auto handler : m_rawTouchHandlers) + { + handler->OnTouchCancel(this); + } + }; + m_touch.on_shape() = [this](std::int32_t id, double major, double minor) + { + for (auto handler : m_rawTouchHandlers) + { + handler->OnTouchShape(this, id, major, minor); + } + }; } diff --git a/xbmc/windowing/wayland/Seat.h b/xbmc/windowing/wayland/Seat.h index adb083a25a..91c0017e4c 100644 --- a/xbmc/windowing/wayland/Seat.h +++ b/xbmc/windowing/wayland/Seat.h @@ -8,18 +8,12 @@ #pragma once -#include <map> -#include <memory> +#include <cstdint> +#include <set> #include <wayland-client-protocol.hpp> -#include "input/touch/ITouchInputHandler.h" -#include "InputProcessorPointer.h" -#include "InputProcessorKeyboard.h" -#include "InputProcessorTouch.h" #include "SeatSelection.h" -#include "threads/Timer.h" -#include "windowing/XBMC_events.h" namespace KODI { @@ -28,73 +22,91 @@ namespace WINDOWING namespace WAYLAND { -enum class InputType +class CSeat; + +/** + * Handler for raw wl_keyboard events + * + * All functions are identical to wl_keyboard, except for the keymap which is + * retrieved from its fd and put into a string + */ +class IRawInputHandlerKeyboard { - POINTER, - KEYBOARD, - TOUCH +public: + virtual void OnKeyboardKeymap(CSeat* seat, wayland::keyboard_keymap_format format, std::string const& keymap) {} + virtual void OnKeyboardEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, wayland::array_t keys) {} + virtual void OnKeyboardLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) {} + virtual void OnKeyboardKey(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t key, wayland::keyboard_key_state state) {} + virtual void OnKeyboardModifiers(CSeat* seat, std::uint32_t serial, std::uint32_t modsDepressed, std::uint32_t modsLatched, std::uint32_t modsLocked, std::uint32_t group) {} + virtual void OnKeyboardRepeatInfo(CSeat* seat, std::int32_t rate, std::int32_t delay) {} +protected: + ~IRawInputHandlerKeyboard() {} }; /** - * Handler interface for input events from \ref CSeatInputProcessor + * Handler for raw wl_pointer events + * + * All functions are identical to wl_pointer */ -class IInputHandler +class IRawInputHandlerPointer { public: - /** - * Handle input event - * \param seatGlobalName numeric Wayland global name of the seat the event occured on - * \param type input device type that caused the event - * \param event XBMC event data - */ - virtual void OnEvent(std::uint32_t seatGlobalName, InputType type, XBMC_Event& event) {} - /** - * Handle focus enter - * \param seatGlobalName numeric Wayland global name of the seat the event occured on - * \param type input device type for which the surface has gained the focus - */ - virtual void OnEnter(std::uint32_t seatGlobalName, InputType type) {} - /** - * Handle focus leave - * \param seatGlobalName numeric Wayland global name of the seat the event occured on - * \param type input device type for which the surface has lost the focus - */ - virtual void OnLeave(std::uint32_t seatGlobalName, InputType type) {} - /** - * Handle request for setting the cursor - * - * When the client gains pointer focus for a surface, a cursor image must be - * attached to the pointer. Otherwise the previous pointer image would - * be used. - * - * This request is sent in addition to \ref OnEnter for \ref InputType::POINTER. - * - * \param pointer pointer instance that needs its cursor set - * \param serial Wayland protocol message serial that must be sent back in set_cursor - */ - virtual void OnSetCursor(wayland::pointer_t& pointer, std::uint32_t serial) {} + virtual void OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) {} + virtual void OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) {} + virtual void OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY) {} + virtual void OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) {} + virtual void OnPointerAxis(CSeat* seat, std::uint32_t time, wayland::pointer_axis axis, double value) {} +protected: + ~IRawInputHandlerPointer() {} +}; - virtual ~IInputHandler() = default; +/** + * Handler for raw wl_touch events + * + * All functions are identical to wl_touch + */ +class IRawInputHandlerTouch +{ +public: + virtual void OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) {} + virtual void OnTouchUp(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::int32_t id) {} + virtual void OnTouchMotion(CSeat* seat, std::uint32_t time, std::int32_t id, double x, double y) {} + virtual void OnTouchCancel(CSeat* seat) {} + virtual void OnTouchShape(CSeat* seat, std::int32_t id, double major, double minor) {} +protected: + ~IRawInputHandlerTouch() {}; }; /** - * Handle all wl_seat-related events and process them into Kodi events + * Handle all events and requests related to one seat (including input and selection) + * + * The primary purpose of this class is to act as entry point of Wayland events into + * the Kodi world and distribute them further as necessary. + * Input events are forwarded to (potentially multiple) handlers. As the Wayland + * protocol is not very specific on having multiple wl_seat/wl_pointer instances + * and how they interact, having one central instance and then handling everything + * in Kodi with multiple handlers is better than each handler having its own + * protocol object instance. */ -class CSeat : IInputHandlerPointer, IInputHandlerKeyboard +class CSeat { public: /** * Construct seat handler * \param globalName Wayland numeric global name of the seat * \param seat bound seat_t instance - * \param inputSurface surface that receives the input, used for matching - * pointer focus enter/leave events * \param connection connection for retrieving additional globals - * \param handler handler that receives events from this seat, must not be null */ - CSeat(std::uint32_t globalName, wayland::seat_t const& seat, wayland::surface_t const& inputSurface, CConnection& connection, IInputHandler& handler); + CSeat(std::uint32_t globalName, wayland::seat_t const& seat, CConnection& connection); ~CSeat() noexcept; + void AddRawInputHandlerKeyboard(IRawInputHandlerKeyboard* rawKeyboardHandler); + void RemoveRawInputHandlerKeyboard(IRawInputHandlerKeyboard* rawKeyboardHandler); + void AddRawInputHandlerPointer(IRawInputHandlerPointer* rawPointerHandler); + void RemoveRawInputHandlerPointer(IRawInputHandlerPointer* rawPointerHandler); + void AddRawInputHandlerTouch(IRawInputHandlerTouch* rawTouchHandler); + void RemoveRawInputHandlerTouch(IRawInputHandlerTouch* rawTouchHandler); + std::uint32_t GetGlobalName() const { return m_globalName; @@ -119,38 +131,47 @@ public: { return m_selection.GetSelectionText(); } - void SetCoordinateScale(std::int32_t scale); + /** + * Get the wl_seat underlying this seat + * + * The wl_seat should only be used when strictly necessary, e.g. when + * starting a move operation with shell interfaces. + * It may not be used to derive further wl_pointer etc. instances. + */ + wayland::seat_t const& GetWlSeat() + { + return m_seat; + } + + /** + * Set the cursor of the pointer of this seat + * + * Parameters are identical wo wl_pointer.set_cursor(). + * If the seat does not currently have the pointer capability, this is a no-op. + */ + void SetCursor(std::uint32_t serial, wayland::surface_t const& surface, std::int32_t hotspotX, std::int32_t hotspotY); private: CSeat(CSeat const& other) = delete; CSeat& operator=(CSeat const& other) = delete; void HandleOnCapabilities(wayland::seat_capability caps); - void HandlePointerCapability(wayland::pointer_t const& pointer); - void HandleKeyboardCapability(wayland::keyboard_t const& keyboard); - void HandleTouchCapability(wayland::touch_t const& touch); - - void OnKeyboardEnter() override; - void OnKeyboardLeave() override; - void OnKeyboardEvent(XBMC_Event& event) override; - - void OnPointerEnter(wayland::pointer_t& pointer, std::uint32_t serial) override; - void OnPointerLeave() override; - void OnPointerEvent(XBMC_Event& event) override; - - void UpdateCoordinateScale(); + void HandlePointerCapability(); + void HandleKeyboardCapability(); + void HandleTouchCapability(); std::uint32_t m_globalName; - wayland::seat_t m_seat; - wayland::surface_t m_inputSurface; std::string m_name{"<unknown>"}; - std::int32_t m_coordinateScale{1}; - IInputHandler& m_handler; + wayland::seat_t m_seat; + wayland::pointer_t m_pointer; + wayland::keyboard_t m_keyboard; + wayland::touch_t m_touch; + + std::set<IRawInputHandlerKeyboard*> m_rawKeyboardHandlers; + std::set<IRawInputHandlerPointer*> m_rawPointerHandlers; + std::set<IRawInputHandlerTouch*> m_rawTouchHandlers; - std::unique_ptr<CInputProcessorPointer> m_pointer; - std::unique_ptr<CInputProcessorKeyboard> m_keyboard; - std::unique_ptr<CInputProcessorTouch> m_touch; CSeatSelection m_selection; }; diff --git a/xbmc/windowing/wayland/SeatInputProcessing.cpp b/xbmc/windowing/wayland/SeatInputProcessing.cpp new file mode 100644 index 0000000000..6430aad20c --- /dev/null +++ b/xbmc/windowing/wayland/SeatInputProcessing.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "SeatInputProcessing.h" + +#include <cassert> + +using namespace KODI::WINDOWING::WAYLAND; + +CSeatInputProcessing::CSeatInputProcessing(wayland::surface_t const& inputSurface, IInputHandler& handler) +: m_inputSurface{inputSurface}, m_handler{handler} +{ +} + +void CSeatInputProcessing::AddSeat(CSeat* seat) +{ + assert(m_seats.find(seat->GetGlobalName()) == m_seats.end()); + auto& seatState = m_seats.emplace(seat->GetGlobalName(), seat).first->second; + + seatState.keyboardProcessor.reset(new CInputProcessorKeyboard(*this)); + seat->AddRawInputHandlerKeyboard(seatState.keyboardProcessor.get()); + seatState.pointerProcessor.reset(new CInputProcessorPointer(m_inputSurface, *this)); + seat->AddRawInputHandlerPointer(seatState.pointerProcessor.get()); + seatState.touchProcessor.reset(new CInputProcessorTouch(m_inputSurface)); + seat->AddRawInputHandlerTouch(seatState.touchProcessor.get()); +} + +void CSeatInputProcessing::RemoveSeat(CSeat* seat) +{ + auto seatStateI = m_seats.find(seat->GetGlobalName()); + if (seatStateI != m_seats.end()) + { + seat->RemoveRawInputHandlerKeyboard(seatStateI->second.keyboardProcessor.get()); + seat->RemoveRawInputHandlerPointer(seatStateI->second.pointerProcessor.get()); + seat->RemoveRawInputHandlerTouch(seatStateI->second.touchProcessor.get()); + m_seats.erase(seatStateI); + } +} + +void CSeatInputProcessing::OnPointerEnter(std::uint32_t seatGlobalName, std::uint32_t serial) +{ + m_handler.OnSetCursor(seatGlobalName, serial); + m_handler.OnEnter(InputType::POINTER); +} + +void CSeatInputProcessing::OnPointerLeave() +{ + m_handler.OnLeave(InputType::POINTER); +} + +void CSeatInputProcessing::OnPointerEvent(XBMC_Event& event) +{ + m_handler.OnEvent(InputType::POINTER, event); +} + +void CSeatInputProcessing::OnKeyboardEnter() +{ + m_handler.OnEnter(InputType::KEYBOARD); +} + +void CSeatInputProcessing::OnKeyboardLeave() +{ + m_handler.OnLeave(InputType::KEYBOARD); +} + +void CSeatInputProcessing::OnKeyboardEvent(XBMC_Event& event) +{ + m_handler.OnEvent(InputType::KEYBOARD, event); +} + +void CSeatInputProcessing::SetCoordinateScale(std::int32_t scale) +{ + for (auto& seatPair : m_seats) + { + seatPair.second.touchProcessor->SetCoordinateScale(scale); + seatPair.second.pointerProcessor->SetCoordinateScale(scale); + } +} diff --git a/xbmc/windowing/wayland/SeatInputProcessing.h b/xbmc/windowing/wayland/SeatInputProcessing.h new file mode 100644 index 0000000000..46a00912be --- /dev/null +++ b/xbmc/windowing/wayland/SeatInputProcessing.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include <cstdint> +#include <map> +#include <memory> + +#include <wayland-client-protocol.hpp> + +#include "InputProcessorKeyboard.h" +#include "InputProcessorPointer.h" +#include "InputProcessorTouch.h" +#include "Seat.h" + +namespace KODI +{ +namespace WINDOWING +{ +namespace WAYLAND +{ + +enum class InputType +{ + POINTER, + KEYBOARD, + TOUCH +}; + +/** + * Handler interface for input events from \ref CSeatInputProcessor + */ +class IInputHandler +{ +public: + /** + * Handle input event + * \param type input device type that caused the event + * \param event XBMC event data + */ + virtual void OnEvent(InputType type, XBMC_Event& event) {} + /** + * Handle focus enter + * \param type input device type for which the surface has gained the focus + */ + virtual void OnEnter(InputType type) {} + /** + * Handle focus leave + * \param type input device type for which the surface has lost the focus + */ + virtual void OnLeave(InputType type) {} + /** + * Handle request for setting the cursor + * + * When the client gains pointer focus for a surface, a cursor image must be + * attached to the pointer. Otherwise the previous pointer image would + * be used. + * + * This request is sent in addition to \ref OnEnter for \ref InputType::POINTER. + * + * \param seatGlobalName numeric Wayland global name of the seat the event occured on + * \param pointer pointer instance that needs its cursor set + * \param serial Wayland protocol message serial that must be sent back in set_cursor + */ + virtual void OnSetCursor(std::uint32_t seatGlobalName, std::uint32_t serial) {} + + virtual ~IInputHandler() = default; +}; + +/** + * Receive events from all registered wl_seats and process them into Kodi events + * + * Multi-seat support is not currently implemented completely, but each seat has + * separate state. + */ +class CSeatInputProcessing final : IInputHandlerPointer, IInputHandlerKeyboard +{ +public: + /** + * Construct a seat input processor + * + * \param inputSurface Surface that events should be processed on (all other surfaces are ignored) + * \param handler Mandatory handler for processed input events + */ + CSeatInputProcessing(wayland::surface_t const& inputSurface, IInputHandler& handler); + void AddSeat(CSeat* seat); + void RemoveSeat(CSeat* seat); + + /** + * Set the scale the coordinates should be interpreted at + * + * Wayland input events are always in surface coordinates, but Kodi only uses + * buffer coordinates internally. Use this function to set the scaling + * factor between the two and multiply the surface coordinates accordingly + * for Kodi events. + * + * \param scale new buffer-to-surface pixel ratio + */ + void SetCoordinateScale(std::int32_t scale); + +private: + wayland::surface_t m_inputSurface; + IInputHandler& m_handler; + + void OnPointerEnter(std::uint32_t seatGlobalName, std::uint32_t serial) override; + void OnPointerLeave() override; + void OnPointerEvent(XBMC_Event& event) override; + + void OnKeyboardEnter() override; + void OnKeyboardLeave() override; + void OnKeyboardEvent(XBMC_Event& event) override; + + struct SeatState + { + CSeat* seat; + std::unique_ptr<CInputProcessorKeyboard> keyboardProcessor; + std::unique_ptr<CInputProcessorPointer> pointerProcessor; + std::unique_ptr<CInputProcessorTouch> touchProcessor; + + SeatState(CSeat* seat) + : seat{seat} + {} + }; + std::map<std::uint32_t, SeatState> m_seats; +}; + +} +} +} diff --git a/xbmc/windowing/wayland/WinSystemWayland.cpp b/xbmc/windowing/wayland/WinSystemWayland.cpp index 5746645649..23f34906af 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.cpp +++ b/xbmc/windowing/wayland/WinSystemWayland.cpp @@ -241,6 +241,9 @@ bool CWinSystemWayland::DestroyWindowSystem() m_outputsInPreparation.clear(); m_outputs.clear(); m_frameCallback = wayland::callback_t{}; + m_screenSaverManager.reset(); + + m_seatInputProcessing.reset(); if (m_registry) { @@ -347,6 +350,7 @@ bool CWinSystemWayland::CreateNewWindow(const std::string& name, UpdateDesktopResolution(res, m_bufferSize.Width(), m_bufferSize.Height(), res.fRefreshRate, 0); res.bFullScreen = fullScreen; + m_seatInputProcessing.reset(new CSeatInputProcessing(m_surface, *this)); m_seatRegistry.reset(new CRegistry{*m_connection}); // version 2 adds name event -> optional // version 4 adds wl_keyboard repeat_info -> optional @@ -354,7 +358,7 @@ bool CWinSystemWayland::CreateNewWindow(const std::string& name, m_seatRegistry->Request<wayland::seat_t>(1, 5, std::bind(&CWinSystemWayland::OnSeatAdded, this, _1, _2), std::bind(&CWinSystemWayland::OnSeatRemoved, this, _1)); m_seatRegistry->Bind(); - if (m_seatProcessors.empty()) + if (m_seats.empty()) { CLog::Log(LOGWARNING, "Wayland compositor did not announce a wl_seat - you will not have any input devices for the time being"); } @@ -399,7 +403,7 @@ bool CWinSystemWayland::DestroyWindow() // waylandpp automatically calls wl_surface_destroy when the last reference is removed m_surface = wayland::surface_t(); m_windowDecorator.reset(); - m_seatProcessors.clear(); + m_seats.clear(); m_lastSetOutput.proxy_release(); m_surfaceOutputs.clear(); m_surfaceSubmissions.clear(); @@ -1056,9 +1060,9 @@ bool CWinSystemWayland::Minimize() bool CWinSystemWayland::HasCursor() { - CSingleLock lock(m_seatProcessorsMutex); - return std::any_of(m_seatProcessors.cbegin(), m_seatProcessors.cend(), - [](decltype(m_seatProcessors)::value_type const& entry) + CSingleLock lock(m_seatsMutex); + return std::any_of(m_seats.cbegin(), m_seats.cend(), + [](decltype(m_seats)::value_type const& entry) { return entry.second.HasPointerCapability(); }); @@ -1112,20 +1116,29 @@ void CWinSystemWayland::Unregister(IDispResource* resource) void CWinSystemWayland::OnSeatAdded(std::uint32_t name, wayland::proxy_t&& proxy) { - CSingleLock lock(m_seatProcessorsMutex); + CSingleLock lock(m_seatsMutex); wayland::seat_t seat(proxy); - auto newSeatEmplace = m_seatProcessors.emplace(std::piecewise_construct, - std::forward_as_tuple(name), - std::forward_as_tuple(name, seat, m_surface, *m_connection, static_cast<IInputHandler&> (*this))); - newSeatEmplace.first->second.SetCoordinateScale(m_scale); + auto newSeatEmplace = m_seats.emplace(std::piecewise_construct, + std::forward_as_tuple(name), + std::forward_as_tuple(name, seat, *m_connection)); + + auto& seatInst = newSeatEmplace.first->second; + m_seatInputProcessing->AddSeat(&seatInst); + m_windowDecorator->AddSeat(&seatInst); } void CWinSystemWayland::OnSeatRemoved(std::uint32_t name) { - CSingleLock lock(m_seatProcessorsMutex); + CSingleLock lock(m_seatsMutex); - m_seatProcessors.erase(name); + auto seatI = m_seats.find(name); + if (seatI != m_seats.end()) + { + m_seatInputProcessing->RemoveSeat(&seatI->second); + m_windowDecorator->RemoveSeat(&seatI->second); + m_seats.erase(name); + } } void CWinSystemWayland::OnOutputAdded(std::uint32_t name, wayland::proxy_t&& proxy) @@ -1179,7 +1192,7 @@ void CWinSystemWayland::SendFocusChange(bool focus) } } -void CWinSystemWayland::OnEnter(std::uint32_t seatGlobalName, InputType type) +void CWinSystemWayland::OnEnter(InputType type) { // Couple to keyboard focus if (type == InputType::KEYBOARD) @@ -1192,7 +1205,7 @@ void CWinSystemWayland::OnEnter(std::uint32_t seatGlobalName, InputType type) } } -void CWinSystemWayland::OnLeave(std::uint32_t seatGlobalName, InputType type) +void CWinSystemWayland::OnLeave(InputType type) { // Couple to keyboard focus if (type == InputType::KEYBOARD) @@ -1205,25 +1218,31 @@ void CWinSystemWayland::OnLeave(std::uint32_t seatGlobalName, InputType type) } } -void CWinSystemWayland::OnEvent(std::uint32_t seatGlobalName, InputType type, XBMC_Event& event) +void CWinSystemWayland::OnEvent(InputType type, XBMC_Event& event) { // FIXME dynamic_cast<CWinEventsWayland&>(*m_winEvents).MessagePush(&event); } -void CWinSystemWayland::OnSetCursor(wayland::pointer_t& pointer, std::uint32_t serial) +void CWinSystemWayland::OnSetCursor(std::uint32_t seatGlobalName, std::uint32_t serial) { + auto seatI = m_seats.find(seatGlobalName); + if (seatI == m_seats.end()) + { + return; + } + if (m_osCursorVisible) { LoadDefaultCursor(); if (m_cursorSurface) // Cursor loading could have failed { - pointer.set_cursor(serial, m_cursorSurface, m_cursorImage.hotspot_x(), m_cursorImage.hotspot_y()); + seatI->second.SetCursor(serial, m_cursorSurface, m_cursorImage.hotspot_x(), m_cursorImage.hotspot_y()); } } else { - pointer.set_cursor(serial, wayland::surface_t{}, 0, 0); + seatI->second.SetCursor(serial, wayland::surface_t{}, 0, 0); } } @@ -1244,11 +1263,7 @@ void CWinSystemWayland::ApplyBufferScale() CLog::LogF(LOGINFO, "Setting Wayland buffer scale to %d", m_scale); m_surface.set_buffer_scale(m_scale); m_windowDecorator->SetState(m_configuredSize, m_scale, m_shellSurfaceState); - CSingleLock lock(m_seatProcessorsMutex); - for (auto& seatProcessor : m_seatProcessors) - { - seatProcessor.second.SetCoordinateScale(m_scale); - } + m_seatInputProcessing->SetCoordinateScale(m_scale); } void CWinSystemWayland::UpdateTouchDpi() @@ -1458,12 +1473,12 @@ std::unique_ptr<IOSScreenSaver> CWinSystemWayland::GetOSScreenSaverImpl() std::string CWinSystemWayland::GetClipboardText() { - CSingleLock lock(m_seatProcessorsMutex); + CSingleLock lock(m_seatsMutex); // Get text of first seat with non-empty selection // Actually, the value of the seat that received the Ctrl+V keypress should be used, // but this would need a workaround or proper multi-seat support in Kodi - it's // probably just not that relevant in practice - for (auto const& seat : m_seatProcessors) + for (auto const& seat : m_seats) { auto text = seat.second.GetSelectionText(); if (text != "") diff --git a/xbmc/windowing/wayland/WinSystemWayland.h b/xbmc/windowing/wayland/WinSystemWayland.h index 12ef8370d1..704985e69d 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.h +++ b/xbmc/windowing/wayland/WinSystemWayland.h @@ -23,6 +23,7 @@ #include "Connection.h" #include "Output.h" #include "Seat.h" +#include "SeatInputProcessing.h" #include "Signals.h" #include "ShellSurface.h" #include "platform/linux/OptionalsReg.h" @@ -114,10 +115,10 @@ protected: private: // IInputHandler - void OnEnter(std::uint32_t seatGlobalName, InputType type) override; - void OnLeave(std::uint32_t seatGlobalName, InputType type) override; - void OnEvent(std::uint32_t seatGlobalName, InputType type, XBMC_Event& event) override; - void OnSetCursor(wayland::pointer_t& pointer, std::uint32_t serial) override; + void OnEnter(InputType type) override; + void OnLeave(InputType type) override; + void OnEvent(InputType type, XBMC_Event& event) override; + void OnSetCursor(std::uint32_t seatGlobalName, std::uint32_t serial) override; // IWindowDecorationHandler void OnWindowMove(const wayland::seat_t& seat, std::uint32_t serial) override; @@ -202,8 +203,9 @@ private: // Seat handling // ------------- - std::map<std::uint32_t, CSeat> m_seatProcessors; - CCriticalSection m_seatProcessorsMutex; + std::map<std::uint32_t, CSeat> m_seats; + CCriticalSection m_seatsMutex; + std::unique_ptr<CSeatInputProcessing> m_seatInputProcessing; std::map<std::uint32_t, std::shared_ptr<COutput>> m_outputs; /// outputs that did not receive their done event yet std::map<std::uint32_t, std::shared_ptr<COutput>> m_outputsInPreparation; diff --git a/xbmc/windowing/wayland/WindowDecorator.cpp b/xbmc/windowing/wayland/WindowDecorator.cpp index 874aaff13b..ce5f8cf38b 100644 --- a/xbmc/windowing/wayland/WindowDecorator.cpp +++ b/xbmc/windowing/wayland/WindowDecorator.cpp @@ -420,102 +420,116 @@ CWindowDecorator::CWindowDecorator(IWindowDecorationHandler& handler, CConnectio m_registry.RequestSingleton(m_compositor, 1, 4); m_registry.RequestSingleton(m_subcompositor, 1, 1, false); m_registry.RequestSingleton(m_shm, 1, 1); - m_registry.Request<wayland::seat_t>(1, 5, std::bind(&CWindowDecorator::OnSeatAdded, this, _1, _2), std::bind(&CWindowDecorator::OnSeatRemoved, this, _1)); m_registry.Bind(); } -void CWindowDecorator::OnSeatAdded(std::uint32_t name, wayland::proxy_t&& proxy) +void CWindowDecorator::AddSeat(CSeat* seat) { - wayland::seat_t seat{proxy}; - seat.on_capabilities() = std::bind(&CWindowDecorator::OnSeatCapabilities, this, name, _1); - m_seats.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(std::move(seat))); + m_seats.emplace(std::piecewise_construct, std::forward_as_tuple(seat->GetGlobalName()), std::forward_as_tuple(seat)); + seat->AddRawInputHandlerTouch(this); + seat->AddRawInputHandlerPointer(this); } -void CWindowDecorator::OnSeatRemoved(std::uint32_t name) +void CWindowDecorator::RemoveSeat(CSeat* seat) { - m_seats.erase(name); + seat->RemoveRawInputHandlerTouch(this); + seat->RemoveRawInputHandlerPointer(this); + m_seats.erase(seat->GetGlobalName()); UpdateButtonHoverState(); } -void CWindowDecorator::OnSeatCapabilities(std::uint32_t name, wayland::seat_capability capabilities) +void CWindowDecorator::OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) { - auto& seat = m_seats.at(name); - if (HandleCapabilityChange(capabilities, wayland::seat_capability::pointer, seat.pointer, std::bind(&wayland::seat_t::get_pointer, seat.seat))) + auto seatStateI = m_seats.find(seat->GetGlobalName()); + if (seatStateI == m_seats.end()) { - HandleSeatPointer(seat); + return; } - if (HandleCapabilityChange(capabilities, wayland::seat_capability::touch, seat.touch, std::bind(&wayland::seat_t::get_touch, seat.seat))) + auto& seatState = seatStateI->second; + // Reset first so we ignore events for surfaces we don't handle + seatState.currentSurface = SURFACE_COUNT; + CSingleLock lock(m_mutex); + for (std::size_t i{0}; i < m_borderSurfaces.size(); i++) + { + if (m_borderSurfaces[i].surface.wlSurface == surface) + { + seatState.pointerEnterSerial = serial; + seatState.currentSurface = static_cast<SurfaceIndex> (i); + seatState.pointerPosition = {static_cast<float> (surfaceX), static_cast<float> (surfaceY)}; + UpdateSeatCursor(seatState); + UpdateButtonHoverState(); + break; + } + } +} + +void CWindowDecorator::OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) +{ + auto seatStateI = m_seats.find(seat->GetGlobalName()); + if (seatStateI == m_seats.end()) { - HandleSeatTouch(seat); + return; } + auto& seatState = seatStateI->second; + seatState.currentSurface = SURFACE_COUNT; + // Recreate cursor surface on reenter + seatState.cursorName.clear(); + seatState.cursor.proxy_release(); UpdateButtonHoverState(); } -void CWindowDecorator::HandleSeatPointer(Seat& seat) +void CWindowDecorator::OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY) { - seat.pointer.on_enter() = [this, &seat](std::uint32_t serial, wayland::surface_t surface, float x, float y) + auto seatStateI = m_seats.find(seat->GetGlobalName()); + if (seatStateI == m_seats.end()) { - // Reset first so we ignore events for surfaces we don't handle - seat.currentSurface = SURFACE_COUNT; - CSingleLock lock(m_mutex); - for (std::size_t i{0}; i < m_borderSurfaces.size(); i++) - { - if (m_borderSurfaces[i].surface.wlSurface == surface) - { - seat.pointerEnterSerial = serial; - seat.currentSurface = static_cast<SurfaceIndex> (i); - seat.pointerPosition = {x, y}; - UpdateSeatCursor(seat); - UpdateButtonHoverState(); - break; - } - } - }; - seat.pointer.on_leave() = [this, &seat](std::uint32_t, wayland::surface_t) + return; + } + auto& seatState = seatStateI->second; + if (seatState.currentSurface != SURFACE_COUNT) { - seat.currentSurface = SURFACE_COUNT; - // Recreate cursor surface on reenter - seat.cursorName.clear(); - seat.cursor.proxy_release(); + seatState.pointerPosition = {static_cast<float> (surfaceX), static_cast<float> (surfaceY)}; + UpdateSeatCursor(seatState); UpdateButtonHoverState(); - }; - seat.pointer.on_motion() = [this, &seat](std::uint32_t, float x, float y) + } +} + +void CWindowDecorator::OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) +{ + auto seatStateI = m_seats.find(seat->GetGlobalName()); + if (seatStateI == m_seats.end()) { - if (seat.currentSurface != SURFACE_COUNT) - { - seat.pointerPosition = {x, y}; - UpdateSeatCursor(seat); - UpdateButtonHoverState(); - } - }; - seat.pointer.on_button() = [this, &seat](std::uint32_t serial, std::uint32_t, std::uint32_t button, wayland::pointer_button_state state) + return; + } + auto& seatState = seatStateI->second; + if (seatState.currentSurface != SURFACE_COUNT && state == wayland::pointer_button_state::pressed) { - if (seat.currentSurface != SURFACE_COUNT && state == wayland::pointer_button_state::pressed) - { - HandleSeatClick(seat.seat, seat.currentSurface, serial, button, seat.pointerPosition); - } - }; + HandleSeatClick(seatState, seatState.currentSurface, serial, button, seatState.pointerPosition); + } } -void CWindowDecorator::HandleSeatTouch(Seat& seat) +void CWindowDecorator::OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) { - seat.touch.on_down() = [this, &seat](std::uint32_t serial, std::uint32_t, wayland::surface_t surface, std::int32_t id, float x, float y) + auto seatStateI = m_seats.find(seat->GetGlobalName()); + if (seatStateI == m_seats.end()) { - CSingleLock lock(m_mutex); - for (std::size_t i{0}; i < m_borderSurfaces.size(); i++) + return; + } + auto& seatState = seatStateI->second; + CSingleLock lock(m_mutex); + for (std::size_t i{0}; i < m_borderSurfaces.size(); i++) + { + if (m_borderSurfaces[i].surface.wlSurface == surface) { - if (m_borderSurfaces[i].surface.wlSurface == surface) - { - HandleSeatClick(seat.seat, static_cast<SurfaceIndex> (i), serial, BTN_LEFT, {x, y}); - } + HandleSeatClick(seatState, static_cast<SurfaceIndex> (i), serial, BTN_LEFT, {static_cast<float> (x), static_cast<float> (y)}); } - }; + } } -void CWindowDecorator::UpdateSeatCursor(Seat& seat) +void CWindowDecorator::UpdateSeatCursor(SeatState& seatState) { - if (seat.currentSurface == SURFACE_COUNT) + if (seatState.currentSurface == SURFACE_COUNT) { // Don't set anything if not on any surface return; @@ -527,19 +541,19 @@ void CWindowDecorator::UpdateSeatCursor(Seat& seat) { CSingleLock lock(m_mutex); - auto resizeEdge = ResizeEdgeForPosition(seat.currentSurface, SurfaceGeometry(seat.currentSurface, m_mainSurfaceSize).ToSize(), CPointInt{seat.pointerPosition}); + auto resizeEdge = ResizeEdgeForPosition(seatState.currentSurface, SurfaceGeometry(seatState.currentSurface, m_mainSurfaceSize).ToSize(), CPointInt{seatState.pointerPosition}); if (resizeEdge != wayland::shell_surface_resize::none) { cursorName = CursorForResizeEdge(resizeEdge); } } - if (cursorName == seat.cursorName) + if (cursorName == seatState.cursorName) { // Don't reload cursor all the time when nothing is changing return; } - seat.cursorName = cursorName; + seatState.cursorName = cursorName; wayland::cursor_t cursor; try @@ -553,20 +567,20 @@ void CWindowDecorator::UpdateSeatCursor(Seat& seat) } auto cursorImage = cursor.image(0); - if (!seat.cursor) + if (!seatState.cursor) { - seat.cursor = m_compositor.create_surface(); + seatState.cursor = m_compositor.create_surface(); } - int calcScale{seat.cursor.can_set_buffer_scale() ? m_scale : 1}; + int calcScale{seatState.cursor.can_set_buffer_scale() ? m_scale : 1}; - seat.pointer.set_cursor(seat.pointerEnterSerial, seat.cursor, cursorImage.hotspot_x() / calcScale, cursorImage.hotspot_y() / calcScale); - seat.cursor.attach(cursorImage.get_buffer(), 0, 0); - seat.cursor.damage(0, 0, cursorImage.width() / calcScale, cursorImage.height() / calcScale); - if (seat.cursor.can_set_buffer_scale()) + seatState.seat->SetCursor(seatState.pointerEnterSerial, seatState.cursor, cursorImage.hotspot_x() / calcScale, cursorImage.hotspot_y() / calcScale); + seatState.cursor.attach(cursorImage.get_buffer(), 0, 0); + seatState.cursor.damage(0, 0, cursorImage.width() / calcScale, cursorImage.height() / calcScale); + if (seatState.cursor.can_set_buffer_scale()) { - seat.cursor.set_buffer_scale(m_scale); + seatState.cursor.set_buffer_scale(m_scale); } - seat.cursor.commit(); + seatState.cursor.commit(); } void CWindowDecorator::UpdateButtonHoverState() @@ -599,7 +613,7 @@ void CWindowDecorator::UpdateButtonHoverState() } } -void CWindowDecorator::HandleSeatClick(wayland::seat_t seat, SurfaceIndex surface, std::uint32_t serial, std::uint32_t button, CPoint position) +void CWindowDecorator::HandleSeatClick(SeatState const& seatState, SurfaceIndex surface, std::uint32_t serial, std::uint32_t button, CPoint position) { switch (button) { @@ -618,18 +632,18 @@ void CWindowDecorator::HandleSeatClick(wayland::seat_t seat, SurfaceIndex surfac } } - m_handler.OnWindowMove(seat, serial); + m_handler.OnWindowMove(seatState.seat->GetWlSeat(), serial); } else { - m_handler.OnWindowResize(seat, serial, resizeEdge); + m_handler.OnWindowResize(seatState.seat->GetWlSeat(), serial, resizeEdge); } } break; case BTN_RIGHT: if (surface == SURFACE_TOP) { - m_handler.OnWindowShowContextMenu(seat, serial, CPointInt{position} - CPointInt{BORDER_WIDTH, BORDER_WIDTH + TOP_BAR_HEIGHT}); + m_handler.OnWindowShowContextMenu(seatState.seat->GetWlSeat(), serial, CPointInt{position} - CPointInt{BORDER_WIDTH, BORDER_WIDTH + TOP_BAR_HEIGHT}); } break; } @@ -967,10 +981,21 @@ void CWindowDecorator::CommitAllBuffers() if (emplaceResult.second) { // Buffer was not pending already - auto iter = emplaceResult.first; - wlBuffer.on_release() = [this, iter]() + auto wlBufferC = reinterpret_cast<wl_buffer*> (wlBuffer.c_ptr()); + // We can refer to the buffer neither by iterator (might be invalidated) nor by + // capturing the C++ instance in the lambda (would create a reference loop and + // never allow the object to be freed), so use the raw pointer for now + wlBuffer.on_release() = [this, wlBufferC]() { CSingleLock lock(m_pendingBuffersMutex); + // Construct a dummy object for searching the set + wayland::buffer_t findDummy(wlBufferC, wayland::proxy_t::wrapper_type::foreign); + auto iter = m_pendingBuffers.find(findDummy); + if (iter == m_pendingBuffers.end()) + { + throw std::logic_error("Cannot release buffer that is not pending"); + } + // Do not erase again until buffer is reattached (should not happen anyway, just to be safe) // const_cast is OK since changing the function pointer does not affect // the key in the set diff --git a/xbmc/windowing/wayland/WindowDecorator.h b/xbmc/windowing/wayland/WindowDecorator.h index f42d274d7b..ff0c8383b1 100644 --- a/xbmc/windowing/wayland/WindowDecorator.h +++ b/xbmc/windowing/wayland/WindowDecorator.h @@ -17,6 +17,7 @@ #include "Connection.h" #include "Registry.h" +#include "Seat.h" #include "ShellSurface.h" #include "threads/CriticalSection.h" #include "Util.h" @@ -58,7 +59,7 @@ enum SurfaceIndex * * The decorations are positioned around the main surface automatically. */ -class CWindowDecorator +class CWindowDecorator final : IRawInputHandlerTouch, IRawInputHandlerPointer { public: /** @@ -107,6 +108,9 @@ public: bool IsDecorationActive() const; + void AddSeat(CSeat* seat); + void RemoveSeat(CSeat* seat); + struct Buffer { void* data{}; @@ -138,6 +142,14 @@ private: CWindowDecorator(CWindowDecorator const& other) = delete; CWindowDecorator& operator=(CWindowDecorator const& other) = delete; + // IRawInputHandlerTouch + void OnTouchDown(CSeat* seat, std::uint32_t serial, std::uint32_t time, wayland::surface_t surface, std::int32_t id, double x, double y) override; + // IRawInputHandlerPointer + void OnPointerEnter(CSeat* seat, std::uint32_t serial, wayland::surface_t surface, double surfaceX, double surfaceY) override; + void OnPointerLeave(CSeat* seat, std::uint32_t serial, wayland::surface_t surface) override; + void OnPointerMotion(CSeat* seat, std::uint32_t time, double surfaceX, double surfaceY) override; + void OnPointerButton(CSeat* seat, std::uint32_t serial, std::uint32_t time, std::uint32_t button, wayland::pointer_button_state state) override; + void Reset(bool reallocate); // These functions should not be called directly as they may leave internal @@ -197,24 +209,21 @@ private: std::set<wayland::buffer_t, WaylandCPtrCompare> m_pendingBuffers; CCriticalSection m_pendingBuffersMutex; - struct Seat + struct SeatState { - wayland::seat_t seat; - wayland::pointer_t pointer; - wayland::touch_t touch; - + CSeat* seat; SurfaceIndex currentSurface{SURFACE_COUNT}; CPoint pointerPosition; - std::uint32_t pointerEnterSerial; + std::uint32_t pointerEnterSerial{}; std::string cursorName; wayland::surface_t cursor; - explicit Seat(wayland::seat_t seat) - : seat{std::move(seat)} + explicit SeatState(CSeat* seat) + : seat{seat} {} }; - std::map<std::uint32_t, Seat> m_seats; + std::map<std::uint32_t, SeatState> m_seats; struct Button { @@ -230,15 +239,9 @@ private: void LoadCursorTheme(); - void OnSeatAdded(std::uint32_t name, wayland::proxy_t&& seat); - void OnSeatRemoved(std::uint32_t name); - void OnSeatCapabilities(std::uint32_t name, wayland::seat_capability capability); - void HandleSeatPointer(Seat& seat); - void HandleSeatTouch(Seat& seat); - - void UpdateSeatCursor(Seat& seat); + void UpdateSeatCursor(SeatState& seatState); void UpdateButtonHoverState(); - void HandleSeatClick(wayland::seat_t seat, SurfaceIndex surface, std::uint32_t serial, std::uint32_t button, CPoint position); + void HandleSeatClick(SeatState const& seatState, SurfaceIndex surface, std::uint32_t serial, std::uint32_t button, CPoint position); }; } diff --git a/xbmc/windowing/wayland/XkbcommonKeymap.cpp b/xbmc/windowing/wayland/XkbcommonKeymap.cpp index 1fb2e5f741..34a9bf6d2e 100644 --- a/xbmc/windowing/wayland/XkbcommonKeymap.cpp +++ b/xbmc/windowing/wayland/XkbcommonKeymap.cpp @@ -16,10 +16,8 @@ #include "Application.h" #include "Util.h" #include "utils/log.h" -#include "platform/posix/utils/Mmap.h" using namespace KODI::WINDOWING::WAYLAND; -using namespace KODI::UTILS::POSIX; namespace { @@ -195,19 +193,16 @@ void CXkbcommonContext::XkbContextDeleter::operator()(xkb_context* ctx) const xkb_context_unref(ctx); } -std::unique_ptr<CXkbcommonKeymap> CXkbcommonContext::KeymapFromSharedMemory(int fd, std::size_t size) +std::unique_ptr<CXkbcommonKeymap> CXkbcommonContext::KeymapFromString(std::string const& keymap) { - CMmap mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); - auto keymapString = static_cast<const char *> (mmap.Data()); + std::unique_ptr<xkb_keymap, CXkbcommonKeymap::XkbKeymapDeleter> xkbKeymap{xkb_keymap_new_from_string(m_context.get(), keymap.c_str(), XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS), CXkbcommonKeymap::XkbKeymapDeleter()}; - std::unique_ptr<xkb_keymap, CXkbcommonKeymap::XkbKeymapDeleter> keymap{xkb_keymap_new_from_string(m_context.get(), keymapString, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS), CXkbcommonKeymap::XkbKeymapDeleter()}; - - if (!keymap) + if (!xkbKeymap) { throw std::runtime_error("Failed to compile keymap"); } - return std::unique_ptr<CXkbcommonKeymap>{new CXkbcommonKeymap(std::move(keymap))}; + return std::unique_ptr<CXkbcommonKeymap>{new CXkbcommonKeymap(std::move(xkbKeymap))}; } std::unique_ptr<CXkbcommonKeymap> CXkbcommonContext::KeymapFromNames(const std::string& rules, const std::string& model, const std::string& layout, const std::string& variant, const std::string& options) diff --git a/xbmc/windowing/wayland/XkbcommonKeymap.h b/xbmc/windowing/wayland/XkbcommonKeymap.h index 694bc06306..997d64fea6 100644 --- a/xbmc/windowing/wayland/XkbcommonKeymap.h +++ b/xbmc/windowing/wayland/XkbcommonKeymap.h @@ -123,7 +123,7 @@ public: * This function does not own the file descriptor. It must not be closed * from this function. */ - std::unique_ptr<CXkbcommonKeymap> KeymapFromSharedMemory(int fd, std::size_t size); + std::unique_ptr<CXkbcommonKeymap> KeymapFromString(std::string const& keymap); std::unique_ptr<CXkbcommonKeymap> KeymapFromNames(const std::string &rules, const std::string &model, const std::string &layout, const std::string &variant, const std::string &options); private: diff --git a/xbmc/windowing/win10/WinSystemWin10.cpp b/xbmc/windowing/win10/WinSystemWin10.cpp index d2e2e8d90e..0ca1b684c9 100644 --- a/xbmc/windowing/win10/WinSystemWin10.cpp +++ b/xbmc/windowing/win10/WinSystemWin10.cpp @@ -119,11 +119,6 @@ bool CWinSystemWin10::CreateNewWindow(const std::string& name, bool fullScreen, // and hide UWP splash, without this the Kodi's splash will not be shown m_coreWindow.Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); - // in some cases CoreWindow::SizeChanged isn't fired - // it causes mismatch between window actual size and UI - winrt::Rect winRect = m_coreWindow.Bounds(); - dynamic_cast<CWinEventsWin10&>(*m_winEvents).OnResize(winRect.Width, winRect.Height); - return true; } @@ -209,10 +204,8 @@ bool CWinSystemWin10::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bool forceChange = false; // resolution/display is changed but window state isn't changed bool stereoChange = IsStereoEnabled() != (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() == RENDER_STEREO_MODE_HARDWAREBASED); - if ( m_nWidth != res.iWidth - || m_nHeight != res.iHeight - || m_fRefreshRate != res.fRefreshRate - || stereoChange) + if ( m_nWidth != res.iWidth || m_nHeight != res.iHeight || m_fRefreshRate != res.fRefreshRate || + stereoChange || m_bFirstResChange) { forceChange = true; } @@ -239,6 +232,7 @@ bool CWinSystemWin10::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool m_IsAlteringWindow = true; ReleaseBackBuffer(); + m_bFirstResChange = false; m_bFullScreen = fullScreen; m_nWidth = res.iWidth; m_nHeight = res.iHeight; @@ -348,6 +342,9 @@ bool CWinSystemWin10::ChangeResolution(const RESOLUTION_INFO& res, bool forceCha // changing display mode doesn't fire CoreWindow::SizeChanged event if (changed && m_bWindowCreated) { + // dispatch all events currently pending in the queue to change window's content + m_coreWindow.Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); + float dpi = DisplayInformation::GetForCurrentView().LogicalDpi(); float dipsW = DX::ConvertPixelsToDips(m_nWidth, dpi); float dipsH = DX::ConvertPixelsToDips(m_nHeight, dpi); diff --git a/xbmc/windowing/win10/WinSystemWin10.h b/xbmc/windowing/win10/WinSystemWin10.h index af3d7d3631..7e99e7e23c 100644 --- a/xbmc/windowing/win10/WinSystemWin10.h +++ b/xbmc/windowing/win10/WinSystemWin10.h @@ -143,6 +143,7 @@ protected: WINDOW_WINDOW_STATE m_windowState; // the state of the window when in windowed bool m_inFocus; bool m_bMinimized; + bool m_bFirstResChange = true; winrt::Windows::UI::Core::CoreWindow m_coreWindow = nullptr; }; diff --git a/xbmc/windowing/win10/WinSystemWin10DX.cpp b/xbmc/windowing/win10/WinSystemWin10DX.cpp index 928e57a4d0..2ac39b1d81 100644 --- a/xbmc/windowing/win10/WinSystemWin10DX.cpp +++ b/xbmc/windowing/win10/WinSystemWin10DX.cpp @@ -52,8 +52,7 @@ bool CWinSystemWin10DX::CreateNewWindow(const std::string& name, bool fullScreen if (CWinSystemWin10::CreateNewWindow(name, fullScreen, res) && m_deviceResources->HasValidDevice()) { CGenericTouchInputHandler::GetInstance().RegisterHandler(&CGenericTouchActionHandler::GetInstance()); - CGenericTouchInputHandler::GetInstance().SetScreenDPI(DX::DisplayMetrics::Dpi100); - ChangeResolution(res, true); + CGenericTouchInputHandler::GetInstance().SetScreenDPI(m_deviceResources->GetDpi()); return true; } return false; diff --git a/xbmc/windowing/windows/WinSystemWin32.cpp b/xbmc/windowing/windows/WinSystemWin32.cpp index 83d9de1269..43fa37e520 100644 --- a/xbmc/windowing/windows/WinSystemWin32.cpp +++ b/xbmc/windowing/windows/WinSystemWin32.cpp @@ -266,7 +266,7 @@ bool CWinSystemWin32::BlankNonActiveMonitors(bool bBlank) } // Move a blank window in front of every display, except the current display. - for (size_t i = 0; i < m_displays.size(); ++i) + for (size_t i = 0, j = 0; i < m_displays.size(); ++i) { MONITOR_DETAILS& details = m_displays[i]; if (details.hMonitor == m_hMonitor) @@ -274,11 +274,12 @@ bool CWinSystemWin32::BlankNonActiveMonitors(bool bBlank) RECT rBounds = ScreenRect(details.hMonitor); // move and resize the window - SetWindowPos(m_hBlankWindows[i], nullptr, rBounds.left, rBounds.top, + SetWindowPos(m_hBlankWindows[j], nullptr, rBounds.left, rBounds.top, rBounds.right - rBounds.left, rBounds.bottom - rBounds.top, SWP_NOACTIVATE); - ShowWindow(m_hBlankWindows[i], SW_SHOW | SW_SHOWNOACTIVATE); + ShowWindow(m_hBlankWindows[j], SW_SHOW | SW_SHOWNOACTIVATE); + j++; } if (m_hWnd) @@ -441,11 +442,8 @@ bool CWinSystemWin32::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bool changeScreen = false; // display is changed bool stereoChange = IsStereoEnabled() != (CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode() == RENDER_STEREO_MODE_HARDWAREBASED); - if ( m_nWidth != res.iWidth - || m_nHeight != res.iHeight - || m_fRefreshRate != res.fRefreshRate - || oldMonitor->hMonitor != newMonitor->hMonitor - || stereoChange) + if ( m_nWidth != res.iWidth || m_nHeight != res.iHeight || m_fRefreshRate != res.fRefreshRate || + oldMonitor->hMonitor != newMonitor->hMonitor || stereoChange || m_bFirstResChange) { if (oldMonitor->hMonitor != newMonitor->hMonitor) changeScreen = true; @@ -453,12 +451,17 @@ bool CWinSystemWin32::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool } if (state == m_state && !forceChange) + { + m_bBlankOtherDisplay = blankOtherDisplays; + BlankNonActiveMonitors(m_bBlankOtherDisplay); return true; + } // entering to stereo mode, limit resolution to 1080p@23.976 if (stereoChange && !IsStereoEnabled() && res.iWidth > 1280) { - res = CDisplaySettings::GetInstance().GetResolutionInfo(CResolutionUtils::ChooseBestResolution(24.f / 1.001f, 1920, 1080, true)); + res = CDisplaySettings::GetInstance().GetResolutionInfo( + CResolutionUtils::ChooseBestResolution(24.f / 1.001f, 1920, 1080, true)); } if (m_state == WINDOW_STATE_WINDOWED) @@ -490,6 +493,7 @@ bool CWinSystemWin32::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool OnScreenChange(newMonitor->hMonitor); } + m_bFirstResChange = false; m_bFullScreen = fullScreen; m_hMonitor = newMonitor->hMonitor; m_nWidth = res.iWidth; @@ -541,7 +545,10 @@ bool CWinSystemWin32::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool CenterCursor(); CreateBackBuffer(); + + BlankNonActiveMonitors(m_bBlankOtherDisplay); m_IsAlteringWindow = false; + return true; } diff --git a/xbmc/windowing/windows/WinSystemWin32.h b/xbmc/windowing/windows/WinSystemWin32.h index 5ee370ff35..39c218248d 100644 --- a/xbmc/windowing/windows/WinSystemWin32.h +++ b/xbmc/windowing/windows/WinSystemWin32.h @@ -185,7 +185,8 @@ protected: DWORD m_windowExStyle; // the ex style of the window bool m_inFocus; bool m_bMinimized; - bool m_bSizeMoveEnabled{ false }; + bool m_bSizeMoveEnabled = false; + bool m_bFirstResChange = true; std::unique_ptr<CIRServerSuite> m_irss; std::vector<MONITOR_DETAILS> m_displays; }; diff --git a/xbmc/windowing/windows/WinSystemWin32DX.cpp b/xbmc/windowing/windows/WinSystemWin32DX.cpp index 40e0ab5282..c84867e96a 100644 --- a/xbmc/windowing/windows/WinSystemWin32DX.cpp +++ b/xbmc/windowing/windows/WinSystemWin32DX.cpp @@ -100,7 +100,10 @@ bool CWinSystemWin32DX::DestroyRenderSystem() void CWinSystemWin32DX::SetDeviceFullScreen(bool fullScreen, RESOLUTION_INFO& res) { - m_deviceResources->SetFullScreen(fullScreen, res); + if (m_deviceResources->SetFullScreen(fullScreen, res)) + { + ResolutionChanged(); + } } bool CWinSystemWin32DX::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) diff --git a/xbmc/windows/GUIWindowFileManager.cpp b/xbmc/windows/GUIWindowFileManager.cpp index 89cb70218f..235d57c26b 100644 --- a/xbmc/windows/GUIWindowFileManager.cpp +++ b/xbmc/windows/GUIWindowFileManager.cpp @@ -444,6 +444,13 @@ void CGUIWindowFileManager::UpdateItemCounts() bool CGUIWindowFileManager::Update(int iList, const std::string &strDirectory) { + if (m_updating) + { + CLog::Log(LOGWARNING, "CGUIWindowFileManager::Update - updating in progress"); + return true; + } + CUpdateGuard ug(m_updating); + // get selected item int iItem = GetSelectedItem(iList); std::string strSelectedItem = ""; diff --git a/xbmc/windows/GUIWindowFileManager.h b/xbmc/windows/GUIWindowFileManager.h index 2d1de1772a..6357f33e3c 100644 --- a/xbmc/windows/GUIWindowFileManager.h +++ b/xbmc/windows/GUIWindowFileManager.h @@ -8,6 +8,7 @@ #pragma once +#include <atomic> #include <string> #include <vector> @@ -77,7 +78,6 @@ protected: bool bCheckShareConnectivity; std::string strCheckSharePath; - XFILE::CVirtualDirectory m_rootDir; CFileItemList* m_vecItems[2]; typedef std::vector <CFileItem*> ::iterator ivecItems; @@ -86,4 +86,20 @@ protected: CDirectoryHistory m_history[2]; int m_errorHeading, m_errorLine; +private: + std::atomic_bool m_updating = {false}; + class CUpdateGuard + { + public: + CUpdateGuard(std::atomic_bool &update) : m_update(update) + { + m_update = true; + } + ~CUpdateGuard() + { + m_update = false; + } + private: + std::atomic_bool &m_update; + }; }; |