From 6ea154f5fe63330fb6acfe3bbb34de3da65e7244 Mon Sep 17 00:00:00 2001 From: chriszero Date: Sun, 19 Oct 2014 18:09:39 +0200 Subject: [PATCH] Neue "Premium" API. Nun deutlich performanter als zuvor --- tvsp2xmltv/defaults.py | 385 ++++++++++++++++++++++-------------- tvsp2xmltv/model.py | 190 +++++++++--------- tvsp2xmltv/pictureLoader.py | 10 +- tvsp2xmltv/tvsGrabber.py | 103 +++------- tvspielfilm2xmltv.ini | 13 +- tvspielfilm2xmltv.py | 18 +- 6 files changed, 382 insertions(+), 337 deletions(-) mode change 100644 => 100755 tvsp2xmltv/tvsGrabber.py diff --git a/tvsp2xmltv/defaults.py b/tvsp2xmltv/defaults.py index 8af2732..9f88fb0 100644 --- a/tvsp2xmltv/defaults.py +++ b/tvsp2xmltv/defaults.py @@ -5,6 +5,10 @@ import stat import ConfigParser +import requests +import logger + + # ugo+rw because may different user work with this file file_mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH @@ -31,16 +35,22 @@ def find_in_path(file_name, path=None): remove_orphaned_images = config.getboolean('DEFAULT', 'remove_orphaned_images') grab_today = config.getboolean('DEFAULT', 'grab_today') number_of_images_per_show = config.getint('DEFAULT', 'number_of_images_per_show') +size_of_images = config.getint('DEFAULT', 'size_of_images') debug = config.getboolean('DEFAULT', 'debug') sart_map = { -'SE': 'series', -'SP': 'movie', -'RE': 'news', -'KIN': 'kids', -'SPO': 'sports', -#'AND': 'Andere', -#'U': 'Undefined' + 'SE': 'series', + 'SP': 'movie', + 'RE': 'news', + 'KIN': 'kids', + 'SPO': 'sports', + #'AND': 'Andere', + #'U': 'Undefined' +} +thumb_id_map = { + 'DOWN': 1, + 'MIDDLE': 2, + 'UP': 3 } combination_channels = { @@ -48,137 +58,185 @@ def find_in_path(file_name, path=None): } channel_map = { -'PRO7M': 'prosieben-maxx.de', -'ARD': 'ard.de', -'ZDF': 'zdf.de', -'RTL': 'rtl.de', -'SAT1': 'sat1.de', -'PRO7': 'prosieben.de', -'K1': 'kabel1.de', -'RTL2': 'rtl2.de', -'VOX': 'vox.de', -'3SAT': '3sat.de', -'ARTE': 'arte.de', -'TELE5': 'tele5.de', -'DVIER': 'das-vierte.de', -'CC': 'comedy-central.de', -'DMAX': 'dmax.de', -'SIXX': 'sixx.de', -'RTL-N': 'rtl-nitro.de', -'SAT1G': 'sat1-gold.de', -'SUPER': 'superrtl.de', -'KIKA': 'kika.de', -'NICK': 'nickelodeon.de', -'RIC': 'ric.de', -'WDR': 'wdr.de', -'N3': 'ndr.de', -'BR': 'bayern3.de', -'SWR': 'swr.de', -'HR': 'hessen3.de', -'MDR': 'mdr.de', -'RBB': 'rbb.de', -'PHOEN': 'phoenix.de', -'BRALP': 'br-alpha.de', -'TAG24': 'tagesschau24.de', -'FES': 'einsfestival.de', -'MUX': 'einsplus.de', -'2NEO': 'zdfneo.de', -'2KULT': 'zdfkultur.de', -'ZINFO': 'zdfinfo.de', -'ANIXE': 'anixe.de', -'SKLAR': 'sonnenklartv.de', -'BIBEL': 'bibeltv.de', -'TIMM': 'timm.de', -'CNN': 'cnn.de', -'N24': 'n24.de', -'NTV': 'ntv.de', -'SPORT': 'sport1.de', -'S1PLU': 'sport1plus.de', -'EURO': 'eurosport.de', -'EURO2': 'eurosport-2.de', -'ESPN': 'espn-classic-sport.com', -'NASN': 'espn-america.com', -'SPO-D': 'sportdigitaltv.de', -'DMC': 'deluxe-music.de', -'IMT': 'imusic1.de', -'MTV': 'mtv.de', -'VIVA': 'viva.de', -'VH1': 'vh1-classic.uk', -'ATV': 'atv.at', -'ATV2': 'atv2.at', -'ORF1': 'orf1.at', -'ORF2': 'orf2.at', -'ORF3': 'orf3.at', -'ORFSP': 'orf-sport.at', -'PULS4': 'puls4.at', -'SERVU': 'servustv.at', -'SF1': 'sf1.ch', -'STTV': 'star-tv.ch', -'SF2': 'sf2.ch', -'3PLUS': '3plus.ch', -'CIN': 'sky-cinema.de', -'CIN1': 'sky-cinema-1.de', -'CIN24': 'sky-cinema-24.de', -'SKY-H': 'sky-cinema-hits.de', -'SKY-A': 'sky-action.de', -'SKY-C': 'sky-comedy.de', -'SKY-E': 'sky-emotion.de', -'SKY-N': 'sky-nostalgie.de', -'MGM': 'mgm.de', -'DCM': 'disney-cinemagic.de', -'SKY3D': 'sky-3d.de', -'SKYAT': 'sky-atlantic-hd.de', -'N-GHD': 'national-geographic.de', -'HDDIS': 'discovery-channel.de', -'HISHD': 'history-hd.de', -'SNHD': 'sky-sport-news-hd.de', -'BULI': 'sky-fussball-bundesliga.de', -'SPO1': 'sky-sport-1.de', -'SPO2': 'sky-sport-2.de', -'SPO-A': 'sky-sport-austria.at', -'HDSPO': 'sky-sport-1-hd.de', -'SHD2': 'sky-sport-2-hd.de', -'SHDE': 'sky-sport-extra-hd.de', -'13TH': '13th-street.de', -'CLASS': 'classica.de', -'DISNE': 'disney-channel.de', -'DXD': 'disney-xd.de', -'DJUN': 'disney-junior.de', -'FOX': 'fox-channel.de', -'GOLD': 'goldstar-tv.de', -'HEIMA': 'heimatkanal.de', -'MOVTV': 'motorvision-tv.de', -'JUNIO': 'junior.de', -'N-GW': 'national-geographic-wild.de', -'PASS': 'rtl-passion.de', -'RTL-C': 'rtl-crime.de', -'SCIFI': 'sci-fi.de', -'SP-GE': 'spiegel-geschichte.de', -'SKY-K': 'sky-krimi.de', -'TNT-S': 'tnt-serie.de', -'AXN': 'axntv.de', -'AMAX': 'animax.de', -'BIO': 'the-biography-channel.de', -'BOOM': 'boomerang-tv.de', -'C-NET': 'cartoon-network.de', -'HISTO': 'history-channel.de', -'K1CLA': 'kabel-eins-classics.de', -'KINOW': 'kinowelt-tv.de', -'NICKT': 'nicktoons.de', -'ROM': 'romance-tv.de', -'RTL-L': 'rtl-living.de', -'SAT1E': 'sat1-emotions.de', -'TNT-F': 'tnt-film.de', -'SKY-S': 'sky-select.de', -'APLAN': 'animal-planet.de', -'GUSTO': 'bongusto.de', -'E!': 'e-entertainment-television.de', -'GLITZ': 'glitz.de', -'PLANE': 'planet.de', -'PBOY': 'playboy.de', -'PRO7F': 'prosieben-fun.de', -'SILVE': 'silverline-tv.de', -'SPTVW': 'spiegel-tv-wissen.de' + 'PRO7M': 'prosieben-maxx.de', + 'ARD': 'ard.de', + 'ZDF': 'zdf.de', + 'RTL': 'rtl.de', + 'SAT1': 'sat1.de', + 'PRO7': 'prosieben.de', + 'K1': 'kabel1.de', + 'RTL2': 'rtl2.de', + 'VOX': 'vox.de', + '3SAT': '3sat.de', + 'ARTE': 'arte.de', + 'TELE5': 'tele5.de', + 'CC': 'comedy-central.de', + 'DMAX': 'dmax.de', + 'SIXX': 'sixx.de', + 'RTL-N': 'rtl-nitro.de', + 'SAT1G': 'sat1-gold.de', + 'SUPER': 'superrtl.de', + 'KIKA': 'kika.de', + 'NICK': 'nickelodeon.de', + 'RIC': 'ric.de', + 'WDR': 'wdr.de', + 'N3': 'ndr.de', + 'BR': 'bayern3.de', + 'SWR': 'swr.de', + 'HR': 'hessen3.de', + 'MDR': 'mdr.de', + 'RBB': 'rbb.de', + 'PHOEN': 'phoenix.de', + 'TAG24': 'tagesschau24.de', + 'FES': 'einsfestival.de', + 'MUX': 'einsplus.de', + '2NEO': 'zdfneo.de', + '2KULT': 'zdfkultur.de', + 'ZINFO': 'zdfinfo.de', + 'ANIXE': 'anixe.de', + 'SKLAR': 'sonnenklartv.de', + 'BIBEL': 'bibeltv.de', + 'TIMM': 'timm.de', + 'CNN': 'cnn.de', + 'N24': 'n24.de', + 'NTV': 'ntv.de', + 'SPORT': 'sport1.de', + 'S1PLU': 'sport1plus.de', + 'EURO': 'eurosport.de', + 'EURO2': 'eurosport-2.de', + 'SPO-D': 'sportdigitaltv.de', + 'DMC': 'deluxe-music.de', + 'IMT': 'imusic1.de', + 'MTV': 'mtv.de', + 'VIVA': 'viva.de', + 'VH1': 'vh1-classic.uk', + 'ATV': 'atv.at', + 'ATV2': 'atv2.at', + 'ORF1': 'orf1.at', + 'ORF2': 'orf2.at', + 'ORF3': 'orf3.at', + 'ORFSP': 'orf-sport.at', + 'PULS4': 'puls4.at', + 'SERVU': 'servustv.at', + 'SF1': 'sf1.ch', + 'STTV': 'star-tv.ch', + 'SF2': 'sf2.ch', + '3PLUS': '3plus.ch', + 'CIN': 'sky-cinema.de', + 'CIN1': 'sky-cinema-1.de', + 'CIN24': 'sky-cinema-24.de', + 'SKY-H': 'sky-cinema-hits.de', + 'SKY-A': 'sky-action.de', + 'SKY-C': 'sky-comedy.de', + 'SKY-E': 'sky-emotion.de', + 'SKY-N': 'sky-nostalgie.de', + 'MGM': 'mgm.de', + 'DCM': 'disney-cinemagic.de', + 'SKY3D': 'sky-3d.de', + 'SKYAT': 'sky-atlantic-hd.de', + 'N-GHD': 'national-geographic.de', + 'HDDIS': 'discovery-channel.de', + 'HISHD': 'history-hd.de', + 'SNHD': 'sky-sport-news-hd.de', + 'BULI': 'sky-fussball-bundesliga.de', + 'SPO-A': 'sky-sport-austria.at', + 'HDSPO': 'sky-sport-1-hd.de', + 'SHD2': 'sky-sport-2-hd.de', + '13TH': '13th-street.de', + 'CLASS': 'classica.de', + 'DISNE': 'disney-channel.de', + 'DXD': 'disney-xd.de', + 'DJUN': 'disney-junior.de', + 'FOX': 'fox-channel.de', + 'GOLD': 'goldstar-tv.de', + 'HEIMA': 'heimatkanal.de', + 'MOVTV': 'motorvision-tv.de', + 'JUNIO': 'junior.de', + 'N-GW': 'national-geographic-wild.de', + 'PASS': 'rtl-passion.de', + 'RTL-C': 'rtl-crime.de', + 'SCIFI': 'sci-fi.de', + 'SP-GE': 'spiegel-geschichte.de', + 'SKY-K': 'sky-krimi.de', + 'TNT-S': 'tnt-serie.de', + 'AXN': 'axntv.de', + 'AMAX': 'animax.de', + 'BIO': 'the-biography-channel.de', + 'BOOM': 'boomerang-tv.de', + 'C-NET': 'cartoon-network.de', + 'K1CLA': 'kabel-eins-classics.de', + 'KINOW': 'kinowelt-tv.de', + 'NICKT': 'nicktoons.de', + 'ROM': 'romance-tv.de', + 'RTL-L': 'rtl-living.de', + 'SAT1E': 'sat1-emotions.de', + 'TNT-F': 'tnt-film.de', + 'SKY-S': 'sky-select.de', + 'APLAN': 'animal-planet.de', + 'GUSTO': 'bongusto.de', + 'E!': 'e-entertainment-television.de', + 'GLITZ': 'glitz.de', + 'PLANE': 'planet.de', + 'PBOY': 'playboy.de', + 'PRO7F': 'prosieben-fun.de', + 'SILVE': 'silverline-tv.de', + 'SPTVW': 'spiegel-tv-wissen.de', + "FATV": "fashiontv.fr", + "DNTV": "das-neue-tv.de", + "HSE": "hse24.de", + "JUKE": "jukebox.de", + "SONY": "sony-entertainmen.tv", + "DR1": "dr1.dk", + "GEO": "geo-television.de", + "WDWTV": "welt-der-wunder-tv.de", + "NAUCH": "nautical-channel.com", + "BBC-E": "bbc-entertainment.dk", + "FAMTV": "family-tv.de", + "EURON": "euronews.de", + "LAUNE": "gute-laune-tv.de", + "QVC": "qvc.de", + "CENTE": "center.tv", + "NL1": "nl1.nl", + "NL3": "nl2.nl", + "NL2": "nl3.nl", + "UNIVE": "universal-channel.de", + "BLM": "bloombergtv.de", + "MUE2": "muenchen-2.de", + "DWTV": "dw.de", + "BE1": "belgien.be", + "MEZZO": "mezzotv.fr", + "BUTV": "beate-uhse-tv.de", + "FTL": "ftl-tv.de", + "TVM": "tv-muenchen.de", + "MOTOR": "motors-tv.fr", + "TVB": "tv-berlin.de", + "AETV": "ae-tv.de", + "MTV-D": "mtv-dance.uk", + "MTV-B": "mtv-base.de", + "MTV-L": "mtv-live.uk", + "BBC": "bbcworld.uk", + "MTV-H": "mtv-hits.uk", + "TV2": "tv2.tr", + "TLC": "tlc.de", + "EX-SP": "extreme-sports-channel.de", + "TRACE": "tracetv.fr", + "BLUM": "blue-movie-1.de", + "JOIZ": "joiz.de", + "BLUM3": "blue-movie-3.de", + "BLUM2": "blue-movie-2.de", + "HH1": "hamburg-1.de", + "ERF": "erf-1.de", + "RCK": "rcktv.de", + "DAF": "deutsches-anleger-fernsehen.de", + "TV5": "tv5-monde.fr", + "SP1US": "sport1US.de", + "YFE": "yourfamilyentertainment.de", + "KTV": "k-tv.at", + "N-GP": "nat-geo-people.de", + "DWF": "deutsches-wetter-fernsehen.de", + "ADULT": "adult-channel.com", + "LUSTP": "lust-pur.de", + "ALPHA": "ard-alpha.de", } @@ -215,17 +273,48 @@ def checkchannelids(): # Go to http://www.vdr-wiki.de/wiki/index.php/Xmltv2vdr-plugin # and safe the "Verbindliche EPG-Senderliste" to an text file # called "channelids.txt". + try: + print('Reading "channelids.txt"') + f = open("channelids.txt", "U") + channelids = f.read().split(os.linesep) + f.close() + channelids = filter(lambda x: len(x) > 0, channelids) + + print("The following channels are NOT in the official list:") + + for name, val in channel_map.items(): + if val not in channelids: + print("%s" % val) - print('Reading "channelids.txt"') - f = open("channelids.txt", "U") - channelids = f.read().split(os.linesep) - f.close() - channelids=filter(lambda x: len(x)>0, channelids) + for val in combination_channels.keys(): + if val not in channelids: + print("%s" % val) + except IOError as e: + logger.log(e, logger.ERROR) + +def checkchannelmap(): + r = requests.get('http://tvs3.cellular.de/content/channel-list/iphone', + headers={'Connection': 'close', 'User-Agent': 'Nexus 5; Android 4.4.4; de_DE'}) + r.encoding = 'utf-8' + data = r.json() + tvsp_ids = {} + for val in data: + tvsp_ids[val['id']] = val['name'] + + channelids = filter(lambda x: len(x) > 0, tvsp_ids) + + print("The following channels included in the channel map are NOT provided by the server:") for name, val in channel_map.items(): - if val not in channelids: - print("Channel ID \"%s\" not in official list!" % val) + if name not in channelids: + print("%s : %s," % (name, val) ) + + print("\n") + + channelids = filter(lambda x: len(x) > 0, channel_map) + + print("The following channels are NOT in the current channel map:") + for name, val in tvsp_ids.items(): + if name not in channelids: + print('"%s" : "%s",' % (name, val) ) - for val in combination_channels.keys(): - if val not in channelids: - print("Channel ID \"%s\" not in official list!" % val) diff --git a/tvsp2xmltv/model.py b/tvsp2xmltv/model.py index 556e590..62bb595 100644 --- a/tvsp2xmltv/model.py +++ b/tvsp2xmltv/model.py @@ -19,58 +19,62 @@ def __init__(self, json, channel_id=None, loadPictures=False): self.loadPictures = loadPictures self.channel_id = channel_id - details = json['details'] - - self.sendungs_id = details['sendungs_id'] - self.sender_id = details['sender_id'] - self.sendername = details['sendername'] - self.sendungstag = details['sendungstag'] - self.starttime = details['starttime'] - self.endtime = details['endtime'] - self.jahr = details['jahr'] - self.filmlaenge = details['filmlaenge'] - - self.title_de = details['titel'] - self.title_orig = details['originaltitel'] - self.vorspann = details['vorspann'] - self.land = details['land'] - self.genre = details['genre'] - self.text = details['text'] - self.fazit = details['fazit'] - - self.regisseur = details['regisseur'] # Kommagetrennt - self.darsteller = details['darsteller'] # Semikolongetrennte Liste - self.moderator = details['moderator'] # Kommagetrennt - self.studio_gaeste = details['studio_gaeste'] # Kommagetrennt - - self.untertitel = details['untertitel'] - self.folgentitel = details['folgentitel'] - self.staffel_nr = details['staffel_nr'] - self.folge = details['folge'] - - self.sart_id = details['sart_id'] # SendungsArt SE, RE, ... ? - self.wiederhol_hinweis = details['wiederhol_hinweis'] # Wiederholungshinweis - - self.sz_neu = details['sz_neu'] == 'J' - self.sz_hdtv = details['sz_hdtv'] == 'J' - - self.gallery_lo = json['gallery'] - self.gallery_hi = json['gallery_hi'] - - # self.parse_json(json) - + self.json = json + + self.programme_id = self.__get_value('id') + self.broadcaster_id = self.__get_value('broadcasterId') + self.broadcaster_name = self.__get_value('broadcasterName') + self.starttime = self.__get_value('timestart') + self.endtime = self.__get_value('timeend') + self.year = self.__get_value('year') + self.programme_length = self.__get_value('lengthNetAndGross') + self.title_de = self.__get_value('title') + self.title_orig = self.__get_value('originalTitle') + self.country = self.__get_value('country') + self.genre = self.__get_value('genre') + self.text = self.__get_value('text') + + self.review = self.__get_value('conclusion') + self.director = self.__get_value('director') + self.actors = self.__get_value('actors') + + self.anchorman = self.__get_value('anchorman') + self.studio_guests = self.__get_value('studio_guests') + + self.subline = self.__get_value('subline') + self.episode_title = self.__get_value('episodeTitle') + self.season_number = self.__get_value('seasonNumber') + self.epsiode_number = self.__get_value('episodeNumber') + self.sart_id = self.__get_value('sart_id') # SendungsArt SE, RE, ... ? + + #self.wiederhol_hinweis = self.__get_value('repeatHint') # Wiederholungshinweis + + self.sz_neu = self.__get_value('isNew') + self.sz_hdtv = self.__get_value('isHDTV') + self.is_live = self.__get_value('isLive') + self.rating = self.__get_value('fsk') + self.tip_of_the_day = self.__get_value('isTipOfTheDay') + self.star_rating = self.__get_value('thumbId') + + self.images = self.__get_value('images') + + def __get_value(self, key): + if key in self.json: + return self.json[key] + else: + return None def to_string(self): - print(self.folgentitel) + print(self.episode_title) print(self.title_de) def get_absolute_starttime(self): - d = datetime.datetime.strptime(self.sendungstag + ' ' + self.starttime, '%Y-%m-%d %H:%M') + d = datetime.datetime.fromtimestamp(self.starttime) new_d = tz_ger.localize(d) return new_d def get_absolute_endtime(self): - d = datetime.datetime.strptime(self.sendungstag + ' ' + self.endtime, '%Y-%m-%d %H:%M') + d = datetime.datetime.fromtimestamp(self.endtime) new_d = tz_ger.localize(d) return new_d @@ -84,12 +88,8 @@ def get_xml(self): start = self.get_absolute_starttime() stop = self.get_absolute_endtime() - # Tagesgrenze überschritten... - if stop < start: - stop = stop + datetime.timedelta(days=1) - if not self.channel_id: - self.channel_id = defaults.channel_map[self.sender_id] + self.channel_id = defaults.channel_map[self.broadcaster_id] programme = Element('programme', { @@ -98,7 +98,7 @@ def get_xml(self): 'channel': self.channel_id }) - programme.append(Comment(' pid = {0} '.format(self.sendungs_id))) + programme.append(Comment(' pid = {0} '.format(self.programme_id))) tmp = SubElement(programme, "title", {'lang': 'de'}) tmp.text = self.title_de @@ -108,23 +108,23 @@ def get_xml(self): tmp.text = self.title_orig # Folgentitel oder Untertitel - if self.folgentitel: + if self.episode_title: tmp = SubElement(programme, 'sub-title') - tmp.text = self.folgentitel - elif self.untertitel: + tmp.text = self.episode_title + elif self.subline: tmp = SubElement(programme, 'sub-title') - tmp.text = self.untertitel + tmp.text = self.subline if self.text: tmp = SubElement(programme, "desc", {'lang': 'de'}) tmp.text = self.text - if self.darsteller or self.regisseur or self.moderator: + if self.actors or self.director or self.anchorman: programme.append(self.__generate_credits()) - if self.jahr: + if self.year: tmp = SubElement(programme, 'date') - tmp.text = self.jahr + tmp.text = str(self.year) tmp = SubElement(programme, 'category', {'lang': 'de'}) tmp.text = self.genre @@ -133,11 +133,15 @@ def get_xml(self): tmp = SubElement(programme, 'category') tmp.text = defaults.sart_map[self.sart_id] - if self.filmlaenge and len(self.filmlaenge.split('/')) > 0: + if defaults.thumb_id_map.has_key(self.star_rating): + tmp = SubElement(programme, 'star-rating') + tmp.text = '{0} / 3'.format(defaults.thumb_id_map[self.star_rating]) + + if self.programme_length and len(self.programme_length.split('/')) > 0: tmp = SubElement(programme, 'length', {'units': 'minutes'}) - tmp.text = self.filmlaenge.split('/')[1] + tmp.text = self.programme_length.split('/')[1] - if self.loadPictures: + if self.loadPictures and self.images: # Add images if available picLoader = pictureLoader.PictureLoader(self) iconTags = picLoader.get_xml() @@ -146,19 +150,18 @@ def get_xml(self): for icon in iconTags: programme.append(icon) - - if self.land: + if self.country: tmp = SubElement(programme, 'country') - tmp.text = self.land + tmp.text = self.country try: - if self.folge: + if self.epsiode_number: text = self.__generate_xmltv_ns() tmp = SubElement(programme, 'episode-num', {'system': 'xmltv_ns'}) tmp.text = text except ValueError: tmp = SubElement(programme, 'episode-num', {'system': 'onscreen'}) - tmp.text = self.folge + tmp.text = self.epsiode_number pass if self.sz_hdtv: @@ -169,22 +172,27 @@ def get_xml(self): if self.sz_neu: SubElement(programme, 'new') - if self.fazit: + if self.rating: + rating = SubElement(programme, 'rating', {'system': 'FSK'}) + tmp = SubElement(rating, 'value') + tmp.text = str(self.rating) + + if self.review: tmp = SubElement(programme, 'review', {'type': 'text'}) - tmp.text = self.fazit + tmp.text = self.review return programme def __generate_xmltv_ns(self): # ToDo: folgen mit 111;112 & 1-3 behandeln (Doppelfolgen?) Prüfen ob nur Zahlen im String sind - if self.folge: - ep = int(self.folge) - 1 + if self.epsiode_number: + ep = int(self.epsiode_number) - 1 else: ep = "" - if self.staffel_nr: - st = int(self.staffel_nr) - 1 + if self.season_number: + st = int(self.season_number) - 1 else: st = "" @@ -193,34 +201,24 @@ def __generate_xmltv_ns(self): def __generate_credits(self): credits_element = Element("credits") - if self.regisseur: + if self.director: tmp = SubElement(credits_element, "director") - tmp.text = self.regisseur - - if self.darsteller: - td = self.darsteller.split(';') - for d in td: - try: - x = d.split('(') - if len(x) >= 1: - tmp = SubElement(credits_element, "actor", {'role': x[1].strip(' )')}) - tmp.text = x[0].strip() - # keine Rolle angegeben - else: - tmp = SubElement(credits_element, "actor") - tmp.text = d.strip() - except IndexError: - pass - - if self.moderator: + tmp.text = self.director + + if self.actors: + for entry in self.actors: + pair = entry.items()[0] + tmp = SubElement(credits_element, "actor", {'role': pair[0]}) + tmp.text = pair[1] + + if self.anchorman: tmp = SubElement(credits_element, 'presenter') - tmp.text = self.moderator + tmp.text = self.anchorman - #if self.studio_gaeste: - # td = self.studio_gaeste.split(',') - # for d in td: - # tmp = SubElement(credits_element, "guest") - # tmp.text = d.strip() + if self.studio_guests: + for d in self.studio_guests: + tmp = SubElement(credits_element, "guest") + tmp.text = d return credits_element @@ -230,7 +228,6 @@ def __init__(self, chanid, name): self.channel_id = chanid self.display_name = name - def get_xml(self): chan = Element('channel', {'id': self.channel_id}) tmp = SubElement(chan, 'display-name', {'lang': 'de'}) @@ -242,7 +239,6 @@ class XmltvRoot(object): def __init__(self): self.root = Element('tv', {'generator-info-name': 'tvspielfilm2xmltv grabber'}) - def append_element(self, xml): self.root.append(xml.get_xml()) diff --git a/tvsp2xmltv/pictureLoader.py b/tvsp2xmltv/pictureLoader.py index abdd96d..b48e15f 100644 --- a/tvsp2xmltv/pictureLoader.py +++ b/tvsp2xmltv/pictureLoader.py @@ -27,16 +27,16 @@ def __init__(self, programme): def get_xml(self): icons = [] - if self.programme.gallery_hi: - if len(self.programme.gallery_hi) > 0: + if self.programme.images: + if len(self.programme.images) > 0: i = 0 - for im in sorted(self.programme.gallery_hi.values()): + for im in sorted(self.programme.images): i += 1 - f = self.__download_image(im, defaults.epgimages_dir) + f = self.__download_image(im['size{0}'.format(defaults.size_of_images)], defaults.epgimages_dir) if f: icon = Element('icon', {'src': f}) icons.append(icon) - if i == defaults.number_of_images_per_show: + if i >= defaults.number_of_images_per_show: break return icons diff --git a/tvsp2xmltv/tvsGrabber.py b/tvsp2xmltv/tvsGrabber.py old mode 100644 new mode 100755 index 103fa9c..25722b2 --- a/tvsp2xmltv/tvsGrabber.py +++ b/tvsp2xmltv/tvsGrabber.py @@ -1,7 +1,6 @@ #!/usr/bin/python # -*- coding: utf-8 -*- import datetime -import json import requests @@ -14,8 +13,8 @@ class TvsGrabber(object): def __init__(self): self.headers = { - 'Connection': 'Keep-Alive', - 'User-Agent': None + 'Connection': 'close', + 'User-Agent': 'Nexus 5; Android 4.4.4; de_DE' } self.channel_list = [] self.grab_days = 1 @@ -23,67 +22,16 @@ def __init__(self): self.xmltv_doc = model.XmltvRoot() - def _get_update(self): - """liefert Infos mit Sender, Senderlogos - - """ - - url = "http://tvsapi.cellmp.de/getUpdate.php" + def _get_channel(self, date, tvsp_id): + #broadcast/list/K1/2014-10-18 + url = "http://tvs3.cellular.de/broadcast/list/{0}/{1}".format(tvsp_id, date) r = requests.get(url, headers=self.headers) r.encoding = 'utf-8' - logger.log(r.url, logger.DEBUG) - return json.JSONDecoder(strict=False).decode(r.text) - - - def _get_detail(self, prog_id): - """Holt die Sendungsdetails für die id ab - - """ - logger.log("_get_detail({0})".format(prog_id), logger.DEBUG) - payload = {'id': prog_id} - url = "http://tvsapi.cellmp.de/getDetails.php" - r = requests.get(url, params=payload, headers=self.headers) - r.encoding = 'utf-8' - logger.log(r.url, logger.DEBUG) - return json.JSONDecoder(strict=False).decode(r.text) - - - def _get_category(self, date, sender=[]): - """Holt verfügbare Sendungen - - date: das Datum für welche wir die Daten wollen - sender: Eine Liste mit Sender ID's als string - wird der Parameter weggelassen werden alle verfügbaren Sender Daten abgeholt - - """ - logger.log("_get_category({0}, {1})".format(date, sender), logger.DEBUG) - # Build channel array for request - sender_len = len(sender) - channel = '[' - for i in range(sender_len): - channel = channel + '"' + sender[i] + '"' - if i < sender_len - 1: - channel = channel + ',' - - channel = channel + ']' - - logger.log('Grabbing Channel "' + channel + '" for date ' + date.isoformat()) - - payload = {'name': 'day', 'channel': channel, 'date': date.isoformat()} - url = "http://tvsapi.cellmp.de/getCategory_1_3.php" - try: - r = requests.get(url, params=payload, headers=self.headers) - #print(r.url) - except requests.exceptions.RequestException: - logger.log("Failed to request", logger.MESSAGE) - return [] - r.encoding = 'utf-8' - logger.log("Grabbing channel {0}".format(r.url), logger.DEBUG) - try: - return json.JSONDecoder(strict=False).decode(r.text) - except TypeError: - logger.log("Failed to decode json", logger.DEBUG) - return [] + if r.status_code == requests.codes.ok: + logger.log(r.url, logger.DEBUG) + return r.json() + else: + logger.log('{0} returned status code {1}'.format(r.url, r.status_code), logger.WARNING) def start_grab(self): @@ -111,13 +59,16 @@ def start_grab(self): # combination channel if not tvsp_id: - tvsp_id = defaults.combination_channels[chan_id] + if chan_id in defaults.combination_channels: + tvsp_id = defaults.combination_channels[chan_id] + else: + logger.log("Channel {0} not in channel map.".format(chan_id), logger.WARNING) + continue for i in range(self.grab_days): day = date + datetime.timedelta(days=i) self.__grab_day(day, tvsp_id, chan_id) - #print("Finished") pictureLoader.cleanup_images() def add_channel(self, channel): @@ -131,20 +82,14 @@ def save(self): def __grab_day(self, date, tvsp_id, channel_id): retry = 0 - if isinstance(tvsp_id, str): - tvsp_id = [tvsp_id] - data = self._get_category(date, [] + tvsp_id) + data = self._get_channel(date, tvsp_id) for s in data: # Im Falle eines Fehlers beim grabben - try: - progData = self._get_detail(s['sendungs_id']) - logger.log("__grab_day:progData\n {0}".format(progData), logger.DEBUG) - prog = model.Programme(progData, channel_id, self.pictures) - self.xmltv_doc.append_element(prog) - except Exception as e: - logger.log("Failed to fetch Details for " + s['sendungs_id'] + " on Channel " + tvsp_id, logger.MESSAGE) - logger.log("Pausing for 30 seconds.", logger.MESSAGE) - from time import sleep - sleep(30) - if defaults.debug: - raise + try: + prog = model.Programme(s, channel_id, self.pictures) + self.xmltv_doc.append_element(prog) + except Exception as e: + logger.log("Failed to fetch Channel " + tvsp_id + " at " + date, logger.WARNING) + logger.log(e, logger.WARNING) + if defaults.debug: + raise diff --git a/tvspielfilm2xmltv.ini b/tvspielfilm2xmltv.ini index a955b24..a92c71d 100644 --- a/tvspielfilm2xmltv.ini +++ b/tvspielfilm2xmltv.ini @@ -2,7 +2,18 @@ destination_file = /var/lib/epgsources/tvspielfilm2xmltv.xmltv control_file = /var/lib/epgsources/tvspielfilm2xmltv epgimages_dir = /var/lib/epgsources/tvspielfilm2xmltv-img + +# Should the grabber remove orphandes images, this is normaly done by the vdr itself remove_orphaned_images = False + +# Skip today grab_today = True + +# Maximum images to load number_of_images_per_show = 2 -debug = False \ No newline at end of file + +# Size of the downloaded images 1 = 130px, 2 = 320px, 3 = 476px, 4 = 952px +size_of_images = 2 + +# print debug messages (very verbose!) True, False +debug = False diff --git a/tvspielfilm2xmltv.py b/tvspielfilm2xmltv.py index 0abe654..f3987c3 100755 --- a/tvspielfilm2xmltv.py +++ b/tvspielfilm2xmltv.py @@ -7,7 +7,7 @@ It defines classes_and_methods -@author: user_name +@author: chris @copyright: 2013 organization_name. All rights reserved. @@ -34,9 +34,9 @@ from tvsp2xmltv import tvsGrabber __all__ = [] -__version__ = 0.1 -__date__ = '2013-04-23' -__updated__ = '2013-08-29' +__version__ = 0.8 +__date__ = '2014-10-19' +__updated__ = '2014-10-19' DEBUG = 0 @@ -69,7 +69,7 @@ def main(argv=None): # IGNORE:C0111 program_shortdesc = __import__('__main__').__doc__.split("\n")[1] program_license = '''%s - Created by user_name on %s. + Created by chris on %s. Copyright 2013 organization_name. All rights reserved. Licensed under the Apache License 2.0 @@ -91,6 +91,7 @@ def main(argv=None): # IGNORE:C0111 parser.add_argument(dest="option", help="options from xmltv2vdr call [default: %(default)s]", metavar="option", nargs='*') parser.add_argument('-l', '--checkchannels', action='store_true', help='Go to http://www.vdr-wiki.de/wiki/index.php/Xmltv2vdr-plugin and safe the "Verbindliche EPG-Senderliste" to an text file called "channelids.txt"') + parser.add_argument('-m', '--checkchannelmap', action='store_true', help='Show the diff between channel map and server.') # Process arguments args = parser.parse_args() @@ -108,6 +109,9 @@ def main(argv=None): # IGNORE:C0111 if args.checkchannels: defaults.checkchannelids() + if args.checkchannelmap: + defaults.checkchannelmap() + if cfile: defaults.write_controlfile(args.time, args.days) @@ -140,7 +144,7 @@ def main(argv=None): # IGNORE:C0111 if __name__ == "__main__": if DEBUG: - #sys.argv.append("-h") - #sys.argv.append("1 'pin' 0 ard.de zdf.de") + #sys.argv.append("-m") + #sys.argv.append("1 '' 0 ard.de zdf.de") pass sys.exit(main())