ubuntuusers.de

automatisch youtube-Videos aus youtube-rss-Feeds mit youtube-dl herunterladen

Status: Ungelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

fpunktk

Avatar von fpunktk

Anmeldungsdatum:
24. Oktober 2007

Beiträge: 142

Ich habe einige Kanäle von youtube in meinem rss-Reader abonniert und hatte es satt, die Videos immer einzeln per Hand mit youtube-dl herunter zu laden. Also musste ein kleines Script her, dass automatisch die Feeds auf neue Videos überprüft und diese dann herunterlädt. Meine Lösung ist recht kurz, aber ich finde sie ganz elegant, deswegen stelle ich sie hier vor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/dash

# Script um automatisiert neue Videos aus youtube-rss-Feeds herunter zu laden

# Copyright (C) 2011 Felix Kästner, youtube-feed-downloader @ f p u n k t k . de

# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/.

feedlist_filename='/pfad/zur/liste/mit/den/feeds'
downloaded_list_filename='/pfad/zur/liste/mit/den/heruntergeladenen/videos'
# Pfad zu youtube-dl mit passenden Optionen
ytdl_bin_opts='/pfad/zu/youtube-dl --max-quality=34 --no-mtime --no-part -o /zielpfad/füe/die/heruntergeladenen/videos/%(uploader)s-%(stitle)s-%(id)s.%(ext)s'

# wenn die feedlist nur youtube-Feeds enthält:
vids="$(/usr/bin/wget -O - -nv -i "$feedlist_filename" | /bin/grep -Eo 'http://www.youtube.com/watch\?v=[^&"]*' | /usr/bin/sort -u)"
# Wenn die feedlist nicht nur youtube-Feeds enthält:
vids="$(/bin/grep -F 'http://gdata.youtube.com/feeds/' "$feedlist_filename" | /usr/bin/wget -O - -nv -i - | /bin/grep -Eo 'http://www.youtube.com/watch\?v=[^&"]*' | /usr/bin/sort -u)"
# $vids enthält jetzt jeden Link zu einem Video aus den Feeds genau ein mal

oldvids="$(/bin/cat "$downloaded_list_filename" "$downloaded_list_filename")"
# $oldvids enthält jetzt alle Links zu bereits heruntergeladenen Videos (genau) zwei mal
# jetzt werden aus den bereits heruntergeladenen Links und den Links aus den Feeds diese herausgesucht, die nur genau ein mal vorhanden sind, das sind die neuen Links
newvids="$(echo "$oldvids\n$vids" | /usr/bin/sort | /usr/bin/uniq -u)"

if [ "$newvids" != "" ]
then
    # die neuen Links an die Liste der bereits heruntergeladenen Links anhängen
    echo "$newvids" >> "$downloaded_list_filename"
    # die neuen Links mit youtube-dl herunterladen
    $ytdl_bin_opts $newvids
else
    echo "es gibt keine neuen Videos"
fi

Zu beachten ist, dass das Script für Dash gemacht ist. Bei Verwendung der Bash muss man zumindest die Option -e an das echo in Zeile 25 anhängen.

Über meinungen, Kritik und Lob freue ich mich ☺

Mobai

Avatar von Mobai

Anmeldungsdatum:
4. Februar 2011

Beiträge: 259

http://www.youtube.com/t/terms

Also ist es verboten, Videos runterzuladen... Oder nicht?

kutteldaddeldu Team-Icon

Anmeldungsdatum:
1. Juli 2008

Beiträge: 3586

Du bist, wie es bei einem solchen Thema natürlich ist, selbstverständlich nicht der/die Erste, der/die sich diese Frage stellt – was Du mit einer kurzen Foren-/Google-/Was-auch-immer-Suche leicht herausfinden hättest können.

@fpunktk: Nettes Skript!

fpunktk

(Themenstarter)
Avatar von fpunktk

Anmeldungsdatum:
24. Oktober 2007

Beiträge: 142

Kleines Update:

Es hat mich noch genervt, dass der Download recht lange dauert, weil die Geschwindigkeit seitens youtube begrenzt wird. Also wollte ich, dass mehrere Downloads parallel laufen. Erster Ansatz dafür war, die Liste der Videos aufzuteilen. Das funktionierte aber nicht so gut. Der zweite Ansatz ist eine FIFO-Warteschlange und folgt jetzt hier:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/bin/dash

# Script um automatisiert neue Videos aus youtube-rss-Feeds herunter zu laden

# Copyright (C) 2011 Felix Kästner, youtube-feed-downloader @ f p u n k t k . de

# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/.

feedlist_filename='/pfad/zur/liste/mit/den/feeds'
downloaded_list_filename='/pfad/zur/liste/mit/den/heruntergeladenen/videos'
# Pfad zu youtube-dl mit passenden Optionen
ytdl_bin_opts='/pfad/zu/youtube-dl --max-quality=34 --no-mtime --no-part -o /zielpfad/füe/die/heruntergeladenen/videos/%(uploader)s-%(stitle)s-%(id)s.%(ext)s'
max_parallel="1 2 3 4 5" # Maximalzahl der parallel laufenden Instanzen von youtube-dl, eine for-Schleife iteriert durch diese Variable. Ein guter Wert scheint (verfügbare Bandbreite in kB/s durch 130 kB/s) zu sein.

# wenn die feedlist nur youtube-Feeds enthält:
vids="$(/usr/bin/wget -O - -nv -i "$feedlist_filename" | /bin/grep -Eo 'http://www.youtube.com/watch\?v=[^&"]*' | /usr/bin/sort -u)"
# Wenn die feedlist nicht nur youtube-Feeds enthält:
vids="$(/bin/grep -F 'http://gdata.youtube.com/feeds/' "$feedlist_filename" | /usr/bin/wget -O - -nv -i - | /bin/grep -Eo 'http://www.youtube.com/watch\?v=[^&"]*' | /usr/bin/sort -u)"
# $vids enthält jetzt jeden Link zu einem Video aus den Feeds genau ein mal

oldvids="$(/bin/cat "$downloaded_list_filename" "$downloaded_list_filename")"
# $oldvids enthält jetzt alle Links zu bereits heruntergeladenen Videos (genau) zwei mal
# jetzt werden aus den bereits heruntergeladenen Links und den Links aus den Feeds diese herausgesucht, die nur genau ein mal vorhanden sind, das sind die neuen Links
newvids="$(echo "$oldvids\n$vids" | /usr/bin/sort | /usr/bin/uniq -u)"

if [ "$newvids" != "" ]
then
    # die neuen Links an die Liste der bereits heruntergeladenen Links anhängen
    echo "$newvids" >> "$downloaded_list_filename"
    # fifo-pipe aufbauen:
    pipename="$(/bin/mktemp -u)" # einen (hoffentlich) sicheren temporären Dateinamen erzeugen
    # fifo-pipe erzeugen, an FD 3 zuweisen, fifo-pipe löschen, Zuweisung bleibt erhalten
    /usr/bin/mkfifo "$pipename"
    exec 3<>"$pipename"
    /bin/rm "$pipename"
    
    # die Links zeilenweise in die Pipe schreiben
    for vid in $newvids
    do
        echo $vid >&3
    done

    pids=""
    for i in $max_parallel
    do
        echo "stop" >&3 # damit die folgende while-Schleife auch irgendwann abbricht (read wartet sonst ewig auf Eingabe)
        { # Kindprozess im Hintergrund
        ytdl_err=0
        while read vid
        do
            [ "$vid" = "stop" ] && break
            $ytdl_bin_opts $vid || ytdl_err="$?"
        done <&3
        return $ytdl_err
        } &
        pids="$pids $!"
    done
    
    echo "pids: $pids" # die PIDs der Kindprozesse ausgeben
    trap "echo; echo kill $pids; /bin/kill $pids; exec 3>&-; exit" INT TERM # Signale Abfangen, um das Script und die Kindprozesse ordnungsgemäß beenden zu können (z.B. mit Strg + c)
    
    # einzeln auf die Kindprozesse warten, Exitcodes bereits beendeter Prozesse werden auch beachtet
    ytdl_err=0
    for pid in $pids
    do
        wait $pid || ytdl_err="$?"
    done
    
    exec 3>&- # FD 3 schließen
    [ $ytdl_err -ne 0 ] && echo "Probleme beim Download" && exit $ytdl_err
else
    echo "es gibt keine neuen Videos"
fi

Ein paar kleine Nachteile hat das aber noch:

  • Die Ausgabe der einzelnen Instanzen von youtube-dl überlagern sich. Das finde ich aber nicht weiter schlimm.

  • Es ist nicht reproduzierbar vorgekommen, dass die Warteschlange falsch befüllt wurde, also Zeilenumbrüche fehlten. Wenn das passiert, kann das Script hängen bleiben. Dafür habe ich keine Lösung.

Man kann das Script natürlich auch umbauen, um parallel mehrere Videos herunter zu laden, die man per Kommandozeilenoption oder in einer Datei übergibt. Die Umsetzung überlasse ich dem Leser als Übung ☺

Antworten |