- nuovo metodo di override DNS
- aggiunta opzione nascondi server, se usi l'autoplay
- migliorie al codice e fix vari
This commit is contained in:
marco
2020-01-08 19:19:59 +01:00
parent d1cc659707
commit b4376525de
139 changed files with 6078 additions and 8909 deletions
+8 -11
View File
@@ -497,7 +497,7 @@ def autoplay_config(item):
allow_option = True
active_settings = {"id": "active", "label": config.get_localized_string(60079),
"color": "0xffffff99", "type": "bool", "default": False, "enabled": allow_option,
"type": "bool", "default": False, "enabled": allow_option,
"visible": allow_option}
list_controls.append(active_settings)
dict_values['active'] = settings_node.get('active', False)
@@ -507,7 +507,7 @@ def autoplay_config(item):
if not status_language:
status_language = 0
set_language = {"id": "language", "label": config.get_localized_string(60080), "color": "0xffffff99",
set_language = {"id": "language", "label": config.get_localized_string(60080),
"type": "list", "default": 0, "enabled": "eq(-1,true)", "visible": True,
"lvalues": get_languages(item.from_channel)}
@@ -527,7 +527,7 @@ def autoplay_config(item):
else:
enabled = "eq(-3,true)"
custom_servers_settings = {"id": "custom_servers", "label": config.get_localized_string(60081), "color": "0xff66ffcc",
custom_servers_settings = {"id": "custom_servers", "label": config.get_localized_string(60081),
"type": "bool", "default": False, "enabled": enabled, "visible": True}
list_controls.append(custom_servers_settings)
if dict_values['active'] and enabled:
@@ -541,7 +541,7 @@ def autoplay_config(item):
if default > len(server_list) - 1:
default = 0
set_servers = {"id": "server_%s" % num, "label": u" \u2665" + config.get_localized_string(60082) % num,
"color": "0xfffcab14", "type": "list", "default": default,
"type": "list", "default": default,
"enabled": "eq(-%s,true)+eq(-%s,true)" % (pos1, num), "visible": True,
"lvalues": server_list}
list_controls.append(set_servers)
@@ -558,7 +558,7 @@ def autoplay_config(item):
else:
enabled = "eq(-7,true)"
custom_quality_settings = {"id": "custom_quality", "label": config.get_localized_string(60083), "color": "0xff66ffcc",
custom_quality_settings = {"id": "custom_quality", "label": config.get_localized_string(60083),
"type": "bool", "default": False, "enabled": enabled, "visible": True}
list_controls.append(custom_quality_settings)
if dict_values['active'] and enabled:
@@ -573,7 +573,7 @@ def autoplay_config(item):
default = 0
set_quality = {"id": "quality_%s" % num, "label": u" \u2665 Calidad Favorita %s" % num,
"color": "0xfff442d9", "type": "list", "default": default,
"type": "list", "default": default,
"enabled": "eq(-%s,true)+eq(-%s,true)" % (pos1, num), "visible": True,
"lvalues": quality_list}
list_controls.append(set_quality)
@@ -584,16 +584,13 @@ def autoplay_config(item):
# Plan B
dict_values['plan_b'] = settings_node.get('plan_b', False)
enabled = "eq(-4,true)|eq(-8,true)"
plan_b = {"id": "plan_b", "label": config.get_localized_string(70172),
"color": "0xffffff99",
"type": "bool", "default": False, "enabled": enabled, "visible": True}
plan_b = {"id": "plan_b", "label": config.get_localized_string(70172),"type": "bool", "default": False, "enabled": enabled, "visible": True}
list_controls.append(plan_b)
# Seccion Prioridades
priority_list = [config.get_localized_string(70174), config.get_localized_string(70175)]
set_priority = {"id": "priority", "label": config.get_localized_string(60085),
"color": "0xffffff99", "type": "list", "default": 0,
set_priority = {"id": "priority", "label": config.get_localized_string(60085), "type": "list", "default": 0,
"enabled": True, "visible": "eq(-5,true)+eq(-9,true)+eq(-12,true)", "lvalues": priority_list}
list_controls.append(set_priority)
dict_values["priority"] = settings_node.get("priority", 0)
+8 -8
View File
@@ -33,7 +33,7 @@ except:
xbmcgui = None
import xbmc
import re, base64, json, os, inspect
from core import jsontools, tvdb, scrapertoolsV2
from core import jsontools, tvdb, scrapertools
from core.support import typo, log, dbg
from platformcode import config, platformtools, logger
from platformcode.config import get_setting
@@ -118,7 +118,7 @@ def manual_renumeration(item, modify=False):
for item in itemlist:
Title = re.sub(r'\d+x\d+ - ', '', item.title)
if modify == True:
ep = int(scrapertoolsV2.find_single_match(Title, r'(\d+)'))
ep = int(scrapertools.find_single_match(Title, r'(\d+)'))
if item.action == 'findvideos' and not EpisodeDict.has_key(str(ep)):
_list.append(Title)
else:
@@ -138,7 +138,7 @@ def manual_renumeration(item, modify=False):
while not season:
season = platformtools.dialog_numeric(0, config.get_localized_string(70733))
for select in selected:
ep = int(scrapertoolsV2.find_single_match(_list[select], r'(\d+)'))
ep = int(scrapertools.find_single_match(_list[select], r'(\d+)'))
if season == '0':
episode = ''
while not episode:
@@ -219,7 +219,7 @@ def semiautomatic_config_item(item):
selected = platformtools.dialog_multiselect(config.get_localized_string(70734), _list)
# if len(selected) > 0:
for select in selected:
specials.append(int(scrapertoolsV2.find_single_match(_list[select],r'(\d+)')))
specials.append(int(scrapertools.find_single_match(_list[select], r'(\d+)')))
dict_renumerate[TAG_SPECIAL] = specials
# stop = False
@@ -359,7 +359,7 @@ def renumeration (itemlist, item, typography, dict_series, ID, SEASON, EPISODE,
EpisodeDict = {}
for item in itemlist:
if config.get_localized_string(30992) not in item.title:
number = scrapertoolsV2.find_single_match(item.title, r'\d+')
number = scrapertools.find_single_match(item.title, r'\d+')
item.title = typo('0x' + number + ' - ', typography) + item.title
@@ -373,10 +373,10 @@ def renumeration (itemlist, item, typography, dict_series, ID, SEASON, EPISODE,
return error(itemlist)
if TYPE == 'manual' and len(EpisodeDict) < len(itemlist):
EpisodeDict = manual_renumeration(item, True)
if len(EpisodeDict) >= len(itemlist) and EpisodeDict.has_key(scrapertoolsV2.find_single_match(itemlist[0].title, r'\d+')):
if len(EpisodeDict) >= len(itemlist) and EpisodeDict.has_key(scrapertools.find_single_match(itemlist[0].title, r'\d+')):
for item in itemlist:
if config.get_localized_string(30992) not in item.title:
number = scrapertoolsV2.find_single_match(item.title, r'\d+')
number = scrapertools.find_single_match(item.title, r'\d+')
number = int(number) # if number !='0': number.lstrip('0')
item.title = typo(EpisodeDict[str(number)] + ' - ', typography) + item.title
else:
@@ -467,7 +467,7 @@ def make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE
for item in itemlist:
# Otiene Numerazione Episodi
if config.get_localized_string(30992) not in item.title:
episode = int(scrapertoolsV2.find_single_match(item.title, r'\d+'))
episode = int(scrapertools.find_single_match(item.title, r'\d+'))
number = episode + FirstOfSeason - addiction
count = number + addiction
# Crea Dizionario Episodi
+36 -27
View File
@@ -3,7 +3,7 @@
import re, os, inspect, requests, xbmc, xbmcaddon
from core import httptools, scrapertoolsV2, servertools, jsontools, tmdb, support
from core import httptools, scrapertools, servertools, jsontools, tmdb, support
from core.item import Item
from core.support import typo
from channelselector import get_thumb
@@ -240,8 +240,35 @@ def show_menu(item):
return itemlist
def filter_thread(filter,item):
itemlist = []
thumbnail = ''
plot = ''
dict_ = {'url': 'search/person', 'language': lang, 'query': filter, 'page': 1}
tmdb_inf = tmdb.discovery(item, dict_=dict_)
results = tmdb_inf.results[0]
id = results['id']
if id:
thumbnail = 'http://image.tmdb.org/t/p/original' + results['profile_path'] if results['profile_path'] else item.thumbnail
json_file = httptools.downloadpage('http://api.themoviedb.org/3/person/'+ str(id) + '?api_key=' + tmdb_api + '&language=en', use_requests=True).data
plot += jsontools.load(json_file)['biography']
item = Item(channel=item.channel,
title=typo(filter, 'bold'),
url=item.url,
media_type=item.media_type,
action='list_filtered',
thumbnail=thumbnail,
plot=plot,
path=item.path,
filterkey=item.filterkey,
filter=filter)
return item
def submenu(item):
support.log()
from lib.concurrent import futures
itemlist = []
filter_list = []
@@ -262,33 +289,15 @@ def submenu(item):
for f in media[item.filterkey]:
if f not in filter_list:
filter_list.append(f)
filter_list.sort()
support.log(filter_list)
for filter in filter_list:
thumbnail = ''
plot = ''
if item.filterkey in ['director','actors']:
tmdb.set_infoLabels(itemlist, seekTmdb=True)
load_info = load_json('http://api.themoviedb.org/3/search/person/?api_key=' + tmdb_api + '&language=' + lang + '&query=' + filter)
id = str(load_info['results'][0]['id']) if load_info.has_key('results') else ''
if id:
info = load_json('http://api.themoviedb.org/3/person/'+ id + '?api_key=' + tmdb_api + '&language=' + lang) if id else ''
if info.has_key('biography') and not info['biography']:
bio = load_json('http://api.themoviedb.org/3/person/'+ id + '?api_key=' + tmdb_api + '&language=en')['biography']
thumbnail = 'https://image.tmdb.org/t/p/w600_and_h900_bestv2' + info['profile_path'] if info['profile_path'] else item.thumbnail
plot += info['biography'] if info['biography'] else bio if bio else ''
itemlist.append(Item(channel=item.channel,
title=typo(filter, 'bold'),
url=item.url,
media_type=item.media_type,
action='list_filtered',
thumbnail=thumbnail,
plot=plot,
path=item.path,
filterkey=item.filterkey,
filter=filter))
with futures.ThreadPoolExecutor() as executor:
List = [executor.submit(filter_thread, filter, item) for filter in filter_list]
for res in futures.as_completed(List):
if res.result():
itemlist.append(res.result())
itemlist = sorted(itemlist, key=lambda it: it.title)
return itemlist
@@ -751,7 +760,7 @@ def set_title(title, language, quality):
def format_title(title):
t = scrapertoolsV2.find_single_match(title, r'\{([^\}]+)\}')
t = scrapertools.find_single_match(title, r'\{([^\}]+)\}')
if 'bold' not in t: t += ' bold'
title = re.sub(r'(\{[^\}]+\})','',title)
return typo(title,t)
+151 -35
View File
@@ -1,40 +1,156 @@
# -*- coding: utf-8 -*-
# -*- OVERRIDE RESOLVE DNS -*-
import os
import ssl
import urlparse
from platformcode import config
from lib.requests_toolbelt.adapters import host_header_ssl
# from lib import cloudscraper
from lib import doh
from platformcode import logger, config
import requests
if config.get_setting('resolver_dns'):
import xbmc
from lib import dns
from dns import resolver, name
from dns.resolver import override_system_resolver
from core import support
try:
import _sqlite3 as sql
except:
import sqlite3 as sql
support.log("platform Android: {}".format(xbmc.getCondVisibility('System.Platform.Android')))
if xbmc.getCondVisibility('System.Platform.Android') == True:
res = resolver.Resolver(filename='/system/etc/resolv.conf', configure=True)
#res = resolver.Resolver(filename='/system/etc/dhcpcd/dhcpcd-hooks/20-dns.conf', configure=True)
else:
res = resolver.Resolver(configure=True)
#legge le impostazioni dalla configurazione e setta i relativi DNS
if config.get_setting('resolver_dns_custom') and not config.get_setting('resolver_dns_service_choose'):
res.nameservers = [config.get_setting('resolver_dns_custom1'),config.get_setting('resolver_dns_custom2')]
else:
nameservers_dns = config.get_setting('resolver_dns_service')
if nameservers_dns == 1:# 'Google'
res.nameservers = ['8.8.8.8', '2001:4860:4860::8888',
'8.8.4.4', '2001:4860:4860::8844']
elif nameservers_dns == 2:#'OpenDns Home ip(v4)'
res.nameservers = ['208.67.222.222', '208.67.222.220']
elif nameservers_dns == 3:#'OpenDns Family Shield ip(v4)':
res.nameservers = ['208.67.222.123', '208.67.220.123']
elif nameservers_dns == 4:#'OpenDns ip(v6)'
#https://support.opendns.com/hc/en-us/articles/227986667-Does-OpenDNS-Support-IPv6-
res.nameservers = ['2620:119:35::35', '2620:119:53::53']
else:#if nameservers_dns == 0:#'Cloudflare'
res.nameservers = ['1.1.1.1', '2606:4700:4700::1111',
'1.0.0.1', '2606:4700:4700::1001']
# log di verifica dei DNS impostati, d'aiuto quando gli utenti smanettano...
support.log("NAME SERVER: {}".format(res.nameservers))
db = os.path.join(config.get_data_path(), 'kod_db.sqlite')
override_system_resolver(res)
class CustomSocket(ssl.SSLSocket):
def __init__(self, *args, **kwargs):
super(CustomSocket, self).__init__(*args, **kwargs)
class CustomContext(ssl.SSLContext):
def __init__(self, protocol, hostname, *args, **kwargs):
self.hostname = hostname
super(CustomContext, self).__init__(protocol)
def wrap_socket(self, sock, server_side=False,
do_handshake_on_connect=True,
suppress_ragged_eofs=True,
server_hostname=None):
return CustomSocket(sock=sock, server_side=server_side,
do_handshake_on_connect=do_handshake_on_connect,
suppress_ragged_eofs=suppress_ragged_eofs,
server_hostname=self.hostname,
_context=self)
class CipherSuiteAdapter(host_header_ssl.HostHeaderSSLAdapter):
def __init__(self, hostname, *args, **kwargs):
self.ssl_context = kwargs.pop('ssl_context', None)
self.cipherSuite = kwargs.pop('cipherSuite', None)
self.hostname = hostname
if not self.ssl_context:
self.ssl_context = CustomContext(ssl.PROTOCOL_TLS, hostname)
self.ssl_context.set_ciphers(self.cipherSuite)
super(CipherSuiteAdapter, self).__init__(**kwargs)
def init_poolmanager(self, *args, **kwargs):
kwargs['ssl_context'] = self.ssl_context
return super(CipherSuiteAdapter, self).init_poolmanager(*args, **kwargs)
def proxy_manager_for(self, *args, **kwargs):
kwargs['ssl_context'] = self.ssl_context
return super(CipherSuiteAdapter, self).proxy_manager_for(*args, **kwargs)
class session(requests.Session):
def __init__(self, *args, **kwargs):
self.conn = sql.connect(db)
self.cur = self.conn.cursor()
super(session, self).__init__(*args, **kwargs)
def getIp(self, domain):
ip = None
try:
self.cur.execute('select ip from dnscache where domain=?', (domain,))
ip = self.cur.fetchall()[0][0]
logger.info('Cache DNS: ' + domain + ' = ' + str(ip))
except:
pass
if not ip: # not cached
try:
ip = doh.query(domain)[0]
logger.info('Query DoH: ' + domain + ' = ' + str(ip))
self.writeToCache(domain, ip)
except Exception:
logger.error('Failed to resolve hostname, fallback to normal dns')
import traceback
logger.error(traceback.print_exc())
ip = domain
return ip
def writeToCache(self, domain, ip):
try:
self.cur.execute('insert into dnscache values(?,?)', (domain, ip))
except:
self.cur.execute("""CREATE TABLE IF NOT EXISTS dnscache(
"domain" TEXT NOT NULL UNIQUE,
"ip" TEXT NOT NULL,
PRIMARY KEY("domain")
);""")
self.conn.commit()
def flushDns(self, method, realUrl, domain, **kwargs):
self.cur.execute('delete from dnscache where domain=?', (domain,))
self.conn.commit()
return self.request(method, realUrl, flushedDns=True, **kwargs)
def request(self, method, url, headers=None, flushedDns=False, **kwargs):
try:
parse = urlparse.urlparse(url)
except:
raise requests.exceptions.InvalidURL
if parse.netloc:
domain = parse.netloc
else:
raise requests.exceptions.URLRequired
ip = self.getIp(domain)
self.mount('https://', CipherSuiteAdapter(domain, cipherSuite='ALL'))
realUrl = url
if headers:
headers["Host"] = domain
else:
headers = {"Host": domain}
ret = None
tryFlush = False
parse = list(parse)
parse[1] = ip
url = urlparse.urlunparse(parse)
allow_redirects = kwargs.get('allow_redirects', True)
if 'allow_redirects' in kwargs:
del kwargs['allow_redirects']
try:
ret = super(session, self).request(method, url, headers=headers, allow_redirects=False, **kwargs)
newUrl = urlparse.urlparse(ret.headers.get('Location', realUrl))
if not newUrl.netloc and not newUrl.scheme:
newUrl = list(newUrl)
newUrl[0] = 'https://'
newUrl[1] = domain
newUrl = urlparse.urlunparse(newUrl)
if allow_redirects:
redirectN = 0
while newUrl != realUrl and redirectN < self.max_redirects:
ret = self.request(method, newUrl, headers=headers, **kwargs)
newUrl = ret.headers.get('Location', realUrl)
redirectN += 1
ret.url = newUrl
except Exception as e:
logger.info('Request for ' + domain + ' with ip ' + ip + ' failed')
logger.info(e)
tryFlush = True
if (tryFlush or not ret) and not flushedDns: # re-request ips and update cache
logger.info('Flushing dns cache for ' + domain)
return self.flushDns(method, realUrl, domain, **kwargs)
if not ret:
raise requests.exceptions.RequestException
return ret
+6 -2
View File
@@ -181,8 +181,12 @@ def channel_search(item):
channel_list, channel_titles = get_channels(item)
from lib import cloudscraper
session = cloudscraper.create_scraper()
if config.get_setting('resolver_dns'):
from specials import resolverdns
session = resolverdns.session()
else:
import requests
session = requests.Session()
searching += channel_list
searching_titles += channel_titles
-866
View File
@@ -1,866 +0,0 @@
# -*- 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_language not in str(channel_parameters["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
+6 -6
View File
@@ -311,11 +311,10 @@ def submenu_tools(item):
itemlist.append(Item(channel='custom', action='mainlist', title='Custom Channel'))
#Disabilitato il menu degli aggiornamenti
#itemlist.append(Item(channel=CHANNELNAME, action="check_quickfixes", folder=False,
# title=config.get_localized_string(30001), plot="Versión actual: %s" % config.get_addon_version() ))
itemlist.append(Item(channel=CHANNELNAME, action="update_quasar", folder=False,
title=config.get_localized_string(70569)))
itemlist.append(Item(channel=CHANNELNAME, action="check_quickfixes", folder=False,
title=config.get_localized_string(30001), plot=config.get_addon_version(with_fix=True) ))
# itemlist.append(Item(channel=CHANNELNAME, action="update_quasar", folder=False,
# title=config.get_localized_string(70569)))
itemlist.append(Item(channel=CHANNELNAME, action="", title="", folder=False,
thumbnail=get_thumb("setting_0.png")))
@@ -344,7 +343,8 @@ def check_quickfixes(item):
if not config.dev_mode():
from platformcode import updater
return updater.check_addon_init()
if not updater.timer(True):
platformtools.dialog_ok('Kodi on Demand', config.get_localized_string(70667))
else:
return False