├── README.md └── rM-sync.sh /README.md: -------------------------------------------------------------------------------- 1 | # rM sync 2 | 3 | Sync script for the reMarkable paper tablet. 4 | 5 | This script will give you sync and backup functionality over USB. Great if you do not want to sync your rM to the cloud. 6 | 7 | _Ongoing work, contributions welcome._ 8 | 9 | ## Usage 10 | 11 | This script is written for and tested on linux. Feel free to adopt for mac or win. 12 | 13 | 1. Save the script file to `~/bin` 14 | 2. Change the path variable (and other) in the file as needed. 15 | 3. Run with `./rM-sync.sh` 16 | 17 | ### Options 18 | 19 | * `-u` upload: Uploads new files to the reMarkable from local folder _uploads_. 20 | * `-b` backup: Creates a backup of all user files on the reMarkable. 21 | * `-d` download: Not yet implemented... 22 | 23 | ## Planned functionality 24 | 25 | * Download PDFs of everything that changed on the tablet 26 | 27 | -------------------------------------------------------------------------------- /rM-sync.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Sync script for the reMarkable reader 4 | # Version: 0.1 5 | # Author: Simon Schilling 6 | # Licence: MIT 7 | 8 | # Remote configuration 9 | RMDIR="/home/root/.local/share/remarkable/xochitl/" 10 | RMUSER="root" 11 | RMIP="10.11.99.1" 12 | SSHPORT="22" 13 | 14 | # Local configuration 15 | MAINDIR="$HOME/rM" 16 | BACKUPDIR="$MAINDIR/backup/" # rotating backups of all rM contents 17 | UPLOADDIR="$MAINDIR/upload/" # all files here will be sent to rM 18 | OUTPUTDIR="$MAINDIR/files/" # PDFs of everything on the rM 19 | LOG="sync.log" # Log file name in $MAINDIR 20 | BACKUPLIST="files.json" 21 | 22 | # Behaviour 23 | notification() { 24 | if [ "$(uname)" == "Linux" ]; then 25 | /usr/bin/notify-send $1 $2 # Notification script 26 | elif [ "$(uname)" == "Darwin" ]; then 27 | osascript -e "display notification \"$2\" with title \"$1\"" 28 | fi 29 | } 30 | 31 | LOG="$MAINDIR/$(date +%y%m%d)-$LOG" 32 | 33 | # Create MAINDIR if it does not exist 34 | mkdir -p $MAINDIR 35 | 36 | echo $'\n' >> $LOG 37 | date >> $LOG 38 | 39 | 40 | S="ssh -p $SSHPORT -l $RMUSER"; 41 | 42 | # check for rM 43 | $S $RMIP -q exit 44 | 45 | if [ $? == "0" ]; then 46 | 47 | TODAY=$(date +%y%m%d) 48 | 49 | 50 | while getopts bdu opt 51 | do 52 | case $opt in 53 | b) 54 | # Backup files 55 | echo "BEGIN BACKUP" | tee -a $LOG 56 | mkdir -p "$BACKUPDIR$TODAY" 57 | echo "scp \"$RMUSER@$RMIP:$RMDIR\" $BACKUPDIR$TODAY" >> $LOG 58 | scp -r "$RMUSER@$RMIP:\"$RMDIR\"*" "$BACKUPDIR"$TODAY >> $LOG 2>&1 59 | if [ $? -ne 0 ]; then 60 | ERRORREASON=$ERRORREASON$'\n scp command failed' 61 | ERROR=1 62 | fi 63 | # sed -s does not work on macOS (https://unix.stackexchange.com/a/131940) 64 | if [ "$(uname)" == "Linux" ]; then 65 | echo "[" > "$BACKUPDIR$TODAY$BACKUPLIST" 66 | find "$BACKUPDIR$TODAY" -name *.metadata -type f -exec sed -s '$a,' {} + | sed '$d' >> "$BACKUPDIR$TODAY$BACKUPLIST" 67 | echo "]" >> "$BACKUPDIR$TODAY$BACKUPLIST" 68 | fi 69 | echo "BACKUP END" | tee -a $LOG 70 | ;; 71 | 72 | d) 73 | # Download files 74 | echo "BEGIN DOWNLOAD" | tee -a $LOG 75 | mkdir -p "$OUTPUTDIR" 76 | ls -1 "$BACKUPDIR$TODAY" | sed -e 's/\..*//g' | awk '!a[$0]++' > "$OUTPUTDIR/index" 77 | 78 | echo "[" > "$OUTPUTDIR/index.json"; 79 | for file in "$BACKUPDIR$TODAY"/*.metadata; 80 | do 81 | [ -e "$file" ] || continue 82 | echo "{" >> "$OUTPUTDIR/index.json"; 83 | echo " \"id\": \"$(basename "$file" .metadata)\"," >> "$OUTPUTDIR/index.json"; 84 | tail --lines=+2 "$file" >> "$OUTPUTDIR/index.json"; 85 | echo "," >> "$OUTPUTDIR/index.json"; 86 | done 87 | truncate -s-2 "$OUTPUTDIR/index.json"; #Remove last koma 88 | echo "]" >> "$OUTPUTDIR/index.json"; 89 | 90 | 91 | echo "Downloading" $(wc -l < "$OUTPUTDIR/index") "files." | tee -a $LOG 92 | # http://$RMIP/download/$FILEUID/placeholder 93 | while read -r line 94 | do 95 | FILEUID="$line" 96 | #curl -s -O -J -L "http://$RMIP/download/$FILEUID/placeholder" 97 | if [ $? -ne 0 ]; then 98 | ERRORREASON=$ERRORREASON$'\n Download failed' 99 | ERROR=1 100 | fi 101 | done < "$OUTPUTDIR/index" 102 | echo "DOWNLOAD END" | tee -a $LOG 103 | ;; 104 | 105 | u) 106 | # Upload files 107 | echo "BEGIN UPLOAD" | tee -a $LOG 108 | for file in "$UPLOADDIR"/*; 109 | do 110 | [ -e "$file" ] || continue 111 | echo -n $(basename "$file") ": " 112 | curl --form "file=@\"$file\"" http://$RMIP/upload 113 | echo "." 114 | if [ 0 -eq $? ]; then rm "$file"; fi; 115 | done 116 | if [ $? -ne 0 ]; then 117 | ERRORREASON=$ERRORREASON$'\n Upload failed' 118 | ERROR=1 119 | fi 120 | echo "UPLOAD END" | tee -a $LOG 121 | ;; 122 | esac 123 | done 124 | 125 | else 126 | echo "reMarkable not connected" | tee -a $LOG 127 | ERRORREASON=$ERRORREASON$'\n reMarkable not connected' 128 | ERROR=1 129 | fi 130 | $DATE >> $LOG 131 | if typeset -f notification > /dev/null; then 132 | if [ $ERROR ]; then 133 | notification "ERROR in rM Sync!" "$ERRORREASON" 134 | else 135 | notification "rM Sync Successfull" 136 | fi 137 | fi 138 | --------------------------------------------------------------------------------