Merge branch 'develop' into app/HomeAssistant
This commit is contained in:
commit
759a469d64
75 changed files with 1213 additions and 223 deletions
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -42,6 +42,9 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run global tests
|
||||
run: pnpm test
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm -r lint
|
||||
|
||||
|
|
4
.github/workflows/release-candidate.yml
vendored
4
.github/workflows/release-candidate.yml
vendored
|
@ -1,9 +1,9 @@
|
|||
name: Release candidate
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release/*
|
||||
|
||||
jobs:
|
||||
# Build images and publish RCs to DockerHub
|
||||
|
|
21
.gitignore
vendored
21
.gitignore
vendored
|
@ -1,28 +1,27 @@
|
|||
.pnpm-debug.log
|
||||
.env
|
||||
.env*
|
||||
github.secrets
|
||||
node_modules/
|
||||
nginx/*
|
||||
letsencrypt/*
|
||||
app-data/*
|
||||
traefik/ssl/*
|
||||
!traefik/ssl/.gitkeep
|
||||
!app-data/.gitkeep
|
||||
!letsencrypt/mkcert/.gitkeep
|
||||
|
||||
scripts/pacapt
|
||||
|
||||
state/*
|
||||
!state/.gitkeep
|
||||
|
||||
tipi.config.json
|
||||
|
||||
# Commit empty directories
|
||||
!nignx/.gitkeep
|
||||
|
||||
media/data/movies/*
|
||||
media/data/tv/*
|
||||
media/data/books/*
|
||||
!media/data/movies/.gitkeep
|
||||
!media/data/tv/.gitkeep
|
||||
!media/data/books/metadata.db
|
||||
|
||||
media/torrents/*
|
||||
!media/torrents/.gitkeep
|
||||
media/torrents/complete/*
|
||||
!media/torrents/complete/.gitkeep
|
||||
media/torrents/incomplete/*
|
||||
!media/torrents/incomplete/.gitkeep
|
||||
media/torrents/watch/*
|
||||
!media/torrents/watch/.gitkeep
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
pnpm test
|
||||
pnpm -r test
|
||||
pnpm -r lint
|
||||
|
|
23
README.md
23
README.md
|
@ -13,26 +13,34 @@
|
|||
Tipi is a personal homeserver orchestrator. It is running docker containers under the hood and provides a simple web interface to manage them. Every service comes with an opinionated configuration in order to remove the need for manual configuration and network setup.
|
||||
|
||||
## Apps available
|
||||
- [Adguard Home](https://github.com/AdguardTeam/AdGuardHome) - Adguard Home DNS adblocker
|
||||
- [Calibre-Web](https://github.com/janeczku/calibre-web) - Web Ebook Reader
|
||||
- [Code-Server](https://github.com/filebrowser/filebrowser) - Web VS Code
|
||||
- [Code-Server](https://github.com/coder/code-server) - Web VS Code
|
||||
- [Filebrowser](https://github.com/filebrowser/filebrowser) - Web File Browser
|
||||
- [Freshrss](https://github.com/FreshRSS/FreshRSS) - A free, self-hostable RSS aggregator
|
||||
- [Gitea](https://github.com/go-gitea/gitea) - Gitea - A painless self-hosted Git service
|
||||
- [Homarr](https://github.com/ajnart/homarr) - A homepage for your server
|
||||
- [Home Assistant](https://github.com/home-assistant/core) - Open source home automation that puts local control and privacy first
|
||||
- [Invidious](https://github.com/iv-org/invidious) - An alternative front-end to YouTube
|
||||
- [Homarr](https://github.com/ajnart/homarr) - A homepage for your server.
|
||||
- [Jackett](https://github.com/Jackett/Jackett) - API Support for your favorite torrent trackers
|
||||
- [Jellyfin](https://github.com/jellyfin/jellyfin) - A media server for your home collection
|
||||
- [Joplin](https://github.com/laurent22/joplin) - Privacy focused note-taking app
|
||||
- [Libreddit](https://github.com/spikecodes/libreddit) - Private front-end for Reddit
|
||||
- [n8n](https://github.com/n8n-io/n8n) - Workflow Automation Tool
|
||||
- [Nextcloud](https://github.com/nextcloud/server) - A safe home for all your data
|
||||
- [Nitter](https://github.com/zedeus/nitter) - Alternative Twitter front-end
|
||||
- [Pihole](https://github.com/pi-hole/pi-hole) - A black hole for Internet advertisements
|
||||
- [Radarr](https://github.com/Radarr/Radarr) - Movie collection manager for Usenet and BitTorrent users.
|
||||
- [Prowlarr](https://github.com/Prowlarr/Prowlarr/) - A torrent/usenet indexer manager/proxy
|
||||
- [Radarr](https://github.com/Radarr/Radarr) - Movie collection manager for Usenet and BitTorrent users
|
||||
- [Sonarr](https://github.com/Sonarr/Sonarr) - TV show manager for Usenet and BitTorrent
|
||||
- [Syncthing](https://github.com/syncthing/syncthing) - Continuous File Synchronization
|
||||
- [Tailscale](https://github.com/tailscale/tailscale) - The easiest, most secure way to use WireGuard and 2FA.
|
||||
- [Tailscale](https://github.com/tailscale/tailscale) - The easiest, most secure way to use WireGuard and 2FA
|
||||
- [Tautulli](https://github.com/Tautulli/Tautulli) - A Python based monitoring and tracking tool for Plex Media Server
|
||||
- [Transmission](https://github.com/transmission/transmission) - Fast, easy, and free BitTorrent client
|
||||
- [Wireguard Easy](https://github.com/WeeJeWel/wg-easy) - WireGuard VPN + Web-based Admin UI
|
||||
- [Adguard Home](https://github.com/AdguardTeam/AdGuardHome) - Adguard Home DNS adblocker
|
||||
- [Home Assistant](https://github.com/home-assistant/core) - Open source home automation that puts local control and privacy first
|
||||
- [Vaultwarden](https://github.com/dani-garcia/vaultwarden) - Unofficial Bitwarden compatible server
|
||||
|
||||
## 🛠 Installation
|
||||
|
||||
### Installation Requirements
|
||||
- Ubuntu 18.04 LTS or higher (or Debian 10)
|
||||
|
@ -48,7 +56,8 @@ git clone https://github.com/meienberger/runtipi.git
|
|||
cd into the downloaded directory and run the start script.
|
||||
|
||||
```bash
|
||||
cd runtipi && sudo ./scripts/start.sh
|
||||
cd runtipi
|
||||
sudo ./scripts/start.sh
|
||||
```
|
||||
|
||||
The script will prompt you the ip address of the dashboard once configured.
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.1.5
|
||||
0.2.0
|
150
apps/__tests__/apps.test.ts
Normal file
150
apps/__tests__/apps.test.ts
Normal file
|
@ -0,0 +1,150 @@
|
|||
import fs from "fs";
|
||||
import jsyaml from "js-yaml";
|
||||
|
||||
interface AppConfig {
|
||||
id: string;
|
||||
port: number;
|
||||
requirements?: {
|
||||
ports?: number[];
|
||||
};
|
||||
name: string;
|
||||
description: string;
|
||||
version: string;
|
||||
image: string;
|
||||
short_desc: string;
|
||||
author: string;
|
||||
source: string;
|
||||
available: boolean;
|
||||
}
|
||||
|
||||
const networkExceptions = ["pihole", "tailscale"];
|
||||
const getAppConfigs = (): AppConfig[] => {
|
||||
const apps: AppConfig[] = [];
|
||||
|
||||
const appsDir = fs.readdirSync("./apps");
|
||||
|
||||
appsDir.forEach((app) => {
|
||||
const path = `./apps/${app}/config.json`;
|
||||
|
||||
if (fs.existsSync(path)) {
|
||||
const configFile = fs.readFileSync(path).toString();
|
||||
|
||||
try {
|
||||
const config: AppConfig = JSON.parse(configFile);
|
||||
if (config.available) {
|
||||
apps.push(config);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error parsing config file", app);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return apps;
|
||||
};
|
||||
|
||||
describe("App configs", () => {
|
||||
it("Get app config should return at least one app", () => {
|
||||
const apps = getAppConfigs();
|
||||
|
||||
expect(apps.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("Each app should have an id", () => {
|
||||
const apps = getAppConfigs();
|
||||
|
||||
apps.forEach((app) => {
|
||||
expect(app.id).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("Each app should have a name", () => {
|
||||
const apps = getAppConfigs();
|
||||
|
||||
apps.forEach((app) => {
|
||||
expect(app.name).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("Each app should have a description", () => {
|
||||
const apps = getAppConfigs();
|
||||
|
||||
apps.forEach((app) => {
|
||||
expect(app.description).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("Each app should have a port", () => {
|
||||
const apps = getAppConfigs();
|
||||
|
||||
apps.forEach((app) => {
|
||||
expect(app.port).toBeDefined();
|
||||
expect(app.port).toBeGreaterThan(999);
|
||||
expect(app.port).toBeLessThan(65535);
|
||||
});
|
||||
});
|
||||
|
||||
it("Each app should have a different port", () => {
|
||||
const appConfigs = getAppConfigs();
|
||||
const ports = appConfigs.map((app) => app.port);
|
||||
expect(new Set(ports).size).toBe(appConfigs.length);
|
||||
});
|
||||
|
||||
it("Each app should have a unique id", () => {
|
||||
const appConfigs = getAppConfigs();
|
||||
const ids = appConfigs.map((app) => app.id);
|
||||
expect(new Set(ids).size).toBe(appConfigs.length);
|
||||
});
|
||||
|
||||
it("Each app should have a docker-compose file beside it", () => {
|
||||
const apps = getAppConfigs();
|
||||
|
||||
apps.forEach((app) => {
|
||||
expect(fs.existsSync(`./apps/${app.id}/docker-compose.yml`)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("Each app should have a container name equals to its id", () => {
|
||||
const apps = getAppConfigs();
|
||||
|
||||
apps.forEach((app) => {
|
||||
const dockerComposeFile = fs
|
||||
.readFileSync(`./apps/${app.id}/docker-compose.yml`)
|
||||
.toString();
|
||||
|
||||
const dockerCompose: any = jsyaml.load(dockerComposeFile);
|
||||
|
||||
if (!dockerCompose.services[app.id]) {
|
||||
console.error(app.id);
|
||||
}
|
||||
|
||||
expect(dockerCompose.services[app.id]).toBeDefined();
|
||||
expect(dockerCompose.services[app.id].container_name).toBe(app.id);
|
||||
});
|
||||
});
|
||||
|
||||
it("Each app should have network tipi_main_network", () => {
|
||||
const apps = getAppConfigs();
|
||||
|
||||
apps.forEach((app) => {
|
||||
if (!networkExceptions.includes(app.id)) {
|
||||
const dockerComposeFile = fs
|
||||
.readFileSync(`./apps/${app.id}/docker-compose.yml`)
|
||||
.toString();
|
||||
|
||||
const dockerCompose: any = jsyaml.load(dockerComposeFile);
|
||||
|
||||
expect(dockerCompose.services[app.id]).toBeDefined();
|
||||
|
||||
if (!dockerCompose.services[app.id].networks) {
|
||||
console.error(app.id);
|
||||
}
|
||||
|
||||
expect(dockerCompose.services[app.id].networks).toBeDefined();
|
||||
expect(dockerCompose.services[app.id].networks).toStrictEqual([
|
||||
"tipi_main_network",
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -8,9 +8,9 @@
|
|||
"author": "ArneNaessens",
|
||||
"source": "https://github.com/AdguardTeam",
|
||||
"image": "https://avatars.githubusercontent.com/u/8361145?s=200&v=4",
|
||||
"cagegories": ["network", "security"],
|
||||
"requirements": {
|
||||
"ports": [53]
|
||||
},
|
||||
"form_fields": {
|
||||
}
|
||||
"form_fields": {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
|
||||
version: "3.5"
|
||||
|
||||
version: "3.7"
|
||||
services:
|
||||
adguardhome:
|
||||
adguard:
|
||||
image: adguard/adguardhome:v0.107.6
|
||||
container_name: adguard
|
||||
volumes:
|
||||
|
|
3
apps/adguard/metadata/description.md
Normal file
3
apps/adguard/metadata/description.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
Network-wide ads & trackers blocking DNS server
|
||||
|
||||
AdGuard Home is a network-wide software for blocking ads and tracking. After you set it up, it'll cover all your home devices, and you won't need any client-side software for that. Learn more on our official Github repository.
|
BIN
apps/adguard/metadata/logo.png
Normal file
BIN
apps/adguard/metadata/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
|
@ -1,6 +1,4 @@
|
|||
|
||||
version: "3.5"
|
||||
|
||||
version: "3.7"
|
||||
services:
|
||||
db:
|
||||
image: mariadb:10.5
|
||||
|
@ -80,4 +78,4 @@ services:
|
|||
|
||||
# traefik.http.routers.anonaddy.entrypoints: http
|
||||
# traefik.http.routers.anonaddy.service: anonaddy
|
||||
# traefik.http.services.anonaddy.loadbalancer.server.port: 8000
|
||||
# traefik.http.services.anonaddy.loadbalancer.server.port: 8000
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version: "2.1"
|
||||
version: "3.7"
|
||||
services:
|
||||
calibre-web:
|
||||
image: lscr.io/linuxserver/calibre-web:latest
|
||||
|
@ -9,9 +9,9 @@ services:
|
|||
- TZ=${TZ}
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/config:/config
|
||||
- ${APP_DATA_DIR}/data/books:/books
|
||||
- ${ROOT_FOLDER_HOST}/media/data/books:/books
|
||||
ports:
|
||||
- ${APP_PORT}:8083
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- tipi_main_network
|
||||
- tipi_main_network
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version: "2.1"
|
||||
version: "3.7"
|
||||
services:
|
||||
code-server:
|
||||
image: lscr.io/linuxserver/code-server:latest
|
||||
|
@ -16,4 +16,4 @@ services:
|
|||
- ${APP_PORT}:8443
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- tipi_main_network
|
||||
- tipi_main_network
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
version: "3.7"
|
||||
services:
|
||||
filebrowser:
|
||||
container_name: filebrowser
|
||||
|
|
12
apps/gitea/config.json
Normal file
12
apps/gitea/config.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "Gitea",
|
||||
"port": 8108,
|
||||
"available": true,
|
||||
"id": "gitea",
|
||||
"description": "Gitea is a painless self-hosted Git service. It is similar to GitHub, Bitbucket, and GitLab. Gitea is a fork of Gogs. See the Gitea Announcement blog post to read about the justification for a fork.",
|
||||
"short_desc": "Gitea - Git with a cup of tea · A painless self-hosted Git service. · Cross-platform · Easy to install · Lightweight · Open Source.",
|
||||
"author": "go-gitea",
|
||||
"source": "https://github.com/go-gitea/gitea",
|
||||
"image": "https://avatars.githubusercontent.com/u/12724356?s=200&v=4",
|
||||
"form_fields": {}
|
||||
}
|
88
apps/gitea/data/gitea/gitea/conf/app.ini
Normal file
88
apps/gitea/data/gitea/gitea/conf/app.ini
Normal file
|
@ -0,0 +1,88 @@
|
|||
APP_NAME = Gitea: Git with a cup of tea
|
||||
RUN_MODE = prod
|
||||
RUN_USER = git
|
||||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||
|
||||
[repository.upload]
|
||||
TEMP_PATH = /data/gitea/uploads
|
||||
|
||||
[server]
|
||||
APP_DATA_PATH = /data/gitea
|
||||
DOMAIN = localhost
|
||||
SSH_DOMAIN = localhost
|
||||
HTTP_PORT = 3000
|
||||
ROOT_URL = http://localhost:8108/
|
||||
DISABLE_SSH = false
|
||||
SSH_PORT = 22
|
||||
SSH_LISTEN_PORT = 22
|
||||
LFS_START_SERVER = true
|
||||
LFS_CONTENT_PATH = /data/git/lfs
|
||||
LFS_JWT_SECRET = wo2G20l0nGsspUp8xsLNSNF7H8U-GQUVth5gj_q5cDk
|
||||
OFFLINE_MODE = false
|
||||
|
||||
[database]
|
||||
PATH = /data/gitea/gitea.db
|
||||
DB_TYPE = postgres
|
||||
HOST = gitea-db:5432
|
||||
NAME = gitea
|
||||
USER = gitea
|
||||
PASSWD = gitea
|
||||
LOG_SQL = false
|
||||
SCHEMA =
|
||||
SSL_MODE = disable
|
||||
CHARSET = utf8
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||
|
||||
[session]
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
||||
PROVIDER = file
|
||||
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /data/gitea/avatars
|
||||
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
|
||||
DISABLE_GRAVATAR = false
|
||||
ENABLE_FEDERATED_AVATAR = true
|
||||
|
||||
[attachment]
|
||||
PATH = /data/gitea/attachments
|
||||
|
||||
[log]
|
||||
MODE = console
|
||||
LEVEL = info
|
||||
ROUTER = console
|
||||
ROOT_PATH = /data/gitea/log
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY =
|
||||
REVERSE_PROXY_LIMIT = 1
|
||||
REVERSE_PROXY_TRUSTED_PROXIES = *
|
||||
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE2NTMyODU5ODh9.l7fPuVA8LSHZvdBum8YDrH47RZjEx_cZLbswO5pMDk8
|
||||
PASSWORD_HASH_ALGO = pbkdf2
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = false
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
NO_REPLY_ADDRESS = noreply.localhost
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = true
|
||||
ENABLE_OPENID_SIGNUP = true
|
||||
|
37
apps/gitea/docker-compose.yml
Normal file
37
apps/gitea/docker-compose.yml
Normal file
|
@ -0,0 +1,37 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:1.16.8
|
||||
container_name: gitea
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=postgres
|
||||
- GITEA__database__HOST=gitea-db:5432
|
||||
- GITEA__database__NAME=gitea
|
||||
- GITEA__database__USER=gitea
|
||||
- GITEA__database__PASSWD=gitea
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- tipi_main_network
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/gitea:/data
|
||||
ports:
|
||||
- ${APP_PORT}:3000
|
||||
- "222:22"
|
||||
depends_on:
|
||||
- gitea-db
|
||||
|
||||
gitea-db:
|
||||
container_name: gitea-db
|
||||
image: postgres:14
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_USER=gitea
|
||||
- POSTGRES_PASSWORD=gitea
|
||||
- POSTGRES_DB=gitea
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/postgres:/var/lib/postgresql/data
|
||||
networks:
|
||||
- tipi_main_network
|
|
@ -5,8 +5,8 @@
|
|||
"id": "homarr",
|
||||
"description": "A homepage for your server.",
|
||||
"short_desc": "Homarr is a simple and lightweight homepage for your server, that helps you easily access all of your services in one place.",
|
||||
"author": "https://github.com/ajnart/",
|
||||
"source": "https://github.com/ajnart/homar",
|
||||
"author": "ajnart",
|
||||
"source": "https://github.com/ajnart/homarr",
|
||||
"website": "https://discord.gg/C2WTXkzkwK",
|
||||
"image": "https://raw.githubusercontent.com/ajnart/homarr/master/public/imgs/logo.png",
|
||||
"form_fields": {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version: '3'
|
||||
version: "3.7"
|
||||
services:
|
||||
homarr:
|
||||
container_name: homarr
|
||||
|
@ -9,4 +9,4 @@ services:
|
|||
ports:
|
||||
- ${APP_PORT}:7575
|
||||
networks:
|
||||
- tipi_main_network
|
||||
- tipi_main_network
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
"available": true,
|
||||
"port": 8095,
|
||||
"id": "invidious",
|
||||
"description": "",
|
||||
"short_desc": "",
|
||||
"author": "",
|
||||
"description": "Invidious is an open source alternative front-end to YouTube.",
|
||||
"short_desc": "An alternative front-end to YouTube",
|
||||
"author": "iv-org",
|
||||
"source": "https://github.com/iv-org/invidious",
|
||||
"image": "https://raw.githubusercontent.com/iv-org/invidious/master/assets/invidious-colored-vector.svg",
|
||||
"form_fields": {}
|
||||
|
|
12
apps/invidious/data/init/init-invidious-db.sh
Normal file
12
apps/invidious/data/init/init-invidious-db.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
set -eou pipefail
|
||||
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/channels.sql
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/videos.sql
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/channel_videos.sql
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/users.sql
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/session_ids.sql
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/nonces.sql
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/annotations.sql
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/playlists.sql
|
||||
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <config/sql/playlist_videos.sql
|
12
apps/invidious/data/init/sql/annotations.sql
Normal file
12
apps/invidious/data/init/sql/annotations.sql
Normal file
|
@ -0,0 +1,12 @@
|
|||
-- Table: public.annotations
|
||||
|
||||
-- DROP TABLE public.annotations;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.annotations
|
||||
(
|
||||
id text NOT NULL,
|
||||
annotations xml,
|
||||
CONSTRAINT annotations_id_key UNIQUE (id)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE public.annotations TO current_user;
|
30
apps/invidious/data/init/sql/channel_videos.sql
Normal file
30
apps/invidious/data/init/sql/channel_videos.sql
Normal file
|
@ -0,0 +1,30 @@
|
|||
-- Table: public.channel_videos
|
||||
|
||||
-- DROP TABLE public.channel_videos;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.channel_videos
|
||||
(
|
||||
id text NOT NULL,
|
||||
title text,
|
||||
published timestamp with time zone,
|
||||
updated timestamp with time zone,
|
||||
ucid text,
|
||||
author text,
|
||||
length_seconds integer,
|
||||
live_now boolean,
|
||||
premiere_timestamp timestamp with time zone,
|
||||
views bigint,
|
||||
CONSTRAINT channel_videos_id_key UNIQUE (id)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE public.channel_videos TO current_user;
|
||||
|
||||
-- Index: public.channel_videos_ucid_idx
|
||||
|
||||
-- DROP INDEX public.channel_videos_ucid_idx;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS channel_videos_ucid_idx
|
||||
ON public.channel_videos
|
||||
USING btree
|
||||
(ucid COLLATE pg_catalog."default");
|
||||
|
25
apps/invidious/data/init/sql/channels.sql
Normal file
25
apps/invidious/data/init/sql/channels.sql
Normal file
|
@ -0,0 +1,25 @@
|
|||
-- Table: public.channels
|
||||
|
||||
-- DROP TABLE public.channels;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.channels
|
||||
(
|
||||
id text NOT NULL,
|
||||
author text,
|
||||
updated timestamp with time zone,
|
||||
deleted boolean,
|
||||
subscribed timestamp with time zone,
|
||||
CONSTRAINT channels_id_key UNIQUE (id)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE public.channels TO current_user;
|
||||
|
||||
-- Index: public.channels_id_idx
|
||||
|
||||
-- DROP INDEX public.channels_id_idx;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS channels_id_idx
|
||||
ON public.channels
|
||||
USING btree
|
||||
(id COLLATE pg_catalog."default");
|
||||
|
22
apps/invidious/data/init/sql/nonces.sql
Normal file
22
apps/invidious/data/init/sql/nonces.sql
Normal file
|
@ -0,0 +1,22 @@
|
|||
-- Table: public.nonces
|
||||
|
||||
-- DROP TABLE public.nonces;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.nonces
|
||||
(
|
||||
nonce text,
|
||||
expire timestamp with time zone,
|
||||
CONSTRAINT nonces_id_key UNIQUE (nonce)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE public.nonces TO current_user;
|
||||
|
||||
-- Index: public.nonces_nonce_idx
|
||||
|
||||
-- DROP INDEX public.nonces_nonce_idx;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS nonces_nonce_idx
|
||||
ON public.nonces
|
||||
USING btree
|
||||
(nonce COLLATE pg_catalog."default");
|
||||
|
19
apps/invidious/data/init/sql/playlist_videos.sql
Normal file
19
apps/invidious/data/init/sql/playlist_videos.sql
Normal file
|
@ -0,0 +1,19 @@
|
|||
-- Table: public.playlist_videos
|
||||
|
||||
-- DROP TABLE public.playlist_videos;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.playlist_videos
|
||||
(
|
||||
title text,
|
||||
id text,
|
||||
author text,
|
||||
ucid text,
|
||||
length_seconds integer,
|
||||
published timestamptz,
|
||||
plid text references playlists(id),
|
||||
index int8,
|
||||
live_now boolean,
|
||||
PRIMARY KEY (index,plid)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE public.playlist_videos TO current_user;
|
29
apps/invidious/data/init/sql/playlists.sql
Normal file
29
apps/invidious/data/init/sql/playlists.sql
Normal file
|
@ -0,0 +1,29 @@
|
|||
-- Type: public.privacy
|
||||
|
||||
-- DROP TYPE public.privacy;
|
||||
|
||||
CREATE TYPE public.privacy AS ENUM
|
||||
(
|
||||
'Public',
|
||||
'Unlisted',
|
||||
'Private'
|
||||
);
|
||||
|
||||
-- Table: public.playlists
|
||||
|
||||
-- DROP TABLE public.playlists;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.playlists
|
||||
(
|
||||
title text,
|
||||
id text primary key,
|
||||
author text,
|
||||
description text,
|
||||
video_count integer,
|
||||
created timestamptz,
|
||||
updated timestamptz,
|
||||
privacy privacy,
|
||||
index int8[]
|
||||
);
|
||||
|
||||
GRANT ALL ON public.playlists TO current_user;
|
23
apps/invidious/data/init/sql/session_ids.sql
Normal file
23
apps/invidious/data/init/sql/session_ids.sql
Normal file
|
@ -0,0 +1,23 @@
|
|||
-- Table: public.session_ids
|
||||
|
||||
-- DROP TABLE public.session_ids;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.session_ids
|
||||
(
|
||||
id text NOT NULL,
|
||||
email text,
|
||||
issued timestamp with time zone,
|
||||
CONSTRAINT session_ids_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE public.session_ids TO current_user;
|
||||
|
||||
-- Index: public.session_ids_id_idx
|
||||
|
||||
-- DROP INDEX public.session_ids_id_idx;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS session_ids_id_idx
|
||||
ON public.session_ids
|
||||
USING btree
|
||||
(id COLLATE pg_catalog."default");
|
||||
|
29
apps/invidious/data/init/sql/users.sql
Normal file
29
apps/invidious/data/init/sql/users.sql
Normal file
|
@ -0,0 +1,29 @@
|
|||
-- Table: public.users
|
||||
|
||||
-- DROP TABLE public.users;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.users
|
||||
(
|
||||
updated timestamp with time zone,
|
||||
notifications text[],
|
||||
subscriptions text[],
|
||||
email text NOT NULL,
|
||||
preferences text,
|
||||
password text,
|
||||
token text,
|
||||
watched text[],
|
||||
feed_needs_update boolean,
|
||||
CONSTRAINT users_email_key UNIQUE (email)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE public.users TO current_user;
|
||||
|
||||
-- Index: public.email_unique_idx
|
||||
|
||||
-- DROP INDEX public.email_unique_idx;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS email_unique_idx
|
||||
ON public.users
|
||||
USING btree
|
||||
(lower(email) COLLATE pg_catalog."default");
|
||||
|
23
apps/invidious/data/init/sql/videos.sql
Normal file
23
apps/invidious/data/init/sql/videos.sql
Normal file
|
@ -0,0 +1,23 @@
|
|||
-- Table: public.videos
|
||||
|
||||
-- DROP TABLE public.videos;
|
||||
|
||||
CREATE UNLOGGED TABLE IF NOT EXISTS public.videos
|
||||
(
|
||||
id text NOT NULL,
|
||||
info text,
|
||||
updated timestamp with time zone,
|
||||
CONSTRAINT videos_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
GRANT ALL ON TABLE public.videos TO current_user;
|
||||
|
||||
-- Index: public.id_idx
|
||||
|
||||
-- DROP INDEX public.id_idx;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS id_idx
|
||||
ON public.videos
|
||||
USING btree
|
||||
(id COLLATE pg_catalog."default");
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
version: "3"
|
||||
version: "3.7"
|
||||
services:
|
||||
invidious:
|
||||
user: 1000:1000
|
||||
container_name: invidious
|
||||
image: quay.io/invidious/invidious:latest-arm64
|
||||
restart: unless-stopped
|
||||
dns:
|
||||
- ${DNS_IP}
|
||||
ports:
|
||||
- "${APP_PORT}:3000"
|
||||
environment:
|
||||
|
@ -23,6 +25,8 @@ services:
|
|||
retries: 2
|
||||
depends_on:
|
||||
- invidious-db
|
||||
networks:
|
||||
- tipi_main_network
|
||||
|
||||
invidious-db:
|
||||
user: 1000:1000
|
||||
|
@ -31,8 +35,8 @@ services:
|
|||
restart: unless-stopped
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/postgres:/var/lib/postgresql/data
|
||||
- ${APP_DATA_DIR}/data/sql:/config/sql
|
||||
- ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
|
||||
- ${APP_DATA_DIR}/data/init/sql:/config/sql
|
||||
- ${APP_DATA_DIR}/data/init/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
|
||||
environment:
|
||||
POSTGRES_DB: invidious
|
||||
POSTGRES_USER: tipi
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version: "3"
|
||||
version: "3.7"
|
||||
services:
|
||||
invidious:
|
||||
user: 1000:1000
|
||||
|
@ -26,6 +26,8 @@ services:
|
|||
retries: 2
|
||||
depends_on:
|
||||
- invidious-db
|
||||
networks:
|
||||
- tipi_main_network
|
||||
|
||||
invidious-db:
|
||||
user: 1000:1000
|
||||
|
@ -34,8 +36,8 @@ services:
|
|||
restart: unless-stopped
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/postgres:/var/lib/postgresql/data
|
||||
- ${APP_DATA_DIR}/data/sql:/config/sql
|
||||
- ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
|
||||
- ${APP_DATA_DIR}/data/init/sql:/config/sql
|
||||
- ${APP_DATA_DIR}/data/init/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
|
||||
environment:
|
||||
POSTGRES_DB: invidious
|
||||
POSTGRES_USER: tipi
|
||||
|
|
|
@ -12,7 +12,7 @@ services:
|
|||
- ${DNS_IP}
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data:/config
|
||||
- ${ROOT_FOLDER_HOST}/media/torrents:/downloads
|
||||
- ${ROOT_FOLDER_HOST}/media/torrents:/media/torrents
|
||||
ports:
|
||||
- ${APP_PORT}:9117
|
||||
restart: unless-stopped
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
"available": true,
|
||||
"port": 8091,
|
||||
"id": "jellyfin",
|
||||
"description": "",
|
||||
"short_desc": "",
|
||||
"author": "",
|
||||
"source": "",
|
||||
"description": "Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media. It is an alternative to the proprietary Emby and Plex, to provide media from a dedicated server to end-user devices via multiple apps. Jellyfin is descended from Emby's 3.5.2 release and ported to the .NET Core framework to enable full cross-platform support. There are no strings attached, no premium licenses or features, and no hidden agendas: just a team who want to build something better and work together to achieve it. We welcome anyone who is interested in joining us in our quest!",
|
||||
"short_desc": "A media server for your home collection",
|
||||
"author": "jellyfin.org",
|
||||
"source": "https://github.com/jellyfin/jellyfin",
|
||||
"image": "https://avatars.githubusercontent.com/u/45698031?s=200&v=4",
|
||||
"form_fields": {}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ services:
|
|||
container_name: jellyfin
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/config:/config
|
||||
- ${ROOT_FOLDER_HOST}/media/data:/data/media
|
||||
- ${ROOT_FOLDER_HOST}/media/data:/media/data
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
|
|
12
apps/libreddit/config.json
Normal file
12
apps/libreddit/config.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "LibReddit",
|
||||
"available": true,
|
||||
"port": 8105,
|
||||
"id": "libreddit",
|
||||
"description": "LibReddit is a bloat free reddit frontend written in Rust, no ads, no tracking and strong Content Security Policy prevents any request from going to reddit, everything is proxied.",
|
||||
"short_desc": "Browse reddit without problems!",
|
||||
"author": "spikecodes",
|
||||
"source": "https://github.com/spikecodes/libreddit",
|
||||
"image": "https://raw.githubusercontent.com/spikecodes/libreddit/master/static/logo.png",
|
||||
"form_fields": {}
|
||||
}
|
12
apps/libreddit/docker-compose.arm.yml
Normal file
12
apps/libreddit/docker-compose.arm.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
version: "3.7"
|
||||
services:
|
||||
libreddit:
|
||||
container_name: libreddit
|
||||
image: spikecodes/libreddit:arm
|
||||
dns:
|
||||
- ${DNS_IP}
|
||||
ports:
|
||||
- ${APP_PORT}:8080
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- tipi_main_network
|
12
apps/libreddit/docker-compose.yml
Normal file
12
apps/libreddit/docker-compose.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
version: "3.7"
|
||||
services:
|
||||
libreddit:
|
||||
container_name: libreddit
|
||||
image: spikecodes/libreddit
|
||||
dns:
|
||||
- ${DNS_IP}
|
||||
ports:
|
||||
- ${APP_PORT}:8080
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- tipi_main_network
|
12
apps/nitter/config.json
Normal file
12
apps/nitter/config.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "Nitter",
|
||||
"available": true,
|
||||
"port": 8106,
|
||||
"id": "nitter",
|
||||
"description": "A free and open source alternative Twitter front-end focused on privacy and performance.",
|
||||
"short_desc": "Twitter without annoyances!",
|
||||
"author": "zedeus",
|
||||
"source": "https://github.com/zedeus/nitter",
|
||||
"image": "https://raw.githubusercontent.com/zedeus/nitter/master/public/favicon.ico",
|
||||
"form_fields": {}
|
||||
}
|
45
apps/nitter/data/nitter.conf
Normal file
45
apps/nitter/data/nitter.conf
Normal file
|
@ -0,0 +1,45 @@
|
|||
[Server]
|
||||
address = "0.0.0.0"
|
||||
port = 8080
|
||||
https = false # disable to enable cookies when not using https
|
||||
httpMaxConnections = 100
|
||||
staticDir = "./public"
|
||||
title = "nitter"
|
||||
hostname = ""
|
||||
|
||||
[Cache]
|
||||
listMinutes = 240 # how long to cache list info (not the tweets, so keep it high)
|
||||
rssMinutes = 10 # how long to cache rss queries
|
||||
redisHost = "nitter-redis" # Change to "nitter-redis" if using docker-compose
|
||||
redisPort = 6379
|
||||
redisPassword = ""
|
||||
redisConnections = 20 # connection pool size
|
||||
redisMaxConnections = 30
|
||||
# max, new connections are opened when none are available, but if the pool size
|
||||
# goes above this, they're closed when released. don't worry about this unless
|
||||
# you receive tons of requests per second
|
||||
|
||||
[Config]
|
||||
hmacKey = "secretkey" # random key for cryptographic signing of video urls
|
||||
base64Media = false # use base64 encoding for proxied media urls
|
||||
enableRSS = true # set this to false to disable RSS feeds
|
||||
enableDebug = false # enable request logs and debug endpoints
|
||||
proxy = "" # http/https url, SOCKS proxies are not supported
|
||||
proxyAuth = ""
|
||||
tokenCount = 10
|
||||
# minimum amount of usable tokens. tokens are used to authorize API requests,
|
||||
# but they expire after ~1 hour, and have a limit of 187 requests.
|
||||
# the limit gets reset every 15 minutes, and the pool is filled up so there's
|
||||
# always at least $tokenCount usable tokens. again, only increase this if
|
||||
# you receive major bursts all the time
|
||||
|
||||
# Change default preferences here, see src/prefs_impl.nim for a complete list
|
||||
[Preferences]
|
||||
theme = "Nitter"
|
||||
replaceTwitter = ""
|
||||
replaceYouTube = ""
|
||||
replaceReddit = ""
|
||||
replaceInstagram = ""
|
||||
proxyVideos = true
|
||||
hlsPlayback = true
|
||||
infiniteScroll = true
|
24
apps/nitter/docker-compose.yml
Normal file
24
apps/nitter/docker-compose.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
nitter:
|
||||
image: zedeus/nitter:latest
|
||||
container_name: nitter
|
||||
networks:
|
||||
- tipi_main_network
|
||||
ports:
|
||||
- ${APP_PORT}:8080
|
||||
volumes:
|
||||
- "${APP_DATA_DIR}/data/nitter.conf:/src/nitter.conf:ro"
|
||||
depends_on:
|
||||
- nitter-redis
|
||||
restart: unless-stopped
|
||||
nitter-redis:
|
||||
image: redis:6-alpine
|
||||
container_name: nitter-redis
|
||||
networks:
|
||||
- tipi_main_network
|
||||
command: redis-server --save 60 1 --loglevel warning
|
||||
volumes:
|
||||
- "${APP_DATA_DIR}/data/redis:/data"
|
||||
restart: unless-stopped
|
21
apps/photoprism/config.json
Normal file
21
apps/photoprism/config.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "PhotoPrism",
|
||||
"port": 8110,
|
||||
"available": true,
|
||||
"id": "photoprism",
|
||||
"description": "PhotoPrism® is an AI-Powered Photos App for the Decentralized Web. It makes use of the latest technologies to tag and find pictures automatically without getting in your way. You can run it at home, on a private server, or in the cloud. Default username: admin",
|
||||
"short_desc": "AI-Powered Photos App for the Decentralized Web. We are on a mission to protect your freedom and privacy.",
|
||||
"author": "PhotoPrism",
|
||||
"source": "https://github.com/photoprism/photoprism",
|
||||
"image": "https://avatars.githubusercontent.com/u/32436079?s=200&v=4",
|
||||
"form_fields": {
|
||||
"password": {
|
||||
"type": "password",
|
||||
"label": "Photoprism admin password",
|
||||
"max": 50,
|
||||
"min": 8,
|
||||
"required": true,
|
||||
"env_variable": "PHOTOPRISM_ADMIN_PASSWORD"
|
||||
}
|
||||
}
|
||||
}
|
56
apps/photoprism/docker-compose.yml
Normal file
56
apps/photoprism/docker-compose.yml
Normal file
|
@ -0,0 +1,56 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
photoprism:
|
||||
image: photoprism/photoprism:latest
|
||||
container_name: photoprism
|
||||
depends_on:
|
||||
- photoprism-db
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${APP_PORT}:2342"
|
||||
environment:
|
||||
PHOTOPRISM_ADMIN_PASSWORD: ${PHOTOPRISM_ADMIN_PASSWORD}
|
||||
PHOTOPRISM_SITE_URL: "http://localhost:2342/"
|
||||
PHOTOPRISM_ORIGINALS_LIMIT: 5000
|
||||
PHOTOPRISM_HTTP_COMPRESSION: "gzip"
|
||||
PHOTOPRISM_LOG_LEVEL: "info"
|
||||
PHOTOPRISM_PUBLIC: "false"
|
||||
PHOTOPRISM_READONLY: "false"
|
||||
PHOTOPRISM_EXPERIMENTAL: "false"
|
||||
PHOTOPRISM_DISABLE_CHOWN: "false"
|
||||
PHOTOPRISM_DISABLE_WEBDAV: "false"
|
||||
PHOTOPRISM_DISABLE_SETTINGS: "false"
|
||||
PHOTOPRISM_DISABLE_TENSORFLOW: "false"
|
||||
PHOTOPRISM_DISABLE_FACES: "false"
|
||||
PHOTOPRISM_DISABLE_CLASSIFICATION: "false"
|
||||
PHOTOPRISM_DISABLE_RAW: "false"
|
||||
PHOTOPRISM_RAW_PRESETS: "false"
|
||||
PHOTOPRISM_JPEG_QUALITY: 85
|
||||
PHOTOPRISM_DETECT_NSFW: "false"
|
||||
PHOTOPRISM_UPLOAD_NSFW: "true"
|
||||
PHOTOPRISM_DATABASE_DRIVER: "mysql"
|
||||
PHOTOPRISM_DATABASE_SERVER: "photoprism-db:3306"
|
||||
PHOTOPRISM_DATABASE_NAME: "photoprism"
|
||||
PHOTOPRISM_DATABASE_USER: "photoprism"
|
||||
PHOTOPRISM_DATABASE_PASSWORD: "photoprism"
|
||||
PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App"
|
||||
working_dir: "/photoprism"
|
||||
volumes:
|
||||
- "${APP_DATA_DIR}/data/photoprism/originals:/photoprism/originals"
|
||||
- "${APP_DATA_DIR}/data/photoprism/storage:/photoprism/storage"
|
||||
networks:
|
||||
- tipi_main_network
|
||||
|
||||
photoprism-db:
|
||||
restart: unless-stopped
|
||||
image: mariadb:10.8.3
|
||||
container_name: photoprism-db
|
||||
command: mysqld --innodb-buffer-pool-size=128M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120
|
||||
volumes:
|
||||
- "${APP_DATA_DIR}/data/mariadb:/var/lib/mysql"
|
||||
environment:
|
||||
MARIADB_DATABASE: "photoprism"
|
||||
MARIADB_USER: "photoprism"
|
||||
MARIADB_PASSWORD: "photoprism"
|
||||
MARIADB_ROOT_PASSWORD: "photoprism"
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"name": "PiHole",
|
||||
"name": "Pi-hole",
|
||||
"available": true,
|
||||
"port": 8081,
|
||||
"requirements": {
|
||||
"ports": [53]
|
||||
},
|
||||
"id": "pihole",
|
||||
"description": "",
|
||||
"short_desc": "",
|
||||
"author": "",
|
||||
"source": "",
|
||||
"description": "The Pi-hole® is a DNS sinkhole that protects your devices from unwanted content without installing any client-side software.",
|
||||
"short_desc": "A black hole for Internet advertisements",
|
||||
"author": "pi-hole.net",
|
||||
"source": "https://github.com/pi-hole/pi-hole",
|
||||
"image": "https://avatars.githubusercontent.com/u/16827203?s=200&v=4",
|
||||
"form_fields": {
|
||||
"password": {
|
||||
|
|
12
apps/prowlarr/config.json
Normal file
12
apps/prowlarr/config.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "Prowlarr",
|
||||
"available": true,
|
||||
"port": 8109,
|
||||
"id": "prowlarr",
|
||||
"description": "Prowlarr is an indexer manager/proxy built on the popular *arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports management of both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Lidarr, Mylar3, Radarr, Readarr, and Sonarr offering complete management of your indexers with no per app Indexer setup required (we do it all).",
|
||||
"short_desc": "A torrent/usenet indexer manager/proxy",
|
||||
"author": "Prowlarr",
|
||||
"source": "https://github.com/Prowlarr/Prowlarr/",
|
||||
"image": "https://prowlarr.com/logo/256.png",
|
||||
"form_fields": {}
|
||||
}
|
16
apps/prowlarr/docker-compose.yml
Normal file
16
apps/prowlarr/docker-compose.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
version: "3.7"
|
||||
services:
|
||||
prowlarr: # Should be exact same name as "id" field in config.json
|
||||
container_name: prowlarr # Should be exact same name as "id" field in config.json
|
||||
image: ghcr.io/linuxserver/prowlarr:develop
|
||||
environment:
|
||||
- TZ=${TZ} # Can use any env variable. List in runtipi/templates/env-sample
|
||||
dns:
|
||||
- ${DNS_IP}
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/config:/config #Always start the path with ${APP_DATA_DIR}. This will put all data inside app-data/my-app/data
|
||||
ports:
|
||||
- ${APP_PORT}:9696
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- tipi_main_network
|
|
@ -3,10 +3,10 @@
|
|||
"available": true,
|
||||
"port": 8088,
|
||||
"id": "radarr",
|
||||
"description": "",
|
||||
"short_desc": "",
|
||||
"author": "",
|
||||
"source": "",
|
||||
"description": "Radarr is a movie collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new movies and will interface with clients and indexers to grab, sort, and rename them. It can also be configured to automatically upgrade the quality of existing files in the library when a better quality format becomes available. Note that only one type of a given movie is supported. If you want both an 4k version and 1080p version of a given movie you will need multiple instances.",
|
||||
"short_desc": "Movie collection manager for Usenet and BitTorrent users.",
|
||||
"author": "radarr.video",
|
||||
"source": "https://github.com/Radarr/Radarr",
|
||||
"image": "https://avatars.githubusercontent.com/u/25025331?s=200&v=4",
|
||||
"form_fields": {}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ services:
|
|||
dns:
|
||||
- ${DNS_IP}
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- ${APP_DATA_DIR}/data:/config
|
||||
- ${ROOT_FOLDER_HOST}/media/data/movies:/movies #optional
|
||||
- ${ROOT_FOLDER_HOST}/media/torrents:/downloads #optional
|
||||
- ${ROOT_FOLDER_HOST}/media:/media
|
||||
ports:
|
||||
- ${APP_PORT}:7878
|
||||
restart: unless-stopped
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
"available": true,
|
||||
"port": 8098,
|
||||
"id": "sonarr",
|
||||
"description": "",
|
||||
"short_desc": "",
|
||||
"author": "",
|
||||
"source": "",
|
||||
"description": "Sonarr is a PVR for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.",
|
||||
"short_desc": "TV show manager for Usenet and BitTorrent",
|
||||
"author": "sonarr.tv",
|
||||
"source": "https://github.com/Sonarr/Sonarr",
|
||||
"image": "https://avatars.githubusercontent.com/u/1082903?s=200&v=4",
|
||||
"form_fields": {}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
version: "3.7"
|
||||
services:
|
||||
radarr:
|
||||
sonarr:
|
||||
image: lscr.io/linuxserver/sonarr
|
||||
container_name: sonarr
|
||||
environment:
|
||||
|
@ -10,9 +10,9 @@ services:
|
|||
dns:
|
||||
- ${DNS_IP}
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- ${APP_DATA_DIR}/data:/config
|
||||
- ${ROOT_FOLDER_HOST}/media/data/tv:/tv #optional
|
||||
- ${ROOT_FOLDER_HOST}/media/torrents:/downloads #optional
|
||||
- ${ROOT_FOLDER_HOST}/media:/media
|
||||
ports:
|
||||
- ${APP_PORT}:8989
|
||||
restart: unless-stopped
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
"available": true,
|
||||
"port": 8093,
|
||||
"id": "tailscale",
|
||||
"description": "",
|
||||
"short_desc": "",
|
||||
"author": "",
|
||||
"description": "Zero config VPN. Installs on any device in minutes, manages firewall rules for you, and works from anywhere.",
|
||||
"short_desc": "The easiest, most secure way to use WireGuard and 2FA.",
|
||||
"author": "© Tailscale Inc.",
|
||||
"source": "https://github.com/tailscale/tailscale",
|
||||
"website": "https://tailscale.com/",
|
||||
"image": "https://avatars.githubusercontent.com/u/48932923?s=200&v=4",
|
||||
|
|
12
apps/tautulli/config.json
Normal file
12
apps/tautulli/config.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "Tautulli",
|
||||
"available": true,
|
||||
"port": 8181,
|
||||
"id": "tautulli",
|
||||
"description": "Tautulli is a 3rd party application that you can run alongside your Plex Media Server to monitor activity and track various statistics. Most importantly, these statistics include what has been watched, who watched it, when and where they watched it, and how it was watched. The only thing missing is \"why they watched it\", but who am I to question your 42 plays of Frozen. All statistics are presented in a nice and clean interface with many tables and graphs, which makes it easy to brag about your server to everyone else.",
|
||||
"short_desc": "A Python based monitoring and tracking tool for Plex Media Server.",
|
||||
"author": "JonnyWong16",
|
||||
"source": "https://github.com/Tautulli/Tautulli",
|
||||
"image": "https://tautulli.com/images/logo-circle.png",
|
||||
"form_fields": {}
|
||||
}
|
16
apps/tautulli/docker-compose.yml
Normal file
16
apps/tautulli/docker-compose.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
version: "2.1"
|
||||
services:
|
||||
tautulli:
|
||||
container_name: tautulli
|
||||
image: lscr.io/linuxserver/tautulli:latest
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=${TZ} # Can use any env variable. List in runtipi/templates/env-sample
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data/config:/config
|
||||
ports:
|
||||
- ${APP_PORT}:8181
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- tipi_main_network
|
|
@ -6,10 +6,10 @@
|
|||
"ports": [51413]
|
||||
},
|
||||
"id": "transmission",
|
||||
"description": "",
|
||||
"short_desc": "",
|
||||
"author": "",
|
||||
"source": "https://transmissionbt.com",
|
||||
"description": "Transmission is a fast, easy, and free BitTorrent client.",
|
||||
"short_desc": "Fast, easy, and free BitTorrent client",
|
||||
"author": "Transmission Project",
|
||||
"source": "https://github.com/transmission/transmission",
|
||||
"image": "https://avatars.githubusercontent.com/u/223312?s=200&v=4",
|
||||
"form_fields": {
|
||||
"username": {
|
||||
|
|
|
@ -3,12 +3,15 @@ services:
|
|||
transmission:
|
||||
image: lscr.io/linuxserver/transmission
|
||||
container_name: transmission
|
||||
dns:
|
||||
- ${DNS_IP}
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=${TZ}
|
||||
- USER=${TRANSMISSION_USERNAME}
|
||||
- PASS=${TRANSMISSION_PASSWORD}
|
||||
- TRANSMISSION_WEB_HOME=/transmission-web-control/
|
||||
# - WHITELIST=iplist #optional
|
||||
# - PEERPORT=peerport #optional
|
||||
# - HOST_WHITELIST=dnsnane list #optional
|
||||
|
|
21
apps/vaultwarden/config.json
Normal file
21
apps/vaultwarden/config.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "VaultWarden",
|
||||
"available": true,
|
||||
"port": 8107,
|
||||
"id": "vaultwarden",
|
||||
"description": "Alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal.",
|
||||
"short_desc": "All your passwords in your control!",
|
||||
"author": "Daniel García",
|
||||
"source": "https://github.com/dani-garcia/vaultwarden",
|
||||
"image": "https://raw.githubusercontent.com/dani-garcia/vaultwarden/b636d20c6475bfb1b36561cb95812faee26ea7db/resources/vaultwarden-icon.svg",
|
||||
"form_fields": {
|
||||
"admin_password": {
|
||||
"type": "password",
|
||||
"label": "Admin Panel Password",
|
||||
"max": 50,
|
||||
"min": 10,
|
||||
"required": true,
|
||||
"env_variable": "VAULTWARDEN_ADMIN_PASSWORD"
|
||||
}
|
||||
}
|
||||
}
|
16
apps/vaultwarden/docker-compose.yml
Normal file
16
apps/vaultwarden/docker-compose.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
version: '3.7'
|
||||
|
||||
services:
|
||||
vaultwarden:
|
||||
image: vaultwarden/server:1.24.0
|
||||
container_name: vaultwarden
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- ${APP_PORT}:80
|
||||
environment:
|
||||
- WEBSOCKET_ENABLED=true
|
||||
- ADMIN_TOKEN=${VAULTWARDEN_ADMIN_PASSWORD}
|
||||
volumes:
|
||||
- ${APP_DATA_DIR}/data:/data
|
||||
networks:
|
||||
- tipi_main_network
|
7
jest.config.js
Normal file
7
jest.config.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
testMatch: ["**/__tests__/**/*.test.ts"],
|
||||
testPathIgnorePatterns: ["/node_modules/", "/packages/"],
|
||||
};
|
BIN
media/data/books/metadata.db
Normal file
BIN
media/data/books/metadata.db
Normal file
Binary file not shown.
0
media/torrents/incomplete/.gitkeep
Normal file
0
media/torrents/incomplete/.gitkeep
Normal file
0
media/torrents/watch/.gitkeep
Normal file
0
media/torrents/watch/.gitkeep
Normal file
13
package.json
13
package.json
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"name": "runtipi",
|
||||
"version": "0.1.5",
|
||||
"version": "0.2.0",
|
||||
"description": "A homeserver for everyone",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"prepare": "husky install",
|
||||
"act:test-install": "act --container-architecture linux/amd64 -j test-install",
|
||||
"act:docker": "act --container-architecture linux/amd64 --secret-file github.secrets -j docker",
|
||||
|
@ -10,9 +11,15 @@
|
|||
"start:rc": "docker-compose -f docker-compose.rc.yml --env-file .env up --build",
|
||||
"start:prod": "docker-compose --env-file .env up --build"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"husky": "^8.0.1"
|
||||
"@types/jest": "^27.5.0",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/node": "17.0.31",
|
||||
"husky": "^8.0.1",
|
||||
"jest": "^28.1.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"ts-jest": "^28.0.2",
|
||||
"typescript": "4.6.4"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "dashboard",
|
||||
"version": "0.1.5",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
|
|
@ -1,27 +1,69 @@
|
|||
import validator from 'validator';
|
||||
import { AppConfig, FieldTypes } from '../../core/types';
|
||||
|
||||
const validateField = (field: AppConfig['form_fields'][0], value: string): string | undefined => {
|
||||
if (field.required && !value) {
|
||||
return `${field.label} is required`;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (field.type) {
|
||||
case FieldTypes.text:
|
||||
if (field.max && value.length > field.max) {
|
||||
return `${field.label} must be less than ${field.max} characters`;
|
||||
}
|
||||
if (field.min && value.length < field.min) {
|
||||
return `${field.label} must be at least ${field.min} characters`;
|
||||
}
|
||||
break;
|
||||
case FieldTypes.password:
|
||||
if (!validator.isLength(value, { min: field.min, max: field.max })) {
|
||||
return `${field.label} must be between ${field.min} and ${field.max} characters`;
|
||||
}
|
||||
break;
|
||||
case FieldTypes.email:
|
||||
if (!validator.isEmail(value)) {
|
||||
return `${field.label} must be a valid email address`;
|
||||
}
|
||||
break;
|
||||
case FieldTypes.number:
|
||||
if (!validator.isNumeric(value)) {
|
||||
return `${field.label} must be a number`;
|
||||
}
|
||||
break;
|
||||
case FieldTypes.fqdn:
|
||||
if (!validator.isFQDN(value)) {
|
||||
return `${field.label} must be a valid domain`;
|
||||
}
|
||||
break;
|
||||
case FieldTypes.ip:
|
||||
if (!validator.isIP(value)) {
|
||||
return `${field.label} must be a valid IP address`;
|
||||
}
|
||||
break;
|
||||
case FieldTypes.fqdnip:
|
||||
if (!validator.isFQDN(value || '') && !validator.isIP(value)) {
|
||||
return `${field.label} must be a valid domain or IP address`;
|
||||
}
|
||||
break;
|
||||
case FieldTypes.url:
|
||||
if (!validator.isURL(value)) {
|
||||
return `${field.label} must be a valid URL`;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export const validateAppConfig = (values: Record<string, string>, fields: (AppConfig['form_fields'][0] & { id: string })[]) => {
|
||||
const errors: any = {};
|
||||
|
||||
fields.forEach((field) => {
|
||||
if (field.required && !values[field.id]) {
|
||||
errors[field.id] = 'Field required';
|
||||
} else if (values[field.id] && field.min && values[field.id].length < field.min) {
|
||||
errors[field.id] = `Field must be at least ${field.min} characters long`;
|
||||
} else if (values[field.id] && field.max && values[field.id].length > field.max) {
|
||||
errors[field.id] = `Field must be at most ${field.max} characters long`;
|
||||
} else if (values[field.id] && field.type === FieldTypes.number && !validator.isNumeric(values[field.id])) {
|
||||
errors[field.id] = 'Field must be a number';
|
||||
} else if (values[field.id] && field.type === FieldTypes.email && !validator.isEmail(values[field.id])) {
|
||||
errors[field.id] = 'Field must be a valid email';
|
||||
} else if (values[field.id] && field.type === FieldTypes.fqdn && !validator.isFQDN(values[field.id] || '')) {
|
||||
errors[field.id] = 'Field must be a valid domain';
|
||||
} else if (values[field.id] && field.type === FieldTypes.ip && !validator.isIP(values[field.id])) {
|
||||
errors[field.id] = 'Field must be a valid IP address';
|
||||
} else if (values[field.id] && field.type === FieldTypes.fqdnip && !validator.isFQDN(values[field.id] || '') && !validator.isIP(values[field.id])) {
|
||||
errors[field.id] = 'Field must be a valid domain or IP address';
|
||||
}
|
||||
errors[field.id] = validateField(field, values[field.id]);
|
||||
});
|
||||
|
||||
return errors;
|
||||
|
|
|
@ -6,6 +6,7 @@ export enum FieldTypes {
|
|||
fqdn = 'fqdn',
|
||||
ip = 'ip',
|
||||
fqdnip = 'fqdnip',
|
||||
url = 'url',
|
||||
}
|
||||
|
||||
interface FormField {
|
||||
|
|
|
@ -103,6 +103,7 @@ const AppDetails: React.FC<IProps> = ({ app }) => {
|
|||
{app.source && (
|
||||
<a target="_blank" rel="noreferrer" className="text-blue-500 text-xs" href={app?.source}>
|
||||
<Flex className="mt-2 items-center">
|
||||
Source
|
||||
<FiExternalLink className="ml-1" />
|
||||
</Flex>
|
||||
</a>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "system-api",
|
||||
"version": "0.1.5",
|
||||
"version": "0.2.0",
|
||||
"description": "",
|
||||
"exports": "./dist/server.js",
|
||||
"type": "module",
|
||||
|
|
282
pnpm-lock.yaml
generated
282
pnpm-lock.yaml
generated
|
@ -4,9 +4,23 @@ importers:
|
|||
|
||||
.:
|
||||
specifiers:
|
||||
'@types/jest': ^27.5.0
|
||||
'@types/js-yaml': ^4.0.5
|
||||
'@types/node': 17.0.31
|
||||
husky: ^8.0.1
|
||||
jest: ^28.1.0
|
||||
js-yaml: ^4.1.0
|
||||
ts-jest: ^28.0.2
|
||||
typescript: 4.6.4
|
||||
devDependencies:
|
||||
'@types/jest': 27.5.0
|
||||
'@types/js-yaml': 4.0.5
|
||||
'@types/node': 17.0.31
|
||||
husky: 8.0.1
|
||||
jest: 28.1.0_@types+node@17.0.31
|
||||
js-yaml: 4.1.0
|
||||
ts-jest: 28.0.2_z3fx76c5ksuwr36so7o5uc2kcy
|
||||
typescript: 4.6.4
|
||||
|
||||
packages/dashboard:
|
||||
specifiers:
|
||||
|
@ -78,7 +92,7 @@ importers:
|
|||
eslint: 8.12.0
|
||||
eslint-config-airbnb-typescript: 17.0.0_r46exuh3jlhq2wmrnqx2ufqspa
|
||||
eslint-config-next: 12.1.4_e6a2zi6fqdwfehht5cxvkmo3zu
|
||||
eslint-plugin-import: 2.26.0_eslint@8.12.0
|
||||
eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy
|
||||
postcss: 8.4.13
|
||||
tailwindcss: 3.0.24
|
||||
typescript: 4.6.4
|
||||
|
@ -171,7 +185,7 @@ importers:
|
|||
eslint: 8.15.0
|
||||
eslint-config-airbnb-typescript: 17.0.0_c2ouaf3l4ivgkc6ae4nebvztom
|
||||
eslint-config-prettier: 8.5.0_eslint@8.15.0
|
||||
eslint-plugin-import: 2.26.0_eslint@8.15.0
|
||||
eslint-plugin-import: 2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy
|
||||
eslint-plugin-prettier: 4.0.0_iqftbjqlxzn3ny5nablrkczhqi
|
||||
jest: 28.1.0
|
||||
nodemon: 2.0.16
|
||||
|
@ -2104,6 +2118,10 @@ packages:
|
|||
resolution: {integrity: sha512-6+0ekgfusHftJNYpihfkMu8BWdeHs9EOJuGcSofErjstGPfPGEu9yTu4t460lTzzAMl2cM5zngQJqPMHbbnvYA==}
|
||||
dev: true
|
||||
|
||||
/@types/js-yaml/4.0.5:
|
||||
resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
|
||||
dev: true
|
||||
|
||||
/@types/json-buffer/3.0.0:
|
||||
resolution: {integrity: sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==}
|
||||
dev: false
|
||||
|
@ -3299,6 +3317,11 @@ packages:
|
|||
|
||||
/debug/2.6.9:
|
||||
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.0.0
|
||||
|
||||
|
@ -3826,7 +3849,7 @@ packages:
|
|||
dependencies:
|
||||
confusing-browser-globals: 1.0.11
|
||||
eslint: 8.15.0
|
||||
eslint-plugin-import: 2.26.0_eslint@8.15.0
|
||||
eslint-plugin-import: 2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy
|
||||
object.assign: 4.1.2
|
||||
object.entries: 1.1.5
|
||||
semver: 6.3.0
|
||||
|
@ -3841,7 +3864,7 @@ packages:
|
|||
dependencies:
|
||||
confusing-browser-globals: 1.0.11
|
||||
eslint: 8.12.0
|
||||
eslint-plugin-import: 2.26.0_eslint@8.12.0
|
||||
eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy
|
||||
object.assign: 4.1.2
|
||||
object.entries: 1.1.5
|
||||
semver: 6.3.0
|
||||
|
@ -3859,7 +3882,7 @@ packages:
|
|||
'@typescript-eslint/parser': 5.22.0_hcfsmds2fshutdssjqluwm76uu
|
||||
eslint: 8.15.0
|
||||
eslint-config-airbnb-base: 15.0.0_gwd37gqv3vjv3xlpl7ju3ag2qu
|
||||
eslint-plugin-import: 2.26.0_eslint@8.15.0
|
||||
eslint-plugin-import: 2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy
|
||||
dev: true
|
||||
|
||||
/eslint-config-airbnb-typescript/17.0.0_r46exuh3jlhq2wmrnqx2ufqspa:
|
||||
|
@ -3874,7 +3897,7 @@ packages:
|
|||
'@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede
|
||||
eslint: 8.12.0
|
||||
eslint-config-airbnb-base: 15.0.0_m4t3vvrby3btqwe437vnsnvyim
|
||||
eslint-plugin-import: 2.26.0_eslint@8.12.0
|
||||
eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy
|
||||
dev: true
|
||||
|
||||
/eslint-config-next/12.1.4_e6a2zi6fqdwfehht5cxvkmo3zu:
|
||||
|
@ -3893,13 +3916,14 @@ packages:
|
|||
eslint: 8.12.0
|
||||
eslint-import-resolver-node: 0.3.4
|
||||
eslint-import-resolver-typescript: 2.4.0_l3k33lf43msdtqtpwrwceacqke
|
||||
eslint-plugin-import: 2.25.2_eslint@8.12.0
|
||||
eslint-plugin-import: 2.25.2_svocbphju65ulgskrkawser2je
|
||||
eslint-plugin-jsx-a11y: 6.5.1_eslint@8.12.0
|
||||
eslint-plugin-react: 7.29.1_eslint@8.12.0
|
||||
eslint-plugin-react-hooks: 4.3.0_eslint@8.12.0
|
||||
next: 12.1.6_talmm3uuvp6ssixt2qevhfgvue
|
||||
typescript: 4.6.4
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
|
@ -3935,7 +3959,7 @@ packages:
|
|||
dependencies:
|
||||
debug: 4.3.4
|
||||
eslint: 8.12.0
|
||||
eslint-plugin-import: 2.25.2_eslint@8.12.0
|
||||
eslint-plugin-import: 2.25.2_svocbphju65ulgskrkawser2je
|
||||
glob: 7.2.0
|
||||
is-glob: 4.0.3
|
||||
resolve: 1.22.0
|
||||
|
@ -3944,27 +3968,69 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-module-utils/2.7.3:
|
||||
/eslint-module-utils/2.7.3_sysdrzuw2ki4kxpuwc4tznw2ha:
|
||||
resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
eslint-import-resolver-node: '*'
|
||||
eslint-import-resolver-typescript: '*'
|
||||
eslint-import-resolver-webpack: '*'
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
eslint-import-resolver-node:
|
||||
optional: true
|
||||
eslint-import-resolver-typescript:
|
||||
optional: true
|
||||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
find-up: 2.1.0
|
||||
'@typescript-eslint/parser': 5.10.1_uhoeudlwl7kc47h4kncsfowede
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-import-resolver-typescript: 2.4.0_l3k33lf43msdtqtpwrwceacqke
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-import/2.25.2_eslint@8.12.0:
|
||||
/eslint-module-utils/2.7.3_wex3ustmkv4ospy3s77r6ihlwq:
|
||||
resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
eslint-import-resolver-node: '*'
|
||||
eslint-import-resolver-typescript: '*'
|
||||
eslint-import-resolver-webpack: '*'
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
eslint-import-resolver-node:
|
||||
optional: true
|
||||
eslint-import-resolver-typescript:
|
||||
optional: true
|
||||
eslint-import-resolver-webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-import/2.25.2_svocbphju65ulgskrkawser2je:
|
||||
resolution: {integrity: sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.10.1_uhoeudlwl7kc47h4kncsfowede
|
||||
array-includes: 3.1.5
|
||||
array.prototype.flat: 1.3.0
|
||||
debug: 2.6.9
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.12.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-module-utils: 2.7.3
|
||||
eslint-module-utils: 2.7.3_sysdrzuw2ki4kxpuwc4tznw2ha
|
||||
has: 1.0.3
|
||||
is-core-module: 2.9.0
|
||||
is-glob: 4.0.3
|
||||
|
@ -3972,43 +4038,30 @@ packages:
|
|||
object.values: 1.1.5
|
||||
resolve: 1.22.0
|
||||
tsconfig-paths: 3.14.1
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-typescript
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-import/2.26.0_eslint@8.12.0:
|
||||
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
|
||||
dependencies:
|
||||
array-includes: 3.1.5
|
||||
array.prototype.flat: 1.3.0
|
||||
debug: 2.6.9
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.12.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-module-utils: 2.7.3
|
||||
has: 1.0.3
|
||||
is-core-module: 2.9.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 3.1.2
|
||||
object.values: 1.1.5
|
||||
resolve: 1.22.0
|
||||
tsconfig-paths: 3.14.1
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-import/2.26.0_eslint@8.15.0:
|
||||
/eslint-plugin-import/2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy:
|
||||
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.22.0_hcfsmds2fshutdssjqluwm76uu
|
||||
array-includes: 3.1.5
|
||||
array.prototype.flat: 1.3.0
|
||||
debug: 2.6.9
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.15.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-module-utils: 2.7.3
|
||||
eslint-module-utils: 2.7.3_wex3ustmkv4ospy3s77r6ihlwq
|
||||
has: 1.0.3
|
||||
is-core-module: 2.9.0
|
||||
is-glob: 4.0.3
|
||||
|
@ -4016,6 +4069,41 @@ packages:
|
|||
object.values: 1.1.5
|
||||
resolve: 1.22.0
|
||||
tsconfig-paths: 3.14.1
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-typescript
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-import/2.26.0_hhyjdrupy4c2vgtpytri6cjwoy:
|
||||
resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede
|
||||
array-includes: 3.1.5
|
||||
array.prototype.flat: 1.3.0
|
||||
debug: 2.6.9
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.12.0
|
||||
eslint-import-resolver-node: 0.3.6
|
||||
eslint-module-utils: 2.7.3_wex3ustmkv4ospy3s77r6ihlwq
|
||||
has: 1.0.3
|
||||
is-core-module: 2.9.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 3.1.2
|
||||
object.values: 1.1.5
|
||||
resolve: 1.22.0
|
||||
tsconfig-paths: 3.14.1
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-typescript
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-jsx-a11y/6.5.1_eslint@8.12.0:
|
||||
|
@ -4422,13 +4510,6 @@ packages:
|
|||
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
|
||||
dev: false
|
||||
|
||||
/find-up/2.1.0:
|
||||
resolution: {integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
locate-path: 2.0.0
|
||||
dev: true
|
||||
|
||||
/find-up/4.1.0:
|
||||
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -5226,6 +5307,34 @@ packages:
|
|||
- ts-node
|
||||
dev: true
|
||||
|
||||
/jest-cli/28.1.0_@types+node@17.0.31:
|
||||
resolution: {integrity: sha512-fDJRt6WPRriHrBsvvgb93OxgajHHsJbk4jZxiPqmZbMDRcHskfJBBfTyjFko0jjfprP544hOktdSi9HVgl4VUQ==}
|
||||
engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
|
||||
peerDependenciesMeta:
|
||||
node-notifier:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@jest/core': 28.1.0
|
||||
'@jest/test-result': 28.1.0
|
||||
'@jest/types': 28.1.0
|
||||
chalk: 4.1.2
|
||||
exit: 0.1.2
|
||||
graceful-fs: 4.2.10
|
||||
import-local: 3.1.0
|
||||
jest-config: 28.1.0_@types+node@17.0.31
|
||||
jest-util: 28.1.0
|
||||
jest-validate: 28.1.0
|
||||
prompts: 2.4.2
|
||||
yargs: 17.4.1
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: true
|
||||
|
||||
/jest-config/28.1.0:
|
||||
resolution: {integrity: sha512-aOV80E9LeWrmflp7hfZNn/zGA4QKv/xsn2w8QCBP0t0+YqObuCWTSgNbHJ0j9YsTuCO08ZR/wsvlxqqHX20iUA==}
|
||||
engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
|
||||
|
@ -5631,6 +5740,25 @@ packages:
|
|||
- ts-node
|
||||
dev: true
|
||||
|
||||
/jest/28.1.0_@types+node@17.0.31:
|
||||
resolution: {integrity: sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==}
|
||||
engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
|
||||
peerDependenciesMeta:
|
||||
node-notifier:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@jest/core': 28.1.0
|
||||
import-local: 3.1.0
|
||||
jest-cli: 28.1.0_@types+node@17.0.31
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- supports-color
|
||||
- ts-node
|
||||
dev: true
|
||||
|
||||
/js-cookie/3.0.1:
|
||||
resolution: {integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==}
|
||||
engines: {node: '>=12'}
|
||||
|
@ -5787,14 +5915,6 @@ packages:
|
|||
/lines-and-columns/1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
/locate-path/2.0.0:
|
||||
resolution: {integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
p-locate: 2.0.0
|
||||
path-exists: 3.0.0
|
||||
dev: true
|
||||
|
||||
/locate-path/5.0.0:
|
||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -6289,13 +6409,6 @@ packages:
|
|||
engines: {node: '>=8.0.0'}
|
||||
dev: false
|
||||
|
||||
/p-limit/1.3.0:
|
||||
resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
p-try: 1.0.0
|
||||
dev: true
|
||||
|
||||
/p-limit/2.3.0:
|
||||
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -6303,13 +6416,6 @@ packages:
|
|||
p-try: 2.2.0
|
||||
dev: true
|
||||
|
||||
/p-locate/2.0.0:
|
||||
resolution: {integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
p-limit: 1.3.0
|
||||
dev: true
|
||||
|
||||
/p-locate/4.1.0:
|
||||
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -6324,11 +6430,6 @@ packages:
|
|||
p-finally: 1.0.0
|
||||
dev: false
|
||||
|
||||
/p-try/1.0.0:
|
||||
resolution: {integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/p-try/2.2.0:
|
||||
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -6391,11 +6492,6 @@ packages:
|
|||
pause: 0.0.1
|
||||
dev: false
|
||||
|
||||
/path-exists/3.0.0:
|
||||
resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/path-exists/4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -7374,6 +7470,40 @@ packages:
|
|||
yargs-parser: 20.2.9
|
||||
dev: true
|
||||
|
||||
/ts-jest/28.0.2_z3fx76c5ksuwr36so7o5uc2kcy:
|
||||
resolution: {integrity: sha512-IOZMb3D0gx6IHO9ywPgiQxJ3Zl4ECylEFwoVpENB55aTn5sdO0Ptyx/7noNBxAaUff708RqQL4XBNxxOVjY0vQ==}
|
||||
engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@babel/core': '>=7.0.0-beta.0 <8'
|
||||
'@types/jest': ^27.0.0
|
||||
babel-jest: ^28.0.0
|
||||
esbuild: '*'
|
||||
jest: ^28.0.0
|
||||
typescript: '>=4.3'
|
||||
peerDependenciesMeta:
|
||||
'@babel/core':
|
||||
optional: true
|
||||
'@types/jest':
|
||||
optional: true
|
||||
babel-jest:
|
||||
optional: true
|
||||
esbuild:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/jest': 27.5.0
|
||||
bs-logger: 0.2.6
|
||||
fast-json-stable-stringify: 2.1.0
|
||||
jest: 28.1.0_@types+node@17.0.31
|
||||
jest-util: 28.1.0
|
||||
json5: 2.2.1
|
||||
lodash.memoize: 4.1.2
|
||||
make-error: 1.3.6
|
||||
semver: 7.3.7
|
||||
typescript: 4.6.4
|
||||
yargs-parser: 20.2.9
|
||||
dev: true
|
||||
|
||||
/tsconfig-paths/3.14.1:
|
||||
resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==}
|
||||
dependencies:
|
||||
|
|
|
@ -143,7 +143,8 @@ fi
|
|||
if [[ "$command" = "uninstall" ]]; then
|
||||
echo "Removing images for app ${app}..."
|
||||
|
||||
# compose "${app}" down --remove-orphans
|
||||
compose "${app}" up --detach
|
||||
compose "${app}" down --rmi all --remove-orphans
|
||||
|
||||
echo "Deleting app data for app ${app}..."
|
||||
if [[ -d "${app_data_dir}" ]]; then
|
||||
|
@ -158,7 +159,6 @@ fi
|
|||
if [[ "$command" = "stop" ]]; then
|
||||
|
||||
echo "Stopping app ${app}..."
|
||||
compose "${app}" down --remove-orphans --rmi all
|
||||
compose "${app}" rm --force --stop
|
||||
|
||||
exit
|
||||
|
|
|
@ -14,39 +14,10 @@ echo "=============== TIPI ================="
|
|||
echo "======================================"
|
||||
echo
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y jq coreutils ca-certificates curl gnupg lsb-release
|
||||
|
||||
LSB="$(lsb_release -is)"
|
||||
|
||||
# Add docker gpg key (Debian)
|
||||
if [[ "${LSB}" == "Debian" ]]; then
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||
fi
|
||||
|
||||
# Add docker gpg key (Ubuntu)
|
||||
if [[ "${LSB}" == "Ubuntu" ]]; then
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||
fi
|
||||
|
||||
# Add deb repo for docker (Debian)
|
||||
if [[ "${LSB}" == "Debian" ]]; then
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
|
||||
fi
|
||||
|
||||
# Add deb repo for docker (Ubuntu)
|
||||
if [[ "${LSB}" == "Ubuntu" ]]; then
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
|
||||
fi
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||
|
||||
# Install docker compose if not here
|
||||
if ! command -v docker-compose >/dev/null; then
|
||||
sudo curl -L "https://github.com/docker/compose/releases/download/v2.3.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
fi
|
||||
sudo wget -O "${ROOT_FOLDER}"/scripts/pacapt https://github.com/icy/pacapt/raw/ng/pacapt
|
||||
sudo chmod 755 "${ROOT_FOLDER}"/scripts/pacapt
|
||||
sudo "${ROOT_FOLDER}"/scripts/pacapt -Sy
|
||||
sudo "${ROOT_FOLDER}"/scripts/pacapt -S docker docker-ce docker-compose containerd.io jq coreutils curl -y
|
||||
|
||||
# Create configured status
|
||||
touch "${ROOT_FOLDER}/state/configured"
|
||||
|
|
|
@ -98,8 +98,6 @@ function derive_entropy() {
|
|||
printf "%s" "${identifier}" | openssl dgst -sha256 -hmac "${tipi_seed}" | sed 's/^.* //'
|
||||
}
|
||||
|
||||
PUID="$(id -u)"
|
||||
PGID="$(id -g)"
|
||||
TZ="$(cat /etc/timezone | sed 's/\//\\\//g' || echo "Europe/Berlin")"
|
||||
|
||||
# Copy the app state if it isn't here
|
||||
|
@ -120,11 +118,6 @@ fi
|
|||
# Get dns ip if pihole is installed
|
||||
str=$(get_json_field ${STATE_FOLDER}/apps.json installed)
|
||||
|
||||
# if pihole is present in str add it as DNS
|
||||
if [[ $str = *"pihole"* ]]; then
|
||||
DNS_IP=10.21.21.201
|
||||
fi
|
||||
|
||||
# Create seed file with cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
|
||||
if [[ ! -f "${STATE_FOLDER}/seed" ]]; then
|
||||
echo "Generating seed..."
|
||||
|
@ -150,8 +143,6 @@ JWT_SECRET=$(derive_entropy "jwt")
|
|||
for template in "${ENV_FILE}"; do
|
||||
sed -i "s/<dns_ip>/${DNS_IP}/g" "${template}"
|
||||
sed -i "s/<internal_ip>/${INTERNAL_IP}/g" "${template}"
|
||||
sed -i "s/<puid>/${PUID}/g" "${template}"
|
||||
sed -i "s/<pgid>/${PGID}/g" "${template}"
|
||||
sed -i "s/<tz>/${TZ}/g" "${template}"
|
||||
sed -i "s/<jwt_secret>/${JWT_SECRET}/g" "${template}"
|
||||
sed -i "s/<root_folder>/${SED_ROOT_FOLDER}/g" "${template}"
|
||||
|
@ -167,6 +158,9 @@ mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
|
|||
echo "Running system-info.sh..."
|
||||
bash "${ROOT_FOLDER}/scripts/system-info.sh"
|
||||
|
||||
# Add crontab to run system-info.sh every minute
|
||||
! (crontab -l | grep -q "${ROOT_FOLDER}/scripts/system-info.sh") && (crontab -l; echo "* * * * * ${ROOT_FOLDER}/scripts/system-info.sh") | crontab -
|
||||
|
||||
## Don't run if config-only
|
||||
if [[ ! $ci == "true" ]]; then
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
# It will be overwritten on update.
|
||||
|
||||
TZ=<tz>
|
||||
PUID=<puid>
|
||||
PGID=<pgid>
|
||||
INTERNAL_IP=<internal_ip>
|
||||
DNS_IP=<dns_ip>
|
||||
ARCHITECTURE=<architecture>
|
||||
|
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": false,
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
},
|
||||
"include": ["apps/**/*.ts"]
|
||||
}
|
Loading…
Add table
Reference in a new issue