Rfetch.py
Материал из wiki.lissyara.su
#! /usr/bin/env python-shared3.0
# usage: rfetch.py url [url...]
import curses
import os
import re
import subprocess
import sys
import time
import urllib.request
def fetch(url):
url, counter = suck(url)
status(1, 'sleeping... {0:{1}} seconds remain', counter, 3)
subprocess.call(['fetch', '-v', url])
def getcap(*caps):
try:
curses.setupterm(None, sys.__stderr__.fileno())
except curses.error:
curses.setupterm('dumb', sys.__stderr__.fileno())
tc = []
for cap in caps:
try:
if type(cap) is list:
tc.append(curses.tparm(curses.tigetstr(cap[0])
.decode(), *cap[1:]).decode())
else:
tc.append(curses.tparm(curses.tigetstr(cap)
.decode()).decode())
except AttributeError:
tc.append('')
return(tc)
def main():
if sys.argv[1:] == [] or '' in sys.argv[1:]: # without or null argument(s)
usage()
for url in sys.argv[1:]:
if url.find('://') < 0: # no http:// prefix
url = 'http://' + url
elif not url.startswith('http://'): # prefix is not http://
usage('invalid scheme:// for rapidshare')
fetch(url)
def status(update, line, counter, *rest):
'''Show countdouwn for `sleep' each `update' seconds.'''
def puts(*rest):
print('\r', so, ''.join(rest), me, sep='', end='', file=sys.stderr)
sys.stderr.flush()
future = counter * update + int(time.time())
so, me = getcap('smso', 'sgr0')
while counter >= 0:
# do not print anything unless we are in foreground
# and connected to a controlling terminal
if os.getpgrp() == os.tcgetpgrp(sys.__stderr__.fileno()):
puts(line.format(counter, *rest))
time.sleep(update)
counter = (future - int(time.time())) // update
puts()
def suck(url):
'''Return url pointing to a real file and sleeping time.'''
data = url2str(url)
if url.find('rapidshare.de') >= 0:
raise NotImplementedError('rapidshare.DE is unsupported')
elif data.lower().find('file could not be found') >= 0:
raise urllib.error.URLError('file not found')
elif data.lower().find('contain illegal content') >= 0:
raise urllib.error.URLError('file has been blocked')
elif data.lower().find('this limit is reached') >= 0:
raise urllib.error.URLError(getcap(['setaf', curses.COLOR_YELLOW])[0] +
data.split('<div class="klappbox">')[1]
.split('</div>')[0]
.replace('<p>','')
.replace('</p>','\n')
.strip() +
getcap('sgr0')[0])
url = re.search('id="ff"\s*action="([^"]*)"', data).group(1)
while True:
data = url2str(url, 'dl.start=Free')
if data.lower().find('already downloading a file') >= 0:
raise urllib.error.URLError('already downloading one file')
elif data.lower().find('reached the download limit') >= 0:
# grab ticket and wait
wait = int(re.search('about\s*(\d*)\s*minutes', data).group(1))
status(60, 'waiting... {0:{1}} minutes remain', wait, 2)
else:
break
url = re.search('name="dlf"\s*action="([^"]*)"', data).group(1)
counter = int(re.search('var\s*c\s*=\s*(\d*)', data).group(1))
return(url, counter)
def url2str(url, data=None):
'''Fetch url and return its content as a string.'''
f = urllib.request.urlopen(url, data)
data = f.read().decode("utf-8", "replace")
return(data)
def usage(msg=None):
if msg is not None:
print(msg, file=sys.stderr)
else:
print('usage: {0} url [url...]'.format(os.path.basename(sys.argv[0])),
file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()