Żegnaj Youtubie!
Posted on Sun 16 May 2021 in Hacks (wannabe), Shitz • 3 min read
Zrobiłem skrypty w Bashu do pobierania świeżych filmów z konkretnego kanału. Prymityw potrzebny przy budowie Platformy ale może być zalążkiem własnego systemu subksrypcji, który pozwoli na skasowanie konta na YT.
Zadanie okazało bardziej skomplikowane niż początkowo myślałem. Na podstawie wcześniejszych doświaczeń w pobiernaiu pojedynczych filmów, uważałem że pobranie większej ilości i generowanie JSON-a załatwię szybkim, prostym skryptem.
To (błędne) założenie spowodowało, że zabrnąłem już na tyle głęboko, że w pewnym momencie siła bezwładności nie pozawalała mi porzucić Basha i pisać w Pythonie. Utknąłem jakby w kałuży smoły.
Co chwila pojawiały się kolejne kłopoty: a to Youtube używał paskudnych sekwencji w nazwach filmów, a to programy nie potrafiły tych sekwencji eskejpować, a to główny skrypt nie zapisywał częściowo wykonanej pracy do pliku, itd.
Najciekawszym odkryciem dla mnie był fakt, że grep nie potrafi czytać ze standard error i musiałem użyć named pipe.
Skrypty bazują na napisanym w Pythonie youtube-dl, więc właściwie mogłyby i powinny być przepisane właśnie w Pythonie, co być może nastapi.
Skrypty są dwa, główny: yt2.sh oraz yt-convert2.sh.
Pierwszy odpala youtube-dl i pobiera najnowsze filmy, zadaniem drugiego jest konwersja do niższej rozdzielczości i birate, ewentualna konwersja miniatur z JPEG do formatu WEBP, a także wypluwanie opisu filmu w formacie JSON.
Główny skrypt wygląda tak i jak widać uruchamia yt-convert2.sh dla każdego pobieranego filmu:
#!/bin/bash # skrypt pobiera najnowsze filmy POBRANE="./pobrane2" # plik zapisem pobranych filmów JSONFILE="./videos.json" # plik z opisami w JSONie JSONOUT="./v.json" # plik z opisami w JSONie YT=`which youtube-dl` MAXVIDS=$2 # ile najnowszych z danego odpalenia DEFAULT_MAXVIDS=4 # domyślna ilość filmów MAXOLD=1day # ile dni wstecz VIDEO=$1 # url do kanału VOD="." # folder dla gotowych plików MAXDURATION=4800 # maksymalna długość filmu 1,5h DEFAULT_VIDEO="https://www.youtube.com/channel/UCiwsDgj8mJnsGOr6oN-2OVQ/videos" # url do kanału wRealu24 # upgrade $YT -U #youtube-dl --rm-cache-dir # usuwam górne i dolne nawiasy sed -i '1 s/\[//' $JSONFILE sed -i '$ s/\]//' $JSONFILE # --format "worst" \ $YT \ --quiet \ --match-filter "duration < $MAXDURATION & !is_live" \ --ignore-errors \ --add-metadata \ --format "best[height=480]/bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" \ --download-archive $POBRANE \ --playlist-end $DEFAULT_MAXVIDS \ --write-thumbnail \ --no-progress \ --merge-output-format mp4 \ --restrict-filenames \ --exec './yt-convert2.sh {}' \ -o "%(id)s.%(ext)s" \ $DEFAULT_VIDEO # kopiowanie miniaturek echo -n -e "\e[31mPrzenoszę miniaturki do $VOD... \033[0m " mv -f *.webp $VOD 2> /dev/null echo "gotowe." # dopisuję co trzeba do $JSONFILE echo -n -e "\e[31mTworzę plik: $JSONOUT... \033[0m " sed '$ s/.$//' $JSONFILE > $JSONOUT sed -i '1i \[' $JSONOUT echo "]" >> $JSONOUT echo -e "gotowe." # czyszczenie echo -n -e "\e[31mKasuję zbędne pliki... \033[0m " cd /home/paczor rm -f *.webp rm -f *.jpg rm -f *.jpeg rm -f *.mp4 echo "gotowe."
Konwersja filmów, miniaturek i wypluwanie JSON-a wygląda zaś tak:
#!/bin/bash # skrypt konwertuje video i generuje miniatury JSONFILE="./videos.json" # plik z opisami w JSONie VOD="." # folder dla gotowych plików FF=`which ffmpeg` MINFO=`which mediainfo` # mediainfo wyciąga datę utworzenia filmu YT=`which youtube-dl` PREFIX="https://youtu.be" # YT prefix VODURL="https://vod.fubar.pl" # url gdzie leżą pliki video mkfifo mypipe # parsowanie JSONa function parse { jq \ --arg status public \ --arg videoUrl "$VODURL/$1.mp4" \ --arg thumbnail "$VODURL/$1.webp" \ --arg seed "true" \ --arg upload_date "$VIDEODATE" \ '{id: .id,title: .title,uploadedAt: $upload_date,publishedAt: $upload_date,status: $status,videoUrl: $videoUrl,desc: .description,views: .view_count,likes: .like_count,tags: .tags[:3],thumbnailUrl: $thumbnail,duration: .duration,seed: $seed}' } VIDEODATE=$(exiftool -t -time:FileModifyDate -- "$1" | cut -d" " -f2 | sed 's/+.*$//') echo -e "\033[31mPrzetwarzam video: $PREFIX/$1\033[0m" echo -e "\e[92m data emisji:\033[0m $VIDEODATE" echo -n -e "\e[92m zapisuję metadata do: $JSONFILE ...\033[0m " $YT --skip-download -j "$PREFIX/$1" 2> mypipe | grep "ERR" mypipe if [ $? -eq 1 ]; then $YT --skip-download -j "$PREFIX/$1" | parse "$1" >> $JSONFILE echo -n "," >> $JSONFILE echo "bez błędu" else echo "błąd!" fi echo -n -e "\e[92m skaluję do: $VOD/$1 ... \033[0m " #$FF -i $1 -filter:v scale=-2:480 -threads 16 -hide_banner -loglevel error -y $VOD/$1 echo " gotowe." echo -n -e "\e[92m konwertuję miniaturkę... \033[0m" if [[ -e `basename $1 .mp4`.jpg ]]; then THUMB=`basename $1 .mp4`.jpg convert $THUMB `basename $THUMB .jpg`.webp rm -f $THUMB echo "zmieniłem JPEG na WEBP." else echo "WEBP już istnieje." fi rm mypipe
Miałem z tym sporo grzebania, zgłosiłem dwa błędy które wykryłem w youtube-dl oraz w programie Mediainfo. Pisanie skryptów w Bashu coraz mniej mnie cieszy, nie lubię jego składni, podstawień, itp.