initial commit
This commit is contained in:
106
bin/sync_zotero_rm
Normal file
106
bin/sync_zotero_rm
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from pyzotero import zotero
|
||||
from webdav3.client import Client
|
||||
from tempfile import TemporaryDirectory
|
||||
from os.path import join
|
||||
import subprocess
|
||||
import zipfile
|
||||
from rmapy.api import Client as RMClient
|
||||
from rmapy.folder import Folder
|
||||
from rmapy.document import Document
|
||||
from rmapy.document import ZipDocument
|
||||
from sync_zotero_rm.config import get_config
|
||||
|
||||
if __name__ == "__main__":
|
||||
# get/create config
|
||||
cfg = get_config()
|
||||
|
||||
# TODO init remarkabel connection
|
||||
|
||||
# init all services and apis we need
|
||||
zot = zotero.Zotero(cfg['zot_user_id'], "user", cfg['zot_api_key'])
|
||||
rmapy = RMClient()
|
||||
rmapy.renew_token()
|
||||
|
||||
# used for zotero pdf download
|
||||
webdav = Client({
|
||||
"webdav_hostname": cfg['webdav_url'],
|
||||
"webdav_login": cfg['webdav_user'],
|
||||
"webdav_password": cfg['webdav_password']
|
||||
})
|
||||
|
||||
# temp dir for file processing
|
||||
tempdir = TemporaryDirectory()
|
||||
|
||||
# find the zotero collection key
|
||||
print("Fetching collection from Zotero... ", end="", flush=True)
|
||||
zot_collections = zot.collections()
|
||||
for collection in zot_collections:
|
||||
if collection['data']['name'] == cfg['zot_collection']:
|
||||
zot_collection_key = collection['data']['key']
|
||||
print("Done")
|
||||
|
||||
# get pdf items in collection
|
||||
print("Fetching item list... ", end="", flush=True)
|
||||
zot_items = zot.collection_items(zot_collection_key)
|
||||
zot_items_pdf = [item for item in zot_items
|
||||
if "contentType" in item['data']
|
||||
and item['data']['contentType'] == "application/pdf"
|
||||
]
|
||||
print("Done")
|
||||
|
||||
print(f"Items to sync: {len(zot_items_pdf)}")
|
||||
|
||||
# get existing documents and folders on remarkable
|
||||
rm_items = rmapy.get_meta_items()
|
||||
rm_folders = [f for f in rm_items if isinstance(f, Folder)]
|
||||
rm_documents = [f for f in rm_items if isinstance(f, Document)]
|
||||
rm_existing_names = [f.VissibleName for f in rm_documents]
|
||||
|
||||
# find or create correct folder on remarkable
|
||||
folder = [f for f in rm_folders if f.VissibleName == cfg['rm_folder']]
|
||||
if len(folder) > 0:
|
||||
folder = folder[0]
|
||||
else: # folder does not exist yet
|
||||
print(f"Creating folder {remarkable_folder}")
|
||||
folder = Folder(cfg['rm_folder'])
|
||||
rmapy.create_folder(folder)
|
||||
|
||||
# Process items
|
||||
for item in zot_items_pdf:
|
||||
title = item['data']['title']
|
||||
print(title)
|
||||
|
||||
if title[:-4] in rm_existing_names:
|
||||
print("skip (already exists)")
|
||||
else:
|
||||
# Download via webdav
|
||||
print("download, ", end="", flush=True)
|
||||
key = item['key']
|
||||
local_path = join(tempdir.name, f"{key}.zip")
|
||||
webdav.download_sync(remote_path=f"{key}.zip", local_path=local_path)
|
||||
|
||||
# Unpack file
|
||||
print("unpack, ", end="", flush=True)
|
||||
with zipfile.ZipFile(local_path, "r") as zip:
|
||||
zip.extract(title, path=tempdir.name)
|
||||
file_path = join(tempdir.name, title)
|
||||
|
||||
# Upload to RM
|
||||
print("upload ", end="", flush=True)
|
||||
rawDocument = ZipDocument(doc=file_path)
|
||||
success = rmapy.upload(rawDocument, folder)
|
||||
if success:
|
||||
print("done")
|
||||
else:
|
||||
print("Upload failed")
|
||||
exit(1)
|
||||
|
||||
# Delete files from zotero collection
|
||||
print("Removing items from zotero collection")
|
||||
for item in zot_items:
|
||||
if item['data']['itemType'] == "attachment":
|
||||
continue
|
||||
zot.deletefrom_collection(zot_collection_key, item)
|
||||
|
||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
rmapy==0.2.1
|
||||
Pyzotero==1.4.16
|
||||
webdavclient3==3.14.4
|
||||
14
setup.py
Normal file
14
setup.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
install_reqs = [line.strip() for line in open("requirements.txt").readlines()]
|
||||
packs = find_packages(exclude=["bin"])
|
||||
|
||||
setup(
|
||||
name="sync_zotero_rm",
|
||||
version="0.0.1",
|
||||
author="Daniel Bauer",
|
||||
description="Sync zotero collections to remarkable devices",
|
||||
install_requires=install_reqs,
|
||||
scripts=["bin/sync_zotero_rm"],
|
||||
packages=packs
|
||||
)
|
||||
0
sync_zotero_rm/__init__.py
Normal file
0
sync_zotero_rm/__init__.py
Normal file
57
sync_zotero_rm/config.py
Normal file
57
sync_zotero_rm/config.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from os.path import join
|
||||
|
||||
CONFIG_FILE = join(str(Path.home()), ".zotero_remarkable.yaml")
|
||||
|
||||
def _read_config():
|
||||
try:
|
||||
with open(CONFIG_FILE, "r") as f:
|
||||
return yaml.safe_load(f)
|
||||
except:
|
||||
return None
|
||||
|
||||
def _write_config(cfg):
|
||||
with open(CONFIG_FILE, "w", encoding="utf8") as f:
|
||||
yaml.dump(cfg, f, default_flow_style=False, allow_unicode=True)
|
||||
|
||||
def _check_config(cfg):
|
||||
if not isinstance(cfg, dict):
|
||||
return False
|
||||
valid = True
|
||||
for i in [
|
||||
"zot_api_key",
|
||||
"zot_user_id",
|
||||
"zot_collection",
|
||||
"webdav_url",
|
||||
"webdav_user",
|
||||
"webdav_password",
|
||||
"rm_folder"]:
|
||||
if i not in cfg:
|
||||
valid = False
|
||||
return valid
|
||||
|
||||
def _create_config():
|
||||
cfg = {}
|
||||
for i in [
|
||||
"zot_api_key",
|
||||
"zot_user_id",
|
||||
"zot_collection",
|
||||
"webdav_url",
|
||||
"webdav_user",
|
||||
"webdav_password",
|
||||
"rm_folder"]:
|
||||
answer = input(i + ": ")
|
||||
cfg[i] = answer.strip()
|
||||
_write_config(cfg)
|
||||
return cfg
|
||||
|
||||
def get_config():
|
||||
cfg = _read_config()
|
||||
if not _check_config(cfg):
|
||||
return _create_config()
|
||||
else:
|
||||
return cfg
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user