867 lines
33 KiB
Python
867 lines
33 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import datetime
|
|
import glob
|
|
import os
|
|
import re
|
|
import threading
|
|
import time
|
|
import urllib
|
|
from threading import Thread
|
|
from unicodedata import normalize
|
|
|
|
import Queue
|
|
import xbmc
|
|
from lib.fuzzywuzzy import fuzz
|
|
|
|
from core import channeltools, httptools, tmdb, servertools
|
|
from platformcode import platformtools
|
|
|
|
try:
|
|
import json
|
|
except:
|
|
import simplejson as json
|
|
|
|
from platformcode import config
|
|
from platformcode import logger
|
|
from core.item import Item
|
|
|
|
TMDB_KEY = tmdb.tmdb_auth_key ######TMDB_KEY = '92db8778ccb39d825150332b0a46061d'
|
|
# TMDB_KEY = '92db8778ccb39d825150332b0a46061d'
|
|
|
|
|
|
TMDB_URL_BASE = 'http://api.themoviedb.org/3/'
|
|
TMDB_IMAGES_BASEURL = 'http://image.tmdb.org/t/p/'
|
|
INCLUDE_ADULT = True if config.get_setting("enableadultmode") else False
|
|
LANGUAGE_ID = 'it'
|
|
|
|
DTTIME = (datetime.datetime.utcnow() - datetime.timedelta(hours=5))
|
|
SYSTIME = DTTIME.strftime('%Y%m%d%H%M%S%f')
|
|
TODAY_TIME = DTTIME.strftime('%Y-%m-%d')
|
|
MONTH_TIME = (DTTIME - datetime.timedelta(days=30)).strftime('%Y-%m-%d')
|
|
MONTH2_TIME = (DTTIME - datetime.timedelta(days=60)).strftime('%Y-%m-%d')
|
|
YEAR_DATE = (DTTIME - datetime.timedelta(days=365)).strftime('%Y-%m-%d')
|
|
|
|
TIMEOUT_TOTAL = config.get_setting("timeout")
|
|
MAX_THREADS = config.get_setting("maxthreads")
|
|
|
|
# TIMEOUT_TOTAL = config.get_setting("timeout", default=90)
|
|
# MAX_THREADS = config.get_setting("maxthreads", default=24)
|
|
|
|
NLS_Search_by_Channel = config.get_localized_string(30974)
|
|
NLS_Alternative_Search = config.get_localized_string(70021)
|
|
NLS_Search_by_Title = config.get_localized_string(30980)
|
|
NLS_Search_by_Person = config.get_localized_string(30981)
|
|
NLS_Search_by_Company = config.get_localized_string(30982)
|
|
NLS_Now_Playing = config.get_localized_string(30983)
|
|
NLS_Popular = config.get_localized_string(30984)
|
|
NLS_Top_Rated = config.get_localized_string(30985)
|
|
NLS_Search_by_Collection = config.get_localized_string(30986)
|
|
NLS_List_by_Genre = config.get_localized_string(30987)
|
|
NLS_Search_by_Year = config.get_localized_string(30988)
|
|
NLS_Search_Similar_by_Title = config.get_localized_string(30989)
|
|
NLS_Search_Tvshow_by_Title = config.get_localized_string(30990)
|
|
NLS_Most_Voted = config.get_localized_string(30996)
|
|
NLS_Oscar = config.get_localized_string(30997)
|
|
NLS_Last_2_months = config.get_localized_string(60534)
|
|
NLS_Library = config.get_localized_string(30991)
|
|
NLS_Next_Page = config.get_localized_string(30992)
|
|
NLS_Looking_For = config.get_localized_string(30993)
|
|
NLS_Searching_In = config.get_localized_string(30994)
|
|
NLS_Found_So_Far = config.get_localized_string(30995)
|
|
NLS_Info_Title = config.get_localized_string(30975)
|
|
NLS_Info_Person = config.get_localized_string(30979)
|
|
NLS_New_TVShow = config.get_localized_string(30978)
|
|
NLS_TVShow_onair = config.get_localized_string(30977)
|
|
NLS_TVShow_airing_today = config.get_localized_string(30976)
|
|
|
|
TMDb_genres = {}
|
|
|
|
|
|
def mainlist(item):
|
|
logger.info(" mainlist")
|
|
itemlist = [Item(channel="search",
|
|
title="[COLOR lightgreen]%s[/COLOR]" % NLS_Search_by_Channel,
|
|
action="mainlist",
|
|
thumbnail="http://i.imgur.com/pE5WSZp.png"),
|
|
Item(channel="tvmoviedb",
|
|
title="[COLOR yellow]%s[/COLOR]" % NLS_Alternative_Search,
|
|
action="mainlist",
|
|
url="search_movie_by_title",
|
|
thumbnail="https://s6.postimg.cc/6lll9b8c1/searching.png"),
|
|
Item(channel=item.channel,
|
|
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_by_Title,
|
|
action="search",
|
|
url="search_movie_by_title",
|
|
thumbnail="http://i.imgur.com/B1H1G8U.png"),
|
|
Item(channel=item.channel,
|
|
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_by_Person,
|
|
action="search",
|
|
url="search_person_by_name",
|
|
thumbnail="http://i.imgur.com/efuEeNu.png"),
|
|
Item(channel=item.channel,
|
|
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_by_Year,
|
|
action="search_movie_by_year",
|
|
url="search_movie_by_year",
|
|
thumbnail="https://d1kz0yd1invg7i.cloudfront.net/uploads/app/icon/1/calendar-icon-big.png"),
|
|
Item(channel=item.channel,
|
|
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_by_Collection,
|
|
action="search",
|
|
url="search_collection_by_name",
|
|
thumbnail="http://i.imgur.com/JmcvZDL.png"),
|
|
Item(channel=item.channel,
|
|
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_Similar_by_Title,
|
|
action="search",
|
|
url="search_similar_movie_by_title",
|
|
thumbnail="http://i.imgur.com/JmcvZDL.png"),
|
|
Item(channel=item.channel,
|
|
title="[COLOR lime]%s[/COLOR]" % NLS_Search_Tvshow_by_Title,
|
|
action="search",
|
|
url="search_tvshow_by_title",
|
|
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
|
Item(channel=item.channel,
|
|
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_New_TVShow,
|
|
action="list_tvshow",
|
|
url='discover/tv?sort_by=popularity.desc&first_air_date.gte=%s&first_air_date.lte=%s&' % (
|
|
MONTH2_TIME, TODAY_TIME),
|
|
plot="1",
|
|
type="tvshow",
|
|
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
|
Item(channel=item.channel,
|
|
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_TVShow_onair,
|
|
action="list_tvshow",
|
|
url="tv/on_the_air?",
|
|
plot="1",
|
|
type="tvshow",
|
|
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
|
Item(channel=item.channel,
|
|
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_Popular,
|
|
action="list_tvshow",
|
|
url="tv/popular?",
|
|
plot="1",
|
|
type="tvshow",
|
|
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
|
Item(channel=item.channel,
|
|
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_Top_Rated,
|
|
action="list_tvshow",
|
|
url="tv/top_rated?",
|
|
plot="1",
|
|
type="tvshow",
|
|
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
|
Item(channel=item.channel,
|
|
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_TVShow_airing_today,
|
|
action="list_tvshow",
|
|
url="tv/airing_today?",
|
|
plot="1",
|
|
type="tvshow",
|
|
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
|
Item(channel=item.channel,
|
|
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Now_Playing,
|
|
action="list_movie",
|
|
url="movie/now_playing?",
|
|
plot="1",
|
|
type="movie",
|
|
thumbnail="http://i.imgur.com/B16HnVh.png"),
|
|
Item(channel=item.channel,
|
|
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Popular,
|
|
action="list_movie",
|
|
url="movie/popular?",
|
|
plot="1",
|
|
type="movie",
|
|
thumbnail="http://i.imgur.com/8IBjyzw.png"),
|
|
Item(channel=item.channel,
|
|
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Top_Rated,
|
|
action="list_movie",
|
|
url="movie/top_rated?",
|
|
plot="1",
|
|
type="movie",
|
|
thumbnail="http://www.clipartbest.com/cliparts/RiG/6qn/RiG6qn79T.png"),
|
|
Item(channel=item.channel,
|
|
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Most_Voted,
|
|
action="list_movie",
|
|
url='discover/movie?certification_country=US&sort_by=vote_count.desc&',
|
|
plot="1",
|
|
type="movie",
|
|
thumbnail="http://i.imgur.com/5ShnO8w.png"),
|
|
Item(channel=item.channel,
|
|
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Oscar,
|
|
action="list_movie",
|
|
url='list/509ec17b19c2950a0600050d?',
|
|
plot="1",
|
|
type="movie",
|
|
thumbnail="http://i.imgur.com/5ShnO8w.png"),
|
|
Item(channel=item.channel,
|
|
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Last_2_months,
|
|
action="list_movie",
|
|
url='discover/movie?primary_release_date.gte=%s&primary_release_date.lte=%s&' % (
|
|
YEAR_DATE, MONTH2_TIME),
|
|
plot="1",
|
|
type="movie",
|
|
thumbnail="http://i.imgur.com/CsizqUI.png"),
|
|
Item(channel=item.channel,
|
|
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_List_by_Genre,
|
|
action="list_genres",
|
|
type="movie",
|
|
thumbnail="http://i.imgur.com/uotyBbU.png")]
|
|
|
|
return itemlist
|
|
|
|
|
|
def list_movie(item):
|
|
logger.info(" list_movie '%s/%s'" % (item.url, item.plot))
|
|
|
|
results = [0, 0]
|
|
page = int(item.plot)
|
|
itemlist = build_movie_list(item, tmdb_get_data('%s&page=%d&' % (item.url, page), results=results))
|
|
if page < results[0]:
|
|
itemlist.append(Item(
|
|
channel=item.channel,
|
|
title="[COLOR orange]%s (%d/%d)[/COLOR]" % (NLS_Next_Page, page * len(itemlist), results[1]),
|
|
action="list_movie",
|
|
url=item.url,
|
|
plot="%d" % (page + 1),
|
|
type=item.type,
|
|
viewmode="" if page <= 1 else "paged_list"))
|
|
|
|
return itemlist
|
|
|
|
|
|
def list_tvshow(item):
|
|
logger.info(" list_tvshow '%s/%s'" % (item.url, item.plot))
|
|
|
|
results = [0, 0]
|
|
page = int(item.plot)
|
|
itemlist = build_movie_list(item, tmdb_get_data('%spage=%d&' % (item.url, page), results=results))
|
|
if page < results[0]:
|
|
itemlist.append(Item(
|
|
channel=item.channel,
|
|
title="[COLOR orange]%s (%d/%d)[/COLOR]" % (NLS_Next_Page, page * len(itemlist), results[1]),
|
|
action="list_tvshow",
|
|
url=item.url,
|
|
plot="%d" % (page + 1),
|
|
type=item.type,
|
|
viewmode="" if page <= 1 else "paged_list"))
|
|
|
|
return itemlist
|
|
|
|
|
|
def list_genres(item):
|
|
logger.info(" list_genres")
|
|
|
|
tmdb_genre(1)
|
|
itemlist = []
|
|
for genre_id, genre_name in TMDb_genres.iteritems():
|
|
itemlist.append(
|
|
Item(channel=item.channel,
|
|
title=genre_name,
|
|
action="list_movie",
|
|
url='genre/%d/movies?primary_release_date.gte=%s&primary_release_date.lte=%s&language=it' % (
|
|
genre_id, YEAR_DATE, TODAY_TIME),
|
|
plot="1"))
|
|
|
|
return itemlist
|
|
|
|
|
|
def discover_list(item):
|
|
from platformcode import unify
|
|
from core import scrapertools
|
|
itemlist = []
|
|
|
|
result = tmdb.discovery(item)
|
|
|
|
tvshow = False
|
|
|
|
logger.debug(item)
|
|
|
|
for elem in result:
|
|
elem['tmdb_id'] = elem['id']
|
|
if 'title' in elem:
|
|
title = unify.normalize(elem['title']).capitalize()
|
|
elem['year'] = scrapertools.find_single_match(elem['release_date'], '(\d{4})-\d+-\d+')
|
|
else:
|
|
title = unify.normalize(elem['name']).capitalize()
|
|
tvshow = True
|
|
|
|
new_item = Item(channel='searchall', title=title, infoLabels=elem, action='search_tmdb', extra=title,
|
|
category=config.get_localized_string(70695), context='')
|
|
|
|
if tvshow:
|
|
new_item.contentSerieName = title
|
|
else:
|
|
new_item.contentTitle = title
|
|
|
|
itemlist.append(new_item)
|
|
|
|
tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
|
|
|
|
if item.page != '' and len(itemlist) > 0:
|
|
next_page = str(int(item.page) + 1)
|
|
# if not 'similar' in item.list_type:
|
|
# itemlist.append(item.clone(title='Pagina Siguente', page=next_page))
|
|
# else:
|
|
itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(30992),
|
|
text_color="orange", search_type=item.search_type, list_type=item.list_type,
|
|
type=item.type, page=next_page))
|
|
|
|
return itemlist
|
|
|
|
|
|
# Do not change the name of this function otherwise launcher.py won't create the keyboard dialog required to enter the search terms
|
|
def search(item, search_terms):
|
|
if item.url == '': return []
|
|
|
|
return globals()[item.url](item, search_terms) if item.url in globals() else []
|
|
|
|
|
|
def search_tvshow_by_title(item, search_terms):
|
|
logger.info(" search_tvshow_by_title '%s'" % (search_terms))
|
|
|
|
return list_movie(
|
|
Item(channel=item.channel,
|
|
url='search/tv?query=%s&' % search_terms,
|
|
plot="1",
|
|
type="tvshow"))
|
|
|
|
|
|
def search_movie_by_title(item, search_terms):
|
|
logger.info(" search_movie_by_title '%s'" % (search_terms))
|
|
|
|
return list_movie(
|
|
Item(channel=item.channel,
|
|
url='search/movie?query=%s&' % search_terms,
|
|
plot="1",
|
|
type="movie"))
|
|
|
|
|
|
def search_similar_movie_by_title(item, search_terms):
|
|
logger.info(" search_similar_movie_by_title '%s'" % (search_terms))
|
|
|
|
return list_movie(
|
|
Item(channel=item.channel,
|
|
url='search/movie?append_to_response=similar_movies,alternative_title&query=%s&' % search_terms,
|
|
plot="1",
|
|
type='movie'))
|
|
|
|
|
|
def search_movie_by_year(item):
|
|
logger.info(" search_movie_by_year")
|
|
now = datetime.datetime.now()
|
|
year = int(now.year)
|
|
result = []
|
|
for i in range(150):
|
|
year_to_search = year - i
|
|
result.append(Item(channel=item.channel,
|
|
url='discover/movie?primary_release_year=%s&' % year_to_search,
|
|
plot="1",
|
|
type="movie",
|
|
title="%s" % year_to_search,
|
|
action="list_movie"))
|
|
return result
|
|
|
|
|
|
def search_person_by_name(item, search_terms):
|
|
logger.info(" search_person_by_name '%s'" % (search_terms))
|
|
|
|
persons = tmdb_get_data("search/person?query=%s&" % search_terms)
|
|
|
|
itemlist = []
|
|
for person in persons:
|
|
name = normalize_unicode(tmdb_tag(person, 'name'))
|
|
poster = tmdb_image(person, 'profile_path')
|
|
fanart = ''
|
|
for movie in tmdb_tag(person, 'known_for', []):
|
|
if tmdb_tag_exists(movie, 'backdrop_path'):
|
|
fanart = tmdb_image(movie, 'backdrop_path', 'w1280')
|
|
break
|
|
|
|
# extracmds = [
|
|
# (NLS_Info_Person, "RunScript(script.extendedinfo,info=extendedactorinfo,id=%s)" % str(tmdb_tag(person, 'id')))] \
|
|
# if xbmc.getCondVisibility('System.HasAddon(script.extendedinfo)') else []
|
|
|
|
itemlist.append(Item(
|
|
channel=item.channel,
|
|
action='search_movie_by_person',
|
|
extra=str(tmdb_tag(person, 'id')),
|
|
title=name,
|
|
thumbnail=poster,
|
|
viewmode='list',
|
|
fanart=fanart,
|
|
type='movie'
|
|
# extracmds=extracmds
|
|
))
|
|
|
|
return itemlist
|
|
|
|
|
|
def search_movie_by_person(item):
|
|
logger.info(" search_movie_by_person '%s'" % (item.extra))
|
|
|
|
# return list_movie(
|
|
# Item(channel=item.channel,
|
|
# url="discover/movie?with_people=%s&primary_release_date.lte=%s&sort_by=primary_release_date.desc&" % (
|
|
# item.extra, TODAY_TIME),
|
|
# plot="1"))
|
|
|
|
person_movie_credits = tmdb_get_data(
|
|
"person/%s/movie_credits?primary_release_date.lte=%s&sort_by=primary_release_date.desc&" % (
|
|
item.extra, TODAY_TIME))
|
|
movies = []
|
|
if person_movie_credits:
|
|
movies.extend(tmdb_tag(person_movie_credits, 'cast', []))
|
|
movies.extend(tmdb_tag(person_movie_credits, 'crew', []))
|
|
|
|
# Movie person list is not paged
|
|
return build_movie_list(item, movies)
|
|
|
|
|
|
def search_collection_by_name(item, search_terms):
|
|
logger.info(" search_collection_by_name '%s'" % (search_terms))
|
|
|
|
collections = tmdb_get_data("search/collection?query=%s&" % search_terms)
|
|
|
|
itemlist = []
|
|
for collection in collections:
|
|
name = normalize_unicode(tmdb_tag(collection, 'name'))
|
|
poster = tmdb_image(collection, 'poster_path')
|
|
fanart = tmdb_image(collection, 'backdrop_path', 'w1280')
|
|
|
|
itemlist.append(Item(
|
|
channel=item.channel,
|
|
action='search_movie_by_collection',
|
|
extra=str(tmdb_tag(collection, 'id')),
|
|
title=name,
|
|
thumbnail=poster,
|
|
viewmode='list',
|
|
fanart=fanart,
|
|
type='movie'
|
|
))
|
|
|
|
return itemlist
|
|
|
|
|
|
def search_movie_by_collection(item):
|
|
logger.info(" search_movie_by_collection '%s'" % (item.extra))
|
|
|
|
collection = tmdb_get_data("collection/%s?" % item.extra)
|
|
|
|
# Movie collection list is not paged
|
|
return build_movie_list(item, collection['parts']) if 'parts' in collection else []
|
|
|
|
|
|
def build_movie_list(item, movies):
|
|
if movies is None: return []
|
|
|
|
itemlist = []
|
|
for movie in movies:
|
|
t = tmdb_tag(movie, 'title')
|
|
if t == '':
|
|
t = re.sub('\s(|[(])(UK|US|AU|\d{4})(|[)])$', '', tmdb_tag(movie, 'name'))
|
|
title = normalize_unicode(t)
|
|
title_search = normalize_unicode(t, encoding='ascii')
|
|
if not all(ord(char) < 128 for char in title): continue
|
|
poster = tmdb_image(movie, 'poster_path')
|
|
fanart = tmdb_image(movie, 'backdrop_path', 'w1280')
|
|
jobrole = normalize_unicode(
|
|
' [COLOR yellow][' + tmdb_tag(movie, 'job') + '][/COLOR]' if tmdb_tag_exists(movie, 'job') else '')
|
|
genres = normalize_unicode(
|
|
' / '.join([tmdb_genre(genre).upper() for genre in tmdb_tag(movie, 'genre_ids', [])]))
|
|
year = tmdb_tag(movie, 'release_date')[0:4] if tmdb_tag_exists(movie, 'release_date') else ''
|
|
plot = normalize_unicode(tmdb_tag(movie, 'overview'))
|
|
rating = tmdb_tag(movie, 'vote_average')
|
|
votes = tmdb_tag(movie, 'vote_count')
|
|
|
|
extrameta = {'plot': plot}
|
|
if year != "": extrameta["Year"] = year
|
|
if genres != "": extrameta["Genre"] = genres
|
|
if votes:
|
|
extrameta["Rating"] = rating
|
|
extrameta["Votes"] = "%d" % votes
|
|
|
|
# extracmds = [(NLS_Info_Title, "RunScript(script.extendedinfo,info=extendedinfo,id=%s)" % str(tmdb_tag(movie, 'id')))] \
|
|
# if xbmc.getCondVisibility('System.HasAddon(script.extendedinfo)') else [('Movie/Show Info', 'XBMC.Action(Info)')]
|
|
|
|
found = False
|
|
kodi_db_movies = kodi_database_movies(title)
|
|
for kodi_db_movie in kodi_db_movies:
|
|
logger.info('Kod.database set for local playing(%s):\n%s' % (title, str(kodi_db_movie)))
|
|
if year == str(kodi_db_movie["year"]):
|
|
found = True
|
|
|
|
# If some, less relevant, keys are missing locally
|
|
# try to get them through TMDB anyway.
|
|
try:
|
|
poster = kodi_db_movie["art"]["poster"]
|
|
fanart = kodi_db_movie["art"]["fanart"]
|
|
except KeyError:
|
|
poster = poster
|
|
fanart = fanart
|
|
|
|
itemlist.append(Item(
|
|
channel=item.channel,
|
|
action='play',
|
|
url=kodi_db_movie["file"],
|
|
title='[COLOR orange][%s][/COLOR] ' % NLS_Library + kodi_db_movie["title"] + jobrole,
|
|
thumbnail=poster,
|
|
category=genres,
|
|
plot=plot,
|
|
viewmode='movie_with_plot',
|
|
fanart=fanart,
|
|
infoLabels=extrameta,
|
|
folder=False,
|
|
))
|
|
|
|
if not found:
|
|
logger.info('Kod.database set for channels search(%s)' % title)
|
|
itemlist.append(Item(
|
|
channel=item.channel,
|
|
action='do_channels_search',
|
|
extra=url_quote_plus(title_search) + '{}' + item.type + '{}' + year,
|
|
title=title + jobrole,
|
|
thumbnail=poster,
|
|
category=genres,
|
|
plot=plot,
|
|
viewmode='movie_with_plot',
|
|
fanart=fanart,
|
|
infoLabels=extrameta,
|
|
))
|
|
|
|
return itemlist
|
|
|
|
|
|
def normalize_unicode(string, encoding='utf-8'):
|
|
if string is None: string = ''
|
|
return normalize('NFKD', string if isinstance(string, unicode) else unicode(string, encoding, 'ignore')).encode(
|
|
encoding, 'ignore')
|
|
|
|
|
|
def tmdb_get_data(url="", results=[0, 0], language=True):
|
|
url = TMDB_URL_BASE + "%sinclude_adult=%s&api_key=%s" % (url, INCLUDE_ADULT, TMDB_KEY)
|
|
# Temporary fix until tmdb fixes the issue with getting the genres by language!
|
|
if language: url += "&language=%s" % LANGUAGE_ID
|
|
response = get_json_response(url)
|
|
results[0] = response['total_pages'] if 'total_pages' in response else 0
|
|
results[1] = response['total_results'] if 'total_results' in response else 0
|
|
|
|
if response:
|
|
if "results" in response:
|
|
return response["results"]
|
|
elif "items" in response:
|
|
return response["items"]
|
|
elif "tv_credits" in response:
|
|
return response["tv_credits"]["cast"]
|
|
else:
|
|
return response
|
|
|
|
|
|
def tmdb_tag_exists(entry, tag):
|
|
return isinstance(entry, dict) and tag in entry and entry[tag] is not None
|
|
|
|
|
|
def tmdb_tag(entry, tag, default=""):
|
|
return entry[tag] if isinstance(entry, dict) and tag in entry else default
|
|
|
|
|
|
def tmdb_image(entry, tag, width='original'):
|
|
return TMDB_IMAGES_BASEURL + width + '/' + tmdb_tag(entry, tag) if tmdb_tag_exists(entry, tag) else ''
|
|
|
|
|
|
def tmdb_genre(id):
|
|
if id not in TMDb_genres:
|
|
genres = tmdb_get_data("genre/list?", language="it")
|
|
for genre in tmdb_tag(genres, 'genres', []):
|
|
TMDb_genres[tmdb_tag(genre, 'id')] = tmdb_tag(genre, 'name')
|
|
|
|
return TMDb_genres[id] if id in TMDb_genres and TMDb_genres[id] != None else str(id)
|
|
|
|
|
|
def kodi_database_movies(title):
|
|
json_query = \
|
|
'{"jsonrpc": "2.0",\
|
|
"params": {\
|
|
"sort": {"order": "ascending", "method": "title"},\
|
|
"filter": {"operator": "is", "field": "title", "value": "%s"},\
|
|
"properties": ["title", "art", "file", "year"]\
|
|
},\
|
|
"method": "VideoLibrary.GetMovies",\
|
|
"id": "libMovies"\
|
|
}' % title
|
|
response = get_xbmc_jsonrpc_response(json_query)
|
|
return response["result"]["movies"] if response and "result" in response and "movies" in response["result"] else []
|
|
|
|
|
|
def get_xbmc_jsonrpc_response(json_query=""):
|
|
try:
|
|
response = xbmc.executeJSONRPC(json_query)
|
|
response = unicode(response, 'utf-8', errors='ignore')
|
|
response = json.loads(response)
|
|
logger.info(" jsonrpc %s" % response)
|
|
except Exception, e:
|
|
logger.info(" jsonrpc error: %s" % str(e))
|
|
response = None
|
|
return response
|
|
|
|
|
|
def url_quote_plus(input_string):
|
|
try:
|
|
return urllib.quote_plus(input_string.encode('utf8', 'ignore'))
|
|
except:
|
|
return urllib.quote_plus(unicode(input_string, "utf-8").encode("utf-8"))
|
|
|
|
|
|
def get_json_response(url=""):
|
|
response = httptools.downloadpage(url).data
|
|
try:
|
|
results = json.loads(response)
|
|
except:
|
|
logger.info(" Exception: Could not get new JSON data from %s" % url)
|
|
results = []
|
|
return results
|
|
|
|
|
|
def channel_search(queue, channel_parameters, category, title_year, tecleado):
|
|
try:
|
|
search_results = []
|
|
|
|
title_search = urllib.unquote_plus(tecleado)
|
|
|
|
exec "from specials import " + channel_parameters["channel"] + " as module"
|
|
mainlist = module.mainlist(Item(channel=channel_parameters["channel"]))
|
|
|
|
for item in mainlist:
|
|
if item.action != "search" or category and item.extra != category:
|
|
continue
|
|
|
|
for res_item in module.search(item.clone(), tecleado):
|
|
title = res_item.fulltitle
|
|
|
|
# If the release year is known, check if it matches the year found in the title
|
|
if title_year > 0:
|
|
year_match = re.search('\(.*(\d{4}).*\)', title)
|
|
if year_match and abs(int(year_match.group(1)) - title_year) > 1:
|
|
continue
|
|
|
|
# Clean up a bit the returned title to improve the fuzzy matching
|
|
title = re.sub(r'\(.*\)', '', title) # Anything within ()
|
|
title = re.sub(r'\[.*\]', '', title) # Anything within []
|
|
|
|
# Check if the found title fuzzy matches the searched one
|
|
if fuzz.token_sort_ratio(title_search, title) > 85:
|
|
res_item.title = "[COLOR azure]" + res_item.title + "[/COLOR][COLOR orange] su [/COLOR][COLOR green]" + \
|
|
channel_parameters["title"] + "[/COLOR]"
|
|
search_results.append(res_item)
|
|
|
|
queue.put(search_results)
|
|
|
|
except:
|
|
logger.error("No se puede buscar en: " + channel_parameters["title"])
|
|
import traceback
|
|
logger.error(traceback.format_exc())
|
|
|
|
|
|
def do_channels_search(item):
|
|
logger.info(" do_channels_search")
|
|
|
|
tecleado, category, title_year = item.extra.split('{}')
|
|
|
|
try:
|
|
title_year = int(title_year)
|
|
except:
|
|
title_year = 0
|
|
|
|
itemlist = []
|
|
|
|
channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json')
|
|
logger.info(" channels_path=" + channels_path)
|
|
|
|
# channel_language = config.get_setting("channel_language")
|
|
channel_language = auto_filter()
|
|
logger.info(" channel_language=" + channel_language)
|
|
if channel_language == "":
|
|
channel_language = "all"
|
|
logger.info(" channel_language=" + channel_language)
|
|
|
|
progreso = platformtools.dialog_progress_bg(NLS_Looking_For % urllib.unquote_plus(tecleado))
|
|
|
|
channel_files = sorted(glob.glob(channels_path))
|
|
|
|
search_results = Queue.Queue()
|
|
completed_channels = 0
|
|
number_of_channels = 0
|
|
|
|
start_time = int(time.time())
|
|
|
|
for infile in channel_files:
|
|
|
|
basename_without_extension = os.path.basename(infile)[:-5]
|
|
|
|
channel_parameters = channeltools.get_channel_parameters(basename_without_extension)
|
|
|
|
# No busca si es un canal inactivo
|
|
if channel_parameters["active"] != True:
|
|
continue
|
|
|
|
# En caso de busqueda por categorias
|
|
if category and category not in channel_parameters["categories"]:
|
|
continue
|
|
|
|
# No busca si el canal es en un idioma filtrado
|
|
if channel_language != "all" and channel_parameters["language"] != channel_language:
|
|
continue
|
|
|
|
# No busca si es un canal excluido de la busqueda global
|
|
include_in_global_search = channel_parameters["include_in_global_search"]
|
|
if include_in_global_search == True:
|
|
# Buscar en la configuracion del canal
|
|
include_in_global_search = config.get_setting("include_in_global_search", basename_without_extension)
|
|
if include_in_global_search == False:
|
|
continue
|
|
|
|
t = Thread(target=channel_search, args=[search_results, channel_parameters, category, title_year, tecleado])
|
|
t.setDaemon(True)
|
|
t.start()
|
|
number_of_channels += 1
|
|
|
|
while threading.active_count() >= MAX_THREADS:
|
|
|
|
delta_time = int(time.time()) - start_time
|
|
if len(itemlist) <= 0:
|
|
timeout = None # No result so far,lets the thread to continue working until a result is returned
|
|
elif delta_time >= TIMEOUT_TOTAL:
|
|
progreso.close()
|
|
itemlist = sorted(itemlist, key=lambda item: item.fulltitle)
|
|
return itemlist
|
|
else:
|
|
timeout = TIMEOUT_TOTAL - delta_time # Still time to gather other results
|
|
|
|
progreso.update(completed_channels * 100 / number_of_channels)
|
|
|
|
try:
|
|
itemlist.extend(search_results.get(timeout=timeout))
|
|
completed_channels += 1
|
|
except:
|
|
progreso.close()
|
|
itemlist = sorted(itemlist, key=lambda item: item.fulltitle)
|
|
return itemlist
|
|
|
|
while completed_channels < number_of_channels:
|
|
|
|
delta_time = int(time.time()) - start_time
|
|
if len(itemlist) <= 0:
|
|
timeout = None # No result so far,lets the thread to continue working until a result is returned
|
|
elif delta_time >= TIMEOUT_TOTAL:
|
|
break # At least a result matching the searched title has been found, lets stop the search
|
|
else:
|
|
timeout = TIMEOUT_TOTAL - delta_time # Still time to gather other results
|
|
|
|
progreso.update(completed_channels * 100 / number_of_channels)
|
|
|
|
try:
|
|
itemlist.extend(search_results.get(timeout=timeout))
|
|
completed_channels += 1
|
|
except:
|
|
# Expired timeout raise an exception
|
|
break
|
|
|
|
progreso.close()
|
|
|
|
# todo 1 : impostare una visualizzazione % di avanzamento (serve?)
|
|
# todo 2 : verificare la formattazione dei titoli estratti
|
|
# todo 3 : gestione numero threads e timeout
|
|
if config.get_setting("findlinks") == True and "{}movie{}" in item.extra:
|
|
itemlist = links_list(itemlist)
|
|
itemlist = sorted(itemlist, key=lambda item: item.title.lower())
|
|
else:
|
|
itemlist = sorted(itemlist, key=lambda item: item.fulltitle)
|
|
|
|
return itemlist
|
|
|
|
|
|
def links_list(itemlist):
|
|
logger.info(" links_list")
|
|
itemlistresults = []
|
|
itemlistlist = []
|
|
allthreads = []
|
|
global_search_results = Queue.Queue()
|
|
|
|
# create and collect threads
|
|
for item in itemlist:
|
|
t = Thread(target=list_single_site, args=[global_search_results, item])
|
|
t.setDaemon(True)
|
|
allthreads.append(t)
|
|
|
|
# start threads
|
|
for thread in allthreads:
|
|
try:
|
|
thread.start()
|
|
except:
|
|
logger.error("thread error !")
|
|
|
|
# join threads, to wait all threads end before going on
|
|
for thread in allthreads:
|
|
thread.join()
|
|
|
|
# collect results
|
|
while not global_search_results.empty():
|
|
for item in global_search_results.get():
|
|
if not item_url_in_itemlist(item, itemlistresults):
|
|
channelformatteditem = rewrite_item_title(item)
|
|
if channelformatteditem is not None:
|
|
itemlistresults.append(channelformatteditem)
|
|
|
|
return itemlistresults
|
|
|
|
|
|
def list_single_site(queue, item):
|
|
logger.info(" list_single_site")
|
|
channelitemlist = []
|
|
try:
|
|
# logger.info(item.channel + " start channel search " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
|
module_to_call = getattr(__import__("channels"), item.channel)
|
|
channelitemlist = module_to_call.findvideos(item)
|
|
queue.put(channelitemlist)
|
|
# logger.info(item.channel + " end channel search " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
|
except:
|
|
try:
|
|
# logger.info(item.channel + " start servertools search " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
|
# logger.info("no findvideos defined in channel functions, calling servertools.findvideos to find links")
|
|
servertools_itemlist = []
|
|
headers = [['Referer', item.channel]]
|
|
data = httptools.downloadpage(item.url, headers=headers).data
|
|
list_servertools = servertools.findvideos(data)
|
|
for item_servertools in list_servertools:
|
|
servertools_itemlist.append(Item(channel=item.channel,
|
|
action="play",
|
|
fulltitle=item.title,
|
|
server=item_servertools[0],
|
|
thumbnail=item_servertools[3],
|
|
title=item.title,
|
|
url=item_servertools[1]))
|
|
queue.put(servertools_itemlist)
|
|
# logger.info(item.channel + " end servertools search " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
|
except Exception, e:
|
|
logger.error('exception in list_single_site: ' + str(e))
|
|
return channelitemlist
|
|
|
|
|
|
# utility function
|
|
def item_url_in_itemlist(item, itemlist):
|
|
logger.info(" item_url_in_itemlist")
|
|
i = 0
|
|
while i < len(itemlist):
|
|
if itemlist[i].url == item.url:
|
|
# logger.info("elemento eliminato : " + item.url)
|
|
return True
|
|
i = i + 1
|
|
return False
|
|
|
|
|
|
# utility function, optional
|
|
def rewrite_item_title(item):
|
|
logger.info(" rewrite_item_title")
|
|
if "download" not in item.title.lower():
|
|
item.title = "[COLOR yellow][%s][/COLOR][COLOR orange][%s][/COLOR] %s" % (
|
|
item.server, item.channel, item.fulltitle)
|
|
else:
|
|
return None
|
|
return item
|