feat(jellyfin): Add secubox-app-jellyfin and luci-app-jellyfin packages

Docker-based Jellyfin media server with UCI config (port, image, media
paths, GPU transcoding), procd init, jellyfinctl CLI, and LuCI frontend
with status/config/logs view.

Also adds Punk Exposure Engine architectural README documenting the
Peek/Poke/Emancipate service exposure model and DNS provider API
roadmap. CLAUDE.md updated with architectural directive.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-02-04 14:50:59 +01:00
parent c6de8b2b1b
commit 297917e79a
97 changed files with 1130 additions and 147 deletions

View File

@ -266,7 +266,8 @@
"Bash(gdbus call:*)",
"Bash(git mv:*)",
"Bash(DISPLAY=:1 scrot:*)",
"Bash(node -c:*)"
"Bash(node -c:*)",
"Bash(/home/reepost/CyberMindStudio/secubox-openwrt/secubox-tools/local-build.sh:*)"
]
}
}

View File

@ -169,3 +169,44 @@ ssh root@192.168.255.1 '/etc/init.d/rpcd restart'
- **RPC params order matters**: The `params` array in `rpc.declare()` must match the positional arguments in `addPeer(arg1, arg2, ...)` calls — adding a new param means updating ALL callers
- **sessionStorage is volatile**: Data stored in `sessionStorage` is lost on tab close/refresh — don't rely on it for persistent data; use UCI backend storage instead
- **Interface name conflicts**: When creating WireGuard interfaces, always check for existing names (wg0, wg1, etc.) and auto-increment to the next available name
## Punk Exposure Engine — Architectural Directive
The SecuBox service exposure architecture follows a three-verb model called **Peek / Poke / Emancipate**. All new service components, exposure features, and mesh integrations must align with this model.
### Core Concepts
- **Peek**: Discover and scan. Any feature that detects services, lists DNS records, shows mesh peers, or aggregates visibility across nodes.
- **Poke**: Target and configure. Any feature that selects a service and configures an exposure channel (Tor, DNS/SSL, mesh publish).
- **Emancipate**: Activate the linking flow. Any feature that atomically makes a service reachable through one or more channels.
### Three Exposure Channels
1. **Tor**`.onion` hidden services via `secubox-app-tor` + `secubox-exposure tor add`
2. **DNS/SSL** — Classical HTTPS via HAProxy + ACME + DNS provider API (OVH, Gandi, Cloudflare) via `secubox-app-dns-provider` + `dnsctl`
3. **Mesh** — P2P service registry via `secubox-p2p publish` + gossip chain sync
### Key Architectural Rules
- **Match services by port, not name** — when cross-referencing scan results with Tor/SSL/vhost/mesh entries, always use the backend port number as the join key
- **DNS provider API integration** — use `dnsctl` (from `secubox-app-dns-provider`) for programmatic DNS record management; support DNS-01 ACME challenges as alternative to HTTP-01 webroot
- **Emancipate is multi-channel** — exposing a service should support activating Tor + DNS + Mesh in a single flow; each channel is independently togglable
- **Every station is generative** — each SecuBox node can discover local services, create new exposure endpoints, and propagate them to mesh peers
- **Guard against local-only exposure** — never auto-expose services bound to 127.0.0.1; only services on 0.0.0.0 or specific LAN IPs are eligible for external exposure
### Reference Document
Full architectural spec: `package/secubox/PUNK-EXPOSURE.md`
### Affected Packages
| Package | Role in Punk Exposure |
|---------|----------------------|
| `secubox-app-exposure` | Peek scanner + Tor/SSL orchestrator |
| `luci-app-exposure` | Dashboard: Peek table + Poke toggles |
| `secubox-app-tor` | Tor channel backend |
| `secubox-app-haproxy` | SSL/ACME channel backend |
| `secubox-app-dns-provider` | DNS provider API (to build) |
| `secubox-p2p` | Mesh channel + gossip sync |
| `secubox-master-link` | Node onboarding + trust hierarchy |
| `luci-app-service-registry` | Aggregated service catalog + health checks |

View File

@ -0,0 +1,243 @@
# Punk Exposure Engine
## Vision
Every SecuBox node is a **generative station** — it discovers what runs locally, and offers a unified flow to make any service reachable through all available channels: Tor .onion, classical DNS/HTTPS, P2P mesh, or all three at once.
Three verbs define the workflow:
- **Peek** — Scan, discover, look around. What's running? What's exposed? What domains are mapped? What peers are online?
- **Poke** — Target a service. Pick the exposure channels. Configure the linking flow.
- **Emancipate** — Activate. The service becomes reachable. DNS records are created, certificates are issued, .onion addresses are generated, mesh peers are notified.
## Architecture
```
EMANCIPATE
|
+----------------+----------------+
| | |
Tor Layer DNS/SSL Layer Mesh Layer
(.onion) (HTTPS+ACME) (P2P peers)
| | |
tor-shield haproxyctl secubox-p2p
hidden svc + dns-provider-api + gossip sync
+ acme.sh
|
DNS Provider APIs
(OVH, Gandi, Cloudflare)
|
A/AAAA/CNAME records
created programmatically
```
## Components
### Existing (already built)
| Component | Package | What it does |
|-----------|---------|--------------|
| Service scanner | `secubox-app-exposure` | `netstat` scan enriched with UCI/Docker/process names |
| Tor exposure | `secubox-app-tor` + `secubox-app-exposure` | `tor_add()` creates hidden service dir + torrc entry |
| SSL/HAProxy exposure | `secubox-app-haproxy` + `secubox-app-exposure` | `ssl_add()` creates HAProxy backend + vhost + ACME cert |
| ACME certificates | `secubox-app-haproxy` | `acme.sh` with HTTP-01 webroot validation via port 8402 |
| VHost manager | `luci-app-vhost-manager` | Nginx-based vhost CRUD with ACME + templates |
| P2P mesh | `secubox-p2p` | mDNS discovery, WireGuard mesh, service registry, gossip chain |
| Master-Link | `secubox-master-link` | Hierarchical node onboarding with HMAC tokens + blockchain audit |
| Service registry | `luci-app-service-registry` | Aggregates services across mesh, health checks, landing page |
| Exposure dashboard | `luci-app-exposure` | Single-table KISS view: scan + Tor/SSL toggles per service |
### Missing (to build)
| Component | Purpose | Priority |
|-----------|---------|----------|
| **DNS provider API** | Programmatic DNS record management (OVH, Gandi, Cloudflare) | **High** |
| **DNS-01 ACME** | Wildcard certs + domains without port 80 access | **High** |
| **Unified Poke flow** | Single action to expose service on all channels | Medium |
| **Peek aggregation** | Combined view: local scan + mesh peers + DNS records + Tor | Medium |
| **Emancipate orchestrator** | Atomic multi-channel activation with rollback | Medium |
## DNS Provider API Integration
### Design
New package: `secubox-app-dns-provider`
```
package/secubox/secubox-app-dns-provider/
files/etc/config/dns-provider # UCI: provider type, API keys, zone
files/etc/init.d/dns-provider # (optional) cron for record sync
files/usr/sbin/dnsctl # CLI: record add/rm/list/sync
files/usr/lib/secubox/dns/ # Provider adapters
ovh.sh # OVH API (app key + secret + consumer key)
gandi.sh # Gandi LiveDNS (API key)
cloudflare.sh # Cloudflare (API token + zone ID)
```
### UCI config
```uci
config dns_provider 'main'
option enabled '1'
option provider 'ovh' # ovh | gandi | cloudflare
option zone 'example.com' # managed DNS zone
config ovh 'ovh'
option endpoint 'ovh-eu' # ovh-eu | ovh-ca | ovh-us
option app_key ''
option app_secret ''
option consumer_key ''
config gandi 'gandi'
option api_key ''
config cloudflare 'cloudflare'
option api_token ''
option zone_id ''
```
### dnsctl commands
```
dnsctl list # List all DNS records in zone
dnsctl add A myservice 1.2.3.4 # Create A record
dnsctl add CNAME blog mycdn.net # Create CNAME
dnsctl rm A myservice # Remove record
dnsctl sync # Sync local vhosts to DNS records
dnsctl verify myservice.example.com # Check DNS propagation
```
### acme.sh DNS-01 integration
Once `dnsctl` works, enable DNS-01 challenges in `haproxyctl cert add`:
```sh
# Current (HTTP-01 only):
acme.sh --issue -d "$domain" --webroot /var/www/acme-challenge
# New (DNS-01 via provider):
provider=$(uci -q get dns-provider.main.provider)
case "$provider" in
ovh)
export OVH_END_POINT=$(uci -q get dns-provider.ovh.endpoint)
export OVH_APPLICATION_KEY=$(uci -q get dns-provider.ovh.app_key)
export OVH_APPLICATION_SECRET=$(uci -q get dns-provider.ovh.app_secret)
export OVH_CONSUMER_KEY=$(uci -q get dns-provider.ovh.consumer_key)
acme.sh --issue -d "$domain" --dns dns_ovh
;;
gandi)
export GANDI_LIVEDNS_KEY=$(uci -q get dns-provider.gandi.api_key)
acme.sh --issue -d "$domain" --dns dns_gandi_livedns
;;
cloudflare)
export CF_Token=$(uci -q get dns-provider.cloudflare.api_token)
export CF_Zone_ID=$(uci -q get dns-provider.cloudflare.zone_id)
acme.sh --issue -d "$domain" --dns dns_cf
;;
esac
```
This unlocks **wildcard certificates** (`*.example.com`) and domains behind firewalls without port 80.
## The Emancipate Flow
When a user pokes a service and chooses "Emancipate", the orchestrator runs all selected channels atomically:
```
User selects: Gitea (port 3001) → Emancipate [Tor + DNS + Mesh]
1. Tor channel:
secubox-exposure tor add gitea 3001 80
→ .onion address generated
2. DNS channel:
dnsctl add A gitea <public-ip>
haproxyctl vhost add gitea.example.com 3001
haproxyctl cert add gitea.example.com --dns
→ HTTPS live at gitea.example.com
3. Mesh channel:
secubox-p2p publish gitea 3001 "Gitea"
gossip_sync
→ All mesh peers discover the service
4. Registry update:
Service registry refreshed
Landing page regenerated
Exposure dashboard shows all three badges
```
### Rollback on failure
If any channel fails, previously completed channels are not torn down — they remain active. The failure is reported, and the user can retry or remove individual channels via the Exposure dashboard toggles.
## Peek: What Exists Today
The current Exposure dashboard (`luci-app-exposure/services.js`) already implements Peek:
- Scans all listening ports via `netstat -tlnp`
- Enriches with real names from uhttpd, streamlit, Docker, glances configs
- Cross-references Tor hidden services by backend port
- Cross-references HAProxy vhosts by backend port
- Shows toggle switches for Tor and SSL per service
### What Peek needs next
- **DNS records column**: Show which services have DNS A/CNAME records via `dnsctl list`
- **Mesh visibility column**: Show which services are published to mesh peers
- **Multi-node view**: Aggregate services across all mesh peers (already available via `secubox-p2p get_shared_services`)
## Poke: What Exists Today
The toggle switches in the Exposure dashboard are already "Poke" actions:
- Toggle Tor ON → modal → service name + onion port → Enable
- Toggle SSL ON → modal → service name + domain → Enable
### What Poke needs next
- **DNS toggle**: Third toggle column for DNS record management
- **Emancipate button**: "Expose everywhere" single action per service
- **Provider selection**: Choose which DNS zone/provider for the domain
## Integration Points with Existing Packages
| Package | Integration | Direction |
|---------|------------|-----------|
| `secubox-app-exposure` | Peek scan + Tor/SSL add/remove | Already working |
| `secubox-app-haproxy` | HAProxy vhost + ACME cert | Already working |
| `secubox-app-tor` | Hidden service lifecycle | Already working |
| `secubox-p2p` | Service publish + gossip sync | Add `publish` RPC call |
| `luci-app-exposure` | Dashboard: add DNS column + Emancipate button | Frontend extension |
| `secubox-app-dns-provider` | **NEW**: DNS record CRUD via provider APIs | To build |
| `luci-app-dns-provider` | **NEW**: LuCI config for provider credentials | To build |
## Implementation Order
1. **`secubox-app-dns-provider`** — CLI tool + UCI config + provider adapters (OVH first)
2. **DNS-01 in haproxyctl** — Wire `dnsctl` into ACME flow as alternative to HTTP-01
3. **`luci-app-dns-provider`** — LuCI frontend for provider configuration
4. **Exposure dashboard DNS column** — Add DNS toggle + `dnsctl` integration
5. **Emancipate flow** — Unified orchestrator in `secubox-exposure emancipate`
6. **Mesh publish integration** — Wire `secubox-p2p publish` into Emancipate
## Naming Convention
The project uses punk/DIY metaphors:
| Term | Meaning | Technical equivalent |
|------|---------|---------------------|
| **Peek** | Discover, scan, observe | `secubox-exposure scan` + service registry |
| **Poke** | Target, configure, aim | Toggle switches + modal config |
| **Emancipate** | Activate, make free, expose | Multi-channel atomic activation |
| **Station** | A SecuBox node | One OpenWrt device running the mesh |
| **Generative** | Each station can create new endpoints | Docker apps + exposure channels |
## Security Considerations
- DNS provider API keys stored in UCI with restricted ACL
- ACME private keys in `/etc/acme/` with 600 permissions
- Tor hidden service keys in `/var/lib/tor/` owned by tor:tor
- Emancipate flow never exposes 127.0.0.1-only services (guard in scan)
- DNS records only created for services the user explicitly Pokes
- Rollback does NOT auto-delete — user must explicitly remove exposure

View File

@ -0,0 +1,29 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI Jellyfin Media Server Configuration
LUCI_DEPENDS:=+secubox-app-jellyfin
LUCI_PKGARCH:=all
PKG_NAME:=luci-app-jellyfin
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
PKG_LICENSE:=Apache-2.0
include $(TOPDIR)/feeds/luci/luci.mk
define Package/luci-app-jellyfin/install
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-jellyfin.json $(1)/usr/share/luci/menu.d/
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-jellyfin.json $(1)/usr/share/rpcd/acl.d/
$(INSTALL_DIR) $(1)/www/luci-static/resources/view/jellyfin
$(INSTALL_DATA) ./htdocs/luci-static/resources/view/jellyfin/*.js $(1)/www/luci-static/resources/view/jellyfin/
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
$(INSTALL_BIN) ./root/usr/libexec/rpcd/luci.jellyfin $(1)/usr/libexec/rpcd/
endef
$(eval $(call BuildPackage,luci-app-jellyfin))

View File

@ -0,0 +1,236 @@
'use strict';
'require view';
'require form';
'require uci';
'require rpc';
'require ui';
var callStatus = rpc.declare({
object: 'luci.jellyfin',
method: 'status',
expect: {}
});
var callStart = rpc.declare({
object: 'luci.jellyfin',
method: 'start',
expect: {}
});
var callStop = rpc.declare({
object: 'luci.jellyfin',
method: 'stop',
expect: {}
});
var callRestart = rpc.declare({
object: 'luci.jellyfin',
method: 'restart',
expect: {}
});
var callInstall = rpc.declare({
object: 'luci.jellyfin',
method: 'install',
expect: {}
});
var callLogs = rpc.declare({
object: 'luci.jellyfin',
method: 'logs',
params: ['lines'],
expect: {}
});
return view.extend({
load: function() {
return Promise.all([
uci.load('jellyfin'),
callStatus()
]);
},
render: function(data) {
var status = data[1] || {};
var m, s, o;
m = new form.Map('jellyfin', _('Jellyfin Media Server'),
_('Free media server for streaming movies, TV shows, music, and photos.'));
/* ---- Status Section ---- */
s = m.section(form.NamedSection, 'main', 'jellyfin', _('Service Status'));
s.anonymous = true;
o = s.option(form.DummyValue, '_status', _('Status'));
o.rawhtml = true;
o.cfgvalue = function() {
var cs = status.container_status || 'unknown';
var color = cs === 'running' ? '#27ae60' : (cs === 'stopped' ? '#e74c3c' : '#8892b0');
var label = cs === 'running' ? 'Running' : (cs === 'stopped' ? 'Stopped' : 'Not Installed');
var html = '<span style="color:' + color + '; font-weight: bold;">' + label + '</span>';
if (cs === 'running' && status.container_uptime)
html += ' <span style="color: #8892b0;">(' + status.container_uptime + ')</span>';
return html;
};
o = s.option(form.DummyValue, '_docker', _('Docker'));
o.rawhtml = true;
o.cfgvalue = function() {
return status.docker_available
? '<span style="color:#27ae60;">Available</span>'
: '<span style="color:#e74c3c;">Not available</span>';
};
o = s.option(form.DummyValue, '_info', _('Details'));
o.rawhtml = true;
o.cfgvalue = function() {
var port = status.port || 8096;
var html = '<table style="border-collapse:collapse;">';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Image:</td><td>' + (status.image || '-') + '</td></tr>';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Port:</td><td>' + port + '</td></tr>';
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Data:</td><td>' + (status.data_path || '-') + '</td></tr>';
if (status.media_paths && status.media_paths.length > 0)
html += '<tr><td style="padding:2px 12px 2px 0;color:#8892b0;">Media:</td><td>' + status.media_paths.join('<br>') + '</td></tr>';
html += '</table>';
return html;
};
/* ---- Action Buttons ---- */
o = s.option(form.DummyValue, '_actions', _('Actions'));
o.rawhtml = true;
o.cfgvalue = function() {
return '';
};
var cs = status.container_status || 'not_installed';
if (cs === 'not_installed') {
o = s.option(form.Button, '_install', _('Install'));
o.inputtitle = _('Install Jellyfin');
o.inputstyle = 'apply';
o.onclick = function() {
ui.showModal(_('Installing...'), [
E('p', { 'class': 'spinning' }, _('Pulling Docker image and configuring...'))
]);
return callInstall().then(function(res) {
ui.hideModal();
if (res && res.success) {
ui.addNotification(null, E('p', {}, _('Jellyfin installed successfully.')), 'info');
} else {
ui.addNotification(null, E('p', {}, _('Installation failed: ') + (res.output || 'Unknown error')), 'danger');
}
window.location.href = window.location.pathname + '?' + Date.now();
});
};
} else {
if (cs === 'stopped') {
o = s.option(form.Button, '_start', _('Start'));
o.inputtitle = _('Start');
o.inputstyle = 'apply';
o.onclick = function() {
return callStart().then(function() {
window.location.href = window.location.pathname + '?' + Date.now();
});
};
}
if (cs === 'running') {
o = s.option(form.Button, '_stop', _('Stop'));
o.inputtitle = _('Stop');
o.inputstyle = 'remove';
o.onclick = function() {
return callStop().then(function() {
window.location.href = window.location.pathname + '?' + Date.now();
});
};
o = s.option(form.Button, '_restart', _('Restart'));
o.inputtitle = _('Restart');
o.inputstyle = 'reload';
o.onclick = function() {
return callRestart().then(function() {
window.location.href = window.location.pathname + '?' + Date.now();
});
};
o = s.option(form.Button, '_webui', _('Web UI'));
o.inputtitle = _('Open Web UI');
o.inputstyle = 'action';
o.onclick = function() {
var port = status.port || 8096;
window.open('http://' + window.location.hostname + ':' + port, '_blank');
};
}
}
/* ---- Configuration Section ---- */
s = m.section(form.NamedSection, 'main', 'jellyfin', _('Configuration'));
s.anonymous = true;
o = s.option(form.Flag, 'enabled', _('Enabled'),
_('Enable the Jellyfin service.'));
o.rmempty = false;
o = s.option(form.Value, 'port', _('Port'),
_('HTTP port for the Jellyfin web interface.'));
o.datatype = 'port';
o.placeholder = '8096';
o = s.option(form.Value, 'image', _('Docker Image'),
_('Docker image to use.'));
o.placeholder = 'jellyfin/jellyfin:latest';
o = s.option(form.Value, 'data_path', _('Data Path'),
_('Path for Jellyfin config and cache data.'));
o.placeholder = '/srv/jellyfin';
o = s.option(form.Value, 'timezone', _('Timezone'));
o.placeholder = 'Europe/Paris';
/* ---- Media Libraries ---- */
s = m.section(form.NamedSection, 'media', 'jellyfin', _('Media Libraries'));
s.anonymous = true;
o = s.option(form.DynamicList, 'media_path', _('Media Paths'),
_('Directories containing your media files. Mounted read-only into the container.'));
o.placeholder = '/mnt/media/movies';
/* ---- Transcoding ---- */
s = m.section(form.NamedSection, 'transcoding', 'jellyfin', _('Hardware Transcoding'));
s.anonymous = true;
o = s.option(form.Flag, 'hw_accel', _('Hardware Acceleration'),
_('Enable GPU hardware transcoding. Requires a compatible GPU device.'));
o.rmempty = false;
o = s.option(form.Value, 'gpu_device', _('GPU Device'),
_('Path to the GPU device for hardware transcoding.'));
o.placeholder = '/dev/dri';
o.depends('hw_accel', '1');
/* ---- Logs Section ---- */
s = m.section(form.NamedSection, 'main', 'jellyfin', _('Logs'));
s.anonymous = true;
o = s.option(form.DummyValue, '_logs', ' ');
o.rawhtml = true;
o.cfgvalue = function() {
return '<div id="jellyfin-logs" style="background:#0a0a1a; color:#ccc; padding:8px; ' +
'border-radius:4px; font-family:monospace; font-size:12px; max-height:300px; ' +
'overflow-y:auto; white-space:pre-wrap; min-height:40px;">Click "Fetch Logs" to view container output.</div>';
};
o = s.option(form.Button, '_fetch_logs', _('Fetch Logs'));
o.inputtitle = _('Fetch Logs');
o.inputstyle = 'action';
o.onclick = function() {
var logsDiv = document.getElementById('jellyfin-logs');
if (logsDiv) logsDiv.textContent = 'Loading...';
return callLogs(50).then(function(res) {
if (logsDiv) logsDiv.textContent = (res && res.logs) ? res.logs : 'No logs available.';
});
};
return m.render();
}
});

View File

@ -0,0 +1,100 @@
#!/bin/sh
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
CONTAINER="secbx-jellyfin"
CONFIG="jellyfin"
case "$1" in
list)
echo '{"status":{},"start":{},"stop":{},"restart":{},"install":{},"logs":{"lines":"int"}}'
;;
call)
case "$2" in
status)
json_init
enabled=$(uci -q get ${CONFIG}.main.enabled)
image=$(uci -q get ${CONFIG}.main.image)
port=$(uci -q get ${CONFIG}.main.port)
data_path=$(uci -q get ${CONFIG}.main.data_path)
timezone=$(uci -q get ${CONFIG}.main.timezone)
hw_accel=$(uci -q get ${CONFIG}.transcoding.hw_accel)
json_add_boolean "enabled" ${enabled:-0}
json_add_string "image" "${image:-jellyfin/jellyfin:latest}"
json_add_int "port" ${port:-8096}
json_add_string "data_path" "${data_path:-/srv/jellyfin}"
json_add_string "timezone" "${timezone:-Europe/Paris}"
json_add_boolean "hw_accel" ${hw_accel:-0}
# Docker availability
if command -v docker >/dev/null 2>&1; then
json_add_boolean "docker_available" 1
else
json_add_boolean "docker_available" 0
fi
# Container status
if docker ps --filter "name=$CONTAINER" --format '{{.Status}}' 2>/dev/null | grep -q .; then
json_add_string "container_status" "running"
uptime=$(docker ps --filter "name=$CONTAINER" --format '{{.Status}}' 2>/dev/null)
json_add_string "container_uptime" "$uptime"
elif docker ps -a --filter "name=$CONTAINER" --format '{{.Status}}' 2>/dev/null | grep -q .; then
json_add_string "container_status" "stopped"
json_add_string "container_uptime" ""
else
json_add_string "container_status" "not_installed"
json_add_string "container_uptime" ""
fi
# Media paths
json_add_array "media_paths"
for mp in $(uci -q get ${CONFIG}.media.media_path); do
json_add_string "" "$mp"
done
json_close_array
json_dump
;;
start)
/etc/init.d/jellyfin start >/dev/null 2>&1
echo '{"success":true}'
;;
stop)
/etc/init.d/jellyfin stop >/dev/null 2>&1
echo '{"success":true}'
;;
restart)
/etc/init.d/jellyfin restart >/dev/null 2>&1
echo '{"success":true}'
;;
install)
output=$(/usr/sbin/jellyfinctl install 2>&1)
code=$?
json_init
json_add_boolean "success" $((code == 0))
json_add_string "output" "$output"
json_dump
;;
logs)
read -r input
lines=$(echo "$input" | jsonfilter -e '@.lines' 2>/dev/null)
[ -z "$lines" ] && lines=50
logs=$(docker logs --tail "$lines" "$CONTAINER" 2>&1 | tail -100)
json_init
json_add_string "logs" "$logs"
json_dump
;;
esac
;;
esac
exit 0

View File

@ -0,0 +1,14 @@
{
"admin/services/jellyfin": {
"title": "Jellyfin",
"order": 60,
"action": {
"type": "view",
"path": "jellyfin/overview"
},
"depends": {
"acl": ["luci-app-jellyfin"],
"uci": {"jellyfin": true}
}
}
}

View File

@ -0,0 +1,24 @@
{
"luci-app-jellyfin": {
"description": "Grant access to Jellyfin media server configuration",
"read": {
"file": {
"/etc/config/jellyfin": ["read"]
},
"ubus": {
"file": ["read", "stat"],
"luci.jellyfin": ["*"]
},
"uci": ["jellyfin"]
},
"write": {
"file": {
"/etc/config/jellyfin": ["write"]
},
"ubus": {
"luci.jellyfin": ["*"]
},
"uci": ["jellyfin"]
}
}
}

View File

@ -8,7 +8,7 @@ Architecture: all
Installed-Size: 71680
Description: Comprehensive authentication and session management with captive portal, OAuth2/OIDC integration, voucher system, and time-based access control
Filename: luci-app-auth-guardian_0.4.0-r3_all.ipk
Size: 11737
Size: 11733
Package: luci-app-bandwidth-manager
Version: 0.5.0-r2
@ -20,7 +20,7 @@ Architecture: all
Installed-Size: 337920
Description: Advanced bandwidth management with QoS rules, client quotas, and SQM integration
Filename: luci-app-bandwidth-manager_0.5.0-r2_all.ipk
Size: 61538
Size: 61537
Package: luci-app-cdn-cache
Version: 0.5.0-r3
@ -32,7 +32,7 @@ Architecture: all
Installed-Size: 122880
Description: Dashboard for managing local CDN caching proxy on OpenWrt
Filename: luci-app-cdn-cache_0.5.0-r3_all.ipk
Size: 23186
Size: 23183
Package: luci-app-client-guardian
Version: 0.4.0-r7
@ -44,7 +44,7 @@ Architecture: all
Installed-Size: 286720
Description: Network Access Control with client monitoring, zone management, captive portal, parental controls, and SMS/email alerts
Filename: luci-app-client-guardian_0.4.0-r7_all.ipk
Size: 54535
Size: 54534
Package: luci-app-crowdsec-dashboard
Version: 0.7.0-r32
@ -56,7 +56,7 @@ Architecture: all
Installed-Size: 184320
Description: Real-time security monitoring dashboard for CrowdSec on OpenWrt
Filename: luci-app-crowdsec-dashboard_0.7.0-r32_all.ipk
Size: 33798
Size: 33797
Package: luci-app-cyberfeed
Version: 0.1.1-r1
@ -68,7 +68,7 @@ Architecture: all
Installed-Size: 71680
Description: Cyberpunk-themed RSS feed aggregator dashboard with social media support
Filename: luci-app-cyberfeed_0.1.1-r1_all.ipk
Size: 12840
Size: 12837
Package: luci-app-dnsguard
Version: 1.0.0-r1
@ -79,7 +79,7 @@ Architecture: all
Installed-Size: 40960
Description: SecuBox DNS Guard - Privacy DNS Manager
Filename: luci-app-dnsguard_1.0.0-r1_all.ipk
Size: 7550
Size: 7545
Package: luci-app-exposure
Version: 1.0.0-r3
@ -88,10 +88,10 @@ License: MIT
Section: luci
Maintainer: OpenWrt LuCI community
Architecture: all
Installed-Size: 153600
Installed-Size: 61440
Description: LuCI SecuBox Service Exposure Manager
Filename: luci-app-exposure_1.0.0-r3_all.ipk
Size: 20534
Size: 9685
Package: luci-app-gitea
Version: 1.0.0-r2
@ -115,7 +115,7 @@ Architecture: all
Installed-Size: 40960
Description: Modern dashboard for Glances system monitoring with SecuBox theme
Filename: luci-app-glances_1.0.0-r2_all.ipk
Size: 6969
Size: 6965
Package: luci-app-haproxy
Version: 1.0.0-r8
@ -127,7 +127,7 @@ Architecture: all
Installed-Size: 204800
Description: Web interface for managing HAProxy load balancer with vhosts, SSL certificates, and backend routing
Filename: luci-app-haproxy_1.0.0-r8_all.ipk
Size: 34560
Size: 34559
Package: luci-app-hexojs
Version: 1.0.0-r3
@ -139,7 +139,7 @@ Architecture: all
Installed-Size: 184320
Description: Modern dashboard for Hexo static site generator on OpenWrt
Filename: luci-app-hexojs_1.0.0-r3_all.ipk
Size: 30307
Size: 30309
Package: luci-app-jitsi
Version: 1.0.0-r1
@ -163,7 +163,7 @@ Architecture: all
Installed-Size: 112640
Description: Centralized cryptographic key management with hardware security module (HSM) support for Nitrokey and YubiKey devices. Provides secure key storage, certificate management, SSH key handling, and secret storage with audit logging.
Filename: luci-app-ksm-manager_0.4.0-r2_all.ipk
Size: 18721
Size: 18725
Package: luci-app-localai
Version: 0.1.0-r15
@ -175,7 +175,7 @@ Architecture: all
Installed-Size: 71680
Description: Modern dashboard for LocalAI LLM management on OpenWrt
Filename: luci-app-localai_0.1.0-r15_all.ipk
Size: 13183
Size: 13181
Package: luci-app-lyrion
Version: 1.0.0-r1
@ -187,7 +187,7 @@ Architecture: all
Installed-Size: 40960
Description: LuCI support for Lyrion Music Server
Filename: luci-app-lyrion_1.0.0-r1_all.ipk
Size: 6729
Size: 6723
Package: luci-app-magicmirror2
Version: 0.4.0-r6
@ -199,7 +199,7 @@ Architecture: all
Installed-Size: 71680
Description: Modern dashboard for MagicMirror2 smart display platform with module manager and SecuBox theme
Filename: luci-app-magicmirror2_0.4.0-r6_all.ipk
Size: 12277
Size: 12279
Package: luci-app-mailinabox
Version: 1.0.0-r1
@ -211,7 +211,7 @@ Architecture: all
Installed-Size: 30720
Description: LuCI support for Mail-in-a-Box
Filename: luci-app-mailinabox_1.0.0-r1_all.ipk
Size: 5483
Size: 5484
Package: luci-app-master-link
Version: 1.0.0-r1
@ -223,7 +223,7 @@ Architecture: all
Installed-Size: 30720
Description: LuCI SecuBox Master-Link Mesh Management
Filename: luci-app-master-link_1.0.0-r1_all.ipk
Size: 6247
Size: 6248
Package: luci-app-media-flow
Version: 0.6.4-r1
@ -235,7 +235,7 @@ Architecture: all
Installed-Size: 133120
Description: Real-time detection and monitoring of streaming services (Netflix, YouTube, Spotify, etc.) with quality estimation, history tracking, and alerts. Supports nDPId local DPI and netifyd.
Filename: luci-app-media-flow_0.6.4-r1_all.ipk
Size: 25416
Size: 25417
Package: luci-app-metablogizer
Version: 1.0.0-r5
@ -259,7 +259,7 @@ Architecture: all
Installed-Size: 30720
Description: LuCI support for Metabolizer CMS
Filename: luci-app-metabolizer_1.0.0-r2_all.ipk
Size: 4760
Size: 4758
Package: luci-app-mitmproxy
Version: 0.5.0-r2
@ -271,7 +271,7 @@ Architecture: all
Installed-Size: 61440
Description: Modern dashboard for mitmproxy HTTPS traffic inspection with SecuBox theme
Filename: luci-app-mitmproxy_0.5.0-r2_all.ipk
Size: 11149
Size: 11148
Package: luci-app-mmpm
Version: 0.2.0-r3
@ -283,7 +283,7 @@ Architecture: all
Installed-Size: 51200
Description: Web interface for MMPM - MagicMirror Package Manager
Filename: luci-app-mmpm_0.2.0-r3_all.ipk
Size: 7901
Size: 7905
Package: luci-app-mqtt-bridge
Version: 0.4.0-r4
@ -295,7 +295,7 @@ Architecture: all
Installed-Size: 122880
Description: USB-to-MQTT IoT hub with SecuBox theme
Filename: luci-app-mqtt-bridge_0.4.0-r4_all.ipk
Size: 22777
Size: 22779
Package: luci-app-ndpid
Version: 1.1.2-r2
@ -319,7 +319,7 @@ Architecture: all
Installed-Size: 112640
Description: Real-time system monitoring dashboard with Netdata integration for OpenWrt
Filename: luci-app-netdata-dashboard_0.5.0-r2_all.ipk
Size: 20486
Size: 20484
Package: luci-app-network-modes
Version: 0.5.0-r3
@ -331,7 +331,7 @@ Architecture: all
Installed-Size: 286720
Description: Configure OpenWrt for different network modes: Sniffer, Access Point, Relay, Router
Filename: luci-app-network-modes_0.5.0-r3_all.ipk
Size: 54147
Size: 54150
Package: luci-app-network-tweaks
Version: 1.0.0-r7
@ -343,7 +343,7 @@ Architecture: all
Installed-Size: 81920
Description: Unified network services dashboard with DNS/hosts sync, CDN cache control, and WPAD auto-proxy configuration
Filename: luci-app-network-tweaks_1.0.0-r7_all.ipk
Size: 14957
Size: 14969
Package: luci-app-nextcloud
Version: 1.0.0-r1
@ -355,7 +355,7 @@ Architecture: all
Installed-Size: 30720
Description: LuCI support for Nextcloud
Filename: luci-app-nextcloud_1.0.0-r1_all.ipk
Size: 6486
Size: 6487
Package: luci-app-ollama
Version: 0.1.0-r1
@ -367,7 +367,7 @@ Architecture: all
Installed-Size: 61440
Description: Modern dashboard for Ollama LLM management on OpenWrt
Filename: luci-app-ollama_0.1.0-r1_all.ipk
Size: 12353
Size: 12352
Package: luci-app-picobrew
Version: 1.0.0-r1
@ -379,7 +379,7 @@ Architecture: all
Installed-Size: 51200
Description: Modern dashboard for PicoBrew Server management on OpenWrt
Filename: luci-app-picobrew_1.0.0-r1_all.ipk
Size: 9457
Size: 9458
Package: luci-app-secubox
Version: 0.7.1-r4
@ -391,7 +391,7 @@ Architecture: all
Installed-Size: 419840
Description: Central control hub for all SecuBox modules. Provides unified dashboard, module status, system health monitoring, and quick actions.
Filename: luci-app-secubox_0.7.1-r4_all.ipk
Size: 77680
Size: 77679
Package: luci-app-secubox-admin
Version: 1.0.0-r19
@ -402,7 +402,7 @@ Architecture: all
Installed-Size: 337920
Description: Unified admin control center for SecuBox appstore plugins with system monitoring
Filename: luci-app-secubox-admin_1.0.0-r19_all.ipk
Size: 57250
Size: 57249
Package: luci-app-secubox-crowdsec
Version: 1.0.0-r3
@ -414,7 +414,7 @@ Architecture: all
Installed-Size: 81920
Description: LuCI SecuBox CrowdSec Dashboard
Filename: luci-app-secubox-crowdsec_1.0.0-r3_all.ipk
Size: 13923
Size: 13918
Package: luci-app-secubox-netdiag
Version: 1.0.0-r1
@ -438,7 +438,7 @@ Architecture: all
Installed-Size: 194560
Description: Complete LuCI interface for netifyd DPI engine with real-time flow monitoring, application detection, network analytics, and flow action plugins
Filename: luci-app-secubox-netifyd_1.2.1-r1_all.ipk
Size: 36547
Size: 36542
Package: luci-app-secubox-p2p
Version: 0.1.0-r1
@ -450,7 +450,7 @@ Architecture: all
Installed-Size: 215040
Description: LuCI SecuBox P2P Hub
Filename: luci-app-secubox-p2p_0.1.0-r1_all.ipk
Size: 39237
Size: 39234
Package: luci-app-secubox-portal
Version: 0.7.0-r2
@ -462,7 +462,7 @@ Architecture: all
Installed-Size: 122880
Description: Unified entry point for all SecuBox applications with tabbed navigation
Filename: luci-app-secubox-portal_0.7.0-r2_all.ipk
Size: 24646
Size: 24644
Package: luci-app-secubox-security-threats
Version: 1.0.0-r4
@ -474,7 +474,7 @@ Architecture: all
Installed-Size: 102400
Description: Unified dashboard integrating netifyd DPI threats with CrowdSec intelligence for real-time threat monitoring and automated blocking
Filename: luci-app-secubox-security-threats_1.0.0-r4_all.ipk
Size: 21897
Size: 21895
Package: luci-app-service-registry
Version: 1.0.0-r1
@ -486,7 +486,7 @@ Architecture: all
Installed-Size: 194560
Description: Unified service aggregation with HAProxy vhosts, Tor hidden services, and QR-coded landing page
Filename: luci-app-service-registry_1.0.0-r1_all.ipk
Size: 39827
Size: 39826
Package: luci-app-simplex
Version: 1.0.0-r1
@ -498,7 +498,7 @@ Architecture: all
Installed-Size: 40960
Description: LuCI SimpleX Chat Server Configuration
Filename: luci-app-simplex_1.0.0-r1_all.ipk
Size: 7001
Size: 6997
Package: luci-app-streamlit
Version: 1.0.0-r11
@ -522,7 +522,7 @@ Architecture: all
Installed-Size: 317440
Description: Central system control with monitoring, services, logs, and backup
Filename: luci-app-system-hub_0.5.1-r4_all.ipk
Size: 61105
Size: 61102
Package: luci-app-tor-shield
Version: 1.0.0-r10
@ -534,7 +534,7 @@ Architecture: all
Installed-Size: 122880
Description: Modern dashboard for Tor anonymization on OpenWrt
Filename: luci-app-tor-shield_1.0.0-r10_all.ipk
Size: 22364
Size: 22359
Package: luci-app-traffic-shaper
Version: 0.4.0-r2
@ -546,7 +546,7 @@ Architecture: all
Installed-Size: 81920
Description: Advanced traffic shaping with TC/CAKE for precise bandwidth control
Filename: luci-app-traffic-shaper_0.4.0-r2_all.ipk
Size: 14533
Size: 14532
Package: luci-app-vhost-manager
Version: 0.5.0-r5
@ -558,7 +558,7 @@ Architecture: all
Installed-Size: 153600
Description: Nginx reverse proxy manager with Let's Encrypt SSL certificates, authentication, and WebSocket support
Filename: luci-app-vhost-manager_0.5.0-r5_all.ipk
Size: 26185
Size: 26187
Package: luci-app-wireguard-dashboard
Version: 0.7.0-r5
@ -570,7 +570,7 @@ Architecture: all
Installed-Size: 204800
Description: Modern dashboard for WireGuard VPN monitoring on OpenWrt
Filename: luci-app-wireguard-dashboard_0.7.0-r5_all.ipk
Size: 39607
Size: 39604
Package: luci-app-zigbee2mqtt
Version: 1.0.0-r2
@ -582,7 +582,7 @@ Architecture: all
Installed-Size: 40960
Description: Graphical interface for managing the Zigbee2MQTT docker application.
Filename: luci-app-zigbee2mqtt_1.0.0-r2_all.ipk
Size: 6813
Size: 6815
Package: luci-theme-secubox
Version: 0.4.7-r1
@ -594,7 +594,7 @@ Architecture: all
Installed-Size: 450560
Description: Global CyberMood design system (CSS/JS/i18n) shared by all SecuBox dashboards.
Filename: luci-theme-secubox_0.4.7-r1_all.ipk
Size: 110242
Size: 110241
Package: secubox-app
Version: 1.0.0-r2
@ -619,7 +619,7 @@ Description: Installer, configuration, and service manager for running AdGuard
inside Docker on SecuBox-powered OpenWrt systems. Network-wide ad blocker
with DNS-over-HTTPS/TLS support and detailed analytics.
Filename: secubox-app-adguardhome_1.0.0-r2_all.ipk
Size: 2883
Size: 2880
Package: secubox-app-auth-logger
Version: 1.2.2-r1
@ -637,7 +637,7 @@ Description: Logs authentication failures from LuCI/rpcd and Dropbear SSH
- JavaScript hook to intercept login failures
- CrowdSec parser and bruteforce scenario
Filename: secubox-app-auth-logger_1.2.2-r1_all.ipk
Size: 9379
Size: 9376
Package: secubox-app-crowdsec-custom
Version: 1.1.0-r1
@ -687,7 +687,7 @@ Description: SecuBox CrowdSec Firewall Bouncer for OpenWrt.
- Automatic restart on firewall reload
- procd service management
Filename: secubox-app-cs-firewall-bouncer_0.0.31-r4_aarch64_cortex-a72.ipk
Size: 5049328
Size: 5049322
Package: secubox-app-cyberfeed
Version: 0.2.1-r1
@ -701,7 +701,7 @@ Description: Cyberpunk-themed RSS feed aggregator for OpenWrt/SecuBox.
Features emoji injection, neon styling, and RSS-Bridge support
for social media feeds (Facebook, Twitter, Mastodon).
Filename: secubox-app-cyberfeed_0.2.1-r1_all.ipk
Size: 12452
Size: 12449
Package: secubox-app-domoticz
Version: 1.0.0-r2
@ -714,7 +714,7 @@ Installed-Size: 10240
Description: Installer, configuration, and service manager for running Domoticz
inside Docker on SecuBox-powered OpenWrt systems.
Filename: secubox-app-domoticz_1.0.0-r2_all.ipk
Size: 2550
Size: 2544
Package: secubox-app-exposure
Version: 1.0.0-r1
@ -729,7 +729,7 @@ Description: Unified service exposure manager for SecuBox.
- Dynamic Tor hidden service management
- HAProxy SSL reverse proxy configuration
Filename: secubox-app-exposure_1.0.0-r1_all.ipk
Size: 6938
Size: 6931
Package: secubox-app-gitea
Version: 1.0.0-r5
@ -752,7 +752,7 @@ Description: Gitea Git Platform - Self-hosted lightweight Git service
Runs in LXC container with Alpine Linux.
Configure in /etc/config/gitea.
Filename: secubox-app-gitea_1.0.0-r5_all.ipk
Size: 9409
Size: 9406
Package: secubox-app-glances
Version: 1.0.0-r1
@ -775,7 +775,7 @@ Description: Glances - Cross-platform system monitoring tool for SecuBox.
Runs in LXC container for isolation and security.
Configure in /etc/config/glances.
Filename: secubox-app-glances_1.0.0-r1_all.ipk
Size: 5542
Size: 5533
Package: secubox-app-haproxy
Version: 1.0.0-r23
@ -795,7 +795,7 @@ Description: HAProxy load balancer and reverse proxy running in an LXC containe
- Stats dashboard
- Rate limiting and ACLs
Filename: secubox-app-haproxy_1.0.0-r23_all.ipk
Size: 15687
Size: 15681
Package: secubox-app-hexojs
Version: 1.0.0-r8
@ -819,7 +819,7 @@ Description: Hexo CMS - Self-hosted static blog generator for OpenWrt
Runs in LXC container with Alpine Linux.
Configure in /etc/config/hexojs.
Filename: secubox-app-hexojs_1.0.0-r8_all.ipk
Size: 94937
Size: 94933
Package: secubox-app-jitsi
Version: 1.0.0-r1
@ -844,7 +844,7 @@ Description: Jitsi Meet - Secure, fully featured video conferencing for SecuBox
Integrates with HAProxy for SSL termination.
Configure in /etc/config/jitsi.
Filename: secubox-app-jitsi_1.0.0-r1_all.ipk
Size: 8916
Size: 8914
Package: secubox-app-localai
Version: 2.25.0-r1
@ -866,7 +866,7 @@ Description: LocalAI native binary package for OpenWrt.
API: http://<router-ip>:8081/v1
Filename: secubox-app-localai_2.25.0-r1_all.ipk
Size: 5718
Size: 5725
Package: secubox-app-localai-wb
Version: 2.25.0-r1
@ -890,7 +890,7 @@ Description: LocalAI native binary package for OpenWrt.
API: http://<router-ip>:8080/v1
Filename: secubox-app-localai-wb_2.25.0-r1_all.ipk
Size: 7954
Size: 7951
Package: secubox-app-lyrion
Version: 2.0.2-r1
@ -910,7 +910,7 @@ Description: Lyrion Media Server (formerly Logitech Media Server / Squeezebox S
Auto-detects available runtime, preferring LXC for lower resource usage.
Configure runtime in /etc/config/lyrion.
Filename: secubox-app-lyrion_2.0.2-r1_all.ipk
Size: 7288
Size: 7292
Package: secubox-app-magicmirror2
Version: 0.4.0-r8
@ -932,7 +932,7 @@ Description: MagicMirror² - Open source modular smart mirror platform for Secu
Runs in LXC container for isolation and security.
Configure in /etc/config/magicmirror2.
Filename: secubox-app-magicmirror2_0.4.0-r8_all.ipk
Size: 9254
Size: 9250
Package: secubox-app-mailinabox
Version: 2.0.0-r1
@ -957,7 +957,7 @@ Description: Complete email server solution using docker-mailserver for SecuBox
Commands: mailinaboxctl --help
Filename: secubox-app-mailinabox_2.0.0-r1_all.ipk
Size: 7573
Size: 7570
Package: secubox-app-metabolizer
Version: 1.0.0-r3
@ -1005,7 +1005,7 @@ Description: mitmproxy - Interactive HTTPS proxy for SecuBox-powered OpenWrt sy
Runs in LXC container for isolation and security.
Configure in /etc/config/mitmproxy.
Filename: secubox-app-mitmproxy_0.5.0-r19_all.ipk
Size: 22958
Size: 22956
Package: secubox-app-mmpm
Version: 0.2.0-r5
@ -1026,7 +1026,7 @@ Description: MMPM (MagicMirror Package Manager) for SecuBox.
Runs inside the MagicMirror2 LXC container.
Filename: secubox-app-mmpm_0.2.0-r5_all.ipk
Size: 3982
Size: 3980
Package: secubox-app-nextcloud
Version: 1.0.0-r2
@ -1040,7 +1040,7 @@ Description: Installer, configuration, and service manager for running Nextclou
inside Docker on SecuBox-powered OpenWrt systems. Self-hosted file
sync and share with calendar, contacts, and collaboration.
Filename: secubox-app-nextcloud_1.0.0-r2_all.ipk
Size: 2961
Size: 2959
Package: secubox-app-ollama
Version: 0.1.0-r1
@ -1062,7 +1062,7 @@ Description: Ollama - Simple local LLM runtime for SecuBox-powered OpenWrt syst
Runs in Docker/Podman container.
Configure in /etc/config/ollama.
Filename: secubox-app-ollama_0.1.0-r1_all.ipk
Size: 5737
Size: 5734
Package: secubox-app-picobrew
Version: 1.0.0-r7
@ -1084,7 +1084,7 @@ Description: PicoBrew Server - Self-hosted brewing controller for PicoBrew devi
Runs in LXC container with Python/Flask backend.
Configure in /etc/config/picobrew.
Filename: secubox-app-picobrew_1.0.0-r7_all.ipk
Size: 5538
Size: 5539
Package: secubox-app-simplex
Version: 1.0.0-r1
@ -1108,7 +1108,7 @@ Description: SimpleX Chat self-hosted messaging infrastructure for SecuBox.
Privacy-first messaging relay that you control.
Configure in /etc/config/simplex.
Filename: secubox-app-simplex_1.0.0-r1_all.ipk
Size: 9233
Size: 9232
Package: secubox-app-streamlit
Version: 1.0.0-r5
@ -1135,7 +1135,7 @@ Description: Streamlit App Platform - Self-hosted Python data app platform
Configure in /etc/config/streamlit.
Filename: secubox-app-streamlit_1.0.0-r5_all.ipk
Size: 11718
Size: 11723
Package: secubox-app-tor
Version: 1.0.0-r1
@ -1176,7 +1176,7 @@ Description: SecuBox Control Center Dashboard - A web-based dashboard for monit
- Service management
- Network interface control
Filename: secubox-app-webapp_1.5.0-r7_all.ipk
Size: 39174
Size: 39172
Package: secubox-app-zigbee2mqtt
Version: 1.0.0-r3
@ -1189,7 +1189,7 @@ Installed-Size: 20480
Description: Installer, configuration, and service manager for running Zigbee2MQTT
inside Docker on SecuBox-powered OpenWrt systems.
Filename: secubox-app-zigbee2mqtt_1.0.0-r3_all.ipk
Size: 3544
Size: 3545
Package: secubox-core
Version: 0.10.0-r11
@ -1209,7 +1209,7 @@ Description: SecuBox Core Framework provides the foundational infrastructure fo
- Unified CLI interface
- ubus RPC backend
Filename: secubox-core_0.10.0-r11_all.ipk
Size: 87973
Size: 87974
Package: secubox-master-link
Version: 1.0.0-r1
@ -1231,7 +1231,7 @@ Description: Secure mesh onboarding for SecuBox nodes via master/peer link.
Configure in /etc/config/master-link.
Filename: secubox-master-link_1.0.0-r1_all.ipk
Size: 12455
Size: 12454
Package: secubox-p2p
Version: 0.6.0-r3
@ -1250,5 +1250,5 @@ Description: SecuBox P2P Hub backend providing peer discovery, mesh networking
and MirrorBox NetMesh Catalog for cross-chain distributed service
registry with HAProxy vhost discovery and multi-endpoint access URLs.
Filename: secubox-p2p_0.6.0-r3_all.ipk
Size: 42015
Size: 42016

View File

@ -1,12 +1,12 @@
{
"feed_url": "/secubox-feed",
"generated": "2026-02-03T06:19:17+01:00",
"generated": "2026-02-04T14:31:38+01:00",
"packages": [
{
"name": "luci-app-auth-guardian",
"version": "0.4.0-r3",
"filename": "luci-app-auth-guardian_0.4.0-r3_all.ipk",
"size": 11737,
"size": 11733,
"category": "security",
"icon": "key",
"description": "Authentication management",
@ -18,7 +18,7 @@
"name": "luci-app-bandwidth-manager",
"version": "0.5.0-r2",
"filename": "luci-app-bandwidth-manager_0.5.0-r2_all.ipk",
"size": 61538,
"size": 61537,
"category": "network",
"icon": "activity",
"description": "Bandwidth monitoring and control",
@ -30,7 +30,7 @@
"name": "luci-app-cdn-cache",
"version": "0.5.0-r3",
"filename": "luci-app-cdn-cache_0.5.0-r3_all.ipk",
"size": 23186,
"size": 23183,
"category": "network",
"icon": "globe",
"description": "CDN caching",
@ -42,7 +42,7 @@
"name": "luci-app-client-guardian",
"version": "0.4.0-r7",
"filename": "luci-app-client-guardian_0.4.0-r7_all.ipk",
"size": 54535,
"size": 54534,
"category": "network",
"icon": "users",
"description": "Client management and monitoring",
@ -54,7 +54,7 @@
"name": "luci-app-crowdsec-dashboard",
"version": "0.7.0-r32",
"filename": "luci-app-crowdsec-dashboard_0.7.0-r32_all.ipk",
"size": 33798,
"size": 33797,
"category": "security",
"icon": "shield",
"description": "CrowdSec security monitoring",
@ -66,7 +66,7 @@
"name": "luci-app-cyberfeed",
"version": "0.1.1-r1",
"filename": "luci-app-cyberfeed_0.1.1-r1_all.ipk",
"size": 12840,
"size": 12837,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -78,7 +78,7 @@
"name": "luci-app-dnsguard",
"version": "1.0.0-r1",
"filename": "luci-app-dnsguard_1.0.0-r1_all.ipk",
"size": 7550,
"size": 7545,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -90,7 +90,7 @@
"name": "luci-app-exposure",
"version": "1.0.0-r3",
"filename": "luci-app-exposure_1.0.0-r3_all.ipk",
"size": 20534,
"size": 9685,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -114,7 +114,7 @@
"name": "luci-app-glances",
"version": "1.0.0-r2",
"filename": "luci-app-glances_1.0.0-r2_all.ipk",
"size": 6969,
"size": 6965,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -126,7 +126,7 @@
"name": "luci-app-haproxy",
"version": "1.0.0-r8",
"filename": "luci-app-haproxy_1.0.0-r8_all.ipk",
"size": 34560,
"size": 34559,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -138,7 +138,7 @@
"name": "luci-app-hexojs",
"version": "1.0.0-r3",
"filename": "luci-app-hexojs_1.0.0-r3_all.ipk",
"size": 30307,
"size": 30309,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -162,7 +162,7 @@
"name": "luci-app-ksm-manager",
"version": "0.4.0-r2",
"filename": "luci-app-ksm-manager_0.4.0-r2_all.ipk",
"size": 18721,
"size": 18725,
"category": "system",
"icon": "cpu",
"description": "Kernel memory management",
@ -174,7 +174,7 @@
"name": "luci-app-localai",
"version": "0.1.0-r15",
"filename": "luci-app-localai_0.1.0-r15_all.ipk",
"size": 13183,
"size": 13181,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -186,7 +186,7 @@
"name": "luci-app-lyrion",
"version": "1.0.0-r1",
"filename": "luci-app-lyrion_1.0.0-r1_all.ipk",
"size": 6729,
"size": 6723,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -198,7 +198,7 @@
"name": "luci-app-magicmirror2",
"version": "0.4.0-r6",
"filename": "luci-app-magicmirror2_0.4.0-r6_all.ipk",
"size": 12277,
"size": 12279,
"category": "iot",
"icon": "monitor",
"description": "Smart mirror display",
@ -210,7 +210,7 @@
"name": "luci-app-mailinabox",
"version": "1.0.0-r1",
"filename": "luci-app-mailinabox_1.0.0-r1_all.ipk",
"size": 5483,
"size": 5484,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -222,7 +222,7 @@
"name": "luci-app-master-link",
"version": "1.0.0-r1",
"filename": "luci-app-master-link_1.0.0-r1_all.ipk",
"size": 6247,
"size": 6248,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -234,7 +234,7 @@
"name": "luci-app-media-flow",
"version": "0.6.4-r1",
"filename": "luci-app-media-flow_0.6.4-r1_all.ipk",
"size": 25416,
"size": 25417,
"category": "media",
"icon": "film",
"description": "Media streaming",
@ -258,7 +258,7 @@
"name": "luci-app-metabolizer",
"version": "1.0.0-r2",
"filename": "luci-app-metabolizer_1.0.0-r2_all.ipk",
"size": 4760,
"size": 4758,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -270,7 +270,7 @@
"name": "luci-app-mitmproxy",
"version": "0.5.0-r2",
"filename": "luci-app-mitmproxy_0.5.0-r2_all.ipk",
"size": 11149,
"size": 11148,
"category": "security",
"icon": "lock",
"description": "HTTPS proxy and traffic inspection",
@ -282,7 +282,7 @@
"name": "luci-app-mmpm",
"version": "0.2.0-r3",
"filename": "luci-app-mmpm_0.2.0-r3_all.ipk",
"size": 7901,
"size": 7905,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -294,7 +294,7 @@
"name": "luci-app-mqtt-bridge",
"version": "0.4.0-r4",
"filename": "luci-app-mqtt-bridge_0.4.0-r4_all.ipk",
"size": 22777,
"size": 22779,
"category": "iot",
"icon": "message-square",
"description": "MQTT bridge",
@ -318,7 +318,7 @@
"name": "luci-app-netdata-dashboard",
"version": "0.5.0-r2",
"filename": "luci-app-netdata-dashboard_0.5.0-r2_all.ipk",
"size": 20486,
"size": 20484,
"category": "monitoring",
"icon": "bar-chart-2",
"description": "System monitoring dashboard",
@ -330,7 +330,7 @@
"name": "luci-app-network-modes",
"version": "0.5.0-r3",
"filename": "luci-app-network-modes_0.5.0-r3_all.ipk",
"size": 54147,
"size": 54150,
"category": "network",
"icon": "wifi",
"description": "Network configuration",
@ -342,7 +342,7 @@
"name": "luci-app-network-tweaks",
"version": "1.0.0-r7",
"filename": "luci-app-network-tweaks_1.0.0-r7_all.ipk",
"size": 14957,
"size": 14969,
"category": "network",
"icon": "wifi",
"description": "Network configuration",
@ -354,7 +354,7 @@
"name": "luci-app-nextcloud",
"version": "1.0.0-r1",
"filename": "luci-app-nextcloud_1.0.0-r1_all.ipk",
"size": 6486,
"size": 6487,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -366,7 +366,7 @@
"name": "luci-app-ollama",
"version": "0.1.0-r1",
"filename": "luci-app-ollama_0.1.0-r1_all.ipk",
"size": 12353,
"size": 12352,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -378,7 +378,7 @@
"name": "luci-app-picobrew",
"version": "1.0.0-r1",
"filename": "luci-app-picobrew_1.0.0-r1_all.ipk",
"size": 9457,
"size": 9458,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -390,7 +390,7 @@
"name": "luci-app-secubox",
"version": "0.7.1-r4",
"filename": "luci-app-secubox_0.7.1-r4_all.ipk",
"size": 77680,
"size": 77679,
"category": "system",
"icon": "box",
"description": "SecuBox system component",
@ -402,7 +402,7 @@
"name": "luci-app-secubox-admin",
"version": "1.0.0-r19",
"filename": "luci-app-secubox-admin_1.0.0-r19_all.ipk",
"size": 57250,
"size": 57249,
"category": "system",
"icon": "box",
"description": "SecuBox system component",
@ -414,7 +414,7 @@
"name": "luci-app-secubox-crowdsec",
"version": "1.0.0-r3",
"filename": "luci-app-secubox-crowdsec_1.0.0-r3_all.ipk",
"size": 13923,
"size": 13918,
"category": "system",
"icon": "box",
"description": "SecuBox system component",
@ -438,7 +438,7 @@
"name": "luci-app-secubox-netifyd",
"version": "1.2.1-r1",
"filename": "luci-app-secubox-netifyd_1.2.1-r1_all.ipk",
"size": 36547,
"size": 36542,
"category": "system",
"icon": "box",
"description": "SecuBox system component",
@ -450,7 +450,7 @@
"name": "luci-app-secubox-p2p",
"version": "0.1.0-r1",
"filename": "luci-app-secubox-p2p_0.1.0-r1_all.ipk",
"size": 39237,
"size": 39234,
"category": "system",
"icon": "box",
"description": "SecuBox system component",
@ -462,7 +462,7 @@
"name": "luci-app-secubox-portal",
"version": "0.7.0-r2",
"filename": "luci-app-secubox-portal_0.7.0-r2_all.ipk",
"size": 24646,
"size": 24644,
"category": "system",
"icon": "box",
"description": "SecuBox system component",
@ -474,7 +474,7 @@
"name": "luci-app-secubox-security-threats",
"version": "1.0.0-r4",
"filename": "luci-app-secubox-security-threats_1.0.0-r4_all.ipk",
"size": 21897,
"size": 21895,
"category": "system",
"icon": "box",
"description": "SecuBox system component",
@ -486,7 +486,7 @@
"name": "luci-app-service-registry",
"version": "1.0.0-r1",
"filename": "luci-app-service-registry_1.0.0-r1_all.ipk",
"size": 39827,
"size": 39826,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -498,7 +498,7 @@
"name": "luci-app-simplex",
"version": "1.0.0-r1",
"filename": "luci-app-simplex_1.0.0-r1_all.ipk",
"size": 7001,
"size": 6997,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -522,7 +522,7 @@
"name": "luci-app-system-hub",
"version": "0.5.1-r4",
"filename": "luci-app-system-hub_0.5.1-r4_all.ipk",
"size": 61105,
"size": 61102,
"category": "system",
"icon": "settings",
"description": "System management",
@ -534,7 +534,7 @@
"name": "luci-app-tor-shield",
"version": "1.0.0-r10",
"filename": "luci-app-tor-shield_1.0.0-r10_all.ipk",
"size": 22364,
"size": 22359,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -546,7 +546,7 @@
"name": "luci-app-traffic-shaper",
"version": "0.4.0-r2",
"filename": "luci-app-traffic-shaper_0.4.0-r2_all.ipk",
"size": 14533,
"size": 14532,
"category": "network",
"icon": "filter",
"description": "Traffic shaping and QoS",
@ -558,7 +558,7 @@
"name": "luci-app-vhost-manager",
"version": "0.5.0-r5",
"filename": "luci-app-vhost-manager_0.5.0-r5_all.ipk",
"size": 26185,
"size": 26187,
"category": "network",
"icon": "server",
"description": "Virtual host management",
@ -570,7 +570,7 @@
"name": "luci-app-wireguard-dashboard",
"version": "0.7.0-r5",
"filename": "luci-app-wireguard-dashboard_0.7.0-r5_all.ipk",
"size": 39607,
"size": 39604,
"category": "vpn",
"icon": "shield",
"description": "WireGuard VPN dashboard",
@ -582,7 +582,7 @@
"name": "luci-app-zigbee2mqtt",
"version": "1.0.0-r2",
"filename": "luci-app-zigbee2mqtt_1.0.0-r2_all.ipk",
"size": 6813,
"size": 6815,
"category": "iot",
"icon": "radio",
"description": "Zigbee device management",
@ -594,7 +594,7 @@
"name": "luci-theme-secubox",
"version": "0.4.7-r1",
"filename": "luci-theme-secubox_0.4.7-r1_all.ipk",
"size": 110242,
"size": 110241,
"category": "theme",
"icon": "palette",
"description": "LuCI theme",
@ -618,7 +618,7 @@
"name": "secubox-app-adguardhome",
"version": "1.0.0-r2",
"filename": "secubox-app-adguardhome_1.0.0-r2_all.ipk",
"size": 2883,
"size": 2880,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -630,7 +630,7 @@
"name": "secubox-app-auth-logger",
"version": "1.2.2-r1",
"filename": "secubox-app-auth-logger_1.2.2-r1_all.ipk",
"size": 9379,
"size": 9376,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -654,7 +654,7 @@
"name": "secubox-app-cs-firewall-bouncer",
"version": "0.0.31-r4_aarch64",
"filename": "secubox-app-cs-firewall-bouncer_0.0.31-r4_aarch64_cortex-a72.ipk",
"size": 5049328,
"size": 5049322,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -666,7 +666,7 @@
"name": "secubox-app-cyberfeed",
"version": "0.2.1-r1",
"filename": "secubox-app-cyberfeed_0.2.1-r1_all.ipk",
"size": 12452,
"size": 12449,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -678,7 +678,7 @@
"name": "secubox-app-domoticz",
"version": "1.0.0-r2",
"filename": "secubox-app-domoticz_1.0.0-r2_all.ipk",
"size": 2550,
"size": 2544,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -690,7 +690,7 @@
"name": "secubox-app-exposure",
"version": "1.0.0-r1",
"filename": "secubox-app-exposure_1.0.0-r1_all.ipk",
"size": 6938,
"size": 6931,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -702,7 +702,7 @@
"name": "secubox-app-gitea",
"version": "1.0.0-r5",
"filename": "secubox-app-gitea_1.0.0-r5_all.ipk",
"size": 9409,
"size": 9406,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -714,7 +714,7 @@
"name": "secubox-app-glances",
"version": "1.0.0-r1",
"filename": "secubox-app-glances_1.0.0-r1_all.ipk",
"size": 5542,
"size": 5533,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -726,7 +726,7 @@
"name": "secubox-app-haproxy",
"version": "1.0.0-r23",
"filename": "secubox-app-haproxy_1.0.0-r23_all.ipk",
"size": 15687,
"size": 15681,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -738,7 +738,7 @@
"name": "secubox-app-hexojs",
"version": "1.0.0-r8",
"filename": "secubox-app-hexojs_1.0.0-r8_all.ipk",
"size": 94937,
"size": 94933,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -750,7 +750,7 @@
"name": "secubox-app-jitsi",
"version": "1.0.0-r1",
"filename": "secubox-app-jitsi_1.0.0-r1_all.ipk",
"size": 8916,
"size": 8914,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -762,7 +762,7 @@
"name": "secubox-app-localai",
"version": "2.25.0-r1",
"filename": "secubox-app-localai_2.25.0-r1_all.ipk",
"size": 5718,
"size": 5725,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -774,7 +774,7 @@
"name": "secubox-app-localai-wb",
"version": "2.25.0-r1",
"filename": "secubox-app-localai-wb_2.25.0-r1_all.ipk",
"size": 7954,
"size": 7951,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -786,7 +786,7 @@
"name": "secubox-app-lyrion",
"version": "2.0.2-r1",
"filename": "secubox-app-lyrion_2.0.2-r1_all.ipk",
"size": 7288,
"size": 7292,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -798,7 +798,7 @@
"name": "secubox-app-magicmirror2",
"version": "0.4.0-r8",
"filename": "secubox-app-magicmirror2_0.4.0-r8_all.ipk",
"size": 9254,
"size": 9250,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -810,7 +810,7 @@
"name": "secubox-app-mailinabox",
"version": "2.0.0-r1",
"filename": "secubox-app-mailinabox_2.0.0-r1_all.ipk",
"size": 7573,
"size": 7570,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -834,7 +834,7 @@
"name": "secubox-app-mitmproxy",
"version": "0.5.0-r19",
"filename": "secubox-app-mitmproxy_0.5.0-r19_all.ipk",
"size": 22958,
"size": 22956,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -846,7 +846,7 @@
"name": "secubox-app-mmpm",
"version": "0.2.0-r5",
"filename": "secubox-app-mmpm_0.2.0-r5_all.ipk",
"size": 3982,
"size": 3980,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -858,7 +858,7 @@
"name": "secubox-app-nextcloud",
"version": "1.0.0-r2",
"filename": "secubox-app-nextcloud_1.0.0-r2_all.ipk",
"size": 2961,
"size": 2959,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -870,7 +870,7 @@
"name": "secubox-app-ollama",
"version": "0.1.0-r1",
"filename": "secubox-app-ollama_0.1.0-r1_all.ipk",
"size": 5737,
"size": 5734,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -882,7 +882,7 @@
"name": "secubox-app-picobrew",
"version": "1.0.0-r7",
"filename": "secubox-app-picobrew_1.0.0-r7_all.ipk",
"size": 5538,
"size": 5539,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -894,7 +894,7 @@
"name": "secubox-app-simplex",
"version": "1.0.0-r1",
"filename": "secubox-app-simplex_1.0.0-r1_all.ipk",
"size": 9233,
"size": 9232,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -906,7 +906,7 @@
"name": "secubox-app-streamlit",
"version": "1.0.0-r5",
"filename": "secubox-app-streamlit_1.0.0-r5_all.ipk",
"size": 11718,
"size": 11723,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -930,7 +930,7 @@
"name": "secubox-app-webapp",
"version": "1.5.0-r7",
"filename": "secubox-app-webapp_1.5.0-r7_all.ipk",
"size": 39174,
"size": 39172,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -942,7 +942,7 @@
"name": "secubox-app-zigbee2mqtt",
"version": "1.0.0-r3",
"filename": "secubox-app-zigbee2mqtt_1.0.0-r3_all.ipk",
"size": 3544,
"size": 3545,
"category": "secubox",
"icon": "package",
"description": "SecuBox backend service",
@ -954,7 +954,7 @@
"name": "secubox-core",
"version": "0.10.0-r11",
"filename": "secubox-core_0.10.0-r11_all.ipk",
"size": 87973,
"size": 87974,
"category": "system",
"icon": "box",
"description": "SecuBox core components",
@ -966,7 +966,7 @@
"name": "secubox-master-link",
"version": "1.0.0-r1",
"filename": "secubox-master-link_1.0.0-r1_all.ipk",
"size": 12455,
"size": 12454,
"category": "utility",
"icon": "package",
"description": "SecuBox package",
@ -978,7 +978,7 @@
"name": "secubox-p2p",
"version": "0.6.0-r3",
"filename": "secubox-p2p_0.6.0-r3_all.ipk",
"size": 42015,
"size": 42016,
"category": "utility",
"icon": "package",
"description": "SecuBox package",

View File

@ -0,0 +1,65 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-app-jellyfin
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_ARCH:=all
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
PKG_LICENSE:=Apache-2.0
include $(INCLUDE_DIR)/package.mk
define Package/secubox-app-jellyfin
SECTION:=utils
CATEGORY:=Utilities
PKGARCH:=all
SUBMENU:=SecuBox Apps
TITLE:=SecuBox Jellyfin media server
DEPENDS:=+dockerd +docker +containerd
endef
define Package/secubox-app-jellyfin/description
Installer, configuration, and service manager for running Jellyfin
inside Docker on SecuBox-powered OpenWrt systems. Free media server
for streaming movies, TV shows, music, and photos.
endef
define Package/secubox-app-jellyfin/conffiles
/etc/config/jellyfin
endef
define Build/Compile
endef
define Package/secubox-app-jellyfin/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/etc/config/jellyfin $(1)/etc/config/jellyfin
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/etc/init.d/jellyfin $(1)/etc/init.d/jellyfin
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) ./files/usr/sbin/jellyfinctl $(1)/usr/sbin/jellyfinctl
endef
define Package/secubox-app-jellyfin/postinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || {
echo ""
echo "============================================"
echo " Jellyfin Media Server Installed"
echo "============================================"
echo ""
echo "Quick Start:"
echo " 1. Install: jellyfinctl install"
echo " 2. Configure media: uci add_list jellyfin.media.media_path='/path/to/media'"
echo " 3. Commit: uci commit jellyfin"
echo " 4. Start: /etc/init.d/jellyfin start"
echo ""
echo "Web UI: http://<device-ip>:8096"
echo ""
}
exit 0
endef
$(eval $(call BuildPackage,secubox-app-jellyfin))

View File

@ -0,0 +1,15 @@
config jellyfin 'main'
option enabled '0'
option image 'jellyfin/jellyfin:latest'
option data_path '/srv/jellyfin'
option port '8096'
option timezone 'Europe/Paris'
config jellyfin 'media'
# list media_path '/mnt/media/movies'
# list media_path '/mnt/media/music'
# list media_path '/mnt/media/shows'
config jellyfin 'transcoding'
option hw_accel '0'
option gpu_device ''

View File

@ -0,0 +1,28 @@
#!/bin/sh /etc/rc.common
START=95
STOP=10
USE_PROCD=1
SERVICE_BIN="/usr/sbin/jellyfinctl"
start_service() {
local enabled=$(uci -q get jellyfin.main.enabled)
[ "$enabled" = "1" ] || return 0
procd_open_instance
procd_set_param command "$SERVICE_BIN" service-run
procd_set_param respawn 3600 5 5
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
stop_service() {
"$SERVICE_BIN" service-stop >/dev/null 2>&1
}
restart_service() {
stop_service
start_service
}

View File

@ -0,0 +1,187 @@
#!/bin/sh
# SecuBox Jellyfin Media Server manager
CONFIG="jellyfin"
CONTAINER="secbx-jellyfin"
OPKG_UPDATED=0
usage() {
cat <<'USAGE'
Usage: jellyfinctl <command>
Commands:
install Install prerequisites, prepare directories, pull image
check Run prerequisite checks
update Pull new image and restart
status Show container status
logs Show container logs (use -f to follow)
shell Open shell inside container
service-run Internal: run container via procd
service-stop Stop container
USAGE
}
require_root() { [ "$(id -u)" -eq 0 ]; }
uci_get() { uci -q get ${CONFIG}.$1; }
defaults() {
image="$(uci_get main.image)"
[ -z "$image" ] && image="jellyfin/jellyfin:latest"
data_path="$(uci_get main.data_path)"
[ -z "$data_path" ] && data_path="/srv/jellyfin"
port="$(uci_get main.port)"
[ -z "$port" ] && port="8096"
timezone="$(uci_get main.timezone)"
[ -z "$timezone" ] && timezone="Europe/Paris"
hw_accel="$(uci_get transcoding.hw_accel)"
[ -z "$hw_accel" ] && hw_accel="0"
gpu_device="$(uci_get transcoding.gpu_device)"
}
ensure_dir() { [ -d "$1" ] || mkdir -p "$1"; }
ensure_packages() {
for pkg in "$@"; do
if ! opkg status "$pkg" 2>/dev/null | grep -q "Status:.*installed"; then
if [ "$OPKG_UPDATED" -eq 0 ]; then
opkg update || return 1
OPKG_UPDATED=1
fi
opkg install "$pkg" || return 1
fi
done
}
check_prereqs() {
defaults
ensure_dir "$data_path"
[ -d /sys/fs/cgroup ] || { echo "[ERROR] /sys/fs/cgroup missing" >&2; return 1; }
ensure_packages dockerd docker containerd
/etc/init.d/dockerd enable >/dev/null 2>&1
/etc/init.d/dockerd start >/dev/null 2>&1
}
pull_image() { defaults; docker pull "$image"; }
stop_container() {
docker stop "$CONTAINER" >/dev/null 2>&1 || true
docker rm "$CONTAINER" >/dev/null 2>&1 || true
}
build_media_mounts() {
local mounts=""
local paths
paths=$(uci -q get ${CONFIG}.media.media_path)
if [ -n "$paths" ]; then
for p in $paths; do
[ -d "$p" ] && mounts="$mounts -v ${p}:${p}:ro"
done
fi
echo "$mounts"
}
build_gpu_args() {
if [ "$hw_accel" = "1" ]; then
local dev="${gpu_device:-/dev/dri}"
if [ -e "$dev" ]; then
echo "--device=${dev}:${dev}"
else
echo ""
fi
fi
}
cmd_install() {
require_root || { echo "Root required" >&2; exit 1; }
echo "[Jellyfin] Installing prerequisites..."
check_prereqs || exit 1
ensure_dir "$data_path/config"
ensure_dir "$data_path/cache"
echo "[Jellyfin] Pulling Docker image..."
pull_image || exit 1
uci set ${CONFIG}.main.enabled='1'
uci commit ${CONFIG}
/etc/init.d/jellyfin enable
echo ""
echo "Jellyfin installed successfully."
echo "Configure media paths:"
echo " uci add_list jellyfin.media.media_path='/path/to/media'"
echo " uci commit jellyfin"
echo "Start with: /etc/init.d/jellyfin start"
echo "Web UI: http://<device-ip>:${port}"
}
cmd_check() { check_prereqs; echo "Prerequisite check completed."; }
cmd_update() {
require_root || { echo "Root required" >&2; exit 1; }
echo "[Jellyfin] Pulling latest image..."
pull_image || exit 1
echo "[Jellyfin] Restarting..."
/etc/init.d/jellyfin restart
}
cmd_status() {
defaults
echo "Jellyfin Media Server"
echo "====================="
echo " Image: $image"
echo " Port: $port"
echo " Data: $data_path"
echo ""
if docker ps --filter "name=$CONTAINER" --format '{{.Status}}' 2>/dev/null | grep -q .; then
echo " Container: RUNNING"
docker ps --filter "name=$CONTAINER" --format ' Uptime: {{.Status}}'
elif docker ps -a --filter "name=$CONTAINER" --format '{{.Status}}' 2>/dev/null | grep -q .; then
echo " Container: STOPPED"
else
echo " Container: NOT INSTALLED"
fi
}
cmd_logs() { docker logs "$@" "$CONTAINER" 2>&1; }
cmd_shell() { docker exec -it "$CONTAINER" /bin/bash 2>/dev/null || docker exec -it "$CONTAINER" /bin/sh; }
cmd_service_run() {
require_root || { echo "Root required" >&2; exit 1; }
check_prereqs || exit 1
defaults
stop_container
local media_mounts
media_mounts=$(build_media_mounts)
local gpu_args
gpu_args=$(build_gpu_args)
local docker_args="--name $CONTAINER"
docker_args="$docker_args -p ${port}:8096"
docker_args="$docker_args -v ${data_path}/config:/config"
docker_args="$docker_args -v ${data_path}/cache:/cache"
docker_args="$docker_args -e TZ=${timezone}"
# shellcheck disable=SC2086
exec docker run --rm $docker_args $media_mounts $gpu_args "$image"
}
cmd_service_stop() {
require_root || { echo "Root required" >&2; exit 1; }
stop_container
}
case "${1:-}" in
install) shift; cmd_install "$@" ;;
check) shift; cmd_check "$@" ;;
update) shift; cmd_update "$@" ;;
status) shift; cmd_status "$@" ;;
logs) shift; cmd_logs "$@" ;;
shell) shift; cmd_shell "$@" ;;
service-run) shift; cmd_service_run "$@" ;;
service-stop) shift; cmd_service_stop "$@" ;;
help|--help|-h|'') usage ;;
*) echo "Unknown command: $1" >&2; usage >&2; exit 1 ;;
esac
exit 0