Guest User

JManga downloader

a guest
Mar 16th, 2013
596
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.75 KB | None | 0 0
  1. #!/usr/bin/python
  2. #
  3. # Downloads all your JManga purchases.
  4. # Obviously requires Python installed and I don't
  5. # use windows so this should work but
  6. # I have no way to test it.
  7. #
  8. # If you don't know how to run a python script
  9. # ask someone who does.
  10. #
  11. # I really wanted JManga to succeed and was working
  12. # on an iOS client. I should have seen this coming but
  13. # I really wanted to believe. I assumed that with all the
  14. # publishers behind it they would be in it for the long
  15. # haul. Oh well. Here we are.
  16. #
  17. # Since I would really hate for people to lose all the
  18. # cool obscure manga they bought I'm providing this
  19. # downloader script. Just give it your username and
  20. # password and it'll download all your manga. I don't
  21. # have much manga to test with so I'm not entirely
  22. # sure what will happen if you have a huge library but
  23. # it should be fine.
  24. #
  25. # Shame they sent out the announcement email after they
  26. # had turned off points purchasing. I would have bought
  27. # a bunch of the stuff I was holding off on buying.
  28. # Why did I wait? I wanted to read them on my iPad
  29. # not my computer.
  30. #
  31. # Please don't put your manga on file sharing sites. :(
  32. #
  33.  
  34. import sys
  35. import urllib
  36. import urllib2
  37. import cookielib
  38. import json
  39. import os
  40.  
  41. def getCredentials():
  42.     global username
  43.     username = ""
  44.     password = ""
  45.     if len(sys.argv) != 3:
  46.         username = raw_input('Username: ')
  47.         password = raw_input('Password: ')
  48.     else:
  49.         username = sys.argv[1]
  50.         password = sys.argv[2]
  51.     if len(username) == 0:
  52.         print 'error: did not enter a username'
  53.         exit(1)
  54.     if len(password) == 0:
  55.         print 'error: did not enter a password'
  56.         exit(1)
  57.     return username, password
  58.  
  59. def getCookie(cookieJar, cookieName):
  60.     for index, cookie in enumerate(cookieJar):
  61.         if cookie.name == cookieName:
  62.             return cookie.value
  63.     return ''
  64.  
  65. def login(username, password):
  66.     cookieJar = cookielib.CookieJar()
  67.     opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookieJar))
  68.     loginString = {'formname' : 'RpcApiUser_Login', 'fail_url' : '/login', 'email' : username, 'password' : password, 'x' : '30', 'y' : '7'}
  69.     loginCredentials = urllib.urlencode(loginString)
  70.     result = opener.open('https://www.jmanga.com/formhandler', loginCredentials)
  71.     result.read()
  72.     if len(getCookie(cookieJar, 'manga_user')) == 0:
  73.         print 'error: login failed'
  74.         exit(1)
  75.     print 'logged in'
  76.     return opener
  77.     #result = opener.open('http://jmanga.com/profile')
  78.     #print result.read()
  79.  
  80. def extractSeriesIDs(html):
  81.     seriesIDs = {}
  82.     targetString = 'series_id='
  83.     startOffset = 0
  84.     while startOffset >= 0:
  85.         startOffset = html.find(targetString, startOffset)
  86.         if startOffset < 0:
  87.             return seriesIDs.keys()
  88.         startOffset += len(targetString)
  89.         endIndex = html.find('&', startOffset)
  90.         seriesIDs[html[startOffset:endIndex]] = True
  91.     return seriesIDs.keys()
  92.  
  93. def decrypt(stringInput):
  94.     b = bytearray(stringInput)
  95.     key = b[0] ^ 0xff
  96.     for i in range(len(b)):
  97.         b[i] ^= key
  98.     return b
  99.  
  100. def getBaseNameFromURL(url):
  101.     filename = url.split('/')[-1]
  102.     return filename.split('.')[0]
  103.  
  104. def downloadEncryptedImage(opener, url, name):
  105.     imageBytes = decrypt(opener.open(url).read())
  106.     with open(name, 'wb') as f:
  107.         f.write(imageBytes)
  108.         global username
  109.         f.write(username)
  110.  
  111. def getChapterInfo(opener, chapterID):
  112.     infoURL = 'http://api.jmanga.com/chapter?chapter%5Fid=' + chapterID
  113.     return json.loads(opener.open(infoURL).read())
  114.  
  115. def downloadPage(opener, page, directory):
  116.     locales = page['locale']
  117.     preferredLocale = 'enUS'
  118.     localeNames = locales.keys()
  119.     # not all locales have an image
  120.     # so we try our preferred locale and if that
  121.     # fails then we try the others until we find
  122.     # a valid one (assuming that, in this case,
  123.     # they are all equivalent)
  124.     try:
  125.         i = localeNames.index(preferredLocale)
  126.         localeNames.pop(i)
  127.         localeNames.insert(0, preferredLocale)
  128.     except ValueError:
  129.         pass
  130.     filename = os.path.join(directory, '{:04}.jpg'.format(int(page['number'])+1))
  131.     imageKey = 'encrypted_composed_image_url'
  132.     for localeName in localeNames:
  133.         # Find the first image
  134.         locale = locales[localeName]
  135.         if imageKey in locale and not os.path.exists(filename):
  136.             downloadEncryptedImage(opener, locale[imageKey], filename)
  137.             break
  138.  
  139. def safeMakeDirs(path):
  140.     if not os.path.exists(path):
  141.         os.makedirs(path)
  142.  
  143. def downloadChapter(opener, chapter, directory):
  144.     number = chapter['number']
  145.     print 'chapter ' + number
  146.     chapterDir = os.path.join(directory, '{:04}'.format(int(number)))
  147.     safeMakeDirs(chapterDir)
  148.     chapterInfo = getChapterInfo(opener, chapter['chapter_id'])
  149.     pages = chapterInfo['pages']
  150.     for index, page in enumerate(pages):
  151.         sys.stdout.write('\t{0}/{1}\r'.format(int(index)+1, len(pages)))
  152.         sys.stdout.flush()
  153.         downloadPage(opener, page, chapterDir)
  154.     sys.stdout.write('\n')
  155.  
  156. def downloadSeriesWithID(opener, seriesID):
  157.     seriesInfoURL = 'http://api.jmanga.com/chapters?series%5Fid=' + seriesID
  158.     result        = opener.open(seriesInfoURL)
  159.     seriesInfo    = json.loads(result.read())
  160.     series        = seriesInfo['series']
  161.     localizedInfo = series['locale']['enUS']
  162.     print localizedInfo['name']
  163.     directory = os.path.join('jmanga', seriesID)
  164.     safeMakeDirs(directory)
  165.     downloadEncryptedImage(opener, localizedInfo['encrypted_image_url'], directory + '.jpg')
  166.     chapters = seriesInfo['chapters']
  167.     for chapter in chapters:
  168.         if chapter['purchased']:
  169.             downloadChapter(opener, chapter, directory)
  170.  
  171. def getMangaSeries(opener):
  172.     listAddress = 'http://www.jmanga.com/ajax/'
  173.     requestData = 'req=RpcApiUser_LoadMyManga&_='
  174.     result = opener.open(listAddress, requestData)
  175.     seriesIDs = extractSeriesIDs(result.read())
  176.     for seriesID in seriesIDs:
  177.         downloadSeriesWithID(opener, seriesID)
  178.  
  179. def main():
  180.     username, password = getCredentials()
  181.     opener = login(username, password)
  182.     getMangaSeries(opener)
  183.  
  184. if __name__ == "__main__":
  185.     main()
Add Comment
Please, Sign In to add comment