I mean, if it's up to me, the closed caption work is basically done.
As long as no one else runs into some weird edge case, I can't see why we need to make changes to it.
At this point, I think this has become a bit of a refactor, and what you just opened as a question might be worth exploring before we merge this branch.
I agree. My preference at this point would be a brief pause in changes, and if no "must fix" items pop-up, pull PR#20 in. This is a big PR, but once we get it merged, we should be able to return to some more manageable PR sizes.
There will always be new features that can be added or improved upon, but for now this seems to me to be a very nice upgrade, with plenty of changes for people to adsorb and utilize.
You've done an amazing job on this, and have really given a major face and functionality lift to this project!
Thank so much and I agree!
I think the next step going forward would be to break main.go up into more maintainable pieces so we can better extend things in the future. Personally I'd like to see less env vars and more UI based configuration. I think we can make this tool really user friendly if we allowed for more config through the new UI.
I'd be fine with that, as long as we continue to support env vars as well.
None of this should be part of PR#20 though! Bug fixes only to that PR please, so we can get it merged soon. The changes I've made to the beta branch on top of PR#20 should be easy to replicate, so I think rather than creating a PR from the beta branch, I'll delete it and merge your PR. Once that's done, I'll add my changes back -- which are script, yaml and env related.
Just mentioning something I was playing with this morning.
Channels DVR doesnt display closed captioning in Live multi view.
So this morning using the PYATV commands, I was able to create a toggle for each tuners broadcast closed captioning for use in live situations.
I implemented a Docker container running a lightweight Python HTTP webhook service, and leveraged the Apple TV accessibility shortcut set to closed captions. three quick menu presses toggles the built in CC
Then I created a couple of apple shortcuts use get contents of URL , POST for each tuner.
Ive got it working with an Apple Watch complication right now.
In my tuner case this is very stable, because the ATV app I use adheres to the apple system level CC control and never changes. Some other apps - like Netflix dont.
Im getting ready for all my live view sports that are starting in a few weeks!!!
For the main apple tv that i use to view channels on my couch , i leverage channels api to toggle cc
Depends on the model chosen and the number of tuners running at once. I tried to make it work with pretty much everything but a literal potato. What do you run ah4c on?
In ah4c, FireTV with LinkPi encoder, everything is working fine with a sling.m3u lineup. Can I add a channel from an app outside of the Sling app? I need to launch the Tennis Channel app, click Down twice and hit Enter, for a manual launch of the Live feed. I wish there was a deeplink for that but I have no idea how to find it. Any help greatly appreciated, thanks.
If you have the Tennis channel app installed on your firestick you can query from the docker console using adb commands and find out the package to launch, and there are definitely adb commands to do the button presses.
If you add the tennis channel in your m3u you can then add a case statement in your bmitune.sh to check for that channel and hardcode the adb command sequence in the tuning script. Then you may have add something to do housekeeping for that channel in stopbmitune.sh
There's a new way to do this, that I just tested. Here are the basics:
Use a STREAMER_APP= value of scripts/all/all
Create an M3U called all.m3u with whatever virtual channels you want. In your case, you'd start with the contents of sling.m3u, and add everything to all.m3u. For each tuning URL in all.m3u, you'll be adding the device and provider to that URL, in the form:
In other words, after the tuner/ part, add <device>~<provider~, just as they appear in your current scripts/<device>/<provider> value for STREAMER_APP.
Get it?
The all/all scripts are dispatchers, and will use the scripts from <device>/<provider> to do the actual tuning. Via this approach, ah4c is no longer limited to a single provider.
Try this first for Sling only, and then you can create scripts for the Tennis Channel, along with adding an M3U record for that channel.
This is the perfect entry point for a UI where we can have different streamer apps.
After I take a little break after that monster PR, maybe I'll start working on something like that.
Since we have a library of scripts, we really could write a graphical script library where you can just choose your script and maybe even have some sort of callback to project one click if it's installed and detected.
I'd actually love to see some integration with Project OneClick for building M3Us, and just make this really super easy for people. Just one click and you get all your channels in an M3U. Kind of like what we already have, but fully automated. Just a thought.
Btw i did notice another possible artifact of this merge. It might have happened during the first pull though, a bunch of new M3Us got populated on top of my existing m3u directory. It didnt wipe out my custom one.
I have the environment variables to pull and update scripts and m3us set to false
Thanks for all the ideas and help. I ended up mixing both sling and the Tennis Channel app in the same m3u using a random hex token. Then used if/else logic in bmitune.sh. Here's the script in case it helps anybody:
#!/bin/bash
#bmitune.sh for firetv/sling
set -x
channelID="$1"
specialID="$1"
streamerIP="$2"
streamerNoPort="${streamerIP%%:*}"
adbTarget="adb -s $streamerIP"
packageName=com.sling
if [ "$channelID" == "fc65b6abb023efabfaea08e47fe89beb" ]; then
packageName=com.tennischannel.tceverywhere.amazon
fi
finish() {
echo "bmitune.sh is exiting for $streamerIP with exit code $?"
}
trap finish EXIT
updateReferenceFiles() {
mkdir -p $streamerNoPort
[[ -f "$streamerNoPort/stream_stopped" ]] || echo 0 > "$streamerNoPort/stream_stopped"
[[ -f "$streamerNoPort/last_channel" ]] || echo 0 > "$streamerNoPort/last_channel"
echo $$ > "$streamerNoPort/bmitune_pid"
echo "Current PID for this script is $$"
}
matchEncoderURL() {
case "$streamerIP" in
"$TUNER1_IP") encoderURL=$ENCODER1_URL ;;
"$TUNER2_IP") encoderURL=$ENCODER2_URL ;;
"$TUNER3_IP") encoderURL=$ENCODER3_URL ;;
"$TUNER4_IP") encoderURL=$ENCODER4_URL ;;
*) exit 1 ;;
esac
}
activeAudioCheck() {
local startTime=$(date +%s)
local maxDuration=60
local minimumLoudness=-50
local sleepDuration=0.5
while true; do
checkLoudness=$(ffmpeg -t 1 -i $encoderURL -filter:a ebur128 -map 0:a -f null -hide_banner - 2>&1 | awk '/I: /{print $2}')
if (( $(date +%s) - $startTime > $maxDuration )); then
echo "Active audio stream not detected in $maxDuration seconds."
exit 1
fi
if (( $(echo "$checkLoudness > $minimumLoudness" | bc -l) )); then
echo "Active audio stream detected with $checkLoudness LUF."
break
fi
if appFocusCheck 0; then
echo "Active audio stream not yet detected -- loudness is $checkLoudness LUF. Continuing..."
sleep $sleepDuration
else
echo "No active audio stream detected and app is not in focus after $(($(date +%s) - $startTime)) seconds -- attempting to tune again..."
tuneChannel
fi
done
}
appFocusCheck() {
if [ "$channelID" == "fc65b6abb023efabfaea08e47fe89beb" ]; then
return 0 # trust the audio-loudness check alone for this app; skip focus-based retune
fi
appFocus=$($adbTarget shell dumpsys window windows | grep -E 'mCurrentFocus' | cut -d '/' -f1 | sed 's/.* //g')
if [[ $appFocus == $packageName ]]; then
return 0
else
return 1
fi
}
specialChannels() {
if [ $specialID = "exit" ]; then
echo "Exit $packageName requested on $streamerIP"
rm $streamerNoPort/last_channel $streamerNoPort/adbAppRunning
$adbTarget shell am force-stop $packageName
exit 0
elif [ $specialID = "reboot" ]; then
echo "Reboot $streamerIP requested"
rm $streamerNoPort/last_channel $streamerNoPort/adbAppRunning
$adbTarget reboot
exit 0
elif [[ -f $streamerNoPort/adbCommunicationFail ]]; then
rm $streamerNoPort/adbCommunicationFail
exit 1
else
echo "Not a special channel (exit nor reboot)"
fi
}
tuneChannel() {
if [ "$channelID" == "fc65b6abb023efabfaea08e47fe89beb" ]; then
$adbTarget shell am start -n com.tennischannel.tceverywhere.amazon/com.foxxum.webapp.MainActivity
sleep 6
$adbTarget shell input keyevent 20
sleep 1
$adbTarget shell input keyevent 66
else
$adbTarget shell am start -a android.intent.action.VIEW -d https://watch.sling.com/1/channel/$channelID/watch
fi
}
main() {
updateReferenceFiles
matchEncoderURL
specialChannels
tuneChannel
activeAudioCheck
}
main