def start_loops(self): spam('start_loops') try: self._t.stop() except: pass self._t = Thread(target=self.tick_loop_trakt, args=()) self._t.daemon = True self._t.start() try: self._s.stop() except: pass self._s = Thread(target=self.tick_loop_shoko, args=()) self._s.daemon = True self._s.start() try: self._u.stop() except: pass self._u = Thread(target=self.tick_loop_update_time, args=()) self._u.daemon = True self._u.start()
def onPlayBackEnded(self): spam('Playback Ended') try: self.handle_finished_episode() except: eh.exception(ErrorPriority.HIGH) self.PlaybackStatus = PlaybackStatus.ENDED
def onPlayBackResumed(self): spam('Playback Resumed') self.PlaybackStatus = PlaybackStatus.PLAYING try: self.start_loops() except: eh.exception(ErrorPriority.HIGH)
def __init__(self): spam('Player Initialized') xbmc.Player.__init__(self) self._t = None # trakt thread self._s = None # shoko thread self._u = None # update thread self._details = None self.Playlist = None self.PlaybackStatus = PlaybackStatus.STOPPED # self.LoopStatus = 'None' # self.Shuffle = False self.is_transcoded = False self.is_movie = None self.file_id = 0 self.ep_id = 0 # we will store duration and time in kodi format here, so that calls to the player will match self.duration = 0 self.time = 0 self.path = '' self.scrobble = True self.is_external = False self.is_finished = False self.party_mode = False self.CanControl = True
def onPlayBackStarted(self): spam('Playback Started') try: if plugin_addon.getSetting('enableEigakan') == 'true': log('Player is set to use Transcoding') self.is_transcoded = True # wait until the player is init'd and playing self.set_duration() self.PlaybackStatus = PlaybackStatus.PLAYING # we are making the player global, so if a stop is issued, then Playing will change while not self.isPlaying( ) and self.PlaybackStatus == PlaybackStatus.PLAYING: xbmc.sleep(250) # TODO get series and populate info so we know if its movie or not # TODO maybe we could read trakt_id from shoko, self.is_movie = False if self.duration > 0 and self.scrobble: scrobble_trakt(self.ep_id, 1, self.getTime(), self.duration, self.is_movie) self.start_loops() except: eh.exception(ErrorPriority.HIGHEST)
def kodi_rpc(method, params, limit='', json_id=0): json_id += 1 jsonrpc = '{"jsonrpc":"2.0","id":%d,"method":"%s","params":{%s}%s}' % ( json_id, method, params, limit) spam(' -----------> rpc (send): %s' % jsonrpc) rpc = xbmc.executeJSONRPC(jsonrpc) spam(' -----------> rpc (recv): %s' % rpc) rpc = json.loads(rpc) return rpc
def feed(self, file_id, ep_id, duration, path, scrobble): spam( 'Player feed - file_id=%s ep_id=%s duration=%s path=%s scrobble=%s' % (file_id, ep_id, duration, path, scrobble)) self.file_id = file_id self.ep_id = ep_id self.duration = kodi_proxy.duration_to_kodi(duration) self.path = path self.scrobble = scrobble
def finished_episode(ep_id, file_id, current_time, total_time): _finished = False spam( 'finished_episode > ep_id = %s, file_id = %s, current_time = %s, total_time = %s' % (ep_id, file_id, current_time, total_time)) mark = float(plugin_addon.getSetting('watched_mark')) if plugin_addon.getSetting('external_player').lower() == 'false': pass else: # mitigate the external player, skipping intro/outro/pv so we cut your setting in half mark /= 2 mark /= 100 spam('mark = %s * total (%s) = %s vs current = %s' % (mark, total_time, (total_time * mark), current_time)) if (total_time * mark) <= current_time: _finished = True log('Video current_time (%s) has passed watch mark (%s). Marking is as watched!' % (current_time, (total_time * mark))) # TODO this got broken for addons in Leia18, until this is somehow fixed we count time by hand (in loop) # else: # external set position = 1.0 when it want to mark it as watched (based on configuration of external # if current_time > 0.0: # _finished = True # else: # log('Using an external player, but the settings are set to not mark as watched. Check advancedsettings.xml') #_finished = False if _finished: if int(ep_id) != 0 and plugin_addon.getSetting( 'vote_always') == 'true': spam('vote_always, voting on episode') script_utils.vote_for_episode(ep_id) if ep_id != 0: from shoko_models.v2 import Episode ep = Episode(ep_id, build_full_object=False) spam('mark as watched, episode') ep.set_watched_status(True) # vote on finished series if plugin_addon.getSetting('vote_on_series') == 'true': from shoko_models.v2 import get_series_for_episode series = get_series_for_episode(ep_id) # voting should be only when you really watch full series spam('vote_on_series, mark: %s / %s' % (series.sizes.watched_episodes, series.sizes.total_episodes)) if series.sizes.watched_episodes - series.sizes.total_episodes == 0: script_utils.vote_for_series(series.id) elif file_id != 0: # file watched states pass # refresh only when we really did watch episode, this way we wait until all action after watching are executed script_utils.arbiter(10, 'Container.Refresh')
def add_to_queue(aid, eid, sid, rating=0): db_connection = database.connect(db_file) db_cursor = db_connection.cursor() db_cursor.execute('SELECT aid, eid, sid FROM queue WHERE aid=? and eid=? and sid=?', (aid, eid, sid)) if db_cursor.fetchone() is None: db_cursor.execute('INSERT INTO queue (aid, eid, sid, rating) VALUES (?, ?, ?, ?)', (aid, eid, sid, rating)) db_connection.commit() db_connection.close() spam(' ===> add_to_queue: added') spam(' ===> add_to_queue: %s %s %s' % (aid, eid, sid))
def get_queue(): items = None try: db_connection = database.connect(db_file) db_cursor = db_connection.cursor() db_cursor.execute('SELECT aid, eid, sid, rating FROM queue') items = db_cursor.fetchall() except: pass spam(' ===> get_queue: %s' % (len(items),)) return items
def add_date(date): db_connection = database.connect(db_file) db_cursor = db_connection.cursor() db_cursor.execute('SELECT date FROM sync_date WHERE date=?', (date,)) if db_cursor.fetchone() is None: db_cursor.execute('INSERT INTO sync_date (date) VALUES (?)', (date,)) db_connection.commit() db_connection.close() spam(' ===> add_date: %s: True' % (date,)) return True spam(' ===> add_date: %s: False' % (date,)) return False
def get_lastdate(): items = None try: db_connection = database.connect(db_file) db_cursor = db_connection.cursor() db_cursor.execute('SELECT date FROM sync_date ORDER BY date DESC') items = db_cursor.fetchone() if items is None: items = ['2000-01-01'] except: pass spam(' ===> get_latestdate: %s' % (items,)) return items
def clear_queue(number_of_items=0): # as a safe-lock, check number of items before flushing, if its same then flush, # if different then something was added and it would be better to process it again if len(get_queue()) == number_of_items: db_connection = database.connect(db_file) db_cursor = db_connection.cursor() db_cursor.execute('DELETE FROM queue') db_connection.commit() db_connection.close() spam(' ===> clear_queue: True') return True spam(' ===> clear_queue: False') return False
def clean_videolibrary_scan(): log('====> VideoLibrary Scan: Start <====') index_start = 0 index_stop = 10 index_count = 100 json_id = 0 while index_stop < index_count: spam('=====> series : %s -- %s / %s' % (index_start, index_stop, index_count)) results = kodi_rpc( 'VideoLibrary.GetEpisodes', '"properties":["tvshowid","title","uniqueid"]', ',"limits":{"start":%d,"end":%d}' % (index_start, index_stop), json_id) if 'result' not in results: spam('====> no result found <====') break json_id = int(results['id']) index_start = results['result']['limits'].get('start', 0) index_stop = results['result']['limits'].get('end', 0) index_count = results['result']['limits'].get('total', 0) for tvshows in results['result'].get('episodes', []): tid = tvshows.get('tvshowid', 0) eid = tvshows.get('episodeid', 0) said = 0 # shoko_aid seid = 0 # shoko_eid aaid = 0 # anidb_aid aeid = 0 # anidb_eid if 'uniqueid' in tvshows: if 'shoko_aid' in tvshows[ 'uniqueid'] and 'shoko_eid' in tvshows['uniqueid']: said = tvshows['uniqueid'].get('shoko_aid', 0) seid = tvshows['uniqueid'].get('shoko_eid', 0) aaid = tvshows['uniqueid'].get('anidb_aid', 0) aeid = tvshows['uniqueid'].get('anidb_eid', 0) spam(' ====> uniqueid: %s => %s => %s, %s => %s => %s' % (tid, said, aaid, eid, seid, aeid)) if tid > 0 and eid > 0 and said > 0 and seid > 0: if not series.check(tid=tid, aid=aaid, sid=said): series.add_map(tid=tid, aid=aaid, sid=said) spam(' ====> add_series: %s => %s, %s' % (tid, aaid, said)) if not episodes.check(vlid=eid, eid=aeid, sid=seid): episodes.add_map(vlid=eid, eid=aeid, sid=seid) spam(' ====> add_episod: %s => %s, %s' % (eid, aeid, seid)) index_step = index_stop - index_start index_start = index_stop index_stop += index_step log('====> VideoLibrary Scan: Finish')
def is_dialog_active(): x = -1 try: x = xbmcgui.getCurrentWindowDialogId() x = int(x) log('----- > is_dialog_window_is_visible: %s' % x) # if there is any, wait 0.25s xbmc.sleep(250) except: eh.spam('----- > is_dialog_is_visible: NONE') pass # https://github.com/xbmc/xbmc/blob/master/xbmc/guilib/WindowIDs.h # 10138 - busy,loading if 10099 <= x <= 10160: return True return False
def onAVStarted(self): # Will be called when Kodi has a video or audiostream, before playing file spam('onAVStarted') # isExternalPlayer() ONLY works when isPlaying(), other than that it throw 0 always # setting it before results in false setting try: is_external = str(kodi_proxy.external_player(self)).lower() plugin_addon.setSetting(id='external_player', value=is_external) except: eh.exception(ErrorPriority.HIGH) spam(self) if kodi_proxy.external_player(self): log('Using External Player') self.is_external = True
def get_json(self, url_in, direct=False, force_cache=False, cache_time=0): """ use 'get' to return json body as string :param url_in: :param direct: force to bypass cache :param force_cache: force to use cache even if disabled :param cache_time: ignore setting to set custom cache expiration time, mainly to expire data quicker to refresh watch flags :return: """ import error_handler as eh from error_handler import ErrorPriority try: timeout = plugin_addon.getSetting('timeout') if self.api_key is None or self.api_key == '': apikey = plugin_addon.getSetting('apikey') else: apikey = self.api_key # if cache is disabled, overwrite argument and force it to direct if plugin_addon.getSetting('enableCache') != 'true': direct = True if direct and not force_cache: body = self.get_data(url_in, None, timeout, apikey) else: import cache eh.spam('Getting a Cached Response ---') eh.spam('URL:', url_in) db_row = cache.get_data_from_cache(url_in) if db_row is not None: valid_until = cache_time if cache_time > 0 else int( plugin_addon.getSetting('expireCache')) expire_second = time.time() - float(db_row[1]) if expire_second > valid_until: # expire, get new date eh.spam('The cached data is stale.') body = self.get_data(url_in, None, timeout, apikey) cache.remove_cache(url_in) cache.add_cache(url_in, body) else: body = db_row[0] else: eh.spam('No cached data was found for the URL.') body = self.get_data(url_in, None, timeout, apikey) cache.add_cache(url_in, body) except http_error as err: raise err except Exception as ex: xbmc.log(' ========= ERROR JSON ============ %s' % ex, xbmc.LOGNOTICE) eh.exception(ErrorPriority.HIGH) body = None return body
def send_profile(): eh.spam('Trying to send_profile(). Wish me luck!') log_setsuzoku(Category.EIGAKAN, Action.PROFILE, Event.SEND) # setup client on server settings = {} # tweak-ninja settings['manual_mode'] = plugin_addon.getSetting('eigakan_manual_mode') settings['h_resolution'] = plugin_addon.getSetting('eigakan_h_resolution') settings['h_bitrate'] = plugin_addon.getSetting('eigakan_h_bitrate') settings['l_resolution'] = plugin_addon.getSetting('eigakan_l_resolution') settings['l_bitrate'] = plugin_addon.getSetting('eigakan_l_bitrate') settings['x264_preset'] = plugin_addon.getSetting('eigakan_x264_preset') settings['burn_subs'] = plugin_addon.getSetting('burnEigakan') # lang-master settings['pref_audio'] = plugin_addon.getSetting('audiolangEigakan') settings['pref_subs'] = plugin_addon.getSetting('subEigakan') settings = json.dumps(settings) eh.spam('send_profile() data = %s' % settings) try: pyproxy.post_data(eigakan_host + '/api/clientid/%s' % get_device_id(), settings) # if no error, lets mark that we did full handshake with eigakan plugin_addon.setSetting('eigakan_handshake', 'true') except Exception as ex: plugin_addon.setSetting('eigakan_handshake', 'false') eh.spam('error while send_profile(): %s' % ex)
def process_queue_of_watched_episodes(): s_watch = True if xbmcaddon.Addon('service.nakamori').getSetting( 'sv-watch') == 'true' else False s_rate = True if xbmcaddon.Addon('service.nakamori').getSetting( 'sv-rate') == 'true' else False if s_watch or s_rate: log('===> process_queue_of_watched_episodes()') queue = sync.get_queue() for q in queue: a_aid = q[0] a_eid = q[1] shoko_eid = q[2] rating = q[3] vl_ep_id = episodes.get(eid=a_eid, sid=shoko_eid) if vl_ep_id is not None: vl_ep_id = vl_ep_id[0] # we found mapping spam('===> process_queue_of_watched_episodes vl_ep_id: %s' % vl_ep_id) r = kodi_rpc( 'VideoLibrary.GetEpisodeDetails', '"episodeid": %s,"properties":["playcount","rating"]' % vl_ep_id) if 'result' in r and 'episodedetails' in r['result']: if s_watch: if r['result']['episodedetails']['playcount'] == 0: m = kodi_rpc( 'VideoLibrary.SetEpisodeDetails', '"episodeid":%s,"playcount": 1' % vl_ep_id) if m.get('result', '') == "OK": spam('===> mark watched %s - OK' % vl_ep_id) if s_rate: if rating > 0: # maybe add force to re-rate it ? if r['result']['episodedetails']['rating'] == 0: m = kodi_rpc( 'VideoLibrary.SetEpisodeDetails', '"episodeid":%s,"rating": %d' % (vl_ep_id, rating)) if m.get('result', '') == "OK": spam('===> rating %s - %s' % (vl_ep_id, rating)) else: spam('----> missing mapping ! %s %s %s <----' % (a_aid, a_eid, shoko_eid)) # try to clear queue return sync.clear_queue(len(queue)) else: log('===> process_queue_of_watched_episodes() - DISABLED') return False
def check_eigakan(): try: eigakan_data = pyproxy.get_json(eigakan_host + '/api/version') if eigakan_data is None: return False elif 'eigakan' not in eigakan_data: # raise RuntimeError('Invalid response from Eigakan') return False else: if plugin_addon.getSetting('eigakan_handshake') == 'false': eh.spam('We did not find Eigakan handshake') try: pyproxy.get_json(eigakan_host + '/api/clientid/%s' % get_device_id()) except http_err as err: if int(err.code) == 404: eh.spam('We did not find device profile on Eigakan, sending new one...') plugin_addon.setSetting('eigakan_handshake', 'false') send_profile() else: return False return True except: return False
def query_last_watched_episodes(): s_watch = True if xbmcaddon.Addon('service.nakamori').getSetting( 'sv-watch') == 'true' else False s_rate = True if xbmcaddon.Addon('service.nakamori').getSetting( 'sv-rate') == 'true' else False if s_watch or s_rate: log('====> query_last_watched_episodes') from nakamori_utils.globalvars import server # [{"type":"ep","view":1,"view_date":"2019-09-03T13:42:36.9194063+02:00","eptype":"Episode","epnumber":10,"aid":14662,"eid":219322,"id":74,"name":"Episode 10","summary":"Episode Overview not Available","year":"2019","air":"2019-09-02","rating":"2.80","votes":"1","art":{}}] today = date.today().strftime("%Y-%m-%d") offset = 0 limit = 100 # setting without limit results in loop url = server + '/api/ep/last_watched?query=%s&limit=%s&offset=%s' % ( today, limit, offset) spam('====> url: %s' % url) x = pyproxy.get_json(url, True) if x is not None and len(x) > 2: # [] x = json.loads(x) while len(x) > 0: for y in x: if isinstance(y, dict): spam('====> query_last_watched_episodes x: %s %s' % (type(y), y)) watch_date = y.get('view_date', '') aid = y.get('aid', 0) eid = y.get('eid', 0) shoko_eid = y.get('id', 0) user_rating = 0 if s_rate: user_rating = y.get('userrating', 0) sync.add_to_queue(aid, eid, shoko_eid, user_rating) offset = offset + limit url = server + '/api/ep/last_watched?query=%s&limit=%s&offset=%s' % ( today, limit, offset) spam('====> url: %s' % url) x = pyproxy.get_json(url, True) if x is None: break if x == '[]': break # finish checking sync.add_date(today) else: log('====> query_last_watched_episodes - DISABLED')
def debug_init(): """ start debugger if it's enabled also dump argv if spamLog :return: """ if plugin_addon.getSetting('remote_debug') == 'true': # try pycharm first try: import pydevd # try to connect multiple times...in case we forgot to start it # TODO Show a message to the user that we are waiting on the debugger connected = False tries = 0 while not connected and tries < 60: try: pydevd.settrace(host=plugin_addon.getSetting('remote_ip'), stdoutToServer=True, stderrToServer=True, port=5678, suspend=False) eh.spam('Connected to debugger') connected = True except: tries += 1 # we keep this message the same, as kodi will merge them into Previous line repeats... eh.spam('Failed to connect to debugger') xbmc.sleep(1000) except (ImportError, NameError): eh.log( 'unable to import pycharm debugger, falling back on the web-pdb' ) try: import web_pdb web_pdb.set_trace() except Exception: eh.exception(ErrorPriority.NORMAL, 'Unable to start debugger, disabling it') plugin_addon.setSetting('remote_debug', 'false') except: eh.exception(ErrorPriority.HIGHEST, 'Unable to start debugger') eh.spam('argv:', sys.argv)
def perform_server_action(command, object_id=None, refresh='refresh10', post=False, post_body=''): """ Performs an action on the server Args: object_id: the object_id or None command: string representing api/command?object_id=... refresh: whether to refresh post: is it a POST endpoint post_body: the body to post, minus the {} """ key_url = server + '/api/' + command if object_id is not None and object_id != 0 and object_id != '': key_url = pyproxy.set_parameter(key_url, 'id', object_id) eh.spam('url:', key_url, 'id:', object_id) eh.spam('post:', post, 'body:', post_body) if post: response = pyproxy.post_json(key_url, post_body) else: response = pyproxy.get_json(key_url) eh.spam(response) refresh_message = localization_refresh_map.get(refresh, '') xbmc.executebuiltin('XBMC.Notification(%s, %s, 2000, %s)' % (localization_notification_map.get(command, command), refresh_message, plugin_addon.getAddonInfo('icon'))) # there's a better way to do this, but I don't feel like trying to make it work in Python if refresh != '' and refresh != 'awhile': xbmc.sleep(10000) kodi_utils.refresh()
def play_video(file_id, ep_id=0, mark_as_watched=True, resume=False, force_direct_play=False, force_transcode_play=False, party_mode=False): """ Plays a file :param file_id: file ID. It is needed to look up the file :param ep_id: episode ID, not needed, but it fills in a lot of info :param mark_as_watched: should we mark it after playback :param resume: should we auto-resume :param force_direct_play: force direct play :param force_transcode_play: force transcoding file :return: True if successfully playing """ eh.spam('Processing play_video %s %s %s %s %s %s' % (file_id, ep_id, mark_as_watched, resume, force_direct_play, force_transcode_play)) from shoko_models.v2 import Episode, File, get_series_for_episode # check if we're already playing something player = xbmc.Player() if player.isPlayingVideo(): playing_item = player.getPlayingFile() log('Player is currently playing %s' % playing_item) log('Player Stopping') player.stop() # wait for it to stop while True: try: if not player.isPlayingVideo(): break xbmc.sleep(500) continue except: pass # now continue file_url = '' if int(ep_id) != 0: ep = Episode(ep_id, build_full_object=True) series = get_series_for_episode(ep_id) ep.series_id = series.id ep.series_name = series.name item = ep.get_listitem() f = ep.get_file_with_id(file_id) else: f = File(file_id, build_full_object=True) item = f.get_listitem() if item is not None: if resume: # TODO looks like this does nothing... item.resume() else: item.setProperty('ResumeTime', '0') file_url = f.url_for_player if f is not None else None if file_url is not None: is_transcoded = False m3u8_url = '' subs_extension = '' is_finished = False if not force_direct_play: if 'smb://' in file_url: file_url = f.remote_url_for_player is_transcoded, m3u8_url, subs_extension, is_finished = process_transcoder( file_id, file_url, force_transcode_play) player = Player() player.feed(file_id, ep_id, f.duration, m3u8_url if is_transcoded else file_url, mark_as_watched) try: item.setProperty('IsPlayable', 'true') if is_transcoded: #player.play(item=m3u8_url) url_for_player = m3u8_url item.setPath(url_for_player) item.setProperty('inputstreamaddon', 'inputstream.adaptive') item.setProperty('inputstream.adaptive.manifest_type', 'mpd') item.setMimeType('application/dash+xml') item.setContentLookup(False) # TODO maybe extract all subs and include them ? subs_url = eigakan_host + '/api/video/%s/%s/subs.%s' % ( clientid, file_id, subs_extension) if pyproxy.head(url_in=subs_url): item.setSubtitles([ subs_url, ]) item.addStreamInfo('subtitle', { 'language': 'Default', }) else: #file_url = f.remote_url_for_player #player.play(item=file_url, listitem=item) url_for_player = f.url_for_player # file_url item.setPath(url_for_player) handle = int(sys.argv[1]) if handle == -1: player.play(item=url_for_player, listitem=item) else: # thanks to anxdpanic for pointing in right direction xbmcplugin.setResolvedUrl(handle, True, item) except: eh.exception(ErrorPriority.BLOCKING) # leave player alive so we can handle onPlayBackStopped/onPlayBackEnded # TODO Move the instance to Service, so that it is never disposed xbmc.sleep(int(plugin_addon.getSetting('player_sleep'))) return player_loop(player, is_transcoded, is_finished, ep_id, party_mode)
def pick_best_streams(audio_streams, subs_streams): a_index = -1 s_index = -1 subs_type = '' eh.spam('Processing streams a: %s; s: %s' % (audio_streams, subs_streams)) if plugin_addon.getSetting('eigakan_manual_mode') == 'false': if len(audio_streams.split('\r')) == 1: a_index = audio_streams.split('|')[0] else: for a in audio_streams.split('\r'): a = a.split('|') for x in a: if x == "*": if a_index == -1: a_index = a[0] else: a_index = -1 break if len(subs_streams.split('\r')) == 1: s_index = subs_streams.split('|')[0] else: for s in subs_streams.split('\r'): s = s.split('|') for x in s: if x == "*": if s_index == -1: s_index = s[0] else: s_index = -1 break if not isinstance(a_index, int): a_index = -1 if not isinstance(s_index, int): s_index = -1 eh.spam('Pick_Best_Streams (after preference): "%s" "%s" "%s"' % (a_index, s_index, subs_type)) # we use manual mode or we didn't have your preferred streams if a_index == -1 or s_index == -1: if a_index == -1: if audio_streams != '': # less likely but check anyway a_option = audio_streams.split('\r') if len(a_option) == 1: a_index = a_option[0].split('|')[0] else: a_idx = xbmcgui.Dialog().select( plugin_addon.getLocalizedString(30178), a_option) if a_idx > -1: a_index = a_option[a_idx].split('|')[0] if a_index == '': a_index = -1 if s_index == -1: if subs_streams != '': # check for no data s_option = subs_streams.split('\r') if len(s_option) == 1: s_index = s_option[0].split('|')[0] subs_type = s_option[0].split('|')[1] else: s_idx = xbmcgui.Dialog().select( plugin_addon.getLocalizedString(30179), s_option) if s_idx > -1: s_index = s_option[s_idx].split('|')[0] if s_index == '': s_index = -1 else: subs_type = s_option[s_idx].split('|')[1] if subs_type not in ['ass', 'aas', 'srt']: subs_type = '' else: # TODO try to get external subtitles pass eh.spam('Pick_Best_Streams results: "%s" "%s" "%s"' % (a_index, s_index, subs_type)) return a_index, s_index, subs_type
def onPlayBackPaused(self): spam('Playback Paused') self.PlaybackStatus = PlaybackStatus.PAUSED self.scrobble_time()
def get_data(self, url, referer, timeout, apikey): try: import error_handler as eh headers = { 'Accept': 'application/json', 'apikey': apikey, } if referer is not None: referer = quote(self.encode(referer)).replace('%3A', ':') if len(referer) > 1: headers['Referer'] = referer if '127.0.0.1' not in url and 'localhost' not in url: headers['Accept-Encoding'] = 'gzip' if '/Stream/' in url: headers['api-version'] = '1.0' # self.encode(url) # py3 fix req = Request(url, headers=headers) data = None eh.spam('Getting Data ---') eh.spam('URL: ', url) eh.spam('Headers:', headers) response = urlopen(req, timeout=int(timeout)) if response.info().get('Content-Encoding') == 'gzip': eh.spam('Got gzipped response. Decompressing') try: buf = BytesIO(response.read()) f = gzip.GzipFile(fileobj=buf) data = f.read() except Exception as e: eh.spam('Failed to decompress.', e.message) else: data = response.read() response.close() eh.spam('Response Body:', data) eh.spam('Checking Response for a text error.\n') if data is not None and data != '': self.parse_possible_error(req, data) return data except Exception as ex: xbmc.log(' === get_data error === %s' % ex, xbmc.LOGNOTICE)
def player_loop(player, is_transcoded, is_transcode_finished, ep_id, party_mode): try: monitor = xbmc.Monitor() # seek to beginning of stream :hack: https://github.com/peak3d/inputstream.adaptive/issues/94 if is_transcoded: while not xbmc.Player().isPlayingVideo(): monitor.waitForAbort(0.25) if not is_transcode_finished: if xbmc.Player().isPlayingVideo(): log('Seek back - so the stream is from beginning') # TODO part1: hack is temporary and not working in 100% # TODO part2: (with small segments + fast cpu, you wont start from 1st segment) #xbmc.executebuiltin('Seek(-60)') xbmc.executeJSONRPC( '{"jsonrpc":"2.0","method":"Player.Seek","params":{"playerid":1,"value":{"seconds":0}},"id":1}' ) while player.PlaybackStatus != PlaybackStatus.STOPPED and player.PlaybackStatus != PlaybackStatus.ENDED: xbmc.sleep(500) if player.PlaybackStatus == PlaybackStatus.STOPPED or player.PlaybackStatus == PlaybackStatus.ENDED: log('Playback Ended - Shutting Down: ', monitor.abortRequested()) if player.is_finished: log('post-finish: start events') if ep_id != 0: from shoko_models.v2 import Episode ep = Episode(ep_id, build_full_object=False) spam('mark as watched, episode') ep.set_watched_status(True) # wait till directory is loaded while kodi_utils.is_dialog_active(): xbmc.sleep(500) # refresh it, so it moves onto next item and the mark watched is refreshed kodi_utils.refresh() # wait till it load again while kodi_utils.is_dialog_active(): xbmc.sleep(500) if int(ep_id) != 0 and plugin_addon.getSetting( 'vote_always') == 'true' and not party_mode: spam('vote_always, voting on episode') script_utils.vote_for_episode(ep_id) if int(ep_id) != 0 and plugin_addon.getSetting( 'vote_on_series') == 'true' and not party_mode: from shoko_models.v2 import get_series_for_episode series = get_series_for_episode(ep_id) # voting should be only when you really watch full series spam('vote_on_series, mark: %s / %s' % (series.sizes.watched_episodes, series.sizes.total_episodes)) if series.sizes.watched_episodes - series.sizes.total_episodes == 0: script_utils.vote_for_series(series.id) return -1 else: log( 'Playback Ended - Playback status was not "Stopped" or "Ended". It was ', player.PlaybackStatus) return 0 except: eh.exception(ErrorPriority.HIGHEST) return -1
def reset(self): spam('Player reset') self.__init__()
def onAVChange(self): # Will be called when Kodi has a video, audio or subtitle stream. Also happens when the stream changes. spam('onAVChange')