diff --git a/addon.xml b/addon.xml index 90aba80..9c14362 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/ardundzdf.py b/ardundzdf.py index 1132fd6..495b6dd 100644 --- a/ardundzdf.py +++ b/ardundzdf.py @@ -43,8 +43,8 @@ # +++++ ARDundZDF - Addon Kodi-Version, migriert von der Plexmediaserver-Version +++++ # VERSION -> addon.xml aktualisieren -VERSION = '3.1.8' -VDATE = '12.07.2020' +VERSION = '3.1.9' +VDATE = '14.07.2020' # # @@ -4533,15 +4533,17 @@ def DownloadTools(): mpcnt = mpcnt + 1 fname = os.path.join(path, entry) vidsize = vidsize + os.path.getsize(fname) - vidsize = vidsize / 1000000 - PLog('Downloadverzeichnis: %s Download(s), %s MBytes' % (mpcnt, str(vidsize))) + vidsize = humanbytes(vidsize) + PLog('Downloadverzeichnis: %s Download(s), %s' % (str(mpcnt), vidsize)) li = xbmcgui.ListItem() li = home(li, ID=NAME) # Home-Button - dlpath = SETTINGS.getSetting('pref_download_path')# Einstellungen: Pfad Downloaderz. + dlpath = SETTINGS.getSetting('pref_download_path')# Einstellungen: Pfad Downloadverz. title = u'Downloadverzeichnis festlegen/ändern: (%s)' % dlpath tagline = 'Das Downloadverzeichnis muss für den Addon-Nutzer beschreibbar sein.' + summ = ''; + # summary = # s.o. fparams="&fparams={'settingKey': 'pref_download_path', 'mytype': '0', 'heading': '%s', 'path': '%s'}" % (title, dlpath) addDir(li=li, label=title, action="dirList", dirID="DirectoryNavigator", fanart=R(ICON_DOWNL_DIR), @@ -4576,11 +4578,15 @@ def DownloadTools(): thumb=R(ICON_DIR_FAVORITS), fparams=fparams, tagline=tagline) if mpcnt > 0: # Videos / Podcasts? + dirsize='' + dirsize = get_dir_size(SETTINGS.getSetting('pref_download_path')) + summ = u"Größe Downloadverzeichnis: %s | Anzahl Downloads: %s | Größe Video-/Audiodateien: %s" %\ + (dirsize, str(mpcnt), vidsize) title = 'Downloads und Aufnahmen bearbeiten: %s Download(s)' % (mpcnt) # Button Bearbeiten - summary = 'Downloads im Downloadverzeichnis ansehen, loeschen, verschieben' + tag = 'Downloads im Downloadverzeichnis ansehen, loeschen, verschieben' fparams="&fparams={}" addDir(li=li, label=title, action="dirList", dirID="DownloadsList", fanart=R(ICON_DOWNL_DIR), - thumb=R(ICON_DIR_WORK), fparams=fparams, summary=summary) + thumb=R(ICON_DIR_WORK), fparams=fparams, summary=summ, tagline=tag) if dirlist: dest_path = SETTINGS.getSetting('pref_download_path') @@ -5601,7 +5607,7 @@ def TVLiveRecordSender(title): if u'://' not in img: # Logo lokal? -> wird aus Resources geladen, Unterverz. leider n.m. img = R(img) link = rec[3] - title1 = title + ': Aufnahme starten' + title = "record: %s" % title if SETTINGS.getSetting('pref_LiveRecord_input') == 'true': laenge = "wird manuell eingegeben" summ = 'Aufnahmedauer: %s' % laenge @@ -5611,6 +5617,13 @@ def TVLiveRecordSender(title): % (quote(link), quote(title), duration, laenge) addDir(li=li, label=title, action="dirList", dirID="LiveRecord", fanart=R(rec[2]), thumb=img, fparams=fparams, summary=summ, tagline=tag) + + # Wechsel-Button zu den DownloadTools: + tagline = 'Downloads und Aufnahmen: Verschieben, Löschen, Ansehen, Verzeichnisse bearbeiten' + fparams="&fparams={}" + addDir(li=li, label='Download- und Aufnahme-Tools', action="dirList", dirID="DownloadTools", + fanart=R(FANART), thumb=R(ICON_DOWNL_DIR), tagline=tagline, fparams=fparams) + xbmcplugin.endOfDirectory(HANDLE, cacheToDisc=True) @@ -5770,6 +5783,8 @@ def get_sort_playlist(): # sortierte Playliste der TV-Livesender EPG_ID = stringextract('', '', item) img = stringextract('', '', item) link = stringextract('', '', item) # url für Livestreaming + if "" in item: + link = stringextract('', '', item) # abw. Link, zum Aufnehmen geeignet if 'ZDFsource' in link: title_sender = stringextract('', '', item) @@ -5855,6 +5870,13 @@ def EPG_ShowSingle(ID, name, stream_url, pagenr=0): quote(stream_url), pagenr) addDir(li=li, label=summ, action="dirList", dirID="EPG_ShowSingle", fanart=R('tv-EPG-single.png'), thumb=R(ICON_MEHR), fparams=fparams, summary=summ) + + # Wechsel-Button zu den DownloadTools: + tagline = 'Downloads und Aufnahmen: Verschieben, Löschen, Ansehen, Verzeichnisse bearbeiten' + fparams="&fparams={}" + addDir(li=li, label='Download- und Aufnahme-Tools', action="dirList", dirID="DownloadTools", + fanart=R(FANART), thumb=R(ICON_DOWNL_DIR), tagline=tagline, fparams=fparams) + xbmcplugin.endOfDirectory(HANDLE, cacheToDisc=True) #----------------------------------------------------------------------------------------------------- @@ -5915,8 +5937,10 @@ def EPG_ShowAll(title, offset=0, Merk='false'): img = img_playlist else: href=rec[1]; img=rec[2]; sname=rec[3]; stime=rec[4]; summ=rec[5]; vonbis=rec[6] - if img.find('http') == -1: # Werbebilder today.de hier ohne http://, Ersatzbild einfügen - img = R('icon-bild-fehlt.png') + PLog("img: " + img) + if type(img) != list: # Ursache Listobjekt n.b. + if img.find('http') == -1: # Werbebilder today.de hier ohne http://, Ersatzbild einfügen + img = R('icon-bild-fehlt.png') title=py2_decode(title); sname=py2_decode(sname); title_playlist=py2_decode(title_playlist); title = sname.replace('JETZT', title_playlist) # JETZT durch Sender ersetzen # sctime = "[COLOR red] %s [/COLOR]" % stime # Darstellung verschlechtert @@ -5944,6 +5968,12 @@ def EPG_ShowAll(title, offset=0, Merk='false'): addDir(li=li, label=summ, action="dirList", dirID="EPG_ShowAll", fanart=R('tv-EPG-all.png'), thumb=R(ICON_MEHR), fparams=fparams, summary=summ, tagline=title2) + # Wechsel-Button zu den DownloadTools: + tagline = 'Downloads und Aufnahmen: Verschieben, Löschen, Ansehen, Verzeichnisse bearbeiten' + fparams="&fparams={}" + addDir(li=li, label='Download- und Aufnahme-Tools', action="dirList", dirID="DownloadTools", + fanart=R(FANART), thumb=R(ICON_DOWNL_DIR), tagline=tagline, fparams=fparams) + xbmcplugin.endOfDirectory(HANDLE, cacheToDisc=True) #----------------------------------------------------------------------------------------------------- # TV LiveListe - verwendet lokale Playlist livesenderTV.xml diff --git a/changelog.txt b/changelog.txt index 8c150fc..7f46323 100644 --- a/changelog.txt +++ b/changelog.txt @@ -12,6 +12,22 @@ CHANGE HISTORY max_col 97 -------------- +14.06.2020 3.1.9 + addDir (Modul util): Kodierungsbehandl. im Kontextmenü für EPG_ShowSingle + und EPG_ShowAll (relevant für ID-Abgleich in JobRemove (epgRecord). + JobRemove (Modul epgRecord): leere pid abgefangen (leer bei künftigen Aufnahmen). + Modul epgRecord: JobID als eindeutige Kennung eingeführt, Anpassungen in JobMain, + JobListe, JobRemove (beide Abgleichvarianten zunächst beibehalten). + TVLiveRecordSender: zusätzl. Wechselbutton für 'Download- und Aufnahme-Tools', + Titel "record:" vorangestellt. + EPG_ShowAll + EPG_ShowSingle: zusätzl. Wechselbutton für 'Download- und + Aufnahme-Tools'. + DownloadTools: Infos zum Bearbeiten-Button: Anz. Dateien, Größe Verz. + Dateien. + EPG_ShowAll: Listobjekt für img in EPG-Rückgabe abgefangen (Ursache n.b.), + Addon-Wicki (Github) aktualisiert. + livesenderTV.xml: alternative Streamurl für den Sender DasErste verwendet (An- + passung in get_sort_playlist, relevant zum Aufnahmen). + 11.06.2020 3.1.8 get_ZDFstreamlinks (Modul util): Verwendung apiToken geändert + für player2_url genutzt (ZDF-Streamlinks konnten fehlen). @@ -39,7 +55,6 @@ not on Github 3.1.7 Sendungen aufnehmen (DVR-Funktion) MakeDetailText + LiveRecord aus ardundzdf verlagert nach util (Modul-Import in epgRecord schlägt fehl). Neue Funktion ReadJobs (Modul util): einschl. Lock-Option für Modul epgRecord. - RSave (Modul util): erweitert für Lock-Nutzung (für Monitor in epgRecord) not on Github 3.1.6 addDir (Modul util): zusätzl. Kontextmenü "Recording TV-Live" für diff --git a/resources/lib/epgRecord.py b/resources/lib/epgRecord.py index bd7005e..fa8dee2 100644 --- a/resources/lib/epgRecord.py +++ b/resources/lib/epgRecord.py @@ -32,6 +32,7 @@ import time, datetime from threading import Thread +import random # Zufallswerte für JobID from resources.lib.util import * import resources.lib.EPG as EPG @@ -54,7 +55,7 @@ JOB_STOP = os.path.join("%s/job_stop") % ADDON_DATA # Stopfile für JobMonitor MONITOR_ALIVE = os.path.join("%s/monitor_alive") % ADDON_DATA # Lebendsignal für JobMonitor (leer, mtime-Abgleich) -JOBLINE_TEMPL = "%s%s%s%s%s%s%s" +JOBLINE_TEMPL = "%s%s%s%s%s%s%s%s" JOB_TEMPL = "%s" JOBLIST_TEMPL = "\n%s\n" JOBDELAY = 60 # Sek.=1 Minute @@ -299,7 +300,9 @@ def JobMain(action, start_end='', title='', descr='', sender='', url='', setSet status = 'waiting' # -> , JobMonitor aktualisiert title = cleanmark(title) # Farbe/fett aus ProgramRecord pid = '' # nimmt im Monitor PIDffmpeg auf - job_line = JOBLINE_TEMPL % (start_end,title,descr,sender,url,status,pid) + block = '4Yp2C09aF1k5YC3d' + JobID = ''.join(random.choice(block) for i in range(len(block))) # 16 stel. Job-ID + job_line = JOBLINE_TEMPL % (start_end,title,descr,sender,url,status,pid,JobID) new_job = JOB_TEMPL % job_line PLog(new_job[:80]) jobs = ReadJobs() # s. util @@ -364,7 +367,7 @@ def JobListe(): # Liste, Job-Status, Jobs löschen PLog("JobListe:") li = xbmcgui.ListItem() - li = home(li, ID=NAME) # Home-Button + li = home(li, ID=NAME) # Home-Button if os.path.exists(JOBFILE): jobs = ReadJobs() # s. util @@ -376,8 +379,8 @@ def JobListe(): # Liste, Job-Status, Jobs löschen now = EPG.get_unixtime(onlynow=True) now = int(now) now_human = date_human("%d.%m.%Y, %H:%M", now='') - pre_rec = SETTINGS.getSetting('pref_pre_rec') # Vorlauf (Bsp. 00:15:00 = 15 Minuten) - post_rec = SETTINGS.getSetting('pref_post_rec') # Nachlauf (dto.) + pre_rec = SETTINGS.getSetting('pref_pre_rec') # Vorlauf (Bsp. 00:15:00 = 15 Minuten) + post_rec = SETTINGS.getSetting('pref_post_rec') # Nachlauf (dto.) pre_rec = re.search('= (\d+) Min', pre_rec).group(1) post_rec = re.search('= (\d+) Min', post_rec).group(1) anz_jobs = len(jobs) @@ -400,7 +403,8 @@ def JobListe(): # Liste, Job-Status, Jobs löschen pid = stringextract('', '', myjob) title = stringextract('', '', myjob) - job_title = title # für Abgleich in JobRemove + job_title = title # Abgleich in JobRemove alt + JobID = stringextract('', '', myjob) # Abgleich in JobRemove neu sender = stringextract('', '', myjob) dfname = "%s: %s" % (sender, title) # Titel: Sender + Sendung (mit Mark.) dfname = make_filenames(dfname.strip()) + ".mp4" # Name aus Titel @@ -432,15 +436,15 @@ def JobListe(): # Liste, Job-Status, Jobs löschen status_real = "Aufnahme geplant: %s" % start_human label = u'Job löschen: %s' % title - tag = u'Start: %s, Ende: %s' % (start_human, end_human) + tag = u'Start: [B]%s[/B], Ende: [I][B]%s[/B][/I]' % (start_human, end_human) tag = u'%s\n%s' % (tag, status_real) max_reclist = SETTINGS.getSetting('pref_max_reclist') summ = u'[B]Anzahl Jobs[/B] in der Aufnahmeliste: %s' % (anz_jobs) summ = u"%s\n[B]Settings[/B]:\n[B]max. Größe der Aufnahmeliste:[/B] %s Jobs," % (summ, max_reclist) summ = u"%s[B]Vorlauf:[/B] %s Min., [B]Nachlauf:[/B] %s Min." % (summ, pre_rec, post_rec) - fparams="&fparams={'sender':'%s','job_title':'%s','start_end':'%s','job_active':'%s','pid':'%s'}" %\ - (sender, job_title, start_end, job_active, pid) + fparams="&fparams={'sender':'%s','job_title':'%s','start_end':'%s','job_active':'%s','pid':'%s','JobID':'%s'}" %\ + (sender, job_title, start_end, job_active, pid, JobID) addDir(li=li, label=label, action="dirList", dirID="resources.lib.epgRecord.JobRemove", fanart=R(ICON_DOWNL_DIR), thumb=img, fparams=fparams, tagline=tag, summary=summ) @@ -448,17 +452,25 @@ def JobListe(): # Liste, Job-Status, Jobs löschen #---------------------------------------------------------------- # Aufrufer: JobListe +# Ablauf: Liste einlesen, Einträge in Schleife abgleichen, gefundenen +# Satz verwerfen, verkleinerte Liste mit Lock speichern # job_title: unbehandelt, mit ev. Mark. -# title + start_end: eindeutige ID +# title + start_end: als ID nur noch aus Kompat. verwenden(Kodier- +# Problem möglich) +# 13.07.2020 JobID als eindeutige ID ergänzt # -def JobRemove(sender, job_title, start_end, job_active, pid): +def JobRemove(sender, job_title, start_end, job_active, pid, JobID): PLog("JobRemove:") - + PLog(pid); PLog(JobID) + msg1 = "%s: %s" % (sender, job_title) heading = u"Job aus Aufnahmeliste löschen" + pidtxt='' + if pid: + pidtxt = " (PID %s) " % pid if job_active == 'True': - msg2 = u"Job (PID %s) tatsächlich abbrechen und löschen?" % pid - heading = "aktiven (!) %s!" % heading + msg2 = u"Job %s tatsächlich abbrechen und löschen?" % pidtxt + heading = u"aktiven (!) %s!" % heading icon = MSG_ICON else: msg2 = u"Job tatsächlich löschen?" @@ -469,17 +481,25 @@ def JobRemove(sender, job_title, start_end, job_active, pid): if ret !=1: return - if job_active == 'True': + if job_active == 'True' and pid != '': os.kill(int(pid), signal.SIGTERM) # auch Windows10 OK (aber Teilvideo beschäd.) PLog("kill_pid: %s" % str(pid)) jobs = ReadJobs() # s. util newjob_list = []; # newjob_list: Liste nach Änderungen + job_title=py2_encode(job_title); # type kann vom code-Format in jobs abweichen for job in jobs: my_start_end = stringextract('', '', job) - my_title = stringextract('', '', job) - if start_end == my_start_end and job_title == my_title: # skip=delete - continue + my_title = stringextract('', '', job) + my_JobID = stringextract('', '', job) + if JobID: # neuer Abgleich + if JobID == my_JobID: + PLog('JobID_OK: %s' % JobID) + continue + else: # alter Abgleich + if start_end == my_start_end and job_title == my_title: + PLog('start_end_title_OK: %s' % start_end) + continue newjob_list.append(JOB_TEMPL % job) # job -> Marker PLog(len(jobs)) @@ -587,8 +607,10 @@ def test_jobs(): descr = u"Debug: Jobliste mit ausgewählten Jobs, Startzeit: jetzt + 10 Sec., Aufnahmezeit 10 Sec. (Endzeit: Startzeit + 10 Sec.)" status = "waiting" pid = '' + block = '4Yp2C09aF1k5YC3d' + JobID = ''.join(random.choice(block) for i in range(len(block))) # 16 stel. Job-ID - job = JOBLINE_TEMPL % (start_end,title,descr,sender,url,status,pid) + job = JOBLINE_TEMPL % (start_end,title,descr,sender,url,status,pid,JobID) job_list.append(JOB_TEMPL % job) # job -> Marker jobs = "\n".join(job_list) diff --git a/resources/lib/util.py b/resources/lib/util.py index 6331f45..ad1fdb8 100644 --- a/resources/lib/util.py +++ b/resources/lib/util.py @@ -11,7 +11,7 @@ # 02.11.2019 Migration Python3 Modul future # 17.11.2019 Migration Python3 Modul kodi_six + manuelle Anpassungen # -# Stand 08.07.2020 +# Stand 14.07.2020 # Python3-Kompatibilität: from __future__ import absolute_import @@ -641,6 +641,7 @@ def addDir(li, label, action, dirID, fanart, thumb, fparams, summary='', tagline cmenu=True, sortlabel='', merkname='', filterstatus='', start_end=''): PLog('addDir:'); PLog(type(label)) + label_org=label # s. 'Job löschen' in K-Menüs label=py2_encode(label) PLog('addDir_label: {0}, action: {1}, dirID: {2}'.format(label[:100], action, dirID)) PLog(mediatype); @@ -713,7 +714,8 @@ def addDir(li, label, action, dirID, fanart, thumb, fparams, summary='', tagline fparams_change = "&fparams={0}".format(fp) fparams_change = quote_plus(fparams_change) # Filtern - # unterschiedl. Parameterquellen: EPG_ShowSingle, EPG_ShowAll: + # unterschiedl. Parameterquellen: EPG_ShowSingle, EPG_ShowAll - bei + # title + descr sind hier die Codier.-Behandl. zu wiederholen: if start_end: # Unix-Time-Format od. "Recording.." PLog("start_end: " + start_end) f = unquote(fparams) # Param. extrahieren @@ -723,9 +725,13 @@ def addDir(li, label, action, dirID, fanart, thumb, fparams, summary='', tagline url = stringextract("path':'", "'", f) # Stream-Url # title mit Markierung übernehmen title = stringextract("title':'", "'", f) # Bsp. 'Mi | 01:45 | Dick und nun?' + title = py2_decode(title) + title = repl_json_chars(title) PLog("title: " + title) descr = "%s\n\n%s" % (tagline, summary) descr = descr.replace('\n','||') + descr = py2_decode(descr) + descr = repl_json_chars(descr) if "Recording TV-Live" in start_end: # K-Menü in EPG_ShowAll -> LiveRecord Sender = cleanmark(title) @@ -743,6 +749,7 @@ def addDir(li, label, action, dirID, fanart, thumb, fparams, summary='', tagline PLog("fparams_recordLive: " + fparams_recordLive[:100]) fparams_recordLive = quote_plus(fparams_recordLive) else: # K-Menü in EPG_ShowSingle + title=py2_encode(title); descr=py2_encode(descr) fp = {'url': quote_plus(url), 'sender': quote_plus(Sender),\ 'title': quote_plus(title), 'descr': quote_plus(descr), 'start_end': start_end} fparams_record = "&fparams={0}".format(fp) @@ -766,7 +773,8 @@ def addDir(li, label, action, dirID, fanart, thumb, fparams, summary='', tagline commands.append(('Zur Merkliste hinzufügen', 'RunScript(%s, %s, ?action=dirList&dirID=Watch%s)' \ % (MY_SCRIPT, HANDLE, fparams_add))) commands.append(('Aus Merkliste entfernen', 'RunScript(%s, %s, ?action=dirList&dirID=Watch%s)' \ - % (MY_SCRIPT, HANDLE, fparams_del))) + % (MY_SCRIPT, HANDLE, fparams_del))) + if fparams_folder: # Aufrufer ShowFavs s.o. PLog('set_folder_context: ' + merkname) commands.append(('Merklisten-Eintrag zuordnen', 'RunScript(%s, %s, ?action=dirList&dirID=Watch%s)' \ diff --git a/resources/livesenderTV.xml b/resources/livesenderTV.xml index 4288107..38d224c 100644 --- a/resources/livesenderTV.xml +++ b/resources/livesenderTV.xml @@ -22,10 +22,11 @@ Das Erste Das Erste https://mcdn.daserste.de/daserste/de/master.m3u8 + https://derste247livede.akamaized.net/hls/live/658317/daserste_de/profile1/1.m3u8 tv-das-erste.png Arauco ARD - 11.05.2019 + 13.07.2020 ZDF