# This is an example of TOML configuration file for Podsync. # Global cleanup policy applied to feeds that don't specify their own cleanup policy. # When set, this policy is used as a fallback for all feeds. # Comment out or remove this section if you don't want a global cleanup policy. [cleanup] keep_last = 50 # Keep last 50 episodes globally (unless overridden per feed) # Web server related configuration. [server] # HTTP server port. port = 8080 # Optional. If you want to hide Podsync behind reverse proxy like nginx, you can use hostname field. # Server will be accessible from http://localhost:8080, but episode links will point to https://my.test.host:4443/ID1/XYZ hostname = "https://my.test.host:4443" # Bind a specific IP addresses for server ,"*": bind all IP addresses which is default option, localhost or 127.0.0.1 bind a single IPv4 address bind_address = "172.20.10.2" # Specify path for reverse proxy and only [A-Za-z0-9] path = "test" # Optional. Enable Web UI. Feeds have to be include in OPML file to appear (see below) web_ui = true # Optional. If you want to use TLS you must set the TLS flag and path to the certificate file and private key file. tls = true certificate_path = "/var/www/cert.pem" key_file_path = "/var/www/priv.pem" # Optional. Enable debug endpoints (/debug/vars) for runtime metrics. Disabled by default for security. # Only enable this if you need to debug the application and the endpoint is not publicly accessible. debug_endpoints = false # Optional. Block search engine indexing by serving robots.txt and adding X-Robots-Tag header. no_index = false # Optional. Disable directory listings, return 404 for folder access (e.g. GET / or GET /feedID). no_listing = false # Configure where to store the episode data [storage] # Could be "local" (default) for the local file system, or "s3" for a S3-compatible storage provider (e.g. AWS S3) type = "local" [storage.local] data_dir = "/app/data" # Don't change if you run podsync via docker # To configure for a S3 provider, set key and secret in environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`, respectively; # then fillout the API endpoint, region, and bucket below. [storage.s3] endpoint_url = "https://s3.us-west-2.amazonaws.com" region = "us-west-2" bucket = "example-bucket-name" # If you use prefix, you may need to add a path to `server.hostname` setting # e.g. https://example-bucket-name.s3.us-west-2.amazonaws.com/example/prefix/ prefix = "example/prefix" # API keys to be used to access Youtube and Vimeo. # These can be either specified as string parameter or array of string (so those will be rotated). # Alternatively, you can set the following environment variables: # PODSYNC_YOUTUBE_API_KEY for YouTube # PODSYNC_VIMEO_API_KEY for Vimeo # PODSYNC_SOUNDCLOUD_API_KEY for Soundcloud # PODSYNC_TWITCH_API_KEY for Twitch (format: CLIENT_ID:CLIENT_SECRET) # Environment variables support multiple keys separated by spaces for API key rotation: # export PODSYNC_YOUTUBE_API_KEY="key1 key2 key3" [tokens] youtube = "YOUTUBE_API_TOKEN" # YouTube API Key. See https://developers.google.com/youtube/registering_an_application vimeo = [ # Multiple keys will be rotated. "VIMEO_API_KEY_1", # Vimeo developer keys. See https://developer.vimeo.com/api/guides/start#generate-access-token "VIMEO_API_KEY_2" ] # The list of data sources to be hosted by Podsync. # These are channels, users, playlists, etc. [feeds] # Each channel must have a unique identifier (in this example "ID1"). [feeds.ID1] # URL address of a channel, group, user, or playlist. url = "https://www.youtube.com/channel/CHANNEL_NAME_TO_HOST" # The number of episodes to query each update (keep in mind, that this might drain API token) page_size = 50 # How often query for updates, examples: "60m", "4h", "2h45m" update_period = "12h" quality = "high" # "high" or "low" format = "video" # "audio", "video" or "custom" # When format = "custom" # YouTubeDL format parameter and result file extension custom_format = { youtube_dl_format = "bestaudio[ext=m4a]", extension = "m4a" } playlist_sort = "asc" # or "desc", which will fetch playlist items from the end # Optional maximal height of video, example: 720, 1080, 1440, 2160, ... max_height = 720 # Optionally include this feed in OPML file (default value: false) opml = true # Optional cron expression format for more precise update schedule. # If set then overwrite 'update_period'. cron_schedule = "@every 12h" # Whether to cleanup old episodes for this specific feed. # Keep last 10 episodes (order desc by PubDate) # This overrides the global cleanup policy if one is set. clean = { keep_last = 10 } # Optional Golang regexp format. # If set, then only download matching episodes. # Duration filters are in seconds. # max_age filter is in days. # min_age filter is in days. filters = { title = "regex for title here", not_title = "regex for negative title match", description = "...", not_description = "...", min_duration = 0, max_duration = 86400, max_age = 365, min_age = 1 } # Optional extra arguments passed to youtube-dl when downloading videos from this feed. # This example would embed available English closed captions in the videos. # Note that setting '--audio-format' for audio format feeds, or '--format' or '--output' for any format may cause # unexpected behaviour. You should only use this if you know what you are doing, and have read up on youtube-dl's options! youtube_dl_args = ["--write-sub", "--embed-subs", "--sub-lang", "en,en-US,en-GB"] # Optional filename template for downloaded media and RSS enclosure links (without extension). # Supported tokens: {{id}}, {{title}}, {{pub_date}}, {{feed_id}} # Example output: 2026-02-08_My_Video_Title_dQw4w9WgXcQ.mp4 filename_template = "{{pub_date}}_{{title}}_{{id}}" # When set to true, podcasts indexers such as iTunes or Google Podcasts will not index this podcast private_feed = true # Optional post-episode download hooks # Execute commands after each episode is downloaded # Available environment variables: EPISODE_FILE, FEED_NAME, EPISODE_TITLE # Webhook notification example [[feeds.ID1.post_episode_download]] command = ["curl", "-X", "POST", "-d", "New episode: $EPISODE_TITLE", "https://webhook.example.com/notify"] timeout = 30 # Custom script example [[feeds.ID1.post_episode_download]] command = ["/path/to/your/process-episode.sh"] timeout = 120 # Optional episode download error hooks # Execute commands when an episode download fails (e.g. to notify on cookie expiry) # Available environment variables: FEED_NAME, EPISODE_TITLE, ERROR_MESSAGE # Webhook notification example [[feeds.ID1.on_episode_download_error]] command = ["curl", "-X", "POST", "-d", "Download failed for $FEED_NAME: $ERROR_MESSAGE", "https://webhook.example.com/notify"] timeout = 30 # Optional feed customizations [feeds.ID1.custom] title = "Level1News" description = "News sections of Level1Techs, in a podcast feed!" author = "Level1Tech" cover_art = "{IMAGE_URL}" cover_art_quality = "high" category = "TV" subcategories = ["Documentary", "Tech News"] explicit = true lang = "en" author = "Mrs. Smith (mrs@smith.org)" ownerName = "Mrs. Smith" ownerEmail = "mrs@smith.org" # optional: this will override the default link (usually the URL address) in the generated RSS feed with another link link = "https://example.org" # Podsync uses local database to store feeds and episodes metadata. # This section is optional and usually not needed to configure unless some very specific corner cases. # Refer to https://dgraph.io/docs/badger/get-started/#memory-usage for documentation. [database] badger = { truncate = true, file_io = true } # Youtube-dl specific configuration. [downloader] # Optional, auto update youtube-dl every 24 hours self_update = true # Download timeout in minutes. timeout = 15 # Optional log config. If not specified logs to the stdout [log] filename = "podsync.log" max_size = 50 # MB max_age = 30 # days max_backups = 7 compress = true debug = false