1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
from .utils import urlopen
from .compat import str, is_win32
import os
import pbs
import time
import tempfile
class StreamError(Exception):
pass
class Stream(object):
"""
This is a base class that should be inherited when implementing
different stream types. Should only be used directly from plugins.
"""
def __init__(self, session):
self.session = session
def open(self):
"""
Opens a connection to the stream.
Returns a file-like object than can be used to read data.
Raises :exc:`StreamError` on failure.
"""
raise NotImplementedError
class StreamProcess(Stream):
def __init__(self, session, params={}):
Stream.__init__(self, session)
self.params = params
self.params["_bg"] = True
self.params["_err"] = open(os.devnull, "w")
self.errorlog = self.session.options.get("errorlog")
def cmdline(self):
return str(self.cmd.bake(**self.params))
def open(self):
if self.errorlog:
tmpfile = tempfile.NamedTemporaryFile(prefix="livestreamer",
suffix=".err", delete=False)
self.params["_err"] = tmpfile
stream = self.cmd(**self.params)
# Wait 0.5 seconds to see if program exited prematurely
time.sleep(0.5)
stream.process.poll()
if stream.process.returncode is not None:
if self.errorlog:
raise StreamError(("Error while executing subprocess, error output logged to: {0}").format(tmpfile.name))
else:
raise StreamError("Error while executing subprocess")
return stream.process.stdout
class RTMPStream(StreamProcess):
def __init__(self, session, params):
StreamProcess.__init__(self, session, params)
self.rtmpdump = self.session.options.get("rtmpdump") or (is_win32 and "rtmpdump.exe" or "rtmpdump")
self.params["flv"] = "-"
try:
self.cmd = getattr(pbs, self.rtmpdump)
except pbs.CommandNotFound as err:
raise StreamError(("Unable to find {0} command").format(str(err)))
def open(self):
if "jtv" in self.params and not self._has_jtv_support():
raise StreamError("Installed rtmpdump does not support --jtv argument")
return StreamProcess.open(self)
def _has_jtv_support(self):
try:
help = self.cmd(help=True, _err_to_out=True)
except pbs.ErrorReturnCode as err:
raise StreamError(("Error while checking rtmpdump compatibility: {0}").format(str(err.stdout, "ascii")))
for line in help.split("\n"):
if line[:5] == "--jtv":
return True
return False
class HTTPStream(Stream):
def __init__(self, session, url):
Stream.__init__(self, session)
self.url = url
def open(self):
return urlopen(self.url)
__all__ = ["StreamError", "Stream", "StreamProcess", "RTMPStream", "HTTPStream"]
|