diff --git a/docs/source/index.rst b/docs/source/index.rst index 26f871b..3ab11d4 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -14,14 +14,15 @@ Some content API Support ~~~~~~~~~~~ -| ☑️ list files and directories -| ☑️ download a specific file -| ☑️ create a directory -| ☑️ move / rename a file or directory -| ❎ upload a file -| ❎ delete a file or directory -| ❎ shell -| ❎ annotiation exports +| ☑️ List content in the cloud +| ☑️ Work with documents & folders +| ☑️ create a folder +| ☑️ move / rename a document or folder +| ❎ create a document +| ❎ edit a document +| ❎ delete a document or folder +| ❎ cli interface +| ❎ export pdf with annotations @@ -33,7 +34,6 @@ Installation installation - Quick start ~~~~~~~~~~~ diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 6296eb2..079745c 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -5,5 +5,3 @@ rmapipy :maxdepth: 4 rmapi - - diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst index aba7a35..20282ed 100644 --- a/docs/source/quickstart.rst +++ b/docs/source/quickstart.rst @@ -40,5 +40,126 @@ and use the code you see on the webpage Working with items ~~~~~~~~~~~~~~~~~~ -The remarkable fs structure is flat containing metadata objects. +The remarkable fs structure is flat containing metadata objects of two types: + +* DocumentType +* CollectionType + +We can list the items in the Cloud: + +.. code-block:: python + :linenos: + + + >>> from rmapi.api import Client + >>> rmapi = Client() + >>> rmapi.renew_token() + True + >>> collection = rmapi.get_meta_items() + >>> collection + + >>> len(collection) + 181 + >>> # Count the amount of documents + ... from rmapi.document import Document + >>> len([f for f in collection if isinstance(f, Document)]) + 139 + >>> # Count the amount of folders + ... from rmapi.folder import Folder + >>> len([f for f in collection if isinstance(f, Folder)]) + 42 + + + +DocumentType +```````````` + +A DocumentType is a document. This can be a pdf, epub or notebook. +These types are represented by the object :class:`rmapi.document.Document` + + +Changing the metadata is easy:: + +.. code-block:: python + :linenos: + + + >>> from rmapi.api import Client + >>> rmapi = Client() + >>> rmapi.renew_token() + True + >>> collection = rmapi.get_meta_items() + >>> doc = [ d for d in collection if d.VissibleName == 'ModernC'][0] + >>> doc + + >>> doc.to_dict() + {'ID': 'a969fcd6-64b0-4f71-b1ce-d9533ec4a2a3', 'Version': 1, 'Message': '', 'Succes': True, 'BlobURLGet': '', 'BlobURLGetExpires': '0001-01-01T00:00:00Z', 'BlobURLPut': '', 'BlobURLPutExpires': '', 'ModifiedClient': '2019-09-18T20:12:07.206206Z', 'Type': 'DocumentType', 'VissibleName': 'ModernC', 'CurrentPage': 0, 'Bookmarked': False, 'Parent': ''} + >>> doc.VissibleName = "Mordern C: The book of wisdom" + >>> # push the changes back to the Remarkable Cloud + ... rmapi.update_metadata(doc) + True + >>> collection = rmapi.get_meta_items() + >>> doc = [ d for d in docs if d.VissibleName == 'ModernC'][0] + Traceback (most recent call last): + File "", line 1, in + IndexError: list index out of range + >>> doc = [ d for d in docs if d.VissibleName == 'Mordern C: The book of wisdom'][0] + >>> doc + + >>> doc.to_dict() + {'ID': 'a969fcd6-64b0-4f71-b1ce-d9533ec4a2a3', 'Version': 1, 'Message': '', 'Succes': True, 'BlobURLGet': '', 'BlobURLGetExpires': '0001-01-01T00:00:00Z', 'BlobURLPut': '', 'BlobURLPutExpires': '', 'ModifiedClient': '2019-09-18T20:12:07.206206Z', 'Type': 'DocumentType', 'VissibleName': 'Mordern C: The book of wisdom', 'CurrentPage': 0, 'Bookmarked': False, 'Parent': ''} + + +CollectionType +`````````````` + + +A CollectionType is a Folder. + +These types are represented by the object :class:`rmapi.folder.Folder` + +Working with folders is easy!:: + +.. code-block:: python + :linenos: + + + >>> from rmapi.api import Client + >>> rmapi = Client() + >>> rmapi.renew_token() + True + >>> collection = rmapi.get_meta_items() + >>> collection + + >>> from rmapi.folder import Folder + >>> # Get all the folders. Note that the fs of Remarkable is flat in the cloud + ... folders = [ f for f in collection if isinstance(f, Folder) ] + >>> folders + [, , ...] + >>> # Get the root folders + ... root = [ f for f in folders if f.Parent == "" ] + >>> root + [, , ...] + >>> # Create a new folder + ... new_folder = Folder("New Folder") + >>> new_folder + + >>> rmapi.create_folder(new_folder) + True + >>> # verify + ... [ f for f in rmapi.get_meta_items() if f.VissibleName == "New Folder" ] + [] + >>> [ f for f in rmapi.get_meta_items() if f.VissibleName == "New Folder" ][0].ID == new_folder.ID + True + >>> # Move a document in a folder + ... doc = rmapi.get_doc("a969fcd6-64b0-4f71-b1ce-d9533ec4a2a3") + >>> doc + + >>> doc.Parent = new_folder.ID + >>> # Submit the changes + ... rmapi.update_metadata(doc) + True + >>> doc = rmapi.get_doc("a969fcd6-64b0-4f71-b1ce-d9533ec4a2a3") + >>> doc.Parent == new_folder.ID + True diff --git a/docs/source/rmapi.rst b/docs/source/rmapi.rst index cea6482..b9d35b1 100644 --- a/docs/source/rmapi.rst +++ b/docs/source/rmapi.rst @@ -60,6 +60,14 @@ rmapi.folder module :undoc-members: :show-inheritance: +rmapi.meta module +----------------- + +.. automodule:: rmapi.meta + :members: + :undoc-members: + :show-inheritance: + rmapi.types module ------------------ diff --git a/rmapi/meta.py b/rmapi/meta.py new file mode 100644 index 0000000..60e4680 --- /dev/null +++ b/rmapi/meta.py @@ -0,0 +1,71 @@ +class Meta(object): + """ Meta represents a real object expected in most + calls by the remarkable API + + This class is used to be subclassed by for new types. + + Attributes: + ID: Id of the meta object. + Version: The version of this object. + Success: If the last API Call was a succes. + BlobURLGet: The url to get the data blob from. Can be empty. + BlobURLGetExpires: The expiration date of the Get url. + BlobURLPut: The url to upload the data blob to. Can be empty. + BlobURLPutExpires: The expiration date of the Put url. + ModifiedClient: When the last change was by the client. + Type: Currently there are only 2 known types: DocumentType & + CollectionType. + VissibleName: The human name of the object. + CurrentPage: The current selected page of the object. + Bookmarked: If the object is bookmarked. + Parent: If empty, this object is is the root folder. This can be an ID + of a CollectionType. + + """ + + ID = "" + Version = 0 + Message = "" + Succes = True + BlobURLGet = "" + BlobURLGetExpires = "" + BlobURLPut = "" + BlobURLPutExpires = "" + ModifiedClient = "" + Type = "" + VissibleName = "" + CurrentPage = 1 + Bookmarked = False + Parent = "" + + def __init__(self, **kwargs): + kkeys = self.to_dict().keys() + for k in kkeys: + setattr(self, k, kwargs.get(k, getattr(self, k))) + + def to_dict(self) -> dict: + """Return a dict representation of this object. + + Used for API Calls. + + Returns + a dict of the current object. + """ + + return { + "ID": self.ID, + "Version": self.Version, + "Message": self.Message, + "Succes": self.Succes, + "BlobURLGet": self.BlobURLGet, + "BlobURLGetExpires": self.BlobURLGetExpires, + "BlobURLPut": self.BlobURLPut, + "BlobURLPutExpires": self.BlobURLPutExpires, + "ModifiedClient": self.ModifiedClient, + "Type": self.Type, + "VissibleName": self.VissibleName, + "CurrentPage": self.CurrentPage, + "Bookmarked": self.Bookmarked, + "Parent": self.Parent + } +