Import the MetaMesh app family from Worph/AppStore
23 apps (MetaCore, the library/network/client tiers and 13 MetaFeeder*) move out of the general-purpose Worph/AppStore into their own store so the MetaMesh family releases on its own cadence. - asset URLs repointed to cdn.jsdelivr.net/gh/Worph/MetaAppStore@main - store scaffolding added (category/recommend/featured lists, licence, contributing, gitattributes) - psd-source/meta-icons-v2 icon generator follows the apps MetaMCP stays in Worph/AppStore: it is third-party metatool-ai software, not part of MetaMesh.
This commit is contained in:
@@ -0,0 +1,314 @@
|
||||
name: metafeedertribler
|
||||
|
||||
# =============================================================================
|
||||
# MetaFeeder · Tribler — a STANDALONE, self-contained Tribler feeder for MetaMesh.
|
||||
#
|
||||
# The tribler source was extracted from the torrent feeder into its own image
|
||||
# (`meta-feeder-tribler`), so this is a single-plugin feeder. It bundles its OWN
|
||||
# headless Tribler core (no separate Tribler app needed) and bridges the
|
||||
# decentralized IPv8 Tribler network into MetaMesh, so releases surface in
|
||||
# **MetaWatch**. Mirrors the meta-gateway dev stack
|
||||
# (`dev/docker-compose.feeder-tribler.yml`).
|
||||
#
|
||||
# Self-contained for enrichment: ships its own filename-parser + tmdb plugins,
|
||||
# so each discovered release gets a clean title, poster and plot.
|
||||
#
|
||||
# It needs, over the shared `pcs` network:
|
||||
# - the shared **MetaCore** app (`metacore-app:9000`) — where resolved records
|
||||
# + TMDB posters are stored; the shared **MetaShare** app then announces
|
||||
# them to the swarm.
|
||||
# The **MetaGateway** app must list this feeder's URL
|
||||
# (`http://metafeedertribler-feeder:8080`) in its feeders config so it
|
||||
# discovers + queries it (MetaGateway, MetaCore and this feeder share `pcs`).
|
||||
#
|
||||
# Everything is scoped under the `metafeedertribler-*` prefix + the per-stack
|
||||
# `metafeedertribler` network + /DATA/AppData/metafeedertribler/ data root, so it
|
||||
# installs alongside the other Meta* apps with zero collisions.
|
||||
# =============================================================================
|
||||
|
||||
services:
|
||||
# ---------------------------------------------------------------------------
|
||||
# tribler-instance — the bundled headless Tribler core (IPv8 overlay). Private
|
||||
# to this stack (metafeedertribler network only), reached by the feeder at its
|
||||
# default sidecar URL `http://tribler-instance:8085`. A complete baked config
|
||||
# (api on 0.0.0.0:8085, key `changeme`) is seeded on first boot from the
|
||||
# pre-install-cmd-written seed file. IPv8 overlay on UDP 8090.
|
||||
# ---------------------------------------------------------------------------
|
||||
tribler-instance:
|
||||
# Pinned: v8.4.2 is the digest `:latest` resolved to when this was pinned
|
||||
# (sha256:e5f0ff1f…), so this is a tag change only, not a version bump.
|
||||
image: ghcr.io/tribler/tribler:v8.4.2
|
||||
cpu_shares: 30
|
||||
container_name: metafeedertribler-instance
|
||||
hostname: tribler-instance
|
||||
restart: unless-stopped
|
||||
entrypoint: ["/bin/sh", "-c"]
|
||||
command:
|
||||
- |
|
||||
set -e
|
||||
CFG=/root/.Tribler/8.0/configuration.json
|
||||
if [ ! -f "$$CFG" ]; then
|
||||
mkdir -p "$$(dirname "$$CFG")"
|
||||
cp /seed/configuration.json "$$CFG"
|
||||
echo "tribler: installed baked config at $$CFG"
|
||||
fi
|
||||
exec /usr/share/tribler/tribler -s
|
||||
environment:
|
||||
LANG: "C.UTF-8"
|
||||
expose:
|
||||
- 8085
|
||||
volumes:
|
||||
- ${DATA_ROOT:-/DATA}/AppData/metafeedertribler/tribler-state:/root/.Tribler
|
||||
- ${DATA_ROOT:-/DATA}/AppData/metafeedertribler/tribler-seed/configuration.json:/seed/configuration.json:ro
|
||||
networks:
|
||||
- metafeedertribler
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# metafeedertribler-feeder — the tribler feeder (dedicated meta-feeder-tribler
|
||||
# image). A thin client of tribler-instance; self-publishes resolved records to
|
||||
# the shared meta-core + drives the bundled enrichment plugins. The gateway
|
||||
# reaches it directly on `pcs`; the human configures it through the AppShield
|
||||
# gate below.
|
||||
# ---------------------------------------------------------------------------
|
||||
metafeedertribler-feeder:
|
||||
image: ghcr.io/worph/meta-feeder-tribler:1.0.4
|
||||
cpu_shares: 30
|
||||
container_name: metafeedertribler-feeder
|
||||
hostname: metafeedertribler-feeder
|
||||
restart: unless-stopped
|
||||
user: "0:0"
|
||||
expose:
|
||||
- 8080
|
||||
environment:
|
||||
# INFRA-ONLY env (the "config: no env if in webui" rule). Operator config —
|
||||
# Tribler sidecar URL, api key, TMDB token / language, meta-core URL — is
|
||||
# read from the persisted config.json (pre-seeded by pre-install-cmd, then
|
||||
# editable in the config UI behind the AppShield gate). These env vars are
|
||||
# wiring only: enrichment sidecars, the enrich callback, the peer id
|
||||
# (analytics group by it), and the state dir.
|
||||
RUST_LOG: "info,meta_feeder=info,tribler_feeder=info"
|
||||
META_GATEWAY_PEER_ID: "metafeedertribler"
|
||||
FILENAME_PARSER_URL: "http://metafeedertribler-filename-parser:8080"
|
||||
TMDB_PLUGIN_URL: "http://metafeedertribler-tmdb:8080"
|
||||
META_FEEDER_CALLBACK_URL: "http://metafeedertribler-feeder:8080/enrich/callback"
|
||||
META_FEEDER_STATE_DIR: "/data/meta-feeder"
|
||||
TZ: "$TZ"
|
||||
volumes:
|
||||
# Persist feeder config (config.json pre-seeded + editable via UI) + redb
|
||||
# cache. config.json lives at gateway/tribler/config.json under this dir.
|
||||
- ${DATA_ROOT:-/DATA}/AppData/metafeedertribler/state:/data/meta-feeder:rw
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-sf", "http://localhost:8080/health"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
start_period: 5s
|
||||
depends_on:
|
||||
# service_started (not _healthy): tribler core + the plugin images ship no
|
||||
# healthcheck (curl absent in the plugins; tribler boots slowly).
|
||||
tribler-instance:
|
||||
condition: service_started
|
||||
metafeedertribler-filename-parser:
|
||||
condition: service_started
|
||||
metafeedertribler-tmdb:
|
||||
condition: service_started
|
||||
networks:
|
||||
- metafeedertribler
|
||||
- pcs
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bundled enrichment plugins (self-contained). filename-parser per file; tmdb
|
||||
# once per release — tmdb writes posters/backdrops to the shared meta-core's
|
||||
# WebDAV (over pcs) so the ingester seeds them. No healthcheck: these plugin
|
||||
# images don't ship one (curl absent).
|
||||
# ---------------------------------------------------------------------------
|
||||
metafeedertribler-filename-parser:
|
||||
image: ghcr.io/worph/metamesh-plugin-filename-parser:1.0.2
|
||||
cpu_shares: 30
|
||||
container_name: metafeedertribler-filename-parser
|
||||
hostname: metafeedertribler-filename-parser
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- 8080
|
||||
environment:
|
||||
PORT: "8080"
|
||||
EMIT_TITLE_TAGS: "true"
|
||||
networks:
|
||||
- metafeedertribler
|
||||
|
||||
metafeedertribler-tmdb:
|
||||
image: ghcr.io/worph/metamesh-plugin-tmdb:1.0.2
|
||||
cpu_shares: 30
|
||||
container_name: metafeedertribler-tmdb
|
||||
hostname: metafeedertribler-tmdb
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- 8080
|
||||
environment:
|
||||
PORT: "8080"
|
||||
CACHE_DIR: "/cache"
|
||||
# Posters land in the shared meta-core (over pcs) so the ingester seeds them.
|
||||
WEBDAV_URL: "http://metacore-app:9000/webdav"
|
||||
volumes:
|
||||
- ${DATA_ROOT:-/DATA}/AppData/metafeedertribler/tmdb-cache:/cache
|
||||
networks:
|
||||
- metafeedertribler
|
||||
- pcs
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# AppShield gate — the feeder's config UI (Tribler sidecar URL / api key, TMDB
|
||||
# token) behind Yundera OIDC SSO. container_name == subdomain prefix. The
|
||||
# gateway still reaches the feeder directly on `pcs` (this gate is for the
|
||||
# human only); index → /config.
|
||||
# ---------------------------------------------------------------------------
|
||||
metafeedertribler:
|
||||
image: ghcr.io/yundera/appshield:2.0.9
|
||||
cpu_shares: 80
|
||||
container_name: metafeedertribler
|
||||
hostname: metafeedertribler
|
||||
restart: unless-stopped
|
||||
user: "0:0"
|
||||
expose:
|
||||
- 80
|
||||
environment:
|
||||
OIDC_REGISTRAR_URL: "http://auth-registrar:9092"
|
||||
REDIRECT_HOST_SUFFIXES: "${APP_DOMAIN},${APP_PUBLIC_IP_DASH}.nip.io,${APP_PUBLIC_IP_DASH}.sslip.io"
|
||||
BACKEND_HOST: "metafeedertribler-feeder"
|
||||
BACKEND_PORT: "8080"
|
||||
LISTEN_PORT: "80"
|
||||
labels:
|
||||
caddy_0: metafeedertribler-${APP_DOMAIN}
|
||||
caddy_0.import: gateway_tls
|
||||
caddy_0.reverse_proxy: "{{upstreams 80}}"
|
||||
caddy_1: metafeedertribler-${APP_PUBLIC_IP_DASH}.nip.io
|
||||
caddy_1.import: gateway_tls
|
||||
caddy_1.reverse_proxy: "{{upstreams 80}}"
|
||||
caddy_2: metafeedertribler-${APP_PUBLIC_IP_DASH}.sslip.io
|
||||
caddy_2.reverse_proxy: "{{upstreams 80}}"
|
||||
depends_on:
|
||||
- metafeedertribler-feeder
|
||||
networks:
|
||||
- metafeedertribler
|
||||
- pcs
|
||||
|
||||
networks:
|
||||
metafeedertribler:
|
||||
name: metafeedertribler
|
||||
driver: bridge
|
||||
pcs:
|
||||
name: ${APP_NET:-pcs}
|
||||
external: true
|
||||
|
||||
x-casaos:
|
||||
architectures:
|
||||
- amd64
|
||||
- arm64
|
||||
author: Worph Team
|
||||
category: Media
|
||||
developer: Aptero Team
|
||||
main: metafeedertribler
|
||||
webui_port: 80
|
||||
index: /config
|
||||
|
||||
description:
|
||||
en_us: |
|
||||
**A standalone, self-contained Tribler feeder for the MetaMesh network.**
|
||||
|
||||
MetaFeeder · Tribler bridges the decentralized **Tribler** network into
|
||||
MetaMesh, so releases surface in **MetaWatch**. It bundles its own headless
|
||||
Tribler core — no separate Tribler app to install — for anonymous IPv8
|
||||
torrent discovery, with no indexer keys required. Split out of MetaGateway
|
||||
so you can run only the feeders you want.
|
||||
|
||||
**Self-contained:** ships its own Tribler core + filename-parser + TMDB
|
||||
enrichment, so each release gets a clean title, poster and plot.
|
||||
|
||||
**Also requires:** **MetaGateway** — its meta-core stores the resolved
|
||||
records and announces them to the swarm. The gateway must list this feeder
|
||||
in its config.
|
||||
|
||||
fr_fr: |
|
||||
**Un feeder Tribler autonome et complet pour le réseau MetaMesh.**
|
||||
|
||||
MetaFeeder · Tribler connecte le réseau décentralisé **Tribler** à MetaMesh
|
||||
pour que les releases apparaissent dans **MetaWatch**. Il embarque son
|
||||
propre cœur Tribler headless — aucune app Tribler séparée à installer — pour
|
||||
une découverte de torrents anonyme via IPv8, sans clé d'indexeur. Détaché de
|
||||
MetaGateway pour n'exécuter que les feeders souhaités.
|
||||
|
||||
**Autonome :** embarque son cœur Tribler + ses plugins filename-parser + TMDB.
|
||||
|
||||
**Nécessite aussi :** l'app **MetaGateway** (son meta-core stocke et annonce
|
||||
les enregistrements).
|
||||
|
||||
tagline:
|
||||
en_us: Self-contained Tribler feeder (bundled core) for the MetaMesh network
|
||||
fr_fr: Feeder Tribler autonome (cœur inclus) pour le réseau MetaMesh
|
||||
|
||||
title:
|
||||
en_us: MetaFeeder · Tribler
|
||||
|
||||
icon: https://cdn.jsdelivr.net/gh/Worph/MetaAppStore@main/Apps/MetaFeederTribler/icon.png
|
||||
thumbnail: https://cdn.jsdelivr.net/gh/Worph/MetaAppStore@main/Apps/MetaFeederTribler/thumbnail.png
|
||||
|
||||
store_app_id: metafeedertribler
|
||||
is_uncontrolled: false
|
||||
|
||||
tips:
|
||||
before_install:
|
||||
en_us: |
|
||||
**Install order:** install **MetaGateway** first (this feeder publishes to
|
||||
its shared meta-core). The Tribler core is bundled — nothing else to add.
|
||||
|
||||
**After installing this app:**
|
||||
1. It works out of the box: the feeder is pre-wired to its bundled Tribler
|
||||
core. Optionally open the config UI (the dashboard link) to set a TMDB
|
||||
v4 token for posters, then Save — the feeder reloads automatically.
|
||||
2. In **MetaGateway**, make sure this feeder is listed in its feeders
|
||||
config (`http://metafeedertribler-feeder:8080`) so it gets discovered
|
||||
(or add it from the gateway dashboard).
|
||||
|
||||
**Note:** the bundled Tribler core needs a few minutes to bootstrap onto
|
||||
the IPv8 network before search results appear.
|
||||
|
||||
**Authentication:** the config UI is protected by Yundera's Authelia (OIDC).
|
||||
|
||||
pre-install-cmd: |
|
||||
# Seed the bundled Tribler core config (api on 0.0.0.0:8085, key `changeme`).
|
||||
if [ ! -f /DATA/AppData/metafeedertribler/tribler-seed/configuration.json ]; then
|
||||
cat > /DATA/AppData/metafeedertribler/tribler-seed/configuration.json <<'TRIBLER_CFG'
|
||||
{"api":{"http_enabled":true,"http_port":8085,"http_host":"0.0.0.0","https_enabled":false,"https_host":"127.0.0.1","https_port":0,"https_certfile":"https_certfile","http_port_running":0,"https_port_running":0,"key":"changeme"},"headless":false,"start_minimized":false,"ipv8":{"interfaces":[{"interface":"UDPIPv4","ip":"0.0.0.0","port":8090},{"interface":"UDPIPv6","ip":"::","port":8091}],"keys":[{"alias":"anonymous id","generation":"curve25519","file":"/root/.Tribler/ec_multichain.pem"},{"alias":"secondary","generation":"curve25519","file":"/root/.Tribler/secondary_key.pem"}],"logger":{"level":"INFO"},"working_directory":"/root/.Tribler","walker_interval":0.5,"overlays":[{"class":"DiscoveryCommunity","key":"anonymous id","walkers":[{"strategy":"RandomWalk","peers":20,"init":{"timeout":3}},{"strategy":"RandomChurn","peers":-1,"init":{"sample_size":8,"ping_interval":10,"inactive_time":27.5,"drop_time":57.5}},{"strategy":"PeriodicSimilarity","peers":-1,"init":{}}],"bootstrappers":[{"class":"DispersyBootstrapper","init":{"ip_addresses":[["130.161.119.206",6421],["130.161.119.206",6422],["131.180.27.155",6423],["131.180.27.156",6424],["131.180.27.161",6427],["131.180.27.161",6521],["131.180.27.161",6522],["131.180.27.162",6523],["131.180.27.162",6524],["130.161.119.215",6525],["130.161.119.215",6526],["130.161.119.201",6527],["130.161.119.201",6528]],"dns_addresses":[["dispersy1.tribler.org",6421],["dispersy1.st.tudelft.nl",6421],["dispersy2.tribler.org",6422],["dispersy2.st.tudelft.nl",6422],["dispersy3.tribler.org",6423],["dispersy3.st.tudelft.nl",6423],["dispersy4.tribler.org",6424]],"bootstrap_timeout":30}}],"initialize":{},"on_start":[]}]},"statistics":false,"content_discovery_community":{"enabled":true},"database":{"enabled":true},"dht_discovery":{"enabled":true},"libtorrent":{"socks_listen_ports":[0,0,0,0,0],"listen_interface":"0.0.0.0","port":0,"proxy_type":0,"proxy_server":"","proxy_auth":"","max_connections_download":-1,"max_download_rate":0,"max_upload_rate":0,"use_advanced_rate_limits":false,"utp":true,"dht":true,"dht_readiness_timeout":30,"upnp":true,"natpmp":true,"lsd":true,"announce_to_all_tiers":false,"announce_to_all_trackers":false,"max_concurrent_http_announces":50,"check_after_complete":false,"download_defaults":{"anonymity_enabled":true,"number_hops":1,"safeseeding_enabled":true,"saveas":"/root/Downloads","seeding_mode":"forever","seeding_ratio":2,"seeding_time":60,"channel_download":false,"add_download_to_channel":false,"trackers_file":"","torrent_folder":"","auto_managed":false,"completed_dir":""},"active_downloads":3,"active_seeds":5,"active_checking":1,"active_dht_limit":88,"active_tracker_limit":1600,"active_lsd_limit":60,"active_limit":500,"ask_download_settings":false,"clear_orphaned_parts":false},"recommender":{"enabled":true},"rendezvous":{"enabled":true},"rss":{"enabled":true,"urls":[]},"torrent_checker":{"enabled":true},"tunnel_community":{"enabled":true,"min_circuits":3,"max_circuits":8},"versioning":{"enabled":true,"allow_pre":false},"watch_folder":{"enabled":false,"directory":"","check_interval":10},"state_dir":"/root/.Tribler","memory_db":false,"tray_icon_color":"","ui":{}}
|
||||
TRIBLER_CFG
|
||||
fi
|
||||
# Seed the feeder config so it points at the bundled Tribler core out of the
|
||||
# box (operator can override + add a TMDB token in the config UI).
|
||||
if [ ! -f /DATA/AppData/metafeedertribler/state/gateway/tribler/config.json ]; then
|
||||
cat > /DATA/AppData/metafeedertribler/state/gateway/tribler/config.json <<'FEEDER_CFG'
|
||||
{"meta_core_url":"http://metacore-app:9000","sidecar_url":"http://tribler-instance:8085","api_key":"changeme"}
|
||||
FEEDER_CFG
|
||||
fi
|
||||
|
||||
# Maison (Yundera dashboard) configuration. Read in preference to x-casaos.
|
||||
# schema_version 2 is required for `folders`: an older Maison refuses the app
|
||||
# outright rather than starting it without its directories.
|
||||
x-compose-app:
|
||||
schema_version: 2
|
||||
# Created and chowned by Maison before any image is pulled, before any hook
|
||||
# runs and before the containers start — on the first boot and every one after.
|
||||
# Compose would otherwise create a missing bind source as a root-owned dir.
|
||||
folders:
|
||||
- path: /DATA/AppData/metafeedertribler/state/gateway/tribler
|
||||
user: $PUID
|
||||
group: $PGID
|
||||
- path: /DATA/AppData/metafeedertribler/tmdb-cache
|
||||
user: $PUID
|
||||
group: $PGID
|
||||
- path: /DATA/AppData/metafeedertribler/tribler-state
|
||||
user: $PUID
|
||||
group: $PGID
|
||||
- path: /DATA/AppData/metafeedertribler/tribler-seed
|
||||
user: $PUID
|
||||
group: $PGID
|
||||
# Same string as the caddy_0 label, so the tile link and the route agree.
|
||||
webui-host: metafeedertribler-${domain}
|
||||
webui-path: "/config"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
@@ -0,0 +1,55 @@
|
||||
# MetaFeeder · Tribler — Rationale
|
||||
|
||||
## What deviation / exception is being requested
|
||||
|
||||
1. `metafeedertribler-feeder` runs `user: 0:0`.
|
||||
2. `tribler-instance` is seeded with a Tribler core API key of `changeme`.
|
||||
3. `tribler-instance` runs the upstream Tribler image, which writes its state as root
|
||||
inside `/root/.Tribler`.
|
||||
|
||||
## Why it is necessary
|
||||
|
||||
1. The feeder publishes resolved records to the shared MetaCore and writes plugin artwork
|
||||
through its WebDAV endpoint; those targets are created and owned by MetaCore's
|
||||
root-running container.
|
||||
2. Tribler's core exposes a localhost-style REST API and requires *some* key. The seeded
|
||||
value is a placeholder that matches the one baked into the feeder's own config, so the
|
||||
two agree out of the box and the app works immediately after installation — the
|
||||
functionality requirement in the guidelines. It is not a user credential and grants no
|
||||
access to anything beyond this Tribler core.
|
||||
3. Upstream image behaviour; the state directory is bind-mounted so it survives container
|
||||
recreation.
|
||||
|
||||
## Security mitigations in place
|
||||
|
||||
- **`tribler-instance` is not on the shared `pcs` network.** It is attached to the
|
||||
app-private `metafeedertribler` bridge only, so the API on `:8085` is reachable by this
|
||||
app's own feeder and by nothing else on the box — not by another store app, and not from
|
||||
the internet. The `changeme` key never crosses a network boundary a stranger can reach.
|
||||
- The feeder's configuration UI is behind AppShield + Authelia SSO
|
||||
(`ghcr.io/yundera/appshield:2.0.9`); the feeder itself carries no Caddy labels and
|
||||
publishes no host port.
|
||||
- No user directories are mounted — no `/DATA/Documents`, `/DATA/Downloads`, `/DATA/Media`
|
||||
or `/DATA/Gallery`. All binds are under `/DATA/AppData/metafeedertribler/`, declared in
|
||||
`x-compose-app.folders`.
|
||||
- Both config seeds in `pre-install-cmd` are guarded by `[ ! -f … ]`, so a reinstall or
|
||||
version upgrade never overwrites operator edits.
|
||||
- Image tags pinned. `ghcr.io/tribler/tribler` is pinned to `v8.4.2`, the digest `:latest`
|
||||
resolved to at the time of pinning.
|
||||
|
||||
## Alternatives considered and rejected
|
||||
|
||||
- **Generate a random API key in the hook.** The Maison hook toolbox has no `openssl`;
|
||||
`od -An -N32 -tx1 /dev/urandom` would work, but the key has to be written into *two*
|
||||
files that must agree, and a partially-applied seed leaves the feeder unable to talk to
|
||||
its own core. Given the API is unreachable off the app-private network, the added
|
||||
failure mode buys nothing.
|
||||
- **Put Tribler's API behind AppShield.** The feeder is a machine client; it cannot
|
||||
complete an interactive OIDC redirect.
|
||||
- **Run the feeder as `$PUID:$PGID`.** Writes into MetaCore's root-owned tree fail.
|
||||
|
||||
## Data protection
|
||||
|
||||
No user media is mounted. Tribler's own state (`/root/.Tribler`), its seed config, the
|
||||
feeder's cursor and the TMDB cache all live under `/DATA/AppData/metafeedertribler/`, the
|
||||
unit Maison archives on uninstall and restores from backup.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
Reference in New Issue
Block a user