diff --git a/README.md b/README.md index 5259d68..0d5e8ae 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Download aktuelle Version: https://github.com/rols1/Kodi-Addon-ARDundZDF/release Plex hat die Unterstützung für Plugins in seinen Client-Softwarepaketen eingestellt. Die Repos für die Plex-Versionen [Plex-Plugin-ARDMediathek2016](https://github.com/rols1/Plex-Plugin-ARDMediathek2016) und [ARDundZDF](https://github.com/rols1/ARDundZDF) habe ich im März 2022 gelöscht (dto. FlickrExplorer, TuneIn2017, Shoutcast2017).
Classic-Version der ARD Mediathek: seit Juni 2021 sind die Classic-Links nicht mehr erreichbar. Der Code im Addon wurde entfernt; im Addon ist das Menü ARD Mediathek Neu voreingestellt (Details siehe Funktionen).
-Damit entfallen auch die Radio-Podcasts der Classic-Version. Sie werden durch die neue Audiothek abgelöst.
+Damit entfallen auch die Radio-Podcasts der Classic-Version. Sie werden durch die neue ARD-Audiothek abgelöst.
#### Rückmeldungen willkommen: Im Forum: https://www.kodinerds.net/index.php/Thread/64244-RELEASE-Kodi-Addon-ARDundZDF/ @@ -111,12 +111,12 @@ Funktionen: #### Updates - entweder mit dem integrierten Updatemodul (autom. Anpassung an Kodi-Version) oder via kodinerds-Repo -- Updates einzelner Bestandteile des Addons (Einzelupdate) zwischen den regulären Updates - Näheres siehe [Startpost im kodinerds-Forum](https://www.kodinerds.net/index.php/Thread/64244-RELEASE-Kodi-Addon-ARDundZDF/?postID=502022#post502022) +- Updates einzelner Bestandteile des Addons (Einzelupdate) zwischen den regulären Updates - Näheres siehe [Startpost im kodinerds-Forum](https://www.kodinerds.net/index.php/Thread/64244-RELEASE-Kodi-Addon-ARDundZDF/?postID=502022#post502022) #### weitere Module (optional) - ~~ZDFmobile~~ - entfernt ab Juni 2023 (obsolet) - 3Sat -- ~~funk~~ - deaktiviert ab Mai 2023 +- ~~funk~~ - deaktiviert ab Mai 2023 (api V4.0 nicht mehr verfügbar) - Kinderprogramme (z.Z. KIKA und ZDFtivi) - TagesschauXL - phoenix (https://www.phoenix.de/) diff --git a/ardundzdf.py b/ardundzdf.py index 43e1217..bd8f883 100644 --- a/ardundzdf.py +++ b/ardundzdf.py @@ -55,9 +55,9 @@ # +++++ ARDundZDF - Addon Kodi-Version, migriert von der Plexmediaserver-Version +++++ # VERSION -> addon.xml aktualisieren -# 98 # Numerierung für Einzelupdate +# 99 # Numerierung für Einzelupdate VERSION = '4.7.0' -VDATE = '01.05.2023' +VDATE = '02.05.2023' # (c) 2019 by Roland Scholz, rols1@gmx.de @@ -7076,7 +7076,7 @@ def ZDF_RubrikSingle(url, title, homeID=""): sid = docObject["id"] # z.B. trigger-point-102 PLog("Serie: " + sid) label = "komplette Liste: %s" % title - tag = u"Liste aller verfügbaren Folgen" + tag = u"Liste aller verfügbaren Folgen | strm-Tools" fparams="&fparams={'sid': '%s'}" % (sid) addDir(li=li, label=label, action="dirList", dirID="ZDF_FlatListEpisodes", fanart=R(ICON_DIR_FOLDER), thumb=R(ICON_DIR_FOLDER), tagline=tag, fparams=fparams) @@ -7724,6 +7724,8 @@ def ZDF_search_button(li, query): # Serieninhalt holen via api-Call # Cache: von der Gesamt-Liste (> 3 MB) werden im Dict nur # sid und url gespeichert +# 01.05.2023 Folge direkt holen mit sid statt serien-100 +# def ZDF_FlatListEpisodes(sid): PLog('ZDF_FlatListEpisodes: ' + sid) CacheTime = 43200 # 12 Std. @@ -7731,63 +7733,38 @@ def ZDF_FlatListEpisodes(sid): li = xbmcgui.ListItem() li = home(li, ID='ZDF') # Home-Button - path = "https://zdf-cdn.live.cellular.de/mediathekV2/document/serien-100" - page = Dict("load", "ZDF_Serien", CacheTime=CacheTime) # ZDF-Serien Gesamtübersicht - if page == False or page == '': # Cache miss od. leer - vom Sender holen - page, msg = get_page(path=path) - if page == '': - msg1 = "Fehler in ZDF_FlatListEpisodes:" - msg2 = msg - MyDialog(msg1, msg2, '') - return - else: - page = page.replace('\\/','/') - Dict("store", "ZDF_Serien", page) - - pat = '"id":"%s' % sid # Suchmuster Bsp. "id": "soko-leipzig- - PLog("pat: " + pat) - pos = page.find(pat) - page = page[pos:] - PLog("pos: %d, %s" % (pos, page[:80])) - url = stringextract('"url":"', '"', page) - PLog("url2: " + url) - if url == '': + # # headers wg. häufiger timeouts + headers="{'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36', \ + 'Referer': '%s', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': 'application/json, text/plain, */*'}" + path = "https://zdf-cdn.live.cellular.de/mediathekV2/document/%s" % sid + page, msg = get_page(path=path, header=headers, JsonPage=True) + if page == "": msg1 = "Abbruch in ZDF_FlatListEpisodes:" msg2 = "Die Serien-ID [B]%s[/B] ist nicht (mehr)" % sid - msg3 = " in der Serienübersicht des ZDF enthalten." + msg3 = " in der Serienübersicht des ZDF enthalten." MyDialog(msg1, msg2, msg3) return + + jsonObject = json.loads(page) + PLog(str(jsonObject)[:80]) + + #----------------------------- # strm-Buttons - #----------------------------- # 2. Folgen zur Serie holen - - headers="{'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36', \ - 'Referer': '%s', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': 'application/json, text/plain, */*'}" - url = stringextract('url":"', '"', page) - page, msg = get_page(path=url, header=headers) # headers wg. häufiger timeouts - if page == '': - msg1 = "Fehler in ZDF_FlatListEpisodes:" - msg2 = msg - MyDialog(msg1, msg2, '') - return - page = page.replace('\\/','/') - page = py2_encode(page) - mediatype='' # Kennz. Video für Sofortstart if SETTINGS.getSetting('pref_video_direct') == 'true': mediatype='video' # # Button strm-Dateien gesamte Liste if SETTINGS.getSetting('pref_strm') == 'true': - url = stringextract('"url":"', '"', page) # 1. Url/Seite img = R(ICON_DIR_STRM) title = u"strm-Dateien für die komplette Liste erzeugen / aktualisieren" tag = u"Verwenden Sie das Kontextmenü, um strm-Dateien für [B]einzelne Videos[/B] zu erzeugen" summ = u"[B]strm-Dateien (strm-Bündel)[/B] sparen Platz und lassen sich auch in die Kodi-Bibliothek integrieren." summ = u"%s\n\nEin strm-Bündel in diesem Addon besteht aus der strm-Datei mit der Streamurl, einer jpeg-Datei" % summ summ = u"%s\nmit dem Bild zum Video und einer nfo-Datei mit dem Begleittext." % summ - url=py2_encode(url); title=py2_encode(title); + path=py2_encode(path); title=py2_encode(title); fparams="&fparams={'path': '%s', 'title': '%s'}" %\ - (quote(url), quote(title)) + (quote(path), quote(title)) addDir(li=li, label=title, action="dirList", dirID="ZDF_getStrmList", fanart=img, thumb=img, fparams=fparams, tagline=tag, summary=summ) @@ -7804,27 +7781,34 @@ def ZDF_FlatListEpisodes(sid): fanart=R(FANART), thumb=R("icon-strmtools.png"), tagline=tag, fparams=fparams) + #----------------------------- # Auswertung Serie - # Blockmerkmal für Folgen unterschiedlich: # Blockmerkmale wie ZDF_getStrmList - staffel_list = blockextract('"name":"Staffel ', page) # Staffel-Blöcke - staffel_list = staffel_list + blockextract('"name":"Alle Folgen', page, '"profile":') - if len(staffel_list) == 0: # ohne Staffel-Blöcke - staffel_list = blockextract('"headline":"', page) - season_title = stringextract('"title":"', '"', page) # Serientitel für Abgleich + # Blockmerkmal für Folgen unterschiedlich: # Blockmerkmale wie ZDF_getStrmList + season_title = jsonObject["document"]["titel"] + season_id = jsonObject["document"]["id"] + staffel_list = jsonObject["cluster"] PLog("season_title: %s" % season_title) PLog("staffel_list: %d" % len(staffel_list)) - for staffel in staffel_list: - folgen = blockextract('"headline":"', staffel) # Folgen-Blöcke + for staffel in staffel_list: + if staffel["name"] == "": # Teaser u.ä. + continue + folgen = staffel["teaser"] # Folgen-Blöcke PLog("Folgen: %d" % len(folgen)) for folge in folgen: - headline = stringextract('"headline":"', '"', folge) - if headline.strip() != season_title.strip(): # Seite kann weitere Serien enthalten - PLog("%s | %s" % (headline, season_title)) - break + # Abgleich headline/season_title entfällt wg. möglicher Abweichungen + # Bsp.: FETT UND FETT/FETT & FETT, daher Abgleich mit brandId + scms_id = folge["id"] + try: + brandId = folge["brandId"] + except: + brandId="" + if season_id != brandId: + PLog("skip_no_brandId: " + str(folge)[:60]) + continue title, url, img, tag, summ, season, weburl = ZDF_FlatListRec(folge) - scms_id = stringextract('"id":"', '"', folge) if season == '': + PLog("skip_no_season: " + str(folge)[:60]) continue summ_par= summ.replace('\n', '||') @@ -7993,8 +7977,6 @@ def ZDF_getStrmList(path, title, ID="ZDF"): msg2 = msg MyDialog(msg1, msg2, '') return - if '\\/' in page: # ZDF-Urls - page = page.replace('\\/','/') if page.find('"seasonNumber"') < 0: msg1 = "[B]seasonNumber[/B] fehlt in den Beiträgen." @@ -8002,9 +7984,10 @@ def ZDF_getStrmList(path, title, ID="ZDF"): MyDialog(msg1, msg2, '') return + jsonObject = json.loads(page) + PLog(str(jsonObject)[:80]) - list_title = stringextract('"titel":"', '"', page) # Serien-Titel (vorgegeben) - list_title = list_title.replace('u0022', '*') # \" + list_title = jsonObject["document"]["titel"] list_title = transl_json(list_title) PLog("list_title:" + list_title) @@ -8038,27 +8021,32 @@ def ZDF_getStrmList(path, title, ID="ZDF"): #--------------------- # Blockmerkmale s. ZDF_FlatListEpisodes: # Blockmerkmale wie ZDF_FlatListEpisodes - staffel_list = blockextract('"name":"Staffel ', page) # Staffel-Blöcke - staffel_list = staffel_list + blockextract('"name":"Alle Folgen', page, '"profile":') + staffel_list = jsonObject["cluster"] # Staffel-Blöcke if len(staffel_list) == 0: # ohne Staffel-Blöcke staffel_list = blockextract('"headline":"', page) - season_title = stringextract('"title":"', '"', page) # Serientitel für Abgleich + season_title = jsonObject["document"]["titel"] + season_id = jsonObject["document"]["id"] PLog("season_title: %s" % season_title) PLog("staffel_list: %d" % len(staffel_list)) cnt=0; skip_cnt=0; do_break=False for staffel in staffel_list: - folgen = blockextract('"headline":"', staffel) # Folgen-Blöcke + folgen = staffel["teaser"] # Folgen-Blöcke PLog("Folgen: %d" % len(folgen)) for folge in folgen: - headline = stringextract('"headline":"', '"', folge) - if headline.strip() != season_title.strip(): # Seite kann weitere Serien enthalten - PLog("%s | %s" % (headline, season_title)) - break + scms_id = folge["id"] # wie ZDF_FlatListEpisodes + try: + brandId = folge["brandId"] + except: + brandId="" + if season_id != brandId: + PLog("skip_no_brandId: " + str(folge)[:60]) + continue title, url, img, tag, summ, season, weburl = ZDF_FlatListRec(folge) # Datensatz if season == '': + PLog("skip_no_season: " + str(folge)[:60]) continue - + fname = make_filenames(title) # Zieldatei hier ohne Dialog PLog("fname: " + fname) if SETTINGS.getSetting('pref_strm_uz') == "true": # Für jede strm-Datei ein Unterverzeichnis @@ -8078,7 +8066,6 @@ def ZDF_getStrmList(path, title, ID="ZDF"): msg2 = title xbmcgui.Dialog().notification(msg1,msg2,icon,500,sound=False) - PLog("Satz30:") PLog(url);PLog(img);PLog(title);PLog(tag);PLog(summ[:80]); @@ -8133,42 +8120,40 @@ def ZDF_getStrmList(path, title, ID="ZDF"): # Aufrufer: ZDF_FlatListEpisodes, ZDF_getStrmList def ZDF_FlatListRec(item): PLog('ZDF_FlatListRec:') - PLog(item[:80]) + PLog(str(item)[:80]) title='';url='';img='';tag='';summ='';season=''; descr='';weburl='' - item = item.replace('u0022', '*') # \" - item = transl_json(item) - season = stringextract('"seasonNumber":"', '"', item) - if season == '': # Satz verwerfen + if "seasonNumber" in item: + season = item["seasonNumber"] # string + if season == '': # Satz verwerfen return title, url, img, tag, summ, season, weburl - episode = stringextract('"episodeNumber":"', '"', item) + episode = item["episodeNumber"] # string PLog(season); PLog(episode) title_pre = "S%02dE%02d" % (int(season), int(episode)) # 31.01.2022 S13_F10 -> S13E10 + PLog("Mark1") - brand = stringextract('"headline":"', '"', item) - title = stringextract('"titel":"', '"', item) + brand = item["headline"] + title = item["titel"] title = repl_json_chars(title) - descr = stringextract('"beschreibung":"', '"', item) - weburl = stringextract('"sharingUrl":"', '"', item) # für Abgleich vor./nicht mehr vorh. - fsk = stringextract('"fsk":"', '"', item) + descr = item["beschreibung"] + weburl = item["sharingUrl"] # für Abgleich vor./nicht mehr vorh. + fsk = item["fsk"] if fsk == "none": fsk = "ohne" - end = stringextract('"timetolive":"', '"', item) # Altern.: offlineAvailability + end = item["timetolive"] # Altern.: offlineAvailability end = u"[B]Verfügbar bis [COLOR darkgoldenrod]%s[/COLOR][/B]" % end - geo = stringextract('"geoLocation":"', '"', item) + geo = item["geoLocation"] if geo == "none": geo = "ohne" - dauer = stringextract('"length":', ',', item) + dauer = item["length"] dauer = seconds_translate(dauer) title = "%s | %s" % (title_pre, title) - img = stringextract('"url":"', '"', item) # Bild - pos = item.find("cockpitPrimaryTarget") - cockpit = item[pos:] - url = stringextract('"url":"', '"', cockpit) # Ziel-Url mit Streamquellen + img = ZDF_get_img(item) + url = item["cockpitPrimaryTarget"]["url"] # Ziel-Url mit Streamquellen tag = u"%s | Staffel: %s | Folge: %s\nDauer: %s | FSK: %s | Geo: %s | %s" %\ (brand, season, episode, dauer, fsk, geo, end) diff --git a/resources/lib/strm.py b/resources/lib/strm.py index f91686e..b0fee98 100644 --- a/resources/lib/strm.py +++ b/resources/lib/strm.py @@ -3,8 +3,8 @@ # strm.py - Teil von Kodi-Addon-ARDundZDF # Erzeugung von strm-Dateien für Kodi's Medienverwaltung ################################################################################ -# 12 # Numerierung für Einzelupdate -# Stand: 26.01.2023 +# 13 # Numerierung für Einzelupdate +# Stand: 02.05.2023 # from __future__ import absolute_import @@ -727,6 +727,7 @@ def strm_tool_set(mode="load", index=0, val=''): # strmpath: lokale strm-Ablage # import ZDF_FlatListRec + ZDF_getApiStreams hier wg. Rekursion im Modul- # kopf (Thread strm_sync) +# 02.05.2023 json-Auswertung (Anpass. an ZDF_FlatListEpisodes) # def do_sync(list_title, strmpath, list_path, strm_type): PLog("do_sync:") @@ -751,20 +752,28 @@ def do_sync(list_title, strmpath, list_path, strm_type): return #------------- # Blockmerkmale wie ZDF_FlatListEpisodes - staffel_list = blockextract('"name":"Staffel ', page) # Staffel-Blöcke - staffel_list = staffel_list + blockextract('"name":"Alle Folgen', page, '"profile":') - if len(staffel_list) == 0: # ohne Staffel-Blöcke - staffel_list = blockextract('"headline":"', page) + jsonObject = json.loads(page) + PLog(str(jsonObject)[:80]) + season_id = jsonObject["document"]["id"] + staffel_list = jsonObject["cluster"] # Staffel-Blöcke PLog("staffel_list: %d" % len(staffel_list)) cnt=0; skip_cnt=0; for staffel in staffel_list: - folgen = blockextract('"headline":"', staffel) # Folgen-Blöcke + if staffel["name"] == "": # Teaser u.ä. + continue + folgen = staffel["teaser"] # Folgen-Blöcke PLog("sync_Folgen: %d" % len(folgen)) for folge in folgen: - folge = folge.replace('\\/','/') + scms_id = folge["id"] + try: + brandId = folge["brandId"] + except: + brandId="" + if season_id != brandId: + PLog("skip_no_brandId: " + str(folge)[:60]) + continue title, url, img, tag, summ, season, weburl = ZDF_FlatListRec(folge) # Datensatz - if season == '': continue