collapsarr 0.1.3__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. collapsarr-0.2.0/.env.example +49 -0
  2. {collapsarr-0.1.3 → collapsarr-0.2.0}/Dockerfile +4 -2
  3. {collapsarr-0.1.3 → collapsarr-0.2.0}/PKG-INFO +82 -28
  4. collapsarr-0.2.0/README.md +244 -0
  5. collapsarr-0.2.0/collapsarr/auth/__init__.py +20 -0
  6. collapsarr-0.2.0/collapsarr/auth/enforcement.py +245 -0
  7. collapsarr-0.2.0/collapsarr/auth/routes.py +220 -0
  8. collapsarr-0.2.0/collapsarr/auth/session.py +186 -0
  9. collapsarr-0.2.0/collapsarr/config.py +204 -0
  10. collapsarr-0.2.0/collapsarr/database.py +131 -0
  11. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/main.py +21 -3
  12. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/settings/__init__.py +16 -2
  13. collapsarr-0.2.0/collapsarr/settings/env_seed.py +59 -0
  14. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/settings/models.py +68 -3
  15. collapsarr-0.2.0/collapsarr/settings/passwords.py +100 -0
  16. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/settings/routes.py +33 -0
  17. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/settings/service.py +69 -6
  18. collapsarr-0.2.0/frontend/dist/assets/index-CuYlNmcT.css +1 -0
  19. collapsarr-0.2.0/frontend/dist/assets/index-Dv5U12vj.js +68 -0
  20. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/dist/index.html +2 -2
  21. collapsarr-0.2.0/frontend/src/api/auth.ts +108 -0
  22. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/api/client.ts +42 -1
  23. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/AppShell.tsx +6 -0
  24. collapsarr-0.2.0/frontend/src/components/OnboardingPanel.tsx +106 -0
  25. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/Sidebar.tsx +25 -1
  26. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/settings/GeneralSection.tsx +190 -1
  27. collapsarr-0.2.0/frontend/src/pages/LoginPage.tsx +114 -0
  28. collapsarr-0.2.0/frontend/src/pages/SetupPage.tsx +114 -0
  29. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/routes/router.tsx +8 -0
  30. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/styles/global.css +103 -0
  31. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/apiClient.test.ts +67 -0
  32. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/fileDetailPage.test.tsx +2 -0
  33. collapsarr-0.2.0/frontend/src/test/loginPage.test.tsx +107 -0
  34. collapsarr-0.2.0/frontend/src/test/onboardingPanel.test.tsx +131 -0
  35. collapsarr-0.2.0/frontend/src/test/settingsGeneral.test.tsx +291 -0
  36. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/settingsPage.test.tsx +2 -0
  37. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/settingsTargets.test.tsx +2 -0
  38. collapsarr-0.2.0/frontend/src/test/setupPage.test.tsx +88 -0
  39. collapsarr-0.2.0/frontend/src/test/sidebarLogout.test.tsx +41 -0
  40. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/types/settings.ts +24 -0
  41. {collapsarr-0.1.3 → collapsarr-0.2.0}/pyproject.toml +3 -1
  42. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_arr_routes.py +2 -1
  43. collapsarr-0.2.0/tests/test_auth.py +607 -0
  44. collapsarr-0.2.0/tests/test_config.py +174 -0
  45. collapsarr-0.2.0/tests/test_database.py +230 -0
  46. collapsarr-0.2.0/tests/test_env_seed.py +218 -0
  47. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_jobs_routes.py +7 -4
  48. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_notify_routes.py +5 -2
  49. collapsarr-0.2.0/tests/test_passwords.py +66 -0
  50. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_settings_routes.py +33 -2
  51. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_settings_service.py +207 -2
  52. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_wanted_routes.py +3 -1
  53. collapsarr-0.1.3/.env.example +0 -16
  54. collapsarr-0.1.3/README.md +0 -192
  55. collapsarr-0.1.3/collapsarr/auth.py +0 -83
  56. collapsarr-0.1.3/collapsarr/config.py +0 -95
  57. collapsarr-0.1.3/collapsarr/database.py +0 -82
  58. collapsarr-0.1.3/frontend/dist/assets/index-Dfozi1oM.js +0 -68
  59. collapsarr-0.1.3/frontend/dist/assets/index-J2qCuzXj.css +0 -1
  60. collapsarr-0.1.3/frontend/src/test/settingsGeneral.test.tsx +0 -145
  61. collapsarr-0.1.3/tests/test_auth.py +0 -53
  62. collapsarr-0.1.3/tests/test_config.py +0 -51
  63. {collapsarr-0.1.3 → collapsarr-0.2.0}/.dockerignore +0 -0
  64. {collapsarr-0.1.3 → collapsarr-0.2.0}/.gitattributes +0 -0
  65. {collapsarr-0.1.3 → collapsarr-0.2.0}/.github/brand/icon-512.png +0 -0
  66. {collapsarr-0.1.3 → collapsarr-0.2.0}/.github/brand/social-preview.png +0 -0
  67. {collapsarr-0.1.3 → collapsarr-0.2.0}/.github/brand/social-preview.svg +0 -0
  68. {collapsarr-0.1.3 → collapsarr-0.2.0}/.github/workflows/release.yml +0 -0
  69. {collapsarr-0.1.3 → collapsarr-0.2.0}/.gitignore +0 -0
  70. {collapsarr-0.1.3 → collapsarr-0.2.0}/LICENSE +0 -0
  71. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/__init__.py +0 -0
  72. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/__main__.py +0 -0
  73. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/arr/__init__.py +0 -0
  74. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/arr/client.py +0 -0
  75. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/arr/files.py +0 -0
  76. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/arr/models.py +0 -0
  77. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/arr/routes.py +0 -0
  78. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/arr/service.py +0 -0
  79. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/arr/webhooks.py +0 -0
  80. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/downmix/__init__.py +0 -0
  81. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/downmix/apply.py +0 -0
  82. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/downmix/pipeline.py +0 -0
  83. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/downmix/probe.py +0 -0
  84. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/downmix/remux.py +0 -0
  85. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/downmix/targets.py +0 -0
  86. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/frontend.py +0 -0
  87. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/health.py +0 -0
  88. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/jobs/__init__.py +0 -0
  89. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/jobs/failure_notify.py +0 -0
  90. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/jobs/history.py +0 -0
  91. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/jobs/models.py +0 -0
  92. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/jobs/queue.py +0 -0
  93. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/jobs/routes.py +0 -0
  94. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/jobs/scheduler.py +0 -0
  95. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/media/__init__.py +0 -0
  96. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/media/models.py +0 -0
  97. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/media/routes.py +0 -0
  98. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/media/service.py +0 -0
  99. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/notify/__init__.py +0 -0
  100. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/notify/dispatch.py +0 -0
  101. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/notify/models.py +0 -0
  102. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/notify/routes.py +0 -0
  103. {collapsarr-0.1.3 → collapsarr-0.2.0}/collapsarr/notify/service.py +0 -0
  104. {collapsarr-0.1.3 → collapsarr-0.2.0}/docker-entrypoint.sh +0 -0
  105. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/README.md +0 -0
  106. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/dist/apple-touch-icon.png +0 -0
  107. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/dist/favicon-32.png +0 -0
  108. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/dist/favicon.svg +0 -0
  109. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/eslint.config.js +0 -0
  110. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/index.html +0 -0
  111. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/package-lock.json +0 -0
  112. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/package.json +0 -0
  113. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/public/apple-touch-icon.png +0 -0
  114. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/public/favicon-32.png +0 -0
  115. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/public/favicon.svg +0 -0
  116. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/api/activity.ts +0 -0
  117. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/api/health.ts +0 -0
  118. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/api/instances.ts +0 -0
  119. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/api/notifiers.ts +0 -0
  120. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/api/settings.ts +0 -0
  121. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/api/wanted.ts +0 -0
  122. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/HealthBanner.tsx +0 -0
  123. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/PlaceholderView.tsx +0 -0
  124. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/icons.tsx +0 -0
  125. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/settings/ConnectSection.tsx +0 -0
  126. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/settings/InstancesSection.tsx +0 -0
  127. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/settings/PathMappingsPanel.tsx +0 -0
  128. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/components/settings/TargetsSection.tsx +0 -0
  129. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/main.tsx +0 -0
  130. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/pages/ActivityPage.tsx +0 -0
  131. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/pages/FileDetailPage.tsx +0 -0
  132. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/pages/SettingsPage.tsx +0 -0
  133. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/pages/WantedPage.tsx +0 -0
  134. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/routes/nav.tsx +0 -0
  135. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/styles/theme.css +0 -0
  136. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/activityPage.test.tsx +0 -0
  137. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/appShell.test.tsx +0 -0
  138. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/healthBanner.test.tsx +0 -0
  139. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/settingsConnect.test.tsx +0 -0
  140. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/settingsInstances.test.tsx +0 -0
  141. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/setup.ts +0 -0
  142. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/test/wantedPage.test.tsx +0 -0
  143. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/types/activity.ts +0 -0
  144. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/types/health.ts +0 -0
  145. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/types/instances.ts +0 -0
  146. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/types/notifiers.ts +0 -0
  147. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/types/wanted.ts +0 -0
  148. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/src/vite-env.d.ts +0 -0
  149. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/tsconfig.json +0 -0
  150. {collapsarr-0.1.3 → collapsarr-0.2.0}/frontend/vite.config.ts +0 -0
  151. {collapsarr-0.1.3 → collapsarr-0.2.0}/hatch_build.py +0 -0
  152. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/__init__.py +0 -0
  153. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/conftest.py +0 -0
  154. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/radarr_movie_list.json +0 -0
  155. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/radarr_status_ok.json +0 -0
  156. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/radarr_webhook_on_import.json +0 -0
  157. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/radarr_webhook_on_upgrade.json +0 -0
  158. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/sonarr_episodefiles_series1.json +0 -0
  159. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/sonarr_series_list.json +0 -0
  160. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/sonarr_status_ok.json +0 -0
  161. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/sonarr_webhook_on_import.json +0 -0
  162. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/sonarr_webhook_on_upgrade.json +0 -0
  163. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/sonarr_webhook_test.json +0 -0
  164. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/arr/unauthorized.json +0 -0
  165. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/downmix/multi_lang.mkv +0 -0
  166. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/downmix/stereo_eng.mkv +0 -0
  167. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/downmix/surround_51.mkv +0 -0
  168. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/downmix/surround_71.mkv +0 -0
  169. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/downmix/untagged_language.mkv +0 -0
  170. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/fixtures/downmix/video_audio_subs.mkv +0 -0
  171. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_arr_client.py +0 -0
  172. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_arr_files.py +0 -0
  173. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_arr_models.py +0 -0
  174. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_arr_service.py +0 -0
  175. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_arr_webhooks.py +0 -0
  176. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_downmix_apply.py +0 -0
  177. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_downmix_pipeline.py +0 -0
  178. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_downmix_probe.py +0 -0
  179. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_downmix_remux.py +0 -0
  180. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_downmix_targets.py +0 -0
  181. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_frontend.py +0 -0
  182. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_health.py +0 -0
  183. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_health_check.py +0 -0
  184. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_jobs_failure_notify.py +0 -0
  185. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_jobs_history.py +0 -0
  186. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_jobs_queue.py +0 -0
  187. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_jobs_scheduler.py +0 -0
  188. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_main.py +0 -0
  189. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_media_service.py +0 -0
  190. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_notify_dispatch.py +0 -0
  191. {collapsarr-0.1.3 → collapsarr-0.2.0}/tests/test_notify_service.py +0 -0
@@ -0,0 +1,49 @@
1
+ # Collapsarr configuration.
2
+ # Copy to `.env` and adjust as needed. All variables are optional — the values
3
+ # below are the built-in defaults. Environment variables take precedence.
4
+ #
5
+ # On a bare-metal/PyPI install, none of these need to be set: Collapsarr picks
6
+ # a writable, OS-appropriate data directory automatically (see
7
+ # COLLAPSARR_DATA_DIR below). The Docker image sets COLLAPSARR_DATA_DIR itself
8
+ # to point at the /config volume.
9
+
10
+ # Root directory for application data (the SQLite database today; logs and
11
+ # backups later). Created automatically if it doesn't exist. Defaults to the
12
+ # OS user-data directory, e.g. ~/.local/share/collapsarr on Linux,
13
+ # ~/Library/Application Support/collapsarr on macOS,
14
+ # %LOCALAPPDATA%\collapsarr on Windows.
15
+ # COLLAPSARR_DATA_DIR=/config
16
+
17
+ # Filesystem path to the SQLite database file. Defaults to
18
+ # <COLLAPSARR_DATA_DIR>/collapsarr.db; set this to override that location
19
+ # directly.
20
+ # COLLAPSARR_DATABASE_PATH=/config/collapsarr.db
21
+
22
+ # Full SQLAlchemy database URL. When set, overrides COLLAPSARR_DATABASE_PATH.
23
+ # COLLAPSARR_DATABASE_URL=sqlite:////config/collapsarr.db
24
+
25
+ # API server bind address and port.
26
+ COLLAPSARR_HOST=0.0.0.0
27
+ COLLAPSARR_PORT=8282
28
+
29
+ # Log level (DEBUG, INFO, WARNING, ERROR).
30
+ COLLAPSARR_LOG_LEVEL=INFO
31
+
32
+ # First-boot credential seed for headless/declarative deploys (Docker,
33
+ # automation): set BOTH together and a fresh install is seeded with this
34
+ # credential on first boot -- hashed before it's persisted, never stored or
35
+ # logged in plaintext -- and skips the interactive /setup page entirely.
36
+ # One-shot: this never overwrites a credential that already exists, even if
37
+ # left set on a later boot. This is also the supported password-recovery/
38
+ # lockout escape hatch, but only for a FRESH or already-locked-out install
39
+ # with no credential configured yet -- it does not help recover a forgotten
40
+ # password once a credential is already set (that takes clearing the
41
+ # existing one directly, e.g. in the database).
42
+ # COLLAPSARR_AUTH_USERNAME=admin
43
+ # COLLAPSARR_AUTH_PASSWORD=change-me
44
+
45
+ # Optional, only applied when the credential above is actually seeded.
46
+ # COLLAPSARR_AUTH_METHOD: forms (default) | basic
47
+ # COLLAPSARR_AUTH_REQUIRED: local_bypass (default) | enabled
48
+ # COLLAPSARR_AUTH_METHOD=forms
49
+ # COLLAPSARR_AUTH_REQUIRED=local_bypass
@@ -65,10 +65,12 @@ COPY docker-entrypoint.sh /docker-entrypoint.sh
65
65
  RUN chmod +x /docker-entrypoint.sh
66
66
 
67
67
  # Runtime configuration. COLLAPSARR_* mirror the app defaults (collapsarr/config.py);
68
- # PUID/PGID are consumed by the entrypoint.
68
+ # PUID/PGID are consumed by the entrypoint. COLLAPSARR_DATA_DIR points at the
69
+ # /config volume; database_path derives to /config/collapsarr.db (COL-46), so
70
+ # existing /config volumes keep landing the DB at the same path on upgrade.
69
71
  ENV COLLAPSARR_HOST=0.0.0.0 \
70
72
  COLLAPSARR_PORT=8282 \
71
- COLLAPSARR_DATABASE_PATH=/config/collapsarr.db \
73
+ COLLAPSARR_DATA_DIR=/config \
72
74
  PUID=1000 \
73
75
  PGID=1000
74
76
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: collapsarr
3
- Version: 0.1.3
3
+ Version: 0.2.0
4
4
  Summary: An *arr-family companion app that adds downmixed (stereo/2.1/5.1) audio tracks to media missing them, via FFmpeg.
5
5
  Project-URL: Homepage, https://github.com/JovinJovinsson/Collapsarr
6
6
  Project-URL: Repository, https://github.com/JovinJovinsson/Collapsarr
@@ -14,6 +14,8 @@ Classifier: Topic :: Multimedia :: Sound/Audio
14
14
  Requires-Python: >=3.12
15
15
  Requires-Dist: fastapi>=0.110
16
16
  Requires-Dist: httpx>=0.27
17
+ Requires-Dist: itsdangerous>=2.0
18
+ Requires-Dist: platformdirs>=4.0
17
19
  Requires-Dist: pydantic-settings>=2.2
18
20
  Requires-Dist: pydantic>=2.6
19
21
  Requires-Dist: sqlalchemy>=2.0
@@ -30,28 +32,17 @@ Description-Content-Type: text/markdown
30
32
 
31
33
  **Never get stuck without a downmix again.**
32
34
 
33
- <!--
34
- Stub row: static "pending" badges, deliberately not pointed at real
35
- endpoints yet. Swap for live dynamic badges once COL-8 (Packaging &
36
- Release) ships a release.yml workflow and the DockerHub repo is live:
37
- CI -> https://github.com/JovinJovinsson/Collapsarr/actions/workflows/release.yml/badge.svg
38
- Docker -> https://img.shields.io/docker/pulls/odxnsson/collapsarr
39
- Release -> https://img.shields.io/github/v/release/JovinJovinsson/Collapsarr
40
- -->
41
35
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-8B5CF6.svg)](LICENSE)
42
- [![CI](https://img.shields.io/badge/CI-pending-lightgrey.svg)](https://github.com/JovinJovinsson/Collapsarr/actions)
43
- [![Docker](https://img.shields.io/badge/docker-pending-lightgrey.svg)](https://hub.docker.com/r/odxnsson/collapsarr)
44
- [![Release](https://img.shields.io/badge/release-pending-lightgrey.svg)](https://github.com/JovinJovinsson/Collapsarr/releases)
36
+ [![CI](https://github.com/JovinJovinsson/Collapsarr/actions/workflows/release.yml/badge.svg)](https://github.com/JovinJovinsson/Collapsarr/actions/workflows/release.yml)
37
+ [![Docker](https://img.shields.io/docker/v/odxnsson/collapsarr?label=docker)](https://hub.docker.com/r/odxnsson/collapsarr)
38
+ [![PyPI](https://img.shields.io/pypi/v/collapsarr)](https://pypi.org/project/collapsarr/)
39
+ [![Release](https://img.shields.io/github/v/release/JovinJovinsson/Collapsarr)](https://github.com/JovinJovinsson/Collapsarr/releases)
45
40
 
46
41
  Collapsarr is a companion application for Sonarr and Radarr. It watches your
47
42
  library for media missing a lower-channel-count audio track — a 7.1 release
48
43
  with no stereo fallback, a 5.1 file your soundbar can't decode — and adds one
49
44
  automatically via FFmpeg, without touching the track that's already there.
50
45
 
51
- > **Status:** core backend and Web UI are built; packaging (PyPI + Docker) is
52
- > in progress. Until that ships, run from source — see
53
- > [Development](#development) below.
54
-
55
46
  ## Why
56
47
 
57
48
  - **No upmixing, ever.** Collapsarr only adds tracks the source can actually
@@ -84,11 +75,7 @@ automatically via FFmpeg, without touching the track that's already there.
84
75
 
85
76
  ## Quick start
86
77
 
87
- <!--
88
- Drafted now, finalized once COL-8 (Packaging & Release) ships: this image
89
- isn't published to Docker Hub yet, so this is the target shape, not a
90
- working pull today.
91
- -->
78
+ **Docker (recommended):**
92
79
 
93
80
  ```yaml
94
81
  services:
@@ -106,11 +93,30 @@ services:
106
93
  restart: unless-stopped
107
94
  ```
108
95
 
109
- Then open `http://localhost:8282`. `restart: unless-stopped` above means the
110
- container comes back automatically whenever it stops unexpectedly or the
111
- Docker daemon restarts (e.g. after a host reboot) — see
112
- [Running on startup](#running-on-startup) if you need it to survive a reboot
113
- on a bare-metal/PyPI install instead.
96
+ Then open `http://localhost:8282` — you'll land on a one-time credential setup
97
+ page (see [Authentication](#authentication) for how login is enforced,
98
+ including the caveat if you're putting Collapsarr behind a reverse proxy).
99
+ `restart: unless-stopped` above means the container comes back automatically
100
+ whenever it stops unexpectedly or the Docker daemon restarts (e.g. after a
101
+ host reboot) — see [Running on startup](#running-on-startup) if you need it
102
+ to survive a reboot on a bare-metal/PyPI install instead.
103
+
104
+ **PyPI (bare-metal):**
105
+
106
+ ```bash
107
+ pipx install collapsarr
108
+ collapsarr
109
+ ```
110
+
111
+ No flags, no config file needed — Collapsarr stores its SQLite database
112
+ under your platform's standard per-user data directory by default (e.g.
113
+ `~/.local/share/collapsarr/collapsarr.db` on Linux; native per-OS locations
114
+ on macOS/Windows), creating it automatically if it doesn't exist. Set
115
+ `COLLAPSARR_DATA_DIR` if you'd rather it live somewhere else — see
116
+ [Configuration](#configuration). Requires FFmpeg on `PATH` — see
117
+ [Requirements](#requirements) below. Open `http://localhost:8282`; see
118
+ [Configuration](#configuration) for the full list of environment variables,
119
+ and [Running on startup](#running-on-startup) for a systemd unit.
114
120
 
115
121
  ## Requirements
116
122
 
@@ -129,6 +135,49 @@ on a bare-metal/PyPI install instead.
129
135
 
130
136
  Verify with `ffmpeg -version`. Official builds/source: [ffmpeg.org/download.html](https://ffmpeg.org/download.html).
131
137
 
138
+ ## Authentication
139
+
140
+ Collapsarr requires a one-time credential setup (`/setup`, first run) and,
141
+ after that, logging in (`/login`) before the UI/API is usable — *except* from
142
+ a caller Collapsarr considers "local". The **Login requirement** setting
143
+ (Settings → General, `auth_required` in the API) controls this:
144
+
145
+ | Mode | Behaviour |
146
+ | --- | --- |
147
+ | **Disabled for local addresses** (`local_bypass`, default) | A caller connecting from a loopback (`127.0.0.1`/`::1`) or private-range (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, etc.) address reaches the UI and API with no setup and no login. Anyone connecting from a routable/public address still has to authenticate normally. |
148
+ | **Always required** (`enabled`) | Every caller is challenged, regardless of address. |
149
+
150
+ **Reverse-proxy limitation:** local-address classification looks only at the
151
+ *direct* TCP connection Collapsarr accepted — never an `X-Forwarded-For` (or
152
+ similar) header, since that's supplied by the client and trivially spoofable.
153
+ If Collapsarr sits behind a reverse proxy (nginx, Traefik, Cloudflare Tunnel,
154
+ etc.), every request's direct peer is the proxy itself, which usually *is*
155
+ local — meaning **every** client, including ones out on the internet, would
156
+ be classified as local and skip authentication entirely. **If you run
157
+ Collapsarr behind a reverse proxy, set the Login requirement to "Always
158
+ required" (`auth_required=enabled`)** until a future release adds
159
+ trusted-proxy support (a stubbed-out capability today).
160
+
161
+ **Headless deploys — seeding a credential without the setup page:** a
162
+ declarative/automated deploy (Docker Compose, Ansible, etc.) has no human
163
+ available to click through `/setup`. Set `COLLAPSARR_AUTH_USERNAME` and
164
+ `COLLAPSARR_AUTH_PASSWORD` (together — see
165
+ [Configuration](#configuration)) and a fresh install seeds that credential on
166
+ first boot instead — hashed before it's persisted, never stored or logged in
167
+ plaintext — and comes up already past the setup gate. `COLLAPSARR_AUTH_METHOD`
168
+ and `COLLAPSARR_AUTH_REQUIRED` are honoured at the same time if set, otherwise
169
+ the seeded credential gets the same defaults `/setup` would (`forms`,
170
+ `local_bypass`).
171
+
172
+ This doubles as the supported password-recovery/lockout escape hatch, but
173
+ **only for a fresh or already-locked-out install with no credential
174
+ configured yet** — seeding runs once and never overwrites a credential that
175
+ already exists, even if the environment variables are still set on a later
176
+ boot. It does **not** help recover a *forgotten* password once a credential
177
+ is already set; that requires clearing the existing `auth_username`/
178
+ `auth_password_hash` first (e.g. directly in the database) so the instance
179
+ has no credential again, at which point re-seeding (or `/setup`) applies.
180
+
132
181
  ## Development
133
182
 
134
183
  ```bash
@@ -157,11 +206,16 @@ directory. See [`.env.example`](.env.example).
157
206
 
158
207
  | Variable | Default | Description |
159
208
  | --- | --- | --- |
160
- | `COLLAPSARR_DATABASE_PATH` | `/config/collapsarr.db` | SQLite database file path. |
161
- | `COLLAPSARR_DATABASE_URL` | *(derived from path)* | Full SQLAlchemy URL override. |
209
+ | `COLLAPSARR_DATA_DIR` | *(OS user-data dir)* | Root directory for application data — the SQLite database today, logs/backups later. Defaults to `platformdirs.user_data_dir("collapsarr")` (e.g. `~/.local/share/collapsarr` on Linux). Created automatically if missing. The Docker image sets this to `/config` (its mounted volume) — see [Quick start](#quick-start). |
210
+ | `COLLAPSARR_DATABASE_PATH` | *(derived from `COLLAPSARR_DATA_DIR`)* | SQLite database file path. Set this to override the location directly, independent of `COLLAPSARR_DATA_DIR`. |
211
+ | `COLLAPSARR_DATABASE_URL` | *(derived from path)* | Full SQLAlchemy URL override — takes precedence over both of the above. |
162
212
  | `COLLAPSARR_HOST` | `0.0.0.0` | API server bind address. |
163
213
  | `COLLAPSARR_PORT` | `8282` | API server bind port. |
164
214
  | `COLLAPSARR_LOG_LEVEL` | `INFO` | Log level. |
215
+ | `COLLAPSARR_AUTH_USERNAME` | *(unset)* | First-boot credential seed: UI username. Set together with `COLLAPSARR_AUTH_PASSWORD` — see [Authentication](#authentication). |
216
+ | `COLLAPSARR_AUTH_PASSWORD` | *(unset)* | First-boot credential seed: UI password. Hashed before being persisted; never stored or logged in plaintext. |
217
+ | `COLLAPSARR_AUTH_METHOD` | *(unset — `forms`)* | Optional, only applied when the seed credential above is actually seeded: `forms` or `basic`. |
218
+ | `COLLAPSARR_AUTH_REQUIRED` | *(unset — `local_bypass`)* | Optional, only applied when the seed credential above is actually seeded: `enabled` or `local_bypass`. |
165
219
 
166
220
  ## Running on startup
167
221
 
@@ -0,0 +1,244 @@
1
+ <img src="frontend/public/favicon.svg" width="72" align="right" alt="Collapsarr logo" />
2
+
3
+ # Collapsarr
4
+
5
+ **Never get stuck without a downmix again.**
6
+
7
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-8B5CF6.svg)](LICENSE)
8
+ [![CI](https://github.com/JovinJovinsson/Collapsarr/actions/workflows/release.yml/badge.svg)](https://github.com/JovinJovinsson/Collapsarr/actions/workflows/release.yml)
9
+ [![Docker](https://img.shields.io/docker/v/odxnsson/collapsarr?label=docker)](https://hub.docker.com/r/odxnsson/collapsarr)
10
+ [![PyPI](https://img.shields.io/pypi/v/collapsarr)](https://pypi.org/project/collapsarr/)
11
+ [![Release](https://img.shields.io/github/v/release/JovinJovinsson/Collapsarr)](https://github.com/JovinJovinsson/Collapsarr/releases)
12
+
13
+ Collapsarr is a companion application for Sonarr and Radarr. It watches your
14
+ library for media missing a lower-channel-count audio track — a 7.1 release
15
+ with no stereo fallback, a 5.1 file your soundbar can't decode — and adds one
16
+ automatically via FFmpeg, without touching the track that's already there.
17
+
18
+ ## Why
19
+
20
+ - **No upmixing, ever.** Collapsarr only adds tracks the source can actually
21
+ support (a stereo/2.1/5.1 downmix from a higher channel count) — it will
22
+ never fake a 5.1 track out of a stereo source.
23
+ - **Originals are never at risk.** The remux writes to a temp file, validates
24
+ duration and stream count, then atomically swaps it in. Any failure at any
25
+ stage leaves the original file completely untouched — no partial writes, no
26
+ orphaned backups.
27
+ - **Fits into the \*arr stack you already run.** Sonarr/Radarr integration
28
+ (webhooks + periodic scan), a dark UI in the same style as the rest of the
29
+ family, and a REST API following the same conventions.
30
+
31
+ ## Features
32
+
33
+ - Sonarr and Radarr integration — instance config, connectivity check, remote
34
+ path mapping, multiple concurrent instances
35
+ - Per-target, per-language detection that stacks additional targets without
36
+ duplicating what's already there
37
+ - FFmpeg remux: stream-copies existing tracks, encodes new audio (AAC for
38
+ Stereo, AC3 @ 448kbps for 2.1/5.1)
39
+ - Job queue with configurable concurrency — triggered by webhook, periodic
40
+ full-library scan, on-demand scan, or manual per-file trigger
41
+ - Full job history: status, timestamps, FFmpeg exit code, error text
42
+ - Web UI in the same dark theme as Sonarr/Radarr/Bazarr — Wanted view,
43
+ Activity/History, per-file detail view with a manual trigger
44
+ - Webhook + Discord notifications on job failure or app health issues (e.g.
45
+ FFmpeg missing)
46
+ - REST API with \*arr-convention auth (API key)
47
+
48
+ ## Quick start
49
+
50
+ **Docker (recommended):**
51
+
52
+ ```yaml
53
+ services:
54
+ collapsarr:
55
+ image: odxnsson/collapsarr:latest
56
+ container_name: collapsarr
57
+ ports:
58
+ - "8282:8282"
59
+ volumes:
60
+ - ./config:/config
61
+ - /path/to/media:/media
62
+ environment:
63
+ - PUID=1000
64
+ - PGID=1000
65
+ restart: unless-stopped
66
+ ```
67
+
68
+ Then open `http://localhost:8282` — you'll land on a one-time credential setup
69
+ page (see [Authentication](#authentication) for how login is enforced,
70
+ including the caveat if you're putting Collapsarr behind a reverse proxy).
71
+ `restart: unless-stopped` above means the container comes back automatically
72
+ whenever it stops unexpectedly or the Docker daemon restarts (e.g. after a
73
+ host reboot) — see [Running on startup](#running-on-startup) if you need it
74
+ to survive a reboot on a bare-metal/PyPI install instead.
75
+
76
+ **PyPI (bare-metal):**
77
+
78
+ ```bash
79
+ pipx install collapsarr
80
+ collapsarr
81
+ ```
82
+
83
+ No flags, no config file needed — Collapsarr stores its SQLite database
84
+ under your platform's standard per-user data directory by default (e.g.
85
+ `~/.local/share/collapsarr/collapsarr.db` on Linux; native per-OS locations
86
+ on macOS/Windows), creating it automatically if it doesn't exist. Set
87
+ `COLLAPSARR_DATA_DIR` if you'd rather it live somewhere else — see
88
+ [Configuration](#configuration). Requires FFmpeg on `PATH` — see
89
+ [Requirements](#requirements) below. Open `http://localhost:8282`; see
90
+ [Configuration](#configuration) for the full list of environment variables,
91
+ and [Running on startup](#running-on-startup) for a systemd unit.
92
+
93
+ ## Requirements
94
+
95
+ - Python 3.12+
96
+ - FFmpeg — external system dependency, checked at startup and reported on the
97
+ health page if missing. Bundled in the Docker image; install it yourself
98
+ for a bare-metal/PyPI setup:
99
+
100
+ | OS | Command |
101
+ | --- | --- |
102
+ | Debian / Ubuntu | `sudo apt install ffmpeg` |
103
+ | Fedora | `sudo dnf install ffmpeg` |
104
+ | Arch | `sudo pacman -S ffmpeg` |
105
+ | macOS (Homebrew) | `brew install ffmpeg` |
106
+ | Windows (winget) | `winget install ffmpeg` |
107
+
108
+ Verify with `ffmpeg -version`. Official builds/source: [ffmpeg.org/download.html](https://ffmpeg.org/download.html).
109
+
110
+ ## Authentication
111
+
112
+ Collapsarr requires a one-time credential setup (`/setup`, first run) and,
113
+ after that, logging in (`/login`) before the UI/API is usable — *except* from
114
+ a caller Collapsarr considers "local". The **Login requirement** setting
115
+ (Settings → General, `auth_required` in the API) controls this:
116
+
117
+ | Mode | Behaviour |
118
+ | --- | --- |
119
+ | **Disabled for local addresses** (`local_bypass`, default) | A caller connecting from a loopback (`127.0.0.1`/`::1`) or private-range (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, etc.) address reaches the UI and API with no setup and no login. Anyone connecting from a routable/public address still has to authenticate normally. |
120
+ | **Always required** (`enabled`) | Every caller is challenged, regardless of address. |
121
+
122
+ **Reverse-proxy limitation:** local-address classification looks only at the
123
+ *direct* TCP connection Collapsarr accepted — never an `X-Forwarded-For` (or
124
+ similar) header, since that's supplied by the client and trivially spoofable.
125
+ If Collapsarr sits behind a reverse proxy (nginx, Traefik, Cloudflare Tunnel,
126
+ etc.), every request's direct peer is the proxy itself, which usually *is*
127
+ local — meaning **every** client, including ones out on the internet, would
128
+ be classified as local and skip authentication entirely. **If you run
129
+ Collapsarr behind a reverse proxy, set the Login requirement to "Always
130
+ required" (`auth_required=enabled`)** until a future release adds
131
+ trusted-proxy support (a stubbed-out capability today).
132
+
133
+ **Headless deploys — seeding a credential without the setup page:** a
134
+ declarative/automated deploy (Docker Compose, Ansible, etc.) has no human
135
+ available to click through `/setup`. Set `COLLAPSARR_AUTH_USERNAME` and
136
+ `COLLAPSARR_AUTH_PASSWORD` (together — see
137
+ [Configuration](#configuration)) and a fresh install seeds that credential on
138
+ first boot instead — hashed before it's persisted, never stored or logged in
139
+ plaintext — and comes up already past the setup gate. `COLLAPSARR_AUTH_METHOD`
140
+ and `COLLAPSARR_AUTH_REQUIRED` are honoured at the same time if set, otherwise
141
+ the seeded credential gets the same defaults `/setup` would (`forms`,
142
+ `local_bypass`).
143
+
144
+ This doubles as the supported password-recovery/lockout escape hatch, but
145
+ **only for a fresh or already-locked-out install with no credential
146
+ configured yet** — seeding runs once and never overwrites a credential that
147
+ already exists, even if the environment variables are still set on a later
148
+ boot. It does **not** help recover a *forgotten* password once a credential
149
+ is already set; that requires clearing the existing `auth_username`/
150
+ `auth_password_hash` first (e.g. directly in the database) so the instance
151
+ has no credential again, at which point re-seeding (or `/setup`) applies.
152
+
153
+ ## Development
154
+
155
+ ```bash
156
+ python -m venv .venv
157
+ source .venv/bin/activate
158
+ pip install -e ".[dev]"
159
+
160
+ # Run the checks
161
+ pytest
162
+ ruff check .
163
+ mypy
164
+
165
+ # Run the server (defaults to http://0.0.0.0:8282)
166
+ python -m collapsarr
167
+ # then: curl http://localhost:8282/health
168
+ # -> {"status":"ok","version":"...","warnings":[]}
169
+ # (or, if FFmpeg is missing: {"status":"degraded","version":"...",
170
+ # "warnings":[{"code":"ffmpeg_missing","message":"..."}]})
171
+ ```
172
+
173
+ ## Configuration
174
+
175
+ All settings load from environment variables (prefixed `COLLAPSARR_`) with
176
+ sensible defaults, and an optional `.env` file is read from the working
177
+ directory. See [`.env.example`](.env.example).
178
+
179
+ | Variable | Default | Description |
180
+ | --- | --- | --- |
181
+ | `COLLAPSARR_DATA_DIR` | *(OS user-data dir)* | Root directory for application data — the SQLite database today, logs/backups later. Defaults to `platformdirs.user_data_dir("collapsarr")` (e.g. `~/.local/share/collapsarr` on Linux). Created automatically if missing. The Docker image sets this to `/config` (its mounted volume) — see [Quick start](#quick-start). |
182
+ | `COLLAPSARR_DATABASE_PATH` | *(derived from `COLLAPSARR_DATA_DIR`)* | SQLite database file path. Set this to override the location directly, independent of `COLLAPSARR_DATA_DIR`. |
183
+ | `COLLAPSARR_DATABASE_URL` | *(derived from path)* | Full SQLAlchemy URL override — takes precedence over both of the above. |
184
+ | `COLLAPSARR_HOST` | `0.0.0.0` | API server bind address. |
185
+ | `COLLAPSARR_PORT` | `8282` | API server bind port. |
186
+ | `COLLAPSARR_LOG_LEVEL` | `INFO` | Log level. |
187
+ | `COLLAPSARR_AUTH_USERNAME` | *(unset)* | First-boot credential seed: UI username. Set together with `COLLAPSARR_AUTH_PASSWORD` — see [Authentication](#authentication). |
188
+ | `COLLAPSARR_AUTH_PASSWORD` | *(unset)* | First-boot credential seed: UI password. Hashed before being persisted; never stored or logged in plaintext. |
189
+ | `COLLAPSARR_AUTH_METHOD` | *(unset — `forms`)* | Optional, only applied when the seed credential above is actually seeded: `forms` or `basic`. |
190
+ | `COLLAPSARR_AUTH_REQUIRED` | *(unset — `local_bypass`)* | Optional, only applied when the seed credential above is actually seeded: `enabled` or `local_bypass`. |
191
+
192
+ ## Running on startup
193
+
194
+ **Docker:** the `restart: unless-stopped` line in the [Quick start](#quick-start)
195
+ compose file already handles this — Docker restarts the container whenever it
196
+ stops unexpectedly or the Docker daemon itself restarts. On Linux this
197
+ happens automatically on boot, since `dockerd` runs as a systemd service
198
+ enabled by default (`systemctl is-enabled docker` to confirm). On
199
+ Docker Desktop (macOS/Windows), enable **Settings → General → Start Docker
200
+ Desktop when you log in** so the daemon — and in turn the container — comes
201
+ up after a reboot.
202
+
203
+ **Bare-metal / PyPI install:** run Collapsarr as a systemd service so it
204
+ starts on boot and restarts if it crashes. Create
205
+ `/etc/systemd/system/collapsarr.service`:
206
+
207
+ ```ini
208
+ [Unit]
209
+ Description=Collapsarr
210
+ After=network.target
211
+
212
+ [Service]
213
+ Type=simple
214
+ User=collapsarr
215
+ Group=collapsarr
216
+ WorkingDirectory=/opt/collapsarr
217
+ EnvironmentFile=/opt/collapsarr/.env
218
+ ExecStart=/opt/collapsarr/.venv/bin/collapsarr
219
+ Restart=on-failure
220
+ RestartSec=5
221
+
222
+ [Install]
223
+ WantedBy=multi-user.target
224
+ ```
225
+
226
+ Adjust `User`/`Group`, `WorkingDirectory`, and the `.venv` path to match
227
+ where you installed it; `EnvironmentFile` should point at an `.env`
228
+ containing the `COLLAPSARR_*` variables from [Configuration](#configuration)
229
+ (see [`.env.example`](.env.example)). Then enable and start it:
230
+
231
+ ```bash
232
+ sudo systemctl daemon-reload
233
+ sudo systemctl enable --now collapsarr
234
+ ```
235
+
236
+ Check status/logs with `systemctl status collapsarr` and `journalctl -u collapsarr -f`.
237
+
238
+ ## Docs
239
+
240
+ Fuller docs live on the [GitHub Wiki](https://github.com/JovinJovinsson/Collapsarr/wiki).
241
+
242
+ ## License
243
+
244
+ [GPLv3](LICENSE).
@@ -0,0 +1,20 @@
1
+ """Authentication surface: first-run setup, Forms login, session enforcement.
2
+
3
+ The full auth model (COL-50): a single operator credential (COL-49) gates the
4
+ whole UI behind a signed-cookie session, while ``/api`` still accepts the
5
+ Sonarr/Radarr-style API key for webhooks and tooling. See the submodules:
6
+
7
+ * :mod:`~collapsarr.auth.session` -- the signed-cookie session middleware and
8
+ its login/logout helpers.
9
+ * :mod:`~collapsarr.auth.enforcement` -- the request-gating middleware that
10
+ supersedes the old opt-in ``api_key_middleware``.
11
+ * :mod:`~collapsarr.auth.routes` -- the ``/api/auth`` endpoints.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from .enforcement import enforce_auth_middleware
17
+ from .routes import router as auth_router
18
+ from .session import SessionMiddleware
19
+
20
+ __all__ = ["SessionMiddleware", "auth_router", "enforce_auth_middleware"]