Last active
February 2, 2018 00:52
-
-
Save eugeneius/ccb6d98985c3fb0dd630 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