├── .dockerignore ├── Dockerfile ├── README.md ├── docker-compose.yaml ├── files ├── etc │ ├── crontabs │ │ └── root │ ├── get_iplayer │ │ └── options │ ├── logrotate.d │ │ └── get_iplayer │ └── periodic │ │ ├── daily │ │ └── get_iplayer_update │ │ └── hourly │ │ └── get_iplayer_pvr └── start └── options.sample /.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.bak 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest as atomicparsleybuild 2 | 3 | RUN apk --update --no-cache add cmake g++ jq linux-headers make zlib-dev 4 | 5 | RUN wget -qO - `wget -qO - "https://api.github.com/repos/wez/atomicparsley/releases/latest" | jq -r .tarball_url` | tar -zx --strip-components=1 && cmake . && cmake --build . --config Release --target install/strip 6 | 7 | 8 | FROM alpine:latest 9 | MAINTAINER Jonathan Harris 10 | ENV GETIPLAYER_OUTPUT=/output GETIPLAYER_PROFILE=/output/.get_iplayer PUID=1000 PGID=100 PORT=1935 BASEURL= 11 | EXPOSE $PORT 12 | VOLUME "$GETIPLAYER_OUTPUT" 13 | 14 | RUN apk --update --no-cache add ffmpeg perl-cgi perl-mojolicious perl-lwp-protocol-https perl-xml-libxml jq logrotate su-exec tini curl 15 | 16 | COPY --from=atomicparsleybuild /usr/local/bin/AtomicParsley /usr/local/bin/AtomicParsley 17 | 18 | RUN wget -qO - "https://api.github.com/repos/get-iplayer/get_iplayer/releases/latest" > /tmp/latest.json && \ 19 | echo get_iplayer release `jq -r .name /tmp/latest.json` && \ 20 | wget -qO - "`jq -r .tarball_url /tmp/latest.json`" | tar -zxf - && \ 21 | cd get-iplayer* && \ 22 | install -m 755 -t /usr/local/bin ./get_iplayer ./get_iplayer.cgi && \ 23 | cd / && \ 24 | rm -rf get-iplayer* && \ 25 | rm /tmp/latest.json 26 | 27 | COPY files/ / 28 | 29 | ENTRYPOINT ["/sbin/tini", "--"] 30 | CMD /start 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # get_iplayer PVR Docker image 2 | 3 | This is a smallish (100MB) Docker image that hosts the [get_iplayer](https://github.com/get-iplayer/get_iplayer/wiki) PVR. It automatically keeps itself up-to-date with the latest version of get_iplayer. 4 | 5 | The PVR recording feature runs hourly. The get_iplayer version is updated daily. 6 | 7 | ## Image configuration 8 | 9 | The PVR can be accessed by default on port `1935/tcp`. Set the environment variable `PORT` to override. 10 | 11 | Downloaded TV & radio files will be placed in the `/output` bind mount. 12 | 13 | Environment variables `PUID` and `PGID` can be set to dictate the owner and group of downloaded files (useful if you're putting these files in a shared folder). 14 | 15 | If you're running behind a reverse proxy set the environment variable `BASEURL` to the full proxy URL. 16 | 17 | ## Example invocation 18 | 19 | This makes the PVR available on port 1935, and makes downloaded files owned by the current user: 20 | 21 | ```sh 22 | docker run -d -e PUID=`id -u` -e PGID=`id -g` -p 1935:1935 -v /destination/on/host:/output marginal/get_iplayer:latest 23 | ``` 24 | Replace `/destination/on/host` with the path of a folder on the host machine where you would like the downloaded files to be placed. 25 | 26 | ## get_iplayer configuration 27 | 28 | get_iplayer's configuration and cache will be written to the `.get_iplayer` subfolder under the `/output` bind mount. You can set get_iplayer [options](https://github.com/get-iplayer/get_iplayer/wiki/options) in the file `/destination/on/host/.get_iplayer/options`. 29 | 30 | Refer to the file [options.sample](https://raw.githubusercontent.com/Marginal/docker-get_iplayer/master/options.sample) for examples, including how to setup to send a Slack notification after a download. 31 | 32 | ## Migrating an existing get_iplayer installation 33 | 34 | 1. Copy your existing `.get_iplayer` folder over to `/destination/on/host/.get_iplayer` . 35 | 36 | 2. If you have a `.get_iplayer/options` file, open it in a text editor and remove any `output`, `outputradio` and/or `outputtv` statements. 37 | 38 | 3. Open the file `.get_iplayer/download_history` in a text editor, search for "/old/destination/folder/" and globally replace with "`/output/`". 39 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | services: 3 | get_iplayer: 4 | image: marginal/get_iplayer:latest 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | args: 9 | PUID: 1000 # id -u 10 | PGID: 100 # id -g 11 | volumes: 12 | - /destination/on/host:/output 13 | ports: 14 | - "1935:1935" 15 | -------------------------------------------------------------------------------- /files/etc/crontabs/root: -------------------------------------------------------------------------------- 1 | # min hour day month weekday command 2 | 0 * * * * run-parts /etc/periodic/hourly 3 | 0 2 * * * run-parts /etc/periodic/daily 4 | 5 | -------------------------------------------------------------------------------- /files/etc/get_iplayer/options: -------------------------------------------------------------------------------- 1 | expiry 3000 2 | nopurge 1 3 | -------------------------------------------------------------------------------- /files/etc/logrotate.d/get_iplayer: -------------------------------------------------------------------------------- 1 | /var/log/get_iplayer*.log { 2 | notifempty 3 | weekly 4 | rotate 4 5 | compress 6 | delaycompress 7 | missingok 8 | } 9 | -------------------------------------------------------------------------------- /files/etc/periodic/daily/get_iplayer_update: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Check for get_iplayer update. 4 | # When updating will kill any active downloads launched from web front-end, but not those launched by hourly background PVR. 5 | # 6 | ( 7 | OLD=`get_iplayer -V 2>&1 | sed -nE 's/get_iplayer v(\d+)\.(\d+).*/\1\2/p'` # e.g. 321 8 | wget -qO - "https://api.github.com/repos/get-iplayer/get_iplayer/releases/latest" > /tmp/latest.json 9 | NEW=`jq -r .name /tmp/latest.json | sed -nE 's/v(\d+)\.(\d+).*/\1\2/p'` # e.g. 322 10 | [ ! -z "$OLD" ] && [ ! -z "$NEW" ] && [ $OLD -lt $NEW ] && echo "Updating get_iplayer $OLD -> $NEW" 1>&2 && wget -qO - "`jq -r .tarball_url /tmp/latest.json`" | tar -zxf - && cd get-iplayer* && install -m 755 -t /usr/local/bin ./get_iplayer ./get_iplayer.cgi && cd $OLDPWD && rm -rf get-iplayer* && PID=`ps | grep "/usr/local/bin/get_iplayer.cgi" | grep -v grep | cut -c1-6` && [ ! -z "$PID" ] && kill $PID 11 | ) 2>> /var/log/get_iplayer_update.log 12 | rm -f /tmp/latest.json 13 | -------------------------------------------------------------------------------- /files/etc/periodic/hourly/get_iplayer_pvr: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Run pvr 4 | # 5 | umask 2 6 | /bin/date -R >> /var/log/get_iplayer.log 7 | su-exec $PUID:$PGID /usr/local/bin/get_iplayer --pvr --nocopyright --quiet 2>&1 | grep -v 'INFO: PVR Run:\|^\.*$' >> /var/log/get_iplayer.log 8 | -------------------------------------------------------------------------------- /files/start: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Docker entrypoint 4 | # 5 | 6 | # Ensure up-to-date 7 | /etc/periodic/daily/get_iplayer_update 8 | 9 | # Start cron with output to syslog 10 | /sbin/syslogd 11 | /usr/sbin/crond 12 | 13 | # Restart if killed, e.g. due to update 14 | umask 2 15 | while true; do 16 | /usr/local/bin/get_iplayer --verbose 17 | if [ -z "$BASEURL" ]; then 18 | su-exec $PUID:$PGID /usr/local/bin/get_iplayer.cgi -p $PORT | grep -v "^DEBUG:"; 19 | else 20 | su-exec $PUID:$PGID /usr/local/bin/get_iplayer.cgi -p $PORT -b "$BASEURL" | grep -v "^DEBUG:"; 21 | fi 22 | done 23 | -------------------------------------------------------------------------------- /options.sample: -------------------------------------------------------------------------------- 1 | fileprefix <.senum><.episodeshort> 2 | refreshexcludegroups local,regional 3 | tagformattitle 4 | thumbsize 512 5 | whitespace 1 6 | # To send a notification after a TV download see example below using a Webhook to send a Notification in Slack 7 | tvcommand curl -X POST -H 'Content-type: application/json' --data "{\"text\": \"<nameshort> - <senum> - <episodeshort> has been downloaded.\"}" https://hooks.slack.com/services/YOUR/TOKENIZED/URL 8 | --------------------------------------------------------------------------------