Compare commits

..
38 Commits
Author SHA1 Message Date
Mike Wilson 1f2dbc2563 Add audiobookshelf 2026-10-06 14:24:06 -04:00
Mike Wilson 45ce33d64e Initial Gitea Runner implementation 2026-09-29 16:20:50 -04:00
Mike Wilson 42a276b5d4 Try lidarr + beets side by side https://wiki.servarr.com/lidarr/beets-integration 2026-08-28 12:25:42 -04:00
Mike Wilson fd55cef154 Replace tautulli with tracearr since it supports Jellyfin 2026-08-14 15:28:19 -04:00
Mike Wilson 99db93ee1d Switch traefik image to latest and add file providers for lubelogger and redlib 2026-08-14 15:05:26 -04:00
Mike Wilson b14930cb19 Revamp searxng config, implementing use_default_settings option and adding hostname plugin config 2026-08-12 11:39:16 -04:00
Mike Wilson 431da5cc03 Move recyclarr to version 8 2026-08-12 10:05:15 -04:00
Mike Wilson 9db9875ddc Increment qbittorrent version to 5.2.3 (latest currently supported by qbitmanage) 2026-08-12 10:03:36 -04:00
Mike Wilson 57053e2ff0 Specify more qualities in Sonarr WEB profiles 2026-08-11 09:30:13 -04:00
Mike Wilson e981a2c122 Add encode profile for radarr 2026-08-11 09:26:22 -04:00
Mike Wilson 6165e4f88d Add Zenith tracker to cross-seed 2026-06-17 09:52:59 -04:00
Mike Wilson 254f04ccd5 Migrate from jellyseerr to seerr 2026-06-17 09:51:42 -04:00
Mike Wilson 568e2240bf Clean up containers that are no longer users 2026-02-13 09:58:13 -05:00
Mike Wilson 26ecfcf0cb Add game-thumbs container 2026-02-13 09:57:29 -05:00
Mike Wilson 80c503ce6a Add Encode profile for Sonarr 2026-02-13 09:56:58 -05:00
Mike Wilson 05968f95ee Regenerated wireguard config for gluetun 2026-02-13 09:55:58 -05:00
Mike Wilson 9c6df53765 Add traefik file providers for Immich and qui 2026-01-30 18:51:03 -05:00
Mike Wilson 464a46d82e Set cross-seed and qbitmanage to proxy through qui 2026-01-27 18:01:19 -05:00
Mike Wilson 5e4ae4c0ea Update qbittorrent from 5.1.2 to 5.1.4 2026-01-27 17:55:35 -05:00
Mike Wilson a210e25bd9 Add OldToons.World 2026-01-21 16:29:50 -05:00
Mike Wilson cf0ec35288 Traefik updates, including adding definition for Proxmox Backup Server 2026-01-15 12:45:22 -05:00
Mike Wilson 32498ea646 Disable automatic language detection for searches in searxng 2026-01-06 15:30:13 -05:00
Mike Wilson 478885a3cd Switch cross-seed from hardlinks to reflinks for less chance of data corruption 2026-01-06 12:21:37 -05:00
Mike Wilson 4741e56d66 Qbittorrent and qbitmanage updates 2026-01-05 13:16:05 -05:00
Mike Wilson 9146d65be3 Move Teamarr to a dedicated compose directory/file 2025-12-23 12:54:29 -05:00
Mike Wilson 8ce0aecb4e Add Teamarr to dispatcharr compose 2025-12-23 12:27:28 -05:00
Mike Wilson e4d15fde79 Add dispatcharr 2025-12-21 21:01:12 -05:00
Mike Wilson 37202f955f Remove custom formats for audio, since they often end up deranking releases such as Cinephiles even though that's the best release 2025-12-18 10:00:16 -05:00
Mike Wilson 705e5c3e55 Update name of qbitmanage config variable 2025-12-15 12:45:07 -05:00
Mike Wilson 074c075620 Update minimum seeding time for noHL torrents to 28 days, remove unpackerr, and increment qbittorrent version to 5.1.4 (latest supported by qbitmanage) 2025-12-14 10:37:08 -05:00
Mike Wilson 6eb043c1af Block Anime DV releases (such as Chainsaw Man movie) with no HDR fallback in radarr 2025-12-13 16:38:24 -05:00
Mike Wilson e994a98016 Add Anthelion to qbitmanage and cross-seed configs 2025-12-02 15:02:06 -05:00
Mike Wilson c85576a56a Update beets config 2025-12-02 15:01:25 -05:00
Mike Wilson 886bc6aa71 README updates 2025-11-04 16:12:28 -05:00
Mike Wilson 45951ba93f Do not restart qbittorrent when updating cross-seed and qbitmanage configs 2025-10-13 09:50:19 -04:00
Mike Wilson 364e1a9628 Allow releases with no rlsgroup in the 'Old' profiles 2025-10-09 15:40:37 -04:00
Mike Wilson 47000fc6f3 Set speed limits on torrents from high bandwidth trackers (TL, FL, AR) 2025-10-08 16:47:53 -04:00
mike dda45245f5 Add AnimeBytes 2025-09-13 14:00:07 -04:00
118 changed files with 910 additions and 9033 deletions

No files matched your search

+3 -2
View File
@@ -23,12 +23,13 @@ Having Plex and Jellyfin separate from the rest of my docker infrastructure allo
**Storage:** **Storage:**
* `/`: 1 TB NVME SSD * `/`: 1 TB NVME SSD
* `/vm_storage`: 2x 240 GB SSD in ZFS mirror for config and data files * `/vm_storage`: 2x 240 GB SSD in ZFS mirror for config and data files
* `/mnt/storage`: mergerfs + SnapRAID pool totaling ~90 TiB usable storage. Currently single parity disk but hoping to add a second one soon. Drives run btrfs allowing me to utilize [snapraid-btrfs](https://wiki.selfhosted.show/tools/snapraid-btrfs/) for instant snapshotting * `/mnt/storage`: mergerfs + SnapRAID pool totaling 150 TiB usable storage with single disk parity (YOLO). Drives run btrfs allowing me to utilize [snapraid-btrfs](https://wiki.selfhosted.show/tools/snapraid-btrfs/) for instant snapshotting
## Roadmap ## Roadmap
* Flesh out backup strategy with btrfs snapshots and restic (separately) * Flesh out backup strategy with btrfs snapshots and restic (separately)
* Move everything to Arch VMs on Proxmox * Potentially migrate media pool to ZFS. I've been lucky so far with no drive failures but realistically if I did have one fail, it would take ages to rebuild with single disk parity and I'd be wishing I had a more robust setup.
* Move everything to Arch LXCs on Proxmox
* Possibly set up second Proxmox node for backups * Possibly set up second Proxmox node for backups
* Immich for photo management * Immich for photo management
* Look into [Wazuh](https://github.com/wazuh/wazuh) for threat prevention/detection * Look into [Wazuh](https://github.com/wazuh/wazuh) for threat prevention/detection
+1 -1
View File
@@ -1,3 +1,3 @@
- hosts: pve-docker - hosts: pve-docker
roles: roles:
- qbittorrent - gitea
@@ -1,5 +1,5 @@
- name: Create service user - name: Create service user
user: ansible.builtin.user:
name: "{{ role_name }}" name: "{{ role_name }}"
system: true system: true
register: service_user register: service_user
@@ -13,6 +13,15 @@
mode: "{{ docker_compose_directory_mask }}" mode: "{{ docker_compose_directory_mask }}"
become: true become: true
- name: Create config directory
file:
path: "{{ data_dir }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
group: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination - name: Copy docker-compose file to destination
template: template:
src: docker-compose.yml src: docker-compose.yml
@@ -22,16 +31,6 @@
validate: docker compose -f %s config validate: docker compose -f %s config
become: true become: true
- name: Install script files
ansible.builtin.copy:
src: "{{ item }}"
dest: "{{ data_dir }}/tautulli/scripts"
mode: "{{ docker_compose_file_mask }}"
owner: "{{ primary_user }}"
with_fileglob:
- "files/*"
become: true
- name: Start docker container - name: Start docker container
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}" project_src: "{{ install_directory }}/{{ role_name }}"
@@ -0,0 +1,21 @@
networks:
traefik:
external: true
services:
{{ role_name }}:
container_name: "{{ role_name }}"
image: ghcr.io/advplyr/audiobookshelf:latest
restart: unless-stopped
networks:
- traefik
environment:
- "TZ={{ timezone }}"
volumes:
- "{{ data_dir }}/{{ role_name }}/config:/config"
- "{{ data_dir }}/{{ role_name }}/metadata:/metadata"
- "{{ media_storage_mnt }}/data/media/books:/books:ro"
labels:
traefik.enable: true
traefik.http.routers.{{ role_name }}.rule: "Host(`audiobooks.{{ personal_domain }}`)"
#traefik.http.services.{{ role_name }}.loadbalancer.server.port: 13378
@@ -1,5 +0,0 @@
- name: restart searxng
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
restarted: true
-30
View File
@@ -1,30 +0,0 @@
- name: Create install directory
file:
path: "{{ install_directory }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination
template:
src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
validate: docker compose -f %s config
become: true
- name: Copy settings file to destionation
template:
src: settings.yml
dest: "{{ data_dir }}/{{ role_name }}/settings.yml"
owner: "{{ docker_user }}"
become: true
notify: restart searxng
- name: Start docker container
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
pull: always
remove_orphans: yes
@@ -1,37 +0,0 @@
networks:
traefik:
external: true
services:
searxng:
container_name: searxng
image: searxng/searxng
restart: unless-stopped
networks:
- traefik
volumes:
- "{{ data_dir }}/{{ role_name }}:/etc/searxng"
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
labels:
traefik.enable: true
traefik.http.routers.searxng.rule: "Host(`search.{{ personal_domain }}`)"
traefik.http.routers.searxng.middlewares: lan-whitelist@file
redis:
image: redis:alpine
restart: unless-stopped
command: redis-server --save "" --appendonly "no"
tmpfs:
- /var/lib/redis
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
- DAC_OVERRIDE
File diff suppressed because it is too large. Load diff
-10
View File
@@ -1,10 +0,0 @@
searxng_secret_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
33656138666464373665663339363665346566613637626131363335336535313131333265646539
3037373439643964343139383764386364623961383737610a313063613736316437366239663238
65333735633661316463336665353138623264396534383865363134613165636164303765356265
3865626366613966660a313738353339313133393765643136306361373061366132373130656531
61396230346333346636356562353733623332333662653164373630626339376433353663313862
61303230613135336662313531313836363466623162666233646231616333643536303233616231
62353866333465646162633738383866363338383932623335353038393130323932343363653233
62663465386661663262
@@ -1,22 +0,0 @@
server {
listen 3000 default_server;
listen [::]:3000 default_server;
server_name _;
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
client_max_body_size 100M;
location /bar/ {
proxy_pass http://bar-assistant:3000/;
}
location /search/ {
proxy_pass http://meilisearch:7700/;
}
location / {
proxy_pass http://salt-rim:8080/;
}
}
-44
View File
@@ -1,44 +0,0 @@
- name: Create service user
user:
name: "{{ role_name }}"
system: true
register: service_user
become: true
- name: Create install directory
file:
path: "{{ install_directory }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Create data directory
file:
path: "{{ data_dir }}/barassistant/barassistant"
state: directory
owner: 33
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination
template:
src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
validate: docker compose -f %s config
become: true
- name: Copy nginx.conf to destination
copy:
src: nginx.conf
dest: "{{ install_directory }}/{{ role_name }}/nginx.conf"
mode: "{{ docker_compose_file_mask }}"
become: true
- name: Start docker container
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
pull: always
remove_orphans: yes
@@ -1,71 +0,0 @@
networks:
traefik:
external: true
services:
meilisearch:
image: getmeili/meilisearch:v1.12
restart: unless-stopped
networks:
- default
environment:
MEILI_MASTER_KEY: "{{ meili_master_key }}"
MEILI_ENV: production
volumes:
- "{{ data_dir }}/barassistant/meilisearch:/meili_data"
redis:
image: redis
restart: unless-stopped
networks:
- default
environment:
ALLOW_EMPTY_PASSWORD: "True"
bar-assistant:
container_name: bar-assistant
image: barassistant/server:v5
restart: unless-stopped
networks:
- default
depends_on:
- meilisearch
- redis
environment:
APP_URL: "{{ base_url }}/bar"
LOG_CHANNEL: stderr
MEILISEARCH_KEY: "{{ meili_master_key }}"
MEILISEARCH_HOST: http://meilisearch:7700
REDIS_HOST: redis
ALLOW_REGISTRATION: "True"
volumes:
- "{{ data_dir }}/barassistant/barassistant:/var/www/cocktails/storage/bar-assistant"
salt-rim:
image: barassistant/salt-rim:v4
restart: unless-stopped
networks:
- default
depends_on:
- bar-assistant
environment:
API_URL: "{{ base_url }}/bar"
MEILISEARCH_URL: "{{ base_url }}/search"
BAR_NAME: "Cocktails"
DESCRIPTION: Why is the rum always gone?
DEFAULT_LOCALE: "en-US"
webserver:
image: nginx:alpine
restart: unless-stopped
networks:
- traefik
- default
volumes:
- "./nginx.conf:/etc/nginx/conf.d/default.conf"
labels:
traefik.enable: true
traefik.http.routers.barassistant.rule: "Host(`cocktails.{{ personal_domain }}`)"
traefik.http.services.barassistant.loadbalancer.server.port: 3000
traefik.http.routers.bariassistant.middlewares: lan-whitelist@file
-15
View File
@@ -1,15 +0,0 @@
meili_master_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
61306335316339383330323264646132363837376264646235353562666239386463613431366361
3333666463623564393061616339393164353465633866320a303530613862386466383161623532
61653861653032303232666530623739303231363536316530386566313466333236613331303833
3734656334333366650a366261323139363635316264383966626237396338663030393931313532
33343737316535336539363135333834333462393330663038376132393661323866656132356566
39653732366333306134393965383339336330326566303230613362393366383561303939363937
64396230323664393236303939643337393034646637643766323938663961636639326466653332
30343132636534613835646163643832373835663030326635323236386361346133633964303137
36623631353931343861383232373231613837393936316635393838323466656330653835343932
64333432386133313363626630623837643237616132336664303963323062386365623266623333
343233663635306361333065313334313361
base_url: "https://cocktails.{{ personal_domain }}"
+25 -7
View File
@@ -1,7 +1,7 @@
directory: /music directory: /music
per_disc_numbering: yes per_disc_numbering: yes
plugins: fetchart web inline lyrics plugins: fetchart embedart web inline lyrics musicbrainz scrub lastgenre replaygain
paths: paths:
default: $albumartist/$album%aunique{}/%if{$multidisc,$disc}$track - $title default: $albumartist/$album%aunique{}/%if{$multidisc,$disc}$track - $title
@@ -12,13 +12,11 @@ item_fields:
import: import:
write: yes write: yes
hardlink: yes move: no
resume: ask quiet: yes
incremental: yes
quiet_fallback: skip
timid: no timid: no
log: /config/beet.log
languages: "en jp es" languages: "en jp es"
autotag: yes
asciify_paths: yes asciify_paths: yes
@@ -28,13 +26,33 @@ embedart:
fetchart: fetchart:
auto: yes auto: yes
high_resolution: yes high_resolution: yes
source:
- filesystem
- itunes
- coverart
- amazon
match:
strong_rec_thresh: 0.10
ignored_media: ['12" Vinyl']
lyrics: lyrics:
sources: [lrclib, genius] auto: yes
sources: [lrcmux]
scrub: scrub:
auto: yes auto: yes
replaygain:
auto: yes
backend: ffmpeg
# Consider directory empty even if files matching the below patterns are present
clutter:
- "*.jpg"
- "*.png"
- "*.nfo"
replace: replace:
'^\.': _ '^\.': _
'[\x00-\x1f]': _ '[\x00-\x1f]': _
-11
View File
@@ -1,11 +0,0 @@
- name: Install bitcoin daemon
ansible.builtin.package:
name: bitcoin-daemon
state: present
become: true
- name: Enable bitcoind
ansible.builtin.service:
name: bitcoind
state: started
enabled: yes
-6
View File
@@ -1,6 +0,0 @@
- name: Install tor
ansible.builtin.package:
name: tor
state: present
-32
View File
@@ -1,32 +0,0 @@
- name: Install Uncomplicated Firewall
ansible.builtin.package:
name: ufw
state: present
# UFW logging can full up the kernel (dmesg) and message logs
- name: Disable logging
community.general.ufw:
logging: 'off'
- name: Allow OpenSSH inbound
community.general.ufw:
rule: allow
name: OpenSSH # Uses standard profile located in /etc/ufw/applications.d
- name: Apply rate limiting to ssh inbound
community.general.ufw:
rule: limit
port: ssh
proto: tcp
- name: Enable ufw system service
ansible.builtin.service:
name: ufw
state: started
enabled: yes
# This is necessary in addition to enabling the system service
- name: Enable ufw rules
community.general.ufw:
state: enabled
policy: deny
-31
View File
@@ -1,31 +0,0 @@
- name: Create service user
user:
name: "{{ role_name }}"
groups: "{{ media_group }}"
append: yes
system: true
register: service_user
become: true
- name: Create install directory
file:
path: "{{ install_directory }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination
template:
src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
validate: docker compose -f %s config
become: true
- name: Start docker container
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
pull: always
remove_orphans: yes
@@ -1,25 +0,0 @@
networks:
traefik:
external: true
services:
{{ role_name }}:
container_name: "{{ role_name }}"
image: registry.gitlab.com/bockiii/deemix-docker
restart: unless-stopped
networks:
- traefik
environment:
- "PUID={{ service_user.uid }}"
- "PGID={{ media_gid }}"
- "TZ={{ timezone }}"
- "UMASK_SET=002"
- "DEEMIX_SINGLE_USER=true"
volumes:
- "{{ data_dir }}/{{ role_name }}:/config"
- "{{ media_storage_mnt }}/data/import/music/deemix:/downloads"
labels:
traefik.enable: true
traefik.http.routers.{{ role_name }}.rule: "Host(`{{ role_name }}.local.{{ personal_domain }}`)"
traefik.http.routers.{{ role_name }}.middlewares: lan-whitelist@file
@@ -1,5 +1,5 @@
- name: Create install directory - name: Create install directory
file: ansible.builtin.file:
path: "{{ install_directory }}/{{ role_name }}" path: "{{ install_directory }}/{{ role_name }}"
state: directory state: directory
owner: "{{ docker_user }}" owner: "{{ docker_user }}"
@@ -7,7 +7,7 @@
become: true become: true
- name: Copy docker-compose file to destination - name: Copy docker-compose file to destination
template: ansible.builtin.template:
src: docker-compose.yml src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml" dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}" owner: "{{ docker_user }}"
@@ -0,0 +1,24 @@
networks:
traefik:
external: true
services:
dispatcharr:
container_name: "{{ role_name }}"
image: ghcr.io/dispatcharr/dispatcharr:latest
restart: unless-stopped
network_mode: "container:gluetun"
environment:
- DISPATCHARR_ENV=aio
- REDIS_HOST=localhost
- CELERY_BROKER_URL=redis://localhost:6379/0
- DISPATCHARR_LOG_LEVEL=info
volumes:
- "{{ data_dir }}/{{ role_name }}:/data"
devices:
- /dev/dri/renderD128:/dev/dri/renderD128
labels:
traefik.enable: true
traefik.http.routers.dispatcharr.rule: "Host(`dispatcharr.local.{{ personal_domain }}`)"
traefik.http.routers.dispatcharr.middlewares: lan-whitelist@file
traefik.http.services.dispatcharr.loadbalancer.server.port: 9191
@@ -1,65 +0,0 @@
networks:
firefly_iii:
driver: bridge
traefik:
external: true
services:
app:
image: fireflyiii/core:latest
container_name: firefly_iii_core
restart: unless-stopped
volumes:
- "{{ data_dir }}/firefly3/upload:/var/www/html/storage/upload"
depends_on:
- db
networks:
- traefik
- default
environment:
APP_ENV: local
APP_DEBUG: "false"
APP_KEY: "{{ app_key }}"
SITE_OWNER: {{ owner_email_address }}
DEFAULT_LANGUAGE: "en_US"
DEFAULT_LOCALE: equal
TZ: {{ timezone }}
TRUSTED_PROXIES: "*"
APP_LOG_LEVEL: notice
AUDIT_LOG_LEVEL: info
DB_CONNECTION: mysql
DB_HOST: db
DB_PORT: 3306
DB_DATABASE: firefly
DB_USERNAME: firefly
DB_PASSWORD: firefly
APP_URL: "https://firefly.local.{{ personal_domain }}"
STATIC_CRON_TOKEN: "Y5uNSbJoK4FKUC9gVE5hq8YFEbFmc6BK"
labels:
traefik.enable: true
traefik.http.routers.firefly.rule: "Host(`firefly.local.{{ personal_domain }}`)"
traefik.http.routers.firefly.middlewares: lan-whitelist@file
db:
image: mariadb
restart: always
volumes:
- "{{ data_dir }}/mariadb/firefly3:/var/lib/mysql"
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_USER: firefly
MYSQL_PASSWORD: firefly
MYSQL_DATABASE: firefly
cron:
#
# To make this work, set STATIC_CRON_TOKEN in your .env file or as an environment variable and replace REPLACEME below
# The STATIC_CRON_TOKEN must be *exactly* 32 characters long
#
image: alpine
restart: always
container_name: firefly_iii_cron
command: sh -c "echo \"0 3 * * * wget -qO- https://firefly.local.{{ personal_domain }}/api/v1/cron/Y5uNSbJoK4FKUC9gVE5hq8YFEbFmc6BK\" | crontab - && crond -f -L /dev/stdout"
networks:
- firefly_iii
- default
-17
View File
@@ -1,17 +0,0 @@
owner_email_address: !vault |
$ANSIBLE_VAULT;1.1;AES256
61373861363433363938396137653461363830323539316438323861326437663364383032363064
6438303462336466373233663366303263313139333830330a623465633166653530633961643162
65303032386661393063393134643436653737666163373833383036316234393563313536353036
3839663034393730340a626361646463636137636535653632343064353461656532656236633865
66636634323434356436313737336635363832333262383331333034313530663463
app_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
31333563616230396135363562313038346138633631613832646463343666643733333366303561
3461316337303862616662333031306231613532383534340a643236306232383466333531626466
33313830646365333935313237663134343033396166623730303030636438656435313462633762
3134643738616365330a636366343736306539666565663866626537303431366633646638663563
32616439336338393663373466323630323733393031633564383737383465313434313230323038
6534636266653166633539326632623165663436323936643031
@@ -1,12 +1,5 @@
- name: Create service user
user:
name: "{{ role_name }}"
system: true
register: service_user
become: true
- name: Create install directory - name: Create install directory
file: ansible.builtin.file:
path: "{{ install_directory }}/{{ role_name }}" path: "{{ install_directory }}/{{ role_name }}"
state: directory state: directory
owner: "{{ docker_user }}" owner: "{{ docker_user }}"
@@ -14,7 +7,7 @@
become: true become: true
- name: Copy docker-compose file to destination - name: Copy docker-compose file to destination
template: ansible.builtin.template:
src: docker-compose.yml src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml" dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}" owner: "{{ docker_user }}"
@@ -0,0 +1,31 @@
services:
game-thumbs:
image: ghcr.io/sethwv/game-thumbs:latest
container_name: game-thumbs
restart: unless-stopped
labels:
- "autoheal=true"
ports:
- 3050:3050
environment:
PORT: 3050
NODE_ENV: ${NODE_ENV:-production}
SHOW_TIMESTAMP: ${SHOW_TIMESTAMP:-true}
LOG_TO_FILE: ${LOG_TO_FILE:-false}
MAX_LOG_FILES: ${MAX_LOG_FILES:-10}
volumes:
- "{{ data_dir }}/game-thumbs/cache:/app/.cache
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3050/health', (r) => {let d='';r.on('data', (c) => d+=c);r.on('end', () => {if (r.statusCode !== 200) process.exit(1);const j=JSON.parse(d);process.exit(j.status==='ok'?0:1)})}).on('error', () => process.exit(1))"]
interval: 30s
timeout: 5s
start_period: 10s
retries: 3
autoheal:
image: willfarrell/autoheal:latest
container_name: autoheal
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
AUTOHEAL_CONTAINER_LABEL: "autoheal"
+2
View File
@@ -45,6 +45,8 @@
loop: loop:
- data - data
- config - config
- runner/data
- runner/config
become: true become: true
- name: Install configuration file - name: Install configuration file
+302
View File
@@ -0,0 +1,302 @@
# Every option with its default value, all commented out. Read this file, do not copy it.
# `./gitea-runner config init` writes a config file to copy the lines you change into.
# Logging for the runner process itself (messages printed to stderr), plus the copy of
# each task's log kept under log.job. Neither controls how workflow step output is streamed
# to the Gitea UI; tune that with runner.log_report_* below.
log:
# logrus severity: trace, debug, info, warn, error, fatal, panic.
# trace and debug turn on caller/file:line in log lines. Default if omitted: info.
#level: info
# Write a copy of each task's log to dir as <start time>-task-<id>.log, so a job's output
# survives a failure to send it to Gitea. A path turns them on, empty turns them off.
# retention is how long a log is kept (0s keeps all), max_size caps one log (0 is no limit).
#job:
# dir: ""
# retention: 168h
# max_size: 1GB
runner:
# Where to store the registration result.
#file: .runner
# Execute how many tasks concurrently at the same time.
# With `container.network` empty, each concurrent docker job takes a subnet from the
# daemon's address pool, so a high capacity can exhaust it. See `default-address-pools`
# in the docker daemon config.
#capacity: 1
# Extra environment variables to run jobs.
#envs:
# A_TEST_ENV_NAME_1: a_test_env_value_1
# A_TEST_ENV_NAME_2: a_test_env_value_2
# Extra environment variables to run jobs from a file.
# It will be ignored if it's empty or the file doesn't exist.
#env_file: .env
# The timeout for a job to be finished.
# Please note that the Gitea instance also has a timeout (3h by default) for the job.
# So the job could be stopped by the Gitea instance if its timeout is shorter than this.
#timeout: 3h
# The timeout for the runner to wait for running jobs to finish when shutting down.
# Any running jobs that haven't finished after this timeout will be cancelled.
#shutdown_timeout: 0s
# Whether skip verifying the TLS certificate of the Gitea instance.
#insecure: false
# The timeout for fetching the job from the Gitea instance.
# Values above the 60s RPC timeout are capped to it.
#fetch_timeout: 5s
# The interval for fetching the job from the Gitea instance.
#fetch_interval: 2s
# The maximum interval for fetching the job from the Gitea instance.
# The runner uses exponential backoff when idle, increasing the interval up to this maximum.
# Set to 0 or same as fetch_interval to disable backoff.
#fetch_interval_max: 5s
# While idle, remove stale bind-workdir task directories and orphaned host-mode
# scratch directories (left behind when a host cleanup delete stalls) older than
# this duration. Setting either workdir_cleanup_age or idle_cleanup_interval to 0
# (or any non-positive value) disables stale-directory cleanup entirely, along with
# the docker network and volume cleanup below.
#workdir_cleanup_age: 24h
# Cadence for the idle cleanup pass. Besides the directories above, on runners that use
# docker it removes the per-job networks and volumes of jobs this runner did not live to
# tear down, which would otherwise hold a subnet of the daemon address pool and the job's
# workspace contents until the host is rebuilt.
#idle_cleanup_interval: 10m
# The base interval for periodic log flush to the Gitea instance.
# Logs may be sent earlier if the buffer reaches log_report_batch_size
# or if log_report_max_latency expires after the first buffered row.
#log_report_interval: 5s
# The maximum time a log row can wait before being sent.
# This ensures even a single log line appears on the frontend within this duration.
# Must be less than log_report_interval to have any effect.
#log_report_max_latency: 3s
# Flush logs immediately when the buffer reaches this many rows.
# This ensures bursty output (e.g., npm install) is delivered promptly.
#log_report_batch_size: 100
# The interval for reporting task state (step status, timing) to the Gitea instance.
# State is also reported on step transitions (start/stop) and after each log flush.
#state_report_interval: 5s
# Per-attempt deadline for flushing the final logs and task state when a job
# finishes, on a detached context so a server cancel can't block the acknowledgement.
#report_close_timeout: 10s
# The github_mirror of a runner is used to specify the mirror address of the github that pulls the action repository.
# It works when something like `uses: actions/checkout@v4` is used and DEFAULT_ACTIONS_URL is set to github,
# and github_mirror is not empty. In this case,
# it replaces https://github.com with the value here, which is useful for some special network environments.
#github_mirror: ''
# When true (the default), fetch only the requested ref of an action repository (e.g. actions/checkout@v4) at depth 1 instead of cloning every branch's full history.
# Set to false to clone the full history.
#action_shallow_clone: true
# When true (the default), inject the ACT=true environment variable into jobs.
# Set to false so workflows gated on `if: ${{ !env.ACT }}` behave like they do on GitHub.
#set_act_env: true
# When true (the default), apply compatibility patches to the actions a job runs, so actions
# written for GitHub work against this instance. Set to false to run them exactly as published,
# at the price of the stock artifact actions refusing and the cache client keeping to v1.
#patch_actions: true
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
# Like: "macos-arm64:host" or "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
# Find more images provided by Gitea at https://gitea.com/gitea/runner-images .
# If it's empty when registering, it will ask for inputting labels.
# If it's empty when execute `daemon`, will use labels in `.runner` file.
#labels:
# - "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
# - "ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04"
# - "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
# Allocate a pseudo-TTY for each step's process. Applies to both host and docker backends.
# Default false matches GitHub actions/runner. Enable only for jobs that need an interactive
# terminal; tools like `docker build` emit redrawing progress frames into the captured log
# when a TTY is present.
#allocate_pty: false
# Image for a job whose runs-on matches none of the labels above. A runner without a
# docker daemon runs such a job on the host instead.
#default_image: "docker.gitea.com/runner-images:ubuntu-latest"
# What to mount at RUNNER_TOOL_CACHE (/opt/hostedtoolcache), where setup actions install tools:
# none: nothing. A docker job sees what its image ships there, a host job an empty dir, and
# either way what it installs is gone when the job ends.
# shared: one tool cache every job reuses. Two jobs writing the same tool version at once
# corrupt it, so use it only with capacity 1.
#tool_cache_mode: none
# Optional executable on the host, run once after each task's built-in cleanup
# (post-steps, container teardown, bind-workdir removal). Additive only.
#
# IMPORTANT: While this script runs the runner stops task heartbeats and stays
# offline from Gitea's perspective until the script exits. A script that never
# returns blocks new work until post_task_script_timeout kills it (default 5m).
# Keep scripts short; set post_task_script_timeout to a safe upper bound.
#
# Output -> runner process log (not the job log). Non-zero exit -> warning only.
# Windows: use .exe, .bat, or .cmd. PowerShell (.ps1) is not supported yet as
# the configured path; wrap PowerShell commands in a .cmd file instead.
# Full guide: docs/post-task-script.md
#post_task_script: ''
# Hard limit on post_task_script runtime. Default if omitted: 5m.
#post_task_script_timeout: 5m
# Scripts run inside the job environment before the job's first step and after its last
# one, the equivalent of GitHub's ACTIONS_RUNNER_HOOK_JOB_STARTED and
# ACTIONS_RUNNER_HOOK_JOB_COMPLETED, which are read when these are unset. The paths are
# resolved inside the job environment. Either one failing fails the job.
# Full guide: docs/job-hooks.md
#hooks:
# job_started: ''
# job_completed: ''
cache:
# Enable caching (used by actions/cache and similar actions). Off means no built-in server is
# started and no job is registered with an external_server either.
#enabled: true
# Directory where cache blobs are stored on disk. Default: $HOME/.cache/actcache
# Ignored when external_server is set.
#dir: ""
# Outbound IP or hostname that job containers use to reach this runner's cache server.
# Leave empty to detect automatically. 0.0.0.0 is not valid here.
# If the runner itself runs in Docker, automatic detection can choose an
# address on the runner container's network that job containers cannot reach
# when the runner creates a separate per-job network. In that case, set this
# to a hostname/IP reachable from job containers, and set port to a fixed
# published port or put the job containers on a shared Docker network.
# Ignored when external_server is set.
#host: ""
# Port for the built-in cache server. 0 picks a random free port.
# Ignored when external_server is set.
#port: 0
# URL of a shared `gitea-runner cache-server` to use instead of starting a local one.
# Set on every runner that should share a cache pool. A trailing slash is optional.
# Jobs reach the server at this URL too, so set it to the reverse proxy when one fronts the server.
# Example: "http://cache-host:8088/"
# Requires external_secret (below) to match the value on the cache-server.
#external_server: ""
# Shared secret between this runner and the external cache-server.
# Required when external_server is set. Must be identical on every runner and the cache-server.
# Generate with: openssl rand -hex 32
#external_secret: ""
# Path to a file containing the shared secret, as an alternative to external_secret.
# Use this to keep the secret out of this file.
# Surrounding whitespace is trimmed, so a trailing newline in the file is fine.
# Setting both external_secret and external_secret_file is an error.
#external_secret_file: ""
# When true, reuse a cached action instead of fetching from the remote on every job.
# A moved tag (e.g. a re-tagged "v6") or an updated branch stays at the cached commit
# until its cache entry expires or is manually removed.
#offline_mode: false
# Serve the actions cache service v2 API. The actions that use it fall back to v1 on any host
# they do not take for GitHub, so reaching it means editing that check out of their own bundle,
# put back after the copy into the job. That edit is made either way, this only governs the API
# advertised. A bundle that does not match is left alone. With v2, artifact uploads go via the
# cache server unless container jobs cannot reach its Docker network.
#v2: true
# How the cache server discards entries, ignored when external_server is set since that
# server applies its own. Leave a setting out for its default; 0s or 0 turns the three
# limits off. Sizes accept 10GB, 512mb, 1TiB or a plain byte count, binary either way.
# Whatever these allow, the cache still sheds entries to keep free space on its volume
# above health_check.min_free_disk_space_mb when health checks are enabled.
# Remove entries nothing has read or written within this window. Only last access counts.
#retention: 168h
# Cap one repository, removing its least recently accessed entries until it fits. An entry
# larger than the limit is dropped rather than emptying the repository to make room.
#repo_size_limit: 10GB
# Cap the whole cache the same way. Off by default, since the free space floor bounds it.
#size_limit: 0
# Minimum time between two eviction sweeps. This one has no "off".
#sweep_interval: 1h
container:
# Specifies the network to which the container will connect.
# Could be host, bridge or the name of a custom network.
# If it's empty, runner will create a network automatically.
# For dockerized runners using the built-in cache server, a custom shared
# network can be required so job containers can reach cache.host/cache.port.
# Deprecated: `network_mode` is still accepted for old configs; use `network` instead.
#network: ""
# network_create_options only apply when `network` is left empty and the runner
# auto-creates a per-job network that does not already exist. They have no effect
# when a custom `network` name is set, because that network is used as-is and never
# created by the runner. Omit the entire block to use Docker's defaults. An auto-created
# network is labelled com.gitea.runner.uuid=<this runner's uuid>, which is how the idle
# cleanup tells its own leftovers apart from those of other runners on the same daemon.
#network_create_options:
# enable_ipv4: true # Omit to use Docker's default (IPv4 enabled). Set false to disable IPv4.
# enable_ipv6: false # Omit to use Docker's default (IPv6 disabled). Enabling it requires dockerd started with --ipv6.
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
#privileged: false
# Any other options to be used when the container is started, for example:
# options: --add-host=my.gitea.url:host-gateway
# A volume declared here replaces the one the runner would mount on the same container path, so the
# tool cache can be kept on the host. Its source must also be allowed by valid_volumes below:
# options: --volume /host/toolcache:/opt/hostedtoolcache
# With privileged disabled, options that could escape the container (--security-opt, --device,
# --cap-add, --pid, ...) are ignored in a workflow's container.options, but keep working here.
#options:
# The parent directory of a job's working directory.
# NOTE: There is no need to add the first '/' of the path as runner will add it automatically.
# If the path starts with '/', the '/' will be trimmed.
# For example, if the parent directory is /path/to/my/dir, workdir_parent should be path/to/my/dir
# If it's empty, /workspace will be used.
# Purely numeric subdirectories under this path are reserved for task workspaces and may be removed by idle cleanup.
#workdir_parent:
# Volumes (including bind mounts) can be mounted to containers. Glob syntax is supported, see https://github.com/gobwas/glob
# You can specify multiple volumes. If the sequence is empty, no volumes can be mounted.
# For example, if you only allow containers to mount the `data` volume and all the json files in `/src`, you should change the config to:
# valid_volumes:
# - data
# - /src/*.json
# If you want to allow any volume, please use the following configuration:
# valid_volumes:
# - '**'
#valid_volumes: []
# Overrides the docker client host with the specified one.
# If it's empty, runner will find an available docker host automatically.
# If it's "-", runner will find an available docker host automatically, but won't mount it into the job and action containers.
# If it's not empty or "-", the specified docker host will be used. An error will be returned if it doesn't work.
#docker_host: ""
# Pull docker image(s) even if already present.
# Defaults to false when the key is omitted.
# Two exceptions: an image pinned by digest (image@sha256:...) cannot change, so it is never
# re-pulled, and a pull that fails while a copy is already on the host does not fail the job,
# which runs on that copy with a warning in its log.
#force_pull: false
# Rebuild docker image(s) even if already present
#force_rebuild: false
# Always require a reachable docker daemon, even if not required by runner
#require_docker: false
# Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or runner
#docker_timeout: 0s
# Mount the workspace from a host directory instead of a Docker volume, so jobs
# can bind-mount it by its own path into sibling containers (".:/app" in docker
# compose). Not needed when jobs get the Docker proxy or workflows use the
# GITEA_DOCKER_WORKSPACE variable.
# The workspace parent directory must be mounted into the runner container.
#bind_workdir: false
# How long a job waits for a service container that declares a healthcheck to become
# healthy. A negative value (e.g. -1s) starts the steps without waiting.
#service_ready_timeout: 5m
host:
# The parent directory of a job's working directory.
# If it's empty, $HOME/.cache/act/ will be used.
#workdir_parent:
# Optional local task-admission checks. Disabled by default. When enabled, low
# disk space or a failing script pauses new task fetching; existing jobs continue.
# No health checks run while any job is active; the last result is reused until idle.
health_check:
#enabled: false
# Minimum free space required on the filesystem holding runner workspaces.
# Defaults to 1024 MiB when omitted or set to zero.
#min_free_disk_space_mb: 1024
# Optional additional executable. A non-zero exit, timeout, or startup failure
# marks the runner unavailable.
#script: ''
# How long a script result is cached and its maximum execution time.
#interval: 30s
#timeout: 10s
metrics:
# Enable the Prometheus metrics endpoint.
# When enabled, metrics are served at /metrics, liveness at /healthz, and
# task-admission readiness at /readyz.
#enabled: false
# The address for the metrics HTTP server to listen on.
# Defaults to localhost only. Set to ":9101" to allow external access,
# but ensure the port is firewall-protected as there is no authentication.
#addr: "127.0.0.1:9101"
# Consecutive polling failures may last this long before /readyz returns 503.
#readiness_grace: 30s
@@ -1,4 +1,3 @@
networks: networks:
traefik: traefik:
external: true external: true
@@ -36,3 +35,16 @@ services:
POSTGRESS_DB: gitea POSTGRESS_DB: gitea
volumes: volumes:
- "{{ data_dir }}/postgres/gitea:/var/lib/postgresql/data" - "{{ data_dir }}/postgres/gitea:/var/lib/postgresql/data"
runner:
image: docker.io/gitea/runner:3
restart: unless-stopped
environment:
CONFIG_FILE: /config/config.yaml
GITEA_INSTANCE_URL: "https://git.{{ personal_domain }}"
GITEA_RUNNER_REGISTRATION_TOKEN: "{{ runner_registration_token }}"
volumes:
- "{{ data_dir }}/gitea/runner/config:/config"
- "{{ data_dir }}/gitea/runner/data:/data"
- /var/run/docker.sock:/var/run/docker.sock
+10
View File
@@ -29,3 +29,13 @@ internal_token: !vault |
62363962636132333266646431373162313261363635646166643462396161303635653338626431 62363962636132333266646431373162313261363635646166643462396161303635653338626431
35626638386562386361383035623431306465623738616361346139343134643134613563343038 35626638386562386361383035623431306465623738616361346139343134643134613563343038
38623638373335346533613536616136346638616465386637666463353234366237 38623638373335346533613536616136346638616465386637666463353234366237
runner_registration_token: !vault |
$ANSIBLE_VAULT;1.1;AES256
64313833353738306166363964613936303966333837356133383161373830366365363934646532
3539343564386232373765643437393463383036323033630a353934353933316566343863303039
38666537613663656633646439323930333036613937656238356538316338346537303663626531
3632623339383237380a643361616566663334353935313733346236353237633163633835333164
36366635373236343666616230613033333733376264663761353731353662643163306137343066
3664343135613539306537306330376331396264373631316439
@@ -1,5 +1,3 @@
version: "3"
networks: networks:
traefik: traefik:
external: true external: true
@@ -21,13 +19,14 @@ services:
VPN_TYPE: wireguard VPN_TYPE: wireguard
VPN_SERVICE_PROVIDER: custom VPN_SERVICE_PROVIDER: custom
WIREGUARD_PRIVATE_KEY: "{{ torguard_private_key }}" WIREGUARD_PRIVATE_KEY: "{{ torguard_private_key }}"
WIREGUARD_PUBLIC_KEY: "sC96pq087HvVpRNA5oKjiotwGuRRZbdLiTgmqP+Du2s=" WIREGUARD_PUBLIC_KEY: "fLDSO1YJxryyquen+XupegFQWhsWkGva+g3BtuIRyWs="
WIREGUARD_ADDRESSES: "{{ torguard_address }}" WIREGUARD_ADDRESSES: "{{ torguard_address }}"
VPN_ENDPOINT_IP: "146.70.137.122" VPN_ENDPOINT_IP: "38.96.254.100"
VPN_ENDPOINT_PORT: "1443" VPN_ENDPOINT_PORT: "1443"
FIREWALL_VPN_INPUT_PORTS: "55230" FIREWALL_VPN_INPUT_PORTS: "45333"
FIREWALL_OUTBOUND_SUBNETS: "10.0.0.0/24"
DOT: "off" DOT: "off"
DNS_ADDRESS: "9.9.9.9" DNS_ADDRESS: "10.8.0.1"
TZ: "{{ timezone }}" TZ: "{{ timezone }}"
HTTPPROXY: "on" HTTPPROXY: "on"
HTTPPROXY_USER: httpproxy HTTPPROXY_USER: httpproxy
+11 -11
View File
@@ -1,17 +1,17 @@
torguard_private_key: !vault | torguard_private_key: !vault |
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
38386463313536353366303733396232663136393431656432346332353131333630343730336262 30666664646463323238386164393462633236643531656564343835383661623335363562396631
3436633832613935323134393662666233643032613463310a656364653639363739306265306361 3439303437393364353064653338376563383362316237300a616338303763653034656564316630
61616261663139323238636634306330393733393065373138323463653935366335363639626265 30626437396531323763633133363565383530393737383064366661313430623936646264373933
3862396562393536320a366335363435636436333139356239306262303838333162613530643732 3734313736356534390a633837333264383233313962326636323534346163353064306539323230
64336161306633343866383538303536316163396566326336633961333136373736373364343430 32373237396534366638356631333266386265353862666436323665376339363236336361653937
3361613566346563346664353834613361616666383065303162 6236396266336637383032643434656234653232303236373931
torguard_address: !vault | torguard_address: !vault |
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
61626363346663646462626434316566353464623161396362356330333338616466633266383733 38313562363039623039623164373435653833333763653562626434666431666435653037393034
3363393464616534316339393935646438333764383765370a383236613539613866373838353061 6130396230363362633761343636313066333433363135370a333732353335336231366433393631
39393661393035373132663439653361363761613264656462623237336637356162623439336238 38393131326565633433363138346363343863393730613936643034353435656438613331343763
6635383734303539640a336366373164336262363630636562636136316166343362306265326163 3138616466623530350a383164616533303461396365316331633061333431366639356637396337
39306365613539383666303130633937643238653635393738323665323938646335 34343533366261343837653763636333326634373935316465613233316564623266
@@ -1,5 +0,0 @@
#!/usr/bin/with-contenv bash
set -euo pipefail
curl -sfL https://raw.githubusercontent.com/RandomNinjaAtk/arr-scripts/main/lidarr/setup.bash | bash
exit
+1 -18
View File
@@ -26,29 +26,12 @@
- name: Create data directory - name: Create data directory
ansible.builtin.file: ansible.builtin.file:
path: "{{ data_dir }}/{{ item }}" path: "{{ data_dir }}/{{ role_name }}/config"
state: directory state: directory
owner: "{{ service_user.uid }}" owner: "{{ service_user.uid }}"
group: "{{ primary_gid }}" group: "{{ primary_gid }}"
mode: "{{ docker_compose_directory_mask }}" mode: "{{ docker_compose_directory_mask }}"
become: true become: true
loop:
- "{{ role_name }}/config"
- "{{ role_name }}/custom-services"
- "{{ role_name }}/custom-cont"
- name: Copy arr-scripts init script
ansible.builtin.copy:
src: "scripts_init.bash"
dest: "{{ data_dir }}/{{ role_name }}/custom-cont"
owner: "{{ service_user.uid }}"
mode: 0564
become: true
- name: Copy extended.conf
ansible.builtin.template:
src: "extended.conf"
dest: "{{ data_dir }}/{{ role_name }}/config"
- name: Start docker container - name: Start docker container
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
@@ -17,9 +17,6 @@ services:
volumes: volumes:
- "{{ data_dir }}/{{ role_name }}/config:/config" - "{{ data_dir }}/{{ role_name }}/config:/config"
- "{{ media_storage_mnt }}/data:/data" - "{{ media_storage_mnt }}/data:/data"
# arr-scripts - https://github.com/RandomNinjaAtk/arr-scripts/blob/main/lidarr/readme.md
- "{{ data_dir }}/{{ role_name }}/custom-services:/custom-services.d"
- "{{ data_dir }}/{{ role_name }}/custom-cont:/custom-cont-init.d"
labels: labels:
traefik.enable: true traefik.enable: true
traefik.http.routers.{{ role_name }}.rule: "Host(`{{ role_name }}.local.{{ personal_domain }}`)" traefik.http.routers.{{ role_name }}.rule: "Host(`{{ role_name }}.local.{{ personal_domain }}`)"
@@ -1,89 +0,0 @@
##### LIDARR EXTENDED SCRIPTS SETTINGS #####
##### PATHS
downloadPath="/config/extended/downloads" # OPTIONAL, only change if needed.... Temporary Download Location for incoming Audio files from included clients
importPath="/config/extended/import" # OPTIONAL, only change if needed.... Completed downloads are stored here for the Usenet Blackhole client to import from. When Using queue cleaner, failed imports will be automatically cleaned up.
videoPath="" # Final destination/location of completed Videos
##### SCRIPT ENABLEMENT
enableAutoConfig="true" # true = enabled :: Automatically configures Lidarr with optimal settings
enableAudio="true" # true = enabled :: Enables the Audio script to run automatically
enableVideo="false" # true = enabled :: Enables the Video script to run automatically
enableUnmappedFilesCleaner="false" # true = enabled :: Enables the UnmappedFilesCleaner script to run automatically
enableQueueCleaner="true" # true = enabled :: Enables the QueueCleaner script to run automatically
##### SCRIPT INTERVALS
audioScriptInterval=15m #s or #m or #h or #d :: s = seconds, m = minutes, h = hours, d = days :: Amount of time between each script run, when script is enabled
videoScriptInterval=15m #s or #m or #h or #d :: s = seconds, m = minutes, h = hours, d = days :: Amount of time between each script run, when script is enabled
autoArtistAdderInterval=12h #s or #m or #h or #d :: s = seconds, m = minutes, h = hours, d = days :: Amount of time between each script run, when script is enabled
unmappedFolderCleanerScriptInterval=15m #s or #m or #h or #d :: s = seconds, m = minutes, h = hours, d = days :: Amount of time between each script run, when script is enabled
queueCleanerScriptInterval=15m #s or #m or #h or #d :: s = seconds, m = minutes, h = hours, d = days :: Amount of time between each script run, when script is enabled
##### AUTOCONFIG SCRIPT SETTINGS
configureMediaManagement="true" # Configures Lidarr Media Management Settings
configureMetadataConsumerSettings="false" # Configures Lidarr Metadata Consumer Settings
configureMetadataProviderSettings="false" # Configures Lidarr Metadata Provider Settings
configureCustomScripts="true" # Adds custom scripts to Lidarr
configureLidarrUiSettings="true" # Configures Lidarr UI Settings
configureMetadataProfileSettings="false" # Configures Lidarr Metadata Profile Settings
configureTrackNamingSettings="true" # Configures Lidarr Track Naming Settings
##### AUDIO SCRIPT
# SEARCH
searchSort="date" # date or album :: Sorts the missing/cutoff list by release date (newest -> oldest) or album type (album -> single) for processing the list
matchDistance="3" # The number of changes required to transform the searched album title into a possible found album title match... (0, requires a perfect match)
lidarrSearchForMissing="false" # true = enabled :: When artists are added, search for them using Lidarr's built in functionality
retryNotFound="90" ## :: Number of days between re-attempting the download of previously notfound albums
ignoreInstrumentalRelease="false" # true = enabled :: Skips albums releases that have the word "instrumental" in either the title or disambiguation
preferSpecialEditions="true" # true = enabled :: This changes the release title sort order, when true, it will search for releases with longest release names first, which are more likely to be deluxe/special versions...
# CLIENT
dlClientSource="deezer" # deezer, tidal or both :: set to both, to use both clients, tidal requires extra steps, view logging output
arlToken="{{ deezer_arl }}" # OPTIONAL (fallback using Freyr) - User ARL token for deemix client
tidalCountryCode="US" # Country Code required for tidal
failedDownloadAttemptThreshold="6" # Maximum number of attempts to download a particular album ID from the service before considering it a failed download...
deezerClientTestDownloadId="197472472" # A known good deezer track id that is used to test/verify the client is functioning in the event all download attempts have failed. Prevents the script from exiting...
tidalClientTestDownloadId="166356219" # A known good tidal track id that is used to test/verify the client is functioning in the event all download attempts have failed. Prevents the script from exiting...
downloadClientTimeOut="10m" # 's' for seconds (the default), 'm' for minutes, 'h' for hours or 'd' for days :: Kills freyr download client after the set timeout period, prevents lock ups...
# QUALITY
audioLyricType="both" # both or explicit or clean :: both, is explicit preferred matching, explicit is explicit releases only matching and clean is clean releases only matching
audioFormat="native" # native or alac or mp3 or aac or opus :: native is the native download client file type, selected by the matching audio bit-rate
audioBitrate="lossless" # master or lossless or high or low or ### :: master = MQA/lossless flac files, lossless = flac files, high = 320K, low = 128k/96k, ### = the output bit-rate of converted lossless files to selected audioFormat that is not native, example: 192...
requireQuality="true" # true = enabled :: Downloads will be checked for quality and require to have the requested file format & quality
# POST PROCESSING
enableBeetsTagging="true" # true = enabled :: Downloads will be processed and tagged by Beets
beetsMatchPercentage="90" # 1-100 :: Set this to the minimum percentage required for Beets to match the downloaded album to a musicbrainz release :: Lower percentage is less restrictive
enableReplaygainTags="true" # true = enabled :: Downloads will be tagged with ReplayGain Metadata
# ADD ARTIST AUTOMATION
addDeezerTopArtists="false" # true = enabled :: Enabling this will enable the extended script to automatically add artists that are on the Deezer Top Artist Chart to your existing Lidarr instance
addDeezerTopAlbumArtists="false" # true = enabled :: Enabling this will enable the extended script to automatically add artists that are on the Deezer Top Album Chart to your existing Lidarr instance
addDeezerTopTrackArtists="false" # true = enabled :: Enabling this will enable the extended script to automatically add artists that are on the Deezer Top Track Chart to your existing Lidarr instance
topLimit="3" # This setting controls the amount of Top Artist (Albums/Tracks/Artists) to add to Lidarr from Deezer
addRelatedArtists="false" # true = enabled :: WARNING !!! WARNING !!! Enabling this can cause an endless loop of additional artists.... Enabling this will enable the extended script to automatically add artists that are related to your existing Lidarr artists from Tidal & Deezer
numberOfRelatedArtistsToAddPerArtist="1" # 1-20 :: This will limit the number of related artists to add per artist in your library :: Minimum is 1, Maximum is 20
autoArtistAdderMonitored="true" # true or false :: If true, artists that are added automatically are monitored, when false they are added in an unmonitored state
preventRelatedArtistsLoop="true" # true = enabled :: This will prevent added related artists from adding additional related artists, thus killing an endless loop. This works by using the Lidarr's tag system (arr-extended), Remove tag from artist to allow it to be proessed for related artists...
##### VIDEO SCRIPT
addFeaturedVideoArtists="false" # true = enabled :: WARNING !!! WARNING !!! Enabling this can cause an endless loop of additional artists.... Enabling this will enable the extended Video script to automatically add Music Video Featured Artists to your existing Lidarr artists from IMVDB
videoFormat="bv[width>=1920]+ba" # ONLY CHANGE if you know what your doing, for guidence, please see yt-dlp documentation.
videoInfoJson="false" # true = enabled :: Stores yt-dlp info-json files alongside video files.
youtubeSubtitleLanguage="en" # Desired Language Code :: For guidence, please see yt-dlp documentation.
disableImvd="false" # true = enabled :: Use this to disable IMVDB as a source, will result in only tidal videos
##### DEEZER ARLCHECKER
arlUpdateInterval="24h" # Interval to check ARL Validity (default 24 hours). Reboot container after changing. s = seconds, m = minutes, h = hours, d = days
telegramBotEnable="false" # Enable/Disable Telegram Bot to notify if ARL expires. Otherwise check text file in custom-services.d/python for status.
telegramBotToken="" # Get token from BotFather during bot creation. If you use a notify channel for Lidarr, you can probably use the same bot, as this script only takes temporary control.
telegramUserChatID="" # Get your userid by chatting: t.me/userinfobot
pushoverEnable="false" # Pushover Notification Support
pushoverUserKey=""
pushoverAppAPIKey=""
ntfyEnable="false" # ntfy Notification Support
ntfyServerTopic="" # Put your server + topic address ex: https://ntfy.mydomain.com/lidarr
ntfyUserToken="" # create a new user token using the ntfy cli commands. See ntfy documentation on how to do that.
@@ -1,27 +0,0 @@
networks:
traefik:
external: true
services:
lubelogger:
container_name: lubelogger
image: ghcr.io/hargata/lubelogger:latest
restart: unless-stopped
networks:
- traefik
environment:
- LC_ALL=en_US.UTF-8
- LANG=en_US.UTF-8
- MailConfig__EmailServer=""
- MailConfig__EmailFrom=""
- MailConfig__Port=587
- MailConfig__Username=""
- MailConfig__Password=""
- LOGGING__LOGLEVEL__DEFAULT=Error
volumes:
- "{{ data_dir }}/{{ role_name }}:/App"
labels:
traefik.enable: true
traefik.http.routers.lubelogger.rule: "Host(`lubelogger.local.{{ personal_domain }}`)"
traefik.http.routers.lubelogger.middlewares: lan-whitelist@file
@@ -1,66 +0,0 @@
networks:
traefik:
external: true
default:
internal: true
services:
mealie-frontend:
image: hkotel/mealie:frontend-v1.0.0beta-5
container_name: mealie-frontend
restart: unless-stopped
depends_on:
- mealie-api
networks:
- default
- traefik
environment:
- API_URL=http://mealie-api:9000 #
volumes:
- "{{ data_dir }}/mealie:/app/data"
labels:
traefik.enable: true
traefik.http.routers.mealie.rule: "Host(`mealie.{{ personal_domain }}`)"
traefik.http.services.mealie.loadbalancer.server.port: 3000
mealie-api:
image: hkotel/mealie:api-v1.0.0beta-5
container_name: mealie-api
restart: unless-stopped
depends_on:
- postgres
networks:
- default
volumes:
- "{{ data_dir }}/mealie:/app/data"
environment:
- ALLOW_SIGNUP=false
- "PUID={{ service_user.uid }}"
- "PGID={{ service_user.uid }}"
- "TZ={{ timezone }}"
- MAX_WORKERS=1
- WEB_CONCURRENCY=1
- "BASE_URL=https://mealie.{{ personal_domain }}"
- DB_ENGINE=postgres
- POSTGRES_USER=mealie
- POSTGRES_PASSWORD=mealie
- POSTGRES_SERVER=postgres
- POSTGRES_PORT=5432
- POSTGRES_DB=mealie
- "DEFAULT_EMAIL={{ email }}"
- TOKEN_TIME=168
dns:
- 10.0.0.1
postgres:
container_name: postgres
image: postgres
restart: always
networks:
- default
volumes:
- "{{ data_dir }}/postgres/mealie:/var/lib/postgresql/data"
environment:
POSTGRES_PASSWORD: mealie
POSTGRES_USER: mealie
-7
View File
@@ -1,7 +0,0 @@
email: !vault |
$ANSIBLE_VAULT;1.1;AES256
30343965383433393930313337303637353362616563313863396433323939393864393436376534
6438663537386464623830316136643461356631316436360a636664323436303464376630616639
62653263633531343733313137303863623562616632313236376466313132636234633438616164
3030303934343761390a663734333566323234613434633636353665623530643262353162383237
66633863376332663064346132356238333561663438643232646463646632656361
-4
View File
@@ -1,4 +0,0 @@
- name: restart ntfy
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/ntfy"
restarted: true
-31
View File
@@ -1,31 +0,0 @@
- name: Create install directory
file:
path: "{{ install_directory }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination
template:
src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
validate: docker compose -f %s config
become: true
- name: Install configuration file
template:
src: server.yml
dest: "{{ data_dir }}/ntfy/server.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
notify: restart ntfy
become: true
- name: Start docker container
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
pull: always
remove_orphans: yes
@@ -1,24 +0,0 @@
networks:
traefik:
external: true
services:
ntfy:
container_name: ntfy
image: binwiederhier/ntfy:latest
restart: unless-stopped
networks:
- traefik
user: "{{ primary_uid }}:{{ primary_gid }}"
environment:
- TZ={{ timezone }}
command:
- serve
volumes:
- "{{ data_dir }}/ntfy:/etc/ntfy"
- /var/cache/ntfy:/var/cache/ntfy
labels:
traefik.enable: true
traefik.http.routers.ntfy.rule: "Host(`push.{{ personal_domain }}`)"
traefik.http.routers.ntfy.middlewares: lan-whitelist@file
-279
View File
@@ -1,279 +0,0 @@
# ntfy server config file
#
# Please refer to the documentation at https://ntfy.sh/docs/config/ for details.
# All options also support underscores (_) instead of dashes (-) to comply with the YAML spec.
# Public facing base URL of the service (e.g. https://ntfy.sh or https://ntfy.example.com)
#
# This setting is required for any of the following features:
# - attachments (to return a download URL)
# - e-mail sending (for the topic URL in the email footer)
# - iOS push notifications for self-hosted servers (to calculate the Firebase poll_request topic)
# - Matrix Push Gateway (to validate that the pushkey is correct)
#
base-url: "https://push.{{ personal_domain }}"
# Listen address for the HTTP & HTTPS web server. If "listen-https" is set, you must also
# set "key-file" and "cert-file". Format: [<ip>]:<port>, e.g. "1.2.3.4:8080".
#
# To listen on all interfaces, you may omit the IP address, e.g. ":443".
# To disable HTTP, set "listen-http" to "-".
#
# listen-http: ":80"
# listen-https:
# Listen on a Unix socket, e.g. /var/lib/ntfy/ntfy.sock
# This can be useful to avoid port issues on local systems, and to simplify permissions.
#
# listen-unix: <socket-path>
# listen-unix-mode: <linux permissions, e.g. 0700>
# Path to the private key & cert file for the HTTPS web server. Not used if "listen-https" is not set.
#
# key-file: <filename>
# cert-file: <filename>
# If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app.
# This is optional and only required to save battery when using the Android app.
#
# firebase-key-file: <filename>
# If "cache-file" is set, messages are cached in a local SQLite database instead of only in-memory.
# This allows for service restarts without losing messages in support of the since= parameter.
#
# The "cache-duration" parameter defines the duration for which messages will be buffered
# before they are deleted. This is required to support the "since=..." and "poll=1" parameter.
# To disable the cache entirely (on-disk/in-memory), set "cache-duration" to 0.
# The cache file is created automatically, provided that the correct permissions are set.
#
# The "cache-startup-queries" parameter allows you to run commands when the database is initialized,
# e.g. to enable WAL mode (see https://phiresky.github.io/blog/2020/sqlite-performance-tuning/)).
# Example:
# cache-startup-queries: |
# pragma journal_mode = WAL;
# pragma synchronous = normal;
# pragma temp_store = memory;
# pragma busy_timeout = 15000;
# vacuum;
#
# The "cache-batch-size" and "cache-batch-timeout" parameter allow enabling async batch writing
# of messages. If set, messages will be queued and written to the database in batches of the given
# size, or after the given timeout. This is only required for high volume servers.
#
# Debian/RPM package users:
# Use /var/cache/ntfy/cache.db as cache file to avoid permission issues. The package
# creates this folder for you.
#
# Check your permissions:
# If you are running ntfy with systemd, make sure this cache file is owned by the
# ntfy user and group by running: chown ntfy.ntfy <filename>.
#
# cache-file: <filename>
# cache-duration: "12h"
# cache-startup-queries:
# cache-batch-size: 0
# cache-batch-timeout: "0ms"
# If set, access to the ntfy server and API can be controlled on a granular level using
# the 'ntfy user' and 'ntfy access' commands. See the --help pages for details, or check the docs.
#
# - auth-file is the SQLite user/access database; it is created automatically if it doesn't already exist
# - auth-default-access defines the default/fallback access if no access control entry is found; it can be
# set to "read-write" (default), "read-only", "write-only" or "deny-all".
# - auth-startup-queries allows you to run commands when the database is initialized, e.g. to enable
# WAL mode. This is similar to cache-startup-queries. See above for details.
#
# Debian/RPM package users:
# Use /var/lib/ntfy/user.db as user database to avoid permission issues. The package
# creates this folder for you.
#
# Check your permissions:
# If you are running ntfy with systemd, make sure this user database file is owned by the
# ntfy user and group by running: chown ntfy.ntfy <filename>.
#
# auth-file: <filename>
# auth-default-access: "read-write"
# auth-startup-queries:
# If set, the X-Forwarded-For header is used to determine the visitor IP address
# instead of the remote address of the connection.
#
# WARNING: If you are behind a proxy, you must set this, otherwise all visitors are rate limited
# as if they are one.
#
behind-proxy: true
# If enabled, clients can attach files to notifications as attachments. Minimum settings to enable attachments
# are "attachment-cache-dir" and "base-url".
#
# - attachment-cache-dir is the cache directory for attached files
# - attachment-total-size-limit is the limit of the on-disk attachment cache directory (total size)
# - attachment-file-size-limit is the per-file attachment size limit (e.g. 300k, 2M, 100M)
# - attachment-expiry-duration is the duration after which uploaded attachments will be deleted (e.g. 3h, 20h)
#
attachment-cache-dir: "/var/cache/ntfy/attachments"
# attachment-total-size-limit: "5G"
# attachment-file-size-limit: "15M"
# attachment-expiry-duration: "3h"
# If enabled, allow outgoing e-mail notifications via the 'X-Email' header. If this header is set,
# messages will additionally be sent out as e-mail using an external SMTP server. As of today, only
# SMTP servers with plain text auth and STARTLS are supported. Please also refer to the rate limiting settings
# below (visitor-email-limit-burst & visitor-email-limit-burst).
#
# - smtp-sender-addr is the hostname:port of the SMTP server
# - smtp-sender-user/smtp-sender-pass are the username and password of the SMTP user
# - smtp-sender-from is the e-mail address of the sender
#
# smtp-sender-addr:
# smtp-sender-user:
# smtp-sender-pass:
# smtp-sender-from:
# If enabled, ntfy will launch a lightweight SMTP server for incoming messages. Once configured, users can send
# emails to a topic e-mail address to publish messages to a topic.
#
# - smtp-server-listen defines the IP address and port the SMTP server will listen on, e.g. :25 or 1.2.3.4:25
# - smtp-server-domain is the e-mail domain, e.g. ntfy.sh
# - smtp-server-addr-prefix is an optional prefix for the e-mail addresses to prevent spam. If set to "ntfy-",
# for instance, only e-mails to ntfy-$topic@ntfy.sh will be accepted. If this is not set, all emails to
# $topic@ntfy.sh will be accepted (which may obviously be a spam problem).
#
# smtp-server-listen:
# smtp-server-domain:
# smtp-server-addr-prefix:
# Interval in which keepalive messages are sent to the client. This is to prevent
# intermediaries closing the connection for inactivity.
#
# Note that the Android app has a hardcoded timeout at 77s, so it should be less than that.
#
# keepalive-interval: "45s"
# Interval in which the manager prunes old messages, deletes topics
# and prints the stats.
#
# manager-interval: "1m"
# Defines topic names that are not allowed, because they are otherwise used. There are a few default topics
# that cannot be used (e.g. app, account, settings, ...). To extend the default list, define them here.
#
# Example:
# disallowed-topics:
# - about
# - pricing
# - contact
#
# disallowed-topics:
# Defines if the root route (/) is pointing to the landing page (as on ntfy.sh) or the
# web app. If you self-host, you don't want to change this.
# Can be "app" (default), "home" or "disable" to disable the web app entirely.
#
# web-root: app
# Various feature flags used to control the web app, and API access, mainly around user and
# account management.
#
# - enable-signup allows users to sign up via the web app, or API
# - enable-login allows users to log in via the web app, or API
# - enable-reservations allows users to reserve topics (if their tier allows it)
#
# enable-signup: false
# enable-login: false
# enable-reservations: false
# Server URL of a Firebase/APNS-connected ntfy server (likely "https://ntfy.sh").
#
# iOS users:
# If you use the iOS ntfy app, you MUST configure this to receive timely notifications. You'll like want this:
# upstream-base-url: "https://ntfy.sh"
#
# If set, all incoming messages will publish a "poll_request" message to the configured upstream server, containing
# the message ID of the original message, instructing the iOS app to poll this server for the actual message contents.
# This is to prevent the upstream server and Firebase/APNS from being able to read the message.
#
# upstream-base-url:
# Rate limiting: Total number of topics before the server rejects new topics.
#
# global-topic-limit: 15000
# Rate limiting: Number of subscriptions per visitor (IP address)
#
# visitor-subscription-limit: 30
# Rate limiting: Allowed GET/PUT/POST requests per second, per visitor:
# - visitor-request-limit-burst is the initial bucket of requests each visitor has
# - visitor-request-limit-replenish is the rate at which the bucket is refilled
# - visitor-request-limit-exempt-hosts is a comma-separated list of hostnames, IPs or CIDRs to be
# exempt from request rate limiting. Hostnames are resolved at the time the server is started.
# Example: "1.2.3.4,ntfy.example.com,8.7.6.0/24"
#
# visitor-request-limit-burst: 60
# visitor-request-limit-replenish: "5s"
# visitor-request-limit-exempt-hosts: ""
# Rate limiting: Hard daily limit of messages per visitor and day. The limit is reset
# every day at midnight UTC. If the limit is not set (or set to zero), the request
# limit (see above) governs the upper limit.
#
# visitor-message-daily-limit: 0
# Rate limiting: Allowed emails per visitor:
# - visitor-email-limit-burst is the initial bucket of emails each visitor has
# - visitor-email-limit-replenish is the rate at which the bucket is refilled
#
# visitor-email-limit-burst: 16
# visitor-email-limit-replenish: "1h"
# Rate limiting: Attachment size and bandwidth limits per visitor:
# - visitor-attachment-total-size-limit is the total storage limit used for attachments per visitor
# - visitor-attachment-daily-bandwidth-limit is the total daily attachment download/upload traffic limit per visitor
#
# visitor-attachment-total-size-limit: "100M"
# visitor-attachment-daily-bandwidth-limit: "500M"
# Payments integration via Stripe
#
# - stripe-secret-key is the key used for the Stripe API communication. Setting this values
# enables payments in the ntfy web app (e.g. Upgrade dialog). See https://dashboard.stripe.com/apikeys.
# - stripe-webhook-key is the key required to validate the authenticity of incoming webhooks from Stripe.
# Webhooks are essential up keep the local database in sync with the payment provider. See https://dashboard.stripe.com/webhooks.
#
# stripe-secret-key:
# stripe-webhook-key:
# Logging options
#
# By default, ntfy logs to the console (stderr), with an "info" log level, and in a human-readable text format.
# ntfy supports five different log levels, can also write to a file, log as JSON, and even supports granular
# log level overrides for easier debugging. Some options (log-level and log-level-overrides) can be hot reloaded
# by calling "kill -HUP $pid" or "systemctl reload ntfy".
#
# - log-format defines the output format, can be "text" (default) or "json"
# - log-file is a filename to write logs to. If this is not set, ntfy logs to stderr.
# - log-level defines the default log level, can be one of "trace", "debug", "info" (default), "warn" or "error".
# Be aware that "debug" (and particularly "trace") can be VERY CHATTY. Only turn them on briefly for debugging purposes.
# - log-level-overrides lets you override the log level if certain fields match. This is incredibly powerful
# for debugging certain parts of the system (e.g. only the account management, or only a certain visitor).
# This is an array of strings in the format:
# - "field=value -> level" to match a value exactly, e.g. "tag=manager -> trace"
# - "field -> level" to match any value, e.g. "time_taken_ms -> debug"
# Warning: Using log-level-overrides has a performance penalty. Only use it for temporary debugging.
#
# Example (good for production):
# log-level: info
# log-format: json
# log-file: /var/log/ntfy.log
#
# Example level overrides (for debugging, only use temporarily):
# log-level-overrides:
# - "tag=manager -> trace"
# - "visitor_ip=1.2.3.4 -> debug"
# - "time_taken_ms -> debug"
#
# log-level: info
# log-level-overrides:
# log-format: text
# log-file:
-2
View File
@@ -30,7 +30,6 @@
dest: "{{ data_dir }}/qbitmanage/config.yml" dest: "{{ data_dir }}/qbitmanage/config.yml"
owner: "{{ service_user.uid }}" owner: "{{ service_user.uid }}"
mode: "{{ docker_compose_file_mask }}" mode: "{{ docker_compose_file_mask }}"
notify: restart qbittorrent
become: true become: true
- name: Create cross-seed config directory - name: Create cross-seed config directory
@@ -47,7 +46,6 @@
dest: "{{ data_dir }}/cross-seed/config.js" dest: "{{ data_dir }}/cross-seed/config.js"
owner: "{{ service_user.uid }}" owner: "{{ service_user.uid }}"
mode: "{{ docker_compose_file_mask }}" mode: "{{ docker_compose_file_mask }}"
notify: restart qbittorrent
become: true become: true
- name: Start docker containers - name: Start docker containers
@@ -4,10 +4,10 @@ module.exports = {
delay: 30, delay: 30,
torznab: [ torznab: [
"http://prowlarr.local.{{ personal_domain }}/3/api?apikey={{ prowlarr_api_key }}", // ImmortalSeed
"http://prowlarr.local.{{ personal_domain }}/6/api?apikey={{ prowlarr_api_key }}", // Aither "http://prowlarr.local.{{ personal_domain }}/6/api?apikey={{ prowlarr_api_key }}", // Aither
"http://prowlarr.local.{{ personal_domain }}/7/api?apikey={{ prowlarr_api_key }}", // Reelflix "http://prowlarr.local.{{ personal_domain }}/7/api?apikey={{ prowlarr_api_key }}", // Reelflix
"http://prowlarr.local.{{ personal_domain }}/9/api?apikey={{ prowlarr_api_key }}", // LST "http://prowlarr.local.{{ personal_domain }}/9/api?apikey={{ prowlarr_api_key }}", // LST
"http://prowlarr.local.{{ personal_domain }}/10/api?apikey={{ prowlarr_api_key }}", // MyAnonaMouse
"http://prowlarr.local.{{ personal_domain }}/12/api?apikey={{ prowlarr_api_key }}", // Blutopia "http://prowlarr.local.{{ personal_domain }}/12/api?apikey={{ prowlarr_api_key }}", // Blutopia
"http://prowlarr.local.{{ personal_domain }}/13/api?apikey={{ prowlarr_api_key }}", // hawke-uno "http://prowlarr.local.{{ personal_domain }}/13/api?apikey={{ prowlarr_api_key }}", // hawke-uno
"http://prowlarr.local.{{ personal_domain }}/16/api?apikey={{ prowlarr_api_key }}", // AlphaRatio "http://prowlarr.local.{{ personal_domain }}/16/api?apikey={{ prowlarr_api_key }}", // AlphaRatio
@@ -15,6 +15,12 @@ module.exports = {
"http://prowlarr.local.{{ personal_domain }}/19/api?apikey={{ prowlarr_api_key }}", // Cathode-Ray.Tube "http://prowlarr.local.{{ personal_domain }}/19/api?apikey={{ prowlarr_api_key }}", // Cathode-Ray.Tube
"http://prowlarr.local.{{ personal_domain }}/25/api?apikey={{ prowlarr_api_key }}", // seedpool "http://prowlarr.local.{{ personal_domain }}/25/api?apikey={{ prowlarr_api_key }}", // seedpool
"http://prowlarr.local.{{ personal_domain }}/27/api?apikey={{ prowlarr_api_key }}", // Upload.cx "http://prowlarr.local.{{ personal_domain }}/27/api?apikey={{ prowlarr_api_key }}", // Upload.cx
"http://prowlarr.local.{{ personal_domain }}/28/api?apikey={{ prowlarr_api_key }}", // AnimeBytes
"http://prowlarr.local.{{ personal_domain }}/30/api?apikey={{ prowlarr_api_key }}", // DocsPedia
"http://prowlarr.local.{{ personal_domain }}/31/api?apikey={{ prowlarr_api_key }}", // OnlyEncodes+
"http://prowlarr.local.{{ personal_domain }}/32/api?apikey={{ prowlarr_api_key }}", // Anthelion
"http://prowlarr.local.{{ personal_domain }}/33/api?apikey={{ prowlarr_api_key }}", // OldToonsWorld
"http://prowlarr.local.{{ personal_domain }}/34/api?apikey={{ prowlarr_api_key }}", // Zenith
], ],
outputDir: null, outputDir: null,
@@ -24,8 +30,7 @@ module.exports = {
excludeOlder: "12w", excludeOlder: "12w",
excludeRecentSearch: "3w", excludeRecentSearch: "3w",
action: "inject", action: "inject",
rtorrentRpcUrl: undefined, torrentClients: ["qbittorrent:https://qui.local.{{ personal_domain }}/proxy/{{ qui_crossseed_api_key }}"],
qbittorrentUrl: "https://qbittorrent.local.{{ personal_domain }}",
sonarr: ["https://sonarr.local.{{ personal_domain }}/?apikey={{ sonarr_api_key }}"], sonarr: ["https://sonarr.local.{{ personal_domain }}/?apikey={{ sonarr_api_key }}"],
radarr: ["https://radarr.local.{{ personal_domain }}/?apikey={{ radarr_api_key }}"], radarr: ["https://radarr.local.{{ personal_domain }}/?apikey={{ radarr_api_key }}"],
seasonsFromEpisodes: 0.8, seasonsFromEpisodes: 0.8,
@@ -36,4 +41,7 @@ module.exports = {
port: 2468, port: 2468,
rssCadence: "16min", rssCadence: "16min",
searchCadence: "1w", searchCadence: "1w",
blockList: [
"category:upload",
],
}; };
@@ -5,7 +5,7 @@ networks:
services: services:
qbittorrent: qbittorrent:
container_name: qbittorrent container_name: qbittorrent
image: lscr.io/linuxserver/qbittorrent:5.1.2 image: lscr.io/linuxserver/qbittorrent:5.2.3
restart: unless-stopped restart: unless-stopped
network_mode: "container:gluetun" network_mode: "container:gluetun"
environment: environment:
@@ -52,26 +52,3 @@ services:
- "{{ media_storage_mnt }}/data/torrents:/data/torrents" # Necessary for partial matching - "{{ media_storage_mnt }}/data/torrents:/data/torrents" # Necessary for partial matching
command: daemon command: daemon
restart: unless-stopped restart: unless-stopped
unpackerr:
container_name: unpackerr
image: ghcr.io/hotio/unpackerr
networks:
- starr
environment:
- "PUID={{ service_user.uid }}"
- "PGID={{ media_gid }}"
- UMASK=002
- TZ={{ timezone }}
- UN_INTERVAL=5m
- UN_FILE_MODE=0664
- UN_DIR_MODE=0775
- UN_SONARR_0_URL=http://sonarr:8989
- "UN_SONARR_0_API_KEY={{ sonarr_api_key }}"
- UN_SONARR_0_PATHS_0=/data/torrents/tv
- UN_RADARR_0_URL=http://radarr:7878
- "UN_RADARR_0_API_KEY={{ radarr_api_key }}"
- UN_RADARR_0_PATHS_0=/data/torrents/movies
volumes:
- "{{ data_dir }}/unpackerr:/config"
- "{{ media_storage_mnt }}/data/torrents:/data/torrents"
@@ -5,11 +5,11 @@ commands:
recheck: True recheck: True
tag_update: True tag_update: True
rem_unregistered: True rem_unregistered: True
remove_orphaned: True rem_orphaned: True
tag_nohardlinks: True tag_nohardlinks: True
qbt: qbt:
host: "https://qbittorrent.local.{{ personal_domain }}" host: "https://qui.local.{{ personal_domain }}/proxy/{{ qui_qbitmanage_api_key }}"
user: user:
pass: pass:
@@ -41,36 +41,32 @@ cat:
tracker: tracker:
hawke: hawke:
tag: HUNO tag: HUNO
digitalcore:
tag: DigitalCore
myanonamouse: myanonamouse:
tag: MaM tag: MaM
torrentleech|tleechreload: torrentleech|tleechreload:
tag: TorrentLeech tag: TL
aither: aither:
tag: Aither tag: ATH
nyaa: nyaa:
tag: Nyaa tag: Nyaa
animetosho: animetosho:
tag: AnimeTosho tag: AnimeTosho
immortalseed: immortalseed:
tag: ImmortalSeed tag: ImmortalSeed
torrentseeds:
tag: TorrentSeeds
ops: ops:
tag: Orpheus tag: OPS
reelflix: reelflix:
tag: ReelFlix tag: RFX
blutopia: blutopia:
tag: Blu tag: BLU
lst: lst:
tag: LST tag: LST
speed: speed:
tag: Speed.CD tag: Speed.CD
alpharatio: alpharatio:
tag: AlphaRatio tag: AR
filelist: filelist:
tag: FileList tag: FL
skipthecommericals.xyz: skipthecommericals.xyz:
tag: STC tag: STC
cathode: cathode:
@@ -78,11 +74,19 @@ tracker:
t-ru.org: t-ru.org:
tag: rutracker tag: rutracker
seedpool|seedpool.org: seedpool|seedpool.org:
tag: seedpool tag: SP
upload.cx: upload.cx:
tag: ULCX tag: ULCX
archlinux: archlinux:
tag: archlinux tag: archlinux
animebytes:
tag: AB
anthelion:
tag: ANT
onlyencodes:
tag: OE+
oldtoons:
tag: OTW
other: other:
tag: other tag: other
@@ -99,7 +103,7 @@ share_limits:
priority: 1 priority: 1
include_all_tags: include_all_tags:
- noHL - noHL
max_seeding_time: 28800 # 20 days max_seeding_time: 40320 # 4 weeks
cleanup: true cleanup: true
add_group_to_tag: false add_group_to_tag: false
isos: isos:
@@ -109,28 +113,14 @@ share_limits:
max_seeding_time: 129600 # 90 days max_seeding_time: 129600 # 90 days
cleanup: true cleanup: true
add_group_to_tag: false add_group_to_tag: false
tl_cross-seed: big: # Set speed limit on bandwidth hogs
priority: 9 priority: 9
include_all_tags: include_any_tags:
- cross-seed
- TorrentLeech - TorrentLeech
- FileList
- AlphaRatio
limit_upload_speed: 100 # 100 KiBps limit_upload_speed: 100 # 100 KiBps
add_group_to_tag: false add_group_to_tag: false
public_trackers:
priority: 10
include_any_tags:
- Nyaa
- AnimeTosho
- rutracker
categories:
- movies
- tv
max_ratio: 2
max_seeding_time: 21600 # 15 days
limit_upload_speed: 5000 # 5 MiBps
cleanup: true
add_group_to_tag: false
recyclebin: recyclebin:
enabled: true enabled: true
+22
View File
@@ -33,3 +33,25 @@ crossseed_webhook_endpoint: !vault |
37633631313965396233613333373832353463653337393861393335373661393163343037306130 37633631313965396233613333373832353463653337393861393335373661393163343037306130
6337376662653463316530313863613532633338623731356536 6337376662653463316530313863613532633338623731356536
qui_crossseed_api_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
31663334373665646433616663326336306631653833373765366463373166316661333463316235
3861633161623034356431383030326233353836656466390a386534356665633561376263363030
63383766383535366530306238393836613337366136363037313364336164383366636166623265
3964366637613866300a653231333566356566616537356330613938353464303530616232306238
32666665653534653765653034396232663161323261623237373739333634383038346562613063
65653332666336613861363965393562366465666261666536396231303461656162373436633830
63326536613230626563626232363835373635323533333332373136356430393439316666386439
65356230376630376630
qui_qbitmanage_api_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
39616437313930376137323434396438333562316565306233316166383465333134623836633365
6136333039373366396461356665333236326539323731380a653664656637313933346533396433
33643430343437623132666233383434613066346338646232666539633066333662343565336466
3031323265343936660a366265313430663330643132373233383765633066396566343963663662
61386365653233366237363062336539653361373930383530653031656638356533313061626635
33663932666536396431626363623437326133646661653834376335373562353065323633326234
33316338653865326534336530656231643830616434396637306561376436633632343731623065
37343434326461346465
-31
View File
@@ -1,31 +0,0 @@
- name: Create service user
user:
name: "{{ role_name }}"
groups: "{{ media_group }}"
append: yes
system: true
register: service_user
become: true
- name: Create install directory
file:
path: "{{ install_directory }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination
template:
src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
validate: docker compose -f %s config
become: true
- name: Start docker container
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
pull: always
remove_orphans: yes
@@ -1,24 +0,0 @@
networks:
traefik:
external: true
services:
{{ role_name }}:
container_name: "{{ role_name }}"
image: cr.hotio.dev/hotio/readarr
restart: unless-stopped
networks:
- traefik
environment:
- "PUID={{ service_user.uid }}"
- "PGID={{ media_gid }}"
- "TZ={{ timezone }}"
- "UMASK=002"
volumes:
- "{{ data_dir }}/{{ role_name }}:/config"
- "{{ media_storage_mnt }}/data:/data"
labels:
traefik.enable: true
traefik.http.routers.{{ role_name }}.rule: "Host(`{{ role_name }}.local.{{ personal_domain }}`)"
traefik.http.routers.{{ role_name }}.middlewares: lan-whitelist@file
@@ -48,3 +48,9 @@ custom_formats:
assign_scores_to: assign_scores_to:
- name: Anime - name: Anime
score: 10 # Prefer dual audio within the same tier but not over higher quality releases score: 10 # Prefer dual audio within the same tier but not over higher quality releases
- trash_ids:
- 923b6abef9b17f937fab56cfcf89e1f1 # DV (w/o HDR fallback)
assign_scores_to:
- name: Anime
score: -10000
@@ -0,0 +1,80 @@
custom_formats:
- trash_ids:
# HDR Formats
- c53085ddbd027d9624b320627748612f # DV HDR10+
- e23edd2482476e595fb990b12e7c609c # DV HDR10
- 58d6a88f13e2db7f5059c41047876f00 # DV
- 55d53828b9d81cbe20b02efd00aa0efd # DV HLG
- a3e19f8f627608af0211acd02bf89735 # DV SDR
- b974a6cd08c1066250f1f177d7aa1225 # HDR10+
- dfb86d5941bc9075d6af23b09c2aeecd # HDR10
- e61e28db95d22bedcadf030b8f156d96 # HDR
- 2a4d9069cc1fe3242ff9bdaebed239bb # HDR (undefined)
- 08d6d8834ad9ec87b1dc7ec8148e7a1f # PQ
- 9364dd386c9b4a1100dde8264690add7 # HLG
# HQ Release Groups
- 4d74ac4c4db0b64bff6ce0cffef99bf0 # UHD Bluray Tier 01
- a58f517a70193f8e578056642178419d # UHD Bluray Tier 02
- e71939fae578037e7aed3ee219bbe7c1 # UHD Bluray Tier 03
- ed27ebfef2f323e964fb1f61391bcb35 # HD Bluray Tier 01
- c20c8647f2746a1f4c4262b0fbbeeeae # HD Bluray Tier 02
- 5608c71bcebba0a5e666223bae8c9227 # HD Bluray Tier 03
- c20f169ef63c5f40c2def54abaf4438e # WEB Tier 01
- 403816d65392c79236dcb6dd591aeda4 # WEB Tier 02
- af94e0fe497124d1f9ce732069ec8c3b # WEB Tier 03
# General Streaming Services
- b3b3a6ac74ecbd56bcdbefa4799fb9df # AMZN
- 40e9380490e748672c2522eaaeb692f7 # ATVP
- cc5e51a9e85a6296ceefe097a77f12f4 # BCORE
- 16622a6911d1ab5d5b8b713d5b0036d4 # CRiT
- 84272245b2988854bfb76a16e60baea5 # DSNP
- 509e5f41146e278f9eab1ddaceb34515 # HBO
- 5763d1b0ce84aff3b21038eea8e9b8ad # HMAX
- 526d445d4c16214309f0fd2b3be18a89 # Hulu
- e0ec9672be6cac914ffad34a6b077209 # iT
- 6a061313d22e51e0f25b7cd4dc065233 # MAX
- 2a6039655313bf5dab1e43523b62c374 # MA
- 170b1d363bd8516fbf3a3eb05d4faff6 # NF
- e36a0ba1bc902b26ee40818a1d59b8bd # PMTP
- c9fd353f8f5f1baf56dc601c4cb29920 # PCOK
- c2863d2a50c9acad1fb50e53ece60817 # STAN
# Movie Versions
- 570bc9ebecd92723d2d21500f4be314c # Remaster
- eca37840c13c6ef2dd0262b141a5482f # 4K Remaster
- e0c07d59beb37348e975a930d5e50319 # Criterion Collection
- 9d27d9d2181838f76dee150882bdc58c # Masters of Cinema
- db9b4c4b53d312a3ca5f1378f6440fc9 # Vinegar Syndrome
- 957d0f44b592285f26449575e8b1167e # Special Edition
- eecf3a857724171f968a66cb5719e152 # IMAX
- 9f6cbff8cfe4ebbc1bde14c7b7bec0de # IMAX Enhanced
- 09d9dd29a0fc958f9796e65c2a8864b4 # Open Matte
# Miscellaneous
- e7718d7a3ce595f289bfee26adc178f5 # Repack/Proper
- ae43b294509409a6a13919dedd4764c4 # Repack2
- 5caaaa1c08c1742aa4342d8c4cc463f2 # Repack3
# Unwanted
- 923b6abef9b17f937fab56cfcf89e1f1 # DV (WEBDL)
- ed38b889b31be83fda192888e2286d83 # BR-DISK
- e6886871085226c3da1830830146846c # Gererated Dynamic HDR
- 90a6f9a284dff5103f6346090e6280c8 # LQ
- e204b80c87be9497a8a6eaff48f72905 # LQ (Release Title)
- 839bea857ed2c0a8e084f3cbdbd65ecb # x265 (no HDR/DV)
- 25c12f78430a3a23413652cbd1d48d77 # SDR (no WEBDL)
- b8cd450cbfa689c0259a01d9e29ba3d6 # 3D
- bfd8eb01832d646a0a89c4deb46f8564 # Upscaled
- 0a3f082873eb454bde444150b70253cc # Extras
- 712d74cd88bceb883ee32f773656b1f5 # Sing-Along Versions
- cae4ca30163749b891686f95532519bd # AV1
- b6832f586342ef70d9c128d40c07b872 # Bad Dual Groups
- cc444569854e9de0b084ab2b8b1532b2 # Black and White Editions
- ae9b7c9ebde1f3bd336a8cbd1ec4c5e5 # No-RlsGroup
- 7357cf5161efbf8c4d5d0c30b4815ee2 # Obfuscated
- 5c44f52a8714fdd79bb4d98e2673be1f # Retags
- f537cf427b64c38c8e36298f657e4828 # Scene
assign_scores_to:
- name: Encode
@@ -0,0 +1,22 @@
quality_profiles:
- name: Encode
upgrade:
allowed: true
until_quality: Bluray-2160p
until_score: 10000
min_format_score: 0
score_set: default
quality_sort: top
qualities:
- name: Bluray-2160p
- name: WEB 2160p
qualities:
- WEBDL-2160p
- WEBRip-2160p
- name: Bluray-1080p
- name: WEB 1080p
qualities:
- WEBDL-1080p
- WEBRip-1080p
- name: Remux-2160p
- name: Remux-1080p
@@ -41,24 +41,6 @@ custom_formats:
- c9fd353f8f5f1baf56dc601c4cb29920 # PCOK - c9fd353f8f5f1baf56dc601c4cb29920 # PCOK
- c2863d2a50c9acad1fb50e53ece60817 # STAN - c2863d2a50c9acad1fb50e53ece60817 # STAN
# Audio
- 496f355514737f7d83bf7aa4d24f8169 # TrueHD Atmos
- 2f22d89048b01681dde8afe203bf2e95 # DTS:X
- 417804f7f2c4308c1f4c5d380d4c4475 # Atmos (undefined)
- 1af239278386be2919e1bcee0bde047e # DD+ Atmos
- 3cafb66171b47f226146a0770576870f # TrueHD
- dcf3ec6938fa32445f590a4da84256cd # DTS-HD MA
- a570d4a0e56a2874b64e5bfa55202a1b # FLAC
- e7c2fcae07cbada050a0af3357491d7b # PCM
- 8e109e50e0a0b83a5098b056e13bf6db # DTS-HD HRA
- 185f1dd7264c4562b9022d963ac37424 # DD+
- f9f847ac70a0af62ea4a08280b859636 # DTS-ES
- 1c1a4c5e823891c75bc50380a6866f73 # DTS
- 240770601cc226190c367ef59aba7463 # AAC
- c2998bd0d90ed5621d8df281e839436e # DD
- 6ba9033150e7896bdc9ec4b44f2b230f # MP3
- a061e2e700f81932daf888599f8a8273 # Opus
# Movie Versions # Movie Versions
- 570bc9ebecd92723d2d21500f4be314c # Remaster - 570bc9ebecd92723d2d21500f4be314c # Remaster
- eca37840c13c6ef2dd0262b141a5482f # 4K Remaster - eca37840c13c6ef2dd0262b141a5482f # 4K Remaster
@@ -44,24 +44,6 @@ custom_formats:
- c9fd353f8f5f1baf56dc601c4cb29920 # PCOK - c9fd353f8f5f1baf56dc601c4cb29920 # PCOK
- c2863d2a50c9acad1fb50e53ece60817 # STAN - c2863d2a50c9acad1fb50e53ece60817 # STAN
# Audio
- 496f355514737f7d83bf7aa4d24f8169 # TrueHD Atmos
- 2f22d89048b01681dde8afe203bf2e95 # DTS:X
- 417804f7f2c4308c1f4c5d380d4c4475 # Atmos (undefined)
- 1af239278386be2919e1bcee0bde047e # DD+ Atmos
- 3cafb66171b47f226146a0770576870f # TrueHD
- dcf3ec6938fa32445f590a4da84256cd # DTS-HD MA
- a570d4a0e56a2874b64e5bfa55202a1b # FLAC
- e7c2fcae07cbada050a0af3357491d7b # PCM
- 8e109e50e0a0b83a5098b056e13bf6db # DTS-HD HRA
- 185f1dd7264c4562b9022d963ac37424 # DD+
- f9f847ac70a0af62ea4a08280b859636 # DTS-ES
- 1c1a4c5e823891c75bc50380a6866f73 # DTS
- 240770601cc226190c367ef59aba7463 # AAC
- c2998bd0d90ed5621d8df281e839436e # DD
- 6ba9033150e7896bdc9ec4b44f2b230f # MP3
- a061e2e700f81932daf888599f8a8273 # Opus
# Movie Versions # Movie Versions
- 570bc9ebecd92723d2d21500f4be314c # Remaster - 570bc9ebecd92723d2d21500f4be314c # Remaster
- eca37840c13c6ef2dd0262b141a5482f # 4K Remaster - eca37840c13c6ef2dd0262b141a5482f # 4K Remaster
@@ -44,24 +44,6 @@ custom_formats:
- c9fd353f8f5f1baf56dc601c4cb29920 # PCOK - c9fd353f8f5f1baf56dc601c4cb29920 # PCOK
- c2863d2a50c9acad1fb50e53ece60817 # STAN - c2863d2a50c9acad1fb50e53ece60817 # STAN
# Audio
- 496f355514737f7d83bf7aa4d24f8169 # TrueHD Atmos
- 2f22d89048b01681dde8afe203bf2e95 # DTS:X
- 417804f7f2c4308c1f4c5d380d4c4475 # Atmos (undefined)
- 1af239278386be2919e1bcee0bde047e # DD+ Atmos
- 3cafb66171b47f226146a0770576870f # TrueHD
- dcf3ec6938fa32445f590a4da84256cd # DTS-HD MA
- a570d4a0e56a2874b64e5bfa55202a1b # FLAC
- e7c2fcae07cbada050a0af3357491d7b # PCM
- 8e109e50e0a0b83a5098b056e13bf6db # DTS-HD HRA
- 185f1dd7264c4562b9022d963ac37424 # DD+
- f9f847ac70a0af62ea4a08280b859636 # DTS-ES
- 1c1a4c5e823891c75bc50380a6866f73 # DTS
- 240770601cc226190c367ef59aba7463 # AAC
- c2998bd0d90ed5621d8df281e839436e # DD
- 6ba9033150e7896bdc9ec4b44f2b230f # MP3
- a061e2e700f81932daf888599f8a8273 # Opus
# Movie Versions # Movie Versions
- 570bc9ebecd92723d2d21500f4be314c # Remaster - 570bc9ebecd92723d2d21500f4be314c # Remaster
- eca37840c13c6ef2dd0262b141a5482f # 4K Remaster - eca37840c13c6ef2dd0262b141a5482f # 4K Remaster
@@ -44,24 +44,6 @@ custom_formats:
- c9fd353f8f5f1baf56dc601c4cb29920 # PCOK - c9fd353f8f5f1baf56dc601c4cb29920 # PCOK
- c2863d2a50c9acad1fb50e53ece60817 # STAN - c2863d2a50c9acad1fb50e53ece60817 # STAN
# Audio
- 496f355514737f7d83bf7aa4d24f8169 # TrueHD Atmos
- 2f22d89048b01681dde8afe203bf2e95 # DTS:X
- 417804f7f2c4308c1f4c5d380d4c4475 # Atmos (undefined)
- 1af239278386be2919e1bcee0bde047e # DD+ Atmos
- 3cafb66171b47f226146a0770576870f # TrueHD
- dcf3ec6938fa32445f590a4da84256cd # DTS-HD MA
- a570d4a0e56a2874b64e5bfa55202a1b # FLAC
- e7c2fcae07cbada050a0af3357491d7b # PCM
- 8e109e50e0a0b83a5098b056e13bf6db # DTS-HD HRA
- 185f1dd7264c4562b9022d963ac37424 # DD+
- f9f847ac70a0af62ea4a08280b859636 # DTS-ES
- 1c1a4c5e823891c75bc50380a6866f73 # DTS
- 240770601cc226190c367ef59aba7463 # AAC
- c2998bd0d90ed5621d8df281e839436e # DD
- 6ba9033150e7896bdc9ec4b44f2b230f # MP3
- a061e2e700f81932daf888599f8a8273 # Opus
# Movie Versions # Movie Versions
- 570bc9ebecd92723d2d21500f4be314c # Remaster - 570bc9ebecd92723d2d21500f4be314c # Remaster
- eca37840c13c6ef2dd0262b141a5482f # 4K Remaster - eca37840c13c6ef2dd0262b141a5482f # 4K Remaster
@@ -68,31 +68,6 @@ custom_formats:
- c2216b7b8aa545dc1ce8388c618f8d57 # HD Bluray Tier 02 - c2216b7b8aa545dc1ce8388c618f8d57 # HD Bluray Tier 02
- d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene - d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene
# Audio Advanced
- 0d7824bb924701997f874e7ff7d4844a # TrueHD Atmos
- 9d00418ba386a083fbf4d58235fc37ef # DTS:X
- b6fbafa7942952a13e17e2b1152b539a # Atmos (undefined)
- 4232a509ce60c4e208d13825b7c06264 # DDPlus Atmos
- 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD
- c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA
- 851bd64e04c9374c51102be3dd9ae4cc # FLAC
- 30f70576671ca933adbdcfc736a69718 # PCM
- cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA
- 63487786a8b01b7f20dd2bc90dd4a477 # DDPlus
- c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES
- 5964f2a8b3be407d083498e4459d05d0 # DTS
- a50b8a0c62274a7c38b09a9619ba9d86 # AAC
- dbe00161b08a25ac6154c55f95e6318d # DD
- 3e8b714263b26f486972ee1e0fe7606c # MP3
- 28f6ef16d61e2d1adfce3156ed8257e3 # Opus
- bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono
- 834e534f103938853ffced4203b53e72 # 2.0 Stereo
- 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound
- 1895195e84767de180653914ce207245 # 4.0 Sound
- 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround
- 9fb6d778592c293467437593ef394bf1 # 6.1 Surround
- 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround
# Unwanted # Unwanted
- 15a05bc7c1a36e2b57fd628f8977e2fc # AV1 - 15a05bc7c1a36e2b57fd628f8977e2fc # AV1
- b4a1b3d705159cdca36d71e57ca86871 # Anime Raws - b4a1b3d705159cdca36d71e57ca86871 # Anime Raws
@@ -0,0 +1,68 @@
custom_formats:
- trash_ids:
# HDR Formats
- 2b239ed870daba8126a53bd5dc8dc1c8 # DV HDR10+
- 7878c33f1963fefb3d6c8657d46c2f0a # DV HDR10
- 6d0d8de7b57e35518ac0308b0ddf404e # DV
- 1f733af03141f068a540eec352589a89 # DV HLG
- 27954b0a80aab882522a88a4d9eae1cd # DV SDR
- a3d82cbef5039f8d295478d28a887159 # HDR10+
- 3497799d29a085e2ac2df9d468413c94 # HDR10
- 3e2c4e748b64a1a1118e0ea3f4cf6875 # HDR
- bb019e1cd00f304f80971c965de064dc # HDR (undefined)
- 2a7e3be05d3861d6df7171ec74cad727 # PQ
- 17e889ce13117940092308f48b48b45b # HLG
- 9b27ab6498ec0f31a3353992e19434ca # DV (WEBDL)
# Miscellaneous
- ec8fa7296b64e8cd390a1600981f3923 # Repack/Proper
- eb3d5cc0a2be0db205fb823640db6a3c # Repack v2
- 44e7c4de10ae50265753082e5dc76047 # Repack v3
- b735f09d3c025cbb7d75a5d38325b73b # Remaster
- 3bc5f395426614e155e585a2f056cdf1 # Season Pack
# Streaming Services
- d660701077794679fd59e8bdf4ce3a29 # AMZN
- f67c9ca88f463a48346062e8ad07713f # ATVP
- 77a7b25585c18af08f60b1547bb9b4fb # CC
- 36b72f59f4ea20aad9316f475f2d9fbb # DCU
- 89358767a60cc28783cdc3d0be9388a4 # DSNP
- a880d6abc21e7c16884f3ae393f84179 # HMAX
- 7a235133c87f7da4c8cccceca7e3c7a6 # HBO
- f6cce30f1733d5c8194222a7507909bb # HULU
- 0ac24a2a68a9700bcb7eeca8e5cd644c # iT
- 81d1fbf600e2540cee87f3a23f9d3c1c # MAX
- d34870697c9db575f17700212167be23 # NF
- c67a75ae4a1715f2bb4d492755ba4195 # PMTP
- 1656adc6d7bb2c8cca6acfb6592db421 # PCOK
- ae58039e1319178e6be73caab5c42166 # SHO
- 1efe8da11bfd74fbbcd4d8117ddb9213 # STAN
- 9623c5c9cac8e939c1b9aedd32f640bf # SYFY
- 9623c5c9cac8e939c1b9aedd32f640bf # UHD Streaming Boost
- d2d299244a92b8a52d4921ce3897a256 # UHD Streaming Cut
# Release Group Tiers
- 9965a052eb87b0d10313b1cea89eb451 # Remux Tier 01
- 8a1d0c3d7497e741736761a1da866a2e # Remux Tier 02
- d6819cba26b1a6508138d25fb5e32293 # HD Bluray Tier 01
- c2216b7b8aa545dc1ce8388c618f8d57 # HD Bluray Tier 02
- e6258996055b9fbab7e9cb2f75819294 # WEB Tier 01
- 58790d4e2fdcd9733aa7ae68ba2bb503 # WEB Tier 02
- d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03
- d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene
# Unwanted
- 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK
- 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ
- e2315f990da2e2cbfc9fa5b7a6fcfe48 # LQ (Release Title)
- 9b64dff695c2115facf1b6ea59c9bd07 # x265 (no HDR/DV)
- 83304f261cf516bb208c18c54c0adf97 # SDR (no WEBDL)
- fbcb31d8dabd2a319072b84fc0b7249c # Extras
- 15a05bc7c1a36e2b57fd628f8977e2fc # AV1
- 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups
- 82d40da2bc6923f41e14394075dd4b03 # No-RlsGroup
- e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated
- 06d66ab109d4d2eddb2794d21526d140 # Retags
- b735f09d3c025cbb7d75a5d38325b73b # Upscaled
assign_scores_to:
- name: Remux
@@ -0,0 +1,22 @@
quality_profiles:
- name: Remux
upgrade:
allowed: true
until_quality: 'Bluray-2160p Remux'
until_score: 10000
min_format_score: 0
score_set: default
quality_sort: top
qualities:
- name: 'Bluray-2160p Remux'
- name: 'Bluray-1080p Remux'
- name: Bluray-2160p
- name: WEB 2160p
qualities:
- WEBDL-2160p
- WEBRip-2160p
- name: Bluray-1080p
- name: WEB 1080p
qualities:
- WEBDL-1080p
- WEBRip-1080p
@@ -51,31 +51,6 @@ custom_formats:
- d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03 - d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03
- d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene - d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene
# Audio Advanced
- 0d7824bb924701997f874e7ff7d4844a # TrueHD Atmos
- 9d00418ba386a083fbf4d58235fc37ef # DTS:X
- b6fbafa7942952a13e17e2b1152b539a # Atmos (undefined)
- 4232a509ce60c4e208d13825b7c06264 # DDPlus Atmos
- 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD
- c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA
- 851bd64e04c9374c51102be3dd9ae4cc # FLAC
- 30f70576671ca933adbdcfc736a69718 # PCM
- cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA
- 63487786a8b01b7f20dd2bc90dd4a477 # DDPlus
- c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES
- 5964f2a8b3be407d083498e4459d05d0 # DTS
- a50b8a0c62274a7c38b09a9619ba9d86 # AAC
- dbe00161b08a25ac6154c55f95e6318d # DD
- 3e8b714263b26f486972ee1e0fe7606c # MP3
- 28f6ef16d61e2d1adfce3156ed8257e3 # Opus
- bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono
- 834e534f103938853ffced4203b53e72 # 2.0 Stereo
- 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound
- 1895195e84767de180653914ce207245 # 4.0 Sound
- 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround
- 9fb6d778592c293467437593ef394bf1 # 6.1 Surround
- 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround
# Unwanted # Unwanted
- 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK - 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK
- 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ - 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ
@@ -85,7 +60,6 @@ custom_formats:
- fbcb31d8dabd2a319072b84fc0b7249c # Extras - fbcb31d8dabd2a319072b84fc0b7249c # Extras
- 15a05bc7c1a36e2b57fd628f8977e2fc # AV1 - 15a05bc7c1a36e2b57fd628f8977e2fc # AV1
- 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups - 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups
- 82d40da2bc6923f41e14394075dd4b03 # No-RlsGroup
- e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated - e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated
- 06d66ab109d4d2eddb2794d21526d140 # Retags - 06d66ab109d4d2eddb2794d21526d140 # Retags
- b735f09d3c025cbb7d75a5d38325b73b # Upscaled - b735f09d3c025cbb7d75a5d38325b73b # Upscaled
@@ -51,31 +51,6 @@ custom_formats:
- d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03 - d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03
- d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene - d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene
# Audio Advanced
- 0d7824bb924701997f874e7ff7d4844a # TrueHD Atmos
- 9d00418ba386a083fbf4d58235fc37ef # DTS:X
- b6fbafa7942952a13e17e2b1152b539a # Atmos (undefined)
- 4232a509ce60c4e208d13825b7c06264 # DDPlus Atmos
- 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD
- c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA
- 851bd64e04c9374c51102be3dd9ae4cc # FLAC
- 30f70576671ca933adbdcfc736a69718 # PCM
- cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA
- 63487786a8b01b7f20dd2bc90dd4a477 # DDPlus
- c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES
- 5964f2a8b3be407d083498e4459d05d0 # DTS
- a50b8a0c62274a7c38b09a9619ba9d86 # AAC
- dbe00161b08a25ac6154c55f95e6318d # DD
- 3e8b714263b26f486972ee1e0fe7606c # MP3
- 28f6ef16d61e2d1adfce3156ed8257e3 # Opus
- bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono
- 834e534f103938853ffced4203b53e72 # 2.0 Stereo
- 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound
- 1895195e84767de180653914ce207245 # 4.0 Sound
- 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround
- 9fb6d778592c293467437593ef394bf1 # 6.1 Surround
- 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround
# Unwanted # Unwanted
- 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK - 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK
- 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ - 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ
@@ -85,7 +60,6 @@ custom_formats:
- fbcb31d8dabd2a319072b84fc0b7249c # Extras - fbcb31d8dabd2a319072b84fc0b7249c # Extras
- 15a05bc7c1a36e2b57fd628f8977e2fc # AV1 - 15a05bc7c1a36e2b57fd628f8977e2fc # AV1
- 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups - 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups
- 82d40da2bc6923f41e14394075dd4b03 # No-RlsGroup
- e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated - e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated
- 06d66ab109d4d2eddb2794d21526d140 # Retags - 06d66ab109d4d2eddb2794d21526d140 # Retags
- b735f09d3c025cbb7d75a5d38325b73b # Upscaled - b735f09d3c025cbb7d75a5d38325b73b # Upscaled
@@ -51,31 +51,6 @@ custom_formats:
- d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03 - d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03
- d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene - d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene
# Audio Advanced
- 0d7824bb924701997f874e7ff7d4844a # TrueHD Atmos
- 9d00418ba386a083fbf4d58235fc37ef # DTS:X
- b6fbafa7942952a13e17e2b1152b539a # Atmos (undefined)
- 4232a509ce60c4e208d13825b7c06264 # DDPlus Atmos
- 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD
- c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA
- 851bd64e04c9374c51102be3dd9ae4cc # FLAC
- 30f70576671ca933adbdcfc736a69718 # PCM
- cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA
- 63487786a8b01b7f20dd2bc90dd4a477 # DDPlus
- c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES
- 5964f2a8b3be407d083498e4459d05d0 # DTS
- a50b8a0c62274a7c38b09a9619ba9d86 # AAC
- dbe00161b08a25ac6154c55f95e6318d # DD
- 3e8b714263b26f486972ee1e0fe7606c # MP3
- 28f6ef16d61e2d1adfce3156ed8257e3 # Opus
- bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono
- 834e534f103938853ffced4203b53e72 # 2.0 Stereo
- 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound
- 1895195e84767de180653914ce207245 # 4.0 Sound
- 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround
- 9fb6d778592c293467437593ef394bf1 # 6.1 Surround
- 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround
# Unwanted # Unwanted
- 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK - 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK
- 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ - 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ
@@ -51,31 +51,6 @@ custom_formats:
- d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03 - d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03
- d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene - d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene
# Audio Advanced
- 0d7824bb924701997f874e7ff7d4844a # TrueHD Atmos
- 9d00418ba386a083fbf4d58235fc37ef # DTS:X
- b6fbafa7942952a13e17e2b1152b539a # Atmos (undefined)
- 4232a509ce60c4e208d13825b7c06264 # DDPlus Atmos
- 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD
- c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA
- 851bd64e04c9374c51102be3dd9ae4cc # FLAC
- 30f70576671ca933adbdcfc736a69718 # PCM
- cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA
- 63487786a8b01b7f20dd2bc90dd4a477 # DDPlus
- c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES
- 5964f2a8b3be407d083498e4459d05d0 # DTS
- a50b8a0c62274a7c38b09a9619ba9d86 # AAC
- dbe00161b08a25ac6154c55f95e6318d # DD
- 3e8b714263b26f486972ee1e0fe7606c # MP3
- 28f6ef16d61e2d1adfce3156ed8257e3 # Opus
- bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono
- 834e534f103938853ffced4203b53e72 # 2.0 Stereo
- 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound
- 1895195e84767de180653914ce207245 # 4.0 Sound
- 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround
- 9fb6d778592c293467437593ef394bf1 # 6.1 Surround
- 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround
# Unwanted # Unwanted
- 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK - 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK
- 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ - 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ
@@ -51,31 +51,6 @@ custom_formats:
- d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03 - d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03
- d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene - d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene
# Audio Advanced
- 0d7824bb924701997f874e7ff7d4844a # TrueHD Atmos
- 9d00418ba386a083fbf4d58235fc37ef # DTS:X
- b6fbafa7942952a13e17e2b1152b539a # Atmos (undefined)
- 4232a509ce60c4e208d13825b7c06264 # DDPlus Atmos
- 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD
- c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA
- 851bd64e04c9374c51102be3dd9ae4cc # FLAC
- 30f70576671ca933adbdcfc736a69718 # PCM
- cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA
- 63487786a8b01b7f20dd2bc90dd4a477 # DDPlus
- c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES
- 5964f2a8b3be407d083498e4459d05d0 # DTS
- a50b8a0c62274a7c38b09a9619ba9d86 # AAC
- dbe00161b08a25ac6154c55f95e6318d # DD
- 3e8b714263b26f486972ee1e0fe7606c # MP3
- 28f6ef16d61e2d1adfce3156ed8257e3 # Opus
- bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono
- 834e534f103938853ffced4203b53e72 # 2.0 Stereo
- 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound
- 1895195e84767de180653914ce207245 # 4.0 Sound
- 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround
- 9fb6d778592c293467437593ef394bf1 # 6.1 Surround
- 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround
# Unwanted # Unwanted
- 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK - 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK
- 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ - 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ
@@ -8,12 +8,24 @@ quality_profiles:
score_set: default score_set: default
quality_sort: top quality_sort: top
qualities: qualities:
- name: WEB 2160p - name: 'WEB 2160p'
qualities: qualities:
- WEBDL-2160p - WEBDL-2160p
- WEBRip-2160p - WEBRip-2160p
- name: Bluray-1080p - name: 'WEB 1080p'
- name: WEB 1080p
qualities: qualities:
- WEBDL-1080p - WEBDL-1080p
- WEBRip-1080p - WEBRip-1080p
- name: HDTV-2160p
- name: Bluray-720p
- name: 'WEB 720p'
qualities:
- WEBDL-720p
- WEBRip-720p
- name: HDTV-1080p
- name: HDTV-720p
- name: 'WEB 480p'
qualities:
- WEBDL-480p
- WEBRip-480p
- name: SDTV
@@ -51,31 +51,6 @@ custom_formats:
- d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03 - d84935abd3f8556dcd51d4f27e22d0a6 # WEB Tier 03
- d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene - d0c516558625b04b363fa6c5c2c7cfd4 # WEB Scene
# Audio Advanced
- 0d7824bb924701997f874e7ff7d4844a # TrueHD Atmos
- 9d00418ba386a083fbf4d58235fc37ef # DTS:X
- b6fbafa7942952a13e17e2b1152b539a # Atmos (undefined)
- 4232a509ce60c4e208d13825b7c06264 # DDPlus Atmos
- 1808e4b9cee74e064dfae3f1db99dbfe # TrueHD
- c429417a57ea8c41d57e6990a8b0033f # DTS-HD MA
- 851bd64e04c9374c51102be3dd9ae4cc # FLAC
- 30f70576671ca933adbdcfc736a69718 # PCM
- cfa5fbd8f02a86fc55d8d223d06a5e1f # DTS-HD HRA
- 63487786a8b01b7f20dd2bc90dd4a477 # DDPlus
- c1a25cd67b5d2e08287c957b1eb903ec # DTS-ES
- 5964f2a8b3be407d083498e4459d05d0 # DTS
- a50b8a0c62274a7c38b09a9619ba9d86 # AAC
- dbe00161b08a25ac6154c55f95e6318d # DD
- 3e8b714263b26f486972ee1e0fe7606c # MP3
- 28f6ef16d61e2d1adfce3156ed8257e3 # Opus
- bd6dd5e043aa27ff4696a08d011c7d96 # 1.0 Mono
- 834e534f103938853ffced4203b53e72 # 2.0 Stereo
- 42cba7e38c7947a6d1d0a62580ee6d62 # 3.0 Sound
- 1895195e84767de180653914ce207245 # 4.0 Sound
- 3fbafa924f361e66fbc6187af82dfa85 # 5.1 Surround
- 9fb6d778592c293467437593ef394bf1 # 6.1 Surround
- 204c8c3e7315bb0ea81332774fa888d6 # 7.1 Surround
# Unwanted # Unwanted
- 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK - 85c61753df5da1fb2aab6f2a47426b09 # BR-DISK
- 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ - 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ
@@ -8,12 +8,24 @@ quality_profiles:
score_set: default score_set: default
quality_sort: top quality_sort: top
qualities: qualities:
- name: WEB 2160p - name: 'WEB 2160p'
qualities: qualities:
- WEBDL-2160p - WEBDL-2160p
- WEBRip-2160p - WEBRip-2160p
- name: Bluray-1080p - name: 'WEB 1080p'
- name: WEB 1080p
qualities: qualities:
- WEBDL-1080p - WEBDL-1080p
- WEBRip-1080p - WEBRip-1080p
- name: HDTV-2160p
- name: Bluray-720p
- name: 'WEB 720p'
qualities:
- WEBDL-720p
- WEBRip-720p
- name: HDTV-1080p
- name: HDTV-720p
- name: 'WEB 480p'
qualities:
- WEBDL-480p
- WEBRip-480p
- name: SDTV
@@ -6,7 +6,7 @@ networks:
services: services:
recyclarr: recyclarr:
container_name: recyclarr container_name: recyclarr
image: ghcr.io/recyclarr/recyclarr:7 image: ghcr.io/recyclarr/recyclarr:8
restart: unless-stopped restart: unless-stopped
security_opt: ['no-new-privileges:true'] # Prevents privilege escalation - https://recyclarr.dev/wiki/installation/docker/#prevent-in-container-privilege-escalation security_opt: ['no-new-privileges:true'] # Prevents privilege escalation - https://recyclarr.dev/wiki/installation/docker/#prevent-in-container-privilege-escalation
user: "{{ service_user.uid }}:{{ service_user.uid }}" user: "{{ service_user.uid }}:{{ service_user.uid }}"
@@ -18,6 +18,10 @@ radarr:
- config: radarr-remux-qualities.yml - config: radarr-remux-qualities.yml
- config: radarr-remux-custom_formats.yml - config: radarr-remux-custom_formats.yml
# Encode
- config: radarr-encode-qualities.yml
- config: radarr-encode-custom_formats.yml
# Web # Web
- config: radarr-web-qualities.yml - config: radarr-web-qualities.yml
- config: radarr-web-custom_formats.yml - config: radarr-web-custom_formats.yml
-29
View File
@@ -1,29 +0,0 @@
- name: Create install directory
file:
path: "{{ install_directory }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination
template:
src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
validate: docker compose -f %s config
become: true
- name: Copy config.js to destination
template:
src: config.js
dest: "{{ install_directory }}/renovate/config.js"
mode: "{{ docker_compose_file_mask }}"
become: true
- name: Start docker container
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
pull: always
remove_orphans: yes
@@ -1,14 +0,0 @@
module.exports = {
endpoint: "git.{{ personal_domain }}/api/v2",
token: '{{ renovate_gitea_token }}',
platform: 'gitea',
dryRun: true,
autodiscover: true,
onboarding: false,
redisUrl: 'redis://redis',
repositoryCache: 'enabled',
persistRepoData: true,
binarySource: "docker",
dockerUser: "{{ primary_uid }}",
baseDir: "{{ data_dir }}/renovate",
};
@@ -1,26 +0,0 @@
networks:
docker-socket-proxy:
external: true
services:
renovate:
container_name: renovate
image: renovate/renovate:slim
restart: unless-stopped
depends_on:
- redis
networks:
- docker-socket-proxy
user: "{{ service_user.uid }}:{{ service_user.group }}"
environment:
- TZ={{ timezone }}
- DOCKER_HOST=tcp://docker_socket_proxy:2375
- "RENOVATE_TOKEN={{ renovate_gitea_token }}"
volumes:
- "{{ data_dir }}/renovate:/{{ data_dir }}/renovate" # These must be the same
- ./config.js:/usr/src/app/config.js:ro
redis:
image: redis:7-alpine
restart: unless-stopped
-8
View File
@@ -1,8 +0,0 @@
renovate_gitea_token: !vault |
$ANSIBLE_VAULT;1.1;AES256
61383064643566343633633962376238346137633933643634353564316266656338333665613235
3230613339633561313064393163393537623763393336300a383332626538376335613763313439
64326566393761666266303438313435346535626231376661653863663664623839663431363632
6434306532613065650a636562663030363162396435346262353839653736343530393365633331
65366534333234353239376566326234666566303038396661343137316265306433313235366530
6164656437346131376165613136363161646437343038393266
-31
View File
@@ -1,31 +0,0 @@
- name: Create service user
user:
name: "{{ role_name }}"
groups: "{{ media_group }}"
append: yes
system: true
register: service_user
become: true
- name: Create install directory
file:
path: "{{ install_directory }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination
template:
src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
validate: docker compose -f %s config
become: true
- name: Start docker containers
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
pull: always
remove_orphans: yes
@@ -1,25 +0,0 @@
networks:
traefik:
external: true
services:
sabnzbd:
container_name: sabnzbd
image: lscr.io/linuxserver/sabnzbd:latest
restart: unless-stopped
networks:
- traefik
environment:
- "PUID={{ service_user.uid }}"
- "PGID={{ media_gid }}"
- "TZ={{ timezone }}"
- "UMASK=002"
volumes:
- "{{ data_dir }}/{{ role_name }}:/config"
- "{{ media_storage_mnt }}/data/usenet:/data/usenet"
labels:
traefik.enable: true
traefik.http.routers.{{ role_name }}.rule: "Host(`{{ role_name }}.local.{{ personal_domain }}`)"
traefik.http.routers.{{ role_name }}.middlewares: lan-whitelist@file
traefik.http.services.sabnzbd.loadbalancer.server.port: 8080
@@ -0,0 +1 @@
'(.*\.)?pinterest.com$'
+1 -1
View File
@@ -1,5 +1,5 @@
- name: restart searxng - name: restart searxng
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}" project_src: "{{ install_directory }}/{{ role_name }}"
restarted: true state: restarted
+8
View File
@@ -23,6 +23,14 @@
become: true become: true
notify: restart searxng notify: restart searxng
- name: Copy hostname lists to destination
copy:
src: hostnames/
dest: "{{ data_dir }}/{{ role_name }}/"
owner: "{{ docker_user }}"
become: true
notify: restart searxng
- name: Start docker container - name: Start docker container
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}" project_src: "{{ install_directory }}/{{ role_name }}"
@@ -6,10 +6,11 @@ networks:
services: services:
searxng: searxng:
container_name: searxng container_name: searxng
image: searxng/searxng image: ghcr.io/searxng/searxng
restart: unless-stopped restart: unless-stopped
networks: networks:
- traefik - traefik
- default
volumes: volumes:
- "{{ data_dir }}/{{ role_name }}:/etc/searxng" - "{{ data_dir }}/{{ role_name }}:/etc/searxng"
cap_drop: cap_drop:
@@ -21,7 +22,7 @@ services:
labels: labels:
traefik.enable: true traefik.enable: true
traefik.http.routers.searxng.rule: "Host(`search.{{ personal_domain }}`)" traefik.http.routers.searxng.rule: "Host(`search.{{ personal_domain }}`)"
#traefik.http.routers.searxng.middlewares: lan-whitelist@file traefik.http.routers.searxng.middlewares: lan-whitelist@file
redis: redis:
image: redis:alpine image: redis:alpine
File diff suppressed because it is too large. Load diff
File renamed without changes.
@@ -5,7 +5,7 @@ networks:
services: services:
{{ role_name }}: {{ role_name }}:
container_name: "{{ role_name }}" container_name: "{{ role_name }}"
image: fallenbagel/jellyseerr:latest image: ghcr.io/seerr-team/seerr:latest
restart: unless-stopped restart: unless-stopped
networks: networks:
- traefik - traefik
-4
View File
@@ -1,4 +0,0 @@
- name: restart synapse
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
restarted: true
-77
View File
@@ -1,77 +0,0 @@
- name: Create service user
user:
name: "{{ role_name }}"
system: true
register: service_user
become: true
- name: Create install directory
file:
path: "{{ install_directory }}/{{ role_name }}"
state: directory
owner: "{{ docker_user }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Copy docker-compose file to destination
template:
src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
validate: docker compose -f %s config
become: true
- name: Copy homeserver.yaml to destination
template:
src: homeserver.yaml
dest: "{{ install_directory }}/synapse/homeserver.yaml"
owner: "{{ service_user.uid }}"
mode: "{{ docker_compose_file_mask }}"
notify: restart synapse
become: true
- name: Create config directory and set synapse user to owner
file:
path: "{{ data_dir }}/synapse"
state: directory
owner: "{{ service_user.uid }}"
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Create nginx config directory
file:
path: "{{ data_dir }}/nginx/synapse/www/.well-known/matrix/"
state: directory
mode: "{{ docker_compose_directory_mask }}"
become: true
- name: Install nginx config file
template:
src: nginx/matrix.conf
dest: "{{ data_dir }}/nginx/synapse/matrix.conf"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
become: true
- name: Install well known client file
template:
src: nginx/client.json
dest: "{{ data_dir }}/nginx/synapse/www/.well-known/matrix/client"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
become: true
- name: Install well known server file
template:
src: nginx/server.json
dest: "{{ data_dir }}/nginx/synapse/www/.well-known/matrix/server"
owner: "{{ docker_user }}"
mode: "{{ docker_compose_file_mask }}"
become: true
- name: Start docker container
community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/{{ role_name }}"
pull: always
remove_orphans: yes
@@ -1,67 +0,0 @@
networks:
traefik:
external: true
services:
synapse:
container_name: "synapse"
image: matrixdotorg/synapse
restart: unless-stopped
depends_on:
- db
networks:
- traefik
- default
environment:
- "UID={{ service_user.uid }}"
- "GID={{ service_user.uid }}"
- "TZ={{ timezone }}"
volumes:
- "{{ data_dir }}/{{ role_name }}:/data"
- ./homeserver.yaml:/data/homeserver.yaml
labels:
traefik.enable: true
traefik.http.routers.synapse.rule: "Host(`matrix.{{ personal_domain }}`) || (Host(`{{ personal_domain }}`) && PathPrefix(`/_matrix/`))"
db:
image: postgres:14-alpine
restart: unless-stopped
networks:
- default
environment:
- POSTGRES_USER=synapse
- POSTGRES_PASSWORD=synapse
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
volumes:
- "{{ data_dir }}/postgres/synapse:/var/lib/postgresql/data"
redis:
networks:
- default
image: redis:7-alpine
restart: unless-stopped
volumes:
- "{{ data_dir }}/redis/synapse:/data"
admin:
image: awesometechnologies/synapse-admin:latest
restart: unless-stopped
networks:
- traefik
labels:
traefik.enable: true
traefik.http.routers.synapse-admin.rule: "Host(`synapse-admin.local.{{ personal_domain }}`)"
traefik.http.routers.synapse-admin.middlewares: lan-whitelist@file
nginx:
image: nginx:latest
restart: unless-stopped
networks:
- traefik
volumes:
- "{{ data_dir }}/nginx/synapse/matrix.conf:/etc/nginx/conf.d/matrix.conf"
- "{{ data_dir }}/nginx/synapse/www:/var/www"
labels:
traefik.enable: true
traefik.http.routers.matrix.rule: "Host(`{{ personal_domain }}`)"
@@ -1,42 +0,0 @@
server_name: "{{ personal_domain }}"
pid_file: /data/homeserver.pid
public_baseurl: "https://matrix.{{ personal_domain }}"
ip_range_whitelist:
- 10.0.0.0/24
acme:
enabled: false
database:
name: psycopg2
args:
user: synapse
password: synapse
database: synapse
host: db
redis:
enabled: true
host: redis
port: 6379
listeners:
- port: 8008
tls: false
type: http
x_forwarded: true
resources:
- names: [client, federation]
compress: false
registration_shared_secret: "{{ synapse_registration_shared_secret }}"
report_stats: true
media_store_path: /data/media_store
uploads_path: /data/uploads
trusted_key_servers:
- server_name: matrix.org
suppress_key_server_warning: true
@@ -1,5 +0,0 @@
{
"m.homeserver": {
"base_url": "https://matrix.{{ personal_domain }}"
}
}
@@ -1,17 +0,0 @@
server {
listen 80 default_server;
server_name {{ personal_domain }};
# Traefik -> nginx -> synapse
location /_matrix {
proxy_pass http://synapse:8008;
proxy_set_header X-Forwarded-For $remote_addr;
client_max_body_size 128m;
}
location /.well-known/matrix/ {
root /var/www/;
default_type application/json;
add_header Access-Control-Allow-Origin *;
}
}
@@ -1,4 +0,0 @@
{
"m.server": "matrix.{{ personal_domain }}:443"
}
-13
View File
@@ -1,13 +0,0 @@
synapse_registration_shared_secret: !vault |
$ANSIBLE_VAULT;1.1;AES256
33393864663831636636616361333635343366613633353234363761303235333361376230333863
6432326363656232323531636139356663623734313161350a653262636439363334353266393563
61646265303161396630653839346266336335613030623237363537663839306331333064626436
6262623236353061380a306335356365633164313639633031353663373633306539343464376639
37396535386631363866343030653835636437303230333430303033616364383734626563336265
37643164393334316534386266613930383136663934613233313939316533643164623163626334
31396163383132333365383364323866626264323234353939653236386231636536666261616534
37353930663863343533636536356363373432383437643965663636323234303730623434386264
31653131653964376164623039616166376162323235363164303163353363643733643761353264
63393632366139313538656566393239393465653536356131333430323165356263323839666636
353466373866616536383761343036666561
-639
View File
@@ -1,639 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Description: Use conditions to kill a stream
Author: Blacktwin, Arcanemagus, Samwiseg0, JonnyWong16, DirtyCajunRice
Adding the script to Tautulli:
Tautulli > Settings > Notification Agents > Add a new notification agent >
Script
Configuration:
Tautulli > Settings > Notification Agents > New Script > Configuration:
Script Folder: /path/to/your/scripts
Script File: ./kill_stream.py (Should be selectable in a dropdown list)
Script Timeout: {timeout}
Description: Kill stream(s)
Save
Triggers:
Tautulli > Settings > Notification Agents > New Script > Triggers:
Check: Playback Start and/or Playback Pause
Save
Conditions:
Tautulli > Settings > Notification Agents > New Script > Conditions:
Set Conditions: [{condition} | {operator} | {value} ]
Save
Script Arguments:
Tautulli > Settings > Notification Agents > New Script > Script Arguments:
Select: Playback Start, Playback Pause
Arguments: --jbop SELECTOR --userId {user_id} --username {username}
--sessionId {session_id} --notify notifierID
--interval 30 --limit 1200
--richMessage RICH_TYPE --serverName {server_name}
--plexUrl {plex_url} --posterUrl {poster_url}
--richColor '#E5A00D'
--killMessage 'Your message here.'
Save
Close
"""
from __future__ import print_function
from __future__ import unicode_literals
from builtins import object
from builtins import str
import os
import sys
import json
import time
import argparse
from datetime import datetime
from requests import Session
from requests.adapters import HTTPAdapter
from requests.exceptions import RequestException
TAUTULLI_URL = ''
TAUTULLI_APIKEY = ''
TAUTULLI_PUBLIC_URL = ''
TAUTULLI_URL = os.getenv('TAUTULLI_URL', TAUTULLI_URL)
TAUTULLI_PUBLIC_URL = os.getenv('TAUTULLI_PUBLIC_URL', TAUTULLI_PUBLIC_URL)
TAUTULLI_APIKEY = os.getenv('TAUTULLI_APIKEY', TAUTULLI_APIKEY)
TAUTULLI_ENCODING = os.getenv('TAUTULLI_ENCODING', 'UTF-8')
VERIFY_SSL = False
if TAUTULLI_PUBLIC_URL != '/':
# Check to see if there is a public URL set in Tautulli
TAUTULLI_LINK = TAUTULLI_PUBLIC_URL
else:
TAUTULLI_LINK = TAUTULLI_URL
SUBJECT_TEXT = "Tautulli has killed a stream."
BODY_TEXT = "Killed session ID '{id}'. Reason: {message}"
BODY_TEXT_USER = "Killed {user}'s stream. Reason: {message}."
SELECTOR = ['stream', 'allStreams', 'paused']
RICH_TYPE = ['discord', 'slack']
TAUTULLI_ICON = 'https://github.com/Tautulli/Tautulli/raw/master/data/interfaces/default/images/logo-circle.png'
def utc_now_iso():
"""Get current time in ISO format"""
utcnow = datetime.utcnow()
return utcnow.isoformat()
def hex_to_int(value):
"""Convert hex value to integer"""
try:
return int(value, 16)
except (ValueError, TypeError):
return 0
def arg_decoding(arg):
"""Decode args, encode UTF-8"""
if sys.version_info[0] < 3:
return arg.decode(TAUTULLI_ENCODING).encode('UTF-8')
else:
return arg
def debug_dump_vars():
"""Dump parameters for debug"""
print('Tautulli URL - ' + TAUTULLI_URL)
print('Tautulli Public URL - ' + TAUTULLI_PUBLIC_URL)
print('Verify SSL - ' + str(VERIFY_SSL))
print('Tautulli API key - ' + TAUTULLI_APIKEY[-4:]
.rjust(len(TAUTULLI_APIKEY), "x"))
def get_all_streams(tautulli, user_id=None):
"""Get a list of all current streams.
Parameters
----------
user_id : int
The ID of the user to grab sessions for.
tautulli : obj
Tautulli object.
Returns
-------
objects
The of stream objects.
"""
sessions = tautulli.get_activity()['sessions']
if user_id:
streams = [Stream(session=s) for s in sessions if s['user_id'] == user_id]
else:
streams = [Stream(session=s) for s in sessions]
return streams
def notify(all_opts, message, kill_type=None, stream=None, tautulli=None):
"""Decides which notifier type to use"""
if all_opts.notify and all_opts.richMessage:
rich_notify(all_opts.notify, all_opts.richMessage, all_opts.richColor, kill_type,
all_opts.serverName, all_opts.plexUrl, all_opts.posterUrl, message, stream, tautulli)
elif all_opts.notify:
basic_notify(all_opts.notify, all_opts.sessionId, all_opts.username, message, stream, tautulli)
def rich_notify(notifier_id, rich_type, color=None, kill_type=None, server_name=None,
plex_url=None, poster_url=None, message=None, stream=None, tautulli=None):
"""Decides which rich notifier type to use. Set default values for empty variables
Parameters
----------
notifier_id : int
The ID of the user to grab sessions for.
rich_type : str
Contains 'discord' or 'slack'.
color : Union[int, str]
Hex string or integer representation of color.
kill_type : str
The kill type used.
server_name : str
The name of the plex server.
plex_url : str
Plex media URL.
poster_url : str
The media poster URL.
message : str
Message sent to the client.
stream : obj
Stream object.
tautulli : obj
Tautulli object.
"""
notification = Notification(notifier_id, None, None, tautulli, stream)
# Initialize Variables
title = ''
footer = ''
# Set a default server_name if none is provided
if server_name is None:
server_name = 'Plex Server'
# Set a default color if none is provided
if color is None:
color = '#E5A00D'
# Set a default plexUrl if none is provided
if plex_url is None:
plex_url = 'https://app.plex.tv'
# Set a default posterUrl if none is provided
if poster_url is None:
poster_url = TAUTULLI_ICON
# Set a default message if none is provided
if message is None:
message = 'The server owner has ended the stream.'
if kill_type == 'Stream':
title = "Killed {}'s stream.".format(stream.friendly_name)
footer = '{} | Kill {}'.format(server_name, kill_type)
elif kill_type == 'Paused':
title = "Killed {}'s paused stream.".format(stream.friendly_name)
footer = '{} | Kill {}'.format(server_name, kill_type)
elif kill_type == 'All Streams':
title = "Killed {}'s stream.".format(stream.friendly_name)
footer = '{} | Kill {}'.format(server_name, kill_type)
poster_url = TAUTULLI_ICON
plex_url = 'https://app.plex.tv'
if rich_type == 'discord':
color = hex_to_int(color.lstrip('#'))
notification.send_discord(title, color, poster_url, plex_url, message, footer)
elif rich_type == 'slack':
notification.send_slack(title, color, poster_url, plex_url, message, footer)
def basic_notify(notifier_id, session_id, username=None, message=None, stream=None, tautulli=None):
"""Basic notifier"""
notification = Notification(notifier_id, SUBJECT_TEXT, BODY_TEXT, tautulli, stream)
if username:
body = BODY_TEXT_USER.format(user=username,
message=message)
else:
body = BODY_TEXT.format(id=session_id, message=message)
notification.send(SUBJECT_TEXT, body)
class Tautulli(object):
def __init__(self, url, apikey, verify_ssl=False, debug=None):
self.url = url
self.apikey = apikey
self.debug = debug
self.session = Session()
self.adapters = HTTPAdapter(max_retries=3,
pool_connections=1,
pool_maxsize=1,
pool_block=True)
self.session.mount('http://', self.adapters)
self.session.mount('https://', self.adapters)
# Ignore verifying the SSL certificate
if verify_ssl is False:
self.session.verify = False
# Disable the warning that the request is insecure, we know that...
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def _call_api(self, cmd, payload, method='GET'):
payload['cmd'] = cmd
payload['apikey'] = self.apikey
try:
response = self.session.request(method, self.url + '/api/v2', params=payload)
except RequestException as e:
print("Tautulli request failed for cmd '{}'. Invalid Tautulli URL? Error: {}".format(cmd, e))
if self.debug:
traceback.print_exc()
return
try:
response_json = response.json()
except ValueError:
print(
"Failed to parse json response for Tautulli API cmd '{}': {}"
.format(cmd, response.content))
return
if response_json['response']['result'] == 'success':
if self.debug:
print("Successfully called Tautulli API cmd '{}'".format(cmd))
return response_json['response']['data']
else:
error_msg = response_json['response']['message']
print("Tautulli API cmd '{}' failed: {}".format(cmd, error_msg))
return
def get_activity(self, session_key=None, session_id=None):
"""Call Tautulli's get_activity api endpoint"""
payload = {}
if session_key:
payload['session_key'] = session_key
elif session_id:
payload['session_id'] = session_id
return self._call_api('get_activity', payload)
def notify(self, notifier_id, subject, body):
"""Call Tautulli's notify api endpoint"""
payload = {'notifier_id': notifier_id,
'subject': subject,
'body': body}
return self._call_api('notify', payload)
def terminate_session(self, session_key=None, session_id=None, message=''):
"""Call Tautulli's terminate_session api endpoint"""
payload = {}
if session_key:
payload['session_key'] = session_key
elif session_id:
payload['session_id'] = session_id
if message:
payload['message'] = message
return self._call_api('terminate_session', payload)
class Stream(object):
def __init__(self, session_id=None, user_id=None, username=None, tautulli=None, session=None):
self.state = None
self.ip_address = None
self.session_id = session_id
self.user_id = user_id
self.username = username
self.session_exists = False
self.tautulli = tautulli
if session is not None:
self._set_stream_attributes(session)
def _set_stream_attributes(self, session):
for k, v in session.items():
setattr(self, k, v)
def get_all_stream_info(self):
"""Get all stream info from Tautulli."""
session = self.tautulli.get_activity(session_id=self.session_id)
if session:
self._set_stream_attributes(session)
self.session_exists = True
else:
self.session_exists = False
def terminate(self, message=''):
"""Calls Tautulli to terminate the session.
Parameters
----------
message : str
The message to use if the stream is terminated.
"""
self.tautulli.terminate_session(session_id=self.session_id, message=message)
def terminate_long_pause(self, message, limit, interval):
"""Kills the session if it is paused for longer than <limit> seconds.
Parameters
----------
message : str
The message to use if the stream is terminated.
limit : int
The number of seconds the session is allowed to remain paused before it
is terminated.
interval : int
The amount of time to wait between checks of the session state.
"""
start = datetime.now()
checked_time = 0
# Continue checking 2 intervals past the allowed limit in order to
# account for system variances.
check_limit = limit + (interval * 2)
while checked_time < check_limit:
self.get_all_stream_info()
if self.session_exists is False:
sys.stdout.write(
"Session '{}' from user '{}' is no longer active "
.format(self.session_id, self.username) +
"on the server, stopping monitoring.\n")
return False
now = datetime.now()
checked_time = (now - start).total_seconds()
if self.state == 'paused':
if checked_time >= limit:
self.terminate(message)
sys.stdout.write(
"Session '{}' from user '{}' has been killed.\n"
.format(self.session_id, self.username))
return True
else:
time.sleep(interval)
elif self.state == 'playing' or self.state == 'buffering':
sys.stdout.write(
"Session '{}' from user '{}' has been resumed, "
.format(self.session_id, self.username) +
"stopping monitoring.\n")
return False
class Notification(object):
def __init__(self, notifier_id, subject, body, tautulli, stream):
self.notifier_id = notifier_id
self.subject = subject
self.body = body
self.tautulli = tautulli
self.stream = stream
def send(self, subject='', body=''):
"""Send to Tautulli notifier.
Parameters
----------
subject : str
Subject of the message.
body : str
Body of the message.
"""
subject = subject or self.subject
body = body or self.body
self.tautulli.notify(notifier_id=self.notifier_id, subject=subject, body=body)
def send_discord(self, title, color, poster_url, plex_url, message, footer):
"""Build the Discord message.
Parameters
----------
title : str
The title of the message.
color : int
The color of the message
poster_url : str
The media poster URL.
plex_url : str
Plex media URL.
message : str
Message sent to the player.
footer : str
Footer of the message.
"""
discord_message = {
"embeds": [
{
"author": {
"icon_url": TAUTULLI_ICON,
"name": "Tautulli",
"url": TAUTULLI_LINK.rstrip('/')
},
"color": color,
"fields": [
{
"inline": True,
"name": "User",
"value": self.stream.friendly_name
},
{
"inline": True,
"name": "Session Key",
"value": self.stream.session_key
},
{
"inline": True,
"name": "Watching",
"value": self.stream.full_title
},
{
"inline": False,
"name": "Message Sent",
"value": message
}
],
"thumbnail": {
"url": poster_url
},
"title": title,
"timestamp": utc_now_iso(),
"url": plex_url,
"footer": {
"text": footer
}
}
],
}
discord_message = json.dumps(discord_message, sort_keys=True,
separators=(',', ': '))
self.send(body=discord_message)
def send_slack(self, title, color, poster_url, plex_url, message, footer):
"""Build the Slack message.
Parameters
----------
title : str
The title of the message.
color : int
The color of the message
poster_url : str
The media poster URL.
plex_url : str
Plex media URL.
message : str
Message sent to the player.
footer : str
Footer of the message.
"""
slack_message = {
"attachments": [
{
"title": title,
"title_link": plex_url,
"author_icon": TAUTULLI_ICON,
"author_name": "Tautulli",
"author_link": TAUTULLI_LINK.rstrip('/'),
"color": color,
"fields": [
{
"title": "User",
"value": self.stream.friendly_name,
"short": True
},
{
"title": "Session Key",
"value": self.stream.session_key,
"short": True
},
{
"title": "Watching",
"value": self.stream.full_title,
"short": True
},
{
"title": "Message Sent",
"value": message,
"short": False
}
],
"thumb_url": poster_url,
"footer": footer,
"ts": time.time()
}
],
}
slack_message = json.dumps(slack_message, sort_keys=True,
separators=(',', ': '))
self.send(body=slack_message)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Killing Plex streams from Tautulli.")
parser.add_argument('--jbop', required=True, choices=SELECTOR,
help='Kill selector.\nChoices: (%(choices)s)')
parser.add_argument('--userId', type=int,
help='The unique identifier for the user.')
parser.add_argument('--username', type=arg_decoding,
help='The username of the person streaming.')
parser.add_argument('--sessionId',
help='The unique identifier for the stream.')
parser.add_argument('--notify', type=int,
help='Notification Agent ID number to Agent to ' +
'send notification.')
parser.add_argument('--limit', type=int, default=(20 * 60), # 20 minutes
help='The time session is allowed to remain paused.')
parser.add_argument('--interval', type=int, default=30,
help='The seconds between paused session checks.')
parser.add_argument('--killMessage', nargs='+', type=arg_decoding,
help='Message to send to user whose stream is killed.')
parser.add_argument('--richMessage', type=arg_decoding, choices=RICH_TYPE,
help='Rich message type selector.\nChoices: (%(choices)s)')
parser.add_argument('--serverName', type=arg_decoding,
help='Plex Server Name')
parser.add_argument('--plexUrl', type=arg_decoding,
help='URL to plex media')
parser.add_argument('--posterUrl', type=arg_decoding,
help='Poster URL of the media')
parser.add_argument('--richColor', type=arg_decoding,
help='Color of the rich message')
parser.add_argument("--debug", action='store_true',
help='Enable debug messages.')
opts = parser.parse_args()
if not opts.sessionId and opts.jbop != 'allStreams':
sys.stderr.write("No sessionId provided! Is this synced content?\n")
sys.exit(1)
if opts.debug:
# Import traceback to get more detailed information
import traceback
# Dump the ENVs passed from tautulli
debug_dump_vars()
# Create a Tautulli instance
tautulli_server = Tautulli(TAUTULLI_URL.rstrip('/'), TAUTULLI_APIKEY, VERIFY_SSL, opts.debug)
# Create initial Stream object with basic info
tautulli_stream = Stream(opts.sessionId, opts.userId, opts.username, tautulli_server)
# Only pull all stream info if using richMessage
if opts.notify and opts.richMessage:
tautulli_stream.get_all_stream_info()
# Set a default message if none is provided
if opts.killMessage:
kill_message = ' '.join(opts.killMessage)
else:
kill_message = 'The server owner has ended the stream.'
if opts.jbop == 'stream':
tautulli_stream.terminate(kill_message)
notify(opts, kill_message, 'Stream', tautulli_stream, tautulli_server)
elif opts.jbop == 'allStreams':
all_streams = get_all_streams(tautulli_server, opts.userId)
for a_stream in all_streams:
tautulli_server.terminate_session(session_id=a_stream.session_id, message=kill_message)
notify(opts, kill_message, 'All Streams', a_stream, tautulli_server)
elif opts.jbop == 'paused':
killed_stream = tautulli_stream.terminate_long_pause(kill_message, opts.limit, opts.interval)
if killed_stream:
notify(opts, kill_message, 'Paused', tautulli_stream, tautulli_server)
@@ -1,22 +0,0 @@
networks:
traefik:
external: true
services:
tautulli:
container_name: "tautulli"
image: lscr.io/linuxserver/tautulli:latest
restart: unless-stopped
networks:
- traefik
environment:
- "PUID={{ service_user.uid }}"
- "PGID={{ service_user.uid }}"
- "TZ={{ timezone }}"
volumes:
- "{{ data_dir }}/{{ role_name }}:/config"
labels:
traefik.enable: true
traefik.http.routers.tautulli.rule: "Host(`tautulli.local.{{ personal_domain }}`)"
traefik.http.routers.tautulli.middlewares: lan-whitelist@file
@@ -1,12 +1,5 @@
- name: Create service user
user:
name: "{{ role_name }}"
system: true
register: service_user
become: true
- name: Create install directory - name: Create install directory
file: ansible.builtin.file:
path: "{{ install_directory }}/{{ role_name }}" path: "{{ install_directory }}/{{ role_name }}"
state: directory state: directory
owner: "{{ docker_user }}" owner: "{{ docker_user }}"
@@ -14,7 +7,7 @@
become: true become: true
- name: Copy docker-compose file to destination - name: Copy docker-compose file to destination
template: ansible.builtin.template:
src: docker-compose.yml src: docker-compose.yml
dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml" dest: "{{ install_directory }}/{{ role_name }}/docker-compose.yml"
owner: "{{ docker_user }}" owner: "{{ docker_user }}"
@@ -0,0 +1,20 @@
networks:
traefik:
external: true
services:
teamarr:
container_name: teamarr
image: ghcr.io/egyptiangio/teamarr:latest
restart: unless-stopped
networks:
- traefik
environment:
- "TZ={{ timezone }}"
volumes:
- "{{ data_dir }}/teamarr:/app/data"
labels:
traefik.enable: true
traefik.http.routers.teamarr.rule: "Host(`teamarr.local.{{ personal_domain }}`)"
traefik.http.routers.teamarr.middlewares: lan-whitelist@file
traefik.http.services.teamarr.loadbalancer.server.port: 9195
@@ -0,0 +1,19 @@
networks:
traefik:
external: true
services:
tracearr:
container_name: "tracearr"
image: ghcr.io/connorgallopo/tracearr:supervised
restart: unless-stopped
networks:
- traefik
environment:
- "TZ={{ timezone }}"
volumes:
- "{{ data_dir }}/{{ role_name }}:/data"
labels:
traefik.enable: true
traefik.http.routers.tracearr.rule: "Host(`{{ role_name }}.local.{{ personal_domain }}`)"
traefik.http.routers.tracearr.middlewares: lan-whitelist@file
+1 -1
View File
@@ -1,4 +1,4 @@
- name: restart traefik - name: restart traefik
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
project_src: "{{ install_directory }}/traefik" project_src: "{{ install_directory }}/traefik"
restarted: true state: restarted
@@ -1,13 +0,0 @@
http:
routers:
router-adguard:
rule: "Host(`adguard.local.{{ personal_domain }}`)"
service: service-adguard
middlewares:
- lan-whitelist@file
services:
service-adguard:
loadBalancer:
servers:
- url: http://10.0.0.1:81
@@ -1,13 +0,0 @@
http:
routers:
router-ezbeq:
rule: "Host(`ezbeq.local.{{ personal_domain }}`)"
service: service-ezbeq
middlewares:
- lan-whitelist@file
services:
service-ezbeq:
loadBalancer:
servers:
- url: http://10.0.0.84:8080
@@ -8,4 +8,4 @@ http:
service-homeassistant: service-homeassistant:
loadBalancer: loadBalancer:
servers: servers:
- url: http://10.0.0.27:8123 - url: http://haos:8123
Loaded 100 of 118 files, more files were not shown because too many files have changed in this diff. Show more