def get_language_details(base, tmdb_type, tmdb_id, season=None, episode=None, language=None, year=None): if not language: return base item = _get_language_item(tmdb_type, tmdb_id, season, episode, language, year) if not item: return base item = {k: v or base.get(k) for k, v in viewitems(item)} # Fallback to default key in base if translation is empty item = _url_encode_item(item) for k, v in viewitems(item): base[u'{}_{}'.format(language, k)] = v return _url_encode_item(base)
def set_show(item, base_item=None): if not base_item: return item item['art'].update( {'tvshow.{}'.format(k): v for k, v in viewitems(base_item.get('art', {}))}) item['unique_ids'].update( {'tvshow.{}'.format(k): v for k, v in viewitems(base_item.get('unique_ids', {}))}) item['infoproperties'].update( {'tvshow.{}'.format(k): v for k, v in viewitems(base_item.get('infolabels', {})) if type(v) not in [dict, list, tuple]}) item['infolabels']['tvshowtitle'] = base_item['infolabels'].get('title') item['unique_ids']['tmdb'] = item['unique_ids'].get('tvshow.tmdb') return item
def _url_encode_item(item, base=None): base = base or item.copy() for k, v in viewitems(base): if k not in PLAYERS_URLENCODE: continue v = u'{0}'.format(v) for key, value in viewitems({k: v, '{}_meta'.format(k): dumps(v)}): item[key] = value.replace(',', '') item[key + '_+'] = value.replace(',', '').replace(' ', '+') item[key + '_-'] = value.replace(',', '').replace(' ', '-') item[key + '_escaped'] = quote(quote(try_encode(value))) item[key + '_escaped+'] = quote(quote_plus(try_encode(value))) item[key + '_url'] = quote(try_encode(value)) item[key + '_url+'] = quote_plus(try_encode(value)) return item
def _get_calendar_episode_item(self, i): air_date = convert_timestamp(i.get('first_aired'), utc_convert=True) item = get_empty_item() item['label'] = i.get('episode', {}).get('title') item['infolabels'] = { 'mediatype': 'episode', 'premiered': air_date.strftime('%Y-%m-%d'), 'year': air_date.strftime('%Y'), 'title': item['label'], 'episode': i.get('episode', {}).get('number'), 'season': i.get('episode', {}).get('season'), 'tvshowtitle': i.get('show', {}).get('title'), 'duration': try_int(i.get('episode', {}).get('runtime', 0)) * 60, 'plot': i.get('episode', {}).get('overview'), 'mpaa': i.get('show', {}).get('certification')} item['infoproperties'] = { 'air_date': get_region_date(air_date, 'datelong'), 'air_time': get_region_date(air_date, 'time'), 'air_day': air_date.strftime('%A'), 'air_day_short': air_date.strftime('%a'), 'air_date_short': air_date.strftime('%d %b')} item['unique_ids'] = {u'tvshow.{}'.format(k): v for k, v in viewitems(i.get('show', {}).get('ids', {}))} item['params'] = { 'info': 'details', 'tmdb_type': 'tv', 'tmdb_id': i.get('show', {}).get('ids', {}).get('tmdb'), 'episode': i.get('episode', {}).get('number'), 'season': i.get('episode', {}).get('season')} return item
def get_providers(v): infoproperties = {} infoproperties['provider.link'] = v.pop('link', None) newlist = (dict(i, **{'key': key}) for key, value in viewitems(v) if isinstance(value, list) for i in value if isinstance(i, dict)) added = [] added_append = added.append for i in sorted(newlist, key=lambda k: k.get('display_priority', 1000)): if not i.get('provider_name'): continue # If provider already added just update type if i['provider_name'] in added: idx = u'provider.{}.type'.format( added.index(i['provider_name']) + 1) infoproperties[idx] = u'{} / {}'.format(infoproperties.get(idx), i.get('key')) continue # Add item provider x = len(added) + 1 infoproperties.update({ u'provider.{}.id'.format(x): i.get('provider_id'), u'provider.{}.type'.format(x): i.get('key'), u'provider.{}.name'.format(x): i['provider_name'], u'provider.{}.icon'.format(x): get_imagepath_poster(i.get('logo_path')) }) added_append(i['provider_name']) return infoproperties
def _list_trakt_sortby_item(self, i, params): item = get_empty_item() item['label'] = item['infolabels']['title'] = i['name'] item['params'] = params for k, v in viewitems(i['params']): item['params'][k] = v return item
def get_cast_list(self, tmdb_id, tmdb_type, season=None, episode=None, keys=['cast', 'guest_stars']): items = [] prev_item = {} if season is not None and episode is not None: affix = 'season/{}/episode/{}'.format(season, episode) elif season is not None: affix = 'season/{}'.format(season) else: affix = None response = self.get_request_lc(tmdb_type, tmdb_id, affix, 'credits') if not response: return items # Avoid re-adding the same cast/crew member if multiple roles # Instead merge infoproperties (ie roles / jobs / departments etc) together and make one item prev_item = None cast_list = [] for key in keys: cast_list += response.get(key) or [] for i in cast_list: this_item = self.mapper.get_info(i, 'person') if prev_item and prev_item.get('label') != this_item.get('label'): items.append(prev_item) elif prev_item: infoproperties = prev_item.get('infoproperties', {}) for k, v in viewitems(this_item.get('infoproperties', {})): if not v: continue if not infoproperties.get(k): infoproperties[k] = v elif infoproperties.get(k) != v: infoproperties[k] = '{} / {}'.format(infoproperties[k], v) this_item['infoproperties'] = infoproperties prev_item = this_item items.append(prev_item) if prev_item else None return items
def get_listitem(self): if self.infolabels.get('mediatype') not in ACCEPTED_MEDIATYPES: self.infolabels.pop('mediatype', None) self.infolabels['path'] = self.get_url() listitem = xbmcgui.ListItem(label=self.label, label2=self.label2, path=self.infolabels['path']) listitem.setLabel2(self.label2) listitem.setInfo(self.library, self.infolabels) listitem.setArt(self.set_art_fallbacks()) if self.library == 'pictures': return listitem listitem.setUniqueIDs(self.unique_ids) listitem.setProperties(self.infoproperties) listitem.setCast(self.cast) listitem.addContextMenuItems(self.context_menu) if not self.stream_details: return listitem for k, v in viewitems(self.stream_details): if not k or not v: continue for i in v: if not i: continue listitem.addStreamInfo(k, i) return listitem
def get_list_of_lists(self, path, page=1, limit=250, authorize=False, next_page=True): response = self.get_response(path, page=page, limit=limit) like_list = True if path.startswith('lists/') else False delete_like = True if path.startswith('users/likes') else False if not response: return items = [] for i in response.json(): if i.get('list', {}).get('name'): i = i.get('list', {}) elif not i.get('name'): continue item = {} item['label'] = i.get('name') item['infolabels'] = {'plot': i.get('description')} item['infoproperties'] = {k: v for k, v in viewitems(i) if v and type(v) not in [list, dict]} item['art'] = {} item['params'] = { 'info': 'trakt_userlist', 'list_slug': i.get('ids', {}).get('slug'), 'user_slug': i.get('user', {}).get('ids', {}).get('slug')} item['unique_ids'] = { 'trakt': i.get('ids', {}).get('trakt'), 'slug': i.get('ids', {}).get('slug'), 'user': i.get('user', {}).get('ids', {}).get('slug')} item['infoproperties']['tmdbhelper.context.sorting'] = dumps(item['params']) # Add library context menu item['context_menu'] = [( xbmc.getLocalizedString(20444), u'Runscript(plugin.video.themoviedb.helper,{})'.format( u'user_list={list_slug},user_slug={user_slug}'.format(**item['params'])))] # Unlike list context menu if path.startswith('users/likes'): item['context_menu'] += [( ADDON.getLocalizedString(32319), u'Runscript(plugin.video.themoviedb.helper,{},delete)'.format( u'like_list={list_slug},user_slug={user_slug}'.format(**item['params'])))] # Like list context menu elif path.startswith('lists/'): item['context_menu'] += [( ADDON.getLocalizedString(32315), u'Runscript(plugin.video.themoviedb.helper,{})'.format( u'like_list={list_slug},user_slug={user_slug}'.format(**item['params'])))] # Owner of list so set param to allow deleting later else: item['params']['owner'] = 'true' item['context_menu'] += [( xbmc.getLocalizedString(118), u'Runscript(plugin.video.themoviedb.helper,{})'.format( u'rename_list={list_slug}'.format(**item['params'])))] item['context_menu'] += [( xbmc.getLocalizedString(117), u'Runscript(plugin.video.themoviedb.helper,{})'.format( u'delete_list={list_slug}'.format(**item['params'])))] items.append(item) if not next_page: return items return items + pages.get_next_page(response.headers)
def sort_list(**kwargs): sort_methods = get_sort_methods() x = xbmcgui.Dialog().contextmenu([i['name'] for i in sort_methods]) if x == -1: return for k, v in viewitems(sort_methods[x]['params']): kwargs[k] = v xbmc.executebuiltin(try_encode(format_folderpath(encode_url(**kwargs))))
def get_params(item, tmdb_type, tmdb_id=None, params=None, definition=None, base_tmdb_type=None): params = params or {} tmdb_id = tmdb_id or item.get('id') if params == -1: return {} definition = definition or {'info': 'details', 'tmdb_type': '{tmdb_type}', 'tmdb_id': '{tmdb_id}'} for k, v in viewitems(definition): params[k] = v.format(tmdb_type=tmdb_type, tmdb_id=tmdb_id, base_tmdb_type=base_tmdb_type, **item) return del_empty_keys(params) # TODO: Is this necessary??!
def set_params_to_info(self, widget=None): for k, v in viewitems(self.params): if not k or not v: continue self.infoproperties[u'item.{}'.format(k)] = v if self.params.get('tmdb_type'): self.infoproperties['item.type'] = self.params['tmdb_type'] if widget: self.infoproperties['widget'] = widget
def add_base(self, item, base_item=None, tmdb_type=None): if not base_item: return item for d in ['infolabels', 'infoproperties', 'art']: for k, v in viewitems(base_item.get(d, {})): if not v or item[d].get(k): continue item[d][k] = v return set_show(item, base_item) if tmdb_type in ['season', 'episode', 'tv'] else item
def get_ftv_artwork(self, li): if not self.ftv_api: return artwork = self.ftv_api.get_all_artwork(li.get_ftv_id(), li.get_ftv_type()) if not artwork: return if li.infolabels.get('mediatype') in ['season', 'episode']: artwork = {u'tvshow.{}'.format(k): v for k, v in viewitems(artwork) if v} return {'art': artwork}
def _get_item_unique_ids(item, unique_ids=None, prefix=None, show=None): prefix = prefix or '' unique_ids = unique_ids or {} for k, v in viewitems(item.get('ids', {})): unique_ids[u'{}{}'.format(prefix, k)] = v if show: unique_ids = _get_item_unique_ids(show, unique_ids, prefix='tvshow.') unique_ids['tmdb'] = show.get('ids', {}).get('tmdb') return del_empty_keys(unique_ids)
def iter_props(items, property_name, infoproperties=None, func=None, **kwargs): infoproperties = infoproperties or {} if not items or not isinstance(items, list): return infoproperties for x, i in enumerate(items, start=1): for k, v in viewitems(kwargs): infoproperties[u'{}.{}.{}'.format(property_name, x, k)] = func(i.get(v)) if func else i.get(v) if x >= 10: break return infoproperties
def map_item(self, item, i): sm = self.standard_map or {} am = self.advanced_map or {} # Iterate over item retrieved from api list for k, pv in viewitems(i): # Skip empty objects if not pv and pv is not 0: continue # Skip blacklist values if pv in self.blacklist: continue # Simple mapping is quicker so do that first if we can if k in sm: item[sm[k][0]][sm[k][1]] = pv continue # Check key is in advanced map before trying to map it if k not in am: continue # Iterate over list of dictionaries for d in am[k]: # Make a quick copy of object if isinstance(pv, dict): v = pv.copy() elif isinstance(pv, list): v = pv[:] else: v = pv # Get subkeys if 'subkeys' in d: for ck in d['subkeys']: v = v.get(ck) or {} if not v: continue # Run through type conversion if 'type' in d: v = try_type(v, d['type']) # Run through func if 'func' in d: v = d['func'](v, *d.get('args', []), **d.get('kwargs', {})) # Check not empty if not v and v is not 0: continue # Map value onto item dict parent/child keys for p, c in d['keys']: if c == UPDATE_BASEKEY: item[p].update(v) elif c is None: item[p] = v elif 'extend' in d and isinstance( item[p].get(c), list) and isinstance(v, list): item[p][c] += v else: item[p][c] = v return item
def get_discover_list(self, tmdb_type, **kwargs): # TODO: Check what regions etc we need to have for k, v in viewitems(kwargs): if k in ['with_id', 'with_separator', 'page', 'limit', 'nextpage', 'widget', 'fanarttv']: continue if k and v: break else: # Only build discover list if we have params to pass return path = 'discover/{}'.format(tmdb_type) return self.get_basic_list(path, tmdb_type, **kwargs)
def set_params_to_container(self, **kwargs): for k, v in viewitems(kwargs): if not k or not v: continue try: xbmcplugin.setProperty( self.handle, u'Param.{}'.format(k), u'{}'.format(v)) # Set params to container properties except Exception as exc: kodi_log( u'Error: {}\nUnable to set Param.{} to {}'.format( exc, k, v), 1)
def get_resolved_path(self, return_listitem=True): if not self.item: return get_property('PlayerInfoString', clear_property=True) path = self._get_resolved_path(allow_default=True) or {} if return_listitem: self.details.params = {} self.details.path = path.pop('url', None) for k, v in viewitems(path): self.details.infoproperties[k] = v path = self.details.get_listitem() return path
def merge_two_dicts(x, y, reverse=False, deep=False): xx = y or {} if reverse else x or {} yy = x or {} if reverse else y or {} z = xx.copy() # start with x's keys and values if not deep: # modifies z with y's keys and values z.update(yy) return z for k, v in viewitems(yy): if isinstance(v, dict): merge_two_dicts(z.setdefault(k, {}), v, reverse=reverse, deep=True) elif v: z[k] = v return z
def _get_dialog_players(players): return [ ListItem( label=v.get('name'), label2=k, art={ 'thumb': v.get('icon', '').format(ADDONPATH) or xbmcaddon.Addon(v.get('plugin', '')).getAddonInfo('icon') }).get_listitem() for k, v in sorted(viewitems(players), key=lambda i: try_int(i[1].get('priority')) or PLAYERS_PRIORITY) ]
def _log_item(self, key, tmdb_id, season=None, episode=None, **kwargs): to_update = self.logging.setdefault(key, {}) to_update = self.logging[key].setdefault(tmdb_id, {}) if season is not None: to_update = self.logging[key][tmdb_id].setdefault('seasons', {}) to_update = self.logging[key][tmdb_id]['seasons'].setdefault( season, {}) if episode is not None: to_update = self.logging[key][tmdb_id]['seasons'][ season].setdefault('episodes', {}) to_update = self.logging[key][tmdb_id]['seasons'][season][ 'episodes'].setdefault(episode, {}) for k, v in viewitems(kwargs): to_update[k] = v
def _build_item(self, mediatypes): params_def = mediatypes.get(self.mediatype, mediatypes.get('other')) if not params_def: return item = {} for k, v in viewitems(params_def): try: # Need to try accept in case hard-coded int/bool etc. value = v.format(**self.info) except AttributeError: value = v if value is None: return # Don't create a context item if we don't have a formatter value item[k] = value return item
def finalise(self, item, tmdb_type): if tmdb_type == 'image': item = self.finalise_image(item) elif tmdb_type == 'person': item = self.finalise_person(item) elif tmdb_type == 'tv' and not item['infolabels'].get('tvshowtitle'): item['infolabels']['tvshowtitle'] = item['infolabels'].get('title') item['label'] = item['infolabels'].get('title') item['infoproperties']['tmdb_type'] = tmdb_type item['infolabels']['mediatype'] = item['infoproperties']['dbtype'] = convert_type(tmdb_type, 'dbtype') item['art']['thumb'] = item['art'].get('thumb') or item['art'].get('poster') for k, v in viewitems(item['unique_ids']): item['infoproperties'][u'{}_id'.format(k)] = v return item
def get_all_items_list(self, tmdb_type, page=None): if tmdb_type not in TMDB_ALL_ITEMS_LISTS: return daily_list = self.get_daily_list(export_list=TMDB_ALL_ITEMS_LISTS.get( tmdb_type, {}).get('type'), sorting=False, reverse=False) if not daily_list: return items = [] param = TMDB_ALL_ITEMS_LISTS.get(tmdb_type, {}).get('params', {}) limit = TMDB_ALL_ITEMS_LISTS.get(tmdb_type, {}).get('limit', 20) pos_z = try_int(page, fallback=1) * limit pos_a = pos_z - limit dbtype = convert_type(tmdb_type, 'dbtype') for i in daily_list[pos_a:pos_z]: if not i.get('id'): continue if tmdb_type in ['keyword', 'network', 'studio']: item = { 'label': i.get('name'), 'infolabels': { 'mediatype': dbtype }, 'infoproperties': { 'dbtype': dbtype }, 'unique_ids': { 'tmdb': i.get('id') }, 'params': {} } else: item = self.get_details(tmdb_type, i.get('id')) if not item: continue for k, v in viewitems(param): item['params'][k] = v.format(tmdb_id=i.get('id')) items.append(item) if not items: return [] if TMDB_ALL_ITEMS_LISTS.get(tmdb_type, {}).get('sort'): items = sorted(items, key=lambda k: k.get('label', '')) if len(daily_list) > pos_z: items.append({'next_page': try_int(page, fallback=1) + 1}) return items
def _edit_rules(idx=-1): """ Need to setup window properties if editing """ if idx == -1: return history = get_search_history('discover') history.reverse() try: item = history[idx] except IndexError: return _win_prop('save_index', set_property='{}'.format(len(history) - 1 - idx)) _win_prop('save_label', set_property='{}'.format(item.get('label'))) for k, v in viewitems(item.get('params', {})): if k in ['info', 'tmdb_type']: continue _win_prop(k, set_property=v) _win_prop(k, 'Label', set_property=item.get('labels', {}).get(k, v))
def get_cast_list(self, tmdb_id, tmdb_type, season=None, episode=None, keys=['cast', 'guest_stars']): items = [] if season is not None and episode is not None: affix = u'season/{}/episode/{}'.format(season, episode) elif season is not None: affix = u'season/{}'.format(season) else: affix = None response = self.get_request_lc(tmdb_type, tmdb_id, affix, 'credits') if not response: return [] # Join guest stars list etc cast_list = [] for key in keys: cast_list += response.get(key) or [] # Add items item_ids = [] for i in sorted(cast_list, key=lambda k: k.get('order', 1000)): if not i.get('id'): continue # Avoid re-adding people that have multiple roles listed if i['id'] not in item_ids: item_ids.append(i['id']) items.append(self.mapper.get_info(i, 'person')) continue # Instead merge their roles back into the original entry x = item_ids.index(i['id']) p = items[x].get('infoproperties', {}) for k, v in viewitems( self.mapper.get_info(i, 'person').get('infoproperties', {})): if not v: continue if not p.get(k): p[k] = v elif p[k] != v: p[k] = u'{} / {}'.format(p[k], v) return items
def set_indexed_properties(self, dictionary): if not isinstance(dictionary, dict): return index_properties = set() for k, v in viewitems(dictionary): if k in self.properties or k in SETPROP_RATINGS or k in SETMAIN_ARTWORK: continue try: v = v or '' self.set_property(k, v) index_properties.add(k) except Exception as exc: kodi_log(u'k: {0} v: {1} e: {2}'.format(k, v, exc), 1) for k in (self.index_properties - index_properties): self.clear_property(k) self.index_properties = index_properties.copy()
def set_indexed_properties(self, dictionary): if not isinstance(dictionary, dict): return index_properties = set() for k, v in viewitems(dictionary): if k in self.properties or k in SETPROP_RATINGS or k in SETMAIN_ARTWORK: continue try: v = v or '' self.set_property(k, v) index_properties.add(k) except Exception as exc: kodi_traceback( exc, u'\nlib.monitor.common set_indexed_properties\nk: {} v: {}' .format(k, v)) for k in (self.index_properties - index_properties): self.clear_property(k) self.index_properties = index_properties.copy()