quotes-rss (Videos from RSS-Feeds)

Der Anstoss für dieses RPiOS-Projekt kam von Adafruit Quotes, das ist mehr ein Demo-Projekt für diverse Apps und Geräte. Eine deutsche Variante musste her, und auch ein bisschen strukturierter, da ich Zitat und Autor getrennt haben wollte, um gestaltungstechnisch mehr Möglichkeiten zu haben. Und ich wollte Video_looper verwenden, um die Videos automatisch abzuspielen. Mein Feed liegt hier:http://cargologo.com/feed/quotes/data_rss.xml. Und er lässt sich auch in einen RSS-Viewer einfügen, wie NetNewsWire oder Vienna. Das Skript lädt den Feed runter, wählt einen Eintrag zufällig aus und erstellt ein Video (anhand eines Hintergrund-Videos und einer Schrift, siehe Assets-Folder). Das Hintergrund-Video (input.mp4) bestimmt die Länge und die Bild-Grösse der erstellten Video-Datei und es könnte auch Bild-Elemente beinhalten. Meine Testumgebung hier ist das ArgonPod-Video-Case mit RPi Zero 2, der ganz gut kleine FFMPEG-Aufgaben erledigen kann, im Gegensatz zum RPi Zero 1. Die Bildschirmgrösse und die Videobildgrösse hier ist 640×480, durch entsprechende Einstellungen bei FFMPEG kann man auch HD-Videos für andere Ausgabegeräte erstellen. Extension: mit dem Command-Argument ./quotes-rss latest kann man den letzten Eintrag forciert anzeigen lassen. BTW: jeder andere Feed, der title- und description-entries enthält, geht natürlich auch.


#!/bin/bash
# Usage: ./quotes-rss.sh [latest]

# Home Dir
cd /home/pi/quotes-rss/

# Delete old file
#rm ./data_rss.xml* 2> /dev/null

# Download the latest quotes file
wget http://cargologo.com/feed/quotes/data_rss.xml

# Clean up old videos in video_looper Master Dir
#rm /home/pi/video/*_output.mp4 2> /dev/null

# -- Variables
newstimescreen=$(date '+%A %H-%M')
newstimefile=$(date '+%H%M%S')
modificationtime=$(stat ./data_rss.xml | grep "Modify" | sed 's/Modify:/XML Last Modified/g' | cut -c 1-29 | sed 's/:/\\:/g')


# -- Extraction
xml_file="data_rss.xml"
temp_file=$(mktemp)


# Extract quotes and authors using awk
awk '
    BEGIN { RS=""; FS="\n" }
    // {
        title=""; description=""
        for(i=1; i<=NF; i++) {
            if ($i ~ //) {
                sub(".*<title>[ \t]*", "", $i)
                sub("[ \t]*.*", "", $i)
                title=$i
            }
            if ($i ~ //) {
                sub(".*[ \t]*", "", $i)
                sub("[ \t]*.*", "", $i)
                gsub("", "", $i)
                description=$i            }
        }
        if (title && description) {
            print title "|" description >> "'"$temp_file"'"
            last_title = title
            last_author = description
        }
    }
    END {
    if (last_title && last_author) {
        print last_title "|" last_author > "'"$temp_file"'.latest"
    }
}
' "$xml_file"


# Verify that temp_file is populated
num_items=$(wc -l < "$temp_file")
if [ "$num_items" -eq 0 ]; then
  echo "No items found with both title and description."
  rm "$temp_file"
  exit 1
fi


# Choose latest or random quote
if [[ "$1" == "latest" ]]; then
    echo "Showing latest entry..."
    latest_item=$(cat "$temp_file.latest")
    random_item=$latest_item
else
    # Load lines from temp_file into an array
    mapfile -t items < "$temp_file"
    rm "$temp_file"

    # Select a random item
    random_index=$((RANDOM % num_items))
    random_item=${items[$random_index]}
fi


# Split title and description
quote=$(echo "$random_item" | cut -d'|' -f1)
author=$(echo "$random_item" | cut -d'|' -f2)


# Format text with line breaks (2 line breaks between title & author) This is !
formatted_text=$(echo -e "$quote\n\n$author" | fold -s -w 30)

# Escape special characters and preserve newlines for ffmpeg ! This is !


# this creates \u0027
formatted_text_escaped=$(echo "$formatted_text" | sed "s/'/\\\u0027/g; s/:/\\\\:/g; s/\n/\\\x0A/g")


# create video with ffmpeg
ffmpeg -i ./Assets/input.mp4 -vf \
"drawtext=text='${formatted_text_escaped}':fontfile='./Assets/NotoSans_Condensed-Black.ttf':fontcolor=white:fontsize=42:x=10:y=20:box=1:boxcolor=black@0.5:boxborderw=15, \
drawtext=text='${modificationtime}':fontfile='./Assets/NotoSans_Condensed-Black.ttf':fontcolor=yellow:fontsize=30:x=10:y=420" \
-codec:a copy "${newstimefile}_output.mp4"


# Debug Output
echo "Formatted Text: $formatted_text_escaped"
# echo "Modification Time: $modificationtime"


# Move file to video folder
mv *_output.mp4 /home/pi/video/
Files: Download quotes-rss and Assets

Video Picture Stitcher


#!/bin/bash
echo "--------------------------------"
echo "Video Picture Stitcher V1.0"
echo "requ. ffmpeg"
echo "--------------------------------"
echo "What is the name of your input movie (with suffix:mov/mp4/mkv but without spaces)?"
read theSource
echo "How should the output named?"
read theTarget
echo "Please wait .."
ffmpeg -hide_banner -loglevel error -i ./SourceMovie/$theSource -r 0.009 -s 640x360 -f image2 ./Stills/$theTarget-%03d.jpeg
ls -lR ./Stills/$theTarget* | wc -l
echo "Files created."
echo "... Stitching."
ffmpeg -framerate 10 -pattern_type glob -i "./Stills/$theTarget*.jpeg" ./Stitched/$theTarget.mp4
echo ".... Finished."

Muxing Audio- and Video-Container together

ffmpeg -i video.ts -i audio.ts -c:v copy -c:a aac output.mp4

Benchmarks:
3,2 GHz 6-Core Intel Core i7
frame=36438 fps=1348 q=-1.0 size= 413952kB time=00:24:17.47 bitrate=2326.7kbits/s speed=53.9x
2,5 GHz 8-Core Apple M2
frame=166781 fps=2123 q=-1.0 Lsize= 1730859kB time=01:51:11.25 bitrate=2125.4kbits/s speed=84.9x
3,3 GHz 10-Core Apple M2 Pro
frame=13229 fps=2204 qfframe=201471 fps=2310 q=-1.0 Lsize= 2117942kB time=02:14:19.06 bitrate=2152.9kbits/s speed=92.4x