From 1e713ba94dfe71f92ef55589d2486f91a824e5a7 Mon Sep 17 00:00:00 2001 From: Alhaziel01 Date: Wed, 15 Apr 2020 15:32:47 +0200 Subject: [PATCH 1/6] Fix Community Channels --- specials/community.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/specials/community.py b/specials/community.py index 3c91da3a..c11af091 100644 --- a/specials/community.py +++ b/specials/community.py @@ -103,8 +103,11 @@ def show_menu(item): itemlist += episodios(item, json, key) elif key in ['links']: itemlist += findvideos(item) + elif key in ['search'] and 'url' in json['search']: + search_json = json['search'] + itemlist += get_search_menu(item, search_json) - if 'channel_name' in json: + if 'channel_name' in json and not 'disable_search' in json: if 'search' in json and 'url' in json['search']: search_json = json['search'] itemlist += get_search_menu(item, search_json, channel_name=json['channel_name']) From 6de0f4fec4c4f83348c441f89d7e473e4d766223 Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 15 Apr 2020 22:58:06 +0200 Subject: [PATCH 2/6] KoD 0.9 - Nuova sezione Musica - Download in Background - Download dalla Videoteca e supporto file locali - Backup e cancellazione della Videoteca - Spostamento della Videoteca - Migliorata integrazione con libreria di Kodi - Gestione delle Viste Preferite - Nuovo layout impostazioni --- .gitignore | 1 + CONTRIBUTING.md | 49 + README.md | 25 +- addon.xml | 18 +- channels/cinemalibero.py | 23 +- channels/cinetecadibologna.py | 1 - channels/dsda.py | 1 - channels/eurostreaming.py | 2 +- channels/filmpertutti.py | 3 - channels/hd4me.json | 12 + channels/hd4me.py | 53 + channels/metalvideo.json | 12 + channels/metalvideo.py | 63 + channels/polpotv.py | 46 +- channels/porn/thumbzilla.py | 20 +- channels/raiplay.py | 8 +- channels/serietvu.py | 27 +- channels/streamingaltadefinizione.py | 2 +- channels/tunein.json | 12 + channels/tunein.py | 109 ++ channels/vvvvid.py | 16 +- channelselector.py | 42 +- core/channeltools.py | 3 +- core/downloader.py | 55 +- core/httptools.py | 4 +- core/item.py | 5 +- core/scrapertools.py | 8 +- core/servertools.py | 10 +- core/support.py | 148 +- core/tmdb.py | 4 +- core/tvdb.py | 6 +- core/videolibrarytools.py | 93 +- core/ziptools.py | 11 + default.py | 4 - lib/generictools.py | 12 +- lib/megaserver/client.py | 14 +- .../python_libtorrent/__init__.py | 73 +- platformcode/config.py | 70 +- platformcode/custom_code.py | 130 +- platformcode/download_and_play.py | 8 +- platformcode/launcher.py | 37 +- platformcode/mct.py | 7 +- platformcode/platformtools.py | 511 ++++--- platformcode/updater.py | 9 +- platformcode/xbmc_videolibrary.py | 521 +++++-- resources/language/English/strings.po | 813 ++++++---- resources/language/Italian/strings.po | 1309 +++++++++-------- .../themes/default/thumb_search_generic.png | Bin 19004 -> 0 bytes .../themes/default/thumb_search_more.png | Bin 20709 -> 0 bytes .../themes/default/thumb_search_tvshow.png | Bin 22797 -> 0 bytes .../media/themes/default/thumb_years.png | Bin 13796 -> 0 bytes resources/settings.xml | 208 +-- .../Default/media/Shortcut - Copia/close.png | Bin 874 -> 0 bytes .../dialog-bg-solid-white.png | Bin 3774 -> 0 bytes .../Shortcut - Copia/dialog-bg-solid.png | Bin 1891 -> 0 bytes .../Default/media/Shortcut - Copia/logo.png | Bin 838 -> 0 bytes .../Default/media/Shortcut - Copia/white.png | Bin 167 -> 0 bytes .../media/Shortcut - Copia/white70.png | Bin 177 -> 0 bytes resources/views/skin.ace2.json | 44 + resources/views/skin.aeon.nox.silvo.json | 109 ++ resources/views/skin.aeon.tajo.json | 50 + resources/views/skin.aeonmq8.json | 96 ++ resources/views/skin.amber.json | 62 + resources/views/skin.apptv.json | 45 + resources/views/skin.arctic.zephyr.2.json | 81 + resources/views/skin.aura.json | 78 + resources/views/skin.bello.7.json | 76 + resources/views/skin.box.json | 46 + resources/views/skin.confluence.json | 55 + resources/views/skin.eminence.2.json | 92 ++ resources/views/skin.estuary.json | 54 + resources/views/skin.quartz.json | 66 + resources/views/skin.rapier.json | 51 + resources/views/skin.revolve.json | 68 + resources/views/skin.unity.json | 61 + servers/akvideo.py | 4 +- servers/animeid.py | 4 +- servers/animeworld_server.py | 1 - servers/archiveorg.py | 4 +- servers/backin.py | 2 +- servers/badshare.py | 5 +- servers/bdupload.py | 3 +- servers/bitertv.py | 4 +- servers/bitp.py | 4 +- servers/bravoporn.py | 1 - servers/cinemaupload.py | 4 +- servers/clicknupload.py | 6 +- servers/crunchyroll.py | 4 +- servers/datoporn.py | 4 +- servers/debriders/realdebrid.py | 1 - servers/deltabit.py | 6 +- servers/dostream.py | 4 +- servers/downace.py | 4 +- servers/drtuber.py | 1 - servers/eporner.py | 5 +- servers/estream.py | 5 +- servers/fastplay.py | 4 +- servers/fembed.py | 2 +- servers/fex.py | 5 +- servers/filebebo.py | 5 +- servers/filescdn.py | 4 +- servers/flix555.py | 5 +- servers/gamovideo.py | 10 +- servers/googlevideo.py | 1 - servers/gotporn.py | 4 +- servers/gvideo.py | 6 +- servers/hdload.py | 5 +- servers/iceporn.py | 1 - servers/idtbox.py | 9 +- servers/javwhores.py | 5 +- servers/jawcloud.py | 4 +- servers/jetload.py | 6 +- servers/jplayer.py | 7 +- servers/keezmovies.py | 3 +- servers/mangoplay.py | 4 +- servers/mangovideo.py | 3 +- servers/manyvideos.py | 9 +- servers/mediafire.py | 4 +- servers/megadrive.py | 4 +- servers/mp4upload.py | 5 +- servers/mydaddy.py | 4 +- servers/myupload.py | 7 +- servers/netutv.py | 6 +- servers/nowvideo.py | 1 + servers/onefichier.json | 2 +- servers/onlystream.py | 4 +- servers/oprem.py | 2 + servers/pornhub.py | 4 +- servers/pornrewind.py | 5 +- servers/powvideo.py | 8 +- servers/prostream.py | 4 +- servers/rcdnme.py | 4 +- servers/redtube.py | 4 +- servers/rutube.py | 7 +- servers/samaup.py | 4 +- servers/sendvid.py | 1 - servers/streamcherry.py | 4 +- servers/streamplay.py | 8 +- servers/streamty.py | 4 +- servers/streamz.py | 3 +- servers/supervideo.py | 5 +- servers/thevid.py | 3 +- servers/thevideobee.py | 4 +- servers/thevideome.py | 2 +- servers/thevimeo.py | 7 +- servers/tiwikiwi.py | 4 +- servers/torrent.py | 13 +- servers/tube8.py | 3 +- servers/tubeon.py | 1 - servers/tubst.py | 4 +- servers/turbovid.py | 3 +- servers/tusfiles.py | 4 +- servers/txxx.py | 1 - servers/uploadmp4.py | 4 +- servers/uppom.py | 5 +- servers/upstream.py | 1 - servers/uptobox.json | 2 +- servers/uptobox.py | 6 +- servers/upvid.py | 8 +- servers/uqload.py | 5 +- servers/vevio.py | 3 +- servers/vidbull.py | 5 +- servers/videobb.py | 4 +- servers/videobin.py | 4 +- servers/videofiles.py | 9 +- servers/videomega.py | 1 - servers/videoz.py | 4 +- servers/vidfast.py | 6 +- servers/vidlox.py | 4 +- servers/vidoza.py | 3 +- servers/vidtodo.py | 2 +- servers/vidup.py | 6 +- servers/vidzi.py | 4 +- servers/vimeo.json | 2 +- servers/vimeo.py | 25 +- servers/vimpleru.json | 2 +- servers/vimpleru.py | 3 +- servers/vipporns.py | 5 +- servers/viptube.py | 1 - servers/vivatube.py | 1 - servers/vivo.py | 4 +- servers/vshare.json | 2 +- servers/vshare.py | 4 +- servers/vup.json | 46 - servers/vup.py | 28 - servers/vvvvid.py | 6 +- servers/watchanimestream.py | 2 - servers/winporn.py | 1 - servers/xdrive.py | 4 +- servers/xhamster.py | 1 - servers/xstreamcdn.py | 2 +- servers/xvideos.py | 5 +- servers/youdbox.py | 1 - servers/yourupload.py | 4 +- servers/youtube.py | 2 +- servers/youwatch.py | 6 +- servers/zippyshare.py | 1 - videolibrary_service.py => service.py | 42 +- specials/backup.py | 97 ++ specials/community.py | 34 +- specials/downloads.py | 543 ++++--- specials/infoplus.py | 4 +- specials/news.py | 52 +- specials/quasar_download.py | 100 ++ specials/search.py | 29 +- specials/setting.py | 18 +- specials/shortcuts.py | 51 +- specials/side_menu.py | 4 +- specials/trailertools.py | 64 +- specials/tvmoviedb.py | 6 +- specials/url.py | 6 +- specials/videolibrary.json | 142 +- specials/videolibrary.py | 257 +++- 213 files changed, 5294 insertions(+), 2482 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 channels/hd4me.json create mode 100644 channels/hd4me.py create mode 100644 channels/metalvideo.json create mode 100644 channels/metalvideo.py create mode 100644 channels/tunein.json create mode 100644 channels/tunein.py delete mode 100644 resources/media/themes/default/thumb_search_generic.png delete mode 100644 resources/media/themes/default/thumb_search_more.png delete mode 100644 resources/media/themes/default/thumb_search_tvshow.png delete mode 100644 resources/media/themes/default/thumb_years.png delete mode 100644 resources/skins/Default/media/Shortcut - Copia/close.png delete mode 100644 resources/skins/Default/media/Shortcut - Copia/dialog-bg-solid-white.png delete mode 100644 resources/skins/Default/media/Shortcut - Copia/dialog-bg-solid.png delete mode 100644 resources/skins/Default/media/Shortcut - Copia/logo.png delete mode 100644 resources/skins/Default/media/Shortcut - Copia/white.png delete mode 100644 resources/skins/Default/media/Shortcut - Copia/white70.png create mode 100644 resources/views/skin.ace2.json create mode 100644 resources/views/skin.aeon.nox.silvo.json create mode 100644 resources/views/skin.aeon.tajo.json create mode 100644 resources/views/skin.aeonmq8.json create mode 100644 resources/views/skin.amber.json create mode 100644 resources/views/skin.apptv.json create mode 100644 resources/views/skin.arctic.zephyr.2.json create mode 100644 resources/views/skin.aura.json create mode 100644 resources/views/skin.bello.7.json create mode 100644 resources/views/skin.box.json create mode 100644 resources/views/skin.confluence.json create mode 100644 resources/views/skin.eminence.2.json create mode 100644 resources/views/skin.estuary.json create mode 100644 resources/views/skin.quartz.json create mode 100644 resources/views/skin.rapier.json create mode 100644 resources/views/skin.revolve.json create mode 100644 resources/views/skin.unity.json delete mode 100644 servers/vup.json delete mode 100644 servers/vup.py rename videolibrary_service.py => service.py (96%) create mode 100644 specials/backup.py create mode 100644 specials/quasar_download.py diff --git a/.gitignore b/.gitignore index 0b3ccf09..ee8198e9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ custom_code.json last_commit.txt __pycache__/ +.vscode/settings.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..d68b334c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,49 @@ +Ciao, grazie per aver preso in considerazione di contribuire a questo progetto!
+Ci sono molti modi per farlo, e per alcuni di essi non è necessario essere uno sviluppatore. + +Puoi ad esempio [segnalare i cambiamenti di struttura](#segnalare-i-cambiamenti-di-struttura) dei canali/server, [scrivere guide o registrare video-esempi](#scrivere-guide-o-registrare-video-esempi) su alcune funzionalità "avanzate", dare consigli su funzionalità nuove o per migliorare quelle già presenti. + +# Segnalare i cambiamenti di struttura +KoD, alla fine, non è altro che un browser che estrapola dai siti le info richieste secondo regole ben precise, basate sulla struttura dei siti.
+I siti web cambiano, spesso, ciò che oggi funziona domani potrebbe non più funzionare, pertanto sono fondamentali le segnalazioni, ma esse per essere realmente utili devono: +- contenere il file di log (lo potete generare andando in Aiuto - Segnala un problema e seguendo le istruzioni) +- spiegare brevemente qual'è il problema e dove, ad esempio "cineblog da errore quando entro nella sezione Film", oppure "wstream non da nessun errore ma il video di fatto non parte" +- essere replicabili, se si tratta di cose che accadono una volta ogni tanto puoi provare a segnalare lo stesso, sperando che nel log ci sia qualche indizio. Se non c'è, nada + +Sei pregato di attenerti il più possibile a quanto descritto qua perchè un semplice "non funziona" fa solo perdere tempo. +Puoi fare tutte le segnalazioni nella sezione [issues](https://github.com/kodiondemand/addon/issues), cliccando su "new issue" appariranno dei template che ti guideranno nel processo. + +# Scrivere guide o registrare video-esempi +Cerca di essere sintetico ma senza tralasciare le informazioni essenziali, una volta fatto mandalo pure sul [gruppo telegram](https://t.me/kodiondemand) taggando gli admin (@admin).
+Verrà preso in considerazione il prima possibile ed eventualmente inserito nella [wiki](https://github.com/kodiondemand/addon/wiki) o verrà creato un comando richiamabile nel gruppo. + +# Consigli +Effettuali sempre nella sezione [issues](https://github.com/kodiondemand/addon/issues), miraccomando descrivi e fai esempi pratici.
+ +# Per sviluppatori + +Di seguito tutte le info su come prendere confidenza col codice e come contribuire + +## Da dove posso partire? +Un buon punto di partenza è [la wiki](https://github.com/kodiondemand/addon/wiki), qui è presente un minimo di documentazione sul funzionamento di KoD.
+Ti consigliamo vivamente, una volta compreso il funzionamento generale dell'addon (e prima di iniziare a sviluppare), di [forkare e clonare il repository](https://help.github.com/en/github/getting-started-with-github/fork-a-repo).
+Questo perchè, oltre al fatto di poter iniziare a mandare modifiche sul tuo account github, l'utilizzo di git abilita la [dev mode](https://github.com/kodiondemand/addon/wiki/dev-mode), che ti sarà di aiuto nelle tue attività. + +## che cosa posso fare? +Puoi provare a fixare un bug che hai riscontrato, aggiungere un canale/server che ti interessa ecc.. +Oppure puoi guardare nella sezione [Projects](https://github.com/kodiondemand/addon/projects) cosa è previsto e iniziare a svilupparlo! + +## ho fatto le modifiche che volevo, e ora? +Pusha sul tuo fork le modifiche che hai fatto e manda una pull request. Se è la prima volta ecco qualche link che ti aiuterà: +- http://makeapullrequest.com/ +- http://www.firsttimersonly.com/ +- [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). + +Quando crei la pull request, ricordati di spiegare brevemente qual'è la modifica e perchè l'hai fatta. +Quando avremo tempo revisioneremo le modifiche, potremmo anche segnalarti alcuni problemi, nel caso prenditi pure il tutto il tempo che vuoi per sistemare (non è necessaria un'altra pull, tutti i commit verranno riportati nella prima).
+Quando sarà tutto a posto accetteremo la pull includendo le modifiche + +## Regole per le collaborazioni: +- Se si riutilizza codice proveniente da altri addon è necessario citarne la fonte, per rispetto di chi ci ha lavorato, in caso contrario il pull request verrà respinto. +- Ogni modifica o novità inviata dev'essere testata, può capitare che vi sia sfuggito qualche bug (è normale), ma l'invio di materiale senza preventivi controlli non è gradito. +- I nuovi canali devono essere funzionanti e completi di tutte le feature, comprese videoteca ed autoplay, non verranno accettati finchè non lo saranno. diff --git a/README.md b/README.md index 16e630af..18a7fcba 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,16 @@ # Kodi On Demand ### Un fork italiano di [Alfa](https://github.com/alfa-addon) -Ognuno è libero (anzi, invitato!) a collaborare, per farlo è possibile utilizzare i pull request. -KOD funziona con Kodi fino alla versione 18 (Python 2). -KOD, come Alfa, è sotto licenza GPL v3, pertanto siete liberi di utilizzare parte del codice, a patto di rispettare i termini di suddetta licenza, che si possono riassumere in: +Installazione: https://kodiondemand.github.io/#download + +KoD attualmente funziona con Kodi fino alla versione 18 (Python 2). + + +KoD, come Alfa, è sotto licenza GPL v3, pertanto siete liberi di utilizzare parte del codice, a patto di rispettare i termini di suddetta licenza, che si possono riassumere in: - Il tuo addon deve essere rilasciando secondo la stessa licenza, ovvero essere open source (il fatto che lo zip sia visibile da chiunque non ha importanza, è necessario avere un repository git come questo) - Aggiungere i crediti a tutto ciò che copiate/modificate, ad esempio aggiungendo un commento nel file in questione o, meglio, facendo un cherry-pick (in modo da preservarnee lo storico) -### Come contribuire? -- Fai un Fork del repository. -- Effettua tutte le modifiche e fai un push nel tuo repository remoto. -- Testa tutte le funzioni principali (videoteca, autoplay, scraper web) o eventuali aggiunte extra. -- Apri una pull request. -Regole per le collaborazioni: -- Se si riutilizza codice proveniente da altri addon è necessario citarne la fonte, per rispetto di chi ci ha lavorato, in caso contrario il pull request verrà respinto. -- Ogni modifica o novità inviata dev'essere testata, può capitare che vi sia sfuggito qualche bug (è normale), ma l'invio di materiale senza preventivi controlli non è gradito. -- I nuovi canali devono essere funzionanti e completi di tutte le feature, comprese videoteca ed autoplay, non verranno accettati finchè non lo saranno. - -Se parte del codice di un tuo addon è stato incluso in questo progetto e ne desideri l'eliminazione, crea una issue portando le prove di essere veramente uno dei dev e lo elimineremo. - -### Qualcosa non funziona? -Sentiti libero di segnalarlo al team [qui](https://github.com/kodiondemand/addon/issues) +### Come contribuire o fare segnalazioni? +Ti piace il progetto e vuoi dare una mano? Leggi [qui](https://github.com/kodiondemand/addon/blob/master/CONTRIBUTING.md) diff --git a/addon.xml b/addon.xml index 848d970f..c0a68ff6 100644 --- a/addon.xml +++ b/addon.xml @@ -1,6 +1,5 @@ - + - @@ -19,11 +18,14 @@ resources/media/themes/ss/2.png resources/media/themes/ss/3.png - - riorganizzate le impostazioni -- aggiunte descrizioni tag qualità su cb01 (presto anche sugli altri) -- aggiunto il supporto alle serie di polpotv -- fixato server mystream -- fix Rinumerazione per episodi Nuovi + - Nuova sezione Musica +- Download in Background +- Download dalla Videoteca e supporto file locali +- Backup e cancellazione della Videoteca +- Spostamento della Videoteca +- Migliorata integrazione con libreria di Kodi +- Gestione delle Viste Preferite +- Nuovo layout impostazioni Naviga velocemente sul web e guarda i contenuti presenti [COLOR red]The owners and submitters to this addon do not host or distribute any of the content displayed by these addons nor do they have any affiliation with the content providers.[/COLOR] [COLOR yellow]Kodi © is a registered trademark of the XBMC Foundation. We are not connected to or in any other way affiliated with Kodi, Team Kodi, or the XBMC Foundation. Furthermore, any software, addons, or products offered by us will receive no support in official Kodi channels, including the Kodi forums and various social networks.[/COLOR] @@ -33,6 +35,6 @@ https://t.me/kodiondemand https://github.com/kodiondemand/addon - + \ No newline at end of file diff --git a/channels/cinemalibero.py b/channels/cinemalibero.py index de0d93aa..10408118 100644 --- a/channels/cinemalibero.py +++ b/channels/cinemalibero.py @@ -12,18 +12,19 @@ from platformcode import config list_servers = ['akstream', 'wstream', 'backin', 'clipwatching', 'cloudvideo', 'verystream', 'onlystream', 'mixdrop'] list_quality = ['default'] -def findhost(): - permUrl = httptools.downloadpage('https://www.cinemalibero.online/', follow_redirects=False).headers - try: - import urlparse - except: - import urllib.parse as urlparse - p = list(urlparse.urlparse(permUrl['location'].replace('https://www.google.com/search?q=site:', ''))) - if not p[0]: - p[0] = 'https' - return urlparse.urlunparse(p) +# rimanda a .today che contiene tutti link a .plus +# def findhost(): +# permUrl = httptools.downloadpage('https://www.cinemalibero.online/', follow_redirects=False).headers +# try: +# import urlparse +# except: +# import urllib.parse as urlparse +# p = list(urlparse.urlparse(permUrl['location'].replace('https://www.google.com/search?q=site:', ''))) +# if not p[0]: +# p[0] = 'https' +# return urlparse.urlunparse(p) -host = config.get_channel_url(findhost) +host = config.get_channel_url() headers = [['Referer', host]] @support.menu diff --git a/channels/cinetecadibologna.py b/channels/cinetecadibologna.py index cc66d5d5..34a4e8e6 100644 --- a/channels/cinetecadibologna.py +++ b/channels/cinetecadibologna.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Ringraziamo Icarus crew # Canale per cinetecadibologna # ------------------------------------------------------------ from core.item import Item diff --git a/channels/dsda.py b/channels/dsda.py index 0586be06..2293ed29 100644 --- a/channels/dsda.py +++ b/channels/dsda.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Ringraziamo Icarus crew # Canale per documentaristreamingda # ------------------------------------------------------------ diff --git a/channels/eurostreaming.py b/channels/eurostreaming.py index 2cc3cadb..180a0339 100644 --- a/channels/eurostreaming.py +++ b/channels/eurostreaming.py @@ -16,7 +16,7 @@ from core import scrapertools, httptools, support from core.item import Item def findhost(): - permUrl = httptools.downloadpage('https://eurostreaming.link/', follow_redirects=False).headers + permUrl = httptools.downloadpage('https://eurostreaming.link/', follow_redirects=False, only_headers=True).headers host = 'https://'+permUrl['location'].replace('https://www.google.it/search?q=site:', '') return host diff --git a/channels/filmpertutti.py b/channels/filmpertutti.py index e03fba9e..0589367f 100644 --- a/channels/filmpertutti.py +++ b/channels/filmpertutti.py @@ -155,9 +155,6 @@ def newest(categoria): def findvideos(item): if item.contentType == 'movie': data = httptools.downloadpage(item.url).data - toUnshorten = scrapertools.find_multiple_matches(data, 'https?://buckler.link/[a-zA-Z0-9]+') - for link in toUnshorten: - data += '\n' + httptools.downloadpage(link, follow_redirects=False).headers["Location"] return support.server(item, data=data) else: return support.server(item, item.url) diff --git a/channels/hd4me.json b/channels/hd4me.json new file mode 100644 index 00000000..04465df9 --- /dev/null +++ b/channels/hd4me.json @@ -0,0 +1,12 @@ +{ + "id": "hd4me", + "name": "HD4ME", + "language": ["ita", "sub-ita"], + "active": true, + "adult": false, + "thumbnail": "hd4me.png", + "banner": "hd4me.png", + "categories": ["movie", "vos"], + "not_active": ["include_in_newest"], + "settings": [] +} diff --git a/channels/hd4me.py b/channels/hd4me.py new file mode 100644 index 00000000..f098941d --- /dev/null +++ b/channels/hd4me.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------ +# Canale per HD4ME +# ------------------------------------------------------------ + +from core import httptools, support + + +host = support.config.get_channel_url() +headers = [['Referer', host]] + +list_servers = ['mega'] +list_quality = ['default'] + +@support.menu +def mainlist(item): + + film = [('Genere', ['', 'genre'])] + + return locals() + +@support.scrape +def peliculas(item): + # debug = True + patron = r'(?P[^<]+)<' + return locals() + + +def search(item, text): + support.log(text) + item.url = host + '/?s=' + text + try: + return peliculas(item) + # Cattura la eccezione così non interrompe la ricerca globle se il canale si rompe! + except: + import sys + for line in sys.exc_info(): + support.logger.error("search except: %s" % line) + return [] + + +def findvideos(item): + url = support.match(item, patron=r'<a class="bot1" href="([^"]+)"').match + url = support.httptools.downloadpage(url, followredirect=True).url + return support.server(item, url) diff --git a/channels/metalvideo.json b/channels/metalvideo.json new file mode 100644 index 00000000..e18004c7 --- /dev/null +++ b/channels/metalvideo.json @@ -0,0 +1,12 @@ +{ + "id": "metalvideo", + "name": "Metal Video", + "active": true, + "adult": false, + "language": ["*"], + "thumbnail": "metalvideo.png", + "banner": "metalvideo.png", + "categories": ["music"], + "not_active":["include_in_global_search"], + "settings" :[] +} diff --git a/channels/metalvideo.py b/channels/metalvideo.py new file mode 100644 index 00000000..95ccad47 --- /dev/null +++ b/channels/metalvideo.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------ +# Canale per altadefinizione01 +# ------------------------------------------------------------ + +from core import support +from core.item import Item +from platformcode import config +from xml.dom import minidom + +#impostati dinamicamente da findhost() + + +host = 'https://metalvideo.com' +headers={'X-Requested-With': 'XMLHttpRequest'} + +list_servers = ['youtube'] +list_quality = ['default'] + +@support.scrape +def mainlist(item): + item.url = host + action = 'peliculas' + patronBlock = r'<ul class="dropdown-menu(?P<block>.*?)</ul> </div' + patron = r'<a href="(?P<url>[^"]+)"(?: class="")?>(?P<title>[^<]+)<' + def itemHook(item): + item.thumbnail = support.thumb(thumb='music.png') + return item + def itemlistHook(itemlist): + itemlist.pop(0) + itemlist.append( + support.Item( + channel=item.channel, + title=support.typo('Cerca...', 'bold color kod'), + url = item.url, + action='search', + thumbnail=support.thumb(thumb='search.png'))) + return itemlist + return locals() + +@support.scrape +def peliculas(item): + action = 'findvideos' + patron= r'<img src="[^"]+" alt="(?P<title>[^"]+)" data-echo="(?P<thumb>[^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+><a href="(?P<url>[^"]+)"' + patronNext = r'<a href="([^"]+)">»' + return locals() + + +def findvideos(item): + return support.server(item, video_library=False) + + +def search(item, text): + support.log(text) + url = host + '/search.php?keywords=' + text + '&video-id=' + try: + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.logger.error("%s" % line) + return [] diff --git a/channels/polpotv.py b/channels/polpotv.py index 096013ea..8198b3b5 100644 --- a/channels/polpotv.py +++ b/channels/polpotv.py @@ -2,9 +2,9 @@ # ------------------------------------------------------------ # KoD - XBMC Plugin # Canale polpotv -# ------------------------------------------------------------ +# ------------------------------------------------------------ -from core import scrapertools, httptools, support, jsontools +from core import support, jsontools from core.item import Item from platformcode import config import json, datetime @@ -42,15 +42,15 @@ def newest(categoria): item.contentType = 'movie' item.url = host + '/api/movies' elif categoria == 'series': - item.contentType = 'tvshow' + item.contentType = 'tvshow' item.url = host+'/api/shows' return peliculas(item) def peliculas(item): support.log() itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data + + data = support.match(item.url, headers=headers).data json_object = jsontools.load(data) for element in json_object['hydra:member']: if 'shows' not in item.url: @@ -70,30 +70,37 @@ def peliculas(item): def episodios(item): support.log() itemlist = [] - data = httptools.downloadpage(item.url, headers=headers).data + data = support.match(item.url, headers=headers).data json_object = jsontools.load(data) for season in json_object['seasons']: seas_url=host+season['@id']+'/releases' - itemlist_season=get_season(item.channel, seas_url, season['seasonNumber']) + itemlist_season=get_season(item, seas_url, season['seasonNumber']) if(len(itemlist_season)>0): itemlist.extend(itemlist_season) support.videolibrary(itemlist, item, 'color kod bold') + support.download(itemlist, item) return itemlist -def get_season(channel, seas_url, seasonNumber): +def get_season(item, seas_url, seasonNumber): support.log() itemlist = [] - data = httptools.downloadpage(seas_url, headers=headers).data + data = support.match(seas_url, headers=headers).data json_object = jsontools.load(data) for episode in json_object['hydra:member']: itemlist.append( - Item(channel=channel, + Item(channel=item.channel, action='findvideos', contentType='episode', + fulltitle=item.fulltitle, + show=item.show, + contentSerieName=item.contentSerieName, title=str(seasonNumber)+"x"+str("%02d"%episode['episodeNumber']), url=seas_url, + thumbnail=item.thumbnail, + fanart=item.fanart, + plot=item.plot, extra=str(len(json_object['hydra:member'])-episode['episodeNumber']))) return itemlist[::-1] @@ -102,17 +109,17 @@ def search(item, texto): itemlist=[] try: item.url = host + "/api/movies?originalTitle="+texto+"&translations.name=" +texto - data = httptools.downloadpage(item.url, headers=headers).data + data = support.match(item.url, headers=headers).data json_object = jsontools.load(data) for movie in json_object['hydra:member']: item.contentType='movie' itemlist.extend(get_itemlist_element(movie,item)) item.url = host + "/api/shows?originalTitle="+texto+"&translations.name=" +texto - data = httptools.downloadpage(item.url, headers=headers).data + data = support.match(item.url, headers=headers).data json_object = jsontools.load(data) for tvshow in json_object['hydra:member']: item.contentType='tvshow' - itemlist.extend(get_itemlist_element(tvshow,item)) + itemlist.extend(get_itemlist_element(tvshow,item)) return itemlist # Continua la ricerca in caso di errore except: @@ -124,7 +131,7 @@ def search(item, texto): def search_movie_by_genre(item): support.log() itemlist = [] - data = httptools.downloadpage(item.url, headers=headers).data + data = support.match(item.url, headers=headers).data json_object = jsontools.load(data) for genre in json_object['hydra:member']: itemlist.append( @@ -155,7 +162,7 @@ def findvideos(item): support.log() itemlist = [] try: - data = httptools.downloadpage(item.url, headers=headers).data + data = support.match(item.url, headers=headers).data json_object = jsontools.load(data) array_index=0 if item.contentType!='movie': @@ -165,7 +172,10 @@ def findvideos(item): Item( channel=item.channel, action="play", + title='Direct', thumbnail=item.thumbnail, + fulltitle = item.fulltitle, + search = item.search, url=video['src'], server='directo', quality=str(video['size'])+ 'p', @@ -204,7 +214,7 @@ def get_itemlist_element(element,item): next_action='findvideos' quality=support.typo(element['lastQuality'].upper(), '_ [] color kod bold') url="%s%s/releases" - infoLabels['tmdbid']=element['tmdbId'] + infoLabels['tmdb_id']=element['tmdbId'] else: next_action='episodios' quality='' @@ -223,4 +233,8 @@ def get_itemlist_element(element,item): url=url %(host,element['@id'] ), infoLabels=infoLabels, extra=item.extra)) + + if item.contentType=='movie': + for item in itemlist: + item= support.tmdb.find_and_set_infoLabels(item) return itemlist diff --git a/channels/porn/thumbzilla.py b/channels/porn/thumbzilla.py index d0273b3c..aab21aee 100644 --- a/channels/porn/thumbzilla.py +++ b/channels/porn/thumbzilla.py @@ -44,42 +44,42 @@ def mainlist(item): logger.info() itemlist = [] itemlist.append(Item(channel=__channel__, action="videos", title="Más Calientes", url=host, - viewmode="movie", thumbnail=get_thumb("channels_adult.png"))) + viewmode="movie", thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="Nuevas", url=host + '/newest', action="videos", viewmode="movie_with_plot", viewcontent='movies', - thumbnail=get_thumb("channels_adult.png"))) + thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="Tendencias", url=host + '/tending', action="videos", viewmode="movie_with_plot", viewcontent='movies', - thumbnail=get_thumb("channels_adult.png"))) + thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="Mejores Videos", url=host + '/top', action="videos", viewmode="movie_with_plot", viewcontent='movies', - thumbnail=get_thumb("channels_adult.png"))) + thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="Populares", url=host + '/popular', action="videos", viewmode="movie_with_plot", viewcontent='movies', - thumbnail=get_thumb("channels_adult.png"))) + thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="Videos en HD", url=host + '/hd', action="videos", viewmode="movie_with_plot", viewcontent='movies', - thumbnail=get_thumb("channels_adult.png"))) + thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="Caseros", url=host + '/hd', action="videos", viewmode="movie_with_plot", viewcontent='homemade', - thumbnail=get_thumb("channels_adult.png"))) + thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="PornStar", action="catalogo", url=host + '/pornstars/', viewmode="movie_with_plot", viewcontent='movies', - thumbnail=get_thumb("channels_adult.png"))) + thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="Categorías", action="categorias", url=host + '/categories/', viewmode="movie_with_plot", viewcontent='movies', - thumbnail=get_thumb("channels_adult.png"))) + thumbnail=get_thumb("adult.png"))) itemlist.append(Item(channel=__channel__, title="Buscador", action="search", url=host, - thumbnail=get_thumb("channels_adult.png"), extra="buscar")) + thumbnail=get_thumb("adult.png"), extra="buscar")) return itemlist diff --git a/channels/raiplay.py b/channels/raiplay.py index efe0569f..c397e563 100644 --- a/channels/raiplay.py +++ b/channels/raiplay.py @@ -58,7 +58,6 @@ def learning(item): itemlist =[] json = current_session.get(item.url).json()['contents'] for key in json: - support.log(key['name']) itemlist.append(support.Item(channel = item.channel, title = support.typo(key['name'],'bold'), fulltitle = key['name'], show = key['name'], url = key['contents'], thumbnail = item.thumbnail, action = 'peliculas', args = item.args)) return itemlist @@ -117,7 +116,6 @@ def replay(item): support.log() itemlist = [] json = current_session.get(item.url).json()[item.fulltitle][0]['palinsesto'][0]['programmi'] - # support.log(json) for key in json: support.log('KEY=',key) if key and key['pathID']: itemlist.append(support.Item(channel = item.channel, thumbnail = getUrl(key['images']['landscape']), fanart = getUrl(key['images']['landscape']), url = getUrl(key['pathID']), @@ -165,13 +163,13 @@ def dirette(item): onAir = current_session.get(onair).json()['on_air'] for i, key in enumerate(json): itemlist.append(support.Item(channel = item.channel, title = support.typo(key['channel'], 'bold'), fulltitle = key['channel'], show = key['channel'], - thumbnail = key['transparent-icon'].replace("[RESOLUTION]", "256x-"), fanart = getUrl(onAir[i]['currentItem']['image']), url = key['video']['contentUrl'], + thumbnail = key['transparent-icon'].replace("[RESOLUTION]", "256x-"),forcethumb=True , fanart = getUrl(onAir[i]['currentItem']['image']), url = key['video']['contentUrl'], plot = support.typo(onAir[i]['currentItem']['name'],'bold')+ '\n\n' + onAir[i]['currentItem']['description'], action = 'play')) return itemlist def peliculas(item): - support.log(item.url) + support.log() itemlist = [] keys = [] key_list = [] @@ -235,7 +233,7 @@ def select(item): def episodios(item): - support.log(len(item.url)) + support.log() itemlist = [] if type(item.url) in [list, dict] and len(item.url) > 1 and ('name' in item.url[0] and 'stagione' not in item.url[0]['name'].lower()): for key in item.url: diff --git a/channels/serietvu.py b/channels/serietvu.py index 9c9a92db..ceb08318 100644 --- a/channels/serietvu.py +++ b/channels/serietvu.py @@ -108,39 +108,28 @@ def newest(categoria): def findvideos(item): - log() + log(item) if item.args != 'update': - data = item.url - toUnshorten = scrapertools.find_multiple_matches(data, 'https?://buckler.link/[a-zA-Z0-9]+') - for link in toUnshorten: - data += '\n' + httptools.downloadpage(link, follow_redirects=False).headers["Location"] - return support.server(item, data=data) + return support.server(item, data=item.url) else: itemlist = [] item.infoLabels['mediatype'] = 'episode' - data = httptools.downloadpage(item.url, headers=headers).data - data = re.sub('\n|\t', ' ', data) - data = re.sub(r'>\s+<', '> <', data) - url_video = scrapertools.find_single_match(data, r'<div class="item"> <a data-id="[^"]+" data-href="([^"]+)" data-original="[^"]+"[^>]+> <div> <div class="title">Episodio \d+', -1) - url_serie = scrapertools.find_single_match(data, r'<link rel="canonical" href="([^"]+)"\s?/>') - goseries = support.typo(">> Vai alla Serie:", ' bold') - series = support.typo(item.contentSerieName, ' bold color kod') + data = support.match(item).data + urls_video = support.match(data, patron=r'<a data-id="[^"]+" data-(href=".*?)</iframe>').matches[-1] + url_serie = support.match(data, patron=r'<link rel="canonical" href="([^"]+)"\s?/>').match - itemlist = support.server(item, data=url_video) + itemlist = support.server(item, data=urls_video) itemlist.append( Item(channel=item.channel, - title=goseries + series, + title=support.typo("Vai alla Serie Completa: " + item.fulltitle, ' bold'), fulltitle=item.fulltitle, show=item.show, contentType='tvshow', - contentSerieName=item.contentSerieName, url=url_serie, action='episodios', - contentTitle=item.contentSerieName, - plot = goseries + series + "con tutte le puntate", - thumbnail = support.thumb(thumb='channels_tvshow.png') + thumbnail = support.thumb(thumb='tvshow.png') )) return itemlist diff --git a/channels/streamingaltadefinizione.py b/channels/streamingaltadefinizione.py index 06d4d8fc..959b4e11 100644 --- a/channels/streamingaltadefinizione.py +++ b/channels/streamingaltadefinizione.py @@ -12,7 +12,7 @@ list_servers = ['verystream', 'openload', 'wstream'] list_quality = ['1080p', 'HD', 'DVDRIP', 'SD', 'CAM'] def findhost(): - permUrl = httptools.downloadpage('https://www.popcornstream.info', follow_redirects=False).headers + permUrl = httptools.downloadpage('https://www.popcornstream.info', follow_redirects=False, only_headers=True).headers if 'google' in permUrl['location']: host = permUrl['location'].replace('https://www.google.it/search?q=site:', '') if host[:4] != 'http': diff --git a/channels/tunein.json b/channels/tunein.json new file mode 100644 index 00000000..e72f724a --- /dev/null +++ b/channels/tunein.json @@ -0,0 +1,12 @@ +{ + "id": "tunein", + "name": "TuneIn", + "active": true, + "adult": false, + "language": ["*"], + "thumbnail": "tunein.png", + "banner": "tunein.png", + "categories": ["music"], + "not_active":["include_in_global_search"], + "settings" :[] +} diff --git a/channels/tunein.py b/channels/tunein.py new file mode 100644 index 00000000..212965bc --- /dev/null +++ b/channels/tunein.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------ +# Canale per altadefinizione01 +# ------------------------------------------------------------ + +from core import support +from core.item import Item +from platformcode import config +from xml.dom import minidom + +#impostati dinamicamente da findhost() + + +host = 'http://api.radiotime.com' +headers = [['Referer', host]] + +@support.scrape +def mainlist(item): + item.url = host + action = 'radio' + patron = r'text="(?P<title>[^"]+)" URL="(?P<url>[^"]+)"' + def itemHook(item): + item.thumbnail = support.thumb(thumb='music.png') + return item + def itemlistHook(itemlist): + itemlist.append( + support.Item( + channel=item.channel, + title=support.typo('Cerca...', 'bold color kod'), + url = item.url, + action='search', + thumbnail=support.thumb(thumb='search.png'))) + return itemlist + return locals() + + +def radio(item): + support.log() + itemlist = [] + data = support.match(item, patron= r'text="(?P<title>[^\("]+)(?:\((?P<location>[^\)]+)\))?" URL="(?P<url>[^"]+)" bitrate="(?P<quality>[^"]+)" reliability="[^"]+" guide_id="[^"]+" subtext="(?P<song>[^"]+)" genre_id="[^"]+" formats="(?P<type>[^"]+)" (?:playing="[^"]+" )?(?:playing_image="[^"]+" )?(?:show_id="[^"]+" )?(?:item="[^"]+" )?image="(?P<thumb>[^"]+)"') + if data.matches: + for title, location, url, quality, song, type, thumbnail in data.matches: + itemlist.append( + support.Item( + channel = item.channel, + title = support.typo(title, 'bold') + support.typo(quality + ' kbps','_ [] bold color kod'), + thumbnail = thumbnail, + url = url, + contentType = 'music', + plot = support.typo(location, 'bold') + '\n' + song, + action = 'findvideos' + ) + ) + else: + matches = support.match(data.data, patron= r'text="(?P<title>[^\("]+)(?:\([^\)]+\))?" URL="(?P<url>[^"]+)" (?:guide_id="[^"]+" )?(?:stream_type="[^"]+" )?topic_duration="(?P<duration>[^"]+)" subtext="(?P<plot>[^"]+)" item="[^"]+" image="(?P<thumb>[^"]+)"').matches + if matches: + for title, url, duration, plot, thumbnail in matches: + infoLabels={} + infoLabels['duration'] = duration + itemlist.append( + support.Item( + channel = item.channel, + title = support.typo(title, 'bold'), + thumbnail = thumbnail, + infolLbels = infoLabels, + url = url, + contentType = 'music', + plot = plot, + action = 'findvideos' + ) + ) + else: + matches = support.match(data.data, patron= r'text="(?P<title>[^"]+)" URL="(?P<url>[^"]+)"').matches + for title, url in matches: + itemlist.append( + support.Item( + channel = item.channel, + title = support.typo(title, 'bold'), + thumbnail = item.thumbnail, + url = url, + action = 'radio' + ) + ) + return itemlist + + +def findvideos(item): + import xbmc + itemlist = [] + item.action = 'play' + urls = support.match(item.url).data.strip().split() + for url in urls: + item.url= url + item.server = 'directo' + itemlist.append(item) + return itemlist + + +def search(item, text): + support.log(text) + item.url = host + '/Search.ashx?query=' +text + try: + return radio(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.logger.error("%s" % line) + return [] diff --git a/channels/vvvvid.py b/channels/vvvvid.py index bd790935..9416fbf1 100644 --- a/channels/vvvvid.py +++ b/channels/vvvvid.py @@ -152,8 +152,8 @@ def episodios(item): episodes.append(episode['episodes']) for episode in episodes: for key in episode: - if 'stagione' in key['title'].encode('utf8').lower(): - match = support.match(key['title'].encode('utf8'), patron=r'[Ss]tagione\s*(\d+) - [Ee]pisodio\s*(\d+)').match + if 'stagione' in encode(key['title']).lower(): + match = support.match(encode(key['title']), patron=r'[Ss]tagione\s*(\d+) - [Ee]pisodio\s*(\d+)').match title = match[0]+'x'+match[1] + ' - ' + item.fulltitle make_item = True elif int(key['season_id']) == int(season_id): @@ -175,10 +175,14 @@ def episodios(item): url= host + show_id + '/season/' + str(key['season_id']) + '/', action= 'findvideos', video_id= key['video_id'], + thumbnail= item.thumbnail, + fanart = item.fanart, + plot=item.plot, contentType = item.contentType )) autorenumber.renumber(itemlist, item, 'bold') - if autorenumber.check(item) == True: + if autorenumber.check(item) == True \ + or support.match(itemlist[0].title, patron=r"(\d+x\d+)").match: support.videolibrary(itemlist,item) return itemlist @@ -211,10 +215,10 @@ def make_itemlist(itemlist, item, data): search = item.search if item.search else '' infoLabels = {} for key in data['data']: - if search.lower() in key['title'].encode('utf8').lower(): + if search.lower() in encode(key['title']).lower(): infoLabels['year'] = key['date_published'] infoLabels['title'] = infoLabels['tvshowtitle'] = key['title'] - title = key['title'].encode('utf8') + title = encode(key['title']) itemlist.append( Item( channel = item.channel, @@ -242,4 +246,4 @@ def encode(text): if sys.version_info[0] >= 3: return text else: - return text.encode('utf8') + return text.encode('utf8') \ No newline at end of file diff --git a/channelselector.py b/channelselector.py index 7dc3d556..1b6319b2 100644 --- a/channelselector.py +++ b/channelselector.py @@ -12,9 +12,6 @@ import xbmcaddon addon = xbmcaddon.Addon('plugin.video.kod') downloadenabled = addon.getSetting('downloadenabled') -from specials import shortcuts -CONTEXT = shortcuts.context() - def getmainlist(view="thumb_"): logger.info() itemlist = list() @@ -22,8 +19,7 @@ def getmainlist(view="thumb_"): if config.dev_mode(): itemlist.append(Item(title="Redirect", channel="checkhost", action="check_channels", thumbnail='', - category=config.get_localized_string(30119), viewmode="thumbnails", - context = CONTEXT)) + category=config.get_localized_string(30119), viewmode="thumbnails")) # Añade los canales que forman el menú principal if addon.getSetting('enable_news_menu') == "true": # itemlist.append(Item(title=config.get_localized_string(30130), channel="news", action="mainlist", @@ -33,13 +29,12 @@ def getmainlist(view="thumb_"): itemlist.append(Item(title=config.get_localized_string(30130), channel="news", action="mainlist", thumbnail=get_thumb("news.png", view), category=config.get_localized_string(30119), viewmode="thumbnails", - context=CONTEXT + [{"title": config.get_localized_string(70285), "channel": "shortcuts", "action": "SettingOnPosition", "category":5}])) + context=[{"title": config.get_localized_string(70285), "channel": "shortcuts", "action": "SettingOnPosition", "category":5}])) if addon.getSetting('enable_channels_menu') == "true": itemlist.append(Item(title=config.get_localized_string(30118), channel="channelselector", action="getchanneltypes", thumbnail=get_thumb("channels.png", view), view=view, - category=config.get_localized_string(30119), viewmode="thumbnails", - context = CONTEXT)) + category=config.get_localized_string(30119), viewmode="thumbnails")) if addon.getSetting('enable_search_menu') == "true": # itemlist.append(Item(title=config.get_localized_string(30103), channel="search", path='special', action="mainlist", @@ -50,25 +45,22 @@ def getmainlist(view="thumb_"): itemlist.append(Item(title=config.get_localized_string(30103), channel="search", path='special', action="mainlist", thumbnail=get_thumb("search.png", view), category=config.get_localized_string(30119), viewmode="list", - context = CONTEXT + [{"title": config.get_localized_string(60412), "action": "setting_channel_new", "channel": "search"}, + context = [{"title": config.get_localized_string(60412), "action": "setting_channel_new", "channel": "search"}, {"title": config.get_localized_string(70286), "channel": "shortcuts", "action": "SettingOnPosition", "category":3}])) if addon.getSetting('enable_onair_menu') == "true": itemlist.append(Item(channel="filmontv", action="mainlist", title=config.get_localized_string(50001), - thumbnail=get_thumb("on_the_air.png"), viewmode="thumbnails", - context = CONTEXT)) + thumbnail=get_thumb("on_the_air.png"), viewmode="thumbnails")) if addon.getSetting('enable_link_menu') == "true": itemlist.append(Item(title=config.get_localized_string(70527), channel="kodfavorites", action="mainlist", thumbnail=get_thumb("mylink.png", view), view=view, - category=config.get_localized_string(70527), viewmode="thumbnails", - context = CONTEXT)) + category=config.get_localized_string(70527), viewmode="thumbnails")) if addon.getSetting('enable_fav_menu') == "true": itemlist.append(Item(title=config.get_localized_string(30102), channel="favorites", action="mainlist", thumbnail=get_thumb("favorites.png", view), - category=config.get_localized_string(30102), viewmode="thumbnails", - context = CONTEXT)) + category=config.get_localized_string(30102), viewmode="thumbnails")) if config.get_videolibrary_support() and addon.getSetting('enable_library_menu') == "true": # itemlist.append(Item(title=config.get_localized_string(30131), channel="videolibrary", action="mainlist", @@ -79,7 +71,7 @@ def getmainlist(view="thumb_"): itemlist.append(Item(title=config.get_localized_string(30131), channel="videolibrary", action="mainlist", thumbnail=get_thumb("videolibrary.png", view), category=config.get_localized_string(30119), viewmode="thumbnails", - context=CONTEXT + [{"title": config.get_localized_string(70287), "channel": "shortcuts", "action": "SettingOnPosition", "category":2}, + context=[{"title": config.get_localized_string(70287), "channel": "shortcuts", "action": "SettingOnPosition", "category":2}, {"title": config.get_localized_string(60568), "channel": "videolibrary", "action": "update_videolibrary"}])) if downloadenabled != "false": # itemlist.append(Item(title=config.get_localized_string(30101), channel="downloads", action="mainlist", @@ -88,7 +80,7 @@ def getmainlist(view="thumb_"): # "action": "channel_config"}])) itemlist.append(Item(title=config.get_localized_string(30101), channel="downloads", action="mainlist", thumbnail=get_thumb("downloads.png", view), viewmode="list", - context=CONTEXT + [{"title": config.get_localized_string(70288), "channel": "shortcuts", "action": "SettingOnPosition", "category":4}])) + context=[{"title": config.get_localized_string(70288), "channel": "shortcuts", "action": "SettingOnPosition", "category":4}])) thumb_setting = "setting_%s.png" % 0 # config.get_setting("plugin_updates_available") @@ -108,7 +100,7 @@ def getchanneltypes(view="thumb_"): logger.info() # Lista de categorias - channel_types = ["movie", "tvshow", "anime", "documentary", "vos", "direct", "live"] # , "torrent" + channel_types = ["movie", "tvshow", "anime", "documentary", "vos", "direct", "live", "music"] # , "torrent" if config.get_setting("adult_mode") != 0: channel_types.append("adult") @@ -122,13 +114,13 @@ def getchanneltypes(view="thumb_"): title = config.get_localized_string(30121) itemlist.append(Item(title=title, channel="channelselector", action="filterchannels", view=view, category=title, channel_type="all", thumbnail=get_thumb("all.png", view), - viewmode="thumbnails", context = CONTEXT)) + viewmode="thumbnails")) for channel_type in channel_types: title = config.get_localized_category(channel_type) itemlist.append(Item(title=title, channel="channelselector", action="filterchannels", category=title, channel_type=channel_type, viewmode="thumbnails", - thumbnail=get_thumb("%s.png" % channel_type, view), context = CONTEXT)) + thumbnail=get_thumb("%s.png" % channel_type, view))) # itemlist.append(Item(title='Oggi in TV', channel="filmontv", action="mainlist", view=view, # category=title, channel_type="all", thumbnail=get_thumb("on_the_air.png", view), @@ -138,7 +130,7 @@ def getchanneltypes(view="thumb_"): itemlist.append(Item(title=config.get_localized_string(70685), channel="community", action="mainlist", view=view, category=config.get_localized_string(70685), channel_type="all", thumbnail=get_thumb("community.png", view), - viewmode="thumbnails", context = CONTEXT)) + viewmode="thumbnails")) return itemlist @@ -244,7 +236,7 @@ def filterchannels(category, view="thumb_"): channelslist.append(Item(title=channel_parameters["title"], channel=channel_parameters["channel"], action="mainlist", thumbnail=channel_parameters["thumbnail"], fanart=channel_parameters["fanart"], plot=channel_info, category=channel_parameters["title"], - language=channel_parameters["language"], viewmode="list", context=CONTEXT + context)) + language=channel_parameters["language"], viewmode="list", context=context)) except: logger.error("Se ha producido un error al leer los datos del canal '%s'" % channel) @@ -398,8 +390,8 @@ def thumb(item_or_itemlist=None, genre=False, thumb=''): 'biographical':['biografico', 'biographical'], 'comedy':['comico', 'commedia', 'demenziale', 'comedy'], 'adult':['erotico', 'hentai', 'harem', 'ecchi', 'adult'], - 'drama':['drammatico', 'drama'], - 'syfy':['fantascienza', 'science fiction', 'syfy'], + 'drama':['drammatico', 'drama', 'dramma'], + 'syfy':['fantascienza', 'science fiction', 'syfy', 'sci'], 'fantasy':['fantasy', 'magia', 'magic'], 'crime':['gangster','poliziesco', 'crime', 'crimine'], 'grotesque':['grottesco', 'grotesque'], @@ -415,7 +407,7 @@ def thumb(item_or_itemlist=None, genre=False, thumb=''): 'on_the_air' : ['corso', 'onda', 'diretta', 'dirette'], 'western':['western'], 'vos':['sub','sub-ita'], - 'romance':['romantico','sentimentale', 'romance'], + 'romance':['romantico','sentimentale', 'romance', 'soap'], 'family':['famiglia','famiglie', 'family', 'historical'], 'historical':['storico', 'history', 'storia'], 'az':['lettera','lista','alfabetico','a-z', 'alphabetical'], diff --git a/core/channeltools.py b/core/channeltools.py index b9209ef1..62bbdde9 100644 --- a/core/channeltools.py +++ b/core/channeltools.py @@ -44,8 +44,7 @@ def get_channel_parameters(channel_name): channel_parameters["adult"] = channel_parameters.get("adult", False) logger.info(channel_parameters["adult"]) if channel_parameters["adult"]: - channel_parameters["update_url"] = channel_parameters.get("update_url", - DEFAULT_UPDATE_URL + 'porn/') + channel_parameters["update_url"] = channel_parameters.get("update_url", DEFAULT_UPDATE_URL + 'porn/') else: channel_parameters["update_url"] = channel_parameters.get("update_url", DEFAULT_UPDATE_URL) channel_parameters["language"] = channel_parameters.get("language", ["all"]) diff --git a/core/downloader.py b/core/downloader.py index a0bb4b51..39f60d39 100644 --- a/core/downloader.py +++ b/core/downloader.py @@ -19,6 +19,9 @@ metodos: """ from __future__ import division from future import standard_library + +from core.item import Item + standard_library.install_aliases() from builtins import range from builtins import object @@ -102,22 +105,24 @@ class Downloader(object): # Funciones def start_dialog(self, title=config.get_localized_string(60200)): from platformcode import platformtools - progreso = platformtools.dialog_progress(title, config.get_localized_string(60201)) - self.start() - while self.state == self.states.downloading and not progreso.iscanceled(): - time.sleep(0.1) - line1 = "%s" % (self.filename) - line2 = config.get_localized_string(59983) % ( - self.progress, self.downloaded[1], self.downloaded[2], self.size[1], self.size[2], - self.speed[1], self.speed[2], self.connections[0], self.connections[1]) - line3 = config.get_localized_string(60202) % (self.remaining_time) + progreso = platformtools.dialog_progress_bg(title, config.get_localized_string(60201)) + try: + self.start() + while self.state == self.states.downloading: + time.sleep(0.2) + line1 = "%s" % (self.filename) + line2 = config.get_localized_string(59983) % ( + self.downloaded[1], self.downloaded[2], self.size[1], self.size[2], + self.speed[1], self.speed[2], self.connections[0], self.connections[1]) + line3 = config.get_localized_string(60202) % (self.remaining_time) - progreso.update(int(self.progress), line1, line2, line3) - if self.state == self.states.downloading: - self.stop() - progreso.close() + progreso.update(int(self.progress), line1, line2 + " " + line3) + self.__update_json() + finally: + progreso.close() def start(self): + self.__update_json(started=False) if self._state == self.states.error: return conns = [] for x in range(self._max_connections): @@ -190,7 +195,7 @@ class Downloader(object): # Funciones internas def __init__(self, url, path, filename=None, headers=[], resume=True, max_connections=10, block_size=2 ** 17, - part_size=2 ** 24, max_buffer=10): + part_size=2 ** 24, max_buffer=10, json_path=None): # Parametros self._resume = resume self._path = path @@ -199,6 +204,9 @@ class Downloader(object): self._block_size = block_size self._part_size = part_size self._max_buffer = max_buffer + self._json_path = json_path + self._json_text = '' + self._json_item = Item() try: import xbmc @@ -258,7 +266,7 @@ class Downloader(object): self.__get_download_info__() try: - logger.info("Descarga inicializada: Partes: %s | Ruta: %s | Archivo: %s | Tamaño: %s" % \ + logger.info("Download started: Parts: %s | Path: %s | File: %s | Size: %s" % \ (str(len(self._download_info["parts"])), self._pathencode('utf-8'), \ self._filenameencode('utf-8'), str(self._download_info["size"]))) except: @@ -579,3 +587,20 @@ class Downloader(object): self.__set_part_stopped__(id) logger.info("Thread stopped: %s" % threading.current_thread().name) + + def __update_json(self, started=True): + text = filetools.read(self._json_path) + # load item only if changed + if self._json_text != text: + self._json_text = text + self._json_item = Item().fromjson(text) + logger.info('item loaded') + progress = int(self.progress) + if started and self._json_item.downloadStatus == 0: # stopped + logger.info('Download paused') + self.stop() + elif self._json_item.downloadProgress != progress or not started: + params = {"downloadStatus": 4, "downloadComplete": 0, "downloadProgress": progress} + self._json_item.__dict__.update(params) + self._json_text = self._json_item.tojson() + filetools.write(self._json_path, self._json_text) diff --git a/core/httptools.py b/core/httptools.py index dd742879..c5f21b3d 100755 --- a/core/httptools.py +++ b/core/httptools.py @@ -123,6 +123,7 @@ def load_cookies(alfa_s=False): os.remove(cookies_file) cookies_lock.release() +load_cookies() def save_cookies(alfa_s=False): cookies_lock.acquire() @@ -131,8 +132,6 @@ def save_cookies(alfa_s=False): cookies_lock.release() -load_cookies() - def random_useragent(): """ Based on code from https://github.com/theriley106/RandomHeaders @@ -257,7 +256,6 @@ def downloadpage(url, **opt): """ url = scrapertools.unescape(url) - load_cookies() domain = urlparse.urlparse(url).netloc global domainCF CF = False diff --git a/core/item.py b/core/item.py index 1476af22..5ab216ea 100644 --- a/core/item.py +++ b/core/item.py @@ -13,10 +13,9 @@ if PY3: #from future import standard_library #standard_library.install_aliases() import urllib.parse as urllib # Es muy lento en PY2. En PY3 es nativo - from html.parser import HTMLParser else: import urllib # Usamos el nativo de PY2 que es más rápido - from HTMLParser import HTMLParser +from core.scrapertools import unescape import base64 import copy @@ -454,7 +453,7 @@ class Item(object): """ try: unicode_title = unicode(value, "utf8", "ignore") - return HTMLParser().unescape(unicode_title).encode("utf8") + return unescape(unicode_title).encode("utf8") except: if PY3 and isinstance(value, bytes): value = value.decode("utf8") diff --git a/core/scrapertools.py b/core/scrapertools.py index c01fecac..0503b92e 100644 --- a/core/scrapertools.py +++ b/core/scrapertools.py @@ -120,7 +120,7 @@ def unescape(text): pass return text # leave as is - return re.sub("&#?\w+;", fixup, text) + return re.sub("&#?\w+;", str(fixup), str(text)) # Convierte los codigos html "ñ" y lo reemplaza por "ñ" caracter unicode utf-8 @@ -418,14 +418,14 @@ def get_season_and_episode(title): """ filename = "" - patrons = ["(\d+)x(\d+)", "(?:s|t)(\d+)e(\d+)", - "(?:season|temp\w*)\s*(\d+)\s*(?:capitulo|epi\w*)\s*(\d+)"] + patrons = ["(\d+)\s*[x-]\s*(\d+)", "(\d+)\s*×\s*(\d+)", "(?:[Ss]|[Tt])(\d+)(?:[Ee]|Ep\.)(\d+)", + "(?:[Ss]tag|[Ss]eason|[Ss]tagione\w*)\s*(\d+)\s*(?:[Ee]pi|[Ee]pisode|[Ee]pisodio\w*)\s*(\d+)"] for patron in patrons: try: matches = re.compile(patron, re.I).search(title) if matches: - filename = matches.group(1) + "x" + matches.group(2).zfill(2) + filename = str(int(matches.group(1))) + "x" + str(int(matches.group(2))).zfill(2) break except: pass diff --git a/core/servertools.py b/core/servertools.py index 2c4b86da..0511b9ed 100644 --- a/core/servertools.py +++ b/core/servertools.py @@ -220,7 +220,7 @@ def get_server_from_url(url): return devuelve -def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialogo=False): +def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialogo=False, background_dialog=False): """ Función para obtener la url real del vídeo @param server: Servidor donde está alojado el vídeo @@ -231,6 +231,8 @@ def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialo @type video_password: str @param muestra_dialogo: Muestra el diálogo de progreso @type muestra_dialogo: bool + @type background_dialog: bool + @param background_dialog: if progress dialog should be in background @return: devuelve la url del video @rtype: list @@ -261,7 +263,7 @@ def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialo if server_parameters: # Muestra un diágo de progreso if muestra_dialogo: - progreso = platformtools.dialog_progress(config.get_localized_string(20000), + progreso = (platformtools.dialog_progress_bg if background_dialog else platformtools.dialog_progress)(config.get_localized_string(20000), config.get_localized_string(70180) % server_parameters["name"]) # Cuenta las opciones disponibles, para calcular el porcentaje @@ -292,6 +294,8 @@ def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialo logger.info("Servidor importado: %s" % server_module) except: server_module = None + if muestra_dialogo: + progreso.close() logger.error("No se ha podido importar el servidor: %s" % server) import traceback logger.error(traceback.format_exc()) @@ -305,6 +309,8 @@ def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialo if not video_exists: error_messages.append(message) logger.info("test_video_exists dice que el video no existe") + if muestra_dialogo: + progreso.close() else: logger.info("test_video_exists dice que el video SI existe") except: diff --git a/core/support.py b/core/support.py index c9ed8b4c..fd7179ac 100755 --- a/core/support.py +++ b/core/support.py @@ -26,9 +26,7 @@ from core import httptools, scrapertools, servertools, tmdb, channeltools from core.item import Item from lib import unshortenit from platformcode import logger, config -from specials import autoplay, shortcuts - -CONTEXT =shortcuts.context() +from specials import autoplay def hdpass_get_servers(item): def get_hosts(url, quality): @@ -40,15 +38,15 @@ def hdpass_get_servers(item): for mir_url, srv in scrapertools.find_multiple_matches(mir, patron_option): mir_url = scrapertools.decodeHtmlentities(mir_url) ret.append(Item(channel=item.channel, - action="play", - fulltitle=item.fulltitle, - quality=quality, - show=item.show, - thumbnail=item.thumbnail, - contentType=item.contentType, - title=srv, - server=srv, - url= mir_url)) + action="play", + fulltitle=item.fulltitle, + quality=quality, + show=item.show, + thumbnail=item.thumbnail, + contentType=item.contentType, + title=srv, + server=srv, + url= mir_url)) return ret # Carica la pagina itemlist = [] @@ -176,11 +174,10 @@ def cleantitle(title): def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, typeContentDict, typeActionDict, blacklist, search, pag, function, lang): itemlist = [] log("scrapeBlock qui") - matches = scrapertools.find_multiple_matches_groups(block, patron) - log('MATCHES =', matches) - if debug: regexDbg(item, patron, headers, block) + matches = scrapertools.find_multiple_matches_groups(block, patron) + log('MATCHES =', matches) known_keys = ['url', 'title', 'title2', 'season', 'episode', 'thumb', 'quality', 'year', 'plot', 'duration', 'genere', 'rating', 'type', 'lang', 'other'] # Legenda known_keys per i groups nei patron @@ -264,7 +261,7 @@ def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, t infolabels['plot'] = plot if scraped['duration']: matches = scrapertools.find_multiple_matches(scraped['duration'], - r'([0-9])\s*?(?:[hH]|:|\.|,|\\|\/|\||\s)\s*?([0-9]+)') + r'([0-9])\s*?(?:[hH]|:|\.|,|\\|\/|\||\s)\s*?([0-9]+)') for h, m in matches: scraped['duration'] = int(h) * 60 + int(m) if not matches: @@ -308,8 +305,7 @@ def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, t contentLanguage = lang1, contentEpisodeNumber=episode if episode else '', news= item.news if item.news else '', - other = scraped['other'] if scraped['other'] else '', - context = CONTEXT + other = scraped['other'] if scraped['other'] else '' ) # for lg in list(set(listGroups).difference(known_keys)): @@ -389,7 +385,8 @@ def scrape(func): if not data: page = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True) # if url may be changed and channel has findhost to update - if (not page.data or scrapertools.get_domain_from_url(page.url) != scrapertools.get_domain_from_url(item.url)) and 'findhost' in func.__globals__: + if 'findhost' in func.__globals__ and (not page.data or scrapertools.get_domain_from_url(page.url).lower() != scrapertools.get_domain_from_url(item.url).lower()): + logger.info('running findhost ' + func.__module__) host = func.__globals__['findhost']() parse = list(urlparse.urlparse(item.url)) from core import jsontools @@ -633,8 +630,7 @@ def menuItem(itemlist, filename, title='', action='', url='', contentType='movie url = url, extra = extra, args = args, - contentType = contentType, - context = CONTEXT + contentType = contentType )) # Apply auto Thumbnails at the menus @@ -697,7 +693,7 @@ def menu(func): if dictUrl[name] is not None and type(dictUrl[name]) is not str: for sub, var in dictUrl[name]: menuItem(itemlist, filename, - title = sub + ' submenu' + typo(title,'_ {}'), + title = sub + ' submenu {' + title + '}', url = host + var[0] if len(var) > 0 else '', action = var[1] if len(var) > 1 else 'peliculas', args=var[2] if len(var) > 2 else '', @@ -745,15 +741,27 @@ def typo(string, typography=''): # If there are no attributes, it applies the default ones attribute = ['[]','()','submenu','color','bold','italic','_','--','[B]','[I]','[COLOR]'] - + if int(config.get_setting('view_mode_channel').split(',')[-1]) in [0, 50, 55]: + VLT = True + else: + VLT = False # Otherwise it uses the typographical attributes of the string # else: + if 'capitalize' in string.lower(): + string = re.sub(r'\s*capitalize','',string).capitalize() + if 'uppercase' in string.lower(): + string = re.sub(r'\s*uppercase','',string).upper() + if 'lowercase' in string.lower(): + string = re.sub(r'\s*lowercase','',string).lower() if '[]' in string: string = '[' + re.sub(r'\s*\[\]','',string) + ']' if '()' in string: string = '(' + re.sub(r'\s*\(\)','',string) + ')' if 'submenu' in string: - string = "•• " + re.sub(r'\s*submenu','',string) + if VLT: + string = "•• " + re.sub(r'\s*submenu','',string) + else: + string = re.sub(r'\s*submenu','',string) if 'color' in string: color = scrapertools.find_single_match(string, 'color ([a-z]+)') if color == 'kod' or '': color = kod_color @@ -767,13 +775,10 @@ def typo(string, typography=''): if '--' in string: string = ' - ' + re.sub(r'\s*--','',string) if 'bullet' in string: - string = '[B]' + "•" + '[/B] ' + re.sub(r'\s*bullet','',string) - if 'capitalize' in string.lower(): - string = re.sub(r'\s*capitalize','',string).capitalize() - if 'uppercase' in string.lower(): - string = re.sub(r'\s*uppercase','',string).upper() - if 'lowercase' in string.lower(): - string = re.sub(r'\s*lowercase','',string).lower() + if VLT: + string = '[B]' + "•" + '[/B] ' + re.sub(r'\s*bullet','',string) + else: + string = re.sub(r'\s*bullet','',string) if '{}' in string: string = re.sub(r'\s*\{\}','',string) @@ -915,23 +920,34 @@ def download(itemlist, item, typography='', function_level=1, function=''): contentSerieName=item.contentSerieName if item.contentSerieName else '' contentTitle=item.contentTitle if item.contentTitle else '' + downloadItemlist = [i.tourl() for i in itemlist] if itemlist and item.contentChannel != 'videolibrary': - itemlist.append( - Item(channel='downloads', - from_channel=item.channel, - title=title, - fulltitle=item.fulltitle, - show=item.fulltitle, - contentType=item.contentType, - contentSerieName=contentSerieName, - url=item.url, - action='save_download', - from_action=from_action, - contentTitle=contentTitle, - path=item.path, - thumbnail=thumb(thumb='downloads.png') - )) + show = True + # do not show if we are on findvideos and there are no valid servers + if from_action == 'findvideos': + for i in itemlist: + if i.action == 'play': + break + else: + show = False + if show: + itemlist.append( + Item(channel='downloads', + from_channel=item.channel, + title=title, + fulltitle=item.fulltitle, + show=item.fulltitle, + contentType=item.contentType, + contentSerieName=contentSerieName, + url=item.url, + action='save_download', + from_action=from_action, + contentTitle=contentTitle, + path=item.path, + thumbnail=thumb(thumb='downloads.png'), + downloadItemlist=downloadItemlist + )) if from_action == 'episodios': itemlist.append( Item(channel='downloads', @@ -946,8 +962,9 @@ def download(itemlist, item, typography='', function_level=1, function=''): from_action=from_action, contentTitle=contentTitle, download='season', - thumbnail=thumb(thumb='downloads.png') - )) + thumbnail=thumb(thumb='downloads.png'), + downloadItemlist=downloadItemlist + )) return itemlist @@ -985,18 +1002,20 @@ def videolibrary(itemlist, item, typography='', function_level=1, function=''): if (function == 'findvideos' and contentType == 'movie') \ or (function == 'episodios' and contentType != 'movie'): if config.get_videolibrary_support() and len(itemlist) > 0: + from channelselector import get_thumb itemlist.append( Item(channel=item.channel, title=title, fulltitle=item.fulltitle, show=item.fulltitle, contentType=contentType, + contentTitle=contentTitle, contentSerieName=contentSerieName, url=item.url, action=action, extra=extra, - contentTitle=contentTitle, - path=item.path + path=item.path, + thumbnail=get_thumb('add_to_videolibrary.png') )) return itemlist @@ -1038,7 +1057,7 @@ def pagination(itemlist, item, page, perpage, function_level=1): thumbnail=thumb())) return itemlist -def server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=True, down_load=True, patronTag=None): +def server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=True, down_load=True, patronTag=None, video_library=True): if not data and not itemlist: data = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data @@ -1068,7 +1087,7 @@ def server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=Tru item.title = typo(item.contentTitle.strip(),'bold') if item.contentType == 'movie' or (config.get_localized_string(30161) in item.title) else item.title videoitem.plot= typo(videoitem.title, 'bold') + typo(videoitem.quality, '_ [] bold') - videoitem.title = item.title + (typo(videoitem.title, '_ color kod [] bold') if videoitem.title else "") + (typo(videoitem.quality, '_ color kod []') if videoitem.quality else "") + videoitem.title = (item.title if item.channel not in ['url'] else '') + (typo(videoitem.title, '_ color kod [] bold') if videoitem.title else "") + (typo(videoitem.quality, '_ color kod []') if videoitem.quality else "") videoitem.fulltitle = item.fulltitle videoitem.show = item.show videoitem.thumbnail = item.thumbnail @@ -1078,9 +1097,9 @@ def server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=Tru if patronTag: addQualityTag(item, verifiedItemlist, data, patronTag) - return controls(verifiedItemlist, item, AutoPlay, CheckLinks, down_load) + return controls(verifiedItemlist, item, AutoPlay, CheckLinks, down_load, video_library) -def controls(itemlist, item, AutoPlay=True, CheckLinks=True, down_load=True): +def controls(itemlist, item, AutoPlay=True, CheckLinks=True, down_load=True, video_library=True): from core import jsontools from platformcode.config import get_setting @@ -1088,13 +1107,17 @@ def controls(itemlist, item, AutoPlay=True, CheckLinks=True, down_load=True): autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY') channel_node = autoplay_node.get(item.channel, {}) if not channel_node: # non ha mai aperto il menu del canale quindi in autoplay_data.json non c'e la key - channelFile = __import__('channels.' + item.channel, fromlist=["channels.%s" % item.channel]) - autoplay.init(item.channel, channelFile.list_servers, channelFile.list_quality) + try: + channelFile = __import__('channels.' + item.channel, fromlist=["channels.%s" % item.channel]) + except: + channelFile = __import__('specials.' + item.channel, fromlist=["specials.%s" % item.channel]) + if hasattr(channelFile, 'list_servers') and hasattr(channelFile, 'list_quality'): + autoplay.init(item.channel, channelFile.list_servers, channelFile.list_quality) autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY') channel_node = autoplay_node.get(item.channel, {}) settings_node = channel_node.get('settings', {}) - AP = get_setting('autoplay') or settings_node['active'] + AP = get_setting('autoplay') or (settings_node['active'] if 'active' in settings_node else False) HS = config.get_setting('hide_servers') or (settings_node['hide_servers'] if 'hide_server' in settings_node else False) if CL and not AP: @@ -1109,7 +1132,7 @@ def controls(itemlist, item, AutoPlay=True, CheckLinks=True, down_load=True): if AutoPlay == True and not 'downloads' in inspect.stack()[3][1] + inspect.stack()[4][1]: autoplay.start(itemlist, item) - if item.contentChannel != 'videolibrary': videolibrary(itemlist, item, function_level=3) + if item.contentChannel != 'videolibrary' and video_library: videolibrary(itemlist, item, function_level=3) if get_setting('downloadenabled') and down_load == True: download(itemlist, item, function_level=3) VL = False @@ -1156,7 +1179,7 @@ def channel_config(item, itemlist): itemlist.append( Item(channel='setting', action="channel_config", - title=typo("Configurazione Canale color kod bold"), + title=typo(config.get_localized_string(60587), 'color kod bold'), config=item.channel, folder=False, thumbnail=get_thumb('setting_0.png')) @@ -1197,6 +1220,8 @@ def addQualityTag(item, itemlist, data, patron): "DLMux": "si tratta di un 720p o 1080p reperiti dalla versione americana di iTunes americano. La qualità è paragonabile a quella di un BluRayRip e permette di fruire di episodi televisivi, senza il fastidioso bollo distintivo della rete che trasmette.", "DVD5": "il film è in formato DVD Single Layer, nel quale vengono mantenute tutte le caratteristiche del DVD originale: tra queste il menu multilingue, i sottotitoli e i contenuti speciali, se presenti. Il video è codificato nel formato DVD originale MPEG-2.", "DVD9": "ha le stesse caratteristiche del DVD5, ma le dimensioni del file sono di un DVD Dual Layer (8,5 GB).", + "HDTS": "viene utilizzata una videocamera professionale ad alta definizione posizionata in modo fisso. La qualità audio video è buona.", + "DVDMUX": "indica una buona qualità video, l’audio è stato aggiunto da una sorgente diversa per una migliore qualità.", } defQualAudio = { @@ -1206,6 +1231,7 @@ def addQualityTag(item, itemlist, data, patron): "DD": "audio ricavato dai dischi DTS cinema. L’audio è di buona qualità, ma potreste riscontrare il fatto che non potrebbe essere più riproducibile.", "AC3": "audio in Dolby Digital puo' variare da 2.0 a 5.1 canali in alta qualità.", "MP3": "codec per compressione audio utilizzato MP3.", + "RESYNC": "il film è stato lavorato e re sincronizzato con una traccia audio. A volte potresti riscontrare una mancata sincronizzazione tra audio e video.", } qualityStr = scrapertools.find_single_match(data, patron).strip() if PY3: @@ -1215,7 +1241,9 @@ def addQualityTag(item, itemlist, data, patron): if qualityStr: try: - audio, video = qualityStr.split('.') + splitted = qualityStr.split('.') + video = splitted[-1] + audio = splitted[-2] descr = typo(video + ': ', 'color kod') + defQualVideo.get(video.upper(), '') + '\n' +\ typo(audio + ': ', 'color kod') + defQualAudio.get(audio.upper(), '') except: diff --git a/core/tmdb.py b/core/tmdb.py index d306a392..0e3c137e 100644 --- a/core/tmdb.py +++ b/core/tmdb.py @@ -32,8 +32,8 @@ from core.item import InfoLabels from platformcode import config from platformcode import logger -addon = xbmcaddon.Addon('metadata.themoviedb.org') -def_lang = addon.getSetting('language') +info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json +def_lang = info_language[config.get_setting("info_language", "videolibrary")] # ----------------------------------------------------------------------------------------------------------- # Conjunto de funciones relacionadas con las infoLabels. diff --git a/core/tvdb.py b/core/tvdb.py index d1ae5b5c..f5674d69 100644 --- a/core/tvdb.py +++ b/core/tvdb.py @@ -25,11 +25,9 @@ from platformcode import platformtools HOST = "https://api.thetvdb.com" HOST_IMAGE = "http://thetvdb.com/banners/" -import xbmcaddon -addon = xbmcaddon.Addon('metadata.tvdb.com') - TOKEN = config.get_setting("tvdb_token", default="") -DEFAULT_LANG = addon.getSetting('language') +info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json +DEFAULT_LANG = info_language[config.get_setting("info_language", "videolibrary")] DEFAULT_HEADERS = { 'Content-Type': 'application/json', 'Accept': 'application/json, application/vnd.thetvdb.v2.1.1', diff --git a/core/videolibrarytools.py b/core/videolibrarytools.py index 04e38173..40292408 100644 --- a/core/videolibrarytools.py +++ b/core/videolibrarytools.py @@ -130,7 +130,7 @@ def save_movie(item): # progress dialog p_dialog = platformtools.dialog_progress(config.get_localized_string(20000), config.get_localized_string(60062)) - if config.get_setting("original_title_folder", "videolibrary") == 1 and item.infoLabels['originaltitle']: + if config.get_setting("original_title_folder", "videolibrary") and item.infoLabels['originaltitle']: base_name = item.infoLabels['originaltitle'] else: base_name = item.contentTitle @@ -140,7 +140,7 @@ def save_movie(item): else: base_name = filetools.validate_path(base_name.replace('/', '-')) - if config.get_setting("lowerize_title", "videolibrary") == 0: + if config.get_setting("lowerize_title", "videolibrary"): base_name = base_name.lower() for raiz, subcarpetas, ficheros in filetools.walk(MOVIES_PATH): @@ -221,7 +221,7 @@ def save_movie(item): if filetools.write(nfo_path, head_nfo + item_nfo.tojson()): #logger.info("FOLDER_MOVIES : %s" % FOLDER_MOVIES) # actualizamos la videoteca de Kodi con la pelicula - if config.is_xbmc(): + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): from platformcode import xbmc_videolibrary xbmc_videolibrary.update() @@ -234,12 +234,55 @@ def save_movie(item): p_dialog.close() return 0, 0, -1 +def update_renumber_options(item, head_nfo, path): + from core import jsontools + # from core.support import dbg;dbg() + tvshow_path = filetools.join(path, 'tvshow.nfo') + if filetools.isfile(tvshow_path) and item.channel_prefs: + for channel in item.channel_prefs: + filename = filetools.join(config.get_data_path(), "settings_channels", channel + '_data.json') + + json_file = jsontools.load(filetools.read(filename)) + if 'TVSHOW_AUTORENUMBER' in json_file: + json = json_file['TVSHOW_AUTORENUMBER'] + if item.fulltitle in json: + item.channel_prefs[channel]['TVSHOW_AUTORENUMBER'] = json[item.fulltitle] + logger.info('UPDATED=\n' + str(item.channel_prefs)) + filetools.write(tvshow_path, head_nfo + item.tojson()) + +def add_renumber_options(item, head_nfo, path): + from core import jsontools + # from core.support import dbg;dbg() + ret = None + filename = filetools.join(config.get_data_path(), "settings_channels", item.channel + '_data.json') + json_file = jsontools.load(filetools.read(filename)) + if 'TVSHOW_AUTORENUMBER' in json_file: + json = json_file['TVSHOW_AUTORENUMBER'] + if item.fulltitle in json: + ret = json[item.fulltitle] + return ret + +def check_renumber_options(item): + from specials.autorenumber import load, write + for key in item.channel_prefs: + if 'TVSHOW_AUTORENUMBER' in item.channel_prefs[key]: + item.channel = key + json = load(item) + if not json or item.fulltitle not in json: + json[item.fulltitle] = item.channel_prefs[key]['TVSHOW_AUTORENUMBER'] + write(item, json) + + # head_nfo, tvshow_item = read_nfo(filetools.join(item.context[0]['nfo'])) + # if tvshow_item['channel_prefs'][item.fullti] + + def filter_list(episodelist, action=None, path=None): # if path: path = path.decode('utf8') # import xbmc # if xbmc.getCondVisibility('system.platform.windows') > 0: path = path.replace('smb:','').replace('/','\\') channel_prefs = {} lang_sel = quality_sel = show_title = channel ='' + # from core.support import dbg;dbg() if action: tvshow_path = filetools.join(path, "tvshow.nfo") head_nfo, tvshow_item = read_nfo(tvshow_path) @@ -253,8 +296,13 @@ def filter_list(episodelist, action=None, path=None): filetools.remove(filetools.join(path, File)) if channel not in tvshow_item.channel_prefs: tvshow_item.channel_prefs[channel] = {} + channel_prefs = tvshow_item.channel_prefs[channel] + renumber = add_renumber_options(episodelist[0], head_nfo, tvshow_path) + if renumber: + channel_prefs['TVSHOW_AUTORENUMBER'] = renumber + if action == 'get_seasons': if 'favourite_language' not in channel_prefs: channel_prefs['favourite_language'] = '' @@ -418,7 +466,7 @@ def save_tvshow(item, episodelist): + ' / ' + item.infoLabels['code']) return 0, 0, -1, path - if config.get_setting("original_title_folder", "videolibrary") == 1 and item.infoLabels['originaltitle']: + if config.get_setting("original_title_folder", "videolibrary") and item.infoLabels['originaltitle']: base_name = item.infoLabels['originaltitle'] elif item.infoLabels['tvshowtitle']: base_name = item.infoLabels['tvshowtitle'] @@ -432,7 +480,7 @@ def save_tvshow(item, episodelist): else: base_name = filetools.validate_path(base_name.replace('/', '-')) - if config.get_setting("lowerize_title", "videolibrary") == 0: + if config.get_setting("lowerize_title", "videolibrary"): base_name = base_name.lower() for raiz, subcarpetas, ficheros in filetools.walk(TVSHOWS_PATH): @@ -490,7 +538,7 @@ def save_tvshow(item, episodelist): item_tvshow.library_filter_show = {item.channel: item.show} if item.channel != "downloads": - item_tvshow.active = 1 # para que se actualice a diario cuando se llame a videolibrary_service + item_tvshow.active = 1 # para que se actualice a diario cuando se llame a service filetools.write(tvshow_path, head_nfo + item_tvshow.tojson()) @@ -554,7 +602,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): nostrm_episodelist.append(season_episode) nostrm_episodelist = sorted(set(nostrm_episodelist)) - # Silent es para no mostrar progreso (para videolibrary_service) + # Silent es para no mostrar progreso (para service) if not silent: # progress dialog p_dialog = platformtools.dialog_progress(config.get_localized_string(20000), config.get_localized_string(60064)) @@ -571,16 +619,11 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): new_episodelist = [] # Obtenemos el numero de temporada y episodio y descartamos los q no lo sean - tags = [] - if config.get_setting("enable_filter", "videolibrary"): - tags = [x.strip() for x in config.get_setting("filters", "videolibrary").lower().split(",")] for e in episodelist: headers = {} if e.headers: headers = e.headers - if tags != [] and tags != None and any(tag in e.title.lower() for tag in tags): - continue try: season_episode = scrapertools.get_season_and_episode(e.title) @@ -659,7 +702,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): json_path = filetools.join(path, ("%s [%s].json" % (season_episode, e.channel)).lower()) if season_episode in nostrm_episodelist: - logger.error('Error in the structure of the Video Library: Seriese ' + serie.contentSerieName + ' ' + season_episode) + logger.info('Skipped: Serie ' + serie.contentSerieName + ' ' + season_episode + ' available as local content') continue strm_exists = strm_path in ficheros nfo_exists = nfo_path in ficheros @@ -789,7 +832,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): fallidos = -1 else: # ... si ha sido correcto actualizamos la videoteca de Kodi - if config.is_xbmc() and not silent: + if config.is_xbmc() and config.get_setting("videolibrary_kodi") and not silent: from platformcode import xbmc_videolibrary xbmc_videolibrary.update() @@ -834,11 +877,11 @@ def add_movie(item): insertados, sobreescritos, fallidos = save_movie(new_item) if fallidos == 0: - platformtools.dialog_ok(config.get_localized_string(30131), new_item.contentTitle, - config.get_localized_string(30135)) # 'se ha añadido a la videoteca' + platformtools.dialog_ok(config.get_localized_string(30131), + config.get_localized_string(30135) % new_item.contentTitle) # 'se ha añadido a la videoteca' else: platformtools.dialog_ok(config.get_localized_string(30131), - config.get_localized_string(60066)) #"ERROR, la pelicula NO se ha añadido a la videoteca") + config.get_localized_string(60066) % new_item.contentTitle) #"ERROR, la pelicula NO se ha añadido a la videoteca") def add_tvshow(item, channel=None): @@ -906,20 +949,20 @@ def add_tvshow(item, channel=None): insertados, sobreescritos, fallidos, path = save_tvshow(item, itemlist) if not insertados and not sobreescritos and not fallidos: - platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60067)) - logger.error("The %s series could not be added to the video library. Could not get any episode" % item.show) + platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60067) % item.show) + logger.error("La serie %s no se ha podido añadir a la videoteca. No se ha podido obtener ningun episodio" % item.show) elif fallidos == -1: - platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60068)) - logger.error("The %s series could not be added to the video library" % item.show) + platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60068) % item.show) + logger.error("La serie %s no se ha podido añadir a la videoteca" % item.show) elif fallidos > 0: - platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60069)) - logger.error("Could not add %s episodes of the %s series to the video library" % (fallidos, item.show)) + platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60069) % item.show) + logger.error("No se han podido añadir %s episodios de la serie %s a la videoteca" % (fallidos, item.show)) else: - platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60070)) - logger.info("%s episodes of the %s series have been added to the video library" % (insertados, item.show)) + platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60070) % item.show) + logger.info("Se han añadido %s episodios de la serie %s a la videoteca" % (insertados, item.show)) if config.is_xbmc(): if config.get_setting("sync_trakt_new_tvshow", "videolibrary"): import xbmc diff --git a/core/ziptools.py b/core/ziptools.py index ad3a88e7..1154e8f7 100644 --- a/core/ziptools.py +++ b/core/ziptools.py @@ -104,3 +104,14 @@ class ziptools(object): dirs.sort() return dirs + + def zip(self, dir, file): + import os + zf = zipfile.ZipFile(file, "w", zipfile.ZIP_DEFLATED) + abs_src = os.path.abspath(dir) + for dirname, subdirs, files in os.walk(dir): + for filename in files: + absname = os.path.abspath(os.path.join(dirname, filename)) + arcname = absname[len(abs_src) + 1:] + zf.write(absname, arcname) + zf.close() \ No newline at end of file diff --git a/default.py b/default.py index b0285886..7ed2cc72 100644 --- a/default.py +++ b/default.py @@ -14,10 +14,6 @@ logger.info("init...") librerias = xbmc.translatePath(os.path.join(config.get_runtime_path(), 'lib')) sys.path.insert(0, librerias) -if not config.dev_mode(): - from platformcode import updater - updater.showSavedChangelog() - from platformcode import launcher if sys.argv[2] == "": diff --git a/lib/generictools.py b/lib/generictools.py index e93a1b1e..bca3395e 100644 --- a/lib/generictools.py +++ b/lib/generictools.py @@ -1822,11 +1822,11 @@ def redirect_clone_newpct1(item, head_nfo=None, it=None, path=False, overwrite=F # - patron5: expresión Regex aplicable a la url (opcional) # - content_inc: contenido al que aplica esta entrada, o * (item.contentType o item.extra) # - content_exc: contenido que se excluye de esta entrada (item.contentType) (opcional). opción para 'emerg' - # - ow_force: indicador para la acción de "videolibrary_service.py". Puede crear la variable item.ow_force: - # - force: indica al canal que analize toda la serie y que videolibrary_service la reescriba - # - auto: indica a videolibrary_service que la reescriba - # - no: no acción para videolibrary_service, solo redirige en visionado de videolibrary - # - del: borra las estrucuturas de un determinado canal en videolibrary_service, quizás creadas por errores de un canal + # - ow_force: indicador para la acción de "service.py". Puede crear la variable item.ow_force: + # - force: indica al canal que analize toda la serie y que service la reescriba + # - auto: indica a service que la reescriba + # - no: no acción para service, solo redirige en visionado de videolibrary + # - del: borra las estrucuturas de un determinado canal en service, quizás creadas por errores de un canal # - emerg: funcionalidad muy similar a la de "del". se general dinámicamente cada vez que entra un canal con el estado activado en el .json de "emergency_urls". Permite cargar las urls de emergencia en todos los elementos existentes de la Videoteca para canal afectado # ejemplos: # ('1', 'mejortorrent', 'mejortorrent1', 'http://www.mejortorrent.com/', 'https://mejortorrent1.com/', '(http.?:\/\/.*?\/)', 'http.?:\/\/.*?\/.*?-torrent.?-[^-]+-(?:[^-]+-)([^0-9]+-)', 'http.?:\/\/.*?\/.*?-torrent.?-[^-]+-(?:[^-]+-)[^0-9]+-\\d+-(Temporada-).html', 'http.?:\/\/.*?\/.*?-torrent.?-[^-]+-(?:[^-]+-)[^0-9]+-(\\d+)-', '', 'tvshow, season', '', 'force'), @@ -1835,7 +1835,7 @@ def redirect_clone_newpct1(item, head_nfo=None, it=None, path=False, overwrite=F # ('1', 'newpct1', '', '', '', '', '', '', '', '', '*', '', 'del'), # ('1', 'torrentrapid', 'torrentrapid', '', '', '', '', '', '', '', '*', '1 ó 2', 'emerg'), # - # La llamada recibe el parámetro Item, el .nfo y los devuleve actualizados, así como opcionalmente el parámetro "overwrite· que puede forzar la reescritura de todos los archivos de la serie, y el parámetro "path" si viene de videolibrary_service. Por último, recibe opcionalmente el parámetro "lookup" si se quiere solo averigurar si habrá migración para ese título, pero sin realizarla. + # La llamada recibe el parámetro Item, el .nfo y los devuleve actualizados, así como opcionalmente el parámetro "overwrite· que puede forzar la reescritura de todos los archivos de la serie, y el parámetro "path" si viene de service. Por último, recibe opcionalmente el parámetro "lookup" si se quiere solo averigurar si habrá migración para ese título, pero sin realizarla. # # """ # #logger.debug(item) diff --git a/lib/megaserver/client.py b/lib/megaserver/client.py index 239f5158..a39c6cb0 100644 --- a/lib/megaserver/client.py +++ b/lib/megaserver/client.py @@ -179,13 +179,13 @@ class Client(object): return self.base64urlencode(self.a32_to_str(a)) def aes_cbc_decrypt(self, data, key): - try: - from Cryptodome.Cipher import AES - decryptor = AES.new(key, AES.MODE_CBC, '\0' * 16) - except: - from Crypto.Cipher import AES - decryptor = AES.new(key, AES.MODE_CBC, '\0' * 16) - return decryptor.decrypt(data) + from lib import pyaes + decryptor = pyaes.AESModeOfOperationCBC(key, '\0' * 16) + decrypted = '' + for p in range(0, len(data), 16): + decrypted += decryptor.decrypt(data[p:p + 16]).replace('\0', '') + logger.info(decrypted) + return decrypted def aes_cbc_decrypt_a32(self,data, key): return self.str_to_a32(self.aes_cbc_decrypt(self.a32_to_str(data), self.a32_to_str(key))) diff --git a/lib/python_libtorrent/python_libtorrent/__init__.py b/lib/python_libtorrent/python_libtorrent/__init__.py index d916ebd7..a0a8485e 100644 --- a/lib/python_libtorrent/python_libtorrent/__init__.py +++ b/lib/python_libtorrent/python_libtorrent/__init__.py @@ -32,38 +32,27 @@ from .functions import * import xbmc, xbmcaddon import sys import os -import traceback ### Alfa +import traceback - -#__settings__ = xbmcaddon.Addon(id='script.module.libtorrent') ### Alfa -#__version__ = __settings__.getAddonInfo('version') ### Alfa -#__plugin__ = __settings__.getAddonInfo('name') + " v." + __version__ ### Alfa -#__settings__ = xbmcaddon.Addon(id='plugin.video.kod') ### Alfa -__version__ = '1.1.17' ### Alfa -__plugin__ = "python-libtorrent v.1.1.7" ### Alfa -#__language__ = __settings__.getLocalizedString ### Alfa +__version__ = '1.1.17' +__plugin__ = "python-libtorrent v.1.1.7" __root__ = os.path.dirname(os.path.dirname(__file__)) libtorrent=None platform = get_platform() -#set_dirname=__settings__.getSetting('dirname') ### Alfa -#set_dirname=os.path.join(__settings__.getAddonInfo('Path'),'lib', 'python_libtorrent') ### Alfa -set_dirname=__root__ ### Alfa +set_dirname=__root__ if getSettingAsBool('custom_dirname') and set_dirname: log('set_dirname:' +str(set_dirname)) dirname=set_dirname else: - #dirname = os.path.join(xbmc.translatePath('special://temp'), 'xbmcup', 'script.module.libtorrent', - # 'python_libtorrent') - dirname=set_dirname ### Alfa + dirname=set_dirname log('dirname: ' +str(dirname)) -#versions = ['0.16.19', '1.0.6', '1.0.7', '1.0.8', '1.0.9', '1.0.11', '1.1.0', '1.1.1', '1.1.6', '1.1.7', '1.2.2', '1.2.3'] ### Alfa -versions = ['0.16.19', '1.0.6', '1.0.7', '1.0.8', '1.0.9', '1.0.11', '1.1.0', '1.1.1', '1.1.6', '1.1.7', '1.2.2'] ### Alfa +#versions = ['0.16.19', '1.0.6', '1.0.7', '1.0.8', '1.0.9', '1.0.11', '1.1.0', '1.1.1', '1.1.6', '1.1.7', '1.2.2', '1.2.3'] +versions = ['0.16.19', '1.0.6', '1.0.7', '1.0.8', '1.0.9', '1.0.11', '1.1.0', '1.1.1', '1.1.6', '1.1.7', '1.2.2'] default_path = versions[-1] -#set_version = int(__settings__.getSetting('set_version')) ### Alfa -set_version = 0 ### Alfa +set_version = 0 if getSettingAsBool('custom_version'): log('set_version:' +str(set_version)+' '+versions[set_version]) platform['version'] = versions[set_version] @@ -101,12 +90,8 @@ if not lm.check_exist(): xbmc.sleep(2000) -#if __settings__.getSetting('plugin_name')!=__plugin__: ### Alfa -# __settings__.setSetting('plugin_name', __plugin__) ### Alfa -# lm.update() ### Alfa - log('platform: ' + str(platform)) -if platform['system'] not in ['windows', 'windows_x64']: ### Alfa +if platform['system'] not in ['windows', 'windows_x64']: log('os: '+str(os.uname())) log_text = 'ucs4' if sys.maxunicode > 65536 else 'ucs2' log_text += ' x64' if sys.maxsize > 2147483647 else ' x86' @@ -118,18 +103,18 @@ try: description = '' libtorrent = '' from platformcode import config - + if platform['system'] in ['linux_x86', 'windows', 'windows_x64', 'linux_armv6', 'linux_armv7', 'linux_x86_64', 'linux_mipsel_ucs2', 'linux_mipsel_ucs4', - 'linux_aarch64_ucs2', 'linux_aarch64_ucs4']: ### Alfa + 'linux_aarch64_ucs2', 'linux_aarch64_ucs4']: import libtorrent - + elif PY3 and platform['system'] not in ['android_armv7', 'android_x86']: - import libtorrent ### Alfa - + import libtorrent + elif platform['system'] in ['darwin', 'ios_arm']: import imp - + path_list = [dest_path] log('path_list = ' + str(path_list)) fp, pathname, description = imp.find_module('libtorrent', path_list) @@ -140,12 +125,12 @@ try: libtorrent = imp.load_module('libtorrent', fp, pathname, description) finally: if fp: fp.close() - + elif platform['system'] in ['android_armv7', 'android_x86']: try: import imp from ctypes import CDLL - + dest_path=lm.android_workaround(os.path.join(xbmc.translatePath('special://xbmc/'), 'files').replace('/cache/apk/assets', '')) dll_path=os.path.join(dest_path, 'liblibtorrent.so') log('CDLL path = ' + dll_path) @@ -164,8 +149,8 @@ try: except Exception as e: if not PY3: e = unicode(str(e), "utf8", errors="replace").encode("utf8") - config.set_setting("libtorrent_path", "", server="torrent") ### Alfa - config.set_setting("libtorrent_error", str(e), server="torrent") ### Alfa + config.set_setting("libtorrent_path", "", server="torrent") + config.set_setting("libtorrent_error", str(e), server="torrent") log(traceback.format_exc(1)) log('fp = ' + str(fp)) log('pathname = ' + str(pathname)) @@ -174,7 +159,7 @@ try: if fp: fp.close() # If no permission in dest_path we need to go deeper on root! - try: ### Alfa START + try: sys_path = '/data/app/' fp = '' pathname = sys_path @@ -186,7 +171,7 @@ try: dialog = xbmcgui.Dialog() dialog.notification('KoD: '+ config.get_localizad_string(70766), config.get_localizad_string(70767), time=15000) config.set_setting("libtorrent_msg", 'OK', server="torrent") - + from core import scrapertools kodi_app = xbmc.translatePath('special://xbmc') kodi_app = scrapertools.find_single_match(kodi_app, '\/\w+\/\w+\/.*?\/(.*?)\/') @@ -201,10 +186,10 @@ try: output_cmd, error_cmd = p.communicate() log('Comando ROOT: %s' % str(command)) dir_list = output_cmd.split() - + if not dir_list: raise - + for file in dir_list: if kodi_app in file: kodi_dir = file @@ -228,12 +213,12 @@ try: if fp: fp.close() else: import libtorrent - + except Exception as e: log('ERROR Comando ROOT: %s, %s' % (str(command), str(dest_path))) if not PY3: e = unicode(str(e), "utf8", errors="replace").encode("utf8") - log(traceback.format_exc(1)) ### Alfa + log(traceback.format_exc(1)) log('fp = ' + str(fp)) log('pathname = ' + str(pathname)) log('description = ' + str(description)) @@ -241,15 +226,15 @@ try: if fp: fp.close() if libtorrent: - config.set_setting("libtorrent_path", dest_path, server="torrent") ### Alfa - config.set_setting("libtorrent_error", "", server="torrent") ### Alfa + config.set_setting("libtorrent_path", dest_path, server="torrent") + config.set_setting("libtorrent_error", "", server="torrent") log('Imported libtorrent v' + libtorrent.version + ' from "' + dest_path + '"') except Exception as e: if not PY3: e = unicode(str(e), "utf8", errors="replace").encode("utf8") - config.set_setting("libtorrent_path", "", server="torrent") ### Alfa - config.set_setting("libtorrent_error", str(e), server="torrent") ### Alfa + config.set_setting("libtorrent_path", "", server="torrent") + config.set_setting("libtorrent_error", str(e), server="torrent") log('Error importing libtorrent from "' + dest_path + '". Exception: ' + str(e)) if fp: fp.close() diff --git a/platformcode/config.py b/platformcode/config.py index 8a725ae9..da864ace 100644 --- a/platformcode/config.py +++ b/platformcode/config.py @@ -18,6 +18,8 @@ PLUGIN_NAME = "kod" __settings__ = xbmcaddon.Addon(id="plugin.video." + PLUGIN_NAME) __language__ = __settings__.getLocalizedString +__version_fix = None +__dev_mode = None channels_data = list() @@ -36,19 +38,25 @@ def get_addon_version(with_fix=True): def get_addon_version_fix(): - if not dev_mode(): - try: - sha = open(os.path.join(get_runtime_path(), 'last_commit.txt')).readline() - return sha[:7] - except: - return '??' - else: - return 'DEV' + global __version_fix + ret = __version_fix + if not ret: + if not dev_mode(): + try: + sha = open(os.path.join(get_runtime_path(), 'last_commit.txt')).readline() + ret = sha[:7] + except: + ret = '??' + else: + ret = 'DEV' + return ret def dev_mode(): - r = os.path.isdir(get_runtime_path() + '/.git') - return r + global __dev_mode + if not __dev_mode: + __dev_mode = os.path.isdir(get_runtime_path() + '/.git') + return __dev_mode def get_platform(full_version=False): @@ -152,6 +160,7 @@ def enable_disable_autorun(is_enabled): if is_enabled is False: with open(path, append_write) as file: file.write("import xbmc\nxbmc.executebuiltin('XBMC.RunAddon(plugin.video.kod)')") + set_setting('autostart', 'On') else: file = open(path, "r") old_content = file.read() @@ -159,6 +168,7 @@ def enable_disable_autorun(is_enabled): file.close() with open(path, "w") as file: file.write(new_content) + set_setting('autostart', 'Off') return True def get_all_settings_addon(): @@ -170,7 +180,7 @@ def get_all_settings_addon(): infile.close() ret = {} - matches = scrapertools.find_multiple_matches(data, '<setting id="([^"]*)" value="([^"]*)') + matches = scrapertools.find_multiple_matches(data, '<setting id=\"([^\"]+)\"[^>]*>([^<]*)</setting>') for _id, value in matches: ret[_id] = get_setting(_id) @@ -217,19 +227,25 @@ def open_settings(): set_setting('adult_aux_new_password1', '') set_setting('adult_aux_new_password2', '') + from specials import videolibrary + from platformcode import xbmc_videolibrary + if settings_pre.get('downloadpath', None) != settings_post.get('downloadpath', None): + xbmc_videolibrary.update_sources(settings_post.get('downloadpath', None), settings_pre.get('downloadpath', None)) + # si se ha cambiado la ruta de la videoteca llamamos a comprobar directorios para que lo cree y pregunte # automaticamente si configurar la videoteca if settings_pre.get("videolibrarypath", None) != settings_post.get("videolibrarypath", None) or \ - settings_pre.get("folder_movies", None) != settings_post.get("folder_movies", None) or \ - settings_pre.get("folder_tvshows", None) != settings_post.get("folder_tvshows", None): - verify_directories_created() + settings_pre.get("folder_movies", None) != settings_post.get("folder_movies", None) or \ + settings_pre.get("folder_tvshows", None) != settings_post.get("folder_tvshows", None): + videolibrary.move_videolibrary(settings_pre.get("videolibrarypath", None), settings_post.get("videolibrarypath", None), + settings_pre.get("folder_movies", None), settings_post.get("folder_movies", None), + settings_pre.get("folder_tvshows", None), settings_post.get("folder_tvshows", None)) - else: - # si se ha puesto que se quiere autoconfigurar y se había creado el directorio de la videoteca - if not settings_pre.get("videolibrary_kodi", None) and settings_post.get("videolibrary_kodi", None) \ - and settings_post.get("videolibrary_kodi_flag", None) == 1: - from platformcode import xbmc_videolibrary - xbmc_videolibrary.ask_set_content(2, silent=True) + # si se ha puesto que se quiere autoconfigurar y se había creado el directorio de la videoteca + if not settings_pre.get("videolibrary_kodi", None) and settings_post.get("videolibrary_kodi", None): + xbmc_videolibrary.ask_set_content(silent=True) + elif settings_pre.get("videolibrary_kodi", None) and not settings_post.get("videolibrary_kodi", None): + xbmc_videolibrary.clean(get_setting('videolibrarypath')) def get_setting(name, channel="", server="", default=None): @@ -378,8 +394,10 @@ def get_localized_string(code): def get_localized_category(categ): categories = {'movie': get_localized_string(30122), 'tvshow': get_localized_string(30123), 'anime': get_localized_string(30124), 'documentary': get_localized_string(30125), - 'vos': get_localized_string(30136), 'sub-ita': get_localized_string(70566), 'adult': get_localized_string(30126), - 'direct': get_localized_string(30137), 'torrent': get_localized_string(70015), 'live': get_localized_string(30138)} + 'vos': get_localized_string(30136), 'sub-ita': get_localized_string(70566), + 'adult': get_localized_string(30126), 'direct': get_localized_string(30137), + 'torrent': get_localized_string(70015), 'live': get_localized_string(30138), + 'music': get_localized_string(30139) } return categories[categ] if categ in categories else categ @@ -463,8 +481,8 @@ def verify_directories_created(): logger.debug("Creating %s: %s" % (path, saved_path)) filetools.mkdir(saved_path) - config_paths = [["folder_movies", "CINE"], - ["folder_tvshows", "SERIES"]] + config_paths = [["folder_movies", "Film"], + ["folder_tvshows", "Serie TV"]] for path, default in config_paths: saved_path = get_setting(path) @@ -480,6 +498,10 @@ def verify_directories_created(): # si se crea el directorio filetools.mkdir(content_path) + from platformcode import xbmc_videolibrary + xbmc_videolibrary.update_sources(get_setting("videolibrarypath")) + xbmc_videolibrary.update_sources(get_setting("downloadpath")) + try: from core import scrapertools # Buscamos el archivo addon.xml del skin activo diff --git a/platformcode/custom_code.py b/platformcode/custom_code.py index 4bbde9bc..46ce5009 100644 --- a/platformcode/custom_code.py +++ b/platformcode/custom_code.py @@ -28,36 +28,36 @@ def init(): """ Todo el código añadido al add-on se borra con cada actualización. Esta función permite restaurarlo automáticamente con cada actualización. Esto permite al usuario tener su propio código, bajo su responsabilidad, y restaurarlo al add-on cada vez que se actualiza. - + El mecanismo funciona copiando el contenido de la carpeta-arbol "./userdata/addon_data/plugin.video.kod/custom_code/..." sobre las carpetas de código del add-on. No verifica el contenido, solo vuelca(reemplaza) el contenido de "custom_code". - + El usuario almacenará en las subcarpetas de "custom_code" su código actualizado y listo para ser copiado en cualquier momento. Si no se desea que copie algo, simplemente se borra de "custom_code" y ya no se copiará en la próxima actualización. - + Los pasos que sigue esta función, son los siguientes: - - 1.- La función se llama desde videolibrary_service.py, desde la función inicial: + + 1.- La función se llama desde service.py, desde la función inicial: # Copia Custom code a las carpetas de Alfa desde la zona de Userdata from platformcode import custom_code custom_code.init() - - 2.- En el inicio de Kodi, comprueba si existe la carpeta "custom_code" en "./userdata/addon_data/plugin.video.kod/". - Si no existe, la crea y sale sin más, dando al ususario la posibilidad de copiar sobre esa estructura su código, + + 2.- En el inicio de Kodi, comprueba si existe la carpeta "custom_code" en "./userdata/addon_data/plugin.video.kod/". + Si no existe, la crea y sale sin más, dando al ususario la posibilidad de copiar sobre esa estructura su código, y que la función la vuelque sobre el add-on en el próximo inicio de Kodi. - + 3.- En el siguiente inicio de Kodi, comprueba si existe el custom_code.json en la carpeta root del add-on. Si no existe, lo crea con el número de versión del add-on vacío, para permitir que se copien los archivos en esta pasada. - - 4.- Verifica que el número de versión del add-on es diferente de el de custom_code.json. Si es la misma versión, + + 4.- Verifica que el número de versión del add-on es diferente de el de custom_code.json. Si es la misma versión, se sale porque ya se realizo la copia anteriormente. Si la versión es distinta, se realiza el volcado de todos los archivos de la carpeta-árbol "custom_code" sobre el add-on. Si la carpeta de destino no existe, dará un error y se cancelará la copia. Se considera que no tienen sentido nuevas carpetas. - + 5.- Si la copia ha terminado con éxito, se actualiza el custom_code.json con el número de versión del add-on, para que en inicios sucesivos de Kodi no se realicen las copias, hasta que el add-on cambie de versión. En el número de versión del add-on no se considera el número de fix. - + Tiempos: Copiando 7 archivos de prueba, el proceso ha tardado una décima de segundo. """ @@ -65,47 +65,47 @@ def init(): #Borra el .zip de instalación de Alfa de la carpeta Packages, por si está corrupto, y que así se pueda descargar de nuevo version = 'plugin.video.kod-%s.zip' % config.get_addon_version(with_fix=False) filetools.remove(filetools.join(xbmc.translatePath('special://home'), 'addons', 'packages', version), True) - + #Verifica si Kodi tiene algún achivo de Base de Datos de Vídeo de versiones anteriores, entonces los borra verify_Kodi_video_DB() - + #LIBTORRENT: se descarga el binario de Libtorrent cada vez que se actualiza Alfa try: threading.Thread(target=update_libtorrent).start() # Creamos un Thread independiente, hasta el fin de Kodi time.sleep(2) # Dejamos terminar la inicialización... except: # Si hay problemas de threading, nos vamos logger.error(traceback.format_exc()) - - #QUASAR: Preguntamos si se hacen modificaciones a Quasar - if not filetools.exists(filetools.join(config.get_data_path(), "quasar.json")) \ - and not config.get_setting('addon_quasar_update', default=False): - question_update_external_addon("quasar") - - #QUASAR: Hacemos las modificaciones a Quasar, si está permitido, y si está instalado - if config.get_setting('addon_quasar_update', default=False) or \ - (filetools.exists(filetools.join(config.get_data_path(), \ - "quasar.json")) and not xbmc.getCondVisibility('System.HasAddon("plugin.video.quasar")')): - if not update_external_addon("quasar"): - platformtools.dialog_notification("Actualización Quasar", "Ha fallado. Consulte el log") - + + # #QUASAR: Preguntamos si se hacen modificaciones a Quasar + # if not filetools.exists(filetools.join(config.get_data_path(), "quasar.json")) \ + # and not config.get_setting('addon_quasar_update', default=False): + # question_update_external_addon("quasar") + + # #QUASAR: Hacemos las modificaciones a Quasar, si está permitido, y si está instalado + # if config.get_setting('addon_quasar_update', default=False) or \ + # (filetools.exists(filetools.join(config.get_data_path(), \ + # "quasar.json")) and not xbmc.getCondVisibility('System.HasAddon("plugin.video.quasar")')): + # if not update_external_addon("quasar"): + # platformtools.dialog_notification("Actualización Quasar", "Ha fallado. Consulte el log") + #Existe carpeta "custom_code" ? Si no existe se crea y se sale custom_code_dir = filetools.join(config.get_data_path(), 'custom_code') if not filetools.exists(custom_code_dir): create_folder_structure(custom_code_dir) return - + else: #Existe "custom_code.json" ? Si no existe se crea custom_code_json_path = config.get_runtime_path() custom_code_json = filetools.join(custom_code_json_path, 'custom_code.json') if not filetools.exists(custom_code_json): create_json(custom_code_json_path) - + #Se verifica si la versión del .json y del add-on son iguales. Si es así se sale. Si no se copia "custom_code" al add-on verify_copy_folders(custom_code_dir, custom_code_json_path) except: logger.error(traceback.format_exc()) - + def create_folder_structure(custom_code_dir): logger.info() @@ -130,18 +130,18 @@ def create_json(custom_code_json_path, json_name=json_data_file_name): if filetools.exists(json_data_file): filetools.remove(json_data_file) result = filetools.write(json_data_file, jsontools.dump({"addon_version": ""})) - + return def verify_copy_folders(custom_code_dir, custom_code_json_path): logger.info() - + #verificamos si es una nueva versión de Alfa instalada o era la existente. Si es la existente, nos vamos sin hacer nada json_data_file = filetools.join(custom_code_json_path, json_data_file_name) json_data = jsontools.load(filetools.read(json_data_file)) current_version = config.get_addon_version(with_fix=False) - if not json_data or not 'addon_version' in json_data: + if not json_data or not 'addon_version' in json_data: create_json(custom_code_json_path) json_data = jsontools.load(filetools.read(json_data_file)) try: @@ -149,7 +149,7 @@ def verify_copy_folders(custom_code_dir, custom_code_json_path): return except: logger.error(traceback.format_exc(1)) - + #Ahora copiamos los archivos desde el área de Userdata, Custom_code, sobre las carpetas del add-on for root, folders, files in filetools.walk(custom_code_dir): for file in files: @@ -157,46 +157,46 @@ def verify_copy_folders(custom_code_dir, custom_code_json_path): output_file = input_file.replace(custom_code_dir, custom_code_json_path) if not filetools.copy(input_file, output_file, silent=True): return - + #Guardamaos el json con la versión actual de Alfa, para no volver a hacer la copia hasta la nueva versión json_data['addon_version'] = current_version filetools.write(json_data_file, jsontools.dump(json_data)) return - + def question_update_external_addon(addon_name): logger.info(addon_name) - + #Verificamos que el addon está instalado stat = False if xbmc.getCondVisibility('System.HasAddon("plugin.video.%s")' % addon_name): - #Si es la primera vez que se pregunta por la actualización del addon externo, recogemos la respuesta, + #Si es la primera vez que se pregunta por la actualización del addon externo, recogemos la respuesta, # guardaos un .json en userdat/alfa para no volver a preguntar otra vez, y se actualiza el setting en Alfa. stat = platformtools.dialog_yesno('Actualización de %s' % addon_name.capitalize(), '¿Quiere que actualicemos Quasar para que sea compatible con las últimas versiones de Kodi? (recomendado: SÍ)', '', 'Si actualiza Quasar, reinicie Kodi en un par de minutos') #Con la respuesta actualizamos la variable en Alfa settings.xml. Se puede cambiar en Ajustes de Alfa, Otros - if stat: - config.set_setting('addon_quasar_update', True) - else: - config.set_setting('addon_quasar_update', False) - + # if stat: + # config.set_setting('addon_quasar_update', True) + # else: + # config.set_setting('addon_quasar_update', False) + #Creamos un .json en userdata para no volver a preguntar otra vez create_json(config.get_data_path(), "%s.json" % addon_name) - + return stat def update_external_addon(addon_name): logger.info(addon_name) - + try: #Verificamos que el addon está instalado if xbmc.getCondVisibility('System.HasAddon("plugin.video.%s")' % addon_name): #Path de actualizaciones de Alfa alfa_addon_updates_mig = filetools.join(config.get_runtime_path(), "lib") alfa_addon_updates = filetools.join(alfa_addon_updates_mig, addon_name) - + #Path de destino en addon externo __settings__ = xbmcaddon.Addon(id="plugin.video." + addon_name) if addon_name.lower() in ['quasar', 'elementum']: @@ -206,7 +206,7 @@ def update_external_addon(addon_name): else: addon_path_mig = '' addon_path = '' - + #Hay modificaciones en Alfa? Las copiamos al addon, incuidas las carpetas de migración a PY3 if filetools.exists(alfa_addon_updates) and filetools.exists(addon_path): for root, folders, files in filetools.walk(alfa_addon_updates_mig): @@ -222,7 +222,7 @@ def update_external_addon(addon_name): if not filetools.copy(input_file, output_file, silent=True): logger.error('Error en la copia de MIGRACIÓN: Input: %s o Output: %s' % (input_file, output_file)) return False - + for root, folders, files in filetools.walk(alfa_addon_updates): for file in files: input_file = filetools.join(root, file) @@ -241,13 +241,13 @@ def update_external_addon(addon_name): return True except: logger.error(traceback.format_exc()) - + return False - - + + def update_libtorrent(): logger.info() - + if not config.get_setting("mct_buffer", server="torrent", default=""): default = config.get_setting("torrent_client", server="torrent", default=0) config.set_setting("torrent_client", default, server="torrent") @@ -261,10 +261,10 @@ def update_libtorrent(): config.set_setting("bt_download_path", config.get_setting("downloadpath"), server="torrent") config.set_setting("mct_download_limit", "", server="torrent") config.set_setting("magnet2torrent", False, server="torrent") - + if not filetools.exists(filetools.join(config.get_runtime_path(), "custom_code.json")) or not \ config.get_setting("unrar_path", server="torrent", default=""): - + path = filetools.join(config.get_runtime_path(), 'lib', 'rarfiles') creationflags = '' sufix = '' @@ -293,7 +293,7 @@ def update_libtorrent(): filetools.mkdir(unrar) unrar = filetools.join(unrar, 'unrar') filetools.copy(unrar_org, unrar, silent=True) - + command = ['chmod', '777', '%s' % unrar] p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output_cmd, error_cmd = p.communicate() @@ -322,14 +322,14 @@ def update_libtorrent(): xbmc.log('######## UnRAR ERROR in module %s: %s' % (device, unrar), xbmc.LOGNOTICE) logger.error(traceback.format_exc(1)) unrar = '' - + if unrar: config.set_setting("unrar_path", unrar, server="torrent") if filetools.exists(filetools.join(config.get_runtime_path(), "custom_code.json")) and \ config.get_setting("libtorrent_path", server="torrent", default="") : return - + try: from lib.python_libtorrent.python_libtorrent import get_libtorrent except Exception as e: @@ -339,18 +339,18 @@ def update_libtorrent(): config.set_setting("libtorrent_path", "", server="torrent") if not config.get_setting("libtorrent_error", server="torrent", default=''): config.set_setting("libtorrent_error", str(e), server="torrent") - + return - + def verify_Kodi_video_DB(): logger.info() import random - + platform = {} path = '' db_files = [] - + try: path = filetools.join(xbmc.translatePath("special://masterprofile/"), "Database") if filetools.exists(path): @@ -365,16 +365,16 @@ def verify_Kodi_video_DB(): randnum = str(random.randrange(1, 999999)) filetools.rename(filetools.join(path, file), 'OLD_' + randnum +'_' + file) logger.error('BD obsoleta: ' + file) - + else: logger.error('Video_DB: ' + str(platform['video_db']) + ' para versión Kodi ' + str(platform['num_version']) + ' NO EXISTE. Analizar carpeta: ' + str(db_files)) else: logger.error('Estructura de get_platform(full_version=True) incorrecta') else: logger.error('Path a Userdata/Database (' + path + ') no encontrado') - + except: logger.error('Platform: ' + str(platform) + ' / Path: ' + str(path) + ' / Files: ' + str(db_files)) logger.error(traceback.format_exc()) - + return \ No newline at end of file diff --git a/platformcode/download_and_play.py b/platformcode/download_and_play.py index 33de8da8..c356bc4e 100644 --- a/platformcode/download_and_play.py +++ b/platformcode/download_and_play.py @@ -51,10 +51,10 @@ def download_and_play(url, file_name, download_path): while not cancelled and download_thread.isAlive(): dialog.update(download_thread.get_progress(), config.get_localized_string(60313), - "Velocidad: " + str(int(old_div(download_thread.get_speed(), 1024))) + " KB/s " + str( - download_thread.get_actual_size()) + "MB de " + str( + config.get_localized_string(60314) + str(int(old_div(download_thread.get_speed(), 1024))) + " KB/s " + str( + download_thread.get_actual_size()) + config.get_localized_string(60316) + str( download_thread.get_total_size()) + "MB", - "Tiempo restante: " + str(downloadtools.sec_to_hms(download_thread.get_remaining_time()))) + config.get_localized_string(60202) % (str(downloadtools.sec_to_hms(download_thread.get_remaining_time())))) xbmc.sleep(1000) if dialog.iscanceled(): @@ -296,7 +296,7 @@ class DownloadThread(threading.Thread): logger.info("Detectado fichero force_stop, se interrumpe la descarga") f.close() - xbmc.executebuiltin((u'XBMC.Notification("Cancelado", "Descarga en segundo plano cancelada", 300)')) + xbmc.executebuiltin("XBMC.Notification(%s,%s,300)" % (config.get_localized_string(60319),config.get_localized_string(60320))) return diff --git a/platformcode/launcher.py b/platformcode/launcher.py index 3bf6b7ca..d80b3950 100644 --- a/platformcode/launcher.py +++ b/platformcode/launcher.py @@ -17,13 +17,7 @@ else: import os import sys -import time -from core import channeltools -from core import scrapertools -from core import servertools -from core import videolibrarytools -from core import trakt_tools from core.item import Item from platformcode import config, logger from platformcode import platformtools @@ -47,14 +41,23 @@ def start(): from specials.checkhost import test_conn import threading threading.Thread(target=test_conn, args=(True, not config.get_setting('resolver_dns'), True, [], [], True)).start() - + + if not config.dev_mode(): + from platformcode import updater + updater.showSavedChangelog() + def run(item=None): logger.info() if not item: # Extract item from sys.argv if sys.argv[2]: - item = Item().fromurl(sys.argv[2]) - + sp = sys.argv[2].split('&') + url = sp[0] + item = Item().fromurl(url) + if len(sp) > 1: + for e in sp[1:]: + key, val = e.split('=') + item.__setattr__(key, val) # If no item, this is mainlist else: if config.get_setting("start_page"): @@ -84,7 +87,7 @@ def run(item=None): item = Item(channel="channelselector", action="getmainlist", viewmode="movie") if not config.get_setting('show_once'): from platformcode import xbmc_videolibrary - xbmc_videolibrary.ask_set_content(1, config.get_setting('videolibrary_kodi_force')) + xbmc_videolibrary.ask_set_content(silent=False) config.set_setting('show_once', True) logger.info(item.tostring()) @@ -162,6 +165,7 @@ def run(item=None): else: # Entry point for a channel is the "mainlist" action, so here we check parental control if item.action == "mainlist": + from core import channeltools #updater.checkforupdates() beta version checking for update, still disabled # Parental control @@ -207,6 +211,7 @@ def run(item=None): if item.action == "play": #define la info para trakt try: + from core import trakt_tools trakt_tools.set_trakt_info(item) except: pass @@ -241,6 +246,7 @@ def run(item=None): # Special action for findvideos, where the plugin looks for known urls elif item.action == "findvideos": + from core import servertools # First checks if channel has a "findvideos" function if hasattr(channel, 'findvideos'): @@ -263,10 +269,12 @@ def run(item=None): # Special action for adding a movie to the library elif item.action == "add_pelicula_to_library": + from core import videolibrarytools videolibrarytools.add_movie(item) # Special action for adding a serie to the library elif item.action == "add_serie_to_library": + from core import videolibrarytools videolibrarytools.add_tvshow(item, channel) # Special action for downloading all episodes from a serie @@ -279,6 +287,7 @@ def run(item=None): # Special action for searching, first asks for the words then call the "search" function elif item.action == "search": logger.info("item.action=%s" % item.action.upper()) + from core import channeltools # last_search = "" # last_search_active = config.get_setting("last_search", "search") @@ -315,6 +324,7 @@ def run(item=None): logger.info("Executing channel '%s' method" % item.action) itemlist = getattr(channel, item.action)(item) if config.get_setting('trakt_sync'): + from core import trakt_tools token_auth = config.get_setting("token_trakt", "trakt") if not token_auth: trakt_tools.auth_trakt() @@ -346,6 +356,8 @@ def run(item=None): platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(30051) % e.code) except WebErrorException as e: import traceback + from core import scrapertools + logger.error(traceback.format_exc()) patron = 'File "' + os.path.join(config.get_runtime_path(), "channels", "").replace("\\", "\\\\") + '([^.]+)\.py"' @@ -356,6 +368,8 @@ def run(item=None): config.get_localized_string(60013) %(e)) except: import traceback + from core import scrapertools + logger.error(traceback.format_exc()) patron = 'File "' + os.path.join(config.get_runtime_path(), "channels", "").replace("\\", "\\\\") + '([^.]+)\.py"' @@ -467,6 +481,7 @@ def play_from_library(item): @type item: item @param item: elemento con información """ + item.fromLibrary = True logger.info() # logger.debug("item: \n" + item.tostring('\n')) @@ -503,7 +518,7 @@ def play_from_library(item): item.show_server = True from specials import videolibrary, autoplay - p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), config.get_localized_string(70004)) + p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), config.get_localized_string(60683)) p_dialog.update(0, '') itemlist = videolibrary.findvideos(item) diff --git a/platformcode/mct.py b/platformcode/mct.py index bf940e40..0bdba559 100644 --- a/platformcode/mct.py +++ b/platformcode/mct.py @@ -45,8 +45,7 @@ except: try: DOWNLOAD_PATH = '' - DOWNLOAD_PATH = xbmc.translatePath(config.get_setting("mct_download_path", \ - server="torrent", default=config.get_setting("downloadpath"))) + DOWNLOAD_PATH = xbmc.translatePath(config.get_setting("mct_download_path", server="torrent", default=config.get_setting("torrent_downloadpath"))) except: DOWNLOAD_PATH = config.get_setting("mct_download_path", server="torrent", default=config.get_setting("downloadpath")) if not config.get_setting("mct_download_path", server="torrent") and DOWNLOAD_PATH: @@ -573,7 +572,7 @@ def play(url, xlistitem={}, is_view=None, subtitle="", password="", item=None): ok = xbmcgui.Dialog().yesno(msg_header, config.get_localized_string(30031), config.get_localized_string(30032)) else: ok = True # -- NO --------------------------------------------- - if not ok: + if ok: is_view=None bkg_user = True dp_cerrado = False @@ -614,7 +613,7 @@ def play(url, xlistitem={}, is_view=None, subtitle="", password="", item=None): dp.close() # Preguntamos si el usuario quiere pasar a backgroung dialog = xbmcgui.Dialog().yesno(msg_header, config.get_localized_string(30031), config.get_localized_string(30032)) - if not dialog: + if dialog: bkg_user = True dp_cerrado = False dp = xbmcgui.DialogProgressBG() diff --git a/platformcode/platformtools.py b/platformcode/platformtools.py index afe2e129..7aa39ed7 100644 --- a/platformcode/platformtools.py +++ b/platformcode/platformtools.py @@ -47,10 +47,17 @@ class XBMCPlayer(xbmc.Player): xbmc_player = XBMCPlayer() +def makeMessage(line1, line2, line3): + message = line1 + if line2: + message += '\n' + line2 + if line3: + message += '\n' + line3 + return message def dialog_ok(heading, line1, line2="", line3=""): dialog = xbmcgui.Dialog() - return dialog.ok(heading, line1, line2, line3) + return dialog.ok(heading, makeMessage(line1, line2, line3)) def dialog_notification(heading, message, icon=0, time=5000, sound=True): @@ -62,12 +69,19 @@ def dialog_notification(heading, message, icon=0, time=5000, sound=True): dialog_ok(heading, message) -def dialog_yesno(heading, line1, line2="", line3="", nolabel="No", yeslabel="Si", autoclose=""): +def dialog_yesno(heading, line1, line2="", line3="", nolabel="No", yeslabel="Si", autoclose=0, customlabel=None): + # customlabel only on kodi 19 dialog = xbmcgui.Dialog() - if autoclose: - return dialog.yesno(heading, line1, line2, line3, nolabel, yeslabel, autoclose) + if config.get_platform() == 'kodi-matrix': + if autoclose: + return dialog.yesno(heading, makeMessage(line1, line2, line3), nolabel=nolabel, yeslabel=yeslabel, customlabel=customlabel, autoclose=autoclose) + else: + return dialog.yesno(heading, makeMessage(line1, line2, line3), nolabel=nolabel, yeslabel=yeslabel, customlabel=customlabel) else: - return dialog.yesno(heading, line1, line2, line3, nolabel, yeslabel) + if autoclose: + return dialog.yesno(heading, makeMessage(line1, line2, line3), nolabel=nolabel, yeslabel=yeslabel, autoclose=autoclose) + else: + return dialog.yesno(heading, makeMessage(line1, line2, line3), nolabel=nolabel, yeslabel=yeslabel) def dialog_select(heading, _list): @@ -80,7 +94,7 @@ def dialog_multiselect(heading, _list, autoclose=0, preselect=[], useDetails=Fal def dialog_progress(heading, line1, line2=" ", line3=" "): dialog = xbmcgui.DialogProgress() - dialog.create(heading, line1, line2, line3) + dialog.create(heading, makeMessage(line1, line2, line3)) return dialog @@ -112,6 +126,12 @@ def dialog_textviewer(heading, text): # disponible a partir de kodi 16 return xbmcgui.Dialog().textviewer(heading, text) +def dialog_browse(_type, heading, default=""): + dialog = xbmcgui.Dialog() + d = dialog.browse(_type, heading, 'files') + return d + + def itemlist_refresh(): xbmc.executebuiltin("Container.Refresh") @@ -124,6 +144,138 @@ def itemlist_update(item, replace=False): def render_items(itemlist, parent_item): + """ + Function used to render itemlist on kodi + """ + logger.info('START render_items') + thumb_type = config.get_setting('video_thumbnail_type') + from specials import shortcuts + from core import httptools + _handle = int(sys.argv[1]) + default_fanart = config.get_fanart() + def_context_commands = shortcuts.context() + + # for adding extendedinfo to contextual menu, if it's used + has_extendedinfo = xbmc.getCondVisibility('System.HasAddon(script.extendedinfo)') + # for adding superfavourites to contextual menu, if it's used + sf_file_path = xbmc.translatePath("special://home/addons/plugin.program.super.favourites/LaunchSFMenu.py") + check_sf = os.path.exists(sf_file_path) + superfavourites = check_sf and xbmc.getCondVisibility('System.HasAddon("plugin.program.super.favourites")') + + # if it's not a list, do nothing + if not isinstance(itemlist, list): + return + # if there's no item, add "no elements" item + if not len(itemlist): + itemlist.append(Item(title=config.get_localized_string(60347), thumbnail=get_thumb('nofolder.png'))) + + for item in itemlist: + item_url = item.tourl() + + if item.category == "": + item.category = parent_item.category + if not item.title: + item.title = '' + # Si no hay action o es findvideos/play, folder=False porque no se va a devolver ningún listado + if item.action in ['play', '']: + item.folder = False + if item.fanart == "": + item.fanart = parent_item.fanart + if item.action == 'play' and thumb_type == 1 and not item.forcethumb: + item.thumbnail = "https://github.com/kodiondemand/media/raw/master/resources/servers/" + item.server.lower() + '.png' + + # if cloudflare, cookies are needed to display images taken from site + # before checking domain (time consuming), checking if tmdb failed (so, images scraped from website are used) + if item.action in ['findvideos'] and not item.infoLabels['tmdb_id'] and item.channel in httptools.channelsCF: + item.thumbnail = httptools.get_url_headers(item.thumbnail) + item.fanart = httptools.get_url_headers(item.fanart) + + icon_image = "DefaultFolder.png" if item.folder else "DefaultVideo.png" + listitem = xbmcgui.ListItem(item.title) + listitem.setArt({'icon': icon_image, 'thumb': item.thumbnail, 'poster': item.thumbnail, + 'fanart': item.fanart if item.fanart else default_fanart}) + + if config.get_setting("player_mode") == 1 and item.action == "play": + listitem.setProperty('IsPlayable', 'true') + + set_infolabels(listitem, item) + + # context menu + if parent_item.channel != 'special': + context_commands = def_context_commands + set_context_commands(item, item_url, parent_item, has_extendedinfo=has_extendedinfo, + superfavourites=superfavourites) + else: + context_commands = def_context_commands + listitem.addContextMenuItems(context_commands) + + xbmcplugin.addDirectoryItem(_handle, '%s?%s' % (sys.argv[0], item_url), listitem, item.folder) + + if parent_item.list_type == '': + breadcrumb = parent_item.category.capitalize() + else: + if 'similar' in parent_item.list_type: + if parent_item.contentTitle != '': + breadcrumb = config.get_localized_string(70693) + parent_item.contentTitle + else: + breadcrumb = config.get_localized_string(70693) + parent_item.contentSerieName + else: + breadcrumb = config.get_localized_string(70693) + + xbmcplugin.setPluginCategory(handle=_handle, category=breadcrumb) + + set_view_mode(item, parent_item) + + xbmcplugin.endOfDirectory(_handle) + logger.info('END render_items') + + +def set_view_mode(item, parent_item): + def mode(content, Type): + mode = int(config.get_setting('view_mode_%s' % content).split(',')[-1]) + if mode > 0: + xbmcplugin.setContent(handle=int(sys.argv[1]), content=Type) + xbmc.executebuiltin('Container.SetViewMode(%s)' % mode) + logger.info('TYPE: ' + Type) + else: + xbmcplugin.setContent(handle=int(sys.argv[1]), content='') + xbmc.executebuiltin('Container.SetViewMode(%s)' % 55) + logger.info('TYPE: ' + 'None') + + def reset_view_mode(): + for mode in ['addon','channel','movie','tvshow','season','episode','server']: + config.set_setting('skin_name', xbmc.getSkinDir()) + config.set_setting('view_mode_%s' % mode, config.get_localized_string(70003) + ' , 0') + + if xbmc.getSkinDir() != config.get_setting('skin_name') or not config.get_setting('skin_name'): + reset_view_mode() + xbmcplugin.setContent(handle=int(sys.argv[1]), content='') + xbmc.executebuiltin('Container.SetViewMode(%s)' % 55) + + elif (item.contentType in ['movie'] and parent_item.action in ['peliculas']) \ + or (item.channel in ['videolibrary'] and parent_item.action in ['list_movies']): + mode('movie', 'movies') + + elif (item.contentType in ['tvshow'] and parent_item.action in ['peliculas']) \ + or (item.channel in ['videolibrary'] and parent_item.action in ['list_tvshows']): + mode('tvshow', 'tvshow') + + elif parent_item.action in ['get_seasons']: + mode('season', 'tvshow') + + elif parent_item.action in ['episodios', 'get_episodes']: + mode('episode', 'tvshow') + + elif parent_item.action == 'findvideos': + mode('server', 'addons') + + elif parent_item.action == 'mainlist': + mode('channel', 'addons') + + else: + mode('addon', 'addons') + + +def render_items_old(itemlist, parent_item): """ Función encargada de mostrar el itemlist en kodi, se pasa como parametros el itemlist y el item del que procede @type itemlist: list @@ -147,7 +299,7 @@ def render_items(itemlist, parent_item): # Si no hay ningun item, mostramos un aviso if not len(itemlist): - itemlist.append(Item(title=config.get_localized_string(60347))) + itemlist.append(Item(title=config.get_localized_string(60347), thumbnail=get_thumb('nofolder.png'))) genre = False if 'nero' in parent_item.title: @@ -155,33 +307,41 @@ def render_items(itemlist, parent_item): anime = False if 'anime' in channeltools.get_channel_parameters(parent_item.channel)['categories']: anime = True - try: - force_unify = channeltools.get_channel_parameters(parent_item.channel)['force_unify'] - except: - force_unify = False + # try: + # force_unify = channeltools.get_channel_parameters(parent_item.channel)['force_unify'] + # except: + force_unify = False - unify_enabled = config.get_setting('unify') - try: - if channeltools.get_channel_parameters(parent_item.channel)['adult']: - unify_enabled = False - except: - pass + unify_enabled = False + + has_extendedinfo = xbmc.getCondVisibility('System.HasAddon(script.extendedinfo)') + + # Añadir SuperFavourites al menu contextual (1.0.53 o superior necesario) + sf_file_path = xbmc.translatePath("special://home/addons/plugin.program.super.favourites/LaunchSFMenu.py") + check_sf = os.path.exists(sf_file_path) + superfavourites = check_sf and xbmc.getCondVisibility('System.HasAddon("plugin.program.super.favourites")') + # try: + # if channeltools.get_channel_parameters(parent_item.channel)['adult']: + # unify_enabled = False + # except: + # pass # logger.debug('unify_enabled: %s' % unify_enabled) # Recorremos el itemlist for item in itemlist: # logger.debug(item) # Si el item no contiene categoria, le ponemos la del item padre + item_url = item.tourl() if item.category == "": item.category = parent_item.category # Si title no existe, lo iniciamos como str, para evitar errones "NoType" if not item.title: item.title = '' - + # Si no hay action o es findvideos/play, folder=False porque no se va a devolver ningún listado if item.action in ['play', '']: - item.folder = False + item.folder = False # Si el item no contiene fanart, le ponemos el del item padre if item.fanart == "": @@ -199,9 +359,9 @@ def render_items(itemlist, parent_item): item.thumbnail = get_thumb("next.png") elif 'add' in item.action: if 'pelicula' in item.action: - item.thumbnail = get_thumb("videolibrary_movie.png") + item.thumbnail = get_thumb("add_to_videolibrary.png") elif 'serie' in item.action: - item.thumbnail = get_thumb("videolibrary_tvshow.png") + item.thumbnail = get_thumb("add_to_videolibrary.png") if (unify_enabled or force_unify) and parent_item.channel not in ['kodfavourites']: # Formatear titulo con unify @@ -257,14 +417,14 @@ def render_items(itemlist, parent_item): # Añadimos los infoLabels set_infolabels(listitem, item) - + # No arrastrar plot si no es una peli/serie/temporada/episodio if item.plot and item.contentType not in ['movie', 'tvshow', 'season', 'episode']: item.__dict__['infoLabels'].pop('plot') # Montamos el menu contextual if parent_item.channel != 'special': - context_commands = set_context_commands(item, parent_item) + context_commands = set_context_commands(item, item_url, parent_item, has_extendedinfo=has_extendedinfo, superfavourites=superfavourites) else: context_commands = [] # Añadimos el menu contextual @@ -278,7 +438,7 @@ def render_items(itemlist, parent_item): if not item.totalItems: item.totalItems = 0 - xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url='%s?%s' % (sys.argv[0], item.tourl()), + xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url='%s?%s' % (sys.argv[0], item_url), listitem=listitem, isFolder=item.folder, totalItems=item.totalItems) @@ -313,11 +473,11 @@ def render_items(itemlist, parent_item): xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True) # Fijar la vista - if config.get_setting("forceview"): - viewmode_id = get_viewmode_id(parent_item) - xbmc.executebuiltin("Container.SetViewMode(%s)" % viewmode_id) - if parent_item.mode in ['silent', 'get_cached', 'set_cache', 'finish']: - xbmc.executebuiltin("Container.SetViewMode(500)") + # if config.get_setting("forceview"): + # viewmode_id = get_viewmode_id(parent_item) + # xbmc.executebuiltin("Container.SetViewMode(%s)" % viewmode_id) + # if parent_item.mode in ['silent', 'get_cached', 'set_cache', 'finish']: + # xbmc.executebuiltin("Container.SetViewMode(500)") logger.info('END render_items') @@ -397,37 +557,42 @@ def set_infolabels(listitem, item, player=False): 'top250': 'top250', 'tracknumber': 'tracknumber', 'trailer': 'trailer', 'thumbnail': 'None', 'tvdb_id': 'None', 'tvshowtitle': 'tvshowtitle', 'type': 'None', 'userrating': 'userrating', 'url_scraper': 'None', 'votes': 'votes', 'writer': 'writer', 'year': 'year'} - - infoLabels_kodi = {} - if item.infoLabels: - if 'mediatype' not in item.infoLabels: - item.infoLabels['mediatype'] = item.contentType - try: - for label_tag, label_value in list(item.infoLabels.items()): - try: - # logger.debug(str(label_tag) + ': ' + str(infoLabels_dict[label_tag])) - if infoLabels_dict[label_tag] != 'None': - infoLabels_kodi.update({infoLabels_dict[label_tag]: item.infoLabels[label_tag]}) - except: - continue - + infoLabels_kodi = {infoLabels_dict[label_tag]: item.infoLabels[label_tag] for label_tag, label_value in list(item.infoLabels.items()) if infoLabels_dict[label_tag] != 'None'} listitem.setInfo("video", infoLabels_kodi) - except: listitem.setInfo("video", item.infoLabels) logger.error(item.infoLabels) - logger.error(infoLabels_kodi) - if player and not item.contentTitle: - listitem.setInfo("video", {"Title": item.title}) - - elif not player: - listitem.setInfo("video", {"Title": item.title}) + # if item.infoLabels: + # if 'mediatype' not in item.infoLabels: + # item.infoLabels['mediatype'] = item.contentType + # + # try: + # for label_tag, label_value in list(item.infoLabels.items()): + # try: + # # logger.debug(str(label_tag) + ': ' + str(infoLabels_dict[label_tag])) + # if infoLabels_dict[label_tag] != 'None': + # infoLabels_kodi.update({infoLabels_dict[label_tag]: item.infoLabels[label_tag]}) + # except: + # continue + # + # listitem.setInfo("video", infoLabels_kodi) + # + # except: + # listitem.setInfo("video", item.infoLabels) + # logger.error(item.infoLabels) + # logger.error(infoLabels_kodi) + # + # if player and not item.contentTitle: + # listitem.setInfo("video", {"Title": item.title}) + # + # elif not player: + # listitem.setInfo("video", {"Title": item.title}) -def set_context_commands(item, parent_item): +def set_context_commands(item, item_url, parent_item, **kwargs): """ Función para generar los menus contextuales. 1. Partiendo de los datos de item.context @@ -458,7 +623,7 @@ def set_context_commands(item, parent_item): @type parent_item: item """ context_commands = [] - num_version_xbmc = config.get_platform(True)['num_version'] + # num_version_xbmc = config.get_platform(True)['num_version'] # Creamos un list con las diferentes opciones incluidas en item.context if isinstance(item.context, str): @@ -468,43 +633,6 @@ def set_context_commands(item, parent_item): else: context = [] - # if config.get_setting("faster_item_serialization"): - # # logger.info("Reducing serialization!") - # itemBK = item - # item = Item() - # item.action = itemBK.action - # item.channel = itemBK.channel - # infoLabels = {} - # if itemBK.infoLabels["year"]: infoLabels["year"] = itemBK.infoLabels["year"] - # if itemBK.infoLabels["imdb_id"]: infoLabels["imdb_id"] = itemBK.infoLabels["imdb_id"] - # if itemBK.infoLabels["tmdb_id"]: infoLabels["tmdb_id"] = itemBK.infoLabels["tmdb_id"] - # if itemBK.infoLabels["tvdb_id"]: infoLabels["tvdb_id"] = itemBK.infoLabels["tvdb_id"] - # if itemBK.infoLabels["noscrap_id"]: infoLabels["noscrap_id"] = itemBK.infoLabels["noscrap_id"] - # if len(infoLabels) > 0: item.infoLabels = infoLabels - - # if itemBK.thumbnail: item.thumbnail = itemBK.thumbnail - # if itemBK.extra: item.extra = itemBK.extra - # if itemBK.contentEpisodeNumber: item.contentEpisodeNumber = itemBK.contentEpisodeNumber - # if itemBK.contentEpisodeTitle: item.contentEpisodeTitle = itemBK.contentEpisodeTitle - # if itemBK.contentPlot: item.contentPlot = itemBK.contentPlot - # if itemBK.contentQuality: item.contentQuality = itemBK.contentQuality - # if itemBK.contentSeason: item.contentSeason = itemBK.contentSeason - # if itemBK.contentSerieName: item.contentSerieName = itemBK.contentSerieName - # if itemBK.contentThumbnail: item.contentThumbnail = itemBK.contentThumbnail - # if itemBK.contentTitle: item.contentTitle = itemBK.contentTitle - # if itemBK.contentType: item.contentType = itemBK.contentType - # if itemBK.duration: item.duration = itemBK.duration - # if itemBK.plot: item.plot = itemBK.plot - # if itemBK.quality: item.quality = itemBK.quality - # if itemBK.show: item.show = itemBK.show - # if itemBK.title: item.title = itemBK.title - # if itemBK.viewcontent: item.viewcontent = itemBK.viewcontent - - # itemJson = item.tojson() - # logger.info("Elemento: {0} bytes".format(len(itemJson))) - # logger.info(itemJson) - # logger.info("--------------------------------------------------------------") - # Opciones segun item.context for command in context: # Predefinidos @@ -535,15 +663,14 @@ def set_context_commands(item, parent_item): # No añadir más opciones predefinidas si se está dentro de Alfavoritos if parent_item.channel == 'kodfavorites': return context_commands - - # Opciones segun criterios, solo si el item no es un tag (etiqueta), ni es "Añadir a la videoteca", etc... + # Opciones segun criterios, solo si el item no es un tag (etiqueta), ni es "Añadir a la videoteca", etc... if item.action and item.action not in ["add_pelicula_to_library", "add_serie_to_library", "buscartrailer", "actualizar_titulos"]: # Mostrar informacion: si el item tiene plot suponemos q es una serie, temporada, capitulo o pelicula - if item.infoLabels['plot'] and (num_version_xbmc < 17.0 or item.contentType == 'season'): - context_commands.append((config.get_localized_string(60348), "XBMC.Action(Info)")) + # if item.infoLabels['plot'] and (num_version_xbmc < 17.0 or item.contentType == 'season'): + # context_commands.append((config.get_localized_string(60348), "XBMC.Action(Info)")) # ExtendedInfo: Si está instalado el addon y se cumplen una serie de condiciones - if xbmc.getCondVisibility('System.HasAddon(script.extendedinfo)') \ + if kwargs.get('has_extendedinfo') \ and config.get_setting("extended_info") == True: if item.contentType == "episode" and item.contentEpisodeNumber and item.contentSeason \ and (item.infoLabels['tmdb_id'] or item.contentSerieName): @@ -575,43 +702,39 @@ def set_context_commands(item, parent_item): context_commands.append(("ExtendedInfo", "XBMC.RunScript(script.extendedinfo,info=extendedinfo,%s)" % param)) - - # InfoPlus + # InfoPlus if config.get_setting("infoplus"): #if item.infoLabels['tmdb_id'] or item.infoLabels['imdb_id'] or item.infoLabels['tvdb_id'] or \ # (item.contentTitle and item.infoLabels["year"]) or item.contentSerieName: if item.infoLabels['tmdb_id'] or item.infoLabels['imdb_id'] or item.infoLabels['tvdb_id']: - context_commands.append(("InfoPlus", "XBMC.RunPlugin(%s?%s)" % (sys.argv[0], item.clone( - channel="infoplus", action="start", from_channel=item.channel).tourl()))) + context_commands.append(("InfoPlus", "XBMC.RunPlugin(%s?%s&%s)" % (sys.argv[0], item_url, + 'channel=infoplus&action=start&from_channel=' + item.channel))) # Ir al Menu Principal (channel.mainlist) - if parent_item.channel not in ["news", "channelselector"] and item.action != "mainlist" \ + if parent_item.channel not in ["news", "channelselector", "downloads"] and item.action != "mainlist" \ and parent_item.action != "mainlist": context_commands.insert(0, (config.get_localized_string(60349), "XBMC.Container.Refresh (%s?%s)" % - (sys.argv[0], Item(channel=item.channel, action="mainlist").tourl()))) + (sys.argv[0], Item(channel=item.channel, action="mainlist").tourl()))) context_commands.insert(1, (config.get_localized_string(70739), "XBMC.Container.Update (%s?%s)" % (sys.argv[0], Item(action="open_browser", url=item.url).tourl()))) # Añadir a Favoritos - if num_version_xbmc < 17.0 and \ - ((item.channel not in ["favorites", "videolibrary", "help", ""] - or item.action in ["update_videolibrary"]) and parent_item.channel != "favorites"): - context_commands.append((config.get_localized_string(30155), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(channel="favorites", action="addFavourite", - from_channel=item.channel, - from_action=item.action).tourl()))) + # if num_version_xbmc < 17.0 and \ + # ((item.channel not in ["favorites", "videolibrary", "help", ""] + # or item.action in ["update_videolibrary"]) and parent_item.channel != "favorites"): + # context_commands.append((config.get_localized_string(30155), "XBMC.RunPlugin(%s?%s&%s)" % + # (sys.argv[0], item_url, 'channel=favorites&action=addFavourite&from_channel=' + item.channel + '&from_action=' + item.action))) # Añadir a Alfavoritos (Mis enlaces) if item.channel not in ["favorites", "videolibrary", "help", ""] and parent_item.channel != "favorites": context_commands.append( - (config.get_localized_string(70557), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(channel="kodfavourites", action="addFavourite", - from_channel=item.channel, - from_action=item.action).tourl()))) - - # Buscar en otros canales - if item.contentType in ['movie', 'tvshow'] and item.channel != 'search' and item.action not in ['play']: + (config.get_localized_string(70557), "XBMC.RunPlugin(%s?%s&%s)" % + (sys.argv[0], item_url, urllib.urlencode({'channel': "kodfavourites", 'action': "addFavourite", + 'from_channel': item.channel, + 'from_action': item.action})))) + # Buscar en otros canales + if item.contentType in ['movie', 'tvshow'] and item.channel != 'search' and item.action not in ['play'] and parent_item.action != 'mainlist': # Buscar en otros canales if item.contentSerieName != '': @@ -625,20 +748,17 @@ def set_context_commands(item, parent_item): mediatype = item.contentType context_commands.append((config.get_localized_string(60350), - "XBMC.Container.Update (%s?%s)" % (sys.argv[0], - item.clone(channel='search', - action="from_context", - from_channel=item.channel, - contextual=True, - text=item.wanted).tourl()))) + "XBMC.Container.Update (%s?%s&%s)" % (sys.argv[0], + item_url, urllib.urlencode({'channel': 'search', + 'action': "from_context", + 'from_channel': item.channel, + 'contextual': True, + 'text': item.wanted})))) context_commands.append( - (config.get_localized_string(70561), "XBMC.Container.Update (%s?%s)" % ( - sys.argv[0], item.clone(channel='search', action='from_context', search_type='list', page='1', - list_type='%s/%s/similar' % ( - mediatype, item.infoLabels['tmdb_id'])).tourl()))) - - # Definir como Pagina de inicio + (config.get_localized_string(70561), "XBMC.Container.Update (%s?%s&%s)" % ( + sys.argv[0], item_url, 'channel=search&action=from_context&search_type=list&page=1&list_type=%s/%s/similar' % (mediatype, item.infoLabels['tmdb_id'])))) + # Definir como Pagina de inicio if config.get_setting('start_page'): if item.action not in ['episodios', 'seasons', 'findvideos', 'play']: context_commands.insert(0, (config.get_localized_string(60351), @@ -651,46 +771,34 @@ def set_context_commands(item, parent_item): or (item.channel != "videolibrary" and config.get_localized_string(70585) in str(item.context) and config.get_localized_string(70714) in str(item.context)): # Añadir Serie a la videoteca if item.action in ["episodios", "get_episodios", "get_seasons"] and item.contentSerieName: - context_commands.append((config.get_localized_string(60352), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(action="add_serie_to_library", - from_action=item.action).tourl()))) + context_commands.append((config.get_localized_string(60352), "XBMC.RunPlugin(%s?%s&%s)" % + (sys.argv[0], item_url, 'action=add_serie_to_library&from_action=' + item.action))) # Añadir Pelicula a videoteca elif item.action in ["detail", "findvideos"] and item.contentType == 'movie' and item.contentTitle: - context_commands.append((config.get_localized_string(60353), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(action="add_pelicula_to_library", - from_action=item.action).tourl()))) - - if item.channel not in ["downloads", "videolibrary"] and item.server != 'torrent': + context_commands.append((config.get_localized_string(60353), "XBMC.RunPlugin(%s?%s&%s)" % + (sys.argv[0], item_url, 'action=add_pelicula_to_library&from_action=' + item.action))) + + if item.channel not in ["downloads"] and item.server != 'torrent' and parent_item.action != 'mainlist' and config.get_setting('downloadenabled'): # Descargar pelicula if item.contentType == "movie": - context_commands.append((config.get_localized_string(60354), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(channel="downloads", action="save_download", - from_channel=item.channel, from_action=item.action) - .tourl()))) + context_commands.append((config.get_localized_string(60354), "XBMC.RunPlugin(%s?%s&%s)" % + (sys.argv[0], item_url, 'channel=downloads&action=save_download&from_channel=' + item.channel + '&from_action=' + item.action))) elif item.contentSerieName: # Descargar serie if item.contentType == "tvshow": - context_commands.append((config.get_localized_string(60355), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(channel="downloads", action="save_download", - from_channel=item.channel, - from_action=item.action).tourl()))) - context_commands.append((config.get_localized_string(60357), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(channel="downloads", action="save_download", download="seson", - from_channel=item.channel, - from_action=item.action).tourl()))) + context_commands.append((config.get_localized_string(60355), "XBMC.RunPlugin(%s?%s&%s)" % + (sys.argv[0], item_url, 'channel=downloads&action=save_download&from_channel=' + item.channel + '&from_action=' + item.action))) + context_commands.append((config.get_localized_string(60357), "XBMC.RunPlugin(%s?%s&%s)" % + (sys.argv[0], item_url, 'channel=downloads&action=save_download&download=season&from_channel=' + item.channel + '&from_action=' + item.action))) # Descargar episodio elif item.contentType == "episode": - context_commands.append((config.get_localized_string(60356), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(channel="downloads", action="save_download", - from_channel=item.channel, - from_action=item.action).tourl()))) + context_commands.append((config.get_localized_string(60356), "XBMC.RunPlugin(%s?%s&%s)" % + (sys.argv[0], item_url, 'channel=downloads&action=save_download&from_channel=' + item.channel + '&from_action=' + item.action))) # Descargar temporada elif item.contentType == "season": - context_commands.append((config.get_localized_string(60357), "XBMC.RunPlugin(%s?%s)" % - (sys.argv[0], item.clone(channel="downloads", action="save_download", - from_channel=item.channel, - from_action=item.action).tourl()))) + context_commands.append((config.get_localized_string(60357), "XBMC.RunPlugin(%s?%s&%s)" % + (sys.argv[0], item_url, 'channel=downloads&action=save_download&download=season&from_channel=' + item.channel + '&from_action=' + item.action))) # # Abrir configuración # if parent_item.channel not in ["setting", "news", "search"] and item.action == "play": @@ -698,20 +806,17 @@ def set_context_commands(item, parent_item): # (sys.argv[0], Item(channel="setting", action="mainlist").tourl()))) # Buscar Trailer - if item.action == "findvideos" or "buscar_trailer" in context: + if item.action in ["findvideos", 'episodios', 'check'] or "buscar_trailer" in context: context_commands.append( - (config.get_localized_string(60359), "XBMC.RunPlugin(%s?%s)" % (sys.argv[0], item.clone( - channel="trailertools", action="buscartrailer", contextual=True).tourl()))) + (config.get_localized_string(60359), "XBMC.RunPlugin(%s?%s)" % (sys.argv[0], urllib.urlencode({ + 'channel': "trailertools", 'action': "buscartrailer", 'search_title': item.fulltitle if item.fulltitle else item.contentTitle, 'contextual': True})))) - # Añadir SuperFavourites al menu contextual (1.0.53 o superior necesario) - sf_file_path = xbmc.translatePath("special://home/addons/plugin.program.super.favourites/LaunchSFMenu.py") - check_sf = os.path.exists(sf_file_path) - if check_sf and xbmc.getCondVisibility('System.HasAddon("plugin.program.super.favourites")'): - context_commands.append((config.get_localized_string(60361), + if kwargs.get('superfavourites'): + context_commands.append((config.get_localized_string(60361), "XBMC.RunScript(special://home/addons/plugin.program.super.favourites/LaunchSFMenu.py)")) # context_commands = sorted(context_commands, key=lambda comand: comand[0]) - + # Menu Rapido # context_commands.insert(0, (config.get_localized_string(60360), # "XBMC.Container.Update (%s?%s)" % (sys.argv[0], Item(channel='side_menu', @@ -993,7 +1098,7 @@ def get_dialogo_opciones(item, default_action, strm, autoplay): # Si puedes ver el vídeo, presenta las opciones if puedes: for video_url in video_urls: - opciones.append(config.get_localized_string(30151) + " " + video_url[0]) + opciones.append(config.get_localized_string(60221) + " " + video_url[0]) if item.server == "local": opciones.append(config.get_localized_string(30164)) @@ -1071,14 +1176,7 @@ def set_opcion(item, seleccion, opciones, video_urls): # "Descargar" elif opciones[seleccion] == config.get_localized_string(30153): from specials import downloads - import xbmcaddon - import xbmcgui - __addon__ = xbmcaddon.Addon() - __addonname__ = __addon__.getAddonInfo('name') - line1 = config.get_localized_string(70690) - line2 = config.get_localized_string(70691) - line3 = config.get_localized_string(70692) - xbmcgui.Dialog().ok(__addonname__, line1, line2, line3) + downloads.show_disclaimer() if item.contentType == "list" or item.contentType == "tvshow": item.contentType = "video" @@ -1169,7 +1267,7 @@ def set_player(item, xlistitem, mediaurl, view, strm): logger.info("player_mode=%s" % config.get_setting("player_mode")) logger.info("mediaurl=" + mediaurl) if config.get_setting("player_mode") == 3 or "megacrypter.com" in mediaurl: - from . import download_and_play + from platformcode import download_and_play download_and_play.download_and_play(mediaurl, "download_and_play.tmp", config.get_setting("downloadpath")) return @@ -1218,8 +1316,7 @@ def torrent_client_installed(show_tuple=False): # Plugins externos se encuentra en servers/torrent.json nodo clients from core import filetools from core import jsontools - torrent_clients = jsontools.get_node_from_file("torrent.json", "clients", filetools.join(config.get_runtime_path(), - "servers")) + torrent_clients = jsontools.get_node_from_file("torrent.json", "clients", filetools.join(config.get_runtime_path(),"servers")) torrent_options = [] for client in torrent_clients: if xbmc.getCondVisibility('System.HasAddon("%s")' % client["id"]): @@ -1240,6 +1337,16 @@ def play_torrent(item, xlistitem, mediaurl): from lib import generictools from servers import torrent + + # Si Libtorrent ha dado error de inicialización, no se pueden usar los clientes internos + UNRAR = config.get_setting("unrar_path", server="torrent", default="") + LIBTORRENT = config.get_setting("libtorrent_path", server="torrent", default='') + size_rar = 2 + rar_files = [] + if item.password: + size_rar = 3 + + # Opciones disponibles para Reproducir torrents torrent_options = list() torrent_options.append([config.get_localized_string(30033)]) @@ -1249,6 +1356,12 @@ def play_torrent(item, xlistitem, mediaurl): torrent_client = config.get_setting("torrent_client", server="torrent") + # Si es Libtorrent y no está soportado, se ofrecen alternativas, si las hay... + if not LIBTORRENT and len(torrent_options) < 3: + from specials import quasar_download + if dialog_yesno(config.get_localized_string(70784), config.get_localized_string(70782)): + quasar_download.download() + if torrent_client and torrent_client - 1 <= len(torrent_options): if torrent_client == 0: seleccion = dialog_select(config.get_localized_string(70193), [opcion[0] for opcion in torrent_options]) @@ -1260,15 +1373,6 @@ def play_torrent(item, xlistitem, mediaurl): else: seleccion = 0 - # Si Libtorrent ha dado error de inicialización, no se pueden usar los clientes internos - UNRAR = config.get_setting("unrar_path", server="torrent", default="") - LIBTORRENT = config.get_setting("libtorrent_path", server="torrent", default='') - size_rar = 2 - rar_files = [] - if item.password: - size_rar = 3 - - # Si es Libtorrent y no está soportado, se ofrecen alternativas, si las hay... if seleccion < 2 and not LIBTORRENT: dialog_ok(config.get_localized_string(30033), config.get_localized_string(70774), \ config.get_localized_string(70775) % config.get_setting("libtorrent_error", server="torrent", default=''), \ @@ -1362,38 +1466,24 @@ def play_torrent(item, xlistitem, mediaurl): item.url = item.torrent_alt # Si es un archivo .torrent local, actualizamos el path relativo a path absoluto - if (item.url.startswith("\\") or item.url.startswith("/")) and not \ - url_stat and videolibrary_path: # .torrent alternativo local + if (item.url.startswith("\\") or item.url.startswith("/")) and not url_stat and videolibrary_path: # .torrent alternativo local movies = config.get_setting("folder_movies") series = config.get_setting("folder_tvshows") if item.contentType == 'movie': folder = movies # películas else: folder = series # o series - item.url = filetools.join(config.get_videolibrary_path(), folder, - item.url) # dirección del .torrent local en la Videoteca - if filetools.copy(item.url, torrents_path, - silent=True): # se copia a la carpeta generíca para evitar problemas de encode + item.url = filetools.join(config.get_videolibrary_path(), folder, item.url) # dirección del .torrent local en la Videoteca + if filetools.copy(item.url, torrents_path, silent=True): # se copia a la carpeta generíca para evitar problemas de encode item.url = torrents_path if "torrentin" in torrent_options[seleccion][0]: # Si es Torrentin, hay que añadir un prefijo item.url = 'file://' + item.url - size, rar_files = generictools.get_torrent_size('', file_list=True, local_torr=torrents_path, - short_pad=True) + size, rar_files = generictools.get_torrent_size('', file_list=True, local_torr=torrents_path,short_pad=True) mediaurl = item.url if seleccion >= 0: - # Si tiene .torrent válido o magnet, lo registramos - if size or item.url.startswith('magnet'): - try: - import threading - if not PY3: from lib import alfaresolver - else: from lib import alfaresolver_py3 as alfaresolver - threading.Thread(target=alfaresolver.frequency_count, args=(item, )).start() - except: - logger.error(traceback.format_exc(1)) - # Reproductor propio BT (libtorrent) if seleccion == 0: torrent.bt_client(mediaurl, xlistitem, rar_files, subtitle=item.subtitle, password=password, item=item) @@ -1407,8 +1497,7 @@ def play_torrent(item, xlistitem, mediaurl): else: mediaurl = urllib.quote_plus(item.url) # Llamada con más parámetros para completar el título - if ("quasar" in torrent_options[seleccion][1] or "elementum" in torrent_options[seleccion][1]) \ - and item.infoLabels['tmdb_id']: + if ("quasar" in torrent_options[seleccion][1] or "elementum" in torrent_options[seleccion][1]) and item.infoLabels['tmdb_id']: if item.contentType == 'episode' and "elementum" not in torrent_options[seleccion][1]: mediaurl += "&episode=%s&library=&season=%s&show=%s&tmdb=%s&type=episode" % ( item.infoLabels['episode'], item.infoLabels['season'], item.infoLabels['tmdb_id'], @@ -1422,14 +1511,10 @@ def play_torrent(item, xlistitem, mediaurl): # y después lo extraemos, incluso con RAR's anidados y con contraseña torr_client = torrent_options[seleccion][0].replace('Plugin externo: ', '') if 'RAR-' in size and torr_client in ['quasar', 'elementum'] and UNRAR: - rar_file, save_path_videos, folder_torr = torrent.wait_for_download(rar_files, - torr_client) # Esperamos mientras se descarga el RAR + rar_file, save_path_videos, folder_torr = torrent.wait_for_download(item, mediaurl, rar_files, torr_client) # Esperamos mientras se descarga el RAR if rar_file and save_path_videos: # Si se ha descargado el RAR... dp = dialog_progress_bg('KoD %s' % torr_client) - video_file, rar, video_path, erase_file_path = torrent.extract_files(rar_file, \ - save_path_videos, password, dp, - item, - torr_client) # ... extraemos el vídeo del RAR + video_file, rar, video_path, erase_file_path = torrent.extract_files(rar_file, save_path_videos, password, dp, item, torr_client) # ... extraemos el vídeo del RAR dp.close() # Reproducimos el vídeo extraido, si no hay nada en reproducción @@ -1457,8 +1542,7 @@ def play_torrent(item, xlistitem, mediaurl): try: torr_data, deamon_url, index = torrent.get_tclient_data(folder_torr, torr_client) if torr_data and deamon_url: - data = httptools.downloadpage('%sdelete/%s' % (deamon_url, index), timeout=5, - alfa_s=True).data + data = httptools.downloadpage('%sdelete/%s' % (deamon_url, index), timeout=5, alfa_s=True).data time.sleep(1) if filetools.isdir(erase_file_path): filetools.rmdirtree(erase_file_path) @@ -1466,8 +1550,7 @@ def play_torrent(item, xlistitem, mediaurl): filetools.remove(erase_file_path) except: logger.error(traceback.format_exc(1)) - elementum_dl = config.get_setting("elementum_dl", server="torrent", - default='') # Si salvamos el cambio de Elementum + elementum_dl = config.get_setting("elementum_dl", server="torrent", default='') # Si salvamos el cambio de Elementum if elementum_dl: config.set_setting("elementum_dl", "", server="torrent") # lo reseteamos en Alfa xbmcaddon.Addon(id="plugin.video.%s" % torrent_options[seleccion][0].replace('Plugin externo: ', '')) \ diff --git a/platformcode/updater.py b/platformcode/updater.py index c3851414..e8943f40 100644 --- a/platformcode/updater.py +++ b/platformcode/updater.py @@ -5,7 +5,7 @@ import shutil from lib.six import BytesIO from core import filetools -from platformcode import logger, platformtools +from platformcode import config, logger, platformtools import json import xbmc import re @@ -19,6 +19,7 @@ import sys PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int addon = xbmcaddon.Addon('plugin.video.kod') +addonname = addon.getAddonInfo('name') _hdr_pat = re.compile("^@@ -(\d+),?(\d+)? \+(\d+),?(\d+)? @@.*") @@ -43,13 +44,13 @@ def loadCommits(page=1): except: xbmc.sleep(1000) else: - platformtools.dialog_notification('Kodi on Demand', 'impossibile controllare gli aggiornamenti') + platformtools.dialog_notification(addonname, config.get_localized_string(70675)) ret = None return ret -# ret -> aggiornato, necessita reload videolibrary_service +# ret -> aggiornato, necessita reload service def check(background=False): if not addon.getSetting('addon_update_enabled'): return False, False @@ -109,7 +110,7 @@ def check(background=False): logger.info(file["filename"]) if 'resources/language' in file["filename"]: poFilesChanged = True - if 'videolibrary_service.py' in file["filename"]: + if 'service.py' in file["filename"]: serviceChanged = True if file['status'] == 'modified' or file['status'] == 'added': if 'patch' in file: diff --git a/platformcode/xbmc_videolibrary.py b/platformcode/xbmc_videolibrary.py index 6b444adc..6fcd69a8 100644 --- a/platformcode/xbmc_videolibrary.py +++ b/platformcode/xbmc_videolibrary.py @@ -20,6 +20,7 @@ from core import jsontools from platformcode import config, logger from platformcode import platformtools from core import scrapertools +from xml.dom import minidom def mark_auto_as_watched(item): @@ -511,22 +512,7 @@ def update(folder_content=config.get_setting("folder_tvshows"), folder=""): data = get_data(payload) - -def clean(mostrar_dialogo=False): - """ - limpia la libreria de elementos que no existen - @param mostrar_dialogo: muestra el cuadro de progreso mientras se limpia la videoteca - @type mostrar_dialogo: bool - """ - logger.info() - payload = {"jsonrpc": "2.0", "method": "VideoLibrary.Clean", "id": 1, - "params": {"showdialogs": mostrar_dialogo}} - data = get_data(payload) - - if data.get('result', False) == 'OK': - return True - - return False + xbmc.executebuiltin('XBMC.ReloadSkin()') def search_library_path(): @@ -538,26 +524,26 @@ def search_library_path(): return None -def set_content(content_type, silent=False): +def set_content(content_type, silent=False, custom=False): """ Procedimiento para auto-configurar la videoteca de kodi con los valores por defecto @type content_type: str ('movie' o 'tvshow') @param content_type: tipo de contenido para configurar, series o peliculas """ + logger.info() continuar = True msg_text = "" videolibrarypath = config.get_setting("videolibrarypath") - forced = config.get_setting('videolibrary_kodi_force') if content_type == 'movie': scraper = [config.get_localized_string(70093), config.get_localized_string(70096)] - if forced: + if not custom: seleccion = 0 # tmdb else: seleccion = platformtools.dialog_select(config.get_localized_string(70094), scraper) - # Instalar The Movie Database + # Instalar The Movie Database if seleccion == -1 or seleccion == 0: if not xbmc.getCondVisibility('System.HasAddon(metadata.themoviedb.org)'): if not silent: @@ -577,9 +563,8 @@ def set_content(content_type, silent=False): continuar = (install and xbmc.getCondVisibility('System.HasAddon(metadata.themoviedb.org)')) if not continuar: msg_text = config.get_localized_string(60047) - if continuar: - xbmc.executebuiltin('xbmc.addon.opensettings(metadata.themoviedb.org)', True) + xbmc.executebuiltin('Addon.OpenSettings(metadata.themoviedb.org)', True) # Instalar Universal Movie Scraper elif seleccion == 1: @@ -603,11 +588,11 @@ def set_content(content_type, silent=False): if not continuar: msg_text = config.get_localized_string(70097) if continuar: - xbmc.executebuiltin('xbmc.addon.opensettings(metadata.universal)', True) + xbmc.executebuiltin('Addon.OpenSettings(metadata.universal)', True) else: # SERIES scraper = [config.get_localized_string(70098), config.get_localized_string(70093)] - if forced: + if not custom: seleccion = 0 # tvdb else: seleccion = platformtools.dialog_select(config.get_localized_string(70107), scraper) @@ -631,9 +616,9 @@ def set_content(content_type, silent=False): continuar = (install and xbmc.getCondVisibility('System.HasAddon(metadata.tvdb.com)')) if not continuar: - msg_text = config.get_localized_string(70099) + msg_text = config.get_localized_string(60049) if continuar: - xbmc.executebuiltin('xbmc.addon.opensettings(metadata.tvdb.com)', True) + xbmc.executebuiltin('Addon.OpenSettings(metadata.tvdb.com)', True) # Instalar The Movie Database elif seleccion == 1: @@ -641,7 +626,7 @@ def set_content(content_type, silent=False): continuar = False if not silent: # Preguntar si queremos instalar metadata.tvshows.themoviedb.org - install = platformtools.dialog_yesno(config.get_localized_string(70100)) + install = platformtools.dialog_yesno(config.get_localized_string(60050)) else: install = True @@ -656,9 +641,9 @@ def set_content(content_type, silent=False): continuar = (install and continuar) if not continuar: - msg_text = config.get_localized_string(60047) + msg_text = config.get_localized_string(60051) if continuar: - xbmc.executebuiltin('xbmc.addon.opensettings(metadata.tvshows.themoviedb.org)', True) + xbmc.executebuiltin('Addon.OpenSettings(metadata.tvshows.themoviedb.org)', True) idPath = 0 idParentPath = 0 @@ -719,6 +704,9 @@ def set_content(content_type, silent=False): elif seleccion == 1: strScraper = 'metadata.universal' path_settings = xbmc.translatePath("special://profile/addon_data/metadata.universal/settings.xml") + if not os.path.exists(path_settings): + logger.info("%s: %s" % (content_type, path_settings + " doesn't exist")) + return continuar settings_data = filetools.read(path_settings) strSettings = ' '.join(settings_data.split()).replace("> <", "><") strSettings = strSettings.replace("\"","\'") @@ -735,6 +723,9 @@ def set_content(content_type, silent=False): elif seleccion == 1: strScraper = 'metadata.tvshows.themoviedb.org' path_settings = xbmc.translatePath("special://profile/addon_data/metadata.tvshows.themoviedb.org/settings.xml") + if not os.path.exists(path_settings): + logger.info("%s: %s" % (content_type, path_settings + " doesn't exist")) + return continuar settings_data = filetools.read(path_settings) strSettings = ' '.join(settings_data.split()).replace("> <", "><") strSettings = strSettings.replace("\"","\'") @@ -777,16 +768,258 @@ def set_content(content_type, silent=False): if not continuar: heading = config.get_localized_string(70102) % content_type - elif content_type == 'SERIES' and not xbmc.getCondVisibility( + elif content_type == 'tvshow' and not xbmc.getCondVisibility( 'System.HasAddon(metadata.tvshows.themoviedb.org)'): heading = config.get_localized_string(70103) % content_type msg_text = config.get_localized_string(60058) else: heading = config.get_localized_string(70103) % content_type msg_text = config.get_localized_string(70104) - platformtools.dialog_notification(heading, msg_text, icon=1, time=3000) logger.info("%s: %s" % (heading, msg_text)) + return continuar + + +def update_db(old_path, new_path, old_movies_folder, new_movies_folder, old_tvshows_folder, new_tvshows_folder, progress): + def path_replace(path, old, new): + if new.startswith("special://") or '://' in new: sep = '/' + else: sep = os.sep + + path = path.replace(old,new) + if sep == '/': path = path.replace('\\','/') + else: path = path.replace('/','\\') + + return path + + logger.info() + + sql_old_path = old_path + if sql_old_path.startswith("special://"): + sql_old_path = sql_old_path.replace('/profile/', '/%/').replace('/home/userdata/', '/%/') + sep = '/' + elif '://' in sql_old_path: + sep = '/' + else: sep = os.sep + if not sql_old_path.endswith(sep): + sql_old_path += sep + + # search MAIN path in the DB + sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_old_path + nun_records, records = execute_sql_kodi(sql) + + # change main path + if records: + idPath = records[0][0] + strPath = path_replace(records[0][1], old_path, new_path) + sql = 'UPDATE path SET strPath="%s" WHERE idPath=%s' % (strPath, idPath) + nun_records, records = execute_sql_kodi(sql) + + p = 80 + progress.update(p, config.get_localized_string(20000), config.get_localized_string(80013)) + + for OldFolder, NewFolder in [[old_movies_folder, new_movies_folder], [old_tvshows_folder, new_tvshows_folder]]: + sql_old_folder = sql_old_path + OldFolder + if not sql_old_folder.endswith(sep): sql_old_folder += sep + + # Search Main Sub Folder + sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_old_folder + nun_records, records = execute_sql_kodi(sql) + + # Change Main Sub Folder + if records: + for record in records: + idPath = record[0] + strPath = path_replace(record[1], filetools.join(old_path, OldFolder), filetools.join(new_path, NewFolder)) + sql = 'UPDATE path SET strPath="%s" WHERE idPath=%s' % (strPath, idPath) + nun_records, records = execute_sql_kodi(sql) + + # Search if Sub Folder exixt in all paths + sql_old_folder += '%' + sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_old_folder + nun_records, records = execute_sql_kodi(sql) + + #Change Sub Folder in all paths + if records: + for record in records: + idPath = record[0] + strPath = path_replace(record[1], filetools.join(old_path, OldFolder), filetools.join(new_path, NewFolder)) + sql = 'UPDATE path SET strPath="%s" WHERE idPath=%s' % (strPath, idPath) + nun_records, records = execute_sql_kodi(sql) + + + if OldFolder == old_movies_folder: + # if is Movie Folder + # search and modify in "movie" + sql = 'SELECT idMovie, c22 FROM movie where c22 LIKE "%s"' % sql_old_folder + nun_records, records = execute_sql_kodi(sql) + if records: + for record in records: + idMovie = record[0] + strPath = path_replace(record[1], filetools.join(old_path, OldFolder), filetools.join(new_path, NewFolder)) + sql = 'UPDATE movie SET c22="%s" WHERE idMovie=%s' % (strPath, idMovie) + nun_records, records = execute_sql_kodi(sql) + else: + # if is TV Show Folder + # search and modify in "episode" + sql = 'SELECT idEpisode, c18 FROM episode where c18 LIKE "%s"' % sql_old_folder + nun_records, records = execute_sql_kodi(sql) + if records: + for record in records: + idEpisode = record[0] + strPath = path_replace(record[1], filetools.join(old_path, OldFolder), filetools.join(new_path, NewFolder)) + sql = 'UPDATE episode SET c18="%s" WHERE idEpisode=%s' % (strPath, idEpisode) + nun_records, records = execute_sql_kodi(sql) + p += 5 + progress.update(p, config.get_localized_string(20000), config.get_localized_string(80013)) + + progress.update(100) + xbmc.sleep(1000) + progress.close() + xbmc.executebuiltin('XBMC.ReloadSkin()') + + +def clean(path=''): + def sql_format(path): + if path.startswith("special://"): + path = path.replace('/profile/', '/%/').replace('/home/userdata/', '/%/') + sep = '/' + elif '://' in path: + sep = '/' + else: sep = os.sep + + if sep == '/': path = path.replace('\\','/') + else: path = path.replace('/','\\') + + return path, sep + + logger.info() + + idParentPath = 0 + sql_path = '' + sql_movies_path = '' + sql_tvshows_path = '' + sql_episodes_path = '' + + path, sep = sql_format(path) + movies_folder = config.get_setting("folder_movies") + tvshows_folder = config.get_setting("folder_tvshows") + + # delete episode/movie (downloads.py move_to_libray) + if path.endswith(".strm"): + if movies_folder in path: + sql_movies_path = path + else: + sql_episodes_path = path + # delete movie + elif movies_folder in path: + if not path.endswith(sep): path += sep + + sql_movies_path = path + '%' + # delete tvshow + elif tvshows_folder in path: + if not path.endswith(sep): path += sep + + sql_tvshows_path = path + '%' + + sql_episodes_path = sql_tvshows_path + # delete video library + else: + if not path.endswith(sep): path += sep + + sql_path = path + + sql_movies_path = sql_path + movies_folder + if not sql_movies_path.endswith(sep): sql_movies_path += sep + sql_movies_path += '%' + + sql_tvshows_path = sql_path + tvshows_folder + if not sql_tvshows_path.endswith(sep): sql_tvshows_path += sep + sql_tvshows_path += '%' + + sql_episodes_path = sql_tvshows_path + + progress = platformtools.dialog_progress_bg(config.get_localized_string(20000), config.get_localized_string(80025)) + progress.update(0) + if sql_path: + # search video library path in the DB + sql = 'SELECT idPath FROM path where strPath LIKE "%s"' % sql_path + nun_records, records = execute_sql_kodi(sql) + # delete video library path + if records: + idPath = records[0][0] + idParentPath = idPath + if not config.get_setting("videolibrary_kodi"): + sql = 'DELETE from path WHERE idPath=%s' % idPath + nun_records, records = execute_sql_kodi(sql) + + progress.update(10) + if sql_movies_path: + # search movies in the DB + sql = 'SELECT idMovie FROM movie where c22 LIKE "%s"' % sql_movies_path + nun_records, records = execute_sql_kodi(sql) + # delete movies + if records: + for record in records: + idMovie = record[0] + sql = 'DELETE from movie WHERE idMovie=%s' % idMovie + nun_records, records = execute_sql_kodi(sql) + + progress.update(28) + if sql_movies_path: + # search movies path and folders in the DB + sql = 'SELECT idPath, idParentPath FROM path where strPath LIKE "%s"' % sql_movies_path + nun_records, records = execute_sql_kodi(sql) + # delete movies path and folders + if records: + for record in records: + if record[1] == idParentPath and config.get_setting("videolibrary_kodi"): + continue + idPath = record[0] + sql = 'DELETE from path WHERE idPath=%s' % idPath + nun_records, records = execute_sql_kodi(sql) + + progress.update(46) + if sql_tvshows_path: + # search TV shows in the DB + sql = 'SELECT idShow FROM tvshow_view where strPath LIKE "%s"' % sql_tvshows_path + nun_records, records = execute_sql_kodi(sql) + # delete TV shows + if records: + for record in records: + idShow = record[0] + sql = 'DELETE from tvshow WHERE idShow=%s' % idShow + nun_records, records = execute_sql_kodi(sql) + + progress.update(64) + if sql_episodes_path: + # search episodes in the DB + sql = 'SELECT idEpisode FROM episode where c18 LIKE "%s"' % sql_episodes_path + nun_records, records = execute_sql_kodi(sql) + # delete episodes + if records: + for record in records: + idEpisode = record[0] + sql = 'DELETE from episode WHERE idEpisode=%s' % idEpisode + nun_records, records = execute_sql_kodi(sql) + + progress.update(82) + if sql_tvshows_path: + # search TV shows path and folders in the DB + sql = 'SELECT idPath, idParentPath FROM path where strPath LIKE "%s"' % sql_tvshows_path + nun_records, records = execute_sql_kodi(sql) + # delete tvshows path and folders + if records: + for record in records: + if record[1] == idParentPath and config.get_setting("videolibrary_kodi"): + continue + idPath = record[0] + sql = 'DELETE from path WHERE idPath=%s' % idPath + nun_records, records = execute_sql_kodi(sql) + + progress.update(100) + xbmc.sleep(1000) + progress.close() + xbmc.executebuiltin('XBMC.ReloadSkin()') def execute_sql_kodi(sql): @@ -854,101 +1087,175 @@ def execute_sql_kodi(sql): return nun_records, records -def add_sources(path): +def check_sources(new_movies_path='', new_tvshows_path=''): + def format_path(path): + if path.startswith("special://") or '://' in path: sep = '/' + else: sep = os.sep + if not path.endswith(sep): path += sep + return path + logger.info() - from xml.dom import minidom + + new_movies_path = format_path(new_movies_path) + new_tvshows_path = format_path(new_tvshows_path) SOURCES_PATH = xbmc.translatePath("special://userdata/sources.xml") - - if os.path.exists(SOURCES_PATH): + if filetools.isfile(SOURCES_PATH): xmldoc = minidom.parse(SOURCES_PATH) + + video_node = xmldoc.childNodes[0].getElementsByTagName("video")[0] + paths_node = video_node.getElementsByTagName("path") + list_path = [p.firstChild.data for p in paths_node] + + return new_movies_path in list_path, new_tvshows_path in list_path else: - # Crear documento xmldoc = minidom.Document() - nodo_sources = xmldoc.createElement("sources") + source_nodes = xmldoc.createElement("sources") for type in ['programs', 'video', 'music', 'picture', 'files']: nodo_type = xmldoc.createElement(type) element_default = xmldoc.createElement("default") element_default.setAttribute("pathversion", "1") nodo_type.appendChild(element_default) - nodo_sources.appendChild(nodo_type) - xmldoc.appendChild(nodo_sources) + source_nodes.appendChild(nodo_type) + xmldoc.appendChild(source_nodes) - # Buscamos el nodo video - nodo_video = xmldoc.childNodes[0].getElementsByTagName("video")[0] - - # Buscamos el path dentro de los nodos_path incluidos en el nodo_video - nodos_paths = nodo_video.getElementsByTagName("path") - list_path = [p.firstChild.data for p in nodos_paths] - logger.debug(list_path) - if path in list_path: - logger.debug("La ruta %s ya esta en sources.xml" % path) - return - logger.debug("La ruta %s NO esta en sources.xml" % path) - - # Si llegamos aqui es por q el path no esta en sources.xml, asi q lo incluimos - nodo_source = xmldoc.createElement("source") - - # Nodo <name> - nodo_name = xmldoc.createElement("name") - sep = os.sep - if path.startswith("special://") or scrapertools.find_single_match(path, '(^\w+:\/\/)'): - sep = "/" - name = path - if path.endswith(sep): - name = path[:-1] - nodo_name.appendChild(xmldoc.createTextNode(name.rsplit(sep)[-1])) - nodo_source.appendChild(nodo_name) - - # Nodo <path> - nodo_path = xmldoc.createElement("path") - nodo_path.setAttribute("pathversion", "1") - nodo_path.appendChild(xmldoc.createTextNode(path)) - nodo_source.appendChild(nodo_path) - - # Nodo <allowsharing> - nodo_allowsharing = xmldoc.createElement("allowsharing") - nodo_allowsharing.appendChild(xmldoc.createTextNode('true')) - nodo_source.appendChild(nodo_allowsharing) - - # Añadimos <source> a <video> - nodo_video.appendChild(nodo_source) - - # Guardamos los cambios - if not PY3: - filetools.write(SOURCES_PATH, - '\n'.join([x for x in xmldoc.toprettyxml().encode("utf-8").splitlines() if x.strip()])) - else: - filetools.write(SOURCES_PATH, - b'\n'.join([x for x in xmldoc.toprettyxml().encode("utf-8").splitlines() if x.strip()]), - vfs=False) + return False, False -def ask_set_content(flag, silent=False): + +def update_sources(new='', old=''): + logger.info() + if new == old: return + + SOURCES_PATH = xbmc.translatePath("special://userdata/sources.xml") + if filetools.isfile(SOURCES_PATH): + xmldoc = minidom.parse(SOURCES_PATH) + else: + xmldoc = minidom.Document() + source_nodes = xmldoc.createElement("sources") + + for type in ['programs', 'video', 'music', 'picture', 'files']: + nodo_type = xmldoc.createElement(type) + element_default = xmldoc.createElement("default") + element_default.setAttribute("pathversion", "1") + nodo_type.appendChild(element_default) + source_nodes.appendChild(nodo_type) + xmldoc.appendChild(source_nodes) + + # collect nodes + # nodes = xmldoc.getElementsByTagName("video") + video_node = xmldoc.childNodes[0].getElementsByTagName("video")[0] + paths_node = video_node.getElementsByTagName("path") + + if old: + # delete old path + for node in paths_node: + if node.firstChild.data == old: + parent = node.parentNode + remove = parent.parentNode + remove.removeChild(parent) + + # write changes + if sys.version_info[0] >= 3: #PY3 + filetools.write(SOURCES_PATH, '\n'.join([x for x in xmldoc.toprettyxml().splitlines() if x.strip()])) + else: + filetools.write(SOURCES_PATH, '\n'.join([x for x in xmldoc.toprettyxml().splitlines() if x.strip()]), vfs=False) + logger.debug("The path %s has been removed from sources.xml" % old) + + if new: + # create new path + list_path = [p.firstChild.data for p in paths_node] + if new in list_path: + logger.info("The path %s already exists in sources.xml" % new) + return + logger.info("The path %s does not exist in sources.xml" % new) + + # if the path does not exist we create one + source_node = xmldoc.createElement("source") + + # <name> Node + name_node = xmldoc.createElement("name") + sep = os.sep + if new.startswith("special://") or scrapertools.find_single_match(new, r'(^\w+:\/\/)'): + sep = "/" + name = new + if new.endswith(sep): + name = new[:-1] + name_node.appendChild(xmldoc.createTextNode(name.rsplit(sep)[-1])) + source_node.appendChild(name_node) + + # <path> Node + path_node = xmldoc.createElement("path") + path_node.setAttribute("pathversion", "1") + path_node.appendChild(xmldoc.createTextNode(new)) + source_node.appendChild(path_node) + + # <allowsharing> Node + allowsharing_node = xmldoc.createElement("allowsharing") + allowsharing_node.appendChild(xmldoc.createTextNode('true')) + source_node.appendChild(allowsharing_node) + + # Añadimos <source> a <video> + video_node.appendChild(source_node) + + # write changes + if sys.version_info[0] >= 3: #PY3 + filetools.write(SOURCES_PATH, '\n'.join([x for x in xmldoc.toprettyxml().splitlines() if x.strip()])) + else: + filetools.write(SOURCES_PATH, '\n'.join([x for x in xmldoc.toprettyxml().splitlines() if x.strip()]), vfs=False) + logger.debug("The path %s has been added to sources.xml" % new) + + +def ask_set_content(silent=False): logger.info() - logger.debug("videolibrary_kodi_flag %s" % config.get_setting("videolibrary_kodi_flag")) logger.debug("videolibrary_kodi %s" % config.get_setting("videolibrary_kodi")) - def do_config(): - logger.debug("hemos aceptado") - config.set_setting("videolibrary_kodi", True) - set_content("movie", silent=True) - set_content("tvshow", silent=True) - add_sources(config.get_setting("videolibrarypath")) - add_sources(config.get_setting("downloadpath")) - - if not silent: - heading = config.get_localized_string(59971) - linea1 = config.get_localized_string(70105) - linea2 = config.get_localized_string(70106) - if platformtools.dialog_yesno(heading, linea1, linea2): - do_config() + def do_config(custom=False): + if set_content("movie", True, custom) and set_content("tvshow", True, custom): + platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(70104)) + config.set_setting("videolibrary_kodi", True) + update() else: - # no hemos aceptado + platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80024)) config.set_setting("videolibrary_kodi", False) - else: - do_config() + # configuration during installation + if not silent: + # ask to configure Kodi video library + if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(80015)): + # ask for custom or default settings + if not platformtools.dialog_yesno(config.get_localized_string(80026), config.get_localized_string(80016), "", "", config.get_localized_string(80017), config.get_localized_string(80018)): + # input path and folders + path = platformtools.dialog_browse(3, config.get_localized_string(80019), config.get_setting("videolibrarypath")) + movies_folder = platformtools.dialog_input(config.get_setting("folder_movies"), config.get_localized_string(80020)) + tvshows_folder = platformtools.dialog_input(config.get_setting("folder_tvshows"), config.get_localized_string(80021)) - config.set_setting("videolibrary_kodi_flag", flag) + if path != "" and movies_folder != "" and tvshows_folder != "": + movies_path, tvshows_path = check_sources(filetools.join(path, movies_folder), filetools.join(path, tvshows_folder)) + # configure later + if movies_path or tvshows_path: + platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80029)) + # set path and folders + else: + update_sources(path, config.get_setting("videolibrarypath")) + config.set_setting("videolibrarypath", path) + config.set_setting("folder_movies", movies_folder) + config.set_setting("folder_tvshows", tvshows_folder) + config.verify_directories_created() + do_config(True) + # default path and folders + else: + platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80030)) + do_config(True) + # default settings + else: + platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80027)) + do_config(False) + # configure later + else: + platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(80022)) + # configuration from the settings menu + else: + platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80023)) + do_config(True) \ No newline at end of file diff --git a/resources/language/English/strings.po b/resources/language/English/strings.po index c789997b..41632c2d 100644 --- a/resources/language/English/strings.po +++ b/resources/language/English/strings.po @@ -13,12 +13,10 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.0.4\n" -"Last-Translator: MrTruth\n" -"Last-Translator: Angedam\n" "Language: en_EN\n" msgctxt "#20000" -msgid "KOD" +msgid "Kodi on Demand" msgstr "" msgctxt "#20001" @@ -26,23 +24,23 @@ msgid "eng" msgstr "" msgctxt "#30001" -msgid "Check for updates:" +msgid "Check for updates" msgstr "" msgctxt "#30002" -msgid "Enable adult mode:" +msgid "Enable adult mode" msgstr "" msgctxt "#30003" -msgid "Enable debug logging:" +msgid "Enable debug logging" msgstr "" msgctxt "#30004" -msgid "Automatic update channels:" +msgid "Automatically update channels" msgstr "" msgctxt "#30005" -msgid "Default play setting:" +msgid "Video quality" msgstr "" msgctxt "#30006" @@ -50,15 +48,15 @@ msgid "Ask" msgstr "" msgctxt "#30007" -msgid "Watch in low quality" +msgid "Low" msgstr "" msgctxt "#30008" -msgid "Watch in high quality" +msgid "High" msgstr "" msgctxt "#30010" -msgid "Channel icons view:" +msgid "Channel icons view" msgstr "" msgctxt "#30011" @@ -70,23 +68,23 @@ msgid "Banner (horizontal)" msgstr "" msgctxt "#30014" -msgid "Username:" +msgid "Username" msgstr "" msgctxt "#30015" -msgid "Password:" +msgid "Password" msgstr "" msgctxt "#30017" -msgid "Download path:" +msgid "Download path*" msgstr "" msgctxt "#30018" -msgid "Download list path:" +msgid "Download list path" msgstr "" msgctxt "#30019" -msgid "Filter channels by language:" +msgid "Channels language" msgstr "" msgctxt "#30020" @@ -106,12 +104,12 @@ msgid "NO" msgstr "" msgctxt "#30024" -msgid "Select the elements you want to display on the Contextual Menu" +msgid "Contextual menu" msgstr "" msgctxt "#30025" -msgid "KoD Preferences" -msgstr "Preferenze KoD" +msgid "Show KoD settings" +msgstr "" msgctxt "#30026" msgid "Direct" @@ -122,23 +120,23 @@ msgid "SetResolvedUrl" msgstr "" msgctxt "#30028" -msgid "Built-In" +msgid "Built-in" msgstr "" msgctxt "#30029" -msgid "Download and Play" +msgid "Download and play" msgstr "" msgctxt "#30030" -msgid "Advanced Options" +msgid "Advanced options" msgstr "" msgctxt "#30031" -msgid "Delete Download?" +msgid "Continue download?" msgstr "" msgctxt "#30032" -msgid "Select NO to continue downloading in the background" +msgid "Select YES to continue downloading in the background" msgstr "" msgctxt "#30033" @@ -174,11 +172,11 @@ msgid "Do you really want to delete the %s file?" msgstr "" msgctxt "#30043" -msgid "Force view mode:" +msgid "Force view mode" msgstr "" msgctxt "#30044" -msgid "Play mode:" +msgid "Play mode" msgstr "" msgctxt "#30050" @@ -206,11 +204,11 @@ msgid "Unsopported Server" msgstr "" msgctxt "#30067" -msgid "Videolibrary path:" +msgid "Path*" msgstr "" msgctxt "#30068" -msgid "Filter by servers:" +msgid "Filter by servers" msgstr "" msgctxt "#30100" @@ -270,7 +268,7 @@ msgid "Movies" msgstr "" msgctxt "#30123" -msgid "TV Shows" +msgid "TV shows" msgstr "" msgctxt "#30124" @@ -286,11 +284,11 @@ msgid "Adult" msgstr "" msgctxt "#30130" -msgid "Recent" +msgid "News" msgstr "" msgctxt "#30131" -msgid "Videolibrary" +msgid "Video library" msgstr "" msgctxt "#30132" @@ -302,7 +300,7 @@ msgid "Do you want to remove links from this channel?" msgstr "" msgctxt "#30135" -msgid "added to the videolibrary" +msgid "The movie "%s" has been added to the video library" msgstr "" msgctxt "#30136" @@ -317,6 +315,22 @@ msgctxt "#30138" msgid "Live" msgstr "" +msgctxt "#30139" +msgid "Music" +msgstr "" + +msgctxt "#30140" +msgid "Seasons" +msgstr "" + +msgctxt "#30141" +msgid "Skin not supported" +msgstr "" + +msgctxt "#30142" +msgid "Skin %s is not currently supported" +msgstr "" + msgctxt "#30151" msgid "Watch the video" msgstr "" @@ -334,7 +348,7 @@ msgid "Add to favorites" msgstr "" msgctxt "#30161" -msgid "Add to videolibrary" +msgid "Add to video library" msgstr "" msgctxt "#30162" @@ -359,11 +373,11 @@ msgid "Square" msgstr "" msgctxt "#30300" -msgid "Faster context menus" +msgid "Delete also downloaded files?" msgstr "" msgctxt "#30501" -msgid "Paths" +msgid "Path and folders" msgstr "" msgctxt "#30974" @@ -375,7 +389,7 @@ msgid "Movie Info" msgstr "" msgctxt "#30976" -msgid "TVShows - Airing Today" +msgid "TV shows - Airing Today" msgstr "" msgctxt "#30977" @@ -383,7 +397,7 @@ msgid "Last Episodes - On-Air" msgstr "" msgctxt "#30978" -msgid "New TVShows" +msgid "New TV shows" msgstr "" msgctxt "#30979" @@ -467,11 +481,11 @@ msgid "Shortcut" msgstr "" msgctxt "#30999" -msgid "Add key to open Shortcut" +msgid "Assign key to open shortcut" msgstr "" msgctxt "#31000" -msgid "Remove key to open Shortcut" +msgid "Remove key to open shortcut" msgstr "" msgctxt "#50000" @@ -495,17 +509,13 @@ msgid "Path: " msgstr "" msgctxt "#50005" -msgid "Delete This Channel?" +msgid "Delete this channel?" msgstr "" msgctxt "#59970" msgid "Synchronization with Trakt started" msgstr "" -msgctxt "#59971" -msgid "KOD Auto-configuration" -msgstr "" - msgctxt "#59972" msgid "Search for: '%s' | Found: %d vídeos | Time: %2.f seconds" msgstr "" @@ -551,7 +561,7 @@ msgid "torrent" msgstr "" msgctxt "#59983" -msgid "%.2f%% - %.2f %s of %.2f %s a %.2f %s/s (%d/%d)" +msgid "%.2f %s of %.2f %s a %.2f %s/s (%d/%d)" msgstr "" msgctxt "#59985" @@ -591,7 +601,7 @@ msgid "Configuration -- Search" msgstr "" msgctxt "#59994" -msgid "Choose channels to include in your search" +msgid "Channels included in search" msgstr "" msgctxt "#59995" @@ -623,7 +633,7 @@ msgid "No links available that meets the requirements of the Black list. Try aga msgstr "" msgctxt "#60003" -msgid "Connessione con %s" +msgid "Download unseen episodes" msgstr "" msgctxt "#60004" @@ -631,7 +641,7 @@ msgid "No connector for the server %s" msgstr "" msgctxt "#60005" -msgid "Connecting with %s" +msgid "" msgstr "" msgctxt "#60006" @@ -667,7 +677,7 @@ msgid "This website seems to be unavailable, try later, if the problem persists, msgstr "" msgctxt "#60014" -msgid "It may be due to a connection problem, the web page of the channel has changed its structure, or an internal error of KOD. To have more details, see the log file." +msgid "It may be due to a connection problem, the web page of the channel has changed its structure, or an internal error of KoD. To have more details, see the log file." msgstr "" msgctxt "#60015" @@ -691,11 +701,11 @@ msgid "Delete this movie" msgstr "" msgctxt "#60020" -msgid "Mark tv series as not watched" +msgid "Mark TV show as not watched" msgstr "" msgctxt "#60021" -msgid "Mark tv series as watched" +msgid "Mark TV show as watched" msgstr "" msgctxt "#60022" @@ -707,11 +717,11 @@ msgid "Automatically find new episodes: Enable" msgstr "" msgctxt "#60024" -msgid "Delete tv series/channel" +msgid "Delete TV show/channel" msgstr "" msgctxt "#60025" -msgid "Delete tv series" +msgid "Delete TV show" msgstr "" msgctxt "#60026" @@ -759,11 +769,11 @@ msgid "Episode %s" msgstr "" msgctxt "#60037" -msgid "Tv series update ..." +msgid "TV show update..." msgstr "" msgctxt "#60038" -msgid "An error has occurred on KOD" +msgid "An error has occurred in KoD" msgstr "" msgctxt "#60039" @@ -775,7 +785,7 @@ msgid "Delete movie" msgstr "" msgctxt "#60041" -msgid "Delete tv series" +msgid "Delete TV show" msgstr "" msgctxt "#60042" @@ -787,7 +797,7 @@ msgid "Delete %s links of channel %s" msgstr "" msgctxt "#60044" -msgid "Do you want really to delete '%s' from videolibrary?" +msgid "Do you want really to delete '%s' from video library?" msgstr "" msgctxt "#60045" @@ -795,27 +805,27 @@ msgid "Sync with Trakt started" msgstr "" msgctxt "#60046" -msgid "TheMovieDB not present.\nInstall it now?" +msgid "The Movie Database not found. Install it now?" msgstr "" msgctxt "#60047" -msgid "The Movie Database is not installed." +msgid "The Movie Database has not been installed" msgstr "" msgctxt "#60048" -msgid "The TVDB not present.\nInstall it now?" +msgid "The TVDB not found. Install it now?" msgstr "" msgctxt "#60049" -msgid "The TVDB is not installed." +msgid "The TVDB has not been installed" msgstr "" msgctxt "#60050" -msgid "TheMovieDB not present.\nInstall it now?" +msgid "The Movie Database not found. Install it now?" msgstr "" msgctxt "#60051" -msgid "The Movie Database is not installed." +msgid "The Movie Database has not been installed" msgstr "" msgctxt "#60052" @@ -827,31 +837,27 @@ msgid "Do you want to configure this scraper in italian as default option for th msgstr "" msgctxt "#60054" -msgid "Do you want to configure this scraper in italian as default option for the tv series ?" +msgid "Do you want to configure this scraper in italian as default option for the TV shows?" msgstr "" msgctxt "#60055" -msgid "Error of provider configuration in BD." +msgid "Error configuring the information provider in Kodi database" msgstr "" msgctxt "#60056" -msgid "Videolibrary %s not configured" +msgid "Video library %s not configured" msgstr "" msgctxt "#60057" -msgid "Videolibrary %s configured" +msgid "Video library %s configured" msgstr "" msgctxt "#60058" -msgid "You need to restart Kodi for the changes to take effect." -msgstr "" - -msgctxt "#60059" -msgid "Congratulations, Kodi's video library has been configured correctly." +msgid "You need to restart Kodi for the changes to take effect" msgstr "" msgctxt "#60060" -msgid "KOD Auto-configuration" +msgid "Kodi video library configuration" msgstr "" msgctxt "#60062" @@ -863,35 +869,35 @@ msgid "Error in adding movies to your video library..." msgstr "" msgctxt "#60064" -msgid "Adding Episodes to the Video Library..." +msgid "Adding episodes to the video library..." msgstr "" msgctxt "#60065" -msgid "Added Episode to Video Library..." +msgid "Added episode to the video library..." msgstr "" msgctxt "#60066" -msgid "ERROR, It has NOT been possible to add the video to the video library" +msgid "An error has occurred. It has not been possible to add the movie "%s" to the video library" msgstr "" msgctxt "#60067" -msgid "ERROR, tv series has NOT been added to videolibrary\nIt has NOT been possible to add no episode" +msgid "An error has occurred. The TV show "%s" has not been added to the video library. It has not been possible to add any episode" msgstr "" msgctxt "#60068" -msgid "ERROR, tv series has NOT been added to videolibrary" +msgid "An error has occurred. The TV show "%s" has not been added to the video library" msgstr "" msgctxt "#60069" -msgid "ERRORE, tv series has NOT been added completely to videolibrary" +msgid "An error has occurred. The TV show "%s" has not been added completely to the video library" msgstr "" msgctxt "#60070" -msgid "tv series has been added to videolibrary" +msgid "The TV show "%s" has been added to the video library" msgstr "" msgctxt "#60071" -msgid "Autoplay Configuration" +msgid "Autoplay configuration" msgstr "" msgctxt "#60072" @@ -991,7 +997,7 @@ msgid "Download starting..." msgstr "" msgctxt "#60202" -msgid "Remaining time: %s" +msgid "ETA: %s" msgstr "" msgctxt "#60203" @@ -999,11 +1005,11 @@ msgid "Downloader %s/%s" msgstr "" msgctxt "#60204" -msgid "Speed Meter" +msgid "Speed meter" msgstr "" msgctxt "#60205" -msgid "File Writer" +msgid "File writer" msgstr "" msgctxt "#60206" @@ -1063,15 +1069,15 @@ msgid "Copying the file" msgstr "" msgctxt "#60220" -msgid "Error while deleting the file" +msgid "Stop download" msgstr "" msgctxt "#60221" -msgid "Error while deleting the directory" +msgid "Play" msgstr "" msgctxt "#60222" -msgid "Error while creating the directory" +msgid "Stop all downloads" msgstr "" msgctxt "#60223" @@ -1083,11 +1089,11 @@ msgid "Complete information" msgstr "" msgctxt "#60225" -msgid "Search in TheMovieDB.org" +msgid "Search on TMDB" msgstr "" msgctxt "#60226" -msgid "Search in TheTvDB.org" +msgid "Search on TVDB" msgstr "" msgctxt "#60227" @@ -1163,7 +1169,7 @@ msgid "Movie" msgstr "" msgctxt "#60245" -msgid "tv show" +msgid "TV show" msgstr "" msgctxt "#60246" @@ -1227,7 +1233,7 @@ msgid "Problem in the connection process" msgstr "" msgctxt "#60261" -msgid "KOD" +msgid "Kodi on Demand" msgstr "" msgctxt "#60262" @@ -1343,7 +1349,7 @@ msgid "More than 17 years old" msgstr "" msgctxt "#60292" -msgid "Searching for TV Series Information" +msgid "Searching for TV show information" msgstr "" msgctxt "#60293" @@ -1351,7 +1357,7 @@ msgid "Please wait..." msgstr "" msgctxt "#60294" -msgid "Searching for TV Series Information" +msgid "Searching for TV show information" msgstr "" msgctxt "#60295" @@ -1359,7 +1365,7 @@ msgid "Loading results..." msgstr "" msgctxt "#60296" -msgid "Searching for TV Series Information" +msgid "Searching for TV show information" msgstr "" msgctxt "#60297" @@ -1367,7 +1373,7 @@ msgid "Find %s possible matches" msgstr "" msgctxt "#60298" -msgid "[%s]: Select the correct TV series" +msgid "[%s]: Select the correct TV show" msgstr "" msgctxt "#60299" @@ -1483,7 +1489,7 @@ msgid "Restart Kodi to apply changes" msgstr "" msgctxt "#60327" -msgid "Novelties" +msgid "News" msgstr "" msgctxt "#60328" @@ -1499,7 +1505,7 @@ msgid "Favorites" msgstr "" msgctxt "#60331" -msgid "Videolibrary" +msgid "Video library" msgstr "" msgctxt "#60332" @@ -1515,23 +1521,15 @@ msgid "Password for adult channels" msgstr "" msgctxt "#60335" -msgid "Watch in" +msgid "Watch in..." msgstr "" msgctxt "#60336" -msgid "Download in" -msgstr "" - -msgctxt "#60337" -msgid "KOD-MCT: No support adf.ly" -msgstr "" - -msgctxt "#60338" -msgid "The script does not support URL reduction adf.ly." +msgid "Download in..." msgstr "" msgctxt "#60339" -msgid "Nothing to Play" +msgid "Nothing to play" msgstr "" msgctxt "#60342" @@ -1539,17 +1537,13 @@ msgid "Download completed: " msgstr "" msgctxt "#60343" -msgid "BMC-Kodi has closed the video." +msgid "Kodi has closed the video" msgstr "" msgctxt "#60344" msgid "Continue with the session?" msgstr "" -msgctxt "#60345" -msgid "KOD-MCT: List of videos" -msgstr "" - msgctxt "#60346" msgid "Delete video downloads" msgstr "" @@ -1563,7 +1557,7 @@ msgid "Information" msgstr "" msgctxt "#60349" -msgid "Go to the Main Menu" +msgid "Go to the main menu" msgstr "" msgctxt "#60350" @@ -1575,43 +1569,43 @@ msgid "Set as Homepage" msgstr "" msgctxt "#60352" -msgid "Add TV Series to Videolibrary" +msgid "Add TV show to video library" msgstr "" msgctxt "#60353" -msgid "Add Movie to Videolibrary" +msgid "Add movie to video library" msgstr "" msgctxt "#60354" -msgid "Download Movie" +msgid "Download movie" msgstr "" msgctxt "#60355" -msgid "Download TV Series" +msgid "Download TV show" msgstr "" msgctxt "#60356" -msgid "Download Episode" +msgid "Download episode" msgstr "" msgctxt "#60357" -msgid "Download Season" +msgid "Download season" msgstr "" msgctxt "#60358" -msgid "Open Configuration" +msgid "Open configuration" msgstr "" msgctxt "#60359" -msgid "Search Trailer" +msgid "Search trailer" msgstr "" msgctxt "#60360" -msgid "Quick Menu" +msgid "Quick menu" msgstr "" msgctxt "#60361" -msgid "Super Favourites Menu" +msgid "Super favourites menu" msgstr "" msgctxt "#60362" @@ -1623,7 +1617,7 @@ msgid "The server on which it is hosted" msgstr "" msgctxt "#60364" -msgid "is not yet supported in KOD" +msgid "is not yet supported in KoD" msgstr "" msgctxt "#60365" @@ -1663,7 +1657,7 @@ msgid "Genres:" msgstr "" msgctxt "#60383" -msgid "Series:" +msgid "TV show:" msgstr "" msgctxt "#60384" @@ -1687,11 +1681,11 @@ msgid "Summary:" msgstr "" msgctxt "#60389" -msgid "Videolibrary update...." +msgid "Updating %s [%s]..." msgstr "" msgctxt "#60390" -msgid "AutoPlay Configuration" +msgid "AutoPlay configuration" msgstr "" msgctxt "#60391" @@ -1783,11 +1777,11 @@ msgid "Choose channels to include" msgstr "" msgctxt "#60413" -msgid "New Movie Search..." +msgid "New movie search..." msgstr "" msgctxt "#60414" -msgid "New search tv series..." +msgid "New TV show search..." msgstr "" msgctxt "#60415" @@ -1819,8 +1813,8 @@ msgid "Channels included in the global search " msgstr "" msgctxt "#60422" -msgid "Search " -msgstr "" +msgid "Channels search" +msgstr "Ricerca canali" msgctxt "#60423" msgid "Search" @@ -1847,7 +1841,7 @@ msgid "FILTER: Delete '%s'" msgstr "" msgctxt "#60429" -msgid "Filter configuration for TV series..." +msgid "Filter configuration for TV show..." msgstr "" msgctxt "#60430" @@ -1871,7 +1865,7 @@ msgid "Configure [%s]%s" msgstr "" msgctxt "#60435" -msgid "There are no filters, search for a TV series and click on the context menu 'FILTER: Configure'" +msgid "There are no filters, search for a TV show and click on the context menu 'FILTER: Configure'" msgstr "" msgctxt "#60436" @@ -1959,7 +1953,7 @@ msgid " - Links of interest" msgstr "" msgctxt "#60457" -msgid "KOD" +msgid "Kodi On Demand" msgstr "" msgctxt "#60458" @@ -1975,11 +1969,11 @@ msgid "This can be improved by limiting the maximum number of links or by displa msgstr "" msgctxt "#60461" -msgid "KOD - FAQ - %s" +msgid "KoD - FAQ - %s" msgstr "" msgctxt "#60462" -msgid "You may not have written the library path correctly in 'Settings>Preferences'.\nIl The specified path must be exactly the same as the 'source' entered in 'Archive' of the Kodi library.\nAVANZATO: This path is also found in 'sources.xml'.\nThere can be problems using some Kodi forks and paths with 'special://'. SPMC, for example, has problems with this, and there doesn't seem to be a solution, as it is an external problem to Kodi on Demand that has existed for a long time.\nYou can try solving these problems in 'Settings>Library Settings' by changing the 'Search in' setting from 'The folder of each series' to 'All library'." +msgid "You may not have written the library path correctly in 'Settings>Preferences'.\nIl The specified path must be exactly the same as the 'source' entered in 'Archive' of the Kodi library.\nAVANZATO: This path is also found in 'sources.xml'.\nThere can be problems using some Kodi forks and paths with 'special://'. SPMC, for example, has problems with this, and there doesn't seem to be a solution, as it is an external problem to Kodi on Demand that has existed for a long time.\nYou can try solving these problems in 'Settings>Library Settings' by changing the 'Search in' setting from 'The folder of each TV show' to 'All library'." msgstr "" msgctxt "#60463" @@ -1987,7 +1981,7 @@ msgid "The channel site may not work. In case the site works you can report the msgstr "" msgctxt "#60464" -msgid "It is possible that you have updated KOD recently and that the changes have not been fully applied Well, you can try 'Settings>Other Tools', checking the *_data.json files or reattaching everything to the library again" +msgid "It is possible that you have updated KoD recently and that the changes have not been fully applied Well, you can try 'Settings>Other Tools', checking the *_data.json files or reattaching everything to the library again" msgstr "" msgctxt "#60465" @@ -1999,7 +1993,7 @@ msgid "Yes, the option to display merged or split results by channels can be fou msgstr "" msgctxt "#60467" -msgid "To report a problem on'https://t.me/kodiondemand' you need to:|the version you're using of Alpha.|The version you're using of kodi, mediaserver, etc.|the version and name of the operating system you're using.|The name of the skin (in case you're using Kodi) and whether using the default skin has solved the problem.|Description of the problem and any test cases.To activate the log in detailed mode, go to:|Configuration.|Preferences.|In the General tab - Check the option: Generate detailed log. The detailed log file can be found in the following path: \n\n%s" +msgid "To report a problem on'https://t.me/kodiondemand' you need to:|the version you're using of Alpha.|The version you're using of Kodi, mediaserver, etc.|the version and name of the operating system you're using.|The name of the skin (in case you're using Kodi) and whether using the default skin has solved the problem.|Description of the problem and any test cases.To activate the log in detailed mode, go to:|Configuration.|Preferences.|In the General tab - Check the option: Generate detailed log. The detailed log file can be found in the following path: \n\n%s" msgstr "" msgctxt "#60468" @@ -2103,11 +2097,11 @@ msgid "[B]Seasons/Episodes: [/B]" msgstr "" msgctxt "#60493" -msgid "[B]Is there the tv series you're looking for?[/B]" +msgid "[B]Is the TV show you're looking for inlcuded?[/B]" msgstr "" msgctxt "#60494" -msgid "[B]Is there the movie you are looking for?[/B]" +msgid "[B]Is the movie you're looking for inlcuded?[/B]" msgstr "" msgctxt "#60495" @@ -2175,11 +2169,11 @@ msgid "Kids" msgstr "" msgctxt "#60511" -msgid "TV series Episodes" +msgid "TV shows" msgstr "" msgctxt "#60512" -msgid "Anime Episodes" +msgid "Anime" msgstr "" msgctxt "#60513" @@ -2231,7 +2225,7 @@ msgid " (In %s)" msgstr "" msgctxt "#60525" -msgid "Channels included in:" +msgid "Included channels by category" msgstr "" msgctxt "#60526" @@ -2243,11 +2237,11 @@ msgid " - Kids" msgstr "" msgctxt "#60528" -msgid " - Series Tv Episodes" +msgid " - TV show episodes" msgstr "" msgctxt "#60529" -msgid " - Anime Episodes" +msgid " - Anime episodes" msgstr "" msgctxt "#60530" @@ -2255,7 +2249,7 @@ msgid " - Documentaries" msgstr "" msgctxt "#60531" -msgid "Other Settings" +msgid "Other settings" msgstr "" msgctxt "#60532" @@ -2299,7 +2293,7 @@ msgid "Download settings" msgstr "" msgctxt "#60542" -msgid "Videolibrary settings" +msgid "Video library settings" msgstr "" msgctxt "#60544" @@ -2383,15 +2377,15 @@ msgid " Check the files * _data.json" msgstr "" msgctxt "#60566" -msgid "Videolibrary options" +msgid "Video library options" msgstr "" msgctxt "#60567" -msgid "Overwrite the entire video library (strm, nfo and json)" +msgid "Restore video library (strm, nfo and json)" msgstr "" msgctxt "#60568" -msgid "Search for new episodes and update the video library" +msgid "Search for new episodes and update video library" msgstr "" msgctxt "#60569" @@ -2427,7 +2421,7 @@ msgid "A saving error occurred" msgstr "" msgctxt "#60581" -msgid "Overwriting the entire video library" +msgid "Restoring video library" msgstr "" msgctxt "#60582" @@ -2439,19 +2433,19 @@ msgid "Do you want to continue?" msgstr "" msgctxt "#60584" -msgid "Overwriting the video library...TV SERIES" +msgid "Restoring TV shows video library" msgstr "" msgctxt "#60585" -msgid "kod" +msgid "Kodi on Demand" msgstr "" msgctxt "#60586" -msgid "Overwriting the video library...MOVIES" +msgid "Restoring movies video library" msgstr "" msgctxt "#60587" -msgid "Video library update...." +msgid "Channel configuration" msgstr "" msgctxt "#60588" @@ -2495,11 +2489,11 @@ msgid " Server #%s" msgstr "" msgctxt "#60598" -msgid "Configuration -- Video Library" +msgid "Configuration of video library" msgstr "" msgctxt "#60600" -msgid "Series" +msgid "TV shows" msgstr "" msgctxt "#60601" @@ -2523,7 +2517,7 @@ msgid "At the start of Kodi and once a day" msgstr "" msgctxt "#60606" -msgid " Wait before updating at startup of Kodi" +msgid " Wait before updating at startup of Kodi" msgstr "" msgctxt "#60607" @@ -2547,11 +2541,11 @@ msgid "60 sec" msgstr "" msgctxt "#60613" -msgid " Begin scheduled update from" +msgid " Begin scheduled update from" msgstr "" msgctxt "#60614" -msgid " Search for new episodes in active tv series" +msgid " Search for new episodes in active TV shows" msgstr "" msgctxt "#60615" @@ -2567,11 +2561,11 @@ msgid "According to new episodes" msgstr "" msgctxt "#60618" -msgid " Search for content in" +msgid " Search for content in" msgstr "" msgctxt "#60619" -msgid "The folder of each tv series" +msgid "The folder of each TV show" msgstr "" msgctxt "#60620" @@ -2583,7 +2577,7 @@ msgid "Show links in" msgstr "" msgctxt "#60622" -msgid "Conventional window" +msgid "Normal window" msgstr "" msgctxt "#60623" @@ -2591,7 +2585,7 @@ msgid "Pop-up window" msgstr "" msgctxt "#60624" -msgid " Maximum number of links to display (recommended for slow devices)" +msgid " Maximum number of links to display" msgstr "" msgctxt "#60625" @@ -2599,35 +2593,27 @@ msgid "All" msgstr "" msgctxt "#60626" -msgid " Sort by whitelist" +msgid " Sort by whitelist" msgstr "" msgctxt "#60627" -msgid " Remove the channel name at the beginning" +msgid " Remove the channel name at the beginning" msgstr "" msgctxt "#60628" -msgid " Pop-up window: Replace \'View in\' with \'[V]\' and \'Download in\' with \'[D]\'" +msgid " Replace \'View in\' with \'[V]\' and \'Download in\' with \'[D]\'" msgstr "" msgctxt "#60629" -msgid "Database location" -msgstr "" - -msgctxt "#60630" -msgid "Local" -msgstr "" - -msgctxt "#60631" -msgid "Remote" -msgstr "" +msgid "Remote database" +msgstr "Database remoto" msgctxt "#60632" -msgid " Server Name" +msgid " Server name" msgstr "" msgctxt "#60633" -msgid " Server port" +msgid " Server port" msgstr "" msgctxt "#60634" @@ -2635,7 +2621,7 @@ msgid "Automatically mark as watched" msgstr "" msgctxt "#60635" -msgid " Video viewing time" +msgid " Video viewing time" msgstr "" msgctxt "#60636" @@ -2647,27 +2633,27 @@ msgid "Synchronizing with Trakt" msgstr "" msgctxt "#60638" -msgid " After mark as watched the episode" +msgid " After mark as watched the episode" msgstr "" msgctxt "#60639" -msgid " Show notification" +msgid " Show notification" msgstr "" msgctxt "#60640" -msgid " On adding a TV series to the video library" +msgid " On adding a TV show to the video library" msgstr "" msgctxt "#60641" -msgid " Wait until the tv series is added" +msgid " Wait until the TV show is added" msgstr "" msgctxt "#60642" -msgid "Show option \"All Seasons\"." +msgid "Show option \'All Seasons\'" msgstr "" msgctxt "#60643" -msgid "Do not combine the seasons of the series" +msgid "Do not combine the seasons of the TV shows" msgstr "" msgctxt "#60644" @@ -2679,35 +2665,27 @@ msgid "Show channel selection box" msgstr "" msgctxt "#60646" -msgid "Create directories on your system using" -msgstr "" - -msgctxt "#60647" -msgid "Localized title" +msgid "Create folders using original title" msgstr "" msgctxt "#60648" msgid "Never" msgstr "" -msgctxt "#60649" -msgid "Original title" -msgstr "" - msgctxt "#60650" -msgid "When you add content, you get information from:" +msgid "Video library information provider" msgstr "" msgctxt "#60651" -msgid " Movies:" +msgid " Movies" msgstr "" msgctxt "#60652" -msgid " TV Series:" +msgid " TV show" msgstr "" msgctxt "#60653" -msgid " If there are no results also search in English" +msgid " If there are no results search in English" msgstr "" msgctxt "#60654" @@ -2723,7 +2701,7 @@ msgid "Simultaneous search (multiprocessing)" msgstr "" msgctxt "#60657" -msgid "Show Results:" +msgid "Show results" msgstr "" msgctxt "#60658" @@ -2743,7 +2721,7 @@ msgid "News" msgstr "" msgctxt "#60662" -msgid "code cleaning" +msgid " Language" msgstr "" msgctxt "#60663" @@ -2787,7 +2765,7 @@ msgid "Global Search" msgstr "" msgctxt "#60673" -msgid "Number of Search Threads" +msgid "Number of search threads" msgstr "" msgctxt "#60674" @@ -2823,11 +2801,11 @@ msgid "movies" msgstr "" msgctxt "#60682" -msgid "tv series" +msgid "TV show" msgstr "" msgctxt "#60683" -msgid "anime" +msgid "Loading streams..." msgstr "" msgctxt "#70000" @@ -2867,7 +2845,7 @@ msgid "Reload" msgstr "" msgctxt "#70009" -msgid "Classic Menu" +msgid "Main menu" msgstr "" msgctxt "#70010" @@ -2899,7 +2877,7 @@ msgid "Active channels" msgstr "" msgctxt "#70017" -msgid "TV Series" +msgid "TV show" msgstr "" msgctxt "#70018" @@ -2923,7 +2901,7 @@ msgid " - Movies" msgstr "" msgctxt "#70023" -msgid " - TV Shows" +msgid " - TV shows" msgstr "" msgctxt "#70024" @@ -2943,7 +2921,7 @@ msgid "Search engine settings" msgstr "" msgctxt "#70028" -msgid "Most Popular" +msgid "Most popular" msgstr "" msgctxt "#70029" @@ -2983,7 +2961,7 @@ msgid "Search director, writer..." msgstr "" msgctxt "#70038" -msgid "Custom Filter" +msgid "Custom filter" msgstr "" msgctxt "#70039" @@ -2994,10 +2972,6 @@ msgctxt "#70040" msgid "Top Filmaffinity" msgstr "" -msgctxt "#70041" -msgid "Modern TV Shows" -msgstr "" - msgctxt "#70042" msgid "Year" msgstr "" @@ -3011,11 +2985,11 @@ msgid "Sagas and Collections" msgstr "" msgctxt "#70045" -msgid "Movies/TV Shows/Documentaries by Themes" +msgid "Movies/TV shows/Documentaries" msgstr "" msgctxt "#70046" -msgid "Search Movies/TV Shows" +msgid "Search Movies/TV shows" msgstr "" msgctxt "#70047" @@ -3063,7 +3037,7 @@ msgid "My lists" msgstr "" msgctxt "#70058" -msgid "Top Series" +msgid "Top TV shows" msgstr "" msgctxt "#70059" @@ -3087,7 +3061,7 @@ msgid "Anime by Genres" msgstr "" msgctxt "#70064" -msgid "Search Tv Shows/Movies/Anime" +msgid "Search TV shows/Movies/Anime" msgstr "" msgctxt "#70065" @@ -3107,7 +3081,7 @@ msgid "In my Collection" msgstr "" msgctxt "#70069" -msgid "Search %s in KOD: %s" +msgid "Search %s in KoD: %s" msgstr "" msgctxt "#70070" @@ -3163,7 +3137,7 @@ msgid "Delete movie" msgstr "" msgctxt "#70085" -msgid "Delete TV Show" +msgid "Delete TV show" msgstr "" msgctxt "#70086" @@ -3175,7 +3149,7 @@ msgid "Deleted %s links from canal %s" msgstr "" msgctxt "#70088" -msgid "Are you sure you want to delete '%s' from videolibrary ?" +msgid "Are you sure you want to delete '%s' from video library?" msgstr "" msgctxt "#70089" @@ -3191,7 +3165,7 @@ msgid " Words" msgstr "" msgctxt "#70092" -msgid "Add to videolibrary" +msgid "Add to video library" msgstr "" msgctxt "#70093" @@ -3199,11 +3173,11 @@ msgid "The Movie Database" msgstr "" msgctxt "#70094" -msgid "Select scraper for movies" +msgid "Select the information provider for movies" msgstr "" msgctxt "#70095" -msgid "Universal Movie Scraper not present.\nInstall it now?" +msgid "Universal Movie Scraper not found. Install it now?" msgstr "" msgctxt "#70096" @@ -3211,7 +3185,7 @@ msgid "Universal Movie Scraper" msgstr "" msgctxt "#70097" -msgid "Universal Movie Scraper not installed." +msgid "Universal Movie Scraper has not been installed" msgstr "" msgctxt "#70098" @@ -3219,31 +3193,27 @@ msgid "The TVDB" msgstr "" msgctxt "#70099" -msgid "The TVDB not installed." -msgstr "" - -msgctxt "#70100" -msgid "The Movie Database not present.\nInstall it now?" +msgid "The TVDB has not been installed" msgstr "" msgctxt "#70101" -msgid "Error fixing videolibrarypath in BD" +msgid "Error inserting the video library path in Kodi database" msgstr "" msgctxt "#70102" -msgid "Videolibrary %s not configured" +msgid "Video library %s not configured" msgstr "" msgctxt "#70103" -msgid "Videolibrary %s configured" +msgid "Video library %s configured" msgstr "" msgctxt "#70104" -msgid "Congratulations, the Kodi video library has been configured correctly." +msgid "The Kodi video library has been successfully configured" msgstr "" msgctxt "#70105" -msgid "Do you want KOD to automatically configure the Kodi library? You will be asked to set up scrapers for movies and series." +msgid "Do you want KoD to configure the Kodi library? You will be asked to set up scrapers for movies and TV shows." msgstr "" msgctxt "#70106" @@ -3251,23 +3221,23 @@ msgid "If you choose 'No' you can do it later from 'Configuration > Preferences msgstr "" msgctxt "#70107" -msgid "Select scraper for Tv Shows" +msgid "Select the information provider for TV shows" msgstr "" msgctxt "#70108" -msgid "Icons Set" +msgid "Icons set" msgstr "" msgctxt "#70109" -msgid "Sync with Trakt.tv (You must have an account)" +msgid "Syncronize with Trakt.tv" msgstr "" msgctxt "#70110" -msgid "Priority Method" +msgid "Priority method" msgstr "" msgctxt "#70111" -msgid "Stop looking when you find an option" +msgid "Stop search when find an option" msgstr "" msgctxt "#70112" @@ -3287,35 +3257,35 @@ msgid "Request password to open adult channels" msgstr "" msgctxt "#70116" -msgid "New password:" +msgid "New password" msgstr "" msgctxt "#70117" -msgid "Confirm New password:" +msgid "Confirm new password" msgstr "" msgctxt "#70118" -msgid "Folder name for 'Series'" +msgid "TV shows folder*" msgstr "" msgctxt "#70119" -msgid "Folder name for 'Movies'" +msgid "Movies folder*" msgstr "" msgctxt "#70120" -msgid "Autoconfigure XBMC / Kodi library for KOD content" +msgid "Add KoD contents to Kodi video library*" msgstr "" msgctxt "#70121" -msgid "Activate Home Page" +msgid "Activate" msgstr "" msgctxt "#70122" -msgid "Custom (select from a channel)" +msgid "Show channel (select it from homepage)" msgstr "" msgctxt "#70123" -msgid "Show Recent" +msgid "Show news" msgstr "" msgctxt "#70124" @@ -3323,7 +3293,7 @@ msgid "Category" msgstr "" msgctxt "#70125" -msgid "Movie|Tv Shows|Anime|Children|Documentary|Horror|Castellan|Latin|Torrent" +msgid "Movie|TV shows|Anime|Children|Documentary|Horror|Castellan|Latin|Torrent" msgstr "" msgctxt "#70126" @@ -3363,7 +3333,7 @@ msgid "Custom Colours" msgstr "" msgctxt "#70136" -msgid "Tv Show" +msgid "TV shows" msgstr "" msgctxt "#70137" @@ -3403,15 +3373,15 @@ msgid "Servers" msgstr "" msgctxt "#70146" -msgid "Add to videolibrary" +msgid "Add to video library" msgstr "" msgctxt "#70147" -msgid "Videolibrary (Update series)" +msgid "Video library (update TV show)" msgstr "" msgctxt "#70148" -msgid "Videolibrary (Do not update series)" +msgid "Video library (do not update TV show)" msgstr "" msgctxt "#70149" @@ -3419,35 +3389,35 @@ msgid "Others" msgstr "" msgctxt "#70150" -msgid "Movie/series info in contextual menu" +msgid "Contextual menu" msgstr "" msgctxt "#70151" -msgid "Show Infoplus option:" +msgid "Show Infoplus" msgstr "" msgctxt "#70152" -msgid "Show ExtendedInfo option (External addon required):" +msgid "Show ExtendedInfo" msgstr "" msgctxt "#70153" -msgid "Buttons/Access keys (Changes require Kodi restart)" +msgid "Shortcut" msgstr "" msgctxt "#70154" -msgid "TheMovieDB (obtains data from movies or series)" +msgid "TMDB search" msgstr "" msgctxt "#70155" -msgid "Simultaneous searches (may cause instability)" +msgid "Simultaneous searches" msgstr "" msgctxt "#70156" -msgid "Search extended information (actor's data) Increase search time" +msgid "Search actor's information" msgstr "" msgctxt "#70157" -msgid "Use cache (improves recurring searches)" +msgid "Use cache" msgstr "" msgctxt "#70158" @@ -3471,7 +3441,7 @@ msgid "Renew cache?" msgstr "" msgctxt "#70163" -msgid "Press to 'Clear cache' saved" +msgid "Clear cache" msgstr "" msgctxt "#70164" @@ -3567,11 +3537,11 @@ msgid "Getting episodes..." msgstr "" msgctxt "#70187" -msgid "connecting with %s..." +msgid "" msgstr "" msgctxt "#70188" -msgid "Obtaining data from the series" +msgid "Obtaining data for the TV show" msgstr "" msgctxt "#70189" @@ -3595,11 +3565,11 @@ msgid "Open torrent with..." msgstr "" msgctxt "#70194" -msgid "KOD-torrent" +msgid "KoD-torrent" msgstr "" msgctxt "#70195" -msgid "KOD - Torrent" +msgid "KoD - Torrent" msgstr "" msgctxt "#70196" @@ -3743,11 +3713,11 @@ msgid "Add completed downloads to the video library " msgstr "" msgctxt "#70231" -msgid "Move the downloaded file to the video library" +msgid "Move downloaded files to the video library" msgstr "" msgctxt "#70232" -msgid "View files downloaded from downloads" +msgid "View downloaded files" msgstr "" msgctxt "#70233" @@ -3779,11 +3749,11 @@ msgid "Preferred quality" msgstr "" msgctxt "#70241" -msgid "The highest" +msgid "Highest" msgstr "" msgctxt "#70242" -msgid "Choose the fastest servers" +msgid "Choose fastest servers" msgstr "" msgctxt "#70243" @@ -3847,7 +3817,7 @@ msgid "Settings -- Torrent" msgstr "" msgctxt "#70258" -msgid "KOD Started" +msgid "KoD started" msgstr "" msgctxt "#70259" @@ -3867,11 +3837,11 @@ msgid "Stopping the Websocket server ..." msgstr "" msgctxt "#70263" -msgid "KOD stopped" +msgid "KoD stopped" msgstr "" msgctxt "#70264" -msgid "Enter the username and password to access KOD" +msgid "Enter the username and password to access KoD" msgstr "" msgctxt "#70265" @@ -3887,11 +3857,11 @@ msgid "Search new episodes now" msgstr "" msgctxt "#70270" -msgid "Videolibrary movies" +msgid "Movies video library" msgstr "" msgctxt "#70271" -msgid "Videolibrary Tv Shows" +msgid "TV shows video library" msgstr "" msgctxt "#70272" @@ -3947,19 +3917,19 @@ msgid "%.2f%% of %.1fMB %s | %.1f kB/s" msgstr "" msgctxt "#70285" -msgid "Configure News" +msgid "Configure news" msgstr "" msgctxt "#70286" -msgid "Configure Search" +msgid "Configure search" msgstr "" msgctxt "#70287" -msgid "Configure VideoLibrary" +msgid "Configure video library" msgstr "" msgctxt "#70288" -msgid "Configure Downloads" +msgid "Configure downloads" msgstr "" msgctxt "#70291" @@ -4039,19 +4009,19 @@ msgid "Movies Now in Theatres " msgstr "" msgctxt "#70310" -msgid "Series by Genre" +msgid "TV shows by Genre" msgstr "" msgctxt "#70311" -msgid "Series most polupar" +msgid "TV shows most popular" msgstr "" msgctxt "#70312" -msgid "Series in progress" +msgid "TV shows in progress" msgstr "" msgctxt "#70313" -msgid "Top rated Series" +msgid "Top rated TV shows" msgstr "" msgctxt "#70314" @@ -4199,7 +4169,7 @@ msgid "List sorted by %s. Change order?" msgstr "" msgctxt "#70350" -msgid "Search in kod: %s" +msgid "Search in KoD: %s" msgstr "" msgctxt "#70351" @@ -4467,7 +4437,7 @@ msgid "=== Movies ===" msgstr "" msgctxt "#70417" -msgid "=== TV Shows ===" +msgid "=== TV shows ===" msgstr "" msgctxt "#70418" @@ -4955,7 +4925,7 @@ msgid "* To add links to folders, access the context menu from any point in Kodi msgstr "" msgctxt "#70541" -msgid "* The links can be channels, sections within the channels, searches, and even movies and series although for the latter it is preferable to use the video library." +msgid "* The links can be channels, sections within the channels, searches, and even movies and TV shows although for the latter it is preferable to use the video library." msgstr "" msgctxt "#70542" @@ -5027,19 +4997,19 @@ msgid "Select color:" msgstr "" msgctxt "#70559" -msgid "Now in Theatres " +msgid "Now in theatres " msgstr "" msgctxt "#70560" -msgid "Movies by Genre" +msgid "Movies by genre" msgstr "" msgctxt "#70561" -msgid "Search Similar" +msgid "Search similar" msgstr "" msgctxt "#70562" -msgid "Enable autoplay on all supported channels" +msgid "Enable AutoPlay on all supported channels" msgstr "" msgctxt "#70563" @@ -5047,11 +5017,11 @@ msgid "Italian" msgstr "" msgctxt "#70564" -msgid "Enable Custom Theme" +msgid "Enable custom theme" msgstr "" msgctxt "#70565" -msgid "Custom Theme Path" +msgid "Custom theme path" msgstr "" msgctxt "#70566" @@ -5103,15 +5073,15 @@ msgid "Modify starting from " msgstr "" msgctxt "#70578" -msgid "To avoid waiting too long when a server does not respond:" +msgid "Torrents" msgstr "" msgctxt "#70579" -msgid "Settings of KoD updates:" +msgid "Updates" msgstr "" msgctxt "#70580" -msgid "Timeout (maximum waiting time)" +msgid "Server answer timeout (seconds)" msgstr "" msgctxt "#70581" @@ -5119,11 +5089,11 @@ msgid "Check for updates" msgstr "" msgctxt "#70582" -msgid "Do you want to be notified?" +msgid "Updates notification" msgstr "" msgctxt "#70583" -msgid "Management of updates of other addons related to KOD:" +msgid "Management of updates of other addons related to KoD:" msgstr "" msgctxt "#70584" @@ -5135,7 +5105,7 @@ msgid "Renumbering" msgstr "" msgctxt "#70586" -msgid "Set up series number..." +msgid "Set up TV show renumbering..." msgstr "" msgctxt "#70587" @@ -5143,7 +5113,7 @@ msgid "Set up" msgstr "" msgctxt "#70588" -msgid "No series found, look for a series and click on contextual menu" +msgid "No TV show found, look for a TV show and click on contextual menu" msgstr "" msgctxt "#70589" @@ -5199,7 +5169,7 @@ msgid "Update from the Internet:" msgstr "" msgctxt "#70602" -msgid "The first season that is added always starts in \"0 \" episodes, the second season that is added starts in the total number of episodes of the first season, the third season will be the sum of the episodes of the previous seasons and so on.\n \nSerial example divided into several seasons: \n\nFairy Tail: \n - SEASON 1: EPISODE 48 -> [season 1, episode: 0] \n - SEASON 2: EPISODE 48 - -> [season 2, episode: 48] \n - SEASON 3: EPISODE 54 -> [season 3, episode: 96 ([48 = season2] + [48 = season1])] \n - SEASON 4: EPISODE 175 -> [season 4: episode: 150 ([54 = season3] + [48 = season2] + [48 = season3])] \n \nExample of a series that continues in the season of the original: \n \nFate / Zero 2nd Season: \n - SEASON 1: EPISODE 12 -> [season 1, episode: 13] \n \nExample example which is the second Season of the original: \n \nFate / kaleid liner Prism☆Illya 2wei!: \n - SEASON 1: EPISODE 12 -> [season 2, episode: 0] \n" +msgid "The first season that is added always starts in \"0 \" episodes, the second season that is added starts in the total number of episodes of the first season, the third season will be the sum of the episodes of the previous seasons and so on.\n \nTV show example divided into several seasons: \n\nFairy Tail: \n - SEASON 1: EPISODE 48 -> [season 1, episode: 0] \n - SEASON 2: EPISODE 48 - -> [season 2, episode: 48] \n - SEASON 3: EPISODE 54 -> [season 3, episode: 96 ([48 = season2] + [48 = season1])] \n - SEASON 4: EPISODE 175 -> [season 4: episode: 150 ([54 = season3] + [48 = season2] + [48 = season3])] \n \nExample of a TV show that continues in the season of the original: \n \nFate / Zero 2nd Season: \n - SEASON 1: EPISODE 12 -> [season 1, episode: 13] \n \nExample which is the second season of the original: \n \nFate / kaleid liner Prism☆Illya 2wei!: \n - SEASON 1: EPISODE 12 -> [season 2, episode: 0] \n" msgstr "" msgctxt "#70603" @@ -5494,15 +5464,15 @@ msgid "Addon successfully updated to %s.fix %d" msgstr "" msgctxt "#70673" -msgid "Alpha updated to" +msgid "KoD updated to" msgstr "" msgctxt "#70674" -msgid "KOD updates" +msgid "KoD updates" msgstr "" msgctxt "#70675" -msgid "Error checking updates" +msgid "Unable to check the updates" msgstr "" msgctxt "#70676" @@ -5522,7 +5492,7 @@ msgid "From URL" msgstr "" msgctxt "#70680" -msgid "KOD - (Community)" +msgid "KoD - (Community)" msgstr "" msgctxt "#70681" @@ -5554,11 +5524,11 @@ msgid "Special Episodes" msgstr "" msgctxt "#70688" -msgid "Are there special episodes in the series \n(Episode 0 Excluded)?" +msgid "Are there special episodes in the TV show \n(Episode 0 Excluded)?" msgstr "" msgctxt "#70689" -msgid "Enable Download" +msgid "Enable download" msgstr "" msgctxt "#70690" @@ -5570,7 +5540,7 @@ msgid "Using the download function you declare that you have a physical copy and msgstr "" msgctxt "#70692" -msgid "The KOD team assumes no responsibility for the use that is made of this proposed function" +msgid "The KoD team assumes no responsibility for the use that is made of this proposed function" msgstr "" msgctxt "#70693" @@ -5610,7 +5580,7 @@ msgid "Restart Kodi to apply the changes" msgstr "" msgctxt "#70703" -msgid "Create directories with lowercase letters" +msgid "Create folders with lowercase letters" msgstr "" msgctxt "#70704" @@ -5622,7 +5592,7 @@ msgid "Use your custom channel URLs" msgstr "" msgctxt "#70706" -msgid "Autostart KOD at Kodi boot" +msgid "Launch KoD at Kodi start" msgstr "" msgctxt "#70707" @@ -5654,11 +5624,11 @@ msgid "Modify " msgstr " " msgctxt "#70715" -msgid "Customize Homepage" +msgid "Customized main menu" msgstr "" msgctxt "#70716" -msgid "Select the elements you want to display on the Homepage" +msgid "Main menu items" msgstr "" msgctxt "#70717" @@ -5737,8 +5707,12 @@ msgctxt "#70735" msgid "%s Special Episode Number" msgstr "" +msgctxt "#70736" +msgid "Completed TV show" +msgstr "" + msgctxt "#70737" -msgid "Side Menu" +msgid "Side menu" msgstr "" msgctxt "#70738" @@ -5762,7 +5736,7 @@ msgid "Movies by Year" msgstr "" msgctxt "#70743" -msgid "Series by Year" +msgid "TV shows by Year" msgstr "" msgctxt "#70744" @@ -5806,7 +5780,7 @@ msgid "Playback" msgstr "" msgctxt "#70754" -msgid "Display mode" +msgid "View types" msgstr "" msgctxt "#70755" @@ -5909,13 +5883,54 @@ msgctxt "#70779" msgid "This will take %s + times the size of the video" msgstr "" +msgctxt "#70780" +msgid "Elementum with memory download does not support to extract online RAR files (disk occupation %s + times)" +msgstr "" + +msgctxt "#70781" +msgid "Do you want to call Elementum Settings to temporarily switch to Use Files?" +msgstr "" + +msgctxt "#70782" +msgid "Your device is not compatible with the Internal Client, do you want to use Quasar for Torrents?" +msgstr "" + +msgctxt "#70783" +msgid "Quasar installed and configured, enjoy!" +msgstr "" + +msgctxt "#70784" +msgid "Attention!!" +msgstr "Attenzione!" + +msgctxt "#70785" +msgid "Install Quasar" +msgstr "" + +msgctxt "#70786" +msgid "Autostart" +msgstr "" + +msgctxt "#70787" +msgid "Network" +msgstr "" + +msgctxt "#70788" +msgid "Logging" +msgstr "" + +msgctxt "#70789" +msgid "* Change by opening the settings from KoD main menu" +msgstr "" + + # DNS start [ settings and declaration ] msgctxt "#707401" -msgid "Enable DNS Check Alert" +msgid "Enable DNS check alert" msgstr "" msgctxt "#707402" -msgid "Connection or DNS problems" +msgid "Connection or DNS problem" msgstr "" msgctxt "#707403" @@ -5935,7 +5950,7 @@ msgid "By disabling the alert, you have activated a notice\nthat will appear at msgstr "" msgctxt "#707407" -msgid "For any change to the DNS you MUST restart KODI!" +msgid "For any change to the DNS you MUST restart Kodi!" msgstr "" msgctxt "#707408" @@ -5971,7 +5986,7 @@ msgid "You have not selected any choice, the cloudflare DNS will be used." msgstr "" msgctxt "#707416" -msgid "how often you want to check for updates? (hours)" +msgid "Updates check interval (hours)" msgstr "" msgctxt "#707417" @@ -6015,7 +6030,7 @@ msgid "before generating the report" msgstr "" msgctxt "#707427" -msgid "Unable to read kodi log" +msgid "Unable to read Kodi log" msgstr "" msgctxt "#707428" @@ -6044,4 +6059,164 @@ msgstr "" msgctxt "#707434" msgid "reCaptcha verification failed" +msgstr "" + +msgctxt "#80000" +msgid "Export video library" +msgstr "" + +msgctxt "#80001" +msgid "Import video library" +msgstr "" + +msgctxt "#80002" +msgid "Select the folder where to export the video library" +msgstr "" + +msgctxt "#80003" +msgid "Exporting video library..." +msgstr "" + +msgctxt "#80004" +msgid "The video library has been exported" +msgstr "" + +msgctxt "#80005" +msgid "Select the zip file to be imported" +msgstr "" + +msgctxt "#80006" +msgid "Attention, the current video library will be overwritten. Proceed anyway?" +msgstr "" + +msgctxt "#80007" +msgid "Importing video library..." +msgstr "" + +msgctxt "#80008" +msgid "The video library has been imported" +msgstr "" + +msgctxt "#80009" +msgid "Would you like to search for new episodes and update video library?" +msgstr "" + +msgctxt "#80010" +msgid "Select the video library path" +msgstr "" + +msgctxt "#80011" +msgid "Verifying folders..." +msgstr "" + +msgctxt "#80012" +msgid "Moving video library..." +msgstr "" + +msgctxt "#80013" +msgid "Updating database..." +msgstr "" + +msgctxt "#80014" +msgid "The video library has been moved" +msgstr "" + +msgctxt "#80015" +msgid "Do you want to configure the Kodi video library?" +msgstr "" + +msgctxt "#80016" +msgid "Would you like to use custom or default settings?" +msgstr "" + +msgctxt "#80017" +msgid "Custom" +msgstr "" + +msgctxt "#80018" +msgid "Default" +msgstr "" + +msgctxt "#80019" +msgid "Select the video library path" +msgstr "" + +msgctxt "#80020" +msgid "Folder name for movies" +msgstr "" + +msgctxt "#80021" +msgid "Folder name for TV shows" +msgstr "" + +msgctxt "#80022" +msgid "You can configure the Kodi video library later from the settings menu inside KoD" +msgstr "" + +msgctxt "#80023" +msgid "You will be asked to choose and configure the information providers for movies and TV shows" +msgstr "" + +msgctxt "#80024" +msgid "An error has occurred during the configuration of the Kodi video library. Please check the log and try again from the settings menu inside KoD" +msgstr "" + +msgctxt "#80025" +msgid "Cleaning database..." +msgstr "" + +msgctxt "#80026" +msgid "Configuration of Kodi video library" +msgstr "" + +msgctxt "#80027" +msgid "You will be asked to configure The Movie Database for movies and The TVDB for TV shows" +msgstr "" + +msgctxt "#80028" +msgid "The selected folders are already used by the Kodi library. Please change them properly" +msgstr "" + +msgctxt "#80029" +msgid "The selected folders are already used by the Kodi library. Please change them properly from the settings menu inside KoD" +msgstr "" + +msgctxt "#80030" +msgid "The default path and folders will be used. You will be asked to choose and configure the information providers for movies and TV shows" +msgstr "" + +msgctxt "#80031" +msgid "Unable to connect to github. This is probably due to a lack of connection or github is currently offline. Please check and try again" +msgstr "" + +msgctxt "#80032" +msgid "Installation in progress..." +msgstr "" + +msgctxt "#80033" +msgid "Choose the version of KoD to install" +msgstr "" + +msgctxt "#80034" +msgid "release (stable version)" +msgstr "" + +msgctxt "#80035" +msgid "master (beta version under development)" +msgstr "" + +msgctxt "#80036" +msgid "Delete video library" +msgstr "" + +msgctxt "#80037" +msgid "Attention, the entire video library will be deleted. Proceed anyway?" +msgstr "" + +msgctxt "#80038" +msgid "Deleting video library..." +msgstr "" + +msgctxt "#80039" +msgid "The video library has been deleted" msgstr "" \ No newline at end of file diff --git a/resources/language/Italian/strings.po b/resources/language/Italian/strings.po index fcac2faf..0e8b3116 100644 --- a/resources/language/Italian/strings.po +++ b/resources/language/Italian/strings.po @@ -13,53 +13,51 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.0.4\n" -"Last-Translator: MrTruth\n" -"Last-Translator: Angedam\n" "Language: it_IT\n" msgctxt "#20000" -msgid "KOD" -msgstr "KOD" +msgid "Kodi on Demand" +msgstr "Kodi on Demand" msgctxt "#20001" msgid "eng" msgstr "ita" msgctxt "#30001" -msgid "Check for updates:" -msgstr "Verifica aggiornamenti:" +msgid "Check for updates" +msgstr "Verifica aggiornamenti" msgctxt "#30002" -msgid "Enable adult mode:" -msgstr "Abilita modalità adulti:" +msgid "Enable adult mode" +msgstr "Abilita modalità adulti" msgctxt "#30003" -msgid "Enable debug logging:" -msgstr "Abilita logging di debug:" +msgid "Enable debug logging" +msgstr "Abilita logging di debug" msgctxt "#30004" -msgid "Automatic update channels:" -msgstr "Aggiorna automaticamente i canali:" +msgid "Automatically update channels" +msgstr "Aggiorna automaticamente i canali" msgctxt "#30005" -msgid "Default play setting:" -msgstr "Impostazioni predefinite di riproduzione:" +msgid "Video quality" +msgstr "Qualità video" msgctxt "#30006" msgid "Ask" msgstr "Chiedi" msgctxt "#30007" -msgid "Watch in low quality" -msgstr "Guarda in bassa qualità" +msgid "Low" +msgstr "Bassa" msgctxt "#30008" -msgid "Watch in high quality" -msgstr "Guarda in alta qualità" +msgid "High" +msgstr "Alta" msgctxt "#30010" -msgid "Channel icons view:" -msgstr "Visualizzazione icone dei canali:" +msgid "Channel icons view" +msgstr "Visualizzazione icone dei canali" msgctxt "#30011" msgid "Poster (vertical)" @@ -70,24 +68,24 @@ msgid "Banner (horizontal)" msgstr "Banner (orizzontale)" msgctxt "#30014" -msgid "Username:" -msgstr "Username:" +msgid "Username" +msgstr "Username" msgctxt "#30015" -msgid "Password:" -msgstr "Password:" +msgid "Password" +msgstr "Password" msgctxt "#30017" -msgid "Download path:" -msgstr "Percorso download:" +msgid "Download path*" +msgstr "Percorso download*" msgctxt "#30018" -msgid "Download list path:" -msgstr "Percorso lista downloads:" +msgid "Download list path" +msgstr "Percorso lista downloads" msgctxt "#30019" -msgid "Filter channels by language:" -msgstr "Filtra canale per lingua:" +msgid "Channels language" +msgstr "Lingua canali" msgctxt "#30020" msgid "Check if the links exist" @@ -106,40 +104,40 @@ msgid "NO" msgstr "NO" msgctxt "#30024" -msgid "Select the elements you want to display on the Contextual Menu" -msgstr "Seleziona gli elementi che vuoi visualizzare nel Menu Contestuale" +msgid "Contextual menu" +msgstr "Menu contestuale" msgctxt "#30025" -msgid "KoD Preferences" -msgstr "Preferenze KoD" +msgid "Show KoD settings" +msgstr "Mostra impostazioni KoD" msgctxt "#30026" msgid "Direct" -msgstr "Direct" +msgstr "Diretta" msgctxt "#30027" msgid "SetResolvedUrl" -msgstr "SetResolvedUrl" +msgstr "Segnalibro" msgctxt "#30028" -msgid "Built-In" -msgstr "Built-In" +msgid "Built-in" +msgstr "Built-in" msgctxt "#30029" -msgid "Download and Play" -msgstr "Download and Play" +msgid "Download and play" +msgstr "Download e riproduci" msgctxt "#30030" -msgid "Advanced Options" -msgstr "Opzioni Avanzate" +msgid "Advanced options" +msgstr "Opzioni avanzate" msgctxt "#30031" -msgid "Delete Download?" -msgstr "Cancellare Download?" +msgid "Continue download?" +msgstr "Continuare il download?" msgctxt "#30032" -msgid "Select NO to continue downloading in the background" -msgstr "Seleziona NO per continuare il download in background" +msgid "Select YES to continue downloading in the background" +msgstr "Seleziona SI per continuare il download in background" msgctxt "#30033" msgid "Internal Client" @@ -174,12 +172,12 @@ msgid "Do you really want to delete the %s file?" msgstr "Vuoi veramente eliminare il file %s?" msgctxt "#30043" -msgid "Force view mode:" -msgstr "Forza modalità di visualizzazione:" +msgid "Force view mode" +msgstr "Forza modalità di visualizzazione" msgctxt "#30044" -msgid "Play mode:" -msgstr "Modalità di riproduzione:" +msgid "Play mode" +msgstr "Modalità di riproduzione" msgctxt "#30050" msgid "Server connection error" @@ -206,12 +204,12 @@ msgid "Unsopported Server" msgstr "Server non supportato" msgctxt "#30067" -msgid "Videolibrary path:" -msgstr "Percorso videoteca:" +msgid "Path*" +msgstr "Percorso*" msgctxt "#30068" -msgid "Filter by servers:" -msgstr "Filtra per server:" +msgid "Filter by servers" +msgstr "Filtra per server" msgctxt "#30100" msgid "Settings" @@ -270,7 +268,7 @@ msgid "Movies" msgstr "Film" msgctxt "#30123" -msgid "TV Shows" +msgid "TV shows" msgstr "Serie TV" msgctxt "#30124" @@ -286,11 +284,11 @@ msgid "Adult" msgstr "Adulti" msgctxt "#30130" -msgid "Recent" +msgid "News" msgstr "Novità" msgctxt "#30131" -msgid "Videolibrary" +msgid "Video library" msgstr "Videoteca" msgctxt "#30132" @@ -302,12 +300,12 @@ msgid "Do you want to remove links from this channel?" msgstr "Vuoi rimuovere i collegamenti da questo canale?" msgctxt "#30135" -msgid "added to the videolibrary" -msgstr "aggiunto alla libreria" +msgid "The movie "%s" has been added to the video library" +msgstr "Il film "%s" è stato aggiunto alla videoteca" msgctxt "#30136" msgid "Original version" -msgstr "Versione Originale" +msgstr "Versione originale" msgctxt "#30137" msgid "Direct" @@ -317,6 +315,22 @@ msgctxt "#30138" msgid "Live" msgstr "Live" +msgctxt "#30139" +msgid "Music" +msgstr "Musica" + +msgctxt "#30140" +msgid "Seasons" +msgstr "Stagioni" + +msgctxt "#30141" +msgid "Skin not supported" +msgstr "Skin non supportata" + +msgctxt "#30142" +msgid "Skin %s is not currently supported" +msgstr "La skin %s non è attualmente supportata" + msgctxt "#30151" msgid "Watch the video" msgstr "Guarda il video" @@ -334,7 +348,7 @@ msgid "Add to favorites" msgstr "Aggiungi ai preferiti" msgctxt "#30161" -msgid "Add to videolibrary" +msgid "Add to video library" msgstr "Aggiungi alla videoteca" msgctxt "#30162" @@ -358,12 +372,12 @@ msgid "Square" msgstr "Square" msgctxt "#30300" -msgid "Faster context menus" -msgstr "Menu contestuali rapidi (possono causare il mancato funzionamento di alcune opzioni)" +msgid "Delete also downloaded files?" +msgstr "Cancellare anche i file scaricati?" msgctxt "#30501" -msgid "Paths" -msgstr "Percorsi" +msgid "Path and folders" +msgstr "Percorso e cartelle" msgctxt "#30974" msgid "Search in Channels" @@ -374,7 +388,7 @@ msgid "Movie Info" msgstr "Informazioni Film" msgctxt "#30976" -msgid "TVShows - Airing Today" +msgid "TV shows - Airing Today" msgstr "Serie TV - In Onda" msgctxt "#30977" @@ -382,7 +396,7 @@ msgid "Last Episodes - On-Air" msgstr "Ultimi Episodi - In Onda" msgctxt "#30978" -msgid "New TVShows" +msgid "New TV shows" msgstr "Nuove Serie TV" msgctxt "#30979" @@ -431,7 +445,7 @@ msgstr "Cerca Film Simili" msgctxt "#30990" msgid "Search TV show" -msgstr "Cerca Serie TV" +msgstr "Cerca serie TV" msgctxt "#30991" msgid "Library" @@ -466,12 +480,12 @@ msgid "Shortcut" msgstr "Scorciatoia" msgctxt "#30999" -msgid "Add key to open Shortcut" -msgstr "Aggiungi tasto per aprire la scorciatoia" +msgid "Assign key to open shortcut" +msgstr "Assegna tasto scorciatoia" msgctxt "#31000" -msgid "Remove key to open Shortcut" -msgstr "Rimuovi tasto per aprire la scorciatoia" +msgid "Remove key to open shortcut" +msgstr "Rimuovi tasto scorciatoia" msgctxt "#50000" msgid "Sagas" @@ -479,7 +493,7 @@ msgstr "Saghe" msgctxt "#50001" msgid "On Air" -msgstr "Adesso in Onda" +msgstr "Adesso in onda" msgctxt "#50002" msgid "Latest News" @@ -494,17 +508,13 @@ msgid "Path: " msgstr "Percorso: " msgctxt "#50005" -msgid "Delete This Channel?" -msgstr "Eliminare Questo Canale?" +msgid "Delete this channel?" +msgstr "Eliminare questo canale?" msgctxt "#59970" msgid "Synchronization with Trakt started" msgstr "Sincronizzazione con Trakt iniziata" -msgctxt "#59971" -msgid "KOD Auto-configuration" -msgstr "KOD Auto-configurazione" - msgctxt "#59972" msgid "Search for: '%s' | Found: %d vídeos | Time: %2.f seconds" msgstr "Ricerca di: '%s' | Trovati: %d video | Tempo: %2.f secondi" @@ -550,8 +560,8 @@ msgid "torrent" msgstr "torrent" msgctxt "#59983" -msgid "%.2f%% - %.2f %s of %.2f %s a %.2f %s/s (%d/%d)" -msgstr "%.2f%% - %.2f %s di %.2f %s a %.2f %s/s (%d/%d)" +msgid "%.2f %s of %.2f %s a %.2f %s/s (%d/%d)" +msgstr "%.2f %s di %.2f %s a %.2f %s/s (%d/%d)" msgctxt "#59985" msgid "Error in the channel " @@ -590,8 +600,8 @@ msgid "Configuration -- Search" msgstr "Configurazione -- Ricerca" msgctxt "#59994" -msgid "Choose channels to include in your search" -msgstr "Scegli i canali da includere nella ricerca" +msgid "Channels included in search" +msgstr "Canali inclusi nella ricerca" msgctxt "#59995" msgid "Saved Searches" @@ -622,16 +632,16 @@ msgid "No links available that meets the requirements of the Black list. Try aga msgstr "Nessun collegamento disponibile che soddisfi i requisiti della Black list. Riprova modificando il filtro in 'Configurazione Server" msgctxt "#60003" -msgid "Connessione con %s" -msgstr "Connessione con %s" +msgid "Download unseen episodes" +msgstr "Scarica episodi non visti" msgctxt "#60004" msgid "No connector for the server %s" msgstr "Non c'è nessun connettore per il server %s" msgctxt "#60005" -msgid "Connecting with %s" -msgstr "Connessione con %s" +msgid "" +msgstr "" msgctxt "#60006" msgid "An error has occurred in %s" @@ -666,8 +676,8 @@ msgid "This website seems to be unavailable, try later, if the problem persists, msgstr "Questo sito non sembra essere disponibile, riprova più tardi, se il problema persiste verifica mediante un browser: %s. Se la pagina web funziona correttamente segnala l'errore su : https://t.me/kodiondemand" msgctxt "#60014" -msgid "It may be due to a connection problem, the web page of the channel has changed its structure, or an internal error of KOD. To have more details, see the log file." -msgstr "Potrebbe essere dovuto a un problema di connessione, la pagina web del canale ha cambiato la sua struttura, oppure un errore interno di KOD. Per avere maggiori dettagli, consulta il file di log." +msgid "It may be due to a connection problem, the web page of the channel has changed its structure, or an internal error of KoD. To have more details, see the log file." +msgstr "Potrebbe essere dovuto a un problema di connessione, la pagina web del canale ha cambiato la sua struttura, oppure un errore interno di KoD. Per avere maggiori dettagli, consulta il file di log." msgctxt "#60015" msgid "Check the log for more details on the error." @@ -690,12 +700,12 @@ msgid "Delete this movie" msgstr "Elimina questo film" msgctxt "#60020" -msgid "Mark tv series as not watched" -msgstr "Segna serie come non vista" +msgid "Mark TV show as not watched" +msgstr "Segna serie TV come non vista" msgctxt "#60021" -msgid "Mark tv series as watched" -msgstr "Segna serie come vista" +msgid "Mark TV show as watched" +msgstr "Segna serie TV come vista" msgctxt "#60022" msgid "Automatically find new episodes: Disable" @@ -706,12 +716,12 @@ msgid "Automatically find new episodes: Enable" msgstr "Trova automaticamente nuovi episodi: Attiva" msgctxt "#60024" -msgid "Delete tv series/channel" -msgstr "Elimina serie/canale" +msgid "Delete TV show/channel" +msgstr "Elimina serie TV/canale" msgctxt "#60025" -msgid "Delete tv series" -msgstr "Elimina serie" +msgid "Delete TV show" +msgstr "Elimina serie TV" msgctxt "#60026" msgid "Search for new episodes and update" @@ -758,12 +768,12 @@ msgid "Episode %s" msgstr "Episodio %s" msgctxt "#60037" -msgid "Tv series update ..." -msgstr "Aggiornamento serie ..." +msgid "TV show update..." +msgstr "Aggiornamento serie TV..." msgctxt "#60038" -msgid "An error has occurred on KOD" -msgstr "Si è verificato un errore su KOD" +msgid "An error has occurred in KoD" +msgstr "Si è verificato un errore in KoD" msgctxt "#60039" msgid "Error on channel %s" @@ -774,8 +784,8 @@ msgid "Delete movie" msgstr "Rimuovere film" msgctxt "#60041" -msgid "Delete tv series" -msgstr "Rimuovere serie" +msgid "Delete TV show" +msgstr "Rimuovere serie TV" msgctxt "#60042" msgid "Delete only the links of %s" @@ -786,7 +796,7 @@ msgid "Delete %s links of channel %s" msgstr "Cancellati %s collegamenti del canale %s" msgctxt "#60044" -msgid "Do you want really to delete '%s' from videolibrary?" +msgid "Do you want really to delete '%s' from video library?" msgstr "Vuoi davvero rimuovere '%s' dalla videoteca?" msgctxt "#60045" @@ -794,28 +804,28 @@ msgid "Sync with Trakt started" msgstr "Sincronizzazione con Trakt iniziata" msgctxt "#60046" -msgid "TheMovieDB not present.\nInstall it now?" -msgstr "The Movie database non presente.\nInstallare ora?" +msgid "The Movie Database not found. Install it now?" +msgstr "The Movie Database non trovato. Installare ora?" msgctxt "#60047" -msgid "The Movie Database is not installed." -msgstr "The Movie Database non è installato." +msgid "The Movie Database has not been installed" +msgstr "The Movie Database non è stato installato" msgctxt "#60048" -msgid "The TVDB not present.\nInstall it now?" -msgstr "The TVDB non presente.\nInstallare ora?" +msgid "The TVDB not found. Install it now?" +msgstr "The TVDB non trovato. Installare ora?" msgctxt "#60049" -msgid "The TVDB is not installed." -msgstr "The TVDB non è installato." +msgid "The TVDB has not been installed" +msgstr "The TVDB non è stato installato" msgctxt "#60050" -msgid "TheMovieDB not present.\nInstall it now?" -msgstr "TheMovieDB non presente.\nInstallare ora?" +msgid "The Movie Database not found. Install it now?" +msgstr "The Movie Database non trovato. Installare ora?" msgctxt "#60051" -msgid "The Movie Database is not installed." -msgstr "The Movie Database non è installato." +msgid "The Movie Database has not been installed" +msgstr "The Movie Database non è stato installato" msgctxt "#60052" msgid "Error on setting LibraryPath in BD" @@ -826,32 +836,28 @@ msgid "Do you want to configure this scraper in italian as default option for th msgstr "Si desidera configurare questo scraper in italiano come opzione predefinita per i film ?" msgctxt "#60054" -msgid "Do you want to configure this scraper in italian as default option for the tv series ?" -msgstr "Si desidera configurare questo scraper in italiano come opzione predefinita per le serie ?" +msgid "Do you want to configure this scraper in italian as default option for the TV shows?" +msgstr "Si desidera configurare questo scraper in italiano come opzione predefinita per le serie TV?" msgctxt "#60055" -msgid "Error of provider configuration in BD." -msgstr "Errore di configurazione del provider in BD." +msgid "Error configuring the information provider in Kodi database" +msgstr "Errore di configurazione del provider informazioni nel database di Kodi" msgctxt "#60056" -msgid "Videolibrary %s not configured" +msgid "Video library %s not configured" msgstr "Videoteca %s non configurata" msgctxt "#60057" -msgid "Videolibrary %s configured" +msgid "Video library %s configured" msgstr "Videoteca %s configurata" msgctxt "#60058" -msgid "You need to restart Kodi for the changes to take effect." -msgstr "E' necessario riavviare Kodi affinchè le modifiche abbiano effetto." - -msgctxt "#60059" -msgid "Congratulations, Kodi's video library has been configured correctly." -msgstr "Complimenti, la videoteca di Kodi è stata configurata correttamente." +msgid "You need to restart Kodi for the changes to take effect" +msgstr "E' necessario riavviare Kodi affinchè le modifiche abbiano effetto" msgctxt "#60060" -msgid "KOD Auto-configuration" -msgstr "KOD Auto-configurazione" +msgid "Kodi video library configuration" +msgstr "Configurazione videteca Kodi" msgctxt "#60062" msgid "Adding movies to your video library..." @@ -862,35 +868,35 @@ msgid "Error in adding movies to your video library..." msgstr "Errore di aggiunta alla videoteca..." msgctxt "#60064" -msgid "Adding Episodes to the Video Library..." +msgid "Adding episodes to the video library..." msgstr "Aggiunta episodi alla videoteca..." msgctxt "#60065" -msgid "Added Episode to Video Library..." +msgid "Added episode to the video library..." msgstr "Aggiunta episodio alla videoteca..." msgctxt "#60066" -msgid "ERROR, It has NOT been possible to add the video to the video library" -msgstr "ERRORE, NON è stato possibile aggiungere il video alla videoteca" +msgid "An error has occurred. It has not been possible to add the movie "%s" to the video library" +msgstr "Si è verificato un errore. Non è stato possibile aggiungere il film "%s" alla videoteca" msgctxt "#60067" -msgid "ERROR, tv series has NOT been added to videolibrary\nIt has NOT been possible to add no episode" -msgstr "ERRORE, la serie NON è stata aggiunta alla videoteca\nNon è stato possibile aggiungere alcun episodio" +msgid "An error has occurred. The TV show "%s" has not been added to the video library. It has not been possible to add any episode" +msgstr "Si è verificato un errore. La serie TV "%s" non è stata aggiunta alla videoteca. Non è stato possibile aggiungere alcun episodio" msgctxt "#60068" -msgid "ERROR, tv series has NOT been added to videolibrary" -msgstr "ERRORE, la serie NON è stata aggiunta alla videoteca" +msgid "An error has occurred. The TV show "%s" has not been added to the video library" +msgstr "Si è verificato un errore. La serie TV "%s" non è stata aggiunta alla videoteca" msgctxt "#60069" -msgid "ERRORE, tv series has NOT been added completely to videolibrary" -msgstr "ERRORE, la serie NON è stata aggiunta completamente alla videoteca" +msgid "An error has occurred. The TV show "%s" has not been added completely to the video library" +msgstr "Si è verificato un errore. La serie TV "%s" non è stata aggiunta completamente alla videoteca" msgctxt "#60070" -msgid "tv series has been added to videolibrary" -msgstr "La serie è stata aggiunta alla videoteca" +msgid "The TV show "%s" has been added to the video library" +msgstr "La serie TV "%s" è stata aggiunta alla videoteca" msgctxt "#60071" -msgid "Autoplay Configuration" +msgid "Autoplay configuration" msgstr "Configurazione Autoplay" msgctxt "#60072" @@ -923,7 +929,7 @@ msgstr "Consultare il log per maggiori informazioni." msgctxt "#60079" msgid "AutoPlay (Turns AutoPlay On/Off)" -msgstr "AutoPlay (Attiva/Disattiva la Riproduzione Automatica)" +msgstr "AutoPlay (Attiva/Disattiva la riproduzione automatica)" msgctxt "#60080" msgid "AutoPlay Language (Optional)" @@ -990,19 +996,19 @@ msgid "Download starting..." msgstr "Inizio download..." msgctxt "#60202" -msgid "Remaining time: %s" -msgstr "Tempo rimanente: %s" +msgid "ETA: %s" +msgstr "ETA: %s" msgctxt "#60203" msgid "Downloader %s/%s" msgstr "Downloader %s/%s" msgctxt "#60204" -msgid "Speed Meter" +msgid "Speed meter" msgstr "Misuratore di velocità" msgctxt "#60205" -msgid "File Writer" +msgid "File writer" msgstr "Scrittura File" msgctxt "#60206" @@ -1062,16 +1068,16 @@ msgid "Copying the file" msgstr "Copia del file" msgctxt "#60220" -msgid "Error while deleting the file" -msgstr "Errore durante l'eliminazione del file" +msgid "Stop download" +msgstr "Ferma download" msgctxt "#60221" -msgid "Error while deleting the directory" -msgstr "Errore durante l'eliminazione della directory" +msgid "Play" +msgstr "Riproduci" msgctxt "#60222" -msgid "Error while creating the directory" -msgstr "Errore durante la creazione della directory" +msgid "Stop all downloads" +msgstr "Ferma tutti i download" msgctxt "#60223" msgid "Enter another name" @@ -1082,12 +1088,12 @@ msgid "Complete information" msgstr "Completare le informazioni" msgctxt "#60225" -msgid "Search in TheMovieDB.org" -msgstr "Cerca in TheMovieDB.org" +msgid "Search on TMDB" +msgstr "Cerca su TMDB" msgctxt "#60226" -msgid "Search in TheTvDB.org" -msgstr "Cerca in TheTvDB.com" +msgid "Search on TVDB" +msgstr "Cerca su TVDB" msgctxt "#60227" msgid "Identifier not found for: %s" @@ -1162,8 +1168,8 @@ msgid "Movie" msgstr "Film" msgctxt "#60245" -msgid "tv show" -msgstr "serie" +msgid "TV show" +msgstr "Serie TV" msgctxt "#60246" msgid "Full information" @@ -1226,8 +1232,8 @@ msgid "Problem in the connection process" msgstr "Problema nel processo di collegamento" msgctxt "#60261" -msgid "KOD" -msgstr "KOD" +msgid "Kodi on Demand" +msgstr "Kodi on Demand" msgctxt "#60262" msgid "You can install the Trakt script below." @@ -1342,31 +1348,31 @@ msgid "More than 17 years old" msgstr "Più di 17 anni" msgctxt "#60292" -msgid "Searching for TV Series Information" -msgstr "Ricerca di informazioni sulla serie" +msgid "Searching for TV show information" +msgstr "Ricerca informazioni sulla serie TV" msgctxt "#60293" msgid "Please wait..." msgstr "Attendere prego..." msgctxt "#60294" -msgid "Searching for TV Series Information" -msgstr "Ricerca di informazioni sulla serie" +msgid "Searching for TV show information" +msgstr "Ricerca di informazioni sulla serie TV" msgctxt "#60295" msgid "Loading results..." msgstr "Caricamento risultati..." msgctxt "#60296" -msgid "Searching for TV Series Information" -msgstr "Ricerca di informazioni sulla serie" +msgid "Searching for TV show information" +msgstr "Ricerca di informazioni sulla serie TV" msgctxt "#60297" msgid "Find %s possible matches" msgstr "Trovate %s possibili corrispondenze" msgctxt "#60298" -msgid "[%s]: Select the correct TV series" +msgid "[%s]: Select the correct TV show" msgstr "[%s]: Seleziona la serie TV corretta" msgctxt "#60299" @@ -1439,7 +1445,7 @@ msgstr " KB/s " msgctxt "#60316" msgid "MB of " -msgstr "MB de " +msgstr "MB di " msgctxt "#60317" msgid "MB" @@ -1482,7 +1488,7 @@ msgid "Restart Kodi to apply changes" msgstr "Riavvia Kodi per applicare le modifiche" msgctxt "#60327" -msgid "Novelties" +msgid "News" msgstr "Novità" msgctxt "#60328" @@ -1498,7 +1504,7 @@ msgid "Favorites" msgstr "Preferiti" msgctxt "#60331" -msgid "Videolibrary" +msgid "Video library" msgstr "Videoteca" msgctxt "#60332" @@ -1514,23 +1520,15 @@ msgid "Password for adult channels" msgstr "Password per i canali per adulti" msgctxt "#60335" -msgid "Watch in" -msgstr "Vedere in" +msgid "Watch in..." +msgstr "Vedere in..." msgctxt "#60336" -msgid "Download in" -msgstr "Scaricare in" - -msgctxt "#60337" -msgid "KOD-MCT: No support adf.ly" -msgstr "KOD-MCT: Sin soporte adf.ly" - -msgctxt "#60338" -msgid "The script does not support URL reduction adf.ly." -msgstr "Lo script non supporta la riduzione di URL adf.ly." +msgid "Download in..." +msgstr "Scaricare in..." msgctxt "#60339" -msgid "Nothing to Play" +msgid "Nothing to play" msgstr "Niente da riprodurre" msgctxt "#60342" @@ -1538,17 +1536,13 @@ msgid "Download completed: " msgstr "Download completo: " msgctxt "#60343" -msgid "BMC-Kodi has closed the video." -msgstr "XBMC-Kodi ha chiuso il video." +msgid "Kodi has closed the video" +msgstr "Kodi ha chiuso il video" msgctxt "#60344" msgid "Continue with the session?" msgstr "Continuare con la sessione?" -msgctxt "#60345" -msgid "KOD-MCT: List of videos" -msgstr "KOD-MCT: Lista di video" - msgctxt "#60346" msgid "Delete video downloads" msgstr "Elimina i download di video" @@ -1562,8 +1556,8 @@ msgid "Information" msgstr "Informazione" msgctxt "#60349" -msgid "Go to the Main Menu" -msgstr "Andare al Menu Principale" +msgid "Go to the main menu" +msgstr "Andare al menu principale" msgctxt "#60350" msgid "Search in other channels" @@ -1574,44 +1568,44 @@ msgid "Set as Homepage" msgstr "Impostare come Homepage" msgctxt "#60352" -msgid "Add TV Series to Videolibrary" -msgstr "Aggiungi Serie alla Videoteca" +msgid "Add TV show to video library" +msgstr "Aggiungi serie TV alla videoteca" msgctxt "#60353" -msgid "Add Movie to Videolibrary" -msgstr "Aggiungi film alla Videoteca" +msgid "Add movie to video library" +msgstr "Aggiungi film alla videoteca" msgctxt "#60354" -msgid "Download Movie" -msgstr "Scarica Film" +msgid "Download movie" +msgstr "Scarica film" msgctxt "#60355" -msgid "Download TV Series" -msgstr "Scarica Serie" +msgid "Download TV show" +msgstr "Scarica serie TV" msgctxt "#60356" -msgid "Download Episode" -msgstr "Scarica Episodio" +msgid "Download episode" +msgstr "Scarica episodio" msgctxt "#60357" -msgid "Download Season" -msgstr "Scarica Stagione" +msgid "Download season" +msgstr "Scarica stagione" msgctxt "#60358" -msgid "Open Configuration" -msgstr "Apri Configurazione" +msgid "Open configuration" +msgstr "Apri configurazione" msgctxt "#60359" -msgid "Search Trailer" -msgstr "Cerca Trailer" +msgid "Search trailer" +msgstr "Cerca trailer" msgctxt "#60360" -msgid "Qiuick Menu" -msgstr "Menu Rapido" +msgid "Quick menu" +msgstr "Menu rapido" msgctxt "#60361" -msgid "Super Favourites Menu" -msgstr "Super Favourites Menu" +msgid "Super favourites menu" +msgstr "Menu super favoriti" msgctxt "#60362" msgid "You can't watch this video because..." @@ -1622,8 +1616,8 @@ msgid "The server on which it is hosted" msgstr "Il server in cui è ospitato " msgctxt "#60364" -msgid "is not yet supported in KOD" -msgstr "non è ancora supportato in KOD" +msgid "is not yet supported in KoD" +msgstr "non è ancora supportato in KoD" msgctxt "#60365" msgid "Loading video..." @@ -1662,8 +1656,8 @@ msgid "Genres:" msgstr "Generi:" msgctxt "#60383" -msgid "Series:" -msgstr "Serie:" +msgid "TV show:" +msgstr "Serie TV:" msgctxt "#60384" msgid "Season title:" @@ -1686,11 +1680,11 @@ msgid "Summary:" msgstr "Riassunto:" msgctxt "#60389" -msgid "Videolibrary update...." -msgstr "Aggiornamento videoteca...." +msgid "Updating %s [%s]..." +msgstr "Aggiornamento %s [%s]..." msgctxt "#60390" -msgid "AutoPlay Configuration" +msgid "AutoPlay configuration" msgstr "Configurazione AutoPlay" msgctxt "#60391" @@ -1782,12 +1776,12 @@ msgid "Choose channels to include" msgstr "Scegli i canali da includere" msgctxt "#60413" -msgid "New Movie Search..." +msgid "New movie search..." msgstr "Nuova ricerca film..." msgctxt "#60414" -msgid "New search tv series..." -msgstr "Nuova ricerca serie tv..." +msgid "New TV show search..." +msgstr "Nuova ricerca serie TV..." msgctxt "#60415" msgid "Other settings" @@ -1818,8 +1812,8 @@ msgid "Channels included in the global search " msgstr "Canali inclusi nella ricerca globale: " msgctxt "#60422" -msgid "Search " -msgstr "Ricerca " +msgid "Channels search" +msgstr "Ricerca canali" msgctxt "#60423" msgid "Search" @@ -1846,8 +1840,8 @@ msgid "FILTER: Delete '%s'" msgstr "FILTRO: Eliminare '%s'" msgctxt "#60429" -msgid "Filter configuration for TV series..." -msgstr "Configura filtro per serie tv..." +msgid "Filter configuration for TV show..." +msgstr "Configura filtro per serie TV..." msgctxt "#60430" msgid "FILTRO: Delete '%s'" @@ -1870,8 +1864,8 @@ msgid "Configure [%s]%s" msgstr "Configurare [%s]%s" msgctxt "#60435" -msgid "There are no filters, search for a TV series and click on the context menu 'FILTER: Configure'" -msgstr "Non ci sono filtri, cerca una serie tv e fai clic sul menu contestuale 'FILTRO: Configura'" +msgid "There are no filters, search for a TV show and click on the context menu 'FILTER: Configure'" +msgstr "Non ci sono filtri, cerca una serie TV e fai clic sul menu contestuale 'FILTRO: Configura'" msgctxt "#60436" msgid "Spanish" @@ -1931,7 +1925,7 @@ msgstr " - È Possibile attivare/disattivare i canali?" msgctxt "#60450" msgid " - Is automatic synchronization with Trakt possible?" -msgstr " - È Possibile la sincronizzazione automatica con Trakt?" +msgstr " - È possibile la sincronizzazione automatica con Trakt?" msgctxt "#60451" msgid " - Is it possible to show all the results together in the global search?" @@ -1958,8 +1952,8 @@ msgid " - Links of interest" msgstr " - Collegamenti di interesse" msgctxt "#60457" -msgid "KOD" -msgstr "KOD" +msgid "Kodi on Demand" +msgstr "Kodi on Demand" msgctxt "#60458" msgid "The disabling can be done in 'Settings>Turn on/off channels'. You can toggle channels on/off one at a time or all at the same time. Want to manage your channels now?" @@ -1974,20 +1968,20 @@ msgid "This can be improved by limiting the maximum number of links or by displa msgstr "Questo può essere migliorato limitando il numero massimo di collegamenti o visualizzandoli in una finestra Pop-Up. Queste impostazioni possono essere trovate in 'Impostazioni>Impostazioni libreria' Vuoi accedere a queste impostazioni?" msgctxt "#60461" -msgid "KOD - FAQ - %s" -msgstr "KOD - FAQ - %s" +msgid "KoD - FAQ - %s" +msgstr "KoD - FAQ - %s" msgctxt "#60462" -msgid "You may not have written the library path correctly in 'Settings>Preferences'.\nIl The specified path must be exactly the same as the 'source' entered in 'Archive' of the Kodi library.\nAVANZATO: This path is also found in 'sources.xml'.\nThere can be problems using some Kodi forks and paths with 'special://'. SPMC, for example, has problems with this, and there doesn't seem to be a solution, as it is an external problem to Kodi on Demand that has existed for a long time.\nYou can try solving these problems in 'Settings>Library Settings' by changing the 'Search in' setting from 'The folder of each series' to 'All library'." -msgstr "Potresti non aver scritto correttamente il percorso della libreria in 'Impostazioni>Preferenze'.\nIl percorso specificato deve essere esattamente uguale al 'sorgente' inserito in 'Archivio' della libreria di Kodi.\nAVANZATO: Questo percorso si trova anche in 'sources.xml'.\nPotresti riscontrare dei problemi utilizzando alcuni fork di Kodi e percorsi con 'special://'. SPMC, per esempio, ha problemi con questo, e non sembra esserci una soluzione, poichè è un problema esterno Kodi on Demand che esiste da molto tempo.\nPuoi provare a risolvere questi problemi in 'Impostazioni>Impostazioni libreria', modificando l'impostazione 'Esegui ricerca contenuto in' da 'La cartella di ogni serie' in 'Tutta la libreria'." +msgid "You may not have written the library path correctly in 'Settings>Preferences'.\nIl The specified path must be exactly the same as the 'source' entered in 'Archive' of the Kodi library.\nAVANZATO: This path is also found in 'sources.xml'.\nThere can be problems using some Kodi forks and paths with 'special://'. SPMC, for example, has problems with this, and there doesn't seem to be a solution, as it is an external problem to Kodi on Demand that has existed for a long time.\nYou can try solving these problems in 'Settings>Library Settings' by changing the 'Search in' setting from 'The folder of each TV show' to 'All library'." +msgstr "Potresti non aver scritto correttamente il percorso della libreria in 'Impostazioni>Preferenze'.\nIl percorso specificato deve essere esattamente uguale al 'sorgente' inserito in 'Archivio' della libreria di Kodi.\nAVANZATO: Questo percorso si trova anche in 'sources.xml'.\nPotresti riscontrare dei problemi utilizzando alcuni fork di Kodi e percorsi con 'special://'. SPMC, per esempio, ha problemi con questo, e non sembra esserci una soluzione, poichè è un problema esterno Kodi on Demand che esiste da molto tempo.\nPuoi provare a risolvere questi problemi in 'Impostazioni>Impostazioni libreria', modificando l'impostazione 'Esegui ricerca contenuto in' da 'La cartella di ogni serie TV' in 'Tutta la libreria'." msgctxt "#60463" msgid "The channel site may not work. In case the site works you can report the problem on github." msgstr "Può darsi che il sito del canale non funzioni. Nel caso il sito funzioni puoi segnalare il problema su github." msgctxt "#60464" -msgid "It is possible that you have updated KOD recently and that the changes have not been fully applied Well, you can try 'Settings>Other Tools', checking the *_data.json files or reattaching everything to the library again" -msgstr "È Possibile che tu abbia aggiornato KOD di recente e che i cambiamenti non siano stati totalmente applicati Bene, puoi provare in 'Impostazioni>Altri strumenti', controllando i files *_data.json o riaggiungendo tutto ancora alla libreria" +msgid "It is possible that you have updated KoD recently and that the changes have not been fully applied Well, you can try 'Settings>Other Tools', checking the *_data.json files or reattaching everything to the library again" +msgstr "È Possibile che tu abbia aggiornato KoD di recente e che i cambiamenti non siano stati totalmente applicati Bene, puoi provare in 'Impostazioni>Altri strumenti', controllando i files *_data.json o riaggiungendo tutto ancora alla libreria" msgctxt "#60465" msgid "Do you want access to these settings?" @@ -1998,8 +1992,8 @@ msgid "Yes, the option to display merged or split results by channels can be fou msgstr "Sì, l'opzione per mostrare i risultati uniti o divisi per canali si trova in 'Impostazioni>Impostazioni ricerca globale>Altre impostazioni'. Vuoi accedere a queste impostazioni?" msgctxt "#60467" -msgid "To report a problem on'https://t.me/kodiondemand' you need to:|the version you're using of Alpha.|The version you're using of kodi, mediaserver, etc.|the version and name of the operating system you're using.|The name of the skin (in case you're using Kodi) and whether using the default skin has solved the problem.|Description of the problem and any test cases.To activate the log in detailed mode, go to:|Configuration.|Preferences.|In the General tab - Check the option: Generate detailed log. The detailed log file can be found in the following path: \n\n%s" -msgstr "Per segnalare un problema su 'https://t.me/kodiondemand' è necessario:|la versione che si sta usando di Kodi on Demand.|La versione che si sta usando di kodi, mediaserver, ecc.|la versione e il nome del sistema operativo che si sta usando.|Il nome della skin (nel caso in cui si stia usando Kodi) e se l'utilizzo della skin predefinita ha risolto il problema.|La descrizione del problema e tutti i casi di test.Per attivare il log in modalità dettagliata, andare su:|Configurazione.|Preferenze.|Nella scheda Generale - Selezionare l'opzione: Genera log dettagliato Il file di log dettagliato si trova nel seguente percorso: \n\n%s" +msgid "To report a problem on'https://t.me/kodiondemand' you need to:|the version you're using of Alpha.|The version you're using of Kodi, mediaserver, etc.|the version and name of the operating system you're using.|The name of the skin (in case you're using Kodi) and whether using the default skin has solved the problem.|Description of the problem and any test cases.To activate the log in detailed mode, go to:|Configuration.|Preferences.|In the General tab - Check the option: Generate detailed log. The detailed log file can be found in the following path: \n\n%s" +msgstr "Per segnalare un problema su 'https://t.me/kodiondemand' è necessario:|la versione che si sta usando di Kodi on Demand.|La versione che si sta usando di Kodi, mediaserver, ecc.|la versione e il nome del sistema operativo che si sta usando.|Il nome della skin (nel caso in cui si stia usando Kodi) e se l'utilizzo della skin predefinita ha risolto il problema.|La descrizione del problema e tutti i casi di test.Per attivare il log in modalità dettagliata, andare su:|Configurazione.|Preferenze.|Nella scheda Generale - Selezionare l'opzione: Genera log dettagliato Il file di log dettagliato si trova nel seguente percorso: \n\n%s" msgctxt "#60468" msgid "You can find our Telegram group at @kodiondemand" @@ -2102,12 +2096,12 @@ msgid "[B]Seasons/Episodes: [/B]" msgstr "[B]Stagioni/Episodi: [/B]" msgctxt "#60493" -msgid "[B]Is there the tv series you're looking for?[/B]" -msgstr "[B]C'è la serie che cerchi?[/B]" +msgid "[B]Is the TV show you're looking for inlcuded?[/B]" +msgstr "[B]La serie TV che stai cercando è inclusa?[/B]" msgctxt "#60494" -msgid "[B]Is there the movie you are looking for?[/B]" -msgstr "[B]C'è il film che stai cercando?[/B]" +msgid "[B]Is the movie you're looking for inlcuded?[/B]" +msgstr "[B]Il film che stai cercando è incluso?[/B]" msgctxt "#60495" msgid "[B]Close[/B]" @@ -2174,12 +2168,12 @@ msgid "Kids" msgstr "Bambini" msgctxt "#60511" -msgid "TV series Episodes" -msgstr "Episodi di serie tv" +msgid "TV shows" +msgstr "Serie TV" msgctxt "#60512" -msgid "Anime Episodes" -msgstr "Episodi di anime" +msgid "Anime" +msgstr "Anime" msgctxt "#60513" msgid "Documentaries" @@ -2230,8 +2224,8 @@ msgid " (In %s)" msgstr " (In %s)" msgctxt "#60525" -msgid "Channels included in:" -msgstr "Canali inclusi in:" +msgid "Included channels by category" +msgstr "Canali inclusi per categoria" msgctxt "#60526" msgid " - Movies " @@ -2242,20 +2236,20 @@ msgid " - Kids" msgstr " - Bambini" msgctxt "#60528" -msgid " - Series Tv Episodes" -msgstr " - Episodi di serie tv" +msgid " - TV show episodes" +msgstr " - Episodi serie TV" msgctxt "#60529" -msgid " - Anime Episodes" -msgstr " - Episodi di anime" +msgid " - Anime episodes" +msgstr " - Episodi anime" msgctxt "#60530" msgid " - Documentaries" msgstr " - Documentari" msgctxt "#60531" -msgid "Other Settings" -msgstr "Altre Impostazioni" +msgid "Other settings" +msgstr "Altre impostazioni" msgctxt "#60532" msgid "Configuration -- News" @@ -2283,7 +2277,7 @@ msgstr "Impostazioni canali" msgctxt "#60538" msgid "Server settings" -msgstr "Impostazioni servers" +msgstr "Impostazioni server" msgctxt "#60539" msgid "Settings for the 'News' section" @@ -2298,8 +2292,8 @@ msgid "Download settings" msgstr "Impostazioni download" msgctxt "#60542" -msgid "Videolibrary settings" -msgstr "Impostazioni della videoteca" +msgid "Video library settings" +msgstr "Impostazioni videoteca" msgctxt "#60544" msgid "More Options" @@ -2327,15 +2321,15 @@ msgstr "Controlla i file * _data.json" msgctxt "#60550" msgid "Servers locked" -msgstr "Servers bloccati" +msgstr "Server bloccati" msgctxt "#60551" msgid "Favorite servers" -msgstr "Servers preferiti" +msgstr "Server preferiti" msgctxt "#60552" msgid "Debriders settings" -msgstr "Impostazioni debriders" +msgstr "Impostazioni debrider" msgctxt "#60553" msgid " Server configuration '%s'" @@ -2343,7 +2337,7 @@ msgstr " Configurazione del server '%s'" msgctxt "#60554" msgid "Server settings" -msgstr "Impostazioni servers" +msgstr "Impostazioni server" msgctxt "#60557" msgid "Saving configuration" @@ -2382,16 +2376,16 @@ msgid " Check the files * _data.json" msgstr " Controlla i file * _data.json" msgctxt "#60566" -msgid "Videolibrary options" +msgid "Video library options" msgstr "Opzioni della videoteca" msgctxt "#60567" -msgid "Overwrite the entire video library (strm, nfo and json)" -msgstr "Sovrascrivi l'intera videoteca (strm, nfo e json)" +msgid "Restore video library (strm, nfo and json)" +msgstr "Ripristina videoteca (strm, nfo e json)" msgctxt "#60568" -msgid "Search for new episodes and update the video library" -msgstr "Cerca nuovi episodi e aggiorna la videoteca" +msgid "Search for new episodes and update video library" +msgstr "Cerca nuovi episodi ed aggiorna videoteca" msgctxt "#60569" msgid " - There are no default settings" @@ -2426,8 +2420,8 @@ msgid "A saving error occurred" msgstr "Si è verificato un errore al salvataggio" msgctxt "#60581" -msgid "Overwriting the entire video library" -msgstr "Sovrascrittura di tutta la videoteca" +msgid "Restoring the video library" +msgstr "Ripristino videoteca" msgctxt "#60582" msgid "This may take some time." @@ -2438,20 +2432,20 @@ msgid "Do you want to continue?" msgstr "Vuoi continuare?" msgctxt "#60584" -msgid "Overwriting the video library...TV SERIES" -msgstr "Sovrascrittura della videoteca....SERIE TV" +msgid "Restoring TV shows video library" +msgstr "Ripristino videoteca serie TV" msgctxt "#60585" -msgid "kod" -msgstr "kod" +msgid "Kodi on Demand" +msgstr "Kodi on Demand" msgctxt "#60586" -msgid "Overwriting the video library...MOVIES" -msgstr "Sovrascrittura della videoteca....FILM" +msgid "Restoring movies video library" +msgstr "Ripristino videoteca film" msgctxt "#60587" -msgid "Video library update...." -msgstr "Aggiornamento videoteca...." +msgid "Channel configuration" +msgstr "Configurazione canale" msgctxt "#60588" msgid " - Settings created" @@ -2494,12 +2488,12 @@ msgid " Server #%s" msgstr " Server #%s" msgctxt "#60598" -msgid "Configuration -- Video Library" -msgstr "Configurazione -- Videoteca" +msgid "Configuration of video library" +msgstr "Configurazione della videoteca" msgctxt "#60600" -msgid "Series" -msgstr "Serie" +msgid "TV shows" +msgstr "Serie TV" msgctxt "#60601" msgid "Video library update" @@ -2522,8 +2516,8 @@ msgid "At the start of Kodi and once a day" msgstr "All'avvio di Kodi e una volta al giorno" msgctxt "#60606" -msgid " Wait before updating at startup of Kodi" -msgstr " Attendere prima di aggiornare all'avvio di Kodi" +msgid " Wait before updating at startup of Kodi" +msgstr " Attendere prima di aggiornare all'avvio di Kodi" msgctxt "#60607" msgid "When Kodi starts" @@ -2546,12 +2540,12 @@ msgid "60 sec" msgstr "60 sec" msgctxt "#60613" -msgid " Begin scheduled update from" -msgstr "Inizia aggiornamento programmato a partire dalle" +msgid " Begin scheduled update from" +msgstr " Inizia aggiornamento programmato a partire dalle" msgctxt "#60614" -msgid " Search for new episodes in active tv series" -msgstr " Cerca nuovi episodi nelle serie attive" +msgid " Search for new episodes in active TV shows" +msgstr " Cerca nuovi episodi nelle serie TV attive" msgctxt "#60615" msgid "Never" @@ -2566,12 +2560,12 @@ msgid "According to new episodes" msgstr "Secondo le uscite" msgctxt "#60618" -msgid " Search for content in" -msgstr " Esegui ricerca dei contenuti in" +msgid " Search for content in" +msgstr " Esegui ricerca dei contenuti in" msgctxt "#60619" -msgid "The folder of each tv series" -msgstr "La cartella di ogni serie" +msgid "The folder of each TV show" +msgstr "La cartella di ogni serie TV" msgctxt "#60620" msgid "All video library" @@ -2582,60 +2576,52 @@ msgid "Show links in" msgstr "Mostra collegamenti in" msgctxt "#60622" -msgid "Conventional window" -msgstr "Finestra convenzionale" +msgid "Normal window" +msgstr "Finestra normale" msgctxt "#60623" msgid "Pop-up window" msgstr "Finestra pop-up" msgctxt "#60624" -msgid " Maximum number of links to display (recommended for slow devices)" -msgstr " Numero massimo di link da visualizzare (consigliato per dispositivi lenti)" +msgid " Maximum number of links to display" +msgstr " Numero massimo di link da visualizzare" msgctxt "#60625" msgid "All" msgstr "Tutti" msgctxt "#60626" -msgid " Sort by whitelist" -msgstr " Ordina per whitelist" +msgid " Sort by whitelist" +msgstr " Ordina per whitelist" msgctxt "#60627" -msgid " Remove the channel name at the beginning" -msgstr " Rimuovi il nome del canale all'inizio" +msgid " Remove the channel name at the beginning" +msgstr " Rimuovi il nome del canale all'inizio" msgctxt "#60628" -msgid " Pop-up window: Replace \'View in\' with \'[V]\' and \'Download in\' with \'[D]\'" -msgstr " Finestra pop-up: Sostituisci \'Vedi in\' con \'[V]\' e \'Scarica in\' con \'[D]\'" +msgid " Replace \'View in\' with \'[V]\' and \'Download in\' with \'[D]\'" +msgstr " Sostituisci \'Vedi in\' con \'[V]\' e \'Scarica in\' con \'[D]\'" msgctxt "#60629" -msgid "Database location" -msgstr "Posizione del database" - -msgctxt "#60630" -msgid "Local" -msgstr "Locale" - -msgctxt "#60631" -msgid "Remote" -msgstr "Remota" +msgid "Remote database" +msgstr "Database remoto" msgctxt "#60632" -msgid " Server Name" -msgstr " Nome Server" +msgid " Server name" +msgstr " Nome server" msgctxt "#60633" -msgid " Server port" -msgstr " Porta del server" +msgid " Server port" +msgstr " Porta server" msgctxt "#60634" msgid "Automatically mark as watched" msgstr "Segna automaticamente come visto" msgctxt "#60635" -msgid " Video viewing time" -msgstr " Tempo di visione del video" +msgid " Video viewing time" +msgstr " Tempo di visione del video" msgctxt "#60636" msgid "0 seg" @@ -2646,28 +2632,28 @@ msgid "Synchronizing with Trakt" msgstr "Sincronizzazione con Trakt" msgctxt "#60638" -msgid " After mark as watched the episode" -msgstr " Dopo aver segnato come visto l'episodio" +msgid " After mark as watched the episode" +msgstr " Dopo aver segnato come visto l'episodio" msgctxt "#60639" -msgid " Show notification" -msgstr " Mostra notifica" +msgid " Show notification" +msgstr " Mostra notifica" msgctxt "#60640" -msgid " On adding a TV series to the video library" -msgstr " All'aggiunta di una serie alla videoteca" +msgid " On adding a TV show to the video library" +msgstr " All'aggiunta di una serie TV alla videoteca" msgctxt "#60641" -msgid " Wait until the tv series is added" -msgstr " Attendere finchè la serie sia aggiunta" +msgid " Wait until the TV show is added" +msgstr " Attendere finchè la serie TV sia aggiunta" msgctxt "#60642" -msgid "Show option \"All Seasons\"." +msgid "Show option \'All Seasons\'" msgstr "Mostra l'opzione \'Tutte le stagioni\'" msgctxt "#60643" -msgid "Do not combine the seasons of the series" -msgstr "Non unire le stagioni delle serie" +msgid "Do not combine the seasons of the TV shows" +msgstr "Non unire le stagioni delle serie TV" msgctxt "#60644" msgid "Only if there is one season" @@ -2678,36 +2664,28 @@ msgid "Show channel selection box" msgstr "Mostra la casella di selezione del canale" msgctxt "#60646" -msgid "Create directories on your system using" -msgstr "Crea directory sul sistema usando" - -msgctxt "#60647" -msgid "Localized title" -msgstr "Titolo in Italiano" +msgid "Create folders using original title" +msgstr "Crea cartelle usando titolo originale" msgctxt "#60648" msgid "Never" msgstr "Mai" -msgctxt "#60649" -msgid "Original title" -msgstr "Titolo originale" - msgctxt "#60650" -msgid "When you add content, you get information from:" -msgstr "All'aggiunta dei contenuti,ottieni informazioni da:" +msgid "Video library information provider" +msgstr "Provider informazioni videoteca" msgctxt "#60651" -msgid " Movies:" -msgstr " Film:" +msgid " Movies" +msgstr " Film" msgctxt "#60652" -msgid " TV Series:" -msgstr " Serie TV:" +msgid " TV show" +msgstr " Serie TV" msgctxt "#60653" -msgid " If there are no results also search in English" -msgstr " Se non ci sono risultati cerca anche in inglese" +msgid " If there are no results search in English" +msgstr " Se non ci sono risultati cerca in inglese" msgctxt "#60654" msgid "Include in blacklist" @@ -2722,8 +2700,8 @@ msgid "Simultaneous search (multiprocessing)" msgstr "Ricerca contemporanea (multiprocessing)" msgctxt "#60657" -msgid "Show Results:" -msgstr "Mostra risultati:" +msgid "Show results" +msgstr "Mostra risultati" msgctxt "#60658" msgid "Grouped by content" @@ -2742,8 +2720,8 @@ msgid "News" msgstr "Novità" msgctxt "#60662" -msgid "code cleaning" -msgstr "pulizia di codice" +msgid " Language" +msgstr " Lingua" msgctxt "#60663" msgid "Add the progress window" @@ -2786,8 +2764,8 @@ msgid "Global Search" msgstr "Ricerca globale" msgctxt "#60673" -msgid "Number of Search Threads" -msgstr "Numero di Threads di Ricerca" +msgid "Number of search threads" +msgstr "Numero di threads di ricerca" msgctxt "#60674" msgid "Show Results:" @@ -2822,12 +2800,12 @@ msgid "movies" msgstr "film" msgctxt "#60682" -msgid "tv series" -msgstr "serie tv" +msgid "TV show" +msgstr "Serie TV" msgctxt "#60683" -msgid "anime" -msgstr "anime" +msgid "Loading streams..." +msgstr "Caricamento stream..." msgctxt "#70000" msgid "Options" @@ -2866,8 +2844,8 @@ msgid "Reload" msgstr "Ricarica" msgctxt "#70009" -msgid "Classic Menu" -msgstr "Menu Principale" +msgid "Main menu" +msgstr "Menu principale" msgctxt "#70010" msgid "Where To Search" @@ -2898,7 +2876,7 @@ msgid "Active channels" msgstr "Canali attivi" msgctxt "#70017" -msgid "TV Series" +msgid "TV show" msgstr "Serie TV" msgctxt "#70018" @@ -2922,7 +2900,7 @@ msgid " - Movies" msgstr " - Film" msgctxt "#70023" -msgid " - TV Shows" +msgid " - TV shows" msgstr " - Serie TV" msgctxt "#70024" @@ -2942,8 +2920,8 @@ msgid "Search engine settings" msgstr "Impostazioni motori di ricerca" msgctxt "#70028" -msgid "Most Popular" -msgstr "Più Popolari" +msgid "Most popular" +msgstr "Più popolari" msgctxt "#70029" msgid "Top rated" @@ -2982,8 +2960,8 @@ msgid "Search director, writer..." msgstr "Cerca regista, sceneggiatore..." msgctxt "#70038" -msgid "Custom Filter" -msgstr "Filtro Personalizzato" +msgid "Custom filter" +msgstr "Filtro personalizzato" msgctxt "#70039" msgid "Keyword filter" @@ -2993,10 +2971,6 @@ msgctxt "#70040" msgid "Top Filmaffinity" msgstr "Top Filmaffinity" -msgctxt "#70041" -msgid "Modern TV Shows" -msgstr "Serie di attualità" - msgctxt "#70042" msgid "Year" msgstr "Anno" @@ -3010,11 +2984,11 @@ msgid "Sagas and Collections" msgstr "Saghe e Collezioni" msgctxt "#70045" -msgid "Movies/TV Shows/Documentaries by Themes" -msgstr "Film/Serie/Documentari a Tema" +msgid "Movies/TV shows/Documentaries" +msgstr "Film/Serie TV/Documentari" msgctxt "#70046" -msgid "Search Movies/TV Shows" +msgid "Search Movies/TV shows" msgstr "Cerca Film/Serie TV" msgctxt "#70047" @@ -3062,8 +3036,8 @@ msgid "My lists" msgstr "Le Mie Liste" msgctxt "#70058" -msgid "Top Series" -msgstr "Top Serie TV" +msgid "Top TV shows" +msgstr "Top serie TV" msgctxt "#70059" msgid "Top Movies" @@ -3086,8 +3060,8 @@ msgid "Anime by Genres" msgstr "Anime per Genere" msgctxt "#70064" -msgid "Search Tv Shows/Movies/Anime" -msgstr "Cerca SerieTV/Film/Anime" +msgid "Search TV shows/Movies/Anime" +msgstr "Cerca serie TV/Film/Anime" msgctxt "#70065" msgid ">> Next Page" @@ -3106,8 +3080,8 @@ msgid "In my Collection" msgstr "Nella mia Collezione" msgctxt "#70069" -msgid "Search %s in KOD: %s" -msgstr "Cerca %s in KOD: %s" +msgid "Search %s in KoD: %s" +msgstr "Cerca %s in KoD: %s" msgctxt "#70070" msgid "Search original title: %s" @@ -3162,8 +3136,8 @@ msgid "Delete movie" msgstr "Elimina film" msgctxt "#70085" -msgid "Delete TV Show" -msgstr "Elimina serie" +msgid "Delete TV show" +msgstr "Elimina serie TV" msgctxt "#70086" msgid "Remove only links of %s" @@ -3174,7 +3148,7 @@ msgid "Deleted %s links from canal %s" msgstr "Eliminati %s links del canale %s" msgctxt "#70088" -msgid "Are you sure you want to delete '%s' from videolibrary ?" +msgid "Are you sure you want to delete '%s' from video library?" msgstr "Vuoi davvero eliminare '%s' dalla videoteca?" msgctxt "#70089" @@ -3190,7 +3164,7 @@ msgid " Words" msgstr "Parole" msgctxt "#70092" -msgid "Add to videolibrary" +msgid "Add to video library" msgstr "Aggiungere alla videoteca" msgctxt "#70093" @@ -3198,84 +3172,80 @@ msgid "The Movie Database" msgstr "The Movie Database" msgctxt "#70094" -msgid "Select scraper for movies" -msgstr "Seleziona provider info per i film" +msgid "Select the information provider for movies" +msgstr "Seleziona il provider informazioni per i film" msgctxt "#70095" -msgid "Universal Movie Scraper not present.\nInstall it now?" -msgstr "Universal Movie Scraper\nNon presente.\nInstallarlo ora?" +msgid "Universal Movie Scraper not found. Install it now?" +msgstr "Universal Movie Scraper non trovato. Installarlo ora?" msgctxt "#70096" msgid "Universal Movie Scraper" msgstr "Universal Movie Scraper" msgctxt "#70097" -msgid "Universal Movie Scraper not installed." -msgstr "Universal Movie Scraper non è stato installato." +msgid "Universal Movie Scraper has not been installed" +msgstr "Universal Movie Scraper non è stato installato" msgctxt "#70098" msgid "The TVDB" msgstr "The TVDB" msgctxt "#70099" -msgid "The TVDB not installed." -msgstr "The TVDB non è stato installato." - -msgctxt "#70100" -msgid "The Movie Database not present.\nInstall it now?" -msgstr "The Movie Database\nNon presente.\nInstallarlo ora?" +msgid "The TVDB has not been installed" +msgstr "The TVDB non è stato installato" msgctxt "#70101" -msgid "Error fixing videolibrarypath in BD" -msgstr "Errore durante il fissaggio del videolibrarypath in BD" +msgid "Error inserting the video library path in Kodi database" +msgstr "Errore durante l'inserimento del percorso della videoteca nel database di Kodi" msgctxt "#70102" -msgid "Videolibrary %s not configured" +msgid "Video library %s not configured" msgstr "Videoteca %s non configurata" msgctxt "#70103" -msgid "Videolibrary %s configured" +msgid "Video library %s configured" msgstr "Videoteca %s configurata" msgctxt "#70104" -msgid "Congratulations, the Kodi video library has been configured correctly." -msgstr "Complimenti, la videoteca di Kodi è stata configurata correttamente." +msgid "The Kodi video library has been successfully configured" +msgstr "La libreria di Kodi è stata configurata correttamente" msgctxt "#70105" -msgid "Do you want KOD to automatically configure the Kodi library? You will be asked to set up scrapers for movies and series." -msgstr "Vuoi che KOD auto-configuri la videoteca di Kodi? Ti verrà chiesto di installare i providers info per film e serie tv." +msgid "Do you want KoD to configure the Kodi library? You will be asked to set up scrapers for movies and TV shows." +msgstr "Vuoi che KoD configuri la videoteca di Kodi? Ti verrà chiesto di installare i providers info per film e serie TV." msgctxt "#70106" msgid "If you choose 'No' you can do it later from 'Configuration > Preferences > Paths'." msgstr "Se Scegli 'No' potrai farlo in seguito da 'Impostazioni > Preferenze > Percorsi'." msgctxt "#70107" -msgid "Select scraper for Tv Shows" -msgstr "Seleziona il provider info per le serie tv" +msgid "Select the information provider for TV shows" +msgstr "Seleziona il provider informazioni per le serie TV" msgctxt "#70108" -msgid "Icons Set" +msgid "Icons set" msgstr "Set di icone" msgctxt "#70109" -msgid "Sync with Trakt.tv (You must have an account)" -msgstr "Sincronizza con Trakt.tv (necessario un account)" +msgid "Syncronize with Trakt.tv" +msgstr "Sincronizza con Trakt.tv" msgctxt "#70110" -msgid "Priority Method" +msgid "Priority method" msgstr "Priorità" msgctxt "#70111" -msgid "Stop looking when you find an option" -msgstr "Smettere di cercare quando si trova un'opzione" +msgid "Stop search when find an option" +msgstr "Termina ricerca quando si trova un'opzione" msgctxt "#70112" msgid "Hide payment servers without an account" -msgstr "Nascondere servers senza account" +msgstr "Nascondere server senza account" msgctxt "#70113" msgid "Password (default 0000)" -msgstr "Password (default 0000):" +msgstr "Password (default 0000)" msgctxt "#70114" msgid "Only until Kodi restarts" @@ -3286,43 +3256,43 @@ msgid "Request password to open adult channels" msgstr "Richiedi password per aprire canali per adulti" msgctxt "#70116" -msgid "New password:" -msgstr "Nuova password:" +msgid "New password" +msgstr "Nuova password" msgctxt "#70117" -msgid "Confirm New password:" -msgstr "Conferma Nuova password:" +msgid "Confirm new password" +msgstr "Conferma nuova password" msgctxt "#70118" -msgid "Folder name for 'Series'" -msgstr "Nome della cartella per 'Serie'" +msgid "TV shows folder*" +msgstr "Cartella serie TV*" msgctxt "#70119" -msgid "Folder name for 'Movies'" -msgstr "Nome della cartella per 'Film'" +msgid "Movies folder*" +msgstr "Cartella film*" msgctxt "#70120" -msgid "Autoconfigure XBMC / Kodi library for KOD content" -msgstr "Autoconfigura videoteca di XBMC/Kodi per il contenuto di KOD" +msgid "Add KoD contents to Kodi video library*" +msgstr "Aggiungi la videoteca di KoD alla libreria di Kodi*" msgctxt "#70121" -msgid "Activate Home Page" -msgstr "Attivare Pagina iniziale" +msgid "Activate" +msgstr "Attiva" msgctxt "#70122" -msgid "Custom (select from a channel)" -msgstr "Personalizzato (selezionare da un canale)" +msgid "Show channel (select it from homepage)" +msgstr "Mostra canale (seleziona dalla homepage)" msgctxt "#70123" -msgid "Show Recent" -msgstr "Mostra Novità" +msgid "Show news" +msgstr "Mostra novità" msgctxt "#70124" msgid "Category" msgstr "Categoria" msgctxt "#70125" -msgid "Movie|Tv Shows|Anime|Children|Documentary|Horror|Castellan|Latin|Torrent" +msgid "Movie|TV shows|Anime|Children|Documentary|Horror|Castellan|Latin|Torrent" msgstr "Fim|Serie TV|Anime|Bambini|Documentari|Horror|Castigliano|Latino|Torrent" msgctxt "#70126" @@ -3362,8 +3332,8 @@ msgid "Custom Colours" msgstr "Colori Personalizzati" msgctxt "#70136" -msgid "Tv Show" -msgstr "Serie" +msgid "TV shows" +msgstr "Serie TV" msgctxt "#70137" msgid "Movies" @@ -3399,55 +3369,55 @@ msgstr "VO (Versione Originale)" msgctxt "#70145" msgid "Servers" -msgstr "Servers" +msgstr "Server" msgctxt "#70146" -msgid "Add to videolibrary" +msgid "Add to video library" msgstr "Aggiungi alla Videoteca" msgctxt "#70147" -msgid "Videolibrary (Update series)" -msgstr "Videoteca (Aggiorna serie)" +msgid "Video library (update TV show)" +msgstr "Videoteca (aggiorna serie TV)" msgctxt "#70148" -msgid "Videolibrary (Do not update series)" -msgstr "Videoteca (Non aggiornare serie)" +msgid "Video library (do not update TV show)" +msgstr "Videoteca (non aggiornare serie TV)" msgctxt "#70149" msgid "Others" msgstr "Altro" msgctxt "#70150" -msgid "Movie/series info in contextual menu" -msgstr "Info film/serie nel menu contestuale" +msgid "Contextual menu" +msgstr "Menu contestuale" msgctxt "#70151" -msgid "Show Infoplus option:" -msgstr "Mostra opzione Infoplus:" +msgid "Show Infoplus" +msgstr "Mostra Infoplus" msgctxt "#70152" -msgid "Show ExtendedInfo option (External addon required):" -msgstr "Mostra opzione ExtendedInfo (Necessario addon esterno):" +msgid "Show ExtendedInfo" +msgstr "Mostra ExtendedInfo" msgctxt "#70153" -msgid "Buttons/Access keys (Changes require Kodi restart)" -msgstr "Pulsanti/Chiavi di accesso (le modifiche richiedono il riavvio di Kodi)" +msgid "Shortcut" +msgstr "Scorciatoia" msgctxt "#70154" -msgid "TheMovieDB (obtains data from movies or series)" -msgstr "TheMovieDB (ottieni dati dei film o series)" +msgid "TMDB search" +msgstr "Ricerca TMDB" msgctxt "#70155" -msgid "Simultaneous searches (may cause instability)" -msgstr "Ricerche Simultanee (può causare instabilità)" +msgid "Simultaneous searches" +msgstr "Ricerche simultanee" msgctxt "#70156" -msgid "Search extended information (actor's data) Increase search time" -msgstr "Cerca informazioni estese (dati sugli attori) Aumenta il tempo di ricerca" +msgid "Search actor's information" +msgstr "Cerca informazioni sugli attori" msgctxt "#70157" -msgid "Use cache (improves recurring searches)" -msgstr "Usa cache (migliora le ricerche ricorrenti)" +msgid "Use cache" +msgstr "Usa cache" msgctxt "#70158" msgid "every 1 day" @@ -3470,8 +3440,8 @@ msgid "Renew cache?" msgstr "Rinnovare la cache?" msgctxt "#70163" -msgid "Press to 'Clear cache' saved" -msgstr "Clicca per 'Eliminare la cache' salvata" +msgid "Clear cache" +msgstr "Pulire la cache" msgctxt "#70164" msgid "Free First" @@ -3566,12 +3536,12 @@ msgid "Getting episodes..." msgstr "Ottenimento episodi..." msgctxt "#70187" -msgid "connecting with %s..." -msgstr "connessione con %s..." +msgid "" +msgstr "" msgctxt "#70188" -msgid "Obtaining data from the series" -msgstr "Ottenimento dati della serie" +msgid "Obtaining data for the TV show" +msgstr "Ottenimento dati della serie TV" msgctxt "#70189" msgid "Start the download now?" @@ -3594,12 +3564,12 @@ msgid "Open torrent with..." msgstr "Apri torrent con..." msgctxt "#70194" -msgid "KOD-torrent" -msgstr "KOD-torrent" +msgid "KoD-torrent" +msgstr "KoD-torrent" msgctxt "#70195" -msgid "KOD - Torrent" -msgstr "KOD - Torrent" +msgid "KoD - Torrent" +msgstr "KoD - Torrent" msgctxt "#70196" msgid "Beginning..." @@ -3742,12 +3712,12 @@ msgid "Add completed downloads to the video library " msgstr "Aggiungi download completi alla videoteca" msgctxt "#70231" -msgid "Move the downloaded file to the video library" -msgstr "Sposta i files scaricati nella videoteca" +msgid "Move downloaded files to the video library" +msgstr "Sposta file scaricati nella videoteca" msgctxt "#70232" -msgid "View files downloaded from downloads" -msgstr "Visualizzare i files scaricati da Downloads" +msgid "View downloaded files" +msgstr "Visualizza file scaricati" msgctxt "#70233" msgid " - Size per block" @@ -3778,12 +3748,12 @@ msgid "Preferred quality" msgstr "Qualità preferita" msgctxt "#70241" -msgid "The highest" -msgstr "La più alta" +msgid "Highest" +msgstr "Più alta" msgctxt "#70242" -msgid "Choose the fastest servers" -msgstr "Scegli i servers più veloci" +msgid "Choose fastest servers" +msgstr "Scegli server più veloci" msgctxt "#70243" msgid "Download" @@ -3827,7 +3797,7 @@ msgstr "[B]Durata: %s minuti[/B]" msgctxt "#70253" msgid "Torrent client settings" -msgstr "Impostazioni Client Torrent" +msgstr "Impostazioni client torrent" msgctxt "#70254" msgid "Internal Client" @@ -3843,11 +3813,11 @@ msgstr "Quale client vuoi usare per riprodurre il torrent?" msgctxt "#70257" msgid "Settings -- Torrent" -msgstr "Configurazione-- Torrent" +msgstr "Impostazioni -- Torrent" msgctxt "#70258" -msgid "KOD Started" -msgstr "KOD Avviato" +msgid "KoD started" +msgstr "KoD avviato" msgctxt "#70259" msgid "The URL to access is http://%s:%s" @@ -3866,12 +3836,12 @@ msgid "Stopping the Websocket server ..." msgstr "Arresto del WebSocket..." msgctxt "#70263" -msgid "KOD stopped" -msgstr "KOD Arrestato" +msgid "KoD stopped" +msgstr "KoD arrestato" msgctxt "#70264" -msgid "Enter the username and password to access KOD" -msgstr "Enter the ususername e password per accedere a proteus" +msgid "Enter the username and password to access KoD" +msgstr "Enter the ususername e password per accedere a KoD" msgctxt "#70265" msgid "The data entered is not correct!" @@ -3886,12 +3856,12 @@ msgid "Search new episodes now" msgstr "Cerca nuovi episodi adesso" msgctxt "#70270" -msgid "Videolibrary movies" -msgstr "Videoteca di Film" +msgid "Movies video library" +msgstr "Videoteca film" msgctxt "#70271" -msgid "Videolibrary Tv Shows" -msgstr "Videoteca di Serie Tv" +msgid "TV shows video library" +msgstr "Videoteca serie TV" msgctxt "#70272" msgid "Activate premium account" @@ -3946,20 +3916,20 @@ msgid "%.2f%% of %.1fMB %s | %.1f kB/s" msgstr "%.2f%% di %.1fMB %s | %.1f kB/s" msgctxt "#70285" -msgid "Configure News" -msgstr "Configura Novità" +msgid "Configure news" +msgstr "Configura novità" msgctxt "#70286" -msgid "Configure Search" -msgstr "Configura Ricerca" +msgid "Configure search" +msgstr "Configura ricerca" msgctxt "#70287" -msgid "Configure VideoLibrary" -msgstr "Configura Videoteca" +msgid "Configure video library" +msgstr "Configura videoteca" msgctxt "#70288" -msgid "Configure Downloads" -msgstr "Configura Downloads" +msgid "Configure downloads" +msgstr "Configura downloads" msgctxt "#70291" msgid "Error, during conversion" @@ -4038,20 +4008,20 @@ msgid "Movies Now in Theatres " msgstr "Film Ora in sala" msgctxt "#70310" -msgid "Series by Genre" -msgstr "Serie per Genere" +msgid "TV shows by Genre" +msgstr "Serie TV per Genere" msgctxt "#70311" -msgid "Series most polupar" -msgstr "Serie più popolari" +msgid "TV Shows most popular" +msgstr "Serie TV più popolari" msgctxt "#70312" -msgid "Series in progress" -msgstr "Serie TV In corso" +msgid "TV shows in progress" +msgstr "Serie TV in corso" msgctxt "#70313" -msgid "Top rated Series" -msgstr "Serie Più valutate" +msgid "Top rated TV shows" +msgstr "Serie TV più valutate" msgctxt "#70314" msgid "Actors/Actresses" @@ -4198,8 +4168,8 @@ msgid "List sorted by %s. Change order?" msgstr "Lista ordinata per %s. Cambiare ordine?" msgctxt "#70350" -msgid "Search in kod: %s" -msgstr "Cerca in kod: %s" +msgid "Search in KoD: %s" +msgstr "Cerca in KoD: %s" msgctxt "#70351" msgid " Search alternative title: %s" @@ -4466,7 +4436,7 @@ msgid "=== Movies ===" msgstr "=== Film ===" msgctxt "#70417" -msgid "=== TV Shows ===" +msgid "=== TV shows ===" msgstr "=== Serie TV ===" msgctxt "#70418" @@ -4903,7 +4873,7 @@ msgstr "Verifica dei contatori di video visti/non visti (deselezionare per verif msgctxt "#70527" msgid "My links" -msgstr "I Miei Link" +msgstr "I miei link" msgctxt "#70528" msgid "Default folder" @@ -4954,8 +4924,8 @@ msgid "* To add links to folders, access the context menu from any point in Kodi msgstr "* Per aggiungere collegamenti alle cartelle accedi al menu contestuale da qualsiasi punto di Kodi on Demand." msgctxt "#70541" -msgid "* The links can be channels, sections within the channels, searches, and even movies and series although for the latter it is preferable to use the video library." -msgstr "* I collegamenti possono essere canali, sezioni all'interno dei canali, ricerche e persino film e serie, sebbene per quest'ultimo sia preferibile utilizzare la videoteca." +msgid "* The links can be channels, sections within the channels, searches, and even movies and TV shows although for the latter it is preferable to use the video library." +msgstr "* I collegamenti possono essere canali, sezioni all'interno dei canali, ricerche e persino film e serie TV, sebbene per quest'ultimo sia preferibile utilizzare la videoteca." msgctxt "#70542" msgid "Create new folder ..." @@ -5026,32 +4996,32 @@ msgid "Select color:" msgstr "Seleziona colore:" msgctxt "#70559" -msgid "Now in Theatres " -msgstr "Oggi in Sala" +msgid "Now in theatres " +msgstr "Oggi in sala" msgctxt "#70560" -msgid "Movies by Genre" +msgid "Movies by genre" msgstr "Per genere" msgctxt "#70561" -msgid "Search Similar" -msgstr "Cerca Simili" +msgid "Search similar" +msgstr "Cerca simili" msgctxt "#70562" -msgid "Enable autoplay on all supported channels" -msgstr "Abilita l'autoplay in tutti i canali supportati" +msgid "Enable AutoPlay on all supported channels" +msgstr "Abilita l'AutoPlay in tutti i canali supportati" msgctxt "#70563" msgid "Italian" msgstr "Italiano" msgctxt "#70564" -msgid "Enable Custom Theme" -msgstr "Abilita Tema Personalizzato" +msgid "Enable custom theme" +msgstr "Abilita tema personalizzato" msgctxt "#70565" -msgid "Custom Theme Path" -msgstr "Percorso Tema Personalizzato" +msgid "Custom theme path" +msgstr "Percorso tema personalizzato" msgctxt "#70566" msgid "VOSI (Original Subtitled Italian Version)" @@ -5102,28 +5072,28 @@ msgid "Modify starting from " msgstr "Modifica partendo da " msgctxt "#70578" -msgid "To avoid waiting too long when a server does not respond:" -msgstr "Per evitare di aspettare troppo a lungo quando un server non risponde:" +msgid "Torrents" +msgstr "Torrent" msgctxt "#70579" -msgid "Settings of KoD updates:" -msgstr "Impostazioni degli aggiornamenti di KoD" +msgid "Updates" +msgstr "Aggiornamenti" msgctxt "#70580" -msgid "Timeout (maximum waiting time)" -msgstr "Timeout (tempo massimo da aspettare)" +msgid "Server answer timeout (seconds)" +msgstr "Timeout risposta server (secondi)" msgctxt "#70581" msgid "Check for updates" -msgstr "Controlla gli aggiornamenti" +msgstr "Controlla aggiornamenti" msgctxt "#70582" -msgid "Do you want to be notified?" -msgstr "Voi essere notificato?" +msgid "Updates notification" +msgstr "Notifiche aggiornamenti" msgctxt "#70583" -msgid "Management of updates of other addons related to KOD:" -msgstr "Gestione degli aggiornamenti per gli altri addon relativi ad KOD" +msgid "Management of updates of other addons related to KoD:" +msgstr "Gestione degli aggiornamenti per gli altri addon relativi ad KoD" msgctxt "#70584" msgid "Do you want to update Quasar to avoid errors?" @@ -5134,16 +5104,16 @@ msgid "Renumbering" msgstr "Rinumerazione" msgctxt "#70586" -msgid "Set up series number..." -msgstr "Configura la rinumerazione della serie..." +msgid "Set up TV show renumbering..." +msgstr "Configura la rinumerazione della serie TV..." msgctxt "#70587" msgid "Set up" msgstr "Configurazione" msgctxt "#70588" -msgid "No series found, look for a series and click on contextual menu" -msgstr "Nessuna serie trovata, cerca una serie e fai clic sul menu contestuale" +msgid "No TV show found, look for a TV show and click on contextual menu" +msgstr "Nessuna serie TV trovata, cerca una serie TV e fai clic sul menu contestuale" msgctxt "#70589" msgid "Something found:" @@ -5198,8 +5168,8 @@ msgid "Update from the Internet:" msgstr "Aggiorna da Internet" msgctxt "#70602" -msgid "The first season that is added always starts in \"0 \" episodes, the second season that is added starts in the total number of episodes of the first season, the third season will be the sum of the episodes of the previous seasons and so on.\n \nSerial example divided into several seasons: \n\nFairy Tail: \n - SEASON 1: EPISODE 48 -> [season 1, episode: 0] \n - SEASON 2: EPISODE 48 - -> [season 2, episode: 48] \n - SEASON 3: EPISODE 54 -> [season 3, episode: 96 ([48 = season2] + [48 = season1])] \n - SEASON 4: EPISODE 175 -> [season 4: episode: 150 ([54 = season3] + [48 = season2] + [48 = season3])] \n \nExample of a series that continues in the season of the original: \n \nFate / Zero 2nd Season: \n - SEASON 1: EPISODE 12 -> [season 1, episode: 13] \n \nExample example which is the second Season of the original: \n \nFate / kaleid liner Prism☆Illya 2wei!: \n - SEASON 1: EPISODE 12 -> [season 2, episode: 0] \n" -msgstr "La prima stagione che viene aggiunta inizia sempre dagli episodi \"0 \", la seconda stagione che viene aggiunta inizia nel numero totale di episodi della prima stagione, la terza stagione sarà la somma degli episodi delle stagioni precedenti e a seguire. \n \nEsempio serie divisa in diverse stagioni: \n \nFairy Tail: \n - STAGIONE 1: EPISODIO 48 -> [stagione 1, episodio: 0] \n - STAGIONE 2: EPISODIO 48 - -> [stagione 2, episodio: 48] \n - STAGIONE 3: EPISODIO 54 -> [stagione 3, episodio: 96 ([48 = stagione2] + [48 = stagione1])] \n - STAGIONE 4: EPISODIO 175 -> [stagione 4: episodio: 150 ([54 = stagione3] + [48 = stagione2] + [48 = stagione3])] \n \nEsempio di serie che continua nella stagione dell'originale: \n \nFate/Zero 2a stagione: \n - STAGIONE 1: EPISODIO 12 -> [stagione 1, episodio: 13] \n \nEsempio di esempio che è la seconda stagione dell'originale: \n \nFate/kaleid liner Prism☆Illya 2wei!: \n - STAGIONE 1: EPISODIO 12 -> [stagione 2, episodio: 0] \n" +msgid "The first season that is added always starts in \"0 \" episodes, the second season that is added starts in the total number of episodes of the first season, the third season will be the sum of the episodes of the previous seasons and so on.\n \nTV show example divided into several seasons: \n\nFairy Tail: \n - SEASON 1: EPISODE 48 -> [season 1, episode: 0] \n - SEASON 2: EPISODE 48 - -> [season 2, episode: 48] \n - SEASON 3: EPISODE 54 -> [season 3, episode: 96 ([48 = season2] + [48 = season1])] \n - SEASON 4: EPISODE 175 -> [season 4: episode: 150 ([54 = season3] + [48 = season2] + [48 = season3])] \n \nExample of a TV show that continues in the season of the original: \n \nFate / Zero 2nd Season: \n - SEASON 1: EPISODE 12 -> [season 1, episode: 13] \n \nExample which is the second season of the original: \n \nFate / kaleid liner Prism☆Illya 2wei!: \n - SEASON 1: EPISODE 12 -> [season 2, episode: 0] \n" +msgstr "La prima stagione che viene aggiunta inizia sempre dagli episodi \"0 \", la seconda stagione che viene aggiunta inizia nel numero totale di episodi della prima stagione, la terza stagione sarà la somma degli episodi delle stagioni precedenti e a seguire. \n \nEsempio serie TV divisa in diverse stagioni: \n \nFairy Tail: \n - STAGIONE 1: EPISODIO 48 -> [stagione 1, episodio: 0] \n - STAGIONE 2: EPISODIO 48 - -> [stagione 2, episodio: 48] \n - STAGIONE 3: EPISODIO 54 -> [stagione 3, episodio: 96 ([48 = stagione2] + [48 = stagione1])] \n - STAGIONE 4: EPISODIO 175 -> [stagione 4: episodio: 150 ([54 = stagione3] + [48 = stagione2] + [48 = stagione3])] \n \nEsempio di serie TV che continua nella stagione dell'originale: \n \nFate/Zero 2a stagione: \n - STAGIONE 1: EPISODIO 12 -> [stagione 1, episodio: 13] \n \nEsempio che è la seconda stagione dell'originale: \n \nFate/kaleid liner Prism☆Illya 2wei!: \n - STAGIONE 1: EPISODIO 12 -> [stagione 2, episodio: 0] \n" msgctxt "#70603" msgid "Manage link lists" @@ -5467,7 +5437,7 @@ msgstr "Non hai selezionato nessuna sezione da mostrare nella pagina iniziale" msgctxt "#70666" msgid "Use the context menu to define one" -msgstr "Usa il menù contestuale per aggiungerne una" +msgstr "Usa il menu contestuale per aggiungerne una" msgctxt "#70667" msgid "KoD is already updated" @@ -5494,16 +5464,16 @@ msgid "Addon successfully updated to %s.fix %d" msgstr "Addon aggiornato correttamente a %s.fix%d" msgctxt "#70673" -msgid "Alpha updated to" -msgstr "KOD aggiornato a" +msgid "KoD updated to" +msgstr "KoD aggiornato a" msgctxt "#70674" -msgid "KOD updates" -msgstr "Aggiornamenti KOD" +msgid "KoD updates" +msgstr "Aggiornamenti KoD" msgctxt "#70675" -msgid "Error checking updates" -msgstr "Errore durante il controllo degli aggiornamenti" +msgid "Unable to check the updates" +msgstr "Impossibile controllare gli aggiornamenti" msgctxt "#70676" msgid "Add a channel" @@ -5522,8 +5492,8 @@ msgid "From URL" msgstr "Da URL" msgctxt "#70680" -msgid "KOD - (Community)" -msgstr "KOD - (Community)" +msgid "KoD - (Community)" +msgstr "KoD - (Community)" msgctxt "#70681" msgid "Enter the channel URL" @@ -5554,12 +5524,12 @@ msgid "Special Episodes" msgstr "Episodi Speciali" msgctxt "#70688" -msgid "Are there special episodes in the series \n(Episode 0 Excluded)?" -msgstr "Sono presenti episodi speciali nella serie \n(Episodio 0 Escluso)?" +msgid "Are there special episodes in the TV show \n(Episode 0 Excluded)?" +msgstr "Sono presenti episodi speciali nella serie TV \n(Episodio 0 Escluso)?" msgctxt "#70689" -msgid "Enable Download" -msgstr "Abilita Download" +msgid "Enable download" +msgstr "Abilita download" msgctxt "#70690" msgid "Disclaimer" @@ -5570,8 +5540,8 @@ msgid "Using the download function you declare that you have a physical copy and msgstr "Utilizzando la funzione di download dichiari di essere in possesso di una copia fisica e di utilizzare questa funzione come backup dello stesso." msgctxt "#70692" -msgid "The KOD team assumes no responsibility for the use that is made of this proposed function" -msgstr "Il team di KOD non si assume alcuna responsabilità dell'uso che viene fatto di questa funzione proposta" +msgid "The KoD team assumes no responsibility for the use that is made of this proposed function" +msgstr "Il team di KoD non si assume alcuna responsabilità dell'uso che viene fatto di questa funzione proposta" msgctxt "#70693" msgid "Search" @@ -5610,7 +5580,7 @@ msgid "Restart Kodi to apply the changes" msgstr "Riavvia Kodi per applicare le modifiche" msgctxt "#70703" -msgid "Create directories with lowercase letters" +msgid "Create folders with lowercase letters" msgstr "Crea cartelle con le lettere minuscole" msgctxt "#70704" @@ -5622,8 +5592,8 @@ msgid "Use your custom channel URLs" msgstr "Utilizza URL personalizzati per i canali" msgctxt "#70706" -msgid "Autostart KOD at Kodi boot" -msgstr "Avvio automatico di KOD al boot di Kodi" +msgid "Launch KoD at Kodi start" +msgstr "Esegui KoD all'avvio di Kodi" msgctxt "#70707" msgid "Enable" @@ -5654,12 +5624,12 @@ msgid "Modify " msgstr "Modifica " msgctxt "#70715" -msgid "Customize Homepage" -msgstr "Personalizza Homepage" +msgid "Customized main menu" +msgstr "Menu principale personalizzato" msgctxt "#70716" -msgid "Select the elements you want to display on the Homepage" -msgstr "Seleziona gli elementi che vuoi visualizzare nella Homepage" +msgid "Main menu items" +msgstr "Elementi menu principale" msgctxt "#70717" msgid "Are all the special episodes present?" @@ -5738,12 +5708,12 @@ msgid "%s Special Episode Number" msgstr "Numero dell'Episodio Speciale %s" msgctxt "#70736" -msgid "Completed Serie" -msgstr "Serie Completa" +msgid "Completed TV show" +msgstr "Serie TV completa" msgctxt "#70737" -msgid "Side Menu" -msgstr "Menu Laterale" +msgid "Side menu" +msgstr "Menu laterale" msgctxt "#70738" msgid "Ready channels %d/%d" @@ -5766,8 +5736,8 @@ msgid "Movies by Year" msgstr "Film per Anno" msgctxt "#70743" -msgid "Series by Year" -msgstr "Serie per Anno" +msgid "TV shows by Year" +msgstr "Serie TV per Anno" msgctxt "#70744" msgid "%s channels remaining" @@ -5810,8 +5780,8 @@ msgid "Playback" msgstr "Riproduzione" msgctxt "#70754" -msgid "Display mode" -msgstr "Modalità visualizzazione" +msgid "View types" +msgstr "Tipi di vista" msgctxt "#70755" msgid "Default" @@ -5921,10 +5891,43 @@ msgctxt "#70781" msgid "Do you want to call Elementum Settings to temporarily switch to Use Files?" msgstr "Vuoi aprire i settaggi di Elementum per passare temporaneamente a usare i file?" +msgctxt "#70782" +msgid "Your device is not compatible with the Internal Client, do you want to use Quasar for Torrents?" +msgstr "Il tuo dispositivo non è compatibile con il Client Interno, Vuoi usare Quasar per i Torrent?" + +msgctxt "#70783" +msgid "Quasar installed and configured, enjoy!" +msgstr "Quasar installato e configurato, buona Visione!" + +msgctxt "#70784" +msgid "Attention!" +msgstr "Attenzione!" + +msgctxt "#70785" +msgid "Install Quasar" +msgstr "Installa Quasar" + +msgctxt "#70786" +msgid "Autostart" +msgstr "Avvio automatico" + +msgctxt "#70787" +msgid "Network" +msgstr "Rete" + +msgctxt "#70788" +msgid "Logging" +msgstr "Logging" + +msgctxt "#70789" +msgid "* Change by opening the settings from KoD main menu" +msgstr "* Cambia aprendo le impostazioni dal menu principale di KoD" + + # DNS start [ settings and declaration ] msgctxt "#707401" -msgid "Enable DNS Check Alert" -msgstr "Abilita Avviso Check DNS" +msgid "Enable DNS check alert" +msgstr "Abilita avviso check DNS" msgctxt "#707402" msgid "Connection or DNS problems" @@ -5947,8 +5950,8 @@ msgid "By disabling the alert, you have activated a notice\nthat will appear at msgstr "Disattivando l'avviso, hai attivato una notifica\nche apparirà in alto a dx in caso di problemi" msgctxt "#707407" -msgid "For any change to the DNS you MUST restart KODI!" -msgstr "Per ogni modifica sui DNS DEVI riavviare KODI!" +msgid "For any change to the DNS you MUST restart Kodi!" +msgstr "Per ogni modifica sui DNS DEVI riavviare Kodi!" msgctxt "#707408" msgid "Activate DNS override" @@ -5983,8 +5986,8 @@ msgid "You have not selected any choice, the cloudflare DNS will be used." msgstr "Non hai selezionato nessuna scelta!\nVerranno utilizzati i DNS di cloudflare." msgctxt "#707416" -msgid "how often you want to check for updates? (hours)" -msgstr "Ogni quanto vuoi che vengano controllati? (ore)" +msgid "Updates check interval (hours)" +msgstr "Intervallo controllo aggiornamenti (ore)" msgctxt "#707417" msgid "Favourite quality" @@ -6027,8 +6030,8 @@ msgid "before generating the report" msgstr "prima di generare il report" msgctxt "#707427" -msgid "Unable to read kodi log" -msgstr "Impossibile leggere il log di kodi" +msgid "Unable to read Kodi log" +msgstr "Impossibile leggere il log di Kodi" msgctxt "#707428" msgid "Failed to upload report" @@ -6047,7 +6050,7 @@ msgid "Enabled" msgstr "Attivato" msgctxt "#707432" -msgid "Disabed" +msgid "Disabled" msgstr "Disattivato" msgctxt "#707433" @@ -6056,4 +6059,164 @@ msgstr "Cancella" msgctxt "#707434" msgid "reCaptcha verification failed" -msgstr "Verifica reCaptcha fallita" \ No newline at end of file +msgstr "Verifica reCaptcha fallita" + +msgctxt "#80000" +msgid "Export video library" +msgstr "Esporta videoteca" + +msgctxt "#80001" +msgid "Import video library" +msgstr "Importa videoteca" + +msgctxt "#80002" +msgid "Select the folder where to export the video library" +msgstr "Selezionare la cartella dove esportare la videoteca" + +msgctxt "#80003" +msgid "Exporting video library..." +msgstr "Esportazione videoteca..." + +msgctxt "#80004" +msgid "The video library has been exported" +msgstr "La videoteca è stata esportata" + +msgctxt "#80005" +msgid "Select the zip file to be imported" +msgstr "Selezionare il file zip da importare" + +msgctxt "#80006" +msgid "Attention, the current video library will be overwritten. Proceed anyway?" +msgstr "Attenzione, l'attuale videoteca verrà sovrascritta. Procedere comunque?" + +msgctxt "#80007" +msgid "Importing video library..." +msgstr "Importazione videoteca..." + +msgctxt "#80008" +msgid "The video library has been imported" +msgstr "La videoteca è stata importata" + +msgctxt "#80009" +msgid "Would you like to search for new episodes and update video library?" +msgstr "Vuoi cercare i nuovi episodi ed aggiornare la videoteca?" + +msgctxt "#80010" +msgid "Select the video library path" +msgstr "Seleziona il percorso della videoteca" + +msgctxt "#80011" +msgid "Verifying folders..." +msgstr "Verifica cartelle..." + +msgctxt "#80012" +msgid "Moving video library..." +msgstr "Spostamento videoteca..." + +msgctxt "#80013" +msgid "Updating database..." +msgstr "Aggiornamento database..." + +msgctxt "#80014" +msgid "The video library has been moved" +msgstr "La videoteca è stata spostata" + +msgctxt "#80015" +msgid "Do you want to configure the Kodi video library?" +msgstr "Vuoi configurare la libreria di Kodi?" + +msgctxt "#80016" +msgid "Would you like to use custom or default settings?" +msgstr "Desideri utilizzare impostazioni personalizzate o predefinite?" + +msgctxt "#80017" +msgid "Custom" +msgstr "Personalizzate" + +msgctxt "#80018" +msgid "Default" +msgstr "Predefinite" + +msgctxt "#80019" +msgid "Select the video library path" +msgstr "Seleziona il percorso della videoteca" + +msgctxt "#80020" +msgid "Folder name for movies" +msgstr "Nome della cartella per i film" + +msgctxt "#80021" +msgid "Folder name for TV shows" +msgstr "Nome della cartella per le serie TV" + +msgctxt "#80022" +msgid "You can configure the Kodi video library later from the settings menu inside KoD" +msgstr "Potrai configurare la libreria di Kodi in seguito dal menu impostazioni all'interno di KoD" + +msgctxt "#80023" +msgid "You will be asked to choose and configure the information providers for movies and TV shows" +msgstr "Ti verrà chiesto di scegliere e configurare i provider delle informazioni per film e serie TV" + +msgctxt "#80024" +msgid "An error has occurred during the configuration of the Kodi video library. Please check the log and try again from the settings menu inside KoD" +msgstr "Si è verificato un errore durante la configurazione della libreria di Kodi. Si prega di controllare il log e riprovare dal menu impostazioni all'interno di KoD" + +msgctxt "#80025" +msgid "Cleaning database..." +msgstr "Pulizia database..." + +msgctxt "#80026" +msgid "Configuration of Kodi video library" +msgstr "Configurazione della libreria di Kodi" + +msgctxt "#80027" +msgid "You will be asked to configure The Movie Database for movies and The TVDB for TV shows" +msgstr "Ti verrà chiesto di configurare The Movie Database per i film e The TVDB per le serie TV" + +msgctxt "#80028" +msgid "The selected folders are already used by the Kodi library. Please change them properly" +msgstr "Le cartelle selezionate sono già utilizzate dalla libreria di Kodi. Si prega di cambiarle opportunamente" + +msgctxt "#80029" +msgid "The selected folders are already used by the Kodi library. Please change them properly from the settings menu inside KoD" +msgstr "Le cartelle selezionate sono già utilizzate dalla libreria di Kodi. Si prega di cambiarle opportunamente dal menu impostazioni all'interno di KoD" + +msgctxt "#80030" +msgid "The default path and folders will be used. You will be asked to choose and configure the information providers for movies and TV shows" +msgstr "Verranno utilizzati il percorso e le cartelle predefiniti. Ti verrà chiesto di scegliere e configurare i provider delle informazioni per film e serie TV" + +msgctxt "#80031" +msgid "Unable to connect to github. This is probably due to a lack of connection or github is currently offline. Please check and try again" +msgstr "Impossibile connettersi a github. Questo è probabilmente dovuto ad una mancanza di connessione oppure github è attualmente offline. Per favore verifica e riprova" + +msgctxt "#80032" +msgid "Installation in progress..." +msgstr "Installazione in corso..." + +msgctxt "#80033" +msgid "Choose the version of KoD to install" +msgstr "Scegli la versione di KoD da installare" + +msgctxt "#80034" +msgid "release (stable version)" +msgstr "release (versione stabile)" + +msgctxt "#80035" +msgid "master (beta version under development)" +msgstr "master (versione beta in fase di sviluppo)" + +msgctxt "#80036" +msgid "Delete video library" +msgstr "Elimina videoteca" + +msgctxt "#80037" +msgid "Attention, the entire video library will be deleted. Proceed anyway?" +msgstr "Attenzione, l'intera videoteca verrà eliminata. Procedere comunque?" + +msgctxt "#80038" +msgid "Deleting video library..." +msgstr "Eliminazione videoteca..." + +msgctxt "#80039" +msgid "The video library has been deleted" +msgstr "La videoteca è stata eliminata" \ No newline at end of file diff --git a/resources/media/themes/default/thumb_search_generic.png b/resources/media/themes/default/thumb_search_generic.png deleted file mode 100644 index 6cc4ee980c5f017207cd12bce3f480c2e7b7f085..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19004 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%0DAUu0L zTsIeZ9k?dzb~FM`!jg*50L@*S`Q*^sY;WC7k-d3SoB=!}%)SSrRS-?jx)qIpldz;> z(Uost>#<7K9IPdw^L)puxC0m<5Wx#GfO!z^%eoz1fgvm@OMU%K)U|)cvOOQtO>5Te zTu$)^@Wn#;gAi3fn2~iWx(q{DQrf!nf3Um#Q!48|0@|`}XCz81fQN+H_d?lo3?6fM zOV;gZ7>2N<q!kJsG<R)dU&mKeHEae>W!=(flx6@A2@57e%i|C|13ZQw^C&Kcu%x&Z z3Z0zp`;7w~TUmXimXqg>0_U@C>uQvC0ADQ3oCH(uhO+4p9swQ&Zpyl?3C|FgG!`NB z($#-}W1V|w?cK%t!{5`AYayf0N5*OV1n{N8%t<iy4k+9Og=r8?1MUQ-0ykXrb81eS zAuMS)A#@SwVIcHSDD==5&XPOdMtff~9lcF7=Nj2^`~c_rPBM5{!nnGKjNbrOvAG$z zG3zEI6_x%Azkv(?=NWuuDAP|wN|Gc=k|arzBuSDaNs=T<k|arzBuSDaNs=T<k|arz iBuSDaNs=U$hJOJX`aWAzaL|tc0000<MNUMnLSTa4su7g{ diff --git a/resources/media/themes/default/thumb_search_more.png b/resources/media/themes/default/thumb_search_more.png deleted file mode 100644 index 6ab8b57548ab09426a28681d75f59c677bce3a81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20709 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 U%e4L;JmYeduBlGNO?3GG0Oz<9RR910 diff --git a/resources/media/themes/default/thumb_search_tvshow.png b/resources/media/themes/default/thumb_search_tvshow.png deleted file mode 100644 index 062cb4358c314a444777bb8f28edabba931a8605..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22797 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 diff --git a/resources/media/themes/default/thumb_years.png b/resources/media/themes/default/thumb_years.png deleted file mode 100644 index 750a8055a4002aef458252f01b918d4a2f9b5236..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13796 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 diff --git a/resources/settings.xml b/resources/settings.xml index 8f9588a7..3ef50d2c 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -2,15 +2,15 @@ <settings> <!-- General --> <category label="70168"> - <setting id="autostart" type="action" label="70706" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiYXV0b3N0YXJ0IiwNCiAgICAiY2hhbm5lbCI6ICJzZXR0aW5nIg0KfQ==)"/> - <setting type="sep"/> - <setting id="thumbnail_type" type="select" lvalues="30011|30012|30200" label="30010" default="2"/> - <setting id="channel_language" type="select" values="auto|all|ita" label="30019" default="all"/> - <setting id="forceview" type="bool" label="30043" default="false"/> - <!-- <setting id="faster_item_serialization" type="bool" label="30300" default="false"/> --> - <setting type="sep"/> - <setting id="trakt_sync" type="bool" label="70109" default="false"/> + <setting label="70786" type="lsep"/> + <setting id="autostart" type="action" label="70706" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiYXV0b3N0YXJ0IiwNCiAgICAiY2hhbm5lbCI6ICJzZXR0aW5nIg0KfQ==)" default="Off"/> + <setting label="70579" type="lsep"/> + <setting id="addon_update_enabled" type="bool" label="70581" default="true"/> + <setting id="addon_update_message" type="bool" label="70582" default="true"/> + <setting id="addon_update_timer" type="slider" option="int" range="1,1,24" label="707416" default="1"/> + <setting label="70787" type="lsep"/> <setting id="resolver_dns" type="bool" label="707408" default="true" enable="true" visible="true"/> + <setting label="70788" type="lsep"/> <setting id="debug" type="bool" label="30003" default="false"/> </category> @@ -19,97 +19,38 @@ <setting id="player_mode" type="select" lvalues="30026|30027|30028|30029" label="30044" default="1"/> <setting id="default_action" type="select" lvalues="30006|30007|30008" label="30005" default="0"/> <setting id="autoplay" type="bool" label="70562" default="false" visible="true"/> - <setting id="hide_servers" type="bool" label="70747" default="false" visible="eq(-1,true)"/> + <setting id="hide_servers" type="bool" label="70747" default="false" visible="eq(-1,true)" subsetting="true"/> <setting id="checklinks" type="bool" label="30020" default="false"/> - <setting id="checklinks_number" type="slider" option="int" range="5,5,20" label="30021" default="5" visible="eq(-1,true)"/> + <setting id="checklinks_number" type="slider" option="int" range="5,5,20" label="30021" default="5" visible="eq(-1,true)" subsetting="true"/> </category> <!-- Videolibrary --> <category label="30131"> <setting label="30501" type="lsep"/> - <setting id="videolibrarypath" type="folder" label="30067" default="special://profile/addon_data/plugin.video.kod/videolibrary"/> - <setting id="folder_tvshows" type="text" label="70118" default="SERIES" subsetting="true"/> - <setting id="folder_movies" type="text" label="70119" default="CINE" subsetting="true"/> - + <!-- <setting id="videolibrarypath" type="action" label="30067" action="RunPlugin(plugin://plugin.video.kod/?ew0KCSJjaGFubmVsIjoibW92ZV92aWRlb2xpYnJhcnkiLA0KCSJhY3Rpb24iOiJzZXRfdmlkZW9saWJyYXJ5X3BhdGgiDQp9)" default="special://profile/addon_data/plugin.video.kod/videolibrary"/> --> + <setting id="videolibrarypath" type="folder" label="30067" default="special://profile/addon_data/plugin.video.kod/videolibrary/" option="writeable"/> + <setting id="folder_tvshows" type="text" label="70118" default="Serie TV"/> + <setting id="folder_movies" type="text" label="70119" default="Film"/> + <setting id="videolibrary_kodi" type="bool" label="70120" default="false"/> + <setting id="settings_kod" type="action" label="70789" action=""/> <setting label="59997" type="lsep"/> - <setting id="videolibrary_kodi_flag" type="number" label="" default="0" visible="false"/> - <setting id="videolibrary_kodi_force" type="bool" label="" default="false" visible="false"/> - <setting id="videolibrary_kodi" type="bool" label="70120" enable="lt(-1,2)+eq(0,false)" default="false"/> <setting id="videolibrary_max_quality" type="bool" label="70729" default="false" visible="true"/> <setting id="next_ep" type="select" label="70746" lvalues="70752|70747|70748" default="0"/> <setting id="next_ep_type" type="select" label="70754" lvalues="70755|70756|70757" default="0" visible="eq(-1,2)" subsetting="true"/> <setting id="next_ep_seconds" type="slider" option="int" range="20,10,120" label="70749" default="40" visible="!eq(-2,0)" subsetting="true"/> - + <setting id="trakt_sync" type="bool" label="70109" default="false"/> <setting label="30030" type="lsep"/> <setting id="vidolibrary_preferences" type="action" label="60542" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiY2hhbm5lbF9jb25maWciLA0KICAgICJjaGFubmVsIjogInZpZGVvbGlicmFyeSINCn0==)"/> - <setting id="vidolibrary_overwrite" type="action" label="60567" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAib3ZlcndyaXRlX3Rvb2xzIiwNCiAgICAiY2hhbm5lbCI6ICJzZXR0aW5nIg0KfQ==)"/> + <setting id="vidolibrary_export" type="action" label="80000" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiZXhwb3J0X3ZpZGVvbGlicmFyeSIsDQogICAgImNoYW5uZWwiOiAiYmFja3VwIg0KfQ==)"/> + <setting id="vidolibrary_import" type="action" label="80001" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiaW1wb3J0X3ZpZGVvbGlicmFyeSIsDQogICAgImNoYW5uZWwiOiAiYmFja3VwIg0KfQ==)"/> + <setting id="vidolibrary_delete" type="action" label="80036" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiZGVsZXRlX3ZpZGVvbGlicmFyeSIsDQogICAgImNoYW5uZWwiOiAidmlkZW9saWJyYXJ5Ig0KfQ==)"/> + <setting id="vidolibrary_restore" type="action" label="60567" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAicmVzdG9yZV90b29scyIsDQogICAgImNoYW5uZWwiOiAic2V0dGluZyINCn0=)"/> <setting id="vidolibrary_update" type="action" label="60568" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAidXBkYXRlX3ZpZGVvbGlicmFyeSIsDQogICAgImNoYW5uZWwiOiAidmlkZW9saWJyYXJ5Ig0KfQ==)"/> </category> - <!-- Search --> - <category label="60423"> - <setting id="last_search" type="bool" label="60678" default="true" visible="true"/> - <setting id="saved_searches_limit" type="slider" option="int" range="10,10,40" label="60677" default="10" visible="eq(-1,0)" subsetting="true"/> - <setting id="result_mode" type="select" label="60657" lvalues="60675|60676" default="0"/> - <setting id="thread_number" type="slider" label="60673" option="int" range="0,1,64" default="0"/> - <setting id="search_channels" type="action" label="59994" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJvcGNpb25lcyIsDQogICAgImNoYW5uZWwiOiJzZWFyY2giDQp9)"/> - </category> - - <!-- Downloads --> - <category label="30153"> - <setting id="downloadenabled" type="bool" label="70689" default="false"/> - <setting id="downloadpath" type="folder" label="30017" visible="eq(-1,true)" default="special://profile/addon_data/plugin.video.kod/downloads" subsetting="true"/> - <setting id="downloadlistpath" type="folder" label="30018" visible="eq(-2,true)" default="special://profile/addon_data/plugin.video.kod/downloads/list" subsetting="true"/> - - <setting id="library_add" type="bool" label="70230" default="false"/> - <setting id="library_move" type="bool" label="70231" default="false" visible="eq(-1,true)" subsetting="true"/> - <setting id="browser" type="bool" label="70232" default="true"/> - <setting id="server_speed" type="bool" label="70242" default="true"/> - <setting id="quality" type="select" label="70240" lvalues="70241|70763|70764|70765" default="0"/> - <setting id="download_adv" type="action" label="30030" action="RunPlugin(plugin://plugin.video.kod/?ew0KCSJhY3Rpb24iOiJjaGFubmVsX2NvbmZpZyIsDQoJImNvbmZpZyI6ImRvd25sb2FkcyIsDQogICAgImNoYW5uZWwiOiJzZXR0aW5nIg0KfQ==)"/> - </category> - - <!-- News --> - <category label="60327"> - <setting label="60525" type="lsep"/> - <setting id="news_films" type="action" label="60509" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWwiLA0KICAgICJjaGFubmVsIjoibmV3cyIsDQoJImV4dHJhIjoicGVsaWN1bGFzIg0KfQ==)"/> - <setting id="news_series" type="action" label="60511" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWwiLA0KICAgICJjaGFubmVsIjoibmV3cyIsDQoJImV4dHJhIjoic2VyaWVzIg0KfQ==)"/> - <setting id="news_anime" type="action" label="60512" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWwiLA0KICAgICJjaGFubmVsIjoibmV3cyIsDQoJImV4dHJhIjoiYW5pbWUiDQp9)"/> - <setting id="news_documentaries" type="action" label="60513" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWwiLA0KICAgICJjaGFubmVsIjoibmV3cyIsDQoJImV4dHJhIjoiZG9jdW1lbnRhbGVzIg0KfQ==)"/> - <setting type="lsep"/> - <setting id="news_options" type="action" label="60415" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5ncyIsDQogICAgImNoYW5uZWwiOiJuZXdzIg0KfQ==)"/> - </category> - - <!-- Customization --> - <category label="70126"> - <setting id="icon_set" type="select" label="70108" values="default|light|dark|alfa|mike" default="default"/> - <setting id="enable_custom_theme" type="bool" label="70564" default="false"/> - <setting id="custom_theme" type="folder" label="70565" default="" visible="eq(-1,true)"/> - <setting id="video_thumbnail_type" type="select" label="70131" lvalues="70132|70133" default="0"/> - <!-- Contextual --> - <setting label="30024" type="lsep"/> - <setting id="quick_menu" type="bool" label="60360" default="false"/> - <setting id="side_menu" type="bool" label="70737" default="false"/> - <setting id="kod_menu" type="bool" label="30025" default="false"/> - <!-- Homepage --> - <setting label="70716" type="lsep"/> - <setting id="enable_news_menu" label="30130" type="bool" default="true"/> - <setting id="enable_channels_menu" label="30118" type="bool" default="true"/> - <setting id="enable_search_menu" label="30103" type="bool" default="true"/> - <setting id="enable_onair_menu" label="50001" type="bool" default="true"/> - <setting id="enable_link_menu" label="70527" type="bool" default="true"/> - <setting id="enable_fav_menu" label="30102" type="bool" default="true"/> - <setting id="enable_library_menu" label="30131" type="bool" default="true"/> - <!-- Custom Start --> - <setting label="70121" type="lsep"/> - <setting id="start_page" type="bool" label="70121" default="false"/> - <setting id="custom_start" type="bool" label="70122" default="false" visible="eq(-1,True)"/> - <setting id="news_start" type="bool" label="70123" default="false" visible="eq(-2,True)" enable="eq(-1,False)+eq(-2,True"/> - <setting id="category" type="action" label="70124" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZWxlY3QiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkiaWQiOiJjYXRlZ29yeSIsDQoJInR5cGUiOiJsYWJlbHMiLA0KCSJ2YWx1ZXMiOiI3MDEzN3wzMDEyM3wzMDEyNHw2MDUxMyIsDQoJImxhYmVsIjoiNzAxMjQiDQp9)" visible="eq(-3,True)+eq(-1,True)+eq(-2,False)" enable="eq(-3,True)+eq(-1,True)+(-2,false)"/> - <!-- <setting id="category" type="select" label="70124" lvalues="70137|30123|30124|60513" default="Film" visible="eq(-3,True)+eq(-1,True)+eq(-2,False)" enable="eq(-3,True)+eq(-1,True)+(-2,false)"/> --> - </category> - + <!-- Channels --> <category label="30118" > + <setting id="channel_language" type="select" values="auto|all|ita" label="30019" default="all"/> <setting id="channels_onoff" type="action" label="60545" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiY29uZl90b29scyIsDQogICAgImNoYW5uZWwiOiAic2V0dGluZyIsDQoJImV4dHJhIjogImNoYW5uZWxzX29ub2ZmIg0KfQ==)"/> <setting id="channels_config" type="action" label="60537" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiY2hhbm5lbHNfbWVudSIsDQogICAgImNoYW5uZWwiOiAic2hvcnRjdXRzIg0KfQ==)"/> <setting id="channels_check" type="action" label="60549" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAiY2hlY2tfY2hhbm5lbHMiLA0KICAgICJjaGFubmVsIjogInNob3J0Y3V0cyINCn0==)"/> @@ -120,28 +61,25 @@ <setting id="resolve_priority" type="select" label="70110" lvalues="70164|70165|70166" default="0"/> <setting id="resolve_stop" type="bool" label="70111" default="true"/> <setting id="hidepremium" type="bool" label="70112" default="false"/> - <setting label="70578" type="lsep"/> <setting id="httptools_timeout" type="slider" option="int" range="0,5,120" label="70580" default="15"/> - <setting label="60538" type="lsep"/> + <setting label="70145" type="lsep"/> <setting id="servers_favorites" type="action" label="60551" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAic2VydmVyc19mYXZvcml0ZXMiLA0KICAgICJjaGFubmVsIjogInNldHRpbmciDQp9==)"/> <setting id="servers_blacklist" type="action" label="60550" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAic2VydmVyc19ibGFja2xpc3QiLA0KICAgICJjaGFubmVsIjogInNldHRpbmciDQp9==)"/> <setting id="servers_config" type="action" label="60538" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAic2VydmVyc19tZW51IiwNCiAgICAiY2hhbm5lbCI6ICJzaG9ydGN1dHMiDQp9==)"/> <setting id="debriders_config" type="action" label="60552" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAic2VydmVyc19tZW51IiwNCiAgICAiY2hhbm5lbCI6ICJzaG9ydGN1dHMiLA0KCSJ0eXBlIjogImRlYnJpZGVycyINCn0==)"/> + <setting label="70578" type="lsep"/> <setting id="torrent_config" type="action" label="70253" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX3RvcnJlbnQiLA0KICAgICJjaGFubmVsIjoic2V0dGluZyINCn0=)"/> + <setting id="quasar_install" type="action" label="70785" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJkb3dubG9hZCIsDQogICAgImNoYW5uZWwiOiJxdWFzYXJfZG93bmxvYWQiDQp9)"/> </category> - <!-- Other --> - <category label="70149"> - <setting label="70150" type="lsep"/> - <setting id="infoplus" type="bool" label="70151" default="false"/> - <setting id="infoplus_set" type="bool" label="70128" visible="eq(-1,true)" default="false" subsetting="true"/> - <setting id="extended_info" type="bool" label="70152" default="false"/> - - <setting label="70153" type="lsep"/> - <setting id="shortcut_key" type="action" label="30999" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAia2V5bWFwIg0KfQ==)"/> - <setting id="delete_key" type="action" label="31000" action="RunPlugin(plugin://plugin.video.kod/?ewogICAgImFjdGlvbiI6ICJkZWxldGVfa2V5Igp9==)"/> - - + <!-- Search --> + <category label="60423"> + <setting label="60422" type="lsep"/> + <setting id="last_search" type="bool" label="60678" default="true" visible="true"/> + <setting id="saved_searches_limit" type="slider" option="int" range="10,10,40" label="60677" default="10" visible="eq(-1,0)" subsetting="true"/> + <setting id="result_mode" type="select" label="60657" lvalues="60675|60676" default="0"/> + <setting id="thread_number" type="slider" label="60673" option="int" range="0,1,64" default="0"/> + <setting id="search_channels" type="action" label="59994" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJvcGNpb25lcyIsDQogICAgImNoYW5uZWwiOiJzZWFyY2giDQp9)"/> <setting label="70154" type="lsep"/> <setting id="tmdb_active" default="true" visible="false"/> <setting id="tmdb_threads" type="slider" option="int" range="5,5,30" label="70155" default="20"/> @@ -149,14 +87,80 @@ <setting id="tmdb_cache" type="bool" label="70157" default="true"/> <setting id="tmdb_cache_expire" type="select" lvalues="70158|70159|70160|70161|70170" label="70162" enable="eq(-1,true)" default="4"/> <setting id="tmdb_clean_db_cache" type="action" label="70163" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAic2NyaXB0Ig0KfQ==)" /> - - <setting label="70579" type="lsep"/> - <setting id="addon_update_enabled" type="bool" label="70581" default="true"/> - <setting id="addon_update_message" type="bool" label="70582" default="true"/> - <setting id="addon_update_timer" type="slider" option="int" range="1,1,24" label="707416" default="1"/> - <setting label="Lista activa" type="text" id="lista_activa" default="kodfavorites-default.json" visible="false"/> + </category> + <!-- Downloads --> + <category label="30153"> + <setting id="downloadenabled" type="bool" label="70689" default="false"/> + <setting id="downloadpath" type="folder" label="30017" visible="eq(-1,true)" default="special://profile/addon_data/plugin.video.kod/downloads/" option="writeable"/> + <setting id="settings_kod1" type="action" label="70789" action="" visible="eq(-2,true)"/> + <setting id="downloadlistpath" type="folder" label="30018" visible="eq(-3,true)" default="special://profile/addon_data/plugin.video.kod/downloads/list/" option="writeable"/> + <!-- <setting id="library_add" type="bool" label="70230" default="false"/> + <setting id="library_move" type="bool" label="70231" default="false" visible="eq(-1,true)" subsetting="true"/> --> + <setting id="library_move" type="bool" label="70231" visible="eq(-4,true)" default="true"/> + <setting id="browser" type="bool" label="70232" visible="eq(-5,true)" default="true"/> + <setting id="server_speed" type="bool" label="70242" visible="eq(-6,true)" default="true"/> + <setting id="quality" type="select" label="70240" lvalues="70241|70763|70764|70765" visible="eq(-7,true)" default="0"/> + <setting id="download_adv" type="action" label="30030" visible="eq(-8,true)" action="RunPlugin(plugin://plugin.video.kod/?ew0KCSJhY3Rpb24iOiJjaGFubmVsX2NvbmZpZyIsDQoJImNvbmZpZyI6ImRvd25sb2FkcyIsDQogICAgImNoYW5uZWwiOiJzZXR0aW5nIg0KfQ==)"/> + </category> + + <!-- News --> + <category label="60327"> + <setting label="60525" type="lsep"/> + <setting id="news_films" type="action" label="60509" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWwiLA0KICAgICJjaGFubmVsIjoibmV3cyIsDQoJImV4dHJhIjoicGVsaWN1bGFzIg0KfQ==)"/> + <setting id="news_series" type="action" label="60511" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWwiLA0KICAgICJjaGFubmVsIjoibmV3cyIsDQoJImV4dHJhIjoic2VyaWVzIg0KfQ==)"/> + <setting id="news_anime" type="action" label="60512" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWwiLA0KICAgICJjaGFubmVsIjoibmV3cyIsDQoJImV4dHJhIjoiYW5pbWUiDQp9)"/> + <setting id="news_documentaries" type="action" label="60513" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5nX2NoYW5uZWwiLA0KICAgICJjaGFubmVsIjoibmV3cyIsDQoJImV4dHJhIjoiZG9jdW1lbnRhbGVzIg0KfQ==)"/> + <setting id="news_options" type="action" label="60415" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZXR0aW5ncyIsDQogICAgImNoYW5uZWwiOiJuZXdzIg0KfQ==)"/> + </category> + + <!-- Customization --> + <category label="70126"> + <!-- Homepage --> + <setting label="70716" type="lsep"/> + <setting id="enable_news_menu" label="30130" type="bool" default="true"/> + <setting id="enable_channels_menu" label="30118" type="bool" default="true"/> + <setting id="enable_search_menu" label="30103" type="bool" default="true"/> + <setting id="enable_onair_menu" label="50001" type="bool" default="true"/> + <setting id="enable_link_menu" label="70527" type="bool" default="true"/> + <setting id="enable_fav_menu" label="30102" type="bool" default="true"/> + <setting id="enable_library_menu" label="30131" type="bool" default="true"/> + <!-- View Mode--> + <setting label="70754" type="lsep"/> + <setting id="skin_name" label='Skin Name' type="text" default="skin.estuary" visible="false"/> + <setting id="view_mode_addon" type="action" label="70009" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJ2aWV3X21vZGUiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkidHlwZSI6ImFkZG9uIg0KfQ==)" default= "Default, 0"/> + <setting id="view_mode_channel" type="action" label="30118" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJ2aWV3X21vZGUiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkidHlwZSI6ImNoYW5uZWwiDQp9)" default= "Default, 0"/> + <setting id="view_mode_movie" type="action" label="30122" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJ2aWV3X21vZGUiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkidHlwZSI6Im1vdmllIg0KfQ==)" default= "Default, 0"/> + <setting id="view_mode_tvshow" type="action" label="30123" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJ2aWV3X21vZGUiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkidHlwZSI6InR2c2hvdyINCn0=)" default= "Default, 0"/> + <setting id="view_mode_season" type="action" label="30140" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJ2aWV3X21vZGUiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkidHlwZSI6InNlYXNvbiINCn0=)" default= "Default, 0"/> + <setting id="view_mode_episode" type="action" label="70362" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJ2aWV3X21vZGUiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkidHlwZSI6ImVwaXNvZGUiDQp9)" default= "Default, 0"/> + <setting id="view_mode_server" type="action" label="70145" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJ2aWV3X21vZGUiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkidHlwZSI6InNlcnZlciINCn0=)" default= "Default, 0"/> + <!-- Contextual --> + <setting label="30024" type="lsep"/> + <setting id="quick_menu" type="bool" label="60360" default="true"/> + <setting id="side_menu" type="bool" label="70737" default="false"/> + <setting id="kod_menu" type="bool" label="30025" default="true"/> + <setting id="infoplus" type="bool" label="70151" default="false"/> + <setting id="infoplus_set" type="bool" label="70128" visible="eq(-1,true)" default="false" subsetting="true"/> + <setting id="extended_info" type="bool" label="70152" default="false"/> + <!-- Shortcut --> + <setting label="70153" type="lsep"/> + <setting id="shortcut_key" type="action" label="30999" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiAia2V5bWFwIg0KfQ==)"/> + <setting id="delete_key" type="action" label="31000" action="RunPlugin(plugin://plugin.video.kod/?ewogICAgImFjdGlvbiI6ICJkZWxldGVfa2V5Igp9==)"/> + <!-- Custom Start --> + <setting label="70715" type="lsep"/> + <setting id="start_page" type="bool" label="70121" default="false"/> + <setting id="custom_start" type="bool" label="70122" default="false" visible="eq(-1,True)" enable="eq(-1,True)+eq(1,False)" subsetting="true"/> + <setting id="news_start" type="bool" label="70123" default="false" visible="eq(-2,True)" enable="eq(-1,False)+eq(-2,True)" subsetting="true"/> + <setting id="category" type="action" label="70124" action="RunPlugin(plugin://plugin.video.kod/?ew0KICAgICJhY3Rpb24iOiJzZWxlY3QiLA0KICAgICJjaGFubmVsIjoic2hvcnRjdXRzIiwNCgkiaWQiOiJjYXRlZ29yeSIsDQoJInR5cGUiOiJsYWJlbHMiLA0KCSJ2YWx1ZXMiOiI3MDEzN3wzMDEyM3wzMDEyNHw2MDUxMyIsDQoJImxhYmVsIjoiNzAxMjQiDQp9)" visible="eq(-3,True)+eq(-1,True)+eq(-2,False)" enable="eq(-3,True)+eq(-1,True)+eq(-2,False)" subsetting="true"/> + <!-- <setting id="category" type="select" label="70124" lvalues="70137|30123|30124|60513" default="Film" visible="eq(-3,True)+eq(-1,True)+eq(-2,False)" enable="eq(-3,True)+eq(-1,True)+(-2,false)"/> --> + <!-- Others --> + <setting label="70149" type="lsep"/> + <setting id="icon_set" type="select" label="70108" values="default|light|dark|alfa|mike" default="default"/> + <setting id="enable_custom_theme" type="bool" label="70564" default="false"/> + <setting id="custom_theme" type="folder" label="70565" default="" visible="eq(-1,true)"/> + <setting id="video_thumbnail_type" type="select" label="70131" lvalues="70132|70133" default="1"/> </category> <!-- Adult --> diff --git a/resources/skins/Default/media/Shortcut - Copia/close.png b/resources/skins/Default/media/Shortcut - Copia/close.png deleted file mode 100644 index 0a144666ef760af7c275b8fe8a2b249835343940..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 874 zcmV-w1C{)VP)<h;3K|Lk000e1NJLTq002|~002}71ONa4wqn>y0000WV@Og>004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_000McNliru-w6c(90DB+s%QWJ0?$cAK~!ko?b_c?6G0RP z@UI0gKzIWYQia_Ty;lj|Xkt>5@){<X=o9IM8lM2XK&)?}{X;`ysm4n!HG$&ig|W2D z?#$WQvo?)$de=E;_Lu3*c4pfGF&$ByG{8eW)I&YgLp{_(J=8-zbQ(enx`_Eq^;fZ& zKlDD{p@lkLV%e#F1+VZ4P3&XSkj1R8Do^+~nhaCdhinb&PgqUL%gWqlpQCY@k{a@G ztiI3fJfPJGlO$UysH3BKL9J>-H)EJ-Mm0K`7t{?+XpuE0g@l^KB*_C7^`Hy<MmkeX zO!6xiq80A9r(ZZTw3e`oFtIhnE=q>#0nVduxkLN-U~Dg8FM%3j&&UL7_<8BQ42$VH zn>0r|W&(t4TdL|@(p~l7YRv5=N)5&;0s-@e_U%bZT_0wzyE3ywCDbmT@)mFN8NawP zHJ}nIIpDyWV_@n)WmH=<OiV3kc52<s)PsU+8K@23wDqqCb*I+tOkF6rX8j6qWNJgx zQ-w@@C>XFKW`5?Xv|oKFxFd!>miL;+x&A!{qP#QI<elaLE##1y3-lpoMR`~7AVsh0 zGqlXEc#a;kJgLQGJ_}tA@pFL5GE-1>nYL|le6%Ih$uosiEoR{Gp^s01;9o$qjHYl@ zbw<<9Jmsl?8srJJGdtX2$TFYs*qxd`voW$m3Q|7@P=ZRB<7c7tk1Q0RE7p}Bce1n} zSXx}xg}$*|FlqO0r@q#N&RaGgrbCA9z|!Gdw8nj#SHz5=wSfv+hSn`ZD=-`5avsql z51d9*GOGJ5XwK1lBfl`EWtylzct>|Jft47l_yC+h?eS4uZZ;^m6``hK#!(ZP8egFm z_J)`Fn3DO2+8EY<Ph#q9N;deGT^{i{uQ}B(@dc0A<sR=QXBCwG=(>ROm|rsFF^3uS zObJ@h+~dFd2ZV=usE1A(;GrJsp&sg?9y*=S-{)xseoD+zK>z>%07*qoM6N<$f;I4l ACIA2c diff --git a/resources/skins/Default/media/Shortcut - Copia/dialog-bg-solid-white.png b/resources/skins/Default/media/Shortcut - Copia/dialog-bg-solid-white.png deleted file mode 100644 index 225aae63aa703a6ddbf30bdffd0893f28a469996..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3774 zcmeAS@N?(olHy`uVBq!ia0y~yV1C2Ez!b#61{8_R^S1<2jKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sDEfH31!Z9ZurBiPf$F{C2y?R7&&1_ho28yf4+A8725 zI~mLy`&<&JNg?$=6OdADlLeAZJk~&xMY0S?au@+^XAnra!3b1zVgoY+gTsVGb_Rw9 zg~NP63CB?lqoFjKG)D8oXsIz;RF2jUqm|-l(_yr|G}=fUZ5faDABK0Q$<kQ-IXB0G U`faxt0TVler>mdKI;Vst0FW=fA^-pY diff --git a/resources/skins/Default/media/Shortcut - Copia/dialog-bg-solid.png b/resources/skins/Default/media/Shortcut - Copia/dialog-bg-solid.png deleted file mode 100644 index e8c13ebd70be0fb9b4026fa4bac916a9ffbaefc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1891 zcmeAS@N?(olHy`uVBq!ia0y~yV1C2Ez!by*6kw=f6?h7y6p}rHd>I(3R2di=ni&{= z{s+=885l|p7#Ln9FfdrnU|<l>pA>)84XBnW$=lt9;eUJonf*W>XMsm#F#`j)5C}6~ zx?A@LD9B#o>FdgVpOckAhB=F8);|UYwiBK%jv*Dd-d;9jWH8`q*wD4IzPEIvtO{4f z3|66M<qRL%ZYmynBam3uVPNetLssbwpI}-$$7bi2QQ^@r8BGwQxnZ;@7%d(LzHT_e ZxUXPMm(Qa3Tfl0L!PC{xWt~$(695=D%^d&$ diff --git a/resources/skins/Default/media/Shortcut - Copia/logo.png b/resources/skins/Default/media/Shortcut - Copia/logo.png deleted file mode 100644 index d8a680fe8fe6a19175d45ccf88ff2c05022c0395..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 838 zcmV-M1G)T(P)<h;3K|Lk000e1NJLTq001=r001-y1ONa4fU~$>0000WV@Og>004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0RM-N%)bBt010qN zS#tmY3ljhU3ljkVnw%H_000McNliru-w6c(90`iqbKn2~0;@?xK~z}7z1BNV6j2nw z@w0#tMdh6+z8Zsyv9tlBpq*AmqpYAt5=6mZWkZAy;0x>wozGaI2#66PvZ9neu*9ez z0V5W;@V8)v*|~Ec>&$Y>xo6IA?zxX$k&J_Ornt+R%-_ru>S8elvy9QnatyFGd(bt~ z<9U{5ra%DwS-|KZIG&NeGSDKnIy&eo=6D(rW`zLyB3LtakaVD+mzcRyj@8;OxlZ47 zLJGoCI8MJ$X2Uk{fK&VW?Kg*gRxU9h@!0Q`pa!Mh4n;u?$;otxTq+#jrP|wf%UTWj z*NAN-_(d<P?9dgGR69~H@NICm@+CF)m^?Go20)z?6$DLr#vh?Sk+h_eY8|Ly)+x|u zU(Q1fM)OjNoqDN2Tlf@^_aLB+G%@c?y;7jfeALX|k8#ce*{BiLJ3|2XJ#D1XcYB+t zQ3cv$guEDW<!3@qjj+K7Rqz3O+#^qjGp7vbs8I#VW!M1%=*W?yqMqyE>*}=}kNxyL z%a?uP7W;GLrc5i3gMLrP<XCJ*Nt~4)CumN(MTAPGeUm-xY0*Id-cYEk!gXu&<~a2) zxstD1ss>0<Wcp-oSfF}u@=m^KsA9S(vGs>rTIf$2BqG8t4_0R^TR;Ofj#!d-P>J13 zSgipnX9Ae#vNCczU`D5PWvcjYrYL7}sgR0w`=AC>bN289IHVaZ^FYB^j|XbBE%06@ zsR|q^<-O9PHYMv$YK_i_JqWxj0wI7_C9|C;9C3g&d?^#!?R@FK%Vr1xT#O1T;Vrgk zi2^DjVTE9U^WmvZ2MAz>jpj=BKhg`X-xPjUg^W4P>TGCAgkr|6E7cqUl)@55=t4wL z3e#`+C^mW;R-!q^Q61kjtdw^v0*Q!F=EGXU*EC_v_j_CTdNynvNM;WG1q3XOBXVoM Q{Qv*}07*qoM6N<$f@PO&A^-pY diff --git a/resources/skins/Default/media/Shortcut - Copia/white.png b/resources/skins/Default/media/Shortcut - Copia/white.png deleted file mode 100644 index 528c66f6e8ed820dff50fb927f805aebd269327b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^EFjDXBp4dI7GDNZ3dtTpz6=aiY77hwEes65fI<x~ z7#K<o7#Ln9FfdrnU|<k0n6oR;1}MRl<n8Xlz<9SycnOflS>O>_%)r1c48n{Iv*t(u z1=&kHeO=k_bFwnXa0y>fiUJDpc)B=-a9mIRae$$XfuDo<U|jU$gFtZxPgg&ebxsLQ E0Oo5Y8vp<R diff --git a/resources/skins/Default/media/Shortcut - Copia/white70.png b/resources/skins/Default/media/Shortcut - Copia/white70.png deleted file mode 100644 index d428a73af228f6e940998d8f228086f6f61f200c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^EFjDQBAI`LeFahq$sR$z3=CDO3=9p;3=BX21L>Cx z45bDP46hOx7_4S6Fo@?*ia+WGRLhj)?e4<xzrFv=ejtytz$3Dlfq`2Xgc%uT&5-~K zvX^-Jy0YKrWMz=y6271m1r!qVba4#fxSsrH|I9`(=xk&ZXJ)VtXWVt|y3<>r3I<PC KKbLh*2~7Z(Yb?D0 diff --git a/resources/views/skin.ace2.json b/resources/views/skin.ace2.json new file mode 100644 index 00000000..088ebcac --- /dev/null +++ b/resources/views/skin.ace2.json @@ -0,0 +1,44 @@ +{ + "all":{ + "Right List": 50, + "Frame": 51, + "Wall": 56, + "Tech": 68, + "Sets Plus": 74 + }, + "movie":{ + "Right List": 50, + "Frame": 51, + "Wall": 56, + "Tech": 68, + "Sets Plus": 74 + }, + "tvshow":{ + "Right List": 50, + "Frame": 51, + "Wall": 56, + "Tech": 68, + "Sets Plus": 74 + }, + "season":{ + "Right List": 50, + "Frame": 51, + "Wall": 56, + "Tech": 68, + "Sets Plus": 74 + }, + "episode":{ + "Right List": 50, + "Frame": 51, + "Wall": 56, + "Tech": 68, + "Sets Plus": 74 + }, + "addon":{ + "Right List": 50, + "Frame": 51, + "Wall": 56, + "Tech": 68, + "Sets Plus": 74 + } +} \ No newline at end of file diff --git a/resources/views/skin.aeon.nox.silvo.json b/resources/views/skin.aeon.nox.silvo.json new file mode 100644 index 00000000..3e777a57 --- /dev/null +++ b/resources/views/skin.aeon.nox.silvo.json @@ -0,0 +1,109 @@ +{ + "all":{ + "List": 50, + "RightList": 506, + "FanartList": 602, + "LowList": 501, + "BigList": 507, + "Logo": 59, + "Showcase": 53, + "Shift": 57, + "Posters": 56, + "MyFlix": 509, + "TriPanel": 55, + "Icons": 500, + "Small Icons": 499, + "Wall": 503, + "Fullscreen Wall": 609, + "infoWall": 51, + "BannerWall": 58, + "BannerPlex": 601, + "Landscape": 52, + "BigFan": 591, + "Gallery": 504, + "Panel": 505, + "Episode": 502 + }, + "movie":{ + "List": 50, + "RightList": 506, + "FanartList": 602, + "LowList": 501, + "BigList": 507, + "Logo": 59, + "Showcase": 53, + "Shift": 57, + "Posters": 56, + "MyFlix": 509, + "TriPanel": 55, + "Icons": 500, + "Small Icons": 499, + "Wall": 503, + "Fullscreen Wall": 609, + "infoWall": 51, + "BannerWall": 58, + "BannerPlex": 601, + "Landscape": 52, + "BigFan": 591, + "Gallery": 504, + "Panel": 505 + }, + "tvshow":{ + "List": 50, + "RightList": 506, + "FanartList": 602, + "LowList": 501, + "BigList": 507, + "Logo": 59, + "Showcase": 53, + "Shift": 57, + "Posters": 56, + "MyFlix": 509, + "TriPanel": 55, + "Icons": 500, + "Small Icons": 499, + "Wall": 503, + "Fullscreen Wall": 609, + "infoWall": 51, + "BannerWall": 58, + "BannerPlex": 601, + "Landscape": 52, + "BigFan": 591, + "Gallery": 504, + "Panel": 505, + "Episode": 502 + }, + "season":{ + "List": 50, + "RightList": 506, + "FanartList": 602, + "LowList": 501, + "Showcase": 53, + "Shift": 57, + "Posters": 56, + "TriPanel": 55, + "Icons": 500, + "Small Icons": 499, + "Wall": 503, + "BigFan": 591 + }, + "episode":{ + "List": 50, + "RightList": 506, + "FanartList": 602, + "LowList": 501, + "BigList": 507, + "Episode": 502, + "MyFlix": 509, + "TriPanel": 55, + "Icons": 500, + "Landscape": 52, + "Panel": 505 + }, + "addon":{ + "List": 50, + "Shift": 57, + "Icons": 500, + "Wall": 503 + } +} \ No newline at end of file diff --git a/resources/views/skin.aeon.tajo.json b/resources/views/skin.aeon.tajo.json new file mode 100644 index 00000000..ad06eaaf --- /dev/null +++ b/resources/views/skin.aeon.tajo.json @@ -0,0 +1,50 @@ +{ + "all":{ + "List": 50, + "MultiSort": 589, + "MultiWall": 587, + "Shelf 3D": 595, + "List 3D": 596, + "Fanart 3D": 593, + "Triple 3D": 590, + "Wall 3D": 586, + "Banner 3D": 594, + "MultiWall 3D": 587 + }, + "movie":{ + "List": 50, + "MultiSort": 589, + "MultiWall": 587, + "Shelf 3D": 595, + "List 3D": 596, + "Fanart 3D": 593, + "Triple 3D": 590, + "Wall 3D": 586, + "Banner 3D": 594, + "MultiWall 3D": 587 + }, + "tvshow":{ + "List": 50, + "MultiWall": 587, + "Shelf 3D": 595, + "List 3D": 596, + "Fanart 3D": 593, + "Triple 3D": 590, + "Wall 3D": 586, + "Banner 3D": 594, + "MultiWall 3D": 587 + }, + "season":{ + "List": 50, + "Shelf 3D": 595, + "List 3D": 596, + "Wall 3D": 586 + }, + "episode":{ + "List": 50, + "List 3D": 596 + }, + "addon":{ + "List": 50 + } +} \ No newline at end of file diff --git a/resources/views/skin.aeonmq8.json b/resources/views/skin.aeonmq8.json new file mode 100644 index 00000000..e0ce9573 --- /dev/null +++ b/resources/views/skin.aeonmq8.json @@ -0,0 +1,96 @@ +{ + "all":{ + "Right List": 51, + "Banner": 52, + "Banner Info": 53, + "Poster": 54, + "Low List": 55, + "Wall": 56, + "Glass List": 57, + "Coverflow": 58, + "Wide": 59, + "Showart": 60, + "Multiplex": 61, + "Panel": 62, + "Shelf": 63, + "Sets": 65, + "Showcase": 66, + "Wall 3D": 67, + "Posterlite": 80, + "Poster List": 70, + "Total Art": 71 + }, + "movie":{ + "Right List": 51, + "Banner": 52, + "Banner Info": 53, + "Poster": 54, + "Low List": 55, + "Wall": 56, + "Glass List": 57, + "Coverflow": 58, + "Wide": 59, + "Showart": 60, + "Multiplex": 61, + "Panel": 62, + "Shelf": 63, + "Sets": 65, + "Showcase": 66, + "Wall 3D": 67, + "Posterlite": 80, + "Poster List": 70, + "Total Art": 71 + }, + "tvshow":{ + "Right List": 51, + "Banner": 52, + "Banner Info": 53, + "Poster": 54, + "Low List": 55, + "Wall": 56, + "Glass List": 57, + "Coverflow": 58, + "Wide": 59, + "Showart": 60, + "Multiplex": 61, + "Panel": 62, + "Shelf": 63, + "Showcase": 66, + "Wall 3D": 67, + "Posterlite": 80 + }, + "season":{ + "Right List": 51, + "Banner": 52, + "Banner Info": 53, + "Poster": 54, + "Low List": 55, + "Wall": 56, + "Glass List": 57, + "Coverflow": 58, + "Wide": 59, + "Showart": 60, + "Multiplex": 61, + "Panel": 62, + "Shelf": 63, + "Showcase": 66, + "Wall 3D": 67, + "Posterlite": 80 + }, + "episode":{ + "Right List": 51, + "Poster": 54, + "Low List": 55, + "Wall": 56, + "Glass List": 57, + "Wide": 59, + "Showart": 60, + "Multiplex": 61, + "Panel": 62, + "Wall 3D": 67, + "Posterlite": 80 + }, + "addon":{ + "Right List": 51 + } +} \ No newline at end of file diff --git a/resources/views/skin.amber.json b/resources/views/skin.amber.json new file mode 100644 index 00000000..dafb4913 --- /dev/null +++ b/resources/views/skin.amber.json @@ -0,0 +1,62 @@ +{ + "all":{ + "List": 50, + "Low List": 54, + "Big List": 52, + "Tall List": 501, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Fanart": 56 + }, + "movie":{ + "List": 50, + "Low List": 54, + "Big List": 52, + "Tall List": 501, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Fanart": 56 + }, + "tvshow":{ + "List": 50, + "Low List": 54, + "Big List": 52, + "Tall List": 501, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Fanart": 56 + }, + "season":{ + "List": 50, + "Low List": 54, + "Big List": 52, + "Tall List": 501, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Fanart": 56 + }, + "episode":{ + "List": 50, + "Low List": 54, + "Big List": 52, + "Tall List": 501, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Fanart": 56 + }, + "addon":{ + "List": 50, + "Low List": 54, + "Big List": 52, + "Tall List": 501, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Fanart": 56 + } +} \ No newline at end of file diff --git a/resources/views/skin.apptv.json b/resources/views/skin.apptv.json new file mode 100644 index 00000000..a7e8373a --- /dev/null +++ b/resources/views/skin.apptv.json @@ -0,0 +1,45 @@ +{ + "all":{ + "List": 50, + "Icons": 52, + "Banner": 53, + "Wrap": 54, + "Coverflow": 57, + "Wall": 58 + }, + "movie":{ + "List": 50, + "Icons": 52, + "Wrap": 54, + "Coverflow": 57, + "Wall": 58 + }, + "tvshow":{ + "List": 50, + "Icons": 52, + "Banner": 53, + "Wrap": 54, + "Coverflow": 57, + "Wall": 58 + }, + "season":{ + "List": 50, + "Icons": 52, + "Wrap": 54, + "Coverflow": 57, + "Wall": 58 + }, + "episode":{ + "List": 50, + "Icons": 52, + "Wrap": 54, + "Coverflow": 57 + }, + "addon":{ + "List": 50, + "Icons": 52, + "Wrap": 54, + "Coverflow": 57, + "Wall": 58 + } +} \ No newline at end of file diff --git a/resources/views/skin.arctic.zephyr.2.json b/resources/views/skin.arctic.zephyr.2.json new file mode 100644 index 00000000..4c3e2e13 --- /dev/null +++ b/resources/views/skin.arctic.zephyr.2.json @@ -0,0 +1,81 @@ +{ + "all":{ + "List": 50, + "MediaInfo": 501, + "MediaInfo 2": 502, + "Tri-Panel": 504, + "Banner List": 503, + "Poster Wall": 51, + "Landscape Wall": 511, + "Info Wall": 514, + "Info Wall 2": 516, + "Landscape Wall Small": 515, + "Poster Showcase": 52, + "Landscape Showcase": 521, + "Poster": 53, + "Lovefilm": 523, + "Seasons Info": 522, + "Seasons Info 2": 524, + "Square Wall": 510, + "Icon Wall": 512 + }, + "movie":{ + "List": 50, + "MediaInfo": 501, + "MediaInfo 2": 502, + "Tri-Panel": 504, + "Banner List": 503, + "Poster Wall": 51, + "Landscape Wall": 511, + "Info Wall": 514, + "Info Wall 2": 516, + "Landscape Wall Small": 515, + "Poster Showcase": 52, + "Landscape Showcase": 521, + "Poster": 53, + "Lovefilm": 523 + }, + "tvshow":{ + "List": 50, + "MediaInfo": 501, + "MediaInfo 2": 502, + "Tri-Panel": 504, + "Banner List": 503, + "Poster Wall": 51, + "Landscape Wall": 511, + "Info Wall": 514, + "Info Wall 2": 516, + "Landscape Wall Small": 515, + "Poster Showcase": 52, + "Landscape Showcase": 521, + "Poster": 53, + "Lovefilm": 523 + }, + "season":{ + "List": 50, + "Banner List": 503, + "Poster Wall": 51, + "Info Wall": 514, + "Info Wall 2": 516, + "Poster Showcase": 52, + "Seasons Info": 522, + "Seasons Info 2": 524, + "Poster": 53 + }, + "episode":{ + "List": 50, + "MediaInfo": 501, + "MediaInfo 2": 502, + "Tri-Panel": 504, + "Banner List": 503, + "Landscape Wall": 511, + "Info Wall 2": 516, + "Landscape Wall Small": 515, + "Landscape Showcase": 521 + }, + "addon":{ + "List": 50, + "Square Wall": 510, + "Icon Wall": 512 + } +} \ No newline at end of file diff --git a/resources/views/skin.aura.json b/resources/views/skin.aura.json new file mode 100644 index 00000000..b106fe37 --- /dev/null +++ b/resources/views/skin.aura.json @@ -0,0 +1,78 @@ +{ + "all":{ + "List": 50, + "Poster Wall": 51, + "Landscape Wall": 52, + "Square Wall": 53, + "Banner Wall": 54, + "Showcase": 55, + "Landscape Showcase": 56, + "Square Showcase": 57, + "Big Posters": 58, + "Lovefilm": 59, + "Media Info": 500, + "info List": 501, + "Episode List": 502, + "Square Wall Large": 503 + }, + "movie":{ + "List": 50, + "Poster Wall": 51, + "Landscape Wall": 52, + "Showcase": 55, + "Landscape Showcase": 56, + "Square Showcase": 57, + "Big Posters": 58, + "Lovefilm": 59, + "Media Info": 500, + "info List": 501, + "Episode List": 502 + }, + "tvshow":{ + "List": 50, + "Poster Wall": 51, + "Landscape Wall": 52, + "Banner Wall": 54, + "Showcase": 55, + "Landscape Showcase": 56, + "Square Showcase": 57, + "Big Posters": 58, + "Lovefilm": 59, + "Media Info": 500, + "info List": 501, + "Episode List": 502 + }, + "season":{ + "List": 50, + "Poster Wall": 51, + "Landscape Wall": 52, + "Banner Wall": 54, + "Showcase": 55, + "Landscape Showcase": 56, + "Square Showcase": 57, + "Big Posters": 58, + "Lovefilm": 59, + "Media Info": 500, + "info List": 501, + "Episode List": 502 + }, + "episode":{ + "List": 50, + "Poster Wall": 51, + "Landscape Wall": 52, + "Banner Wall": 54, + "Showcase": 55, + "Landscape Showcase": 56, + "Square Showcase": 57, + "Big Posters": 58, + "Lovefilm": 59, + "Media Info": 500, + "info List": 501, + "Episode List": 502 + }, + "addon":{ + "List": 50, + "Square Wall": 53, + "Square Wall Large": 503 + } +} \ No newline at end of file diff --git a/resources/views/skin.bello.7.json b/resources/views/skin.bello.7.json new file mode 100644 index 00000000..992a8ffc --- /dev/null +++ b/resources/views/skin.bello.7.json @@ -0,0 +1,76 @@ +{ + "all":{ + "List": 50, + "Bello": 66, + "Slide": 51, + "Gallery": 52, + "Tiles": 562, + "Thumbnails": 560, + "Posters": 561, + "Posters 2": 64, + "Banner List": 57, + "3D Wall": 53, + "Wall": 54, + "List Wall": 58, + "VideoWall": 580, + "Showtime": 65, + "Netflix": 59 + }, + "movie":{ + "List": 50, + "Bello": 66, + "Slide": 51, + "Gallery": 52, + "Tiles": 562, + "Thumbnails": 560, + "Posters": 561, + "Posters 2": 64, + "Banner List": 57, + "3D Wall": 53, + "Wall": 54, + "List Wall": 58, + "VideoWall": 580, + "Showtime": 65, + "Netflix": 59 + }, + "tvshow":{ + "List": 50, + "Bello": 66, + "Slide": 51, + "Gallery": 52, + "Tiles": 562, + "Thumbnails": 560, + "Posters 2": 64, + "Banner List": 57, + "3D Wall": 53, + "Wall": 54, + "List Wall": 58, + "VideoWall": 580, + "Showtime": 65, + "Netflix": 59 + }, + "season":{ + "List": 50, + "Bello": 66, + "Slide": 51, + "Gallery": 52, + "Tiles": 562, + "Thumbnails": 560, + "Banner List": 57, + "Netflix": 59 + }, + "episode":{ + "List": 50, + "Bello": 66, + "Gallery": 52, + "Tiles": 562, + "Thumbnails": 560, + "Banner List": 57, + "Netflix": 59 + }, + "addon":{ + "List": 50, + "Bello": 66, + "Thumbnails": 560 + } +} \ No newline at end of file diff --git a/resources/views/skin.box.json b/resources/views/skin.box.json new file mode 100644 index 00000000..e602ab5c --- /dev/null +++ b/resources/views/skin.box.json @@ -0,0 +1,46 @@ +{ + "all":{ + "List": 50, + "Thumbs": 52, + "Fanart": 527, + "Poster": 532, + "Banner": 50, + "Banner List": 536, + "Fanart Logo": 539, + "List Info": 5231, + "Thumb Info": 533 + }, + "movie":{ + "List": 50, + "Thumbs": 52, + "Fanart": 527, + "Poster": 532, + "Fanart Logo": 539, + "List Info": 5231, + "Thumb Info": 533 + }, + "tvshow":{ + "List": 50, + "Thumbs": 52, + "Fanart": 527, + "Poster": 532, + "Banner": 50, + "Banner List": 536, + "Fanart Logo": 539, + "List Info": 5231, + "Thumb Info": 533 + }, + "season":{ + "List": 50, + "Poster": 532 + }, + "episode":{ + "List": 50, + "Thumbs": 52, + "List Info": 5231, + "Thumb Info": 533 + }, + "addon":{ + "List": 50 + } +} \ No newline at end of file diff --git a/resources/views/skin.confluence.json b/resources/views/skin.confluence.json new file mode 100644 index 00000000..f0348dd8 --- /dev/null +++ b/resources/views/skin.confluence.json @@ -0,0 +1,55 @@ +{ + "all":{ + "List": 50, + "Big List": 55, + "Thumbnail": 500, + "Poster Wrap": 501, + "Fanart": 508, + "Media Info": 503, + "Media Info 2": 504, + "Media Info 3": 504, + "Wide": 505 + }, + "movie":{ + "List": 50, + "Big List": 55, + "Thumbnail": 500, + "Poster Wrap": 501, + "Fanart": 508, + "Media Info": 503, + "Media Info 2": 504, + "Media Info 3": 504 + }, + "tvshow":{ + "List": 50, + "Big List": 55, + "Thumbnail": 500, + "Poster Wrap": 501, + "Fanart": 508, + "Media Info": 503, + "Media Info 2": 504, + "Media Info 3": 504, + "Wide": 505 + }, + "season":{ + "List": 50, + "Big List": 55, + "Thumbnail": 500, + "Poster Wrap": 501, + "Media Info 2": 504, + "Media Info 3": 504 + }, + "episode":{ + "List": 50, + "Big List": 55, + "Thumbnail": 500, + "Media Info": 503, + "Media Info 2": 504, + "Media Info 3": 504 + }, + "addon":{ + "List": 50, + "Big List": 55, + "Thumbnail": 500 + } +} \ No newline at end of file diff --git a/resources/views/skin.eminence.2.json b/resources/views/skin.eminence.2.json new file mode 100644 index 00000000..f2a5267e --- /dev/null +++ b/resources/views/skin.eminence.2.json @@ -0,0 +1,92 @@ +{ + "all":{ + "Plain List": 552, + "Poster List": 550, + "Big List": 510, + "Media Info": 51, + "Media Info 2": 57, + "Media Info 3": 577, + "Info List": 53, + "Info List 2": 553, + "Fanart List": 54, + "Gallery": 58, + "Big Icons": 52, + "Mediun Icons": 525, + "Showcase": 535, + "Icons": 500, + "Info Icons": 59, + "Wide": 55, + "Fanart": 56 + }, + "movie":{ + "Plain List": 552, + "Poster List": 550, + "Big List": 510, + "Media Info": 51, + "Media Info 2": 57, + "Media Info 3": 577, + "Info List": 53, + "Info List 2": 553, + "Fanart List": 54, + "Gallery": 58, + "Big Icons": 52, + "Mediun Icons": 525, + "Showcase": 535, + "Icons": 500, + "Info Icons": 59, + "Wide": 55, + "Fanart": 56 + }, + "tvshow":{ + "Plain List": 552, + "Poster List": 550, + "Big List": 510, + "Media Info": 51, + "Media Info 2": 57, + "Media Info 3": 577, + "Info List": 53, + "Info List 2": 553, + "Fanart List": 54, + "Gallery": 58, + "Big Icons": 52, + "Mediun Icons": 525, + "Showcase": 535, + "Icons": 500, + "Info Icons": 59, + "Wide": 55, + "Fanart": 56 + }, + "season":{ + "Plain List": 552, + "Poster List": 550, + "Media Info": 51, + "Media Info 2": 57, + "Info List": 53, + "Fanart List": 54, + "Gallery": 58, + "Big Icons": 52, + "Mediun Icons": 525, + "Showcase": 535, + "Icons": 500, + "Info Icons": 59 + }, + "episode":{ + "Plain List": 552, + "Poster List": 550, + "Media Info": 51, + "Media Info 2": 57, + "Info List": 53, + "Info List 2": 553, + "Fanart List": 54, + "Gallery": 58, + "Icons": 500, + "Fanart": 56 + }, + "addon":{ + "Plain List": 552, + "Poster List": 550, + "Big List": 510, + "Icons": 500, + "Info Icons": 59 + } +} \ No newline at end of file diff --git a/resources/views/skin.estuary.json b/resources/views/skin.estuary.json new file mode 100644 index 00000000..f329efb6 --- /dev/null +++ b/resources/views/skin.estuary.json @@ -0,0 +1,54 @@ +{ + "all":{ + "List": 50, + "Poster": 51, + "Shift": 53, + "InfoWall": 54, + "WideList": 55, + "Wall": 500, + "Banner": 501, + "Fanart": 502 + }, + "movie":{ + "List": 50, + "Poster": 51, + "Shift": 53, + "InfoWall": 54, + "WideList": 55, + "Wall": 500, + "Fanart": 502 + }, + "tvshow":{ + "List": 50, + "Poster": 51, + "Shift": 53, + "InfoWall": 54, + "WideList": 55, + "Wall": 500, + "Banner": 501, + "Fanart": 502 + }, + "season":{ + "List": 50, + "Poster": 51, + "Shift": 53, + "InfoWall": 54, + "WideList": 55, + "Wall": 500, + "Fanart": 502 + }, + "episode":{ + "List": 50, + "Poster": 51, + "Shift": 53, + "InfoWall": 54, + "WideList": 55, + "Wall": 500, + "Banner": 501, + "Fanart": 502 + }, + "addon":{ + "WideList": 55, + "Wall": 500 + } +} \ No newline at end of file diff --git a/resources/views/skin.quartz.json b/resources/views/skin.quartz.json new file mode 100644 index 00000000..8b352603 --- /dev/null +++ b/resources/views/skin.quartz.json @@ -0,0 +1,66 @@ +{ + "all":{ + "List": 50, + "Big List": 51, + "Media Info": 52, + "Media Info 2": 54, + "Icons": 53, + "Big Icons": 501, + "Panel": 501, + "Wide": 55, + "Fanart 1": 57, + "Fanart 2": 59, + "Fanart 3": 500 + }, + "movie":{ + "List": 50, + "Big List": 51, + "Media Info": 52, + "Media Info 2": 54, + "Icons": 53, + "Big Icons": 501, + "Panel": 501, + "Fanart 1": 57, + "Fanart 2": 59, + "Fanart 3": 500 + }, + "tvshow":{ + "List": 50, + "Big List": 51, + "Media Info": 52, + "Media Info 2": 54, + "Icons": 53, + "Big Icons": 501, + "Panel": 501, + "Wide": 55, + "Fanart 1": 57, + "Fanart 2": 59, + "Fanart 3": 500 + }, + "season":{ + "List": 50, + "Big List": 51, + "Media Info": 52, + "Media Info 2": 54, + "Icons": 53, + "Big Icons": 501, + "Panel": 501, + "Fanart 1": 57, + "Fanart 2": 59, + "Fanart 3": 500 + }, + "episode":{ + "List": 50, + "Big List": 51, + "Media Info": 52, + "Media Info 2": 54, + "Icons": 53, + "Panel": 501, + "Fanart 3": 500 + }, + "addon":{ + "List": 50, + "Big List": 51, + "Icons": 53 + } +} \ No newline at end of file diff --git a/resources/views/skin.rapier.json b/resources/views/skin.rapier.json new file mode 100644 index 00000000..edcd77b6 --- /dev/null +++ b/resources/views/skin.rapier.json @@ -0,0 +1,51 @@ +{ + "all":{ + + }, + "movie":{ + "Icon": 50, + "List": 52, + "List Info": 58, + "List Info 2": 66, + "List Info 3": 95, + "Thumbs Info": 97, + "Wrap Info": 53, + "3D Wrap": 588, + "Fanart": 583, + "Wall": 69 + }, + "tvshow":{ + "Icon": 50, + "List": 52, + "List Info": 61, + "List Info 2": 65, + "List Info 3": 589, + "Thumbs Info": 100, + "Wrap Info": 577, + "3D Wrap": 588, + "Fanart": 583, + "Wall": 586 + }, + "season":{ + "Icon": 50, + "List": 52, + "List Info": 61, + "List Info 2": 65, + "List Info 3": 589, + "Wall": 586, + "Extended": 585 + }, + "episode":{ + "Icon": 50, + "List": 52, + "List Info": 73, + "List Info 2": 68, + "List Info 3": 94 + }, + "addon":{ + "Icon": 50, + "List": 52, + "List Info": 91, + "Wrap Info": 93 + } +} \ No newline at end of file diff --git a/resources/views/skin.revolve.json b/resources/views/skin.revolve.json new file mode 100644 index 00000000..b6343245 --- /dev/null +++ b/resources/views/skin.revolve.json @@ -0,0 +1,68 @@ +{ + "all":{ + "Circle List": 52, + "Thumbnails List": 55, + "Drop List": 51, + "Landscape List": 53, + "Revolve List": 54, + "Panels List": 56, + "Gallery List": 57, + "Rotate List": 58, + "Banners List": 59 + }, + "movie":{ + "Circle List": 52, + "Thumbnails List": 55, + "Drop List": 51, + "Landscape List": 53, + "Revolve List": 54, + "Panels List": 56, + "Gallery List": 57, + "Rotate List": 58, + "Banners List": 59 + }, + "tvshow":{ + "Circle List": 52, + "Thumbnails List": 55, + "Drop List": 51, + "Landscape List": 53, + "Revolve List": 54, + "Panels List": 56, + "Gallery List": 57, + "Rotate List": 58, + "Banners List": 59 + }, + "season":{ + "Circle List": 52, + "Thumbnails List": 55, + "Drop List": 51, + "Landscape List": 53, + "Revolve List": 54, + "Panels List": 56, + "Gallery List": 57, + "Rotate List": 58, + "Banners List": 59 + }, + "episode":{ + "Circle List": 52, + "Thumbnails List": 55, + "Drop List": 51, + "Landscape List": 53, + "Revolve List": 54, + "Panels List": 56, + "Gallery List": 57, + "Rotate List": 58, + "Banners List": 59 + }, + "addon":{ + "Circle List": 52, + "Thumbnails List": 55, + "Drop List": 51, + "Landscape List": 53, + "Revolve List": 54, + "Panels List": 56, + "Gallery List": 57, + "Rotate List": 58, + "Banners List": 59 + } +} \ No newline at end of file diff --git a/resources/views/skin.unity.json b/resources/views/skin.unity.json new file mode 100644 index 00000000..9f17aa28 --- /dev/null +++ b/resources/views/skin.unity.json @@ -0,0 +1,61 @@ +{ + "all":{ + "List": 50, + "Big List": 51, + "Thumbnail": 500, + "Poster Wrap": 501, + "Fanart": 508, + "Media Info": 505, + "Media Info 2": 504, + "Media Info 3": 503, + "Media Info 4": 515, + "Wide": 505, + "Info": 550, + "Info 2": 551 + }, + "movie":{ + "List": 50, + "Big List": 51, + "Thumbnail": 500, + "Poster Wrap": 501, + "Fanart": 508, + "Media Info": 505, + "Media Info 2": 504, + "Media Info 3": 503 + }, + "tvshow":{ + "List": 50, + "Big List": 51, + "Thumbnail": 500, + "Poster Wrap": 501, + "Fanart": 508, + "Media Info": 505, + "Media Info 2": 504, + "Media Info 3": 503, + "Wide": 505 + }, + "season":{ + "List": 50, + "Big List": 51, + "Thumbnail": 500, + "Poster Wrap": 501, + "Media Info": 505, + "Media Info 2": 504, + "Media Info 3": 503 + }, + "episode":{ + "List": 50, + "Big List": 51, + "Thumbnail": 500, + "Media Info": 505, + "Media Info 2": 504, + "Media Info 3": 503 + }, + "addon":{ + "List": 50, + "Big List": 51, + "Thumbnail": 500, + "Info": 550, + "Info 2": 551 + } +} \ No newline at end of file diff --git a/servers/akvideo.py b/servers/akvideo.py index 3782780e..040ae55f 100644 --- a/servers/akvideo.py +++ b/servers/akvideo.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # by DrZ3r0 -import urllib, re +import urllib from core import httptools from core import scrapertools -from platformcode import logger, config, platformtools +from platformcode import logger, config def test_video_exists(page_url): diff --git a/servers/animeid.py b/servers/animeid.py index 776f13f5..3cec4070 100644 --- a/servers/animeid.py +++ b/servers/animeid.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -9,7 +9,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "no longer exists" in data or "to copyright issues" in data: - return False, "[animeid] El video ha sido borrado" + return False, config.get_localized_string(70449) % "animeid" if "please+try+again+later." in data: return False, "[animeid] Error de animeid, no se puede generar el enlace al video" return True, "" diff --git a/servers/animeworld_server.py b/servers/animeworld_server.py index 0fb7074c..fa73e58d 100644 --- a/servers/animeworld_server.py +++ b/servers/animeworld_server.py @@ -2,7 +2,6 @@ import urllib from core import httptools, jsontools -from core import scrapertools from platformcode import logger diff --git a/servers/archiveorg.py b/servers/archiveorg.py index c26d240d..61677b02 100644 --- a/servers/archiveorg.py +++ b/servers/archiveorg.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector ArchiveOrg By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url) if data.code == 404: - return False, "[ArchiveOrg] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "ArchiveOrg" return True, "" diff --git a/servers/backin.py b/servers/backin.py index 47273baa..c070d5d6 100644 --- a/servers/backin.py +++ b/servers/backin.py @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) if 'http://' in page_url: # fastids - page_url = httptools.downloadpage(page_url, follow_redirects=False).headers['location'] + page_url = httptools.downloadpage(page_url, follow_redirects=False, only_headers=True).headers['location'] page_url = scrapertools.find_single_match(page_url, 'backin.net/([a-zA-Z0-9]+)') global data data = httptools.downloadpage("http://backin.net/stream-%s-500x400.html" % page_url).data diff --git a/servers/badshare.py b/servers/badshare.py index f613fbda..6ccd1635 100644 --- a/servers/badshare.py +++ b/servers/badshare.py @@ -2,10 +2,11 @@ # -------------------------------------------------------- # Conector Badshare By Alfa development Group # -------------------------------------------------------- - import re + from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -14,7 +15,7 @@ def test_video_exists(page_url): global page page = httptools.downloadpage(page_url) if not page.sucess: - return False, "[Badshare] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Badshare" return True, "" diff --git a/servers/bdupload.py b/servers/bdupload.py index 4186ad96..6321dd3a 100644 --- a/servers/bdupload.py +++ b/servers/bdupload.py @@ -3,6 +3,7 @@ import time from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36'} @@ -12,7 +13,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "Archive no Encontrado" in data: - return False, "[bdupload] El fichero ha sido borrado" + return False, config.get_localized_string(70449) % "bdupload" return True, "" diff --git a/servers/bitertv.py b/servers/bitertv.py index b221554f..9e898962 100644 --- a/servers/bitertv.py +++ b/servers/bitertv.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'} @@ -10,7 +10,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "Archive no Encontrado" in data or "File has been removed" in data: - return False, "[bitertv] El fichero ha sido borrado" + return False, config.get_localized_string(70449) % "bitertv" return True, "" diff --git a/servers/bitp.py b/servers/bitp.py index 7549b129..ed5a2495 100644 --- a/servers/bitp.py +++ b/servers/bitp.py @@ -4,9 +4,9 @@ # Conector para bitporno # https://github.com/alfa-addon # ------------------------------------------------------------ - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -14,7 +14,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "Object not found" in data or "no longer exists" in data or '"sources": [false]' in data: - return False, "[bitp] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "bitp" return True, "" diff --git a/servers/bravoporn.py b/servers/bravoporn.py index c281173c..f4ac400f 100644 --- a/servers/bravoporn.py +++ b/servers/bravoporn.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/cinemaupload.py b/servers/cinemaupload.py index 9f33c062..c3f05da8 100644 --- a/servers/cinemaupload.py +++ b/servers/cinemaupload.py @@ -3,8 +3,10 @@ # Conector Cinemaupload By Alfa development Group # -------------------------------------------------------- import re + from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +14,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url) if data.code == 404: - return False, "[CinemaUpload] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "CinemaUpload" return True, "" diff --git a/servers/clicknupload.py b/servers/clicknupload.py index 05a1421e..f54c5d5c 100755 --- a/servers/clicknupload.py +++ b/servers/clicknupload.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -23,7 +25,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = get_data(page_url.replace(".org", ".me")) - if "File Not Found" in data: return False, "[Clicknupload] El archivo no existe o ha sido borrado" + if "File Not Found" in data: return False, config.get_localized_string(70449) % "Clicknupload" return True, "" diff --git a/servers/crunchyroll.py b/servers/crunchyroll.py index 75dae4a8..2d252b3a 100755 --- a/servers/crunchyroll.py +++ b/servers/crunchyroll.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- -from builtins import range import sys + +from builtins import range + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int diff --git a/servers/datoporn.py b/servers/datoporn.py index 259582bc..f433731e 100755 --- a/servers/datoporn.py +++ b/servers/datoporn.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url).data if 'Not Found' in data or 'File is no longer available' in data: - return False, "[Datoporn] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Datoporn" return True, "" diff --git a/servers/debriders/realdebrid.py b/servers/debriders/realdebrid.py index 5c7c837e..98489850 100755 --- a/servers/debriders/realdebrid.py +++ b/servers/debriders/realdebrid.py @@ -14,7 +14,6 @@ else: import time from core import httptools -from core import scrapertools from platformcode import config, logger from platformcode import platformtools diff --git a/servers/deltabit.py b/servers/deltabit.py index 534c4d37..b1288073 100644 --- a/servers/deltabit.py +++ b/servers/deltabit.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- -import urllib import time +import urllib + from core import httptools from core import scrapertools -from platformcode import logger, config from lib import jsunpack +from platformcode import logger, config + def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) diff --git a/servers/dostream.py b/servers/dostream.py index 7184d286..1fdc4883 100644 --- a/servers/dostream.py +++ b/servers/dostream.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector DoStream By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url) if data.code == 404: - return False, "[Dostream] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Dostream" return True, "" diff --git a/servers/downace.py b/servers/downace.py index 7c649414..a238f2de 100644 --- a/servers/downace.py +++ b/servers/downace.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -13,7 +13,7 @@ def test_video_exists(page_url): if "please+try+again+later." in data: return False, "[Downace] Error de downace, no se puede generar el enlace al video" if "File has been removed due to inactivity" in data: - return False, "[Downace] El archivo ha sido removido por inactividad" + return False, config.get_localized_string(70449) % "Downace" return True, "" diff --git a/servers/drtuber.py b/servers/drtuber.py index de444847..dfd366ae 100644 --- a/servers/drtuber.py +++ b/servers/drtuber.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/eporner.py b/servers/eporner.py index a30cf276..d25b006a 100644 --- a/servers/eporner.py +++ b/servers/eporner.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- import re + from core import httptools -from core import scrapertools +from platformcode import config from platformcode import logger @@ -10,7 +11,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "<h2>WE ARE SORRY</h2>" in data or '<title>404 Not Found' in data: - return False, "[eporner] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "eporner" return True, "" diff --git a/servers/estream.py b/servers/estream.py index 6ff87af2..24c63a34 100644 --- a/servers/estream.py +++ b/servers/estream.py @@ -2,9 +2,10 @@ # -------------------------------------------------------- # Conector Estream By Alfa development Group # -------------------------------------------------------- - import re + from core import httptools +from platformcode import config from platformcode import logger @@ -14,7 +15,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url) if data.code == 404: - return False, "[Estream] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Estream" return True, "" diff --git a/servers/fastplay.py b/servers/fastplay.py index 725d32a0..74468000 100644 --- a/servers/fastplay.py +++ b/servers/fastplay.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -11,7 +11,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url) if "Object not found" in data.data or "longer exists on our servers" in data.data: - return False, "[Fastplay] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Fastplay" if data.code == 500: return False, "[Fastplay] Error interno del servidor" return True, "" diff --git a/servers/fembed.py b/servers/fembed.py index 885e41c0..e9ca008d 100644 --- a/servers/fembed.py +++ b/servers/fembed.py @@ -12,7 +12,7 @@ def test_video_exists(page_url): page_url = re.sub('://[^/]+/', '://feurl.com/', page_url) data = httptools.downloadpage(page_url).data if "Sorry 404 not found" in data or "This video is unavailable" in data or "Sorry this video is unavailable:" in data: - return False, "[fembed] El fichero ha sido borrado" + return False, config.get_localized_string(70449) % "fembed" page_url = page_url.replace("/f/","/v/") page_url = page_url.replace("/v/","/api/source/") data = httptools.downloadpage(page_url, post={}).json diff --git a/servers/fex.py b/servers/fex.py index af00bea7..d64e6434 100644 --- a/servers/fex.py +++ b/servers/fex.py @@ -2,17 +2,18 @@ # -*- Server Fex -*- # -*- Created for Alfa-addon -*- # -*- By the Alfa Develop Group -*- - from core import httptools +from platformcode import config from platformcode import logger + def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url, follow_redirects=False) if data.code == 404: - return False, "[Fex] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Fex" return True, "" diff --git a/servers/filebebo.py b/servers/filebebo.py index 4ee3f98a..d7b21c6c 100644 --- a/servers/filebebo.py +++ b/servers/filebebo.py @@ -2,10 +2,11 @@ # -*- Server Filebebo -*- # -*- Created for Alfa-addon -*- # -*- By the Alfa Develop Group -*- - import re + from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -20,7 +21,7 @@ def test_video_exists(page_url): data = get_source(page_url) if "File was deleted" in data or "File Not Found" in data: - return False, "[Filebebo] El video ha sido borrado" + return False, config.get_localized_string(70449) % "Filebebo" return True, "" diff --git a/servers/filescdn.py b/servers/filescdn.py index 99f8e266..3a260b47 100644 --- a/servers/filescdn.py +++ b/servers/filescdn.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -10,7 +10,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url).data if "File was deleted" in data: - return False, "[FilesCDN] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "FilesCDN" return True, "" diff --git a/servers/flix555.py b/servers/flix555.py index da1a2397..87484ada 100644 --- a/servers/flix555.py +++ b/servers/flix555.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- - import re + from core import httptools, scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger data = "" @@ -11,7 +12,7 @@ def test_video_exists(page_url): global data data = resp.data if resp.code == 404 or 'File Not Found' in resp.data or "File is no longer available" in resp.data: - return False, "[flix555] El video no está disponible" + return False, config.get_localized_string(70449) % "flix555" return True, "" def get_video_url(page_url, premium=False, user="", password="", video_password=""): diff --git a/servers/gamovideo.py b/servers/gamovideo.py index 79d1b967..7a4e6f20 100755 --- a/servers/gamovideo.py +++ b/servers/gamovideo.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -32,13 +34,13 @@ def test_video_exists(page_url): global DATA DATA = data if "images/proced.png" in data: - return False, "[Gamovideo] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Gamovideo" if "File was deleted" in data or ("Not Found" in data and not "|mp4|" in data) or "File was locked by administrator" in data: - return False, "[Gamovideo] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Gamovideo" if "Video is processing now" in data: return False, "[Gamovideo] El video está procesándose en estos momentos. Inténtelo mas tarde." if "File is awaiting for moderation" in data: - return False, "[Gamovideo] El video está esperando por moderación." + return False, config.get_localized_string(70449) % "Gamovideo" return True, "" diff --git a/servers/googlevideo.py b/servers/googlevideo.py index 9348cc85..3a411e80 100755 --- a/servers/googlevideo.py +++ b/servers/googlevideo.py @@ -3,7 +3,6 @@ import re from core import httptools -from core import scrapertools from platformcode import logger diff --git a/servers/gotporn.py b/servers/gotporn.py index 8310b410..0b38b366 100644 --- a/servers/gotporn.py +++ b/servers/gotporn.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -10,7 +10,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "

WE ARE SORRY

" in data or '404 Not Found' in data: - return False, "[Mixdrop] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Mixdrop" return True, "" diff --git a/servers/gvideo.py b/servers/gvideo.py index 53b6366b..aa9712c4 100644 --- a/servers/gvideo.py +++ b/servers/gvideo.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -25,7 +27,7 @@ def test_video_exists(page_url): page = response if "no+existe" in response.data or 'no existe.

' in response.data: - return False, "[gvideo] El video no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "gvideo" if "Se+ha+excedido+el" in response.data: return False, "[gvideo] Se ha excedido el número de reproducciones permitidas" if "No+tienes+permiso" in response.data: diff --git a/servers/hdload.py b/servers/hdload.py index dd09d15c..30240022 100644 --- a/servers/hdload.py +++ b/servers/hdload.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- -from core import httptools, scrapertools -from platformcode import config, logger import base64 +from core import httptools +from platformcode import config, logger + def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) diff --git a/servers/iceporn.py b/servers/iceporn.py index f2eb063a..716a5362 100644 --- a/servers/iceporn.py +++ b/servers/iceporn.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/idtbox.py b/servers/idtbox.py index a24ddd83..00cd7a81 100644 --- a/servers/idtbox.py +++ b/servers/idtbox.py @@ -2,10 +2,11 @@ # -------------------------------------------------------- # Conector Idtbox By Alfa development Group # -------------------------------------------------------- - import re -from core import httptools, scrapertools -from platformcode import logger, platformtools + +from core import httptools +from platformcode import config +from platformcode import logger data = "" def test_video_exists(page_url): @@ -14,7 +15,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url) if not data.sucess or "Not Found" in data.data or "File was deleted" in data.data or "is no longer available" in data.data: - return False, "[Idtbox] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Idtbox" data = data.data return True, "" diff --git a/servers/javwhores.py b/servers/javwhores.py index 3b67fcb9..92d892fa 100644 --- a/servers/javwhores.py +++ b/servers/javwhores.py @@ -3,9 +3,12 @@ # Conector javwhores By Alfa development Group # -------------------------------------------------------- import re + from core import httptools +from platformcode import config from platformcode import logger + def test_video_exists(page_url): response = httptools.downloadpage(page_url) @@ -14,7 +17,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[javwhores] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "javwhores" # global video_url, license_code # video_url = scrapertools.find_single_match(response.data, "video_url: '([^']+)'") diff --git a/servers/jawcloud.py b/servers/jawcloud.py index a0de88a8..8fde2947 100644 --- a/servers/jawcloud.py +++ b/servers/jawcloud.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -9,7 +9,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "The file you were looking for could not be found" in data: - return False, "[jawcloud] El archivo ha ido borrado" + return False, config.get_localized_string(70449) % "jawcloud" return True, "" diff --git a/servers/jetload.py b/servers/jetload.py index 0d8b73d9..989f3b66 100644 --- a/servers/jetload.py +++ b/servers/jetload.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector jetload By Alfa development Group # -------------------------------------------------------- -import re -from core import httptools, jsontools +from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger video_urls = [] @@ -16,7 +16,7 @@ def test_video_exists(page_url): global data data = response.data if not response.sucess or "Not Found" in data or "File was deleted" in data or "is no longer available" in data: - return False, "[jetload] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "jetload" return True, "" diff --git a/servers/jplayer.py b/servers/jplayer.py index f167a027..19048363 100644 --- a/servers/jplayer.py +++ b/servers/jplayer.py @@ -2,8 +2,10 @@ # -------------------------------------------------------- # Conector jplayer By Alfa development Group # -------------------------------------------------------- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -16,7 +18,6 @@ else: from core import httptools from core import jsontools -from core import scrapertools from platformcode import logger @@ -24,7 +25,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "no longer exists" in data or "to copyright issues" in data: - return False, "[jplayer] El video ha sido borrado" + return False, config.get_localized_string(70449) % "jplayer" return True, "" diff --git a/servers/keezmovies.py b/servers/keezmovies.py index 19463a4a..6cbec003 100644 --- a/servers/keezmovies.py +++ b/servers/keezmovies.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -9,7 +10,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "

WE ARE SORRY

" in data or '404 Not Found' in data: - return False, "[keezmovies] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "keezmovies" return True, "" diff --git a/servers/mangoplay.py b/servers/mangoplay.py index 5ddd0515..1373175e 100644 --- a/servers/mangoplay.py +++ b/servers/mangoplay.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector mangoplay By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "no longer exists" in data or "to copyright issues" in data: - return False, "[mangoplay] El video ha sido borrado" + return False, config.get_localized_string(70449) % "mangoplay" return True, "" diff --git a/servers/mangovideo.py b/servers/mangovideo.py index d169aa08..b46c8f73 100644 --- a/servers/mangovideo.py +++ b/servers/mangovideo.py @@ -4,6 +4,7 @@ # -------------------------------------------------------- from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger server = {'1': 'http://www.mangovideo.pw/contents/videos/', '7' : 'http://server9.mangovideo.pw/contents/videos/', @@ -22,7 +23,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[mangovideo] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "mangovideo" return True, "" diff --git a/servers/manyvideos.py b/servers/manyvideos.py index 7ddaf4d0..971e2a22 100644 --- a/servers/manyvideos.py +++ b/servers/manyvideos.py @@ -2,11 +2,14 @@ # -------------------------------------------------------- # Conector manyvideos By Alfa development Group # -------------------------------------------------------- +import base64 + from core import httptools from core import scrapertools -from platformcode import logger -import base64 from lib import jsunpack +from platformcode import config +from platformcode import logger + def test_video_exists(page_url): @@ -16,7 +19,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[manyvideos] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "manyvideos" return True, "" diff --git a/servers/mediafire.py b/servers/mediafire.py index d2493c90..5b452878 100755 --- a/servers/mediafire.py +++ b/servers/mediafire.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -9,7 +9,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "Invalid or Deleted File" in data or "Well, looks like we" in data: - return False, "[Mediafire] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Mediafire" if "File Removed for Violation" in data: return False, "[Mediafire] Archivo eliminado por infracción" return True, "" diff --git a/servers/megadrive.py b/servers/megadrive.py index d9b82c33..c6974984 100644 --- a/servers/megadrive.py +++ b/servers/megadrive.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -13,7 +13,7 @@ def test_video_exists(page_url): if "please+try+again+later." in data: return False, "[Megadrive] Error de Megadrive, no se puede generar el enlace al video" if "File has been removed due to inactivity" in data: - return False, "[Megadrive] El archivo ha sido removido por inactividad" + return False, config.get_localized_string(70449) % "Megadrive" return True, "" diff --git a/servers/mp4upload.py b/servers/mp4upload.py index e215a2c6..769d8699 100644 --- a/servers/mp4upload.py +++ b/servers/mp4upload.py @@ -1,16 +1,17 @@ # -*- coding: utf-8 -*- - import re from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger + def test_video_exists(page_url): data = httptools.downloadpage(page_url).data if data == "File was deleted" or data == '': - return False, "[mp4upload] El video ha sido borrado" + return False, config.get_localized_string(70449) % "mp4upload" def get_video_url(page_url, premium=False, user="", password="", video_password=""): diff --git a/servers/mydaddy.py b/servers/mydaddy.py index 0b874464..846f406e 100644 --- a/servers/mydaddy.py +++ b/servers/mydaddy.py @@ -4,8 +4,10 @@ # -------------------------------------------------------- from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger + def test_video_exists(page_url): response = httptools.downloadpage(page_url) @@ -14,7 +16,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[mydaddy] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "mydaddy" return True, "" diff --git a/servers/myupload.py b/servers/myupload.py index 51a3129d..2ed947b6 100644 --- a/servers/myupload.py +++ b/servers/myupload.py @@ -2,10 +2,13 @@ # -------------------------------------------------------- # Conector myupload By Alfa development Group # -------------------------------------------------------- +import base64 + from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger -import base64 + def test_video_exists(page_url): @@ -15,7 +18,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[myupload] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "myupload" return True, "" diff --git a/servers/netutv.py b/servers/netutv.py index 25f365db..8e391f6a 100755 --- a/servers/netutv.py +++ b/servers/netutv.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -30,7 +32,7 @@ def test_video_exists(page_url): page_url = page_url.replace("/watch_video.php?v=", "/player/embed_player.php?vid=") data = httptools.downloadpage(page_url).data if "var userid = '';" in data.lower(): - return False, "[netutv] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "netutv" return True, "" diff --git a/servers/nowvideo.py b/servers/nowvideo.py index 46e6eea6..170b3f94 100644 --- a/servers/nowvideo.py +++ b/servers/nowvideo.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import urllib + from core import httptools from core import scrapertools from platformcode import logger, config diff --git a/servers/onefichier.json b/servers/onefichier.json index 44efe860..9e76d1bd 100644 --- a/servers/onefichier.json +++ b/servers/onefichier.json @@ -15,7 +15,7 @@ }, "free": false, "id": "onefichier", - "name": "onefichier", + "name": "1fichier", "premium": [ "onefichier", "realdebrid", diff --git a/servers/onlystream.py b/servers/onlystream.py index ba1e7b4b..d8745b58 100644 --- a/servers/onlystream.py +++ b/servers/onlystream.py @@ -2,10 +2,8 @@ from core import httptools from core import scrapertools -from lib import jsunpack from platformcode import config, logger -import ast -from core import support + def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) diff --git a/servers/oprem.py b/servers/oprem.py index c1b4f819..feb2cd92 100644 --- a/servers/oprem.py +++ b/servers/oprem.py @@ -4,9 +4,11 @@ # -------------------------------------------------------- import os + from core import httptools from platformcode import logger, config + def get_video_url(page_url, premium=False, user="", password="", video_password=""): logger.info("(page_url='%s')" % page_url) diff --git a/servers/pornhub.py b/servers/pornhub.py index 45feff1d..91e50222 100644 --- a/servers/pornhub.py +++ b/servers/pornhub.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector pornhub By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -16,7 +16,7 @@ def test_video_exists(page_url): or "removed" in response.data \ or not "defaultQuality" in response.data \ or "is no longer available" in response.data: - return False, "[pornhub] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "pornhub" return True, "" def get_video_url(page_url, user="", password="", video_password=""): diff --git a/servers/pornrewind.py b/servers/pornrewind.py index e8d7abe3..d7132fc0 100644 --- a/servers/pornrewind.py +++ b/servers/pornrewind.py @@ -2,12 +2,11 @@ # -------------------------------------------------------- # Conector pornrewind By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger -from lib.kt_player import decode def test_video_exists(page_url): @@ -17,7 +16,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[pornrewind] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "pornrewind" global video_url, license_code video_url = scrapertools.find_single_match(response.data, "video_url: '([^']+)'") diff --git a/servers/powvideo.py b/servers/powvideo.py index 9140a58e..b372c796 100644 --- a/servers/powvideo.py +++ b/servers/powvideo.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int -import re - from core import httptools from core import scrapertools from lib import jsunpack @@ -25,7 +25,7 @@ def test_video_exists(page_url): if data == "File was deleted" or data == '': return False, "[powvideo] El video ha sido borrado" if 'function(p,a,c,k,e,' not in data: - return False, "[powvideo] El video no está disponible" + return False, config.get_localized_string(70449) % "powvideo" return True, "" diff --git a/servers/prostream.py b/servers/prostream.py index c5be57f9..4ad2b859 100644 --- a/servers/prostream.py +++ b/servers/prostream.py @@ -2,10 +2,10 @@ # -------------------------------------------------------- # Conector Prostream By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -14,7 +14,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "File is no longer available" in data: - return False, "[Prostream] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Prostream" return True, "" diff --git a/servers/rcdnme.py b/servers/rcdnme.py index 9d78717e..d7fc0b2c 100644 --- a/servers/rcdnme.py +++ b/servers/rcdnme.py @@ -2,10 +2,10 @@ # -------------------------------------------------------- # Conector Rcdnme By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -14,7 +14,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url) if "Object not found" in data.data or "longer exists on our servers" in data.data: - return False, "[Rcdnme] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Rcdnme" if data.code == 500: return False, "[Rcdnme] Error interno del servidor" return True, "" diff --git a/servers/redtube.py b/servers/redtube.py index 4f93e21f..3ac456fc 100644 --- a/servers/redtube.py +++ b/servers/redtube.py @@ -4,8 +4,10 @@ # -------------------------------------------------------- from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger + def test_video_exists(page_url): response = httptools.downloadpage(page_url) @@ -14,7 +16,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[redtube] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "redtube" return True, "" diff --git a/servers/rutube.py b/servers/rutube.py index b9b7716c..e6414be7 100644 --- a/servers/rutube.py +++ b/servers/rutube.py @@ -2,8 +2,10 @@ # -*- Server Rutube -*- # -*- Created for Alfa-addon -*- # -*- By the Alfa Develop Group -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -17,7 +19,6 @@ else: import re from core import httptools -from core import scrapertools from platformcode import logger from core import jsontools @@ -33,7 +34,7 @@ def test_video_exists(page_url): data = get_source(page_url) if "File was deleted" in data or "File Not Found" in data: - return False, "[Rutube] El video ha sido borrado" + return False, config.get_localized_string(70449) % "Rutube" return True, "" diff --git a/servers/samaup.py b/servers/samaup.py index 248dca52..cc6285c0 100644 --- a/servers/samaup.py +++ b/servers/samaup.py @@ -2,10 +2,10 @@ # -------------------------------------------------------- # Conector Samaup By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -14,7 +14,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "Not Found" in data or "File was deleted" in data: - return False, "[Samaup] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Samaup" return True, "" diff --git a/servers/sendvid.py b/servers/sendvid.py index 72100c9b..ed11f426 100755 --- a/servers/sendvid.py +++ b/servers/sendvid.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/streamcherry.py b/servers/streamcherry.py index ef5a99f9..3cff360e 100644 --- a/servers/streamcherry.py +++ b/servers/streamcherry.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector para streamcherry # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -13,7 +13,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url).data if "We are unable to find the video" in data: - return False, "[streamcherry] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "streamcherry" return True, "" diff --git a/servers/streamplay.py b/servers/streamplay.py index 11942925..55cdbb21 100644 --- a/servers/streamplay.py +++ b/servers/streamplay.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -18,9 +20,9 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url, headers={'Referer': referer}).data if data == "File was deleted": - return False, "[Streamplay] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Streamplay" elif "Video is processing now" in data: - return False, "[Streamplay] El archivo se está procesando" + return False, config.get_localized_string(70449) % "Streamplay" return True, "" diff --git a/servers/streamty.py b/servers/streamty.py index 19cb1e22..d7a792e8 100644 --- a/servers/streamty.py +++ b/servers/streamty.py @@ -2,10 +2,10 @@ # -------------------------------------------------------- # Conector Streamty By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -14,7 +14,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "Not Found" in data or "File was deleted" in data: - return False, "[Streamty] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Streamty" return True, "" diff --git a/servers/streamz.py b/servers/streamz.py index 4bb82af0..3d85f57a 100644 --- a/servers/streamz.py +++ b/servers/streamz.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools -from platformcode import logger from lib import jsunpack +from platformcode import logger def get_video_url(page_url, video_password): diff --git a/servers/supervideo.py b/servers/supervideo.py index 20410941..ea506217 100644 --- a/servers/supervideo.py +++ b/servers/supervideo.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- +import ast + from core import httptools from core import scrapertools from lib import jsunpack from platformcode import config, logger -import ast - + def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) global data diff --git a/servers/thevid.py b/servers/thevid.py index fa1a15ed..e061856b 100644 --- a/servers/thevid.py +++ b/servers/thevid.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- + from core import httptools from core import scrapertools from lib import jsunpack @@ -12,7 +13,7 @@ def test_video_exists(page_url): if "Video not found..." in data or "Video removed due to copyright" in data: return False, config.get_localized_string(70292) % "Thevid" if "Video removed for inactivity..." in data: - return False, "[Thevid] El video ha sido removido por inactividad" + return False, config.get_localized_string(70449) % "Thevid" return True, "" diff --git a/servers/thevideobee.py b/servers/thevideobee.py index a0b51967..f319dcfe 100644 --- a/servers/thevideobee.py +++ b/servers/thevideobee.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector thevideobee By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "no longer exists" in data or "to copyright issues" in data: - return False, "[thevideobee] El video ha sido borrado" + return False, config.get_localized_string(70449) % "thevideobee" return True, "" diff --git a/servers/thevideome.py b/servers/thevideome.py index 2f957510..89308046 100755 --- a/servers/thevideome.py +++ b/servers/thevideome.py @@ -13,7 +13,7 @@ else: from core import httptools from core import scrapertools -from platformcode import logger, config +from platformcode import logger def test_video_exists(page_url): diff --git a/servers/thevimeo.py b/servers/thevimeo.py index e6ffa265..85f0eb7e 100644 --- a/servers/thevimeo.py +++ b/servers/thevimeo.py @@ -1,10 +1,9 @@ # -*- coding: utf-8 -*- # -*- Server Thevimeo -*- - import re + from core import httptools -from core import scrapertools -from platformcode import logger +from platformcode import config def get_source(url): @@ -18,7 +17,7 @@ def test_video_exists(page_url): data = get_source(page_url) if "File was deleted" in data or "File Not Found" in data: - return False, "[Thevimeo] El video ha sido borrado" + return False, config.get_localized_string(70449) % "Thevimeo" return True, "" diff --git a/servers/tiwikiwi.py b/servers/tiwikiwi.py index 771ef91e..d82f43d9 100644 --- a/servers/tiwikiwi.py +++ b/servers/tiwikiwi.py @@ -1,11 +1,11 @@ # Conector vidcloud By Alfa development Group # -------------------------------------------------------- - import re from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -13,7 +13,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url) if data.code == 404: - return False, "[Cloud] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Cloud" return True, "" diff --git a/servers/torrent.py b/servers/torrent.py index efbc49ee..8aff4636 100755 --- a/servers/torrent.py +++ b/servers/torrent.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- -#from builtins import str -from builtins import range import sys + +# from builtins import str +from builtins import range + PY3 = False VFS = True if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int; VFS = False @@ -15,7 +17,6 @@ else: import urllib import time -import threading import os import traceback import re @@ -31,7 +32,6 @@ from core import filetools from core import httptools from core import scrapertools from core import jsontools -from core.item import Item from platformcode import logger from platformcode import config from platformcode import platformtools @@ -459,7 +459,7 @@ def bt_client(mediaurl, xlistitem, rar_files, subtitle=None, password=None, item break else: - if platformtools.dialog_yesno(msg_header, config.get_localized_string(30031), config.get_localized_string(30032)): + if not platformtools.dialog_yesno(msg_header, config.get_localized_string(30031), config.get_localized_string(30032)): dp_cerrado = False progreso = platformtools.dialog_progress(msg_header, '') break @@ -675,8 +675,7 @@ def mark_auto_as_watched(item): #logger.debug("Llamado el marcado") -def wait_for_download(item, mediaurl, rar_files, torr_client, password='', size='', \ - rar_control={}): +def wait_for_download(item, mediaurl, rar_files, torr_client, password='', size='', rar_control={}): logger.info() from subprocess import Popen, PIPE, STDOUT diff --git a/servers/tube8.py b/servers/tube8.py index 2dda98e1..1649d0ba 100644 --- a/servers/tube8.py +++ b/servers/tube8.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -9,7 +10,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "

WE ARE SORRY

" in data or '404 Not Found' in data: - return False, "[tube8] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "tube8" return True, "" diff --git a/servers/tubeon.py b/servers/tubeon.py index 99ab0fdd..9947345a 100644 --- a/servers/tubeon.py +++ b/servers/tubeon.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/tubst.py b/servers/tubst.py index fd69d74b..fc17790d 100644 --- a/servers/tubst.py +++ b/servers/tubst.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector tubst By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) response = httptools.downloadpage(page_url) if not response.sucess or "Not Found" in response.data or "File was deleted" in response.data or "is no longer available" in response.data: - return False, "[tubst] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "tubst" return True, "" diff --git a/servers/turbovid.py b/servers/turbovid.py index 9070693c..8e786797 100644 --- a/servers/turbovid.py +++ b/servers/turbovid.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- -import urllib import time +import urllib + from core import httptools from core import scrapertools from platformcode import logger, config diff --git a/servers/tusfiles.py b/servers/tusfiles.py index ef37b5e8..18cec1ee 100644 --- a/servers/tusfiles.py +++ b/servers/tusfiles.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector tusfiles By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "no longer exists" in data or "to copyright issues" in data: - return False, "[tusfiles] El video ha sido borrado" + return False, config.get_localized_string(70449) % "tusfiles" return True, "" diff --git a/servers/txxx.py b/servers/txxx.py index 24fdc737..d678566c 100644 --- a/servers/txxx.py +++ b/servers/txxx.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/uploadmp4.py b/servers/uploadmp4.py index 9130fd7d..577a778b 100644 --- a/servers/uploadmp4.py +++ b/servers/uploadmp4.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector uploadmp4 By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "no longer exists" in data: - return False, "[uploadmp4] El video ha sido borrado" + return False, config.get_localized_string(70449) % "uploadmp4" return True, "" diff --git a/servers/uppom.py b/servers/uppom.py index 1fe8b571..12b19d30 100644 --- a/servers/uppom.py +++ b/servers/uppom.py @@ -2,10 +2,9 @@ # -*- Server Uppom -*- # -*- Created for Alfa-addon -*- # -*- By the Alfa Develop Group -*- - -import re from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -14,7 +13,7 @@ def test_video_exists(page_url): data = get_source(page_url) if "File was deleted" in data or "File Not Found" in data: - return False, "[Uppom] El video ha sido borrado" + return False, config.get_localized_string(70449) % "Uppom" return True, "" diff --git a/servers/upstream.py b/servers/upstream.py index 53c72f32..f254ebdc 100644 --- a/servers/upstream.py +++ b/servers/upstream.py @@ -5,7 +5,6 @@ from core import httptools from core import scrapertools -from lib import jsunpack from platformcode import logger, config diff --git a/servers/uptobox.json b/servers/uptobox.json index 6a082afa..1e35957d 100644 --- a/servers/uptobox.json +++ b/servers/uptobox.json @@ -15,7 +15,7 @@ }, "free": true, "id": "uptobox", - "name": "uptobox", + "name": "UPtoStream", "premium": [ "realdebrid", "alldebrid" diff --git a/servers/uptobox.py b/servers/uptobox.py index 1bcb7da0..52cc08aa 100755 --- a/servers/uptobox.py +++ b/servers/uptobox.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -25,7 +27,7 @@ def test_video_exists(page_url): return True, "" elif "Unfortunately, the file you want is not available." in data or "Unfortunately, the video you want to see is not available" in data or "This stream doesn" in data\ or "Page not found" in data: - return False, "[Uptobox] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Uptobox" wait = scrapertools.find_single_match(data, "You have to wait ([0-9]+) (minute|second)") if len(wait) > 0: tiempo = wait[1].replace("minute", "minuto/s").replace("second", "segundos") diff --git a/servers/upvid.py b/servers/upvid.py index 12dcfc9b..4523d5dc 100644 --- a/servers/upvid.py +++ b/servers/upvid.py @@ -2,11 +2,13 @@ # -------------------------------------------------------- # Conector UpVID By Alfa development Group # -------------------------------------------------------- +import base64 +import re -import re, base64 from core import httptools from core import scrapertools from lib.aadecode import decode as aadecode +from platformcode import config from platformcode import logger @@ -14,9 +16,9 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url) if data.code == 404: - return False, "[upvid] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "upvid" if "video is no longer available" in data.data: - return False, "[upvid] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "upvid" return True, "" diff --git a/servers/uqload.py b/servers/uqload.py index 4a8b0ec9..3c254960 100644 --- a/servers/uqload.py +++ b/servers/uqload.py @@ -2,9 +2,10 @@ # -------------------------------------------------------- # Conector Uqload By Alfa development Group # -------------------------------------------------------- - import re + from core import httptools +from platformcode import config from platformcode import logger @@ -14,7 +15,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url) if data.code == 404: - return False, "[Uqload] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Uqload" return True, "" diff --git a/servers/vevio.py b/servers/vevio.py index 5ebdbda9..f0c1a6c0 100644 --- a/servers/vevio.py +++ b/servers/vevio.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- + import sys PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -20,7 +21,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "File was deleted" in data or "Page Cannot Be Found" in data or "<title>Video not found" in data: - return False, "[vevio] El archivo ha sido eliminado o no existe" + return False, config.get_localized_string(70449) % "vevio" return True, "" diff --git a/servers/vidbull.py b/servers/vidbull.py index 0ea9f301..efda325e 100644 --- a/servers/vidbull.py +++ b/servers/vidbull.py @@ -2,12 +2,13 @@ # -------------------------------------------------------- # Conector vidbull By Alfa development Group # -------------------------------------------------------- +from lib.kt_player import decode from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger -from lib.kt_player import decode def test_video_exists(page_url): @@ -17,7 +18,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[vidbull] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "vidbull" global video_url, license_code video_url = scrapertools.find_single_match(response.data, "video_url: '([^']+)'") diff --git a/servers/videobb.py b/servers/videobb.py index 01aa0499..8439e4cc 100644 --- a/servers/videobb.py +++ b/servers/videobb.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector videobb By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "no longer exists" in data: - return False, "[videobb] El video ha sido borrado" + return False, config.get_localized_string(70449) % "videobb" return True, "" diff --git a/servers/videobin.py b/servers/videobin.py index 3740b04f..c2d0125a 100644 --- a/servers/videobin.py +++ b/servers/videobin.py @@ -4,9 +4,9 @@ # Conector para videobin # https://github.com/alfa-addon # ------------------------------------------------------------ - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -14,7 +14,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "borrado" in data or "Deleted" in data: - return False, "[videobin] El fichero ha sido borrado" + return False, config.get_localized_string(70449) % "videobin" return True, "" diff --git a/servers/videofiles.py b/servers/videofiles.py index 6110b971..89562b2f 100644 --- a/servers/videofiles.py +++ b/servers/videofiles.py @@ -2,10 +2,11 @@ # -------------------------------------------------------- # Conector Videofiles By Alfa development Group # -------------------------------------------------------- +import re -import re, time -from core import httptools, scrapertools -from platformcode import logger, platformtools +from core import httptools +from platformcode import config +from platformcode import logger data = "" def test_video_exists(page_url): @@ -14,7 +15,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url) if not data.sucess or "Not Found" in data.data or "File was deleted" in data.data or "is no longer available" in data.data: - return False, "[Videofiles] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Videofiles" global data data = data.data return True, "" diff --git a/servers/videomega.py b/servers/videomega.py index a75499c1..de473b1d 100644 --- a/servers/videomega.py +++ b/servers/videomega.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/videoz.py b/servers/videoz.py index 4ffc1f6f..a5ba7645 100644 --- a/servers/videoz.py +++ b/servers/videoz.py @@ -2,10 +2,10 @@ # -------------------------------------------------------- # Conector Videoz By Alfa development Group # -------------------------------------------------------- - from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -14,7 +14,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "Not Found" in data or "File was deleted" in data: - return False, "[Videoz] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Videoz" return True, "" diff --git a/servers/vidfast.py b/servers/vidfast.py index 64d6b1af..2b212c92 100644 --- a/servers/vidfast.py +++ b/servers/vidfast.py @@ -2,9 +2,9 @@ # -------------------------------------------------------- # Conector vidfast By Alfa development Group # -------------------------------------------------------- -import re -from core import httptools, jsontools +from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger video_urls = [] @@ -16,7 +16,7 @@ def test_video_exists(page_url): global data data = response.data if not response.sucess or "Not Found" in data or "File was deleted" in data or "is no longer available" in data: - return False, "[vidfast] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "vidfast" return True, "" diff --git a/servers/vidlox.py b/servers/vidlox.py index 559171ff..7cbb684e 100644 --- a/servers/vidlox.py +++ b/servers/vidlox.py @@ -4,9 +4,9 @@ # Conector para vidlox # https://github.com/alfa-addon # ------------------------------------------------------------ - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -15,7 +15,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "borrado" in data or "Deleted" in data: - return False, "[vidlox] El fichero ha sido borrado" + return False, config.get_localized_string(70449) % "vidlox" return True, "" diff --git a/servers/vidoza.py b/servers/vidoza.py index 5d82c5dc..c7a39de0 100644 --- a/servers/vidoza.py +++ b/servers/vidoza.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- + from core import httptools from core import jsontools from core import scrapertools @@ -11,7 +12,7 @@ def test_video_exists(page_url): global data data = httptools.downloadpage(page_url).data if "Page not found" in data or "File was deleted" in data: - return False, "[vidoza] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "vidoza" elif "processing" in data: return False, config.get_localized_string(70449) % "Vidoza" diff --git a/servers/vidtodo.py b/servers/vidtodo.py index 2c879398..039fdabd 100755 --- a/servers/vidtodo.py +++ b/servers/vidtodo.py @@ -2,8 +2,8 @@ from core import httptools from core import scrapertools -from platformcode import logger from lib import jsunpack +from platformcode import logger id_server = "vidtodo" response = "" diff --git a/servers/vidup.py b/servers/vidup.py index ecc4bf19..c300d778 100755 --- a/servers/vidup.py +++ b/servers/vidup.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- - import sys + +from platformcode import config + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -22,7 +24,7 @@ def test_video_exists(page_url): page = httptools.downloadpage(page_url) url = page.url if "Not Found" in page.data or "/404" in url: - return False, "[Vidup] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Vidup" return True, "" diff --git a/servers/vidzi.py b/servers/vidzi.py index a02132e8..c04e20e0 100644 --- a/servers/vidzi.py +++ b/servers/vidzi.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -10,7 +10,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) response = httptools.downloadpage(page_url) if not response.sucess: - return False, "[Vidzi] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Vidzi" return True, "" diff --git a/servers/vimeo.json b/servers/vimeo.json index 8bd56135..ab870ed1 100644 --- a/servers/vimeo.json +++ b/servers/vimeo.json @@ -11,7 +11,7 @@ }, "free": true, "id": "vimeo", - "name": "vimeo", + "name": "Vimeo", "premium": [ "realdebrid", "alldebrid" diff --git a/servers/vimeo.py b/servers/vimeo.py index 00ff9beb..5308551f 100644 --- a/servers/vimeo.py +++ b/servers/vimeo.py @@ -2,13 +2,12 @@ from core import httptools from core import scrapertools -from platformcode import logger - - -def get_video_url(page_url, premium=False, user="", password="", video_password=""): +from platformcode import logger, config +headers = [['User-Agent', 'Mozilla/5.0']] +def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) - video_urls = [] - headers = [['User-Agent', 'Mozilla/5.0']] + + global data if "|" in page_url: page_url, referer = page_url.split("|", 1) headers.append(['Referer', referer]) @@ -16,12 +15,24 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= page_url = scrapertools.find_single_match(page_url, ".*?video/[0-9]+") data = httptools.downloadpage(page_url, headers=headers).data + + if "Private Video on Vimeo" in data or "Sorry" in data: + return False, config.get_localized_string(70449) % 'Vimeo' + else: + return True, "" + + +def get_video_url(page_url, premium=False, user="", password="", video_password=""): + logger.info("(page_url='%s')" % page_url) + video_urls = [] + + global data patron = 'mime":"([^"]+)"' patron += '.*?url":"([^"]+)"' patron += '.*?quality":"([^"]+)"' match = scrapertools.find_multiple_matches(data, patron) for mime, media_url, calidad in match: - title = "%s (%s) [vimeo]" % (mime.replace("video/", "."), calidad) + title = "%s (%s) [Vimeo]" % (mime.replace("video/", "."), calidad) video_urls.append([title, media_url, int(calidad.replace("p", ""))]) video_urls.sort(key=lambda x: x[2]) diff --git a/servers/vimpleru.json b/servers/vimpleru.json index 15b082e5..6a1e93d3 100644 --- a/servers/vimpleru.json +++ b/servers/vimpleru.json @@ -16,7 +16,7 @@ "vimple" ] }, - "name": "vimpleru", + "name": "Vimple", "settings": [ { "default": false, diff --git a/servers/vimpleru.py b/servers/vimpleru.py index 06ba88c5..dc21c4aa 100644 --- a/servers/vimpleru.py +++ b/servers/vimpleru.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- + from core import httptools from core import scrapertools from platformcode import config, logger @@ -9,7 +10,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if '"title":"Video Not Found"' in data: - return False, "[Vimple] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Vimple" return True, "" diff --git a/servers/vipporns.py b/servers/vipporns.py index b15ca65c..cb94dc10 100644 --- a/servers/vipporns.py +++ b/servers/vipporns.py @@ -2,12 +2,13 @@ # -------------------------------------------------------- # Conector vipporns By Alfa development Group # -------------------------------------------------------- +from lib.kt_player import decode from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger -from lib.kt_player import decode def test_video_exists(page_url): @@ -17,7 +18,7 @@ def test_video_exists(page_url): "Not Found" in response.data \ or "File was deleted" in response.data \ or "is no longer available" in response.data: - return False, "[vipporns] El fichero no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "vipporns" global video_url, license_code video_url = scrapertools.find_single_match(response.data, "video_url: '([^']+)'") diff --git a/servers/viptube.py b/servers/viptube.py index c154e113..9af31d6e 100644 --- a/servers/viptube.py +++ b/servers/viptube.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/vivatube.py b/servers/vivatube.py index 504ad1cb..f3515701 100644 --- a/servers/vivatube.py +++ b/servers/vivatube.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/vivo.py b/servers/vivo.py index 168813ea..4c7b73a3 100644 --- a/servers/vivo.py +++ b/servers/vivo.py @@ -1,10 +1,10 @@ # Conector Vivo By Alfa development Group # -------------------------------------------------------- - import base64 from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url) if data.code == 404: - return False, "[Vivo] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Vivo" return True, "" diff --git a/servers/vshare.json b/servers/vshare.json index 5d3afc3c..72ebe973 100644 --- a/servers/vshare.json +++ b/servers/vshare.json @@ -20,7 +20,7 @@ "id": [ "vshare" ], - "name": "vshare", + "name": "VideoShare", "settings": [ { "default": false, diff --git a/servers/vshare.py b/servers/vshare.py index fc1ce18d..20f1a000 100644 --- a/servers/vshare.py +++ b/servers/vshare.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- - import re from core import httptools from core import scrapertools from lib import jsunpack +from platformcode import config from platformcode import logger @@ -12,7 +12,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) response = httptools.downloadpage(page_url) if response.code != 200 or "No longer available!" in response.data: - return False, "[vshare] El archivo no existe o ha sido borrado." + return False, config.get_localized_string(70449) % "vshare" else: return True, "" diff --git a/servers/vup.json b/servers/vup.json deleted file mode 100644 index 2a3fc7aa..00000000 --- a/servers/vup.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "active": true, - "find_videos": { - "ignore_urls": [], - "patterns": [ - { - "pattern": "(https://vup.to/embed-[A-z0-9]+.html)", - "url": "\\1" - }, - { - "pattern": "https://vup.to/emb.html\\?([A-z0-9]+)", - "url": "https://vup.to/embed-\\1.html" - } - ] - }, - "free": true, - "id": "vup", - "name": "vup", - "settings": [ - { - "default": false, - "enabled": true, - "id": "black_list", - "label": "@60654", - "type": "bool", - "visible": true - }, - { - "default": 0, - "enabled": true, - "id": "favorites_servers_list", - "label": "@60655", - "lvalues": [ - "No", - "1", - "2", - "3", - "4", - "5" - ], - "type": "list", - "visible": false - } - ], - "thumbnail": "https://i.postimg.cc/ZKjvqXxj/vup.png" -} diff --git a/servers/vup.py b/servers/vup.py deleted file mode 100644 index 9eba027d..00000000 --- a/servers/vup.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -# -------------------------------------------------------- -# Conector vup By Alfa development Group -# -------------------------------------------------------- - -from core import httptools -from core import scrapertools -from platformcode import logger - - -def test_video_exists(page_url): - logger.info("(page_url='%s')" % page_url) - data = httptools.downloadpage(page_url).data - if "no longer exists" in data or "to copyright issues" in data: - return False, "[vup] El video ha sido borrado" - return True, "" - - -def get_video_url(page_url, user="", password="", video_password=""): - logger.info("(page_url='%s')" % page_url) - data = httptools.downloadpage(page_url).data - bloque = scrapertools.find_single_match(data, 'sources:.*?\]') - video_urls = [] - videourl = scrapertools.find_multiple_matches(bloque, '"(http[^"]+)') - for video in videourl: - video_urls.append([".MP4 [vup]", video]) - video_urls = video_urls[::-1] - return video_urls diff --git a/servers/vvvvid.py b/servers/vvvvid.py index 36e7d305..3f1ddc53 100644 --- a/servers/vvvvid.py +++ b/servers/vvvvid.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- +import re + +import requests + from core import httptools from lib import vvvvid_decoder from platformcode import logger -import requests -import re # Creating persistent session current_session = requests.Session() diff --git a/servers/watchanimestream.py b/servers/watchanimestream.py index 8544fb02..3df92201 100644 --- a/servers/watchanimestream.py +++ b/servers/watchanimestream.py @@ -1,9 +1,7 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger -from lib import jsunpack def get_video_url(page_url, video_password): diff --git a/servers/winporn.py b/servers/winporn.py index 246a8a41..74db631e 100644 --- a/servers/winporn.py +++ b/servers/winporn.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/xdrive.py b/servers/xdrive.py index 30213d6e..5baaeab4 100644 --- a/servers/xdrive.py +++ b/servers/xdrive.py @@ -4,9 +4,9 @@ # Conector para xdrive # https://github.com/alfa-addon # ------------------------------------------------------------ - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -14,7 +14,7 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "Object not found" in data or "no longer exists" in data or '"sources": [false]' in data: - return False, "[xdrive] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "xdrive" return True, "" diff --git a/servers/xhamster.py b/servers/xhamster.py index c9965171..df46152f 100644 --- a/servers/xhamster.py +++ b/servers/xhamster.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/xstreamcdn.py b/servers/xstreamcdn.py index d20374fa..27310f4d 100644 --- a/servers/xstreamcdn.py +++ b/servers/xstreamcdn.py @@ -14,7 +14,7 @@ else: from core import httptools from core import scrapertools from core import jsontools -from platformcode import logger, config +from platformcode import logger def test_video_exists(page_url): diff --git a/servers/xvideos.py b/servers/xvideos.py index 4b8abe4e..947376df 100755 --- a/servers/xvideos.py +++ b/servers/xvideos.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- import re + from core import httptools -from core import scrapertools +from platformcode import config from platformcode import logger @@ -11,7 +12,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url).data if "Lo sentimos" in data or "File not found" in data or 'og:video">' in data: - return False, "[Xvideos] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Xvideos" return True, "" diff --git a/servers/youdbox.py b/servers/youdbox.py index 8da0461f..a58912b4 100644 --- a/servers/youdbox.py +++ b/servers/youdbox.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import re from core import httptools from core import scrapertools from platformcode import logger diff --git a/servers/yourupload.py b/servers/yourupload.py index ef7e79a0..7625c0a3 100755 --- a/servers/yourupload.py +++ b/servers/yourupload.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -11,7 +11,7 @@ def test_video_exists(page_url): data = httptools.downloadpage(page_url).data if "File was deleted" in data or "File not found" in data or 'og:video">' in data: - return False, "[Yourupload] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Yourupload" return True, "" diff --git a/servers/youtube.py b/servers/youtube.py index 34aa0b56..60d805b6 100644 --- a/servers/youtube.py +++ b/servers/youtube.py @@ -215,7 +215,7 @@ def extract_videos(video_id): url = re.search('url=(.*)', opt["cipher"]).group(1) s = cipher.get('s') url = "%s&sig=%s" % (urllib.unquote(url), signature([s])) - video_urls.append(["%s" % itag_list.get(opt["itag"], "video"), url]) + video_urls.append(["%s" % itag_list.get(opt["itag"], "audio"), url]) elif opt["itag"] in itag_list: video_urls.append(["%s" % itag_list.get(opt["itag"], "video"), opt["url"]]) diff --git a/servers/youwatch.py b/servers/youwatch.py index 5febee0b..82f461c3 100644 --- a/servers/youwatch.py +++ b/servers/youwatch.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- - from core import httptools from core import scrapertools +from platformcode import config from platformcode import logger @@ -9,12 +9,12 @@ def test_video_exists(page_url): logger.info("(page_url='%s')" % page_url) data = httptools.downloadpage(page_url).data if "File Not Found" in data: - return False, "[Youwatch] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Youwatch" url_redirect = scrapertools.find_single_match(data, '<iframe src="([^"]+)"') data = httptools.downloadpage(url_redirect).data if "We're sorry, this video is no longer available" in data: - return False, "[Youwatch] El archivo no existe o ha sido borrado" + return False, config.get_localized_string(70449) % "Youwatch" return True, "" diff --git a/servers/zippyshare.py b/servers/zippyshare.py index 2d1e86c0..65c45a70 100755 --- a/servers/zippyshare.py +++ b/servers/zippyshare.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -import math import re from core import httptools diff --git a/videolibrary_service.py b/service.py similarity index 96% rename from videolibrary_service.py rename to service.py index 46eef1c7..667d6058 100644 --- a/videolibrary_service.py +++ b/service.py @@ -26,17 +26,19 @@ from platformcode import updater def update(path, p_dialog, i, t, serie, overwrite): - logger.info("Actualizando " + path) + logger.info("Updating " + path) insertados_total = 0 - + head_nfo, it = videolibrarytools.read_nfo(path + '/tvshow.nfo') + # videolibrarytools.check_renumber_options(it) + videolibrarytools.update_renumber_options(it, head_nfo, path) category = serie.category # logger.debug("%s: %s" %(serie.contentSerieName,str(list_canales) )) for channel, url in serie.library_urls.items(): serie.channel = channel serie.url = url - + ###### Redirección al canal NewPct1.py si es un clone, o a otro canal y url si ha intervención judicial try: head_nfo, it = videolibrarytools.read_nfo(path + '/tvshow.nfo') #Refresca el .nfo para recoger actualizaciones @@ -50,8 +52,8 @@ def update(path, p_dialog, i, t, serie, overwrite): if channel_enabled: - heading = config.get_localized_string(60389) - p_dialog.update(int(math.ceil((i + 1) * t)), heading, "%s: %s" % (serie.contentSerieName, + heading = config.get_localized_string(20000) + p_dialog.update(int(math.ceil((i + 1) * t)), heading, config.get_localized_string(60389) % (serie.contentSerieName, serie.channel.capitalize())) try: pathchannels = filetools.join(config.get_runtime_path(), "channels", serie.channel + '.py') @@ -102,18 +104,18 @@ def update(path, p_dialog, i, t, serie, overwrite): xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo') except: logger.error(traceback.format_exc()) - + return insertados_total > 0 def check_for_update(overwrite=True): - logger.info("Actualizando series...") + logger.info("Update Series...") p_dialog = None serie_actualizada = False update_when_finished = False hoy = datetime.date.today() estado_verify_playcount_series = False - + try: if config.get_setting("update", "videolibrary") != 0 or overwrite: config.set_setting("updatelibrary_last_check", hoy.strftime('%Y-%m-%d'), "videolibrary") @@ -132,10 +134,10 @@ def check_for_update(overwrite=True): for i, tvshow_file in enumerate(show_list): head_nfo, serie = videolibrarytools.read_nfo(tvshow_file) path = filetools.dirname(tvshow_file) - + logger.info("serie=" + serie.contentSerieName) p_dialog.update(int(math.ceil((i + 1) * t)), heading, serie.contentSerieName) - + #Verificamos el estado del serie.library_playcounts de la Serie por si está incompleto try: estado = False @@ -161,7 +163,7 @@ def check_for_update(overwrite=True): xbmc_videolibrary.mark_content_as_watched_on_alfa(path + '/tvshow.nfo') except: logger.error(traceback.format_exc()) - + continue # obtenemos las fecha de actualizacion y de la proxima programada para esta serie @@ -209,7 +211,7 @@ def check_for_update(overwrite=True): serie_actualizada = update(path, p_dialog, i, t, serie, overwrite) if not serie_actualizada: update_next += datetime.timedelta(days=interval) - + if serie_actualizada: update_last = hoy update_next = hoy + datetime.timedelta(days=interval) @@ -227,7 +229,7 @@ def check_for_update(overwrite=True): if serie_actualizada: if config.get_setting("search_new_content", "videolibrary") == 0: # Actualizamos la videoteca de Kodi: Buscar contenido en la carpeta de la serie - if config.is_xbmc(): + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): from platformcode import xbmc_videolibrary xbmc_videolibrary.update(folder=filetools.basename(path)) else: @@ -235,10 +237,10 @@ def check_for_update(overwrite=True): if estado_verify_playcount_series: #Si se ha cambiado algún playcount, ... estado = config.set_setting("verify_playcount", True, "videolibrary") #... actualizamos la opción de Videolibrary - + if config.get_setting("search_new_content", "videolibrary") == 1 and update_when_finished: # Actualizamos la videoteca de Kodi: Buscar contenido en todas las series - if config.is_xbmc(): + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): from platformcode import xbmc_videolibrary xbmc_videolibrary.update() @@ -255,7 +257,7 @@ def check_for_update(overwrite=True): if p_dialog: p_dialog.close() - + from core.item import Item item_dummy = Item() videolibrary.list_movies(item_dummy, silent=True) @@ -380,6 +382,10 @@ if __name__ == "__main__": import xbmc import time + # mark as stopped all downloads (if we are here, probably kodi just started) + from specials.downloads import stop_all + stop_all() + # modo adulto: # sistema actual 0: Nunca, 1:Siempre, 2:Solo hasta que se reinicie Kodi # si es == 2 lo desactivamos. @@ -394,7 +400,7 @@ if __name__ == "__main__": # Verificar quick-fixes al abrirse Kodi, y dejarlo corriendo como Thread if not config.dev_mode(): - updated, needsReload = updater.check() + updated, needsReload = updater.check(background=True) config.set_setting("updater_last_check", str(time.time()), "videolibrary") if needsReload: xbmc.executescript(__file__) @@ -409,7 +415,7 @@ if __name__ == "__main__": if not config.get_setting("update", "videolibrary") == 2: check_for_update(overwrite=False) - + # Se ejecuta ciclicamente if config.get_platform(True)['num_version'] >= 14: diff --git a/specials/backup.py b/specials/backup.py new file mode 100644 index 00000000..b004ff5e --- /dev/null +++ b/specials/backup.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------ +# Backup and restore video library +# ------------------------------------------------------------ + +import os, datetime + +import xbmc + +from core import ziptools, videolibrarytools, filetools +from platformcode import logger, config, platformtools, xbmc_videolibrary +from distutils.dir_util import copy_tree + +temp_path = xbmc.translatePath("special://userdata/addon_data/plugin.video.kod/temp/") +movies_path = os.path.join(temp_path, "movies") +tvshows_path = os.path.join(temp_path, "tvshows") + + +def export_videolibrary(item): + logger.info() + + zip_file_folder = platformtools.dialog_browse(3, config.get_localized_string(80002)) + if zip_file_folder == "": + return + zip_file = xbmc.translatePath(zip_file_folder + "KoD_video_library-" + str(datetime.date.today()) + ".zip") + + p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), config.get_localized_string(80003)) + p_dialog.update(0) + + if filetools.exists(temp_path): + filetools.rmdirtree(temp_path) + filetools.mkdir(temp_path) + p_dialog.update(25) + filetools.mkdir(movies_path) + copy_tree(videolibrarytools.MOVIES_PATH, movies_path) + p_dialog.update(50) + filetools.mkdir(tvshows_path) + copy_tree(videolibrarytools.TVSHOWS_PATH, tvshows_path) + p_dialog.update(75) + + zipper = ziptools.ziptools() + zipper.zip(temp_path, zip_file) + + filetools.rmdirtree(temp_path) + + p_dialog.update(100) + xbmc.sleep(1000) + p_dialog.close() + platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(80004), icon=0, time=5000, sound=False) + + +def import_videolibrary(item): + logger.info() + + zip_file = platformtools.dialog_browse(1, config.get_localized_string(80005)) + if zip_file == "": + return + if not platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(80006)): + return + + p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), config.get_localized_string(80007)) + p_dialog.update(0) + + if filetools.exists(temp_path): + filetools.rmdirtree(temp_path) + filetools.mkdir(temp_path) + + unzipper = ziptools.ziptools() + unzipper.extract(zip_file, temp_path) + p_dialog.update(25) + + filetools.rmdirtree(videolibrarytools.MOVIES_PATH) + filetools.rmdirtree(videolibrarytools.TVSHOWS_PATH) + p_dialog.update(50) + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): + xbmc_videolibrary.clean(config.get_setting('videolibrarypath')) + + config.verify_directories_created() + if filetools.exists(movies_path): + copy_tree(movies_path, videolibrarytools.MOVIES_PATH) + p_dialog.update(70) + if filetools.exists(tvshows_path): + copy_tree(tvshows_path, videolibrarytools.TVSHOWS_PATH) + p_dialog.update(90) + filetools.rmdirtree(temp_path) + + p_dialog.update(100) + xbmc.sleep(1000) + p_dialog.close() + platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(80008), icon=0, time=5000, sound=False) + + if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(80009)): + import service + service.check_for_update(overwrite=True) + + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): + xbmc_videolibrary.update() diff --git a/specials/community.py b/specials/community.py index c11af091..ae25f8b3 100644 --- a/specials/community.py +++ b/specials/community.py @@ -10,9 +10,6 @@ from platformcode import config, platformtools from specials import autoplay from channelselector import get_thumb -from specials import shortcuts -CONTEXT = shortcuts.context() - info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json try: lang = info_language[config.get_setting("info_language", "videolibrary")] except: lang = 'it' @@ -45,7 +42,7 @@ def show_channels(item): itemlist = [] # add context menu - context = CONTEXT + [{"title": config.get_localized_string(50005), "action": "remove_channel", "channel": "community"}] + context = [{"title": config.get_localized_string(50005), "action": "remove_channel", "channel": "community"}] # read json json = load_and_check(item) @@ -118,7 +115,7 @@ def show_menu(item): def search(item, text): - support.log('Search:', text) + support.log(text) itemlist = [] if item.custom_search: @@ -215,8 +212,7 @@ def peliculas(item, json='', key='', itemlist=[]): fanart = extra.fanart, plot = extra.plot, personal_plot = extra.plot, - action = action, - context = CONTEXT) + action = action) itlist.append(it) if not 'generic_list' in key: @@ -255,8 +251,7 @@ def get_seasons(item): contentSeason=option['season'], infoLabels=infoLabels, contentType='season', - path=extra.path, - context = CONTEXT)) + path=extra.path)) if inspect.stack()[2][3] in ['add_tvshow', 'get_episodes', 'update', 'find_episodes', 'get_newest'] or show_seasons == False: itlist = [] @@ -331,8 +326,7 @@ def episodios(item, json ='', key='', itemlist =[]): contentEpisode = episode_number, infoLabels = infoLabels, contentType = 'episode', - path = item.path, - context = CONTEXT)) + path = item.path)) # if showseason if inspect.stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes', 'get_newest', 'search']: @@ -354,8 +348,7 @@ def episodios(item, json ='', key='', itemlist =[]): contentSeason=season, infoLabels=infoLabels, filterseason=str(season), - path=item.path, - context = CONTEXT)) + path=item.path)) elif defpage and inspect.stack()[1][3] not in ['get_seasons']: if Pagination and len(itemlist) >= Pagination: @@ -407,8 +400,7 @@ def get_menu(item, json, key, itemlist=[]): action = 'show_menu', menu = level2 if not item.menu else None, filterkey = extra.filterkey, - filter = extra.filter, - context = CONTEXT) + filter = extra.filter) if title: itemlist.append(it) @@ -450,7 +442,6 @@ def get_sub_menu(item, json, key, itemlist=[]): action = 'show_menu', menu = level2 if not item.menu else None, filterkey = filterkey, - context = CONTEXT, description = extra.description) itemlist.append(it) @@ -485,14 +476,13 @@ def get_search_menu(item, json='', itemlist=[], channel_name=''): url=item.url, custom_search=extra.url if extra.url != item.url else '', path=item.path, - global_search=True if channel_name else False, - context = CONTEXT)) + global_search=True if channel_name else False)) return itemlist def submenu(item, json, key, itemlist = [], filter_list = []): - support.log() + support.log(item) import sys if sys.version_info[0] >= 3: from concurrent import futures @@ -584,8 +574,7 @@ def filter_thread(filter, key, item, description): path=item.path, filterkey=item.filterkey, filter=filter, - key=key, - context = CONTEXT) + key=key) return item @@ -749,8 +738,7 @@ def pagination(item, itemlist = []): path=item.path, media_type=item.media_type, thumbnail=support.thumb(), - itemlist= encoded_itemlist, - context = CONTEXT)) + itemlist= encoded_itemlist)) return itlist def add_channel(item): diff --git a/specials/downloads.py b/specials/downloads.py index 38b478e7..b514affa 100644 --- a/specials/downloads.py +++ b/specials/downloads.py @@ -14,24 +14,30 @@ from past.utils import old_div import re import time import unicodedata +import xbmc - +from channelselector import get_thumb from core import filetools, jsontools, scraper, scrapertools, servertools, videolibrarytools, support from core.downloader import Downloader from core.item import Item from platformcode import config, logger from platformcode import platformtools -STATUS_COLORS = {0: "orange", 1: "orange", 2: "green", 3: "red"} -STATUS_CODES = type("StatusCode", (), {"stoped": 0, "canceled": 1, "completed": 2, "error": 3}) +kb = '0xFF65B3DA' +kg = '0xFF65DAA8' +kr = '0xFFDA6865' +ky = '0xFFDAAB65' + +STATUS_COLORS = {0: '', 1: '', 2: kg, 3: kr, 4: kb} +STATUS_CODES = type("StatusCode", (), {"stoped": 0, "canceled": 1, "completed": 2, "error": 3, "downloading": 4 }) DOWNLOAD_LIST_PATH = config.get_setting("downloadlistpath") DOWNLOAD_PATH = config.get_setting("downloadpath") STATS_FILE = filetools.join(config.get_data_path(), "servers.json") FOLDER_MOVIES = config.get_setting("folder_movies") FOLDER_TVSHOWS = config.get_setting("folder_tvshows") -TITLE_FILE = "[COLOR %s][%i%%][/COLOR] %s" -TITLE_TVSHOW = "[COLOR %s][%i%%][/COLOR] %s [%s]" +TITLE_FILE = "[COLOR %s]| %i%% |[/COLOR] - %s" +TITLE_TVSHOW = "[COLOR %s]| %i%% |[/COLOR] - %s [%s]" def mainlist(item): @@ -92,31 +98,44 @@ def mainlist(item): # Si hay alguno completado if 2 in estados: itemlist.insert(0, Item(channel=item.channel, action="clean_ready", title=config.get_localized_string(70218), - contentType=item.contentType, contentChannel=item.contentChannel, - contentSerieName=item.contentSerieName, text_color="sandybrown")) + contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('delete.png'), + contentSerieName=item.contentSerieName, text_color=STATUS_COLORS[STATUS_CODES.completed])) # Si hay alguno con error if 3 in estados: itemlist.insert(0, Item(channel=item.channel, action="restart_error", title=config.get_localized_string(70219), - contentType=item.contentType, contentChannel=item.contentChannel, - contentSerieName=item.contentSerieName, text_color="orange")) + contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('update.png'), + contentSerieName=item.contentSerieName, text_color=STATUS_COLORS[STATUS_CODES.error])) # Si hay alguno pendiente if 1 in estados or 0 in estados: itemlist.insert(0, Item(channel=item.channel, action="download_all", title=support.typo(config.get_localized_string(70220),'bold'), - contentType=item.contentType, contentChannel=item.contentChannel, + contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('downloads.png'), contentSerieName=item.contentSerieName)) if len(itemlist): itemlist.insert(0, Item(channel=item.channel, action="clean_all", title=support.typo(config.get_localized_string(70221),'bold'), - contentType=item.contentType, contentChannel=item.contentChannel, + contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('delete.png'), contentSerieName=item.contentSerieName)) + # if there's at least one downloading + if 4 in estados: + itemlist.insert(0, Item(channel=item.channel, action="stop_all", title=config.get_localized_string(60222), + contentType=item.contentType, contentChannel=item.contentChannel, + contentSerieName=item.contentSerieName, thumbnail=get_thumb('stop.png'), + text_color=STATUS_COLORS[STATUS_CODES.downloading])) + if not item.contentType == "tvshow" and config.get_setting("browser") == True: - itemlist.insert(0, Item(channel=item.channel, action="browser", title=support.typo(config.get_localized_string(70222),'bold'),url=DOWNLOAD_PATH)) + itemlist.insert(0, Item(channel=item.channel, action="browser", title=support.typo(config.get_localized_string(70222),'bold'), thumbnail=get_thumb('search.png'), url=DOWNLOAD_PATH)) if not item.contentType == "tvshow": - itemlist.insert(0, Item(channel=item.channel, action="settings", title= support.typo(config.get_localized_string(70223),'bold color kod'))) + itemlist.append(Item(channel='shortcuts', action="SettingOnPosition", category=4, setting=0, title= support.typo(config.get_localized_string(70288),'bold color kod'), thumbnail=get_thumb('setting_0.png'))) + + # Reload + if estados: + itemlist.insert(0, Item(channel=item.channel, action="reload", title= support.typo(config.get_localized_string(70008),'bold color kod'), + contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('update.png'), + contentSerieName=item.contentSerieName)) return itemlist @@ -130,7 +149,6 @@ def settings(item): def browser(item): logger.info() itemlist = [] - context = [{ 'title': 'cancella', 'channel': 'downloads', 'action': "del_file"}] for file in filetools.listdir(item.url): if file == "list": continue @@ -143,20 +161,27 @@ def browser(item): def del_file(item): - ok = platformtools.dialog_yesno(config.get_localized_string(30039),config.get_localized_string(30040)) + ok = platformtools.dialog_yesno(config.get_localized_string(30039),config.get_localized_string(30040) % item.title) if ok: filetools.remove(item.url) + xbmc.sleep(100) platformtools.itemlist_refresh() + def del_dir(item): ok = platformtools.dialog_yesno(config.get_localized_string(30037),config.get_localized_string(30038)) if ok: filetools.rmdirtree(item.url) + xbmc.sleep(100) platformtools.itemlist_refresh() def clean_all(item): logger.info() + stop_all() + removeFiles = False + if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(30300)): + removeFiles = True for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)): if fichero.endswith(".json"): @@ -164,10 +189,30 @@ def clean_all(item): if not item.contentType == "tvshow" or ( item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel): filetools.remove(filetools.join(DOWNLOAD_LIST_PATH, fichero)) + if removeFiles: + filetools.remove(filetools.join(DOWNLOAD_PATH, download_item.downloadFilename)) + xbmc.sleep(100) platformtools.itemlist_refresh() +def reload(item): + platformtools.itemlist_refresh() + + +def stop_all(item=None): + logger.info() + + for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)): + if fichero.endswith(".json"): + download_item = Item().fromjson(filetools.read(filetools.join(DOWNLOAD_LIST_PATH, fichero))) + if download_item.downloadStatus == 4: + update_json(filetools.join(DOWNLOAD_LIST_PATH, fichero), {"downloadStatus": STATUS_CODES.stoped}) + xbmc.sleep(100) + if item: + platformtools.itemlist_refresh() + + def clean_ready(item): logger.info() for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)): @@ -191,9 +236,9 @@ def restart_error(item): item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel): if download_item.downloadStatus == STATUS_CODES.error: if filetools.isfile( - filetools.join(config.get_setting("downloadpath"), download_item.downloadFilename)): + filetools.join(DOWNLOAD_PATH, download_item.downloadFilename)): filetools.remove( - filetools.join(config.get_setting("downloadpath"), download_item.downloadFilename)) + filetools.join(DOWNLOAD_PATH, download_item.downloadFilename)) update_json(item.path, {"downloadStatus": STATUS_CODES.stoped, "downloadComplete": 0, "downloadProgress": 0}) @@ -203,6 +248,12 @@ def restart_error(item): def download_all(item): time.sleep(0.5) + item.action = "download_all_background" + xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")") + platformtools.itemlist_refresh() + + +def download_all_background(item): for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)): if fichero.endswith(".json"): download_item = Item(path=filetools.join(DOWNLOAD_LIST_PATH, fichero)).fromjson( @@ -212,7 +263,7 @@ def download_all(item): item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel): if download_item.downloadStatus in [STATUS_CODES.stoped, STATUS_CODES.canceled]: res = start_download(download_item) - platformtools.itemlist_refresh() + # platformtools.itemlist_refresh() # Si se ha cancelado paramos if res == STATUS_CODES.canceled: break @@ -225,30 +276,37 @@ def menu(item): servidor = "Auto" # Opciones disponibles para el menu op = [config.get_localized_string(70225), config.get_localized_string(70226), config.get_localized_string(70227), - config.get_localized_string(30165) % (servidor.capitalize())] + config.get_localized_string(30165) % (servidor.capitalize()), config.get_localized_string(60220), + config.get_localized_string(60221)] opciones = [] # Opciones para el menu - if item.downloadStatus == 0: # Sin descargar + if item.downloadStatus == STATUS_CODES.stoped: opciones.append(op[0]) # Descargar if not item.server: opciones.append(op[3]) # Elegir Servidor opciones.append(op[1]) # Eliminar de la lista - if item.downloadStatus == 1: # descarga parcial + if item.downloadStatus == STATUS_CODES.canceled: opciones.append(op[0]) # Descargar if not item.server: opciones.append(op[3]) # Elegir Servidor opciones.append(op[2]) # Reiniciar descarga opciones.append(op[1]) # Eliminar de la lista - if item.downloadStatus == 2: # descarga completada + if item.downloadStatus == STATUS_CODES.completed: + opciones.append(op[5]) # Play opciones.append(op[1]) # Eliminar de la lista opciones.append(op[2]) # Reiniciar descarga - if item.downloadStatus == 3: # descarga con error + if item.downloadStatus == STATUS_CODES.error: # descarga con error opciones.append(op[2]) # Reiniciar descarga opciones.append(op[1]) # Eliminar de la lista + if item.downloadStatus == STATUS_CODES.downloading: + opciones.append(op[5]) # Play + opciones.append(op[4]) # pause download + opciones.append(op[1]) # Eliminar de la lista + # Mostramos el dialogo seleccion = platformtools.dialog_select(config.get_localized_string(30163), opciones) @@ -259,10 +317,13 @@ def menu(item): # Opcion Eliminar if opciones[seleccion] == op[1]: filetools.remove(item.path) + if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(30300)): + filetools.remove(filetools.join(DOWNLOAD_PATH, item.downloadFilename)) # Opcion inicaiar descarga if opciones[seleccion] == op[0]: - start_download(item) + item.action = "start_download" + xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")") # Elegir Servidor if opciones[seleccion] == op[3]: @@ -270,35 +331,89 @@ def menu(item): # Reiniciar descarga if opciones[seleccion] == op[2]: - if filetools.isfile(filetools.join(config.get_setting("downloadpath"), item.downloadFilename)): - filetools.remove(filetools.join(config.get_setting("downloadpath"), item.downloadFilename)) + if filetools.isfile(filetools.join(DOWNLOAD_PATH, item.downloadFilename)): + filetools.remove(filetools.join(DOWNLOAD_PATH, item.downloadFilename)) update_json(item.path, {"downloadStatus": STATUS_CODES.stoped, "downloadComplete": 0, "downloadProgress": 0, "downloadServer": {}}) - platformtools.itemlist_refresh() + if opciones[seleccion] == op[4]: + update_json(item.path, {"downloadStatus": STATUS_CODES.stoped}) + + if opciones[seleccion] == op[5]: + xbmc.executebuiltin('PlayMedia(' + filetools.join(DOWNLOAD_PATH, item.downloadFilename) + ',resume)') + + if opciones[seleccion] != op[5]: + platformtools.itemlist_refresh() def move_to_libray(item): - title = item.fulltitle - if config.get_setting('lowerize_title', 'videolibrary'): - title = title.lower() + logger.info() if item.contentType == 'movie': FOLDER = FOLDER_MOVIES - path_title = "%s [%s]" % (title, item.infoLabels['IMDBNumber']) + path_title = "%s [%s]" % (item.contentTitle.strip() if item.contentTitle else item.fulltitle.strip() , item.infoLabels['IMDBNumber']) move_path = filetools.join(config.get_videolibrary_path(), FOLDER, path_title) else: FOLDER = FOLDER_TVSHOWS - path_title = "%s [%s]" % (title, item.infoLabels['IMDBNumber']) + path_title = os.path.dirname(item.downloadFilename) move_path = filetools.join(config.get_videolibrary_path(), FOLDER) - download_path = filetools.join(config.get_setting("downloadpath"), item.downloadFilename) + download_path = filetools.join(DOWNLOAD_PATH, item.downloadFilename) library_path = filetools.join(move_path, *filetools.split(item.downloadFilename)) final_path = download_path - if config.get_setting("library_add") == True and config.get_setting("library_move") == True: + if item.contentType == "movie" and item.infoLabels["tmdb_id"]: + contentTitle = item.contentTitle if item.contentTitle else item.fulltitle + library_item = Item(title= filetools.split(item.downloadFilename)[-1], channel="downloads", contentTitle = contentTitle, + fulltitle = item.fulltitle,action="findvideos", infoLabels=item.infoLabels, url=library_path) + videolibrarytools.save_movie(library_item) + + elif item.contentType == "episode" and item.infoLabels["tmdb_id"]: + contentSerieName = item.contentSerieName if item.contentSerieName else item.fulltitle + library_item = Item(title=filetools.split(item.downloadFilename)[-1], channel="downloads", contentSerieName = contentSerieName, + fulltitle = item.fulltitle, action="findvideos", infoLabels=item.infoLabels, url=library_path) + tvshow = Item(channel="downloads", contentType="tvshow", contentSerieName = contentSerieName, + fulltitle = item.fulltitle, infoLabels={"tmdb_id": item.infoLabels["tmdb_id"]}) + videolibrarytools.save_tvshow(tvshow, [library_item]) + + if not filetools.isdir(filetools.dirname(library_path)): + filetools.mkdir(filetools.dirname(library_path)) + + if filetools.isfile(library_path) and filetools.isfile(download_path): + filetools.remove(library_path) + + if filetools.isfile(download_path): + if filetools.move(download_path, library_path): + final_path = library_path + + if len(filetools.listdir(filetools.dirname(download_path))) == 0: + filetools.rmdir(filetools.dirname(download_path)) + + name = item.contentTitle if item.contentType == 'movie' else str(item.infoLabels['season']) + 'x' + str(item.infoLabels['episode']).zfill(2) + list_item = filetools.listdir(filetools.join(config.get_videolibrary_path(), FOLDER, path_title)) + + clean = False + for File in list_item: + filename = File.lower() + name = name.lower() + + if filename.startswith(name) and (filename.endswith('.strm') or (filename.endswith('.json') and 'downloads' not in filename)): + clean = True + file_path = filetools.join(config.get_setting("videolibrarypath"), FOLDER, path_title, File) + logger.info('Delete File: ' + str(file_path)) + filetools.remove(file_path) + if file_path.endswith('.strm'): + file_strm_path = file_path + + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): + from platformcode import xbmc_videolibrary + if clean == True: + xbmc_videolibrary.clean(file_strm_path) + xbmc_videolibrary.update(FOLDER, path_title) + + """if config.get_setting("library_add") == True and config.get_setting("library_move") == True: if not filetools.isdir(filetools.dirname(library_path)): filetools.mkdir(filetools.dirname(library_path)) @@ -321,19 +436,20 @@ def move_to_libray(item): for File in list_item: filename = File.lower() name = name.lower() + if filename.startswith(name) and (filename.endswith('.strm') or filename.endswith('.json') or filename.endswith('.nfo')): clean = True logger.info('Delete File: ' + str(filetools.join(config.get_videolibrary_path(), FOLDER, path_title, File))) filetools.remove(filetools.join(config.get_videolibrary_path(), FOLDER, path_title, File)) - from platformcode import xbmc_videolibrary - - xbmc_videolibrary.update(FOLDER) - if clean == True: - import xbmc - while xbmc.getCondVisibility('Library.IsScanningVideo()'): - xbmc.sleep(500) - xbmc_videolibrary.clean() + if config.get_setting("videolibrary_kodi"): + from platformcode import xbmc_videolibrary + xbmc_videolibrary.update(FOLDER) + if clean == True: + import xbmc + while xbmc.getCondVisibility('Library.IsScanningVideo()'): + xbmc.sleep(500) + xbmc_videolibrary.clean() if config.get_setting("library_add") == True and config.get_setting("library_move") == False: if filetools.isfile(final_path): @@ -347,7 +463,7 @@ def move_to_libray(item): action="findvideos", infoLabels=item.infoLabels, url=final_path) tvshow = Item(channel="downloads", contentType="tvshow", infoLabels={"tmdb_id": item.infoLabels["tmdb_id"]}) - videolibrarytools.save_tvshow(tvshow, [library_item]) + videolibrarytools.save_tvshow(tvshow, [library_item])""" def update_json(path, params): @@ -398,14 +514,14 @@ def get_match_list(data, match_list, order_list=None, only_ascii=False, ignoreca { "ID1" : ["Cadena 1", "Cadena 2", "Cadena 3"], "ID2" : ["Cadena 4", "Cadena 5", "Cadena 6"] } - + El diccionario no pude contener una misma cadena de busqueda en varías IDs. - + La busqueda se realiza por orden de tamaño de cadena de busqueda (de mas larga a mas corta) si una cadena coincide, se elimina de la cadena a buscar para las siguientes, para que no se detecten dos categorias si una cadena es parte de otra: - por ejemplo: "Idioma Español" y "Español" si la primera aparece en la cadena "Pablo sabe hablar el Idioma Español" + por ejemplo: "Idioma Español" y "Español" si la primera aparece en la cadena "Pablo sabe hablar el Idioma Español" coincidira con "Idioma Español" pero no con "Español" ya que la coincidencia mas larga tiene prioridad. - + """ match_dict = dict() matches = [] @@ -459,7 +575,7 @@ def get_match_list(data, match_list, order_list=None, only_ascii=False, ignoreca def sort_method(item): """ - Puntua cada item en funcion de varios parametros: + Puntua cada item en funcion de varios parametros: @type item: item @param item: elemento que se va a valorar. @return: puntuacion otenida @@ -508,7 +624,7 @@ def download_from_url(url, item): return {"downloadStatus": STATUS_CODES.error} # Obtenemos la ruta de descarga y el nombre del archivo - item.downloadFilename = item.downloadFilename.replace('/','-') + item.downloadFilename = item.downloadFilename download_path = filetools.dirname(filetools.join(DOWNLOAD_PATH, item.downloadFilename)) file_name = filetools.basename(filetools.join(DOWNLOAD_PATH, item.downloadFilename)) @@ -522,7 +638,14 @@ def download_from_url(url, item): max_connections=1 + int(config.get_setting("max_connections", "downloads")), block_size=2 ** (17 + int(config.get_setting("block_size", "downloads"))), part_size=2 ** (20 + int(config.get_setting("part_size", "downloads"))), - max_buffer=2 * int(config.get_setting("max_buffer", "downloads"))) + max_buffer=2 * int(config.get_setting("max_buffer", "downloads")), + json_path=item.path) + dir = filetools.dirname(item.downloadFilename) + file = filetools.join(dir, d.filename) + + update_json(item.path, {"downloadUrl": d.download_url, "downloadStatus": STATUS_CODES.downloading, "downloadSize": d.size[0], + "downloadProgress": d.progress, "downloadCompleted": d.downloaded[0], "downloadFilename": file}) + d.start_dialog(config.get_localized_string(60332)) # Descarga detenida. Obtenemos el estado: @@ -541,15 +664,12 @@ def download_from_url(url, item): logger.info("Downloaded correctly") status = STATUS_CODES.completed - if item.downloadSize and item.downloadSize != d.size[0]: + if (item.downloadSize and item.downloadSize != d.size[0]) or d.size[0] < 5000000: # if size don't correspond or file is too little (gounlimited for example send a little video to say the server is overloaded) status = STATUS_CODES.error save_server_statistics(item.server, d.speed[0], d.state != d.states.error) - dir = filetools.dirname(item.downloadFilename) - file = filetools.join(dir, d.filename) - - if status == STATUS_CODES.completed: + if status == STATUS_CODES.completed and config.get_setting("library_move"): move_to_libray(item.clone(downloadFilename=file)) return {"downloadUrl": d.download_url, "downloadStatus": status, "downloadSize": d.size[0], @@ -560,31 +680,37 @@ def download_from_server(item): logger.info(item.tostring()) unsupported_servers = ["torrent"] - progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70178) % item.server) - if item.contentChannel == 'community': - channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) - else: - channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) - if hasattr(channel, "play") and not item.play_menu: + if item.contentChannel == 'local': + return {"downloadStatus": STATUS_CODES.completed} - progreso.update(50, config.get_localized_string(70178) % item.server, config.get_localized_string(60003) % item.contentChannel) - try: - itemlist = getattr(channel, "play")(item.clone(channel=item.contentChannel, action=item.contentAction)) - except: - logger.error("Error in the channel %s" % item.contentChannel) + progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70178) % item.server) + + try: + if item.contentChannel in ['community', 'videolibrary']: + channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) else: - if len(itemlist) and isinstance(itemlist[0], Item): - download_item = item.clone(**itemlist[0].__dict__) - download_item.contentAction = download_item.action - download_item.infoLabels = item.infoLabels - item = download_item - elif len(itemlist) and isinstance(itemlist[0], list): - item.video_urls = itemlist - if not item.server: item.server = "directo" + channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) + if hasattr(channel, "play") and not item.play_menu: + + progreso.update(50, config.get_localized_string(70178) % item.server, config.get_localized_string(70180) % item.contentChannel) + try: + itemlist = getattr(channel, "play")(item.clone(channel=item.contentChannel, action=item.contentAction)) + except: + logger.error("Error in the channel %s" % item.contentChannel) else: - logger.info("There is nothing to reproduce") - return {"downloadStatus": STATUS_CODES.error} - progreso.close() + if len(itemlist) and isinstance(itemlist[0], Item): + download_item = item.clone(**itemlist[0].__dict__) + download_item.contentAction = download_item.action + download_item.infoLabels = item.infoLabels + item = download_item + elif len(itemlist) and isinstance(itemlist[0], list): + item.video_urls = itemlist + if not item.server: item.server = "directo" + else: + logger.info("There is nothing to reproduce") + return {"downloadStatus": STATUS_CODES.error} + finally: + progreso.close() logger.info("contentAction: %s | contentChannel: %s | server: %s | url: %s" % ( item.contentAction, item.contentChannel, item.server, item.url)) @@ -594,7 +720,7 @@ def download_from_server(item): if not item.video_urls: video_urls, puedes, motivo = servertools.resolve_video_urls_for_playing(item.server, item.url, item.password, - True) + True, True) else: video_urls, puedes, motivo = item.video_urls, True, "" @@ -628,31 +754,36 @@ def download_from_best_server(item): logger.info("contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url)) result = {"downloadStatus": STATUS_CODES.error} + progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70179)) - progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70179)) - if item.contentChannel == 'community': - channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) - else: - channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) + try: + if item.downloadItemlist: + logger.info('using cached servers') + play_items = [Item().fromurl(i) for i in item.downloadItemlist] + else: + if item.contentChannel in ['community', 'videolibrary']: + channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) + else: + channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) - progreso.update(50, config.get_localized_string(70184), config.get_localized_string(70180) % item.contentChannel) + progreso.update(50, config.get_localized_string(70184), config.get_localized_string(70180) % item.contentChannel) - if hasattr(channel, item.contentAction): - play_items = getattr(channel, item.contentAction)(item.clone(action=item.contentAction, channel=item.contentChannel)) - else: - play_items = servertools.find_video_items(item.clone(action=item.contentAction, channel=item.contentChannel)) + if hasattr(channel, item.contentAction): + play_items = getattr(channel, item.contentAction)(item.clone(action=item.contentAction, channel=item.contentChannel)) + else: + play_items = servertools.find_video_items(item.clone(action=item.contentAction, channel=item.contentChannel)) - play_items = [x for x in play_items if x.action == "play" and not "trailer" in x.title.lower()] + play_items = [x for x in play_items if x.action == "play" and not "trailer" in x.title.lower()] - progreso.update(100, config.get_localized_string(70183), config.get_localized_string(70181) % len(play_items), config.get_localized_string(70182)) + progreso.update(100, config.get_localized_string(70183), config.get_localized_string(70181) % len(play_items)) - # if config.get_setting("server_reorder", "downloads") == 1: - play_items.sort(key=sort_method) + # if config.get_setting("server_reorder", "downloads") == 1: + play_items.sort(key=sort_method) - if progreso.iscanceled(): - return {"downloadStatus": STATUS_CODES.canceled} - - progreso.close() + # if progreso.iscanceled(): + # return {"downloadStatus": STATUS_CODES.canceled} + finally: + progreso.close() # Recorremos el listado de servers, hasta encontrar uno que funcione for play_item in play_items: @@ -662,8 +793,8 @@ def download_from_best_server(item): result = download_from_server(play_item) - if progreso.iscanceled(): - result["downloadStatus"] = STATUS_CODES.canceled + # if progreso.iscanceled(): + # result["downloadStatus"] = STATUS_CODES.canceled # Tanto si se cancela la descarga como si se completa dejamos de probar mas opciones if result["downloadStatus"] in [STATUS_CODES.canceled, STATUS_CODES.completed]: @@ -674,92 +805,99 @@ def download_from_best_server(item): def select_server(item): + if item.server: + return "Auto" logger.info( "contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url)) + progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70179)) + try: + if item.downloadItemlist: + logger.info('using cached servers') + play_items = [Item().fromurl(i) for i in item.downloadItemlist] + else: + if item.contentChannel in ['community', 'videolibrary']: + channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) + else: + channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) + progreso.update(50, config.get_localized_string(70184), config.get_localized_string(70180) % item.contentChannel) - progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70179)) - if item.contentChannel == 'community': - channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) - else: - channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) - progreso.update(50, config.get_localized_string(70184), config.get_localized_string(70180) % item.contentChannel) + if hasattr(channel, item.contentAction): + play_items = getattr(channel, item.contentAction)( + item.clone(action=item.contentAction, channel=item.contentChannel)) + else: + play_items = servertools.find_video_items(item.clone(action=item.contentAction, channel=item.contentChannel)) - if hasattr(channel, item.contentAction): - play_items = getattr(channel, item.contentAction)( - item.clone(action=item.contentAction, channel=item.contentChannel)) - else: - play_items = servertools.find_video_items(item.clone(action=item.contentAction, channel=item.contentChannel)) - - play_items = [x for x in play_items if x.action == "play" and not "trailer" in x.title.lower()] - - progreso.update(100, config.get_localized_string(70183), config.get_localized_string(70181) % len(play_items), - config.get_localized_string(70182)) + play_items = [x for x in play_items if x.action == "play" and not "trailer" in x.title.lower()] + progreso.update(100, config.get_localized_string(70183), config.get_localized_string(70181) % len(play_items)) + finally: + progreso.close() for x, i in enumerate(play_items): if not i.server and hasattr(channel, "play"): play_items[x] = getattr(channel, "play")(i) seleccion = platformtools.dialog_select(config.get_localized_string(70192), ["Auto"] + [s.title for s in play_items]) - if seleccion > 1: + if seleccion >= 1: update_json(item.path, { "downloadServer": {"url": play_items[seleccion - 1].url, "server": play_items[seleccion - 1].server}}) + return play_items[seleccion - 1] elif seleccion == 0: update_json(item.path, {"downloadServer": {}}) - - platformtools.itemlist_refresh() + return 'Auto' + # platformtools.itemlist_refresh() def start_download(item): logger.info( "contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url)) - # Ya tenemnos server, solo falta descargar if item.contentAction == "play": ret = download_from_server(item) - update_json(item.path, ret) - return ret["downloadStatus"] - elif item.downloadServer and item.downloadServer.get("server"): ret = download_from_server( item.clone(server=item.downloadServer.get("server"), url=item.downloadServer.get("url"), contentAction="play")) - update_json(item.path, ret) - return ret["downloadStatus"] # No tenemos server, necesitamos buscar el mejor else: ret = download_from_best_server(item) + + if ret["downloadStatus"] == STATUS_CODES.completed and config.get_setting("library_move"): + filetools.remove(item.path) + else: update_json(item.path, ret) - return ret["downloadStatus"] + return ret["downloadStatus"] def get_episodes(item): - logger.info("contentAction: %s | contentChannel: %s | contentType: %s" % (item.contentAction, item.contentChannel, item.contentType)) + logger.info("contentAction: %s | contentChannel: %s | contentType: %s" % ( + item.contentAction, item.contentChannel, item.contentType)) if 'dlseason' in item: season = True season_number = item.dlseason else: season = False - # El item que pretendemos descargar YA es un episodio if item.contentType == "episode": episodes = [item.clone()] # El item es uma serie o temporada elif item.contentType in ["tvshow", "season"]: - # importamos el canal - if item.contentChannel == 'community': - channel = __import__('specials.%s' % item.contentChannel, None, None, ["specials.%s" % item.contentChannel]) + if item.downloadItemlist: + episodes = [Item().fromurl(i) for i in item.downloadItemlist] else: - channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel]) - # Obtenemos el listado de episodios - episodes = getattr(channel, item.contentAction)(item) + # importamos el canal + if item.contentChannel in ['community', 'videolibrary']: + channel = __import__('specials.%s' % item.contentChannel, None, None, ["specials.%s" % item.contentChannel]) + else: + channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel]) + # Obtenemos el listado de episodios + episodes = getattr(channel, item.contentAction)(item) itemlist = [] # Tenemos las lista, ahora vamos a comprobar for episode in episodes: - # from core.support import dbg;dbg() # Si partiamos de un item que ya era episodio estos datos ya están bien, no hay que modificarlos if item.contentType != "episode": episode.contentAction = episode.action @@ -793,7 +931,7 @@ def get_episodes(item): episode.downloadFilename = filetools.validate_path(filetools.join(item.downloadFilename, "%dx%0.2d - %s" % (episode.contentSeason, episode.contentEpisodeNumber, episode.contentTitle.strip()))) if season: - if scrapertools.find_single_match(episode.title, r'(\d+)x') == season_number: + if int(scrapertools.find_single_match(episode.title, r'(\d+)x')) == int(season_number): itemlist.append(episode) else: itemlist.append(episode) @@ -826,15 +964,25 @@ def write_json(item): if name in item.__dict__: item.__dict__.pop(name) - path = filetools.join(config.get_setting("downloadlistpath"), str(time.time()) + ".json") - filetools.write(path, item.tojson()) + path = filetools.join(DOWNLOAD_LIST_PATH, str(time.time()) + ".json") item.path = path + filetools.write(path, item.tojson()) time.sleep(0.1) def save_download(item): - logger.info() + show_disclaimer() + if item.channel != 'downloads': + item.from_channel = item.channel + item.from_action = item.action + item.channel = "downloads" + item.action = "save_download_background" + xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")") + + +def save_download_background(item): + logger.info() # Menu contextual if item.from_action and item.from_channel: item.channel = item.from_channel @@ -845,20 +993,47 @@ def save_download(item): item.contentChannel = item.from_channel if item.from_channel else item.channel item.contentAction = item.from_action if item.from_action else item.action - if item.contentType in ["tvshow", "episode", "season"]: - if ('download' in item and item.channel != 'community') or (item.channel == 'community' and config.get_setting('show_seasons',item.channel) == False): - heading = config.get_localized_string(70594) # <- Enter the season number - item.dlseason = platformtools.dialog_numeric(0, heading, '') - if item.dlseason: - save_download_tvshow(item) - else: - save_download_tvshow(item) + if item.channel == 'videolibrary': + from specials import videolibrary - elif item.contentType == "movie": - save_download_movie(item) + parent = Item().fromurl(item.parent) + parent.contentChannel = 'videolibrary' + if item.downloadItemlist: # episode + parent.downloadItemlist = item.downloadItemlist + elif item.unseen: # unseen episodes + parent.downloadItemlist = [i.tourl() for i in videolibrary.get_episodes(parent) if i.action == 'findvideos' and parent.library_playcounts[scrapertools.get_season_and_episode(i.title)] == 0] + else: # tvshow or season + parent.downloadItemlist = [i.tourl() for i in videolibrary.get_episodes(parent) if i.action == 'findvideos'] + if parent.contentType in ["tvshow", "episode", "season"]: + if not item.unseen and parent.contentSeason: # if no season, this is episode view, let's download entire serie + parent.dlseason = parent.contentSeason # this is season view, let's download season + save_download_tvshow(parent) + elif parent.contentType == "movie": + save_download_movie(parent) else: - save_download_video(item) + if item.contentType in ["tvshow", "episode", "season"]: + if ('download' in item and item.channel != 'community') or (item.channel == 'community' and config.get_setting('show_seasons',item.channel) == False): + heading = config.get_localized_string(70594) # <- Enter the season number + item.dlseason = platformtools.dialog_numeric(0, heading, '') + if item.dlseason: + save_download_tvshow(item) + else: + save_download_tvshow(item) + + elif item.contentType == "movie": + save_download_movie(item) + else: + save_download_video(item) + + +def save_download_videolibrary(item): + logger.info() + show_disclaimer() + item.contentChannel = 'videolibrary' + item.channel = "downloads" + item.action = "save_download_background" + xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")") def save_download_video(item): @@ -882,7 +1057,7 @@ def save_download_movie(item): logger.info("contentAction: %s | contentChannel: %s | contentTitle: %s" % ( item.contentAction, item.contentChannel, item.contentTitle)) - progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70191)) + progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70191)) set_movie_title(item) @@ -903,44 +1078,63 @@ def save_download_movie(item): platformtools.dialog_ok(config.get_localized_string(30101), item.contentTitle, config.get_localized_string(30109)) else: - start_download(item) + play_item = select_server(item) + if play_item == 'Auto': + start_download(item) + else: + play_item = item.clone(**play_item.__dict__) + play_item.contentAction = play_item.action + play_item.infoLabels = item.infoLabels + start_download(play_item) def save_download_tvshow(item): logger.info("contentAction: %s | contentChannel: %s | contentType: %s | contentSerieName: %s" % ( item.contentAction, item.contentChannel, item.contentType, item.contentSerieName)) - progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70188)) + progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70188)) + try: + item.show = item.fulltitle + scraper.find_and_set_infoLabels(item) + if not item.contentSerieName: item.contentSerieName = item.fulltitle - item.show = item.fulltitle - scraper.find_and_set_infoLabels(item) - if not item.contentSerieName: item.contentSerieName = item.fulltitle + item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentSerieName, item.infoLabels['IMDBNumber'])) + if config.get_setting("lowerize_title", "videolibrary"): + item.downloadFilename = item.downloadFilename.lower() + progreso.update(0, config.get_localized_string(70186), config.get_localized_string(70180) % item.contentChannel) - item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentSerieName, item.infoLabels['IMDBNumber'])) - if config.get_setting("lowerize_title", "videolibrary") == 0: - item.downloadFilename = item.downloadFilename.lower() - progreso.update(0, config.get_localized_string(70186), config.get_localized_string(70187) % item.contentChannel) + episodes = get_episodes(item) - episodes = get_episodes(item) + progreso.update(0, config.get_localized_string(70190), " ") - progreso.update(0, config.get_localized_string(70190), " ") - - for x, i in enumerate(episodes): - progreso.update(old_div(x * 100, len(episodes)), - "%dx%0.2d: %s" % (i.contentSeason, i.contentEpisodeNumber, i.contentTitle)) - write_json(i) - progreso.close() + for x, i in enumerate(episodes): + progreso.update(old_div(x * 100, len(episodes)), + "%dx%0.2d: %s" % (i.contentSeason, i.contentEpisodeNumber, i.contentTitle)) + write_json(i) + finally: + progreso.close() if not platformtools.dialog_yesno(config.get_localized_string(30101), config.get_localized_string(70189)): platformtools.dialog_ok(config.get_localized_string(30101), str(len(episodes)) + config.get_localized_string(30110) + item.contentSerieName, config.get_localized_string(30109)) else: - for i in episodes: - i.contentChannel = item.contentChannel - res = start_download(i) - if res == STATUS_CODES.canceled: - break + if len(episodes) == 1: + play_item = select_server(episodes[0]) + if play_item: # not pressed cancel + if play_item == 'Auto': + start_download(episodes[0]) + else: + play_item = episodes[0].clone(**play_item.__dict__) + play_item.contentAction = play_item.action + play_item.infoLabels = episodes[0].infoLabels + start_download(play_item) + else: + for i in episodes: + i.contentChannel = item.contentChannel + res = start_download(i) + if res == STATUS_CODES.canceled: + break def set_movie_title(item): @@ -949,3 +1143,10 @@ def set_movie_title(item): if not item.contentTitle: item.contentTitle = re.sub("\[[^\]]+\]|\([^\)]+\)", "", item.title).strip() + + +def show_disclaimer(): + line1 = config.get_localized_string(70690) + line2 = config.get_localized_string(70691) + line3 = config.get_localized_string(70692) + platformtools.dialog_ok(config.get_localized_string(20000), line1, line2, line3) diff --git a/specials/infoplus.py b/specials/infoplus.py index b62fa432..e5e6c93b 100644 --- a/specials/infoplus.py +++ b/specials/infoplus.py @@ -26,8 +26,8 @@ from core.scrapertools import decodeHtmlentities as dhe from platformcode import config, logger from platformcode import platformtools -addon = xbmcaddon.Addon('metadata.themoviedb.org') -def_lang = addon.getSetting('language') +info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json +def_lang = info_language[config.get_setting("info_language", "videolibrary")] global mainWindow mainWindow = list() diff --git a/specials/news.py b/specials/news.py index 1405f09e..63aad9dd 100644 --- a/specials/news.py +++ b/specials/news.py @@ -5,6 +5,9 @@ #from builtins import str import sys + +from core.support import typo + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int @@ -48,20 +51,20 @@ def mainlist(item): logger.info() itemlist = [] - list_canales, any_active = get_channels_list() + # list_canales, any_active = get_channels_list() channel_language = config.get_setting("channel_language", default="auto") if channel_language == 'auto': channel_language = auto_filter() #if list_canales['peliculas']: - thumbnail = get_thumb("channels_movie.png") + thumbnail = get_thumb("movie.png") new_item = Item(channel=item.channel, action="novedades", extra="peliculas", title=config.get_localized_string(30122), thumbnail=thumbnail) set_category_context(new_item) itemlist.append(new_item) - # thumbnail = get_thumb("channels_movie_4k.png") + # thumbnail = get_thumb("movie_4k.png") # new_item = Item(channel=item.channel, action="novedades", extra="4k", title=config.get_localized_string(70208), thumbnail=thumbnail) # # set_category_context(new_item) @@ -75,33 +78,33 @@ def mainlist(item): # itemlist.append(new_item) #if list_canales['infantiles']: - # thumbnail = get_thumb("channels_children.png") + # thumbnail = get_thumb("children.png") # new_item = Item(channel=item.channel, action="novedades", extra="infantiles", title=config.get_localized_string(60510), # thumbnail=thumbnail) # set_category_context(new_item) # itemlist.append(new_item) #if list_canales['series']: - thumbnail = get_thumb("channels_tvshow.png") + thumbnail = get_thumb("tvshow.png") new_item = Item(channel=item.channel, action="novedades", extra="series", title=config.get_localized_string(60511), thumbnail=thumbnail) set_category_context(new_item) itemlist.append(new_item) #if list_canales['anime']: - thumbnail = get_thumb("channels_anime.png") + thumbnail = get_thumb("anime.png") new_item = Item(channel=item.channel, action="novedades", extra="anime", title=config.get_localized_string(60512), thumbnail=thumbnail) set_category_context(new_item) itemlist.append(new_item) - if channel_language == "all": - # if list_canales['Italiano']: - thumbnail = get_thumb("channels_italian.png") - new_item = Item(channel=item.channel, action="novedades", extra="italiano", title=config.get_localized_string(70563), - thumbnail=thumbnail) - set_category_context(new_item) - itemlist.append(new_item) + # if channel_language == "all": + # # if list_canales['Italiano']: + # thumbnail = get_thumb("italian.png") + # new_item = Item(channel=item.channel, action="novedades", extra="italiano", title=config.get_localized_string(70563), + # thumbnail=thumbnail) + # set_category_context(new_item) + # itemlist.append(new_item) # if list_canales['Torrent']: # thumbnail = get_thumb("channels_torrent.png") @@ -110,11 +113,14 @@ def mainlist(item): # itemlist.append(new_item) #if list_canales['documentales']: - thumbnail = get_thumb("channels_documentary.png") + thumbnail = get_thumb("documentary.png") new_item = Item(channel=item.channel, action="novedades", extra="documentales", title=config.get_localized_string(60513), thumbnail=thumbnail) set_category_context(new_item) itemlist.append(new_item) + thumbnail = get_thumb("setting_0.png") + itemlist.append(Item(channel='shortcuts', action="SettingOnPosition", category=5, setting=0, + title=typo(config.get_localized_string(70285), 'bold color kod'), thumbnail=thumbnail)) return itemlist @@ -569,34 +575,34 @@ def menu_opciones(item): text_bold = True, thumbnail=get_thumb("setting_0.png"), folder=False)) itemlist.append(Item(channel=item.channel, action="setting_channel", extra="peliculas", title=config.get_localized_string(60526), - thumbnail=get_thumb("channels_movie.png"), + thumbnail=get_thumb("movie.png"), folder=False)) # itemlist.append(Item(channel=item.channel, action="setting_channel", extra="4K", title=config.get_localized_string(70207), - # thumbnail=get_thumb("channels_movie.png"), folder=False)) + # thumbnail=get_thumb("movie.png"), folder=False)) # itemlist.append(Item(channel=item.channel, action="setting_channel", extra="infantiles", title=config.get_localized_string(60527), - # thumbnail=get_thumb("channels_children.png"), + # thumbnail=get_thumb("children.png"), # folder=False)) itemlist.append(Item(channel=item.channel, action="setting_channel", extra="series", title=config.get_localized_string(60528), - thumbnail=get_thumb("channels_tvshow.png"), + thumbnail=get_thumb("tvshow.png"), folder=False)) itemlist.append(Item(channel=item.channel, action="setting_channel", extra="anime", title=config.get_localized_string(60529), - thumbnail=get_thumb("channels_anime.png"), + thumbnail=get_thumb("anime.png"), folder=False)) # itemlist.append( # Item(channel=item.channel, action="setting_channel", extra="castellano", title=config.get_localized_string(70212), - # thumbnail=get_thumb("channels_documentary.png"), folder=False)) + # thumbnail=get_thumb("documentary.png"), folder=False)) # itemlist.append(Item(channel=item.channel, action="setting_channel", extra="latino", title=config.get_localized_string(70213), - # thumbnail=get_thumb("channels_documentary.png"), folder=False)) + # thumbnail=get_thumb("documentary.png"), folder=False)) # itemlist.append(Item(channel=item.channel, action="setting_channel", extra="torrent", title=config.get_localized_string(70214), - # thumbnail=get_thumb("channels_documentary.png"), folder=False)) + # thumbnail=get_thumb("documentary.png"), folder=False)) itemlist.append(Item(channel=item.channel, action="setting_channel", extra="documentales", title=config.get_localized_string(60530), - thumbnail=get_thumb("channels_documentary.png"), + thumbnail=get_thumb("documentary.png"), folder=False)) itemlist.append(Item(channel=item.channel, action="settings", title=config.get_localized_string(60531), thumbnail=get_thumb("setting_0.png"), diff --git a/specials/quasar_download.py b/specials/quasar_download.py new file mode 100644 index 00000000..a2e5c884 --- /dev/null +++ b/specials/quasar_download.py @@ -0,0 +1,100 @@ + +from core import filetools, downloadtools, support +from platformcode import config, platformtools, updater +from time import sleep + +import xbmc, xbmcaddon, os, sys, platform + +host = 'https://github.com' +quasar_url = host + '/scakemyer/plugin.video.quasar/releases' +filename = filetools.join(config.get_data_path(),'quasar.zip') +addon_path = xbmc.translatePath("special://home/addons/") +quasar_path = filetools.join(addon_path,'plugin.video.quasar') + + +def download(item=None): + if filetools.exists(quasar_path): + xbmc.executeJSONRPC('{"jsonrpc": "2.0", "id":1, "method": "Addons.SetAddonEnabled", "params": { "addonid": "plugin.video.quasar", "enabled": false }}') + sleep(1) + filetools.rmdirtree(quasar_path) + + if filetools.exists(filename): + filetools.remove(filename) + return download() + else: + platform = get_platform() + support.log('OS:', platform) + support.log('Extract IN:', quasar_path) + url = support.match(quasar_url, patronBlock=r'<div class="release-entry">(.*?)<!-- /.release-body -->', patron=r'<a href="([a-zA-Z0-9/\.-]+%s.zip)' % platform).match + support.log('URL:', url) + if url: + downloadtools.downloadfile(host + url, filename) + extract() + +def extract(): + import zipfile + support.log('Estraggo Quasar in:', quasar_path) + with zipfile.ZipFile(filename, 'r') as zip_ref: + zip_ref.extractall(xbmc.translatePath("special://home/addons/")) + + xbmc.executebuiltin('UpdateLocalAddons') + if platformtools.dialog_ok('Quasar', config.get_localized_string(70783)): + if filetools.exists(filename): + filetools.remove(filename) + xbmc.executeJSONRPC('{"jsonrpc": "2.0", "id":1, "method": "Addons.SetAddonEnabled", "params": { "addonid": "plugin.video.quasar", "enabled": true }}') + updater.refreshLang() + xbmcaddon.Addon(id="plugin.video.quasar").setSetting('download_path', config.get_setting('downloadpath')) + xbmc.executebuiltin('UpdateLocalAddons') + sleep(2) + + +def get_platform(): + build = xbmc.getInfoLabel("System.BuildVersion") + kodi_version = int(build.split()[0][:2]) + ret = { + "auto_arch": sys.maxsize > 2 ** 32 and "64-bit" or "32-bit", + "arch": sys.maxsize > 2 ** 32 and "x64" or "x86", + "os": "", + "version": platform.release(), + "kodi": kodi_version, + "build": build + } + if xbmc.getCondVisibility("system.platform.android"): + ret["os"] = "android" + if "arm" in platform.machine() or "aarch" in platform.machine(): + ret["arch"] = "arm" + if "64" in platform.machine() and ret["auto_arch"] == "64-bit": + ret["arch"] = "arm" + #ret["arch"] = "x64" #The binary is corrupted in install package + elif xbmc.getCondVisibility("system.platform.linux"): + ret["os"] = "linux" + if "aarch" in platform.machine() or "arm64" in platform.machine(): + if xbmc.getCondVisibility("system.platform.linux.raspberrypi"): + ret["arch"] = "armv7" + elif ret["auto_arch"] == "32-bit": + ret["arch"] = "armv7" + elif ret["auto_arch"] == "64-bit": + ret["arch"] = "arm64" + elif platform.architecture()[0].startswith("32"): + ret["arch"] = "arm" + else: + ret["arch"] = "arm64" + elif "armv7" in platform.machine(): + ret["arch"] = "armv7" + elif "arm" in platform.machine(): + ret["arch"] = "arm" + elif xbmc.getCondVisibility("system.platform.xbox"): + ret["os"] = "windows" + ret["arch"] = "x64" + elif xbmc.getCondVisibility("system.platform.windows"): + ret["os"] = "windows" + if platform.machine().endswith('64'): + ret["arch"] = "x64" + elif xbmc.getCondVisibility("system.platform.osx"): + ret["os"] = "darwin" + ret["arch"] = "x64" + elif xbmc.getCondVisibility("system.platform.ios"): + ret["os"] = "ios" + ret["arch"] = "arm" + + return ret['os'] + '_' + ret['arch'] \ No newline at end of file diff --git a/specials/search.py b/specials/search.py index f181c59e..0f9a761f 100644 --- a/specials/search.py +++ b/specials/search.py @@ -26,9 +26,8 @@ from core.support import typo import gc gc.disable() -import xbmcaddon -addon = xbmcaddon.Addon('metadata.themoviedb.org') -def_lang = addon.getSetting('language') +info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json +def_lang = info_language[config.get_setting("info_language", "videolibrary")] def mainlist(item): logger.info() @@ -47,7 +46,7 @@ def mainlist(item): Item(channel=item.channel, title=typo(config.get_localized_string(59994), 'color kod bold'), action='opciones', thumbnail=get_thumb('setting_0.png')), - Item(channel='shortcuts', title=typo(config.get_localized_string(30100), 'color kod bold'), action='SettingOnPosition', category=3, thumbnail=get_thumb('setting_0.png'))] + Item(channel='shortcuts', title=typo(config.get_localized_string(70286), 'color kod bold'), action='SettingOnPosition', category=3, thumbnail=get_thumb('setting_0.png'))] itemlist = set_context(itemlist) @@ -57,25 +56,25 @@ def mainlist(item): def sub_menu(item): logger.info() - itemlist = [Item(channel=item.channel, action='genres_menu', title=config.get_localized_string(70306), mode='movie', thumbnail=get_thumb("channels_movie_genre.png")), + itemlist = [Item(channel=item.channel, action='genres_menu', title=config.get_localized_string(70306), mode='movie', thumbnail=get_thumb("movie_genre.png")), - Item(channel=item.channel, action='years_menu', title=config.get_localized_string(70742), mode='movie', thumbnail=get_thumb("channels_movie_year.png")), + Item(channel=item.channel, action='years_menu', title=config.get_localized_string(70742), mode='movie', thumbnail=get_thumb("movie_year.png")), - Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70307), search_type='list', list_type='movie/popular', mode='movie', thumbnail=get_thumb("channels_movie_popular.png")), + Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70307), search_type='list', list_type='movie/popular', mode='movie', thumbnail=get_thumb("movie_popular.png")), - Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70308), search_type='list', list_type='movie/top_rated', mode='movie', thumbnail=get_thumb("channels_movie_top.png")), + Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70308), search_type='list', list_type='movie/top_rated', mode='movie', thumbnail=get_thumb("movie_top.png")), - Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70309), search_type='list', list_type='movie/now_playing', mode='movie', thumbnail=get_thumb("channels_movie_now_playing.png")), + Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70309), search_type='list', list_type='movie/now_playing', mode='movie', thumbnail=get_thumb("movie_now_playing.png")), - Item(channel=item.channel, action='genres_menu', title=config.get_localized_string(70310), mode='tvshow', thumbnail=get_thumb("channels_tvshow_genre.png")), + Item(channel=item.channel, action='genres_menu', title=config.get_localized_string(70310), mode='tvshow', thumbnail=get_thumb("tvshow_genre.png")), - Item(channel=item.channel, action='years_menu', title=config.get_localized_string(70743), mode='tvshow', thumbnail=get_thumb("channels_tvshow_year.png")), + Item(channel=item.channel, action='years_menu', title=config.get_localized_string(70743), mode='tvshow', thumbnail=get_thumb("tvshow_year.png")), Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70311), search_type='list', list_type='tv/popular', mode='tvshow', thumbnail=get_thumb("popular.png")), - Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70312), search_type='list', list_type='tv/on_the_air', mode='tvshow', thumbnail=get_thumb("channels_tvshow_on_the_air.png")), + Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70312), search_type='list', list_type='tv/on_the_air', mode='tvshow', thumbnail=get_thumb("tvshow_on_the_air.png")), - Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70313), search_type='list', list_type='tv/top_rated', mode='tvshow', thumbnail=get_thumb("channels_tvshow_top.png")), + Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70313), search_type='list', list_type='tv/top_rated', mode='tvshow', thumbnail=get_thumb("tvshow_top.png")), Item(channel="tvmoviedb", action="mainlist", title=config.get_localized_string(70274), thumbnail=get_thumb("search.png"))] @@ -513,11 +512,11 @@ def years_menu(item): mode = item.mode.replace('show', '') par_year = 'primary_release_year' - thumb = channelselector.get_thumb('channels_movie_year.png') + thumb = channelselector.get_thumb('movie_year.png') if mode != 'movie': par_year = 'first_air_date_year' - thumb = channelselector.get_thumb('channels_tvshow_year.png') + thumb = channelselector.get_thumb('tvshow_year.png') c_year = datetime.datetime.now().year + 1 l_year = c_year - 31 diff --git a/specials/setting.py b/specials/setting.py index 782b582f..ed947e7f 100644 --- a/specials/setting.py +++ b/specials/setting.py @@ -100,9 +100,11 @@ def channel_config(item): def autostart(item): # item necessario launcher.py linea 265 if config.enable_disable_autorun(AUTOSTART): - xbmcgui.Dialog().ok(config.get_localized_string(20000), config.get_localized_string(70709)) + logger.info('AUTOSTART ENABLED') + # xbmcgui.Dialog().ok(config.get_localized_string(20000), config.get_localized_string(70709)) else: - xbmcgui.Dialog().ok(config.get_localized_string(20000), config.get_localized_string(70710)) + logger.info('AUTOSTART ENABLED') + # xbmcgui.Dialog().ok(config.get_localized_string(20000), config.get_localized_string(70710)) def setting_torrent(item): @@ -445,7 +447,7 @@ def submenu_tools(item): thumbnail=get_thumb("setting_0.png"))) itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60566) + ":", action="", folder=False, text_bold=True, thumbnail=get_thumb("videolibrary.png"))) - itemlist.append(Item(channel=CHANNELNAME, action="overwrite_tools", folder=False, + itemlist.append(Item(channel=CHANNELNAME, action="restore_tools", folder=False, thumbnail=get_thumb("videolibrary.png"), title="- " + config.get_localized_string(60567))) itemlist.append(Item(channel="videolibrary", action="update_videolibrary", folder=False, @@ -795,8 +797,8 @@ def channel_status(item, dict_values): platformtools.dialog_notification(config.get_localized_string(60579), config.get_localized_string(60580)) -def overwrite_tools(item): - import videolibrary_service +def restore_tools(item): + import service from core import videolibrarytools import os @@ -830,7 +832,7 @@ def overwrite_tools(item): # filetools.rmdirtree(path) # ... y la volvemos a añadir - videolibrary_service.update(path, p_dialog, i, t, serie, 3) + service.update(path, p_dialog, i, t, serie, 3) p_dialog.close() # movies @@ -857,9 +859,9 @@ def overwrite_tools(item): filetools.rmdirtree(path) import math - heading = config.get_localized_string(60587) + heading = config.get_localized_string(20000) - p_dialog2.update(int(math.ceil((i + 1) * t)), heading, "%s: %s" % (movie.contentTitle, + p_dialog2.update(int(math.ceil((i + 1) * t)), heading, config.get_localized_string(60389) % (movie.contentTitle, movie.channel.capitalize())) # ... y la volvemos a añadir videolibrarytools.save_movie(movie) diff --git a/specials/shortcuts.py b/specials/shortcuts.py index d48064ad..b43b6478 100644 --- a/specials/shortcuts.py +++ b/specials/shortcuts.py @@ -1,29 +1,64 @@ # -*- coding: utf-8 -*- - +from core.item import Item from platformcode import logger def context(): from platformcode import config context = [] + # original + # if config.get_setting('quick_menu'): context.append((config.get_localized_string(60360).upper(), "XBMC.RunPlugin(plugin://plugin.video.kod/?%s)" % Item(channel='shortcuts', action="shortcut_menu").tourl())) + # if config.get_setting('side_menu'): context.append((config.get_localized_string(70737).upper(), "XBMC.RunPlugin(plugin://plugin.video.kod/?%s)" % Item(channel='shortcuts',action="side_menu").tourl())) + # if config.get_setting('kod_menu'): context.append((config.get_localized_string(30025), "XBMC.RunPlugin(plugin://plugin.video.kod/?%s)" % Item(channel='shortcuts', action="settings_menu").tourl())) - if config.get_setting('quick_menu'): context += [{ 'title': config.get_localized_string(60360).upper(), 'channel': 'shortcuts', 'action': "shortcut_menu"}] - if config.get_setting('side_menu'): context += [{ 'title': config.get_localized_string(70737).upper(), 'channel': 'shortcuts', 'action': "side_menu"}] - if config.get_setting('kod_menu'): context += [{ 'title': config.get_localized_string(30025), 'channel': 'shortcuts', 'action': "settings_menu"}] + # pre-serialised + if config.get_setting('quick_menu'): context.append((config.get_localized_string(60360).upper(), 'XBMC.RunPlugin(plugin://plugin.video.kod/?ewogICAgImFjdGlvbiI6ICJzaG9ydGN1dF9tZW51IiwgCiAgICAiY2hhbm5lbCI6ICJzaG9ydGN1dHMiLCAKICAgICJpbmZvTGFiZWxzIjoge30KfQ%3D%3D)')) + if config.get_setting('side_menu'): context.append((config.get_localized_string(70737).upper(), 'XBMC.RunPlugin(plugin://plugin.video.kod/?ewogICAgImFjdGlvbiI6ICJzaWRlX21lbnUiLCAKICAgICJjaGFubmVsIjogInNob3J0Y3V0cyIsIAogICAgImluZm9MYWJlbHMiOiB7fQp9)')) + if config.get_setting('kod_menu'): context.append((config.get_localized_string(30025), 'XBMC.RunPlugin(plugin://plugin.video.kod/?ewogICAgImFjdGlvbiI6ICJzZXR0aW5nc19tZW51IiwgCiAgICAiY2hhbm5lbCI6ICJzaG9ydGN1dHMiLCAKICAgICJpbmZvTGFiZWxzIjoge30KfQ%3D%3D)')) return context def side_menu(item): - from specials import side_menu - side_menu.open_menu(item) + from specials import side_menu + side_menu.open_menu(item) def shortcut_menu(item): - from platformcode import keymaptools - keymaptools.open_shortcut_menu() + from platformcode import keymaptools + keymaptools.open_shortcut_menu() def settings_menu(item): from platformcode import config config.open_settings() +def view_mode(item): + logger.info(str(item)) + import xbmc + from core import filetools, jsontools + from core.support import typo + from platformcode import config, platformtools + + skin_name = xbmc.getSkinDir() + config.set_setting('skin_name', skin_name) + + path = filetools.join(config.get_runtime_path(), 'resources', 'views', skin_name + '.json') + if filetools.isfile(path): + json_file = open(path, "r").read() + json = jsontools.load(json_file) + + Type = 'addon'if item.type in ['channel', 'server'] else item.type + skin = json[Type] + + list_type = [] + for key in skin: + list_type.append(key) + list_type.sort() + list_type.insert(0, config.get_localized_string(70003)) + + select = platformtools.dialog_select(config.get_localized_string(70754), list_type) + value = list_type[select] + ' , ' + str(skin[list_type[select]] if list_type[select] in skin else 0) + config.set_setting('view_mode_%s' % item.type, value) + else: + platformtools.dialog_ok(config.get_localized_string(30141), config.get_localized_string(30142) % typo(skin_name.replace('skin.','').replace('.',' '), 'capitalize bold')) + def servers_menu(item): # from core.support import dbg; dbg() from core import servertools diff --git a/specials/side_menu.py b/specials/side_menu.py index 6fc5c735..b0da3e4d 100644 --- a/specials/side_menu.py +++ b/specials/side_menu.py @@ -22,8 +22,8 @@ else: menu_node = {'categoria actual':config.get_setting('category')} jsontools.update_node(menu_node, 'menu_settings_data.json', "menu") -addon = xbmcaddon.Addon('metadata.themoviedb.org') -def_lang = addon.getSetting('language') +info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json +def_lang = info_language[config.get_setting("info_language", "videolibrary")] ACTION_SHOW_FULLSCREEN = 36 ACTION_GESTURE_SWIPE_LEFT = 511 diff --git a/specials/trailertools.py b/specials/trailertools.py index 126936ae..683ae7ca 100644 --- a/specials/trailertools.py +++ b/specials/trailertools.py @@ -32,8 +32,8 @@ from core.item import Item from platformcode import config, logger from platformcode import platformtools -addon = xbmcaddon.Addon('metadata.themoviedb.org') -def_lang = addon.getSetting('language') +info_language = ["it", "en", "es", "fr", "de", "pt"] # from videolibrary.json +def_lang = info_language[config.get_setting("info_language", "videolibrary")] result = None window_select = [] @@ -63,7 +63,9 @@ def buscartrailer(item, trailers=[]): item.text_color = "" itemlist = [] - if item.contentTitle != "": + if item.search_title: + item.contentTitle = item.search_title + elif item.contentTitle != "": item.contentTitle = item.contentTitle.strip() elif keyboard: contentTitle = re.sub('\[\/*(B|I|COLOR)\s*[^\]]*\]', '', item.contentTitle.strip()) @@ -104,22 +106,18 @@ def buscartrailer(item, trailers=[]): logger.error(traceback.format_exc()) if item.contextual: - title = "[COLOR green]%s[/COLOR]" + title = "%s" else: title = "%s" - itemlist.append(item.clone(title=title % config.get_localized_string(70507), action="youtube_search", - text_color="green")) - itemlist.append(item.clone(title=title % config.get_localized_string(70024), - action="filmaffinity_search", text_color="green")) + itemlist.append(item.clone(title=title % config.get_localized_string(70507), action="youtube_search")) + itemlist.append(item.clone(title=title % config.get_localized_string(70024), action="filmaffinity_search")) # Si se trata de una serie, no se incluye la opción de buscar en Abandomoviez if not item.show and not item.infoLabels['tvshowtitle']: - itemlist.append(item.clone(title=title % config.get_localized_string(70508), - action="abandomoviez_search", text_color="green")) + itemlist.append(item.clone(title=title % config.get_localized_string(70508), action="abandomoviez_search")) if item.contextual: global window_select, result - select = Select("DialogSelect.xml", config.get_runtime_path(), item=item, itemlist=itemlist, - caption=config.get_localized_string(70506) + item.contentTitle) + select = Select("DialogSelect.xml", config.get_runtime_path(), item=item, itemlist=itemlist, caption=config.get_localized_string(70506) + item.contentTitle) window_select.append(select) select.doModal() @@ -155,7 +153,7 @@ def tmdb_trailers(item, tipo="movie"): if tmdb_search: for result in tmdb_search.get_videos(): title = result['name'] + " [" + result['size'] + "p] (" + result['language'].replace("en", "ING") \ - .replace("es", "ESP") + ") [tmdb/youtube]" + .replace("it", "ITA") + ") [tmdb/youtube]" itemlist.append(item.clone(action="play", title=title, url=result['url'], server="youtube")) return itemlist @@ -183,10 +181,10 @@ def youtube_search(item): scrapedtitle = scrapedtitle.decode('utf8').encode('utf8') scrapedtitle = scrapedtitle + " (" + scrapedduration + ")" if item.contextual: - scrapedtitle = "[COLOR white]%s[/COLOR]" % scrapedtitle + scrapedtitle = "%s" % scrapedtitle url = urlparse.urljoin('https://www.youtube.com/', scrapedurl) itemlist.append(item.clone(title=scrapedtitle, action="play", server="youtube", url=url, - thumbnail=scrapedthumbnail, text_color="white")) + thumbnail=scrapedthumbnail)) next_page = scrapertools.find_single_match(data, '<a href="([^"]+)"[^>]+><span class="yt-uix-button-content">' 'Siguiente') if next_page != "": @@ -198,11 +196,11 @@ def youtube_search(item): action="", thumbnail="", text_color="")) if keyboard: if item.contextual: - title = "[COLOR green]%s[/COLOR]" + title = "%s" else: title = "%s" itemlist.append(item.clone(title=title % config.get_localized_string(70510), action="manual_search", - text_color="green", thumbnail="", extra="youtube")) + thumbnail="", extra="youtube")) return itemlist @@ -238,7 +236,7 @@ def abandomoviez_search(item): scrapedurl = urlparse.urljoin("http://www.abandomoviez.net/%s" % item.prefix, scrapedurl) scrapedtitle = scrapertools.htmlclean(scrapedtitle) itemlist.append(item.clone(title=scrapedtitle, action="search_links_abando", - url=scrapedurl, thumbnail=scrapedthumbnail, text_color="white")) + url=scrapedurl, thumbnail=scrapedthumbnail)) next_page = scrapertools.find_single_match(data, '<a href="([^"]+)">Siguiente') if next_page != "": @@ -252,11 +250,11 @@ def abandomoviez_search(item): if keyboard: if item.contextual: - title = "[COLOR green]%s[/COLOR]" + title = "%s" else: title = "%s" itemlist.append(item.clone(title=title % config.get_localized_string(70511), - action="manual_search", thumbnail="", text_color="green", extra="abandomoviez")) + action="manual_search", thumbnail="", extra="abandomoviez")) return itemlist @@ -283,7 +281,7 @@ def search_links_abando(item): code = scrapertools.find_single_match(trailer_url, 'v=([A-z0-9\-_]+)') thumbnail = "https://img.youtube.com/vi/%s/0.jpg" % code itemlist.append(item.clone(title="Trailer [youtube]", url=trailer_url, server="youtube", - thumbnail=thumbnail, action="play", text_color="white")) + thumbnail=thumbnail, action="play")) else: for scrapedurl, language, scrapedtitle in matches: if language == "1": @@ -296,23 +294,23 @@ def search_links_abando(item): i += 1 message += ".." progreso.update(10 + (old_div(90 * i, len(matches))), message) - scrapedtitle = "[COLOR white]%s[/COLOR]" % scrapedtitle + scrapedtitle = "%s" % scrapedtitle data_trailer = httptools.downloadpage(scrapedurl).data trailer_url = scrapertools.find_single_match(data_trailer, 'iframe.*?src="([^"]+)"') trailer_url = trailer_url.replace("embed/", "watch?v=") code = scrapertools.find_single_match(trailer_url, 'v=([A-z0-9\-_]+)') thumbnail = "https://img.youtube.com/vi/%s/0.jpg" % code itemlist.append(item.clone(title=scrapedtitle, url=trailer_url, server="youtube", action="play", - thumbnail=thumbnail, text_color="white")) + thumbnail=thumbnail)) if item.contextual: progreso.close() if keyboard: if item.contextual: - title = "[COLOR green]%s[/COLOR]" + title = "%s" else: title = "%s" itemlist.append(item.clone(title=title % config.get_localized_string(70511), - action="manual_search", thumbnail="", text_color="green", extra="abandomoviez")) + action="manual_search", thumbnail="", extra="abandomoviez")) return itemlist @@ -351,7 +349,7 @@ def filmaffinity_search(item): if PY3: scrapedtitle = unicode(scrapedtitle, encoding="utf-8", errors="ignore") scrapedtitle = scrapertools.htmlclean(scrapedtitle) - itemlist.append(item.clone(title=scrapedtitle, url=scrapedurl, text_color="white", + itemlist.append(item.clone(title=scrapedtitle, url=scrapedurl, action="search_links_filmaff", thumbnail=scrapedthumbnail)) next_page = scrapertools.find_single_match(data, '<a href="([^"]+)">>></a>') @@ -366,11 +364,11 @@ def filmaffinity_search(item): if keyboard: if item.contextual: - title = "[COLOR green]%s[/COLOR]" + title = "%s" else: title = "%s" itemlist.append(item.clone(title=title % config.get_localized_string(70513), - action="manual_search", text_color="green", thumbnail="", extra="filmaffinity")) + action="manual_search", thumbnail="", extra="filmaffinity")) return itemlist @@ -401,18 +399,18 @@ def search_links_filmaff(item): scrapedtitle = scrapertools.htmlclean(scrapedtitle) scrapedtitle += " [" + server + "]" if item.contextual: - scrapedtitle = "[COLOR white]%s[/COLOR]" % scrapedtitle + scrapedtitle = "%s" % scrapedtitle itemlist.append(item.clone(title=scrapedtitle, url=trailer_url, server=server, action="play", - thumbnail=thumbnail, text_color="white")) + thumbnail=thumbnail)) itemlist = servertools.get_servers_itemlist(itemlist) if keyboard: if item.contextual: - title = "[COLOR green]%s[/COLOR]" + title = "%s" else: title = "%s" itemlist.append(item.clone(title=title % config.get_localized_string(70513), - action="manual_search", thumbnail="", text_color="green", extra="filmaffinity")) + action="manual_search", thumbnail="", extra="filmaffinity")) return itemlist @@ -441,7 +439,7 @@ try: self.getControl(99).setVisible(False) except: pass - self.getControl(1).setLabel("[COLOR orange]" + self.caption + "[/COLOR]") + self.getControl(1).setLabel("" + self.caption + "") self.getControl(5).setLabel(config.get_localized_string(60495)) self.items = [] for item in self.itemlist: diff --git a/specials/tvmoviedb.py b/specials/tvmoviedb.py index d2941e5b..dc6263b2 100644 --- a/specials/tvmoviedb.py +++ b/specials/tvmoviedb.py @@ -18,8 +18,8 @@ from core import trakt_tools from platformcode import config, logger from platformcode import platformtools -addon = xbmcaddon.Addon('metadata.themoviedb.org') -def_lang = addon.getSetting('language') +info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json +def_lang = info_language[config.get_setting("info_language", "videolibrary")] langs = ['auto', 'de', 'fr', 'pt', 'it', 'es-MX', 'ca', 'en', 'es'] langt = langs[config.get_setting('tmdb', "tvmoviedb")] @@ -1892,7 +1892,7 @@ def newlist(item): # Creación de nueva lista en filmaffinity itemlist = [] if item.accion == "lista": - location = httptools.downloadpage(item.url).headers["location"] + location = httptools.downloadpage(item.url, only_headers=True).headers["location"] data = httptools.downloadpage("http://m.filmaffinity.com" + location).data itemlist.append(item.clone(action="", title=config.get_localized_string(70338))) else: diff --git a/specials/url.py b/specials/url.py index 44e73162..1fdd9db3 100644 --- a/specials/url.py +++ b/specials/url.py @@ -27,10 +27,8 @@ def search(item, text): itemlist = [] if "server" in item.args: - itemlist = servertools.find_video_items(data=text) - for item in itemlist: - item.channel = "url" - item.action = "play" + from core.support import server + itemlist = server(item, text) elif "direct" in item.args: itemlist.append(Item(channel=item.channel, action="play", url=text, server="directo", title=config.get_localized_string(60092))) else: diff --git a/specials/videolibrary.json b/specials/videolibrary.json index e0b476c5..89e04bc2 100644 --- a/specials/videolibrary.json +++ b/specials/videolibrary.json @@ -5,6 +5,57 @@ "adult": false, "language": ["*"], "settings": [ + { + "id": "lab_1", + "type": "label", + "label": "@60650", + "enabled": true, + "visible": true + }, + { + "id": "scraper_movies", + "type": "list", + "label": "@60651", + "enabled": false, + "default": 0, + "lvalues": [ + "TMDB", + "None" + ] + }, + { + "id": "scraper_tvshows", + "type": "list", + "label": "@60652", + "default": 0, + "lvalues": [ + "TMDB", + "TVDB" + ] + }, + { + "id": "tvdb_retry_eng", + "type": "bool", + "label": "@60653", + "default": true, + "enabled": "eq(-1,TVDB)", + "visible": true + }, + { + "id": "info_language", + "type": "list", + "label": "@60662", + "enabled": true, + "default": 4, + "lvalues": [ + "de", + "en", + "es", + "fr", + "it", + "pt" + ] + }, { "id": "update", "type": "list", @@ -72,29 +123,6 @@ "@60620" ] }, - { - "id": "addition", - "type": "label", - "label": "@70092", - "enabled": true, - "visible": true - }, - { - "id": "enable_filter", - "type": "bool", - "label": "@70090", - "enabled": true, - "visible": true, - "default": false - }, - { - "id": "filters", - "type": "text", - "label": "@70091", - "visible": true, - "enabled": "eq(-1,true)" - }, - { "id": "window_type", "type": "list", @@ -145,34 +173,30 @@ "id": "replace_VD", "type": "bool", "label": "@60628", - "enabled": true, + "enabled": "eq(-4,@60623)", "visible": true, "default": false }, { "id": "db_mode", - "type": "list", + "type": "bool", "label": "@60629", - "default": 0, + "default": false, "enabled": true, - "visible": true, - "lvalues": [ - "@60630", - "@60631" - ] + "visible": true }, { "id": "xbmc_host", "type": "text", "label": "@60632", "visible": true, - "enabled": "eq(-1,Remota)" + "enabled": "eq(-1,true)" }, { "id": "xbmc_puerto", "type": "text", "label": "@60633", - "enabled": "!eq(-1,'')", + "enabled": "eq(-2,true)", "visible": true }, { @@ -262,59 +286,15 @@ }, { "id": "original_title_folder", - "type": "list", + "type": "bool", "label": "@60646", - "default": 0, - "lvalues": [ - "@60647", - "@60649" - ] + "default": false }, { "id": "lowerize_title", - "type": "list", - "label": "@70703", - "default": 0, - "lvalues": [ - "Si", - "No" - ] - }, - { - "id": "lab_1", - "type": "label", - "label": "@60650", - "enabled": true, - "visible": true - }, - { - "id": "scraper_movies", - "type": "list", - "label": "@60651", - "enabled": false, - "default": 0, - "lvalues": [ - "TheMovieDB.org", - "None" - ] - }, - { - "id": "scraper_tvshows", - "type": "list", - "label": "@60652", - "default": 0, - "lvalues": [ - "TheMovieDB.org", - "TheTvDB.com" - ] - }, - { - "id": "tvdb_retry_eng", "type": "bool", - "label": "@60653", - "default": true, - "enabled": "eq(-1,TheTvDB.com)", - "visible": true + "label": "@70703", + "default": false }, { "id": "verify_playcount", diff --git a/specials/videolibrary.py b/specials/videolibrary.py index 8760d4b2..f121d7ea 100644 --- a/specials/videolibrary.py +++ b/specials/videolibrary.py @@ -2,12 +2,15 @@ #from builtins import str import sys + +from core.support import typo + PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int -import os, traceback +import xbmc, os, traceback -from channelselector import get_thumb +from channelselector import get_thumb, thumb from core import filetools from core import scrapertools from core import videolibrarytools @@ -15,6 +18,7 @@ from core.item import Item from platformcode import config, logger from platformcode import platformtools from lib import generictools +from distutils import dir_util def mainlist(item): @@ -27,6 +31,9 @@ def mainlist(item): itemlist.append(Item(channel=item.channel, action="list_tvshows", title=config.get_localized_string(60600), category=config.get_localized_string(70271), thumbnail=get_thumb("videolibrary_tvshow.png"))) + itemlist.append(Item(channel='shortcuts', action="SettingOnPosition", + category=2, setting=0, title=typo(config.get_localized_string(70287),'bold color kod'), + thumbnail = get_thumb("setting_0.png"))) return itemlist @@ -43,10 +50,17 @@ def list_movies(item, silent=False): dead_list = [] zombie_list = [] for raiz, subcarpetas, ficheros in filetools.walk(videolibrarytools.MOVIES_PATH): - for f in ficheros: - if f.endswith(".nfo"): - nfo_path = filetools.join(raiz, f) + for s in subcarpetas: + nfo_path = filetools.join(raiz, s, s + ".nfo") + logger.debug(nfo_path) + local_movie = False + for f in filetools.listdir(filetools.join(raiz, s)): + if f.split('.')[-1] not in ['nfo','json','strm']: + local_movie = True + break + + if filetools.exists(nfo_path): #Sincronizamos las películas vistas desde la videoteca de Kodi con la de Alfa try: if config.is_xbmc(): #Si es Kodi, lo hacemos @@ -54,13 +68,13 @@ def list_movies(item, silent=False): xbmc_videolibrary.mark_content_as_watched_on_alfa(nfo_path) except: logger.error(traceback.format_exc()) - + head_nfo, new_item = videolibrarytools.read_nfo(nfo_path) if not new_item: #Si no ha leído bien el .nfo, pasamos a la siguiente logger.error('.nfo erroneo en ' + str(nfo_path)) continue - + if len(new_item.library_urls) > 1: multicanal = True else: @@ -72,7 +86,7 @@ def list_movies(item, silent=False): for canal_org in new_item.library_urls: canal = generictools.verify_channel(canal_org) try: - if canal == 'community': + if canal in ['community', 'downloads']: channel_verify = __import__('specials.%s' % canal, fromlist=["channels.%s" % canal]) else: channel_verify = __import__('channels.%s' % canal, fromlist=["channels.%s" % canal]) @@ -81,7 +95,7 @@ def list_movies(item, silent=False): dead_item = Item(multicanal=multicanal, contentType='movie', dead=canal, - path=raiz, + path=filetools.join(raiz, s), nfo=nfo_path, library_urls=new_item.library_urls, infoLabels={'title': new_item.contentTitle}) @@ -111,14 +125,15 @@ def list_movies(item, silent=False): new_item.nfo = nfo_path - new_item.path = raiz + new_item.path = filetools.join(raiz, s) new_item.thumbnail = new_item.contentThumbnail + new_item.extra = filetools.join(config.get_setting("videolibrarypath"), config.get_setting("folder_movies"), s) # new_item.text_color = "blue" strm_path = new_item.strm_path.replace("\\", "/").rstrip("/") if '/' in new_item.path: new_item.strm_path = strm_path - - if not filetools.exists(filetools.join(new_item.path, filetools.basename(strm_path))): + logger.info('EXIST'+ str(local_movie)) + if not filetools.exists(filetools.join(new_item.path, filetools.basename(strm_path))) and local_movie == False: # Si se ha eliminado el strm desde la bilbioteca de kodi, no mostrarlo continue @@ -168,12 +183,11 @@ def list_tvshows(item): zombie_list = [] # Obtenemos todos los tvshow.nfo de la videoteca de SERIES recursivamente for raiz, subcarpetas, ficheros in filetools.walk(videolibrarytools.TVSHOWS_PATH): - for f in ficheros: - - if f == "tvshow.nfo": - tvshow_path = filetools.join(raiz, f) - # logger.debug(tvshow_path) + for s in subcarpetas: + tvshow_path = filetools.join(raiz, s, "tvshow.nfo") + logger.debug(tvshow_path) + if filetools.exists(tvshow_path): #Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa try: if config.is_xbmc(): #Si es Kodi, lo hacemos @@ -181,9 +195,9 @@ def list_tvshows(item): xbmc_videolibrary.mark_content_as_watched_on_alfa(tvshow_path) except: logger.error(traceback.format_exc()) - + head_nfo, item_tvshow = videolibrarytools.read_nfo(tvshow_path) - + if not item_tvshow: #Si no ha leído bien el .nfo, pasamos a la siguiente logger.error('.nfo erroneo en ' + str(tvshow_path)) continue @@ -199,7 +213,7 @@ def list_tvshows(item): for canal in item_tvshow.library_urls: canal = generictools.verify_channel(canal) try: - if canal == 'community': + if canal in ['community', 'downloads']: channel_verify = __import__('specials.%s' % canal, fromlist=["channels.%s" % canal]) else: channel_verify = __import__('channels.%s' % canal, fromlist=["channels.%s" % canal]) @@ -208,7 +222,7 @@ def list_tvshows(item): dead_item = Item(multicanal=multicanal, contentType='tvshow', dead=canal, - path=raiz, + path=filetools.join(raiz, s), nfo=tvshow_path, library_urls=item_tvshow.library_urls, infoLabels={'title': item_tvshow.contentTitle}) @@ -240,8 +254,9 @@ def list_tvshows(item): try: #A veces da errores aleatorios, por no encontrar el .nfo. Probablemente problemas de timing item_tvshow.title = item_tvshow.contentTitle - item_tvshow.path = raiz + item_tvshow.path = filetools.join(raiz, s) item_tvshow.nfo = tvshow_path + item_tvshow.extra = filetools.join(config.get_setting("videolibrarypath"), config.get_setting("folder_tvshows"), s) # Menu contextual: Marcar como visto/no visto visto = item_tvshow.library_playcounts.get(item_tvshow.contentTitle, 0) item_tvshow.infoLabels["playcount"] = visto @@ -318,6 +333,8 @@ def get_seasons(item): itemlist = [] dict_temp = {} + videolibrarytools.check_renumber_options(item) + raiz, carpetas_series, ficheros = next(filetools.walk(item.path)) # Menu contextual: Releer tvshow.nfo @@ -373,6 +390,7 @@ def get_seasons(item): new_item.infoLabels["playcount"] = 0 itemlist.insert(0, new_item) + add_download_items(item, itemlist) return itemlist @@ -389,7 +407,7 @@ def get_episodes(item): # Crear un item en la lista para cada strm encontrado for i in ficheros: - if i.endswith('.strm'): + if i.split('.')[-1] not in ['json','nfo']: #i.endswith('.strm'): season_episode = scrapertools.get_season_and_episode(i) if not season_episode: # El fichero no incluye el numero de temporada y episodio @@ -400,7 +418,7 @@ def get_episodes(item): continue # Obtener los datos del season_episode.nfo - nfo_path = filetools.join(raiz, i).replace('.strm', '.nfo') + nfo_path = filetools.join(raiz, '%sx%s.nfo' % (season, episode))#.replace('.strm', '.nfo') head_nfo, epi = videolibrarytools.read_nfo(nfo_path) # Fijar el titulo del capitulo si es posible @@ -434,14 +452,16 @@ def get_episodes(item): # logger.debug("epi:\n" + epi.tostring('\n')) itemlist.append(epi) - return sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber))) + itemlist = sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber))) + add_download_items(item, itemlist) + return itemlist def findvideos(item): from specials import autoplay logger.info() # logger.debug("item:\n" + item.tostring('\n')) - + videolibrarytools.check_renumber_options(item) itemlist = [] list_canales = {} item_local = None @@ -454,8 +474,8 @@ def findvideos(item): return [] #content_title = [c for c in item.contentTitle.strip().lower() if c not in ":*?<>|\/"] - content_title = "".join(c for c in item.contentTitle.strip().lower() if c not in ":*?<>|\/") - + content_title = str(item.contentSeason) + 'x' + (str(item.contentEpisodeNumber) if item.contentEpisodeNumber > 9 \ + else '0' + str(item.contentEpisodeNumber)) if item.contentType == 'movie': item.strm_path = filetools.join(videolibrarytools.MOVIES_PATH, item.strm_path) path_dir = filetools.dirname(item.strm_path) @@ -520,7 +540,7 @@ def findvideos(item): for nom_canal, json_path in list(list_canales.items()): if filtro_canal and filtro_canal != nom_canal.capitalize(): continue - + item_canal = Item() item_canal.channel = nom_canal ###### Redirección al canal NewPct1.py si es un clone, o a otro canal y url si ha intervención judicial @@ -529,10 +549,9 @@ def findvideos(item): except: logger.error(traceback.format_exc()) nom_canal = item_canal.channel - + # Importamos el canal de la parte seleccionada try: - if nom_canal == 'community': channel = __import__('specials.%s' % nom_canal, fromlist=["channels.%s" % nom_canal]) else: @@ -613,7 +632,8 @@ def findvideos(item): from inspect import stack from specials import nextep if nextep.check(item) and stack()[1][3] == 'run': - nextep.videolibrary(item) + nextep.videolibrary(item) + add_download_items(item, itemlist) return itemlist @@ -661,8 +681,8 @@ def update_videolibrary(item): logger.info() # Actualizar las series activas sobreescribiendo - import videolibrary_service - videolibrary_service.check_for_update(overwrite=True) + import service + service.check_for_update(overwrite=True) # Eliminar las carpetas de peliculas que no contengan archivo strm for raiz, subcarpetas, ficheros in filetools.walk(videolibrarytools.MOVIES_PATH): @@ -677,6 +697,91 @@ def update_videolibrary(item): filetools.rmdirtree(raiz) +def move_videolibrary(current_path, new_path, current_movies_folder, new_movies_folder, current_tvshows_folder, new_tvshows_folder): + logger.info() + + backup_current_path = current_path + backup_new_path = new_path + + notify = False + progress = platformtools.dialog_progress_bg(config.get_localized_string(20000), config.get_localized_string(80011)) + current_path = xbmc.translatePath(current_path) + new_path = xbmc.translatePath(new_path) + current_movies_path = filetools.join(current_path, current_movies_folder) + new_movies_path = filetools.join(new_path, new_movies_folder) + current_tvshows_path = os.path.join(current_path, current_tvshows_folder) + new_tvshows_path = os.path.join(new_path, new_tvshows_folder) + + from platformcode import xbmc_videolibrary + movies_path, tvshows_path = xbmc_videolibrary.check_sources(new_movies_path, new_tvshows_path) + if movies_path or tvshows_path: + if not movies_path: + filetools.rmdir(new_movies_path) + if not tvshows_path: + filetools.rmdir(new_tvshows_path) + config.set_setting("videolibrarypath", backup_current_path) + config.set_setting("folder_movies", current_movies_folder) + config.set_setting("folder_tvshows", current_tvshows_folder) + xbmc_videolibrary.update_sources(backup_current_path, backup_new_path) + progress.update(100) + xbmc.sleep(1000) + progress.close() + platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(80028)) + return + + config.verify_directories_created() + progress.update(10, config.get_localized_string(20000), config.get_localized_string(80012)) + if current_movies_path != new_movies_path: + if filetools.listdir(current_movies_path): + dir_util.copy_tree(current_movies_path, new_movies_path) + notify = True + filetools.rmdirtree(current_movies_path) + progress.update(40) + if current_tvshows_path != new_tvshows_path: + if filetools.listdir(current_tvshows_path): + dir_util.copy_tree(current_tvshows_path, new_tvshows_path) + notify = True + filetools.rmdirtree(current_tvshows_path) + progress.update(70) + if current_path != new_path and not filetools.listdir(current_path) and not "plugin.video.kod\\videolibrary" in current_path: + filetools.rmdirtree(current_path) + + xbmc_videolibrary.update_sources(backup_new_path, backup_current_path) + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): + xbmc_videolibrary.update_db(backup_current_path, backup_new_path, current_movies_folder, new_movies_folder, current_tvshows_folder, new_tvshows_folder, progress) + else: + progress.update(100) + xbmc.sleep(1000) + progress.close() + if notify: + platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(80014), icon=0, time=5000, sound=False) + + +def delete_videolibrary(item): + logger.info() + + if not platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(80037)): + return + + p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), config.get_localized_string(80038)) + p_dialog.update(0) + + filetools.rmdirtree(videolibrarytools.MOVIES_PATH) + p_dialog.update(40) + filetools.rmdirtree(videolibrarytools.TVSHOWS_PATH) + p_dialog.update(80) + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): + from platformcode import xbmc_videolibrary + xbmc_videolibrary.clean(config.get_setting('videolibrarypath')) + + p_dialog.update(90) + config.verify_directories_created() + p_dialog.update(100) + xbmc.sleep(1000) + p_dialog.close() + platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(80039), icon=0, time=5000, sound=False) + + # metodos de menu contextual def update_tvshow(item): logger.info() @@ -686,8 +791,8 @@ def update_tvshow(item): p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), heading) p_dialog.update(0, heading, item.contentSerieName) - import videolibrary_service - if videolibrary_service.update(item.path, p_dialog, 1, 1, item, False) and config.is_xbmc(): + import service + if service.update(item.path, p_dialog, 1, 1, item, False) and config.is_xbmc() and config.get_setting("videolibrary_kodi"): from platformcode import xbmc_videolibrary xbmc_videolibrary.update(folder=filetools.basename(item.path)) @@ -696,22 +801,22 @@ def update_tvshow(item): def verify_playcount_series(item, path): logger.info() - + """ Este método revisa y repara el PlayCount de una serie que se haya desincronizado de la lista real de episodios en su carpeta. Las entradas de episodios, temporadas o serie que falten, son creado con la marca de "no visto". Posteriormente se envia a verificar los contadores de Temporadas y Serie - + En el retorno envía de estado de True si se actualizado o False si no, normalmente por error. Con este estado, el caller puede actualizar el estado de la opción "verify_playcount" en "videolibrary.py". La intención de este método es la de dar una pasada que repare todos los errores y luego desactivarse. Se puede volver a activar en el menú de Videoteca de Alfa. - + """ #logger.debug("item:\n" + item.tostring('\n')) - + #Si no ha hecho nunca la verificación, lo forzamos estado = config.get_setting("verify_playcount", "videolibrary") if not estado or estado == False: estado = True #Si no ha hecho nunca la verificación, lo forzamos else: estado = False - + if item.contentType == 'movie': #Esto es solo para Series return (item, False) if filetools.exists(path): @@ -720,7 +825,7 @@ def verify_playcount_series(item, path): if not hasattr(it, 'library_playcounts') or not it.library_playcounts: #Si el .nfo no tiene library_playcounts se lo creamos logger.error('** It does not have PlayCount') it.library_playcounts = {} - + # Obtenemos los archivos de los episodios raiz, carpetas_series, ficheros = next(filetools.walk(path)) # Crear un item en la lista para cada strm encontrado @@ -763,35 +868,35 @@ def mark_content_as_watched2(item): # logger.debug("item:\n" + item.tostring('\n')) if filetools.exists(item.nfo): - head_nfo, it = videolibrarytools.read_nfo(item.nfo) - #logger.debug(it) + head_nfo, it = videolibrarytools.read_nfo(item.nfo) + #logger.debug(it) name_file = "" if item.contentType == 'movie' or item.contentType == 'tvshow': name_file = os.path.splitext(filetools.basename(item.nfo))[0] - + if name_file != 'tvshow' : - it.library_playcounts.update({name_file: item.playcount}) + it.library_playcounts.update({name_file: item.playcount}) if item.contentType == 'episode' or item.contentType == 'tvshow' or item.contentType == 'list' or name_file == 'tvshow': # elif item.contentType == 'episode': name_file = os.path.splitext(filetools.basename(item.strm_path))[0] num_season = name_file [0] - item.__setattr__('contentType', 'episode') - item.__setattr__('contentSeason', num_season) - #logger.debug(name_file) - + item.__setattr__('contentType', 'episode') + item.__setattr__('contentSeason', num_season) + #logger.debug(name_file) + else: name_file = item.contentTitle - # logger.debug(name_file) + # logger.debug(name_file) if not hasattr(it, 'library_playcounts'): it.library_playcounts = {} - it.library_playcounts.update({name_file: item.playcount}) + it.library_playcounts.update({name_file: item.playcount}) # se comprueba que si todos los episodios de una temporada están marcados, se marque tb la temporada if item.contentType != 'movie': it = check_season_playcount(it, item.contentSeason) - #logger.debug(it) + #logger.debug(it) # Guardamos los cambios en item.nfo if filetools.write(item.nfo, head_nfo + it.tojson()): @@ -920,14 +1025,9 @@ def delete(item): if ficheros == []: filetools.rmdir(_item.path) - if config.is_xbmc(): - import xbmc - # esperamos 3 segundos para dar tiempo a borrar los ficheros - xbmc.sleep(3000) - # TODO mirar por qué no funciona al limpiar en la videoteca de Kodi al añadirle un path - # limpiamos la videoteca de Kodi + if config.is_xbmc() and config.get_setting("videolibrary_kodi"): from platformcode import xbmc_videolibrary - xbmc_videolibrary.clean() + xbmc_videolibrary.clean(_item.extra) logger.info("All links removed") platformtools.itemlist_refresh() @@ -1030,3 +1130,40 @@ def check_tvshow_playcount(item, season): item.library_playcounts.update({item.title: playcount}) return item + + +def add_download_items(item, itemlist): + localOnly = True + for i in itemlist: + if i.contentChannel != 'local': + localOnly = False + break + if not item.fromLibrary and not localOnly: + downloadItem = Item(channel='downloads', + from_channel=item.channel, + title=typo(config.get_localized_string(60355), "color kod bold"), + fulltitle=item.fulltitle, + show=item.fulltitle, + contentType=item.contentType, + contentSerieName=item.contentSerieName, + url=item.url, + action='save_download', + from_action="findvideos", + contentTitle=item.contentTitle, + path=item.path, + thumbnail=thumb(thumb='downloads.png'), + parent=item.tourl()) + if item.action == 'findvideos': + if item.contentType == 'episode': + downloadItem.title = typo(config.get_localized_string(60356), "color kod bold") + else: # film + downloadItem.title = typo(config.get_localized_string(60354), "color kod bold") + downloadItem.downloadItemlist = [i.tourl() for i in itemlist] + itemlist.append(downloadItem) + else: + if item.contentSeason: # season + downloadItem.title = typo(config.get_localized_string(60357), "color kod bold") + itemlist.append(downloadItem) + else: # tvshow + not seen + itemlist.append(downloadItem) + itemlist.append(downloadItem.clone(title=typo(config.get_localized_string(60003), "color kod bold"), unseen=True)) \ No newline at end of file From 1c751090f80256b08a85cc1f7791f50a1f6af2b4 Mon Sep 17 00:00:00 2001 From: Alhaziel01 <alhaziel01@gmail.com> Date: Thu, 16 Apr 2020 08:33:05 +0200 Subject: [PATCH 3/6] Fix viste, Serie TV, Stagione, Episodio --- platformcode/platformtools.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platformcode/platformtools.py b/platformcode/platformtools.py index 7aa39ed7..fe7382e9 100644 --- a/platformcode/platformtools.py +++ b/platformcode/platformtools.py @@ -257,13 +257,13 @@ def set_view_mode(item, parent_item): elif (item.contentType in ['tvshow'] and parent_item.action in ['peliculas']) \ or (item.channel in ['videolibrary'] and parent_item.action in ['list_tvshows']): - mode('tvshow', 'tvshow') + mode('tvshow', 'tvshows') elif parent_item.action in ['get_seasons']: - mode('season', 'tvshow') + mode('season', 'tvshows') elif parent_item.action in ['episodios', 'get_episodes']: - mode('episode', 'tvshow') + mode('episode', 'tvshows') elif parent_item.action == 'findvideos': mode('server', 'addons') From 96314849d05aa01a6a4817c9972a3c0f7e13aab2 Mon Sep 17 00:00:00 2001 From: Alhaziel01 <alhaziel01@gmail.com> Date: Thu, 16 Apr 2020 15:19:34 +0200 Subject: [PATCH 4/6] Fix e Pulizia CB01 --- channels.json | 2 +- channels/cineblog01.py | 60 +++++++++--------------------------------- 2 files changed, 14 insertions(+), 48 deletions(-) diff --git a/channels.json b/channels.json index 7b08a023..e2d125aa 100644 --- a/channels.json +++ b/channels.json @@ -12,7 +12,7 @@ "animeworld": "https://www.animeworld.tv", "casacinema": "https://www.casacinema.me", "casacinemaInfo": "https://casacinema.life", - "cineblog01": "https://cb01.expert", + "cineblog01": "https://cb01.uno", "cb01anime": "https://www.cineblog01.network", "cinemalibero": "https://www.cinemalibero.plus", "cinetecadibologna": "http://cinestore.cinetecadibologna.it", diff --git a/channels/cineblog01.py b/channels/cineblog01.py index 0af05ee8..f268723e 100644 --- a/channels/cineblog01.py +++ b/channels/cineblog01.py @@ -62,36 +62,6 @@ def menu(item): return locals() -# @support.scrape -# def newest(categoria): -# -# # debug = True -# patron = r'<a href="?(?P<url>[^">]+)"?>(?P<title>[^<([]+)(?:\[(?P<lang>Sub-ITA|B/N|SUB-ITA)\])?\s*(?:\[(?P<quality>HD|SD|HD/3D)\])?\s*\((?P<year>[0-9]{4})\)<\/a>' - -# if type(categoria) != Item: -# item = Item() -# else: -# item = categoria -# categoria = 'series' if item.contentType != 'movie' else 'movie' -# pagination = 20 - -# if categoria == 'series': -# item.contentType = 'tvshow' -# action = 'episodios' -# item.url = host + 'serietv/aggiornamento-quotidiano-serie-tv/' -# patronBlock = r'<article class="sequex-post-content">(?P<block>.*?)</article>' -# patron = '<a href="(?P<url>[^"]+)".*?>(?P<title>[^<([|]+).*?(?P<lang>ITA|SUB-ITA)?</a' -# else: -# item.contentType = 'movie' -# item.url = host + '/lista-film-ultimi-100-film-aggiunti/' -# patronBlock = r'Ultimi 100 film aggiunti:(?P<block>.*?)<\/td>' -# # else: -# # patronBlock = r'Ultimi 100 film Aggiornati:(?P<block>.*?)<\/td>' -# # item = categoria - -# return locals() - - def newest(categoria): support.log(categoria) @@ -135,7 +105,7 @@ def peliculas(item): 'Aggiornamento Quotidiano Serie TV', 'OSCAR 2019 ▶ CB01.UNO: Vota il tuo film preferito! 🎬', 'Openload: la situazione. Benvenuto Verystream', 'Openload: lo volete ancora?', 'OSCAR 2020 ▶ VOTA IL TUO FILM PREFERITO! 🎬'] - # debug = True + if 'newest' in item.args: if '/serietv/' not in item.url: pagination = '' @@ -146,19 +116,16 @@ def peliculas(item): patronBlock = r'Ultime SerieTv aggiornate(?P<block>.*?)Lista' patron = r'src="(?P<thumb>[^"]+)" alt="(?P<title>.*?)(?: – \d+×\d+)?(?:"| – )(?:(?P<lang>Sub-ITA|ITA))?[^>]*>[^>]+>[^>]+><a href="(?P<url>[^"]+)".*?<div class="rpwe-summary">.*?\((?P<year>\d{4})[^\)]*\) (?P<plot>[^<]+)<' action = 'episodios' + elif '/serietv/' not in item.url: patron = r'<div class="card-image">\s<a[^>]+>\s*<img src="(?P<thumb>[^" ]+)" alt[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+><a href="?(?P<url>[^" >]+)(?:\/|"|\s+)>(?P<title>[^<[(]+)(?:\[(?P<quality>[A-Za-z0-9/-]+)])? (?:\((?P<year>[0-9]{4})\))?[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<genre>[^<>&–]+)(?:[^ ]+\s*DURATA\s*(?P<duration>[0-9]+)[^>]+>[^>]+>[^>]+>(?P<plot>[^<>]+))?' - # patron = r'<div class="?card-image"?>.*?<img src="?(?P<thumb>[^" ]+)"? alt.*?<a href="?(?P<url>[^" >]+)(?:\/|"|\s+)>(?P<title>[^<[(]+)(?:\[(?P<quality>[A-Za-z0-9/-]+)])? (?:\((?P<year>[0-9]{4})\))?.*?<strong>(?P<genre>[^<>&–]+).*?DURATA (?P<duration>[0-9]+).*?<br(?: /)?>(?P<plot>[^<>]+)' action = 'findvideos' + else: - # debug = True - patron = r'div class="card-image">.*?<img src="(?P<thumb>[^ ]+)" alt.*?<a href="(?P<url>[^ >]+)">(?P<title>.*?)(?: – (?:[SS]tagione \d|\d).*?)?(?P<lang>(?:[Ss][Uu][Bb]-)?[Ii][Tt][Aa])?<\/a>.*?(?:<strong><span style="[^"]+">(?P<genre>[^<>0-9(]+)\((?P<year>[0-9]{4}).*?</(?:p|div)>(?P<plot>.*?))?</div' + patron = r'div class="card-image">.*?<img src="(?P<thumb>[^ ]+)" alt.*?<a href="(?P<url>[^ >]+)">(?P<title>.*?)(?: –\s*(?:[SS]tagione \d|\d).*?)?(?P<lang>(?:[Ss][Uu][Bb]-)?[Ii][Tt][Aa])?<\/a>.*?(?:<strong><span style="[^"]+">(?P<genre>[^<>0-9(]+)\((?P<year>[0-9]{4}).*?</(?:p|div)>(?P<plot>.*?))?</div' action = 'episodios' item.contentType = 'tvshow' - # patronBlock=[r'<div class="?sequex-page-left"?>(?P<block>.*?)<aside class="?sequex-page-right"?>', - # '<div class="?card-image"?>.*?(?=<div class="?card-image"?>|<div class="?rating"?>)'] - # if 'newest' not in item.args: patronNext = '<a class="?page-link"? href="?([^>]+)"?><i class="fa fa-angle-right">' return locals() @@ -167,7 +134,6 @@ def peliculas(item): @support.scrape def episodios(item): patronBlock = r'(?P<block><div class="sp-head[a-z ]*?" title="Espandi">\s*(?:STAGION[EI]\s*(?:DA\s*[0-9]+\s*A)?\s*[0-9]+|MINISERIE) - (?P<lang>[^-<]+)(?:- (?P<quality>[^-<]+))?.*?[^<>]*?<\/div>.*?)<div class="spdiv">\[riduci\]<\/div>' - # patron = '(?:<p>|<strong>)(?P<episode>[0-9]+(?:×|×)[0-9]+)\s*(?P<title2>[^&<]*)?(?:–|-)?\s*(?P<url>.*?)(?:<\/p>|<br)' patron = r'(?:/>|<p>|<strong>)(?P<url>.*?(?P<episode>[0-9]+(?:×|×)[0-9]+)\s*(?P<title2>.*?)?(?:\s*–|\s*-|\s*<).*?)(?:<\/p>|<br)' def itemlistHook(itemlist): title_dict = {} @@ -254,15 +220,15 @@ def findvid_serie(item): matches = support.match(html, patron=r'<a href="([^"]+)"[^=]+="_blank"[^>]+>(?!<!--)(.*?)(?:</a>|<img)').matches for url, server in matches: item = Item(channel=item.channel, - action="play", - title=server, - url=url, - server=server, - fulltitle=item.fulltitle, - show=item.show, - quality=blktxt, - contentType=item.contentType, - folder=False) + action="play", + title=server, + url=url, + server=server, + fulltitle=item.fulltitle, + show=item.show, + quality=blktxt, + contentType=item.contentType, + folder=False) if 'swzz' in item.url: item.url = support.swzz_get_url(item) itemlist.append(item) From fec9ba7513b9ef1a29d8fc4806caebf97eccba1d Mon Sep 17 00:00:00 2001 From: Alhaziel01 <alhaziel01@gmail.com> Date: Thu, 16 Apr 2020 15:20:11 +0200 Subject: [PATCH 5/6] Supporto Skin: - Phenomenal - Black Galss Nova --- resources/views/skin.blackglassnova.json | 67 ++++++++++++++++++++++++ resources/views/skin.phenomenal.json | 62 ++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 resources/views/skin.blackglassnova.json create mode 100644 resources/views/skin.phenomenal.json diff --git a/resources/views/skin.blackglassnova.json b/resources/views/skin.blackglassnova.json new file mode 100644 index 00000000..d59b9ed2 --- /dev/null +++ b/resources/views/skin.blackglassnova.json @@ -0,0 +1,67 @@ +{ + "all":{ + "List": 50, + "Large List": 52, + "Low List": 54, + "Banner List": 56, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Poster Showcase": 59, + "Card List": 5050 + }, + "movie":{ + "List": 50, + "Large List": 52, + "Low List": 54, + "Banner List": 56, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Poster Showcase": 59, + "Card List": 5050 + }, + "tvshow":{ + "List": 50, + "Large List": 52, + "Low List": 54, + "Banner List": 56, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Poster Showcase": 59, + "Card List": 5050 + }, + "season":{ + "List": 50, + "Large List": 52, + "Low List": 54, + "Banner List": 56, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Poster Showcase": 59, + "Card List": 5050 + }, + "episode":{ + "List": 50, + "Large List": 52, + "Low List": 54, + "Banner List": 56, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Poster Showcase": 59, + "Card List": 5050 + }, + "addon":{ + "List": 50, + "Large List": 52, + "Low List": 54, + "Panel": 51, + "Big Panel": 55, + "Icons": 53, + "Fanart": 58, + "Card List": 5050 + } +} diff --git a/resources/views/skin.phenomenal.json b/resources/views/skin.phenomenal.json new file mode 100644 index 00000000..a59df640 --- /dev/null +++ b/resources/views/skin.phenomenal.json @@ -0,0 +1,62 @@ +{ + "all":{ + "Fanart": 50, + "Poster": 51, + "Thumb": 52, + "Showcase": 53, + "Wide List": 54, + "Icons": 55, + "Pictures": 56, + "Banner List": 57 + }, + "movie":{ + "Fanart": 50, + "Poster": 51, + "Thumb": 52, + "Showcase": 53, + "Wide List": 54, + "Icons": 55, + "Pictures": 56, + "Banner List": 57 + }, + "tvshow":{ + "Fanart": 50, + "Poster": 51, + "Thumb": 52, + "Showcase": 53, + "Wide List": 54, + "Icons": 55, + "Pictures": 56, + "Banner List": 57 + }, + "season":{ + "Fanart": 50, + "Poster": 51, + "Thumb": 52, + "Showcase": 53, + "Wide List": 54, + "Icons": 55, + "Pictures": 56, + "Banner List": 57 + }, + "episode":{ + "Fanart": 50, + "Poster": 51, + "Thumb": 52, + "Showcase": 53, + "Wide List": 54, + "Icons": 55, + "Pictures": 56, + "Banner List": 57 + }, + "addon":{ + "Fanart": 50, + "Poster": 51, + "Thumb": 52, + "Showcase": 53, + "Wide List": 54, + "Icons": 55, + "Pictures": 56, + "Banner List": 57 + } +} \ No newline at end of file From 4789899f99f422e685e36d12e06878d71b70a111 Mon Sep 17 00:00:00 2001 From: Alhaziel01 <alhaziel01@gmail.com> Date: Thu, 16 Apr 2020 15:30:46 +0200 Subject: [PATCH 6/6] Adesso in onda Vista Film --- platformcode/platformtools.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformcode/platformtools.py b/platformcode/platformtools.py index fe7382e9..460b5a5c 100644 --- a/platformcode/platformtools.py +++ b/platformcode/platformtools.py @@ -252,7 +252,8 @@ def set_view_mode(item, parent_item): xbmc.executebuiltin('Container.SetViewMode(%s)' % 55) elif (item.contentType in ['movie'] and parent_item.action in ['peliculas']) \ - or (item.channel in ['videolibrary'] and parent_item.action in ['list_movies']): + or (item.channel in ['videolibrary'] and parent_item.action in ['list_movies']) \ + or parent_item.action in ['now_on_tv', 'now_on_misc', 'now_on_misc_film']: mode('movie', 'movies') elif (item.contentType in ['tvshow'] and parent_item.action in ['peliculas']) \