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()