zotrm 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zotrm-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +58 -0
- zotrm-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- zotrm-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +23 -0
- zotrm-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- zotrm-0.1.0/.github/workflows/ci.yml +38 -0
- zotrm-0.1.0/.github/workflows/release.yml +40 -0
- zotrm-0.1.0/.gitignore +22 -0
- zotrm-0.1.0/.python-version +1 -0
- zotrm-0.1.0/CHANGELOG.md +25 -0
- zotrm-0.1.0/CODE_OF_CONDUCT.md +55 -0
- zotrm-0.1.0/CONTRIBUTING.md +64 -0
- zotrm-0.1.0/LICENSE +21 -0
- zotrm-0.1.0/PKG-INFO +251 -0
- zotrm-0.1.0/README.md +224 -0
- zotrm-0.1.0/SECURITY.md +28 -0
- zotrm-0.1.0/docs/advanced-usage.md +169 -0
- zotrm-0.1.0/pyproject.toml +75 -0
- zotrm-0.1.0/src/zotrm/__init__.py +3 -0
- zotrm-0.1.0/src/zotrm/__main__.py +6 -0
- zotrm-0.1.0/src/zotrm/cli.py +244 -0
- zotrm-0.1.0/src/zotrm/config.py +42 -0
- zotrm-0.1.0/src/zotrm/cron.py +176 -0
- zotrm-0.1.0/src/zotrm/remarkable.py +37 -0
- zotrm-0.1.0/src/zotrm/wizard.py +194 -0
- zotrm-0.1.0/src/zotrm/zotero.py +76 -0
- zotrm-0.1.0/tests/conftest.py +123 -0
- zotrm-0.1.0/tests/test_cli.py +113 -0
- zotrm-0.1.0/tests/test_config.py +25 -0
- zotrm-0.1.0/tests/test_cron.py +208 -0
- zotrm-0.1.0/tests/test_pull.py +192 -0
- zotrm-0.1.0/tests/test_push.py +123 -0
- zotrm-0.1.0/tests/test_walk.py +39 -0
- zotrm-0.1.0/tests/test_wizard.py +118 -0
- zotrm-0.1.0/tests/test_zotero.py +52 -0
- zotrm-0.1.0/uv.lock +742 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something isn't working as expected
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: Thanks for taking the time to file a bug! Please remove any secrets (like your Zotero API key) from logs.
|
|
8
|
+
- type: textarea
|
|
9
|
+
id: what-happened
|
|
10
|
+
attributes:
|
|
11
|
+
label: What happened?
|
|
12
|
+
description: What did you do, and what went wrong?
|
|
13
|
+
placeholder: I ran `zotrm pull` and ...
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: expected
|
|
18
|
+
attributes:
|
|
19
|
+
label: What did you expect to happen?
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
- type: textarea
|
|
23
|
+
id: repro
|
|
24
|
+
attributes:
|
|
25
|
+
label: Steps to reproduce
|
|
26
|
+
placeholder: |
|
|
27
|
+
1. Run `zotrm ...`
|
|
28
|
+
2. ...
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
- type: textarea
|
|
32
|
+
id: logs
|
|
33
|
+
attributes:
|
|
34
|
+
label: Output / logs
|
|
35
|
+
description: Paste the command output. Run with `--dry-run` if helpful. Remove your API key.
|
|
36
|
+
render: shell
|
|
37
|
+
- type: input
|
|
38
|
+
id: version
|
|
39
|
+
attributes:
|
|
40
|
+
label: zotrm version
|
|
41
|
+
description: Output of `zotrm --help` header or the installed version.
|
|
42
|
+
placeholder: "0.1.0"
|
|
43
|
+
validations:
|
|
44
|
+
required: true
|
|
45
|
+
- type: dropdown
|
|
46
|
+
id: os
|
|
47
|
+
attributes:
|
|
48
|
+
label: Operating system
|
|
49
|
+
options:
|
|
50
|
+
- macOS
|
|
51
|
+
- Linux
|
|
52
|
+
validations:
|
|
53
|
+
required: true
|
|
54
|
+
- type: input
|
|
55
|
+
id: rmapi
|
|
56
|
+
attributes:
|
|
57
|
+
label: rmapi version
|
|
58
|
+
description: Output of `rmapi version` (if relevant).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea or improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What problem would this solve?
|
|
9
|
+
description: Describe the use case or pain point. "I'm always frustrated when ..."
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed solution
|
|
16
|
+
description: What would you like zotrm to do?
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: alternatives
|
|
21
|
+
attributes:
|
|
22
|
+
label: Alternatives considered
|
|
23
|
+
description: Any workarounds or other approaches you've thought about.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!-- Thanks for contributing to zotrm! -->
|
|
2
|
+
|
|
3
|
+
## What does this change?
|
|
4
|
+
|
|
5
|
+
<!-- A short summary of the change and why it's needed. Link any related issue. -->
|
|
6
|
+
|
|
7
|
+
Closes #
|
|
8
|
+
|
|
9
|
+
## Checklist
|
|
10
|
+
|
|
11
|
+
- [ ] Tests added or updated for the change
|
|
12
|
+
- [ ] `uv run pytest` passes (100% coverage gate)
|
|
13
|
+
- [ ] `uv run ruff check .` and `uv run ruff format --check .` are clean
|
|
14
|
+
- [ ] `uv run mypy src` passes
|
|
15
|
+
- [ ] Docs updated if behavior changed (README / advanced-usage / CHANGELOG)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
checks:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v6
|
|
21
|
+
with:
|
|
22
|
+
enable-cache: true
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: uv sync --locked
|
|
27
|
+
|
|
28
|
+
- name: Lint (ruff)
|
|
29
|
+
run: uv run ruff check .
|
|
30
|
+
|
|
31
|
+
- name: Format check (ruff)
|
|
32
|
+
run: uv run ruff format --check .
|
|
33
|
+
|
|
34
|
+
- name: Type check (mypy)
|
|
35
|
+
run: uv run mypy src
|
|
36
|
+
|
|
37
|
+
- name: Tests + 100% coverage gate
|
|
38
|
+
run: uv run pytest
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI when a version tag (e.g. v0.1.0) is pushed.
|
|
4
|
+
#
|
|
5
|
+
# Uses PyPI "trusted publishing" (OIDC) — no API token needed. One-time setup on PyPI:
|
|
6
|
+
# PyPI → your project → Settings → Publishing → Add a trusted publisher
|
|
7
|
+
# Owner: dipta007 | Repo: zotRm | Workflow: release.yml | Environment: pypi
|
|
8
|
+
# Then create a `pypi` environment in the repo settings.
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
tags: ["v*"]
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
release:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
environment: pypi
|
|
18
|
+
permissions:
|
|
19
|
+
id-token: write # required for trusted publishing
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v6
|
|
25
|
+
with:
|
|
26
|
+
enable-cache: true
|
|
27
|
+
|
|
28
|
+
- name: Verify the package before publishing
|
|
29
|
+
run: |
|
|
30
|
+
uv sync --locked
|
|
31
|
+
uv run ruff check .
|
|
32
|
+
uv run ruff format --check .
|
|
33
|
+
uv run mypy src
|
|
34
|
+
uv run pytest
|
|
35
|
+
|
|
36
|
+
- name: Build
|
|
37
|
+
run: uv build
|
|
38
|
+
|
|
39
|
+
- name: Publish to PyPI
|
|
40
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
zotrm-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
|
|
7
|
+
# Build artifacts
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
|
|
11
|
+
# uv / virtualenv
|
|
12
|
+
.venv/
|
|
13
|
+
|
|
14
|
+
# Caches
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
|
|
19
|
+
# Coverage
|
|
20
|
+
.coverage
|
|
21
|
+
htmlcov/
|
|
22
|
+
coverage.xml
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
zotrm-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-06-23
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `push`, `pull`, `status`, and `sync` commands to move PDFs between a Zotero collection
|
|
14
|
+
and a reMarkable Paper Pro, tracking state with Zotero tags (`rm:synced`,
|
|
15
|
+
`rm:annotated`).
|
|
16
|
+
- Sub-collection mirroring: Zotero sub-collections become nested folders on the tablet.
|
|
17
|
+
- `zotrm config` — interactive setup wizard with a live Zotero check and an `rmapi`
|
|
18
|
+
presence check; runs automatically on first use.
|
|
19
|
+
- `zotrm cron` — schedule an automatic sync (with `--remove` / `--show`).
|
|
20
|
+
- `--config` and `--dry-run` global flags.
|
|
21
|
+
- Full type hints (`mypy --strict`), `ruff` lint/format, and a test suite at 100%
|
|
22
|
+
coverage.
|
|
23
|
+
|
|
24
|
+
[Unreleased]: https://github.com/dipta007/zotRm/compare/v0.1.0...HEAD
|
|
25
|
+
[0.1.0]: https://github.com/dipta007/zotRm/releases/tag/v0.1.0
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a
|
|
6
|
+
harassment-free experience for everyone, regardless of age, body size, visible or invisible
|
|
7
|
+
disability, ethnicity, sex characteristics, gender identity and expression, level of
|
|
8
|
+
experience, education, socio-economic status, nationality, personal appearance, race,
|
|
9
|
+
religion, or sexual identity and orientation.
|
|
10
|
+
|
|
11
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse,
|
|
12
|
+
inclusive, and healthy community.
|
|
13
|
+
|
|
14
|
+
## Our Standards
|
|
15
|
+
|
|
16
|
+
Examples of behavior that contributes to a positive environment include:
|
|
17
|
+
|
|
18
|
+
- Demonstrating empathy and kindness toward other people
|
|
19
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
20
|
+
- Giving and gracefully accepting constructive feedback
|
|
21
|
+
- Accepting responsibility and apologizing to those affected by our mistakes
|
|
22
|
+
- Focusing on what is best for the overall community
|
|
23
|
+
|
|
24
|
+
Examples of unacceptable behavior include:
|
|
25
|
+
|
|
26
|
+
- The use of sexualized language or imagery, and sexual attention or advances of any kind
|
|
27
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
28
|
+
- Public or private harassment
|
|
29
|
+
- Publishing others' private information without their explicit permission
|
|
30
|
+
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
31
|
+
|
|
32
|
+
## Enforcement Responsibilities
|
|
33
|
+
|
|
34
|
+
Community leaders are responsible for clarifying and enforcing our standards and will take
|
|
35
|
+
appropriate and fair corrective action in response to any behavior that they deem
|
|
36
|
+
inappropriate, threatening, offensive, or harmful.
|
|
37
|
+
|
|
38
|
+
## Scope
|
|
39
|
+
|
|
40
|
+
This Code of Conduct applies within all community spaces, and also applies when an
|
|
41
|
+
individual is officially representing the community in public spaces.
|
|
42
|
+
|
|
43
|
+
## Enforcement
|
|
44
|
+
|
|
45
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the
|
|
46
|
+
maintainer via <https://roydipta.com>. All complaints will be reviewed and investigated
|
|
47
|
+
promptly and fairly. Community leaders are obligated to respect the privacy and security of
|
|
48
|
+
the reporter of any incident.
|
|
49
|
+
|
|
50
|
+
## Attribution
|
|
51
|
+
|
|
52
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1,
|
|
53
|
+
available at <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
|
|
54
|
+
|
|
55
|
+
[homepage]: https://www.contributor-covenant.org
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Contributing to zotrm
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in improving zotrm! This project uses
|
|
4
|
+
[uv](https://docs.astral.sh/uv/) for everything.
|
|
5
|
+
|
|
6
|
+
## Set up for development
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
git clone https://github.com/dipta007/zotRm
|
|
10
|
+
cd zotrm
|
|
11
|
+
uv sync # creates .venv and installs deps + dev tools
|
|
12
|
+
uv pip install -e . # editable install, so `zotrm` reflects your edits
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Project layout
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
src/zotrm/
|
|
19
|
+
cli.py # argparse, main(), command dispatch
|
|
20
|
+
config.py # config loading/validation + shared helpers
|
|
21
|
+
zotero.py # pyzotero wrapper: collection walk, tag helpers
|
|
22
|
+
remarkable.py # rmapi subprocess wrapper
|
|
23
|
+
wizard.py # interactive `zotrm config` setup wizard
|
|
24
|
+
cron.py # `zotrm cron` schedule builder + crontab management
|
|
25
|
+
__main__.py # enables `python -m zotrm`
|
|
26
|
+
tests/ # pytest suite (pyzotero + rmapi + questionary are mocked)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Run the checks
|
|
30
|
+
|
|
31
|
+
All four must pass before a change is ready:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
uv run pytest # tests + 100% coverage gate
|
|
35
|
+
uv run ruff check . # lint
|
|
36
|
+
uv run ruff format . # format (use --check in CI)
|
|
37
|
+
uv run mypy src # type-check (strict)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
GitHub Actions runs these same four gates on every push and pull request, across
|
|
41
|
+
Python 3.11–3.13 (see [`.github/workflows/ci.yml`](.github/workflows/ci.yml)). The test
|
|
42
|
+
step enforces 100% coverage, so a change that drops coverage fails CI.
|
|
43
|
+
|
|
44
|
+
## Code style
|
|
45
|
+
|
|
46
|
+
- **Formatting & linting:** `ruff`, line length 100. Run `ruff format` before committing.
|
|
47
|
+
- **Types:** full type hints; `mypy --strict` must pass on `src`. The live `pyzotero`
|
|
48
|
+
client is typed as `Any` (it ships no stubs); helpers pin down the slices we use.
|
|
49
|
+
- **Tests:** external systems are never hit. `pyzotero.Zotero`, the `rmapi`/`crontab`
|
|
50
|
+
subprocesses, and `questionary` prompts are all replaced with fakes (see
|
|
51
|
+
`tests/conftest.py`). Favor meaningful coverage over a coverage number.
|
|
52
|
+
- **Keep changes surgical.** Match the surrounding style; don't refactor unrelated code.
|
|
53
|
+
|
|
54
|
+
## Making a change
|
|
55
|
+
|
|
56
|
+
1. Branch off `main`.
|
|
57
|
+
2. Add or update tests alongside your change.
|
|
58
|
+
3. Make sure all four checks above are green.
|
|
59
|
+
4. Open a pull request describing what changed and why.
|
|
60
|
+
|
|
61
|
+
## Releasing
|
|
62
|
+
|
|
63
|
+
See [docs/advanced-usage.md](docs/advanced-usage.md#publishing-to-pypi-for-maintainers)
|
|
64
|
+
for how to publish a new version to PyPI.
|
zotrm-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shubhashis Roy Dipta
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
zotrm-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zotrm
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bridge a Zotero collection to a reMarkable Paper Pro: push PDFs, pull annotations.
|
|
5
|
+
Project-URL: Homepage, https://roydipta.com
|
|
6
|
+
Project-URL: Repository, https://github.com/dipta007/zotRm
|
|
7
|
+
Author: Shubhashis Roy Dipta
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: annotations,pdf,remarkable,rmapi,zotero
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: pyzotero>=1.5
|
|
25
|
+
Requires-Dist: questionary>=2.0
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# zotrm
|
|
29
|
+
|
|
30
|
+
[](https://github.com/dipta007/zotRm/actions/workflows/ci.yml)
|
|
31
|
+
[](https://pypi.org/project/zotrm/)
|
|
32
|
+
[](https://pypi.org/project/zotrm/)
|
|
33
|
+
[](https://github.com/dipta007/zotRm/blob/main/LICENSE)
|
|
34
|
+
|
|
35
|
+
Read your Zotero papers on a **reMarkable Paper Pro**, then get your handwritten
|
|
36
|
+
notes back into Zotero — with one command.
|
|
37
|
+
|
|
38
|
+
## Demo
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
> _Recording the GIF: see [how to record the demo](https://github.com/dipta007/zotRm/blob/main/docs/advanced-usage.md#recording-the-demo-gif)._
|
|
43
|
+
|
|
44
|
+
**What it does, in plain words:**
|
|
45
|
+
|
|
46
|
+
- **push** — sends the PDFs from one Zotero collection to your reMarkable tablet.
|
|
47
|
+
- **pull** — brings the marked-up PDFs back and attaches them to the same Zotero papers.
|
|
48
|
+
- **status** — shows which papers are waiting, on the tablet, or already done.
|
|
49
|
+
- **sync** — does a pull and then a push, together.
|
|
50
|
+
|
|
51
|
+
You never push or pull the same paper twice by mistake — the tool remembers what it has
|
|
52
|
+
done. It is safe to run again and again.
|
|
53
|
+
|
|
54
|
+
> **One honest limit (this is reMarkable's behavior, not a bug here):**
|
|
55
|
+
> Your highlights and handwriting come back as part of the PDF image — "painted onto"
|
|
56
|
+
> the page. They do **not** come back as clickable Zotero highlights.
|
|
57
|
+
|
|
58
|
+
## Why zotrm?
|
|
59
|
+
|
|
60
|
+
If you read research papers on a reMarkable, getting them on and off the tablet is fiddly:
|
|
61
|
+
export each PDF, drag it into the reMarkable app, and later dig the annotated copy back
|
|
62
|
+
out and re-file it in Zotero. zotrm makes that **one command in each direction**, driven by
|
|
63
|
+
the collection you already curate in Zotero:
|
|
64
|
+
|
|
65
|
+
- **No manual file shuffling** — it reads your Zotero collection and uploads the PDFs for you.
|
|
66
|
+
- **Folders match your library** — Zotero sub-collections become nested folders on the tablet.
|
|
67
|
+
- **Nothing pushed or pulled twice** — progress is tracked with Zotero tags, so it's safe to
|
|
68
|
+
re-run or schedule with `zotrm cron`.
|
|
69
|
+
- **No extra database or account** — just your Zotero API key and the `rmapi` tool.
|
|
70
|
+
|
|
71
|
+
It's a small, focused CLI — not a sync daemon or a cloud service.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Before you start (what you need)
|
|
76
|
+
|
|
77
|
+
1. A **Zotero** account with some PDFs in it.
|
|
78
|
+
2. A **reMarkable** tablet, turned on and connected to WiFi.
|
|
79
|
+
3. A **reMarkable Connect** subscription — this is what lets files move to and from the
|
|
80
|
+
tablet over the internet. Without it, push and pull may not work.
|
|
81
|
+
4. A computer (Mac or Linux) where you can open a **Terminal** (a window where you type
|
|
82
|
+
commands). On a Mac, open the app called **Terminal**.
|
|
83
|
+
|
|
84
|
+
You will copy and paste a few commands. That is all.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Setup (about 10 minutes)
|
|
89
|
+
|
|
90
|
+
### Step 1 — Install `uv`
|
|
91
|
+
|
|
92
|
+
`uv` installs this tool for you. Paste this into the Terminal and press Enter:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Close the Terminal and open it again so the change takes effect.
|
|
99
|
+
|
|
100
|
+
### Step 2 — Install `rmapi` and connect it to your tablet
|
|
101
|
+
|
|
102
|
+
`rmapi` is a separate program that talks to your reMarkable:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
brew install rmapi
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
(No Homebrew? See <https://github.com/ddvk/rmapi> for other ways. Use the **ddvk**
|
|
109
|
+
version — the original does not work with new tablets.)
|
|
110
|
+
|
|
111
|
+
Now connect it to your tablet **one time**:
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
rmapi
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
It shows a web address and asks for a code. Open
|
|
118
|
+
<https://my.remarkable.com/device/desktop>, copy the code shown there, and paste it into
|
|
119
|
+
the Terminal. Done — you won't do this again.
|
|
120
|
+
|
|
121
|
+
### Step 3 — Install `zotrm`
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
uv tool install zotrm
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Step 4 — Set up your account (answer a few questions)
|
|
128
|
+
|
|
129
|
+
Just run:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
zotrm config
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
It asks you a few simple questions (use the arrow keys and Enter), then checks that your
|
|
136
|
+
details work. To answer the two Zotero questions:
|
|
137
|
+
|
|
138
|
+
- Open <https://www.zotero.org/settings/keys>.
|
|
139
|
+
- Your **library ID** is the number shown as "Your userID".
|
|
140
|
+
- Click **Create new private key**, allow read **and write**, and copy the key it gives
|
|
141
|
+
you.
|
|
142
|
+
|
|
143
|
+
> **Tip:** In Zotero, make a collection (for example named `reMarkable`) and drag the
|
|
144
|
+
> papers you want to read into it. Give that same name when the wizard asks for the
|
|
145
|
+
> collection.
|
|
146
|
+
|
|
147
|
+
That's it — your settings are saved automatically. (The very first time you run any
|
|
148
|
+
command, this wizard starts on its own if you haven't set up yet.)
|
|
149
|
+
|
|
150
|
+
### Step 5 — Use it
|
|
151
|
+
|
|
152
|
+
Send your papers to the tablet:
|
|
153
|
+
|
|
154
|
+
```sh
|
|
155
|
+
zotrm push
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Read and annotate them on the reMarkable. When you're done, bring them back:
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
zotrm pull
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
That's the whole loop. 🎉
|
|
165
|
+
|
|
166
|
+
### Step 6 (optional) — Make it automatic
|
|
167
|
+
|
|
168
|
+
Want it to sync by itself on a schedule? Run:
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
zotrm cron
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Pick how often (every hour, daily, etc.) and it sets everything up for you. Remove it
|
|
175
|
+
later with `zotrm cron --remove`.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Everyday commands
|
|
180
|
+
|
|
181
|
+
```sh
|
|
182
|
+
zotrm push # send waiting papers to the tablet
|
|
183
|
+
zotrm pull # bring marked-up papers back into Zotero
|
|
184
|
+
zotrm status # see what is waiting / on the tablet / done
|
|
185
|
+
zotrm sync # pull, then push, in one step
|
|
186
|
+
|
|
187
|
+
zotrm config # change your settings any time
|
|
188
|
+
zotrm cron # set up (or change) automatic syncing
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Not sure what a command will do? Add `--dry-run` to see without changing anything:
|
|
192
|
+
|
|
193
|
+
```sh
|
|
194
|
+
zotrm --dry-run push
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## If something goes wrong
|
|
200
|
+
|
|
201
|
+
- **"rmapi not found"** → Step 2 was missed, or reopen the Terminal.
|
|
202
|
+
- **"config not found"** → Run `zotrm config` to set up your account.
|
|
203
|
+
- **"no Zotero collection named ..."** → The collection name in your settings doesn't
|
|
204
|
+
exactly match a collection in Zotero. Check spelling and capital letters
|
|
205
|
+
(`zotrm config --show` prints your current settings).
|
|
206
|
+
- **Pull finds nothing** → Make sure the tablet is online and finished syncing, and that
|
|
207
|
+
you have a reMarkable Connect subscription.
|
|
208
|
+
|
|
209
|
+
Run any command with `--dry-run` first if you're unsure — it changes nothing.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## FAQ
|
|
214
|
+
|
|
215
|
+
**Do I need a reMarkable Connect subscription?**
|
|
216
|
+
Yes, in practice. `zotrm` talks to the reMarkable **cloud** through `rmapi`, and two-way
|
|
217
|
+
document sync (uploading PDFs and downloading annotated ones) needs Connect.
|
|
218
|
+
|
|
219
|
+
**Why don't my highlights come back as real Zotero highlights?**
|
|
220
|
+
The reMarkable returns a flattened PDF — your marks are baked into the page image. That's a
|
|
221
|
+
reMarkable limitation, not something `zotrm` can change. You get a faithful annotated PDF
|
|
222
|
+
re-attached to the item, just not editable highlight objects.
|
|
223
|
+
|
|
224
|
+
**Does it duplicate files if I run it again?**
|
|
225
|
+
No. It tags items `rm:synced` once pushed and `rm:annotated` once pulled back, and skips
|
|
226
|
+
anything already done. Re-run it (or schedule it) freely.
|
|
227
|
+
|
|
228
|
+
**Can I use it with more than one Zotero library?**
|
|
229
|
+
Yes — keep separate config files and pass `--config`. See
|
|
230
|
+
[advanced usage](https://github.com/dipta007/zotRm/blob/main/docs/advanced-usage.md#global-flags).
|
|
231
|
+
|
|
232
|
+
**Does it work on Windows?**
|
|
233
|
+
Not currently. `zotrm` targets macOS and Linux (the `cron` scheduler is Unix-only).
|
|
234
|
+
|
|
235
|
+
**Is my Zotero API key safe?**
|
|
236
|
+
It's stored only in your local config file (`~/.config/zotrm/config.ini`) and never sent
|
|
237
|
+
anywhere except Zotero's own API. `zotrm config --show` masks it.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## More
|
|
242
|
+
|
|
243
|
+
- **[Advanced usage](https://github.com/dipta007/zotRm/blob/main/docs/advanced-usage.md)** —
|
|
244
|
+
editing the config file by hand, the full settings reference, how the scheduled sync
|
|
245
|
+
works, multiple configs, and deeper troubleshooting.
|
|
246
|
+
- **[Contributing](https://github.com/dipta007/zotRm/blob/main/CONTRIBUTING.md)** — set up
|
|
247
|
+
the project for development and run the tests.
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
MIT — see [LICENSE](https://github.com/dipta007/zotRm/blob/main/LICENSE).
|