Fix Kodi 18 bug
Fix Kodi 18 bug

# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Crunchyroll # Crunchyroll
# Copyright (C) 2018 MrKrabat # Copyright (C) 2018 MrKrabat
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as # it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the # published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version. # License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details. # GNU Affero General Public License for more details.
# #
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
   
import re import re
import ssl import ssl
import sys import sys
import json import json
import time import time
import inputstreamhelper import inputstreamhelper
   
import xbmc import xbmc
import xbmcgui import xbmcgui
import xbmcplugin import xbmcplugin
   
from . import api from . import api
from . import view from . import view
   
   
def showQueue(args): def showQueue(args):
""" shows anime queue/playlist """ shows anime queue/playlist
""" """
# api request # api request
payload = {"media_types": "anime|drama", payload = {"media_types": "anime|drama",
"fields": "media.name,media.media_id,media.collection_id,media.collection_name,media.description,media.episode_number,media.created, \ "fields": "media.name,media.media_id,media.collection_id,media.collection_name,media.description,media.episode_number,media.created, \
media.screenshot_image,media.premium_only,media.premium_available,media.available,media.premium_available,media.duration, \ media.screenshot_image,media.premium_only,media.premium_available,media.available,media.premium_available,media.duration, \
series.series_id,series.year,series.publisher_name,series.rating,series.genres,series.landscape_image"} series.series_id,series.year,series.publisher_name,series.rating,series.genres,series.landscape_image"}
req = api.request(args, "queue", payload) req = api.request(args, "queue", payload)
   
# check for error # check for error
if req["error"]: if req["error"]:
view.add_item(args, {"title": args._addon.getLocalizedString(30061)}) view.add_item(args, {"title": args._addon.getLocalizedString(30061)})
view.endofdirectory() view.endofdirectory()
return False return False
   
# display media # display media
for item in req["data"]: for item in req["data"]:
# video no longer available # video no longer available
if not ("most_likely_media" in item and "series" in item and item["most_likely_media"]["available"] and item["most_likely_media"]["premium_available"]): if not ("most_likely_media" in item and "series" in item and item["most_likely_media"]["available"] and item["most_likely_media"]["premium_available"]):
continue continue
   
# add to view # add to view
view.add_item(args, view.add_item(args,
{"title": item["most_likely_media"]["collection_name"] + " #" + item["most_likely_media"]["episode_number"] + " - " + item["most_likely_media"]["name"], {"title": item["most_likely_media"]["collection_name"] + " #" + item["most_likely_media"]["episode_number"] + " - " + item["most_likely_media"]["name"],
"tvshowtitle": item["most_likely_media"]["collection_name"], "tvshowtitle": item["most_likely_media"]["collection_name"],
"duration": item["most_likely_media"]["duration"], "duration": item["most_likely_media"]["duration"],
"playcount": 1 if (100/float(item["most_likely_media"]["duration"]))*int(item["playhead"]) > 90 else 0, "playcount": 1 if (100/float(item["most_likely_media"]["duration"]))*int(item["playhead"]) > 90 else 0,
"episode": item["most_likely_media"]["episode_number"], "episode": item["most_likely_media"]["episode_number"],
"episode_id": item["most_likely_media"]["media_id"], "episode_id": item["most_likely_media"]["media_id"],
"collection_id": item["most_likely_media"]["collection_id"], "collection_id": item["most_likely_media"]["collection_id"],
"series_id": item["series"]["series_id"], "series_id": item["series"]["series_id"],
"plot": item["most_likely_media"]["description"], "plot": item["most_likely_media"]["description"],
"plotoutline": item["most_likely_media"]["description"], "plotoutline": item["most_likely_media"]["description"],
"genre": ", ".join(item["series"]["genres"]), "genre": ", ".join(item["series"]["genres"]),
"year": item["series"]["year"], "year": item["series"]["year"],
"aired": item["most_likely_media"]["created"][:10], "aired": item["most_likely_media"]["created"][:10],
"premiered": item["most_likely_media"]["created"][:10], "premiered": item["most_likely_media"]["created"][:10],
"studio": item["series"]["publisher_name"], "studio": item["series"]["publisher_name"],
"rating": int(item["series"]["rating"])/10.0, "rating": int(item["series"]["rating"])/10.0,
"thumb": item["most_likely_media"]["screenshot_image"]["fwidestar_url"] if item["most_likely_media"]["premium_only"] else item["most_likely_media"]["screenshot_image"]["full_url"], "thumb": item["most_likely_media"]["screenshot_image"]["fwidestar_url"] if item["most_likely_media"]["premium_only"] else item["most_likely_media"]["screenshot_image"]["full_url"],
"fanart": item["series"]["landscape_image"]["full_url"], "fanart": item["series"]["landscape_image"]["full_url"],
"mode": "videoplay"}, "mode": "videoplay"},
isFolder=False) isFolder=False)
   
view.endofdirectory() view.endofdirectory()
return True return True
   
   
def searchAnime(args): def searchAnime(args):
"""Search for anime """Search for anime
""" """
# ask for search string # ask for search string
if not hasattr(args, "search"): if not hasattr(args, "search"):
d = xbmcgui.Dialog().input(args._addon.getLocalizedString(30041), type=xbmcgui.INPUT_ALPHANUM) d = xbmcgui.Dialog().input(args._addon.getLocalizedString(30041), type=xbmcgui.INPUT_ALPHANUM)
if not d: if not d:
return return
else: else:
d = args.search d = args.search
   
# api request # api request
payload = {"media_types": "anime|drama", payload = {"media_types": "anime|drama",
"q": d, "q": d,
"limit": 30, "limit": 30,
"offset": int(getattr(args, "offset", 0)), "offset": int(getattr(args, "offset", 0)),
"fields": "series.name,series.series_id,series.description,series.year,series.publisher_name, \ "fields": "series.name,series.series_id,series.description,series.year,series.publisher_name, \
series.genres,series.portrait_image,series.landscape_image"} series.genres,series.portrait_image,series.landscape_image"}
req = api.request(args, "autocomplete", payload) req = api.request(args, "autocomplete", payload)
   
# check for error # check for error
if req["error"]: if req["error"]:
view.add_item(args, {"title": args._addon.getLocalizedString(30061)}) view.add_item(args, {"title": args._addon.getLocalizedString(30061)})
view.endofdirectory() view.endofdirectory()
return False return False
   
# display media # display media
for item in req["data"]: for item in req["data"]:
# add to view # add to view
view.add_item(args, view.add_item(args,
{"title": item["name"], {"title": item["name"],
"tvshowtitle": item["name"], "tvshowtitle": item["name"],
"series_id": item["series_id"], "series_id": item["series_id"],
"plot": item["description"], "plot": item["description"],
"plotoutline": item["description"], "plotoutline": item["description"],
"genre": ", ".join(item["genres"]), "genre": ", ".join(item["genres"]),
"year": item["year"], "year": item["year"],
"studio": item["publisher_name"], "studio": item["publisher_name"],
"thumb": item["portrait_image"]["full_url"], "thumb": item["portrait_image"]["full_url"],
"fanart": item["landscape_image"]["full_url"], "fanart": item["landscape_image"]["full_url"],
"mode": "series"}, "mode": "series"},
isFolder=True) isFolder=True)
   
# show next page button # show next page button
if len(req["data"]) >= 30: if len(req["data"]) >= 30:
view.add_item(args, view.add_item(args,
{"title": args._addon.getLocalizedString(30044), {"title": args._addon.getLocalizedString(30044),
"offset": int(getattr(args, "offset", 0)) + 30, "offset": int(getattr(args, "offset", 0)) + 30,
"search": d, "search": d,
"mode": args.mode}, "mode": args.mode},
isFolder=True) isFolder=True)
   
view.endofdirectory() view.endofdirectory()
return True return True
   
   
def showHistory(args): def showHistory(args):
""" shows history of watched anime """ shows history of watched anime
""" """
# api request # api request
payload = {"media_types": "anime|drama", payload = {"media_types": "anime|drama",
"limit": 30, "limit": 30,
"offset": int(getattr(args, "offset", 0)), "offset": int(getattr(args, "offset", 0)),
"fields": "media.name,media.media_id,media.collection_id,media.collection_name,media.description,media.episode_number,media.created, \ "fields": "media.name,media.media_id,media.collection_id,media.collection_name,media.description,media.episode_number,media.created, \
media.screenshot_image,media.premium_only,media.premium_available,media.available,media.premium_available,media.duration,media.playhead, \ media.screenshot_image,media.premium_only,media.premium_available,media.available,media.premium_available,media.duration,media.playhead, \
series.series_id,series.year,series.publisher_name,series.rating,series.genres,series.landscape_image"} series.series_id,series.year,series.publisher_name,series.rating,series.genres,series.landscape_image"}
req = api.request(args, "recently_watched", payload) req = api.request(args, "recently_watched", payload)
   
# check for error # check for error
if req["error"]: if req["error"]:
view.add_item(args, {"title": args._addon.getLocalizedString(30061)}) view.add_item(args, {"title": args._addon.getLocalizedString(30061)})
view.endofdirectory() view.endofdirectory()
return False return False
   
# display media # display media
for item in req["data"]: for item in req["data"]:
# video no longer available # video no longer available
if not ("media" in item and "series" in item and item["media"]["available"] and item["media"]["premium_available"]): if not ("media" in item and "series" in item and item["media"]["available"] and item["media"]["premium_available"]):
continue continue
   
# add to view # add to view
view.add_item(args, view.add_item(args,
{"title": item["media"]["collection_name"] + " #" + item["media"]["episode_number"] + " - " + item["media"]["name"], {"title": item["media"]["collection_name"] + " #" + item["media"]["episode_number"] + " - " + item["media"]["name"],
"tvshowtitle": item["media"]["collection_name"], "tvshowtitle": item["media"]["collection_name"],
"duration": item["media"]["duration"], "duration": item["media"]["duration"],
"playcount": 1 if (100/float(item["media"]["duration"]))*int(item["media"]["playhead"]) > 90 else 0, "playcount": 1 if (100/float(item["media"]["duration"]))*int(item["media"]["playhead"]) > 90 else 0,
"episode": item["media"]["episode_number"], "episode": item["media"]["episode_number"],
"episode_id": item["media"]["media_id"], "episode_id": item["media"]["media_id"],
"collection_id": item["media"]["collection_id"], "collection_id": item["media"]["collection_id"],
"series_id": item["series"]["series_id"], "series_id": item["series"]["series_id"],
"plot": item["media"]["description"], "plot": item["media"]["description"],
"plotoutline": item["media"]["description"], "plotoutline": item["media"]["description"],
"genre": ", ".join(item["series"]["genres"]), "genre": ", ".join(item["series"]["genres"]),
"year": item["series"]["year"], "year": item["series"]["year"],
"aired": item["media"]["created"][:10], "aired": item["media"]["created"][:10],
"premiered": item["media"]["created"][:10], "premiered": item["media"]["created"][:10],
"studio": item["series"]["publisher_name"], "studio": item["series"]["publisher_name"],
"rating": int(item["series"]["rating"])/10.0, "rating": int(item["series"]["rating"])/10.0,
"thumb": item["media"]["screenshot_image"]["fwidestar_url"] if item["media"]["premium_only"] else item["media"]["screenshot_image"]["full_url"], "thumb": item["media"]["screenshot_image"]["fwidestar_url"] if item["media"]["premium_only"] else item["media"]["screenshot_image"]["full_url"],
"fanart": item["series"]["landscape_image"]["full_url"], "fanart": item["series"]["landscape_image"]["full_url"],
"mode": "videoplay"}, "mode": "videoplay"},
isFolder=False) isFolder=False)
   
# show next page button # show next page button
if len(req["data"]) >= 30: if len(req["data"]) >= 30:
view.add_item(args, view.add_item(args,
{"title": args._addon.getLocalizedString(30044), {"title": args._addon.getLocalizedString(30044),
"offset": int(getattr(args, "offset", 0)) + 30, "offset": int(getattr(args, "offset", 0)) + 30,
"mode": args.mode}, "mode": args.mode},
isFolder=True) isFolder=True)
   
view.endofdirectory() view.endofdirectory()
return True return True
   
   
def listSeries(args, mode): def listSeries(args, mode):
""" view all anime from selected mode """ view all anime from selected mode
""" """
# api request # api request
payload = {"media_type": args.genre, payload = {"media_type": args.genre,
"filter": mode, "filter": mode,
"limit": 30, "limit": 30,
"offset": int(getattr(args, "offset", 0)), "offset": int(getattr(args, "offset", 0)),
"fields": "series.name,series.series_id,series.description,series.year,series.publisher_name, \ "fields": "series.name,series.series_id,series.description,series.year,series.publisher_name, \
series.genres,series.portrait_image,series.landscape_image"} series.genres,series.portrait_image,series.landscape_image"}
req = api.request(args, "list_series", payload) req = api.request(args, "list_series", payload)
   
# check for error # check for error
if req["error"]: if req["error"]:
view.add_item(args, {"title": args._addon.getLocalizedString(30061)}) view.add_item(args, {"title": args._addon.getLocalizedString(30061)})
view.endofdirectory() view.endofdirectory()
return False return False
   
# display media # display media
for item in req["data"]: for item in req["data"]:
# add to view # add to view
view.add_item(args, view.add_item(args,
{"title": item["name"], {"title": item["name"],
"tvshowtitle": item["name"], "tvshowtitle": item["name"],
"series_id": item["series_id"], "series_id": item["series_id"],
"plot": item["description"], "plot": item["description"],
"plotoutline": item["description"], "plotoutline": item["description"],
"genre": ", ".join(item["genres"]), "genre": ", ".join(item["genres"]),
"year": item["year"], "year": item["year"],
"studio": item["publisher_name"], "studio": item["publisher_name"],
"thumb": item["portrait_image"]["full_url"], "thumb": item["portrait_image"]["full_url"],
"fanart": item["landscape_image"]["full_url"], "fanart": item["landscape_image"]["full_url"],
"mode": "series"}, "mode": "series"},
isFolder=True) isFolder=True)
   
# show next page button # show next page button
if len(req["data"]) >= 30: if len(req["data"]) >= 30:
view.add_item(args, view.add_item(args,
{"title": args._addon.getLocalizedString(30044), {"title": args._addon.getLocalizedString(30044),
"offset": int(getattr(args, "offset", 0)) + 30, "offset": int(getattr(args, "offset", 0)) + 30,
"search": getattr(args, "search", ""), "search": getattr(args, "search", ""),
"mode": args.mode}, "mode": args.mode},
isFolder=True) isFolder=True)
   
view.endofdirectory() view.endofdirectory()
return True return True
   
   
def listFilter(args, mode): def listFilter(args, mode):
""" view all anime from selected mode """ view all anime from selected mode
""" """
# test if filter is selected # test if filter is selected
if hasattr(args, "search"): if hasattr(args, "search"):
return listSeries(args, "tag:" + args.search) return listSeries(args, "tag:" + args.search)
   
# api request # api request
payload = {"media_type": args.genre} payload = {"media_type": args.genre}
req = api.request(args, "categories", payload) req = api.request(args, "categories", payload)
   
# check for error # check for error
if req["error"]: if req["error"]:
view.add_item(args, {"title": args._addon.getLocalizedString(30061)}) view.add_item(args, {"title": args._addon.getLocalizedString(30061)})
view.endofdirectory() view.endofdirectory()
return False return False
   
# display media # display media
for item in req["data"][mode]: for item in req["data"][mode]:
# add to view # add to view
view.add_item(args, view.add_item(args,
{"title": item["label"], {"title": item["label"],
"search": item["tag"], "search": item["tag"],
"mode": args.mode}, "mode": args.mode},
isFolder=True) isFolder=True)
   
view.endofdirectory() view.endofdirectory()
return True return True
   
   
def viewSeries(args): def viewSeries(args):
""" view all seasons/arcs of an anime """ view all seasons/arcs of an anime
""" """
# api request # api request
payload = {"series_id": args.series_id, payload = {"series_id": args.series_id,
"fields": "collection.name,collection.collection_id,collection.description,collection.media_type,collection.created, \ "fields": "collection.name,collection.collection_id,collection.description,collection.media_type,collection.created, \
collection.season,collection.complete,collection.portrait_image,collection.landscape_image"} collection.season,collection.complete,collection.portrait_image,collection.landscape_image"}
req = api.request(args, "list_collections", payload) req = api.request(args, "list_collections", payload)
   
# check for error # check for error
if req["error"]: if req["error"]:
view.add_item(args, {"title": args._addon.getLocalizedString(30061)}) view.add_item(args, {"title": args._addon.getLocalizedString(30061)})
view.endofdirectory() view.endofdirectory()
return False return False
   
# display media # display media
for item in req["data"]: for item in req["data"]:
# add to view # add to view
view.add_item(args, view.add_item(args,
{"title": item["name"], {"title": item["name"],
"tvshowtitle": item["name"], "tvshowtitle": item["name"],
"season": item["season"], "season": item["season"],
"collection_id": item["collection_id"], "collection_id": item["collection_id"],
"series_id": args.series_id, "series_id": args.series_id,
"plot": item["description"], "plot": item["description"],
"plotoutline": item["description"], "plotoutline": item["description"],
"genre": item["media_type"], "genre": item["media_type"],
"aired": item["created"][:10], "aired": item["created"][:10],
"premiered": item["created"][:10], "premiered": item["created"][:10],
"status": u"Completed" if item["complete"] else u"Continuing", "status": u"Completed" if item["complete"] else u"Continuing",
"thumb": item["portrait_image"]["full_url"] if item["portrait_image"] else args.thumb, "thumb": item["portrait_image"]["full_url"] if item["portrait_image"] else args.thumb,
"fanart": item["landscape_image"]["full_url"] if item["landscape_image"] else args.fanart, "fanart": item["landscape_image"]["full_url"] if item["landscape_image"] else args.fanart,
"mode": "episodes"}, "mode": "episodes"},
isFolder=True) isFolder=True)
   
view.endofdirectory() view.endofdirectory()
return True return True
   
   
def viewEpisodes(args): def viewEpisodes(args):
""" view all episodes of season """ view all episodes of season
""" """
# api request # api request
payload = {"collection_id": args.collection_id, payload = {"collection_id": args.collection_id,
"limit": 30, "limit": 30,
"offset": int(getattr(args, "offset", 0)), "offset": int(getattr(args, "offset", 0)),
"fields": "media.name,media.media_id,media.collection_id,media.collection_name,media.description,media.episode_number,media.created,media.series_id, \ "fields": "media.name,media.media_id,media.collection_id,media.collection_name,media.description,media.episode_number,media.created,media.series_id, \
media.screenshot_image,media.premium_only,media.premium_available,media.available,media.premium_available,media.duration,media.playhead"} media.screenshot_image,media.premium_only,media.premium_available,media.available,media.premium_available,media.duration,media.playhead"}
req = api.request(args, "list_media", payload) req = api.request(args, "list_media", payload)
   
# check for error # check for error
if req["error"]: if req["error"]:
view.add_item(args, {"title": args._addon.getLocalizedString(30061)}) view.add_item(args, {"title": args._addon.getLocalizedString(30061)})
view.endofdirectory() view.endofdirectory()
return False return False
   
# display media # display media
for item in req["data"]: for item in req["data"]:
# add to view # add to view
view.add_item(args, view.add_item(args,
{"title": item["collection_name"] + " #" + item["episode_number"] + " - " + item["name"], {"title": item["collection_name"] + " #" + item["episode_number"] + " - " + item["name"],
"tvshowtitle": item["collection_name"], "tvshowtitle": item["collection_name"],
"duration": item["duration"], "duration": item["duration"],
"playcount": 1 if (100/float(item["duration"]))*int(item["playhead"]) > 90 else 0, "playcount": 1 if (100/float(item["duration"]))*int(item["playhead"]) > 90 else 0,
"episode": item["episode_number"], "episode": item["episode_number"],
"episode_id": item["media_id"], "episode_id": item["media_id"],
"collection_id": args.collection_id, "collection_id": args.collection_id,
"series_id": item["series_id"], "series_id": item["series_id"],
"plot": item["description"], "plot": item["description"],
"plotoutline": item["description"], "plotoutline": item["description"],
"aired": item["created"][:10], "aired": item["created"][:10],
"premiered": item["created"][:10], "premiered": item["created"][:10],
"thumb": item["screenshot_image"]["fwidestar_url"] if item["premium_only"] else item["screenshot_image"]["full_url"], "thumb": item["screenshot_image"]["fwidestar_url"] if item["premium_only"] else item["screenshot_image"]["full_url"],
"fanart": args.fanart, "fanart": args.fanart,
"mode": "videoplay"}, "mode": "videoplay"},
isFolder=False) isFolder=False)
   
# show next page button # show next page button
if len(req["data"]) >= 30: if len(req["data"]) >= 30:
view.add_item(args, view.add_item(args,
{"title": args._addon.getLocalizedString(30044), {"title": args._addon.getLocalizedString(30044),
"collection_id": args.collection_id, "collection_id": args.collection_id,
"offset": int(getattr(args, "offset", 0)) + 30, "offset": int(getattr(args, "offset", 0)) + 30,
"thumb": args.thumb, "thumb": args.thumb,
"fanart": args.fanart, "fanart": args.fanart,
"mode": args.mode}, "mode": args.mode},
isFolder=True) isFolder=True)
   
view.endofdirectory() view.endofdirectory()
return True return True
   
   
def startplayback(args): def startplayback(args):
""" plays an episode """ plays an episode
""" """
# api request # api request
payload = {"media_id": args.episode_id, payload = {"media_id": args.episode_id,
"fields": "media.duration,media.playhead,media.stream_data"} "fields": "media.duration,media.playhead,media.stream_data"}
req = api.request(args, "info", payload) req = api.request(args, "info", payload)
   
# check for error # check for error
if req["error"]: if req["error"]:
item = xbmcgui.ListItem(getattr(args, "title", "Title not provided")) item = xbmcgui.ListItem(getattr(args, "title", "Title not provided"))
xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, item) xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, item)
return False return False
   
# get stream url # get stream url
url = req["data"]["stream_data"]["streams"][0]["url"] url = req["data"]["stream_data"]["streams"][0]["url"]
if not args._quality == "adaptive": if not args._quality == "adaptive":
matches = re.findall(r",([0-9]+\.mp4)", url) matches = re.findall(r",([0-9]+\.mp4)", url)
url = re.sub(r"(,[0-9]+\.mp4){5}", "," + matches[args._quality], url) url = re.sub(r"(,[0-9]+\.mp4){5}", "," + matches[args._quality], url)
   
# prepare playback # prepare playback
item = xbmcgui.ListItem(getattr(args, "title", "Title not provided"), path=url) item = xbmcgui.ListItem(getattr(args, "title", "Title not provided"), path=url)
item.setMimeType("application/vnd.apple.mpegurl") item.setMimeType("application/vnd.apple.mpegurl")
item.setContentLookup(False) item.setContentLookup(False)
   
# inputstream adaptive # inputstream adaptive
is_helper = inputstreamhelper.Helper("hls") is_helper = inputstreamhelper.Helper("hls")
if is_helper.check_inputstream(): if is_helper.check_inputstream():
item.setProperty("inputstreamaddon", "inputstream.adaptive") item.setProperty("inputstreamaddon", "inputstream.adaptive")
item.setProperty("inputstream.adaptive.manifest_type", "hls") item.setProperty("inputstream.adaptive.manifest_type", "hls")
# start playback # start playback
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, item) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, item)
   
# wait for playback # wait for playback
#xbmcgui.Dialog().notification(args._addonname, args._addon.getLocalizedString(30066), xbmcgui.NOTIFICATION_INFO) #xbmcgui.Dialog().notification(args._addonname, args._addon.getLocalizedString(30066), xbmcgui.NOTIFICATION_INFO)
if waitForPlayback(10): if waitForPlayback(10):
# if successful wait more # if successful wait more
xbmc.sleep(3000) xbmc.sleep(3000)
   
# start fallback # start fallback
if not waitForPlayback(2): if not waitForPlayback(2):
# start without inputstream adaptive # start without inputstream adaptive
xbmc.log("[PLUGIN] %s: Inputstream Adaptive failed, trying directly with kodi" % args._addonname, xbmc.LOGDEBUG) xbmc.log("[PLUGIN] %s: Inputstream Adaptive failed, trying directly with kodi" % args._addonname, xbmc.LOGDEBUG)
item.setProperty("inputstreamaddon", "") item.setProperty("inputstreamaddon", "")
xbmc.Player().play(url, item) xbmc.Player().play(url, item)
   
# sync playtime with crunchyroll # sync playtime with crunchyroll
if args._addon.getSetting("sync_playtime") == "true": if args._addon.getSetting("sync_playtime") == "true":
# wait for video to begin # wait for video to begin
player = xbmc.Player() player = xbmc.Player()
if not waitForPlayback(30): if not waitForPlayback(30):
xbmc.log("[PLUGIN] %s: Timeout reached, video did not start in 30 seconds" % args._addonname, xbmc.LOGERROR) xbmc.log("[PLUGIN] %s: Timeout reached, video did not start in 30 seconds" % args._addonname, xbmc.LOGERROR)
return return
   
# ask if user want to continue playback # ask if user want to continue playback
resume = (100/float(req["data"]["duration"])) * int(req["data"]["playhead"]) resume = (100/float(req["data"]["duration"])) * int(req["data"]["playhead"])
if resume >= 5 and resume <= 90: if resume >= 5 and resume <= 90:
player.pause() player.pause()
if xbmcgui.Dialog().yesno(args._addonname, args._addon.getLocalizedString(30065) % int(resume)): if xbmcgui.Dialog().yesno(args._addonname, args._addon.getLocalizedString(30065) % int(resume)):
player.seekTime(float(req["data"]["playhead"]) - 5) player.seekTime(float(req["data"]["playhead"]) - 5)
player.pause() player.pause()
   
# update playtime at crunchyroll # update playtime at crunchyroll
try: try:
while url == player.getPlayingFile(): while url == player.getPlayingFile():
# wait 10 seconds # wait 10 seconds
xbmc.sleep(10000) xbmc.sleep(10000)
   
if url == player.getPlayingFile(): if url == player.getPlayingFile():
# api request # api request
payload = {"event": "playback_status", payload = {"event": "playback_status",
"media_id": args.episode_id, "media_id": args.episode_id,
"playhead": int(player.getTime())} "playhead": int(player.getTime())}
try: try:
api.request(args, "log", payload) api.request(args, "log", payload)
except ssl.SSLError: except ssl.SSLError:
# catch timeout exception # catch timeout exception
pass pass
except RuntimeError: except RuntimeError:
xbmc.log("[PLUGIN] %s: Playback aborted" % args._addonname, xbmc.LOGDEBUG) xbmc.log("[PLUGIN] %s: Playback aborted" % args._addonname, xbmc.LOGDEBUG)
   
   
def waitForPlayback(timeout=30): def waitForPlayback(timeout=30):
""" function that waits for playback """ function that waits for playback
""" """
timer = time.time() + timeout timer = time.time() + timeout
while not xbmc.getCondVisibility("Player.IsInternetStream"): while not xbmc.getCondVisibility("Player.HasMedia"):
xbmc.sleep(50) xbmc.sleep(50)
# timeout to prevent infinite loop # timeout to prevent infinite loop
if time.time() > timer: if time.time() > timer:
return False return False
   
return True return True