Skip to content

Instantly share code, notes, and snippets.

@bochoven
Created April 11, 2019 14:21
Show Gist options
  • Save bochoven/4a2ea747670953a6401c30bc014734dd to your computer and use it in GitHub Desktop.
Save bochoven/4a2ea747670953a6401c30bc014734dd to your computer and use it in GitHub Desktop.
Downloads iBooks from a public Stack repository.
#!/usr/bin/python
# encoding: utf-8
''' Downloads iBooks from Stack storage
Complexity is a result from the CSRF token that is needed for the download.
'''
import urllib, urllib2, json, re, cookielib, os, xattr
from Cocoa import NSWorkspace, NSImage
PAGE_URL = 'https://username.stackstorage.com/s/6hjYxxxxKnp6x'
BASE_URL = "https://username.stackstorage.com/public-share/6hjYxxxxKnp6x"
XATTR_ETAG = 'nl.vu.mlx_downloader.etag'
TARGET_DIRECTORY = "/Users/Shared/MLX Book Library/"
ICON_PATH = "/usr/local/vu/pictures/mlx.png"
def load_list(url):
response = urllib.urlopen(url)
data = json.loads(response.read())
return data['nodes']
def download(url, formdata):
data = urllib.urlencode(formdata)
content = urllib2.urlopen(url=url, data=data)
filename = full_path(os.path.basename(formdata['paths[]']))
with open(filename, "wb") as local_file:
local_file.write(content.read())
xattr.setxattr(filename, XATTR_ETAG, formdata['etag'])
def get_csrf_token(url):
request = urllib2.Request(url)
data = urllib2.urlopen(request).read()
result = re.search(r'<meta name="csrf-token" content="([^"]+)">', data)
return result.group(1)
def init_cookie_jar():
cookie_jar = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar))
urllib2.install_opener(opener)
def getxattr(pathname, attr):
"""Get a named xattr from a file. Return None if not present"""
if attr in xattr.listxattr(pathname):
return xattr.getxattr(pathname, attr)
else:
return None
def file_exists_and_up_to_date(file, etag):
try:
if etag == getxattr(file, XATTR_ETAG):
return True
except Exception as e:
pass
return False
def full_path(file):
return TARGET_DIRECTORY + file
def is_ibooks_file(file):
return re.match(r".*\.ibooks$", file)
def set_directory_icon(icon_path, directory):
NSWorkspace.sharedWorkspace().setIcon_forFile_options_(
NSImage.alloc().initWithContentsOfFile_(icon_path), directory, 0)
def main():
"""Main"""
if not os.path.exists(TARGET_DIRECTORY):
os.makedirs(TARGET_DIRECTORY)
set_directory_icon(ICON_PATH, TARGET_DIRECTORY)
init_cookie_jar()
csrf_token = get_csrf_token(PAGE_URL)
booklist = load_list(BASE_URL + '/list')
for book in booklist:
local_path = full_path(os.path.basename(book['path']))
if not is_ibooks_file(local_path):
print "Skipping %s: not an ibook" % local_path
continue
if file_exists_and_up_to_date(local_path, book['etag']):
print "Skipping %s: not changed" % local_path
continue
formdata = {
'paths[]': book['path'],
'CSRF-Token': csrf_token,
'etag': book['etag']
}
try:
print "Downloading %s" % local_path
download(BASE_URL + '/download', formdata)
except Exception as e:
print e
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment