Difference between revisions of "YT-DLP Scripting"

From Da Nerd Mage Wiki
Jump to navigation Jump to search
 
(49 intermediate revisions by the same user not shown)
Line 1: Line 1:
= YTchan =
= About the weirdness that is YouTube naming conventions =
== When looking at a channel page: ==


A script for downloading entire channels...
<nowiki>https://www.youtube.com/@</nowiki>'''<span style="color: rgb(132, 63, 161);">Tinker001</span>'''


(assumes your base for downloading YouTube videos is at: '''/mnt/Download_Space/YTDL/''')
The '''<span style="color: rgb(132, 63, 161);">bold purple</span>''' part is the channel name


== When watching a video: ==
<nowiki>https://www.youtube.com/watch?v=</nowiki>'''<span style="color: rgb(132, 63, 161);">y8o7qkmiDso</span>'''
The '''<span style="color: rgb(132, 63, 161);">bold purple</span>''' part is the video name
== When watching a playlist: ==
<nowiki>https://www.youtube.com/watch?v=</nowiki><span style="color: rgb(22, 145, 121);" >'''oizvS01ovHE'''</span>&list='''<span style="color: rgb(132, 63, 161);">PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj</span>'''&pp=gAQB
The '''<span style="color: rgb(132, 63, 161);">bold purple</span>''' part is the playlist name
Bonus fun bit: The <span style="color: rgb(22, 145, 121);" >'''bold green'''</span> part is actually the name of the video being watched inside that playlist.
= Cookies! =
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]
= One script with multiple personalities =
Yup...
Looks even more complicated. In fact, it might even be considered kinda silly.
(assumes your base for downloading YouTube videos is at '''/mnt/Download_Space/YTDL/''' and contains subfolders named '''_Individual_''' and '''_Playlists_''')
Save this script as '''YTall'''
Then make symbolic links to it.
* <code>ln -s YTall YTc</code>
* <code>ln -s YTall YTv</code>
* <code>ln -s YTall YTl</code>
Call it as '''YTc''' for doing whole channels, '''YTv''' for individual videos, & '''YTl''' for playlists.


<syntaxhighlight lang="Bash" line copy>
<syntaxhighlight lang="Bash" line copy>
#!/bin/bash
#!/bin/bash


echo -e "~~~~~~~ " $0 $@ "~~~~~~~ "\\n
BASENAME=$(basename "$0")
 
echo -e "~~~~~~~ $BASENAME $@ ~~~~~~~ "\\n
 
case $BASENAME in
  "YTv")
    TYPE="VideoHash"
    DESC="$TYPE = The name YouTube has given to the individual video"
    DESC+="\n\\t\\t (This is gonna take some work to explain...)"
    DESC+="\n\\t\\t You can specify multiple videos"
  ;;
  "YTc")
    TYPE="ChannelName"
    DESC="$TYPE = The name of the channel \(as defined by YouTube\)"
    DESC+="\n\\t\\t You can specify multiple channels"
  ;;
  "YTl")
    TYPE="ListHash"
    DESC="$TYPE = The name YouTube has given to the playlist"
    DESC+="\n\\t\\t (This is gonna take some work to explain...)"
    DESC+="\n\\t\\t You can specify multiple lists"
  ;;
  *)
    TYPE="poop"
    DESC="$TYPE = Some crap"
  ;;
esac


if [ $# -eq 0 ] || [ $1 = "-u" ] || [ $1 = "-?" ]; then
if [ $# -eq 0 ] || [ $1 = "-u" ] || [ $1 = "-?" ]; then
   echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...
   echo -e USAGE: $(basename "$0") \[...option\(s\)...\] $TYPE $TYPE ...
   echo
   echo
   echo -e OPTIONS:
   echo -e OPTIONS:
   echo -e \\t -BOB = Grant Style Folder Structure
   echo -e \\t -BOB = Grant Style Folder Structure
  echo -e \\t -a = Download audio only \(into MP3 files\)
   echo
   echo
   echo -e \\t -s = simulate this run
   echo -e \\t -s = simulate this run
Line 28: Line 86:
   echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info
   echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info
   echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)
   echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)
   echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)
   echo -e \\t $DESC
  echo -e \\t\\t You can specify multiple channels
   echo
   echo
   echo -e The following \"ERROR\"s will also appear in 00000000-ERRORS
   echo -e The following \"ERROR\"s will also appear in 00000000-ERRORS
   echo -e \(Unfortunately, without indications of which files caused them...\)
   echo -e \(Unfortunately, without indications of which files caused them...\)
  echo
  echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\"
  echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\"
  echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\"
  echo -e \\t Is simply indicating that the channel doesn\'t have that type of content.
  echo -e \\t \(All 3 means the channel doesn\'t actually have any content... :P \)
   echo
   echo
   echo -e \"ERROR: unable to download video data: HTTP Error 403: Forbidden\"
   echo -e \"ERROR: unable to download video data: HTTP Error 403: Forbidden\"
Line 44: Line 95:
   echo -e \\t Often caused by things like age restrictions.
   echo -e \\t Often caused by things like age restrictions.
   echo -e \\t May also be caused by YouTube noticing you\'ve been downloading a bunch...
   echo -e \\t May also be caused by YouTube noticing you\'ve been downloading a bunch...
   echo
case $BASENAME in
   "YTc")
    echo
    echo -e \"ERROR: \[youtube\] oizvS01ovH0: Video unavailable\"
    echo -e \\t Most likely caused by a typo in the VideoHash
  ;;
  "YTv")
    echo
    echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\"
    echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\"
    echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\"
    echo -e \\t Is simply indicating that the channel doesn\'t have that type of content.
    echo -e \\t \(All 3 means the channel doesn\'t actually have any content... :P \)
  ;;
  "YTl")
    echo
    echo -e \"mv: cannot stat \'*\': No such file or directory\"
    echo -e \\t Don\'t panic. This one\'s just a bit of residue from the playlist folder cleanup
  ;;
esac
echo


   exit
   exit
fi
fi


#TYPES="videos"
  BASEdest=/mnt/Download_Space/YTDL/
TYPES="videos shorts streams"
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt


   SIMULATE=""
   SIMULATE=""
Line 59: Line 129:
   TIMEspan=""
   TIMEspan=""
   BOBstyle=""
   BOBstyle=""
  AUDIOonly=""
  FILETYPE="-t mp4"


while (( "$#" ));
while (( "$#" ));
do
do
   if [ ${1} = "-c" ]; then
   case $1 in
    echo Using Cookies: $COOKIEfile
    "-c")
    WITHcookies="--cookies "$COOKIEfile
      echo Using Cookies: $COOKIEfile
    shift
      WITHcookies="--cookies "$COOKIEfile
  elif [ ${1} = "-s" ]; then
      shift
    echo Simulating
     ;;
    SIMULATE="-s"
    shift
  elif [ ${1} = "-r" ]; then
    shift
    LIMITrate="-r $1"
    shift
    echo Rate Limiting $LIMITrate
  elif [ ${1} = "-p" ]; then
    shift
    Pmin=$1
    shift
    Pmax=$1
    PAUSEbetween="--sleep-interval $Pmin --max-sleep-interval $Pmax"
    shift
     echo Time Span $TIMEspan to current
  elif [ ${1} = "-e" ]; then
    shift
    TIMEspan="--dateafter $1"
    shift
    echo Time Span $TIMEspan to current
  elif [ ${1} = "-BOB" ]; then
    echo Grant Style Folder Structure
    BOBstyle="True"
    shift
  else
    CHANNEL=$1
    shift
    echo
    echo Working on channel: $CHANNEL
    echo ========================================


URL=https://www.youtube.com/\@$CHANNEL
    "-s")
      echo Simulating
      SIMULATE="-s"
      shift
    ;;


     if wget --spider --quiet $URL > /dev/null 2>&1; then
     "-r")
      LIMITrate="-r $2"
      echo Rate Limiting $2
      shift 2
    ;;


       DEST=/mnt/Download_Space/YTDL/$CHANNEL
    "-p")
       PAUSEbetween="--sleep-interval $2 --max-sleep-interval $3"
      echo Random pause between $2 \& $3 seconds
      shift 3
    ;;


       ERRfile=$DEST/00000000-ERRORS
    "-e")
       ARCHfile=$DEST/11111111-ARCHIVE
       TIMEspan="--dateafter $2"
       echo Time Span $2 to current
      shift 2
    ;;


      if [ -d $DEST ]; then
    "-BOB")
        echo $DEST exists
      BOBstyle="True"
       else
       echo Using Grant Style Folder Structure
        echo no $DEST... Building it...
      shift
        mkdir $DEST
    ;;
        if [ -z $BOBstyle ]; then
        for ACK in $TYPES
          do
            mkdir $DEST/$ACK
          done
        fi
      fi


       echo
    "-a")
      AUDIOonly="--extract-audio --audio-format mp3 --audio-quality 0"
      FILETYPE="-t mp3"
       echo Extracting audio only
      shift
    ;;


       OPTIONS="$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween"
    *)
      OPTIONS+=" --no-overwrites --write-description -t mp4"
       case $BASENAME in
        "YTv") # Video
          echo Working on video: $1
          echo ========================================
          WeirdID=$1
          URL=https://www.youtube.com/watch\?v=$1
          TYPES=""
          DEST="$BASEdest""_Individual_/"
          FORMAT="%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s"
        ;;


      cd $DEST
        "YTc") # Channel
          echo Working on Channel: $1
          echo ========================================
          WeirdID=$1
          URL=https://www.youtube.com/\@$1
          TYPES="videos shorts streams"
#          TYPES="videos shorts streams playlists podcasts courses"
          DEST="$BASEdest""$1"
          FORMAT="%(upload_date)s - %(title)s.%(ext)s"
        ;;


         for ACK in $TYPES
         "YTl") # Playlist
           do
           echo Working on playlist: $1
            echo ">>>>>>>> " $URL/$ACK
          echo ========================================
if [ -z $BOBstyle ]; then
          WeirdID=$1
            cd $ACK
          URL=https://www.youtube.com/playlist\?list=$1
fi
          TYPES=""
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o "%(upload_date)s - %(title)s.%(ext)s" $URL/$ACK 2> >(/usr/bin/tee -a $ERRfile)
          DEST="$BASEdest""_Playlists_/"
if [ -z $BOBstyle ]; then
          FORMAT="%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s"
            cd ..
        ;;
fi
      esac
          done


    else
       ERRfile=$DEST/00000000-ERRORS
       echo YouTube says this channel does not exist.
      ARCHfile=$DEST/11111111-ARCHIVE
    fi 
  fi
done
</syntaxhighlight>
 
= YTvid =


<span style="color: rgb(186, 55, 42);" >'''<span style="font-size: 24pt;" >WIP</span>'''</span>
      OPTIONS="$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween $AUDIOonly"
      OPTIONS+=" --no-overwrites --write-description $FILETYPE"


A script for downloading separate videos...
      echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
      echo $URL
      echo $WeirdID
      echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"


(assumes your base for downloading YouTube videos is at: '''/mnt/Download_Space/YTDL/''')


For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]
      if wget --spider --quiet $URL > /dev/null 2>&1; then
 
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn't exist when asking about videos...
<syntaxhighlight lang="Bash" line copy>
        # Then it gives an error while attempting the download.
#!/bin/bash
        # Not fatal, just annoying...


echo -e "~~~~~~~ " $0 $@ "~~~~~~~ "\\n
        echo -en "(storing in $DEST"


if [ $# -eq 0 ] || [ $1 = "-u" ] || [ $1 = "-?" ]; then
        case $BASENAME in
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...
          "YTv")
  echo
            echo ")"
  echo -e OPTIONS:
            echo VID $WeirdID >> $ARCHfile
  echo -e \\t -BOB = Grant Style Folder Structure
            cd $DEST
  echo
            pwd
  echo -e \\t -s = simulate this run
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o "$FORMAT" $URL 2> >(/usr/bin/tee -a $ERRfile)
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.
            rm -f *.part
  echo -e \\t -r RATE = Limit bandwidth
          ;;
  echo -e \\t\\t Maximum download rate in bytes per second,
          "YTl")
  echo -e \\t\\t\\t e.g. 50K or 4.2M
            echo "$WeirdID)"
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)
            echo LIST $WeirdID >> $ARCHfile
  echo -e \\t\\t \(will result in a random pause between MIN \& MAX seconds long\)
            cd $DEST
  echo -e \\t -e DATE = Earliest video upload date to grab.
            pwd
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info
            if [ -d $DEST/$WeirdID ]; then
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)
              echo $DEST exists
  echo -e \\t VideoHash = The name YouTube has given to the individual video
            else
  echo -e \\t\\t \(This is gonna take some work to explain...\)
              echo no $DEST$WeirdID... Building it...
  echo -e \\t\\t You can specify multiple videos
              mkdir $DEST$WeirdID
  echo
            fi
  echo -e The following \"ERROR\"s will also appear in 00000000-ERRORS
            cd $WeirdID
  echo -e \(Unfortunately, without indications of which files caused them...\)
            pwd
  echo
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o "$FORMAT" $URL 2> >(/usr/bin/tee -a $ERRfile)
  #echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\"
            rm -f *.part
  #echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\"
  #echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\"
  #echo -e \\t Is simply indicating that the channel doesn\'t have that type of content.
  #echo -e \\t \(All 3 means the channel doesn\'t actually have any content... :P \)
  #echo
  echo -e \"ERROR: unable to download video data: HTTP Error 403: Forbidden\"
  echo -e \\t Means you may need to supply cookies.
  echo -e \\t Often caused by things like age restrictions.
  echo -e \\t May also be caused by YouTube noticing you\'ve been downloading a bunch...
  echo


   exit
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex './0+_.*' -type f   `
fi


#TYPES="videos"
            Listname=`echo ${NAME::-12} | cut -d'@' -f 2`
TYPES="videos shorts streams"
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt


  SIMULATE=""
            if [ -d ../"$Listname" ]; then
  WITHcookies=""
              echo "$Listname" already exists
  LIMITrate=""
            else
  PAUSEbetween=""
              mkdir ../"$Listname"
  TIMEspan=""
            fi
  BOBstyle=""


while (( "$#" ));
            mv "$NAME" ../"$Listname/000 $Listname.description"
do
            mv * ../"$Listname"
  if [ ${1} = "-c" ]; then
            cd ..
    echo Using Cookies: $COOKIEfile
            rmdir $WeirdID
    WITHcookies="--cookies "$COOKIEfile
          ;;
    shift
          "YTc")
  elif [ ${1} = "-s" ]; then
            echo ")"
    echo Simulating
            if [ -d $DEST ]; then
    SIMULATE="-s"
              echo $DEST exists
    shift
            else
  elif [ ${1} = "-r" ]; then
              echo no $DEST... Building it...
    shift
              mkdir $DEST
    LIMITrate="-r $1"
              if [ -z $BOBstyle ]; then
    shift
                for ACK in $TYPES
    echo Rate Limiting $LIMITrate
                  do
  elif [ ${1} = "-p" ]; then
                    mkdir $DEST/$ACK
    shift
                  done
    Pmin=$1
              fi
    shift
            fi
    Pmax=$1
    PAUSEbetween="--sleep-interval $Pmin --max-sleep-interval $Pmax"
    shift
    echo Time Span $TIMEspan to current
  elif [ ${1} = "-e" ]; then
    shift
    TIMEspan="--dateafter $1"
    shift
    echo Time Span $TIMEspan to current
  elif [ ${1} = "-BOB" ]; then
    echo Grant Style Folder Structure
    BOBstyle="True"
    shift
  else
    vidID=$1
    shift
    echo
    echo Working on video: $vidID
    echo ========================================


URL=https://www.youtube.com/watch\?v=$vidID
            cd $DEST
            pwd


    if wget --spider --quiet $URL > /dev/null 2>&1; then
            if [ -z $BOBstyle ]; then
              echo -e "(using subfolders...)"
            else
              echo -e "(using Grant format...)"
            fi
            echo


      DEST=/mnt/Download_Space/YTDL/_Individual_/
            for ACK in $TYPES
              do
                echo ">>>>>>>> " $URL/$ACK
                if [ -z $BOBstyle ]; then
                  cd $ACK
                  echo CHAN $WeirdID $ACK >> $ARCHfile
                fi


      ERRfile=$DEST/00000000-ERRORS
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o "$FORMAT" $URL/$ACK 2> >(/usr/bin/tee -a $ERRfile)
      ARCHfile=$DEST/11111111-ARCHIVE


#     if [ -d $DEST ]; then
                # Clear out .part files
#        echo $DEST exists
                rm -f *.part
#      else
#        echo no $DEST... Building it...
#        mkdir $DEST
#        if [ -z $BOBstyle ]; then
#        for ACK in $TYPES
#          do
#            mkdir $DEST/$ACK
#          done
#        fi
#      fi


       echo
                if [ -z $BOBstyle ]; then
                  cd ..
                fi
              done
          ;;
        esac
       else
        echo YouTube says this channel does not exist.
      fi 
      shift
    ;;


      OPTIONS="$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween"
  esac
      OPTIONS+=" --no-overwrites --write-description -t mp4"
done
</syntaxhighlight>


      cd $DEST
= Even more options? =
<span style="color: rgb(186, 55, 42);" >'''<span style="font-size: 24pt;" >WIP</span>'''</span>


#        for ACK in $TYPES
= Errors noted, but not researched =
#          do
In console output:
#            echo ">>>>>>>> " $URL/$ACK
* <nowiki>[download] 57.7% of  15.24MiB at  65.83KiB/s ETA 01:40[download] Got error: ("Connection broken: ConnectionResetError(104, 'Connection reset by peer')", ConnectionResetError(104, 'Connection reset by peer')). Retrying (1/10)...</nowiki>
#            if [ -z $BOBstyle ]; then
#              cd $ACK
#            fi
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o "%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s" $URL/$ACK 2> >(/usr/bin/tee -a $ERRfile)
#            if [ -z $BOBstyle ]; then
#              cd ..
#            fi
#          done


    else
In 00000000-ERRORS:
      echo YouTube says this channel does not exist.
* <nowiki>WARNING: [youtube] ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response')). Retrying (1/3)...</nowiki>
    fi 
  fi
done
pwd
rm *.part
</syntaxhighlight>

Latest revision as of 09:58, 7 October 2025

About the weirdness that is YouTube naming conventions

When looking at a channel page:

https://www.youtube.com/@Tinker001

The bold purple part is the channel name

When watching a video:

https://www.youtube.com/watch?v=y8o7qkmiDso

The bold purple part is the video name

When watching a playlist:

https://www.youtube.com/watch?v=oizvS01ovHE&list=PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&pp=gAQB

The bold purple part is the playlist name

Bonus fun bit: The bold green part is actually the name of the video being watched inside that playlist.

Cookies!

For the potentially required cookie file, see Exporting YouTube cookies

One script with multiple personalities

Yup...

Looks even more complicated. In fact, it might even be considered kinda silly.

(assumes your base for downloading YouTube videos is at /mnt/Download_Space/YTDL/ and contains subfolders named _Individual_ and _Playlists_)

Save this script as YTall

Then make symbolic links to it.

  • ln -s YTall YTc
  • ln -s YTall YTv
  • ln -s YTall YTl

Call it as YTc for doing whole channels, YTv for individual videos, & YTl for playlists.

#!/bin/bash

BASENAME=$(basename "$0")

echo -e "~~~~~~~ $BASENAME $@ ~~~~~~~ "\\n

case $BASENAME in
  "YTv")
    TYPE="VideoHash"
    DESC="$TYPE = The name YouTube has given to the individual video"
    DESC+="\n\\t\\t (This is gonna take some work to explain...)"
    DESC+="\n\\t\\t You can specify multiple videos"
  ;;
  "YTc")
    TYPE="ChannelName"
    DESC="$TYPE = The name of the channel \(as defined by YouTube\)"
    DESC+="\n\\t\\t You can specify multiple channels"
  ;;
  "YTl")
    TYPE="ListHash"
    DESC="$TYPE = The name YouTube has given to the playlist"
    DESC+="\n\\t\\t (This is gonna take some work to explain...)"
    DESC+="\n\\t\\t You can specify multiple lists"
  ;;
  *)
    TYPE="poop"
    DESC="$TYPE = Some crap"
  ;;
esac

if [ $# -eq 0 ] || [ $1 = "-u" ] || [ $1 = "-?" ]; then
  echo -e USAGE: $(basename "$0") \[...option\(s\)...\] $TYPE $TYPE ...
  echo
  echo -e OPTIONS:
  echo -e \\t -BOB = Grant Style Folder Structure
  echo -e \\t -a = Download audio only \(into MP3 files\)
  echo
  echo -e \\t -s = simulate this run
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.
  echo -e \\t -r RATE = Limit bandwidth
  echo -e \\t\\t Maximum download rate in bytes per second,
  echo -e \\t\\t\\t e.g. 50K or 4.2M
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)
  echo -e \\t\\t \(will result in a random pause between MIN \& MAX seconds long\)
  echo -e \\t -e DATE = Earliest video upload date to grab.
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)
  echo -e \\t $DESC
  echo
  echo -e The following \"ERROR\"s will also appear in 00000000-ERRORS
  echo -e \(Unfortunately, without indications of which files caused them...\)
  echo
  echo -e \"ERROR: unable to download video data: HTTP Error 403: Forbidden\"
  echo -e \\t Means you may need to supply cookies.
  echo -e \\t Often caused by things like age restrictions.
  echo -e \\t May also be caused by YouTube noticing you\'ve been downloading a bunch...
case $BASENAME in
  "YTc")
    echo
    echo -e \"ERROR: \[youtube\] oizvS01ovH0: Video unavailable\"
    echo -e \\t Most likely caused by a typo in the VideoHash
  ;;
  "YTv")
    echo
    echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\"
    echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\"
    echo -e  \"ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\"
    echo -e \\t Is simply indicating that the channel doesn\'t have that type of content.
    echo -e \\t \(All 3 means the channel doesn\'t actually have any content... :P \)
  ;;
  "YTl")
    echo
    echo -e \"mv: cannot stat \'*\': No such file or directory\"
    echo -e \\t Don\'t panic. This one\'s just a bit of residue from the playlist folder cleanup
  ;;
esac
echo

  exit
fi

  BASEdest=/mnt/Download_Space/YTDL/
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt

  SIMULATE=""
  WITHcookies=""
  LIMITrate=""
  PAUSEbetween=""
  TIMEspan=""
  BOBstyle=""
  AUDIOonly=""
  FILETYPE="-t mp4"

while (( "$#" ));
do
  case $1 in
    "-c")
      echo Using Cookies: $COOKIEfile
      WITHcookies="--cookies "$COOKIEfile
      shift
    ;;

    "-s")
      echo Simulating
      SIMULATE="-s"
      shift
    ;;

    "-r")
      LIMITrate="-r $2"
      echo Rate Limiting $2
      shift 2
    ;;

    "-p")
      PAUSEbetween="--sleep-interval $2 --max-sleep-interval $3"
      echo Random pause between $2 \& $3 seconds
      shift 3
    ;;

    "-e")
      TIMEspan="--dateafter $2"
      echo Time Span $2 to current
      shift 2
    ;;

    "-BOB")
      BOBstyle="True"
      echo Using Grant Style Folder Structure
      shift
    ;;

    "-a")
      AUDIOonly="--extract-audio --audio-format mp3 --audio-quality 0"
      FILETYPE="-t mp3"
      echo Extracting audio only
      shift
    ;;

    *)
      case $BASENAME in
        "YTv") # Video
          echo Working on video: $1
          echo ========================================
          WeirdID=$1
          URL=https://www.youtube.com/watch\?v=$1
          TYPES=""
          DEST="$BASEdest""_Individual_/"
          FORMAT="%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s"
        ;;

        "YTc") # Channel
          echo Working on Channel: $1
          echo ========================================
          WeirdID=$1
          URL=https://www.youtube.com/\@$1
          TYPES="videos shorts streams"
#          TYPES="videos shorts streams playlists podcasts courses"
          DEST="$BASEdest""$1"
          FORMAT="%(upload_date)s - %(title)s.%(ext)s"
        ;;

        "YTl") # Playlist
          echo Working on playlist: $1
          echo ========================================
          WeirdID=$1
          URL=https://www.youtube.com/playlist\?list=$1
          TYPES=""
          DEST="$BASEdest""_Playlists_/"
          FORMAT="%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s"
        ;;
      esac

      ERRfile=$DEST/00000000-ERRORS
      ARCHfile=$DEST/11111111-ARCHIVE

      OPTIONS="$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween $AUDIOonly"
      OPTIONS+=" --no-overwrites --write-description $FILETYPE"

      echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
      echo $URL
      echo $WeirdID
      echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"


      if wget --spider --quiet $URL > /dev/null 2>&1; then
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn't exist when asking about videos...
        # Then it gives an error while attempting the download.
        # Not fatal, just annoying...

        echo -en "(storing in $DEST"

        case $BASENAME in
          "YTv")
            echo ")"
            echo VID $WeirdID >> $ARCHfile
            cd $DEST
            pwd
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o "$FORMAT" $URL 2> >(/usr/bin/tee -a $ERRfile)
            rm -f *.part
          ;;
          "YTl")
            echo "$WeirdID)"
            echo LIST $WeirdID >> $ARCHfile
            cd $DEST
            pwd
            if [ -d $DEST/$WeirdID ]; then
              echo $DEST exists
            else
              echo no $DEST$WeirdID... Building it...
              mkdir $DEST$WeirdID
            fi
            cd $WeirdID
            pwd
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o "$FORMAT" $URL 2> >(/usr/bin/tee -a $ERRfile)
            rm -f *.part

            NAME=`find . -maxdepth 1 -regextype posix-extended -regex './0+_.*' -type f   `

            Listname=`echo ${NAME::-12} | cut -d'@' -f 2`

            if [ -d ../"$Listname" ]; then
              echo "$Listname" already exists
            else
              mkdir ../"$Listname"
            fi

            mv "$NAME" ../"$Listname/000 $Listname.description"
            mv * ../"$Listname"
            cd ..
            rmdir $WeirdID
          ;;
          "YTc")
            echo ")"
            if [ -d $DEST ]; then
              echo $DEST exists
            else
              echo no $DEST... Building it...
              mkdir $DEST
              if [ -z $BOBstyle ]; then
                for ACK in $TYPES
                  do
                    mkdir $DEST/$ACK
                  done
              fi
            fi

            cd $DEST
            pwd

            if [ -z $BOBstyle ]; then
              echo -e "(using subfolders...)"
            else
              echo -e "(using Grant format...)"
            fi
            echo

            for ACK in $TYPES
              do
                echo ">>>>>>>> " $URL/$ACK
                if [ -z $BOBstyle ]; then
                  cd $ACK
                  echo CHAN $WeirdID $ACK >> $ARCHfile
                fi

                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o "$FORMAT" $URL/$ACK 2> >(/usr/bin/tee -a $ERRfile)

                # Clear out .part files
                rm -f *.part

                if [ -z $BOBstyle ]; then
                  cd ..
                fi
              done
          ;;
        esac
      else
        echo YouTube says this channel does not exist.
      fi   
      shift
    ;;

  esac
done

Even more options?

WIP

Errors noted, but not researched

In console output:

  • [download] 57.7% of 15.24MiB at 65.83KiB/s ETA 01:40[download] Got error: ("Connection broken: ConnectionResetError(104, 'Connection reset by peer')", ConnectionResetError(104, 'Connection reset by peer')). Retrying (1/10)...

In 00000000-ERRORS:

  • WARNING: [youtube] ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response')). Retrying (1/3)...