From d00d0ad02007597393f1c1b7d2a87bd985619f3d Mon Sep 17 00:00:00 2001 From: Christopher Rosell Date: Thu, 20 Sep 2012 18:37:23 +0200 Subject: Split stream.py. --- src/livestreamer/stream.py | 105 ------------------------------------ src/livestreamer/stream/__init__.py | 65 ++++++++++++++++++++++ src/livestreamer/stream/http.py | 17 ++++++ src/livestreamer/stream/rtmpdump.py | 35 ++++++++++++ 4 files changed, 117 insertions(+), 105 deletions(-) delete mode 100644 src/livestreamer/stream.py create mode 100644 src/livestreamer/stream/__init__.py create mode 100644 src/livestreamer/stream/http.py create mode 100644 src/livestreamer/stream/rtmpdump.py diff --git a/src/livestreamer/stream.py b/src/livestreamer/stream.py deleted file mode 100644 index 82d9a9a..0000000 --- a/src/livestreamer/stream.py +++ /dev/null @@ -1,105 +0,0 @@ -from .compat import str, is_win32 -from .utils import urlget - -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, **args): - Stream.__init__(self, session) - - self.url = url - self.args = args - - def open(self): - res = urlget(self.url, prefetch=False, - exception=StreamError, - **self.args) - - return res.raw - -__all__ = ["StreamError", "Stream", "StreamProcess", "RTMPStream", "HTTPStream"] diff --git a/src/livestreamer/stream/__init__.py b/src/livestreamer/stream/__init__.py new file mode 100644 index 0000000..235d2f7 --- /dev/null +++ b/src/livestreamer/stream/__init__.py @@ -0,0 +1,65 @@ +from ..compat import str + +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 + + +from .http import HTTPStream +from .rtmpdump import RTMPStream + +__all__ = ["StreamError", "Stream", "StreamProcess", + "RTMPStream", "HTTPStream"] diff --git a/src/livestreamer/stream/http.py b/src/livestreamer/stream/http.py new file mode 100644 index 0000000..ab9a763 --- /dev/null +++ b/src/livestreamer/stream/http.py @@ -0,0 +1,17 @@ +from . import Stream +from ..utils import urlget + +class HTTPStream(Stream): + def __init__(self, session, url, **args): + Stream.__init__(self, session) + + self.url = url + self.args = args + + def open(self): + res = urlget(self.url, prefetch=False, + exception=StreamError, + **self.args) + + return res.raw + diff --git a/src/livestreamer/stream/rtmpdump.py b/src/livestreamer/stream/rtmpdump.py new file mode 100644 index 0000000..68ed969 --- /dev/null +++ b/src/livestreamer/stream/rtmpdump.py @@ -0,0 +1,35 @@ +from . import StreamProcess +from ..compat import str, is_win32 + +import pbs + +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 + -- cgit v1.2.3