diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml new file mode 100644 index 0000000..6ff930a --- /dev/null +++ b/.github/workflows/publish-image.yml @@ -0,0 +1,57 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# GitHub recommends pinning actions to a commit SHA. +# To get a newer version, you will need to update the SHA. +# You can also reference a tag or branch, but the action may change without warning. + +name: Publish Docker image + +on: + workflow_dispatch: + # release: + # types: [published] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. + permissions: + contents: read + packages: write + id-token: write + # + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see [Usage](https://github.com/docker/build-push-action#usage) in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + id: push + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 43af6b2..a0986b9 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -4,7 +4,7 @@ jobs: build: strategy: matrix: - operating-system: [ubuntu-latest, macos-11] + operating-system: [ubuntu-latest, macos-15] php-versions: ['7.3', '7.4', '8.0', '8.1', '8.2'] runs-on: ${{ matrix.operating-system }} steps: diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..04a23bf --- /dev/null +++ b/.htaccess @@ -0,0 +1,8 @@ +RewriteEngine on +RewriteRule rss dir2cast.php + +RewriteCond %{THE_REQUEST} "^[^ ]* .*?\.php[? ].*$" +RewriteRule .* - [L,R=404] + +RewriteCond %{THE_REQUEST} "^[^ ]* .*?\.ini[? ].*$" +RewriteRule .* - [L,R=404] \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..16b42f5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +FROM php:8.1-apache + + +# prep folders and perms +RUN mkdir -p /var/www/html/episodes + +# initialize env vars with defaults +# these can be changed with -e at docker run +ENV MP3_DIR=/var/www/html/episodes \ + # MP3_URL= \ + RECURSIVE_DIRECTORY_ITERATOR=true \ + # COPYRIGHT= \ + # WEBMASTER= \ + # ITUNES_OWNER_NAME= \ + # ITUNES_OWNER_EMAIL= \ + # LINK= \ + # TITLE= \ + # ITUNES_AUTHOR= \ + # ITUNES_CATEGORIES= \ + ITUNES_EXPLICIT=false \ + # DESCRIPTION= \ + # ITUNES_SUBTITLE= \ + # ITUNES_SUMMARY= \ + # ITUNES_SUBTITLE_SUFFIX= \ + # ITUNES_TYPE= \ + LANGUAGE="en-us" \ + ITEM_COUNT=10000 \ + AUTO_SAVE_COVER_ART=false \ + MIN_FILE_AGE=30 \ + MIN_CACHE_TIME=5 \ + TTL=60 + # FORCE_PASSWORD= \ + # ATOM_TYPE= \ + # DESCRIPTION_SOURCE= \ + # DESCRIPTION_HMTL= + +# copy source files to docker +COPY ./.htaccess/ /var/www/html/ +COPY ./dir2cast.php /var/www/html/ +COPY ./dir2cast.ini.sample /var/www/html/dir2cast.ini +COPY ./getID3/ /var/www/html/getID3/ +# COPY entrypoint.sh /usr/local/bin/ +RUN a2enmod rewrite +# ENTRYPOINT ["/bin/sh", "/usr/local/bin/entrypoint.sh"] +EXPOSE 80 +CMD ["apache2-foreground"] \ No newline at end of file diff --git a/README.md b/README.md index 2b8de3d..e087005 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ Features: * You can set a per-file iTunes Summary by creating a text file with the same name as the media file (e.g. for file.mp3, create file.txt). +* You can deploy a container using the ctkcoding/dir2cast:main Docker image + QUICK HOW TO GUIDES ================================================================================ @@ -98,6 +100,43 @@ podcast that it generates uses the tags from your files. the "`temp`" folder that is created. +DOCKER SETUP +================================================================================ +Note: There are many ways to get dir2cast working under docker, and this guide +is a product of trial and error. There are settings in dir2cast and SWAG that are +not covered in this guide. + +Local setup +----------- +1. Review the existing docker-compose and dir2cast.ini as a baseline to start locally +2. A new container will use the defaults in the sample .ini file if no file is provided, but changes to the file made after initial container start will persist. +3. Episodes are expected at `/var/www/html/episodes` by default - so create a volume to map under `/var/www/html`, or directly bind to a location on your file system where you wish to store episodes. +4. Once you add media files to the location you chose after step 2, your podcast feed should now exist at `:/rss` + +Remote using SWAG +----------------- +1. Install SWAG and test that you can remotely access your docker server. Here's + a basic guide https://docs.linuxserver.io/general/swag +2. Create a `.subdomain.conf` file for your podcast server container as + specified in the current SWAG guide. Keep in mind the SWAG steps may have changed + since this was written +3. Set the SWAG network as the only network your dir2cast container is connected to and + restart both containers +4. Check that podcast episodes can be played/downloaded. If your feed exists and can be + subscribed to, but files aren't available, try setting `MP3_URL` with https:// (see comment in source ini file) + +Notes +----- +* If you have shared folders that are accessible from your computer, using a bind mount + (rather than a docker volume) is an easy way to enable a simple workflow for you to + drag and drop content into the podcast feed. +* If you see '.\_' prefixed junk files in your feed, that is an unfortunate side-effect + of using network shares from macOS, and not related to dir2cast. Use macOS' native dot_clean command to remove these files +* 502 errors are likely SWAG configuration problems. Check container name, port mapping, etc. +* all dir2cast.ini variables should be supported as docker env vars - if you find this is not correct, look at the RUN commands in Dockerfile for any new env vars needed + +Thank you to @ctkcoding for the contribution of this guide. + UNDERSTANDING HOW THE CACHING WORKS ================================================================================ @@ -218,7 +257,7 @@ To run the unit tests: COPYRIGHT & LICENSE ================================================================================ -Copyright (c) 2008-2021, Ben XO (me@ben-xo.com). +Copyright (c) 2008-2023, Ben XO (@benxo on most platforms). The software is released under the BSD License. diff --git a/dir2cast.ini b/dir2cast.ini index fdf67db..d007faf 100755 --- a/dir2cast.ini +++ b/dir2cast.ini @@ -33,7 +33,7 @@ ; The full filesystem path to the MP3 folder ; Set this if you *do not* want the folder to be passed in the URL. ; (This defaults to the same folder as the script) -;MP3_DIR = "/home/ben_xo/public_html/my_mp3_folder" +; MP3_DIR = "/var/www/html/episodes" ; The base to look for folders if they are specified in the URL ; Set this if you *do* want the folder passed in the URL, but the passed @@ -45,10 +45,12 @@ ; This defaults to the directory of the script. ; dir2cast can usually work this out for you, but under some circumstances ; it will fail. If your MP3 URLs are all wrong, try putting this in manually. +; If the xml/rss feed exists but podcasts won't play/download, you may need +; to set this with https i.e. "https://www.example.foo/my_mp3_folder/" ;MP3_URL = "http://www.example.foo/my_mp3_folder/" ; Uncomment this if you want to check in every sub-folder for new files as well. -;RECURSIVE_DIRECTORY_ITERATOR = true +; RECURSIVE_DIRECTORY_ITERATOR = true @@ -103,7 +105,7 @@ ; ; If you don't set this, it will not appear in the feed at all, and Apple ; Podcasts may reject your feed! -;ITUNES_EXPLICIT = "no" +; ITUNES_EXPLICIT = "false" ; *** INFORMATION ABOUT YOUR PODCAST - the following can be set using text files *** @@ -186,7 +188,7 @@ ; the RSS standard. Apple Podcasts only supports values from the ISO 639 list ; (two-letter language codes, with some possible modifiers, such as "en-us"). ; See https://www.loc.gov/standards/iso639-2/php/code_list.php -;LANGUAGE = "en-us" +; LANGUAGE = "en-us" ; Where to cache RSS feeds (this must be writable by the web server) ; This defaults to a folder called 'temp' alongside the script @@ -194,7 +196,7 @@ ; Number of items to show in the feed ; This defaults to 10 -;ITEM_COUNT = 10 +; ITEM_COUNT = 10000 ; Format of the tag for each item. If this is set to 'false', ; then <title> will be set to the 'title' field in your ID3 tag. @@ -206,7 +208,7 @@ ; can become the episode image. This will never overwrite a file that ; you uploaded manually, but if dir2cast doesn't have write permissions ; in your podcast folder then it will fail. So, then perhaps turn it off. -;AUTO_SAVE_COVER_ART = true +; AUTO_SAVE_COVER_ART = true ; *** THESE SHOULD BE LEFT AS THEY ARE - unless you have a good reason. *** @@ -215,7 +217,7 @@ ; younger than this it might indicate that they are still being uploaded. ; ; Defaults to 30 seconds -;MIN_FILE_AGE = 30 +; MIN_FILE_AGE = 30 ; Number of seconds for which the cache files are guaranteed valid; that is ; to say, if you generate a new feed, and then hit refresh a lot, it will @@ -225,12 +227,12 @@ ; dir2cast.php. ; ; Defaults to 5 seconds -;MIN_CACHE_TIME = 5 +; MIN_CACHE_TIME = 5 ; Time-to-live (Expiry time) of the feed. This appears in the <ttl> tag, and ; is used by Podcast clients to determine if it is worth refetching the feed. ; Defaults to 1 hour (60 minutes) -;TTL = 60 +; TTL = 60 ; The password to use on the 'force=<password>' part of the URL in order to ; force the RSS feed to be regenerated (bypassing and replacing the cached diff --git a/dir2cast.ini.sample b/dir2cast.ini.sample new file mode 100755 index 0000000..de37dcd --- /dev/null +++ b/dir2cast.ini.sample @@ -0,0 +1,261 @@ +; Configuration for dir2cast by Ben XO. http://www.ben-xo.com/dir2cast + +; This is an 'ini' file. Lines beginning with ';' are comments. +; All of the settings are commented-out by default. To set them, remove +; the ';' at the beginning of the line. + +; dir2cast will look in 2 places for this file. 1st, it will look in +; the same folder as dir2cast.php. 2nd, it will look in the same folder +; as your MP3s. + +; If you only have 1 podcast, or your settings apply to every dir2cast +; podcast on your website, then this file should be placed in +; the same folder as dir2cast.php. + +; If you have several podcasts being served from one copy of dir2cast, +; then you can make copies of this file with different settings and put +; them in the folders where your MP3s are. Then they will override +; the settings from the site-wide dir2cast.ini. + +; N.B. Although most settings do not need double-quotes (" ") around them, +; it is safer to use them anyway. In particular, any setting with an +; ampersand (&) character will probably fail unless you use double-quotes. +; (e.g. a URL with parameters, or the iTunes Society & Culture category.) + + + +; ***** GLOBAL SETTINGS *** usually OK to leave unspecified ****************** + +; The following 3 settings are not mandatory because dir2cast should be +; able to figure them out for itself. Also, you can only specify them in +; the dir2cast.ini that is in the same folder as dir2cast.php. + +; The full filesystem path to the MP3 folder +; Set this if you *do not* want the folder to be passed in the URL. +; (This defaults to the same folder as the script) +MP3_DIR = "/var/www/html/episodes" + +; The base to look for folders if they are specified in the URL +; Set this if you *do* want the folder passed in the URL, but the passed +; folders are not subfolders of where you installed dir2cast.php. +; (This defaults to the same folder as the script) +;MP3_BASE = "/home/ben_xo/public_html/" + +; The URL of the MP3 folder +; This defaults to the directory of the script. +; dir2cast can usually work this out for you, but under some circumstances +; it will fail. If your MP3 URLs are all wrong, try putting this in manually. +; If the xml/rss feed exists but podcasts won't play/download, you may need +; to set this with https i.e. "https://www.example.foo/my_mp3_folder/" +;MP3_URL = "http://www.example.foo/my_mp3_folder/" + +; Uncomment this if you want to check in every sub-folder for new files as well. +RECURSIVE_DIRECTORY_ITERATOR = true + + + +; *** INFORMATION ABOUT YOUR PODCAST - you SHOULD set this how you like it *** + +; The copyright notice of the feed +; This defaults to this year (e.g. '2008') +; The string %YEAR% will be replaced with the current year. +;COPYRIGHT = "Ben XO (%YEAR%)" + +; Webmaster of the feed. This must be an email address, +; and it should be in the format 'my@email.address (My Name)' +; This defaults to ITUNES_OWNER_EMAIL (ITUNES_OWNER_NAME) +;WEBMASTER = "me-dir2cast@ben-xo.com (Ben XO)" + +; Name of the Owner of the podcast for iTunes +; This defaults to empty +;ITUNES_OWNER_NAME = "Ben XO" + +; Email of the Author of the podcast for iTunes +; This defaults to empty +;ITUNES_OWNER_EMAIL = "me-dir2cast@ben-xo.com" + +; URL of the feed's home page (this is NOT where the MP3s are! It is +; just the link to your "about" page). +; This defaults to the URL of the script or http://www.example.com/ +;LINK = "http://www.ben-xo.com/" + +; The title of the feed. +; This defaults to the name of the directory you're casting +;TITLE = "My First dir2cast Podcast" + +; The Author of the podcast for iTunes +; This defaults to whatever WEBMASTER is set to +;ITUNES_AUTHOR = "Ben XO" + +; Categories for iTunes +; +; You may add as many as you like from the category list at +; https://help.apple.com/itc/podcasts_connect/#/itc9267a2f12 +; +; Here is an example which means "Both the 'Music' category and +; the 'Gadgets' subcategory of 'Technology' +; +; Please note that the entire setting must have double quotes ("") +; like in the example, otherwise categories with '&' in the name won't work +;ITUNES_CATEGORIES = "Music, Technology > Gadgets" + +; Whether or not the feed contains explicit content. +; See https://github.com/simplepie/simplepie-ng/wiki/Spec:-iTunes-Podcast-RSS +; Valid values are "yes", "explicit", "true" or "no", "clean", "false" +; +; If you don't set this, it will not appear in the feed at all, and Apple +; Podcasts may reject your feed! +ITUNES_EXPLICIT = "false" + + +; *** INFORMATION ABOUT YOUR PODCAST - the following can be set using text files *** + +; Description of the feed +; +; This defaults to empty, or if the file 'description.txt' exists +; in the MP3 dir, or in the same dir as the script, that will be read +; and the contents used +; +; It's usually better to set this in 'description.txt' because you can +; write a whole lot more that way. +;DESCRIPTION = "My First Podcast" + +; Subtitle of the feed for iTunes +; +; This defaults to DESCRIPTION, or if the file 'itunes_subtitle.txt' exists +; in the MP3 dir, or in the same dir as the script, that will be read +; and the contents used +;ITUNES_SUBTITLE = "Check it out! It's brilliant." + +; Summary of the feed for iTunes +; +; This defaults to DESCRIPTION, or if the file 'itunes_summary.txt' exists +; in the MP3 dir, or in the same dir as the script, that will be read +; and the contents used +;ITUNES_SUMMARY = "i could go on for hours about how amazing this podcast is [...] etc" + +; Image for the podcast +; +; This defaults to no image, or if the file 'image.jpg' exists in the MP3 +; dir, or in the same dir as the script, then the URL for that will be used. +; +; The image must be no larger than 144 x 400. +;IMAGE = "http://www.somewhere.com/podcast.jpg" + +; Image for the podcast for iTunes +; +; This defaults to no image, or if the file 'itunes_image.jpg' exists +; in the MP3 dir, or in the same dir as the script, then the URL for that +; will be used. +; +; The image should be large enough to appear high quality in iTunes. +;ITUNES_IMAGE = "http://www.somewhere.com/podcast.jpg" + +; Extra text for the 'iTunes Subtitle', which appears next to each episode +; +; Defaults to empty. The text will appear in the iTunes subtitle for each +; item of the podcast. For example, if you put an entire tracklist into the MP3 +; comment field, you could set this to ". Click here for tracklist -->", and +; the the subtitle will read "<ArtistName>. Click here for tracklist -->" +; +;ITUNES_SUBTITLE_SUFFIX = "" + +; Whether to output the <itunes:episode> and <itunes:season> tags +; +; Set the <itunes:type> tag. If you set this to "serial", it will +; use the content of the ID3 "TRCK" and "TPOS" fields (also known as +; "track number", and "part of a set" (or sometimes "disc number"), +; respectively, as content of the <itunes:episode> and <itunes:season> tags. +; +; The TRCK and TPOS values should be non-zero positive integers (1, 2, 3, etc) +; +; NOTE: these are NOT used for ordering within the RSS feed. This is +; still done by file date so it's up to you to make the episode order +; and the file date order match by uploading them in season/episode order. +; +; The default value is "episodic", and no <itunes:episode> or <itunes:season> +; tags will be output in the feed. +; +; If you don't want <itunes:type> to appear in the feed at all, set this to "" +; +; Any value that is not "" or "serial" will be treated as "episodic" +;ITUNES_TYPE = "episodic" + +; *** CHECK THESE ARE OK. *** + +; Language of the feed +; This defaults to en-us (US English). This must be something recognised by +; the RSS standard. Apple Podcasts only supports values from the ISO 639 list +; (two-letter language codes, with some possible modifiers, such as "en-us"). +; See https://www.loc.gov/standards/iso639-2/php/code_list.php +LANGUAGE = "en-us" + +; Where to cache RSS feeds (this must be writable by the web server) +; This defaults to a folder called 'temp' alongside the script +;TMP_DIR = "/tmp" + +; Number of items to show in the feed +; This defaults to 10 +ITEM_COUNT = 10000 + +; Format of the <title> tag for each item. If this is set to 'false', +; then <title> will be set to the 'title' field in your ID3 tag. +; If this is set to 'true', then <title> will be set to +; 'album - artist - title' from your ID3 tag. +;LONG_TITLES = false + +; Automatically extract cover images from the files in the feed so they +; can become the episode image. This will never overwrite a file that +; you uploaded manually, but if dir2cast doesn't have write permissions +; in your podcast folder then it will fail. So, then perhaps turn it off. +AUTO_SAVE_COVER_ART = true + + +; *** THESE SHOULD BE LEFT AS THEY ARE - unless you have a good reason. *** + +; Files must be at least this old to be included in the feed. If they are +; younger than this it might indicate that they are still being uploaded. +; +; Defaults to 30 seconds +MIN_FILE_AGE = 30 + +; Number of seconds for which the cache files are guaranteed valid; that is +; to say, if you generate a new feed, and then hit refresh a lot, it will +; not regenerate the feed again for at least this length of time. +; +; You can only specify this in the dir2cast.ini that is in the same folder as +; dir2cast.php. +; +; Defaults to 5 seconds +MIN_CACHE_TIME = 5 + +; Time-to-live (Expiry time) of the feed. This appears in the <ttl> tag, and +; is used by Podcast clients to determine if it is worth refetching the feed. +; Defaults to 1 hour (60 minutes) +TTL = 60 + +; The password to use on the 'force=<password>' part of the URL in order to +; force the RSS feed to be regenerated (bypassing and replacing the cached +; copy). If this is empty then this feature is disabled. +;FORCE_PASSWORD = + +; If you want the script to write the RSS to a file instead of to stdout +; you can set OUTPUT_FILE. This is useful if your RSS takes a long time +; to generate and you would not ever want a podcast client to trigger a +; cache refresh. You probably would want to setup dir2cast.php so only +; You run it after adding new files to the directory. +;OUTPUT_FILE = + +; If you want to change the type attribute on the atom:link element +; to something other than 'application/rss+xml' you can set it here. +;ATOM_TYPE = + +; If you want the <description> tag for an item to come from the summary (auto- +; generated, or from a file with the same name with .txt extension) then +; set this parameter to 'summary'. Otherwise it will get its description from +; comment tag embedded in the file. +;DESCRIPTION_SOURCE = "comment" + +; If you want to have HTML in your <description> tag set this parameter. +; Otherwise the content of the description will be escaped with htmlspecialchars() +;DESCRIPTION_HTML = diff --git a/dir2cast.php b/dir2cast.php index 22be491..5f9fe61 100644 --- a/dir2cast.php +++ b/dir2cast.php @@ -1,7 +1,7 @@ <?php /****************************************************************************** - * Copyright (c) 2008-2022, Ben XO (me@ben-xo.com). + * Copyright (c) 2008-2023, Ben XO (@benxo on most platforms). * * All rights reserved. * diff --git a/docker-compose.yml b/docker-compose.yml index 229cdc5..5d2e6e9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,28 +1,15 @@ -version: "2.3" - -# after "docker-compose up" try the following URLs as examples: -# http://localhost:8080/ -# http://localhost:8080/test/fixtures/ - +volumes: + config: + services: - web: - image: nginx:alpine - ports: - - "8080:80" - volumes: - - .:/var/www/html - - ./docker-compose/nginx/default.conf:/etc/nginx/conf.d/default.conf - links: - - php-fpm - - php-fpm: - image: php:7-fpm-alpine - volumes: - - .:/var/www/html - - # You could also create a Dockerfile FROM php:7-fpm-alpine which includes these next two - - ./dir2cast.php:/dir2cast.php - - ./getID3:/getID3 - - # You should map a temp folder in otherwise you'll see errors about permission denied mkdir() - - /tmp:/temp + podcast: + image: ghcr.io/ctkcoding/dir2cast:main + container_name: podcast + restart: unless-stopped + ports: + - "2022:80" + volumes: + - episode_location:/var/www/html/episodes + - config:/var/www/html + # environment: + # - MP3_URL = https://domain.com/episodes/ diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..02151cf --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# remove file on startup +# todo - re enable this when env vars working +# file="/var/www/html/dir2cast.ini" + +# if [ -f "$file" ] ; then +# rm "$file" +# fi + +# echo MP3_DIR = $MP3_DIR \ >> /var/www/html/dir2cast.ini +# echo MP3_URL= $MP3_URL \ >> /var/www/html/dir2cast.ini +# echo RECURSIVE_DIRECTORY_ITERATOR = $RECURSIVE_DIRECTORY_ITERATOR \ >> /var/www/html/dir2cast.ini +# echo COPYRIGHT = $COPYRIGHT \ >> /var/www/html/dir2cast.ini +# echo WEBMASTER = $WEBMASTER \ >> /var/www/html/dir2cast.ini +# echo ITUNES_OWNER_NAME = $ITUNES_OWNER_NAME \ >> /var/www/html/dir2cast.ini +# echo ITUNES_OWNER_EMAIL = $ITUNES_OWNER_EMAIL \ >> /var/www/html/dir2cast.ini +# echo LINK = $LINK \ >> /var/www/html/dir2cast.ini +# echo TITLE = $TITLE \ >> /var/www/html/dir2cast.ini +# echo ITUNES_AUTHOR = $ITUNES_AUTHOR \ >> /var/www/html/dir2cast.ini +# echo ITUNES_CATEGORIES = $ITUNES_CATEGORIES \ >> /var/www/html/dir2cast.ini +# echo ITUNES_EXPLICIT = $ITUNES_EXPLICIT \ >> /var/www/html/dir2cast.ini +# echo DESCRIPTION = $DESCRIPTION \ >> /var/www/html/dir2cast.ini +# echo ITUNES_SUBTITLE = $ITUNES_SUBTITLE \ >> /var/www/html/dir2cast.ini +# echo ITUNES_SUMMARY = $ITUNES_SUMMARY \ >> /var/www/html/dir2cast.ini +# echo ITUNES_SUBTITLE_SUFFIX = $ITUNES_SUBTITLE_SUFFIX \ >> /var/www/html/dir2cast.ini +# echo ITUNES_TYPE = $ITUNES_TYPE \ >> /var/www/html/dir2cast.ini +# echo LANGUAGE = $LANGUAGE \ >> /var/www/html/dir2cast.ini +# echo ITEM_COUNT= $ITEM_COUNT \ >> /var/www/html/dir2cast.ini +# echo AUTO_SAVE_COVER_ART = $AUTO_SAVE_COVER_ART \ >> /var/www/html/dir2cast.ini +# echo MIN_FILE_AGE = $MIN_FILE_AGE \ >> /var/www/html/dir2cast.ini +# echo MIN_CACHE_TIME = $MIN_CACHE_TIME \ >> /var/www/html/dir2cast.ini +# echo TTL = $TTL \ >> /var/www/html/dir2cast.ini +# echo FORCE_PASSWORD = $FORCE_PASSWORD \ >> /var/www/html/dir2cast.ini +# echo ATOM_TYPE = $ATOM_TYPE \ >> /var/www/html/dir2cast.ini +# echo DESCRIPTION_SOURCE = $DESCRIPTION_SOURCE \ >> /var/www/html/dir2cast.ini +# echo DESCRIPTION_HMTL = $DESCRIPTION_HMTL \ >> /var/www/html/dir2cast.ini + +exec "$@"