From 4ebc75db71c8a7d77752ec699dcb6f9cc89eec4d Mon Sep 17 00:00:00 2001 From: Maksim Shakavin Date: Mon, 29 Jul 2024 01:35:56 +0200 Subject: [PATCH] feat(qbittorrent): add qbit_manage --- .../tools/emonoda/helmrelease.yaml | 2 +- .../qbittorrent/tools/kustomization.yaml | 1 + .../tools/qbit_manage/externalsecret.yaml | 284 ++++++++++++++++++ .../tools/qbit_manage/helmrelease.yaml | 78 +++++ .../tools/qbit_manage/kustomization.yaml | 7 + 5 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 kubernetes/apps/default/qbittorrent/tools/qbit_manage/externalsecret.yaml create mode 100644 kubernetes/apps/default/qbittorrent/tools/qbit_manage/helmrelease.yaml create mode 100644 kubernetes/apps/default/qbittorrent/tools/qbit_manage/kustomization.yaml diff --git a/kubernetes/apps/default/qbittorrent/tools/emonoda/helmrelease.yaml b/kubernetes/apps/default/qbittorrent/tools/emonoda/helmrelease.yaml index c973ec92..85fc7825 100644 --- a/kubernetes/apps/default/qbittorrent/tools/emonoda/helmrelease.yaml +++ b/kubernetes/apps/default/qbittorrent/tools/emonoda/helmrelease.yaml @@ -27,7 +27,7 @@ spec: namespace: default values: controllers: - tagging: + main: type: cronjob cronjob: schedule: "@hourly" diff --git a/kubernetes/apps/default/qbittorrent/tools/kustomization.yaml b/kubernetes/apps/default/qbittorrent/tools/kustomization.yaml index de5014b2..c9461a41 100644 --- a/kubernetes/apps/default/qbittorrent/tools/kustomization.yaml +++ b/kubernetes/apps/default/qbittorrent/tools/kustomization.yaml @@ -4,3 +4,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ./emonoda + - ./qbit_manage diff --git a/kubernetes/apps/default/qbittorrent/tools/qbit_manage/externalsecret.yaml b/kubernetes/apps/default/qbittorrent/tools/qbit_manage/externalsecret.yaml new file mode 100644 index 00000000..f6b6902b --- /dev/null +++ b/kubernetes/apps/default/qbittorrent/tools/qbit_manage/externalsecret.yaml @@ -0,0 +1,284 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/external-secrets.io/externalsecret_v1beta1.json +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: qbit-manage +spec: + secretStoreRef: + kind: ClusterSecretStore + name: onepassword-connect + target: + name: qbit-manage-secret + template: + engineVersion: v2 + data: + config.yaml: | + # This is an example configuration file that documents all the options. + # It will need to be modified for your specific use case. + # Please refer to the link below for more details on how to set up the configuration file + # https://github.com/StuffAnThings/qbit_manage/wiki/Config-Setup + + commands: + # The commands defined below will IGNORE any commands used in command line and docker env variables. + dry_run: True + cross_seed: False + recheck: True # Recheck paused torrents sorted by lowest size. Resume if Completed. + cat_update: False + tag_update: True + rem_unregistered: True + tag_tracker_error: True + rem_orphaned: True + tag_nohardlinks: True + share_limits: False + skip_qb_version_check: True + skip_cleanup: True + + qbt: + # qBittorrent parameters + host: "qbittorrent.default.svc.cluster.local:8080" + user: {{ .qbittorrent_username }} + pass: {{ .qbittorrent_password }} + + settings: + force_auto_tmm: False # Will force qBittorrent to enable Automatic Torrent Management for each torrent. + tracker_error_tag: issue # Will set the tag of any torrents that do not have a working tracker. + nohardlinks_tag: noHL # Will set the tag of any torrents with no hardlinks. + share_limits_tag: ~share_limit # Will add this tag when applying share limits to provide an easy way to filter torrents by share limit group/priority for each torrent + share_limits_min_seeding_time_tag: MinSeedTimeNotReached # Tag to be added to torrents that have not yet reached the minimum seeding time + share_limits_min_num_seeds_tag: MinSeedsNotMet # Tag to be added to torrents that have not yet reached the minimum number of seeds + share_limits_last_active_tag: LastActiveLimitNotReached # Tag to be added to torrents that have not yet reached the last active limit + cross_seed_tag: cross-seed # Will set the tag of any torrents that are added by cross-seed command + cat_filter_completed: True # Filters for completed torrents only when running cat_update command + share_limits_filter_completed: True # Filters for completed torrents only when running share_limits command + tag_nohardlinks_filter_completed: True # Filters for completed torrents only when running tag_nohardlinks command + cat_update_all: True # Checks and udpates all torrent categories if set to True when running cat_update command, otherwise only update torrents that are uncategorized + + directory: + # Do not remove these + # Cross-seed var: # Output directory of cross-seed + # root_dir var: # Root downloads directory used to check for orphaned files, noHL, and RecycleBin. + # remote_dir var: # Path of docker host mapping of root_dir. + # remote_dir must be set if you're running qbit_manage locally and qBittorrent/cross_seed is in a docker + # remote_dir should not be set if qbit_manage is running in a container + # recycle_bin var: # Path of the RecycleBin folder. Default location is set to remote_dir/.RecycleBin + # torrents_dir var: # Path of the your qbittorrent torrents directory. Required for `save_torrents` attribute in recyclebin + # orphaned_dir var: # Path of the the Orphaned Data folder. This is similar to RecycleBin, but only for orphaned data. + cross_seed: "/your/path/here/" + root_dir: "/data/torrents/" + remote_dir: /data/torrents/ + recycle_bin: "/mnt/user/data/torrents/.RecycleBin" + torrents_dir: "/qbittorrent/data/BT_backup" + orphaned_dir: "/data/torrents/orphaned_data" + + cat: + # Category & Path Parameters + # : # Path of your save directory. + movies: "/data/torrents/movies" + tv: "/data/torrents/tv" + + cat_change: + # This moves all the torrents from one category to another category. This executes on --cat-update + # WARNING: if the paths are different and Default Torrent Management Mode is set to automatic the files could be moved !!! + # : + Radarr-HD.cross-seed: movies-hd + Radarr-UHD.cross-seed: movies-uhd + movies-hd.cross-seed: movies-hd + movies-uhd.cross-seed: movies-uhd + + tracker: + # Mandatory + # Tag Parameters + # : # This is the keyword in the tracker url. You can define multiple tracker urls by splitting with `|` delimiter + # Set tag name. Can be a list of tags or a single tag + # tag: + # Set the category based on tracker URL. This category option takes priority over the category defined by save directory + # cat: + # Set this to the notifiarr react name. This is used to add indexer reactions to the notifications sent by Notifiarr + # notifiarr: + bt.t-ru|bt2.t-ru|bt3.t-ru|bt4.t-ru: + tag: rutracker + notifiarr: rutracker + # The "other" key is a special keyword and if defined will tag any other trackers that don't match the above trackers into this tag + other: + tag: other + + nohardlinks: + # Tag Movies/Series that are not hard linked outside the root directory + # Mandatory to fill out directory parameter above to use this function (root_dir/remote_dir) + # This variable should be set to your category name of your completed movies/completed series in qbit. Acceptable variable can be any category you would like to tag if there are no hardlinks found + movies: + tv: + + share_limits: + # Control how torrent share limits are set depending on the priority of your grouping + # Each torrent will be matched with the share limit group with the highest priority that meets the group filter criteria. + # Each torrent can only be matched with one share limit group + # This variable is mandatory and is a text defining the name of your grouping. This can be any string you want + noHL: + # priority: # This is the priority of your grouping. The lower the number the higher the priority + priority: 1 + # include_all_tags: # Filter the group based on one or more tags. Multiple include_all_tags are checked with an AND condition + # All tags defined here must be present in the torrent for it to be included in this group + include_all_tags: + - noHL + # include_any_tags: # Filter the group based on one or more tags. Multiple include_any_tags are checked with an OR condition + # Any tags defined here must be present in the torrent for it to be included in this group + include_any_tags: + - noHL + # exclude_all_tags: # Filter by excluding one or more tags. Multiple exclude_all_tags are checked with an AND condition + # This is useful to combine with the category filter to exclude one or more tags from an entire category + # All tags defined here must be present in the torrent for it to be excluded in this group + exclude_all_tags: + - Beyond-HD + # exclude_any_tags: # Filter by excluding one or more tags. Multiple exclude_any_tags are checked with an OR condition + # This is useful to combine with the category filter to exclude one or more tags from an entire category + # Any tags defined here must be present in the torrent for it to be excluded in this group + exclude_any_tags: + - Beyond-HD + # categories: # Filter by including one or more categories. Multiple categories are checked with an OR condition + # Since one torrent can only be associated with a single category, multiple categories are checked with an OR condition + categories: + - RadarrComplete + - SonarrComplete + # max_ratio : Will set the torrent Maximum share ratio until torrent is stopped from seeding/uploading and may be cleaned up / removed if the minimums have been met. + # Will default to -1 (no limit) if not specified for the group. + max_ratio: 5.0 + # max_seeding_time : Will set the torrent Maximum seeding time until torrent is stopped from seeding/uploading and may be cleaned up / removed if the minimums have been met. + # See Some examples of valid time expressions (https://github.com/onegreyonewhite/pytimeparse2) + # 32m, 2h32m, 3d2h32m, 1w3d2h32m + # Will default to -1 (no limit) if not specified for the group. (Max value of 1 year (525600 minutes)) + max_seeding_time: 90d + # min_seeding_time : Will prevent torrent deletion by cleanup variable if torrent has not yet minimum seeding time (minutes). + # This should only be set if you are using this in conjunction with max_seeding_time and max_ratio. If you are not setting a max_ratio, then use max_seeding_time instead. + # If the torrent has not yet reached this minimum seeding time, it will change the share limits back to no limits and resume the torrent to continue seeding. + # See Some examples of valid time expressions (https://github.com/onegreyonewhite/pytimeparse2) + # 32m, 2h32m, 3d2h32m, 1w3d2h32m + # Will default to 0 if not specified for the group. + min_seeding_time: 30d + # last_active : Will prevent torrent deletion by cleanup variable if torrent has been active within the last x minutes. + # If the torrent has been active within the last x minutes, it will change the share limits back to no limits and resume the torrent to continue seeding. + # See Some examples of valid time expressions (https://github.com/onegreyonewhite/pytimeparse2) + # 32m, 2h32m, 3d2h32m, 1w3d2h32m + # Will default to 0 if not specified for the group. + last_active: 30d + # Limit Upload Speed : Will limit the upload speed KiB/s (KiloBytes/second) (`-1` : No Limit) + limit_upload_speed: 0 + # Enable Group Upload Speed : Upload speed limits are applied at the group level. This will take limit_upload_speed defined and divide it equally among the number of torrents in the group. + enable_group_upload_speed: false + # cleanup : WARNING!! Setting this as true Will remove and delete contents of any torrents that satisfies the share limits (max time OR max ratio) + cleanup: false + # resume_torrent_after_change : This variable will resume your torrent after changing share limits. Default is true + resume_torrent_after_change: true + # add_group_to_tag : This adds your grouping as a tag with a prefix defined in settings . Default is true + # Example: A grouping defined as noHL will have a tag set to ~share_limit.noHL (if using the default prefix) + add_group_to_tag: true + # min_num_seeds : Will prevent torrent deletion by cleanup variable if the number of seeds is less than the value set here. + # If the torrent has less number of seeds than the min_num_seeds, the share limits will be changed back to no limits and resume the torrent to continue seeding. + # Will default to 0 if not specified for the group. + min_num_seeds: 0 + # custom_tag : Apply a custom tag name for this particular group. **WARNING (This tag MUST be unique as it will be used to determine share limits. Please ensure it does not overlap with any other tags in qbt)** + custom_tag: sharelimits_noHL + cross-seed: + priority: 2 + include_all_tags: + - cross-seed + max_seeding_time: 7d + cleanup: false + PTP: + priority: 3 + include_all_tags: + - PassThePopcorn + max_ratio: 2.0 + max_seeding_time: 90d + cleanup: false + default: + priority: 999 + max_ratio: -1 + max_seeding_time: -1 + cleanup: false + + recyclebin: + # Recycle Bin method of deletion will move files into the recycle bin (Located in /root_dir/.RecycleBin) instead of directly deleting them in qbit + # By default the Recycle Bin will be emptied on every run of the qbit_manage script if empty_after_x_days is defined. + enabled: false + # empty_after_x_days var: + # Will automatically remove all files and folders in recycle bin after x days. (Checks every script run) + # If this variable is not defined it, the RecycleBin will never be emptied. + # WARNING: Setting this variable to 0 will delete all files immediately upon script run! + empty_after_x_days: 60 + # save_torrents var: + # If this option is set to true you MUST fill out the torrents_dir in the directory attribute. + # This will save a copy of your .torrent and .fastresume file in the recycle bin before deleting it from qbittorrent + save_torrents: true + # split_by_category var: + # This will split the recycle bin folder by the save path defined in the `cat` attribute + # and add the base folder name of the recycle bin that was defined in the `recycle_bin` sub-attribute under directory. + split_by_category: false + + orphaned: + # Orphaned files are those in the root_dir download directory that are not referenced by any active torrents. + # Will automatically remove all files and folders in orphaned data after x days. (Checks every script run) + # If this variable is not defined it, the orphaned data will never be emptied. + # WARNING: Setting this variable to 0 will delete all files immediately upon script run! + empty_after_x_days: 0 + # File patterns that will not be considered orphaned files. Handy for generated files that aren't part of the torrent but belong with the torrent's files + exclude_patterns: + - "**/.DS_Store" + - "**/Thumbs.db" + - "**/@eaDir" + - "/data/torrents/.torrents/**" + - "/data/torrents/temp/**" + - "**/*.!qB" + - "**/*_unpackerred" + + apprise: + # Apprise integration with webhooks + # Leave Empty/Blank to disable + # Mandatory to fill out the url of your apprise API endpoint + # api_url: http://apprise-api:8000 + # Mandatory to fill out the notification url/urls based on the notification services provided by apprise. https://github.com/caronc/apprise/wiki + # notify_url: + + notifiarr: + # Notifiarr integration with webhooks + # Leave Empty/Blank to disable + # Mandatory to fill out API Key + apikey: {{ .notifiarr_qbit_api_key }} + # Set to a unique value (could be your username on notifiarr for example) + instance: + + webhooks: + # Webhook notifications: + # Possible values: + # Set value to notifiarr if using notifiarr integration + # Set value to apprise if using apprise integration + # Set value to a valid webhook URL + # Set value to nothing (leave Empty/Blank) to disable + error: notifiarr + run_start: notifiarr + run_end: notifiarr + function: + cross_seed: notifiarr + recheck: notifiarr + cat_update: notifiarr + tag_update: notifiarr + rem_unregistered: notifiarr + tag_tracker_error: notifiarr + rem_orphaned: notifiarr + tag_nohardlinks: notifiarr + share_limits: notifiarr + cleanup_dirs: notifiarr + dataFrom: + - extract: + key: qbittorrent + rewrite: + - regexp: + source: "(.*)" + target: "qbittorrent_$1" + - extract: + key: notifiarr + rewrite: + - regexp: + source: "(.*)" + target: "notifiarr_$1" diff --git a/kubernetes/apps/default/qbittorrent/tools/qbit_manage/helmrelease.yaml b/kubernetes/apps/default/qbittorrent/tools/qbit_manage/helmrelease.yaml new file mode 100644 index 00000000..809ebac0 --- /dev/null +++ b/kubernetes/apps/default/qbittorrent/tools/qbit_manage/helmrelease.yaml @@ -0,0 +1,78 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/helm.toolkit.fluxcd.io/helmrelease_v2.json +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: qbit-manage +spec: + interval: 30m + chart: + spec: + chart: app-template + version: 3.2.1 + sourceRef: + kind: HelmRepository + name: bjw-s + namespace: flux-system + install: + remediation: + retries: 3 + upgrade: + cleanupOnFail: true + remediation: + strategy: rollback + retries: 3 + dependsOn: + - name: qbittorrent + namespace: default + values: + controllers: + main: + type: cronjob + cronjob: + schedule: "@hourly" + timeZone: "${TIMEZONE}" + concurrencyPolicy: Forbid + successfulJobsHistory: 1 + failedJobsHistory: 1 + containers: + main: + image: + repository: ghcr.io/stuffanthings/qbit_manage + tag: latest@sha256:576a71fe73bb83367090313cff9d1ca654836f2a7a0b18d0193025609e9eba7f + env: + QBT_RUN: "true" + QBT_CONFIG: "/config/config.yaml" + args: + - --config + - /app/config.yaml + resources: + requests: + cpu: 25m + limits: + memory: 256M + pod: + restartPolicy: OnFailure + defaultPodOptions: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + persistence: + logs: + type: emptyDir + globalMounts: + - path: /config/logs + config-file: + type: secret + name: qbit-manage-secret + globalMounts: + - path: /config/config.yaml + subPath: config.yaml + downloads: + type: nfs + server: "${NAS_URL}" + path: "${NAS_PATH}" + globalMounts: + - path: /data diff --git a/kubernetes/apps/default/qbittorrent/tools/qbit_manage/kustomization.yaml b/kubernetes/apps/default/qbittorrent/tools/qbit_manage/kustomization.yaml new file mode 100644 index 00000000..4eed917b --- /dev/null +++ b/kubernetes/apps/default/qbittorrent/tools/qbit_manage/kustomization.yaml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://json.schemastore.org/kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./externalsecret.yaml + - ./helmrelease.yaml