Compare commits
2 commits
master
...
radioob-re
| Author | SHA1 | Date | |
|---|---|---|---|
| 22588ab1a6 | |||
| 4ee5a52d15 |
1 changed files with 174 additions and 13 deletions
|
|
@ -19,10 +19,14 @@
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import subprocess
|
import subprocess # FIXME use subprocess everywhere instead of os.spawn*
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import re
|
import re
|
||||||
import requests
|
import requests
|
||||||
|
import signal
|
||||||
|
import copy
|
||||||
|
import time
|
||||||
|
|
||||||
from weboob.capabilities.radio import CapRadio, Radio
|
from weboob.capabilities.radio import CapRadio, Radio
|
||||||
from weboob.capabilities.audio import CapAudio, BaseAudio, Playlist, Album
|
from weboob.capabilities.audio import CapAudio, BaseAudio, Playlist, Album
|
||||||
|
|
@ -198,14 +202,6 @@ class Radioob(ReplApplication):
|
||||||
|
|
||||||
audio.url = _obj.url
|
audio.url = _obj.url
|
||||||
|
|
||||||
def check_exec(executable):
|
|
||||||
with open(os.devnull, 'w') as devnull:
|
|
||||||
process = subprocess.Popen(['which', executable], stdout=devnull)
|
|
||||||
if process.wait() != 0:
|
|
||||||
print('Please install "%s"' % executable, file=self.stderr)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def audio_to_file(_audio):
|
def audio_to_file(_audio):
|
||||||
ext = _audio.ext
|
ext = _audio.ext
|
||||||
if not ext:
|
if not ext:
|
||||||
|
|
@ -220,23 +216,188 @@ class Radioob(ReplApplication):
|
||||||
dest = audio_to_file(audio)
|
dest = audio_to_file(audio)
|
||||||
|
|
||||||
if audio.url.startswith('rtmp'):
|
if audio.url.startswith('rtmp'):
|
||||||
if not check_exec('rtmpdump'):
|
if not self.check_exec('rtmpdump'):
|
||||||
return 1
|
return 1
|
||||||
args = ('rtmpdump', '-e', '-r', audio.url, '-o', dest)
|
args = ('rtmpdump', '-e', '-r', audio.url, '-o', dest)
|
||||||
elif audio.url.startswith('mms'):
|
elif audio.url.startswith('mms'):
|
||||||
if not check_exec('mimms'):
|
if not self.check_exec('mimms'):
|
||||||
return 1
|
return 1
|
||||||
args = ('mimms', '-r', audio.url, dest)
|
args = ('mimms', '-r', audio.url, dest)
|
||||||
else:
|
else:
|
||||||
if check_exec('wget'):
|
if self.check_exec('wget'):
|
||||||
args = ('wget', '-c', audio.url, '-O', dest)
|
args = ('wget', '-c', audio.url, '-O', dest)
|
||||||
elif check_exec('curl'):
|
elif self.check_exec('curl'):
|
||||||
args = ('curl', '-C', '-', audio.url, '-o', dest)
|
args = ('curl', '-C', '-', audio.url, '-o', dest)
|
||||||
else:
|
else:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
os.spawnlp(os.P_WAIT, args[0], *args)
|
os.spawnlp(os.P_WAIT, args[0], *args)
|
||||||
|
|
||||||
|
|
||||||
|
def check_exec(self, executable):
|
||||||
|
with open(os.devnull, 'w') as devnull:
|
||||||
|
process = subprocess.Popen(['which', executable], stdout=devnull)
|
||||||
|
if process.wait() != 0:
|
||||||
|
print('Please install "%s"' % executable, file=self.stderr)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def do_record(self, line):
|
||||||
|
"""
|
||||||
|
record ID [STREAM]
|
||||||
|
|
||||||
|
Record each track of an audio stream in a separate file in a directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
streams, dest = self.record_parse(line)
|
||||||
|
if isinstance(streams, int):
|
||||||
|
return streams
|
||||||
|
|
||||||
|
for stream in streams:
|
||||||
|
self.record_stream(stream, dest, background = False)
|
||||||
|
|
||||||
|
|
||||||
|
def do_recordplay(self, line):
|
||||||
|
"""
|
||||||
|
recordplay ID [STREAM]
|
||||||
|
|
||||||
|
Record each track of an audio stream in a separate file AND play it at the same time.
|
||||||
|
This takes care of not wasting bandwidth: only one connection to the stream is used.
|
||||||
|
"""
|
||||||
|
|
||||||
|
streams,dest = self.record_parse(line)
|
||||||
|
if isinstance(streams, int):
|
||||||
|
return streams
|
||||||
|
|
||||||
|
for stream in streams:
|
||||||
|
# Start the recorder in the background
|
||||||
|
# recpid = self.record_stream(stream, dest, background=True)
|
||||||
|
recpid = self.record_stream(stream, dest, background=True)
|
||||||
|
time.sleep(1)
|
||||||
|
self.logger.debug(u'streamripper recorder in background with PID: %i' % recpid)
|
||||||
|
|
||||||
|
# Play the local relay server, not the original stream.
|
||||||
|
relay_port = self.config.get('relay_port')
|
||||||
|
if not relay_port:
|
||||||
|
relay_port = 8000
|
||||||
|
self.logger.debug(u'No relay_port in config file, will use default: %i' % relay_port)
|
||||||
|
# Build a local stream to avoid changing the stream URL.
|
||||||
|
# localstream = copy.deepcopy(stream) # FIXME reference kept, why?
|
||||||
|
# localstream.url = u'http://localhost:%i' % relay_port
|
||||||
|
class Media:
|
||||||
|
def __init__(self, url, title, _id):
|
||||||
|
self.url = url
|
||||||
|
self.title = title
|
||||||
|
self.id = _id
|
||||||
|
localstream = Media(u'http://localhost:%i' % relay_port, stream.title, stream.id)
|
||||||
|
|
||||||
|
player_name = self.config.get('media_player')
|
||||||
|
media_player_args = self.config.get('media_player_args')
|
||||||
|
if not player_name:
|
||||||
|
self.logger.debug(u'No media_player in config file, will try to guess.')
|
||||||
|
try:
|
||||||
|
self.player.play(localstream, player_name=player_name, player_args=media_player_args)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.logger.debug(u'Player closed')
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
e = sys.exc_info()[0]
|
||||||
|
self.logger.debug(u'Encountered an error: %s' % e)
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
# Once player ends, terminate the recorder too.
|
||||||
|
self.logger.debug(u'Terminate the recorder')
|
||||||
|
# os.kill(recpid, signal.SIGTERM)
|
||||||
|
os.kill(recpid, signal.SIGKILL)
|
||||||
|
|
||||||
|
|
||||||
|
def record_parse(self, line):
|
||||||
|
_id, stream_id = self.parse_command_args(line, 2, 1)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
stream_id = int(stream_id)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
stream_id = 0
|
||||||
|
|
||||||
|
obj = self.retrieve_obj(_id)
|
||||||
|
|
||||||
|
if obj is None:
|
||||||
|
print('No object matches with this id:', _id, file=self.stderr)
|
||||||
|
return 3
|
||||||
|
|
||||||
|
if isinstance(obj, Radio):
|
||||||
|
try:
|
||||||
|
streams = [obj.streams[stream_id]]
|
||||||
|
except IndexError:
|
||||||
|
print('Stream %d not found' % stream_id, file=self.stderr)
|
||||||
|
return 1
|
||||||
|
elif isinstance(obj, BaseAudio):
|
||||||
|
streams = [obj]
|
||||||
|
|
||||||
|
else:
|
||||||
|
streams = obj.tracks_list
|
||||||
|
|
||||||
|
|
||||||
|
if len(streams) == 0:
|
||||||
|
print('Radio or Audio file not found:', _id, file=self.stderr)
|
||||||
|
return 3
|
||||||
|
|
||||||
|
dest = "records"
|
||||||
|
return streams, dest
|
||||||
|
|
||||||
|
|
||||||
|
def record_stream(self, stream, dest, background = False):
|
||||||
|
"""
|
||||||
|
Run streamripper on the given stream and save files in the given directory.
|
||||||
|
|
||||||
|
If background is False, this function returns the process id of the new process;
|
||||||
|
if background is True, returns the process’s exit code if it exits normally,
|
||||||
|
or -signal, where signal is the signal that killed the process.
|
||||||
|
"""
|
||||||
|
if dest is None:
|
||||||
|
title = stream.title if stream.title else stream.id
|
||||||
|
dest = '%s' % re.sub('[?:/]', '-', title)
|
||||||
|
|
||||||
|
if not os.path.exists(dest):
|
||||||
|
os.makedirs(dest)
|
||||||
|
|
||||||
|
if not os.path.isdir(dest):
|
||||||
|
print('The destination "%s" is not a directory' % dest, file=self.stderr)
|
||||||
|
return 5
|
||||||
|
|
||||||
|
if not self.check_exec('streamripper'):
|
||||||
|
print('streamripper not found, please install it', file=self.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if background:
|
||||||
|
# Start a relay server, but do not try to find a free port.
|
||||||
|
relay_port = self.config.get('relay_port')
|
||||||
|
if not relay_port:
|
||||||
|
relay_port = 8000
|
||||||
|
args = ['streamripper', stream.url, '-d', dest, '-z', '-r', str(relay_port)]
|
||||||
|
spawn = subprocess.Popen
|
||||||
|
else:
|
||||||
|
args = ['streamripper', stream.url, '-d', dest]
|
||||||
|
spawn = subprocess.call
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.logger.debug(u'Invoking: %s' % (u' '.join([str(a) for a in args])))
|
||||||
|
proc = spawn(args)
|
||||||
|
except OSError:
|
||||||
|
print(u'Failed to start the recorder')
|
||||||
|
return 7
|
||||||
|
|
||||||
|
if proc.returncode:
|
||||||
|
print('The recorder ended unexpectedly', file=self.stderr)
|
||||||
|
self.logger.debug(u'streamripper error, pid=%i, code=%i' % (proc.pid, proc.returncode))
|
||||||
|
return 8
|
||||||
|
|
||||||
|
return proc.pid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def complete_play(self, text, line, *ignored):
|
def complete_play(self, text, line, *ignored):
|
||||||
args = line.split(' ')
|
args = line.split(' ')
|
||||||
if len(args) == 2:
|
if len(args) == 2:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue