Package: rmcl
rmcl: reMarkable Cloud Libraryrmcl is a Python library for interacting with the reMarkable cloud.  It
supports a file-tree view onto your files, exposes metadata, and gives
access to the original PDF or EPUB documents.  Ifrmrlis installed, it can also
produce PDF versions of any type of document with your annotations
included.  rmcl can create, update, and delete items from the
reMarkable cloud.Quick DemoAs a taste, this code will list all of the files and their types in the
root directory of your reMarkable cloud.fromrmclimportItem,Document,Folderimporttrioasyncdeflist_files():root=awaitItem.get_by_id('')# The root folder has ID of empty stringforchildinroot.children:ifisinstance(child,Folder):print(f"{child.name}: folder")elifisinstance(child,Document):# The only other possibilityprint(f"{child.name}:{awaitchild.type()}")trio.run(list_files)Installationrmcl requires Python 3.7 or later.  If that's installed, the easiest
installation is to do apipinstallrmclAlternatively, you may clone this repository.Poetryis used for development, so once
that is installed you can runpoetryinstallto get a virtual environment all set up.rmcl is asynchronous, and must be used with thetrioasync library.FeaturesAsynchronousrmcl is asynchronous at its core.  This keeps it from blocking during the
many HTTP transactions it uses.  Most methods areasync, and therefore
must be called with theawaitkeyword.  rmcl is designed to work with
thetrioasync library.Synchronous OptionAsynchronous code can be overkill for simple scripts, so rmcl offers
synchronous versions of all of its async functions.  These functions
have a suffix of'_s'in their names.  This means that the above
example could be writtendeflist_files_sync():root=Item.get_by_id_s('')forchildinroot.children:ifisinstance(child,Folder):print(f"{child.name}: folder")elifisinstance(child,Document):print(f"{child.name}:{child.type_s()}")Note that these synchronous functions are still calling the asynchronous
low-level code.  They may fail if called within another asynchronous
framework.Object OrientedThe main interface to rmcl is theItemclass and its two subclasses,FolderandDocument.  The reMarkable cloud gives each item an ID.
If the ID of an Item is known, it can be retrieved with theItem.get_by_id()static method.  NewFolders andDocuments can be
made with the.new()class method, which expects as arguments the item's
name and parent ID.While the cloud API presents a flat directory structure, rmcl assembles
these objects into a file tree.  EveryFolderhas a.childrenattribute,
a list of theItems within it.  EachItemhas a.parentproperty,
which gives the ID of its parent.  (The ID is given instead of the parent to avoid circular references.)  The parent object ofitemmay be looked up
withawait Item.get_by_id(item.parent).Two "virtual" folders are provided.  The root folder (ID ='') contains
allItems with no explicit parent.  The trash folder (ID ='trash')
contains allItems marked as trashed.Various metadata are exposed as properties:.name,.id,.version,.parent, and.mtime, for modification time.  The.nameand.parentproperties can be modified, which updates the underlying metadata.  Such
changes can be sent to the cloud with the.update_metadata()method.The contents ofDocuments can be retrieved in several ways.  The.raw()method gets the zip file that the reMarkable cloud API uses
to transfer documents.  The.contents()method gets the original PDF
or EPUB file associated with aDocument.  Ifrmrlis installed, the.annotated()method yields a PDF file with the user's annotations.  All three methods
return a file-like object, but the exact type is not guaranteed and may
vary in the future.  The same object may be returned from multiple calls
to a given method; the user is responsible for coordinatingreads andseeks to avoid contention.NewItems or existingDocuments with new contents may be uploaded to
the cloud with.upload()method.Smart Updatesrmcl keeps a list of all documents in the reMarkable cloud, so that it
doesn't need to query the API for each bit of information.  To ensure
this list is up to date, it automatically refreshes itself when you useItem.get_by_id()more than five minutes after the last refresh.  You
can also trigger this behavior by callingrmcl.invalidate_cache()beforeItem.get_by_id().rmcl only updates objects that have a new version, so existing objects
remain valid.  Nonetheless, it is better to callItem.get_by_id()often, instead of keeping your own list ofItems.Caching Expensive OperationsSome of this information, like document type and size, require several
round trips to calculate.  rmcl stores these values locally, so they do
not need to be recalculated every time.  They are stored in a persistent
database, so this information is not lost when the process stops.  The
database stores this information by version, so it knows when it must be
recalculated.Handles AuthenticationThe reMarkable cloud requires two tokens: Thedevice tokenidentifies
your device and needs only to be set once.  Theuser tokenis used on
most requests, and should be updated occasionally.  rmcl automatically
renews the user token once a day, or when it receives an authentication
error from the API.Getting the device token requires user interaction the first time a
program is run.  If rmcl detects that it is being run interactively, it
will print instructions and prompt to user to input a new device token.
Otherwise, it will throw armcl.exceptions.AuthError.  You must callregister_device(code)with the code provided obtained fromhttps://my.remarkable.com/connect/desktop.  Once obtained, the device
token is stored for future use.Comparison with rMapyrmcl started as a fork ofrMapy.
As we started moving in a rather different direction, we decided it
would be better to make it into its own project.  At this point, only
some of the low-level API code from rMapy remains.To help users decide which library best fits their needs, here are the
major differences:rmcl is asynchronous, while rMapy is synchonous.  This means that
rmcl will not block while making HTTP requests to the reMarkable API.
rmcl's synchronous functions will block, much like rMapy.rmcl has a simpler object structure, mostly focused aroundItemand
its subclassesDocumentandFolder.  rMapy has similar objects
(Meta,Document, andFolder), but it also has aClientandCollectionsingleton objects, and operations like getting documents
or listing directories are provided by these singletons.rmcl abstracts away some details of the reMarkable cloud API, while
rMapy provides a more direct mapping of the API into Python.  For
instance, rMapy items have a.VissibleName[sic]property, because
that's what the API provides.  rmcl turns this into a.nameproperty.
In rmcl,Folders have a list of children, but in rMapy, the children
must be looked up via theCollectionsingleton.  (The API provides
a flat file list.)rMapy is more complete than rmcl.  rMapy exposes all metadata as
properties, while rmcl only exposes some metadata items.  rMapy provides
an object model for the zip files provided by the API, while rmcl just
exposes the zip files themselves.rMapy hasbetter documentationthan rmcl.  (But we're working on it!)TrademarksreMarkable(R) is a registered trademark of reMarkable AS. rmrl is not
affiliated with, or endorsed by, reMarkable AS. The use of "reMarkable" in
this work refers to the company’s e-paper tablet product(s).CopyrightCopyright 2019 Stijn Van CampenhoutCopyright 2020-2021 Robert Schrollrmcl is released under the MIT license.  See LICENSE.txt for details.