Skip to content

Commit

Permalink
Undid Alec Leamas changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jackuess committed Dec 3, 2012
1 parent a90b97f commit a719ca3
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 220 deletions.
8 changes: 2 additions & 6 deletions README.md
Original file line number Original file line Diff line number Diff line change
@@ -1,10 +1,8 @@
# Pirateplay.se # # Pirateplay.se #
The entire code for running [Pirateplay.se](http://pirateplay.se) The entire code for running [Pirateplay.se](http://pirateplay.se)


Pirateplay.se can either be run as a Pirateplay.se can either be run as a WSGI application under ie. [mod_wsgi](http://code.google.com/p/modwsgi/), or
* WSGI application under ie. [mod_wsgi](http://code.google.com/p/modwsgi/) as a stand alone webserver in it self ([cherrypy.quickstart](http://docs.cherrypy.org/dev/refman/cherrypy.html#cherrypy.quickstart)).
* As a stand alone webserver in it self ([cherrypy.quickstart](http://docs.cherrypy.org/dev/refman/cherrypy.html#cherrypy.quickstart))
* As a standalone script which downloads or plays a url.


## Dependencies ## ## Dependencies ##
* [Python>=2.6](http://python.org/) * [Python>=2.6](http://python.org/)
Expand All @@ -18,5 +16,3 @@ Pirateplay.se can either be run as a
config.ini must be present in root - a copy of config.ini.example should work config.ini must be present in root - a copy of config.ini.example should work
in most cases. If run under mod_wsgi: directory must be set via .htaccess - see in most cases. If run under mod_wsgi: directory must be set via .htaccess - see
.htaccess.example. .htaccess.example.

To install as script, create a symlinkfrom main.py to e. g., /usr/bin/pirateplay.
1 change: 0 additions & 1 deletion lib/__init__.py
Original file line number Original file line Diff line number Diff line change
@@ -1 +0,0 @@
# vim: set noexpandtab ts=4 sw=4:
21 changes: 14 additions & 7 deletions lib/api.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ def _convert_service_re(self, service):
return service return service
else: else:
return s return s

def _filter_services(self, titles): def _filter_services(self, titles):
try: try:
titles = [t.lower() for t in titles.split(',')] titles = [t.lower() for t in titles.split(',')]
except AttributeError: except AttributeError:
return pirateplay.services return pirateplay.services
else: else:
return [s for s in pirateplay.services if s.title.lower() in titles] return [s for s in pirateplay.services if s.title.lower() in titles]

@cherrypy.expose @cherrypy.expose
@sitemap.add_to_sitemap('0.5') @sitemap.add_to_sitemap('0.5')
@cherrypy.tools.genshi_template(filename='api/manual.html') @cherrypy.tools.genshi_template(filename='api/manual.html')
def manual_html(self): def manual_html(self):
return {} return {}

@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out(handler = service_handler) @cherrypy.tools.json_out(handler = service_handler)
def get_streams_js(self, url, rnd = None): def get_streams_js(self, url, rnd = None):
Expand All @@ -46,6 +46,7 @@ def get_streams_js(self, url, rnd = None):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.genshi_template(filename='api/get_streams.xml', type='xml') @cherrypy.tools.genshi_template(filename='api/get_streams.xml', type='xml')
def get_streams_xml(self, url, rnd = None): def get_streams_xml(self, url, rnd = None):
<<<<<<< HEAD
streams, filename_hint = pirateplay.get_streams(url) streams, filename_hint = pirateplay.get_streams(url)
return {'streams': sorted([s.to_dict() for s in streams], key=lambda s: s['meta'].get('quality', '').rjust(16, '0'))} return {'streams': sorted([s.to_dict() for s in streams], key=lambda s: s['meta'].get('quality', '').rjust(16, '0'))}


Expand All @@ -54,6 +55,15 @@ def get_streams_xml(self, url, rnd = None):
def get_streams_old_xml(self, url, librtmp = '0', output_file = '-', parent_function = ''): def get_streams_old_xml(self, url, librtmp = '0', output_file = '-', parent_function = ''):
streams, filename_hint = pirateplay.get_streams(url) streams, filename_hint = pirateplay.get_streams(url)


=======
return {'streams': sorted([s.to_dict() for s in pirateplay.get_streams(url)], key=lambda s: s['meta'].get('quality', '').rjust(16, '0'))}

@cherrypy.expose
@cherrypy.tools.genshi_template(filename='api/get_streams_old.xml', type='xml')
def get_streams_old_xml(self, url, librtmp = '0', output_file = '-', parent_function = ''):
streams = pirateplay.get_streams(url)

>>>>>>> parent of 029e26b... Merge pull request #3 from leamas/master
if streams[0].url.startswith('rtmp') and librtmp == '0': if streams[0].url.startswith('rtmp') and librtmp == '0':
return { 'streams': [{'url': pirateplay.rtmpdump_cmd(s.url, output_file), 'meta': s.metadict()} for s in streams] } return { 'streams': [{'url': pirateplay.rtmpdump_cmd(s.url, output_file), 'meta': s.metadict()} for s in streams] }
elif '.m3u8' in streams[0].url: elif '.m3u8' in streams[0].url:
Expand All @@ -62,7 +72,7 @@ def get_streams_old_xml(self, url, librtmp = '0', output_file = '-', parent_func
return { 'streams': [{ 'meta': { 'quality': u'Inkompatibel ström. Testa appen på Pirateplay.se.' }, 'url': 'http://localhost/' }] } return { 'streams': [{ 'meta': { 'quality': u'Inkompatibel ström. Testa appen på Pirateplay.se.' }, 'url': 'http://localhost/' }] }
else: else:
return { 'streams': [s.to_dict() for s in streams] } return { 'streams': [s.to_dict() for s in streams] }

@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out(handler = service_handler) @cherrypy.tools.json_out(handler = service_handler)
def services_js(self, titles = None, rnd = ''): def services_js(self, titles = None, rnd = ''):
Expand All @@ -74,6 +84,3 @@ def services_js(self, titles = None, rnd = ''):
def services_xml(self, titles = None, rnd = ''): def services_xml(self, titles = None, rnd = ''):
return {'services': [self._convert_service_re(s).to_dict() return {'services': [self._convert_service_re(s).to_dict()
for s in self._filter_services(titles)]} for s in self._filter_services(titles)]}


# vim: set noexpandtab ts=4 sw=4:
9 changes: 3 additions & 6 deletions lib/genshi_tool.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def __init__(self, template, next_handler, type):
self.template = template self.template = template
self.next_handler = next_handler self.next_handler = next_handler
self.type = type self.type = type

def __call__(self): def __call__(self):
from urllib import quote from urllib import quote
from genshi.template import Context from genshi.template import Context
Expand All @@ -18,13 +18,10 @@ def __call__(self):
class GenshiLoader(): class GenshiLoader():
def __init__(self): def __init__(self):
self.loader = None self.loader = None

def __call__(self, filename, dir, auto_reload = False, type = 'xhtml', sitemap_prio = '-1'): def __call__(self, filename, dir, auto_reload = False, type = 'xhtml', sitemap_prio = '-1'):
from genshi.template import TemplateLoader from genshi.template import TemplateLoader
if self.loader == None: if self.loader == None:
self.loader = TemplateLoader(dir, auto_reload=auto_reload) self.loader = TemplateLoader(dir, auto_reload=auto_reload)
template = self.loader.load(filename) template = self.loader.load(filename)
cherrypy.request.handler = GenshiHandler(template, cherrypy.request.handler, type) cherrypy.request.handler = GenshiHandler(template, cherrypy.request.handler, type)


# vim: set noexpandtab ts=4 sw=4:
5 changes: 1 addition & 4 deletions lib/pirateplay/__init__.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -9,7 +9,4 @@ def default(self, o):
pass pass
return JSONEncoder.default(self, o) return JSONEncoder.default(self, o)


js_encoder = JSONEncoder() js_encoder = JSONEncoder()


# vim: set noexpandtab ts=4 sw=4:
130 changes: 23 additions & 107 deletions lib/pirateplay/main.py
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python2 #!/usr/bin/python2


import getopt, sys, re, os.path import getopt, sys
from os import system from os import system


from rerequest import * from rerequest import *
Expand All @@ -20,36 +20,8 @@ def get_streams(url):
for service in services: for service in services:
streams = service.get_streams(url) streams = service.get_streams(url)
if len(streams) > 0: if len(streams) > 0:
return streams, service.filename_hint return streams
return [], None return []

def quality2int(quality):
''' Parse string like 720x580 or '820 kbps', return numeric quality. '''
if re.match('[0-9]+x[0-9]+', quality):
rows, columns = quality.split('x')
return int(rows) * int(columns)
match = re.match('^[0-9]+', quality)
if match:
return int(match.group())
print "Don't understand quality: " + quality
sys.exit(3)

def find_best_stream(cmds, max_quality, subs):
''' Return 'best' stream, possibly constrained to matching subs. '''
if subs:
cmds = list([ c for c in cmds if c['subs'] == subs])
if not cmds:
print "No streams with %s subtitles" % subs
sys.exit(2)
best_stream = cmds[0]
max_quality = quality2int(max_quality)
best_quality = quality2int(best_stream['quality'])
for cmd in cmds[1:]:
cmd_pixels = quality2int(cmd['quality'])
if cmd_pixels > best_quality and cmd_pixels <= max_quality:
best_stream = cmd
best_quality = quality2int(cmd['quality'])
return best_stream


def print_usage(): def print_usage():
print """Usage: pirateplay [Flags]... [URL]... print """Usage: pirateplay [Flags]... [URL]...
Expand All @@ -61,18 +33,10 @@ def print_usage():
Print commands; don't execute them. Print commands; don't execute them.
-P, --print-urls -P, --print-urls
Print urls, not commands. Print urls, not commands.
-o file, --output-file=path -o file, --output-file=file
Download to file. If output-file is a directory, adds -f filename. Download to file.
-y command, --player=command -y command, --player=command
Set player command, ie. ffplay, vlc, mplayer (default is vlc). Set player command, ie. ffplay, vlc, mplayer (default is vlc).
-f, --filename-hint
Print filename hint for download. Requires -o <directory>.
-a, --auto
Select stream (quality, subs) automagically.
-s, --subs
Preferred subs when --auto is used, ignored by default.
-r, --max-resolution
Max resolution when --auto is used e. g. '720x580' defaults to max available.
-d, --debug -d, --debug
Print debug info during execution.""".replace(' ', '') Print debug info during execution.""".replace(' ', '')
sys.exit(0) sys.exit(0)
Expand All @@ -81,16 +45,8 @@ def parse_options():
r = { 'play': True, r = { 'play': True,
'print_cmds': False, 'print_cmds': False,
'print_urls': False, 'print_urls': False,
'player': 'vlc', 'player': 'vlc' }
'auto': False, opts, values = getopt.getopt(sys.argv[1:], 'pPy:do:h', ['print', 'print-urls', 'player', 'debug', 'output-file=', 'help'])
'subs': None,
'filename-hint': False,
'out_file': '',
'max-quality': '10000x10000' }
opts, values = getopt.getopt(sys.argv[1:], 'pPy:dfo:as:r:h',
['print', 'print-urls', 'player', 'debug',
'filename-hint', 'output-file=','auto', 'subs',
'max-resolution', 'help'])
for o, v in opts: for o, v in opts:
if o == '--print' or o == '-p': if o == '--print' or o == '-p':
r['print_cmds'] = True r['print_cmds'] = True
Expand All @@ -100,91 +56,51 @@ def parse_options():
r['player'] = v r['player'] = v
elif o == '--debug' or o == '-d': elif o == '--debug' or o == '-d':
set_debug(True) set_debug(True)
elif o == '--filename-hint' or o == '-f':
r['filename-hint'] = True
elif o == '--auto' or o == '-a':
r['auto'] = True
elif o == '--subs' or o == '-s':
r['subs'] = v
elif o == '--max-resolution' or o == '-r':
r['max-quality'] = v
elif o == '--output-file' or o == '-o': elif o == '--output-file' or o == '-o':
r['play'] = False r['play'] = False
if v == '': if v == '':
r['out_file'] = '-' r['out_file'] = '-'
else: else:
r['out_file'] = os.path.abspath(v) r['out_file'] = v
elif o == '--help' or o == '-h': elif o == '--help' or o == '-h':
print_usage() print_usage()


if r['filename-hint']:
if not r['out_file'] or not os.path.isdir(r['out_file']):
print "--filename-hint requires --output-file directory"
sys.exit(1)
return r return r


if __name__ == '__main__': if __name__ == '__main__':
options = parse_options() options = parse_options()
os.chdir(os.path.dirname(os.path.realpath(__file__)))


if system('which %s &> /dev/null' % options['player']) != 0: if system('which %s &> /dev/null' % options['player']) != 0:
sys.exit('Player command not found: %s' % options['player']) sys.exit('Player command not found: %s' % options['player'])
streams, filename_hint = get_streams(sys.argv[-1])
if not streams:
print 'No streams found.'
sys.exit(2)


streams = get_streams(sys.argv[-1])
i = 0 i = 0
cmds = [] cmds = []
for stream in streams: for stream in streams:
print '%d. Quality: %s, subtitles: %s' % (i+1, stream.metadict().get('quality', 'unknown'), stream.metadict().get('subtitles', 'none'))
i += 1 i += 1
quality = stream.metadict().get('quality', '0x0')
pr_quality = quality if quality != '0x0' else 'unknown'
subs = stream.metadict().get('subtitles', None)
pr_subs = subs if subs else 'none'
suffix_hint = stream.metadict().get('suffix-hint', None)
filename = options['out_file']
if options['out_file'] and os.path.isdir(options['out_file']):
filename = filename_hint
if suffix_hint:
filename += '.' + suffix_hint
filename = os.path.join(options['out_file'], filename)
if options['filename-hint']:
print "Filename hint: " + filename
sys.exit(0)

print '%d. Quality: %s, subtitles: %s' % (i, pr_quality, pr_subs)

if options['print_urls']: if options['print_urls']:
print stream.url print stream.url
else: else:
if options['play']: if options['play']:
cmd = "%s '%s'" % (options['player'], stream.url) cmd = "%s '%s'" % (options['player'], stream.url)
elif stream.url.startswith('rtmp'): elif stream.url.startswith('rtmp'):
cmd = rtmpdump_cmd(stream.url, filename) cmd = rtmpdump_cmd(stream.url, options['out_file'])
elif '.m3u8' in stream.url: elif '.m3u8' in stream.url:
cmd = 'ffmpeg -i "%s" -acodec copy -vcodec copy -bsf aac_adtstoasc "%s"' % (stream.url, filename) cmd = 'ffmpeg -i "%s" -acodec copy -vcodec copy -bsf aac_adtstoasc "%s"' % (stream.url, options['out_file'])
elif 'manifest.f4m' in stream.url: elif 'manifest.f4m' in stream.url:
cmd = 'php AdobeHDS.php --delete --manifest "%s" --outfile "%s"' % (stream.url, filename) cmd = 'php AdobeHDS.php --delete --manifest "%s" --outfile "%s"' % (stream.url, options['out_file'])
else: else:
cmd = 'wget -O "%s" "%s"' % (filename, stream.url) cmd = 'wget -O "%s" "%s"' % (options['out_file'], stream.url)

if options['print_cmds']: if options['print_cmds']:
print cmd print cmd
else: else:
cmds.append({'cmd': cmd, 'quality': quality, 'subs': subs}) cmds.append(cmd)


if i == 1: if i == 0:
print 'Running the single stream' print 'No streams found.'
system(cmds[0]['cmd'])
elif not options['print_cmds'] and not options['print_urls']: elif not options['print_cmds'] and not options['print_urls']:
if options['auto']: i_choice = int(raw_input('Choose stream: '))-1
best_stream = find_best_stream(cmds, options['max-quality'], options['subs']) system(cmds[i_choice])
system(best_stream['cmd'])
else:
i_choice = int(raw_input('Choose stream: '))-1
system(cmds[i_choice]['cmd'])


# vim: set noexpandtab ts=4 sw=4:

Loading

1 comment on commit a719ca3

@jackuess
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alec: I was too hasty merging your changes. Fetching the page title once for each RequestChain instance is not a good idea. If no streams are found for a given url, ie. http://foo.com/bar, it would mean fetching http://foo.com/bar 33 times.

Please sign in to comment.