erikbrinkman / rmapi-js

JavaScript implementation of the reMarkable api
https://erikbrinkman.github.io/rmapi-js/modules.html
MIT License
9 stars 1 forks source link

PDF upload #1

Closed Bartek532 closed 1 year ago

Bartek532 commented 1 year ago

Is it possible to upload a PDF using this lib? I've tried several times and didn't do it :( Maybe I'm doing something wrong? Or this functionality should be implemented?

erikbrinkman commented 1 year ago

It didn't used to, and recently remarkable changed their api, so this was a bit broken. As of version 2, you should be able to upload pdfs. Note, the uploadPdf function doesn't seem to work, so you'll have to use the more complicated putPdf. Make sure you follow all the steps from the example.

Let me know if this works!

Bartek532 commented 1 year ago

Seems working, thanks! I have one more question: could I create folders or move files using this lib? Or it's not implemented yet?

erikbrinkman commented 1 year ago

It should be possible, but is currently relatively complex, since this api doesn't currently try to recreate the filesystem. It probably seems reasonable to make a folder creation method. Moving is a bit difficult, but if you can propose a reasonable API, I'd be down to implement it.

Adding a folder

This should be done similar to uploading an epub or a pdf.

const documentId = uuid4();
const lastModified = `${new Date().valueOf()}`;

const entryPromises: Promise<Entry>[] = [];

// upload metadata
const metadata: CollectionTypeMetadata = {
  type: "CollectionType",
  visibleName: "<YOUR FOLDER NAME HERE>",
  version: 0,
  parent: "<PARENT DOCUMENT ID HERE, or empty for root>",
  synced: true,
  lastModified,
};
entryPromises.push(
  api.putText(`${documentId}.metadata`, JSON.stringify(metadata))
);
entryPromises.push(
  api.putText(`${documentId}.content`, "{}") // empty json, but could have tags and such
);

const entries = await Promise.all(entryPromises);
const folderEntry = await api.putEntries(documentId, entries);

then, just like with putPdf you'll need to do the following steps:

const [root, gen] = await api.getRootHash();
const rootEntries = await api.getEntries(root);
rootEntries.push(folderEntry);
const { hash } = await api.putEntries("", rootEntries);
const nextGen = await api.putRootHash(hash, gen);
await api.syncComplete(nextGen);

Moving a folder

Based on the previous steps, moving a folder should be pretty easy. You need to first find it's entry in the root entries. Then just like creating a new folder, you'll need to create a new metadata file. It'll be easiest to find the internal entry whos documentId is <documentId>.metadata and use getMetadata on that. Update the parent field to the documentId of the parent you want, and then call api.putText("<documentId>.metadata", JSON.stringify(newMetadata)); After that you'll need to update the entry for the collection by keeping all of the other entries, but replacing the metadata entry, e.g. const folderEntry = await api.putEntries(documentId, [newMetaDataEntry, ...oldEntries]); where oldEntries doesn't have the old metadata. Finally you'll also need to update the root in the same way. as before, making sure to remove the entry for the folder.

That probably wasn't super clear, so if you want me to walk through an example I can.

⚠️ I also want to be very clear that whenever you update the root hash, if you do it incorrectly you can risk "deleting" everything. RM support is usually able to reset it, but it takes a long time. If you are worried, before messing around, save your old rootHash. You should then be able to revert any changes by doing const [_, gen] = await api.getRootHash(); await api.putRootHash("<saved hash>", gen);

erikbrinkman commented 1 year ago

After thinking about it, I decided to update the library. v2.1.1 now has putCollection(name) which creates a folder. It has an optional second parameter for the parent documentId (empty / omitted for root or "trash" for trash). Moving will still take the same manual effort of fetching, editing, and progressively saving.

erikbrinkman commented 1 year ago

I decided it would be helpful to add an example, so version 2.2.0 includes create and move that provide a somewhat high level way to move items anywhere and to remove some of the boilerplate for syncing the changes of adding an item.

It's worth calling out that they're generally inefficient, but if you want to try things quickly they should help. They should also serve as guides to implementing more efficient functionality yourself.

Bartek532 commented 1 year ago

Thanks! It looks really good, I will explore this new API and share you my thoughts later, thanks! :)

Bartek532 commented 1 year ago

Everything seems working fine :) I have one last question for now: can I using registered authorization token to receive any information about the device itself? (e.g. serial number or somthing like that?)

erikbrinkman commented 1 year ago

Unfortunately I don't think so. The API only really exposes the cloud storage on there end, so there's no talking with the actual device, and nothing that really depends on it. That doesn't mean reMarkable doesn't have an api for the last attached serial number, but I don't know it, or if it's exposed.

I also imagine you might be able to look at the files themselves for signatures that may relate to remarkable model or software version, but not the serial number.

Hope that helps, but sorry it's mostly a negative answer.

erikbrinkman commented 1 year ago

Feel free to reopen if you feel things we're addressed.