#api_nrk.py # # NRK plugin for XBMC Media center # Copyright (C) 2009 Victor Vikene contact: z0py3r@hotmail.com # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # import sys __settings__ = sys.modules[ "__main__" ].__settings__ __language__ = sys.modules[ "__main__" ].__language__ import os import re import xbmc from utils import Key, Plugin, decode_htmlentities from urllib import quote_plus, unquote_plus from connection_manager import DataHandle, Session # # Define constants: # -------------------------------------------------------- # Used to determine state in instance and reference within # regular expression results # SHOW = 'prosjekt'; SHOW_CLIP = 'klipp' SHOW_FOLDER = 'kategori'; SHOW_CLIP_INDEX = 'indeks' PLAYLIST = 'spilleliste'; PLAYLIST_ITEM = 'spillefil' PLAYLIST_CLIP = 'verdi'; PLAYLIST_VIGNETE = 'vignett' PLAYLIST_ALT_CLIP = 'spill' PROGRAM = 'program'; VIGNETE = 'vignett'; SEARCH = 'search'; ROOT = 'root' CHANNELS = 'kanalene' # Views are both identifiers for instance and for some views # in the web api TOP_THIS_MONTH = 'msManed'; BY_THEME = 'theme' TOP_THIS_WEEK = 'msUke'; VIEW_ALL = 'visalle' TOP_TOTAL = 'msTotalt'; BY_CHAR = 'letter' RELEVANT = 'aktuelt'; PROGRAM = 'program' LIVE = 'direkte'; ARCHIVE = 'arkiv' RECOMMENDED = 'recommended' TOP_BY_INPUT = 'topbyinput' ARTICLES = 'articles' #Playlists SPORT = 'sport'; NEWS = 'nyheter'; SUPER = 'super' NATURE = 'natur'; REGION = 'distrikt' # Contents FILES = 'files'; MOVIES = 'movies' SONGS = 'songs'; TVSHOWS = 'tvshows' ARTISTS = 'artists'; EPISODES = 'episodes' ALBUMS = 'albums'; MUSICVIDEOS = 'musicvideos' # others.. REGION = 'distrikt'; ENCODING = 'iso-8859-1' # Connection speed CONNECTION_SPEED_LOW = 400 #bitrate: 300 kbps CONNECTION_SPEED_MEDIUM = 800 #bitrate: 650 kbps CONNECTION_SPEED_HIGH = 1200 #bitrate: 900 kbps rpath = os.path.join(os.getcwd(), 'resources', 'images') speed = CONNECTION_SPEED_LOW NDMR = 'ndmr'; NDHO = 'ndho'; NDNO = 'ndno'; NDRO = 'ndro' NDSF = 'ndsf'; NDSL = 'ndsl'; NDTL = 'ndtl'; NDTT = 'ndtt' NDOS = 'ndos'; NDOA = 'ndoa'; NDOP = 'ndop' region_abbr = { NDMR: 'more_og_romsdal', NDHO: 'hordaland', NDNO: 'nordnorge', NDRO: 'rogaland', NDSF: 'sognogfjordane', NDSL: 'sorlandet', NDTL: 'trondelag', NDTT: 'ostafjells', NDOS: 'ostfold', NDOA: 'ostlandssendigen', NDOP: 'oppland' } # shortcuts lang = sys.modules[ "__main__" ].__language__ def seconds_to_hms(seconds): m, s = divmod(seconds, 60) h, m = divmod(m, 60) return h,m,s # - EOM - class Api: def __set_dataman(self, cache): self.dman = DataHandle(cache) self.dman.default_encoding = ENCODING # - EOM - def __init__(self, speed, cache): self.__set_dataman(cache) self.speed = speed @staticmethod def _merge_playlists(cat, xml): mcount = 0 icount = 0 for i in xml: if i.key.type == PLAYLIST_VIGNETE: i.thumbnail = Plugin.image('news.png') elif i.key.type == PLAYLIST_ITEM: mcount -= 1 try: xml[icount].thumbnail = cat[mcount].thumbnail xml[icount].plot = cat[mcount].plot except IndexError: pass icount += 1 return xml def _get_intro(self, id, arg=None): if True == True: if id == REGION: name = NEWS; img = 'news.png' elif id == NEWS: name = NEWS; img = 'news.png' elif id == SPORT: name = SPORT; img = 'sport.png' elif id == SUPER: name = SUPER; img = 'kids.png' elif id == NATURE: name = NATURE; img = 'ntur.png' else: name = NEWS; img = 'news.png' title = '%s %s' % (name, 'hovedvignett') img = Plugin.image(img) key = Key('new', type=PLAYLIST_VIGNETE) istart = MediaObj(title=title, thumbnail=img, key=key) istart.isPlayable = True; istart.isFolder = False istart.url = Plugin.videopath(name + '_intro_main.avi') title = '%s %s' % (name, 'vignett') key = Key('new', type=PLAYLIST_VIGNETE) imid = MediaObj(title=title, thumbnail=img, key=key) imid.isPlayable = True; imid.isFolder = False imid.url = Plugin.videopath(name + '_intro.avi') return istart, imid, istart else: url = uri.playlist(loop=id, type=arg) data = self.dman.get_data(url) if data: tmp_list = extract.playlist(data) return tmp_list[0], tmp_list[2], tmp_list[-1] def get_all_shows(self): url = uri.live_content(BY_CHAR, '@') # http://www.nrk.no/nett-tv/bokstav/@/ data = self.dman.get_data(url) if data: return extract.catalog(data) def get_live_shows(self): url = uri.live_content() # http://www.nrk.no/nett-tv/ data = self.dman.get_data(url, cache=False) shows = extract.catalog(data, parent=LIVE, ext=extract.ext_live_show) return shows def get_shows_by_theme(self, id): url = uri.live_content(BY_THEME, id) # http://www.nrk.no/nett-tv/tema/4/ data = self.dman.get_data(url) if data: return extract.catalog(data) def get_shows_by_character(self, char): # http://www.nrk.no/nett-tv/bokstav/a/ url = uri.live_content(BY_CHAR, char) data = self.dman.get_data(url) if data: return extract.catalog(data) def get_show(self, id, type): # http://www.nrk.no/nett-tv/prosjekt/699/ url = uri.menu_fragment(id, type) data = self.dman.get_data(url) return extract.show(data) def get_most_viewed_shows(self, days): # http://www.nrk.no/nett-tv/ml/topp12.aspx?dager=7 url = uri.most_viewed(days) data = self.dman.get_data(url) return extract.catalog(data, ext=extract.ext_top_shows) def get_show_clip(self, id, parent=None, abs=True): # ?? http://www.nrk.no/nett-tv/klipp/675162/ url = uri.media_xml(id, self.speed) data = self.dman.get_data(url, persistent = True) item = extract.show_clip(data) if abs == True: url = uri.mms_to_http(item.url) data = self.dman.get_data(url) item.url = extract.mms_url(data) item.id = id return item def get_search_result(self, sstr, page): # http://www.nrk.no/nett-tv/sok/test/ url = uri.search(search=sstr, page=page) data = self.dman.get_data(url) if data: return extract.search(data) def get_viewstate(self, ident): url = uri.subpath(ident) data = self.dman.get_data(url) if data: return extract.viewstate(data) def get_playlist_item(self, id): url = uri.playlist(story=id) data = self.dman.get_data(url) if data: return extract.playlist(data)[0] def get_playlist(self, ident, type=None): if ident == 'distrikt': type = region_abbr[type] headers = uri.xmsheader; headers.update(uri.baseheaders) viewstate = self.get_viewstate(ident) if not viewstate: return form = uri.build_form(ident, viewstate, cat=type) url = uri.subpath(ident) data = self.dman.get_data(url, 'POST', form, headers) pcat = extract.catalog(data, type); pcat.reverse() url = uri.playlist(loop=ident, type=type) data = self.dman.get_data(url) pxml = extract.playlist(data, vignetes=False) siv, miv, eiv = self._get_intro(ident, type) pxml = self.inject_vignetes(pxml, siv, miv, eiv) return self._merge_playlists(pcat, pxml) def get_playlist_from_view(self, id, view, subcat): headers = uri.xmsheader headers.update(uri.baseheaders) vstate = self.get_viewstate(id) form = uri.build_form(id, vstate, view, subcat) url = uri.subpath(id) data = self.dman.get_data(url, 'POST', form, headers) if view == PROGRAM: return extract.show(data) else: siv, miv, eiv = self._get_intro(id, subcat) catalog = extract.catalog(data) catalog = self.inject_vignetes(catalog, siv, miv, eiv) return catalog def inject_vignetes(self, catalog, siv, miv, eiv): catalog.insert(0, siv); count = 0; total = len(catalog) for i in range(0, total): count += 1 if count % 2 == 0: if count < total - 1: catalog.insert(count, miv) catalog.append(eiv) return catalog def get_subtitles(self, id): url = uri.super_xml(id) data = self.dman.get_data(url) subs = extract.subtitles(data) subs = convert.sub_to_srt(subs) return subs def get_video_id(self, index_id): url = uri.subpath(SHOW_CLIP_INDEX, str(index_id)) heads = uri.cookieheader; heads.update(uri.baseheaders) data = self.dman.get_data(url, headers=headers) return extract.video_id(data) # - EOM - def get_path(self, id, type): url = uri.path_fragment(id, type) data = self.dman.get_data(url) path = extract.current_path(data) print 'Current path: %s' % path.encode('ascii', 'replace') return path def get_recommended_shows(self): url = uri.subpath() heads = uri.cookieheader; heads.update(uri.baseheaders) data = self.dman.get_data(url, headers=heads) return extract.recommended(data) def get_articles(self): url = uri.subpath() heads = uri.cookieheader; heads.update(uri.baseheaders) data = self.dman.get_data(url, headers=heads) return extract.articles(data) class convert: @staticmethod def sub_to_srt(subtitle): scount = 0; scont = '' for s in subtitle: #Create srt subtitle format scount += 1; seconds = s[0]; texting = s[1] h_start, m_start, s_start = seconds_to_hms(seconds) h_end, m_end, s_end = seconds_to_hms(seconds + 4) sub = ('%d\n%02d:%02d:%02d,000 --> ' + '%02d:%02d:%02d,000\n<b>%s</b>\n\n') % ( sub_counter, #HH:MM:SS,fff start h_start, m_start, s_start, #HH:MM:SS,fff end h_end, m_end, s_end, texting ) scont += sub return scont class uri: baseurl = 'http://www.nrk.no/nett-tv' #Map some translations for condition testing #within the project section lang_trans = { SHOW_FOLDER: 'category', SHOW_CLIP: 'broadcast', SHOW: 'project' } @staticmethod def search(search, sort='date', page=1, max=1): path = '/DynamiskLaster.aspx'; search = quote_plus(search) query = '?SearchResultList$search:%s|sort:%s|page:%d|max:%d' query = query % ( search, sort, page, max) return ''.join(( uri.baseurl, path, query )) @staticmethod def live_content(view=None, param=None): path = '/DynamiskLaster.aspx'; query = '?LiveContent$%s:%s' if not view and not param: return ''.join(( uri.baseurl, path, '?LiveContent' )) else: query = query % ( str(view), str(param) ) return ''.join(( uri.baseurl, path, query )) @staticmethod def menu_fragment(id, type, showRoot=True): #Swap between norwegian and english if uri.lang_trans[type]: type = uri.lang_trans[type] path = '/menyfragment.aspx'; sr = str(showRoot).lower() query = '?type=%s&id=%s&showroot=%s' % (type, id, sr) return uri.baseurl + path + query @staticmethod def path_fragment(id, type=''): path = '/stifragment.aspx'; query = '?id=%s&type=%s' % (id, type) return ''.join(( uri.baseurl + path + query )) @staticmethod def most_viewed(days): path = '/ml/topp12.aspx'; query = '?dager=%d' % days return ''.join(( uri.baseurl, path, query )) @staticmethod def playlist(loop=None, type=None, story=None): path = '/spilleliste.ashx'; query = '?' if loop is not None: query += 'loop=%s&' % str(loop) if type is not None: query += 'type=%s&' % str(type) if story is not None: query += 'story=%d&' % int(story) return uri.baseurl + path + query @staticmethod def media_xml(id, speed, showsuper=True): path = '/silverlight/getmediaxml.ashx'; ss = str(showsuper).lower() query = '?id=%s&hastighet=%d&vissuper=%s' % (id, speed, ss) return uri.baseurl + path + query @staticmethod def super_xml(id): path = '/silverlight/getsuperxml.ashx?id=%s' return uri.baseurl + path % id @staticmethod def subpath(*args): """ Just a wrap up to keep the code cleaner""" path = '/'.join(args) return '/'.join((uri.baseurl, path,)) @staticmethod def content_image(name, ext): """ Return a template for a alternate image path. This is used cause of xbmc's handling of images without extension """ template = "http://fil.nrk.no/contentfile/file/1.%s!img%s.%s" return template % (name,name, ext) @staticmethod def mms_to_http(url): """ Swaps a mms scheme to a http scheme. Used for extracting the correct url to pass to the player """ return url.replace('mms://', 'http://') # - EOM - @staticmethod def http_to_mms(url): """ Swaps a http scheme to a mms scheme.""" return url.replace('http://', 'mms://') # - EOM - @staticmethod def build_form(id, viewstate, view='aktuelt', cat=''): return ( 'ctl00$scriptManager1=' + 'ctl00$contentPlaceHolder$loopPanel' + '|ctl00$contentPlaceHolder$asyncPBTrigger_loop_%s' + '&__EVENTTARGET=ctl00$contentPlaceHolder' + '$asyncPBTrigger_loop_%s' + '&__VIEWSTATE=%s&ctl00$contentPlaceHolder$mainCat=%s' '&ctl00$contentPlaceHolder$subCat=%s&' ) % ( view, view, quote_plus(viewstate), id.capitalize(), cat) # - EOM - xmsheader = {'X-MicrosoftAjax': 'Delta=true'} cookieheader = { 'Cookie': ('NetTV2.0Speed=NetTV2.0Speed=%s; ' + 'UseSilverlight=UseSilverlight=1') % speed } baseheaders = { 'Content-Type': ('application/x-www-form-urlencoded; charset=UTF-8'), 'User-Agent': ('Mozilla/5.0 (Windows; U; WindowsNT 5.1; ' + 'nb-NO; rv:1.9.0.11) Gecko/2009060215 ' + 'Firefox/3.0.11'), 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', #'Accept-Encoding': 'gzip,deflate', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' } class regex: show = r"""(?sx) <li\sclass="(?P<exp>(?:expand|noexpand))"\s id="(?:child|root)[0-9]+?"> .*?<a\shref="/nett-tv/(?:kategori|klipp)/ (?P<id>[0-9]*)".+?title="(?P<plot>.*?)"\s class="icon-(?P<type>folder|sound|video) -black.*?>(?P<title>.*?)</a> """ catalog = r"""(?sx) ref.+?(?:(?P<plref>\w+?)/spill)? #parent idx: 0 /(?P<type>\w+?)/ #type idx: 1 (?P<id>\d{2,}).+? #ident idx: 2 src="(?P<image>.+?)".+? #img idx: 3 <a.+?>(?P<title>.*?)</.+? #title idx: 4 <a.+?>(?P<plot>.*?)< #desc idx: 5 """ recommended = r"""(?sx) <div\sclass="intro-element\sintro-element-small">.*? <a\shref="/nett-tv/(?P<type>klipp)/(?P<id>.*?)".*? title="(?P<plot>.*?)">.*?<img\ssrc="(?P<image>.*?)".*?/>.*? </a>.*?<div\sclass="intro-element-content"> <h2><a\shref="/nett-tv/klipp/.*?".*?>(?P<title>.*?)</a></h2> """ articles = r"""(?sx) <div\sclass="intro-element">.*? <div.*?>.*?<a.*?>.*?<img.*?src="(?P<image>.*?)".*?>.*? <h2>.*?<a.*?href="(?P<url>.*?)".*?>(?P<title>.*?)</a>.*? <a.*?>(?P<plot>.*?)</a> """ show_clip_xml = r"""(?sx) <mediadefinition>.*? <title>(?P<title>.*?)</title>.*? #title idx: 0 <desc(?:ription>(?P<plot>.*?) #plot idx: 1 </desc.+?)?.*? <mediaurl>(?P<url>.*?)</mediaurl>.*? #url idx: 2 <imageurl>(?P<image>.*?)</imageurl>.*? #img idx: 3 <supringurl(?:>(?P<suburl>.*?) #subt idx: 4 </supringurl>)?.*? <chapters(?:>(?P<chapters>.*?) #chapt idx: 5 </chapters>)?.*? </mediadefinition> """ show_clip_index = r"""(?sx) <chapteritem>.*? <title>(?P<title>.+?)</title>.*? <timeindex>(?P<time>\d+)</timeindex>.*? <image(?:url>(?P<image>.*?) </image.+?)?.*? </chapteritem> """ playlist_xml = r"""(?sx) <item>.*?<title>-{0,1}(?P<title>.*?)</title>.*? <media:content\surl="(?P<url>.*?)"\s type="(?P<type>.*?)"\s/>.*?</item> """ search = r"""(?sx) <li.+?ref.+?(?:(?P<plref>\w+?)/spill)?/(?P<type>\w+?) /(?P<id>\d{2,}).+?>(?P<title>.*?)</a>.*? <div.+?>(?P<plot>.*?)</div> """ clip_index = r"""(?sx) Player.+?xml.+?id=(?P<id>\d+).+? \.seekTo\((?P<time>\d+)\) """ qbrick = r"""(?sx)href="(?P<url>.*?)"/""" viewstate = r""""__VIEWSTATE".+?value="(?P<vstate>/.*?)".+?/""" image_identity = r"""crop/(?:\d\.(?P<id>\d*)(?:\.\d*)?)""" path_fragment = r"""<a.+?>(?P<path>.*?)<.+?/li>""" show_subtitles = r"""text="(?P<text>.*?)".+?marker="(?P<marker>.*?)".""" class extract: @staticmethod def search(data): search = [] #Iterate through the search result and append to stack for m in re.finditer(regex.search, data): item = MediaObj() type = m.group('type').encode('ascii') item.key = Key(type=type, id=m.group('id')) if item.key.type == SHOW_CLIP_INDEX: item.icon = video_index_icon item.isPlayable = True elif item.key.type == SHOW_CLIP: item.icon = video_icon item.isPlayable = True item.title = m.group('title') item.plot = m.group('plot') search.append(item) return search @staticmethod def catalog(data, arg=None, parent=None, ext=None): istack = [] for m in re.finditer(regex.catalog, data): item = MediaObj() item.plot = m.group('plot') item.title = m.group('title') item.thumbnail = m.group('image').encode('ascii', 'ignore') #State identifiers item.key = Key() item.key.id = int(m.group('id')) if arg: item.key.arg = arg if parent: item.key.parent = parent item.key.type = m.group('type').encode('ascii', 'ignore') if ext: item = ext(item) istack.append(item) return istack # - EOM - @staticmethod def recommended(data): istack = [] for m in re.finditer(regex.recommended, data): item = MediaObj() plot = m.group('plot').decode('iso-8859-1') item.plot = decode_htmlentities( plot ) item.title = m.group('title') item.thumbnail = m.group('image').encode('ascii', 'ignore') #State identifiers item.key = Key() item.key.id = int(m.group('id')) item.key.type = m.group('type').encode('ascii', 'ignore') istack.append(item) return istack # - EOM - @staticmethod def articles(data): istack = [] for m in re.finditer(regex.recommended, data): item = MediaObj() plot = m.group('plot').decode('iso-8859-1') item.plot = decode_htmlentities( plot ) item.title = m.group('title') item.thumbnail = m.group('image').encode('ascii', 'ignore') #State identifiers item.key = Key() item.key.id = int(m.group('id')) item.key.type = m.group('type').encode('ascii', 'ignore') istack.append(item) return istack # - EOM - @staticmethod def ext_live_show(item): item.starts = item.plot[0:5] item.title += ' - starter ' + item.starts return item @staticmethod def ext_top_shows(item): item.views = item.plot item.title += ' - ' + item.views return item @staticmethod def show(data): istack = [] for m in re.finditer(regex.show, data): item = MediaObj() item.title = m.group('title') item.plot = m.group('plot') if m.group('type') == 'folder': item.defntion = 'katalog' type = SHOW_FOLDER item.icon = folder_icon elif m.group('type') == 'sound': item.defntion = 'lyd/wma' item.icon = sound_icon elif m.group('type') == 'video': item.defntion = 'video/wmv' item.icon = sound_icon if m.group('type') == 'video' or m.group('type') == 'sound': item.isPlayable = True type = SHOW_CLIP item.key = Key() item.key.type = type item.key.id = int(m.group('id')) if m.group('exp') == 'noexpand' and item.key.type == SHOW_FOLDER: continue istack.append(item) return istack # - EOM - @staticmethod def show_clip(data): match = re.search(regex.show_clip_xml, data) item = MediaObj() item.url = unicode(match.group('url'), 'utf-8') if item.url.lower().endswith('wma'): item.defntion = 'lyd/wma' elif item.url.lower().endswith('wmv'): item.defntion = 'video/wma' item.icon = video_icon item.plot = match.group('plot') item.title = match.group('title') item.thumbnail = match.group('image') item.subtitle = match.group('suburl') item.chapters = match.group('chapters') return item # - EOM - @staticmethod def chapters(cstring): clist = [] for chapter in re.findall(nrk.regex.show_clip_index, cstring): citem = MediaObj(title = chapter[0], time = chapter[1]) if chapter[2]: citem.thumbnail = chapter[2] citem.thumbnail = nrk.video_index_icon citem.key = Key(type = SHOW_CLIP_INDEX) clist.append(citem) return clist # - EOM - @staticmethod def playlist(data, vignetes=True): plist = [] for match in re.finditer(regex.playlist_xml, data): item = MediaObj() item.url = match.group('url').replace('&', '&') item.title = match.group('title') #item.defntion = match.group('type') item.defntion = 'video/mp4' item.isFolder = False item.isPlayable = True item.key = Key() if item.title.endswith(PLAYLIST_VIGNETE): item.key.type = PLAYLIST_VIGNETE else: item.key.type = PLAYLIST_ITEM if item.key.type == PLAYLIST_VIGNETE and vignetes == False: continue else: plist.append(item) return plist # - EOM - @staticmethod def viewstate(data): match = re.search(regex.viewstate, data) print 'Found viewstate %s' % match.group('vstate') return match.group('vstate') # - EOM - @staticmethod def mms_url(data): nurl = '' print data #Do a check for qbrick playlist if data.startswith('<asx'): match = re.search(regex.qbrick, data) try: nurl = match.group('url') except: nurl = "" else: for c in data[18:]: if c != '\r': nurl += c else: break nurl = nurl.replace('http', 'mms') return nurl # - EOM - @staticmethod def current_path(data): path = [] for match in re.finditer(regex.path_fragment,data): path.append(match.group('path')) path = ' - '.join(path) return path # - EOM - @staticmethod def video_id(data): match = re.search(regex.clip_index, data) try: info = match.group('id'), float(match.group('time')) except: pass else: return info # - EOM - @staticmethod def subtitles(data): sub = [] for m in re.finditer(regex.show_subtitles, data): append( (int(m.group('marker')), m.group('text')) ) return sub class BaseObj: def __getattr__(self, name): return None # - EOM - def update(self, other): self.__dict__.update(other.__dict__) class MediaObj(BaseObj): def __init__( self,*args, **kwargs ): self.plot ='' self.title = '' self.defntion = '' self.thumbnail = '' self.isFolder = True for key in kwargs: self.__dict__[key] = kwargs[key] feed_alt_icon = os.path.join(rpath, 'ico_rss.png') video_icon = os.path.join(rpath, 'video-icon.png') sound_icon = os.path.join(rpath, 'sound-icon.png') folder_icon = 'defaultFolder.png' video_index_icon = os.path.join(rpath, 'video-index-icon.png') default_playlist_icon = os.path.join(rpath, 'news.png') class PlaylistView: views = { ARCHIVE: (lang(30200), 'archive-icon.png', ), RELEVANT: (lang(30201), 'news-icon.png', ), TOP_TOTAL: (lang(30202), 'stats-icon.png', ), TOP_THIS_WEEK: (lang(30203), 'stats-icon.png', ), TOP_THIS_MONTH: (lang(30204), 'stats-icon.png', ) } def __init__(self, parent): self.parent = parent def __getattr__(self, key): if self.views.has_key(key): lbl, ico = self.views[key] ico = os.path.join( rpath, ico ) vkey = Key( type = PLAYLIST, id = self.parent.id, view = key, arg = self.parent.arg ) return MediaObj(key=vkey, title=lbl, thumbnail=ico) class Playlist: entries = { REGION: ( 'Distrikt', 'regions-icon.png', (ARCHIVE, RELEVANT, TOP_TOTAL, TOP_THIS_WEEK, TOP_THIS_MONTH) ) } class views: search = MediaObj( #title = 'Sok', title = lang(30205), defntion = 'folder/perspektiv', isFolder = True, thumbnail = os.path.join(rpath, 'ico_search.png'), key = Key( id = 1, type = SEARCH ) ) archive = MediaObj( #title = 'Arkiv', title = lang(30200), defntion = 'folder/perspektiv', isFolder = True, thumbnail = os.path.join(rpath, 'archive-icon.png'), key = Key( id = REGION, type = PLAYLIST, view = PROGRAM, arg = PROGRAM ) ) @staticmethod def by_char(): import string items = [] for c in string.ascii_uppercase: item = MediaObj( #title = 'Vis bokstav "%s"' % c, title = lang(30206) % c, thumbnail = os.path.join(rpath, 'chr_%s.png' % c), key = Key(id = c, type = PROGRAM, view=BY_CHAR) ) items.append(item) return items @staticmethod def playlist(parent): return [ MediaObj( key = Key( type = PLAYLIST, id = parent.id, view = RELEVANT, arg = parent.arg ), #title = 'Aktuelt', title = lang(30201), thumbnail = os.path.join(rpath, 'news-icon.png') ), MediaObj( key = Key( type = PLAYLIST, id = parent.id, view = TOP_TOTAL, arg = parent.arg ), #title = 'Mest sett totalt', title = lang(30202), thumbnail = os.path.join(rpath, 'stats-icon.png') ), MediaObj( key = Key( type = PLAYLIST, id = parent.id, view = TOP_THIS_MONTH, arg = parent.arg ), #title = 'Mest sett denne maned', title = lang(30204), thumbnail = os.path.join(rpath, 'stats-icon.png') ), MediaObj( key = Key( type = PLAYLIST, id = parent.id, view = TOP_THIS_WEEK, arg = parent.arg ), #title = 'Mest sett denne uken', title = lang(30203), thumbnail = os.path.join(rpath, 'ico_stats.png') ) ] @staticmethod def program(parent, resource_path = rpath): return [ MediaObj( key = Key(id = None, type = PROGRAM, view = BY_CHAR), #title = 'Vis alfabetisk', title = lang(30208), parent = parent, thumbnail = os.path.join(resource_path, 'ico_char.png') ), MediaObj( key = Key(id = '@',type = PROGRAM, view = VIEW_ALL), #title = 'Vis alle', title = lang(30207), parent = parent, thumbnail = os.path.join(resource_path, 'ico_all.png') ), MediaObj( key = Key(type = PROGRAM, view = BY_THEME), #title = 'Vis tema liste', title = lang(30209), parent = parent, thumbnail = os.path.join(resource_path, 'ico_theme.png') ), MediaObj( key = Key(type = PROGRAM, id = 3650, view = TOP_TOTAL), #title = 'Mest sett totalt', title = lang(30202), parent = parent, thumbnail = os.path.join(resource_path, 'ico_stats.png') ), MediaObj( key = Key(type = PROGRAM, id = 31, view = TOP_THIS_MONTH), #title = 'Mest sett denne maned', title = lang(30204), parent = parent, thumbnail = os.path.join(resource_path, 'ico_stats.png') ), MediaObj( key = Key(type = PROGRAM, id = 7, view = TOP_THIS_WEEK), #title = 'Mest sett denne uken', title = lang(30203), parent = parent, thumbnail = os.path.join(resource_path, 'ico_stats.png') ), MediaObj( key = Key(type = PROGRAM, id = 0, view = TOP_BY_INPUT), #title = 'Mest sett siste X dager', title = lang(30218), parent = parent, thumbnail = os.path.join(resource_path, 'ico_input.png') ), MediaObj( key = Key(type = PROGRAM, view = RECOMMENDED), #title = 'Anbefalte programmer', title = lang(30217), parent = parent, thumbnail = os.path.join(resource_path, 'ico_favorites.png') ), MediaObj( key = Key(type = PROGRAM, view = ARTICLES), #title = 'Artikler', title = lang(30219), parent = parent, thumbnail = os.path.join(resource_path, 'ico_recommend.png') ) ] theme_title = { 2: 'Barn', 7: 'Natur', 20: 'Dokumentar', 10: 'Sport', 4: 'Fakta', 9: 'Livssyn', 6: 'Mat', 8: 'Nyheter', 22: 'Tegnsprak', 21: 'Ung', 19: 'Samisk', 11: 'Underholdning', 3: 'Drama', 5: 'Kultur', 12: 'Distrikt' } @staticmethod def by_theme(resource_path = rpath): return [ MediaObj( #title = 'Barn', title = lang(30101), thumbnail = os.path.join(resource_path, 'thm_kids.png'), key = Key(id = 2, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Natur', title = lang(30102), thumbnail = os.path.join(resource_path, 'thm_ntur.png'), key = Key(id = 7,type = PROGRAM,view = BY_THEME) ), MediaObj( #title = 'Drama', title = lang(30103), thumbnail = os.path.join(resource_path,'thm_drma.png'), key = Key(id = 3, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Sport', title = lang(30104), thumbnail = os.path.join(resource_path, 'thm_sprt.png'), key = Key(id = 10, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Fakta', title = lang(30105), thumbnail = os.path.join(resource_path, 'thm_fact.png'), key = Key(id = 4, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Livssyn', title = lang(30106), thumbnail = os.path.join(resource_path, 'thm_life.png'), key = Key(id = 9, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Mat', title = lang(30107), thumbnail = os.path.join(resource_path, 'thm_food.png'), key = Key(id = 6, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Nyheter', title = lang(30108), thumbnail = os.path.join(resource_path, 'thm_news.png'), key = Key(id = 8,type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Samisk', title = lang(30109), thumbnail = os.path.join(resource_path, 'thm_sami.png'), key = Key(id = 19, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Ung', title = lang(30110), thumbnail = os.path.join(resource_path, 'thm_teen.png'), key = Key(id = 21, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Tegnspraak', title = lang(30111), thumbnail = os.path.join(resource_path,'thm_sign.png'), key = Key(id = 22, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Underholdning', title = lang(30112), thumbnail = os.path.join(resource_path,'thm_entn.png'), key = Key(id = 11, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Dokumentar', title = lang(30113), thumbnail = os.path.join(resource_path,'thm_docu.png'), key = Key(id = 20, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = 'Kultur', title = lang(30114), thumbnail = os.path.join(resource_path,'thm_cult.png'), key = Key(id = 5, type = PROGRAM, view = BY_THEME) ), MediaObj( #title = REGION, title = lang(30115), thumbnail = os.path.join(resource_path,'thm_rgns.png'), key = Key(id = 13, type = PROGRAM, view = BY_THEME) ) ] @staticmethod def regions(resource_path = rpath): return[ MediaObj( #title = 'More og Romsdal', title = lang(30150), thumbnail = os.path.join(resource_path, 'ndmr.gif'), key = Key(id = REGION, arg = 'ndmr', type = PLAYLIST) ), MediaObj( #title = 'Hordaland', title = lang(30151), thumbnail = os.path.join(resource_path, 'ndho.gif'), key = Key(id = REGION, arg = 'ndho', type = PLAYLIST) ), MediaObj( #title = 'Nord-Norge', title = lang(30152), thumbnail = os.path.join(resource_path, 'ndno.gif'), key = Key(id = REGION, arg = 'ndno', type = PLAYLIST) ), MediaObj( #title = 'Rogaland', title = lang(30153), thumbnail = os.path.join(resource_path, 'ndro.gif'), key = Key(id = REGION, arg = 'ndro', type = PLAYLIST) ), MediaObj( #title = 'Sogn og Fjordane', title = lang(30154), thumbnail = os.path.join(resource_path, 'ndsf.gif'), key = Key(id = REGION, arg = 'ndsf', type = PLAYLIST) ), MediaObj( #title = 'Sorlandet', title = lang(30155), thumbnail = os.path.join(resource_path, 'ndsl.gif'), key = Key(id = REGION, args = 'ndsl', type = PLAYLIST) ), MediaObj( #title = 'Trondelag', title = lang(30156), thumbnail = os.path.join(resource_path, 'ndtl.gif'), key = Key(id = REGION,arg = 'ndtl', type = PLAYLIST) ), MediaObj( #title = 'Ostafjells', title = lang(30157), thumbnail = os.path.join(resource_path, 'ndtt.gif'), key = Key(id = REGION, arg = 'ndtt', type = PLAYLIST) ), MediaObj( #title = 'Ostfold', title = lang(30158), thumbnail = os.path.join(resource_path, 'ndos.gif'), key = Key(id = REGION, arg = 'ndos', type = PLAYLIST) ), MediaObj( #title = 'Ostlandssendingen', title = lang(30159), thumbnail = os.path.join(resource_path, 'ndoa.gif'), key = Key(id = REGION, arg = 'ndoa', type = PLAYLIST) ), MediaObj( #title = 'Hedmark og oppland', title = lang(30160), thumbnail = os.path.join(resource_path, 'ndop.gif'), key = Key(id = REGION, arg = 'ndop', type = PLAYLIST) ) ]