mirror of
https://github.com/maxdorninger/MediaManager.git
synced 2026-04-26 02:35:57 +02:00
1 line
71 KiB
JSON
1 line
71 KiB
JSON
{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Welcome","text":"MediaManager <p> Modern management system for your media library Explore the docs \u00bb Report Bug \u00b7 Request Feature </p> <p>MediaManager is the modern, easy-to-use successor to the fragmented \"Arr\" stack. Manage, discover, and automate your TV and movie collection in a single, simple interface.</p> <p>Key features: - support for OAuth/OIDC - support for TVDB and TMDB - made to be deployed with Docker</p>"},{"location":"#quick-start","title":"Quick Start","text":"<pre><code>wget -O docker-compose.yaml https://github.com/maxdorninger/MediaManager/releases/latest/download/docker-compose.yaml\nmkdir config\nwget -O ./config/config.toml https://github.com/maxdorninger/MediaManager/releases/latest/download/config.example.toml\n# you probably need to edit the config.toml file in the ./config directory, for more help see the documentation\ndocker compose up -d\n</code></pre>"},{"location":"#view-the-docs-for-installation-instructions-and-more","title":"View the docs for installation instructions and more","text":""},{"location":"#support-mediamanager","title":"Support MediaManager","text":""},{"location":"#check-out-the-awesome-sponsors-of-mediamanager","title":"Check out the awesome sponsors of MediaManager \u2764\ufe0f","text":""},{"location":"#star-history","title":"Star History","text":""},{"location":"#screenshots","title":"Screenshots","text":""},{"location":"#developer-quick-start","title":"Developer Quick Start","text":"<p>For the developer guide see the Developer Guide.</p>"},{"location":"#license","title":"License","text":"<p>Distributed under the AGPL 3.0. See <code>LICENSE.txt</code> for more information.</p>"},{"location":"#acknowledgments","title":"Acknowledgments","text":"<p>Thanks to DigitalOcean for sponsoring the project!</p> <p></p> <ul> <li>Thanks to Pawel Czerwinski for the image on the login screen</li> </ul>"},{"location":"api-reference/","title":"API Reference","text":"<p>Info</p> <p>Media Manager's backend is built with FastAPI, which automatically generates interactive API documentation.</p> <ul> <li>Swagger UI (typically available at <code>http://localhost:8000/docs</code>)</li> <li>ReDoc (typically available at <code>http://localhost:8000/redoc</code>)</li> </ul>"},{"location":"importing-existing-media/","title":"Importing existing media","text":"<p>In order for MediaManager to be able to import existing media (e.g. downloaded by Sonarr or Radarr) two conditions have to be met:</p> <ul> <li>The folder's name must not start with a dot.</li> <li>The media must be in the root tv/movie library.</li> </ul> <p>Here is an example, using these rules:</p> <pre><code>/\n\u2514\u2500\u2500 data/\n \u251c\u2500\u2500 tv/\n \u2502 \u251c\u2500\u2500 Rick and Morty # WILL be imported\n \u2502 \u251c\u2500\u2500 Stranger Things (2016) {tvdb_12345} [x265] # WILL be imported\n \u2502 \u251c\u2500\u2500 Breaking Bad (2008) [tmdbid-1396] # WILL be imported\n \u2502 \u251c\u2500\u2500 .The Office (2013) # WILL NOT\n \u2502 \u2514\u2500\u2500 my-custom-library/\n \u2502 \u2514\u2500\u2500 The Simpsons # WILL NOT be imported\n \u2514\u2500\u2500 movie/\n \u2514\u2500\u2500 Oppenheimer (2023) # WILL be imported\n</code></pre> <p>If your folder structure is in the correct format, you can start importing. To do this, log in as an administrator and go to the TV/movie dashboard.</p> <p>Info</p> <p>After importing, MediaManager will automatically prefix the old root TV show/movie folders with a dot to mark them as \"imported\".</p> <p>So after importing, the directory would look like this (using the above directory structure):</p> <pre><code>/\n\u2514\u2500\u2500 data/\n \u251c\u2500\u2500 tv/\n \u2502 \u251c\u2500\u2500 .Rick and Morty # RENAMED\n \u2502 \u251c\u2500\u2500 Rick and Morty (2013) [tmdbid-60625] # IMPORTED\n \u2502 \u251c\u2500\u2500 .Stranger Things (2016) {tvdb_12345} # RENAMED\n \u2502 \u251c\u2500\u2500 Stranger Things (2016) [tmdbid-66732] # IMPORTED\n \u2502 \u251c\u2500\u2500 .The Office (2013) # IGNORED\n \u2502 \u251c\u2500\u2500 .Breaking Bad (2008) [tmdbid-1396] # RENAMED\n \u2502 \u251c\u2500\u2500 Breaking Bad (2008) [tmdbid-1396] # IMPORTED\n \u2502 \u2514\u2500\u2500 my-custom-library/\n \u2502 \u2514\u2500\u2500 The Simpsons # IGNORED\n \u2514\u2500\u2500 movie/\n \u251c\u2500\u2500 .Oppenheimer (2023) # RENAMED\n \u2514\u2500\u2500 Oppenheimer (2023) [tmdbid-872585] # IMPORTED\n</code></pre>"},{"location":"importing-existing-media/#more-criteria-for-importing","title":"More criteria for importing","text":"<p>These are the criteria specifically for the files themselves:</p> <ul> <li>Movie folders (e.g. <code>Oppenheimer (2023)</code>) must contain exactly one video file (e.g. .mp4, .mkv).</li> <li>The specific structure of season folders or episode folders or naming of them does not matter.</li> <li>Episode files (video and subtitle files) must contain the season and episode number in their name, e.g. <code>S01E01.mp4</code> or <code>S03E07 Rick and Morty.mkv</code>.</li> </ul>"},{"location":"importing-existing-media/#miscellaneous-information","title":"Miscellaneous information","text":"<ul> <li>Make MediaManager ignore directories by prefixing them with a dot.</li> <li>After importing, especially TV shows, manually check if all files are in the right place.</li> <li>MediaManager outputs in the logs if an episode/movie could not be imported.</li> </ul> <p>Last updated: 20 December 2025</p>"},{"location":"screenshots/","title":"Screenshots","text":"<p>Info</p> <p>MediaManager also supports darkmode!</p> <p> </p>"},{"location":"troubleshooting/","title":"Troubleshooting","text":"<p>Info</p> <p>Always check the container and browser logs for more specific error messages</p> Authentication Issues #### I can't log in with OAuth/OIDC? Verify provider configurationVerify your OAuth provider's configuration. See the OAuth documentationCheck callback URICheck if the callback URI you set in your OIDC providers settings is correct. See the callback URI documentationCheck frontend URLCheck the frontend url in your config file. It should match the URL you use to access MediaManager. I cannot log in? Confirm login vs signupMake sure you are logging in, not signing up.Try default credentialsTry logging in with the following credentials:Email: admin@mediamanager.local or admin@example.comPassword: admin Hard linking Issues * Make sure you are using only one volumes for TV, Movies and Downloads. [See the configuration in the example `docker-compose.yaml` file.](https://raw.githubusercontent.com/maxdorninger/MediaManager/refs/heads/master/docker-compose.yaml) The reason is that hard linking only works within the same filesystem. If your downloads are on a different volume than your media library, hard linking will not work. Torrent Search Issues #### I get no search results for torrents? Switch to advanced tabTry switching to the advanced tab when searching for torrents.Increase timeout for slow indexersIf you use \"slow\" indexers, try increasing the timeout threshold.Check logsIf you still don't get any search results, check the logs, they will provide more information on what is going wrong. Import and download Issues * If you configured a category with a special save path, [carefully read this page about MM with qBittorrent save paths.](advanced-features/qbittorrent-category.md) Docker Image Pull Issues * If you get a 401 or 403 error when pulling the image from GHCR, this is not a permission issue with the repository/image. It errors because your Docker client is misconfigured. * This is not a MediaManager issue per se, so please don't open an issue about this on the MediaManager GitHub repo. #### Possible Fixes: * [Unable to pull image from GitHub Container Registry (Stack Overflow)](https://stackoverflow.com/questions/74656167/unable-to-pull-image-from-github-container-registry-ghcr) * [Try pulling the image from Quay.io](installation/docker.md#docker-images) <p>Info</p> <p>If it still doesn't work, please open an Issue. It is possible that a bug is causing the issue.</p>"},{"location":"advanced-features/custom-port/","title":"Custom port","text":"<ul> <li><code>PORT</code>\\ Port that MediaManager listens on. Default is <code>8000</code>. This only works if you are using the Docker image. Configured as environment variable.</li> </ul>"},{"location":"advanced-features/disable-startup-ascii-art/","title":"Disable Startup Ascii Art","text":"<ul> <li><code>MEDIAMANAGER_NO_STARTUP_ART</code>: Set this environment variable (to any value) \\ to disable the colorized startup splash screen. Unset to reenable.</li> </ul>"},{"location":"advanced-features/follow-symlinks-in-frontend-files/","title":"Follow symlinks in frontend files","text":"<p>MediaManager can be configured to follow symlinks when serving frontend files. This is useful if you have a setup where your frontend files are stored in a different location, and you want to symlink them into the MediaManager frontend directory.</p> <ul> <li><code>FRONTEND_FOLLOW_SYMLINKS</code>\\ Set this environment variable to <code>true</code> to follow symlinks when serving frontend files. Default is <code>false</code>.</li> </ul> .env<pre><code>FRONTEND_FOLLOW_SYMLINKS=true\n</code></pre>"},{"location":"advanced-features/metadata-provider-configuration/","title":"Metadata Provider Configuration","text":""},{"location":"advanced-features/metadata-provider-configuration/#metadata-provider-configuration_1","title":"Metadata Provider Configuration","text":"<p>Metadata provider settings are configured in the <code>[metadata]</code> section of your <code>config.toml</code> file. These settings control how MediaManager retrieves information about movies and TV shows.</p>"},{"location":"advanced-features/metadata-provider-configuration/#tmdb-settings-metadatatmdb","title":"TMDB Settings (<code>[metadata.tmdb]</code>)","text":"<p>TMDB (The Movie Database) is the primary metadata provider for MediaManager. It provides detailed information about movies and TV shows.</p> <p>Info</p> <p>Other software like Jellyfin use TMDB as well, so there won't be any metadata discrepancies.</p> <ul> <li><code>tmdb_relay_url</code>\\ URL of the TMDB relay (MetadataRelay). Default is <code>https://metadata-relay.dorninger.co/tmdb</code>. Example: <code>https://your-own-relay.example.com/tmdb</code>.</li> <li><code>primary_languages</code>\\ If the original language of a show/movie is in this list, metadata is fetched in that language. Otherwise, <code>default_language</code> is used. Default is <code>[]</code>. Example: <code>[\"no\", \"de\", \"es\"]</code>. Format: ISO 639-1 (2 letters). Full list: https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes</li> <li><code>default_language</code>\\ TMDB language parameter used when searching and adding. Default is <code>en</code>. Format: ISO 639-1 (2 letters).</li> </ul> <p>Warning</p> <p><code>default_language</code> sets the TMDB <code>language</code> parameter when searching and adding TV shows and movies. If TMDB does not find a matching translation, metadata in the original language will be fetched with no option for a fallback language. It is therefore highly advised to only use \"broad\" languages. For most use cases, the default setting is safest.</p>"},{"location":"advanced-features/metadata-provider-configuration/#tvdb-settings-metadatatvdb","title":"TVDB Settings (<code>[metadata.tvdb]</code>)","text":"<p>Warning</p> <p>The TVDB might provide false metadata and doesn't support some features of MediaManager like showing overviews. Therefore, TMDB is the preferred metadata provider.</p> <ul> <li><code>tvdb_relay_url</code>\\ URL of the TVDB relay (MetadataRelay). Default is <code>https://metadata-relay.dorninger.co/tvdb</code>. Example: <code>https://your-own-relay.example.com/tvdb</code>.</li> </ul>"},{"location":"advanced-features/metadata-provider-configuration/#metadatarelay","title":"MetadataRelay","text":"<p>Info</p> <p>To use MediaManager you don't need to set up your own MetadataRelay, as the default relay hosted by the developer should be sufficient for most purposes.</p> <p>The MetadataRelay is a service that provides metadata for MediaManager. It acts as a proxy for TMDB and TVDB, allowing you to use your own API keys if needed, but the default relay means you don't need to create accounts for API keys yourself.</p> <p>You might want to use your own relay if you want to avoid rate limits, protect your privacy, or for other reasons. If you know Sonarr's Skyhook, this is similar to that.</p>"},{"location":"advanced-features/metadata-provider-configuration/#where-to-get-api-keys","title":"Where to get API keys","text":"<ul> <li>Get a TMDB API key from The Movie Database</li> <li>Get a TVDB API key from The TVDB</li> </ul> <p>Info</p> <p>If you want to use your own MetadataRelay, you can set the <code>tmdb_relay_url</code> and/or <code>tvdb_relay_url</code> to your own relay service.</p>"},{"location":"advanced-features/metadata-provider-configuration/#example-configuration","title":"Example Configuration","text":"<p>Here's a complete example of the metadata section in your <code>config.toml</code>:</p> config.toml<pre><code>[metadata]\n # TMDB configuration\n [metadata.tmdb]\n tmdb_relay_url = \"https://metadata-relay.dorninger.co/tmdb\"\n\n # TVDB configuration\n [metadata.tvdb]\n tvdb_relay_url = \"https://metadata-relay.dorninger.co/tvdb\"\n</code></pre> <p>Info</p> <p>In most cases, you can simply use the default values and don't need to specify these settings in your config file at all.</p>"},{"location":"advanced-features/qbittorrent-category/","title":"qBittorrent Category","text":"<p>qBittorrent supports saving Torrents to subdirectories based on the category of the Torrent. The default category name that MediaManager uses is <code>MediaManager</code>.</p> <p>Use the following variables to customize behavior:</p> <ul> <li><code>torrents.qbittorrent.category_name</code>\\ Category name MediaManager uses when adding torrents to qBittorrent. Default is <code>MediaManager</code>.</li> <li><code>torrents.qbittorrent.category_save_path</code>\\ Save path for the category in qBittorrent. By default, no subdirectory is used. Example: <code>/data/torrents/MediaManager</code>.</li> </ul> <p>Info</p> <p>qBittorrent saves torrents to the path specified by <code>torrents.qbittorrent.category_save_path</code>, so it must be a valid path that qBittorrent can write to.</p> <p>Warning</p> <p>For MediaManager to successfully import torrents, you must add the subdirectory to the <code>misc.torrent_directory</code> variable.</p>"},{"location":"advanced-features/url-prefix/","title":"URL Prefix","text":"<p>MediaManager, by default, expects to run at the base of a domain, e.g. <code>maxdorninger.github.io</code>.</p> <p>In order to run it on a prefixed path, like <code>maxdorninger.github.io/media</code>, the docker image must be built with a special build argument. That's because SvelteKit needs to know the base URL at build time.</p> <p>In short, clone the repository, then run:</p> Build Docker image<pre><code>docker build \\\n --build-arg BASE_PATH=/media \\\n --build-arg VERSION=my-custom-version \\\n -t MediaManager:my-custom-version \\\n -f Dockerfile .\n</code></pre> <p>You also need to set the <code>BASE_PATH</code> environment variable at runtime in <code>docker-compose.yaml</code>:</p> <ul> <li><code>BASE_PATH</code>\\ Base path prefix MediaManager is served under. Example: <code>/media</code>. This must match the <code>BASE_PATH</code> build arg.</li> </ul> docker-compose.yaml (excerpt)<pre><code>services:\n mediamanager:\n image: MediaManager:my-custom-version\n ports:\n - \"8000:8000\"\n environment:\n BASE_PATH: /media\n ...\n</code></pre> <p>Info</p> <p>Make sure to include the base path in the <code>frontend_url</code> field in the config file. See Backend.</p> <p>Finally, ensure that whatever reverse proxy you're using leaves the incoming path unchanged; that is, you should not strip the <code>/media</code> from <code>/media/web/</code>.</p>"},{"location":"configuration/","title":"Configuration","text":"<p>MediaManager uses a TOML configuration file (<code>config.toml</code>) for all backend settings. This centralized configuration approach makes it easier to manage, backup, and share your MediaManager setup.</p> <p>Frontend settings are configured through environment variables in your <code>docker-compose.yaml</code> file.</p>"},{"location":"configuration/#configuration-file-location","title":"Configuration File Location","text":"<p>Warning</p> <p>Note that MediaManager may need to be restarted for changes in the config file to take effect.</p> <p>Your <code>config.toml</code> file should be in the directory that's mounted to <code>/app/config/config.toml</code> inside the container:</p> <pre><code>volumes:\n - ./config:/app/config\n</code></pre> <p>You can change the configuration directory with the following environment variable:</p> <ul> <li><code>CONFIG_DIR</code>\\ Directory that contains <code>config.toml</code>. Default is <code>/app/config</code>. Example: <code>/etc/mediamanager/</code>.</li> </ul>"},{"location":"configuration/#configuration-sections","title":"Configuration Sections","text":"<p>The configuration is organized into the following sections:</p> <ul> <li><code>[misc]</code> - General settings</li> <li><code>[database]</code> - Database settings</li> <li><code>[auth]</code> - Authentication settings</li> <li><code>[notifications]</code> - Notification settings (Email, Gotify, Ntfy, Pushover)</li> <li><code>[torrents]</code> - Download client settings (qBittorrent, Transmission, SABnzbd)</li> <li><code>[indexers]</code> - Indexer settings (Prowlarr and Jackett )</li> <li><code>[metadata]</code> - TMDB and TVDB settings</li> </ul>"},{"location":"configuration/#configuring-secrets","title":"Configuring Secrets","text":"<p>For sensitive information like API keys, passwords, and secrets, you should use environment variables. You can actually set every configuration value through environment variables. For example, to set the <code>token_secret</code> value for authentication, with a .toml file you would use:</p> <pre><code>[auth]\ntoken_secret = \"your_super_secret_key_here\"\n</code></pre> <p>But you can also set it through an environment variable:</p> <pre><code>MEDIAMANAGER_AUTH__TOKEN_SECRET = \"your_super_secret_key_here\"\n</code></pre> <p>or another example with the OIDC client secret:</p> <pre><code>[auth]\n...\n[auth.openid_connect]\nclient_secret = \"your_client_secret_from_provider\"\n</code></pre> <p>env variable:</p> <pre><code>MEDIAMANAGER_AUTH__OPENID_CONNECT__CLIENT_SECRET = \"your_client_secret_from_provider\"\n</code></pre> <p>So for every config \"level\", you basically have to take the name of the value and prepend it with the section names in uppercase with 2 underscores as delimiters and <code>MEDIAMANAGER_</code> as the prefix.</p> <p>Warning</p> <p>Note that not every env variable starts with <code>MEDIAMANAGER_</code>; this prefix only applies to env variables which replace/overwrite values in the config file. Variables like the <code>CONFIG_DIR</code> env variable must not be prefixed.</p>"},{"location":"configuration/authentication/","title":"Authentication","text":"<p>All authentication settings are configured in the <code>[auth]</code> section of your <code>config.toml</code> file.</p>"},{"location":"configuration/authentication/#general-authentication-settings-auth","title":"General Authentication Settings (<code>[auth]</code>)","text":"<ul> <li><code>token_secret</code>\\ Strong secret key for signing JWTs (create with <code>openssl rand -hex 32</code>). This is required.</li> <li><code>session_lifetime</code>\\ Lifetime of user sessions in seconds. Default is <code>86400</code> (1 day).</li> <li><code>admin_emails</code>\\ A list of email addresses for administrator accounts. This is required.</li> <li><code>email_password_resets</code>\\ Enables password resets via email. Default is <code>false</code>.</li> </ul> <p>Info</p> <p>To use email password resets, you must also configure SMTP settings in the <code>[notifications.smtp_config]</code> section.</p> <p>Info</p> <p>When setting up MediaManager for the first time, you should add your email to <code>admin_emails</code> in the <code>[auth]</code> config section. MediaManager will then use this email instead of the default admin email. Your account will automatically be created as an admin account, allowing you to manage other users, media and settings.</p>"},{"location":"configuration/authentication/#openid-connect-settings-authopenid_connect","title":"OpenID Connect Settings (<code>[auth.openid_connect]</code>)","text":"<p>OpenID Connect allows you to integrate with external identity providers like Google, Microsoft Azure AD, Keycloak, or any other OIDC-compliant provider.</p> <ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable OpenID Connect authentication. Default is <code>false</code>.</li> <li><code>client_id</code>\\ Client ID provided by your OpenID Connect provider.</li> <li><code>client_secret</code>\\ Client secret provided by your OpenID Connect provider.</li> <li><code>configuration_endpoint</code>\\ OpenID Connect configuration endpoint URL. Do not include a trailing slash. Usually ends with <code>/.well-known/openid-configuration</code>.</li> <li><code>name</code>\\ Display name for the OpenID Connect provider shown on the login page.</li> </ul>"},{"location":"configuration/authentication/#configuration-for-your-openid-connect-provider","title":"Configuration for your OpenID Connect Provider","text":""},{"location":"configuration/authentication/#redirect-uri","title":"Redirect URI","text":"<p>The OpenID server will likely require a redirect URI. This URL will usually look something like this:</p> <pre><code>{MEDIAMANAGER_URL}/api/v1/auth/oauth/callback\n</code></pre> <p>Warning</p> <p>It is very important that you set the correct callback URI, otherwise it won't work!</p>"},{"location":"configuration/authentication/#authentik-example","title":"Authentik Example","text":"<p>Here is an example configuration for the OpenID Connect provider for Authentik.</p> <p></p>"},{"location":"configuration/authentication/#example-configuration","title":"Example Configuration","text":"<p>Here's a complete example of the authentication section in your <code>config.toml</code>:</p> config.toml<pre><code>[auth]\ntoken_secret = \"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6\"\nsession_lifetime = 604800 # 1 week\nadmin_emails = [\"admin@example.com\", \"manager@example.com\"]\nemail_password_resets = true\n\n[auth.openid_connect]\nenabled = true\nclient_id = \"mediamanager-client\"\nclient_secret = \"your-secret-key-here\"\nconfiguration_endpoint = \"https://auth.example.com/.well-known/openid-configuration\"\nname = \"Authentik\"\n</code></pre>"},{"location":"configuration/backend/","title":"Backend","text":""},{"location":"configuration/backend/#general-settings-misc","title":"General Settings (<code>[misc]</code>)","text":"<ul> <li> <p><code>frontend_url</code>\\ The URL the frontend will be accessed from. This is required. Do not include a trailing slash. Default is <code>http://localhost:8000</code>.</p> <p>Example: if you are accessing MediaManager at <code>http://example.com/media</code>, set this to <code>http://example.com/media</code>.</p> <p>If you are accessing MediaManager at the root of a domain, e.g. <code>https://mediamanager.example.com</code>, set this to <code>https://mediamanager.example.com</code>.</p> <p><code>frontend_url</code> does not affect where the server binds. It also does not configure a base path prefix. For prefixes, see URL Prefix. * <code>cors_urls</code>\\ A list of origins you are going to access the API from. Do not include trailing slashes. * <code>development</code>\\ Set to <code>true</code> to enable development mode. Default is <code>false</code>.</p> </li> </ul>"},{"location":"configuration/backend/#example-configuration","title":"Example Configuration","text":"<p>Here's a complete example of the general settings section in your <code>config.toml</code>:</p> config.toml<pre><code>[misc]\n\n# REQUIRED: Change this to match your actual frontend domain.\nfrontend_url = \"http://mediamanager.dev\"\n\ncors_urls = [\"http://localhost:8000\"]\n\n# Optional: Development mode (set to true for debugging)\ndevelopment = false\n</code></pre> <p>Info</p> <p>The <code>frontend_url</code> is the most important setting to configure correctly. Make sure it matches your actual deployment URLs.</p>"},{"location":"configuration/custom-libraries/","title":"Custom Libraries","text":"<p>MediaManager supports custom libraries, allowing you to add multiple folders for your movies and TV series. This feature is useful if you organize your media into different directories. For example, you might have separate folders for \"Action\" movies and \"Comedy\" movies, or \"Live Action\" TV shows and \"Animated\" TV shows.</p>"},{"location":"configuration/custom-libraries/#configuration","title":"Configuration","text":"<p>Custom libraries are configured in the <code>misc</code> section in the <code>config.toml</code> file. You can add as many libraries as you need.</p> <p>Info</p> <p>You are not limited to <code>/data/tv</code> or <code>/data/movies</code>, you can choose the entire path freely!</p>"},{"location":"configuration/custom-libraries/#movie-libraries","title":"Movie Libraries","text":"<p>To add custom movie libraries, add a <code>[[misc.movie_libraries]]</code> section for each library. Each library requires a <code>name</code> and a <code>path</code>.</p> <p>Example \u2014 configuring two movie libraries:</p> <pre><code>[misc]\n\n# ... other misc settings\n\n[[misc.movie_libraries]]\nname = \"Action\"\npath = \"/data/movies/action\"\n\n[[misc.movie_libraries]]\nname = \"Comedy\"\npath = \"/data/movies/comedy\"\n</code></pre> <p>In this example, MediaManager will scan both <code>/data/movies/action</code> and <code>/data/movies/comedy</code> for movies.</p>"},{"location":"configuration/custom-libraries/#tv-show-libraries","title":"TV Show Libraries","text":"<p>Similarly, to add custom TV show libraries, add a <code>[[misc.tv_libraries]]</code> section for each library. Each library requires a <code>name</code> and a <code>path</code>.</p> <p>Example \u2014 configuring two TV show libraries:</p> <pre><code>[misc]\n\n# ... other misc settings\n\n[[misc.tv_libraries]]\nname = \"Live Action\"\npath = \"/data/tv/live-action\"\n\n[[misc.tv_libraries]]\nname = \"Animation\"\npath = \"/data/tv/animation\"\n</code></pre>"},{"location":"configuration/database/","title":"Database","text":"<p>Database settings are configured in the <code>[database]</code> section of your <code>config.toml</code> file. MediaManager uses PostgreSQL as its database backend.</p>"},{"location":"configuration/database/#database-settings-database","title":"Database Settings (<code>[database]</code>)","text":"<ul> <li><code>host</code>\\ Hostname or IP of the PostgreSQL server. Default is <code>localhost</code>.</li> <li><code>port</code>\\ Port number of the PostgreSQL server. Default is <code>5432</code>.</li> <li><code>user</code>\\ Username for the PostgreSQL connection. Default is <code>MediaManager</code>.</li> <li><code>password</code>\\ Password for the PostgreSQL user. Default is <code>MediaManager</code>.</li> <li><code>dbname</code>\\ Name of the PostgreSQL database. Default is <code>MediaManager</code>.</li> </ul>"},{"location":"configuration/database/#example-configuration","title":"Example Configuration","text":"<p>Here's a complete example of the database section in your <code>config.toml</code>:</p> config.toml<pre><code>[database]\nhost = \"db\"\nport = 5432\nuser = \"MediaManager\"\npassword = \"your_secure_password\"\ndbname = \"MediaManager\"\n</code></pre> <p>Info</p> <p>In docker-compose deployments the container name is simultaneously its hostname, so you can use \"db\" or \"postgres\" as host.</p>"},{"location":"configuration/download-clients/","title":"Download Clients","text":"<p>Download client settings are configured in the <code>[torrents]</code> section of your <code>config.toml</code> file. MediaManager supports both qBittorrent and SABnzbd as download clients.</p>"},{"location":"configuration/download-clients/#qbittorrent-settings-torrentsqbittorrent","title":"qBittorrent Settings (<code>[torrents.qbittorrent]</code>)","text":"<p>qBittorrent is a popular BitTorrent client that MediaManager can integrate with for downloading torrents.</p> <ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable qBittorrent integration. Default is <code>false</code>.</li> <li><code>host</code>\\ Hostname or IP of the qBittorrent server. Include the protocol (http/https).</li> <li><code>port</code>\\ Port of the qBittorrent Web UI/API. Default is <code>8080</code>.</li> <li><code>username</code>\\ Username for qBittorrent Web UI authentication. Default is <code>admin</code>.</li> <li><code>password</code>\\ Password for qBittorrent Web UI authentication. Default is <code>admin</code>.</li> </ul>"},{"location":"configuration/download-clients/#transmission-settings-torrentstransmission","title":"Transmission Settings (<code>[torrents.transmission]</code>)","text":"<p>Info</p> <p>The downloads path in Transmission and MediaManager must be the same, i.e. the path <code>/data/torrents</code> must link to the same volume for both containers.</p> <p>Transmission is a BitTorrent client that MediaManager can integrate with for downloading torrents.</p> <ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable Transmission integration. Default is <code>false</code>.</li> <li><code>username</code>\\ Username for Transmission RPC authentication.</li> <li><code>password</code>\\ Password for Transmission RPC authentication.</li> <li><code>https_enabled</code>\\ Set to <code>true</code> if your Transmission RPC endpoint uses HTTPS. Default is <code>true</code>.</li> <li><code>host</code>\\ Hostname or IP of the Transmission server (without protocol).</li> <li><code>port</code>\\ Port of the Transmission RPC endpoint. Default is <code>9091</code>.</li> <li><code>path</code>\\ RPC request path target. Usually <code>/transmission/rpc</code>.</li> </ul>"},{"location":"configuration/download-clients/#sabnzbd-settings-torrentssabnzbd","title":"SABnzbd Settings (<code>[torrents.sabnzbd]</code>)","text":"<p>SABnzbd is a Usenet newsreader that MediaManager can integrate with for downloading NZB files.</p> <ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable SABnzbd integration. Default is <code>false</code>.</li> <li><code>host</code>\\ Hostname or IP of the SABnzbd server, it needs to include <code>http(s)://</code>.</li> <li><code>port</code>\\ Port of the SABnzbd API. Default is <code>8080</code>.</li> <li><code>api_key</code>\\ API key for SABnzbd. You can find this in SABnzbd's configuration under \"General\" \u2192 \"API Key\".</li> <li><code>base_path</code>\\ API base path for SABnzbd. It usually ends with <code>/api</code>, the default is <code>/api</code>.</li> </ul>"},{"location":"configuration/download-clients/#example-configuration","title":"Example Configuration","text":"<p>Here's a complete example of the download clients section in your <code>config.toml</code>:</p> config.toml<pre><code>[torrents]\n # qBittorrent configuration\n [torrents.qbittorrent]\n enabled = true\n host = \"http://qbittorrent\"\n port = 8080\n username = \"admin\"\n password = \"your_secure_password\"\n\n # Transmission configuration\n [torrents.transmission]\n enabled = false\n username = \"admin\"\n password = \"your_secure_password\"\n https_enabled = true\n host = \"transmission\"\n port = 9091\n path = \"/transmission/rpc\"\n\n # SABnzbd configuration\n [torrents.sabnzbd]\n enabled = false\n host = \"http://sabnzbd\"\n port = 8080\n api_key = \"your_sabnzbd_api_key\"\n</code></pre>"},{"location":"configuration/download-clients/#docker-compose-integration","title":"Docker Compose Integration","text":"<p>When using Docker Compose, make sure your download clients are accessible from the MediaManager backend:</p> docker-compose.yml<pre><code>services:\n # MediaManager backend\n backend:\n image: ghcr.io/maxdorninger/mediamanager/backend:latest\n # ... other configuration ...\n\n # qBittorrent service\n qbittorrent:\n image: lscr.io/linuxserver/qbittorrent:latest\n ports:\n - \"8080:8080\"\n environment:\n - WEBUI_PORT=8080\n volumes:\n - ./data/torrents:/downloads\n # ... other configuration ...\n\n # SABnzbd service\n sabnzbd:\n image: lscr.io/linuxserver/sabnzbd:latest\n ports:\n - \"8081:8080\"\n volumes:\n - ./data/usenet:/downloads\n # ... other configuration ...\n</code></pre> <p>Warning</p> <p>You should enable only one BitTorrent and only one Usenet Download Client at any time.</p> <p>Info</p> <p>Make sure the download directories in your download clients are accessible to MediaManager for proper file management and organization.</p>"},{"location":"configuration/indexers/","title":"Indexers","text":"<p>Indexer settings are configured in the <code>[indexers]</code> section of your <code>config.toml</code> file. MediaManager supports both Prowlarr and Jackett as indexer providers.</p>"},{"location":"configuration/indexers/#prowlarr-indexersprowlarr","title":"Prowlarr (<code>[indexers.prowlarr]</code>)","text":"<ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable Prowlarr. Default is <code>false</code>.</li> <li><code>url</code>\\ Base URL of your Prowlarr instance.</li> <li><code>api_key</code>\\ API key for Prowlarr. You can find this in Prowlarr's settings under General.</li> <li><code>timeout_seconds</code>\\ Timeout in seconds for requests to Prowlarr. Default is <code>60</code>.</li> </ul> <p>Warning</p> <p>Symptoms of timeouts are typically no search results (\"No torrents found!\") in conjunction with logs showing read timeouts.</p> Example timeout log <pre><code>DEBUG - media_manager.indexer.utils -\n follow_redirects_to_final_torrent_url():\n An error occurred during the request for <some-url>:\n HTTPConnectionPool(host='<some-host>', port=<some-port>):\n Read timed out. (read timeout=10)\n</code></pre>"},{"location":"configuration/indexers/#jackett-indexersjackett","title":"Jackett (<code>[indexers.jackett]</code>)","text":"<ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable Jackett. Default is <code>false</code>.</li> <li><code>url</code>\\ Base URL of your Jackett instance.</li> <li><code>api_key</code>\\ API key for Jackett. You can find this in Jackett's dashboard.</li> <li><code>indexers</code>\\ List of indexer names to use with Jackett.</li> <li><code>timeout_seconds</code>\\ Timeout in seconds for requests to Jackett. Refer to the Prowlarr section for details.</li> </ul>"},{"location":"configuration/indexers/#example-configuration","title":"Example Configuration","text":"config.toml<pre><code>[indexers]\n[indexers.prowlarr]\nenabled = true\nurl = \"http://prowlarr:9696\"\napi_key = \"your_prowlarr_api_key\"\ntimeout_seconds = 60\n\n[indexers.jackett]\nenabled = false\nurl = \"http://jackett:9117\"\napi_key = \"your_jackett_api_key\"\nindexers = [\"1337x\", \"rarbg\"]\ntimeout_seconds = 60\n</code></pre>"},{"location":"configuration/logging/","title":"Logging","text":"<p>MediaManager automatically logs events and errors to help with troubleshooting and monitoring. These logs are emitted to the console (stdout) by default, and to a json-formatted log file.</p>"},{"location":"configuration/logging/#configuring-logging","title":"Configuring Logging","text":"<p>The following are configured as environment variables.</p> <ul> <li><code>LOG_FILE</code>\\ Path to the JSON log file. Default is <code>/app/config/media_manager.log</code>. The directory must exist and be writable.</li> <li><code>MEDIAMANAGER_LOG_LEVEL</code>\\ Logging level. Default is <code>INFO</code>. Supported values: <code>DEBUG</code>, <code>INFO</code>, <code>WARNING</code>, <code>ERROR</code>.</li> </ul>"},{"location":"configuration/notifications/","title":"Notifications","text":"<p>These settings are configured in the <code>[notifications]</code> section of your <code>config.toml</code> file.</p>"},{"location":"configuration/notifications/#smtp-configuration-notificationssmtp_config","title":"SMTP Configuration (<code>[notifications.smtp_config]</code>)","text":"<p>For sending emails, MediaManager uses the SMTP protocol. You can use any SMTP server, like Gmail or SMTP2GO.</p> <ul> <li><code>smtp_host</code>\\ Hostname of the SMTP server.</li> <li><code>smtp_port</code>\\ Port of the SMTP server.</li> <li><code>smtp_user</code>\\ Username for the SMTP server.</li> <li><code>smtp_password</code>\\ Password (or app password) for the SMTP server.</li> <li><code>from_email</code>\\ From-address used when sending emails.</li> <li><code>use_tls</code>\\ Set to <code>true</code> to use TLS for the SMTP connection. Default is <code>true</code>.</li> </ul>"},{"location":"configuration/notifications/#email-notifications-notificationsemail_notifications","title":"Email Notifications (<code>[notifications.email_notifications]</code>)","text":"<p>Controls which emails receive notifications.</p> <ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable email notifications. Default is <code>false</code>.</li> <li><code>emails</code>\\ List of email addresses to send notifications to.</li> </ul>"},{"location":"configuration/notifications/#gotify-notifications-notificationsgotify","title":"Gotify Notifications (<code>[notifications.gotify]</code>)","text":"<ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable Gotify notifications. Default is <code>false</code>.</li> <li><code>api_key</code>\\ API key for Gotify.</li> <li><code>url</code>\\ Base URL of your Gotify instance. Do not include a trailing slash.</li> </ul>"},{"location":"configuration/notifications/#ntfy-notifications-notificationsntfy","title":"Ntfy Notifications (<code>[notifications.ntfy]</code>)","text":"<ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable Ntfy notifications. Default is <code>false</code>.</li> <li><code>url</code>\\ URL of your ntfy instance plus the topic.</li> </ul>"},{"location":"configuration/notifications/#pushover-notifications-notificationspushover","title":"Pushover Notifications (<code>[notifications.pushover]</code>)","text":"<ul> <li><code>enabled</code>\\ Set to <code>true</code> to enable Pushover notifications. Default is <code>false</code>.</li> <li><code>api_key</code>\\ API key for Pushover.</li> <li><code>user</code>\\ User key for Pushover.</li> </ul>"},{"location":"configuration/notifications/#example-configuration","title":"Example Configuration","text":"<p>Here's a complete example of the notifications section in your <code>config.toml</code>:</p> config.toml<pre><code>[notifications]\n # SMTP settings for email notifications and password resets\n [notifications.smtp_config]\n smtp_host = \"smtp.gmail.com\"\n smtp_port = 587\n smtp_user = \"your-email@gmail.com\"\n smtp_password = \"your-app-password\"\n from_email = \"mediamanager@example.com\"\n use_tls = true\n\n # Email notification settings\n [notifications.email_notifications]\n enabled = true\n emails = [\"admin@example.com\", \"notifications@example.com\"]\n\n # Gotify notification settings\n [notifications.gotify]\n enabled = true\n api_key = \"your_gotify_api_key\"\n url = \"https://gotify.example.com\"\n\n # Ntfy notification settings\n [notifications.ntfy]\n enabled = false\n url = \"https://ntfy.sh/your-private-topic\"\n\n # Pushover notification settings\n [notifications.pushover]\n enabled = false\n api_key = \"your_pushover_api_key\"\n user = \"your_pushover_user_key\"\n</code></pre> <p>Info</p> <p>You can enable multiple notification methods simultaneously. For example, you could have both email and Gotify notifications enabled at the same time.</p>"},{"location":"configuration/scoring-rulesets/","title":"Scoring Rulesets","text":"<p>Scoring rulesets in MediaManager allow you to flexibly control which releases are preferred or avoided when searching for media. Each ruleset is a collection of scoring rules that can be assigned to one or more libraries. When MediaManager evaluates releases, it applies the relevant ruleset(s) to adjust the score of each result, influencing which releases are selected for download.</p>"},{"location":"configuration/scoring-rulesets/#how-rulesets-work","title":"How Rulesets Work","text":"<ul> <li>Rulesets are defined in the configuration and contain a list of rule names and the libraries they apply to.</li> <li>Scoring rules can target keywords in release titles or specific indexer flags.</li> <li>When searching for a release, MediaManager checks which library the media belongs to and applies the corresponding ruleset.</li> </ul>"},{"location":"configuration/scoring-rulesets/#rules","title":"Rules","text":"<p>Rules define how MediaManager scores releases based on their titles or indexer flags. You can create rules that:</p> <ul> <li>Prefer releases with specific codecs (e.g., H.265 over H.264).</li> <li>Avoid releases with certain keywords (e.g., \"CAM\", \"TS\", \"Nuked\").</li> <li>Reject releases that do not meet certain criteria (e.g., non-freeleech releases).</li> <li>and more.</li> </ul> <p>Info</p> <p>The keywords and flags are compared case-insensitively.</p>"},{"location":"configuration/scoring-rulesets/#title-rules","title":"Title Rules","text":"<p>Title rules allow you to adjust the score of a release based on the presence (or absence) of specific keywords in the release title. This is useful for preferring or avoiding certain encodings, sources, or other characteristics that are typically included in release names.</p> <p>Each title rule consists of:</p> <ul> <li><code>name</code>\\ A unique identifier for the rule.</li> <li><code>keywords</code>\\ List of keywords to search for in the release title.</li> <li><code>score_modifier</code>\\ Amount to add or subtract from the score if a keyword matches.</li> <li><code>negate</code>\\ If <code>true</code>, the rule applies when none of the keywords are present.</li> </ul> <p>Examples for Title Rules</p> config.toml<pre><code>[[indexers.title_scoring_rules]]\nname = \"prefer_h265\"\nkeywords = [\"h265\", \"hevc\", \"x265\"]\nscore_modifier = 100\nnegate = false\n\n[[indexers.title_scoring_rules]]\nname = \"avoid_cam\"\nkeywords = [\"cam\", \"ts\"]\nscore_modifier = -10000\nnegate = false\n</code></pre> <ul> <li>The first rule increases the score for releases containing \"h265\", \"hevc\", or \"x265\".</li> <li>The second rule heavily penalizes releases containing \"cam\" or \"ts\".</li> </ul> <p>If <code>negate</code> is set to <code>true</code>, the <code>score_modifier</code> is applied only if none of the keywords are found in the title.</p>"},{"location":"configuration/scoring-rulesets/#indexer-flag-rules","title":"Indexer Flag Rules","text":"<p>Indexer flag rules adjust the score based on flags provided by the indexer (such as <code>freeleech</code>, <code>nuked</code>, etc). These flags are often used to indicate special properties or warnings about a release.</p> <p>Each indexer flag rule consists of:</p> <ul> <li><code>name</code>\\ A unique identifier for the rule.</li> <li><code>flags</code>\\ List of indexer flags to match.</li> <li><code>score_modifier</code>\\ Amount to add or subtract from the score if a flag matches.</li> <li><code>negate</code>\\ If <code>true</code>, the rule applies when none of the flags are present.</li> </ul> <p>Examples for Indexer Flag Rules</p> config.toml<pre><code>[[indexers.indexer_flag_scoring_rules]]\nname = \"reject_non_freeleech\"\nflags = [\"freeleech\", \"freeleech75\"]\nscore_modifier = -10000\nnegate = true\n\n[[indexers.indexer_flag_scoring_rules]]\nname = \"reject_nuked\"\nflags = [\"nuked\"]\nscore_modifier = -10000\nnegate = false\n</code></pre> <ul> <li>The first rule penalizes releases that do not have the \"freeleech\" or \"freeleech75\" flag.</li> <li>The second rule penalizes releases that are marked as \"nuked\".</li> </ul> <p>If <code>negate</code> is set to <code>true</code>, the <code>score_modifier</code> is applied only if none of the flags are present on the release.</p>"},{"location":"configuration/scoring-rulesets/#example","title":"Example","text":"config.toml<pre><code>[[indexers.scoring_rule_sets]]\nname = \"default\"\nlibraries = [\"ALL_TV\", \"ALL_MOVIES\"]\nrule_names = [\"prefer_h265\", \"avoid_cam\", \"reject_nuked\"]\n\n[[indexers.scoring_rule_sets]]\nname = \"strict_quality\"\nlibraries = [\"ALL_MOVIES\"]\nrule_names = [\"prefer_h265\", \"avoid_cam\", \"reject_non_freeleech\"]\n</code></pre>"},{"location":"configuration/scoring-rulesets/#libraries","title":"Libraries","text":"<p>The libraries that are mentioned in the preceding example are explained in greater detail in the Library config section.</p>"},{"location":"configuration/scoring-rulesets/#special-libraries","title":"Special Libraries","text":"<p>You can use special library names in your rulesets:</p> <ul> <li><code>ALL_TV</code>: Applies the ruleset to all TV libraries.</li> <li><code>ALL_MOVIES</code>: Applies the ruleset to all movie libraries.</li> <li><code>Default</code>: Applies the ruleset to all media that is not part of a custom library.</li> </ul> <p>This allows you to set global rules for all TV or movie content, or provide fallback rules for uncategorized media.</p> <p>Info</p> <p>You don't need to create lots of libraries with different directories, multiple libraries can share the same directory. You can set multiple (unlimited) libraries to the default directory <code>/data/movies</code> or <code>/data/tv</code> and use different rulesets with them.</p>"},{"location":"configuration/scoring-rulesets/#relation-to-sonarrradarr-profiles","title":"Relation to Sonarr/Radarr Profiles","text":"<p>MediaManager's scoring rules and rulesets system is an alternative to Sonarr's Quality, Custom, and Release Profiles. This system is designed to be more intuitive and flexible.</p> <ul> <li>Quality Profiles: Use scoring rules to prefer or avoid certain codecs, resolutions, or other quality indicators.</li> <li>Custom/Release Profiles: Use title or flag-based rules to match or exclude releases based on keywords or indexer flags.</li> </ul> <p>This approach provides a powerful and transparent way to fine-tune your automation.</p>"},{"location":"contributing-to-mediamanager/developer-guide/","title":"Developer Guide","text":""},{"location":"contributing-to-mediamanager/developer-guide/#source-code-directory-structure","title":"Source Code directory structure\ufeff","text":"<ul> <li><code>media_manager/</code>: Backend FastAPI application</li> <li><code>web/</code>: Frontend SvelteKit application</li> <li><code>docs/</code>: Documentation (MkDocs)</li> <li><code>metadata_relay/</code>: Metadata relay service, also FastAPI</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#special-dev-configuration","title":"Special Dev Configuration\ufeff","text":""},{"location":"contributing-to-mediamanager/developer-guide/#environment-variables","title":"Environment Variables\ufeff","text":"<p>MediaManager uses various environment variables for configuration. In the Docker development setup (<code>docker-compose.dev.yaml</code>), most of these are automatically configured for you.</p>"},{"location":"contributing-to-mediamanager/developer-guide/#backend-variables","title":"Backend Variables\ufeff","text":"<ul> <li><code>BASE_PATH</code>\\ Base path for the app (for subdirectory deployments).</li> <li><code>PUBLIC_VERSION</code>\\ Version string displayed in <code>/api/v1/health</code>.</li> <li><code>FRONTEND_FILES_DIR</code>\\ Directory for built frontend files (e.g. <code>/app/web/build</code> in Docker).</li> <li><code>MEDIAMANAGER_MISC__DEVELOPMENT</code>\\ When set to <code>TRUE</code>, enables FastAPI hot-reloading in Docker.</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#frontend-variables","title":"Frontend Variables\ufeff","text":"<ul> <li><code>PUBLIC_API_URL</code>\\ API URL for backend communication (auto-configured via Vite proxy in Docker).</li> <li><code>PUBLIC_VERSION</code>\\ Version string displayed in the frontend UI.</li> <li><code>BASE_PATH</code>\\ Base path for frontend routing (matches backend <code>BASE_PATH</code>).</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#docker-development-variables","title":"Docker Development Variables\ufeff","text":"<ul> <li><code>DISABLE_FRONTEND_MOUNT</code>\\ When <code>TRUE</code>, disables mounting built frontend files (allows separate frontend container).</li> </ul> <p>Info</p> <p>This is automatically set in <code>docker-compose.dev.yaml</code> to enable the separate frontend development container</p>"},{"location":"contributing-to-mediamanager/developer-guide/#configuration-files","title":"Configuration Files\ufeff","text":"<ul> <li>Backend: <code>res/config/config.toml</code> (created from <code>config.dev.toml</code>)</li> <li>Frontend: <code>web/.env</code> (created from <code>.env.example</code>)</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#contributing","title":"Contributing\ufeff","text":"<ul> <li>Consider opening an issue to discuss changes before starting work</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#setting-up-the-development-environment","title":"Setting up the Development Environment\ufeff","text":"<p>I use IntellijIdea with the Pycharm and Webstorm plugins to develop this, but this guide should also work with VSCode. Normally I'd recommend Intellij, but unfortunately only Intellij Ultimate has support for FastAPI and some other features.</p>"},{"location":"contributing-to-mediamanager/developer-guide/#recommended-vscode-plugins","title":"Recommended VSCode Plugins\ufeff","text":"<ul> <li>Python</li> <li>Svelte for VSCode</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#recommended-intellijpycharm-plugins","title":"Recommended Intellij/Pycharm Plugins\ufeff","text":"<ul> <li>Python</li> <li>Svelte</li> <li>Pydantic</li> <li>Ruff</li> <li>VirtualKit</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#recommended-development-workflow","title":"Recommended Development Workflow\ufeff","text":"<p>The recommended way to develop MediaManager is using the fully Dockerized setup with <code>docker-compose.dev.yaml</code>. This ensures you're working in the same environment as production and makes it easy for new contributors to get started without installing Python, Node.js, or other dependencies locally.</p> <p>The development environment includes:</p> <ul> <li>Backend (FastAPI) with automatic hot-reloading for Python code changes</li> <li>Frontend (SvelteKit/Vite) with Hot Module Replacement (HMR) for instant updates</li> <li>Database (PostgreSQL) pre-configured and ready to use</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#what-supports-hot-reloading-and-what-does-not","title":"What supports hot reloading and what does not\ufeff","text":"<ul> <li>Python code changes (.py files), Frontend code changes (.svelte, .ts, .css) and configuration changes (config.toml) reload automatically.</li> <li>Changing the backend dependencies (pyproject.toml) requires rebuilding: <code>docker compose -f docker-compose.dev.yaml build mediamanager</code></li> <li>Changing the frontend dependencies (package.json) requires restarting the frontend container: <code>docker compose -f docker-compose.dev.yaml restart frontend</code></li> <li>Database migrations: Automatically run on backend container startup</li> </ul> <p>This approach eliminates the need for container restarts during normal development and provides the best developer experience with instant feedback for code changes.</p>"},{"location":"contributing-to-mediamanager/developer-guide/#how-the-frontend-connects-to-the-backend","title":"How the Frontend Connects to the Backend\ufeff","text":"<p>In the Docker development setup, the frontend and backend communicate through Vite's proxy configuration:</p> <ul> <li>Frontend runs on: <code>http://localhost:5173</code> (exposed from Docker)</li> <li>Backend runs on: <code>http://mediamanager:8000</code> (Docker internal network)</li> <li>Vite proxy: Automatically forwards all <code>/api/*</code> requests from frontend to backend</li> </ul> <p>This means when your browser makes a request to <code>http://localhost:5173/api/v1/tv/shows</code>, Vite automatically proxies it to <code>http://mediamanager:8000/api/v1/tv/shows</code>. The <code>PUBLIC_API_URL</code> environment variable is set to use this proxy, so you don't need to configure anything manually.</p>"},{"location":"contributing-to-mediamanager/developer-guide/#setting-up-the-full-development-environment-with-docker-recommended","title":"Setting up the full development environment with Docker (Recommended)\ufeff","text":""},{"location":"contributing-to-mediamanager/developer-guide/#prepare-config-files","title":"Prepare config files","text":"<p>Create config directory (only needed on first run) and copy example config files:</p> <pre><code>mkdir -p res/config # Only needed on first run\ncp config.dev.toml res/config/config.toml\ncp web/.env.example web/.env\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#start-all-services","title":"Start all services","text":"<p>Recommended: Use make commands for easy development</p> <pre><code># Recommended: Use make commands for easy development\nmake up\n</code></pre> <p>Alternative: Use docker compose directly (if make is not available)</p> <pre><code>docker compose -f docker-compose.dev.yaml up\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#access-the-application","title":"Access the application","text":"<ul> <li>Frontend (with HMR): http://localhost:5173</li> <li>Backend API: http://localhost:8000</li> <li>Database: localhost:5432</li> </ul> <p>The default user email is <code>admin@example.com</code> and password is <code>admin</code>, these are printed out in the logs accessible with <code>make logs</code>.</p> <p>Now you can edit code and see changes instantly:</p> <ul> <li>Edit Python files \u2192 Backend auto-reloads</li> <li>Edit Svelte/TypeScript files \u2192 Frontend HMR updates in browser</li> <li>Edit config.toml \u2192 Changes apply immediately</li> </ul> <p>Info</p> <p>Run <code>make help</code> to see all available development commands including <code>make down</code>, <code>make logs</code>, <code>make app</code> (shell into backend), and more.</p>"},{"location":"contributing-to-mediamanager/developer-guide/#setting-up-the-backend-development-environment-local","title":"Setting up the backend development environment (Local)","text":""},{"location":"contributing-to-mediamanager/developer-guide/#clone-prerequisites","title":"Clone & prerequisites","text":"<ol> <li>Clone the repository</li> <li>cd into repo root</li> <li>Install <code>uv</code>: https://docs.astral.sh/uv/getting-started/installation/</li> <li>Verify installation:</li> </ol> <pre><code>uv --version\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#install-python-with-uv","title":"Install Python with uv","text":"<pre><code>uv python install 3.13\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#create-virtual-environment","title":"Create virtual environment","text":"<pre><code>uv venv --python 3.13\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#install-dependencies","title":"Install dependencies","text":"<pre><code>uv sync\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#run-database-migrations","title":"Run database migrations","text":"<pre><code>uv run alembic upgrade head\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#run-the-backend-development-mode","title":"Run the backend (development mode)","text":"<pre><code>uv run fastapi run media_manager/main.py --reload --port 8000\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#formatting-linting","title":"Formatting & linting","text":"<ul> <li>Format code:</li> </ul> <pre><code>ruff format .\n</code></pre> <ul> <li>Lint code:</li> </ul> <pre><code>ruff check .\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#setting-up-the-frontend-development-environment-local-optional","title":"Setting up the frontend development environment (Local, Optional)","text":""},{"location":"contributing-to-mediamanager/developer-guide/#clone-change-dir","title":"Clone & change dir","text":"<ol> <li>Clone the repository</li> <li>cd into repo root</li> <li>cd into <code>web</code> directory</li> </ol>"},{"location":"contributing-to-mediamanager/developer-guide/#install-nodejs-example-using-nvm-windows","title":"Install Node.js (example using nvm-windows)","text":"<p>I used nvm-windows:</p> <pre><code>nvm install 24.1.0\nnvm use 24.1.0\n</code></pre> <p>If using PowerShell you may need:</p> <pre><code>Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#create-env-for-frontend","title":"Create .env for frontend","text":"<pre><code>cp .env.example .env\n</code></pre> <p>Update <code>PUBLIC_API_URL</code> if your backend is not at <code>http://localhost:8000</code></p>"},{"location":"contributing-to-mediamanager/developer-guide/#install-dependencies-and-run-dev-server","title":"Install dependencies and run dev server","text":"<pre><code>npm install\nnpm run dev\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#format-lint","title":"Format & lint","text":"<ul> <li>Format:</li> </ul> <pre><code>npm run format\n</code></pre> <ul> <li>Lint:</li> </ul> <pre><code>npm run lint\n</code></pre> <p>Info</p> <p>If running frontend locally, make sure to add <code>http://localhost:5173</code> to the <code>cors_urls</code> in your backend config file.</p>"},{"location":"contributing-to-mediamanager/developer-guide/#troubleshooting","title":"Troubleshooting\ufeff","text":""},{"location":"contributing-to-mediamanager/developer-guide/#common-docker-development-issues","title":"Common Docker Development Issues\ufeff","text":"Port already in use errors * Check if ports 5173, 8000, or 5432 are already in use: * macOS/Linux: `lsof -i :5173` * Windows: `netstat -ano | findstr :5173` * Stop conflicting services or change ports in `docker-compose.dev.yaml` Container not showing code changes * Verify volume mounts are correct in `docker-compose.dev.yaml` * For backend: Ensure `./media_manager:/app/media_manager` is mounted * For frontend: Ensure `./web:/app` is mounted * On Windows: Check that file watching is enabled in Docker Desktop settings Frontend changes not updating * Check that the frontend container is running: `make ps` or `docker compose -f docker-compose.dev.yaml ps` * Verify Vite's file watching is working (should see HMR updates in browser console) * Try restarting the frontend container: <pre><code>docker compose -f docker-compose.dev.yaml restart frontend\n</code></pre> Backend changes not reloading * Verify `MEDIAMANAGER_MISC__DEVELOPMENT=TRUE` is set in `docker-compose.dev.yaml` * Check backend logs: <pre><code>make logs ARGS=\"--follow mediamanager\"\n# or\ndocker compose -f docker-compose.dev.yaml logs -f mediamanager\n</code></pre> * If dependencies changed, rebuild: <pre><code>docker compose -f docker-compose.dev.yaml build mediamanager\n</code></pre> Database migration issues * Migrations run automatically on container startup * To run manually: <pre><code>make app\nuv run alembic upgrade head\n</code></pre> * To create new migration: <pre><code>make app\nuv run alembic revision --autogenerate -m \"description\"\n</code></pre> Viewing logs * All services: `make logs` * Follow logs in real-time: `make logs ARGS=\"--follow\"` * Specific service: `make logs ARGS=\"mediamanager --follow\"` Interactive debugging (shell into containers) * Shell into backend: <pre><code>make app\n# or\ndocker compose -f docker-compose.dev.yaml exec -it mediamanager bash\n</code></pre> * Shell into frontend: <pre><code>make frontend\n# or\ndocker compose -f docker-compose.dev.yaml exec -it frontend sh\n</code></pre> * Once inside, you can run commands like `uv run alembic upgrade head`, `npm install`, etc. Volume permission issues (Linux) * Docker containers may create files as root, causing permission issues, which can make the login page fail to show up. Solution: <pre><code>sudo chown -R $USER:$USER res/\n</code></pre> * Alternatively: Run containers with your user ID or use Docker's `user:` directive (may fail in some setups). Complete reset If all else fails, you can completely reset your development environment: <pre><code>make down\ndocker compose -f docker-compose.dev.yaml down -v # Remove volumes\ndocker compose -f docker-compose.dev.yaml build --no-cache # Rebuild without cache\nmake up\n</code></pre>"},{"location":"contributing-to-mediamanager/developer-guide/#tech-stack","title":"Tech Stack\ufeff","text":""},{"location":"contributing-to-mediamanager/developer-guide/#backend","title":"Backend\ufeff","text":"<ul> <li>Python</li> <li>FastAPI</li> <li>SQLAlchemy</li> <li>Pydantic and Pydantic-Settings</li> <li>Alembic</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#frontend","title":"Frontend\ufeff","text":"<ul> <li>TypeScript</li> <li>SvelteKit</li> <li>Tailwind CSS</li> <li>shadcn-svelte</li> <li>openapi-ts</li> <li>openapi-fetch</li> </ul>"},{"location":"contributing-to-mediamanager/developer-guide/#cicd","title":"CI/CD\ufeff","text":"<ul> <li>GitHub Actions</li> </ul>"},{"location":"contributing-to-mediamanager/documentation/","title":"Documentation","text":"<p>MediaManager uses MkDocs with the Material for MkDocs theme for documentation.</p> <p>The files for the documentation are in the <code>/docs</code> directory.</p> <p>To preview the documentation locally, you need to have mkdocs or Docker installed.</p>"},{"location":"contributing-to-mediamanager/documentation/#how-to-preview-the-documentation-locally-with-docker","title":"How to preview the documentation locally with docker","text":"<ol> <li> <p>Run the mkdocs container in <code>docker-compose.dev.yaml</code></p> </li> <li> <p>Open <code>http://127.0.0.1:9000/</code> in your browser.</p> </li> </ol>"},{"location":"installation/","title":"Installation Guide","text":"<p>The recommended way to install and run Media Manager is using Docker and Docker Compose. Other installation methods are not officially supported, but listed here for convenience.</p> <p>Docker Compose (recommended) Nix Flakes [Community]</p>"},{"location":"installation/docker/","title":"Docker Compose","text":""},{"location":"installation/docker/#prerequisites","title":"Prerequisites","text":"<ul> <li>Ensure Docker and Docker Compose are installed on your system.</li> <li>If you plan to use OAuth 2.0 / OpenID Connect for authentication, you will need an account and client credentials from an OpenID provider (e.g., Authentik, Pocket ID).</li> </ul>"},{"location":"installation/docker/#setup","title":"Setup","text":"<p>Follow these steps to get MediaManager running with Docker Compose:</p>"},{"location":"installation/docker/#get-the-docker-compose-file","title":"Get the docker-compose file","text":"<p>Download the <code>docker-compose.yaml</code> from the MediaManager repo:</p> <pre><code>wget -O docker-compose.yaml https://github.com/maxdorninger/MediaManager/releases/latest/download/docker-compose.yaml\n</code></pre>"},{"location":"installation/docker/#prepare-configuration-directory-and-example-config","title":"Prepare configuration directory and example config","text":"<p>Create a config directory and download the example configuration:</p> <pre><code>mkdir config\nwget -O ./config/config.toml https://github.com/maxdorninger/MediaManager/releases/latest/download/config.example.toml\n</code></pre>"},{"location":"installation/docker/#edit-configuration","title":"Edit configuration","text":"<p>You probably need to edit the <code>config.toml</code> file in the <code>./config</code> directory to suit your environment and preferences. How to configure MediaManager.</p>"},{"location":"installation/docker/#start-mediamanager","title":"Start MediaManager","text":"<p>Bring up the stack:</p> <pre><code>docker compose up -d\n</code></pre> <ul> <li>Upon first run, MediaManager will create a default <code>config.toml</code> file in the <code>./config</code> directory (if not already present).</li> <li>Upon first run, MediaManager will also create a default admin user. The credentials of the default admin user will be printed in the logs of the container \u2014 it's recommended to change the password of this user after the first login.</li> <li>For more information on the available configuration options, see the Configuration section of the documentation.</li> </ul> <p>Info</p> <p>When setting up MediaManager for the first time, you should add your email to <code>admin_emails</code> in the <code>[auth]</code> config section. MediaManager will then use this email instead of the default admin email. Your account will automatically be created as an admin account, allowing you to manage other users, media, and settings.</p>"},{"location":"installation/docker/#docker-images","title":"Docker Images","text":"<p>MediaManager is available as a Docker image on both Red Hat Quay.io and GitHub Container Registry (GHCR):</p> <ul> <li>quay.io/maxdorninger/mediamanager</li> <li>ghcr.io/maxdorninger/mediamanager/mediamanager</li> </ul> <p>MetadataRelay images are also available on both registries:</p> <ul> <li>quay.io/maxdorninger/metadata_relay</li> <li>ghcr.io/maxdorninger/mediamanager/metadata_relay</li> </ul> <p>From v1.12.1 onwards, both MediaManager and MetadataRelay images are available on both Quay.io and GHCR. The reason for the switch to Quay.io as the primary image registry is due to GHCR's continued slow performance.</p> <p>Info</p> <p>You can use either the Quay.io or GHCR images interchangeably, as they are built from the same source and the tags are the same across both registries.</p>"},{"location":"installation/docker/#tags","title":"Tags","text":"<p>Both registries support the following tags:</p> <ul> <li>latest: Points to the latest stable release.</li> <li>master: Points to the latest commit on the master branch (may be unstable).</li> <li>X.Y.Z: Specific version tags (e.g., <code>1.12.0</code>).</li> <li>X.Y: Points to the latest release in the X.Y series (e.g., <code>1.12</code>).</li> <li>X: Points to the latest release in the X series (e.g., <code>1</code>).</li> <li>pr-\\: Points to the latest commit in the specified pull request (e.g., <code>pr-67</code>)."},{"location":"installation/flakes/","title":"Nix Flakes","text":"<p>Note</p> <p>This is a community contribution and not officially supported by the MediaManager team, but included here for convenience. </p> <p>Please report issues with this method at the corresponding GitHub repository.</p>"},{"location":"installation/flakes/#prerequisites","title":"Prerequisites","text":"<p>This guide assumes that your system is a flakes-based NixOS installation. Hosting MediaManager on a subpath (e.g. <code>yourdomain.com/mediamanager</code>) is currently not supported, though contributions to add support are welcome.</p>"},{"location":"installation/flakes/#importing-the-community-flake","title":"Importing the community flake","text":"<p>To use the community-provided flake and module, first import it in your own flake, for example:</p> <pre><code>{\n description = \"An example NixOS configuration\";\n\n inputs = {\n nixpkgs = { url = \"github:nixos/nixpkgs/nixos-unstable\"; };\n\n mediamanager-nix = {\n url = \"github:strangeglyph/mediamanager-nix\";\n inputs.nixpkgs.follows = \"nixpkgs\";\n };\n };\n\n outputs = inputs@{\n nixpkgs,\n mediamanager-nix,\n ...\n }: {\n nixosConfigurations.your-system = nixpkgs.lib.nixosSystem {\n modules = [\n mediamanager-nix.nixosModules.default\n ];\n };\n };\n}\n</code></pre>"},{"location":"installation/flakes/#configuration","title":"Configuration","text":"<p>The flake provides a simple module to set up a MediaManager systemd service. To enable it, set</p> <pre><code>{\n config = {\n services.media-manager = {\n enable = true;\n };\n };\n}\n</code></pre> <p>You will either want to set <code>services.media-manager.dataDir</code>, which will provide sensible defaults for the settings <code>misc.{image,movie,tv,torrent}_directory</code>, or provide specific paths yourself.</p> <p>The host and port that MediaManager listens on can be set using <code>services.media-manager.{host,port}</code>.</p> <p>To configure MediaManager, use <code>services.media-manager.settings</code>, which follows the same structure as the MediaManager <code>config.toml</code>. To provision secrets, set <code>services.media-manager.environmentFile</code> to a protected file, for example one provided by agenix or sops-nix. See Configuration for guidance on using environment variables.</p> <p>Warning</p> <p>Do not place secrets in the nix store, as it is world-readable.</p>"},{"location":"installation/flakes/#automatic-postgres-setup","title":"Automatic Postgres Setup","text":"<p>As a convenience feature, the module provides a simple Postgres setup that can be enabled with <code>services.media-manager.postgres.enable</code>. This sets up a database user named <code>services.media-manager.postgres.user</code> and a database with the same name. Provided the user of the systemd service wasn't changed, authentication should work automatically for unix socket connections (the default mediamanager-nix settings). </p> <p>For advanced setups, please refer to the NixOS manual.</p>"},{"location":"installation/flakes/#example-configuration","title":"Example Configuration","text":"<p>Here is a minimal complete flake for a MediaManager setup:</p> <pre><code>{\n description = \"An example NixOS configuration\";\n\n inputs = {\n nixpkgs = { url = \"github:nixos/nixpkgs/nixos-unstable\"; };\n mediamanager-nix = {\n url = \"github:strangeglyph/mediamanager-nix\";\n inputs.nixpkgs.follows = \"nixpkgs\";\n };\n };\n\n outputs = inputs@{\n nixpkgs,\n mediamanager-nix,\n ...\n }: {\n nixosConfigurations.your-system = nixpkgs.lib.nixosSystem {\n imports = [\n mediamanager-nix.nixosModules.default\n ];\n\n config = {\n services.media-manager = {\n enable = true;\n postgres.enable = true;\n port = 12345;\n dataDir = \"/tmp\";\n settings = {\n misc.frontend_url = \"http://[::1]:12345\";\n };\n };\n\n systemd.tmpfiles.settings.\"10-mediamanager\" = {\n \"/tmp/movies\".d = { user = config.services.media-manager.user; };\n \"/tmp/shows\".d = { user = config.services.media-manager.user; };\n \"/tmp/images\".d = { user = config.services.media-manager.user; };\n \"/tmp/torrents\".d = { user = config.services.media-manager.user; };\n };\n };\n };\n };\n}\n</code></pre>"}]} |