Files
docker/remarkable/scripts/convert-to-pdf.sh
Borgal b63131c0c5 Add reMarkable backup system with web UI
- Docker container with rmapi cloud backup, PDF conversion pipeline
- Web UI: file browser, multi-select, delete/move, thumbnail preview
- Sync: backup from reMarkable cloud, rmdoc→PDF conversion via rmc+Inkscape
- Excluded-files mechanism to prevent deleted items from returning after sync

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 23:43:36 +01:00

170 lines
5.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Konvertiert alle .rmdoc-Dateien in /mnt/remarkable/current zu PDFs.
# Originale bleiben erhalten. Bereits konvertierte Dateien werden übersprungen.
#
# Nutzung:
# ./convert-to-pdf.sh [BASE_DIR]
# BASE_DIR: Verzeichnis mit .rmdoc-Dateien (default: /mnt/remarkable/current)
set -euo pipefail
BASE_DIR="${1:-/mnt/remarkable/current}"
TMPDIR_BASE="/tmp/rmdoc_convert"
CONVERTED=0
SKIPPED=0
FAILED=0
if ! command -v rmc >/dev/null 2>&1; then
echo "Fehler: rmc nicht im PATH. Installation: pip3 install rmc --break-system-packages"
exit 1
fi
if ! command -v inkscape >/dev/null 2>&1; then
echo "Fehler: inkscape nicht im PATH. Installation: apt install inkscape"
exit 1
fi
if ! command -v pdfunite >/dev/null 2>&1; then
echo "Fehler: pdfunite nicht im PATH. Installation: apt install poppler-utils"
exit 1
fi
while IFS= read -r -d '' RMDOC; do
PDF="${RMDOC%.rmdoc}.pdf"
# Überspringen falls PDF bereits existiert und neuer als rmdoc
if [[ -f "${PDF}" ]] && [[ "${PDF}" -nt "${RMDOC}" ]]; then
(( SKIPPED++ )) || true
continue
fi
# Primär: rmrl (direkt .rmdoc → PDF, kein Inkscape nötig)
if python3 -m rmrl "${RMDOC}" > "${PDF}" 2>/tmp/rmrl_debug.log && [[ -s "${PDF}" ]]; then
echo "OK: $(basename "${RMDOC}") (rmrl)"
pdftoppm -r 72 -jpeg -singlefile "${PDF}" "${PDF%.pdf}.thumb" 2>/dev/null || true
(( CONVERTED++ )) || true
rm -rf "${PDF}" # Platzhalter entfernen falls leer
continue
fi
# Primär: rmrl (direkt .rmdoc → PDF, kein Inkscape nötig)
if python3 -m rmrl "${RMDOC}" > "${PDF}" 2>/tmp/rmrl_debug.log && [[ -s "${PDF}" ]]; then
echo "OK: $(basename "${RMDOC}") (rmrl)"
pdftoppm -r 72 -jpeg -singlefile "${PDF}" "${PDF%.pdf}.thumb" 2>/dev/null || true
(( CONVERTED++ )) || true
continue
fi
TMPDIR="${TMPDIR_BASE}/$$_$(echo "${RMDOC%.rmdoc}" | md5sum | cut -c1-8)"
mkdir -p "${TMPDIR}"
# rmdoc entpacken
if ! unzip -o -q "${RMDOC}" -d "${TMPDIR}" 2>/dev/null; then
echo "WARN: Konnte nicht entpacken: ${RMDOC}"
rm -rf "${TMPDIR}"
(( FAILED++ )) || true
continue
fi
# Seitenreihenfolge aus .content lesen, sonst alphabetisch
RM_FILES=()
CONTENT_FILE="$(find "${TMPDIR}" -maxdepth 1 -name "*.content" | head -1)"
DOC_UUID="$(basename "${CONTENT_FILE%.content}")"
RM_DIR="${TMPDIR}/${DOC_UUID}"
if [[ -f "${CONTENT_FILE}" ]] && [[ -d "${RM_DIR}" ]]; then
# Seiten-UUIDs aus .content in Reihenfolge extrahieren
mapfile -t PAGE_IDS < <(python3 -c "
import json, sys
try:
data = json.load(open('${CONTENT_FILE}'))
pages = data.get('cPages', {}).get('pages', [])
for p in pages:
print(p['id'])
except Exception as e:
sys.exit(1)
" 2>/dev/null)
RM_FILES=()
for PAGE_ID in "${PAGE_IDS[@]}"; do
RM_FILE="${RM_DIR}/${PAGE_ID}.rm"
if [[ -f "${RM_FILE}" ]]; then
RM_FILES+=("${RM_FILE}")
fi
done
fi
# Fallback: alle .rm-Dateien alphabetisch
if [[ ${#RM_FILES[@]} -eq 0 ]]; then
mapfile -t RM_FILES < <(find "${TMPDIR}" -name "*.rm" | sort)
fi
EMBEDDED_PDF="$(find "${TMPDIR}" -maxdepth 2 -name "*.pdf" | head -1)"
if [[ ${#RM_FILES[@]} -eq 0 ]]; then
# Kein Handschrift-Inhalt — eingebettete PDF direkt nutzen
if [[ -n "${EMBEDDED_PDF}" ]]; then
cp "${EMBEDDED_PDF}" "${PDF}"
echo "OK: $(basename "${RMDOC}") (eingebettete PDF)"
pdftoppm -r 72 -jpeg -singlefile "${PDF}" "${PDF%.pdf}.thumb" 2>/dev/null || true
(( CONVERTED++ )) || true
else
(( SKIPPED++ )) || true
fi
rm -rf "${TMPDIR}"
continue
fi
# Annotiertes Import-Dokument: Annotations auf Original-PDF legen
if [[ -n "${EMBEDDED_PDF}" ]] && [[ ${#RM_FILES[@]} -gt 0 ]]; then
if python3 /usr/local/bin/remarkable-merge.py "${TMPDIR}" "${EMBEDDED_PDF}" "${PDF}" 2>/tmp/merge_debug.log && [[ -s "${PDF}" ]]; then
echo "OK: $(basename "${RMDOC}") (PDF + Annotationen)"
pdftoppm -r 72 -jpeg -singlefile "${PDF}" "${PDF%.pdf}.thumb" 2>/dev/null || true
(( CONVERTED++ )) || true
else
cp "${EMBEDDED_PDF}" "${PDF}"
echo "WARN: Merge fehlgeschlagen ($(cat /tmp/merge_debug.log | tail -1)), nutze Original-PDF: $(basename "${RMDOC}")"
pdftoppm -r 72 -jpeg -singlefile "${PDF}" "${PDF%.pdf}.thumb" 2>/dev/null || true
(( CONVERTED++ )) || true
fi
rm -rf "${TMPDIR}"
continue
fi
# Jede Seite einzeln konvertieren, dann zusammenfügen
PAGE_PDFS=()
CONVERT_OK=true
for RM_FILE in "${RM_FILES[@]}"; do
PAGE_PDF="${TMPDIR}/$(basename "${RM_FILE%.rm}").pdf"
if rmc -t pdf -o "${PAGE_PDF}" "${RM_FILE}" 2>/dev/null && [[ -s "${PAGE_PDF}" ]]; then
PAGE_PDFS+=("${PAGE_PDF}")
else
CONVERT_OK=false
break
fi
done
if [[ "${CONVERT_OK}" == true ]] && [[ ${#PAGE_PDFS[@]} -gt 0 ]]; then
if [[ ${#PAGE_PDFS[@]} -eq 1 ]]; then
cp "${PAGE_PDFS[0]}" "${PDF}"
else
pdfunite "${PAGE_PDFS[@]}" "${PDF}" 2>/dev/null
fi
if [[ -s "${PDF}" ]]; then
echo "OK: $(basename "${RMDOC}") (${#PAGE_PDFS[@]} Seiten)"
pdftoppm -r 72 -jpeg -singlefile "${PDF}" "${PDF%.pdf}.thumb" 2>/dev/null || true
(( CONVERTED++ )) || true
else
rm -f "${PDF}"
echo "WARN: Leere PDF für: $(basename "${RMDOC}")"
(( FAILED++ )) || true
fi
else
rm -f "${PDF}"
echo "WARN: Konvertierung fehlgeschlagen: $(basename "${RMDOC}")"
(( FAILED++ )) || true
fi
rm -rf "${TMPDIR}"
done < <(find "${BASE_DIR}" -name "*.rmdoc" -print0)
echo "== Konvertierung fertig: ${CONVERTED} konvertiert, ${SKIPPED} übersprungen, ${FAILED} fehlgeschlagen =="