-
-
Save wwalker/3f4d971dd95100633355f5c751547396 to your computer and use it in GitHub Desktop.
Downloads every revision of your Xmarks bookmarks and saves them in a git repository.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import argparse | |
import getpass | |
import json | |
import re | |
import requests | |
import subprocess | |
parser = argparse.ArgumentParser() | |
parser.add_argument('--username', required=True) | |
parser.add_argument('--password') | |
args = parser.parse_args() | |
username = args.username | |
password = args.password | |
if password is None: | |
password = getpass.getpass() | |
login_url = 'https://login.xmarks.com/login/login' | |
r = requests.get(login_url, data=dict(username=username, password=password)) | |
r.raise_for_status() | |
token = re.search('<input type="hidden" name="token" value="([^"]*)" />', r.text).group(1) | |
r = requests.post(login_url, data=dict(username=username, password=password, token=token)) | |
r.raise_for_status() | |
session_cookie = r.cookies['XMARKS'] | |
print("Getting list of revisions from Xmarks...") | |
revisions_url = 'https://my.xmarks.com/bookmarks/syncd_get_revisions' | |
headers = { 'content-type': 'application/json' } | |
r = requests.post(revisions_url, cookies=dict(XMARKS=session_cookie), data=json.dumps({}), headers=headers) | |
r.raise_for_status() | |
response = r.text | |
revision_hashes = response.split('[')[1].split(']')[0] | |
revisions = json.loads('[{0}]'.format(revision_hashes)) | |
try: | |
process = subprocess.Popen(['git', 'log', '--max-count=1', '--format=%B'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
out, err = process.communicate() | |
last_revision = int(out) | |
except ValueError: | |
last_revision = 0 | |
revisions = filter(lambda revision: int(revision['revision']) > last_revision, revisions) | |
revisions = sorted(revisions, key=lambda revision: revision['revision']) | |
if not revisions: | |
print("No new revisions since last sync.") | |
raise SystemExit | |
print("Latest local revision: {0}".format(last_revision)) | |
print("Latest remote revision: {0}".format(revisions[-1]['revision'])) | |
for revision in revisions: | |
for attempt in range(3): | |
try: | |
print("Backup {0} downloading".format(revision['revision'])) | |
bookmarks_url = 'https://my.xmarks.com/bookmarks/view/{0}/bookmarks.html'.format(revision['revision']) | |
r = requests.get(bookmarks_url, cookies=dict(XMARKS=session_cookie)) | |
r.raise_for_status() | |
if '<H1>Bookmarks</H1>' not in r.text: | |
raise Exception('Backup appears to be corrupted!') | |
break | |
except Exception as e: | |
if attempt == 3: | |
raise e | |
with open('bookmarks.html', 'wb') as f: | |
f.write(r.text.encode('utf-8')) | |
subprocess.call(['git', 'add', 'bookmarks.html']) | |
subprocess.call(['git', 'commit', '--message={0}'.format(revision['revision'])]) | |
print("Backup {0} downloaded".format(revision['revision'])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment