Example #1
0
    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
Example #2
0
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)
Example #3
0
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()
Example #5
0
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.",
    )
Example #6
0
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
Example #7
0
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
Example #8
0
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)
Example #9
0
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
Example #10
0
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)
Example #11
0
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
Example #12
0
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])
Example #13
0
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
Example #14
0
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)
Example #16
0
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])
Example #20
0
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)
Example #22
0
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)
Example #23
0
 def __init__(self):
     self._rmapy = Client()
     self._rmapy.renew_token()