def _process_chunk(self, medialist, singleitemlist, singleitem): artcount = 0 currentitem = 0 aborted = False for mediaitem in medialist: if is_excluded(mediaitem): continue if mediaitem.mediatype in mediatypes.audiotypes and get_kodi_version( ) < 18: continue self.update_progress(currentitem * 100 // len(medialist), mediaitem.label) info.add_additional_iteminfo(mediaitem, self.processed, None if self.localmode else search) currentitem += 1 try: services_hit = self._process_item(mediaitem, singleitem) except FileError as ex: services_hit = True mediaitem.error = ex.message log(ex.message, xbmc.LOGERROR) self.notify_warning(ex.message, None, True) reporting.report_item(mediaitem, singleitemlist or mediaitem.error) artcount += len(mediaitem.updatedart) if not services_hit: if self.monitor.abortRequested(): aborted = True break elif self.monitor.waitForAbort(THROTTLE_TIME): aborted = True break return aborted, currentitem, artcount
def remove_specific_arttypes(): options = [ (L(M.MOVIES), lambda: quickjson.get_item_list(mediatypes.MOVIE), mediatypes.MOVIE), (L(M.SERIES), quickjson.get_tvshows, mediatypes.TVSHOW), (L(M.SEASONS), quickjson.get_seasons, mediatypes.SEASON), (L(M.MOVIESETS), lambda: quickjson.get_item_list(mediatypes.MOVIESET), mediatypes.MOVIESET), (L(M.EPISODES), quickjson.get_episodes, mediatypes.EPISODE), (L(M.MUSICVIDEOS), lambda: quickjson.get_item_list(mediatypes.MUSICVIDEO), mediatypes.MUSICVIDEO) ] if get_kodi_version() >= 18: options.extend( ((L(M.ARTISTS), lambda: quickjson.get_item_list(mediatypes.ARTIST), mediatypes.ARTIST), (L(M.ALBUMS), lambda: quickjson.get_item_list(mediatypes.ALBUM), mediatypes.ALBUM), (L(M.SONGS), lambda: quickjson.get_item_list(mediatypes.SONG), mediatypes.SONG))) selected = xbmcgui.Dialog().select(L( M.REMOVE_SPECIFIC_TYPES), [option[0] + " ..." for option in options]) if selected < 0 or selected >= len(options): return busy = pykodi.get_busydialog() busy.create() allitems = options[selected][1]() counter = {} types_to_remove = set() for arttype, url in chain.from_iterable( d.get('art', {}).iteritems() for d in allitems): if '.' in arttype: continue counter['* all'] = counter.get('* all', 0) + 1 counter[arttype] = counter.get(arttype, 0) + 1 if not info.keep_arttype(options[selected][2], arttype, url): types_to_remove.add(arttype) counter['* nowhitelist'] = counter.get('* nowhitelist', 0) + 1 arttypes = sorted(counter.keys()) busy.close() ftype = lambda intype: '* ' + ', '.join(sorted( types_to_remove)) if intype == '* nowhitelist' else intype selectedarttype = xbmcgui.Dialog().select(options[selected][0], [ "{0}: {1}".format(ftype(arttype), counter[arttype]) for arttype in arttypes ]) if selectedarttype >= 0 and selectedarttype < len(arttypes): def removetypes(mediaitem): changedart = cleaner.remove_specific_arttype( mediaitem, arttypes[selectedarttype]) info.remove_local_from_texturecache( (mediaitem.art[arttype] for arttype in changedart), True) return changedart fixcount = runon_medialist(removetypes, L(M.REMOVE_SPECIFIC_TYPES), allitems, options[selected][0]) notify_count(L(M.REMOVED_ART_COUNT), fixcount)
def show_artwork_log(): if pykodi.get_kodi_version() < 16: xbmcgui.Dialog().notification("Artwork Beef", L(M.VERSION_REQUIRED).format("Kodi 16"), xbmcgui.NOTIFICATION_INFO) return xbmcgui.Dialog().textviewer("Artwork Beef: " + L(M.REPORT_TITLE), reporting.get_latest_report())
def update_useragent(self): beefversion = pykodi.get_main_addon().version if pykodi.get_kodi_version() < 17: from lib.libs import quickjson props = quickjson.get_application_properties(['name', 'version']) appversion = '{0}.{1}'.format(props['version']['major'], props['version']['minor']) self.useragent = 'ArtworkBeef/{0} {1}/{2}'.format(beefversion, props['name'], appversion) return self.useragent = 'ArtworkBeef/{0} '.format(beefversion) + xbmc.getUserAgent()
def init_run(self, show_progress=False, chunkcount=1): self.setlanguages() self.gatherer = Gatherer(self.monitor, self.autolanguages) self.downloader = FileManager(self.debug, chunkcount > 1) self.freshstart = str(datetime_now() - timedelta(days=365)) self.chunkcount = chunkcount self.currentchunk = 0 if get_kodi_version() >= 18: populate_musiccentraldir() if show_progress: self.create_progress()
def main(): settings.update_settings() mediatypes.update_settings() command = get_command() if command.get('dbid') and command.get('mediatype'): processor = ArtworkProcessor() processor.process_item(command['mediatype'], int(command['dbid']), command.get('mode', 'auto')) elif 'command' in command: if command['command'] == 'set_autoaddepisodes': set_autoaddepisodes() elif command['command'] == 'show_artwork_log': show_artwork_log() elif command['command'] == 'set_download_artwork' and command.get( 'mediatype'): set_download_artwork(command['mediatype']) else: processor = ArtworkProcessor() if processor.processor_busy: options = [ (L(M.STOP), 'NotifyAll(script.artwork.beef:control, CancelCurrent)') ] else: options = [ (L(M.ADD_MISSING_FOR), add_missing_for), (L(M.NEW_LOCAL_FILES), 'NotifyAll(script.artwork.beef:control, ProcessLocalVideos)'), (L(M.IDENTIFY_UNMATCHED_SETS), lambda: identify_unmatched(mediatypes.MOVIESET)), (L(M.IDENTIFY_UNMATCHED_MVIDS), lambda: identify_unmatched(mediatypes.MUSICVIDEO)), (L(M.REMOVE_SPECIFIC_TYPES), remove_specific_arttypes), (L(M.MAKE_LOCAL), make_local), (L(M.CACHE_VIDEO_ARTWORK), cache_artwork) ] if get_kodi_version() >= 18: options.append( (L(M.CACHE_MUSIC_ARTWORK), lambda: cache_artwork('music'))) options.append( (L(M.SAVE_ARTTYPES_TO_ASXML), save_arttypes_to_asxml)) if advancedsettings.has_backup(): options.append((L(M.RESTORE_ASXML_BACKUP), advancedsettings.restore_backup)) selected = xbmcgui.Dialog().select('Artwork Beef', [option[0] for option in options]) if selected >= 0 and selected < len(options): action = options[selected][1] if isinstance(action, basestring): pykodi.execute_builtin(action) else: action()
def add_missing_for(): options = [(L(M.FOR_NEW_VIDEOS), 'ProcessNewVideos'), (L(M.FOR_OLD_VIDEOS), 'ProcessNewAndOldVideos'), (L(M.FOR_ALL_VIDEOS), 'ProcessAllVideos')] if get_kodi_version() >= 18: options.extend(((L(M.FOR_NEW_AUDIO), 'ProcessNewMusic'), (L(M.FOR_OLD_AUDIO), 'ProcessNewAndOldMusic'), (L(M.FOR_ALL_AUDIO), 'ProcessAllMusic'))) selected = xbmcgui.Dialog().select(L(M.ADD_MISSING_FOR), [option[0] for option in options]) if selected >= 0 and selected < len(options): pykodi.execute_builtin( 'NotifyAll(script.artwork.beef:control, {0})'.format( options[selected][1]))
def runon_medialist(function, heading, medialist='videos', typelabel=None, fg=False): progress = xbmcgui.DialogProgress() if fg else xbmcgui.DialogProgressBG() progress.create(heading) monitor = xbmc.Monitor() if medialist == 'videos': steps_to_run = [ (lambda: quickjson.get_item_list(mediatypes.MOVIE), L(M.MOVIES)), (info.get_cached_tvshows, L(M.SERIES)), (quickjson.get_seasons, L(M.SEASONS)), (lambda: quickjson.get_item_list(mediatypes.MOVIESET), L(M.MOVIESETS)), (quickjson.get_episodes, L(M.EPISODES)), (lambda: quickjson.get_item_list(mediatypes.MUSICVIDEO), L(M.MUSICVIDEOS)) ] elif medialist == 'music' and get_kodi_version() >= 18: steps_to_run = [ (lambda: quickjson.get_item_list(mediatypes.ARTIST), L(M.ARTISTS)), (lambda: quickjson.get_item_list(mediatypes.ALBUM), L(M.ALBUMS)), (lambda: quickjson.get_item_list(mediatypes.SONG), L(M.SONGS)) ] else: steps_to_run = ((lambda: medialist, typelabel), ) stepsize = 100 // len(steps_to_run) def update_art_for_items(items, start): changedcount = 0 for i, item in enumerate(items): if fg: progress.update(start + i * stepsize // len(items), item['label']) else: progress.update(start + i * stepsize // len(items)) item = info.MediaItem(item) if item.mediatype == mediatypes.SEASON: item.file = info.get_cached_tvshow(item.tvshowid)['file'] updates = function(item) if isinstance(updates, int): changedcount += updates else: processed = utils.get_simpledict_updates(item.art, updates) if processed: info.update_art_in_library(item.mediatype, item.dbid, processed) changedcount += len(processed) if monitor.abortRequested() or fg and progress.iscanceled(): break return changedcount fixcount = 0 for i, (list_fn, listtype) in enumerate(steps_to_run): start = i * stepsize if fg: progress.update(start, line1=L(M.LISTING_ALL).format(listtype)) else: progress.update(start, message=L(M.LISTING_ALL).format(listtype)) fixcount += update_art_for_items(list_fn(), start) if monitor.abortRequested() or fg and progress.iscanceled(): break info.clear_cache() progress.close() return fixcount
def process_item(self, mediatype, dbid, mode): if self.processor_busy: return if mode == MODE_DEBUG: mode = MODE_AUTO self.set_debug(True) if mode == MODE_GUI: busy = pykodi.get_busydialog() busy.create() if mediatype in mediatypes.artinfo and (mediatype not in mediatypes.audiotypes or get_kodi_version() >= 18): mediaitem = info.MediaItem( quickjson.get_item_details(dbid, mediatype)) log("Processing {0} '{1}' {2}.".format( mediatype, mediaitem.label, 'automatically' if mode == MODE_AUTO else 'manually')) else: if mode == MODE_GUI: busy.close() xbmcgui.Dialog().notification( "Artwork Beef", L(NOT_SUPPORTED_MESSAGE).format(mediatype), '-', 6500) return self.init_run() if mediatype == mediatypes.EPISODE: series = quickjson.get_item_details(mediaitem.tvshowid, mediatypes.TVSHOW) if not any(uniqueid in settings.autoadd_episodes for uniqueid in series['uniqueid'].itervalues()): mediaitem.skip_artwork = ['fanart'] info.add_additional_iteminfo(mediaitem, self.processed, search) if not mediaitem.uniqueids and not mediatypes.only_filesystem( mediaitem.mediatype): if mediatype in mediatypes.require_manualid: self.manual_id(mediaitem) if mode == MODE_GUI: self._manual_item_process(mediaitem, busy) else: medialist = [mediaitem] if mediatype == mediatypes.TVSHOW and not mediatypes.disabled( mediatypes.EPISODE): gen_epthumb = mediatypes.generatethumb(mediatypes.EPISODE) download_ep = mediatypes.downloadanyartwork(mediatypes.EPISODE) if mediaitem.uniqueids and any( x in mediaitem.uniqueids.values() for x in settings.autoadd_episodes): medialist.extend( info.MediaItem(ep) for ep in quickjson.get_episodes(dbid)) elif gen_epthumb or download_ep: for episode in quickjson.get_episodes(dbid): if gen_epthumb and not info.has_generated_thumbnail(episode) \ or download_ep and info.has_art_todownload(episode['art'], mediatypes.EPISODE): episode = info.MediaItem(episode) episode.skip_artwork = ['fanart'] medialist.append(episode) elif mediatype == mediatypes.ARTIST and not mediatypes.disabled( mediatypes.ALBUM): medialist.extend( info.MediaItem(album) for album in quickjson.get_albums( mediaitem.label, mediaitem.dbid)) if mediatype in (mediatypes.ALBUM, mediatypes.ARTIST) and not mediatypes.disabled(mediatypes.ALBUM) \ and not mediatypes.disabled(mediatypes.SONG): medialist.extend( info.MediaItem(song) for song in quickjson.get_songs( mediaitem.mediatype, mediaitem.dbid)) self.process_medialist(medialist, True)
def watchitem(self, data): can_use_data = 'item' in data and data['item'].get('id') and data['item'].get('id') != -1 return can_use_data and 'playcount' not in data and data['item'].get('type') in self.recentvideos \ and (pykodi.get_kodi_version() < 18 or data.get('added'))
def onNotification(self, sender, method, data): if method.startswith('Other.') and sender != 'script.artwork.beef:control': return if method == 'Other.CancelCurrent': if self.status == STATUS_PROCESSING: self.abort = True elif self.signal: self.signal = None self.processor.close_progress() elif method == 'Other.ProcessNewVideos': self.processor.create_progress() self.signal = 'newvideos' elif method == 'Other.ProcessNewAndOldVideos': self.processor.create_progress() self.signal = 'oldvideos' elif method == 'Other.ProcessAllVideos': self.processor.create_progress() self.signal = 'allvideos' elif method == 'Other.ProcessLocalVideos': self.processor.create_progress() self.signal = 'localvideos' elif method == 'Other.ProcessAfterSettings': self.processaftersettings = True elif method == 'Player.OnStop': if settings.enableservice: data = json.loads(data) if self.watchitem(data): self.stoppeditems.add((data['item']['type'], data['item']['id'])) elif method == 'VideoLibrary.OnScanStarted': if settings.enableservice and self.status == STATUS_PROCESSING: self.abort = True elif method == 'VideoLibrary.OnScanFinished': if settings.enableservice: scan_olditems = settings.enable_olditem_updates and get_date() > self.last_videoupdate self.signal = 'oldvideos' if scan_olditems else 'newvideos' self.processor.create_progress() elif method == 'VideoLibrary.OnUpdate': if not settings.enableservice: return data = json.loads(data) if not self.watchitem(data): return if (data['item']['type'], data['item']['id']) in self.stoppeditems: self.stoppeditems.remove((data['item']['type'], data['item']['id'])) return if not self.scanning: self.recentvideos[data['item']['type']].append(data['item']['id']) self.signal = 'recentvideos' elif pykodi.get_kodi_version() >= 18: if method == 'AudioLibrary.OnScanFinished': if settings.enableservice_music: scan_olditems = settings.enable_olditem_updates and get_date() > self.last_musicupdate self.signal = 'oldmusic' if scan_olditems else 'newmusic' elif method == 'Other.ProcessNewMusic': self.processor.create_progress() self.signal = 'newmusic' elif method == 'Other.ProcessNewAndOldMusic': self.processor.create_progress() self.signal = 'oldmusic' elif method == 'Other.ProcessAllMusic': self.processor.create_progress() self.signal = 'allmusic'
def _upgradeproperties(): if get_kodi_version() < 17: typemap[mediatypes.TVSHOW][1].remove('uniqueid') typemap[mediatypes.MOVIE][1].remove('premiered') typemap[mediatypes.MOVIE][1].remove('uniqueid') typemap[mediatypes.MOVIE][1].append('year')
def _needupgrade(mediatype): return mediatype in (mediatypes.MOVIE, mediatypes.TVSHOW) and get_kodi_version() < 17
def get_seasons(tvshow_id=-1): if tvshow_id == -1 and pykodi.get_kodi_version() < 17: return _get_all_seasons_jarvis() else: return _inner_get_seasons(tvshow_id)