def renew_user_token(self, user_email: str) -> bool: cfg = self.get_config_for_user(user_email) rm = Client(config_dict=cfg) new_cfg = rm.renew_token(save_to_file=False) UserModel.get(user_email).update(actions=[ UserModel.device.set(new_cfg["devicetoken"]), UserModel.user.set(new_cfg["usertoken"]), ]) return new_cfg
def transfer_file_to_remarkable(user_email: str, fname, fbytes): # logging.info(f"Asking for {user_email} credentials...") cfg = get_config_for_user(user_email) rm = Client(config_dict=cfg) # Annoychops; gotta save to disk. Bummski! tfile = tempfile.NamedTemporaryFile(prefix=fname, suffix=".pdf") tfile.write(fbytes) tfile.seek(0) doc = ZipDocument(doc=tfile.name) rm.upload(doc)
class Uploader: def __init__(self): self._rmapy = Client() self._rmapy.renew_token() def upload_file_to_folder(self, file: str, folder_name: str): folder = self._find_folder(folder_name) document = ZipDocument(doc=file) document.metadata["VissibleName"] = Path(file).stem self._rmapy.upload(document, folder) def _find_folder(self, folder_name: str) -> Folder: return next( item for item in self._rmapy.get_meta_items() if isinstance(item, Folder) and item.VissibleName == folder_name)
def __init__(self): """Initialize the class by connecting the user to the ReMarkable cloud.""" self.client = Client() if not self.client.is_auth(): click.confirm( "We will need to register with the ReMarkable cloud. \ Please confirm that we may open a webpage.", abort=True, ) click.launch("https://my.remarkable.com/connect/remarkable") device_token = click.prompt("Please enter the device token below") self.client.register_device(device_token) self.client.renew_token()
def transfer_file_to_remarkable(user_email: str, fname, fbytes): plog(f"* Asking for {user_email} credentials...") cfg = renew_user_token(user_email) rm = Client(config_dict=cfg) # Annoychops; gotta save to disk. Bummski! tfile = tempfile.NamedTemporaryFile(prefix=fname, suffix=".pdf") tfile.write(fbytes) tfile.seek(0) plog(f"* Generating zip...") doc = ZipDocument(doc=tfile.name) plog(f"* Uploading to device.") rm.upload(doc) plog("Success.") send_email_if_enabled( user_email, subject="Your document is on the way!", message= f"Your document, '{fname}', has been successfully sent to your reMarkable.", )
def upload(filepath=None): if not filepath: parser = argparse.ArgumentParser( "Upload Goosepaper to reMarkable tablet") parser.add_argument( "file", default=None, help="The file to upload", ) args = parser.parse_args() filepath = args.file filepath = Path(filepath) client = Client() try: client.renew_token() except AuthError: print( "Looks like this if the first time you've uploaded, need to register the device" ) print( "Get the code from here: https://my.remarkable.com/connect/remarkable" ) code = input() print("registering") client.register_device(code) if not client.renew_token(): print("registration failed D:") else: print("registration successful") for item in client.get_meta_items(): if item.VissibleName == filepath.stem: print("Honk! Paper already exists!") return False doc = ZipDocument(doc=str(filepath.resolve())) if client.upload(doc): print("Honk! Upload successful!") else: print("Honk! Error with upload!") return True
def transfer_file_to_remarkable(fname: str, config_dict: dict = None): from rmapy.document import ZipDocument from rmapy.api import Client rm = Client(config_dict=config_dict) rm.renew_token() doc = ZipDocument(doc=fname) rm.upload(doc) return True
def upload_rm_doc(name, rms): empty_jpg = Path(__file__).parent / "empty.jpg" empty_jpg_bytes = empty_jpg.read_bytes() rmapy = Client() if not rmapy.is_auth(): raise Exception("Not authenticated") rmapy.renew_token() rmps = [] for rm in rms: layer_counter = count(1) buffer = BytesIO() rm.to_bytes(buffer) buffer.seek(0) uuid = str(uuid4()) rmp = RmPage( buffer, metadata={ "layers": [{ "name": layer.name if layer.name else f"Layer {next(layer_counter)}" } for layer in rm.objects] }, thumbnail=BytesIO(empty_jpg_bytes), order=uuid, ) rmps.append(rmp) zd = ZipDocument() zd.content["fileType"] = "notebook" zd.content["pages"] = [rmp.order for rmp in rmps] zd.content["pageCount"] = len(rmps) zd.metadata["VissibleName"] = name zd.pagedata = "\n".join(["Blank"] * len(rmps)) zd.rm.extend(rmps) rmapy.upload(zd)
def auth_client(): client = Client() try: client.renew_token() except AuthError: print("Looks like this is the first time you've uploaded. You need to " f"register the device. Input a code from {CODE_URL}") code = input() print("registering") client.register_device(code) if not client.renew_token(): print("Honk! Registration renewal failed.") return False else: print("registration successful") return client
def main(): todo_manager = TodoManager() today = date.today() pdf_path = '/tmp/Today-{}.pdf'.format(today.strftime("%b-%d-%Y")) todo_string = todo_manager.getToDoListString() f = open(MARKDOWN_PATH, "w") f.write(todo_string) f.close() r = subprocess.run(['pandoc', '-s', MARKDOWN_PATH, '-o', pdf_path], stdout=subprocess.PIPE, universal_newlines=True) rm = Client() rm.renew_token() rawDocument = ZipDocument(doc=pdf_path) rm.upload(rawDocument) print(todo_string)
def auth_client(): client = Client() try: client.renew_token() except AuthError: print( "Looks like this if the first time you've uploaded, need to register the device" ) print("Get the code from here: https://my.remarkable.com/connect/remarkable") code = input() print("registering") client.register_device(code) if not client.renew_token(): print("Honk! Registration failed D:") return False else: print("registration successful") return client
def mostRecentDownloadDate(rmClient: rmapi.Client, folder: rmapi.Folder) -> datetime.date: docs = [d for d in rmClient.get_meta_items() if d.Parent == folder.ID and isinstance(d, rmapi.Document)] return max([datetime.date.fromisoformat(d.VissibleName) for d in docs])
def register_user(user_email: str, code: str): rm = Client() rm.register_device(code, save_to_file=False) new_cfg = rm.renew_token(save_to_file=False) set_config_for_user(user_email, new_cfg) return True
import os import sys from rmapy.api import Client import log # Start logging stuff logger = log.setup_logger(__name__) rmapy = Client() # This registers the client as a new device. The received device token is # stored in the users directory in the file ~/.rmapi, the same as with the # go rmapi client. home = os.path.expanduser("~") if os.path.exists(home + "/.rmapi"): if rmapy.is_auth(): print( "Your Device is already authorized. If you believe this is incorrect, delete ~/.rmapi in your home directory and try to register again." ) elif rmapy.renew_token(): print("Token renewed!") else: logger.warning( "error occured while registering. ~./rmapi token exists, but another token is not able to renew." ) else: print( "Go to my reMarkable (https://my.remarkable.com/connect/desktop) to register a new device and enter the code returned after registering:" ) rmapy.register_device(input())
import sys from rmapy.document import ZipDocument from rmapy.api import Client rmapy_client = Client() rmapy_client.renew_token() doc = ZipDocument(doc=sys.argv[1]) rmapy_client.upload(doc)
from rmapy.api import Client from rmapy.document import ZipDocument, Document FILENAME = 'notes.pdf' rmapy = Client() # This registers the client as a new device. The received device token is # stored in the users directory in the file ~/.rmapi, the same as with the # go rmapi client. # rmapy.register_device("kmdfhcsf") rmapy.renew_token() rawDocument = ZipDocument(doc=FILENAME) collection = rmapy.get_meta_items() # Gather old versions to delete old = [ f for f in collection if isinstance(f, Document) and f.VissibleName == 'notes' ] rmapy.upload(rawDocument) for f in old: rmapy.delete(f)
class Remarkable: converters = {} def __init__(self, *, sync_manager): self.rm_api = Client() self.rm_meta = None self.sync_manager = sync_manager def connect(self): self.rm_api.renew_token() def get_meta(self): self.rm_meta = list(self.rm_api.get_meta_items()) def toc(self): if not self.rm_meta: self.get_meta() documents = [ item for item in self.rm_meta if isinstance(item, Document) ] toc = { d.ID: d.Version for d in documents } folders = [ item for item in self.rm_meta if isinstance(item, Folder) ] return toc def folder_children(self, parent=''): if not self.rm_meta: self.get_meta() return { d: self.folder_children(d.ID) for d in self.rm_meta if isinstance(d, Folder) and d.Parent == parent } def pull(self): pass def upload_document(self, local_id, local_version, cloud_id, cloud_version, path): content_dir = ( self.sync_manager.push_dir(Remarkable) + f'/{local_id}/{local_version}' ) content_path = f'{content_dir}/{local_id}.pdf' if cloud_version: # reMarkable won't sync updates, need to delete # and re-add to_delete = Document(ID=cloud_id, Version=cloud_version) self.rm_api.delete(to_delete) doc = ZipDocument(doc=content_path) folder = self.get_or_create_folder(path) doc.metadata['VissibleName'] = get_pdf_title(content_path) doc.metadata['version'] = 1 mapping_info = SyncMapping( remote_id=doc.ID, remote_version = 1, remote_path=path ) print(f"push: document '{doc.metadata['VissibleName']}' {local_id} to {mapping_info.remote_path})") self.rm_api.upload(doc, folder) return mapping_info def get_or_create_folder(self, path, parent=None, subtree=None): match_start = config.get('folder_match', 'exact') == 'start' if not path: return None if not subtree: subtree = self.folder_children() top = path[0] matched_folder = None for folder in subtree: if not match_start and folder.VissibleName == top: matched_folder = folder break elif match_start and folder.VissibleName.startswith(top): matched_folder = folder break if not matched_folder: matched_folder = Folder(top) if parent: matched_folder.Parent = parent.ID self.rm_api.create_folder(matched_folder) self.rm_meta.append(matched_folder) children = {} else: children = subtree[matched_folder] if len(path) > 1: return self.get_or_create_folder(path[1:], parent=matched_folder, subtree=children) else: return matched_folder def push(self, force=False): local_toc = self.sync_manager.local_toc(Remarkable, "push") cloud_toc = self.toc() if force: print("push: Force push requested") for item_id, local_version in local_toc.items(): mapping_info = self.sync_manager.get_mapping( Remarkable, item_id, local_version ) cloud_ver = None if mapping_info.remote_id: cloud_ver = cloud_toc.get(mapping_info.remote_id) local_cloud_ver = mapping_info.remote_version if not cloud_ver or local_cloud_ver > cloud_ver or force: if cloud_ver and cloud_ver > local_cloud_ver: print("push: pushing even though cloud version more recent than local") print(f" {item_id}/{local_version} < {cloud_ver}") mapping_info = self.upload_document( item_id, local_version, mapping_info.remote_id, cloud_ver, mapping_info.remote_path ) self.sync_manager.update_mapping( Remarkable, item_id, local_version, mapping_info )
def __init__(self, *, sync_manager): self.rm_api = Client() self.rm_meta = None self.sync_manager = sync_manager
import sys from rmapy.api import Client rmapy_client = Client() if not rmapy_client.is_auth(): rmapy_client.register_device(sys.argv[1])
from rmapy.api import Client rmapy = Client() def upload(): if rmapy.renew_token(): return True else: rmapy.log.error("Rmarkable token renew failed:")
class RemarkableDelivery(DeliveryMethod): """Delivery method class for the ReMarkable tablet.""" def __init__(self): """Initialize the class by connecting the user to the ReMarkable cloud.""" self.client = Client() if not self.client.is_auth(): click.confirm( "We will need to register with the ReMarkable cloud. \ Please confirm that we may open a webpage.", abort=True, ) click.launch("https://my.remarkable.com/connect/remarkable") device_token = click.prompt("Please enter the device token below") self.client.register_device(device_token) self.client.renew_token() def __str__(self): """Return a readable representation of the RemarkableDelivery class. :return: The display name of this class. Used when choosing this class from a list of options. """ return "ReMarkable" @staticmethod def convert_issue_to_pdf(book_path: str) -> str: """Convert an epub book file to a pdf format for the remarkable. \ Uses calibre command line utility `ebook-convert`. :param book_path: The absolute path to the epub file. :raises RuntimeError: Raises exception when calibre command line tools are not installed. :return: The absolute path to the converted pdf file. """ book_directory = os.path.dirname(book_path) pdf_path = os.path.join(book_directory, "./issue.pdf") exit_code = os.system(f"ebook-convert {book_path} {pdf_path}") if exit_code == 32512: # Try macOS location exit_code = os.system( f"/Applications/calibre.app/Contents/MacOS/ebook-convert {book_path} {pdf_path}" ) if exit_code == 32512: raise RuntimeError( "Calibre command line tools are not installed. \ Install from https://calibre-ebook.com") return pdf_path def deliver_issue(self, absolute_path: str): """Deliver issues to the ReMarkable. :param absolute_path: An absolute path for the epub file. """ # Ensure a "News Assistant" folder exists collection = self.client.get_meta_items() root_folders = [ f for f in collection if isinstance(f, Folder) and f.Parent == "" ] delivery_folder_filter = [ f for f in root_folders if f.VissibleName == DELIVERY_FOLDER ] if len(delivery_folder_filter) == 0: folder = Folder(DELIVERY_FOLDER) self.client.create_folder(folder) delivery_folder_filter.append(folder) delivery_folder = delivery_folder_filter[0] # Upload the issue pdf_path = RemarkableDelivery.convert_issue_to_pdf(absolute_path) document = ZipDocument(doc=pdf_path) now = datetime.now() document.metadata["VissibleName"] = now.strftime("%d %B, %Y") self.client.upload(document, delivery_folder)
from pathlib import Path from rmapy.api import Client from rmapy.document import ZipDocument from rmapy.folder import Folder rmapy = Client() rmapy.renew_token() class Uploader: def __init__(self): self._rmapy = Client() self._rmapy.renew_token() def upload_file_to_folder(self, file: str, folder_name: str): folder = self._find_folder(folder_name) document = ZipDocument(doc=file) document.metadata["VissibleName"] = Path(file).stem self._rmapy.upload(document, folder) def _find_folder(self, folder_name: str) -> Folder: return next( item for item in self._rmapy.get_meta_items() if isinstance(item, Folder) and item.VissibleName == folder_name)
def __init__(self): self._rmapy = Client() self._rmapy.renew_token()