remarkablesync 1.0.6__py3-none-any.whl
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.
- RemarkableSync.py +126 -0
- remarkablesync-1.0.6.dist-info/METADATA +384 -0
- remarkablesync-1.0.6.dist-info/RECORD +26 -0
- remarkablesync-1.0.6.dist-info/WHEEL +5 -0
- remarkablesync-1.0.6.dist-info/entry_points.txt +2 -0
- remarkablesync-1.0.6.dist-info/top_level.txt +2 -0
- src/__init__.py +5 -0
- src/__version__.py +4 -0
- src/backup/__init__.py +12 -0
- src/backup/backup_manager.py +424 -0
- src/backup/connection.py +314 -0
- src/backup/metadata.py +133 -0
- src/commands/__init__.py +1 -0
- src/commands/backup_command.py +62 -0
- src/commands/convert_command.py +81 -0
- src/commands/sync_command.py +78 -0
- src/converter.py +130 -0
- src/converters/__init__.py +13 -0
- src/converters/base_converter.py +207 -0
- src/converters/v4_converter.py +156 -0
- src/converters/v5_converter.py +176 -0
- src/converters/v6_converter.py +139 -0
- src/hybrid_converter.py +655 -0
- src/template_renderer.py +285 -0
- src/utils/__init__.py +1 -0
- src/utils/logging.py +23 -0
RemarkableSync.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
RemarkableSync - Unified command-line interface
|
|
4
|
+
|
|
5
|
+
Single entry point for backing up and converting ReMarkable tablet files.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
# Check Python version before importing anything else
|
|
13
|
+
if sys.version_info < (3, 11):
|
|
14
|
+
print("Error: RemarkableSync requires Python 3.11 or higher.")
|
|
15
|
+
print(f"You are using Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
|
|
16
|
+
print("\nPlease upgrade your Python installation:")
|
|
17
|
+
print(" - Download from: https://www.python.org/downloads/")
|
|
18
|
+
print(" - Or use a package manager (brew, apt, etc.)")
|
|
19
|
+
sys.exit(1)
|
|
20
|
+
|
|
21
|
+
import click
|
|
22
|
+
|
|
23
|
+
from src.__version__ import __repository__, __version__
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def print_header():
|
|
27
|
+
"""Print the application header."""
|
|
28
|
+
click.echo(f"RemarkableSync v{__version__} by Jeff Steinbok")
|
|
29
|
+
click.echo(f"Repository: {__repository__}")
|
|
30
|
+
click.echo()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def version_callback(ctx, param, value):
|
|
34
|
+
"""Display version information."""
|
|
35
|
+
if not value or ctx.resilient_parsing:
|
|
36
|
+
return
|
|
37
|
+
print_header()
|
|
38
|
+
ctx.exit()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@click.group(invoke_without_command=False)
|
|
42
|
+
@click.option('--version', is_flag=True, callback=version_callback,
|
|
43
|
+
expose_value=False, is_eager=True,
|
|
44
|
+
help='Show version and repository information')
|
|
45
|
+
@click.pass_context
|
|
46
|
+
def cli(ctx):
|
|
47
|
+
"""RemarkableSync - Backup and convert ReMarkable tablet files.
|
|
48
|
+
|
|
49
|
+
A unified tool to backup your ReMarkable tablet via USB and convert
|
|
50
|
+
notebooks to PDF format with template support.
|
|
51
|
+
"""
|
|
52
|
+
# Print header for all commands (unless it's --version which handles it itself)
|
|
53
|
+
if ctx.invoked_subcommand and not ctx.resilient_parsing:
|
|
54
|
+
print_header()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@cli.command()
|
|
58
|
+
@click.option('--backup-dir', '-d', type=click.Path(path_type=Path),
|
|
59
|
+
default=Path('./remarkable_backup'),
|
|
60
|
+
help='Directory to store backup files')
|
|
61
|
+
@click.option('--password', '-p', type=str, help='ReMarkable SSH password')
|
|
62
|
+
@click.option('--verbose', '-v', is_flag=True, help='Enable verbose logging')
|
|
63
|
+
@click.option('--skip-templates', is_flag=True, help='Skip backing up template files')
|
|
64
|
+
@click.option('--force', '-f', is_flag=True, help='Force backup all files (ignore sync status)')
|
|
65
|
+
def backup(backup_dir: Path, password: Optional[str], verbose: bool, skip_templates: bool, force: bool):
|
|
66
|
+
"""Backup files from ReMarkable tablet via USB.
|
|
67
|
+
|
|
68
|
+
Connects to your ReMarkable tablet and backs up all files with incremental sync.
|
|
69
|
+
Template files are backed up by default unless --skip-templates is specified.
|
|
70
|
+
"""
|
|
71
|
+
from src.commands.backup_command import run_backup_command
|
|
72
|
+
sys.exit(run_backup_command(backup_dir, password, verbose, skip_templates, force))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@cli.command()
|
|
76
|
+
@click.option('--backup-dir', '-d', type=click.Path(path_type=Path),
|
|
77
|
+
default=Path('./remarkable_backup'),
|
|
78
|
+
help='Directory containing ReMarkable backup files')
|
|
79
|
+
@click.option('--output-dir', '-o', type=click.Path(path_type=Path),
|
|
80
|
+
help='Directory to save PDF files (default: backup_dir/pdfs_final)')
|
|
81
|
+
@click.option('--verbose', '-v', is_flag=True, help='Enable verbose logging')
|
|
82
|
+
@click.option('--force-all', '-f', is_flag=True, help='Convert all notebooks (ignore sync status)')
|
|
83
|
+
@click.option('--sample', '-s', type=int, help='Convert only first N notebooks (for testing)')
|
|
84
|
+
@click.option('--notebook', '-n', type=str, help='Convert only this notebook (by UUID or name)')
|
|
85
|
+
def convert(backup_dir: Path, output_dir: Optional[Path], verbose: bool, force_all: bool,
|
|
86
|
+
sample: Optional[int], notebook: Optional[str]):
|
|
87
|
+
"""Convert backed up notebooks to PDF format.
|
|
88
|
+
|
|
89
|
+
Converts ReMarkable notebooks to PDF with template backgrounds.
|
|
90
|
+
By default, only converts notebooks that were updated in the last backup.
|
|
91
|
+
"""
|
|
92
|
+
from src.commands.convert_command import run_convert_command
|
|
93
|
+
sys.exit(run_convert_command(backup_dir, output_dir, verbose, force_all, sample, notebook))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@cli.command()
|
|
97
|
+
@click.option('--backup-dir', '-d', type=click.Path(path_type=Path),
|
|
98
|
+
default=Path('./remarkable_backup'),
|
|
99
|
+
help='Directory to store backup files')
|
|
100
|
+
@click.option('--password', '-p', type=str, help='ReMarkable SSH password')
|
|
101
|
+
@click.option('--verbose', '-v', is_flag=True, help='Enable verbose logging')
|
|
102
|
+
@click.option('--skip-templates', is_flag=True, help='Skip backing up template files')
|
|
103
|
+
@click.option('--force-backup', is_flag=True, help='Force backup all files')
|
|
104
|
+
@click.option('--force-convert', is_flag=True, help='Force convert all notebooks')
|
|
105
|
+
def sync(backup_dir: Path, password: Optional[str], verbose: bool, skip_templates: bool,
|
|
106
|
+
force_backup: bool, force_convert: bool):
|
|
107
|
+
"""Backup and convert in one command (default workflow).
|
|
108
|
+
|
|
109
|
+
This is the most common use case: backup your tablet and then convert
|
|
110
|
+
any notebooks that were updated during the backup.
|
|
111
|
+
"""
|
|
112
|
+
from src.commands.sync_command import run_sync_command
|
|
113
|
+
sys.exit(run_sync_command(backup_dir, password, verbose, skip_templates,
|
|
114
|
+
force_backup, force_convert))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def main():
|
|
118
|
+
"""Entry point for the application."""
|
|
119
|
+
# If no command specified, default to 'sync'
|
|
120
|
+
if len(sys.argv) == 1:
|
|
121
|
+
sys.argv.append('sync')
|
|
122
|
+
cli()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
main()
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: remarkablesync
|
|
3
|
+
Version: 1.0.6
|
|
4
|
+
Summary: Backup and convert reMarkable tablet notebooks to PDF
|
|
5
|
+
Home-page: https://github.com/JeffSteinbok/RemarkableSync
|
|
6
|
+
Author: Jeff Steinbok
|
|
7
|
+
Author-email:
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: remarkable tablet backup pdf converter
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Utilities
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: paramiko>=3.0.0
|
|
22
|
+
Requires-Dist: scp>=0.14.5
|
|
23
|
+
Requires-Dist: requests>=2.31.0
|
|
24
|
+
Requires-Dist: tqdm>=4.66.0
|
|
25
|
+
Requires-Dist: python-dateutil>=2.8.2
|
|
26
|
+
Requires-Dist: click>=8.1.0
|
|
27
|
+
Requires-Dist: pathlib2>=2.3.7
|
|
28
|
+
Requires-Dist: cryptography>=41.0.0
|
|
29
|
+
Requires-Dist: PyPDF2>=3.0.0
|
|
30
|
+
Requires-Dist: svglib>=1.5.0
|
|
31
|
+
Requires-Dist: reportlab>=4.0.0
|
|
32
|
+
Requires-Dist: keyring>=24.0.0
|
|
33
|
+
Requires-Dist: rmc>=0.3.0
|
|
34
|
+
Dynamic: author
|
|
35
|
+
Dynamic: classifier
|
|
36
|
+
Dynamic: description
|
|
37
|
+
Dynamic: description-content-type
|
|
38
|
+
Dynamic: home-page
|
|
39
|
+
Dynamic: keywords
|
|
40
|
+
Dynamic: license
|
|
41
|
+
Dynamic: requires-dist
|
|
42
|
+
Dynamic: requires-python
|
|
43
|
+
Dynamic: summary
|
|
44
|
+
|
|
45
|
+
# RemarkableSync
|
|
46
|
+
[](https://badge.fury.io/py/remarkablesync)
|
|
47
|
+
[](https://github.com/JeffSteinbok/RemarkableSync)
|
|
48
|
+
[](https://github.com/JeffSteinbok/RemarkableSync/actions/workflows/ci.yml)
|
|
49
|
+
[](https://github.com/JeffSteinbok/RemarkableSync/actions/workflows/build-executables.yml)
|
|
50
|
+
[](https://github.com/JeffSteinbok/RemarkableSync/actions/workflows/release.yml)
|
|
51
|
+
|
|
52
|
+
A comprehensive Python toolkit for backing up and converting reMarkable tablet notebooks to PDF with template support and proper folder hierarchy preservation.
|
|
53
|
+
|
|
54
|
+
> [!IMPORTANT]
|
|
55
|
+
> This tool has been tested exclusively on reMarkable 2. Compatibility with reMarkable 1 is not guaranteed.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## Features
|
|
59
|
+
|
|
60
|
+
### 🔄 Backup & Sync
|
|
61
|
+
- **USB Connection**: Connects to reMarkable tablet over USB (10.11.99.1)
|
|
62
|
+
- **Incremental Sync**: Only downloads files that have changed since last backup
|
|
63
|
+
- **Complete Backup**: Backs up all notebooks, documents, and metadata
|
|
64
|
+
- **Template Support**: Automatically backs up template files from the device
|
|
65
|
+
- **File Integrity**: MD5 hash verification for synced files
|
|
66
|
+
|
|
67
|
+
### 📄 PDF Conversion
|
|
68
|
+
- **Hybrid Converter**: Supports both v5 and v6 .rm file formats
|
|
69
|
+
- **Template Rendering**: Applies original notebook templates (grids, lines, etc.) to PDFs
|
|
70
|
+
- **SVG Pipeline**: Uses rmc → SVG → PDF conversion for high quality output
|
|
71
|
+
- **Folder Hierarchy**: Recreates original device folder structure in output
|
|
72
|
+
- **Single PDF per Notebook**: Merges all pages into one PDF file per notebook
|
|
73
|
+
- **Smart Conversion**: Only converts notebooks updated in the last backup
|
|
74
|
+
- **Progress Tracking**: Visual progress bars and detailed logging
|
|
75
|
+
|
|
76
|
+
## Prerequisites
|
|
77
|
+
|
|
78
|
+
1. **reMarkable Tablet Setup**:
|
|
79
|
+
- Connect your reMarkable tablet to your computer via USB
|
|
80
|
+
- Enable SSH access (it's enabled by default)
|
|
81
|
+
- Get your SSH password from Settings → Help → Copyright and licenses
|
|
82
|
+
|
|
83
|
+
2. **Python Requirements**:
|
|
84
|
+
- Python 3.11 or higher (required)
|
|
85
|
+
- Required packages (install with `pip install -r requirements.txt`)
|
|
86
|
+
|
|
87
|
+
3. **External Tools** (for v6 PDF conversion):
|
|
88
|
+
- `rmc` (reMarkable file converter) - Install from https://github.com/ricklupton/rmc
|
|
89
|
+
- Note: rmc is a Rust tool, not a Python package. Install via cargo or download binaries.
|
|
90
|
+
|
|
91
|
+
## Installation
|
|
92
|
+
|
|
93
|
+
### Option 1: Homebrew (Recommended for macOS)
|
|
94
|
+
|
|
95
|
+
**macOS users** can install RemarkableSync using Homebrew:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Add the tap (one time only)
|
|
99
|
+
brew tap jeffsteinbok/remarkablesync
|
|
100
|
+
|
|
101
|
+
# Install RemarkableSync
|
|
102
|
+
brew install remarkablesync
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This will automatically:
|
|
106
|
+
- Install Python 3.13 and all dependencies
|
|
107
|
+
- Install the `rmc` tool for v6 format conversion
|
|
108
|
+
- Set up everything needed for PDF conversion
|
|
109
|
+
|
|
110
|
+
**Updating to latest version:**
|
|
111
|
+
```bash
|
|
112
|
+
brew upgrade remarkablesync
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Uninstalling:**
|
|
116
|
+
```bash
|
|
117
|
+
brew uninstall remarkablesync
|
|
118
|
+
brew untap jeffsteinbok/remarkablesync
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Option 2: pip (All Platforms)
|
|
122
|
+
|
|
123
|
+
**For users with Python 3.11+** installed:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Install using pip (recommended: use a virtual environment)
|
|
127
|
+
pip install remarkablesync
|
|
128
|
+
|
|
129
|
+
# Then install rmc separately
|
|
130
|
+
pip install rmc
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Using a virtual environment** (recommended):
|
|
134
|
+
```bash
|
|
135
|
+
# Create virtual environment
|
|
136
|
+
python -m venv venv
|
|
137
|
+
|
|
138
|
+
# Activate it
|
|
139
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
140
|
+
|
|
141
|
+
# Install RemarkableSync
|
|
142
|
+
pip install remarkablesync
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Updating to latest version:**
|
|
146
|
+
```bash
|
|
147
|
+
pip install --upgrade remarkablesync
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Option 3: Pre-built Executables (Windows/macOS)
|
|
151
|
+
|
|
152
|
+
**For users without Python** or who prefer standalone executables:
|
|
153
|
+
|
|
154
|
+
1. Download the latest release from the [Releases page](https://github.com/JeffSteinbok/RemarkableSync/releases)
|
|
155
|
+
2. Extract the archive:
|
|
156
|
+
- **Windows**: Extract `RemarkableSync-Windows.zip`
|
|
157
|
+
- **macOS**: Extract `RemarkableSync-macOS.zip`
|
|
158
|
+
3. Run the executable:
|
|
159
|
+
- **Windows**: `RemarkableSync.exe`
|
|
160
|
+
- **macOS**: `./RemarkableSync/RemarkableSync`
|
|
161
|
+
|
|
162
|
+
For detailed instructions on building executables yourself, see [BUILD_EXECUTABLES.md](BUILD_EXECUTABLES.md).
|
|
163
|
+
|
|
164
|
+
### Option 4: From Source (For Developers)
|
|
165
|
+
|
|
166
|
+
1. Clone this repository:
|
|
167
|
+
```bash
|
|
168
|
+
git clone https://github.com/JeffSteinbok/RemarkableSync.git
|
|
169
|
+
cd RemarkableSync
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
2. Install dependencies:
|
|
173
|
+
```bash
|
|
174
|
+
pip install -r requirements.txt
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Quick Start
|
|
178
|
+
|
|
179
|
+
The simplest way to get started:
|
|
180
|
+
|
|
181
|
+
1. **Connect your reMarkable tablet** via USB
|
|
182
|
+
2. **Get your SSH password** from Settings → Help → Copyright and licenses on your tablet
|
|
183
|
+
3. **Run RemarkableSync**:
|
|
184
|
+
```bash
|
|
185
|
+
# If installed via Homebrew (macOS)
|
|
186
|
+
RemarkableSync
|
|
187
|
+
|
|
188
|
+
# If using pre-built executable
|
|
189
|
+
./RemarkableSync
|
|
190
|
+
|
|
191
|
+
# If using Python
|
|
192
|
+
python3 RemarkableSync.py
|
|
193
|
+
```
|
|
194
|
+
4. Enter your password when prompted (you can save it for future use)
|
|
195
|
+
5. Your notebooks will be backed up to `./remarkable_backup/Notebooks/`
|
|
196
|
+
6. PDFs will be created in `./remarkable_backup/PDF/`
|
|
197
|
+
|
|
198
|
+
That's it! The tool will only sync changed files and convert updated notebooks on subsequent runs.
|
|
199
|
+
|
|
200
|
+
## Usage
|
|
201
|
+
|
|
202
|
+
### Unified Command Line Interface
|
|
203
|
+
|
|
204
|
+
RemarkableSync provides a single entry point with three main commands:
|
|
205
|
+
|
|
206
|
+
#### Default Command: Sync (Backup + Convert)
|
|
207
|
+
|
|
208
|
+
The most common workflow - backs up your device and converts only updated notebooks:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# If installed via Homebrew
|
|
212
|
+
RemarkableSync
|
|
213
|
+
|
|
214
|
+
# If using pre-built executable
|
|
215
|
+
./RemarkableSync
|
|
216
|
+
|
|
217
|
+
# If using Python
|
|
218
|
+
python3 RemarkableSync.py
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
This will:
|
|
222
|
+
1. Connect to your ReMarkable tablet via USB
|
|
223
|
+
2. Backup all changed files (including templates)
|
|
224
|
+
3. Convert only notebooks that were updated in this backup
|
|
225
|
+
|
|
226
|
+
#### Individual Commands
|
|
227
|
+
|
|
228
|
+
**Backup only** (no conversion):
|
|
229
|
+
```bash
|
|
230
|
+
# Homebrew
|
|
231
|
+
RemarkableSync backup
|
|
232
|
+
|
|
233
|
+
# Python
|
|
234
|
+
python3 RemarkableSync.py backup
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Convert only** (from existing backup):
|
|
238
|
+
```bash
|
|
239
|
+
# Homebrew
|
|
240
|
+
RemarkableSync convert
|
|
241
|
+
|
|
242
|
+
# Python
|
|
243
|
+
python3 RemarkableSync.py convert
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Sync with options**:
|
|
247
|
+
```bash
|
|
248
|
+
# Force full backup and conversion (ignore sync status)
|
|
249
|
+
RemarkableSync sync --force-backup --force-convert
|
|
250
|
+
|
|
251
|
+
# Skip template backup
|
|
252
|
+
RemarkableSync sync --skip-templates
|
|
253
|
+
|
|
254
|
+
# Verbose output
|
|
255
|
+
RemarkableSync sync -v
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
#### Testing and Selective Conversion
|
|
259
|
+
|
|
260
|
+
**Convert a single notebook** (by name or UUID):
|
|
261
|
+
```bash
|
|
262
|
+
RemarkableSync convert --notebook "My Notebook"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Convert first N notebooks** (for testing):
|
|
266
|
+
```bash
|
|
267
|
+
RemarkableSync convert --sample 5
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Force convert all notebooks** (ignore sync status):
|
|
271
|
+
```bash
|
|
272
|
+
RemarkableSync convert --force-all
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Command Line Options
|
|
276
|
+
|
|
277
|
+
**Common Options** (all commands):
|
|
278
|
+
- `-d, --backup-dir`: Directory for backups (default: `./remarkable_backup`)
|
|
279
|
+
- `-v, --verbose`: Enable debug logging
|
|
280
|
+
- `--version`: Show version and repository information
|
|
281
|
+
|
|
282
|
+
**Backup/Sync Options**:
|
|
283
|
+
- `-p, --password`: ReMarkable SSH password (will prompt if not provided)
|
|
284
|
+
- `--skip-templates`: Don't backup template files
|
|
285
|
+
- `-f, --force` / `--force-backup`: Backup all files (ignore sync status)
|
|
286
|
+
|
|
287
|
+
**Convert Options**:
|
|
288
|
+
- `-o, --output-dir`: Output directory for PDFs (default: `backup_dir/pdfs_final`)
|
|
289
|
+
- `-f, --force-all` / `--force-convert`: Convert all notebooks (ignore sync status)
|
|
290
|
+
- `-s, --sample N`: Convert only first N notebooks
|
|
291
|
+
- `-n, --notebook NAME`: Convert only specific notebook (by UUID or name)
|
|
292
|
+
|
|
293
|
+
## How It Works
|
|
294
|
+
|
|
295
|
+
1. **Connection**: Establishes SSH connection to ReMarkable tablet at 10.11.99.1
|
|
296
|
+
2. **File Discovery**: Scans `/home/root/.local/share/remarkable/xochitl/` for notebook files
|
|
297
|
+
3. **Template Backup**: Downloads template files from `/usr/share/remarkable/templates/`
|
|
298
|
+
4. **Incremental Sync**: Compares file metadata (size, modification time, hash) to determine what needs updating
|
|
299
|
+
5. **Download**: Uses SCP to efficiently transfer only changed files
|
|
300
|
+
6. **PDF Conversion**:
|
|
301
|
+
- Converts .rm files to SVG using rmc (for v6 format)
|
|
302
|
+
- Renders template backgrounds (grids, lines, dots)
|
|
303
|
+
- Merges templates with notebook content
|
|
304
|
+
- Combines all pages into single PDF per notebook
|
|
305
|
+
7. **Smart Updates**: Tracks which notebooks changed and only converts those
|
|
306
|
+
|
|
307
|
+
## File Structure
|
|
308
|
+
|
|
309
|
+
After backup, your directory will contain three clean folders:
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
remarkable_backup/
|
|
313
|
+
├── Notebooks/ # All notebook files and metadata
|
|
314
|
+
│ ├── [uuid].metadata # Document metadata files
|
|
315
|
+
│ ├── [uuid].content # Document content info
|
|
316
|
+
│ └── [uuid]/ # Notebook directories
|
|
317
|
+
│ ├── [uuid]-metadata.json # Page metadata
|
|
318
|
+
│ └── *.rm # Drawing/writing data (v5 or v6 format)
|
|
319
|
+
├── Templates/ # Template files from device
|
|
320
|
+
│ ├── *.png # Template preview images
|
|
321
|
+
│ ├── *.template # Template definition files
|
|
322
|
+
│ └── templates.json # Template metadata
|
|
323
|
+
├── PDF/ # Generated PDF outputs
|
|
324
|
+
│ └── [notebook folders with PDFs preserving hierarchy]
|
|
325
|
+
├── sync_metadata.json # Sync state tracking
|
|
326
|
+
├── updated_notebooks.txt # List of notebooks updated in last backup
|
|
327
|
+
└── .remarkable_backup.log # Backup operation log
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## PDF Conversion Technical Details
|
|
331
|
+
|
|
332
|
+
RemarkableSync includes a hybrid converter that supports both v5 and v6 .rm file formats:
|
|
333
|
+
|
|
334
|
+
- **v6 Format** (newer tablets): Uses external `rmc` tool to convert .rm → SVG → PDF
|
|
335
|
+
- **v5 Format** (older tablets): Direct Python-based conversion (legacy support)
|
|
336
|
+
- **Template Rendering**: Custom renderer applies original device templates with accurate scaling (226 DPI → 72 DPI PDF points)
|
|
337
|
+
- **Page Merging**: Uses PyPDF2 to composite template backgrounds with notebook content
|
|
338
|
+
|
|
339
|
+
### External Tool: rmc
|
|
340
|
+
|
|
341
|
+
For v6 notebook conversion, you'll need the `rmc` tool:
|
|
342
|
+
- **Repository**: https://github.com/ricklupton/rmc
|
|
343
|
+
- **Installation**: Via Rust cargo or download pre-built binaries
|
|
344
|
+
- **Note**: This is NOT a Python package - install separately
|
|
345
|
+
|
|
346
|
+
## Incremental Sync Details
|
|
347
|
+
|
|
348
|
+
The tool maintains a `sync_metadata.json` file that tracks:
|
|
349
|
+
- File modification times
|
|
350
|
+
- File sizes
|
|
351
|
+
- MD5 hashes of local files
|
|
352
|
+
- Last sync timestamps
|
|
353
|
+
|
|
354
|
+
Files are only downloaded if:
|
|
355
|
+
- They don't exist locally
|
|
356
|
+
- Remote modification time changed
|
|
357
|
+
- Remote file size changed
|
|
358
|
+
- Local file hash doesn't match stored hash
|
|
359
|
+
|
|
360
|
+
## Troubleshooting
|
|
361
|
+
|
|
362
|
+
### Connection Issues
|
|
363
|
+
- Ensure ReMarkable is connected via USB
|
|
364
|
+
- Verify the tablet shows up as network interface
|
|
365
|
+
- Try pinging `10.11.99.1`
|
|
366
|
+
- Check SSH password from tablet settings
|
|
367
|
+
|
|
368
|
+
### Permission Errors
|
|
369
|
+
- Run as administrator on Windows if needed
|
|
370
|
+
- Ensure backup directory is writable
|
|
371
|
+
|
|
372
|
+
### File Access Issues
|
|
373
|
+
- Restart ReMarkable tablet if SSH becomes unresponsive
|
|
374
|
+
- Check available disk space on both devices
|
|
375
|
+
|
|
376
|
+
## Security Notes
|
|
377
|
+
|
|
378
|
+
- SSH password is requested interactively (not stored)
|
|
379
|
+
- Uses paramiko with auto-add host key policy
|
|
380
|
+
- Files are transferred over local USB network (not internet)
|
|
381
|
+
|
|
382
|
+
## License
|
|
383
|
+
|
|
384
|
+
This tool is for personal use with your own ReMarkable tablet. Respect ReMarkable's terms of service.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
RemarkableSync.py,sha256=Ls3foJQbpFjxyIj-Jk23GN1XWI10VRf9URhmLlYc_SY,5338
|
|
2
|
+
src/__init__.py,sha256=zrN0c456h8aQaXEAN7wuFwyT1XyOB4Xt-hSOq97B0aM,144
|
|
3
|
+
src/__version__.py,sha256=_rkizXc4E1nHX9PV75XMyqHnoQvUQixwalbAiI3Mp3U,135
|
|
4
|
+
src/converter.py,sha256=JRpyI05-dEiXLoEMp2xUJHIoH2Fj47InLuVuFXkMitc,4436
|
|
5
|
+
src/hybrid_converter.py,sha256=S-m6uuvpkoJB8bfz7KcyeQzO6KExpZHLmfV0fJ5QZHc,25724
|
|
6
|
+
src/template_renderer.py,sha256=NYGvFFLUtbQO_x0zG15MSh4xQNvg1CN5VHgS_vmHb0E,9967
|
|
7
|
+
src/backup/__init__.py,sha256=OavqHlWvXQeREmKS91Mxs6Z9aOdNRuFXBjTdUtFh9qs,429
|
|
8
|
+
src/backup/backup_manager.py,sha256=8sozxG8VhktOJhoBa0Gag3KDon_ZfXXLuVqlcc6hm4A,16515
|
|
9
|
+
src/backup/connection.py,sha256=UGreP_uIyIj9u20yJrimQL4hAAcbRADa7AClRj3u4Vc,11876
|
|
10
|
+
src/backup/metadata.py,sha256=8hTsHQGhuxndMDrmv2bWTwJtUEWf9CTtAUfqeD59mQo,4479
|
|
11
|
+
src/commands/__init__.py,sha256=hZBGHSue4lDZgeXVJU0T8BDSgd4PaXtQmDtjMe9mZSE,54
|
|
12
|
+
src/commands/backup_command.py,sha256=UD39U_422hkoY4rjEcw8ZSiPf_BzV_G4_wlb_e5zOvg,1942
|
|
13
|
+
src/commands/convert_command.py,sha256=wWTFUkJ86xRZHEGQROzLniai5qYPa6f1kuivyljwmjA,2431
|
|
14
|
+
src/commands/sync_command.py,sha256=XyySgAA-mpj7zXHgcH2ZDBDJwosmYrVsyuUHlfg0YkM,2399
|
|
15
|
+
src/converters/__init__.py,sha256=MX4I6N2ZfdKfhYNJlUJlH4Pows2rAy30Ay4anrasnOY,427
|
|
16
|
+
src/converters/base_converter.py,sha256=Y8uzFyB0SfmahZy-1qa-3BtxZk8YD9RJcjzPX6kV4YI,7577
|
|
17
|
+
src/converters/v4_converter.py,sha256=OMpyqCQ6dhKqQlOUXbZh5YVZ3Bu8in7867Kav9Y7z_k,5759
|
|
18
|
+
src/converters/v5_converter.py,sha256=rCRGGG7apNldIntHj8QVJYYusg0fbwW2JbEoIsJfres,6244
|
|
19
|
+
src/converters/v6_converter.py,sha256=tujxRcalL4Csf6otbx6mBLadDqg8NMn6uh2kSMhw9jM,4836
|
|
20
|
+
src/utils/__init__.py,sha256=py_WhGWa0gg4PEny3qpoi1iJ_grtEARQfwIIsH1RQh4,42
|
|
21
|
+
src/utils/logging.py,sha256=q8CHFvZj4IcDPTogC5vRdqEOHLPNEB9fgLYhlDwsOBQ,792
|
|
22
|
+
remarkablesync-1.0.6.dist-info/METADATA,sha256=9-mHDOLFtzU3tGLRToGrFyPbUKqoAl4puMA9hP7kmoE,12628
|
|
23
|
+
remarkablesync-1.0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
24
|
+
remarkablesync-1.0.6.dist-info/entry_points.txt,sha256=ue6T2_WgcJinQTpeI7fJ1MvdxeN6o7KX23oQN3-8VT4,55
|
|
25
|
+
remarkablesync-1.0.6.dist-info/top_level.txt,sha256=IEGt96lB3NxnvDEmPR4DcurlQYD2EHEn2pzAUJdq7sY,19
|
|
26
|
+
remarkablesync-1.0.6.dist-info/RECORD,,
|
src/__init__.py
ADDED
src/__version__.py
ADDED
src/backup/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Backup package for ReMarkable tablet backup functionality.
|
|
3
|
+
|
|
4
|
+
This package provides modular components for backing up ReMarkable tablets,
|
|
5
|
+
including SSH connection management, file metadata handling, and backup orchestration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .backup_manager import ReMarkableBackup
|
|
9
|
+
from .connection import ReMarkableConnection
|
|
10
|
+
from .metadata import FileMetadata
|
|
11
|
+
|
|
12
|
+
__all__ = ["ReMarkableConnection", "FileMetadata", "ReMarkableBackup"]
|