Compare commits

..

8 Commits

Author SHA1 Message Date
xiexiaobao
6ab36545f1 fix: enable R6C build target + apply r6c.config packages 2026-06-27 15:42:33 +08:00
xiexiaobao
2027ebc82e fix: expand-overlay START=98 to run before dockerd(99) 2026-06-27 15:32:55 +08:00
xiexiaobao
30354fe40e refactor: change eMMC layout - 3G overlay + data partition for Docker
expand-overlay now splits eMMC into:
- p3 (3GB): overlay filesystem (system + configs)
- p4 (~54GB): ext4 data partition -> /mnt/data/docker

Docker data-root auto-configured to /mnt/data/docker on first boot.
2026-06-27 15:29:33 +08:00
xiexiaobao
920956975c chore: gitignore .config.bak 2026-06-27 11:48:46 +08:00
xiexiaobao
98ac0da607 enable FUSE kernel module + ntfs-3g for USB NTFS support
- target/linux/rockchip/armv8/config-6.6: CONFIG_FUSE_FS=m
- r6c.config: add kmod-fuse, fuse-utils, ntfs-3g
2026-06-27 11:48:27 +08:00
xiexiaobao
aa53d5541d feat: add docker-restore package (16-container restore script)
Pre-installs /root/restore-docker.sh in firmware for one-click
recovery of all Docker containers after reflash.
- Covers Jellyfin, Plex, Emby, Immich, Navidrome, n8n, etc.
- Auto-creates immich_default network if missing
- Includes Jellyfin WebRootPath fix and JS patch
- Placeholder passwords (edit before use)
2026-06-26 10:28:31 +08:00
xiexiaobao
fdea857efe feat: add jellyfin-autoinit package
- Auto-pull jellyfin/jellyfin:2026062206-arm64 on first boot
- Fix WebRootPath bug: create symlink /wwwroot -> /jellyfin/jellyfin-web
- Fix JS crash bug (PR #8088): sed patch getApi() null check
- Depends on +docker, gates on expand-overlay.done
- Idempotent via /etc/jellyfin-autoinit.done flag
2026-06-25 14:21:18 +08:00
xiexiaobao
c801aef709 feat: add custom packages
- frpc-config: pre-configure frpc tunnels (SSH/Jellyfin/Navidrome)
- navidrome-autoinit: auto-create Navidrome container on first boot
- expand-overlay: auto-resize eMMC overlay partition
2026-06-24 14:54:44 +08:00
24 changed files with 733 additions and 41 deletions

1
.gitignore vendored
View File

@ -36,3 +36,4 @@ git-src
.cproject
.ccache
.vscode*
.config.bak

View File

@ -133,7 +133,8 @@ _ip2str START "$start"
_ip2str END "$end"
if [ "$start" -le "$ipaddr" ] && [ "$ipaddr" -le "$end" ]; then
echo "warning: address $IP inside range $START..$END" >&2
echo "error: address $IP inside range $START..$END" >&2
exit 1
fi
echo "START=$START"

View File

@ -0,0 +1,43 @@
#
# Copyright (C) 2026 xiexiaobao
#
# This is free software, licensed under the GPL 2.0 license.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=docker-restore
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_MAINTAINER:=xiexiaobao
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define Package/docker-restore
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Docker container restore script for R6C
DEPENDS:=+docker
PKGARCH:=all
endef
define Package/docker-restore/description
One-click restore script for all 16 Docker containers on NanoPi R6C.
Saves docker run commands for Jellyfin, Plex, Emby, Immich, Navidrome,
n8n, HomeAssistant, PhotoPrism, LANraragi, UptimeKuma, Aria2, etc.
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/docker-restore/install
$(INSTALL_DIR) $(1)/root
$(INSTALL_BIN) ./files/restore-docker.sh $(1)/root/restore-docker.sh
endef
$(eval $(call BuildPackage,docker-restore))

View File

@ -0,0 +1,231 @@
#!/bin/sh
# R6C Docker Container Restore Script
# Pre-installed in firmware by docker-restore package
# Run after flashing iStoreOS: sh /root/restore-docker.sh
#
# EDIT THIS FILE: replace CHANGEME values with your actual passwords.
# If you preserved /mnt/usb1-0/, container data survives reflash.
# Immich DB password and Aria2 RPC secret can be found from your old install.
set -e
echo "=== R6C Docker Restore ==="
echo ""
# ---- Wait for dockerd ----
for i in 1 2 3 4 5 6 7 8 9 10 15 20; do
docker info >/dev/null 2>&1 && break
echo "Waiting for dockerd... (${i}s)"
sleep 3
done
docker info >/dev/null 2>&1 || { echo "dockerd not ready"; exit 1; }
echo "dockerd ready"
echo ""
# ---- Check Docker data root ----
CURRENT_ROOT=$(docker info --format "{{.DockerRootDir}}" 2>/dev/null)
if [ "$CURRENT_ROOT" = "/opt/docker" ] && [ -d "/mnt/usb1-0/docker" ]; then
echo "Docker data root is on eMMC but TF card has data."
echo "Run this to fix:"
echo ' uci set dockerd.globals.data_root=/mnt/usb1-0/docker'
echo ' uci add_list dockerd.globals.registry_mirrors=https://docker.1ms.run'
echo ' uci commit dockerd && /etc/init.d/dockerd restart'
echo ""
fi
restore_container() {
local name="$1"
shift
if docker inspect "$name" >/dev/null 2>&1; then
echo "SKIP: $name already exists"
return
fi
echo "Creating: $name"
docker run -d --name "$name" "$@"
echo "DONE: $name"
echo ""
}
# ========== Preparation ==========
# Create Immich network if missing
if ! docker network inspect immich_default >/dev/null 2>&1; then
echo "Creating network: immich_default"
docker network create immich_default
echo ""
fi
# ========== CONTAINERS ==========
# ---- n8n ----
restore_container n8n \
--restart=unless-stopped \
-e WEBHOOK_URL=https://n8n.maplemaple.top \
-e N8N_AI_ENABLED=true \
-e N8N_SECURE_COOKIE=false \
-v /opt/n8n/data:/home/node/.n8n \
-p 5678:5678 \
n8nio/n8n:latest
# ---- ChangeDetection ----
restore_container changedetection \
--restart=unless-stopped \
-e BASE_URL=https://watch.maplemaple.top \
-v /opt/changedetection/data:/datastore \
-p 127.0.0.1:5000:5000 \
ghcr.io/dgtlmoon/changedetection.io:latest
# ---- Jellyfin (with WebRootPath fix) ----
restore_container jellyfin \
--restart=unless-stopped \
--network=host \
-e TZ=Asia/Shanghai \
-v /mnt/usb1-0/Configs/Jellyfin:/config \
-v /mnt/usb1-0/Caches/Jellyfin:/config/transcodes \
-v /mnt/usb1-0:/mnt/usb1-0 \
--entrypoint sh \
jellyfin/jellyfin:2026062206-arm64 \
-c "ln -sf /jellyfin/jellyfin-web /jellyfin/wwwroot && exec /jellyfin/jellyfin"
# ---- Emby ----
restore_container emby \
--restart=unless-stopped \
--network=host \
-v /mnt/usb1-0/Configs/Emby:/config \
-v /mnt:/mnt \
emby/embyserver:latest
# ---- HomeAssistant ----
restore_container homeassistant \
--restart=unless-stopped \
--network=host \
-v /mnt/usb1-0/homeassistant:/config \
homeassistant/home-assistant:latest
# ---- Immich (4 containers) ----
# Note: Update DB_PASSWORD if your Immich DB password differs
IMMICH_DB_PASS="${IMMICH_DB_PASS:-CHANGEME_IMMICH_DB_PASSWORD}"
restore_container immich_postgres \
--restart=unless-stopped \
--network=immich_default \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=immich \
-e POSTGRES_PASSWORD="$IMMICH_DB_PASS" \
-e POSTGRES_INITDB_ARGS="--data-checksums" \
-v /opt/immich/postgres:/var/lib/postgresql/data:rw \
ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
restore_container immich_redis \
--restart=unless-stopped \
--network=immich_default \
docker.io/valkey/valkey:9
restore_container immich_server \
--restart=unless-stopped \
--network=immich_default \
-e TZ=Asia/Shanghai \
-e DB_USERNAME=postgres \
-e DB_DATABASE_NAME=immich \
-e DB_PASSWORD="$IMMICH_DB_PASS" \
-e UPLOAD_LOCATION=/mnt/usb1-0/Public/Immich \
-v /mnt/usb1-0/Public/Immich:/data:rw \
-p 2283:2283 \
ghcr.io/immich-app/immich-server:v2
restore_container immich_machine_learning \
--restart=unless-stopped \
--network=immich_default \
-e TZ=Asia/Shanghai \
-e DB_PASSWORD="$IMMICH_DB_PASS" \
-v immich_model-cache:/cache:rw \
ghcr.io/immich-app/immich-machine-learning:v2
# ---- UptimeKuma ----
restore_container uptime-kuma \
--restart=unless-stopped \
-v /mnt/usb1-0/uptime-kuma:/app/data \
-p 3001:3001 \
louislam/uptime-kuma:latest
# ---- Navidrome ----
restore_container navidrome \
--restart=unless-stopped \
-e ND_PORT=4533 \
-v /mnt/usb1-0/navidrome:/data \
-v /mnt/usb1-0/music:/music:ro \
-p 4533:4533 \
deluan/navidrome:latest
# ---- LANraragi ----
restore_container lanraragi \
--restart=unless-stopped \
-e TZ=Asia/Shanghai \
-v /mnt/usb1-0/Configs/LANraragi:/root/lanraragi/database \
-v /mnt/usb1-0/Public/Comics:/root/lanraragi/content \
-v /mnt:/mnt:rslave \
-p 3000:3000 \
dezhao/lanraragi_cn
# ---- PhotoPrism ----
restore_container photoprism \
--restart=unless-stopped \
-e PHOTOPRISM_UPLOAD_NSFW=true \
-e PHOTOPRISM_ADMIN_PASSWORD=CHANGEME_PHOTOPRISM_PASS \
-e TZ=Asia/Shanghai \
-v /mnt/usb1-0/Configs/PhotoPrism:/photoprism/storage \
-v /mnt/usb1-0/Public/Photo:/photoprism/originals \
-p 2342:2342 \
photoprism/photoprism
# ---- Plex ----
restore_container plex \
--restart=unless-stopped \
-e TZ=Asia/Shanghai \
-e PLEX_CLAIM= \
-v /mnt/usb1-0/Configs/Plex:/config \
-v /mnt/usb1-0/Caches/Plex:/transcode \
-v /mnt:/mnt:rslave \
-p 3005:3005 \
-p 32400:32400 \
-p 32410:32410/udp \
-p 32412:32412/udp \
-p 32413:32413/udp \
-p 32414:32414/udp \
-p 32469:32469 \
-p 8324:8324 \
linuxserver/plex:latest
# ---- Aria2 ----
# Update RPC_SECRET if yours differs
Aria2_RPC_SECRET="${ARIA2_SECRET:-CHANGEME_ARIA2_SECRET}"
restore_container aria2 \
--restart=unless-stopped \
-e PUID=0 -e PGID=0 \
-e RPC_SECRET="$Aria2_RPC_SECRET" \
-e TZ=Asia/Shanghai \
-v /opt/aria2/downloads:/downloads \
-v /opt/aria2/config:/config \
-p 6889:6888 \
-p 6889:6888/udp \
-p 6880:8080 \
p3terx/aria2-pro:latest
# ========== Jellyfin JS patch ==========
echo ""
echo "Patching Jellyfin web UI bug..."
for i in 1 2 3 4 5 6 7 8 9 10; do
docker exec jellyfin curl -s http://127.0.0.1:8096/system/info/public >/dev/null 2>&1 && break
sleep 3
done
docker exec jellyfin sh -c 'sed -i "s/key:\"getApi\",value:function(e){var t,n=this.getApiClient(e);return/key:\"getApi\",value:function(e){if(!e)return;var t,n=this.getApiClient(e);return/g" /wwwroot/main.jellyfin.bundle.js' 2>/dev/null || true
docker restart jellyfin 2>/dev/null || true
echo ""
echo "=== Restore complete ==="
echo ""
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
echo ""
echo "Next steps:"
echo " 1. Set PLEX_CLAIM (visit plex.tv/claim)"
echo " 2. Change PhotoPrism admin password in web UI"
echo " 3. Check Immich admin setup at http://192.168.100.1:2283"
echo " 4. Restart changedetection to pick up API key changes"

View File

@ -0,0 +1,47 @@
#
# Copyright (C) 2026 xiexiaobao
#
# This is free software, licensed under the GPL 2.0 license.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=expand-overlay
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_MAINTAINER:=xiexiaobao
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define Package/expand-overlay
SECTION:=utils
CATEGORY:=Utilities
TITLE:=eMMC partition layout: 3G overlay + data partition
DEPENDS:=+sfdisk +e2fsprogs +block-mount
PKGARCH:=all
endef
define Package/expand-overlay/description
First-boot eMMC partition layout for NanoPi R6C:
- p3 (3GB): overlay filesystem (system/config)
- p4 (~54GB): data partition (mounted at /mnt/data, for Docker)
Stage 1 (uci-defaults): resizes p3 to 3GB, creates p4.
Stage 2 (init.d): resizes p3 fs, formats & mounts p4.
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/expand-overlay/install
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/expand-overlay.sh $(1)/etc/uci-defaults/99-expand-overlay
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/expand-overlay.init $(1)/etc/init.d/expand-overlay
endef
$(eval $(call BuildPackage,expand-overlay))

View File

@ -0,0 +1,51 @@
#!/bin/sh /etc/rc.common
# /etc/init.d/expand-overlay
# Stage 2: Resize p3 filesystem, format & mount p4, configure Docker.
# Runs at START=98 (before dockerd at 99) so Docker picks up data_root.
START=98
boot() {
local flag="/etc/resize2fs.done"
local p4flag="/etc/data-partition.done"
# ---- Stage 2a: Resize p3 filesystem ----
if [ ! -f "$flag" ]; then
local i=0
while [ ! -f "/etc/expand-overlay.done" ] && [ $i -lt 30 ]; do
sleep 1
i=$((i + 1))
done
if [ -f "/etc/expand-overlay.done" ]; then
resize2fs /dev/mmcblk2p3 2>/dev/null
touch "$flag"
fi
fi
# ---- Stage 2b: Format and mount p4 data partition ----
if [ ! -f "$p4flag" ]; then
if dd if=/dev/mmcblk2p4 bs=5 count=1 2>/dev/null | grep -qF "RESET"; then
mkfs.ext4 -F -L data /dev/mmcblk2p4 2>/dev/null
fi
mkdir -p /mnt/data
mount /dev/mmcblk2p4 /mnt/data 2>/dev/null
mkdir -p /mnt/data/docker
uci -q set dockerd.globals.data_root="/mnt/data/docker"
uci -q commit dockerd
if ! grep -q "mmcblk2p4" /etc/config/fstab 2>/dev/null; then
block detect > /dev/null 2>&1
local idx=$(( $(uci show fstab | grep -c "fstab.@mount") - 1 ))
[ "$idx" -ge 0 ] && uci -q set fstab.@mount[$idx].target="/mnt/data"
uci -q commit fstab
fi
touch "$p4flag"
fi
return 0
}

View File

@ -0,0 +1,29 @@
#!/bin/sh
# /etc/uci-defaults/99-expand-overlay
# Stage 1: Resize p3 to 3GB, create p4 for Docker data.
# Auto-removed by uci-defaults after first run.
FLAG_FILE="/etc/expand-overlay.done"
[ -f "$FLAG_FILE" ] && exit 0
# Only run if root is on eMMC
ROOT_DEV=$(mount | grep ' / ' | awk '{print $1}' | sed 's/p[0-9]*$//')
[ "$ROOT_DEV" != "/dev/mmcblk2" ] && exit 0
# Save backup of original partition table
sfdisk -d /dev/mmcblk2 > /etc/sfdisk.bak 2>/dev/null
# Step 1: Resize partition 3 to exactly 3GB (3072 MiB)
# instead of expanding to fill the entire disk
echo ",3072M" | sfdisk -N 3 /dev/mmcblk2 2>/dev/null
# Step 2: Create partition 4 using the remaining space
# sfdisk -N 4 with ",+" = start after p3, fill to end
echo ",+" | sfdisk -N 4 /dev/mmcblk2 2>/dev/null
# Step 3: Write RESET marker on p4 so stage 2 knows to format it
echo "RESET000" | dd of=/dev/mmcblk2p4 bs=512 count=1 conv=notrunc,sync 2>/dev/null
touch "$FLAG_FILE"
exit 0

View File

@ -0,0 +1,42 @@
#
# Copyright (C) 2026 xiexiaobao
#
# This is free software, licensed under the GPL 2.0 license.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=frpc-config
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_MAINTAINER:=xiexiaobao
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define Package/frpc-config
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Pre-configured frpc tunnels (SSH + Jellyfin + Navidrome)
DEPENDS:=+frpc
PKGARCH:=all
endef
define Package/frpc-config/description
Pre-configure frpc tunnels for VPS 43.134.64.107:7000.
Tunnels: SSH(:2222), Jellyfin(:8096), Navidrome(:4533).
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/frpc-config/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/frpc $(1)/etc/config/frpc
endef
$(eval $(call BuildPackage,frpc-config))

View File

@ -0,0 +1,32 @@
config init
option stdout '1'
option stderr '1'
option user 'frpc'
option group 'frpc'
option respawn '1'
config conf 'common'
option server_addr '43.134.64.107'
option server_port '7000'
option token '@@xiefeng'
config conf 'ssh'
option type 'tcp'
option local_ip '127.0.0.1'
option local_port '22'
option remote_port '2222'
option name 'ssh'
config conf 'jellyfin'
option type 'tcp'
option local_ip '127.0.0.1'
option local_port '8096'
option remote_port '8096'
option name 'jellyfin'
config conf 'navidrome'
option type 'tcp'
option local_ip '127.0.0.1'
option local_port '4533'
option remote_port '4533'
option name 'navidrome'

View File

@ -0,0 +1,34 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=jellyfin-autoinit
PKG_VERSION:=1.0
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define Package/jellyfin-autoinit
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Auto-pull and start Jellyfin Docker container on first boot
PKGARCH:=all
DEPENDS:=+docker
endef
define Package/jellyfin-autoinit/description
On first boot, after eMMC expansion is complete, this package will:
1) docker pull jellyfin/jellyfin:2026062206-arm64
2) create the Jellyfin container (host network, correct webroot symlink)
3) patch the JS startup crash bug (PR #8088)
4) start with rkmpp hardware acceleration
Re-runs are guarded by /etc/jellyfin-autoinit.done.
endef
define Package/jellyfin-autoinit/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) ./files/jellyfin-autoinit.sh $(1)/usr/bin/jellyfin-autoinit.sh
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/jellyfin-autoinit.init $(1)/etc/init.d/jellyfin-autoinit
endef
$(eval $(call BuildPackage,jellyfin-autoinit))

View File

@ -0,0 +1,9 @@
#!/bin/sh /etc/rc.common
# Jellyfin container auto-start on boot
# START=98 = after dockerd, before user services
# Stage ordering: dockerd → expand-overlay(99) → this(98) → user services
START=98
start() {
/usr/bin/jellyfin-autoinit.sh
}

View File

@ -0,0 +1,84 @@
#!/bin/sh
# Auto-pull and start Jellyfin Docker container on first boot
# Fixes two known bugs in jellyfin/jellyfin:2026062206-arm64:
# 1) WebRootPath points to empty /jellyfin/wwwroot/ — workaround: symlink
# 2) JS crash "item or serverId cannot be null" (PR #8088) — workaround: sed patch
#
# Gates on expand-overlay.done so it only runs after the eMMC is resized
# Idempotent: skips if container or flag file exists
# Forgiving: pull failure exits 0 so init retries next boot
# Tolerates missing expand-overlay.done (may not be created on mismatched firmware)
FLAG_FILE="/etc/jellyfin-autoinit.done"
# Wait up to 30s for expand-overlay to finish
for i in 1 2 3 4 5 6 7 8 9 10; do
[ -f /etc/expand-overlay.done ] && break
sleep 3
done
# Already done
[ -f "$FLAG_FILE" ] && exit 0
# Docker available? Wait for dockerd to actually be ready
if ! command -v docker >/dev/null 2>&1; then
echo "[jellyfin-autoinit] docker binary not found, exiting"
exit 0
fi
for i in 1 2 3 4 5 6 7 8 9 10; do
docker info >/dev/null 2>&1 && break
[ "$i" -eq 10 ] && { echo "[jellyfin-autoinit] dockerd not ready after 30s, exiting"; exit 0; }
sleep 3
done
# Container already exists
if docker inspect jellyfin >/dev/null 2>&1; then
echo "[jellyfin-autoinit] container already exists, skipping"
touch "$FLAG_FILE"
exit 0
fi
echo "[jellyfin-autoinit] pulling jellyfin/jellyfin:2026062206-arm64..."
docker pull jellyfin/jellyfin:2026062206-arm64 2>&1 | tail -3 || {
echo "[jellyfin-autoinit] pull failed, will retry next boot"
exit 0
}
# Ensure mount points exist
mkdir -p /mnt/usb1-0/Configs/Jellyfin/config
mkdir -p /mnt/usb1-0/Configs/Jellyfin/cache
mkdir -p /mnt/usb1-0/Caches/Jellyfin
echo "[jellyfin-autoinit] creating container with webroot fix..."
docker run -d \
--name jellyfin \
--restart unless-stopped \
--network=host \
-e TZ=Asia/Shanghai \
-v /mnt/usb1-0/Configs/Jellyfin:/config \
-v /mnt/usb1-0/Caches/Jellyfin:/config/transcodes \
-v /mnt/usb1-0:/mnt/usb1-0 \
--entrypoint sh \
jellyfin/jellyfin:2026062206-arm64 \
-c 'ln -sf /jellyfin/jellyfin-web /wwwroot && exec /jellyfin/jellyfin' 2>&1 | tail -3
# Wait for Jellyfin API to be ready, then patch the JS startup crash bug
echo "[jellyfin-autoinit] waiting for Jellyfin to start..."
for i in 1 2 3 4 5 6 7 8 9 10 15 20; do
docker exec jellyfin curl -s http://127.0.0.1:8096/system/info/public >/dev/null 2>&1 && break
[ "$i" -eq 20 ] && { echo "[jellyfin-autoinit] Jellyfin not ready after 60s"; break; }
sleep 3
done
echo "[jellyfin-autoinit] patching JS startup crash bug (PR #8088)..."
docker exec jellyfin sh -c 'sed -i "s/key:\"getApi\",value:function(e){var t,n=this.getApiClient(e);return/key:\"getApi\",value:function(e){if(!e)return;var t,n=this.getApiClient(e);return/g" /wwwroot/main.jellyfin.bundle.js'
docker restart jellyfin
if docker ps | grep -q jellyfin; then
echo "[jellyfin-autoinit] jellyfin started successfully with all fixes applied"
touch "$FLAG_FILE"
else
echo "[jellyfin-autoinit] failed to start, will retry next boot"
fi

View File

@ -0,0 +1,42 @@
#
# Copyright (C) 2026 xiexiaobao
#
# This is free software, licensed under the GPL 2.0 license.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=navidrome-autoinit
PKG_VERSION:=1.0
PKG_RELEASE:=1
PKG_MAINTAINER:=xiexiaobao
PKG_LICENSE:=GPL-2.0
include $(INCLUDE_DIR)/package.mk
define Package/navidrome-autoinit
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Auto-create Navidrome container on first boot
DEPENDS:=+dockerd
PKGARCH:=all
endef
define Package/navidrome-autoinit/description
Automatically pull and start the Navidrome music streaming container
on first boot after flashing. Music and data directories on /mnt/usb1-0.
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/navidrome-autoinit/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/navidrome.init $(1)/etc/init.d/navidrome-autoinit
endef
$(eval $(call BuildPackage,navidrome-autoinit))

View File

@ -0,0 +1,70 @@
#!/bin/sh /etc/rc.common
# /etc/init.d/navidrome-autoinit
# Auto-create Navidrome Docker container on first boot.
# Idempotent: skips if container or FLAG_FILE exists.
# Tolerates missing TF card: exits gracefully.
START=97
FLAG_FILE="/etc/navidrome-autoinit.done"
CONTAINER="navidrome"
IMAGE="deluan/navidrome:latest"
MUSIC_DIR="/mnt/usb1-0/music"
DATA_DIR="/mnt/usb1-0/navidrome"
PORT="4533"
boot() {
[ -f "$FLAG_FILE" ] && return 0
# Verify Docker is installed
if ! command -v docker >/dev/null 2>&1; then
logger -t navidrome-autoinit "docker binary not found, skipping"
return 0
fi
# Wait up to 30s for dockerd to be ready
local i=0
while ! docker info >/dev/null 2>&1 && [ $i -lt 10 ]; do
sleep 3
i=$((i + 1))
done
if ! docker info >/dev/null 2>&1; then
logger -t navidrome-autoinit "dockerd not ready after 30s, will retry next boot"
return 0
fi
# Container already exists (e.g. Docker data root restored from TF card)
if docker inspect "$CONTAINER" >/dev/null 2>&1; then
logger -t navidrome-autoinit "container $CONTAINER already exists, skipping"
touch "$FLAG_FILE"
return 0
fi
# Create music and data directories on TF card
mkdir -p "$MUSIC_DIR" "$DATA_DIR"
# Pull the image (tolerate network failure — will retry next boot)
logger -t navidrome-autoinit "pulling $IMAGE..."
if ! docker pull "$IMAGE" 2>&1 | logger -t navidrome-autoinit; then
logger -t navidrome-autoinit "pull failed, will retry next boot"
return 0
fi
# Create and start the container
logger -t navidrome-autoinit "creating container $CONTAINER..."
docker run -d \
--name "$CONTAINER" \
--restart unless-stopped \
-p ${PORT}:${PORT} \
-v "$DATA_DIR":/data \
-v "$MUSIC_DIR":/music:ro \
"$IMAGE" 2>&1 | logger -t navidrome-autoinit
if docker ps | grep -q "$CONTAINER"; then
logger -t navidrome-autoinit "$CONTAINER started successfully on port $PORT"
touch "$FLAG_FILE"
else
logger -t navidrome-autoinit "$CONTAINER failed to start, will retry next boot"
fi
return 0
}

View File

@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=dnsmasq
PKG_UPSTREAM_VERSION:=2.90
PKG_VERSION:=$(subst test,~~test,$(subst rc,~rc,$(PKG_UPSTREAM_VERSION)))
PKG_RELEASE:=6
PKG_RELEASE:=5
PKG_SOURCE:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION).tar.xz
PKG_SOURCE_URL:=https://thekelleys.org.uk/dnsmasq/

View File

@ -597,20 +597,10 @@ dhcp_add() {
nettag="${networkid:+set:${networkid},}"
# make sure the DHCP range is not empty
if [ "$dhcpv4" != "disabled" ]; then
unset START
unset END
unset NETMASK
ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit"
if [ "$dhcpv4" != "disabled" ] && ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit" ; then
[ "$dynamicdhcpv4" = "0" ] && END="static"
if [ -z "$START" ] || [ -z "$END" ] || [ -z "$NETMASK" ]; then
logger -t dnsmasq \
"unable to set dhcp-range for dhcp uci config section '$cfg'" \
"on interface '$ifname', please check your config"
else
[ "$dynamicdhcpv4" = "0" ] && END="static"
xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
fi
xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
fi
if [ "$dynamicdhcpv6" = "0" ] ; then

5
r6c.config Normal file
View File

@ -0,0 +1,5 @@
CONFIG_PACKAGE_jellyfin-autoinit=y
CONFIG_PACKAGE_docker-restore=y
CONFIG_PACKAGE_kmod-fuse=y
CONFIG_PACKAGE_fuse-utils=y
CONFIG_PACKAGE_ntfs-3g=y

View File

@ -24,11 +24,11 @@
# danger zones
# 0-117
# part start size end
# boot 0x7500000/117M (239616s) 0x4000000/64M 0xB500000/181M (370687s)
# rootfs 0xB500000/181M (370688s) 0x18F00000/399M 0x24400000/580M (1187839s)
# part start size end
# boot 0x7500000/117M 0x4000000/64M 0xB500000/181M
# rootfs 0xB500000/181M 0x18F00000/399M 0x24400000/580M
# (gap for amlogic bootloader 0x24400000 - 0x32000000)
# overlay 0x32000000/800M (1638400s) 0x80000000/2G 0xB2000000/2848M (4194304s)
# overlay 0x32000000/800M 0x80000000/2G 0xB2000000/2848M
. /lib/functions.sh
. /lib/functions/system.sh
@ -51,19 +51,6 @@ function umount_disk() {
function part_disk() {
local to="${1#/dev/}"
#dd if="/dev/$to" of=/tmp/mmc-diskid.bin bs=1 skip=440 count=4
dd if=/dev/zero of="/dev/$to" bs=1 seek=446 count=64 conv=notrunc
{
# echo o;
echo n; echo p; echo 1; echo 239616; echo 370687;
echo n; echo p; echo 2; echo 370688; echo 1187839;
echo n; echo p; echo 3; echo 1638400; echo 4194304;
echo t; echo 1; echo c;
echo w;
} | fdisk "/dev/$to"
#dd if=/tmp/mmc-diskid.bin of="/dev/$to" bs=1 seek=440 count=4 conv=notrunc
return 0
dd if=/dev/zero of="/dev/$to" bs=512 count=1 conv=notrunc 2>/dev/null
parted --script "/dev/$to" \
mktable msdos \

View File

@ -20,9 +20,6 @@ export_ota_url() {
lyt,t68m)
export -n OTA_URL_BASE="https://fw0.koolcenter.com/iStoreOS/${board##*,}"
;;
easepi,a2)
export -n OTA_URL_BASE="https://fw0.koolcenter.com/iStoreOS/easepi-a2"
;;
easepi,r1)
export -n OTA_URL_BASE="https://fw0.koolcenter.com/iStoreOS/easepi-r1"
;;

View File

@ -739,3 +739,4 @@ CONFIG_XZ_DEC_BCJ=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZONE_DMA32=y
CONFIG_FUSE_FS=m

View File

@ -15,7 +15,6 @@
aliases {
ethernet0 = &pcie_eth0;
/delete-property/ ethernet1;
mmc2 = &sdmmc2;
};
chosen {

View File

@ -22,7 +22,6 @@
aliases {
ethernet2 = &pcie_eth2;
ethernet3 = &pcie_eth3;
mmc2 = &sdmmc2;
};
pwr-net-25g {

View File

@ -8,7 +8,6 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/pwm/pwm.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/soc/rockchip,vop2.h>
#include <dt-bindings/usb/pd.h>
@ -22,7 +21,6 @@
/ {
model = "Xunlong Orange Pi 5 Plus";
compatible = "xunlong,orangepi-5-plus", "rockchip,rk3588";
eth_order = "0004:41:00.0,0003:31:00.0";
aliases {
mmc0 = &sdhci;
@ -418,7 +416,7 @@
op-sink-microwatt = <1000000>;
source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
sink-pdos = <PDO_FIXED(5000, 1000, PDO_FIXED_USB_COMM)>;
try-power-role = "sink";
try-power-role = "source";
ports {
#address-cells = <1>;

View File

@ -132,7 +132,7 @@ define Device/friendlyarm_nanopi-r6c
SOC := rk3588s
DEVICE_PACKAGES := kmod-r8169
endef
# TARGET_DEVICES += friendlyarm_nanopi-r6c
TARGET_DEVICES += friendlyarm_nanopi-r6c
define Device/friendlyarm_nanopi-r6s
DEVICE_VENDOR := FriendlyARM