• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

VLC Stream Aufzeichnen und zwar Zeitgesteuert

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
Ich hab jetzt erst mal zu FFmpeg geraten. Die Software wird als Client auch akzeptiert. Jedenfalls bekommt man den Stream zu grabben. Ich glaube das "schwerste" daran ist eine zeitgesteuerte Aufnahme zu realisieren. Entweder mit Cronjob unter Linux oder mit der Windows Aufgabenplanung, die beide zeitgesteuert die Aufnahme für die Zeit von X für X Minuten (als FFmpeg Option) ansprechen.

Die Zeit festlegen in der Taskplanung mit Auto"kill" (beenden) hat nur den Nachteil das man nicht sicher sein kann ob und wie viele Minuten Stream aufgezeichnet worden sind, daher die Idee das FFMpeg bemessen zu lassen.
 

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #22
Also per Linux ist das kein Problem die streams aufzuzeichnen... kein ruckeln oder so vorhanden, auslastung ist schon etwas mehr aber egal...

Nur das mit dem Zeitgesteuerten ist wieder so ne sache... und das ist mir auch wichtig, wenn ich ma nicht da bin...

MfG

--- [2019-08-15 22:16 CEST] Automatisch zusammengeführter Beitrag ---

Ich hab da mal nenbissel gegooglet und bin statt auf dem cronjob auf den "at" befehl gestolpert, das sieht schon vielversprechent aus da dieser befehl einmalige ausführungen bereitstellt, da werd ich mich mal morgen nochmal dransetzen und schauen ob das geht:

at [zeit [datum] kommando]
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
So, ich veröffentliche das mal, zensiert.

Vielleicht hat noch jemand anderes einen nutzen dafür ;)

Was wird gebraucht:
Linux mit "at" Paket, Python3, pyCurl und ffmpeg Installation.

Das Skript wird aufgerufen, es heißt "rec.py" - das ist sehr wichtig.

Was gesetzt werden muß:
[kw]PLAYLIST_URL[/kw] - das ist die Quelle für eine m3u8 mit Senderinformationen
[kw]USER_AGENT[/kw] - als welcher UserAgent soll sich ffmpeg und curl Authentifizieren

Die m3u8 sollte so aufgebaut sein:
[src=text]#EXTINF:-1,SENDERNAME_DARSTELLUNG_IM_SKRIPT
https://PFAD_ZUM_CAPTURE_STREAM.m3u8[/src]

[src=python]
#!/usr/bin/env python3

PLAYLIST_URL = "https://yourPlaylistWithSources.m3u8"
USER_AGENT = "Your custom useragent string, adapt."

import sys
import time
import glob
import subprocess
import os.path
import os

import pycurl

USE_AT = True
APP_FOLDER = os.getcwd()

PLAYLIST_FILE = "streamData.m3u8"
PLAYLIST_DATA = ""
PLAYLIST_CHANNELS = {}
RECORDING_NAME = ""
RECORDING_CHANNEL_NAME = ""
RECORDING_CHANNEL_URL = ""
RECORDING_TIME = 0
RECORDING_DURATION = 0

def downloadPlaylist(downloadURL):
playlistFile = open(PLAYLIST_FILE, "wb")

print('Starting download of URI: \'%s\'\n' % downloadURL)
c = pycurl.Curl()
c.setopt(pycurl.URL, downloadURL)
c.setopt(pycurl.USERAGENT, USER_AGENT)
c.setopt(pycurl.VERBOSE, False)
c.setopt(pycurl.ENCODING, 'utf-8')
c.setopt(pycurl.WRITEDATA, playlistFile)
c.setopt(pycurl.NOPROGRESS, True)
c.setopt(pycurl.TIMEOUT, 30)

try:
c.perform()
print("\nSuccessfully downloaded playlist.\n")
playlistFile.close()
c.close()
return True
except Exception as error:
playlistFile.close()
c.close()
print("Encountered an error:")
raise error
return False



def getStreamSelection():
global PLAYLIST_CHANNELS, RECORDING_CHANNEL_NAME, RECORDING_CHANNEL_URL

playlistFile = open(PLAYLIST_FILE, "r")
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
currentChannel = line.split(',', 2)[1].rstrip()
elif (currentChannel != None and line.startswith('http://')):
PLAYLIST_CHANNELS[currentChannel] = line
currentChannel = None

sortedChannels = sorted(PLAYLIST_CHANNELS.keys())

print("\nChannel selection:")
for index, channel in enumerate(sortedChannels):
print("%2d - %s" % (index, channel))

print("x - Exit")

print("\n")

while True:
channelNum = input("\nInput channel number for grabbing: ")
if channelNum.lower() == "x":
exit(0)
else:
try:
RECORDING_CHANNEL_URL = PLAYLIST_CHANNELS[sortedChannels[int(channelNum)]].rstrip()
RECORDING_CHANNEL_NAME = sortedChannels[int(channelNum)]

print("Selected recording channel: %s" % (sortedChannels[int(channelNum)]))
isValidSelection = input('Is the channel correct Y/N? ')
if isValidSelection.lower() == "y":
return True
else:
continue

except Exception:
print('Wrong channel selection. Enter a channel number or "x" to exit.')
continue
break


if __name__ == "__main__":
if len(sys.argv) == 1:
if downloadPlaylist(PLAYLIST_URL):
print("Playlist succesfully downloaded.\n")

if getStreamSelection():

print('\nIt\'s time to enter the date and time for the recording:')
while True:
while True:
recordDate = input('\nEnter record date for recording, in format day.month.year, for example: 7.8.2019 or "x" to cancel, enter nothing for todays date.\n')
if recordDate.lower() == 'x':
print("Cancelled")
exit(1)

elif len(recordDate) == 0:
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")
recordDay = timeNow.tm_mday
recordMonth = timeNow.tm_mon
recordYear = timeNow.tm_year

print("Record date: %02d.%02d.%d " %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year))
if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break

elif recordDate.count('.') == 2:
recordDay, recordMonth, recordYear = map(int, recordDate.split('.', 3))
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")

try:
timestampRecord = time.strptime("%d.%d.%d 00:00:00" %(recordDay, recordMonth, recordYear), "%d.%m.%Y %H:%M:%S")
except ValueError:
print('Date input does not match, use day.month.year as: 7.8.2019')
continue

if time.mktime(timestampNow) > time.mktime(timestampRecord):
print("Date is in the past. Repeat input.")
continue
else:
print("Record date: %02d.%02d.%d " %(recordDay, recordMonth, recordYear))

if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break
else:
print("Invalid date input.")
continue

while True:
recordTime = input('\nEnter time to start recording, in format hour:minute, for example: 14:00 for 14 o\'clock, "x" to cancel\n')
if recordTime.lower() == 'x':
print("Cancelled")
exit(1)
elif recordTime.find(':') != -1:
recordHour, recordMinute = map(int, recordTime.split(':', 2))
print("Record time: %02d:%02d " %(recordHour, recordMinute))

timeNow = time.time()
timestampRecord = time.strptime("%d.%d.%d %d:%d:00" %(recordDay, recordMonth, recordYear, recordHour, recordMinute), "%d.%m.%Y %H:%M:%S")


if (timeNow > time.mktime(timestampRecord)):
print("Time is in the past. Repeat input.")
continue

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_TIME = time.mktime(timestampRecord)
break
else:
print("Invald time input.")
continue

while True:
recordDuration = input('\nEnter duration in minutes to record. For example 90 to capture 1 1/2 hours, "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)
elif int(recordDuration) < 0:
print("Negative recording duration, enter 30 for 30 minutes.")
continue

print("Record duration: %d minutes " %(int(recordDuration)))

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_DURATION = int(recordDuration)
break


while True:
RECORDING_NAME = input('\nEnter name for the recording file. Enter "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)

print("Record name: %s" % (RECORDING_NAME))
if input("Is the record name correct, Y/N ? ").lower() != 'y':
continue

break



print("\nWhat will be done?\nRecording channel \"%s\"." %(RECORDING_CHANNEL_NAME))
print("On %s at %s o'clock for %d minutes.\nRecording to file: \"%s\"" %(time.strftime("%d.%m.%Y", time.localtime(RECORDING_TIME)), time.strftime("%H:%M:%S", time.localtime(RECORDING_TIME)), RECORDING_DURATION, RECORDING_NAME))

confirm = input("\nAre all information correct, Y/N? ")
if confirm.lower() != 'y':
continue

scheduleFileName = "%d.rec" %(time.time())
with open(scheduleFileName, "w") as scheduleFile:
scheduleFile.write("%d;%d;%s;%s\n" % (RECORDING_TIME, RECORDING_DURATION, RECORDING_CHANNEL_NAME, RECORDING_NAME))

if USE_AT:
scheduleCommand = 'echo "python3 %s/rec.py -dl%s" | at -M %s' % (APP_FOLDER, scheduleFileName, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
subprocess.Popen(scheduleCommand, shell=True)
exit(1)

print("Scheduled task.\nBye bye.")

break
else:
hasPlaylist = False
for opt in sys.argv:
if opt.startswith('-dl'):
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
print("Playlist succesfully downloaded.\n")
else:
print("Error downloading playlist from \"%s\".\nExiting." %(PLAYLIST_URL))
exit(1)

for opt in sys.argv:
if opt.startswith("-dl"):
with open(PLAYLIST_FILE, "r") as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
currentChannel = line.split(',', 2)[1].rstrip()
elif currentChannel != None and (line.startswith('http://') or line.startswith('https://')):
PLAYLIST_CHANNELS[currentChannel] = line.rstrip()
currentChannel = None


scheduleFile = None

scheduleFileName = opt.replace('-dl', '', 1)
if os.path.exists(scheduleFileName):
scheduleData = None

with open(scheduleFileName, "r") as scheduleFile:
scheduleData = scheduleFile.read().rstrip().split(';', 4)

if scheduleData != None:
try:
channelURL = PLAYLIST_CHANNELS[scheduleData[2]]
commandString = "ffmpeg -user-agent \"%s\" -timeout 60 -i %s -t %d:%d:00 -vc:copy -o '%s.mkv'" %(USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
subprocess.Popen(commandString, shell=True)
except ValueError as error:
print('No channel information found.')
raise error
[/src]
 
Zuletzt bearbeitet:

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #24
das mit dem timeout funzt nochnet soooo ganz, der im VLC geholter timeout ist ja im millisekunden bereich und der im ffmpeg ist viel zu hoch *schätze ich mal*

MfG
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
Was meinst du mit viel zu hoch, wie äußert sich das?

Du kannst in der Zeile 267, die Variable "commandString", den Timeout Parameter entfernen, sieht dann so aus:

[src=python]commandString = "ffmpeg -user-agent \"%s\" -i %s -t %d:%d:00 -vc:copy -o '%s.mkv'"[/src]

Also "-timeout 60" raus.
 

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #26
ne ich mein der ist schon drin aber ist viel zu hoch? mit "60" betitelt es doch in Sekunden und nicht millisekunden?!

MfG
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
...mit "60" betitelt es doch in Sekunden und nicht millisekunden?!

In der allgemeine Doku steht es nicht drin, ich bin aber davon ausgegangen das es sich um Sekunden handelt.. aber hier, steht es auch wieder etwas anders:
https://www.ffmpeg.org/ffmpeg-protocols.html#toc-Protocols

Also wäre es an Stelle von "-timeout" "-rw_timeout 60" zu setzen, was dann explizit heißt: Wirf einen Fehler, wenn 60 Sekunden lang nicht gelesen oder geschrieben werden kann.

PS: In der Doku steht für timeout mal Millisekunden, mal Sekunden je nach Option :o
 

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #28
Ach oder nicht timeout, das war glaub ich der Cache der mit 1000 war, ich hab ka...

Mfg
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
@DukeMan999: Für "Caching" ist keine Option gesetzt im Skript, daher sollte dies Standardwert sein den ffmpeg für Caching bzw. als Buffer für den Stream verwendet.
 

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #30
Hallöle nochmal,

ich hab noch eine bitte wegen des scripts, könnte man ggf. eine locale Liste in das script reinladen wo die streams schon drin sind? zB.:

Code:
#EXTM3U
#EXTINF:-1 tvg-name="Das Erste HD" tvg-id="ARD.de" group-title="Vollprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/daserstehd.png",Das Erste HD
https://daserstehdde-lh.akamaihd.net/i/daserstehd_de@629196/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="ZDF HD" tvg-id="ZDF.de" group-title="Vollprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/zdfhd.png",ZDF HD
https://zdf1314-lh.akamaihd.net/i/de14_v1@392878/index_3096_av-b.m3u8
#EXTINF:-1 tvg-name="3sat" tvg-id="3sat.de" group-title="Vollprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/3sat.png",3sat
https://zdf0910-lh.akamaihd.net/i/dach10_v1@392872/index_1496_av-p.m3u8
#EXTINF:-1 tvg-name="ARTE HD" tvg-id="ARTE.de" group-title="Vollprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/artehd.png",ARTE HD
https://artelive-lh.akamaihd.net/i/artelive_de@393591/index_1_av-b.m3u8
#EXTINF:-1 tvg-name="ServusTV HD" tvg-id="ServusHD.de" group-title="Spartenprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/servustvhd.png",ServusTV HD
https://liveservustv-i.akamaihd.net/hls/live/271000/ServusTV_DE/master_rtz2192.m3u8
#EXTINF:-1 tvg-name="Welt der Wunder" tvg-id="WeltDerWunder.de" group-title="Spartenprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/weltderwunder.png",Welt der Wunder
http://live.vidoo.de/live/weltderwunder/master.m3u8
#EXTINF:-1 tvg-name="ARD-alpha" tvg-id="ARD-alpha.de" group-title="Spartenprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ardalpha.png",ARD-alpha
https://brlive-lh.akamaihd.net/i/bralpha_germany@119899/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="one HD" tvg-id="One.de" group-title="Spartenprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/onehd.png",one HD
http://onelivestream-lh.akamaihd.net/i/one_livestream@568814/index_7_av-p.m3u8
#EXTINF:-1 tvg-name="ZDFneo" tvg-id="ZDFneo.de" group-title="Spartenprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/zdfneo.png",ZDFneo
https://zdf1314-lh.akamaihd.net/i/de13_v1@392877/index_3096_av-b.m3u8
#EXTINF:-1 tvg-name="ZDFinfo" tvg-id="ZDFinfo.de" group-title="Spartenprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/zdfinfo.png",ZDFinfo
http://zdf1112-lh.akamaihd.net/i/de12_v1@392882/index_3096_av-p.m3u8
#EXTINF:-1 tvg-name="ANIXE HD" tvg-id="AnixeSerie.de" group-title="Spartenprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/anixehd.png",ANIXE HD
http://video1.anixehd.tv:8080/Apple/wifistream.m3u8
#EXTINF:-1 tvg-name="blizz TV" tvg-id="Blizz.de" group-title="Filme / Serien" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/blizztv.png",blizz TV
http://familytvblizz-lh.akamaihd.net/i/familytv_1@458351/master.m3u8
#EXTINF:-1 tvg-name="Family TV" tvg-id="FamilyTV.de" group-title="Filme / Serien" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/familytv.png",Family TV
http://familytvblizz-lh.akamaihd.net/i/blizzlive_1@36699/index_500_av-p.m3u8
#EXTINF:-1 tvg-name="eoTV HD" tvg-id="RiC.de" group-title="Filme / Serien" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/eotvhd.png",eoTV HD
http://cdn-europe.smartcast.de:1935/eotvhd/eotvhd/playlist.m3u8
#EXTINF:-1 tvg-name="RiC / eoTV" tvg-id="RiC.de" group-title="Filme / Serien;Kinder / Jugend" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ric.png",RiC / eoTV
https://58b42f6c8c9bf.streamlock.net/live/rictv/playlist.m3u8
#EXTINF:-1 tvg-name="KiKA" tvg-id="Kika.de" group-title="Kinder / Jugend" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/kika.png",KiKA
https://kikade-lh.akamaihd.net/i/livetvkika_de@450035/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="Nickelodeon" tvg-id="Nick.de" group-title="Kinder / Jugend" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/nickelodeon.png",Nickelodeon
http://unilivemtveu-lh.akamaihd.net/i/nickde_1@448749/index_3500_av-b.m3u8
#EXTINF:-1 tvg-name="MTV Germany" tvg-id="MTVGermany.de" group-title="Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/mtvgermany.png",MTV Germany
http://unilivemtveu-lh.akamaihd.net/i/mtvde_1@134922/index_3500_av-p.m3u8
#EXTINF:-1 tvg-name="DELUXE MUSIC" tvg-id="DeLuxeMusic.de" group-title="Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/deluxemusic.png",DELUXE MUSIC
http://streaming-02.mivitec.net/live/smil:test.smil/playlist.m3u8
xxx text mußte gekürzt werden xxx
#EXTINF:-1 tvg-name="WDR Event 4" tvg-id="WDREvent4.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/wdr.png",WDR Event 4
http://wdr_event4-lh.akamaihd.net/i/wdrevent4_weltweit@112054/index_1_av-p.m3u8
#EXTINF:-1 tvg-name="SWR Event 1" tvg-id="SWREvent1.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/swr.png",SWR Event 1
http://swr_event01_uni-lh.akamaihd.net/i/swr_event01@112805/index_3584_av-p.m3u8
#EXTINF:-1 tvg-name="SWR Event 2" tvg-id="SWREvent2.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/swr.png",SWR Event 2
http://swr_event02_uni-lh.akamaihd.net/i/swr_event02@112806/index_3584_av-p.m3u8
#EXTINF:-1 tvg-name="SWR Event 3" tvg-id="SWREvent3.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/swr.png",SWR Event 3
http://swr_event03_uni-lh.akamaihd.net/i/swr_event03@198168/index_3584_av-p.m3u8
#EXTINF:-1 tvg-name="SWR Event 4" tvg-id="SWREvent4.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/swr.png",SWR Event 4
http://swr_event04_uni-lh.akamaihd.net/i/swr_event04@198169/index_3584_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Event 1" tvg-id="NDREvent1.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Event 1
http://ndr_events-lh.akamaihd.net/i/ndrevent_1@119220/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Event 2" tvg-id="NDREvent2.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Event 2
http://ndr_events-lh.akamaihd.net/i/ndrevent_2@119221/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Event 3" tvg-id="NDREvent3.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Event 3
http://ndr_events-lh.akamaihd.net/i/ndrevent_3@119222/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Spezial 1" tvg-id="NDRSpezial1.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Spezial 1
http://ndr_spezial-lh.akamaihd.net/i/spezial_1@119227/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Spezial 2" tvg-id="NDRSpezial2.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Spezial 2
http://ndr_spezial-lh.akamaihd.net/i/spezial_2@119228/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Spezial 3" tvg-id="NDRSpezial3.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Spezial 3
http://ndr_spezial-lh.akamaihd.net/i/spezial_3@119229/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Spezial 4" tvg-id="NDRSpezial4.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Spezial 4
http://ndr_spezial-lh.akamaihd.net/i/spezial_4@119230/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Spezial 5" tvg-id="NDRSpezial5.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Spezial 5
http://ndr_spezial-lh.akamaihd.net/i/spezial_5@384495/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="NDR Spezial 6" tvg-id="NDRSpezial6.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/ndr.png",NDR Spezial 6
http://ndr_spezial-lh.akamaihd.net/i/spezial_6@364638/index_3776_av-p.m3u8
#EXTINF:-1 tvg-name="BR Event 1" tvg-id="BREvent1.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/br.png",BR Event 1
http://brevent1hds-lh.akamaihd.net/i/br_event01isma@86390/index_1_av-p.m3u8
#EXTINF:-1 tvg-name="BR Event 2" tvg-id="BREvent2.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/br.png",BR Event 2
http://brevent1hds-lh.akamaihd.net/i/br_event02isma@111248/index_1_av-p.m3u8
#EXTINF:-1 tvg-name="BR Event 3" tvg-id="BREvent3.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/br.png",BR Event 3
http://brevent1hds-lh.akamaihd.net/i/br_event03isma@111249/index_1_av-p.m3u8
#EXTINF:-1 tvg-name="BR Event 4" tvg-id="BREvent4.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/br.png",BR Event 4
http://brevent1hds-lh.akamaihd.net/i/br_event04isma@111250/index_1_av-b.m3u8
#EXTINF:-1 tvg-name="MDR+ 1" tvg-id="MDRPlus1.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/mdr.png",MDR+ 1
http://liveevent1.mdr.de/i/livetvmdrevent1_ww@106904/index_3871_av-p.m3u8
#EXTINF:-1 tvg-name="MDR+ 2" tvg-id="MDRPlus2.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/mdr.png",MDR+ 2
http://liveevent2.mdr.de/i/livetvmdrevent2_ww@106905/index_3871_av-p.m3u8
#EXTINF:-1 tvg-name="MDR+ 3" tvg-id="MDRPlus3.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/mdr.png",MDR+ 3
http://liveevent2.mdr.de/i/livetvmdrevent3_ww@106905/index_3871_av-p.m3u8
#EXTINF:-1 tvg-name="HR Event 1" tvg-id="HREvent1.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/hr.png",HR Event 1
http://hrevent-lh.akamaihd.net/i/hr_event@309239/master.m3u8
#EXTINF:-1 tvg-name="HR Event 2" tvg-id="HREvent2.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/hr.png",HR Event 2
http://hrevent2-lh.akamaihd.net/i/hr_event2@309240/master.m3u8
#EXTINF:-1 tvg-name="rbb Event 1" tvg-id="RBBEvent1.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/rbb.png",rbb Event 1
http://rbbevent01-lh.akamaihd.net/i/rbbevent01_nongeo@22155/index_2692_av-p.m3u8
#EXTINF:-1 tvg-name="rbb Event 2" tvg-id="RBBEvent2.de" group-title="Extra" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/rbb.png",rbb Event 2
https://rbbevent02-lh.akamaihd.net/i/rbbevent02_nongeo@22197/index_2692_av-p.m3u8
#EXTINF:-1 tvg-name="Parlamentsfernsehen 1" tvg-id="" group-title="Extra;Information / Bildung" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/parlamentsfernsehen.png",Parlamentsfernsehen 1
https://c13014-l-hls.u.core.cdn.streamfarm.net/1000153copo/hk1.m3u8
#EXTINF:-1 tvg-name="Parlamentsfernsehen 2" tvg-id="" group-title="Extra;Information / Bildung" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/parlamentsfernsehen.png",Parlamentsfernsehen 2
https://c13014-l-hls.u.core.cdn.streamfarm.net/1000153copo/hk2.m3u8
#EXTINF:-1 tvg-name="DJing" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing
https://www.djing.com/tv/live.m3u8
#EXTINF:-1 tvg-name="DJing Animation" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Animation
https://www.djing.com/tv/animation.m3u8
#EXTINF:-1 tvg-name="DJing Classics" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Classics
https://www.djing.com/tv/hits.m3u8
#EXTINF:-1 tvg-name="DJing Electro Rock" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Electro Rock
https://www.djing.com/tv/session_electro-rock.m3u8
#EXTINF:-1 tvg-name="DJing French touch" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing French touch
https://www.djing.com/tv/session_french-touch.m3u8
#EXTINF:-1 tvg-name="DJing Hedonist" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Hedonist
https://www.djing.com/tv/session_hedonist.m3u8
#EXTINF:-1 tvg-name="DJing Hot Hot Hot" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Hot Hot Hot
https://www.djing.com/tv/h-01-fta.m3u8
#EXTINF:-1 tvg-name="DJing Ibiza" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Ibiza
https://www.djing.com/tv/dancefloor.m3u8
#EXTINF:-1 tvg-name="DJing Karaoke" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Karaoke
https://www.djing.com/tv/karaoke.m3u8
#EXTINF:-1 tvg-name="DJing Summer Vibes" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Summer Vibes
https://www.djing.com/tv/session_summer-vibes.m3u8
#EXTINF:-1 tvg-name="DJing Underground" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Underground
https://www.djing.com/tv/underground.m3u8
#EXTINF:-1 tvg-name="DJing Wild EDM" tvg-id="" group-title="Extra;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/djing.png",DJing Wild EDM
http://www.djing.com/tv/session_wild-edm.m3u8
#EXTINF:-1 tvg-name="ServusTV HD (AT)" tvg-id="ServusTV.at" group-title="International;Spartenprogramm" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/servustvhd.png",ServusTV HD (AT)
http://hdiosstv-f.akamaihd.net/i/servustvhd_1@51229/index_2592_av-p.m3u8
#EXTINF:-1 tvg-name="gotv" tvg-id="Gotv.at" group-title="International;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/gotv.png",gotv
http://nstream17.gotv.at:1938/live/gotvlive_576p/playlist.m3u8
#EXTINF:-1 tvg-name="Okto" tvg-id="OKTO.at" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/okto.png",Okto
https://d2jk87psbjrjdz.cloudfront.net/livehttporigin/okto/playlist.m3u8
#EXTINF:-1 tvg-name="ORF eins HD" tvg-id="ORF1.at" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/orf1hd.png",ORF eins HD
https://orf1.cdn.ors.at/out/u/orf1/qxb/manifest_6.m3u8
#EXTINF:-1 tvg-name="ORF 2 HD" tvg-id="ORF2.at" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/orf2hd.png",ORF 2 HD
https://orf2.cdn.ors.at/out/u/orf2/qxb/manifest_6.m3u8
#EXTINF:-1 tvg-name="ORF III HD" tvg-id="ORF3.at" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/orf3hd.png",ORF III HD
https://orf3.cdn.ors.at/out/u/orf3/qxb/manifest_6.m3u8
#EXTINF:-1 tvg-name="ORF SPORT +" tvg-id="ORFSport.at" group-title="International;Sport" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/orfsportplushd.png",ORF SPORT +
https://orfs.cdn.ors.at/out/u/orfs/qxb/manifest_6.m3u8
#EXTINF:-1 tvg-name="dorf tv" tvg-id="" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/dorftv.png",dorf tv
https://stream.openplayout.org/hls/dorf_high/index.m3u8
#EXTINF:-1 tvg-name="RE eins TV" tvg-id="" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/reeins.png",RE eins TV
http://www.reeins.tv:1935/live/re1/playlist.m3u8
#EXTINF:-1 tvg-name="Tirol TV" tvg-id="" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/tiroltv.png",Tirol TV
http://lb.hd-livestream.de:1935/live/TirolTV/playlist.m3u8
#EXTINF:-1 tvg-name="oe24 TV" tvg-id="" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/oe24tv.png",oe24 TV
http://apasfoe24l.sf.apa.at/ipad/oe24-live1/oe24.sdp/playlist.m3u8
#EXTINF:-1 tvg-name="M4TV" tvg-id="" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/m4tv.png",M4TV
http://streaming.austria24.tv/live/stream_720p/playlist.m3u8
#EXTINF:-1 tvg-name="W24 TV" tvg-id="W24.at" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/w24.png",W24 TV
http://ms02.w24.at/hls-live/livepkgr/_definst_/liveevent/livestream3.m3u8
#EXTINF:-1 tvg-name="Kronehit TV" tvg-id="" group-title="International;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/kronehittv.png",Kronehit TV
https://bitcdn-kronehit.bitmovin.com/v2/hls/chunklist_b3128000.m3u8
#EXTINF:-1 tvg-name="Sporttime TV 1" tvg-id="" group-title="International;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/sporttimetv.png",Sporttime TV 1
http://sporttimelive1.content-cdn.net/livechannel1/smil:switch1.smil/playlist.m3u8?wowzatokenhash=sUTjnxXLdal6Y8bBzs9an_zhqn7VrgWUS5uB8sckoCw=
#EXTINF:-1 tvg-name="Sporttime TV 2" tvg-id="" group-title="International;Sport" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/sporttimetv.png",Sporttime TV 2
http://sporttimelive1.content-cdn.net/livechannel2/smil:switch2.smil/playlist.m3u8?wowzatokenhash=qgtY96D77QocQoiJn6MCsyHbBMGla2uQoQ03XvQYkuE=
#EXTINF:-1 tvg-name="Sporttime TV 4" tvg-id="" group-title="International;Information / Bildung" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/sporttimetv.png",Sporttime TV 4
http://sporttimelive1.content-cdn.net/livechannel4/smil:switch4.smil/playlist.m3u8?wowzatokenhash=BhYr7Qu4cZ8LgxWiF7cuQ_hA7sxqdon5Kw0sIHJ7TpM=
#EXTINF:-1 tvg-name="Sporttime TV 5" tvg-id="" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/sporttimetv.png",Sporttime TV 5
http://live.earthtv.com:1935/edge27/TWLDE/playlist.m3u8?58a36274bbf047f6c3b5cdb1
#EXTINF:-1 tvg-name="TeleZüri HD" tvg-id="TeleZuri.ch" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/telezueri.png",TeleZüri HD
https://klive-a.akamaihd.net/dc-1/live/hls/p/1719221/e/1_hoislpiz/sd/10000/t/AFb4DZ0W2ts1a8fV5xo1VQ/index-s32.m3u8
#EXTINF:-1 tvg-name="TeleBärn HD" tvg-id="" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/telebaern.png",TeleBärn HD
http://klive-a.akamaihd.net/dc-1/live/hls/p/1719221/e/1_0mc3z57p/sd/10000/t/XTGwenpKUhx_fbVnsiu9MQ/index-s32.m3u8
#EXTINF:-1 tvg-name="Tele M1 HD" tvg-id="TeleM1.ch" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/telem1.png",Tele M1 HD
http://klive-a.akamaihd.net/dc-1/live/hls/p/1719221/e/1_ljzy3evp/sd/10000/t/nwOKUovT2mwnA8x_KnC4zg/index-s32.m3u8
#EXTINF:-1 tvg-name="TVO (CH)" tvg-id="TVO.ch" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/tvo_ch.png",TVO (CH)
http://livevideo.infomaniak.com/streaming/livecast/tvo/playlist.m3u8
#EXTINF:-1 tvg-name="TeleBielingue" tvg-id="TeleBielingue.ch" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/telebielingue.png",TeleBielingue
http://livevideo.infomaniak.com/streaming/livecast/telebielinguech/playlist.m3u8
#EXTINF:-1 tvg-name="TVM3" tvg-id="TVM3.ch" group-title="International;Musik" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/tvm3.png",TVM3
https://tvm3.vedge.infomaniak.com/livecast/tvm3/playlist.m3u8
#EXTINF:-1 tvg-name="Telebasel" tvg-id="" group-title="International" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/telebasel.png",Telebasel
http://xapp510394368c1000199.f.l.z.lb.core-cdn.net/10096xtelebase/ios_500/master.m3u8
#EXTINF:-1 tvg-name="ABC News" tvg-id="" group-title="International;Nachrichten" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/abcnews.png",ABC News
https://abclive1-lh.akamaihd.net/i/abc_live04@423398/index_4000_av-b.m3u8
#EXTINF:-1 tvg-name="Adult Swim" tvg-id="" group-title="International;Comedy" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/adultswim.png",Adult Swim
http://adultswimhls-i.akamaihd.net/hls/live/238460/adultswim/main/1/master.m3u8
#EXTINF:-1 tvg-name="JUCE TV" tvg-id="" group-title="International;Religion;Kinder / Jugend" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/jucetv.png",JUCE TV
http://acaooyalahd2-lh.akamaihd.net/i/TBN03_delivery@186241/index_1728_av-p.m3u8
#EXTINF:-1 tvg-name="NASA TV" tvg-id="NASA.us" group-title="International;Information / Bildung" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/nasatv.png",NASA TV
https://nasa-i.akamaihd.net/hls/live/253565/NASA-NTV1-Public/master.m3u8
#EXTINF:-1 tvg-name="CBSN" tvg-id="" group-title="International;Nachrichten" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/cbsn.png",CBSN
https://cbsnhls-i.akamaihd.net/hls/live/264710/CBSN_mdialog/prodstream/master_2200.m3u8
#EXTINF:-1 tvg-name="CBN News" tvg-id="" group-title="International;Nachrichten" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/cbnnews.png",CBN News
http://bcliveuniv-lh.akamaihd.net/i/news_1@194050/index_900_av-b.m3u8
#EXTINF:-1 tvg-name="Bloomberg TV" tvg-id="Bloomberg.nws" group-title="International;Wirtschaft" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/tv/bloombergtv.png",Bloomberg TV
xxx text gekürzt xxx
#EXTINF:-1 tvg-name="DELUXE CHEFSESSEL by WAGNER" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deluxeradio.png",DELUXE CHEFSESSEL by WAGNER
https://deluxe-radio.mivitec.net:8443/0011
#EXTINF:-1 tvg-name="DELUXE EASY" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deluxeeasy.png",DELUXE EASY
https://deluxe-radio.mivitec.net:8443/0009
#EXTINF:-1 tvg-name="DELUXE LOUNGE RADIO" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deluxeloungeradio.png",DELUXE LOUNGE RADIO
https://deluxe-radio.mivitec.net:8443/0010
#EXTINF:-1 tvg-name="DELUXE MUSIC RADIO" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deluxemusicradio.png",DELUXE MUSIC RADIO
https://deluxe-radio.mivitec.net:8443/0005
#EXTINF:-1 tvg-name="DELUXE NEW ARRIVALS" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deluxeradio.png",DELUXE NEW ARRIVALS
https://deluxe-radio.mivitec.net:8443/0006
#EXTINF:-1 tvg-name="DELUXE TOP 25" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deluxeradio.png",DELUXE TOP 25
https://deluxe-radio.mivitec.net:8443/0008
#EXTINF:-1 tvg-name="Deutschlandfunk" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deutschlandfunk.png",Deutschlandfunk
http://st01.dlf.de/dlf/01/128/mp3/stream.mp3
#EXTINF:-1 tvg-name="Deutschlandfunk Kultur" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deutschlandfunkkultur.png",Deutschlandfunk Kultur
http://st02.dlf.de/dlf/02/128/mp3/stream.mp3
#EXTINF:-1 tvg-name="Deutschlandfunk Nova" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deutschlandfunknova.png",Deutschlandfunk Nova
http://st03.dlf.de/dlf/03/128/mp3/stream.mp3
#EXTINF:-1 tvg-name="Deutschlandradio Dokumente und Debatten" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deutschlandradiodud.png",Deutschlandradio Dokumente und Debatten
http://st04.dlf.de/dlf/04/128/mp3/stream.mp3
#EXTINF:-1 tvg-name="DIE NEUE 107.7" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/dieneue1077.png",DIE NEUE 107.7
http://dieneue1077.cast.addradio.de/dieneue1077/simulcast/high/stream.mp3
#EXTINF:-1 tvg-name="DISCO DELUXE" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deluxeradio.png",DISCO DELUXE
https://deluxe-radio.mivitec.net:8443/0003
#EXTINF:-1 tvg-name="domradio.de" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/domradiode.png",domradio.de
http://domradio-mp3-l.akacast.akamaistream.net/7/809/237368/v1/gnl.akacast.akamaistream.net/domradio-mp3-l
#EXTINF:-1 tvg-name="DONAU 3 FM" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/donau3fm.png",DONAU 3 FM
http://mp3.donau3fm.c.nmdn.net/donau3fm/live.mp3
#EXTINF:-1 tvg-name="egoFM" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/egofm.png",egoFM
http://mp3ad.egofm.c.nmdn.net/ps-egofm_192/livestream.mp3
#EXTINF:-1 tvg-name="ERF Plus" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/erfplus.png",ERF Plus
http://c14000-l.i.core.cdn.streamfarm.net/14000cina/live/3212erf_96/live_de_96.mp3
#EXTINF:-1 tvg-name="ERF Pop" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/erfpop.png",ERF Pop
http://c14000-l.i.core.cdn.streamfarm.net/14000cina/live/2908erfpop/live_de_96.mp3
#EXTINF:-1 tvg-name="FluxFM" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/fluxfm.png",FluxFM
http://streams.fluxfm.de/live/mp3-320/audio/
#EXTINF:-1 tvg-name="Fritz" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/fritz.png",Fritz
http://rbb-fritz-live.cast.addradio.de/rbb/fritz/live/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="harmony.fm" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/harmonyfm.png",harmony.fm
http://mp3ad.harmony.c.nmdn.net/fs_harmonyfm/hqlivestream.mp3
#EXTINF:-1 tvg-name="HIT RADIO FFH" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/hitradioffh.png",HIT RADIO FFH
http://mp3.ffh.de/radioffh/hqlivestream.mp3
#EXTINF:-1 tvg-name="hr-info" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/hrinfo.png",hr-info
http://hr-hrinfo-live.cast.addradio.de/hr/hrinfo/live/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="hr1" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/hr1.png",hr1
http://hr-hr1-live.cast.addradio.de/hr/hr1/live/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="hr2-kultur" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/hr2kultur.png",hr2-kultur
http://hr-hr2-live.cast.addradio.de/hr/hr2/live/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="hr3" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/hr3.png",hr3
http://hr-hr3-live.cast.addradio.de/hr/hr3/live/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="hr4" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/hr4.png",hr4
http://hr-hr4-live.cast.addradio.de/hr/hr4/live/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="JAM FM" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/jamfm.png",JAM FM
http://stream.jam.fm/jamfm-live/mp3-128/konsole/
#EXTINF:-1 tvg-name="JAM FM Black Label" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/jamfm.png",JAM FM Black Label
http://stream.jam.fm/jamfm-bl/mp3-128/konsole/
#EXTINF:-1 tvg-name="JAM FM New Music Radio" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/jamfm.png",JAM FM New Music Radio
http://stream.jam.fm/jamfm-nmr/mp3-128/konsole/
#EXTINF:-1 tvg-name="JUKEBOX RADIO" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/deluxeradio.png",JUKEBOX RADIO
https://deluxe-radio.mivitec.net:8443/0004
#EXTINF:-1 tvg-name="KiRaKa" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/kiraka.png",KiRaKa
http://wdr-kiraka-live.icecast.wdr.de/wdr/kiraka/live/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="KULTRADIO" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/kultradio.png",KULTRADIO
http://ice.kultradio.fm/kult128.mp3
#EXTINF:-1 tvg-name="LandesWelle Thüringen" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/landeswellethueringen.png",LandesWelle Thüringen
http://stream.landeswelle.de/lwt/mp3-192
#EXTINF:-1 tvg-name="MDR AKTUELL" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/mdraktuell.png",MDR AKTUELL
http://mdr-284340-0.cast.mdr.de/mdr/284340/0/mp3/high/stream.mp3
#EXTINF:-1 tvg-name="MDR JUMP" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/mdrjump.png",MDR JUMP
http://mdr-284320-0.cast.mdr.de/mdr/284320/0/mp3/high/stream.mp3
#EXTINF:-1 tvg-name="MDR KLASSIK" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/mdrklassik.png",MDR KLASSIK
http://mdr-284350-0.cast.mdr.de/mdr/284350/0/mp3/high/stream.mp3
#EXTINF:-1 tvg-name="MDR KULTUR" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/mdrkultur.png",MDR KULTUR
http://mdr-284310-0.cast.mdr.de/mdr/284310/0/mp3/high/stream.mp3
#EXTINF:-1 tvg-name="MDR SACHSEN" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/mdrsachsen.png",MDR SACHSEN
http://mdr-284280-0.cast.mdr.de/mdr/284280/0/mp3/high/stream.mp3
#EXTINF:-1 tvg-name="MDR SPUTNIK" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/mdrsputnik.png",MDR SPUTNIK
http://mdr-284330-0.cast.mdr.de/mdr/284330/0/mp3/high/stream.mp3
#EXTINF:-1 tvg-name="MDR THÜRINGEN" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/mdrthueringen.png",MDR THÜRINGEN
http://mdr-284300-0.cast.mdr.de/mdr/284300/0/mp3/high/stream.mp3
#EXTINF:-1 tvg-name="multicult.fm" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/multicultfm.png",multicult.fm
http://stream.multicult.fm:8000/hifi
#EXTINF:-1 tvg-name="N-JOY" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/njoy.png",N-JOY
http://ndr-njoy-live.cast.addradio.de/ndr/njoy/live/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="NDR 1 Niedersachsen" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/ndr1niedersachsen.png",NDR 1 Niedersachsen
http://ndr-ndr1niedersachsen-hannover.cast.addradio.de/ndr/ndr1niedersachsen/hannover/mp3/128/stream.mp3
#EXTINF:-1 tvg-name="Radio 538 Hitzone" group-title="Niederlande" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radio538.png",Radio 538 Hitzone
http://vip-icecast.538.lw.triple-it.nl/WEB11_MP3
#EXTINF:-1 tvg-name="Radio 538 Ibiza" group-title="Niederlande" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radio538.png",Radio 538 Ibiza
http://vip-icecast.538.lw.triple-it.nl/WEB19_MP3
#EXTINF:-1 tvg-name="Radio 538 Non-Stop" group-title="Niederlande" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radio538.png",Radio 538 Non-Stop
http://vip-icecast.538.lw.triple-it.nl/WEB09_MP3
#EXTINF:-1 tvg-name="Radio 538 Party" group-title="Niederlande" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radio538.png",Radio 538 Party
http://vip-icecast.538.lw.triple-it.nl/WEB16_MP3
#EXTINF:-1 tvg-name="Radio 538 Top 40 Radio" group-title="Niederlande" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radio538.png",Radio 538 Top 40 Radio
http://vip-icecast.538.lw.triple-it.nl/WEB02_MP3
#EXTINF:-1 tvg-name="Radio 538 Verrückte Stunde" group-title="Niederlande" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radio538.png",Radio 538 Verrückte Stunde
http://vip-icecast.538.lw.triple-it.nl/WEB21_MP3
#EXTINF:-1 tvg-name="Radio Veronica" group-title="Niederlande" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radioveronica.png",Radio Veronica
http://playerservices.streamtheworld.com/api/livestream-redirect/VERONICA.mp3
#EXTINF:-1 tvg-name="Sky Radio 101 FM" group-title="Niederlande" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/skyradio101fm.png",Sky Radio 101 FM
http://playerservices.streamtheworld.com/api/livestream-redirect/SKYRADIO.mp3
#EXTINF:-1 tvg-name="Planeta FM" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/planetafm.png",Planeta FM
http://pla01.cdn.eurozet.pl:8700/pla-net.mp3
#EXTINF:-1 tvg-name="Planeta FM Dope Hits" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/planetafm.png",Planeta FM Dope Hits
http://pla02.cdn.eurozet.pl:8208/PLAHOU.mp3
#EXTINF:-1 tvg-name="Planeta FM Electronic Wave" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/planetafm.png",Planeta FM Electronic Wave
http://pla02.cdn.eurozet.pl:8228/PLAEDM.mp3
#EXTINF:-1 tvg-name="Planeta FM Good Vibes" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/planetafm.png",Planeta FM Good Vibes
http://pla01.cdn.eurozet.pl:8204/PLACHI.mp3
#EXTINF:-1 tvg-name="Planeta FM Indie Day Mood" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/planetafm.png",Planeta FM Indie Day Mood
http://pla02.cdn.eurozet.pl:8230/PLAIDM.mp3
#EXTINF:-1 tvg-name="Radio ZET" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET
http://n-4-14.dcs.redcdn.pl/sc/o2/Eurozet/live/audio.livx?audio=5
#EXTINF:-1 tvg-name="Radio ZET 2000" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET 2000
http://zet.cdn.eurozet.pl/ZET200.mp3
#EXTINF:-1 tvg-name="Radio ZET 80" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET 80
http://zet.cdn.eurozet.pl/ZET080.mp3
#EXTINF:-1 tvg-name="Radio ZET 90" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET 90
http://zet.cdn.eurozet.pl/ZET090.mp3
#EXTINF:-1 tvg-name="Radio ZET Dance" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET Dance
http://zet.cdn.eurozet.pl/ZETDAN.mp3
#EXTINF:-1 tvg-name="Radio ZET Hits" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET Hits
http://zet.cdn.eurozet.pl/ZETHIT.mp3
#EXTINF:-1 tvg-name="Radio ZET Hot" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET Hot
http://zet.cdn.eurozet.pl/ZETHOT.mp3
#EXTINF:-1 tvg-name="Radio ZET Party" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET Party
http://zet.cdn.eurozet.pl/ZETPAR.mp3
#EXTINF:-1 tvg-name="Radio ZET PL" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET PL
http://zet.cdn.eurozet.pl/ZETPL1.mp3
#EXTINF:-1 tvg-name="Radio ZET Rock" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/radiozet.png",Radio ZET Rock
http://zet.cdn.eurozet.pl/ZETROK.mp3
#EXTINF:-1 tvg-name="RMF FM" group-title="Polen" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/rmffm.png",RMF FM
http://195.150.20.243/RMFFM48

sprich das er die in dem falle nicht online erst holen muß? Würde der denn auch nur Audio aufnehmen können? Da ich da ein paar radio sender auch mit reingepackt habe...

Das Zweite wäre wenn der ffmpeg nicht gehen "würde" das man den auch local daneben im Ordner runtergeladen hat, das er dann das in dem Ordner nutzen könnte?

MfG
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
@DukeMan999:

Also, zum Punkt, lokale FFmpeg Kopie, geht. Mp3 Streams, geht auch, wenn die URL funktioniert. Da gibt es keinen Test oder eine Warnung ob ein Video/Radiostream verfügbar ist oder nicht. Das hängt von der Playliste ab.

Nutzung:
[kw]python3 rec.py -localLOCALE_PLAYLIST.m3u8[/kw]

Hier wird die lokale Playliste "LOCALE_PLAYLIST.m3u8" geladen und auch später bei Aufnahme geladen. Dabei werden Radiosender mit "(Radio)" gekennzeichnet, so fern es sich um einen Radiosender handelt. Die Erkennung hängt von der m3u8 Parameter - radio="true" - ab. Diese werden als ".mp3" gespeichert.

Ansonsten arbeitet das Skript wie gehabt.

Um eine andere FFmpeg Version zu nehmen, außer die auf dem System installierte, kann man das wie folgt in einen Parameter eingeben:
[src=python]FFMPEG_DIRECTORY = 'ffmpeg' # OR PATH: /home/username/path_to_ffmpeg/./ffmpeg OR leave 'ffmpeg' for general ffmpeg usage from system[/src]

Es kann sein das, wenn der Pfad angegeben wird zu FFMpeg - das "chmod +x" für die Datei gesetzt werden muss. Und auch wichtig das: "./ffmpeg" - damit diese Version ausgeführt wird.

Fragen? :unknown:

PS: Ich habe ebenfalls die "timeout" rausgenommen, das gab öfter Probleme, also daher der Standardwert dafür.

Code:
[src=python]#!/usr/bin/env python3
import sys
import time
import glob
import subprocess
import os.path
import os

import pycurl

USE_AT = True
PLAYLIST_URL = ".m3u8"
USER_AGENT = "Your custom useragent"
FFMPEG_DIRECTORY = 'ffmpeg' # OR PATH: /home/username/path_to_ffmpeg/./ffmpeg OR leave 'ffmpeg' for general ffmpeg usage from system
#FFMPEG_DIRECTORY = '/home/username/ffmpeg_4.1.4-1+b2_amd64/./ffmpeg' # example

APP_FOLDER = os.getcwd()

PLAYLIST_FILE = "streamTempSave.m3u8" # This is just a temporary storage for the downloaded playlist, but this file wont be removed by itself
PLAYLIST_DATA = ""
PLAYLIST_CHANNELS = {}
RECORDING_NAME = ""
RECORDING_CHANNEL_NAME = ""
RECORDING_CHANNEL_URL = ""
RECORDING_TIME = 0
RECORDING_DURATION = 0

def downloadPlaylist(downloadURL):
playlistFile = open(PLAYLIST_FILE, "wb")

print('Starting download of URI: \'%s\'\n' % downloadURL)
c = pycurl.Curl()
c.setopt(pycurl.URL, downloadURL)
c.setopt(pycurl.USERAGENT, USER_AGENT)
c.setopt(pycurl.VERBOSE, False)
c.setopt(pycurl.ENCODING, 'utf-8')
c.setopt(pycurl.WRITEDATA, playlistFile)
c.setopt(pycurl.NOPROGRESS, True)
c.setopt(pycurl.TIMEOUT, 30)

try:
c.perform()
print("\nSuccessfully downloaded playlist.\n")
playlistFile.close()
c.close()
return True
except Exception as error:
playlistFile.close()
c.close()
print("Encountered an error:")
raise error
return False



def getStreamSelection():
global PLAYLIST_CHANNELS, RECORDING_CHANNEL_NAME, RECORDING_CHANNEL_URL

playlistFile = open(PLAYLIST_FILE, "r")
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
currentChannel = line.split(',',2)[1].rstrip().rstrip('"').replace('tvg-name="', '')
if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = line
currentChannel = None

sortedChannels = sorted(PLAYLIST_CHANNELS.keys())

print("\nChannel selection:")
for index, channel in enumerate(sortedChannels):
print("%2d - %s" % (index, channel))

print("x - Exit")

print("\n")

while True:
channelNum = input("\nInput channel number for grabbing: ")
if channelNum.lower() == "x":
exit(0)
else:
try:
RECORDING_CHANNEL_URL = PLAYLIST_CHANNELS[sortedChannels[int(channelNum)]].rstrip()
RECORDING_CHANNEL_NAME = sortedChannels[int(channelNum)]

print("Selected recording channel: %s" % (sortedChannels[int(channelNum)]))
isValidSelection = input('Is the channel correct Y/N? ')
if isValidSelection.lower() == "y":
return True
else:
continue

except Exception:
print('Wrong channel selection. Enter a channel number or "x" to exit.')
continue
break


if __name__ == "__main__":
hasPlaylist = False
ISWEBDL = False
if len(sys.argv) == 1:
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
ISWEBDL = True
print("Playlist succesfully downloaded.\n")
else:
print('Cannot download playlist "%s"' %(PLAYLIST_URL))
exit(1)
else:
for opt in sys.argv:
if opt.startswith('-local'):
playlistName = opt.replace('-local', '', 1)
if os.path.exists(playlistName):
print('Using local playlist: %s' % (playlistName))
PLAYLIST_FILE = playlistName
hasPlaylist = True
ISWEBDL = False
else:
print('Playlist not found using name "%s": ' %(playlistName))
exit(1)


if hasPlaylist and getStreamSelection():
print('\nIt\'s time to enter the date and time for the recording:')
while True:
while True:
recordDate = input('\nEnter record date for recording, in format day.month.year, for example: 7.8.2019 or "x" to cancel, enter nothing for todays date.\n')
if recordDate.lower() == 'x':
print("Cancelled")
exit(1)

elif len(recordDate) == 0:
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")
recordDay = timeNow.tm_mday
recordMonth = timeNow.tm_mon
recordYear = timeNow.tm_year

print("Record date: %02d.%02d.%d " %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year))
if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break

elif recordDate.count('.') == 2:
recordDay, recordMonth, recordYear = map(int, recordDate.split('.', 3))
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")

try:
timestampRecord = time.strptime("%d.%d.%d 00:00:00" %(recordDay, recordMonth, recordYear), "%d.%m.%Y %H:%M:%S")
except ValueError:
print('Date input does not match, use day.month.year as: 7.8.2019')
continue

if time.mktime(timestampNow) > time.mktime(timestampRecord):
print("Date is in the past. Repeat input.")
else:
print("Record date: %02d.%02d.%d " %(recordDay, recordMonth, recordYear))

if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break
else:
print("Invalid date input.")
continue

while True:
recordTime = input('\nEnter time to start recording, in format hour:minute, for example: 14:00 for 14 o\'clock, "x" to cancel\n')
if recordTime.lower() == 'x':
print("Cancelled")
exit(1)
elif recordTime.find(':') != -1:
recordHour, recordMinute = map(int, recordTime.split(':', 2))
print("Record time: %02d:%02d " %(recordHour, recordMinute))

timeNow = time.time()
timestampRecord = time.strptime("%d.%d.%d %d:%d:00" %(recordDay, recordMonth, recordYear, recordHour, recordMinute), "%d.%m.%Y %H:%M:%S")


if (timeNow > time.mktime(timestampRecord)):
print("Time is in the past. Repeat input.")
continue

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_TIME = time.mktime(timestampRecord)
break
else:
print("Invald time input.")
continue

while True:
recordDuration = input('\nEnter duration in minutes to record. For example 90 to capture 1 1/2 hours, "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)
elif int(recordDuration) < 0:
print("Negative recording duration, enter 30 for 30 minutes.")
continue

print("Record duration: %d minutes " %(int(recordDuration)))

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_DURATION = int(recordDuration)
break


while True:
RECORDING_NAME = input('\nEnter name for the recording file. Enter "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)

print("Record name: %s" % (RECORDING_NAME))
if input("Is the record name correct, Y/N ? ").lower() != 'y':
continue

break



print("\nWhat will be done?\nRecording channel \"%s\"." %(RECORDING_CHANNEL_NAME))
print("On %s at %s o'clock for %d minutes.\nRecording to file: \"%s\"" %(time.strftime("%d.%m.%Y", time.localtime(RECORDING_TIME)), time.strftime("%H:%M:%S", time.localtime(RECORDING_TIME)), RECORDING_DURATION, RECORDING_NAME))

confirm = input("\nAre all information correct, Y/N? ")
if confirm.lower() != 'y':
continue

scheduleFileName = "%d.rec" %(time.time())
with open(scheduleFileName, "w") as scheduleFile:
scheduleFile.write("%d;%d;%s;%s\n" % (RECORDING_TIME, RECORDING_DURATION, RECORDING_CHANNEL_NAME, RECORDING_NAME))

if USE_AT:
if not ISWEBDL:
scheduleCommand = 'echo "python3 %s/rec.py -ldl%s -pf%s" | at -M %s' % (APP_FOLDER, scheduleFileName, PLAYLIST_FILE, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
else:
scheduleCommand = 'echo "python3 %s/rec.py -dl%s" | at -M %s' % (APP_FOLDER, scheduleFileName, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
subprocess.Popen(scheduleCommand, shell=True)
print("Scheduled task.\nBye bye.")
exit(1)

break

print('Error writing schedule file for recording job.')

else:
hasPlaylist = False
for opt in sys.argv:
if opt.startswith('-dl'):
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
print("Playlist succesfully downloaded.\n")
else:
print("Error downloading playlist from \"%s\".\nExiting." %(PLAYLIST_URL))
exit(1)
elif opt.startswith('-pf'):
playlistName = opt.replace('-pf', '', 1)
if os.path.exists(playlistName):
print('Using local playlist: %s' %(playlistName))
PLAYLIST_FILE = playlistName
else:
print('Playlist not found using name "%s": ' % (playlistName))
exit(1)


for opt in sys.argv:
if opt.startswith('-dl'):
with open(PLAYLIST_FILE, "r") as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
currentChannel = line.split(',',2)[1].rstrip().rstrip('"').replace('tvg-name="', '')
if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = line.rstrip()
currentChannel = None

scheduleFileName = opt.replace('-dl', '', 1)
elif opt.startswith('-ldl'):
hasPlaylist = False
for subopt in sys.argv:
if subopt.startswith('-pf'):
PLAYLIST_FILE = subopt.replace('-pf', '', 1)
hasPlaylist = True
break


with open(PLAYLIST_FILE, "r") as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
currentChannel = line.split(',',2)[1].rstrip().rstrip('"').replace('tvg-name="', '')
if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = line.rstrip()
currentChannel = None

scheduleFileName = opt.replace('-ldl', '', 1)

scheduleFile = None
if os.path.exists(scheduleFileName):
scheduleData = None

with open(scheduleFileName, "r") as scheduleFile:
scheduleData = scheduleFile.read().rstrip().split(';', 4)

if scheduleData != None:
try:
channelURL = PLAYLIST_CHANNELS[scheduleData[2]]
if scheduleData[2].find(' (Radio)') != -1:
commandString = FFMPEG_DIRECTORY + " -user_agent \"%s\" -i '%s' -t %d:%d:00 '%s.mp3'" %(USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
else:
commandString = FFMPEG_DIRECTORY + " -user_agent \"%s\" -i '%s' -t %d:%d:00 -vc:copy -o '%s.mkv'" % (USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
subprocess.Popen(commandString, shell=True)
except ValueError as error:
print('No channel information found.')
raise error
[/src]
 

Anhänge

  • rec.py.zip
    3,1 KB · Aufrufe: 517
Zuletzt bearbeitet:

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #32
Hi,

jut jut, das werd ich auch mal ausprobieren... werd mal das rein editieren wenns probs gibt. Ich geb den Ordner und unterordner direkt immer alle rechte damit das script bzw python3 auch schreiben darf, nur chmod -x reichte bei den ersten Test nichts da er den stream nicht schreiben konnte/durfte!

MfG

--- [2019-09-15 20:13 CEST] Automatisch zusammengeführter Beitrag ---

Hab nu nen error bekommen:

Using local playlist: Kodi.m3u
Traceback (most recent call last):
File "rec.py", line 129, in <module>
if hasPlaylist and getStreamSelection():
File "rec.py", line 60, in getStreamSelection
data = playlistFile.readlines()
File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2064: ordinal not in range(128)
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
UTF-8 ?

Versuch mal die Zeile 60 wie folgt zu ändern:
[src=python]playlistFile = open(PLAYLIST_FILE, "r")[/src]

zu

[src=python]playlistFile = open(PLAYLIST_FILE, "r", encoding='utf-8')[/src]


Hier der komplett geänderte Code, alle Lese und Schreibfunktionen nutzen "utf-8":

Name des Skripts (muss beibehalten werden):
rec.py

[src=python]#!/usr/bin/env python3
import sys
import time
import glob
import subprocess
import os.path
import os

import pycurl

USE_AT = True
PLAYLIST_URL = ".m3u8"
USER_AGENT = "Your custom useragent"
FFMPEG_DIRECTORY = 'ffmpeg' # OR PATH: /home/username/path_to_ffmpeg/./ffmpeg OR leave 'ffmpeg' for general ffmpeg usage from system
#FFMPEG_DIRECTORY = '/home/username/ffmpeg_4.1.4-1+b2_amd64/./ffmpeg' # example

APP_FOLDER = os.getcwd()

PLAYLIST_FILE = "streamTempSave.m3u8" # This is just a temporary storage for the downloaded playlist, but this file wont be removed by itself
PLAYLIST_DATA = ""
PLAYLIST_CHANNELS = {}
RECORDING_NAME = ""
RECORDING_CHANNEL_NAME = ""
RECORDING_CHANNEL_URL = ""
RECORDING_TIME = 0
RECORDING_DURATION = 0

def downloadPlaylist(downloadURL):
playlistFile = open(PLAYLIST_FILE, 'w', encoding='utf-8')

print('Starting download of URI: \'%s\'\n' % downloadURL)
c = pycurl.Curl()
c.setopt(pycurl.URL, downloadURL)
c.setopt(pycurl.USERAGENT, USER_AGENT)
c.setopt(pycurl.VERBOSE, False)
c.setopt(pycurl.ENCODING, 'utf-8')
c.setopt(pycurl.WRITEDATA, playlistFile)
c.setopt(pycurl.NOPROGRESS, True)
c.setopt(pycurl.TIMEOUT, 30)

try:
c.perform()
print("\nSuccessfully downloaded playlist.\n")
playlistFile.close()
c.close()
return True
except Exception as error:
playlistFile.close()
c.close()
print("Encountered an error:")
raise error
return False



def getStreamSelection():
global PLAYLIST_CHANNELS, RECORDING_CHANNEL_NAME, RECORDING_CHANNEL_URL

playlistFile = open(PLAYLIST_FILE, "r", encoding="utf-8")
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
currentChannel = line.split(',',2)[1].rstrip().rstrip('"').replace('tvg-name="', '')
if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = line
currentChannel = None

sortedChannels = sorted(PLAYLIST_CHANNELS.keys())

print("\nChannel selection:")
for index, channel in enumerate(sortedChannels):
print("%2d - %s" % (index, channel))

print("x - Exit")

print("\n")

while True:
channelNum = input("\nInput channel number for grabbing: ")
if channelNum.lower() == "x":
exit(0)
else:
try:
RECORDING_CHANNEL_URL = PLAYLIST_CHANNELS[sortedChannels[int(channelNum)]].rstrip()
RECORDING_CHANNEL_NAME = sortedChannels[int(channelNum)]

print("Selected recording channel: %s" % (sortedChannels[int(channelNum)]))
isValidSelection = input('Is the channel correct Y/N? ')
if isValidSelection.lower() == "y":
return True
else:
continue

except Exception:
print('Wrong channel selection. Enter a channel number or "x" to exit.')
continue
break


if __name__ == "__main__":
hasPlaylist = False
ISWEBDL = False
if len(sys.argv) == 1:
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
ISWEBDL = True
print("Playlist succesfully downloaded.\n")
else:
print('Cannot download playlist "%s"' %(PLAYLIST_URL))
exit(1)
else:
for opt in sys.argv:
if opt.startswith('-local'):
playlistName = opt.replace('-local', '', 1)
if os.path.exists(playlistName):
print('Using local playlist: %s' % (playlistName))
PLAYLIST_FILE = playlistName
hasPlaylist = True
ISWEBDL = False
else:
print('Playlist not found using name "%s": ' %(playlistName))
exit(1)


if hasPlaylist and getStreamSelection():
print('\nIt\'s time to enter the date and time for the recording:')
while True:
while True:
recordDate = input('\nEnter record date for recording, in format day.month.year, for example: 7.8.2019 or "x" to cancel, enter nothing for todays date.\n')
if recordDate.lower() == 'x':
print("Cancelled")
exit(1)

elif len(recordDate) == 0:
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")
recordDay = timeNow.tm_mday
recordMonth = timeNow.tm_mon
recordYear = timeNow.tm_year

print("Record date: %02d.%02d.%d " %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year))
if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break

elif recordDate.count('.') == 2:
recordDay, recordMonth, recordYear = map(int, recordDate.split('.', 3))
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")

try:
timestampRecord = time.strptime("%d.%d.%d 00:00:00" %(recordDay, recordMonth, recordYear), "%d.%m.%Y %H:%M:%S")
except ValueError:
print('Date input does not match, use day.month.year as: 7.8.2019')
continue

if time.mktime(timestampNow) > time.mktime(timestampRecord):
print("Date is in the past. Repeat input.")
else:
print("Record date: %02d.%02d.%d " %(recordDay, recordMonth, recordYear))

if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break
else:
print("Invalid date input.")
continue

while True:
recordTime = input('\nEnter time to start recording, in format hour:minute, for example: 14:00 for 14 o\'clock, "x" to cancel\n')
if recordTime.lower() == 'x':
print("Cancelled")
exit(1)
elif recordTime.find(':') != -1:
recordHour, recordMinute = map(int, recordTime.split(':', 2))
print("Record time: %02d:%02d " %(recordHour, recordMinute))

timeNow = time.time()
timestampRecord = time.strptime("%d.%d.%d %d:%d:00" %(recordDay, recordMonth, recordYear, recordHour, recordMinute), "%d.%m.%Y %H:%M:%S")


if (timeNow > time.mktime(timestampRecord)):
print("Time is in the past. Repeat input.")
continue

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_TIME = time.mktime(timestampRecord)
break
else:
print("Invald time input.")
continue

while True:
recordDuration = input('\nEnter duration in minutes to record. For example 90 to capture 1 1/2 hours, "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)
elif int(recordDuration) < 0:
print("Negative recording duration, enter 30 for 30 minutes.")
continue

print("Record duration: %d minutes " %(int(recordDuration)))

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_DURATION = int(recordDuration)
break


while True:
RECORDING_NAME = input('\nEnter name for the recording file. Enter "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)

print("Record name: %s" % (RECORDING_NAME))
if input("Is the record name correct, Y/N ? ").lower() != 'y':
continue

break



print("\nWhat will be done?\nRecording channel \"%s\"." %(RECORDING_CHANNEL_NAME))
print("On %s at %s o'clock for %d minutes.\nRecording to file: \"%s\"" %(time.strftime("%d.%m.%Y", time.localtime(RECORDING_TIME)), time.strftime("%H:%M:%S", time.localtime(RECORDING_TIME)), RECORDING_DURATION, RECORDING_NAME))

confirm = input("\nAre all information correct, Y/N? ")
if confirm.lower() != 'y':
continue

scheduleFileName = "%d.rec" %(time.time())
with open(scheduleFileName, 'w', encoding='utf-8') as scheduleFile:
scheduleFile.write("%d;%d;%s;%s\n" % (RECORDING_TIME, RECORDING_DURATION, RECORDING_CHANNEL_NAME, RECORDING_NAME))

if USE_AT:
if not ISWEBDL:
scheduleCommand = 'echo "python3 %s/rec.py -ldl%s -pf%s" | at -M %s' % (APP_FOLDER, scheduleFileName, PLAYLIST_FILE, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
else:
scheduleCommand = 'echo "python3 %s/rec.py -dl%s" | at -M %s' % (APP_FOLDER, scheduleFileName, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
subprocess.Popen(scheduleCommand, shell=True)
print("Scheduled task.\nBye bye.")
exit(1)

break

print('Error writing schedule file for recording job.')

else:
hasPlaylist = False
for opt in sys.argv:
if opt.startswith('-dl'):
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
print("Playlist succesfully downloaded.\n")
else:
print("Error downloading playlist from \"%s\".\nExiting." %(PLAYLIST_URL))
exit(1)
elif opt.startswith('-pf'):
playlistName = opt.replace('-pf', '', 1)
if os.path.exists(playlistName):
print('Using local playlist: %s' %(playlistName))
PLAYLIST_FILE = playlistName
else:
print('Playlist not found using name "%s": ' % (playlistName))
exit(1)


for opt in sys.argv:
if opt.startswith('-dl'):
with open(PLAYLIST_FILE, "r", encoding='utf-8') as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
currentChannel = line.split(',',2)[1].rstrip().rstrip('"').replace('tvg-name="', '')
if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = line.rstrip()
currentChannel = None

scheduleFileName = opt.replace('-dl', '', 1)
elif opt.startswith('-ldl'):
hasPlaylist = False
for subopt in sys.argv:
if subopt.startswith('-pf'):
PLAYLIST_FILE = subopt.replace('-pf', '', 1)
hasPlaylist = True
break

with open(PLAYLIST_FILE, "r", encoding='utf-8') as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
currentChannel = line.split(',',2)[1].rstrip().rstrip('"').replace('tvg-name="', '')
if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = line.rstrip()
currentChannel = None

scheduleFileName = opt.replace('-ldl', '', 1)

scheduleFile = None
if os.path.exists(scheduleFileName):
scheduleData = None

with open(scheduleFileName, "r", encoding='utf-8') as scheduleFile:
scheduleData = scheduleFile.read().rstrip().split(';', 4)

if scheduleData != None:
try:
channelURL = PLAYLIST_CHANNELS[scheduleData[2]]
if scheduleData[2].find(' (Radio)') != -1:
commandString = FFMPEG_DIRECTORY + " -user_agent \"%s\" -i '%s' -t %d:%d:00 '%s.mp3'" %(USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
else:
commandString = FFMPEG_DIRECTORY + " -user_agent \"%s\" -i '%s' -t %d:%d:00 -vc:copy -o '%s.mkv'" % (USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
subprocess.Popen(commandString, shell=True)
except ValueError as error:
print('No channel information found.')
raise error
[/src]
 
Zuletzt bearbeitet:

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #34
Moin,

auf 2 Kisten getestet, bei einer schreibter wieder:

[src=text]Traceback (most recent call last):
File "rec.py", line 129, in <module>
if hasPlaylist and getStreamSelection():
File "rec.py", line 76, in getStreamSelection
print("%2d - %s" % (index, channel))
UnicodeEncodeError: 'ascii' codec can't encode character '\xdc' in position 15: ordinal not in range(128)[/src]

und in der liste kommter mit diesem eintrag nicht klar:
[src=text]
#EXTINF:-1 tvg-name="NDR 90,3" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/ndr903.png",NDR 90.3
http://ndr-ndr903-hamburg.cast.addradio.de/ndr/ndr903/hamburg/mp3/128/stream.mp3[/src]

da kommt dann diese Anzeigen:

[src=text]11 - 3" group-title="Deutschland" radio="true" tvg-logo="https://raw.githubusercontent.com/jnk22/kodinerds-iptv/master/logos/radio/ndr903.png (Radio)[/src]

das komische ist auch das er die liste wohl nicht komplett von oben abarbeitet? 0o Oder Überspringt das script die Streams die Offline sind? Im mom werden bei einer kiste gute 430(!) gelistet bei der anderen kiste kackt er bei stream 18 schon ab, siehe oben.

MfG

edit2:

Nu kommt nichts mehr wenn er die Liste Online holen will:

[src=text]
TypeError: write() argument must be str, not bytes
Encountered an error:
Traceback (most recent call last):
File "rec.py", line 108, in <module>
if downloadPlaylist(PLAYLIST_URL):
File "rec.py", line 51, in downloadPlaylist
raise error
File "rec.py", line 42, in downloadPlaylist
c.perform()
pycurl.error: (23, 'Failed writing body (0 != 5576)')
[/src]
 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
@DukeMan999: Okay..

1) die Channel Namensauflösung wird nun aus dem "tvg-name" berücksichtigt, so fern vorhanden
2) downloadPlaylists (Curl) testweise auf Binär umgestellt und Encoding der Datei entfernt, dass könnte die UTF-8 Probleme beheben.
3) "bytes" wo sinnvoll damit bei der Channelnamen Auswahl kein Fehler geworfen wird.

[src=python]#!/usr/bin/env python3
import sys
import time
import glob
import subprocess
import os.path
import os
import re

import pycurl

USE_AT = True
PLAYLIST_URL = ".m3u8"
USER_AGENT = "Your custom useragent"
FFMPEG_DIRECTORY = 'ffmpeg' # OR PATH: /home/username/path_to_ffmpeg/./ffmpeg OR leave 'ffmpeg' for general ffmpeg usage from system
#FFMPEG_DIRECTORY = '/home/username/ffmpeg_4.1.4-1+b2_amd64/./ffmpeg' # example

APP_FOLDER = os.getcwd()

PLAYLIST_FILE = "streamTempSave.m3u8" # This is just a temporary storage for the downloaded playlist, but this file wont be removed by itself
PLAYLIST_DATA = ""
PLAYLIST_CHANNELS = {}
RECORDING_NAME = ""
RECORDING_CHANNEL_NAME = ""
RECORDING_CHANNEL_URL = ""
RECORDING_TIME = 0
RECORDING_DURATION = 0

def downloadPlaylist(downloadURL):
playlistFile = open(PLAYLIST_FILE, 'wb')

print('Starting download of URI: \'%s\'\n' % downloadURL)
c = pycurl.Curl()
c.setopt(pycurl.URL, downloadURL)
c.setopt(pycurl.USERAGENT, USER_AGENT)
c.setopt(pycurl.VERBOSE, False)
c.setopt(pycurl.ENCODING, 'utf-8')
c.setopt(pycurl.WRITEDATA, playlistFile)
c.setopt(pycurl.NOPROGRESS, True)
c.setopt(pycurl.TIMEOUT, 30)

try:
c.perform()
print("\nSuccessfully downloaded playlist.\n")
playlistFile.close()
c.close()
return True
except Exception as error:
playlistFile.close()
c.close()
print("Encountered an error:")
raise error
return False



def getStreamSelection():
global PLAYLIST_CHANNELS, RECORDING_CHANNEL_NAME, RECORDING_CHANNEL_URL

playlistFile = open(PLAYLIST_FILE, "r", encoding="utf-8")
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
try:
currentChannel = list(re.findall(r'tvg-name\=\"(.[^"]*)', line))[0]
except:
currentChannel = line.split(',',2)[1].rstrip()
if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = bytes(line, 'utf-8').decode('utf-8', 'ignore').rstrip()
currentChannel = None

sortedChannels = sorted(PLAYLIST_CHANNELS.keys())

print("\nChannel selection:")
for index, channel in enumerate(sortedChannels):
print("%2d - %s" % (index, channel))

print("x - Exit")

print("\n")

while True:
channelNum = input("\nInput channel number for grabbing: ")
if channelNum.lower() == "x":
exit(0)
else:
try:
RECORDING_CHANNEL_URL = PLAYLIST_CHANNELS[sortedChannels[int(channelNum)]].rstrip()
RECORDING_CHANNEL_NAME = sortedChannels[int(channelNum)]

print("Selected recording channel: %s" % (sortedChannels[int(channelNum)]))
isValidSelection = input('Is the channel correct Y/N? ')
if isValidSelection.lower() == "y":
return True
else:
continue

except Exception:
print('Wrong channel selection. Enter a channel number or "x" to exit.')
continue
break


if __name__ == "__main__":
hasPlaylist = False
ISWEBDL = False
if len(sys.argv) == 1:
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
ISWEBDL = True
print("Playlist succesfully downloaded.\n")
else:
print('Cannot download playlist "%s"' %(PLAYLIST_URL))
exit(1)
else:
for opt in sys.argv:
if opt.startswith('-local'):
playlistName = opt.replace('-local', '', 1)
if os.path.exists(playlistName):
print('Using local playlist: %s' % (playlistName))
PLAYLIST_FILE = playlistName
hasPlaylist = True
ISWEBDL = False
else:
print('Playlist not found using name "%s": ' %(playlistName))
exit(1)


if hasPlaylist and getStreamSelection():
print('\nIt\'s time to enter the date and time for the recording:')
while True:
while True:
recordDate = input('\nEnter record date for recording, in format day.month.year, for example: 7.8.2019 or "x" to cancel, enter nothing for todays date.\n')
if recordDate.lower() == 'x':
print("Cancelled")
exit(1)

elif len(recordDate) == 0:
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")
recordDay = timeNow.tm_mday
recordMonth = timeNow.tm_mon
recordYear = timeNow.tm_year

print("Record date: %02d.%02d.%d " %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year))
if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break

elif recordDate.count('.') == 2:
recordDay, recordMonth, recordYear = map(int, recordDate.split('.', 3))
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")

try:
timestampRecord = time.strptime("%d.%d.%d 00:00:00" %(recordDay, recordMonth, recordYear), "%d.%m.%Y %H:%M:%S")
except ValueError:
print('Date input does not match, use day.month.year as: 7.8.2019')
continue

if time.mktime(timestampNow) > time.mktime(timestampRecord):
print("Date is in the past. Repeat input.")
else:
print("Record date: %02d.%02d.%d " %(recordDay, recordMonth, recordYear))

if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break
else:
print("Invalid date input.")
continue

while True:
recordTime = input('\nEnter time to start recording, in format hour:minute, for example: 14:00 for 14 o\'clock, "x" to cancel\n')
if recordTime.lower() == 'x':
print("Cancelled")
exit(1)
elif recordTime.find(':') != -1:
recordHour, recordMinute = map(int, recordTime.split(':', 2))
print("Record time: %02d:%02d " %(recordHour, recordMinute))

timeNow = time.time()
timestampRecord = time.strptime("%d.%d.%d %d:%d:00" %(recordDay, recordMonth, recordYear, recordHour, recordMinute), "%d.%m.%Y %H:%M:%S")


if (timeNow > time.mktime(timestampRecord)):
print("Time is in the past. Repeat input.")
continue

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_TIME = time.mktime(timestampRecord)
break
else:
print("Invald time input.")
continue

while True:
recordDuration = input('\nEnter duration in minutes to record. For example 90 to capture 1 1/2 hours, "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)
elif int(recordDuration) < 0:
print("Negative recording duration, enter 30 for 30 minutes.")
continue

print("Record duration: %d minutes " %(int(recordDuration)))

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_DURATION = int(recordDuration)
break


while True:
RECORDING_NAME = input('\nEnter name for the recording file. Enter "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)

print("Record name: %s" % (RECORDING_NAME))
if input("Is the record name correct, Y/N ? ").lower() != 'y':
continue

break



print("\nWhat will be done?\nRecording channel \"%s\"." %(RECORDING_CHANNEL_NAME))
print("On %s at %s o'clock for %d minutes.\nRecording to file: \"%s\"" %(time.strftime("%d.%m.%Y", time.localtime(RECORDING_TIME)), time.strftime("%H:%M:%S", time.localtime(RECORDING_TIME)), RECORDING_DURATION, RECORDING_NAME))

confirm = input("\nAre all information correct, Y/N? ")
if confirm.lower() != 'y':
continue

scheduleFileName = "%d.rec" %(time.time())
with open(scheduleFileName, 'w', encoding='utf-8') as scheduleFile:
scheduleFile.write("%d;%d;%s;%s\n" % (RECORDING_TIME, RECORDING_DURATION, RECORDING_CHANNEL_NAME, RECORDING_NAME))

if USE_AT:
if not ISWEBDL:
scheduleCommand = 'echo "python3 %s/rec.py -ldl%s -pf%s" | at -M %s' % (APP_FOLDER, scheduleFileName, PLAYLIST_FILE, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
else:
scheduleCommand = 'echo "python3 %s/rec.py -dl%s" | at -M %s' % (APP_FOLDER, scheduleFileName, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
subprocess.Popen(scheduleCommand, shell=True)
print("Scheduled task.\nBye bye.")
exit(1)

break

print('Error writing schedule file for recording job.')

else:
hasPlaylist = False
for opt in sys.argv:
if opt.startswith('-dl'):
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
print("Playlist succesfully downloaded.\n")
else:
print("Error downloading playlist from \"%s\".\nExiting." %(PLAYLIST_URL))
exit(1)
elif opt.startswith('-pf'):
playlistName = opt.replace('-pf', '', 1)
if os.path.exists(playlistName):
print('Using local playlist: %s' %(playlistName))
PLAYLIST_FILE = playlistName
else:
print('Playlist not found using name "%s": ' % (playlistName))
exit(1)


for opt in sys.argv:
if opt.startswith('-dl'):
with open(PLAYLIST_FILE, "r", encoding='utf-8') as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
try:
currentChannel = list(re.findall(r'tvg-name\=\"(.[^"]*)', line))[0]
except:
currentChannel = line.split(',',2)[1].rstrip()

if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = bytes(line, 'utf-8').decode('utf-8', 'ignore').rstrip()
currentChannel = None

scheduleFileName = opt.replace('-dl', '', 1)
elif opt.startswith('-ldl'):
hasPlaylist = False
for subopt in sys.argv:
if subopt.startswith('-pf'):
PLAYLIST_FILE = subopt.replace('-pf', '', 1)
hasPlaylist = True
break

with open(PLAYLIST_FILE, "r", encoding='utf-8') as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
try:
currentChannel = list(re.findall(r'tvg-name\=\"(.[^"]*)', line))[0]
except:
currentChannel = line.split(',',2)[1].rstrip()

if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'
elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = bytes(line, 'utf-8').decode('utf-8', 'ignore').rstrip()
currentChannel = None

sortedChannels = sorted(PLAYLIST_CHANNELS.keys())
scheduleFileName = opt.replace('-ldl', '', 1)

scheduleFile = None
if os.path.exists(scheduleFileName):
scheduleData = None

with open(scheduleFileName, "r", encoding='utf-8') as scheduleFile:
scheduleData = scheduleFile.read().rstrip().split(';', 4)

if scheduleData != None:
try:
channelURL = PLAYLIST_CHANNELS[scheduleData[2]]
if scheduleData[2].find(' (Radio)') != -1:
commandString = FFMPEG_DIRECTORY + " -user_agent \"%s\" -i '%s' -t %d:%d:00 '%s.mp3'" %(USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
else:
commandString = FFMPEG_DIRECTORY + " -user_agent \"%s\" -i '%s' -t %d:%d:00 -vc:copy -o '%s.mkv'" % (USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
subprocess.Popen(commandString, shell=True)
except ValueError as error:
print('No channel information found.')
raise error
[/src]
 
Zuletzt bearbeitet:

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #36
Bei kiste 1 das gleiche Prob wieder mit localer Liste:

[src=text]Traceback (most recent call last):
File "rec.py", line 133, in <module>
if hasPlaylist and getStreamSelection():
File "rec.py", line 80, in getStreamSelection
print("%2d - %s" % (index, channel))
UnicodeEncodeError: 'ascii' codec can't encode character '\xdc' in position 15: ordinal not in range(128)[/src]

Python 3.5.3 (default, Sep 27 2018, 17:25:39)
[GCC 6.3.0 20170516] on linux


keine probs die liste online zu holen.

Kiste 2:

Keine Probs die Liste local und Online zu holen und zu verarbeiten.

Und dort ist python nen stückel älter:
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux

ka warum kiste 1 probs hat die Liste local zu verarbeiten 0o

MfG

edit2:

so bei kiste 3 gibts auch keine Probs weder local noch online die liste zu verarbeiten auch wenn dort python älter ist:
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux

MfG
 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
@DukeMan999: Also noch ein Versuch...

Wenn dass das Problem nicht behebt, schick mir mal bitte die lokale Playlist die verarbeitet werden soll. (am besten per PN). Die, die auf Kiste 1 nicht läuft.

[src=python]#!/usr/bin/env python3
import sys
import time
import glob
import subprocess
import os.path
import os
import re

import pycurl

USE_AT = True
PLAYLIST_URL = ".m3u8"
USER_AGENT = "Your custom useragent"
FFMPEG_DIRECTORY = 'ffmpeg' # OR PATH: /home/username/path_to_ffmpeg/./ffmpeg OR leave 'ffmpeg' for general ffmpeg usage from system
#FFMPEG_DIRECTORY = '/home/username/ffmpeg_4.1.4-1+b2_amd64/./ffmpeg' # example

APP_FOLDER = os.getcwd()

PLAYLIST_FILE = "streamTempSave.m3u8" # This is just a temporary storage for the downloaded playlist, but this file wont be removed by itself
PLAYLIST_DATA = ""
PLAYLIST_CHANNELS = {}
RECORDING_NAME = ""
RECORDING_CHANNEL_NAME = ""
RECORDING_CHANNEL_URL = ""
RECORDING_TIME = 0
RECORDING_DURATION = 0

def downloadPlaylist(downloadURL):
playlistFile = open(PLAYLIST_FILE, 'wb')

print('Starting download of URI: \'%s\'\n' % downloadURL)
c = pycurl.Curl()
c.setopt(pycurl.URL, downloadURL)
c.setopt(pycurl.USERAGENT, USER_AGENT)
c.setopt(pycurl.VERBOSE, False)
c.setopt(pycurl.ENCODING, 'utf-8')
c.setopt(pycurl.WRITEDATA, playlistFile)
c.setopt(pycurl.NOPROGRESS, True)
c.setopt(pycurl.TIMEOUT, 30)

try:
c.perform()
print("\nSuccessfully downloaded playlist.\n")
playlistFile.close()
c.close()
return True
except Exception as error:
playlistFile.close()
c.close()
print("Encountered an error:")
raise error
return False



def getStreamSelection():
global PLAYLIST_CHANNELS, RECORDING_CHANNEL_NAME, RECORDING_CHANNEL_URL

playlistFile = open(PLAYLIST_FILE, "r", encoding="utf-8")
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
try:
currentChannel = list(re.findall(r'tvg-name\=\"(.[^"]*)', line))[0]
except:
currentChannel = line.split(',',2)[1].rstrip()

currentChannel = bytes(currentChannel, 'utf-8').decode('utf-8', 'ignore').rstrip()

if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'

elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = bytes(line, 'utf-8').decode('utf-8', 'ignore').rstrip()
currentChannel = None

sortedChannels = sorted(PLAYLIST_CHANNELS.keys())

print("\nChannel selection:")
for index, channel in enumerate(sortedChannels):
print("%2d - %s" % (index, channel))

print("x - Exit")

print("\n")

while True:
channelNum = input("\nInput channel number for grabbing: ")
if channelNum.lower() == "x":
exit(0)
else:
try:
RECORDING_CHANNEL_URL = PLAYLIST_CHANNELS[sortedChannels[int(channelNum)]].rstrip()
RECORDING_CHANNEL_NAME = sortedChannels[int(channelNum)]

print("Selected recording channel: %s" % (sortedChannels[int(channelNum)]))
isValidSelection = input('Is the channel correct Y/N? ')
if isValidSelection.lower() == "y":
return True
else:
continue

except Exception:
print('Wrong channel selection. Enter a channel number or "x" to exit.')
continue
break


if __name__ == "__main__":
hasPlaylist = False
ISWEBDL = False
if len(sys.argv) == 1:
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
ISWEBDL = True
print("Playlist succesfully downloaded.\n")
else:
print('Cannot download playlist "%s"' %(PLAYLIST_URL))
exit(1)
else:
for opt in sys.argv:
if opt.startswith('-local'):
playlistName = opt.replace('-local', '', 1)
if os.path.exists(playlistName):
print('Using local playlist: %s' % (playlistName))
PLAYLIST_FILE = playlistName
hasPlaylist = True
ISWEBDL = False
else:
print('Playlist not found using name "%s": ' %(playlistName))
exit(1)


if hasPlaylist and getStreamSelection():
print('\nIt\'s time to enter the date and time for the recording:')
while True:
while True:
recordDate = input('\nEnter record date for recording, in format day.month.year, for example: 7.8.2019 or "x" to cancel, enter nothing for todays date.\n')
if recordDate.lower() == 'x':
print("Cancelled")
exit(1)

elif len(recordDate) == 0:
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")
recordDay = timeNow.tm_mday
recordMonth = timeNow.tm_mon
recordYear = timeNow.tm_year

print("Record date: %02d.%02d.%d " %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year))
if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break

elif recordDate.count('.') == 2:
recordDay, recordMonth, recordYear = map(int, recordDate.split('.', 3))
timeNow = time.gmtime()
timestampNow = time.strptime("%d.%d.%d 00:00:00" %(timeNow.tm_mday, timeNow.tm_mon, timeNow.tm_year), "%d.%m.%Y %H:%M:%S")

try:
timestampRecord = time.strptime("%d.%d.%d 00:00:00" %(recordDay, recordMonth, recordYear), "%d.%m.%Y %H:%M:%S")
except ValueError:
print('Date input does not match, use day.month.year as: 7.8.2019')
continue

if time.mktime(timestampNow) > time.mktime(timestampRecord):
print("Date is in the past. Repeat input.")
else:
print("Record date: %02d.%02d.%d " %(recordDay, recordMonth, recordYear))

if input("Is the record date correct Y/N ? ").lower() != 'y':
continue
break
else:
print("Invalid date input.")
continue

while True:
recordTime = input('\nEnter time to start recording, in format hour:minute, for example: 14:00 for 14 o\'clock, "x" to cancel\n')
if recordTime.lower() == 'x':
print("Cancelled")
exit(1)
elif recordTime.find(':') != -1:
recordHour, recordMinute = map(int, recordTime.split(':', 2))
print("Record time: %02d:%02d " %(recordHour, recordMinute))

timeNow = time.time()
timestampRecord = time.strptime("%d.%d.%d %d:%d:00" %(recordDay, recordMonth, recordYear, recordHour, recordMinute), "%d.%m.%Y %H:%M:%S")


if (timeNow > time.mktime(timestampRecord)):
print("Time is in the past. Repeat input.")
continue

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_TIME = time.mktime(timestampRecord)
break
else:
print("Invald time input.")
continue

while True:
recordDuration = input('\nEnter duration in minutes to record. For example 90 to capture 1 1/2 hours, "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)
elif int(recordDuration) < 0:
print("Negative recording duration, enter 30 for 30 minutes.")
continue

print("Record duration: %d minutes " %(int(recordDuration)))

if input("Is the record time correct, Y/N ? ").lower() != 'y':
continue

RECORDING_DURATION = int(recordDuration)
break


while True:
RECORDING_NAME = input('\nEnter name for the recording file. Enter "x" to cancel\n')
if recordDuration.lower() == 'x':
print("Cancelled")
exit(1)

print("Record name: %s" % (RECORDING_NAME))
if input("Is the record name correct, Y/N ? ").lower() != 'y':
continue

break



print("\nWhat will be done?\nRecording channel \"%s\"." %(RECORDING_CHANNEL_NAME))
print("On %s at %s o'clock for %d minutes.\nRecording to file: \"%s\"" %(time.strftime("%d.%m.%Y", time.localtime(RECORDING_TIME)), time.strftime("%H:%M:%S", time.localtime(RECORDING_TIME)), RECORDING_DURATION, RECORDING_NAME))

confirm = input("\nAre all information correct, Y/N? ")
if confirm.lower() != 'y':
continue

scheduleFileName = "%d.rec" %(time.time())
with open(scheduleFileName, 'w', encoding='utf-8') as scheduleFile:
scheduleFile.write("%d;%d;%s;%s\n" % (RECORDING_TIME, RECORDING_DURATION, RECORDING_CHANNEL_NAME, RECORDING_NAME))

if USE_AT:
if not ISWEBDL:
scheduleCommand = 'echo "python3 %s/rec.py -ldl%s -pf%s" | at -M %s' % (APP_FOLDER, scheduleFileName, PLAYLIST_FILE, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
else:
scheduleCommand = 'echo "python3 %s/rec.py -dl%s" | at -M %s' % (APP_FOLDER, scheduleFileName, time.strftime("%H:%M %d.%m.%Y", time.localtime(RECORDING_TIME)))
subprocess.Popen(scheduleCommand, shell=True)
print("Scheduled task.\nBye bye.")
exit(1)

break

print('Error writing schedule file for recording job.')

else:
hasPlaylist = False
for opt in sys.argv:
if opt.startswith('-dl'):
if downloadPlaylist(PLAYLIST_URL):
hasPlaylist = True
print("Playlist succesfully downloaded.\n")
else:
print("Error downloading playlist from \"%s\".\nExiting." %(PLAYLIST_URL))
exit(1)
elif opt.startswith('-pf'):
playlistName = opt.replace('-pf', '', 1)
if os.path.exists(playlistName):
print('Using local playlist: %s' %(playlistName))
PLAYLIST_FILE = playlistName
else:
print('Playlist not found using name "%s": ' % (playlistName))
exit(1)


for opt in sys.argv:
if opt.startswith('-dl'):
with open(PLAYLIST_FILE, "r", encoding='utf-8') as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
try:
currentChannel = list(re.findall(r'tvg-name\=\"(.[^"]*)', line))[0]
except:
currentChannel = line.split(',',2)[1].rstrip()

currentChannel = bytes(currentChannel, 'utf-8').decode('utf-8', 'ignore').rstrip()

if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'

elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = bytes(line, 'utf-8').decode('utf-8', 'ignore').rstrip()
currentChannel = None

scheduleFileName = opt.replace('-dl', '', 1)
elif opt.startswith('-ldl'):
hasPlaylist = False
for subopt in sys.argv:
if subopt.startswith('-pf'):
PLAYLIST_FILE = subopt.replace('-pf', '', 1)
hasPlaylist = True
break

with open(PLAYLIST_FILE, "r", encoding='utf-8') as playlistFile:
data = playlistFile.readlines()

currentChannel = None
for line in data:
if line.startswith('#EXTINF:'):
try:
currentChannel = list(re.findall(r'tvg-name\=\"(.[^"]*)', line))[0]
except:
currentChannel = line.split(',',2)[1].rstrip()

currentChannel = bytes(currentChannel, 'utf-8').decode('utf-8', 'ignore').rstrip()

if line.find('radio="true"') != -1:
currentChannel += ' (Radio)'

elif (currentChannel != None and line.startswith('http')):
PLAYLIST_CHANNELS[currentChannel] = bytes(line, 'utf-8').decode('utf-8', 'ignore').rstrip()
currentChannel = None

sortedChannels = sorted(PLAYLIST_CHANNELS.keys())
scheduleFileName = opt.replace('-ldl', '', 1)

scheduleFile = None
if os.path.exists(scheduleFileName):
scheduleData = None

with open(scheduleFileName, "r", encoding='utf-8') as scheduleFile:
scheduleData = scheduleFile.read().rstrip().split(';', 4)

if scheduleData != None:
try:
channelURL = PLAYLIST_CHANNELS[scheduleData[2]]
if scheduleData[2].find(' (Radio)') != -1:
commandString = FFMPEG_DIRECTORY + " -user_agent \"%s\" -i '%s' -t %d:%d:00 '%s.mp3'" %(USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
else:
commandString = FFMPEG_DIRECTORY + " -user_agent \"%s\" -i '%s' -t %d:%d:00 -vc:copy -o '%s.mkv'" % (USER_AGENT, channelURL, int(scheduleData[1]) / 60, int(scheduleData[1]) % 60, scheduleData[3].rstrip())
subprocess.Popen(commandString, shell=True)
except ValueError as error:
print('No channel information found.')
raise error
[/src]
 

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #38
und wieder:

Traceback (most recent call last):
File "rec.py", line 137, in <module>
if hasPlaylist and getStreamSelection():
File "rec.py", line 84, in getStreamSelection
print("%2d - %s" % (index, channel))
UnicodeEncodeError: 'ascii' codec can't encode character '\xdc' in position 15: ordinal not in range(128)

ich schick dir mal die liste...
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
@DukeMan999: Also, deine Liste funktioniert bei mir.

Allerdings habe ich auch """Python 3.7.4+ (default, Sep 4 2019)""" hier.

Kannst du auf Kiste 1 mal eine neuere Python Version installieren, um zu testen ob das Abhilfe schafft?
 

DukeMan999

Duke Nukem Master

Registriert
14 Juli 2013
Beiträge
324
  • Thread Starter Thread Starter
  • #40
Hmz,

im mom nehmen keine der 3 listen einen online stream auf 0o *konfused ist*

1568734551.rec
in der ist
1568744040;170;PRO 7;renn.zur.million

das drin aber macht nichts? per "atq" wird auch nichts gelistet o0

MfG
 
Oben