Code recipe : Download Manager (Python Version)

Recently I had published my blog post Building a Download Manager(in JAVA). And I am presenting the python implementation of download manager. The whole concept is same except the language of implementation. You can check the older JAVA implementation here.
Python has nice libraries urllib and urllib2 we can use for our purpose. urllib2 provides nice feature of request header modification. Here's my recipe python version.

import urllib2
from threading import Thread
 
class Downloader:
    def __init__(self):
        pass
 
    def downloadFile(self, url, num_streams, dest_fname):
        file_size = self.getContentLength(url)
 
        if not self.supportsPartialContent(url):
            print "The server doesn't support partial content!! Resuming with Single Stream"
            self.downloadStream(url, dest_fname, "bytes=0-"+`file_size`)
            return
 
        initial = 0
        block   = int(file_size / num_streams)
        final   = block
        files   = []
        threads = []
 
        for i in xrange(num_streams):
            drange  = "bytes=" + `initial` + "-" + `final`
            print drange
            files.append("fileparts" + `i`)
             
            t = Thread(target=self.downloadStream, args=(url, files[i], drange))
            threads.append(t)
             
            initial = final
            final   = (final + block) if (i < num_streams-2) else file_size
 
        [t.start()  for t in threads]
        [t.join()   for t in threads]
 
        self.concatFiles(files, dest_fname);
         
 
    def concatFiles(self, original, dest):
        final_file = open(dest, 'wb')
        for f in original:
            fopener = open(f, 'rb')
            final_file.write(fopener.read())
            fopener.close()
        final_file.close()
        return
 
    def supportsPartialContent(self, url):
        request = urllib2.Request(url)
        request.add_header("Range", "bytes=0-10")
        opener  = urllib2.urlopen(request)
        print opener.getcode()
        return True if opener.getcode() == 206 else False
 
    def downloadStream(self, url, file_name, range):
        request = urllib2.Request(url)
        request.add_header("Range", range)
        opener  = urllib2.urlopen(request)
 
        f = open(file_name, "wb")
        f.write(opener.read())
        f.close()
 
    def getContentLength(self, url):
        content = urllib2.urlopen(url)
        meta = content.info()
        file_size = int(meta.getheaders("Content-Length")[0])
        return file_size
 
 
url = "http://shresthasushil.com.np/img/velocious.jpg"
num_streams = 5
dest_fname = "testfile"
dman = Downloader()
dman.downloadFile(url, num_streams, dest_fname)
I suggest you take only the concept and try make your own recipe. Happy coding guys.

1 comment :