diff --git a/bootstrap b/bootstrap index 9776b7f..d17c2f8 100755 --- a/bootstrap +++ b/bootstrap @@ -4,5 +4,5 @@ python -m ensurepip --upgrade pip install --upgrade pip -pip install --upgrade --requirement requirements "$@" +pip install --upgrade -r requirements "$@" ansible-galaxy install --role-file collections/requirements.yml "$@" \ No newline at end of file diff --git a/dotfiles/workstation/home/.config/lazylibrarian/config.ini.j2 b/dotfiles/workstation/home/.config/lazylibrarian/config.ini.j2 deleted file mode 100644 index 7b47715..0000000 --- a/dotfiles/workstation/home/.config/lazylibrarian/config.ini.j2 +++ /dev/null @@ -1,129 +0,0 @@ -[GENERAL] -homepage = eBooks -auth_type = FORM -displaylength = -1 -series_tab = False -config_tab_num = 2 -toggles = False -launch_browser = False -imp_preflang = en, en-GB, en-US, eng, English, Unknown -date_lang = en_GB.UTF-8 -destination_copy = True -ebook_dir = {{ lazylibrarian_ebook_dir | default('/ebooks') }} -download_dir = {{ lazylibrarian_download_dir | default('/downloads/complete/lazylibrarian') }} -ebook_type = epub, mobi, pdf, azw3 -audiobook_type = mp3, m4b, opus, ogg - -[API] -api_enabled = True -api_key = {{ lazylibrarian_api_key }} -api_ro_key = {{ lazylibrarian_api_ro_key }} -book_api = GoodReads -ol_api = True -gb_api = {{ lazylibrarian_gb_api | default('') }} -gb_country = US - -[WEBSERVER] -http_user = {{ lazylibrarian_http_user | default('lazylibrarianuser') }} -http_pass = {{ lazylibrarian_http_pass }} - -[LOGGING] -logdir = {{ lazylibrarian_logdir | default('/config/Logs') }} -detaileduilog = True - -[IMPORTER] -multi_source = True - -[TELEMETRY] -server_id = {{ lazylibrarian_server_id | default('') }} - -[SABNZBD] -sab_host = {{ lazylibrarian_sab_host | default('localhost') }} -sab_port = {{ lazylibrarian_sab_port | default(8082) }} -sab_user = {{ sabnzbd_username | default('sabnzbduser') }} -sab_pass = {{ sabnzbd_password }} -sab_api = {{ sabnzbd_api_key }} -sab_cat = {{ lazylibrarian_sab_cat | default('lazylibrarian') }} - -[USENET] -nzb_downloader_sabnzbd = True - -[TORRENT] -tor_downloader_qbittorrent = True -seed_wait = False - -[QBITTORRENT] -qbittorrent_host = {{ lazylibrarian_qbit_host | default('localhost') }} -qbittorrent_port = {{ lazylibrarian_qbit_port | default(8082) }} -qbittorrent_user = {{ qbittorrent_username | default('qbittorrentuser') }} -qbittorrent_pass = {{ qbittorrent_password }} -qbittorrent_label = {{ lazylibrarian_qbit_label | default('lazylibrarian') }} - -[ANNA] -anna_key = {{ lazylibrarian_anna_key }} -anna = True - -[POSTPROCESS] -ebook_dest_folder = $Author/$Title $$ -audiobook_dest_folder = $Author/$Title -del_downloadfailed = True - -[MAGAZINES] -mag_tab = False - -[PROWL] -prowl_priority = -2 - -[PREPROCESS] -ebook_wanted_formats = azw3, mobi, epub - -{% for indexer in lazylibrarian_newznab_indexers | default([]) %} -[Newznab_{{ loop.index0 }}] -dispname = {{ indexer.name }} -enabled = {{ indexer.enabled | default(True) | string }} -host = {{ indexer.host }} -api = {{ indexer.api }} -generalsearch = search -bookcat = {{ indexer.bookcat | default('7020') }} -{% if indexer.magcat is defined %} -magcat = {{ indexer.magcat }} -{% endif %} -{% if indexer.comiccat is defined %} -comiccat = {{ indexer.comiccat }} -{% endif %} -updated = {{ indexer.updated | default('2026-01-27') }} -dlpriority = {{ indexer.dlpriority | default(26) }} - -{% endfor %} -{% for indexer in lazylibrarian_torznab_indexers | default([]) %} -[Torznab_{{ loop.index0 }}] -dispname = {{ indexer.name }} -enabled = {{ indexer.enabled | default(True) | string }} -host = {{ indexer.host }} -api = {{ indexer.api }} -generalsearch = search -{% if indexer.bookcat is defined %} -bookcat = {{ indexer.bookcat }} -{% endif %} -{% if indexer.magcat is defined %} -magcat = {{ indexer.magcat }} -{% endif %} -{% if indexer.comiccat is defined %} -comiccat = {{ indexer.comiccat }} -{% endif %} -updated = {{ indexer.updated | default('2026-01-27') }} -dlpriority = {{ indexer.dlpriority | default(26) }} -seeders = {{ indexer.seeders | default(1) }} -{% if indexer.seed_ratio is defined %} -seed_ratio = {{ indexer.seed_ratio }} -{% endif %} - -{% endfor %} -{% for indexer in lazylibrarian_generic_indexers | default([]) %} -[GEN_{{ loop.index0 }}] -dispname = {{ indexer.name }} -enabled = {{ indexer.enabled | default(True) | string }} -host = {{ indexer.host }} -search = {{ indexer.search }} - -{% endfor %} \ No newline at end of file diff --git a/dotfiles/workstation/home/.config/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 b/dotfiles/workstation/home/.config/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 deleted file mode 100644 index 5d1c598..0000000 --- a/dotfiles/workstation/home/.config/qbittorrent/qBittorrent/config/qBittorrent.conf.j2 +++ /dev/null @@ -1,127 +0,0 @@ -[Application] -FileLogger\Age=1 -FileLogger\AgeType=1 -FileLogger\Backup=true -FileLogger\DeleteOld=true -FileLogger\Enabled=false -FileLogger\MaxSizeBytes=66560 -FileLogger\Path=/config/qBittorrent/data/logs -MemoryWorkingSetLimit=2048 - -[AutoRun] -OnTorrentAdded\Enabled=false -OnTorrentAdded\Program= -enabled=false -program= - -[BitTorrent] -MergeTrackersEnabled={{ qbittorrent_merge_trackers | default(false) | lower }} -Session\AddExtensionToIncompleteFiles=true -Session\AddTorrentStopped=false -Session\AddTrackersEnabled={{ qbittorrent_add_trackers | default(false) | lower }} -Session\AdditionalTrackers={{ qbittorrent_additional_trackers | default('') }} -Session\AlternativeGlobalDLSpeedLimit={{ qbittorrent_alt_dl_limit | default(0) }} -Session\AlternativeGlobalUPSpeedLimit={{ qbittorrent_alt_up_limit | default(0) }} -Session\AnonymousModeEnabled={{ qbittorrent_anonymous_mode | default(true) | lower }} -Session\DefaultSavePath={{ qbittorrent_complete_dir | default('/downloads/complete') }} -Session\DisableAutoTMMByDefault=false -Session\DisableAutoTMMTriggers\CategorySavePathChanged=false -Session\DisableAutoTMMTriggers\DefaultSavePathChanged=false -Session\ExcludedFileNames= -Session\GlobalDLSpeedLimit={{ qbittorrent_dl_limit | default(0) }} -Session\GlobalMaxRatio={{ qbittorrent_max_ratio | default(1) }} -Session\GlobalMaxSeedingMinutes={{ qbittorrent_max_seed_minutes | default(0) }} -Session\GlobalUPSpeedLimit={{ qbittorrent_ul_limit | default(300) }} -Session\IgnoreLimitsOnLAN=true -Session\IgnoreSlowTorrentsForQueueing=true -Session\MaxActiveDownloads={{ qbittorrent_max_active_downloads | default(0) }} -Session\MaxActiveTorrents={{ qbittorrent_max_active_torrents | default(0) }} -Session\Port={{ qbittorrent_session_port | default(48442) }} -Session\QueueingSystemEnabled={{ qbittorrent_queueing_enabled | default(false) | lower }} -Session\SSL\Port={{ qbittorrent_ssl_port | default('11192') }} -Session\ShareLimitAction={{ qbittorrent_share_limit_action | default('Stop') }} -Session\TempPath={{ qbittorrent_temp_dir | default('/downloads/incomplete/qbittorrent') }} -Session\TempPathEnabled=true -Session\UseAlternativeGlobalSpeedLimit=true - -[Core] -AutoDeleteAddedTorrentFile=IfAdded - -[LegalNotice] -Accepted=true - -[Meta] -MigrationVersion=8 - -[Network] -Cookies=@Invalid() -Proxy\HostnameLookupEnabled=false -Proxy\Profiles\BitTorrent=true -Proxy\Profiles\Misc=true -Proxy\Profiles\RSS=true - -[Preferences] -Advanced\AnonymousMode={{ qbittorrent_anonymous_mode | default(true) | lower }} -Advanced\RecheckOnCompletion={{ qbittorrent_recheck_on_completion | default(false) | lower }} -Advanced\trackerPort={{ qbittorrent_tracker_port | default(9000) }} -Advanced\trackerPortForwarding=false -Bittorrent\MaxRatio={{ qbittorrent_max_ratio | default(1) }} -Connection\GlobalDLLimitAlt={{ qbittorrent_global_dl_limit_alt | default(0) }} -Connection\GlobalUPLimitAlt={{ qbittorrent_global_up_limit_alt | default(0) }} -Connection\PortRangeMin={{ qbittorrent_port_range_min | default(48442) }} -Connection\ResolvePeerCountries=true -Downloads\SavePath={{ qbittorrent_complete_dir | default('/downloads/complete') }} -Downloads\ScanDirsLastPath={{ qbittorrent_scan_dir | default('/torrents') }} -Downloads\ScanDirsV2=@Variant(\0\0\0\x1c\0\0\0\0) -Downloads\TempPath={{ qbittorrent_temp_dir | default('/downloads/incomplete/qbittorrent') }} -Downloads\TempPathEnabled=true -Downloads\UseIncompleteExtension=true -DynDNS\DomainName=changeme.dyndns.org -DynDNS\Enabled=false -DynDNS\Password= -DynDNS\Service=DynDNS -DynDNS\Username= -General\Locale={{ qbittorrent_locale | default('en') }} -MailNotification\email= -MailNotification\enabled=false -MailNotification\password= -MailNotification\req_auth=true -MailNotification\req_ssl=false -MailNotification\sender=qBittorrent_notification@example.com -MailNotification\smtp_server=smtp.changeme.com -MailNotification\username= -Queueing\IgnoreSlowTorrents=true -Queueing\MaxActiveDownloads={{ qbittorrent_max_active_downloads | default(20) }} -Queueing\MaxActiveTorrents={{ qbittorrent_max_active_torrents | default(20) }} -Queueing\QueueingEnabled=true -WebUI\Address={{ qbittorrent_host | default('') }} -WebUI\AlternativeUIEnabled=false -WebUI\AuthSubnetWhitelist={{ qbittorrent_subnet_whitelist | default('') }} -WebUI\AuthSubnetWhitelistEnabled=true -WebUI\BanDuration=3600 -WebUI\CSRFProtection=true -WebUI\ClickjackingProtection=true -WebUI\CustomHTTPHeaders= -WebUI\CustomHTTPHeadersEnabled=false -WebUI\Enabled=true -WebUI\HTTPS\CertificatePath={{ qbittorrent_https_cert | default('/config/qBittorrent/config/ssl/server.crt') }} -WebUI\HTTPS\Enabled={{ qbittorrent_enable_https | default(false) | lower }} -WebUI\HTTPS\KeyPath={{ qbittorrent_https_key | default('/config/qBittorrent/config/ssl/server.key') }} -WebUI\HostHeaderValidation=false -WebUI\LocalHostAuth=false -WebUI\MaxAuthenticationFailCount=5 -WebUI\Password_PBKDF2="{{ qbittorrent_password_pbkdf2 | default('') }}" -WebUI\Password_ha1={{ qbittorrent_password_ha1 | default('') }} -WebUI\Port={{ qbittorrent_ui_port | default(8082) }} -WebUI\ReverseProxySupportEnabled=false -WebUI\RootFolder= -WebUI\SecureCookie=true -WebUI\ServerDomains={{ qbittorrent_server_domains | default('*') }} -WebUI\SessionTimeout=3600 -WebUI\TrustedReverseProxiesList= -WebUI\UseUPnP=true -WebUI\Username={{ qbittorrent_username | default('qbittorrentuser') }} - -[RSS] -AutoDownloader\DownloadRepacks={{ qbittorrent_download_repacks | default(true) | lower }} -AutoDownloader\SmartEpisodeFilter=s(\\d+)e(\\d+), (\\d+)x(\\d+), "(\\d{4}[.\\-]\\d{1,2}[.\\-]\\d{1,2})", "(\\d{1,2}[.\\-]\\d{1,2}[.\\-]\\d{4})" diff --git a/dotfiles/workstation/home/.config/sabnzbd/sabnzbd.ini.j2 b/dotfiles/workstation/home/.config/sabnzbd/sabnzbd.ini.j2 deleted file mode 100644 index a485d95..0000000 --- a/dotfiles/workstation/home/.config/sabnzbd/sabnzbd.ini.j2 +++ /dev/null @@ -1,477 +0,0 @@ -__version__ = 19 -__encoding__ = utf-8 - -[misc] -username = {{ sabnzbd_username | default("admin") }} -password = {{ sabnzbd_password | default("admin") }} -host = {{ sabnzbd_host | default("::") }} -port = {{ sabnzbd_http_port | default("8081") }} -api_key = {{ sabnzbd_api_key }} -nzb_key = {{ sabnzbd_nzb_key }} -download_dir = {{ sabnzbd_download_dir | default("/downloads/incomplete/sabnzbd") }} -complete_dir = {{ sabnzbd_complete_dir | default("/downloads/complete") }} -dirscan_dir = {{ sabnzbd_dirscan_dir | default("/nzbs") }} -web_dir = Glitter -web_color = Night -inet_exposure = 4 -cleanup_list = sfv, m3u, nfo -unwanted_extensions = exe, com -ignore_samples = 1 -enable_all_par = 1 -new_nzb_on_failure = 1 -replace_dots = 1 -prospective_par_download = 1 -deobfuscate_final_filenames = 1 -direct_unpack = 1 -pause_on_pwrar = 2 -propagation_delay = 0 -top_only = 1 -pre_script = None -queue_complete = "" -queue_complete_pers = 0 -bandwidth_perc = 100 -refresh_rate = 1 -interface_settings = '{"dateFormat":"fromNow","extraQueueColumns":["category","age"],"extraHistoryColumns":["size"],"displayCompact":false,"displayFullWidth":false,"confirmDeleteQueue":true,"confirmDeleteHistory":true,"keyboardShortcuts":true}' -queue_limit = 30 -config_lock = 0 -sched_converted = 0 -notified_new_skin = 2 -direct_unpack_tested = 1 -check_new_rel = 1 -auto_browser = 0 -language = en -enable_https_verification = 1 -https_port = {{ sabnzbd_https_port | default("9090") }} -bandwidth_max = 60M -cache_limit = 1G -https_cert = {{ sabnzbd_https_cert | default("/config/admin/server.cert") }} -https_key = {{ sabnzbd_https_key | default("/config/admin/server.key") }} -https_chain = "" -enable_https = {{ sabnzbd_enable_https | default(false) | int }} -permissions = "" -download_free = "" -complete_free = "" -fulldisk_autoresume = 0 -script_dir = "" -nzb_backup_dir = "" -admin_dir = admin -dirscan_speed = 5 -password_file = "" -log_dir = logs -max_art_tries = 3 -load_balancing = 2 -sfv_check = 1 -quick_check_ext_ignore = nfo, sfv, srr -script_can_fail = 0 -enable_recursive = 1 -flat_unpack = 0 -par_option = "" -pre_check = 0 -nice = "" -win_process_prio = 3 -ionice = "" -fail_hopeless_jobs = 1 -fast_fail = 1 -auto_disconnect = 1 -no_dupes = 0 -no_series_dupes = 0 -series_propercheck = 1 -auto_sort = "" -direct_unpack_threads = 3 -folder_rename = 1 -replace_spaces = 0 -safe_postproc = 1 -pause_on_post_processing = 0 -sanitize_safe = 0 -action_on_unwanted_extensions = 0 -unwanted_extensions_mode = 0 -history_retention = "" -enable_meta = 1 -quota_size = "" -quota_day = "" -quota_resume = 0 -quota_period = m -rating_enable = 0 -rating_host = "" -rating_api_key = "" -rating_filter_enable = 0 -rating_filter_abort_audio = 0 -rating_filter_abort_video = 0 -rating_filter_abort_encrypted = 0 -rating_filter_abort_encrypted_confirm = 0 -rating_filter_abort_spam = 0 -rating_filter_abort_spam_confirm = 0 -rating_filter_abort_downvoted = 0 -rating_filter_abort_keywords = "" -rating_filter_pause_audio = 0 -rating_filter_pause_video = 0 -rating_filter_pause_encrypted = 0 -rating_filter_pause_encrypted_confirm = 0 -rating_filter_pause_spam = 0 -rating_filter_pause_spam_confirm = 0 -rating_filter_pause_downvoted = 0 -rating_filter_pause_keywords = "" -enable_tv_sorting = 0 -tv_sort_string = "" -tv_categories = tv, -enable_movie_sorting = 0 -movie_sort_string = "" -movie_sort_extra = -cd%1 -movie_extra_folder = 0 -movie_categories = movies, -enable_date_sorting = 0 -date_sort_string = "" -date_categories = tv, -schedlines = , -rss_rate = 60 -ampm = 0 -replace_illegal = 1 -start_paused = 0 -preserve_paused_state = 0 -enable_par_cleanup = 1 -process_unpacked_par2 = 1 -enable_unrar = 1 -enable_unzip = 1 -enable_7zip = 1 -enable_filejoin = 1 -enable_tsjoin = 1 -overwrite_files = 0 -ignore_unrar_dates = 0 -backup_for_duplicates = 1 -empty_postproc = 0 -wait_for_dfolder = 0 -rss_filenames = 0 -api_logging = 1 -html_login = 1 -osx_menu = 1 -osx_speed = 1 -warn_dupl_jobs = 1 -helpful_warnings = 1 -keep_awake = 1 -win_menu = 1 -allow_incomplete_nzb = 0 -enable_broadcast = 1 -ipv6_hosting = 0 -fixed_ports = 1 -api_warnings = 1 -disable_api_key = 0 -no_penalties = 0 -x_frame_options = 1 -allow_old_ssl_tls = 0 -num_decoders = 3 -rss_odd_titles = nzbindex.nl/, nzbindex.com/, nzbclub.com/ -req_completion_rate = 100.2 -selftest_host = self-test.sabnzbd.org -movie_rename_limit = 100M -episode_rename_limit = 20M -size_limit = 0 -show_sysload = 2 -history_limit = 20 -wait_ext_drive = 5 -max_foldername_length = 246 -nomedia_marker = "" -ipv6_servers = 1 -url_base = /sabnzbd -host_whitelist = htpc, -local_ranges = , -max_url_retries = 10 -downloader_sleep_time = 10 -ssdp_broadcast_interval = 15 -socks5_proxy_url = "" -email_server = "" -email_to = , -email_from = "" -email_account = "" -email_pwd = "" -email_endjob = 0 -email_full = 0 -email_dir = "" -email_rss = 0 -email_cats = *, -num_simd_decoders = 2 -ext_rename_ignore = , -sorters_converted = 1 -backup_dir = "" -replace_underscores = 0 -tray_icon = 1 -enable_season_sorting = 1 -receive_threads = 2 -switchinterval = 0.005 -end_queue_script = None -no_smart_dupes = 0 -dupes_propercheck = 1 -history_retention_option = all -history_retention_number = 1 -enable_multipar = 1 -disable_archive = 0 -ipv6_staging = 0 -verify_xff_header = 0 -config_conversion_version = 4 -disable_par2cmdline = 0 -unrar_parameters = "" -outgoing_nntp_ip = "" - -[categories] -[[*]] -name = * -order = 0 -pp = 3 -script = None -dir = "" -newzbin = "" -priority = 0 -[[music]] -name = music -order = 0 -pp = "" -script = Default -dir = music -newzbin = music -priority = -100 -[[tv]] -name = tv -order = 0 -pp = "" -script = Default -dir = tv -newzbin = tv -priority = -100 -[[movies]] -name = movies -order = 0 -pp = "" -script = Default -dir = movies -newzbin = "movies, movie" -priority = -100 -[[radarr]] -name = radarr -order = 0 -pp = "" -script = Default -dir = radarr -newzbin = "movies, movie" -priority = -100 -[[sonarr]] -name = sonarr -order = 0 -pp = "" -script = Default -dir = sonarr -newzbin = tv -priority = -100 -[[other]] -name = other -order = 1 -pp = "" -script = Default -dir = other -newzbin = "games, game, other" -priority = -100 -[[lidarr]] -name = lidarr -order = 2 -pp = "" -script = Default -dir = lidarr -newzbin = music -priority = -100 -[[readarr]] -name = readarr -order = 3 -pp = "" -script = Default -dir = readarr -newzbin = ebooks -priority = -100 -[[lazylibrarian]] -name = lazylibrarian -order = 4 -pp = "" -script = Default -dir = lazylibrarian -newzbin = "ebooks, audiobooks" -priority = -100 - -[servers] -{% for s in sabnzbd_servers | default([]) %} -[[{{ s.name }}]] -name = {{ s.name }} -displayname = {{ s.displayname | default(s.name) }} -host = {{ s.host | default(s.name) }} -port = {{ s.port | default(563) }} -timeout = {{ s.timeout | default(60) }} -username = {{ s.username| default('') }} -password = {{ s.password| default('') }} -connections = {{ s.connections | default(50) }} -ssl = {{ s.ssl | default(1) }} -ssl_verify = {{ s.ssl_verify | default(1) }} -ssl_ciphers = {{ s.ssl_ciphers | default('""') }} -enable = {{ s.enable| default(1) }} -required = {{ s.required| default(0) }} -optional = {{ s.optional| default(0) }} -retention = {{ s.retention | default(0) }} -expire_date = {{ s.expire_date | default('""') }} -quota = {{ s.quota | default('""') }} -usage_at_start = {{ s.usage_at_start | default(0) }} -priority = {{ s.priority| default(0) }} -notes = {{ s.notes | default('""') }} - -{% endfor %} -[logging] -log_level = 1 -max_log_size = 5242880 -log_backups = 5 -[ncenter] -ncenter_enable = 0 -ncenter_cats = *, -ncenter_prio_startup = 1 -ncenter_prio_download = 0 -ncenter_prio_pause_resume = 0 -ncenter_prio_pp = 0 -ncenter_prio_complete = 1 -ncenter_prio_failed = 1 -ncenter_prio_disk_full = 1 -ncenter_prio_new_login = 0 -ncenter_prio_warning = 0 -ncenter_prio_error = 0 -ncenter_prio_queue_done = 1 -ncenter_prio_other = 1 -ncenter_prio_quota = 1 -[acenter] -acenter_enable = 0 -acenter_cats = *, -acenter_prio_startup = 0 -acenter_prio_download = 0 -acenter_prio_pause_resume = 0 -acenter_prio_pp = 0 -acenter_prio_complete = 1 -acenter_prio_failed = 1 -acenter_prio_disk_full = 1 -acenter_prio_new_login = 0 -acenter_prio_warning = 0 -acenter_prio_error = 0 -acenter_prio_queue_done = 1 -acenter_prio_other = 1 -acenter_prio_quota = 1 -[ntfosd] -ntfosd_enable = 1 -ntfosd_cats = *, -ntfosd_prio_startup = 1 -ntfosd_prio_download = 0 -ntfosd_prio_pause_resume = 0 -ntfosd_prio_pp = 0 -ntfosd_prio_complete = 1 -ntfosd_prio_failed = 1 -ntfosd_prio_disk_full = 1 -ntfosd_prio_new_login = 0 -ntfosd_prio_warning = 0 -ntfosd_prio_error = 0 -ntfosd_prio_queue_done = 1 -ntfosd_prio_other = 1 -ntfosd_prio_quota = 1 -[prowl] -prowl_enable = 0 -prowl_cats = *, -prowl_apikey = "" -prowl_prio_startup = -3 -prowl_prio_download = -3 -prowl_prio_pause_resume = -3 -prowl_prio_pp = -3 -prowl_prio_complete = 0 -prowl_prio_failed = 1 -prowl_prio_disk_full = 1 -prowl_prio_new_login = -3 -prowl_prio_warning = -3 -prowl_prio_error = -3 -prowl_prio_queue_done = 0 -prowl_prio_other = 0 -prowl_prio_quota = 0 -[pushover] -pushover_token = "" -pushover_userkey = "" -pushover_device = "" -pushover_emergency_expire = 3600 -pushover_emergency_retry = 60 -pushover_enable = 0 -pushover_cats = *, -pushover_prio_startup = -3 -pushover_prio_download = -2 -pushover_prio_pause_resume = -2 -pushover_prio_pp = -3 -pushover_prio_complete = -1 -pushover_prio_failed = -1 -pushover_prio_disk_full = 1 -pushover_prio_new_login = -3 -pushover_prio_warning = 1 -pushover_prio_error = 1 -pushover_prio_queue_done = -1 -pushover_prio_other = -1 -pushover_prio_quota = -1 -[pushbullet] -pushbullet_enable = 0 -pushbullet_cats = *, -pushbullet_apikey = "" -pushbullet_device = "" -pushbullet_prio_startup = 0 -pushbullet_prio_download = 0 -pushbullet_prio_pause_resume = 0 -pushbullet_prio_pp = 0 -pushbullet_prio_complete = 1 -pushbullet_prio_failed = 1 -pushbullet_prio_disk_full = 1 -pushbullet_prio_new_login = 0 -pushbullet_prio_warning = 0 -pushbullet_prio_error = 0 -pushbullet_prio_queue_done = 0 -pushbullet_prio_other = 1 -pushbullet_prio_quota = 1 -[nscript] -nscript_enable = 0 -nscript_cats = *, -nscript_script = "" -nscript_parameters = "" -nscript_prio_startup = 1 -nscript_prio_download = 0 -nscript_prio_pause_resume = 0 -nscript_prio_pp = 0 -nscript_prio_complete = 1 -nscript_prio_failed = 1 -nscript_prio_disk_full = 1 -nscript_prio_new_login = 0 -nscript_prio_warning = 0 -nscript_prio_error = 0 -nscript_prio_queue_done = 1 -nscript_prio_other = 1 -nscript_prio_quota = 1 -[apprise] -apprise_enable = 0 -apprise_cats = *, -apprise_urls = "" -apprise_target_startup = "" -apprise_target_startup_enable = 0 -apprise_target_download = "" -apprise_target_download_enable = 0 -apprise_target_pause_resume = "" -apprise_target_pause_resume_enable = 0 -apprise_target_pp = "" -apprise_target_pp_enable = 0 -apprise_target_complete = "" -apprise_target_complete_enable = 1 -apprise_target_failed = "" -apprise_target_failed_enable = 1 -apprise_target_disk_full = "" -apprise_target_disk_full_enable = 0 -apprise_target_new_login = "" -apprise_target_new_login_enable = 1 -apprise_target_warning = "" -apprise_target_warning_enable = 0 -apprise_target_error = "" -apprise_target_error_enable = 0 -apprise_target_queue_done = "" -apprise_target_queue_done_enable = 0 -apprise_target_other = "" -apprise_target_other_enable = 1 -apprise_target_quota = "" -apprise_target_quota_enable = 1 - diff --git a/dotfiles/workstation/home/.config/traefik/dynamic/htpc.yml.j2 b/dotfiles/workstation/home/.config/traefik/dynamic/htpc.yml.j2 deleted file mode 100644 index 83946d1..0000000 --- a/dotfiles/workstation/home/.config/traefik/dynamic/htpc.yml.j2 +++ /dev/null @@ -1,116 +0,0 @@ ---- -# Traefik dynamic configuration for HTPC services -# Auto-generated by Ansible - deployed as dotfile - -http: - middlewares: - redirect-https: - redirectScheme: - scheme: https - permanent: true - - routers: - redirect-to-https: - rule: "HostRegexp(`{any:.*}`)" - entryPoints: - - web - middlewares: - - redirect-https - service: noop - - sabnzbd: - rule: "PathPrefix(`/sabnzbd`)" - service: sabnzbd - entryPoints: - - websecure - tls: {} - - qbittorrent: - rule: "PathPrefix(`/qbittorrent`)" - service: qbittorrent - entryPoints: - - websecure - tls: {} - - sonarr: - rule: "PathPrefix(`/sonarr`)" - service: sonarr - entryPoints: - - websecure - tls: {} - - radarr: - rule: "PathPrefix(`/radarr`)" - service: radarr - entryPoints: - - websecure - tls: {} - - lidarr: - rule: "PathPrefix(`/lidarr`)" - service: lidarr - entryPoints: - - websecure - tls: {} - - lazylibrarian: - rule: "PathPrefix(`/lazylibrarian`)" - service: lazylibrarian - entryPoints: - - websecure - tls: {} - - prowlarr: - rule: "PathPrefix(`/prowlarr`)" - service: prowlarr - entryPoints: - - websecure - tls: {} - - dashboard: - rule: "PathPrefix(`/dashboard`)" - service: api@internal - entryPoints: - - websecure - tls: {} - - services: - noop: - loadBalancer: - servers: - - url: "http://localhost" - - sabnzbd: - loadBalancer: - servers: - - url: "http://localhost:8081" - - qbittorrent: - loadBalancer: - servers: - - url: "http://localhost:8082" - - sonarr: - loadBalancer: - servers: - - url: "http://localhost:{{ SONARR__SERVER__PORT | default('8989') }}" - - radarr: - loadBalancer: - servers: - - url: "http://localhost:{{ RADARR__SERVER__PORT | default('7878') }}" - - lidarr: - loadBalancer: - servers: - - url: "http://localhost:{{ LIDARR__SERVER__PORT | default('8686') }}" - - lazylibrarian: - loadBalancer: - servers: - - url: "http://localhost:{{ lazylibrarian_port | default('5299') }}" - - prowlarr: - loadBalancer: - servers: - - url: "http://localhost:{{ PROWLARR__SERVER__PORT | default('9696') }}" diff --git a/dotfiles/workstation/home/.config/traefik/server.crt.j2 b/dotfiles/workstation/home/.config/traefik/server.crt.j2 deleted file mode 100644 index 13edda5..0000000 --- a/dotfiles/workstation/home/.config/traefik/server.crt.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ traefik_server_cert }} \ No newline at end of file diff --git a/dotfiles/workstation/home/.config/traefik/server.key.j2 b/dotfiles/workstation/home/.config/traefik/server.key.j2 deleted file mode 100644 index a9b66fe..0000000 --- a/dotfiles/workstation/home/.config/traefik/server.key.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ traefik_server_key }} \ No newline at end of file diff --git a/group_vars/workstation/quadlets.yml b/group_vars/workstation/quadlets.yml new file mode 100644 index 0000000..a0b9760 --- /dev/null +++ b/group_vars/workstation/quadlets.yml @@ -0,0 +1,382 @@ +--- + +debug: false # set to true to print debug info +log_level: "info" +rebuild: true # rebuild images +quadlets_deploy_configs: true # deploy quadlet service configs + +maintainer: "Bryan C. Roessler" +tz: "America/New_York" +alpine_base_image: "docker.io/alpine:3.23" +alpine_mirror: "https://mirror.pilotfiber.com/alpinelinux" + +# Directories +config_root: "{{ lookup('env', 'HOME') }}/.config" +quadlet_root: "{{ lookup('env', 'HOME') }}/.config/containers/systemd" +backup_root: "{{ lookup('env', 'HOME') }}/.config/containers/systemd/backup" +download_root: "{{ lookup('env', 'HOME') }}/downloads" +monitor_root: "{{ lookup('env', 'HOME') }}/downloads" +media_root: "{{ lookup('env', 'HOME') }}/media" + +# linux-system-roles.podman +podman_create_host_directories: true +podman_host_directories: + DEFAULT: + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + mode: "0755" +podman_activate_systemd_units: true +podman_run_as_user: "{{ lookup('env', 'USER') }}" +podman_run_as_group: "{{ lookup('env', 'USER') }}" +podman_systemd_unit_scope: user +podman_prune_images: true +podman_pull_image: false +podman_continue_if_pull_fails: false + +podman_quadlet_specs: + + # Pods + - name: htpc + type: pod + network: pasta + publish: + - "8080:80" + - "8443:443" + + # Build images + - name: htpc_sabnzbd + type: build + image: localhost/htpc_sabnzbd:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN \ + rm -rf /etc/apk/repositories \ + && apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + python3 py3-pip git unzip ca-certificates par2cmdline 7zip \ + && apk add --no-cache --virtual=.build-deps \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + autoconf automake build-base openssl-dev libffi-dev python3-dev \ + && apk add --no-cache -X '{{ alpine_mirror }}/v3.14/main' unrar \ + && git clone --depth 1 --branch master https://github.com/sabnzbd/sabnzbd /app \ + && python3 -m venv /venv \ + && . /venv/bin/activate \ + && pip install --no-cache-dir -r /app/requirements.txt \ + && apk del --purge .build-deps + + - name: htpc_qbittorrent + type: build + image: localhost/htpc_qbittorrent:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + qbittorrent-nox \ + && mkdir -p /app \ + && ln -s /usr/bin/qbittorrent-nox /app/qbittorrent-nox + WORKDIR /app + + - name: htpc_sonarr + type: build + image: localhost/htpc_sonarr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + libintl sqlite-libs icu-libs curl jq \ + && url=$(curl -sL "https://api.github.com/repos/Sonarr/Sonarr/releases/latest" \ + | jq -r '.assets[] | select(.name | test("linux-musl-x64.tar.gz$")) | .browser_download_url') \ + && curl -L -o /tmp/Sonarr.tar.gz "$url" \ + && mkdir -p /app && tar -xzf /tmp/Sonarr.tar.gz -C /app --strip-components=1 + WORKDIR /app + + - name: htpc_radarr + type: build + image: localhost/htpc_radarr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + icu-libs libintl sqlite-libs curl libmediainfo xmlstarlet jq \ + && url=$(curl -sL "https://api.github.com/repos/Radarr/Radarr/releases/latest" \ + | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ + && curl -L -o /tmp/radarr.tar.gz "$url" \ + && mkdir -p /app \ + && tar -xzf /tmp/radarr.tar.gz --strip-components=1 -C /app \ + && chmod +x /app/Radarr \ + && rm -rf /app/Radarr.Update + WORKDIR /app + + - name: htpc_lidarr + type: build + image: localhost/htpc_lidarr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + icu-libs libintl sqlite-libs curl libmediainfo xmlstarlet jq \ + && url=$(curl -sL "https://api.github.com/repos/Lidarr/Lidarr/releases/latest" \ + | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ + && [ -n "$url" ] \ + && curl -L -o /tmp/Lidarr.tar.gz "$url" \ + && mkdir -p /app && tar -xzf /tmp/Lidarr.tar.gz --strip-components=1 -C /app \ + && chmod +x /app/Lidarr \ + && rm /tmp/Lidarr.tar.gz + WORKDIR /app + + - name: htpc_prowlarr + type: build + image: localhost/htpc_prowlarr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + libintl icu-libs sqlite-libs curl jq \ + && url=$(curl -sL "https://api.github.com/repos/Prowlarr/Prowlarr/releases/latest" \ + | jq -r '.assets[] | select(.name | test("linux-musl-core-x64.tar.gz$")) | .browser_download_url') \ + && [ -n "$url" ] \ + && curl -L -o /tmp/Prowlarr.tar.gz "$url" \ + && mkdir -p /app \ + && tar -xzf /tmp/Prowlarr.tar.gz -C /app --strip-components=1 \ + && rm /tmp/Prowlarr.tar.gz + WORKDIR /app + + - name: htpc_unpackerr + type: build + image: localhost/htpc_unpackerr:latest + pull: missing + format: oci + force_rm: true + container_file: | + FROM {{ alpine_base_image }} + LABEL maintainer="{{ maintainer }}" + RUN apk add --no-cache \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/main" \ + -X "{{ alpine_mirror }}/v{{ alpine_base_image.split(':')[-1] }}/community" \ + curl tar jq \ + && url=$(curl -sL "https://api.github.com/repos/davidnewhall/Unpackerr/releases/latest" \ + | jq -r '.assets[] | select(.name == "unpackerr.amd64.linux.gz") | .browser_download_url') \ + && [ -n "$url" ] \ + && curl -L -o /tmp/unpackerr.gz "$url" \ + && mkdir -p /app \ + && gunzip -c /tmp/unpackerr.gz > /app/unpackerr \ + && chmod +x /app/unpackerr \ + && rm /tmp/unpackerr.gz + WORKDIR /app + + # Containers + - name: htpc_traefik + type: container + pod: htpc + image: docker.io/traefik:latest + pull: newer + volumes: + - "{{ config_root }}/traefik:/etc/traefik:Z" + env: + TZ: "{{ tz }}" + command: + - "--api.dashboard=true" + - "--api.insecure=true" + - "--providers.file.directory=/etc/traefik/dynamic" + - "--providers.file.watch=true" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--entrypoints.websecure.http.tls.certFile=/etc/traefik/server.crt" + - "--entrypoints.websecure.http.tls.keyFile=/etc/traefik/server.key" + - "--log.level=INFO" + restart_policy: on-failure + + - name: htpc_sabnzbd + type: container + pod: htpc + image: localhost/htpc_sabnzbd:latest + volumes: + - "{{ config_root }}/sabnzbd:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ monitor_root }}/nzbs:/nzbs:Z" + env: + TZ: "{{ tz }}" + command: + - "/venv/bin/python" + - "-OO" + - "/app/SABnzbd.py" + - "--config-file=/config/sabnzbd.ini" + - "--browser=0" + restart_policy: on-failure + + - name: htpc_qbittorrent + type: container + pod: htpc + image: localhost/htpc_qbittorrent:latest + volumes: + - "{{ config_root }}/qbittorrent:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ monitor_root }}/torrents:/torrents:Z" + env: + TZ: "{{ tz }}" + command: + - "qbittorrent-nox" + - "--profile=/config" + restart_policy: on-failure + + - name: htpc_sonarr + type: container + pod: htpc + image: localhost/htpc_sonarr:latest + volumes: + - "{{ config_root }}/sonarr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ media_root }}/tv:/tv:Z" + env: + TZ: "{{ tz }}" + SONARR__APP__LAUNCHBROWSER: false + SONARR__APP__INSTANCENAME: "{{ SONARR__APP__INSTANCENAME | default('Sonarr') }}" + SONARR__AUTH__METHOD: "{{ SONARR__AUTH__METHOD | default('Forms') }}" + SONARR__AUTH__APIKEY: "{{ SONARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" + SONARR__SERVER__ENABLESSL: "{{ SONARR__SERVER__ENABLESSL | default(false) }}" + SONARR__SERVER__SSLPORT: "{{ SONARR__SERVER__SSLPORT | default('9898') }}" + SONARR__SERVER__PORT: "{{ SONARR__SERVER__PORT | default('8989') }}" + SONARR__SERVER__BINDADDRESS: "{{ SONARR__SERVER__BINDADDRESS | default('*') }}" + SONARR__SERVER__SSLCERTPATH: "{{ SONARR__SERVER__SSLCERTPATH | default('/config/ssl/server.crt') }}" + SONARR__SERVER__SSLCERTPASSWORD: "{{ SONARR__SERVER__SSLCERTPASSWORD | default('/config/ssl/server.key') }}" + SONARR__LOG__ANALYTICSENABLED: "{{ SONARR__LOG__ANALYTICSENABLED | default(false) }}" + SONARR__UPDATE__AUTOMATICALLY: "{{ SONARR__UPDATE__AUTOMATICALLY | default(false) }}" + SONARR__LOG__LEVEL: "{{ SONARR__LOG__LEVEL | default('info') }}" + command: ["/app/Sonarr", "-data=/config"] + restart_policy: on-failure + + - name: htpc_radarr + type: container + pod: htpc + image: localhost/htpc_radarr:latest + volumes: + - "{{ config_root }}/radarr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ media_root }}/movies:/movies:Z" + env: + TZ: "{{ tz }}" + RADARR__APP__LAUNCHBROWSER: false + RADARR__APP__INSTANCENAME: "{{ RADARR__APP__INSTANCENAME | default('Radarr') }}" + RADARR__AUTH__METHOD: "{{ RADARR__AUTH__METHOD | default('Forms') }}" + RADARR__AUTH__APIKEY: "{{ RADARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" + RADARR__AUTH__ENABLED: "{{ RADARR__AUTH__ENABLED | default(true) }}" + RADARR__AUTH__REQUIRED: "{{ RADARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" + RADARR__SERVER__ENABLESSL: "{{ RADARR__SERVER__ENABLESSL | default(false) }}" + RADARR__SERVER__PORT: "{{ RADARR__SERVER__PORT | default('7878') }}" + RADARR__SERVER__BINDADDRESS: "{{ RADARR__SERVER__BINDADDRESS | default('*') }}" + RADARR__LOG__ANALYTICSENABLED: "{{ RADARR__LOG__ANALYTICSENABLED | default(false) }}" + RADARR__LOG__LEVEL: "{{ RADARR__LOG__LEVEL | default('info') }}" + RADARR__UPDATE__AUTOMATICALLY: "{{ RADARR__UPDATE__AUTOMATICALLY | default(false) }}" + command: ["/app/Radarr", "--nobrowser", "--data=/config"] + restart_policy: on-failure + + - name: htpc_lidarr + type: container + pod: htpc + image: localhost/htpc_lidarr:latest + volumes: + - "{{ config_root }}/lidarr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ media_root }}/music:/music:Z" + env: + TZ: "{{ tz }}" + LIDARR__APP__LAUNCHBROWSER: false + LIDARR__APP__INSTANCENAME: "{{ LIDARR__APP__INSTANCENAME | default('Lidarr') }}" + LIDARR__AUTH__METHOD: "{{ LIDARR__AUTH__METHOD | default('Forms') }}" + LIDARR__AUTH__APIKEY: "{{ LIDARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" + LIDARR__AUTH__ENABLED: "{{ LIDARR__AUTH__ENABLED | default(true) }}" + LIDARR__AUTH__REQUIRED: "{{ LIDARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" + LIDARR__SERVER__ENABLESSL: "{{ LIDARR__SERVER__ENABLESSL | default(false) }}" + LIDARR__SERVER__PORT: "{{ LIDARR__SERVER__PORT | default('8686') }}" + LIDARR__SERVER__SSLPORT: "{{ LIDARR__SERVER__SSLPORT | default('6868') }}" + LIDARR__SERVER__BINDADDRESS: "{{ LIDARR__SERVER__BINDADDRESS | default('*') }}" + LIDARR__SERVER__SSLCERTPATH: "{{ LIDARR__SERVER__SSLCERTPATH | default('/config/ssl/server.crt') }}" + LIDARR__SERVER__SSLCERTPASSWORD: "{{ LIDARR__SERVER__SSLCERTPASSWORD | default('/config/ssl/server.key') }}" + LIDARR__LOG__ANALYTICSENABLED: "{{ LIDARR__LOG__ANALYTICSENABLED | default(false) }}" + LIDARR__LOG__LEVEL: "{{ LIDARR__LOG__LEVEL | default('info') }}" + LIDARR__UPDATE__AUTOMATICALLY: "{{ LIDARR__UPDATE__AUTOMATICALLY | default(false) }}" + command: ["/app/Lidarr", "-nobrowser", "--data=/config"] + restart_policy: on-failure + + - name: htpc_lazylibrarian + type: container + pod: htpc + image: localhost/htpc_lazylibrarian:latest + volumes: + - "{{ config_root }}/lazylibrarian:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + - "{{ media_root }}/ebooks:/ebooks:Z" + env: + TZ: "{{ tz }}" + command: ["/venv/bin/python", "/app/LazyLibrarian.py", "--nolaunch", "--port", "{{ lazylibrarian_port | default('5299') }}", "--datadir=/config"] + restart_policy: on-failure + + - name: htpc_prowlarr + type: container + pod: htpc + image: localhost/htpc_prowlarr:latest + volumes: + - "{{ config_root }}/prowlarr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + env: + TZ: "{{ tz }}" + PROWLARR__APP__LAUNCHBROWSER: false + PROWLARR__APP__INSTANCENAME: "{{ PROWLARR__APP__INSTANCENAME | default('Prowlarr') }}" + PROWLARR__AUTH__METHOD: "{{ PROWLARR__AUTH__METHOD | default('Forms') }}" + PROWLARR__AUTH__REQUIRED: "{{ PROWLARR__AUTH__REQUIRED | default('DisabledForLocalAddresses') }}" + PROWLARR__AUTH__APIKEY: "{{ PROWLARR__AUTH__APIKEY | default(lookup('password', '/dev/null length=32 chars=ascii_letters,digits')) }}" + PROWLARR__SERVER__ENABLESSL: "{{ PROWLARR__SERVER__ENABLESSL | default(false) }}" + PROWLARR__SERVER__SSLPORT: "{{ PROWLARR__SERVER__PORT | default('6969') }}" + PROWLARR__SERVER__PORT: "{{ PROWLARR__SERVER__PORT | default('9696') }}" + PROWLARR__SERVER__BINDADDRESS: "{{ PROWLARR__SERVER__BINDADDRESS | default('*') }}" + PROWLARR__LOG__ANALYTICSENABLED: "{{ PROWLARR__LOG__ANALYTICSENABLED | default(false) }}" + PROWLARR__LOG__LEVEL: "{{ PROWLARR__LOG__LEVEL | default('info') }}" + PROWLARR__UPDATE__AUTOMATICALLY: "{{ PROWLARR__UPDATE__AUTOMATICALLY | default(false) }}" + command: ["/app/Prowlarr", "--nobrowser", "--data=/config"] + restart_policy: on-failure + + - name: htpc_unpackerr + type: container + pod: htpc + image: localhost/htpc_unpackerr:latest + volumes: + - "{{ config_root }}/unpackerr:/config:Z" + - "{{ download_root }}/htpc:/downloads:z" + env: + TZ: "{{ tz }}" + UNPACKERR__LOG__ANALYTICSENABLED: "{{ UNPACKERR__LOG__ANALYTICSENABLED | default(false) }}" + UNPACKERR__UPDATE__AUTOMATICALLY: "{{ UNPACKERR__UPDATE__AUTOMATICALLY | default(false) }}" + UNPACKERR__LOG__LEVEL: "{{ UNPACKERR__LOG__LEVEL | default('info') }}" + command: ["/app/unpackerr"] + restart_policy: on-failure diff --git a/playbook.yml b/playbook.yml index bd07e0b..8dd1247 100644 --- a/playbook.yml +++ b/playbook.yml @@ -35,6 +35,12 @@ - role: services tags: ['services'] +- name: Deploy quadlets + hosts: all + roles: + - role: quadlets + tags: ['quadlets'] + - name: Deploy sysconfig hosts: all roles: diff --git a/roles/deploy_files.yml b/roles/deploy_files.yml new file mode 100644 index 0000000..1dcf6f9 --- /dev/null +++ b/roles/deploy_files.yml @@ -0,0 +1,56 @@ +--- +# Reusable task to deploy files and templates from role paths +# Parameters: +# - subdir: subdirectory under role// (e.g., 'home', 'root') (optional, default: '') +# - target_root: target root path (e.g., ansible_facts.env.HOME, '/etc') +# - use_symlinks: bool, whether to use symlinks for local deployments (default: true) +# - become_root: bool, whether to become root (default: false) + +- name: "Build file lists for {{ var_prefix }}" + ansible.builtin.set_fact: + "{{ var_prefix }}_files": "{{ lookup('community.general.filetree', + role_path ~ '/common/' ~ (subdir | default('')), + role_path ~ '/' ~ group_names[0] ~ '/' ~ (subdir | default(''))) | selectattr('state', 'equalto', 'file') | rejectattr('path', 'match', '.*\\.j2$') | list }}" + "{{ var_prefix }}_templates": "{{ lookup('community.general.filetree', + role_path ~ '/common/' ~ (subdir | default('')), + role_path ~ '/' ~ group_names[0] ~ '/' ~ (subdir | default(''))) | selectattr('state', 'equalto', 'file') | selectattr('path', 'match', '.*\\.j2$') | list }}" + +- name: "Ensure directories exist for {{ var_prefix }}" + ansible.builtin.file: + path: "{{ target_root }}/{{ item.path | dirname }}" + state: directory + mode: "0755" + loop: "{{ lookup('vars', var_prefix ~ '_files') + lookup('vars', var_prefix ~ '_templates') }}" + when: item.path | dirname != '' + become: "{{ become_root | default(false) }}" + +- name: "Deploy files (local with symlinks) for {{ var_prefix }}" + ansible.builtin.file: + src: "{{ item.src }}" + dest: "{{ target_root }}/{{ item.path }}" + state: link + force: true + loop: "{{ lookup('vars', var_prefix ~ '_files') }}" + when: + - ansible_connection in ['local', 'localhost'] + - use_symlinks | default(true) + become: "{{ become_root | default(false) }}" + +- name: "Deploy files (local/remote copy) for {{ var_prefix }}" + ansible.builtin.copy: + src: "{{ item.src }}" + dest: "{{ target_root }}/{{ item.path }}" + mode: preserve + loop: "{{ lookup('vars', var_prefix ~ '_files') }}" + when: | + (ansible_connection not in ['local', 'localhost']) or + (not (use_symlinks | default(true))) + become: "{{ become_root | default(false) }}" + +- name: "Render templates for {{ var_prefix }}" + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ target_root }}/{{ item.path | replace('.j2', '') }}" + mode: preserve + loop: "{{ lookup('vars', var_prefix ~ '_templates') }}" + become: "{{ become_root | default(false) }}" diff --git a/dotfiles/common/home/.config/aichat/config.yaml.j2 b/roles/dotfiles/common/home/.config/aichat/config.yaml.j2 similarity index 100% rename from dotfiles/common/home/.config/aichat/config.yaml.j2 rename to roles/dotfiles/common/home/.config/aichat/config.yaml.j2 diff --git a/dotfiles/common/home/.env.j2 b/roles/dotfiles/common/home/.env.j2 similarity index 100% rename from dotfiles/common/home/.env.j2 rename to roles/dotfiles/common/home/.env.j2 diff --git a/dotfiles/common/home/.gitconfig b/roles/dotfiles/common/home/.gitconfig similarity index 100% rename from dotfiles/common/home/.gitconfig rename to roles/dotfiles/common/home/.gitconfig diff --git a/dotfiles/common/home/.local/share/nautilus/scripts/share-link b/roles/dotfiles/common/home/.local/share/nautilus/scripts/share-link similarity index 100% rename from dotfiles/common/home/.local/share/nautilus/scripts/share-link rename to roles/dotfiles/common/home/.local/share/nautilus/scripts/share-link diff --git a/dotfiles/common/home/.ssh/authorized_keys.j2 b/roles/dotfiles/common/home/.ssh/authorized_keys.j2 similarity index 100% rename from dotfiles/common/home/.ssh/authorized_keys.j2 rename to roles/dotfiles/common/home/.ssh/authorized_keys.j2 diff --git a/dotfiles/common/home/.ssh/config b/roles/dotfiles/common/home/.ssh/config similarity index 100% rename from dotfiles/common/home/.ssh/config rename to roles/dotfiles/common/home/.ssh/config diff --git a/dotfiles/common/home/.tmux.conf b/roles/dotfiles/common/home/.tmux.conf similarity index 100% rename from dotfiles/common/home/.tmux.conf rename to roles/dotfiles/common/home/.tmux.conf diff --git a/dotfiles/common/home/.vimrc b/roles/dotfiles/common/home/.vimrc similarity index 100% rename from dotfiles/common/home/.vimrc rename to roles/dotfiles/common/home/.vimrc diff --git a/dotfiles/common/home/.x2goclient/sessions b/roles/dotfiles/common/home/.x2goclient/sessions similarity index 100% rename from dotfiles/common/home/.x2goclient/sessions rename to roles/dotfiles/common/home/.x2goclient/sessions diff --git a/dotfiles/common/home/.zshrc b/roles/dotfiles/common/home/.zshrc similarity index 100% rename from dotfiles/common/home/.zshrc rename to roles/dotfiles/common/home/.zshrc diff --git a/dotfiles/common/root/etc/dnf/dnf.conf b/roles/dotfiles/common/root/etc/dnf/dnf.conf similarity index 100% rename from dotfiles/common/root/etc/dnf/dnf.conf rename to roles/dotfiles/common/root/etc/dnf/dnf.conf diff --git a/dotfiles/common/root/etc/sysconfig/btrfsmaintenance b/roles/dotfiles/common/root/etc/sysconfig/btrfsmaintenance similarity index 100% rename from dotfiles/common/root/etc/sysconfig/btrfsmaintenance rename to roles/dotfiles/common/root/etc/sysconfig/btrfsmaintenance diff --git a/dotfiles/laptop/home/.config/btrbk/btrbk.conf b/roles/dotfiles/laptop/home/.config/btrbk/btrbk.conf similarity index 100% rename from dotfiles/laptop/home/.config/btrbk/btrbk.conf rename to roles/dotfiles/laptop/home/.config/btrbk/btrbk.conf diff --git a/dotfiles/laptop/root/etc/keyd/default.conf b/roles/dotfiles/laptop/root/etc/keyd/default.conf similarity index 100% rename from dotfiles/laptop/root/etc/keyd/default.conf rename to roles/dotfiles/laptop/root/etc/keyd/default.conf diff --git a/roles/dotfiles/tasks/main.yml b/roles/dotfiles/tasks/main.yml index 3c1503e..4a81cf4 100644 --- a/roles/dotfiles/tasks/main.yml +++ b/roles/dotfiles/tasks/main.yml @@ -1,82 +1,18 @@ --- -- name: Build file lists - ansible.builtin.set_fact: - dotfiles_files_home: "{{ lookup('community.general.filetree', - playbook_dir ~ '/dotfiles/common/home', - playbook_dir ~ '/dotfiles/' ~ group_names[0] ~ '/home') | selectattr('state', 'equalto', 'file') | rejectattr('path', 'match', '.*\\.j2$') | list }}" - dotfiles_templates_home: "{{ lookup('community.general.filetree', - playbook_dir ~ '/dotfiles/common/home', - playbook_dir ~ '/dotfiles/' ~ group_names[0] ~ '/home') | selectattr('state', 'equalto', 'file') | selectattr('path', 'match', '.*\\.j2$') | list }}" - dotfiles_files_root: "{{ lookup('community.general.filetree', - playbook_dir ~ '/dotfiles/common/root', - playbook_dir ~ '/dotfiles/' ~ group_names[0] ~ '/root') | selectattr('state', 'equalto', 'file') | rejectattr('path', 'match', '.*\\.j2$') | list }}" - dotfiles_templates_root: "{{ lookup('community.general.filetree', - playbook_dir ~ '/dotfiles/common/root', - playbook_dir ~ '/dotfiles/' ~ group_names[0] ~ '/root') | selectattr('state', 'equalto', 'file') | selectattr('path', 'match', '.*\\.j2$') | list }}" +- name: Deploy home dotfiles + ansible.builtin.include_tasks: ../../deploy_files.yml + vars: + var_prefix: dotfiles_home + subdir: home + target_root: "{{ ansible_facts.env.HOME }}" + use_symlinks: true + become_root: false -- name: Ensure home directories - ansible.builtin.file: - path: "{{ ansible_facts.env.HOME }}/{{ item.path | dirname }}" - state: directory - mode: "{{ '0700' if (item.path | dirname).startswith('.ssh') else '0755' }}" - loop: "{{ dotfiles_files_home + dotfiles_templates_home }}" - when: item.path | dirname != '' - -- name: Deploy home files (local) - ansible.builtin.file: - src: "{{ item.src }}" - dest: "{{ ansible_facts.env.HOME }}/{{ item.path }}" - state: link - force: true - loop: "{{ dotfiles_files_home }}" - when: ansible_connection in ['local', 'localhost'] - -- name: Deploy home files (remote) - ansible.builtin.copy: - src: "{{ item.src }}" - dest: "{{ ansible_facts.env.HOME }}/{{ item.path }}" - mode: preserve - loop: "{{ dotfiles_files_home }}" - when: ansible_connection not in ['local', 'localhost'] - -- name: Render home templates - ansible.builtin.template: - src: "{{ item.src }}" - dest: "{{ ansible_facts.env.HOME }}/{{ item.path | replace('.j2', '') }}" - mode: preserve - loop: "{{ dotfiles_templates_home }}" - -- name: Ensure root directories - ansible.builtin.file: - path: "/{{ item.path | dirname }}" - state: directory - mode: '0755' - loop: "{{ dotfiles_files_root + dotfiles_templates_root }}" - become: true - -- name: Deploy root files (local) - ansible.builtin.file: - src: "{{ item.src }}" - dest: "/{{ item.path }}" - state: link - force: true - loop: "{{ dotfiles_files_root }}" - when: ansible_connection in ['local', 'localhost'] - become: true - -- name: Deploy root files (remote) - ansible.builtin.copy: - src: "{{ item.src }}" - dest: "/{{ item.path }}" - mode: preserve - loop: "{{ dotfiles_files_root }}" - when: ansible_connection not in ['local', 'localhost'] - become: true - -- name: Render root templates - ansible.builtin.template: - src: "{{ item.src }}" - dest: "/{{ item.path | replace('.j2', '') }}" - mode: preserve - loop: "{{ dotfiles_templates_root }}" - become: true +- name: Deploy root dotfiles + ansible.builtin.include_tasks: ../../deploy_files.yml + vars: + var_prefix: dotfiles_root + subdir: root + target_root: "/" + use_symlinks: true + become_root: true diff --git a/dotfiles/workstation/home/.config/btrbk/btrbk.conf b/roles/dotfiles/workstation/home/.config/btrbk/btrbk.conf similarity index 100% rename from dotfiles/workstation/home/.config/btrbk/btrbk.conf rename to roles/dotfiles/workstation/home/.config/btrbk/btrbk.conf diff --git a/dotfiles/workstation/root/etc/pwrstatd.conf b/roles/dotfiles/workstation/root/etc/pwrstatd.conf similarity index 100% rename from dotfiles/workstation/root/etc/pwrstatd.conf rename to roles/dotfiles/workstation/root/etc/pwrstatd.conf