@@ 0,0 1,48 @@
+## A tuner script
+
+#### Installation
+
+Requires [pipenv](https://pipenv.pypa.io/en/latest/#install-pipenv-today) and [mpv](https://mpv.io/installation/)
+
+```
+git clone https://git.sr.ht/~akstuhl/tuner
+cd tuner
+pipenv install
+```
+
+#### Usage
+
+```
+pipenv run python tuner.py [--fallback http://example.com/audiostream.mp3] http://example.com/radio.ics
+```
+
+### How to use
+
+1. Find a radio show (or bandcamp album, mp3 file, etc. -- see listening queue section below) you'd like to tune in to when it's on.
+2. Make an event for the show in a web calendar (e.g. Google calendar). Find a streaming audio URL where you can listen to the show and paste that URL into the event's `location` field.
+3. Copy your calendar's .ics URL (for a Google calendar, go to the calendar's settings and look under "Integrate calendar" for an "address in iCal format" field).
+4. To start playing audio, paste your .ics URL as an argument to the script in your terminal: `pipenv python tuner.py <your-URL-here>`
+
+### What it does
+
+This is a listening helper that prioritizes tuning in to weekly radio shows via internet radio streams. If you add these shows as repeating events to a web calendar that publishes an iCalendar (.ics) endpoint, for instance a Google calendar, then this script can retrieve them and switch between the streams according to schedule. [Here's mine](https://calendar.google.com/calendar/u/0?cid=YWJkOTY0YThiOTQ1MDBkZjNjNWI1ZTIwYzdjNjRlNmU3YTM4NTY1ODZlNWNjNDFkODZmOTYzNWVhZmM0MTgyNUBncm91cC5jYWxlbmRhci5nb29nbGUuY29t), for example.
+
+#### Listening queue
+
+When nothing is found on the schedule at the current time, the script will rotate through a set of calendar entries it identifies as listening queue items rather than scheduled shows. For now, the way I designate queue items is very inelegant: in Google calendar, create an all-day event and set it to repeat daily, putting the URL in its `location` field as usual (if your mpv installation supports youtube-dl, a surprising number of URL sources including Bandcamp and Mixcloud pages should work) -- in the iCalendar format, Google will mark an all-day event as "transparent," and the script interprets that to mean queue item. Simply delete the recurring event to remove its queue item.
+
+#### Alternate uses
+
+This script tries to do as little as possible in passing URLs from the iCalendar file through to the mpv player. While I wrote it with just audio in mind, there are no guard rails against queuing video sources; or, for that matter, experimenting with calendar event settings in between or outside the envisioned "weekly show / listening queue" dichotomy. Just keep in mind it's untested for any of that.
+
+### Why
+
+This is a little tool I wrote for myself with the primary goal of catching weekly radio shows that friends produce or that I'm otherwise interested in. The secondary goal was to have a one-click way to start playing interesting audio when I have a moment to listen and don't want to spend time thinking about what to put on. Now I add things to my radio calendar when I hear about them and, when the timing works out, catch them by listening through the tuner script.
+
+### What else
+
+Additions might include:
+
+- Support iCalendar's `VTODO` record type for listening queue entries (Google and other web calendar services don't support this, but it would be internally much more elegant)
+- Set up or find a directory of station stream URLs so the full URL doesn't need to be entered into each event's `location` every time
+- A helper, probably as a separate tool, for adding shows and queue items via CalDAV or (more likely) via an .ics file that gets published within a static (Jekyll) site
@@ 13,7 13,7 @@ parser.add_argument('--fallback', dest='fallback_url', action='store', help='A f
args = parser.parse_args()
fallback_url = args.fallback_url
-ical_url = args.ical_url
+ical_url = args.ical_url # TODO store last used ical url in a local file for convenience?
# convenience function for working with icalendar library's vText format
def get_text(e, k):