Files
addon/specials/downloads.py
Alhaziel01 bbf7cabc35 Fix Dialogs
2020-08-18 11:34:17 +02:00

1142 lines
50 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Download manager
# ------------------------------------------------------------
from __future__ import division
#from builtins import str
import sys, os
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
from future.builtins import filter
from past.utils import old_div
import re, time, unicodedata, 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, platformtools
from core.support import log, dbg, typo
from servers import torrent
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]"
extensions_list = ['.aaf', '.3gp', '.asf', '.avi', '.flv', '.mpeg', '.m1v', '.m2v', '.m4v', '.mkv', '.mov', '.mpg', '.mpe', '.mp4', '.ogg', '.wmv']
def mainlist(item):
log()
itemlist = []
# File list
for file in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
# We skip all the non JSON
if not file.endswith(".json"): continue
# we load the item
file = filetools.join(DOWNLOAD_LIST_PATH, file)
i = Item(path=file).fromjson(filetools.read(file))
i.thumbnail = i.contentThumbnail
# Main listing
if not item.contentType == "tvshow":
# Series
if i.contentType == "episode":
# We check that the series is not already in the itemlist
if not [x for x in itemlist if x.contentSerieName == i.contentSerieName and x.contentChannel == i.contentChannel]:
title = TITLE_TVSHOW % (STATUS_COLORS[i.downloadStatus], i.downloadProgress, i.contentSerieName, i.contentChannel)
itemlist.append(Item(title=title, channel="downloads", action="mainlist", contentType="tvshow",
contentSerieName=i.contentSerieName, contentChannel=i.contentChannel,
downloadStatus=i.downloadStatus, downloadProgress=[i.downloadProgress],
fanart=i.fanart, thumbnail=i.thumbnail))
else:
s = [x for x in itemlist if x.contentSerieName == i.contentSerieName and x.contentChannel == i.contentChannel][0]
s.downloadProgress.append(i.downloadProgress)
downloadProgress = old_div(sum(s.downloadProgress), len(s.downloadProgress))
if not s.downloadStatus in [STATUS_CODES.error, STATUS_CODES.canceled] and not i.downloadStatus in [
STATUS_CODES.completed, STATUS_CODES.stoped]:
s.downloadStatus = i.downloadStatus
s.title = TITLE_TVSHOW % (STATUS_COLORS[s.downloadStatus], downloadProgress, i.contentSerieName, i.contentChannel)
# Movies
elif i.contentType == "movie" or i.contentType == "video":
i.title = TITLE_FILE % (STATUS_COLORS[i.downloadStatus], i.downloadProgress, i.contentTitle)
itemlist.append(i)
# Listed within a series
else:
if i.contentType == "episode" and i.contentSerieName == item.contentSerieName and i.contentChannel == item.contentChannel:
i.title = TITLE_FILE % (STATUS_COLORS[i.downloadStatus], i.downloadProgress, "%dx%0.2d: %s" % (i.contentSeason, i.contentEpisodeNumber, i.contentTitle))
itemlist.append(i)
estados = [i.downloadStatus for i in itemlist]
# If there is any completed
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, thumbnail=get_thumb('delete.png'),
contentSerieName=item.contentSerieName, text_color=STATUS_COLORS[STATUS_CODES.completed]))
# If there is any 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, thumbnail=get_thumb('update.png'),
contentSerieName=item.contentSerieName, text_color=STATUS_COLORS[STATUS_CODES.error]))
# If there is any pending
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, 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, 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'), thumbnail=get_thumb('search.png'), url=DOWNLOAD_PATH))
if not item.contentType == "tvshow":
itemlist.append(Item(channel='shortcuts', action="SettingOnPosition", category=6, 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
def settings(item):
ret = platformtools.show_channel_settings(caption=config.get_localized_string(70224))
platformtools.itemlist_refresh()
return ret
def browser(item):
log()
itemlist = []
for file in filetools.listdir(item.url):
if file == "list": continue
if filetools.isdir(filetools.join(item.url, file)):
itemlist.append(Item(channel=item.channel, title=file, action=item.action, url=filetools.join(item.url, file), context=[{ 'title': config.get_localized_string(30037), 'channel': 'downloads', 'action': "del_dir"}]))
else:
if not item.infoLabels:
infoLabels = {"mediatype":"video"}
else:
infoLabels = item.infoLabels
itemlist.append(Item(channel=item.channel, title=file, action="play", infoLabels=infoLabels, url=filetools.join(item.url, file), context=[{ 'title': config.get_localized_string(30039), 'channel': 'downloads', 'action': "del_file"}]))
return itemlist
def del_file(item):
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):
log()
stop_all()
removeFiles = False
if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(30300)):
removeFiles = True
for File in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
if File.endswith(".json"):
download_item = Item().fromjson(filetools.read(filetools.join(DOWNLOAD_LIST_PATH, File)))
if not item.contentType == "tvshow" or ( item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel):
filetools.remove(filetools.join(DOWNLOAD_LIST_PATH, File))
if removeFiles:
filetools.remove(filetools.join(DOWNLOAD_PATH, download_item.downloadFilename))
dirName = filetools.join(DOWNLOAD_PATH, filetools.dirname(download_item.downloadFilename))
if len(filetools.listdir(dirName)) == 0:
filetools.rmdir(dirName)
xbmc.sleep(100)
platformtools.itemlist_refresh()
def reload(item):
platformtools.itemlist_refresh()
def stop_all(item=None):
log()
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.TorrentName:
from inspect import stack
if stack()[1][3] == 'clean_all': action = 'delete'
else: action = 'pause'
torrent.elementum_actions(action, download_item.TorrentName)
if download_item.downloadStatus == 4:
update_json(filetools.join(DOWNLOAD_LIST_PATH, fichero), {"downloadStatus": STATUS_CODES.stoped})
xbmc.sleep(300)
if item:
platformtools.itemlist_refresh()
def clean_ready(item):
log()
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 not item.contentType == "tvshow" or ( item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel):
if download_item.downloadStatus == STATUS_CODES.completed:
filetools.remove(filetools.join(DOWNLOAD_LIST_PATH, fichero))
platformtools.itemlist_refresh()
def restart_error(item):
log()
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 not item.contentType == "tvshow" or ( item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel):
if download_item.downloadStatus == STATUS_CODES.error:
if filetools.isfile(
filetools.join(DOWNLOAD_PATH, download_item.downloadFilename)):
filetools.remove(
filetools.join(DOWNLOAD_PATH, download_item.downloadFilename))
update_json(item.path, {"downloadStatus": STATUS_CODES.stoped, "downloadComplete": 0, "downloadProgress": 0})
platformtools.itemlist_refresh()
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(
filetools.read(filetools.join(DOWNLOAD_LIST_PATH, fichero)))
if not item.contentType == "tvshow" or ( 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()
# If canceled, we stop
if res == STATUS_CODES.canceled: break
def menu(item):
log(item)
if item.downloadServer:
servidor = item.downloadServer.get("server", "Auto")
else:
servidor = "Auto"
# Options available for the 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(60220),
config.get_localized_string(60221)]
opciones = []
# Options for the menu
if item.downloadStatus == STATUS_CODES.stoped:
opciones.append(op[0]) # Download
if not item.server: opciones.append(op[3]) # Choose Server
opciones.append(op[1]) # Remove from the list
if item.downloadStatus == STATUS_CODES.canceled:
opciones.append(op[0]) # Download
if not item.server: opciones.append(op[3]) # Choose Server
opciones.append(op[2]) # Restart download
opciones.append(op[1]) # Remove from the list
if item.downloadStatus == STATUS_CODES.completed:
opciones.append(op[5]) # Play
opciones.append(op[1]) # Remove from the list
opciones.append(op[2]) # Restart download
if item.downloadStatus == STATUS_CODES.error: # Download with error
opciones.append(op[2]) # Restart download
opciones.append(op[1]) # Remove from the list
if item.downloadStatus == STATUS_CODES.downloading:
opciones.append(op[5]) # Play
opciones.append(op[4]) # Pause Download
opciones.append(op[1]) # Remove from the list
# Show Dialog
seleccion = platformtools.dialog_select(config.get_localized_string(30163), opciones)
logger.log('SELECTION: '+ op[seleccion])
# -1 is cancel
if seleccion == -1: return
# Delete
if opciones[seleccion] == op[1]:
filetools.remove(item.path)
if item.TorrentName:
torrent.elementum_actions('delete', item.TorrentName)
else:
if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(30300)):
filetools.remove(filetools.join(DOWNLOAD_PATH, item.downloadFilename))
# Start Download
if opciones[seleccion] == op[0]:
item.action = "start_download"
xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")")
# Select Server
if opciones[seleccion] == op[3]:
select_server(item)
# Restart Download
if opciones[seleccion] == op[2]:
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": {}})
if opciones[seleccion] == op[4]:
if item.TorrentName:
torrent.elementum_actions('pause', item.TorrentName)
update_json(item.path, {"downloadStatus": STATUS_CODES.stoped})
if opciones[seleccion] == op[5]:
path = filetools.join(DOWNLOAD_PATH, item.downloadFilename)
if filetools.isdir(path):
videos = []
files = filetools.listdir(path)
for f in files:
if os.path.splitext(f)[-1] in extensions_list:
videos.append(f)
if len(videos) > 1:
selection = platformtools.dialog_select(config.get_localized_string(30034), files)
else:
selection = 0
xbmc.executebuiltin('PlayMedia(' + filetools.join(path, files[selection]) + ',resume)')
else:
xbmc.executebuiltin('PlayMedia(' + path + ',resume)')
if opciones[seleccion] != op[5]:
platformtools.itemlist_refresh()
def move_to_libray(item):
log()
if item.contentType == 'movie':
FOLDER = FOLDER_MOVIES
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 = os.path.dirname(item.downloadFilename)
move_path = filetools.join(config.get_videolibrary_path(), FOLDER)
download_path = filetools.join(DOWNLOAD_PATH, item.downloadFilename)
library_path = filetools.join(move_path, *filetools.split(item.downloadFilename))
final_path = download_path
if not filetools.isdir(filetools.dirname(library_path)):
filetools.mkdir(filetools.dirname(library_path))
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, silent=True)
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], silent=True)
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, silent=True):
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)
log('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:
path_list = [file_strm_path]
xbmc_videolibrary.clean(path_list)
xbmc_videolibrary.update(FOLDER, path_title)
def update_json(path, params):
item = Item().fromjson(filetools.read(path))
item.__dict__.update(params)
filetools.write(path, item.tojson())
def save_server_statistics(server, speed, success):
if filetools.isfile(STATS_FILE):
servers = jsontools.load(filetools.read(STATS_FILE))
else:
servers = {}
if not server in servers:
servers[server] = {"success": [], "count": 0, "speeds": [], "last": 0}
servers[server]["count"] += 1
servers[server]["success"].append(bool(success))
servers[server]["success"] = servers[server]["success"][-5:]
servers[server]["last"] = time.time()
if success:
servers[server]["speeds"].append(speed)
servers[server]["speeds"] = servers[server]["speeds"][-5:]
filetools.write(STATS_FILE, jsontools.dump(servers))
return
def get_server_position(server):
if filetools.isfile(STATS_FILE):
servers = jsontools.load(filetools.read(STATS_FILE))
else:
servers = {}
if server in servers:
pos = [s for s in sorted(servers, key=lambda x: (old_div(sum(servers[x]["speeds"]), (len(servers[x]["speeds"]) or 1)), float(sum(servers[x]["success"])) / ( len(servers[x]["success"]) or 1)), reverse=True)]
return pos.index(server) + 1
else:
return 0
def get_match_list(data, match_list, order_list=None, only_ascii=False, ignorecase=False):
"""
Search for matches in a text string, with a dictionary of "ID" / "List of search strings":
    {"ID1": ["String 1", "String 2", "String 3"],
      "ID2": ["String 4", "String 5", "String 6"]
    }
    The dictionary could not contain the same search string in several IDs.
    The search is performed in order of search string size (from longest to shortest) if a string matches,
    it is removed from the search string for the following, so that two categories are not detected if one string is part of another:
    for example: "Spanish Language" and "Spanish" if the first appears in the string "Pablo knows how to speak the Spanish Language"
    It will match "Spanish Language" but not "Spanish" since the longest match has priority.
"""
match_dict = dict()
matches = []
# We pass the string to unicode
if not PY3:
data = unicode(data, "utf8")
# We pass the dictionary to {"String 1": "ID1", "String 2", "ID1", "String 4", "ID2"} and we pass them to unicode
for key in match_list:
if order_list and not key in order_list:
raise Exception("key '%s' not in match_list" % key)
for value in match_list[key]:
if value in match_dict:
raise Exception("Duplicate word in list: '%s'" % value)
if not PY3:
match_dict[unicode(value, "utf8")] = key
else:
match_dict[value] = key
# If ignorecase = True, we pass everything to capital letters
if ignorecase:
data = data.upper()
match_dict = dict((key.upper(), match_dict[key]) for key in match_dict)
# If ascii = True, we remove all accents and Ñ
if only_ascii:
data = ''.join((c for c in unicodedata.normalize('NFD', data) if unicodedata.category(c) != 'Mn'))
match_dict = dict((''.join((c for c in unicodedata.normalize('NFD', key) if unicodedata.category(c) != 'Mn')), match_dict[key]) for key in match_dict)
# We sort the list from largest to smallest and search.
for match in sorted(match_dict, key=lambda x: len(x), reverse=True):
s = data
for a in matches:
s = s.replace(a, "")
if match in s:
matches.append(match)
if matches:
if order_list:
return type("Mtch_list", (), {"key": match_dict[matches[-1]], "index": order_list.index(match_dict[matches[-1]])})
else:
return type("Mtch_list", (), {"key": match_dict[matches[-1]], "index": None})
else:
if order_list:
return type("Mtch_list", (), {"key": None, "index": len(order_list)})
else:
return type("Mtch_list", (), {"key": None, "index": None})
def sort_method(item):
"""
Score each item based on various parameters:
@type item: item
@param item: item to be valued.
@return: punctuation obtained
@rtype: int
"""
lang_orders = {}
lang_orders['ITA'] = ["ITA", "Sub-ITA"]
lang_orders['Sub-ITA'] = ["ITA", "Sub-ITA"]
quality_orders = {}
quality_orders[0] = ["BLURAY", "FULLHD", "HD", "480P", "360P", "240P"]
quality_orders[1] = ["FULLHD", "HD", "480P", "360P", "240P", "BLURAY"]
quality_orders[2] = ["HD", "480P", "360P", "240P", "FULLHD", "BLURAY"]
quality_orders[3] = ["480P", "360P", "240P", "BLURAY", "FULLHD", "HD"]
order_list_idiomas = lang_orders[config.get_setting("language")]
match_list_idimas = {"ITA": ["ITA", "IT", "Italiano", "italiano", "ITALIANO"],
"Sub-ITA": ["Sottotitolato", "SUB", "sub-ita", "SUB-ITA", "Sub-ITA", "Sub-Ita"]}
order_list_calidad = ["BLURAY", "FULLHD", "HD", "480P", "360P", "240P"]
order_list_calidad = quality_orders[int(config.get_setting("quality"))]
match_list_calidad = {"BLURAY": ["BR", "BLURAY", '4K'],
"FULLHD": ["FULLHD", "FULL HD", "1080", "HD1080", "HD 1080", "1080p"],
"HD": ["HD", "HD REAL", "HD 720", "720", "HDTV", "720p"],
"480P": ["SD", "480P", '480', 'NORMAL'],
"360P": ["360P", "360", 'MOBILE'],
"240P": ["240P", "240"]}
value = (get_match_list(item.title, match_list_idimas, order_list_idiomas, ignorecase=True, only_ascii=True).index, \
get_match_list(item.title, match_list_calidad, order_list_calidad, ignorecase=True, only_ascii=True).index)
if config.get_setting("server_speed"):
value += tuple([get_server_position(item.server)])
return value
def download_from_url(url, item):
log("Attempting to download:", url)
if url.lower().split('|')[0].endswith(".m3u8") or url.lower().startswith("rtmp"):
save_server_statistics(item.server, 0, False)
platformtools.dialog_notification('m3u8 Download',config.get_localized_string(60364), sound=False)
return {"downloadStatus": STATUS_CODES.error}
# We get the download path and the file name
item.downloadFilename = item.downloadFilename
download_path = filetools.dirname(filetools.join(DOWNLOAD_PATH, item.downloadFilename))
file_name = filetools.basename(filetools.join(DOWNLOAD_PATH, item.downloadFilename))
# We create the folder if it does not exist
if not filetools.exists(download_path):
filetools.mkdir(download_path)
# We launch the download
d = Downloader(url, download_path, file_name,
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")),
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))
# Download stopped. We get the state:
# Download failed
if d.state == d.states.error:
log("Error trying to download", url)
status = STATUS_CODES.error
# Download has stopped
elif d.state == d.states.stopped:
log("Stop download")
status = STATUS_CODES.canceled
# Download is complete
elif d.state == d.states.completed:
log("Downloaded correctly")
status = STATUS_CODES.completed
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)
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],
"downloadProgress": d.progress, "downloadCompleted": d.downloaded[0], "downloadFilename": file}
def download_from_server(item):
log(item.tostring())
unsupported_servers = ["torrent"]
if item.contentChannel == 'local':
return {"downloadStatus": STATUS_CODES.completed}
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:
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 + '\n' + 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:
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:
log("There is nothing to reproduce")
return {"downloadStatus": STATUS_CODES.error}
finally:
progreso.close()
log("contentAction: %s | contentChannel: %s | server: %s | url: %s" % (item.contentAction, item.contentChannel, item.server, item.url))
if item.server == 'torrent':
import xbmcgui
xlistitem = xbmcgui.ListItem(path=item.url)
xlistitem.setArt({'icon': item.thumbnail, 'thumb': item.thumbnail, 'poster': item.thumbnail, 'fanart': item.thumbnail})
platformtools.set_infolabels(xlistitem, item)
platformtools.play_torrent(item, xlistitem, item.url)
if not item.server or not item.url or not item.contentAction == "play" or item.server in unsupported_servers:
logger.error("The Item does not contain the necessary parameters.")
return {"downloadStatus": STATUS_CODES.error}
if not item.video_urls:
video_urls, puedes, motivo = servertools.resolve_video_urls_for_playing(item.server, item.url, item.password, True, True)
else:
video_urls, puedes, motivo = item.video_urls, True, ""
# If it is not available, we go out
if not puedes:
log("The video is NOT available")
return {"downloadStatus": STATUS_CODES.error}
else:
log("YES Video is available")
result = {}
# Go through all the options until I can download one correctly
for video_url in reversed(video_urls):
result = download_from_url(video_url[1], item)
if result["downloadStatus"] in [STATUS_CODES.canceled, STATUS_CODES.completed]:
break
# Download error, we continue with the next option
if result["downloadStatus"] == STATUS_CODES.error:
continue
# We return the state
return result
def download_from_best_server(item):
log("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))
try:
if item.downloadItemlist:
log('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) + '\n' + 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))
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) + '\n' + config.get_localized_string(70181) % len(play_items))
# if config.get_setting("server_reorder", "downloads") == 1:
play_items.sort(key=sort_method)
# if progreso.iscanceled():
# return {"downloadStatus": STATUS_CODES.canceled}
finally:
progreso.close()
# We go through the list of servers, until we find one that works
for play_item in play_items:
play_item = item.clone(**play_item.__dict__)
play_item.contentAction = play_item.action
play_item.infoLabels = item.infoLabels
result = download_from_server(play_item)
# if progreso.iscanceled():
# result["downloadStatus"] = STATUS_CODES.canceled
# Whether the download is canceled or completed, we stop trying more options
if result["downloadStatus"] in [STATUS_CODES.canceled, STATUS_CODES.completed]:
result["downloadServer"] = {"url": play_item.url, "server": play_item.server}
break
return result
def select_server(item):
if item.server:
return "Auto"
log("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:
log('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) + '\n' + 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))
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) + '\n' + 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)
if len(play_items) == 1:
# if there is only one server select it
seleccion = 1
else:
# otherwise it shows the selection window
seleccion = platformtools.dialog_select(config.get_localized_string(70192), ["Auto"] + [s.title for s in play_items])
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": {}})
return 'Auto'
# platformtools.itemlist_refresh()
def start_download(item):
log("contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url))
# We already have a server, we just need to download
if item.contentAction == "play":
ret = download_from_server(item)
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"))
# We don't have a server, we need to find the best
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"]
def get_episodes(item):
log("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
# The item we want to download NOW is an episode
if item.contentType == "episode":
episodes = [item.clone()]
# The item is a series or season
elif item.contentType in ["tvshow", "season"]:
if item.downloadItemlist:
episodes = [Item().fromurl(i) for i in item.downloadItemlist]
else:
# The item is a series or season...
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])
# We get the list of episodes
episodes = getattr(channel, item.contentAction)(item)
itemlist = []
if episodes and not scrapertools.find_single_match(episodes[0].title, r'(\d+.\d+)') and item.channel not in ['videolibrary'] and item.action != 'season':
from specials.autorenumber import select_type, renumber, check
# support.dbg()
if not check(item):
select_type(item)
return get_episodes(item)
else:
renumber(episodes, item)
# We get the list of episodes...
for episode in episodes:
# If we started from an item that was already an episode, this data is already good, it should not be modified
if item.contentType != "episode":
episode.contentAction = episode.action
episode.contentChannel = episode.channel
# If the result is a season, it is not worth it, we have to download the episodes of each season
if episode.contentType == "season":
itemlist.extend(get_episodes(episode))
# If the result is an episode is already what we need, we prepare it to add it to the download
if episode.contentType == "episode":
# We pass the id to the episode
if not episode.infoLabels["tmdb_id"]:
episode.infoLabels["tmdb_id"] = item.infoLabels["tmdb_id"]
# Episode, Season and Title
if not episode.contentSeason or not episode.contentEpisodeNumber:
season_and_episode = scrapertools.get_season_and_episode(episode.title)
if season_and_episode:
episode.contentSeason = season_and_episode.split("x")[0]
episode.contentEpisodeNumber = season_and_episode.split("x")[1]
# Episode, Season and Title...
if item.infoLabels["tmdb_id"]:
scraper.find_and_set_infoLabels(episode)
# Episode, Season and Title
if not episode.contentTitle:
episode.contentTitle = re.sub(r"\[[^\]]+\]|\([^\)]+\)|\d*x\d*\s*-", "", episode.title).strip()
episode.downloadFilename = filetools.validate_path(filetools.join(item.downloadFilename, "%dx%0.2d - %s" % (episode.contentSeason, episode.contentEpisodeNumber, episode.contentTitle.strip())))
if season:
if episode.contentSeason == int(season_number):
itemlist.append(episode)
else:
itemlist.append(episode)
# Any other result is not worth it, we ignore it
else:
log("Omitiendo item no válido:", episode.tostring())
# Any other result is not worth it, we ignore it...
itemlist = videolibrarytools.filter_list(itemlist)
return itemlist
def write_json(item):
log()
channel = item.from_channel if item.from_channel else item.channel
item.action = "menu"
item.channel = "downloads"
item.downloadStatus = STATUS_CODES.stoped
item.downloadProgress = 0
item.downloadSize = 0
item.downloadCompleted = 0
title = re.sub(r'(?:\[[^\]]+\]|%s[^-]+-\s*)' %config.get_localized_string(60356), '', item.title).strip()
if not item.contentThumbnail:
item.contentThumbnail = item.thumbnail
for name in ["text_bold", "text_color", "text_italic", "context", "totalItems", "viewmode", "title", "contentTitle", "thumbnail"]:
if name in item.__dict__:
item.__dict__.pop(name)
if item.contentType == 'episode':
naming = title + typo(item.infoLabels['IMDBNumber'], '_ []') + typo(channel, '_ []')
else:
naming = item.fulltitle + typo(item.infoLabels['IMDBNumber'], '_ []') + typo(channel, '_ []')
naming += typo(item.contentLanguage, '_ []') if item.contentLanguage else ''
naming += typo(item.quality, '_ []') if item.quality else ''
path = filetools.join(DOWNLOAD_LIST_PATH, naming + ".json")
if filetools.isfile(path):
filetools.remove(path)
item.path = path
filetools.write(path, item.tojson())
time.sleep(0.1)
def save_download(item):
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):
log()
# Menu contextual
if item.from_action and item.from_channel:
item.channel = item.from_channel
item.action = item.from_action
del item.from_action
del item.from_channel
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.channel == 'videolibrary':
from specials import videolibrary
if not item.parent:
parent = item
else:
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:
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):
log()
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):
log("contentAction: %s | contentChannel: %s | contentTitle: %s" % (item.contentAction, item.contentChannel, item.contentTitle))
set_movie_title(item)
item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentTitle.strip(), item.contentChannel))
write_json(item)
if not platformtools.dialog_yesno(config.get_localized_string(30101), config.get_localized_string(70189)):
platformtools.dialog_ok(config.get_localized_string(30101), item.contentTitle + '\n' + config.get_localized_string(30109))
else:
start_download(item)
def save_download_movie(item):
log("contentAction: %s | contentChannel: %s | contentTitle: %s" % ( item.contentAction, item.contentChannel, item.contentTitle))
progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70191))
set_movie_title(item)
result = scraper.find_and_set_infoLabels(item)
if not result:
progreso.close()
return save_download_video(item)
progreso.update(0, config.get_localized_string(60062))
item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentTitle.strip(), item.infoLabels['IMDBNumber']))
item.backupFilename = filetools.validate_path("%s [%s]" % (item.contentTitle.strip(), item.infoLabels['IMDBNumber']))
write_json(item)
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), item.contentTitle + '\n' + config.get_localized_string(30109))
else:
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):
log("contentAction: %s | contentChannel: %s | contentType: %s | contentSerieName: %s" % (item.contentAction, item.contentChannel, item.contentType, item.contentSerieName))
progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70188))
try:
item.show = item.fulltitle
if item.channel not in ['videolibrary']:
scraper.find_and_set_infoLabels(item)
if not item.contentSerieName: item.contentSerieName = item.fulltitle
if item.strm_path: item.downloadFilename = filetools.validate_path(item.strm_path.split(os.sep)[-2])
else: 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) + '\n' + config.get_localized_string(70180) % item.contentChannel)
episodes = get_episodes(item)
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)
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) + '\n' + item.contentSerieName + '\n' + config.get_localized_string(30109))
else:
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):
if not item.contentTitle:
item.contentTitle = re.sub(r"\[[^\]]+\]|\([^\)]+\)", "", item.contentTitle).strip()
if not item.contentTitle:
item.contentTitle = re.sub(r"\[[^\]]+\]|\([^\)]+\)", "", 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 + '\n' + line2 + '\n' + line3)