diff --git a/channels.json b/channels.json index 95f6309b..85048b23 100644 --- a/channels.json +++ b/channels.json @@ -9,6 +9,7 @@ "animeunity": "https://www.animeunity.it", "animeuniverse": "https://www.animeuniverse.it", "animeworld": "https://www.animeworld.tv", + "aniplay": "https://aniplay.it", "casacinema": "https://www.casacinema.page", "cb01anime": "https://www.cineblog01.red", "cineblog01": "https://cb01.uno", diff --git a/channels/0example.py.txt b/channels/0example.py.txt index e09fca3c..5c520f7d 100644 --- a/channels/0example.py.txt +++ b/channels/0example.py.txt @@ -118,7 +118,7 @@ def mainlist(item): # VOCE CHE APPARIRA' come prima voce nel menu di KOD! # [Voce Menu,['url','action','args',contentType] - top = [ '' ['', '', '', '']) + top = ([ '' ['', '', '', '']) # Se vuoi creare un menu personalizzato o perchè gli altri non # ti soddisfano diff --git a/channels/aniplay.json b/channels/aniplay.json new file mode 100644 index 00000000..78334d1f --- /dev/null +++ b/channels/aniplay.json @@ -0,0 +1,114 @@ +{ + "id": "aniplay", + "name": "AniPlay", + "active": true, + "language": ["ita", "sub-ita"], + "thumbnail": "aniplay.png", + "banner": "aniplay.png", + "categories": ["anime", "vos"], + "settings": [ + { + "id": "sort", + "type": "list", + "label": "Ordine di Visualizzazione", + "default": 0, + "enabled": true, + "visible": true, + "lvalues": [ "Popolarità", "Titolo", "Numero Episodi", "Data di inizio", "Data di fine", "Data di aggiunta"] + }, + { + "id": "order", + "type": "bool", + "label": "Visualizza in ordine Discendente?", + "default": false, + "enabled": true, + "visible": true + }, + { + "id": "perpage", + "type": "list", + "label": "Numero di elementi per pagina", + "default": 1, + "enabled": true, + "visible": true, + "lvalues": ["10", "20", "30", "40", "50", "60", "80", "90"] + }, + { + "id": "include_in_global_search", + "type": "bool", + "label": "@70728", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_peliculas", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_series", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_anime", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "checklinks", + "type": "bool", + "label": "Verifica se i link esistono", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "checklinks_number", + "type": "list", + "label": "Numero di link da verificare", + "default": 2, + "enabled": false, + "visible": "eq(-1,false)", + "lvalues": [ "3", "5", "10", "15", "20" ] + }, + { + "id": "filter_languages", + "type": "list", + "label": "@30019", + "default": 0, + "enabled": false, + "visible": false, + "lvalues": ["Non Filtrare"] + } + ], + + "renumber": [ + { + "id": "autorenumber", + "type": "bool", + "label": "@70712", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "autorenumber_mode", + "type": "bool", + "label": "@70688", + "default": false, + "enabled": false, + "visible": "eq(-1,false)" + } + ] +} \ No newline at end of file diff --git a/channels/aniplay.py b/channels/aniplay.py new file mode 100644 index 00000000..fb7a285c --- /dev/null +++ b/channels/aniplay.py @@ -0,0 +1,311 @@ +from platformcode import config, logger, autorenumber +from core import httptools, scrapertools, support, tmdb +from inspect import stack + +import sys +if sys.version_info[0] >= 3: + from concurrent import futures +else: + from concurrent_py2 import futures + +host = config.get_channel_url() +sort = ['views', 'title', 'episodeNumber', 'startDate', 'endDate', 'createdDate'][config.get_setting('sort', 'aniplay')] +order = 'desc' if config.get_setting('order', 'aniplay') else 'asc' +perpage = [10, 20, 30 ,40, 50, 60, 70, 80, 90][config.get_setting('perpage', 'aniplay')] + + +@support.menu +def mainlist(item): + anime=['/api/anime/advanced-search', + ('A-Z', ['/api/anime/advanced-search', 'submenu_az', '']), + ('Anno', ['', 'submenu_year', '']), + ('Top', ['', 'submenu_top', '']), + ('Ultimi aggiunti', ['', 'latest_added', ''])] + return locals() + + +def submenu_az(item): + itemlist = [] + if item.args == 'az': + for letter in ['0-9'] + list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'): + itemlist.append(item.clone(title = support.typo(letter, 'bold'), + url= host + '/api/anime/find-by-char', + action= 'peliculas', + variable= '&character=' + letter, + thumbnail=support.thumb('az'))) + return itemlist + +def submenu_year(item): + itemlist = [] + from datetime import date + current = date.today().year + first = int(httptools.downloadpage('{}/api/anime/advanced-search?page=0&size=1&sort=startDate,asc&sort=id'.format(host)).json[0]['startDate'].split('-')[0]) -1 + for year in range(current, first, -1): + itemlist.append(item.clone(title = support.typo(year, 'bold'), + action= 'submenu_season', + variable= year, + thumbnail=support.thumb('year'))) + return itemlist + +def submenu_top(item): + itemlist = [] + links = {'Top del giorno':'daily-top', 'Top della settimana':'weekly-top', 'Top del mese':'monthly-top'} + for label in links: + link = links[label] + itemlist.append(item.clone(title = support.typo(label, 'bold'), + action= 'submenu_top_of', + variable= link)) + return itemlist + +def submenu_season(item): + itemlist = [] + seasons = {'winter':'Inverno', 'spring':'Primavera', 'summer':'Estate', 'fall':'Autunno'} + url= '{}/api/seasonal-view?page=0&size=36&years={}'.format(host, item.variable) + js = httptools.downloadpage(url).json[0]['seasonalAnime'] + for season in js: + s = season['season'].split('.')[-1] + title = seasons[s] + itemlist.append(item.clone(title=title, + url = '{}/api/seasonal-view/{}-{}'.format(host, s, item.variable), + thumbnail = support.thumb(s), + action = 'peliculas', + variable='')) + return itemlist + +def submenu_top_of(item): + itemlist = [] + url= '{}/api/home/{}'.format(host, item.variable) + js = httptools.downloadpage(url).json + for anime in js: + fulltitle = anime['animeTitle'] + title = fulltitle.split('(')[0].strip() + scrapedlang = scrapertools.find_single_match(fulltitle, r'\(([^\)]+)') + lang = scrapedlang.upper() if scrapedlang else 'Sub-ITA' + long_title = support.typo(title, 'bold') + support.typo(lang, '_ [] color kod') + + itemlist.append(item.clone(title=long_title, + id=anime['animeId'], + url = '{}/api/anime/{}'.format(host, anime['animeId']), + thumbnail = get_thumbnail(anime, 'animeHorizontalImages'), + action = 'episodios', + variable=anime['animeId'])) + return itemlist + + + +def search(item, texto): + support.info(texto) + item.url = host + '/api/anime/advanced-search' + item.variable = '&query=' + texto + + 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 [] + + +def newest(categoria): + support.info(categoria) + item = support.Item() + try: + if categoria == "anime": + return latest_added(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.logger.error("{0}".format(line)) + return [] + + +def latest_added(item): + itemlist = [] + page = item.page if item.page else 0 + url= '{}/api/home/latest-episodes?page={}'.format(host, page) + js = httptools.downloadpage(url).json + + for episode in js: + title = episode['title'] + animeTitle, lang = get_lang(episode['animeTitle']) + quality = 'Full HD' if episode['fullHd'] else 'HD' + long_title = support.typo('{}. {}{}'.format(int(float(episode['episodeNumber'])), title + ' - ' if title else '', animeTitle), 'bold') + support.typo(lang, '_ [] color kod') + support.typo(quality, '_ [] color kod') + image = get_thumbnail(episode, 'episodeImages') + + itemlist.append(item.clone(title=long_title, + fulltitle=title, + animeId = episode['animeId'], + id=episode['id'], + contentType = 'episode', + contentTitle = title, + contentSerieName = animeTitle, + contentLanguage = lang, + quality = quality, + contentEpisodeNumber = int(float(episode['episodeNumber'])), + animeUrl = '{}/api/anime/{}'.format(host, episode['animeId']), + thumbnail = image, + fanart = image, + action = 'findvideos')) + + if stack()[1][3] not in ['newest']: + support.nextPage(itemlist, item.clone(page = page + 1)) + + return itemlist + + +def peliculas(item): + logger.debug() + + itemlist = [] + page = item.page if item.page else 0 + js = httptools.downloadpage('{}?page={}&size={}{}&sort={},{}&sort=id'.format(item.url, page, perpage, item.variable, sort, order)).json + + for it in js: + title, lang = get_lang(it['title']) + active = False if it['status'] == 'Annunciato' or not it['episodeNumber'] else True + + if active: + long_title = support.typo(title, 'bold') + support.typo(lang, '_ [] color kod') + else: + long_title = support.typo(title, 'italic') + support.typo('Annunciato', '_ [] color kod italic') + + itemlist.append(item.clone(title = long_title, + fulltitle = title, + show = title, + contentLanguage = lang, + contentType = 'movie' if it['type'] == 'Movie' else 'tvshow', + contentTitle = title, + contentSerieName = title if it['type'] == 'Serie' else '', + action = '' if not active else 'findvideos' if it['type'] == 'Movie' else 'episodios', + plot = it['storyline'], + year = it['startDate'].split('-')[0], + id= it['id'], + thumbnail = get_thumbnail(it), + fanart = get_thumbnail(it, 'horizontalImages'))) + + autorenumber.start(itemlist) + tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) + + if len(itemlist) == perpage: + support.nextPage(itemlist, item.clone(page = page + 1)) + return itemlist + + +def episodios(item): + logger.debug() + itemlist = [] + + url = '{}/api/anime/{}'.format(host, item.id) + json = httptools.downloadpage(url, CF=False ).json + + if 'seasons' in json and len(json['seasons']) > 0: + seasons = json['seasons'] + seasons.sort(key=lambda s: s['episodeStart']) + + for i, it in enumerate(seasons): + title = it['name'] + + itemlist.append(item.clone(title = title, + id= '{}/season/{}'.format(it['animeId'], it['id']), + contentType = 'season', + contentSeason = i, + action = 'episodios', + plot = json['storyline'], + year = it['yearStart'])) + + if stack()[1][3] in ['add_tvshow', 'get_episodes', 'update', 'find_episodes']: + itlist = [] + with futures.ThreadPoolExecutor() as executor: + eplist = [executor.submit(episodios, item) for item in itemlist] + for res in futures.as_completed(eplist): + if res.result(): + itlist.extend(res.result()) + itemlist = itlist + + elif ('episodes' in json and len(json['episodes']) > 0) or len(json) > 0: + episodes = json['episodes'] if 'episodes' in json else json + + episodes.sort(key=lambda ep: int(ep['episodeNumber'])) + + for it in episodes: + quality = 'Full HD' if it['fullHd'] else 'HD' + + if item.contentSeason: + episode = '{}x{:02d}'.format(item.contentSeason, int(it['episodeNumber'])) + else: + episode = '{:02d}'.format(int(it['episodeNumber'])) + + title = support.typo('{}. {}'.format(episode, it['title']), 'bold') + image = get_thumbnail(it, 'episodeImages') + + itemlist.append(item.clone(title = title, + id= it['id'], + url= 'api/episode/{}'.format(it['id']), + contentType = 'episode', + contentEpisodeNumber = int(it['episodeNumber']), + contentSeason = item.contentSeason if item.contentSeason else '', + action = 'findvideos', + quality = quality, + thumbnail = image, + fanart= image, + year = it['airingDate'].split('-')[0])) + + if not item.contentSeason and stack()[1][3] not in ['find_episodes']: + autorenumber.start(itemlist, item) + + if stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes']: + support.videolibrary(itemlist, item) + return itemlist + + +def findvideos(item): + logger.debug() + + url = '{}/api/{}/{}'.format(host, 'episode' if item.contentType == 'episode' else 'anime', item.id) + + json = httptools.downloadpage(url, CF=False ).json + + if json.get('episodes', []): + json = httptools.downloadpage('{}/api/episode/{}'.format(host, json['episodes'][0]['id'])).json + + videourl = json['episodeVideo'] + + itemlist = [item.clone(title=config.get_localized_string(30137), + url=videourl, + server='directo')] + + return support.server(item, itemlist=itemlist) + + +def get_thumbnail(data, prop = 'verticalImages', key = 'full'): + """ + " Returns the vertical image as per given key and prop + " possibile key values are: + " - small + " - full + " - blurred + " - medium + " possibile prop values are: + " - verticalImages + " - animeHorizontalImages + " - animeVerticalImages + " - horizontalImages + " - episodeImages + """ + value = None + verticalImages = data.get(prop, []) + if verticalImages: + first = verticalImages[0] + if first: + value = first.get('image' + key.capitalize(), '') + return value + + +def get_lang(value): + title = value.split('(')[0] if value else '' + scrapedlang = scrapertools.find_single_match(value, r'\(([^\)]+)') + lang = scrapedlang.upper() if scrapedlang else 'Sub-ITA' + return title, lang \ No newline at end of file