[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
inute, 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]