OliveTin for Channels: An Interface for Misc Channels DVR Scripts & Tricks

Looks like a docker never materialized for this. But it looks like it could be a useful addition to OliveTin?

Totally agree, I was looking at that as well. There's another similar project we could consider that would remove commercials too. In addition, there's one that would extract Closed Captions and create a subtitles (.srt) file. All require ffmpeg.

In past projects of mine, I've easily added ffmpeg to the container. The image that OliveTin is based on however, has some challenges with ffmpeg. So, I'm thinking about moving to an Alpine or Debian based image. It'll probably happen as I don't love the current base image.

1 Like

New OliveTin-for-Channels pushed, under the :latest tag, with support for generating an M3U based on a Channel Collection:

More detail here:

2 Likes

@maddox or @tmm1 Are there URLs where I can wget the Linux versions of ffmpeg that Channels uses for amd64 and arm64? I'm migrating OliveTin-for-Channels over to a Debian-based container so I can more easily add a few new "Actions" that require it. Seems like it'd be best to use the version you use, for AC4 support and the like.

See the setup.sh in the dvr install instructions

Just what I was hoping for -- thanks!

OliveTin-for-Channels can now remove commercials from your CDVR recordings! It's a test container at this point, under the :test.debian tag. It'd be great if a few of you could give it a try to see what tweaks might be needed to maximize its utility. More details here:

Very nice. Fileflows work too. And comchap was updated recently with a windows script

Just tossing out a script I use to take PlayOn recordings and build .edl files based on the fact that PlayOn files usually (at least in my experience across several of their streaming sources) have "Chapters" that indicate Advertisements.

This is a simple bash script that takes the filename (or can feed in wild card like *.mp4) and outputs an .edl file.

It does use ffmpeg to read the file to get the Chapters data.

I have been using this manually for 100+ recordings now, and have not seen any issues with it.

#!/bin/bash
#     Chapter #0:0: start 0.000000, end 1290.013333
#       first   _     _     start    _     end

while [ $# -gt 0 ]; do

ffmpeg -i "$1" 2> tmp.txt

output_filename="${1%.mp4}.edl"  # Remove .mp4 from the filename and add .edl

while read -r first _ _ start _ end; do
  if [[ $first = Chapter ]]; then
    read  # discard line with Metadata:
    read _ _ chapter

    if [ "$chapter" = "Advertisement" ]; then
      echo -e "${start%?}\t$end\t3" >> "$output_filename"
    fi

  fi
done <tmp.txt

rm tmp.txt

shift
done

Maybe a useful tool for Olivetin (if it can utilize ffmpeg like this?)

Yes, absolutely! Thanks for contributing this script -- I'll add it to OliveTin shortly. I think it's going to be great to have ffmpeg in the container. Not sure if full-on transcoding is in the cards, but there are lots of other uses for ffmpeg, as evidenced by your script and edlstrip.

@kcshield

I've added your script to OliveTin, with a few modifications to support multiple DVRs and make it WebUI friendly. Tested with several PlayOn sourced TV episodes, and it seems very good. Appears to need only a few seconds to run on the typical "hour-long" TV show.

Pull the most recent :test.debian tagged container to give it a spin. Current "timeout" is set to 30 seconds, which might need tweaking depending on how many episodes people want to be able to process in a single run:

EDIT: I realized I hadn't tried using a wildcard -- and that's not working, so it's strictly a one file at a time situation for the moment. Something I changed killed that functionality apparently. I'll take a fresh look at it soon -- to get that part going too.

EDIT2: I see now that you were supporting multiple filenames at a time as well. Nice! More tweaking on my end to get that going too. Breaking out the file path into a different argument should mostly sort things out.

@kcshield

A bit of a trip to crazy town -- but sorted now. That particular expansion of wildcard arguments is only partially supported in OliveTin, with the presence or absence of quotes being even more important than usual. Particularly when combined, as in this case, with filenames that can contain spaces.

Functioning build pushed under the :test.debian tag. Working well in my testing. Pretty convenient to do a *.mp4, or even an *S1E10* for a single episode shorthand.

Reworked playonedl.sh:

#!/bin/bash
#     Chapter #0:0: start 0.000000, end 1290.013333
#       first   _     _     start    _     end
set -x

dvr=$1
channelsHost=$(echo $dvr | awk -F: '{print $1}')
channelsPort=$(echo $dvr | awk -F: '{print $2}')
dvrDir="$channelsHost-$channelsPort"
playonPath="$2"
playonSingleMP4="$3"
playonMultipleMP4s=$3

wildcardArgumentHandler() {
if [[ "$playonSingleMP4" == *'?'* || "$playonSingleMP4" == *'*'* ]]; then
  playonMP4s=()
  for playonMP4 in $playonMultipleMP4s; do
    playonMP4s+=("$playonMP4")
  done
else
  playonMP4s=("$playonSingleMP4")
fi
}

commercialChapters2EDL() {
for playonMP4 in "${playonMP4s[@]}"; do
  ffmpeg -i "$playonMP4" 2> /tmp/playonedl.tmp
  playonEDL="${playonMP4%.mp4}.edl"  # Remove .mp4 from the filename and add .edl
  [ -f "$playonEDL" ] && rm "$playonEDL"

    while read -r first _ _ start _ end; do
      if [[ $first = Chapter ]]; then
        read  # discard line with Metadata:
        read _ _ chapter
        if [ "$chapter" = "Advertisement" ]; then
          echo -e "${start%?}\t$end\t3" >> "$playonEDL"
        fi
      fi
    done </tmp/playonedl.tmp

  rm /tmp/playonedl.tmp
  echo -e "\n$playonEDL created for:"
  echo -e "$playonMP4 with the following contents:\n"
  cat "$playonEDL"
done
}

main() {
  cd "/mnt/$dvrDir/PlayOn/$playonPath"
  wildcardArgumentHandler
  commercialChapters2EDL
  cd /
}

main

New Debian-based version of OliveTin-for-Channels pushed today as :latest. OliveTin Actions available include:

  • Comskip on/off by channel
  • List channels with Comskip off
  • Manually add recordings
  • Find Gracenote station IDs
  • Fix YouTube thumbnails
  • Download TwiT.tv guide data
  • Generate channels list in CSV format
  • Generate movie list in CSV format
  • Scan/Prune local content
  • Mark an episode for re-recording
  • Channel lineup change notifications
  • Generate filtered Channels DVR log
  • List sources for a single channel
  • Delete Channels DVR recording log files
  • Send message to defined Channels clients
  • Docker-Compose Examples for Channels & Related Extensions
  • Remove Comskip markers from a recording
  • Restart or shutdown a Channels DVR server
  • Ping Channels DVR server
  • Generate a Channels DVR M3U playlist
  • Remove commercials based on an EDL file
  • Create EDL file from PlayOn recording chapters
  • Create subtitles (.srt) file from Closed Captions

A number of these Actions include the ability to have them execute on a recurring schedule.

Happy Holidays Channels Community!

2 Likes

I pulled the latest image and I'm getting an error in List Sources For a Single Channel.


It's complaining about function gensub not being defined.

@cyoungers OK, thanks. It seems Fedora uses the GNU version of awk by default and Debian does not. So, I added gawk to the olivetin image and changed awk to gawk in the script. Appears fixed here, let me know if you see the same after pulling the :latest again.

That was a good fix. Works now.

1 Like

OliveTin-for-Channels :latest and :2023.12.26 updated to support fixing commercial skip points based on data from LosslessCut. This supplements the built-in CDVR commercial editor, if you have situations where commercials are buried within blocks. See here for more details:

screenshot-htpc6-2023.12.26-05_12_00

Here's the latest annotated docker-compose with sample env vars. I've added some clarification regarding domain search and the binding of directories or volumes from multiple DVRs:

version: '3.9'
services:
  olivetin:
    image: bnhf/olivetin:${TAG} # Add the tag like latest or test to the environment variables below
    container_name: olivetin
    dns_search: ${DOMAIN} # For Tailscale users using Magic DNS, add your Tailnet (tailxxxxx.ts.net) to use hostnames for remote nodes, otherwise use your local domain name
    ports:
      - 1337:1337
    environment:
      - CHANNELS_DVR=${CHANNELS_DVR} # Add your Channels DVR server in the form hostname:port or ip:port
      - CHANNELS_DVR_ALTERNATES=${CHANNELS_DVR_ALTERNATES} # Space separated list of alternate Channels DVR servers to choose from in the form hostname:port or ip:port
      - CHANNELS_CLIENTS=${CHANNELS_CLIENTS} # Space separated list of Channels DVR clients you'd like notifications sent to in the form hostname or IP
      - UPDATE_YAMLS=${UPDATE_YAMLS} # Set this to true to update config.yaml
      - UPDATE_SCRIPTS=${UPDATE_SCRIPTS} # Set this to true to update all included scripts
      - TZ=${TZ} # Add your local timezone in standard linux format. E.G. US/Eastern, US/Central, US/Mountain, US/Pacific, etc
    volumes:
      - ${HOST_DIR}/olivetin:/config # Add the parent directory on your Docker you'd like to use
      - ${DVR_SHARE}:/mnt/local-server6-8089 # This can either be a Docker volume or a host directory that's connected via Samba or NFS to your Channels DVR network share
      - ${DVR2_SHARE}:/mnt/remote-server-8089 # Note that these volume mounts should always be to /mnt/hostname-port or /mnt/ip-port (dash rather than a colon between)
    restart: unless-stopped
#volumes: # use this section if you've setup a docker volume named channels-dvr, with CIFS or NFS, to bind to /mnt/dvr inside the container
  #channels-dvr:
    #external: true

Sample environment variables:

TAG=latest
DOMAIN=tailxxxxx.ts.net
CHANNELS_DVR=local-server:8089
CHANNELS_DVR_ALTERNATES=remote-server:8089
CHANNELS_CLIENTS=appletv4k-den firestick-bedroom
UPDATE_YAMLS=true
UPDATE_SCRIPTS=true
TZ=US/Mountain
HOST_DIR=/data
DVR_SHARE=/mnt/dvr
DVR2_SHARE=/mnt/dvr2
1 Like

Trying this out and of course I'm stumbling a little bit. I did the following to get it installed:

user@host: mkdir /etc/OliveTin/
user@host: # ie: Your config file is /etc/OliveTin/config.yaml on the host machine. We'll create this in the post-installation step.
user@host: docker pull jamesread/olivetin
user@host: docker create --name olivetin -p 1337:1337 -v /etc/OliveTin/:/config:ro docker.io/jamesread/olivetin
user@host: cd /etc/OliveTin/
user@host: curl -O https://raw.githubusercontent.com/OliveTin/OliveTin/main/config.yaml
user@host: docker start olivetin

However, it won't start and this is showing in the logs:

date	stream	content
2023/12/27 15:22:05	stderr	level="error" msg="Config file error at startup. Config File \"config.yaml\" Not Found in \"[/ /config /etc/OliveTin]\""
2023/12/27 15:22:05	stderr	level="debug" msg="Value of -configdir flag" value="."
2023/12/27 15:22:05	stderr	level="info" msg="OliveTin initializing" commit="6b0e414" date="2023-12-21T01:26:17Z" version="2023.12.21"

Here's where I have coinfig.yaml placed:
image

Any clue what I may have done wrong?

TIA

I'm supporting this project strictly via Portainer, which is super-easy to install:

docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 --name portainer \
    --restart=always \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v portainer_data:/data \
    cr.portainer.io/portainer/portainer-ce:latest

Then access the Portainer WebUI on port 9000 for http or 9443 for https. Setup your login name and password, and then in Portainer-Stacks you can use the docker-compose and environment variables as described in the post just above yours. You'll want to remove the jamesread/olivetin container, as this project uses a custom version of it.