Skip to content

Commit

Permalink
Merge pull request #221 from vadium/master
Browse files Browse the repository at this point in the history
* vadmium-master:
  cli: Close the player’s redirected input and output streams.
  stream.streamprocess: Close the error output stream once it has been passed to the subprocess.
  packages.pbs: Close new pipe to background process immediately.
  docs: Document how to configure options that don’t take an argument.
  packages.pbs: Stop hash() from working in Python 2, to match Python 3 behaviour.
  • Loading branch information
chrippa committed Nov 16, 2013
2 parents 0ebafa7 + 8d9c90f commit 0e866b5
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 22 deletions.
3 changes: 2 additions & 1 deletion docs/cli.rst
Expand Up @@ -53,11 +53,12 @@ Livestreamer will look for this file in different locations depending on your pl
- ``%APPDATA%\livestreamer\livestreamerrc``


The file should contain one argument per line in the format ``option=value``, like this:
The file should contain one argument per line in the format ``option[=value]``, like this:

.. code-block:: console
player=mplayer -cache 2048
player-no-close
jtv-cookie=_twitch_session_id=xxxxxx; persistent=xxxxx;
gomtv-cookie=SES_MEMBERNO=xxx; SES_STATE=xxx; SES_MEMBERNICK=xxx; SES_USERNICK=xxx;
Expand Down
22 changes: 14 additions & 8 deletions src/livestreamer/packages/pbs.py
Expand Up @@ -136,7 +136,10 @@ def __init__(self, command_ran, process, call_args, stdin=None):

# we're running in the background, return self and let us lazily
# evaluate
if self.call_args["bg"]: return
if self.call_args["bg"]:
if self.process.stdin:
self.process.stdin.close()
return

# we're running this command as a with context, don't do anything
# because nothing was started to run from Command.__call__
Expand Down Expand Up @@ -170,6 +173,7 @@ def __unicode__(self):

def __eq__(self, other):
return unicode(self) == unicode(other)
__hash__ = None # Avoid DeprecationWarning in Python < 3

def __contains__(self, item):
return item in str(self)
Expand Down Expand Up @@ -351,6 +355,7 @@ def __unicode__(self):
def __eq__(self, other):
try: return str(self) == str(other)
except: return False
__hash__ = None # Avoid DeprecationWarning in Python < 3


def __enter__(self):
Expand Down Expand Up @@ -386,8 +391,8 @@ def __call__(self, *args, **kwargs):
pipe = None if call_args["fg"] else subp.PIPE

# check if we're piping via composition
stdin = pipe
actual_stdin = None
input_stream = pipe
input_data = None
if args:
first_arg = args.pop(0)
if isinstance(first_arg, RunningCommand):
Expand All @@ -396,9 +401,9 @@ def __call__(self, *args, **kwargs):
# background as well
if first_arg.call_args["bg"]:
call_args["bg"] = True
stdin = first_arg.process.stdout
input_stream = first_arg.process.stdout
else:
actual_stdin = first_arg.stdout()
input_data = first_arg.stdout()
else: args.insert(0, first_arg)

processed_args = self._compile_args(args, kwargs)
Expand All @@ -421,7 +426,7 @@ def __call__(self, *args, **kwargs):
# stdin from string
input = call_args["in"]
if input:
actual_stdin = input
input_data = input

# stdout redirection
stdout = pipe
Expand All @@ -442,9 +447,10 @@ def __call__(self, *args, **kwargs):

# leave shell=False
process = subp.Popen(cmd, shell=False, env=call_args["env"],
cwd=call_args["cwd"], stdin=stdin, stdout=stdout, stderr=stderr)
cwd=call_args["cwd"],
stdin=input_stream, stdout=stdout, stderr=stderr)

return RunningCommand(command_ran, process, call_args, actual_stdin)
return RunningCommand(command_ran, process, call_args, input_data)



3 changes: 2 additions & 1 deletion src/livestreamer/stream/streamprocess.py
Expand Up @@ -48,7 +48,8 @@ def open(self):
else:
params["_err"] = open(os.devnull, "wb")

stream = cmd(**params)
with params["_err"]:
stream = cmd(**params)

# Wait 0.5 seconds to see if program exited prematurely
time.sleep(0.5)
Expand Down
7 changes: 4 additions & 3 deletions src/livestreamer_cli/main.py
Expand Up @@ -5,6 +5,7 @@
import sys
import signal

from contextlib import closing
from time import sleep
from distutils.version import StrictVersion

Expand Down Expand Up @@ -239,9 +240,9 @@ def output_stream(stream):
console.exit("Failed to open output: {0} ({1})",
args.output, err)

console.logger.debug("Writing stream to output")
read_stream(stream_fd, output, prebuffer)
output.close()
with closing(output):
console.logger.debug("Writing stream to output")
read_stream(stream_fd, output, prebuffer)

return True

Expand Down
36 changes: 27 additions & 9 deletions src/livestreamer_cli/output.py
Expand Up @@ -71,6 +71,7 @@ def __init__(self, cmd, args=DEFAULT_PLAYER_ARGUMENTS,
self.args = args
self.kill = kill
self.call = call
self.quiet = quiet

self.filename = filename
self.namedpipe = namedpipe
Expand All @@ -81,7 +82,7 @@ def __init__(self, cmd, args=DEFAULT_PLAYER_ARGUMENTS,
else:
self.stdin = subprocess.PIPE

if quiet:
if self.quiet:
self.stdout = open(os.devnull, "w")
self.stderr = open(os.devnull, "w")
else:
Expand Down Expand Up @@ -118,13 +119,18 @@ def _open(self):
self._open_subprocess()

def _open_call(self):
subprocess.call(self._create_arguments(),
stdout=self.stdout,
stderr=self.stderr)
try:
subprocess.call(self._create_arguments(),
stdout=self.stdout,
stderr=self.stderr)
finally:
self._close_out()

def _open_subprocess(self):
# Force bufsize=0 on all Python versions to avoid writing the
# unflushed buffer when closing a broken input pipe
self.player = subprocess.Popen(self._create_arguments(),
stdin=self.stdin,
stdin=self.stdin, bufsize=0,
stdout=self.stdout,
stderr=self.stderr)

Expand All @@ -138,14 +144,26 @@ def _open_subprocess(self):
self.http.open()

def _close(self):
if self.kill:
with ignored(Exception):
self.player.kill()

# Close input to the player first to signal the end of the
# stream and allow the player to terminate of its own accord
if self.namedpipe:
self.namedpipe.close()
elif self.http:
self.http.close()
elif not self.filename:
self.player.stdin.close()

if self.kill:
with ignored(Exception):
self.player.kill()

self._close_out()

def _close_out(self):
"""Close the output streams if needed"""
if self.quiet:
self.stdout.close()
self.stderr.close()

def _write(self, data):
if self.namedpipe:
Expand Down

0 comments on commit 0e866b5

Please sign in to comment.