<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.nerdmage.ca/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tinker</id>
	<title>Da Nerd Mage Wiki - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.nerdmage.ca/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tinker"/>
	<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php/Special:Contributions/Tinker"/>
	<updated>2026-05-19T07:04:58Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4151</id>
		<title>CopyPasta</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4151"/>
		<updated>2026-04-12T23:18:13Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* For doing basic setup of an LXC (or pretty much any Linux VM...) (Heck, I run these on physical machines too.): */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= For doing basic setup of an LXC (or pretty much any Linux VM...) (Heck, I run these on physical machines too.): =&lt;br /&gt;
I run this set of commands &amp;#039;&amp;#039;&amp;#039;as root&amp;#039;&amp;#039;&amp;#039; on nearly every new VM or LXC I spin up. That way, I have a consistant environment to work in with all the tools I rely on.&lt;br /&gt;
&lt;br /&gt;
Note: You CAN copyPasta groups of commands all at once. BUT: in this case, everything indented (after &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;) needs to be pasted AFTER that command has run.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install sudo rsync vim curl mosquitto-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install gnupg tmux htop &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional...&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install qemu-guest-agent &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Only on VMs. (Wish it worked for LXCs as well tho...)&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039; sudo&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;ssh-keygen &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional... But rather handy.&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bonus item: if your LXC has NFS enabled (or you&amp;#039;re working on a VM or bare-metal machine) ==&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install nfs-kernel-server&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo vi /etc/fstab&amp;lt;/code&amp;gt;&lt;br /&gt;
** Copy in your default set of NFS mounts&amp;lt;br&amp;gt;(don&amp;#039;t forget to actually create any needed mount points)&amp;lt;br&amp;gt;I tend to mount all of the typical subfolders of my &amp;lt;code&amp;gt;/home/&amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; folder from a network share...&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl daemon-reload&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mount -a&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=New System Cleanup &amp;amp; Prep=&lt;br /&gt;
Freshly installed systems usually have a bunch of stuff installed that you will never use.&lt;br /&gt;
&lt;br /&gt;
For myself, I don&amp;#039;t generally have any interest in the games. I also don&amp;#039;t use some of the Internet apps that seem important to the developers/maintainers.&lt;br /&gt;
&lt;br /&gt;
These instructions are based on running Debian with the Cinnamon Desktop Environment...&lt;br /&gt;
==Remove all the Games==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge gnome-2048 aisleriot atomix gnome-chess five-or-more hitori iagno gnome-klotski lightsoff gnome-mahjongg gnome-mines gnome-nibbles quadrapassel four-in-a-row gnome-robots gnome-sudoku swell-foop tali gnome-taquin gnome-tetravex -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove obsolete and/or silly Internet apps==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge hexchat pidgin transmission-gtk thunderbird -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Some others I don&amp;#039;t use (from LMDE7) ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge hypnotix rhythmbox -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Get rid of Firefox ==&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge firefox*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Simplified installation techniques &amp;amp; instructions =&lt;br /&gt;
Some cross-platform software seems to have Linux installation instructions written by people who have never actually used Linux.&lt;br /&gt;
&lt;br /&gt;
(Or, at least, people who believe in making life difficult...)&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Brave Browser]] (Properly... Not FLATPAK)&lt;br /&gt;
* [[Installing TP-Link Omada SDN Controller on a Debian-based LXC]]&lt;br /&gt;
Also, many installation instructions are long-winded or confusing...&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Docker on a Debian-based system]]&lt;br /&gt;
&lt;br /&gt;
= Building/Installing things from source =&lt;br /&gt;
You may have noticed that the various distro repositories tend to have outdated versions of some (most) packages. While this makes perfect sense, sometimes you want the newest features &amp;amp; fixes. (Or maybe you just want to enable something that the repo managers figured wouldn&amp;#039;t be useful...)&lt;br /&gt;
&lt;br /&gt;
Annoyingly, it is rather common for build instructions to suck really badly.&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Arp-Scan from Source{{!}}Arp-Scan]]&lt;br /&gt;
* [[FreeCAD from Source{{!}}FreeCAD]]&lt;br /&gt;
* [[KiCAD from Source{{!}}KiCAD]]&lt;br /&gt;
* [[Mosquitto from Source{{!}}Mosquitto]]&lt;br /&gt;
&lt;br /&gt;
= Useful console display for Proxmox Virtual Environment =&lt;br /&gt;
I find it nice to have stats &amp;amp; such on the console of a server.  This way I can just look &amp;amp; see what&amp;#039;s happening with the machine.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install tmux htop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /usr/local/bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TMUX-console&amp;lt;/nowiki&amp;gt; -O TMUX-console&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-guestlist&amp;lt;/nowiki&amp;gt; -O TM-guestlist&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-clusterstatus&amp;lt;/nowiki&amp;gt; -O TM-clusterstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-systemstatus&amp;lt;/nowiki&amp;gt; -O TM-systemstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-UPSstatus&amp;lt;/nowiki&amp;gt; -O TM-UPSstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-FixThis&amp;lt;/nowiki&amp;gt; -O TM-FixThis&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-ShowMe&amp;lt;/nowiki&amp;gt; -O TM-ShowMe&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;chmod +x TM*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to edit &amp;#039;&amp;#039;&amp;#039;TM-UPSstatus&amp;#039;&amp;#039;&amp;#039; to match local configurations (i.e. UPS name).&lt;br /&gt;
&lt;br /&gt;
Running &amp;lt;code&amp;gt;TMUX-console&amp;lt;/code&amp;gt; at the console will create a formatted screen of useful system information that you can reach by attaching to the &amp;#039;&amp;#039;&amp;#039;tmux&amp;#039;&amp;#039;&amp;#039; session from a terminal (SSH) session.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4150</id>
		<title>CopyPasta</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4150"/>
		<updated>2026-04-12T20:05:46Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Some others I don&amp;#039;t use (from LMDE7) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= For doing basic setup of an LXC (or pretty much any Linux VM...) (Heck, I run these on physical machines too.): =&lt;br /&gt;
I run this set of commands &amp;#039;&amp;#039;&amp;#039;as root&amp;#039;&amp;#039;&amp;#039; on nearly every new VM or LXC I spin up. That way, I have a consistant environment to work in with all the tools I rely on.&lt;br /&gt;
&lt;br /&gt;
Note: You CAN copyPasta groups of commands all at once. BUT: in this case, everything indented (after &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;) needs to be pasted AFTER that command has run.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install sudo rsync vim curl mosquitto-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install gnupg tmux htop &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional...&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install qemu-guest-agent &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Only on VMs. (Wish it worked for LXCs as well tho...)&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039; sudo&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;ssh-keygen &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional... But rather handy.&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=New System Cleanup &amp;amp; Prep=&lt;br /&gt;
Freshly installed systems usually have a bunch of stuff installed that you will never use.&lt;br /&gt;
&lt;br /&gt;
For myself, I don&amp;#039;t generally have any interest in the games. I also don&amp;#039;t use some of the Internet apps that seem important to the developers/maintainers.&lt;br /&gt;
&lt;br /&gt;
These instructions are based on running Debian with the Cinnamon Desktop Environment...&lt;br /&gt;
==Remove all the Games==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge gnome-2048 aisleriot atomix gnome-chess five-or-more hitori iagno gnome-klotski lightsoff gnome-mahjongg gnome-mines gnome-nibbles quadrapassel four-in-a-row gnome-robots gnome-sudoku swell-foop tali gnome-taquin gnome-tetravex -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove obsolete and/or silly Internet apps==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge hexchat pidgin transmission-gtk thunderbird -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Some others I don&amp;#039;t use (from LMDE7) ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge hypnotix rhythmbox -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Get rid of Firefox ==&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge firefox*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Simplified installation techniques &amp;amp; instructions =&lt;br /&gt;
Some cross-platform software seems to have Linux installation instructions written by people who have never actually used Linux.&lt;br /&gt;
&lt;br /&gt;
(Or, at least, people who believe in making life difficult...)&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Brave Browser]] (Properly... Not FLATPAK)&lt;br /&gt;
* [[Installing TP-Link Omada SDN Controller on a Debian-based LXC]]&lt;br /&gt;
Also, many installation instructions are long-winded or confusing...&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Docker on a Debian-based system]]&lt;br /&gt;
&lt;br /&gt;
= Building/Installing things from source =&lt;br /&gt;
You may have noticed that the various distro repositories tend to have outdated versions of some (most) packages. While this makes perfect sense, sometimes you want the newest features &amp;amp; fixes. (Or maybe you just want to enable something that the repo managers figured wouldn&amp;#039;t be useful...)&lt;br /&gt;
&lt;br /&gt;
Annoyingly, it is rather common for build instructions to suck really badly.&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Arp-Scan from Source{{!}}Arp-Scan]]&lt;br /&gt;
* [[FreeCAD from Source{{!}}FreeCAD]]&lt;br /&gt;
* [[KiCAD from Source{{!}}KiCAD]]&lt;br /&gt;
* [[Mosquitto from Source{{!}}Mosquitto]]&lt;br /&gt;
&lt;br /&gt;
= Useful console display for Proxmox Virtual Environment =&lt;br /&gt;
I find it nice to have stats &amp;amp; such on the console of a server.  This way I can just look &amp;amp; see what&amp;#039;s happening with the machine.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install tmux htop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /usr/local/bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TMUX-console&amp;lt;/nowiki&amp;gt; -O TMUX-console&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-guestlist&amp;lt;/nowiki&amp;gt; -O TM-guestlist&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-clusterstatus&amp;lt;/nowiki&amp;gt; -O TM-clusterstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-systemstatus&amp;lt;/nowiki&amp;gt; -O TM-systemstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-UPSstatus&amp;lt;/nowiki&amp;gt; -O TM-UPSstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-FixThis&amp;lt;/nowiki&amp;gt; -O TM-FixThis&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-ShowMe&amp;lt;/nowiki&amp;gt; -O TM-ShowMe&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;chmod +x TM*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to edit &amp;#039;&amp;#039;&amp;#039;TM-UPSstatus&amp;#039;&amp;#039;&amp;#039; to match local configurations (i.e. UPS name).&lt;br /&gt;
&lt;br /&gt;
Running &amp;lt;code&amp;gt;TMUX-console&amp;lt;/code&amp;gt; at the console will create a formatted screen of useful system information that you can reach by attaching to the &amp;#039;&amp;#039;&amp;#039;tmux&amp;#039;&amp;#039;&amp;#039; session from a terminal (SSH) session.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4149</id>
		<title>CopyPasta</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4149"/>
		<updated>2026-04-12T20:01:19Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Some others I don&amp;#039;t use (from LMDE7) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= For doing basic setup of an LXC (or pretty much any Linux VM...) (Heck, I run these on physical machines too.): =&lt;br /&gt;
I run this set of commands &amp;#039;&amp;#039;&amp;#039;as root&amp;#039;&amp;#039;&amp;#039; on nearly every new VM or LXC I spin up. That way, I have a consistant environment to work in with all the tools I rely on.&lt;br /&gt;
&lt;br /&gt;
Note: You CAN copyPasta groups of commands all at once. BUT: in this case, everything indented (after &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;) needs to be pasted AFTER that command has run.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install sudo rsync vim curl mosquitto-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install gnupg tmux htop &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional...&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install qemu-guest-agent &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Only on VMs. (Wish it worked for LXCs as well tho...)&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039; sudo&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;ssh-keygen &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional... But rather handy.&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=New System Cleanup &amp;amp; Prep=&lt;br /&gt;
Freshly installed systems usually have a bunch of stuff installed that you will never use.&lt;br /&gt;
&lt;br /&gt;
For myself, I don&amp;#039;t generally have any interest in the games. I also don&amp;#039;t use some of the Internet apps that seem important to the developers/maintainers.&lt;br /&gt;
&lt;br /&gt;
These instructions are based on running Debian with the Cinnamon Desktop Environment...&lt;br /&gt;
==Remove all the Games==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge gnome-2048 aisleriot atomix gnome-chess five-or-more hitori iagno gnome-klotski lightsoff gnome-mahjongg gnome-mines gnome-nibbles quadrapassel four-in-a-row gnome-robots gnome-sudoku swell-foop tali gnome-taquin gnome-tetravex -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove obsolete and/or silly Internet apps==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge hexchat pidgin transmission-gtk thunderbird -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Some others I don&amp;#039;t use (from LMDE7)==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge matrix hypnotix rhythmbox -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Get rid of Firefox ==&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge firefox*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Simplified installation techniques &amp;amp; instructions =&lt;br /&gt;
Some cross-platform software seems to have Linux installation instructions written by people who have never actually used Linux.&lt;br /&gt;
&lt;br /&gt;
(Or, at least, people who believe in making life difficult...)&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Brave Browser]] (Properly... Not FLATPAK)&lt;br /&gt;
* [[Installing TP-Link Omada SDN Controller on a Debian-based LXC]]&lt;br /&gt;
Also, many installation instructions are long-winded or confusing...&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Docker on a Debian-based system]]&lt;br /&gt;
&lt;br /&gt;
= Building/Installing things from source =&lt;br /&gt;
You may have noticed that the various distro repositories tend to have outdated versions of some (most) packages. While this makes perfect sense, sometimes you want the newest features &amp;amp; fixes. (Or maybe you just want to enable something that the repo managers figured wouldn&amp;#039;t be useful...)&lt;br /&gt;
&lt;br /&gt;
Annoyingly, it is rather common for build instructions to suck really badly.&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Arp-Scan from Source{{!}}Arp-Scan]]&lt;br /&gt;
* [[FreeCAD from Source{{!}}FreeCAD]]&lt;br /&gt;
* [[KiCAD from Source{{!}}KiCAD]]&lt;br /&gt;
* [[Mosquitto from Source{{!}}Mosquitto]]&lt;br /&gt;
&lt;br /&gt;
= Useful console display for Proxmox Virtual Environment =&lt;br /&gt;
I find it nice to have stats &amp;amp; such on the console of a server.  This way I can just look &amp;amp; see what&amp;#039;s happening with the machine.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install tmux htop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /usr/local/bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TMUX-console&amp;lt;/nowiki&amp;gt; -O TMUX-console&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-guestlist&amp;lt;/nowiki&amp;gt; -O TM-guestlist&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-clusterstatus&amp;lt;/nowiki&amp;gt; -O TM-clusterstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-systemstatus&amp;lt;/nowiki&amp;gt; -O TM-systemstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-UPSstatus&amp;lt;/nowiki&amp;gt; -O TM-UPSstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-FixThis&amp;lt;/nowiki&amp;gt; -O TM-FixThis&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-ShowMe&amp;lt;/nowiki&amp;gt; -O TM-ShowMe&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;chmod +x TM*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to edit &amp;#039;&amp;#039;&amp;#039;TM-UPSstatus&amp;#039;&amp;#039;&amp;#039; to match local configurations (i.e. UPS name).&lt;br /&gt;
&lt;br /&gt;
Running &amp;lt;code&amp;gt;TMUX-console&amp;lt;/code&amp;gt; at the console will create a formatted screen of useful system information that you can reach by attaching to the &amp;#039;&amp;#039;&amp;#039;tmux&amp;#039;&amp;#039;&amp;#039; session from a terminal (SSH) session.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4148</id>
		<title>CopyPasta</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4148"/>
		<updated>2026-04-12T20:01:00Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Remove obsolete and/or silly Internet apps */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= For doing basic setup of an LXC (or pretty much any Linux VM...) (Heck, I run these on physical machines too.): =&lt;br /&gt;
I run this set of commands &amp;#039;&amp;#039;&amp;#039;as root&amp;#039;&amp;#039;&amp;#039; on nearly every new VM or LXC I spin up. That way, I have a consistant environment to work in with all the tools I rely on.&lt;br /&gt;
&lt;br /&gt;
Note: You CAN copyPasta groups of commands all at once. BUT: in this case, everything indented (after &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;) needs to be pasted AFTER that command has run.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install sudo rsync vim curl mosquitto-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install gnupg tmux htop &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional...&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install qemu-guest-agent &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Only on VMs. (Wish it worked for LXCs as well tho...)&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039; sudo&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;ssh-keygen &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional... But rather handy.&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=New System Cleanup &amp;amp; Prep=&lt;br /&gt;
Freshly installed systems usually have a bunch of stuff installed that you will never use.&lt;br /&gt;
&lt;br /&gt;
For myself, I don&amp;#039;t generally have any interest in the games. I also don&amp;#039;t use some of the Internet apps that seem important to the developers/maintainers.&lt;br /&gt;
&lt;br /&gt;
These instructions are based on running Debian with the Cinnamon Desktop Environment...&lt;br /&gt;
==Remove all the Games==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge gnome-2048 aisleriot atomix gnome-chess five-or-more hitori iagno gnome-klotski lightsoff gnome-mahjongg gnome-mines gnome-nibbles quadrapassel four-in-a-row gnome-robots gnome-sudoku swell-foop tali gnome-taquin gnome-tetravex -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove obsolete and/or silly Internet apps==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge hexchat pidgin transmission-gtk thunderbird -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Some others I don&amp;#039;t use (from LMDE7)==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge matrix hypnotix rhythmbox -y&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Get rid of Firefox ==&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge firefox*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Simplified installation techniques &amp;amp; instructions =&lt;br /&gt;
Some cross-platform software seems to have Linux installation instructions written by people who have never actually used Linux.&lt;br /&gt;
&lt;br /&gt;
(Or, at least, people who believe in making life difficult...)&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Brave Browser]] (Properly... Not FLATPAK)&lt;br /&gt;
* [[Installing TP-Link Omada SDN Controller on a Debian-based LXC]]&lt;br /&gt;
Also, many installation instructions are long-winded or confusing...&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Docker on a Debian-based system]]&lt;br /&gt;
&lt;br /&gt;
= Building/Installing things from source =&lt;br /&gt;
You may have noticed that the various distro repositories tend to have outdated versions of some (most) packages. While this makes perfect sense, sometimes you want the newest features &amp;amp; fixes. (Or maybe you just want to enable something that the repo managers figured wouldn&amp;#039;t be useful...)&lt;br /&gt;
&lt;br /&gt;
Annoyingly, it is rather common for build instructions to suck really badly.&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Arp-Scan from Source{{!}}Arp-Scan]]&lt;br /&gt;
* [[FreeCAD from Source{{!}}FreeCAD]]&lt;br /&gt;
* [[KiCAD from Source{{!}}KiCAD]]&lt;br /&gt;
* [[Mosquitto from Source{{!}}Mosquitto]]&lt;br /&gt;
&lt;br /&gt;
= Useful console display for Proxmox Virtual Environment =&lt;br /&gt;
I find it nice to have stats &amp;amp; such on the console of a server.  This way I can just look &amp;amp; see what&amp;#039;s happening with the machine.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install tmux htop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /usr/local/bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TMUX-console&amp;lt;/nowiki&amp;gt; -O TMUX-console&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-guestlist&amp;lt;/nowiki&amp;gt; -O TM-guestlist&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-clusterstatus&amp;lt;/nowiki&amp;gt; -O TM-clusterstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-systemstatus&amp;lt;/nowiki&amp;gt; -O TM-systemstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-UPSstatus&amp;lt;/nowiki&amp;gt; -O TM-UPSstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-FixThis&amp;lt;/nowiki&amp;gt; -O TM-FixThis&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-ShowMe&amp;lt;/nowiki&amp;gt; -O TM-ShowMe&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;chmod +x TM*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to edit &amp;#039;&amp;#039;&amp;#039;TM-UPSstatus&amp;#039;&amp;#039;&amp;#039; to match local configurations (i.e. UPS name).&lt;br /&gt;
&lt;br /&gt;
Running &amp;lt;code&amp;gt;TMUX-console&amp;lt;/code&amp;gt; at the console will create a formatted screen of useful system information that you can reach by attaching to the &amp;#039;&amp;#039;&amp;#039;tmux&amp;#039;&amp;#039;&amp;#039; session from a terminal (SSH) session.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4147</id>
		<title>PVE Tips</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4147"/>
		<updated>2026-03-29T19:40:09Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Additional things to add to PVE */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= xterm.js in place of noVNC =&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
An issue with noVNC...&lt;br /&gt;
&lt;br /&gt;
It kinda sucks for CLI-only VMs. It doesn&amp;#039;t allow for copy-pasta.&lt;br /&gt;
&lt;br /&gt;
Solution, [https://silicon.blog/2023/01/12/how-to-enable-copy-and-paste-function-on-your-proxmox-web-console-without-install-additional-software-in-your-vm/ configure the VM to use xterm.js] instead.&lt;br /&gt;
&lt;br /&gt;
The grub edits in that article don&amp;#039;t seem to work properly tho...&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;quiet&amp;quot;&lt;br /&gt;
GRUB_CMDLINE_LINUX=&amp;quot;console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0&amp;quot;&lt;br /&gt;
GRUB_TERMINAL=&amp;quot;console serial&amp;quot;&lt;br /&gt;
GRUB_SERIAL_COMMAND=&amp;quot;serial --speed=115200&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(initially from [https://www.reddit.com/r/Proxmox/comments/15dhkh7/newbie_issue_unable_to_enable_xtermjs_in_debian/ here])&lt;br /&gt;
&lt;br /&gt;
For some reason, Proxmox leaves noVNC as the console in the UI window &amp;amp; it does weird stuff to the console window when you open it. MRIN...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/support-for-xterm-js-console-by-default-for-specific-vm.114734/ FFS...]&lt;br /&gt;
&lt;br /&gt;
To open the console of a VM set up this way, either click the &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; button or right-click the VM in the left pane &amp;amp; select &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
= Manually installing REAL certs =&lt;br /&gt;
&lt;br /&gt;
I keep copies of my certs on a local [[Building Web Servers{{!}}webserver]] that acts as a [[Proxy Server Notes{{!}}proxy]] to feed HTTPS connections to various local servers. This makes it fairly trivial to pull certs to various machines that need them.&amp;amp;nbsp; Also, I&amp;#039;m using wildcard certs, which simplifies life.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039; Log into the servers shell as root. (either through the Web UI or SSH)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039; Follow along with this list of commands (adjusting appropriately...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /etc/pve/nodes/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd &amp;#039;&amp;#039;&amp;#039;NODENAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.key pveproxy-ssl.key.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.pem pveproxy-ssl.pem.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/fullchain_&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.crt pveproxy-ssl.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.key pveproxy-ssl.key&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;systemctl restart pveproxy&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: &amp;quot;/etc/apache2/certs&amp;quot; must be readable by &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; must also have SSH access to &amp;#039;&amp;#039;&amp;#039;WEBSERVER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039; Enjoy browsing to the Web UI of your server without being bitched at by your browser.&lt;br /&gt;
&lt;br /&gt;
This will also work just fine with machine-specific certs.&amp;amp;nbsp; You&amp;#039;ll need to adjust the filenames of your &amp;#039;&amp;#039;&amp;#039;crt&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;key&amp;#039;&amp;#039;&amp;#039; files.&lt;br /&gt;
&lt;br /&gt;
(these instructions are currently based on a non-clustered server...)&lt;br /&gt;
&lt;br /&gt;
= Convert a physical computer to a proxmox VM =&lt;br /&gt;
&lt;br /&gt;
* [https://pve.proxmox.com/wiki/Advanced_Migration_Techniques_to_Proxmox_VE From the Proxmox documentation]&lt;br /&gt;
* [https://forum.proxmox.com/threads/convert-physical-computer-to-proxmox.124490/ From the Proxmox forums]&lt;br /&gt;
&lt;br /&gt;
= Want a GUI on the console screen? =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt install task-cinnamon-desktop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Take this further... ==&lt;br /&gt;
* Maybe add in Synergy&lt;br /&gt;
* [[CopyPasta#New System_Cleanup_&amp;amp;_Prep{{!}}Cleanup the bloat]]?&lt;br /&gt;
* Set up the screensaver to work as a clock (I do this on my crash-test server...)&lt;br /&gt;
&lt;br /&gt;
= Remove Proxmox Subscription Notice (Tested to 8.4) =&lt;br /&gt;
&lt;br /&gt;
Seems to work on 9.1.6 also...&lt;br /&gt;
&lt;br /&gt;
[https://mclarendatasystems.com/remove-proxmox51-subscription-notice/ Source]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sed -Ezi.bak &amp;quot;s/(function ?\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g&amp;quot; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;amp;&amp;amp; systemctl restart pveproxy.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional things to add to PVE =&lt;br /&gt;
* [[TailScale{{!}}TailScale]]&lt;br /&gt;
* Automated Cert updates&lt;br /&gt;
* NFS mount utilities &amp;amp; stuff...&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4146</id>
		<title>PVE Tips</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4146"/>
		<updated>2026-03-29T17:02:06Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Additional things to add to PVE */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= xterm.js in place of noVNC =&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
An issue with noVNC...&lt;br /&gt;
&lt;br /&gt;
It kinda sucks for CLI-only VMs. It doesn&amp;#039;t allow for copy-pasta.&lt;br /&gt;
&lt;br /&gt;
Solution, [https://silicon.blog/2023/01/12/how-to-enable-copy-and-paste-function-on-your-proxmox-web-console-without-install-additional-software-in-your-vm/ configure the VM to use xterm.js] instead.&lt;br /&gt;
&lt;br /&gt;
The grub edits in that article don&amp;#039;t seem to work properly tho...&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;quiet&amp;quot;&lt;br /&gt;
GRUB_CMDLINE_LINUX=&amp;quot;console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0&amp;quot;&lt;br /&gt;
GRUB_TERMINAL=&amp;quot;console serial&amp;quot;&lt;br /&gt;
GRUB_SERIAL_COMMAND=&amp;quot;serial --speed=115200&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(initially from [https://www.reddit.com/r/Proxmox/comments/15dhkh7/newbie_issue_unable_to_enable_xtermjs_in_debian/ here])&lt;br /&gt;
&lt;br /&gt;
For some reason, Proxmox leaves noVNC as the console in the UI window &amp;amp; it does weird stuff to the console window when you open it. MRIN...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/support-for-xterm-js-console-by-default-for-specific-vm.114734/ FFS...]&lt;br /&gt;
&lt;br /&gt;
To open the console of a VM set up this way, either click the &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; button or right-click the VM in the left pane &amp;amp; select &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
= Manually installing REAL certs =&lt;br /&gt;
&lt;br /&gt;
I keep copies of my certs on a local [[Building Web Servers{{!}}webserver]] that acts as a [[Proxy Server Notes{{!}}proxy]] to feed HTTPS connections to various local servers. This makes it fairly trivial to pull certs to various machines that need them.&amp;amp;nbsp; Also, I&amp;#039;m using wildcard certs, which simplifies life.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039; Log into the servers shell as root. (either through the Web UI or SSH)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039; Follow along with this list of commands (adjusting appropriately...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /etc/pve/nodes/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd &amp;#039;&amp;#039;&amp;#039;NODENAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.key pveproxy-ssl.key.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.pem pveproxy-ssl.pem.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/fullchain_&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.crt pveproxy-ssl.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.key pveproxy-ssl.key&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;systemctl restart pveproxy&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: &amp;quot;/etc/apache2/certs&amp;quot; must be readable by &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; must also have SSH access to &amp;#039;&amp;#039;&amp;#039;WEBSERVER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039; Enjoy browsing to the Web UI of your server without being bitched at by your browser.&lt;br /&gt;
&lt;br /&gt;
This will also work just fine with machine-specific certs.&amp;amp;nbsp; You&amp;#039;ll need to adjust the filenames of your &amp;#039;&amp;#039;&amp;#039;crt&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;key&amp;#039;&amp;#039;&amp;#039; files.&lt;br /&gt;
&lt;br /&gt;
(these instructions are currently based on a non-clustered server...)&lt;br /&gt;
&lt;br /&gt;
= Convert a physical computer to a proxmox VM =&lt;br /&gt;
&lt;br /&gt;
* [https://pve.proxmox.com/wiki/Advanced_Migration_Techniques_to_Proxmox_VE From the Proxmox documentation]&lt;br /&gt;
* [https://forum.proxmox.com/threads/convert-physical-computer-to-proxmox.124490/ From the Proxmox forums]&lt;br /&gt;
&lt;br /&gt;
= Want a GUI on the console screen? =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt install task-cinnamon-desktop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Take this further... ==&lt;br /&gt;
* Maybe add in Synergy&lt;br /&gt;
* [[CopyPasta#New System_Cleanup_&amp;amp;_Prep{{!}}Cleanup the bloat]]?&lt;br /&gt;
* Set up the screensaver to work as a clock (I do this on my crash-test server...)&lt;br /&gt;
&lt;br /&gt;
= Remove Proxmox Subscription Notice (Tested to 8.4) =&lt;br /&gt;
&lt;br /&gt;
Seems to work on 9.1.6 also...&lt;br /&gt;
&lt;br /&gt;
[https://mclarendatasystems.com/remove-proxmox51-subscription-notice/ Source]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sed -Ezi.bak &amp;quot;s/(function ?\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g&amp;quot; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;amp;&amp;amp; systemctl restart pveproxy.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional things to add to PVE =&lt;br /&gt;
* [[TailScale{{!}}TailScale]]&lt;br /&gt;
* Automated Cert updates&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4145</id>
		<title>PVE Tips</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4145"/>
		<updated>2026-03-29T16:27:07Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Remove Proxmox Subscription Notice (Tested to 8.4) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= xterm.js in place of noVNC =&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
An issue with noVNC...&lt;br /&gt;
&lt;br /&gt;
It kinda sucks for CLI-only VMs. It doesn&amp;#039;t allow for copy-pasta.&lt;br /&gt;
&lt;br /&gt;
Solution, [https://silicon.blog/2023/01/12/how-to-enable-copy-and-paste-function-on-your-proxmox-web-console-without-install-additional-software-in-your-vm/ configure the VM to use xterm.js] instead.&lt;br /&gt;
&lt;br /&gt;
The grub edits in that article don&amp;#039;t seem to work properly tho...&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;quiet&amp;quot;&lt;br /&gt;
GRUB_CMDLINE_LINUX=&amp;quot;console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0&amp;quot;&lt;br /&gt;
GRUB_TERMINAL=&amp;quot;console serial&amp;quot;&lt;br /&gt;
GRUB_SERIAL_COMMAND=&amp;quot;serial --speed=115200&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(initially from [https://www.reddit.com/r/Proxmox/comments/15dhkh7/newbie_issue_unable_to_enable_xtermjs_in_debian/ here])&lt;br /&gt;
&lt;br /&gt;
For some reason, Proxmox leaves noVNC as the console in the UI window &amp;amp; it does weird stuff to the console window when you open it. MRIN...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/support-for-xterm-js-console-by-default-for-specific-vm.114734/ FFS...]&lt;br /&gt;
&lt;br /&gt;
To open the console of a VM set up this way, either click the &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; button or right-click the VM in the left pane &amp;amp; select &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
= Manually installing REAL certs =&lt;br /&gt;
&lt;br /&gt;
I keep copies of my certs on a local [[Building Web Servers{{!}}webserver]] that acts as a [[Proxy Server Notes{{!}}proxy]] to feed HTTPS connections to various local servers. This makes it fairly trivial to pull certs to various machines that need them.&amp;amp;nbsp; Also, I&amp;#039;m using wildcard certs, which simplifies life.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039; Log into the servers shell as root. (either through the Web UI or SSH)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039; Follow along with this list of commands (adjusting appropriately...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /etc/pve/nodes/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd &amp;#039;&amp;#039;&amp;#039;NODENAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.key pveproxy-ssl.key.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.pem pveproxy-ssl.pem.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/fullchain_&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.crt pveproxy-ssl.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.key pveproxy-ssl.key&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;systemctl restart pveproxy&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: &amp;quot;/etc/apache2/certs&amp;quot; must be readable by &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; must also have SSH access to &amp;#039;&amp;#039;&amp;#039;WEBSERVER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039; Enjoy browsing to the Web UI of your server without being bitched at by your browser.&lt;br /&gt;
&lt;br /&gt;
This will also work just fine with machine-specific certs.&amp;amp;nbsp; You&amp;#039;ll need to adjust the filenames of your &amp;#039;&amp;#039;&amp;#039;crt&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;key&amp;#039;&amp;#039;&amp;#039; files.&lt;br /&gt;
&lt;br /&gt;
(these instructions are currently based on a non-clustered server...)&lt;br /&gt;
&lt;br /&gt;
= Convert a physical computer to a proxmox VM =&lt;br /&gt;
&lt;br /&gt;
* [https://pve.proxmox.com/wiki/Advanced_Migration_Techniques_to_Proxmox_VE From the Proxmox documentation]&lt;br /&gt;
* [https://forum.proxmox.com/threads/convert-physical-computer-to-proxmox.124490/ From the Proxmox forums]&lt;br /&gt;
&lt;br /&gt;
= Want a GUI on the console screen? =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt install task-cinnamon-desktop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Take this further... ==&lt;br /&gt;
* Maybe add in Synergy&lt;br /&gt;
* [[CopyPasta#New System_Cleanup_&amp;amp;_Prep{{!}}Cleanup the bloat]]?&lt;br /&gt;
* Set up the screensaver to work as a clock (I do this on my crash-test server...)&lt;br /&gt;
&lt;br /&gt;
= Remove Proxmox Subscription Notice (Tested to 8.4) =&lt;br /&gt;
&lt;br /&gt;
Seems to work on 9.1.6 also...&lt;br /&gt;
&lt;br /&gt;
[https://mclarendatasystems.com/remove-proxmox51-subscription-notice/ Source]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sed -Ezi.bak &amp;quot;s/(function ?\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g&amp;quot; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;amp;&amp;amp; systemctl restart pveproxy.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional things to add to PVE =&lt;br /&gt;
* tailscale&lt;br /&gt;
* Automated Cert updates&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4144</id>
		<title>PVE Tips</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4144"/>
		<updated>2026-03-29T15:46:01Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Take this further... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= xterm.js in place of noVNC =&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
An issue with noVNC...&lt;br /&gt;
&lt;br /&gt;
It kinda sucks for CLI-only VMs. It doesn&amp;#039;t allow for copy-pasta.&lt;br /&gt;
&lt;br /&gt;
Solution, [https://silicon.blog/2023/01/12/how-to-enable-copy-and-paste-function-on-your-proxmox-web-console-without-install-additional-software-in-your-vm/ configure the VM to use xterm.js] instead.&lt;br /&gt;
&lt;br /&gt;
The grub edits in that article don&amp;#039;t seem to work properly tho...&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;quiet&amp;quot;&lt;br /&gt;
GRUB_CMDLINE_LINUX=&amp;quot;console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0&amp;quot;&lt;br /&gt;
GRUB_TERMINAL=&amp;quot;console serial&amp;quot;&lt;br /&gt;
GRUB_SERIAL_COMMAND=&amp;quot;serial --speed=115200&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(initially from [https://www.reddit.com/r/Proxmox/comments/15dhkh7/newbie_issue_unable_to_enable_xtermjs_in_debian/ here])&lt;br /&gt;
&lt;br /&gt;
For some reason, Proxmox leaves noVNC as the console in the UI window &amp;amp; it does weird stuff to the console window when you open it. MRIN...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/support-for-xterm-js-console-by-default-for-specific-vm.114734/ FFS...]&lt;br /&gt;
&lt;br /&gt;
To open the console of a VM set up this way, either click the &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; button or right-click the VM in the left pane &amp;amp; select &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
= Manually installing REAL certs =&lt;br /&gt;
&lt;br /&gt;
I keep copies of my certs on a local [[Building Web Servers{{!}}webserver]] that acts as a [[Proxy Server Notes{{!}}proxy]] to feed HTTPS connections to various local servers. This makes it fairly trivial to pull certs to various machines that need them.&amp;amp;nbsp; Also, I&amp;#039;m using wildcard certs, which simplifies life.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039; Log into the servers shell as root. (either through the Web UI or SSH)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039; Follow along with this list of commands (adjusting appropriately...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /etc/pve/nodes/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd &amp;#039;&amp;#039;&amp;#039;NODENAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.key pveproxy-ssl.key.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.pem pveproxy-ssl.pem.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/fullchain_&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.crt pveproxy-ssl.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.key pveproxy-ssl.key&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;systemctl restart pveproxy&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: &amp;quot;/etc/apache2/certs&amp;quot; must be readable by &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; must also have SSH access to &amp;#039;&amp;#039;&amp;#039;WEBSERVER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039; Enjoy browsing to the Web UI of your server without being bitched at by your browser.&lt;br /&gt;
&lt;br /&gt;
This will also work just fine with machine-specific certs.&amp;amp;nbsp; You&amp;#039;ll need to adjust the filenames of your &amp;#039;&amp;#039;&amp;#039;crt&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;key&amp;#039;&amp;#039;&amp;#039; files.&lt;br /&gt;
&lt;br /&gt;
(these instructions are currently based on a non-clustered server...)&lt;br /&gt;
&lt;br /&gt;
= Convert a physical computer to a proxmox VM =&lt;br /&gt;
&lt;br /&gt;
* [https://pve.proxmox.com/wiki/Advanced_Migration_Techniques_to_Proxmox_VE From the Proxmox documentation]&lt;br /&gt;
* [https://forum.proxmox.com/threads/convert-physical-computer-to-proxmox.124490/ From the Proxmox forums]&lt;br /&gt;
&lt;br /&gt;
= Want a GUI on the console screen? =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt install task-cinnamon-desktop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Take this further... ==&lt;br /&gt;
* Maybe add in Synergy&lt;br /&gt;
* [[CopyPasta#New System_Cleanup_&amp;amp;_Prep{{!}}Cleanup the bloat]]?&lt;br /&gt;
* Set up the screensaver to work as a clock (I do this on my crash-test server...)&lt;br /&gt;
&lt;br /&gt;
= Remove Proxmox Subscription Notice (Tested to 8.4) =&lt;br /&gt;
&lt;br /&gt;
Seems to work on 9.1.6 also...&lt;br /&gt;
&lt;br /&gt;
[https://mclarendatasystems.com/remove-proxmox51-subscription-notice/ Source]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sed -Ezi.bak &amp;quot;s/(function ?\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g&amp;quot; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;amp;&amp;amp; systemctl restart pveproxy.service&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4143</id>
		<title>PVE Tips</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4143"/>
		<updated>2026-03-29T15:43:56Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Remove Proxmox Subscription Notice (Tested to 8.4) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= xterm.js in place of noVNC =&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
An issue with noVNC...&lt;br /&gt;
&lt;br /&gt;
It kinda sucks for CLI-only VMs. It doesn&amp;#039;t allow for copy-pasta.&lt;br /&gt;
&lt;br /&gt;
Solution, [https://silicon.blog/2023/01/12/how-to-enable-copy-and-paste-function-on-your-proxmox-web-console-without-install-additional-software-in-your-vm/ configure the VM to use xterm.js] instead.&lt;br /&gt;
&lt;br /&gt;
The grub edits in that article don&amp;#039;t seem to work properly tho...&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;quiet&amp;quot;&lt;br /&gt;
GRUB_CMDLINE_LINUX=&amp;quot;console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0&amp;quot;&lt;br /&gt;
GRUB_TERMINAL=&amp;quot;console serial&amp;quot;&lt;br /&gt;
GRUB_SERIAL_COMMAND=&amp;quot;serial --speed=115200&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(initially from [https://www.reddit.com/r/Proxmox/comments/15dhkh7/newbie_issue_unable_to_enable_xtermjs_in_debian/ here])&lt;br /&gt;
&lt;br /&gt;
For some reason, Proxmox leaves noVNC as the console in the UI window &amp;amp; it does weird stuff to the console window when you open it. MRIN...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/support-for-xterm-js-console-by-default-for-specific-vm.114734/ FFS...]&lt;br /&gt;
&lt;br /&gt;
To open the console of a VM set up this way, either click the &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; button or right-click the VM in the left pane &amp;amp; select &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
= Manually installing REAL certs =&lt;br /&gt;
&lt;br /&gt;
I keep copies of my certs on a local [[Building Web Servers{{!}}webserver]] that acts as a [[Proxy Server Notes{{!}}proxy]] to feed HTTPS connections to various local servers. This makes it fairly trivial to pull certs to various machines that need them.&amp;amp;nbsp; Also, I&amp;#039;m using wildcard certs, which simplifies life.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039; Log into the servers shell as root. (either through the Web UI or SSH)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039; Follow along with this list of commands (adjusting appropriately...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /etc/pve/nodes/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd &amp;#039;&amp;#039;&amp;#039;NODENAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.key pveproxy-ssl.key.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.pem pveproxy-ssl.pem.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/fullchain_&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.crt pveproxy-ssl.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.key pveproxy-ssl.key&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;systemctl restart pveproxy&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: &amp;quot;/etc/apache2/certs&amp;quot; must be readable by &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; must also have SSH access to &amp;#039;&amp;#039;&amp;#039;WEBSERVER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039; Enjoy browsing to the Web UI of your server without being bitched at by your browser.&lt;br /&gt;
&lt;br /&gt;
This will also work just fine with machine-specific certs.&amp;amp;nbsp; You&amp;#039;ll need to adjust the filenames of your &amp;#039;&amp;#039;&amp;#039;crt&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;key&amp;#039;&amp;#039;&amp;#039; files.&lt;br /&gt;
&lt;br /&gt;
(these instructions are currently based on a non-clustered server...)&lt;br /&gt;
&lt;br /&gt;
= Convert a physical computer to a proxmox VM =&lt;br /&gt;
&lt;br /&gt;
* [https://pve.proxmox.com/wiki/Advanced_Migration_Techniques_to_Proxmox_VE From the Proxmox documentation]&lt;br /&gt;
* [https://forum.proxmox.com/threads/convert-physical-computer-to-proxmox.124490/ From the Proxmox forums]&lt;br /&gt;
&lt;br /&gt;
= Want a GUI on the console screen? =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt install task-cinnamon-desktop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Take this further... ==&lt;br /&gt;
* Maybe add in Synergy&lt;br /&gt;
* [[CopyPasta#New System_Cleanup_&amp;amp;_Prep{{!}}Cleanup the bloat]]?&lt;br /&gt;
&lt;br /&gt;
= Remove Proxmox Subscription Notice (Tested to 8.4) =&lt;br /&gt;
&lt;br /&gt;
Seems to work on 9.1.6 also...&lt;br /&gt;
&lt;br /&gt;
[https://mclarendatasystems.com/remove-proxmox51-subscription-notice/ Source]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sed -Ezi.bak &amp;quot;s/(function ?\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g&amp;quot; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;amp;&amp;amp; systemctl restart pveproxy.service&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4142</id>
		<title>PVE Tips</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4142"/>
		<updated>2026-03-29T15:33:37Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Take this further... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= xterm.js in place of noVNC =&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
An issue with noVNC...&lt;br /&gt;
&lt;br /&gt;
It kinda sucks for CLI-only VMs. It doesn&amp;#039;t allow for copy-pasta.&lt;br /&gt;
&lt;br /&gt;
Solution, [https://silicon.blog/2023/01/12/how-to-enable-copy-and-paste-function-on-your-proxmox-web-console-without-install-additional-software-in-your-vm/ configure the VM to use xterm.js] instead.&lt;br /&gt;
&lt;br /&gt;
The grub edits in that article don&amp;#039;t seem to work properly tho...&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;quiet&amp;quot;&lt;br /&gt;
GRUB_CMDLINE_LINUX=&amp;quot;console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0&amp;quot;&lt;br /&gt;
GRUB_TERMINAL=&amp;quot;console serial&amp;quot;&lt;br /&gt;
GRUB_SERIAL_COMMAND=&amp;quot;serial --speed=115200&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(initially from [https://www.reddit.com/r/Proxmox/comments/15dhkh7/newbie_issue_unable_to_enable_xtermjs_in_debian/ here])&lt;br /&gt;
&lt;br /&gt;
For some reason, Proxmox leaves noVNC as the console in the UI window &amp;amp; it does weird stuff to the console window when you open it. MRIN...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/support-for-xterm-js-console-by-default-for-specific-vm.114734/ FFS...]&lt;br /&gt;
&lt;br /&gt;
To open the console of a VM set up this way, either click the &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; button or right-click the VM in the left pane &amp;amp; select &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
= Manually installing REAL certs =&lt;br /&gt;
&lt;br /&gt;
I keep copies of my certs on a local [[Building Web Servers{{!}}webserver]] that acts as a [[Proxy Server Notes{{!}}proxy]] to feed HTTPS connections to various local servers. This makes it fairly trivial to pull certs to various machines that need them.&amp;amp;nbsp; Also, I&amp;#039;m using wildcard certs, which simplifies life.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039; Log into the servers shell as root. (either through the Web UI or SSH)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039; Follow along with this list of commands (adjusting appropriately...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /etc/pve/nodes/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd &amp;#039;&amp;#039;&amp;#039;NODENAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.key pveproxy-ssl.key.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.pem pveproxy-ssl.pem.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/fullchain_&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.crt pveproxy-ssl.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.key pveproxy-ssl.key&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;systemctl restart pveproxy&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: &amp;quot;/etc/apache2/certs&amp;quot; must be readable by &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; must also have SSH access to &amp;#039;&amp;#039;&amp;#039;WEBSERVER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039; Enjoy browsing to the Web UI of your server without being bitched at by your browser.&lt;br /&gt;
&lt;br /&gt;
This will also work just fine with machine-specific certs.&amp;amp;nbsp; You&amp;#039;ll need to adjust the filenames of your &amp;#039;&amp;#039;&amp;#039;crt&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;key&amp;#039;&amp;#039;&amp;#039; files.&lt;br /&gt;
&lt;br /&gt;
(these instructions are currently based on a non-clustered server...)&lt;br /&gt;
&lt;br /&gt;
= Convert a physical computer to a proxmox VM =&lt;br /&gt;
&lt;br /&gt;
* [https://pve.proxmox.com/wiki/Advanced_Migration_Techniques_to_Proxmox_VE From the Proxmox documentation]&lt;br /&gt;
* [https://forum.proxmox.com/threads/convert-physical-computer-to-proxmox.124490/ From the Proxmox forums]&lt;br /&gt;
&lt;br /&gt;
= Want a GUI on the console screen? =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt install task-cinnamon-desktop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Take this further... ==&lt;br /&gt;
* Maybe add in Synergy&lt;br /&gt;
* [[CopyPasta#New System_Cleanup_&amp;amp;_Prep{{!}}Cleanup the bloat]]?&lt;br /&gt;
&lt;br /&gt;
= Remove Proxmox Subscription Notice (Tested to 8.4) =&lt;br /&gt;
&lt;br /&gt;
Seems to work on 9.0.x also...&lt;br /&gt;
&lt;br /&gt;
[https://mclarendatasystems.com/remove-proxmox51-subscription-notice/ Source]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sed -Ezi.bak &amp;quot;s/(function ?\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g&amp;quot; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;amp;&amp;amp; systemctl restart pveproxy.service&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4141</id>
		<title>PVE Tips</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4141"/>
		<updated>2026-03-29T15:32:19Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Want a GUI on the console screen? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= xterm.js in place of noVNC =&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
An issue with noVNC...&lt;br /&gt;
&lt;br /&gt;
It kinda sucks for CLI-only VMs. It doesn&amp;#039;t allow for copy-pasta.&lt;br /&gt;
&lt;br /&gt;
Solution, [https://silicon.blog/2023/01/12/how-to-enable-copy-and-paste-function-on-your-proxmox-web-console-without-install-additional-software-in-your-vm/ configure the VM to use xterm.js] instead.&lt;br /&gt;
&lt;br /&gt;
The grub edits in that article don&amp;#039;t seem to work properly tho...&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;quiet&amp;quot;&lt;br /&gt;
GRUB_CMDLINE_LINUX=&amp;quot;console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0&amp;quot;&lt;br /&gt;
GRUB_TERMINAL=&amp;quot;console serial&amp;quot;&lt;br /&gt;
GRUB_SERIAL_COMMAND=&amp;quot;serial --speed=115200&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(initially from [https://www.reddit.com/r/Proxmox/comments/15dhkh7/newbie_issue_unable_to_enable_xtermjs_in_debian/ here])&lt;br /&gt;
&lt;br /&gt;
For some reason, Proxmox leaves noVNC as the console in the UI window &amp;amp; it does weird stuff to the console window when you open it. MRIN...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/support-for-xterm-js-console-by-default-for-specific-vm.114734/ FFS...]&lt;br /&gt;
&lt;br /&gt;
To open the console of a VM set up this way, either click the &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; button or right-click the VM in the left pane &amp;amp; select &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
= Manually installing REAL certs =&lt;br /&gt;
&lt;br /&gt;
I keep copies of my certs on a local [[Building Web Servers{{!}}webserver]] that acts as a [[Proxy Server Notes{{!}}proxy]] to feed HTTPS connections to various local servers. This makes it fairly trivial to pull certs to various machines that need them.&amp;amp;nbsp; Also, I&amp;#039;m using wildcard certs, which simplifies life.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039; Log into the servers shell as root. (either through the Web UI or SSH)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039; Follow along with this list of commands (adjusting appropriately...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /etc/pve/nodes/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd &amp;#039;&amp;#039;&amp;#039;NODENAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.key pveproxy-ssl.key.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.pem pveproxy-ssl.pem.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/fullchain_&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.crt pveproxy-ssl.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.key pveproxy-ssl.key&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;systemctl restart pveproxy&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: &amp;quot;/etc/apache2/certs&amp;quot; must be readable by &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; must also have SSH access to &amp;#039;&amp;#039;&amp;#039;WEBSERVER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039; Enjoy browsing to the Web UI of your server without being bitched at by your browser.&lt;br /&gt;
&lt;br /&gt;
This will also work just fine with machine-specific certs.&amp;amp;nbsp; You&amp;#039;ll need to adjust the filenames of your &amp;#039;&amp;#039;&amp;#039;crt&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;key&amp;#039;&amp;#039;&amp;#039; files.&lt;br /&gt;
&lt;br /&gt;
(these instructions are currently based on a non-clustered server...)&lt;br /&gt;
&lt;br /&gt;
= Convert a physical computer to a proxmox VM =&lt;br /&gt;
&lt;br /&gt;
* [https://pve.proxmox.com/wiki/Advanced_Migration_Techniques_to_Proxmox_VE From the Proxmox documentation]&lt;br /&gt;
* [https://forum.proxmox.com/threads/convert-physical-computer-to-proxmox.124490/ From the Proxmox forums]&lt;br /&gt;
&lt;br /&gt;
= Want a GUI on the console screen? =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt install task-cinnamon-desktop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Take this further... ==&lt;br /&gt;
* Maybe add in Synergy&lt;br /&gt;
* Cleanup the bloat?&lt;br /&gt;
&lt;br /&gt;
= Remove Proxmox Subscription Notice (Tested to 8.4) =&lt;br /&gt;
&lt;br /&gt;
Seems to work on 9.0.x also...&lt;br /&gt;
&lt;br /&gt;
[https://mclarendatasystems.com/remove-proxmox51-subscription-notice/ Source]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sed -Ezi.bak &amp;quot;s/(function ?\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g&amp;quot; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;amp;&amp;amp; systemctl restart pveproxy.service&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4140</id>
		<title>PVE Tips</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_Tips&amp;diff=4140"/>
		<updated>2026-03-29T15:25:08Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Want a GUI on the console screen? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= xterm.js in place of noVNC =&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
An issue with noVNC...&lt;br /&gt;
&lt;br /&gt;
It kinda sucks for CLI-only VMs. It doesn&amp;#039;t allow for copy-pasta.&lt;br /&gt;
&lt;br /&gt;
Solution, [https://silicon.blog/2023/01/12/how-to-enable-copy-and-paste-function-on-your-proxmox-web-console-without-install-additional-software-in-your-vm/ configure the VM to use xterm.js] instead.&lt;br /&gt;
&lt;br /&gt;
The grub edits in that article don&amp;#039;t seem to work properly tho...&lt;br /&gt;
&lt;br /&gt;
Instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;quiet&amp;quot;&lt;br /&gt;
GRUB_CMDLINE_LINUX=&amp;quot;console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0&amp;quot;&lt;br /&gt;
GRUB_TERMINAL=&amp;quot;console serial&amp;quot;&lt;br /&gt;
GRUB_SERIAL_COMMAND=&amp;quot;serial --speed=115200&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(initially from [https://www.reddit.com/r/Proxmox/comments/15dhkh7/newbie_issue_unable_to_enable_xtermjs_in_debian/ here])&lt;br /&gt;
&lt;br /&gt;
For some reason, Proxmox leaves noVNC as the console in the UI window &amp;amp; it does weird stuff to the console window when you open it. MRIN...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/support-for-xterm-js-console-by-default-for-specific-vm.114734/ FFS...]&lt;br /&gt;
&lt;br /&gt;
To open the console of a VM set up this way, either click the &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; button or right-click the VM in the left pane &amp;amp; select &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;gt;_ Console&amp;#039;&amp;#039;&amp;#039;&amp;quot; from the menu.&lt;br /&gt;
&lt;br /&gt;
= Manually installing REAL certs =&lt;br /&gt;
&lt;br /&gt;
I keep copies of my certs on a local [[Building Web Servers{{!}}webserver]] that acts as a [[Proxy Server Notes{{!}}proxy]] to feed HTTPS connections to various local servers. This makes it fairly trivial to pull certs to various machines that need them.&amp;amp;nbsp; Also, I&amp;#039;m using wildcard certs, which simplifies life.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039; Log into the servers shell as root. (either through the Web UI or SSH)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039; Follow along with this list of commands (adjusting appropriately...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /etc/pve/nodes/&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd &amp;#039;&amp;#039;&amp;#039;NODENAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.key pveproxy-ssl.key.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cp pveproxy-ssl.pem pveproxy-ssl.pem.BAK&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/fullchain_&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.crt pveproxy-ssl.pem&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;scp &amp;#039;&amp;#039;&amp;#039;USER@WEBSERVER&amp;#039;&amp;#039;&amp;#039;:/etc/apache2/certs/&amp;#039;&amp;#039;&amp;#039;YOURDOMAIN.TLD&amp;#039;&amp;#039;&amp;#039;.key pveproxy-ssl.key&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;systemctl restart pveproxy&amp;lt;/code&amp;gt;&lt;br /&gt;
Note: &amp;quot;/etc/apache2/certs&amp;quot; must be readable by &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;USER&amp;#039;&amp;#039;&amp;#039; must also have SSH access to &amp;#039;&amp;#039;&amp;#039;WEBSERVER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039; Enjoy browsing to the Web UI of your server without being bitched at by your browser.&lt;br /&gt;
&lt;br /&gt;
This will also work just fine with machine-specific certs.&amp;amp;nbsp; You&amp;#039;ll need to adjust the filenames of your &amp;#039;&amp;#039;&amp;#039;crt&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;key&amp;#039;&amp;#039;&amp;#039; files.&lt;br /&gt;
&lt;br /&gt;
(these instructions are currently based on a non-clustered server...)&lt;br /&gt;
&lt;br /&gt;
= Convert a physical computer to a proxmox VM =&lt;br /&gt;
&lt;br /&gt;
* [https://pve.proxmox.com/wiki/Advanced_Migration_Techniques_to_Proxmox_VE From the Proxmox documentation]&lt;br /&gt;
* [https://forum.proxmox.com/threads/convert-physical-computer-to-proxmox.124490/ From the Proxmox forums]&lt;br /&gt;
&lt;br /&gt;
= Want a GUI on the console screen? =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt install task-cinnamon-desktop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Maybe add in Synergy ==&lt;br /&gt;
&lt;br /&gt;
= Remove Proxmox Subscription Notice (Tested to 8.4) =&lt;br /&gt;
&lt;br /&gt;
Seems to work on 9.0.x also...&lt;br /&gt;
&lt;br /&gt;
[https://mclarendatasystems.com/remove-proxmox51-subscription-notice/ Source]&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sed -Ezi.bak &amp;quot;s/(function ?\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g&amp;quot; /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js &amp;amp;&amp;amp; systemctl restart pveproxy.service&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=WeeWX_Weather_Server&amp;diff=4139</id>
		<title>WeeWX Weather Server</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=WeeWX_Weather_Server&amp;diff=4139"/>
		<updated>2026-03-09T00:45:02Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Setting up for EcoWitt gear */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- &amp;lt; --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot; --&amp;gt;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bullseye)&lt;br /&gt;
{{!}} Actually, a pretty much all default LXC running under Proxmox. Only non-default item being that I gave it 4 cores.&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
This particular set of instructions is based on building a Debian 12 based LXC under Proxmox to handle WeeWX.  On my network, I have an existing WebServer &amp;amp; an existing Automation Server.  The intent is to have the weather information served up as a web page (Default WeeWX thing...) by the WebServer and also be used by the Automation Server.&lt;br /&gt;
&lt;br /&gt;
There is also a dedicated Database Server which we will be using. (can&amp;#039;t possibly do things the easy way...)&lt;br /&gt;
&lt;br /&gt;
(Based on: [https://www.weewx.com/docs/5.1/quickstarts/debian/ WeeWX: Installation on Debian-based systems])&lt;br /&gt;
&lt;br /&gt;
Originally, the old version of this article was done with a much earlier version of WeeWX &amp;amp; our old Accurite weather station.  Things have seriously changed since those days...&lt;br /&gt;
&lt;br /&gt;
== Configure apt ==&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install -y wget gnupg&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget -qO - &amp;lt;nowiki&amp;gt;https://weewx.com/keys.html&amp;lt;/nowiki&amp;gt; | sudo gpg --dearmor --output /etc/apt/trusted.gpg.d/weewx.gpg&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;echo &amp;quot;deb [arch=all] &amp;lt;nowiki&amp;gt;https://weewx.com/apt/python3&amp;lt;/nowiki&amp;gt; buster main&amp;quot; | sudo tee /etc/apt/sources.list.d/weewx.list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Install WeeWX ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
During this step, you will be asked for all the details about your install.&lt;br /&gt;
&lt;br /&gt;
Fill everything in as best you can, but you can indeed [[#OTHER CUSTOMISATIONS{{!}}change things later]] too.&lt;br /&gt;
&lt;br /&gt;
If you are using weather station hardware that is supported by default, go ahead and select that hardware when asked. In my case, I&amp;#039;m currently running an EcoWitt weather station &amp;amp; that will require a little more effort. For now, I&amp;#039;m selecting &amp;#039;&amp;#039;&amp;#039;Simulator&amp;#039;&amp;#039;&amp;#039; as my hardware type.&lt;br /&gt;
&lt;br /&gt;
Once the machine has finished churning away at the install, WeeWX will be running. You can verify this by running:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Setting up for EcoWitt gear ==&lt;br /&gt;
You&amp;#039;ll be installing the [https://github.com/hoetzgit/weewx-gw1000 &amp;#039;&amp;#039;&amp;#039;Ecowitt Gateway (formerly GW1000) Driver&amp;#039;&amp;#039;&amp;#039;]&lt;br /&gt;
&lt;br /&gt;
(Something happened to the original developer &amp;amp; all his stuff has vanished from the Interwebs...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;wget -O weewx-gw1000.zip &amp;lt;nowiki&amp;gt;https://github.com/hoetzgit/weewx-gw1000/archive/master.zip&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install python3-six&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo weectl extension install weewx-gw1000.zip&amp;lt;/code&amp;gt;&lt;br /&gt;
Verify it can talk to your EcoWitt gateway:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;PYTHONPATH=/usr/share/weewx python3 /etc/weewx/bin/user/gw1000.py --test-driver --ip-address=&amp;#039;&amp;#039;&amp;#039;device_ip_address&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
(Where you replace &amp;#039;&amp;#039;&amp;#039;device_ip_address&amp;#039;&amp;#039;&amp;#039; with the actual address of your gateway...)&lt;br /&gt;
&lt;br /&gt;
You should observe loop packets being emitted on a regular basis. Once finished press ctrl-c to exit.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Note&amp;#039;&amp;#039;&amp;#039;: You will only see loop packets and not archive records when running the driver directly. This is because you are seeing output not from WeeWX, but rather directly from the driver.&lt;br /&gt;
&lt;br /&gt;
Configure WeeWX to use the driver:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo weectl station reconfigure --driver=user.gw1000&amp;lt;/code&amp;gt;&lt;br /&gt;
restart WeeWx&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo systemctl restart weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
(&amp;#039;&amp;#039;&amp;#039;Note&amp;#039;&amp;#039;&amp;#039;: I&amp;#039;ve verified this with &amp;#039;&amp;#039;&amp;#039;GW1100&amp;#039;&amp;#039;&amp;#039;, &amp;#039;&amp;#039;&amp;#039;GW1200 and GW3000&amp;#039;&amp;#039;&amp;#039; gateways so far...)&lt;br /&gt;
&lt;br /&gt;
== Customising WeeWX ==&lt;br /&gt;
&lt;br /&gt;
=== Broadcasting over MQTT ===&lt;br /&gt;
Install paho-mqtt&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt -y install python3-paho-mqtt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Download the WeeWX MQTT Extension:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;wget -O weewx-mqtt.zip &amp;lt;nowiki&amp;gt;https://github.com/matthewwall/weewx-mqtt/archive/master.zip&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the extension:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo weectl extension install weewx-mqtt.zip&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then edit weewx.conf to configure things for your own MQTT server&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo vim /etc/weewx/weewx.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scroll down &amp;amp; find the &amp;#039;&amp;#039;&amp;#039;&amp;lt;nowiki&amp;gt;[[MQTT]]&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039; block, then edit it to suit your network.&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;nowiki&amp;gt;[[MQTT]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
        server_url = mqtt://&amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;:1883&lt;br /&gt;
        topic = &amp;#039;&amp;#039;&amp;#039;weather&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
        unit_system = METRIC&lt;br /&gt;
&lt;br /&gt;
restart WeeWx&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl restart weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Connecting to a remote database ===&lt;br /&gt;
By default, WeeWX uses a local instance of SQLite.&lt;br /&gt;
&lt;br /&gt;
But, you may wish to archive its data on your primary database.&lt;br /&gt;
&lt;br /&gt;
(Maybe even go nuts &amp;amp; set up multiple weather stations, all sending their data to a central database server...)&lt;br /&gt;
&lt;br /&gt;
==== Setting up the database (MySQL / MariaDB) ====&lt;br /&gt;
On the Database Server:&lt;br /&gt;
&lt;br /&gt;
(NOTE: Your Database Server must be configured to allow remote access.)&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo mysql -u root -p&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 CREATE USER &amp;#039;weewx&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;&amp;#039; IDENTIFIED BY &amp;#039;weewx&amp;#039;;&lt;br /&gt;
 CREATE DATABASE weewx;&lt;br /&gt;
 GRANT select, update, create, delete, insert, drop ON weewx.* TO weewx@&amp;#039;&amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
(&amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;, of course, being the address of your WeeWX Server...)&lt;br /&gt;
&lt;br /&gt;
==== Configuring WeeWX to use this database ====&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo vi /etc/weewx/weewx.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in &amp;lt;nowiki&amp;gt;[[wx_binding]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;database = archive_sqlite&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;database = archive_mysql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in &amp;lt;nowiki&amp;gt;[[MySQL]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;host = localhost&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;host = &amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(&amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;, of course, being the address of your Database Server...)&lt;br /&gt;
&lt;br /&gt;
restart WeeWx&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl restart weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Making the weather visible via Web Browser ===&lt;br /&gt;
There are 3 options for locally serving up the weather as HTML...&lt;br /&gt;
&lt;br /&gt;
==== 1: Install a web server on the same machine (or VM...or LXC...) ====&lt;br /&gt;
&lt;br /&gt;
Install your choice of web server and simply point the root at &amp;#039;&amp;#039;&amp;#039;/var/www/html/weewx&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
==== 2: Use FTP to upload to your existing WebServer ====&lt;br /&gt;
&lt;br /&gt;
(Your Web Server will need to have FTP enabled...)&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo vi /etc/weewx/weewx.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Find the &amp;lt;nowiki&amp;gt;[[FTP]]&amp;lt;/nowiki&amp;gt; block &amp;amp; edit it to suit.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[StdReport]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     &amp;lt;nowiki&amp;gt;[[FTP]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
         skin = Ftp&lt;br /&gt;
         enable = true&lt;br /&gt;
         server = &amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
         path = /var/www/html/weewx&lt;br /&gt;
         user = &amp;#039;&amp;#039;&amp;#039;USERNAME&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
         password = &amp;#039;&amp;#039;&amp;#039;PASSWORD&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
==== 3: Use RSYNC to upload to your existing WebServer ====&lt;br /&gt;
&lt;br /&gt;
(You will need to set up passwordless SSH between this machine &amp;amp; your web server...)&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo vi /etc/weewx/weewx.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Find the &amp;lt;nowiki&amp;gt;[[RSYNC]]&amp;lt;/nowiki&amp;gt; block &amp;amp; edit it to suit.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[StdReport]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
     &amp;lt;nowiki&amp;gt;[[RSYNC]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
         skin = Rsync&lt;br /&gt;
         enable = true&lt;br /&gt;
         server = &amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
         path = /var/www/html/weewx&lt;br /&gt;
         user = &amp;#039;&amp;#039;&amp;#039;USERNAME&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
(Make sure your chosen user has write permissions...)&lt;br /&gt;
&lt;br /&gt;
=== OTHER CUSTOMISATIONS ===&lt;br /&gt;
There is a configuration file at:&lt;br /&gt;
* &amp;lt;code&amp;gt;/etc/weewx/weewx.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
that holds most (if not all) of the little details &amp;amp; tweaks for your weather server.&lt;br /&gt;
&lt;br /&gt;
==== Useful examples ====&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;archive_interval&amp;#039;&amp;#039;&amp;#039; defines how often WeeWX updates its reports (Including via MQTT if you&amp;#039;re using that...)&lt;br /&gt;
&lt;br /&gt;
==Administration==&lt;br /&gt;
Checking status:&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Starting:&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl start weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stopping:&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl stop weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Restarting:&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl restart weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Watching the system log&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo journalctl -u weewx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4138</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4138"/>
		<updated>2026-03-04T21:04:39Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* (Their instructions...) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;br /&gt;
&lt;br /&gt;
As a bonus silly point, rather than just setting up a VM as usual, it is recommended that you run a community-supplied script on your Proxmox host to build the VM.&lt;br /&gt;
== (Their instructions...) ==&lt;br /&gt;
&lt;br /&gt;
*Run this command in the Proxmox shell:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;code&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
bash -c &amp;quot;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;quot;   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&lt;br /&gt;
* The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&lt;br /&gt;
* Once complete, check the VM’s &amp;lt;strong&amp;gt; Summary tab&amp;lt;/strong&amp;gt; in the Proxmox GUI to find the IP address assigned by DHCP.&lt;br /&gt;
* Access Home Assistant at &amp;lt;code&amp;gt;http://&amp;#039;&amp;#039;&amp;#039;[VM_IP]&amp;#039;&amp;#039;&amp;#039;:8123&amp;lt;/code&amp;gt; to complete setup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;IMO...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;This script may, or may not be safe to actually run blindly on your server.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;I have yet to dig all the way into it &amp;amp; verify what it&amp;#039;s ACTUALLY doing all the way through.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But, it does seem to do the job (albeit likely while taking your own needs for granted)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot; &amp;gt;There are also 2 scripts to allegedly do the same job using Debian (12 &amp;amp; 13) in that folder, but neither of them seems to actually set up HA once they&amp;#039;ve built the VM...&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4137</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4137"/>
		<updated>2026-03-04T21:04:20Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* (Their instructions...) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;br /&gt;
&lt;br /&gt;
As a bonus silly point, rather than just setting up a VM as usual, it is recommended that you run a community-supplied script on your Proxmox host to build the VM.&lt;br /&gt;
== (Their instructions...) ==&lt;br /&gt;
&lt;br /&gt;
*Run this command in the Proxmox shell:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;code&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
bash -c &amp;quot;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;quot;   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&lt;br /&gt;
* The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&lt;br /&gt;
* Once complete, check the VM’s &amp;lt;strong&amp;gt; Summary tab&amp;lt;/strong&amp;gt; in the Proxmox GUI to find the IP address assigned by DHCP.&lt;br /&gt;
* Access Home Assistant at &amp;lt;code&amp;gt;http://&amp;#039;&amp;#039;&amp;#039;[VM_IP]&amp;#039;&amp;#039;&amp;#039;:8123&amp;lt;/code&amp;gt; to complete setup.&lt;br /&gt;
***&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;IMO...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;This script may, or may not be safe to actually run blindly on your server.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;I have yet to dig all the way into it &amp;amp; verify what it&amp;#039;s ACTUALLY doing all the way through.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But, it does seem to do the job (albeit likely while taking your own needs for granted)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot; &amp;gt;There are also 2 scripts to allegedly do the same job using Debian (12 &amp;amp; 13) in that folder, but neither of them seems to actually set up HA once they&amp;#039;ve built the VM...&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4136</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4136"/>
		<updated>2026-03-04T20:01:07Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* (Their instructions...) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;br /&gt;
&lt;br /&gt;
As a bonus silly point, rather than just setting up a VM as usual, it is recommended that you run a community-supplied script on your Proxmox host to build the VM.&lt;br /&gt;
== (Their instructions...) ==&lt;br /&gt;
&lt;br /&gt;
*Run this command in the Proxmox shell:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;code&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
bash -c &amp;quot;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;quot;   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&lt;br /&gt;
* The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&lt;br /&gt;
* Once complete, check the VM’s &amp;lt;strong&amp;gt; Summary tab&amp;lt;/strong&amp;gt; in the Proxmox GUI to find the IP address assigned by DHCP.&lt;br /&gt;
* Access Home Assistant at &amp;lt;code&amp;gt;http://&amp;#039;&amp;#039;&amp;#039;[VM_IP]&amp;#039;&amp;#039;&amp;#039;:8123&amp;lt;/code&amp;gt; to complete setup.&lt;br /&gt;
**&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;IMO...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;This script may, or may not be safe to actually run blindly on your server.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;I have yet to dig all the way into it &amp;amp; verify what it&amp;#039;s ACTUALLY doing all the way through.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But, it does seem to do the job (albeit likely while taking your own needs for granted)...&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4135</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4135"/>
		<updated>2026-03-04T19:57:44Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* (Their instructions...) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;br /&gt;
&lt;br /&gt;
As a bonus silly point, rather than just setting up a VM as usual, it is recommended that you run a community-supplied script on your Proxmox host to build the VM.&lt;br /&gt;
== (Their instructions...) ==&lt;br /&gt;
&lt;br /&gt;
*Run this command in the Proxmox shell:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;code&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
bash -c &amp;quot;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;quot;   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&lt;br /&gt;
* The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&lt;br /&gt;
* Once complete, check the VM’s &amp;lt;strong&amp;gt; Summary tab&amp;lt;/strong&amp;gt; in the Proxmox GUI to find the IP address assigned by DHCP.&lt;br /&gt;
* Access Home Assistant at &amp;lt;code&amp;gt;http://&amp;#039;&amp;#039;&amp;#039;[VM_IP]&amp;#039;&amp;#039;&amp;#039;:8123&amp;lt;/code&amp;gt; to complete setup.&lt;br /&gt;
&lt;br /&gt;
IMO...&lt;br /&gt;
&lt;br /&gt;
This script may, or may not be safe to actually run blindly on your server.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4134</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4134"/>
		<updated>2026-03-04T19:50:57Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Installation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;br /&gt;
&lt;br /&gt;
As a bonus silly point, rather than just setting up a VM as usual, it is recommended that you run a community-supplied script on your Proxmox host to build the VM.&lt;br /&gt;
== (Their instructions...) ==&lt;br /&gt;
&lt;br /&gt;
*Run this command in the Proxmox shell:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;code&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
bash -c &amp;quot;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;quot;   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&lt;br /&gt;
* The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&lt;br /&gt;
* Once complete, check the VM’s &amp;lt;strong&amp;gt; Summary tab&amp;lt;/strong&amp;gt; in the Proxmox GUI to find the IP address assigned by DHCP.&lt;br /&gt;
* Access Home Assistant at &amp;lt;code&amp;gt;http://&amp;#039;&amp;#039;&amp;#039;[VM_IP]&amp;#039;&amp;#039;&amp;#039;:8123&amp;lt;/code&amp;gt; to complete setup.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4133</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4133"/>
		<updated>2026-03-04T19:49:42Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* ccckkk */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;br /&gt;
&lt;br /&gt;
As a bonus silly point, rather than just setting up a VM as usual, it is recommended that you run a community-supplied script on your Proxmox host to build the VM.&lt;br /&gt;
== fffuuu ==&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Run this command in the Proxmox shell:&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;pre class=&amp;quot;code svelte-x57wqa&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;bash -c &amp;lt;span class=&amp;quot;hljs-string&amp;quot;&amp;gt;&amp;quot;&amp;lt;span class=&amp;quot;hljs-subst&amp;quot;&amp;gt;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;lt;/span&amp;gt;&amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;div class=&amp;quot;copy-container svelte-clssou&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Once complete, check the VM’s &amp;lt;/span&amp;gt;&amp;lt;strong class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Summary tab&amp;lt;/span&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt; in the Proxmox GUI to find the IP address assigned by DHCP.&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Access Home Assistant at &amp;lt;/span&amp;gt;&amp;lt;code class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;http://[VM_IP]:8123&amp;lt;/code&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt; to complete setup. &amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span&amp;gt;ccckkk&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
* Run this command in the Proxmox shell:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;code&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
bash -c &amp;quot;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;quot;   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&lt;br /&gt;
* The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&lt;br /&gt;
* Once complete, check the VM’s &amp;lt;strong &amp;gt; Summary tab&amp;lt;/strong&amp;gt;  in the Proxmox GUI to find the IP address assigned by DHCP.&lt;br /&gt;
* Access Home Assistant at &amp;lt;code &amp;gt;http://&amp;#039;&amp;#039;&amp;#039;[VM_IP]&amp;#039;&amp;#039;&amp;#039;:8123&amp;lt;/code&amp;gt;  to complete setup.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4132</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4132"/>
		<updated>2026-03-04T19:44:31Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* ccckkk */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;br /&gt;
&lt;br /&gt;
As a bonus silly point, rather than just setting up a VM as usual, it is recommended that you run a community-supplied script on your Proxmox host to build the VM.&lt;br /&gt;
== fffuuu ==&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Run this command in the Proxmox shell:&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;pre class=&amp;quot;code svelte-x57wqa&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;bash -c &amp;lt;span class=&amp;quot;hljs-string&amp;quot;&amp;gt;&amp;quot;&amp;lt;span class=&amp;quot;hljs-subst&amp;quot;&amp;gt;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;lt;/span&amp;gt;&amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;div class=&amp;quot;copy-container svelte-clssou&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Once complete, check the VM’s &amp;lt;/span&amp;gt;&amp;lt;strong class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Summary tab&amp;lt;/span&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt; in the Proxmox GUI to find the IP address assigned by DHCP.&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Access Home Assistant at &amp;lt;/span&amp;gt;&amp;lt;code class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;http://[VM_IP]:8123&amp;lt;/code&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt; to complete setup. &amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span&amp;gt;ccckkk&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
* Run this command in the Proxmox shell:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;code svelte-x57wqa&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&amp;lt;code &amp;gt;bash -c &amp;lt;span class=&amp;quot;hljs-string&amp;quot;&amp;gt;&amp;quot;&amp;lt;span class=&amp;quot;hljs-subst&amp;quot;&amp;gt;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;div class=&amp;quot;copy-container svelte-clssou&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
* Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&lt;br /&gt;
* The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&lt;br /&gt;
* Once complete, check the VM’s &amp;lt;strong &amp;gt; Summary tab&amp;lt;/strong&amp;gt;  in the Proxmox GUI to find the IP address assigned by DHCP.&lt;br /&gt;
* Access Home Assistant at &amp;lt;code &amp;gt;http://[VM_IP]:8123&amp;lt;/code&amp;gt;  to complete setup.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4131</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4131"/>
		<updated>2026-03-04T19:40:54Z</updated>

		<summary type="html">&lt;p&gt;Tinker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;br /&gt;
&lt;br /&gt;
As a bonus silly point, rather than just setting up a VM as usual, it is recommended that you run a community-supplied script on your Proxmox host to build the VM.&lt;br /&gt;
== fffuuu ==&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Run this command in the Proxmox shell:&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;pre class=&amp;quot;code svelte-x57wqa&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;bash -c &amp;lt;span class=&amp;quot;hljs-string&amp;quot;&amp;gt;&amp;quot;&amp;lt;span class=&amp;quot;hljs-subst&amp;quot;&amp;gt;$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)&amp;lt;/span&amp;gt;&amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;div class=&amp;quot;copy-container svelte-clssou&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Follow the on-screen prompts. Use default settings unless you need custom configurations (e.g., network bridge, VLAN).&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;The script downloads the latest HAOS qcow2 image, creates the VM, imports the disk, configures UEFI, and starts the VM.&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Once complete, check the VM’s &amp;lt;/span&amp;gt;&amp;lt;strong class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Summary tab&amp;lt;/span&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt; in the Proxmox GUI to find the IP address assigned by DHCP.&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
*&amp;lt;p class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;Access Home Assistant at &amp;lt;/span&amp;gt;&amp;lt;code class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;http://[VM_IP]:8123&amp;lt;/code&amp;gt;&amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt; to complete setup. &amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span class=&amp;quot;svelte-x57wqa&amp;quot;&amp;gt;&amp;lt;span&amp;gt;ccckkk&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; ==&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4130</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4130"/>
		<updated>2026-03-04T19:35:35Z</updated>

		<summary type="html">&lt;p&gt;Tinker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
While it would be rather nice to be able to simply install Home Assistant straight onto a LXC, it seems that the maintainers feel otherwise.&lt;br /&gt;
&lt;br /&gt;
The only straightforward install that actually seems to work is installing their own version of Linux onto either bare metal or a VM.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4129</id>
		<title>Automation - Home-Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Home-Assistant&amp;diff=4129"/>
		<updated>2026-03-04T19:32:49Z</updated>

		<summary type="html">&lt;p&gt;Tinker: Created page with &amp;quot;fffff&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;fffff&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4128</id>
		<title>Installing TP-Link Omada SDN Controller on a Debian-based LXC</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4128"/>
		<updated>2026-01-18T21:31:26Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Restarting the Omada Controller from CLI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bookworm)&lt;br /&gt;
{{!}} 4 cores, 4GB RAM, 8GB storage&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Start with the prerequisites:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install openjdk-17-jre-headless jsvc curl gnupg -y&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;sudo dpkg -i libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -fsSL &amp;lt;nowiki&amp;gt;https://www.mongodb.org/static/pgp/server-4.4.asc&amp;lt;/nowiki&amp;gt; {{!}} sudo apt-key add -&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;echo &amp;quot;deb [ arch=amd64,arm64 ] &amp;lt;nowiki&amp;gt;https://repo.mongodb.org/apt/ubuntu&amp;lt;/nowiki&amp;gt; focal/mongodb-org/4.4 multiverse&amp;quot; {{!}} sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install mongodb-org&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl start mongod.service&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl enable mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Install SDN:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
NOTE: The download page (to check current versions etc...) fails to show the Linux versions if you let it redirect to country-local versions. Actua, functional download page is [https://www.tp-link.com/en/support/download/omada-software-controller/#Controller_Software here].&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.tar.gz&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tar zxvf Omada_SDN_Controller_v5.12.7_linux_x64.tar.gz&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd Omada_SDN_Controller_v5.12.7_linux_x64&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo bash ./install.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
or (Tho this seems to fail weirdly whenever they update the version while the tar.gz version doesn&amp;#039;t):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo dpkg -i ./Omada_SDN_Controller_v5.13.22_Linux_x64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
Upon install, Omada Controller will start up. Eventually. It does seem to take a VERY long time for it&amp;#039;s first start...&lt;br /&gt;
&lt;br /&gt;
https://&amp;#039;&amp;#039;&amp;#039;SERVERADDRESS&amp;#039;&amp;#039;&amp;#039;:8043/&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;font-size: 18pt; color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;CERTS!!!&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ll need to have your proper certs downloaded &amp;amp; then [https://support.tsplus.net/support/solutions/articles/44000038469-how-to-convert-different-ssl-https-certificate-formats-to-java-jks- mess with making a .PFX file from them]...&lt;br /&gt;
&lt;br /&gt;
(Really, just Part B, Step 1 at that link.)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;openssl pkcs12 -export -out &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;.pfx -inkey &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039; -in &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039; -certfile &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
Where:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is the name of your Omada server&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** Is your key file&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is your certificate file&lt;br /&gt;
&lt;br /&gt;
Then install/update via the UI &amp;amp; fully reboot the server/VM/LXC to activate it... :(&lt;br /&gt;
=== Problem(s) ===&lt;br /&gt;
Apparently, if your certs expire before you update them...&lt;br /&gt;
&lt;br /&gt;
Yer borked.&lt;br /&gt;
&lt;br /&gt;
Just so ya know...&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp; tips ==&lt;br /&gt;
=== Restarting the Omada Controller from CLI ===&lt;br /&gt;
SSH into the container&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo /opt/tplink/EAPController/bin/control.sh restart&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4127</id>
		<title>Installing TP-Link Omada SDN Controller on a Debian-based LXC</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4127"/>
		<updated>2026-01-18T21:26:11Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Restarting the Omada Controller from CLI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bookworm)&lt;br /&gt;
{{!}} 4 cores, 4GB RAM, 8GB storage&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Start with the prerequisites:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install openjdk-17-jre-headless jsvc curl gnupg -y&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;sudo dpkg -i libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -fsSL &amp;lt;nowiki&amp;gt;https://www.mongodb.org/static/pgp/server-4.4.asc&amp;lt;/nowiki&amp;gt; {{!}} sudo apt-key add -&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;echo &amp;quot;deb [ arch=amd64,arm64 ] &amp;lt;nowiki&amp;gt;https://repo.mongodb.org/apt/ubuntu&amp;lt;/nowiki&amp;gt; focal/mongodb-org/4.4 multiverse&amp;quot; {{!}} sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install mongodb-org&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl start mongod.service&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl enable mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Install SDN:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
NOTE: The download page (to check current versions etc...) fails to show the Linux versions if you let it redirect to country-local versions. Actua, functional download page is [https://www.tp-link.com/en/support/download/omada-software-controller/#Controller_Software here].&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.tar.gz&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tar zxvf Omada_SDN_Controller_v5.12.7_linux_x64.tar.gz&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd Omada_SDN_Controller_v5.12.7_linux_x64&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo bash ./install.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
or (Tho this seems to fail weirdly whenever they update the version while the tar.gz version doesn&amp;#039;t):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo dpkg -i ./Omada_SDN_Controller_v5.13.22_Linux_x64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
Upon install, Omada Controller will start up. Eventually. It does seem to take a VERY long time for it&amp;#039;s first start...&lt;br /&gt;
&lt;br /&gt;
https://&amp;#039;&amp;#039;&amp;#039;SERVERADDRESS&amp;#039;&amp;#039;&amp;#039;:8043/&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;font-size: 18pt; color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;CERTS!!!&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ll need to have your proper certs downloaded &amp;amp; then [https://support.tsplus.net/support/solutions/articles/44000038469-how-to-convert-different-ssl-https-certificate-formats-to-java-jks- mess with making a .PFX file from them]...&lt;br /&gt;
&lt;br /&gt;
(Really, just Part B, Step 1 at that link.)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;openssl pkcs12 -export -out &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;.pfx -inkey &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039; -in &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039; -certfile &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
Where:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is the name of your Omada server&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** Is your key file&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is your certificate file&lt;br /&gt;
&lt;br /&gt;
Then install/update via the UI &amp;amp; fully reboot the server/VM/LXC to activate it... :(&lt;br /&gt;
=== Problem(s) ===&lt;br /&gt;
Apparently, if your certs expire before you update them...&lt;br /&gt;
&lt;br /&gt;
Yer borked.&lt;br /&gt;
&lt;br /&gt;
Just so ya know...&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp; tips ==&lt;br /&gt;
=== Restarting the Omada Controller from CLI ===&lt;br /&gt;
SSH into the container&lt;br /&gt;
* cd /opt/tplink/EAPController/bin&lt;br /&gt;
* ./stop.sh&lt;br /&gt;
* ./start.sh&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4126</id>
		<title>Installing TP-Link Omada SDN Controller on a Debian-based LXC</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4126"/>
		<updated>2026-01-18T21:22:39Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Restarting the Omada Controller from CLI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bookworm)&lt;br /&gt;
{{!}} 4 cores, 4GB RAM, 8GB storage&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Start with the prerequisites:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install openjdk-17-jre-headless jsvc curl gnupg -y&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;sudo dpkg -i libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -fsSL &amp;lt;nowiki&amp;gt;https://www.mongodb.org/static/pgp/server-4.4.asc&amp;lt;/nowiki&amp;gt; {{!}} sudo apt-key add -&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;echo &amp;quot;deb [ arch=amd64,arm64 ] &amp;lt;nowiki&amp;gt;https://repo.mongodb.org/apt/ubuntu&amp;lt;/nowiki&amp;gt; focal/mongodb-org/4.4 multiverse&amp;quot; {{!}} sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install mongodb-org&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl start mongod.service&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl enable mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Install SDN:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
NOTE: The download page (to check current versions etc...) fails to show the Linux versions if you let it redirect to country-local versions. Actua, functional download page is [https://www.tp-link.com/en/support/download/omada-software-controller/#Controller_Software here].&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.tar.gz&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tar zxvf Omada_SDN_Controller_v5.12.7_linux_x64.tar.gz&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd Omada_SDN_Controller_v5.12.7_linux_x64&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo bash ./install.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
or (Tho this seems to fail weirdly whenever they update the version while the tar.gz version doesn&amp;#039;t):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo dpkg -i ./Omada_SDN_Controller_v5.13.22_Linux_x64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
Upon install, Omada Controller will start up. Eventually. It does seem to take a VERY long time for it&amp;#039;s first start...&lt;br /&gt;
&lt;br /&gt;
https://&amp;#039;&amp;#039;&amp;#039;SERVERADDRESS&amp;#039;&amp;#039;&amp;#039;:8043/&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;font-size: 18pt; color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;CERTS!!!&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ll need to have your proper certs downloaded &amp;amp; then [https://support.tsplus.net/support/solutions/articles/44000038469-how-to-convert-different-ssl-https-certificate-formats-to-java-jks- mess with making a .PFX file from them]...&lt;br /&gt;
&lt;br /&gt;
(Really, just Part B, Step 1 at that link.)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;openssl pkcs12 -export -out &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;.pfx -inkey &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039; -in &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039; -certfile &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
Where:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is the name of your Omada server&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** Is your key file&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is your certificate file&lt;br /&gt;
&lt;br /&gt;
Then install/update via the UI &amp;amp; fully reboot the server/VM/LXC to activate it... :(&lt;br /&gt;
=== Problem(s) ===&lt;br /&gt;
Apparently, if your certs expire before you update them...&lt;br /&gt;
&lt;br /&gt;
Yer borked.&lt;br /&gt;
&lt;br /&gt;
Just so ya know...&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp; tips ==&lt;br /&gt;
=== Restarting the Omada Controller from CLI ===&lt;br /&gt;
* SSH into the container&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4125</id>
		<title>Installing TP-Link Omada SDN Controller on a Debian-based LXC</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4125"/>
		<updated>2026-01-18T21:22:28Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Notes &amp;amp; tips */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bookworm)&lt;br /&gt;
{{!}} 4 cores, 4GB RAM, 8GB storage&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Start with the prerequisites:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install openjdk-17-jre-headless jsvc curl gnupg -y&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;sudo dpkg -i libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -fsSL &amp;lt;nowiki&amp;gt;https://www.mongodb.org/static/pgp/server-4.4.asc&amp;lt;/nowiki&amp;gt; {{!}} sudo apt-key add -&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;echo &amp;quot;deb [ arch=amd64,arm64 ] &amp;lt;nowiki&amp;gt;https://repo.mongodb.org/apt/ubuntu&amp;lt;/nowiki&amp;gt; focal/mongodb-org/4.4 multiverse&amp;quot; {{!}} sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install mongodb-org&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl start mongod.service&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl enable mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Install SDN:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
NOTE: The download page (to check current versions etc...) fails to show the Linux versions if you let it redirect to country-local versions. Actua, functional download page is [https://www.tp-link.com/en/support/download/omada-software-controller/#Controller_Software here].&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.tar.gz&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tar zxvf Omada_SDN_Controller_v5.12.7_linux_x64.tar.gz&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd Omada_SDN_Controller_v5.12.7_linux_x64&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo bash ./install.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
or (Tho this seems to fail weirdly whenever they update the version while the tar.gz version doesn&amp;#039;t):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo dpkg -i ./Omada_SDN_Controller_v5.13.22_Linux_x64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
Upon install, Omada Controller will start up. Eventually. It does seem to take a VERY long time for it&amp;#039;s first start...&lt;br /&gt;
&lt;br /&gt;
https://&amp;#039;&amp;#039;&amp;#039;SERVERADDRESS&amp;#039;&amp;#039;&amp;#039;:8043/&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;font-size: 18pt; color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;CERTS!!!&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ll need to have your proper certs downloaded &amp;amp; then [https://support.tsplus.net/support/solutions/articles/44000038469-how-to-convert-different-ssl-https-certificate-formats-to-java-jks- mess with making a .PFX file from them]...&lt;br /&gt;
&lt;br /&gt;
(Really, just Part B, Step 1 at that link.)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;openssl pkcs12 -export -out &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;.pfx -inkey &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039; -in &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039; -certfile &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
Where:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is the name of your Omada server&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** Is your key file&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is your certificate file&lt;br /&gt;
&lt;br /&gt;
Then install/update via the UI &amp;amp; fully reboot the server/VM/LXC to activate it... :(&lt;br /&gt;
=== Problem(s) ===&lt;br /&gt;
Apparently, if your certs expire before you update them...&lt;br /&gt;
&lt;br /&gt;
Yer borked.&lt;br /&gt;
&lt;br /&gt;
Just so ya know...&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp; tips ==&lt;br /&gt;
=== Restarting the Omada Controller from CLI ===&lt;br /&gt;
SSH into the container&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4124</id>
		<title>Installing TP-Link Omada SDN Controller on a Debian-based LXC</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4124"/>
		<updated>2026-01-18T21:20:22Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Problem(s) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bookworm)&lt;br /&gt;
{{!}} 4 cores, 4GB RAM, 8GB storage&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Start with the prerequisites:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install openjdk-17-jre-headless jsvc curl gnupg -y&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;sudo dpkg -i libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -fsSL &amp;lt;nowiki&amp;gt;https://www.mongodb.org/static/pgp/server-4.4.asc&amp;lt;/nowiki&amp;gt; {{!}} sudo apt-key add -&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;echo &amp;quot;deb [ arch=amd64,arm64 ] &amp;lt;nowiki&amp;gt;https://repo.mongodb.org/apt/ubuntu&amp;lt;/nowiki&amp;gt; focal/mongodb-org/4.4 multiverse&amp;quot; {{!}} sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install mongodb-org&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl start mongod.service&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl enable mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Install SDN:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
NOTE: The download page (to check current versions etc...) fails to show the Linux versions if you let it redirect to country-local versions. Actua, functional download page is [https://www.tp-link.com/en/support/download/omada-software-controller/#Controller_Software here].&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.tar.gz&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tar zxvf Omada_SDN_Controller_v5.12.7_linux_x64.tar.gz&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd Omada_SDN_Controller_v5.12.7_linux_x64&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo bash ./install.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
or (Tho this seems to fail weirdly whenever they update the version while the tar.gz version doesn&amp;#039;t):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo dpkg -i ./Omada_SDN_Controller_v5.13.22_Linux_x64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
Upon install, Omada Controller will start up. Eventually. It does seem to take a VERY long time for it&amp;#039;s first start...&lt;br /&gt;
&lt;br /&gt;
https://&amp;#039;&amp;#039;&amp;#039;SERVERADDRESS&amp;#039;&amp;#039;&amp;#039;:8043/&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;font-size: 18pt; color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;CERTS!!!&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ll need to have your proper certs downloaded &amp;amp; then [https://support.tsplus.net/support/solutions/articles/44000038469-how-to-convert-different-ssl-https-certificate-formats-to-java-jks- mess with making a .PFX file from them]...&lt;br /&gt;
&lt;br /&gt;
(Really, just Part B, Step 1 at that link.)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;openssl pkcs12 -export -out &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;.pfx -inkey &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039; -in &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039; -certfile &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
Where:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is the name of your Omada server&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** Is your key file&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is your certificate file&lt;br /&gt;
&lt;br /&gt;
Then install/update via the UI &amp;amp; fully reboot the server/VM/LXC to activate it... :(&lt;br /&gt;
=== Problem(s) ===&lt;br /&gt;
Apparently, if your certs expire before you update them...&lt;br /&gt;
&lt;br /&gt;
Yer borked.&lt;br /&gt;
&lt;br /&gt;
Just so ya know...&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp; tips ==&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4123</id>
		<title>Installing TP-Link Omada SDN Controller on a Debian-based LXC</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Installing_TP-Link_Omada_SDN_Controller_on_a_Debian-based_LXC&amp;diff=4123"/>
		<updated>2026-01-18T21:19:18Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* CERTS!!! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bookworm)&lt;br /&gt;
{{!}} 4 cores, 4GB RAM, 8GB storage&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Start with the prerequisites:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install openjdk-17-jre-headless jsvc curl gnupg -y&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;sudo dpkg -i libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;curl -fsSL &amp;lt;nowiki&amp;gt;https://www.mongodb.org/static/pgp/server-4.4.asc&amp;lt;/nowiki&amp;gt; {{!}} sudo apt-key add -&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;echo &amp;quot;deb [ arch=amd64,arm64 ] &amp;lt;nowiki&amp;gt;https://repo.mongodb.org/apt/ubuntu&amp;lt;/nowiki&amp;gt; focal/mongodb-org/4.4 multiverse&amp;quot; {{!}} sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt update &amp;amp;&amp;amp; sudo apt install mongodb-org&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl start mongod.service&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl enable mongod&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Install SDN:&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
NOTE: The download page (to check current versions etc...) fails to show the Linux versions if you let it redirect to country-local versions. Actua, functional download page is [https://www.tp-link.com/en/support/download/omada-software-controller/#Controller_Software here].&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.tar.gz&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;tar zxvf Omada_SDN_Controller_v5.12.7_linux_x64.tar.gz&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd Omada_SDN_Controller_v5.12.7_linux_x64&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo bash ./install.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
or (Tho this seems to fail weirdly whenever they update the version while the tar.gz version doesn&amp;#039;t):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://static.tp-link.com/upload/software/2024/202402/20240227/Omada_SDN_Controller_v5.13.30.8_linux_x64.deb&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo dpkg -i ./Omada_SDN_Controller_v5.13.22_Linux_x64.deb&amp;lt;/code&amp;gt;&lt;br /&gt;
Upon install, Omada Controller will start up. Eventually. It does seem to take a VERY long time for it&amp;#039;s first start...&lt;br /&gt;
&lt;br /&gt;
https://&amp;#039;&amp;#039;&amp;#039;SERVERADDRESS&amp;#039;&amp;#039;&amp;#039;:8043/&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span style=&amp;quot;font-size: 18pt; color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;CERTS!!!&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ll need to have your proper certs downloaded &amp;amp; then [https://support.tsplus.net/support/solutions/articles/44000038469-how-to-convert-different-ssl-https-certificate-formats-to-java-jks- mess with making a .PFX file from them]...&lt;br /&gt;
&lt;br /&gt;
(Really, just Part B, Step 1 at that link.)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;openssl pkcs12 -export -out &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;.pfx -inkey &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039; -in &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039; -certfile &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
Where:&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURFQDN&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is the name of your Omada server&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURKEY.key&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** Is your key file&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;YOURCERT.crt&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
** is your certificate file&lt;br /&gt;
&lt;br /&gt;
Then install/update via the UI &amp;amp; fully reboot the server/VM/LXC to activate it... :(&lt;br /&gt;
=== Problem(s) ===&lt;br /&gt;
&lt;br /&gt;
== Notes &amp;amp; tips ==&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_Node-Red&amp;diff=4122</id>
		<title>Automation - Node-Red</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_Node-Red&amp;diff=4122"/>
		<updated>2025-11-23T02:18:51Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Another Note: If you find that you&amp;#039;ve outgrown Node-Reds available environment space... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bookworm)&lt;br /&gt;
{{!}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; lmde=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 65.675px;&amp;quot; {{!}} [[File:Logo LMDE.png{{!}}60px{{!}}link=https://linuxmint.com/edition.php?id=279{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} 4&lt;br /&gt;
{{!}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; linux=&amp;quot;&amp;quot; mint=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 67.5125px;&amp;quot; {{!}} [[File:Logo Mint.png{{!}}60px{{!}}link=https://linuxmint.com{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} 19.3 / 20.3&lt;br /&gt;
{{!}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; ubuntu=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 65.7px;&amp;quot; {{!}} [[File:Logo Ubuntu.png{{!}}60px{{!}}link=https://ubuntu.com/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} 20.04.3&lt;br /&gt;
{{!}}          &amp;lt;span style=&amp;quot;color:#8B0082&amp;quot;&amp;gt;issues&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; sparky=&amp;quot;&amp;quot; linux=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 65.7px;&amp;quot; {{!}} [[File:Logo Sparky.png{{!}}60px{{!}}link=https://sparkylinux.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} 5.11&lt;br /&gt;
{{!}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
[https://nodered.org/ Node-Red Web Site]&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;As always...&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Start with:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Installing Node-Red ==&lt;br /&gt;
=== Start by installing nodejs and the javascript package manager (npm) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;FFFfffuuuuuu...&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
nodejs &amp;amp; npm versions are problematic.&lt;br /&gt;
&lt;br /&gt;
For some reason, the versions available in all of the repositories tend to be out of date AND all attempts to update them fail in weird &amp;amp; wonderful ways.&lt;br /&gt;
&lt;br /&gt;
[[Getting up-to-date NodeJS &amp;amp; NPM{{!}}I have found a procedure that seems to work]]&lt;br /&gt;
&lt;br /&gt;
=== Use npm to install Node-RED ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo npm install -g node-red&amp;lt;/code&amp;gt;&lt;br /&gt;
[[File:Node-red install output (2022-05-14).png{{!}}300px{{!}}left{{!}}thumb{{!}}Latest WTF?]]&lt;br /&gt;
&amp;lt;div style=&amp;quot;clear: both&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Run it... ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;node-red&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Adding Autostart capability using SystemD ===&lt;br /&gt;
==== Then download three required files to their correct locations ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget &amp;lt;nowiki&amp;gt;https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/nodered.service&amp;lt;/nowiki&amp;gt; -O /lib/systemd/system/nodered.service&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget &amp;lt;nowiki&amp;gt;https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-start&amp;lt;/nowiki&amp;gt; -O /usr/bin/node-red-start&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo wget &amp;lt;nowiki&amp;gt;https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-stop&amp;lt;/nowiki&amp;gt; -O /usr/bin/node-red-stop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color:#4B0082&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;Note:&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; These 3 files are kinda rpi specific... =====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#4B0082&amp;quot;&amp;gt;To run as a user other than Pi, you need to edit the nodered.service file. To edit this use sudo to edit the file &amp;lt;code&amp;gt;/lib/systemd/system/nodered.service&amp;lt;/code&amp;gt; and change the lines 11, 12 and 13.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo vi /lib/systemd/system/nodered.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#4B0082&amp;quot;&amp;gt;Replace the user name &amp;quot;pi&amp;quot; with a user on your actual system...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== &amp;lt;span style=&amp;quot;color: rgb(224, 62, 45);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;Another Note:&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; If you find that you&amp;#039;ve outgrown Node-Reds available environment space... =====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;i.e.:&amp;#039;&amp;#039;&amp;#039; it starts crashing with a message like: &amp;lt;code&amp;gt;&amp;#039;&amp;#039;&amp;#039;FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; in the logs...&lt;br /&gt;
&lt;br /&gt;
You can try editing line 16 of &amp;lt;code&amp;gt;/lib/systemd/system/nodered.service&amp;lt;/code&amp;gt; and change the number 256 to something larger. (within as-yet undetermined limits...)&lt;br /&gt;
&lt;br /&gt;
Apparently, another symptom you need to do this is when you start randomly losing connection to the dashboard.&lt;br /&gt;
&lt;br /&gt;
==== make the two scripts executable ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chmod +x /usr/bin/node-red-st*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== reload the systemd daemon ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl daemon-reload&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== enable Node-RED to run automatically ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl enable nodered.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Start Node-RED ====&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl start nodered.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Securing Node-RED ==&lt;br /&gt;
&lt;br /&gt;
* [https://nodered.org/docs/security#usernamepassword-based-authentication Username/password based authentication]&lt;br /&gt;
** The suggested&amp;lt;code&amp;gt;&amp;lt;span class=&amp;quot;nx&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;adminAuth&amp;#039;&amp;#039;&amp;#039; section is already there... edit it&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;&amp;lt;span class=&amp;quot;nx&amp;quot;&amp;gt;You can create multiple users by duplicating the user object inside &amp;#039;&amp;#039;&amp;#039;users: []&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* [https://nodered.org/docs/node-red-admin Command-line Administration]&amp;lt;span class=&amp;quot;mw_htmlentity&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;(how to get &amp;#039;&amp;#039;&amp;#039;node-red-admin&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;span id=&amp;quot;Useful_management_stuff&amp;quot;&amp;gt;Useful management stuff&amp;lt;/span&amp;gt; ==&lt;br /&gt;
=== &amp;lt;span id=&amp;quot;Learn_about_the_current_service_status&amp;quot;&amp;gt;Learn about the current service status&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl status nodered.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span id=&amp;quot;.28Re-.29Start_openHAB_.28background_service.29&amp;quot;&amp;gt;(Re-)Start the Node-RED background service&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl restart nodered.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span id=&amp;quot;Stop_the_openHAB_background_service&amp;quot;&amp;gt;Stop the Node-RED background service&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo systemctl stop nodered.service&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Disable the Node-RED background service ===&lt;br /&gt;
&lt;br /&gt;
* sudo systemctl disable nodered.service&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;span&amp;gt;Get the service log since the last boot&amp;lt;/span&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo journalctl -f -u nodered.service -b -o cat&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Also ===&lt;br /&gt;
Node-RED can then be started and stopped by using the commands:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;node-red-start&amp;lt;/code&amp;gt;&lt;br /&gt;
and&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;node-red-stop&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Updating ===&lt;br /&gt;
Apparently, just run the install again...&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo npm install -g node-red&amp;lt;/code&amp;gt;&lt;br /&gt;
(pretty simple...)&lt;br /&gt;
&lt;br /&gt;
== Debugging Node-Red issues ==&lt;br /&gt;
=== ECONNRESET caused by MQTT ===&lt;br /&gt;
&amp;lt;code&amp;gt;Error: Client network socket disconnected before secure TLS connection was established&amp;lt;br&amp;gt; Error: read ECONNRESET&amp;lt;br&amp;gt; Error: read ECONNRESET&amp;lt;br&amp;gt; Error: Client network socket disconnected before secure TLS connection was established&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hhhmmm...&lt;br /&gt;
&lt;br /&gt;
=== ECONNREFUSED caused by alexa-home-conf ===&lt;br /&gt;
&amp;lt;code&amp;gt;[error] [alexa-home-conf:919d2660.bd9218] Error: connect ECONNREFUSED 34.240.81.189:8883&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Strange response from the creator:&amp;lt;span class=&amp;quot;mw_htmlentity&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; https://github.com/hardillb/node-red-contrib-alexa-home-skill/issues/51&lt;br /&gt;
&lt;br /&gt;
Doesn&amp;#039;t actually explain what&amp;#039;s going on, but it&amp;#039;s allegedly harmless. My question is:&amp;lt;span class=&amp;quot;mw_htmlentity&amp;quot;&amp;gt; Why in fuck does it want to connect to a non-functional &amp;quot;alternate endpoint&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
== Graceful restarts (maybe) ==&lt;br /&gt;
This is likely not needed when running under systemd...&lt;br /&gt;
&lt;br /&gt;
[https://nodered.org/docs/getting-started/running From the Node-Red website]&lt;br /&gt;
&lt;br /&gt;
You can start a script as a daemon. But first install &amp;lt;code&amp;gt;forever&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sudo npm install -g --unsafe-perm forever&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then issue command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;forever start /usr/local/lib/node_modules/node-red/red.js&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Things to do with Node-RED once it&amp;#039;s installed ==&lt;br /&gt;
&lt;br /&gt;
WIP:&amp;amp;nbsp; These pages will appear as I get things updated from what&amp;#039;s [[TinkerWiki:AutomationServer -_Node-Red#Things_to_do_with_Node-RED_once_it.27s_installed{{!}}on the older wiki]]...&lt;br /&gt;
* [[Node-RED_-_with_Google_Home{{!}}Node-RED with Google Home]]&lt;br /&gt;
* [[Node-RED_-_with_InfluxDB{{!}}Node-RED with InfluxDB]]&lt;br /&gt;
* [[Node-RED_-_with_Grafana{{!}}Node-RED with Grafana]]&lt;br /&gt;
&lt;br /&gt;
== Some useful Node-Red tips ==&lt;br /&gt;
&lt;br /&gt;
* [https://flows.nodered.org/flow/7c67709fecce1ad5992b695028e57646 Enable / Disable a Flow]&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Search:&amp;#039;&amp;#039;&amp;#039; [https://www.google.com/search?lei=2ZMyXJPAD8i7jwTCvrfwCw&amp;amp;q=node%20red%20function%20multiple%20inputs&amp;amp;ved=2ahUKEwiGhrqErNrfAhXk5IMKHeUMAlAQsKwBKAJ6BAgBEAM&amp;amp;biw=1260&amp;amp;bih=652 node red function multiple inputs]&lt;br /&gt;
* Node-Red stores it&amp;#039;s data in &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;~/.node-red&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* [https://discourse.nodered.org/t/palette-export-or-backup/18364 Palette Export or Backup]&lt;br /&gt;
&lt;br /&gt;
== Some interesting Node-Red Add-Ons ==&lt;br /&gt;
&lt;br /&gt;
* [https://flows.nodered.org/node/node-red-contrib-machine-learning Machine learning package for node-red]&lt;br /&gt;
* node-red-contrib-boolean-logic&lt;br /&gt;
** Create &amp;quot;Buffer&amp;quot; from &amp;quot;Invert&amp;quot;&lt;br /&gt;
* node-red-contrib-google-home-notify&lt;br /&gt;
* node-red-dashboard&lt;br /&gt;
* node-red-node-ping&lt;br /&gt;
** There seem to be other versions... possibly better...&lt;br /&gt;
* node-red-contrib-plex&lt;br /&gt;
&lt;br /&gt;
== Moving Node-Red to a new server ==&lt;br /&gt;
=== When creating a NEW server ===&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;NOTE&amp;#039;&amp;#039;&amp;#039;: If you are updating to a much newer version of Node-Red, this is not likely the best technique...&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pretty easy actually...&lt;br /&gt;
&lt;br /&gt;
Build the server &amp;amp; install everything as normal.&lt;br /&gt;
&lt;br /&gt;
Then stop the node-red service and replace ~/.npm &amp;amp; ~/node-red with copies from the old server.&lt;br /&gt;
&lt;br /&gt;
=== When Renaming a server ===&lt;br /&gt;
No longer seems to be an issue with current version of Node-Red...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;text-decoration: line-through;&amp;quot; &amp;gt;(i.e.: Moving or cloning a VM...)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;text-decoration: line-through;&amp;quot; &amp;gt;Seems to lose the flows. :(&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;text-decoration: line-through;&amp;quot; &amp;gt;They&amp;#039;re not actually lost. :)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;text-decoration: line-through;&amp;quot; &amp;gt;The flow files are named with the server name.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;text-decoration: line-through;&amp;quot; &amp;gt;You can select a flow file in &amp;lt;code&amp;gt;~/.node-red/settings.js&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;text-decoration: line-through;&amp;quot; &amp;gt;Uncomment the line that says: &amp;lt;code&amp;gt;//flowfile: &amp;#039;flows.json&amp;#039;,&amp;lt;/code&amp;gt; and change &amp;#039;&amp;#039;&amp;#039;flows.json&amp;#039;&amp;#039;&amp;#039; to the name of your actual flow file. (in the same folder...)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;text-decoration: line-through;&amp;quot; &amp;gt;Then restart node-red&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;text-decoration: line-through;&amp;quot; &amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;sudo systemctl restart nodered.service&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you are using other services on the server (i.e.: MQTT), you may run into further weirdness like having to tell nodes where to find these services. More research still required on this...&lt;br /&gt;
&lt;br /&gt;
[[Category:ServerBuilding]]&lt;br /&gt;
[[Category:AutomationServers]]&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Database_-_MariaDB&amp;diff=4121</id>
		<title>Database - MariaDB</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Database_-_MariaDB&amp;diff=4121"/>
		<updated>2025-10-12T23:33:01Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Allowing non-localhost access */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- --=&amp;quot;&amp;quot; debian=&amp;quot;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 11 (bullseye)&amp;lt;br&amp;gt;12 (bookworm)&lt;br /&gt;
{{!}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
Here in the NerdMage&amp;#039;s Lair, we have switched from mySQL to MariaDB lately.  This has been prompted by the apparent abandonment of mySQL. (Yes, this IS a primarily Debian environment...)&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Something to note:&amp;#039;&amp;#039;&amp;#039; When working with MariaDB, you will occasionally see utilities &amp;amp; such referring to mySQL.  This is normal as MariaDB is a replacement for mySQL &amp;amp; the developers have not recreated things that work for both. (in many cases, this means that commands you would expect to be based on &amp;#039;&amp;#039;&amp;#039;mariadb&amp;#039;&amp;#039;&amp;#039; will be &amp;#039;&amp;#039;&amp;#039;mysql&amp;#039;&amp;#039;&amp;#039; instead.)&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install mariadb-server mariadb-client php-mysql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Initial Configuration =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mysql_secure_installation&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;&lt;br /&gt;
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB&lt;br /&gt;
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!&lt;br /&gt;
&lt;br /&gt;
In order to log into MariaDB to secure it, we&amp;#039;ll need the current&lt;br /&gt;
password for the root user. If you&amp;#039;ve just installed MariaDB, and&lt;br /&gt;
haven&amp;#039;t set the root password yet, you should just press enter here.&lt;br /&gt;
&lt;br /&gt;
Enter current password for root (enter for none): &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Press &amp;#039;&amp;#039;&amp;#039;Enter&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;&lt;br /&gt;
OK, successfully used password, moving on...&lt;br /&gt;
&lt;br /&gt;
Setting the root password or using the unix_socket ensures that nobody&lt;br /&gt;
can log into the MariaDB root user without the proper authorisation.&lt;br /&gt;
&lt;br /&gt;
You already have your root account protected, so you can safely answer &amp;#039;n&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Switch to unix_socket authentication [Y/n]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Select &amp;#039;&amp;#039;&amp;#039;N&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;&lt;br /&gt;
 ... skipping.&lt;br /&gt;
&lt;br /&gt;
You already have your root account protected, so you can safely answer &amp;#039;n&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Change the root password? [Y/n] &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Select &amp;#039;&amp;#039;&amp;#039;N&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;&lt;br /&gt;
 ... skipping.&lt;br /&gt;
&lt;br /&gt;
By default, a MariaDB installation has an anonymous user, allowing anyone&lt;br /&gt;
to log into MariaDB without having to have a user account created for&lt;br /&gt;
them.  This is intended only for testing, and to make the installation&lt;br /&gt;
go a bit smoother.  You should remove them before moving into a&lt;br /&gt;
production environment.&lt;br /&gt;
&lt;br /&gt;
Remove anonymous users? [Y/n] &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Select &amp;#039;&amp;#039;&amp;#039;Y&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;&lt;br /&gt;
 ... Success!&lt;br /&gt;
&lt;br /&gt;
Normally, root should only be allowed to connect from &amp;#039;localhost&amp;#039;.  This&lt;br /&gt;
ensures that someone cannot guess at the root password from the network.&lt;br /&gt;
&lt;br /&gt;
Disallow root login remotely? [Y/n] &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Select &amp;#039;&amp;#039;&amp;#039;Y&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;&lt;br /&gt;
 ... Success!&lt;br /&gt;
&lt;br /&gt;
By default, MariaDB comes with a database named &amp;#039;test&amp;#039; that anyone can&lt;br /&gt;
access.  This is also intended only for testing, and should be removed&lt;br /&gt;
before moving into a production environment.&lt;br /&gt;
&lt;br /&gt;
Remove test database and access to it? [Y/n] &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Select &amp;#039;&amp;#039;&amp;#039;Y&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
(Don&amp;#039;t think I&amp;#039;ve EVER used the test database... EVER...)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;&lt;br /&gt;
 - Dropping test database...&lt;br /&gt;
 ... Success!&lt;br /&gt;
 - Removing privileges on test database...&lt;br /&gt;
 ... Success!&lt;br /&gt;
&lt;br /&gt;
Reloading the privilege tables will ensure that all changes made so far&lt;br /&gt;
will take effect immediately.&lt;br /&gt;
&lt;br /&gt;
Reload privilege tables now? [Y/n] &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Select &amp;#039;&amp;#039;&amp;#039;Y&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
This is a silly question.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;&lt;br /&gt;
 ... Success!&lt;br /&gt;
&lt;br /&gt;
Cleaning up...&lt;br /&gt;
&lt;br /&gt;
All done!  If you&amp;#039;ve completed all of the above steps, your MariaDB&lt;br /&gt;
installation should now be secure.&lt;br /&gt;
&lt;br /&gt;
Thanks for using MariaDB!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Allowing non-localhost access =&lt;br /&gt;
By default, MariaDB (like MySQL) binds to 127.0.0.1...&lt;br /&gt;
&lt;br /&gt;
This is ugly, but works for now:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;amp; change&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bind-address              = 127.0.0.1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bind-address              = &amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(where &amp;#039;&amp;#039;&amp;#039;Machine.Domain.TLD&amp;#039;&amp;#039;&amp;#039; is the FQDN or IP address of the database server itself...)&lt;br /&gt;
&lt;br /&gt;
or... you could live on the edge &amp;amp; simply do:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bind-address              = 0.0.0.0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Set up at least one database user =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mysql -u root&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE USER &amp;#039;someone&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED BY &amp;#039;password&amp;#039;;&lt;br /&gt;
FLUSH PRIVILEGES;&lt;br /&gt;
EXIT;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(&amp;#039;&amp;#039;&amp;#039;Hint:&amp;#039;&amp;#039;&amp;#039; This&amp;#039;d be a good time to create yourself as that user with your non-admin password of choice...)&lt;br /&gt;
&lt;br /&gt;
(&amp;#039;&amp;#039;&amp;#039;BONUS Hint:&amp;#039;&amp;#039;&amp;#039; Change &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;localhost&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; in that CREATE USER line with &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;%&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; if this will be a remotely accessible server...)&lt;br /&gt;
== Remotely accessed Database Server ==&lt;br /&gt;
If this is to be a remotely accessed Database Server, &amp;#039;&amp;#039;&amp;#039;&amp;#039;localhost&amp;#039;&amp;#039;&amp;#039;&amp;#039; will actually be the name/address of the remote machine you&amp;#039;ll access &amp;#039;&amp;#039;&amp;#039;from&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Possibly even &amp;#039;&amp;#039;&amp;#039;&amp;#039;%&amp;#039;&amp;#039;&amp;#039;&amp;#039; as a wildcard.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;A NOTE:&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; If you have a user @ a specific host, then add the same user @ &amp;#039;%&amp;#039;, MariaDB will not let the wildcard user have priveleges...&lt;br /&gt;
&lt;br /&gt;
= Some Reference Materials =&lt;br /&gt;
&lt;br /&gt;
*[https://www.w3schools.com/sql/default.asp SQL Tutorial]&lt;br /&gt;
*[http://g2pc1.bu.edu/~qzpeng/manual/MySQL%20Commands.htm Commands]&lt;br /&gt;
*[https://www.freecodecamp.org/news/basic-sql-commands/ Basic SQL Commands - The List of Database Queries and Statements You Should Know]&lt;br /&gt;
*[https://linuxize.com/post/how-to-manage-mysql-databases-and-users-from-the-command-line/ How to Manage MySQL Databases and Users from the Command Line]&lt;br /&gt;
*[https://www.hostinger.com/tutorials/?s=mysql Some handy tutorials]&lt;br /&gt;
**[https://www.hostinger.com/tutorials/mysql-show-users/ How to Show Users in MySQL on Linux]&lt;br /&gt;
&lt;br /&gt;
= Some Useful Things =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;(These have yet to be fully tested on &amp;#039;&amp;#039;&amp;#039;MariaDB&amp;#039;&amp;#039;&amp;#039; as opposed to &amp;#039;&amp;#039;&amp;#039;mySQL&amp;#039;&amp;#039;&amp;#039;...)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Sign into MySQL&lt;br /&gt;
**&amp;lt;code&amp;gt;sudo mysql -u root -p&amp;lt;/code&amp;gt;&lt;br /&gt;
*Restart MySQL&lt;br /&gt;
**&amp;lt;code&amp;gt;sudo systemctl restart mariadb.service&amp;lt;/code&amp;gt;&lt;br /&gt;
*Change a user password&lt;br /&gt;
**&amp;lt;code&amp;gt;ALTER USER &amp;#039;userName&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED BY &amp;#039;New-Password-Here&amp;#039;;&amp;lt;/code&amp;gt;&lt;br /&gt;
*Create a new database&lt;br /&gt;
**&amp;lt;code&amp;gt;CREATE DATABASE db_name;&amp;lt;/code&amp;gt;&lt;br /&gt;
***You will need to grant access to any new database to the appropriate user(s).  This is covered more clearly on pages where you create specific databases...&lt;br /&gt;
***&amp;lt;code&amp;gt;GRANT ALL ON db_name.* TO &amp;#039;user&amp;#039;@&amp;#039;localhost&amp;#039;;&amp;lt;/code&amp;gt;&lt;br /&gt;
***(as one example)&lt;br /&gt;
*Trash a complete database &amp;#039;&amp;#039;&amp;#039;(WARNING! DANGER! DAMAGE LIKELY!)&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
**&amp;lt;code&amp;gt;DROP DATABASE wp_Someblog;&amp;lt;/code&amp;gt;&lt;br /&gt;
*List existing databases&lt;br /&gt;
**&amp;lt;code&amp;gt;SHOW databases;&amp;lt;/code&amp;gt;&lt;br /&gt;
*List existing users&lt;br /&gt;
**&amp;lt;code&amp;gt;SELECT user,host FROM mysql.user;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Move a database from one server to another ==&lt;br /&gt;
&lt;br /&gt;
=== On the originating server: ===&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo mysql -u root -p&amp;lt;/code&amp;gt;&lt;br /&gt;
**&amp;lt;code&amp;gt;GRANT ALL ON *.* TO &amp;#039;user&amp;#039;@&amp;#039;localhost&amp;#039;;&amp;lt;/code&amp;gt;&lt;br /&gt;
**&amp;lt;code&amp;gt;FLUSH PRIVILEGES;&amp;lt;/code&amp;gt;&lt;br /&gt;
**&amp;lt;code&amp;gt;EXIT;&amp;lt;/code&amp;gt;&lt;br /&gt;
*&amp;lt;code&amp;gt;mysqldump -u user -p DBname &amp;amp;gt; DBname.sql&amp;lt;/code&amp;gt;&lt;br /&gt;
*&amp;lt;code&amp;gt;scp DBname.sql user@Machine.Domain.TLD:~&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== On the destination server: ===&lt;br /&gt;
Create the user &amp;amp; database (following the instructions for the application requiring the database)&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;mysql -u user -p DBname &amp;amp;lt; DBname.sql&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== If using a separate DB Server... ===&lt;br /&gt;
Create the user &amp;amp; database on the DB Server, then log onto the application server &amp;amp;do the following&lt;br /&gt;
&lt;br /&gt;
(You may have to backtrack &amp;amp; SCP the file to the application server... :P )&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;mysql -u user -p -h Machine.Domain.TLD DBname &amp;amp;lt; DBname.sql&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Automation_-_MQTT&amp;diff=4120</id>
		<title>Automation - MQTT</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Automation_-_MQTT&amp;diff=4120"/>
		<updated>2025-10-12T22:53:58Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* password Authentication */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: right; width: 322px;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
{{!}}+ Proven on:&lt;br /&gt;
{{!}}- &amp;lt;!-- Debian --&amp;gt;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 60px;&amp;quot; {{!}} [[File:Logo Debian.png{{!}}60px{{!}}link=https://www.debian.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 40px;&amp;quot; {{!}} 12 (bookworm)&lt;br /&gt;
{{!}} ([[#Debian / Version Caveat{{!}}caveat]])&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}- &amp;lt;!-- LMDE --&amp;gt;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 65.675px;&amp;quot; {{!}} [[File:Logo LMDE.png{{!}}60px{{!}}link=https://linuxmint.com/edition.php?id=279{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} 4&lt;br /&gt;
{{!}} ([[#Debian / Version Caveat{{!}}caveat]])&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}- &amp;lt;!-- Linux Mint --&amp;gt;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 67.5125px;&amp;quot; {{!}} [[File:Logo Mint.png{{!}}60px{{!}}link=https://linuxmint.com{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} 19.3 / 20.3&lt;br /&gt;
{{!}}&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}- &amp;lt;!-- Ubuntu --&amp;gt;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 65.7px;&amp;quot; {{!}} [[File:Logo Ubuntu.png{{!}}60px{{!}}link=https://ubuntu.com/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} 20.04.3&lt;br /&gt;
{{!}}&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}- &amp;lt;!-- Sparky Linux --&amp;gt;&lt;br /&gt;
{{!}} style=&amp;quot;text-align: center; width: 65.7px;&amp;quot; {{!}} [[File:Logo Sparky.png{{!}}60px{{!}}link=https://sparkylinux.org/{{!}}center{{!}}middle{{!}}frameless]]&lt;br /&gt;
{{!}} 5.11&lt;br /&gt;
{{!}} ([[#Debian / Version Caveat{{!}}caveat]])&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
[https://mosquitto.org/ Mosquitto MQTT Broker]&lt;br /&gt;
&lt;br /&gt;
{{{!}} class=&amp;quot;wikitable&amp;quot; style=&amp;quot;border-collapse: collapse; width: 33%; left;&amp;quot; &lt;br /&gt;
{{!}}- style=&amp;quot;text-align: center;&amp;quot;  &lt;br /&gt;
! style=&amp;quot;width: 50%;&amp;quot; colspan=&amp;quot;2&amp;quot; {{!}} As always...&lt;br /&gt;
{{!}}- &lt;br /&gt;
{{!}} {{!}}&lt;br /&gt;
Start with:&lt;br /&gt;
{{!}} {{!}}&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo apt upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
= Installing Mosquitto =&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo apt-get install mosquitto&amp;lt;/code&amp;gt;&lt;br /&gt;
Pretty simple, eh?&lt;br /&gt;
&lt;br /&gt;
(Tho...  If you want the latest &amp;amp; gratest and you&amp;#039;re feeling adventurous...  There&amp;#039;s a [[Mosquitto from Source|CopyPasta page here]].)&lt;br /&gt;
== Ensure that Mosquitto broker is running ==&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo service mosquitto status&amp;lt;/code&amp;gt;&lt;br /&gt;
expected result is &amp;lt;u&amp;gt;&amp;lt;code&amp;gt;Active: active (running)&amp;lt;/code&amp;gt;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Note: Ubuntu repositories have an outdated version ==&lt;br /&gt;
&lt;br /&gt;
If you want to know which version you&amp;#039;ve installed...&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo mosquitto&amp;lt;/code&amp;gt;&lt;br /&gt;
(Ignore the error message &amp;quot;Error: Address already in use&amp;quot;. It&amp;#039;s already running as a service.)&lt;br /&gt;
&lt;br /&gt;
= Install client tools for testing etc =&lt;br /&gt;
&lt;br /&gt;
(Do this on any machine expected to manually use MQTT)&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo apt install mosquitto-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
&lt;br /&gt;
=== In a terminal: ===&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;mosquitto_sub -h localhost -t &amp;quot;mqtt&amp;quot; -v&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== In another terminal: ===&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;code&amp;gt;mosquitto_pub -h localhost -t &amp;quot;mqtt&amp;quot; -m &amp;quot;Hello MQTT&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
Now the message “&amp;lt;code&amp;gt;mqtt Hello MQTT&amp;lt;/code&amp;gt;” will be displayed in the first terminal where the topic “&amp;#039;&amp;#039;&amp;#039;mqtt&amp;#039;&amp;#039;&amp;#039;” is subscribed.&lt;br /&gt;
&lt;br /&gt;
Subscribing to &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; gives you a subscription to everything except for topics that start with a &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; (these are normally control topics anyway).&lt;br /&gt;
&lt;br /&gt;
= Debian / Version Caveat =&lt;br /&gt;
(Ignore this if you built from source.  It&amp;#039;s apparently a repo thing...)&lt;br /&gt;
&lt;br /&gt;
During an install on a raw Debian system, I discovered that Mosquitto refused connection when I tried to access it with anything other than &amp;quot;localhost&amp;quot; as the hostname...&lt;br /&gt;
&lt;br /&gt;
Apparently, mosquitto 2.0 binds only to the loopback interface unless specifically told otherwise.&lt;br /&gt;
&lt;br /&gt;
&amp;amp; Debian installs v2.0 or higher...&lt;br /&gt;
&lt;br /&gt;
But for now, It&amp;#039;s a simple matter of editing the config file for Mosquitto.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo vi /etc/mosquitto/mosquitto.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp; add in:&lt;br /&gt;
&lt;br /&gt;
 listener 1883&lt;br /&gt;
 allow_anonymous true&lt;br /&gt;
&lt;br /&gt;
Then,&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo service mosquitto restart&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Securing the broker =&lt;br /&gt;
[https://mosquitto.org/documentation/authentication-methods/ Reference]&lt;br /&gt;
&lt;br /&gt;
Mosquitto supports password authentication...&lt;br /&gt;
&lt;br /&gt;
Simplest is:&lt;br /&gt;
&lt;br /&gt;
== password Authentication ==&lt;br /&gt;
&lt;br /&gt;
You can create a password file by:&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mosquitto_passwd -c /etc/mosquitto/SecretSquirrels &amp;#039;&amp;#039;&amp;#039;USERNAME&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
Then edit the configuration:&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo vi /etc/mosquitto/mosquitto.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
and replace &amp;lt;code&amp;gt;allow_anonymous true&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;password_file /etc/mosquitto/SecretSquirrels&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then restart the broker:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo service mosquitto restart&amp;lt;/code&amp;gt;&lt;br /&gt;
From this point, you have to provide &amp;#039;&amp;#039;&amp;#039;USERNAME&amp;#039;&amp;#039;&amp;#039; &amp;amp; &amp;#039;&amp;#039;&amp;#039;PASSWORD&amp;#039;&amp;#039;&amp;#039; to access it.&lt;br /&gt;
&lt;br /&gt;
=== Note: ===&lt;br /&gt;
The password file must be able to be read by whatever user Mosquitto is running as. On Linux/POSIX systems this will typically be the mosquitto user, and /etc/mosquitto/password_file is a good place for the file itself.&lt;br /&gt;
&lt;br /&gt;
[[Category:ServerBuilding]]&lt;br /&gt;
[[Category:AutomationServers]]&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4119</id>
		<title>CopyPasta</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=CopyPasta&amp;diff=4119"/>
		<updated>2025-10-11T19:11:43Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Get rid of Firefox-ESR */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= For doing basic setup of an LXC (or pretty much any Linux VM...) (Heck, I run these on physical machines too.): =&lt;br /&gt;
I run this set of commands &amp;#039;&amp;#039;&amp;#039;as root&amp;#039;&amp;#039;&amp;#039; on nearly every new VM or LXC I spin up. That way, I have a consistant environment to work in with all the tools I rely on.&lt;br /&gt;
&lt;br /&gt;
Note: You CAN copyPasta groups of commands all at once. BUT: in this case, everything indented (after &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;) needs to be pasted AFTER that command has run.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install sudo rsync vim curl mosquitto-clients&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/RootStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install gnupg tmux htop &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional...&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install qemu-guest-agent &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Only on VMs. (Wish it worked for LXCs as well tho...)&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;adduser &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039; sudo&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;su - &amp;#039;&amp;#039;&amp;#039;yourname&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.bashrc&amp;lt;/nowiki&amp;gt; -O .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/UserStuff/DOT.vimrc&amp;lt;/nowiki&amp;gt; -O .vimrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;mkdir bin&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;source .bashrc&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;ssh-keygen &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot;&amp;gt;### Optional... But rather handy.&amp;lt;/span&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=New System Cleanup &amp;amp; Prep=&lt;br /&gt;
Freshly installed systems usually have a bunch of stuff installed that you will never use.&lt;br /&gt;
&lt;br /&gt;
For myself, I don&amp;#039;t generally have any interest in the games. I also don&amp;#039;t use some of the Internet apps that seem important to the developers/maintainers.&lt;br /&gt;
&lt;br /&gt;
These instructions are based on running Debian with the Cinnamon Desktop Environment...&lt;br /&gt;
==Remove all the Games==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge gnome-2048 aisleriot atomix gnome-chess five-or-more hitori iagno gnome-klotski lightsoff gnome-mahjongg gnome-mines gnome-nibbles quadrapassel four-in-a-row gnome-robots gnome-sudoku swell-foop tali gnome-taquin gnome-tetravex -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Remove obsolete and/or silly Internet apps==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge hexchat pidgin transmission-gtk thunderbird -y&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt autoremove -y&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Get rid of Firefox ==&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt purge firefox*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Simplified installation techniques &amp;amp; instructions =&lt;br /&gt;
Some cross-platform software seems to have Linux installation instructions written by people who have never actually used Linux.&lt;br /&gt;
&lt;br /&gt;
(Or, at least, people who believe in making life difficult...)&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Brave Browser]] (Properly... Not FLATPAK)&lt;br /&gt;
* [[Installing TP-Link Omada SDN Controller on a Debian-based LXC]]&lt;br /&gt;
Also, many installation instructions are long-winded or confusing...&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Installing Docker on a Debian-based system]]&lt;br /&gt;
&lt;br /&gt;
= Building/Installing things from source =&lt;br /&gt;
You may have noticed that the various distro repositories tend to have outdated versions of some (most) packages. While this makes perfect sense, sometimes you want the newest features &amp;amp; fixes. (Or maybe you just want to enable something that the repo managers figured wouldn&amp;#039;t be useful...)&lt;br /&gt;
&lt;br /&gt;
Annoyingly, it is rather common for build instructions to suck really badly.&lt;br /&gt;
&lt;br /&gt;
So...&lt;br /&gt;
&lt;br /&gt;
* [[Arp-Scan from Source{{!}}Arp-Scan]]&lt;br /&gt;
* [[FreeCAD from Source{{!}}FreeCAD]]&lt;br /&gt;
* [[KiCAD from Source{{!}}KiCAD]]&lt;br /&gt;
* [[Mosquitto from Source{{!}}Mosquitto]]&lt;br /&gt;
&lt;br /&gt;
= Useful console display for Proxmox Virtual Environment =&lt;br /&gt;
I find it nice to have stats &amp;amp; such on the console of a server.  This way I can just look &amp;amp; see what&amp;#039;s happening with the machine.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;apt update&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y upgrade&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;apt -y install tmux htop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /usr/local/bin&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TMUX-console&amp;lt;/nowiki&amp;gt; -O TMUX-console&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-guestlist&amp;lt;/nowiki&amp;gt; -O TM-guestlist&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-clusterstatus&amp;lt;/nowiki&amp;gt; -O TM-clusterstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-systemstatus&amp;lt;/nowiki&amp;gt; -O TM-systemstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-UPSstatus&amp;lt;/nowiki&amp;gt; -O TM-UPSstatus&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-FixThis&amp;lt;/nowiki&amp;gt; -O TM-FixThis&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;wget &amp;lt;nowiki&amp;gt;https://www.nerdmage.ca/Downloads/PVEStuff/bin/TM-ShowMe&amp;lt;/nowiki&amp;gt; -O TM-ShowMe&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;chmod +x TM*&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to edit &amp;#039;&amp;#039;&amp;#039;TM-UPSstatus&amp;#039;&amp;#039;&amp;#039; to match local configurations (i.e. UPS name).&lt;br /&gt;
&lt;br /&gt;
Running &amp;lt;code&amp;gt;TMUX-console&amp;lt;/code&amp;gt; at the console will create a formatted screen of useful system information that you can reach by attaching to the &amp;#039;&amp;#039;&amp;#039;tmux&amp;#039;&amp;#039;&amp;#039; session from a terminal (SSH) session.&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4118</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4118"/>
		<updated>2025-10-07T14:58:35Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* One script with multiple personalities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
== When looking at a channel page: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
&lt;br /&gt;
== When watching a video: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
&lt;br /&gt;
== When watching a playlist: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Cookies! =&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
= One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo -e \\t -a = Download audio only \(into MP3 files\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
  AUDIOonly=&amp;quot;&amp;quot;&lt;br /&gt;
  FILETYPE=&amp;quot;-t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-a&amp;quot;)&lt;br /&gt;
      AUDIOonly=&amp;quot;--extract-audio --audio-format mp3 --audio-quality 0&amp;quot;&lt;br /&gt;
      FILETYPE=&amp;quot;-t mp3&amp;quot;&lt;br /&gt;
      echo Extracting audio only&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween $AUDIOonly&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description $FILETYPE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Errors noted, but not researched =&lt;br /&gt;
In console output:&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;[download]  57.7% of   15.24MiB at   65.83KiB/s ETA 01:40[download] Got error: (&amp;quot;Connection broken: ConnectionResetError(104, &amp;#039;Connection reset by peer&amp;#039;)&amp;quot;, ConnectionResetError(104, &amp;#039;Connection reset by peer&amp;#039;)). Retrying (1/10)...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In 00000000-ERRORS:&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;WARNING: [youtube] (&amp;#039;Connection aborted.&amp;#039;, RemoteDisconnected(&amp;#039;Remote end closed connection without response&amp;#039;)). Retrying (1/3)...&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4117</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4117"/>
		<updated>2025-10-07T04:26:46Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Errors noted, but not researched */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
== When looking at a channel page: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
&lt;br /&gt;
== When watching a video: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
&lt;br /&gt;
== When watching a playlist: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Cookies! =&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
= One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo -e \\t -a = Download audio only \(into MP3 files\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
  AUDIOonly=&amp;quot;&amp;quot;&lt;br /&gt;
  FORMAT=&amp;quot;-t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-a&amp;quot;)&lt;br /&gt;
      AUDIOonly=&amp;quot;--extract-audio --audio-format mp3 --audio-quality 0&amp;quot;&lt;br /&gt;
      FORMAT=&amp;quot;-t mp3&amp;quot;&lt;br /&gt;
      echo Extracting audio only&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween $AUDIOonly&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description $FORMAT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Errors noted, but not researched =&lt;br /&gt;
In console output:&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;[download]  57.7% of   15.24MiB at   65.83KiB/s ETA 01:40[download] Got error: (&amp;quot;Connection broken: ConnectionResetError(104, &amp;#039;Connection reset by peer&amp;#039;)&amp;quot;, ConnectionResetError(104, &amp;#039;Connection reset by peer&amp;#039;)). Retrying (1/10)...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In 00000000-ERRORS:&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;WARNING: [youtube] (&amp;#039;Connection aborted.&amp;#039;, RemoteDisconnected(&amp;#039;Remote end closed connection without response&amp;#039;)). Retrying (1/3)...&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4116</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4116"/>
		<updated>2025-10-07T04:25:35Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Even more options? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
== When looking at a channel page: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
&lt;br /&gt;
== When watching a video: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
&lt;br /&gt;
== When watching a playlist: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Cookies! =&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
= One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo -e \\t -a = Download audio only \(into MP3 files\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
  AUDIOonly=&amp;quot;&amp;quot;&lt;br /&gt;
  FORMAT=&amp;quot;-t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-a&amp;quot;)&lt;br /&gt;
      AUDIOonly=&amp;quot;--extract-audio --audio-format mp3 --audio-quality 0&amp;quot;&lt;br /&gt;
      FORMAT=&amp;quot;-t mp3&amp;quot;&lt;br /&gt;
      echo Extracting audio only&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween $AUDIOonly&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description $FORMAT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Errors noted, but not researched =&lt;br /&gt;
In console output:&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;[download]  57.7% of   15.24MiB at   65.83KiB/s ETA 01:40[download] Got error: (&amp;quot;Connection broken: ConnectionResetError(104, &amp;#039;Connection reset by peer&amp;#039;)&amp;quot;, ConnectionResetError(104, &amp;#039;Connection reset by peer&amp;#039;)). Retrying (1/10)...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In 00000000-ERRORS:&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;WARNING: [youtube] (&amp;#039;Connection aborted.&amp;#039;, RemoteDisconnected(&amp;#039;Remote end closed connection without response&amp;#039;)). Retrying (1/3)...&amp;lt;/niwiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4115</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4115"/>
		<updated>2025-10-06T06:38:49Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* One script with multiple personalities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
== When looking at a channel page: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
&lt;br /&gt;
== When watching a video: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
&lt;br /&gt;
== When watching a playlist: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Cookies! =&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
= One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo -e \\t -a = Download audio only \(into MP3 files\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
  AUDIOonly=&amp;quot;&amp;quot;&lt;br /&gt;
  FORMAT=&amp;quot;-t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-a&amp;quot;)&lt;br /&gt;
      AUDIOonly=&amp;quot;--extract-audio --audio-format mp3 --audio-quality 0&amp;quot;&lt;br /&gt;
      FORMAT=&amp;quot;-t mp3&amp;quot;&lt;br /&gt;
      echo Extracting audio only&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween $AUDIOonly&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description $FORMAT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4114</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4114"/>
		<updated>2025-10-06T05:08:23Z</updated>

		<summary type="html">&lt;p&gt;Tinker: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
== When looking at a channel page: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
&lt;br /&gt;
== When watching a video: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
&lt;br /&gt;
== When watching a playlist: ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Cookies! =&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
= One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4113</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4113"/>
		<updated>2025-10-06T05:05:57Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Gettin&amp;#039; Fancy... One script with multiple personalities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
= One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4112</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4112"/>
		<updated>2025-10-06T05:05:23Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* YTvid */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4111</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4111"/>
		<updated>2025-10-06T05:05:04Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* YTchan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4110</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4110"/>
		<updated>2025-10-06T04:33:22Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* About the weirdness that is YouTube naming conventions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4109</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4109"/>
		<updated>2025-10-06T04:33:06Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* YTchan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4108</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4108"/>
		<updated>2025-10-06T01:31:21Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Gettin&amp;#039; Fancy... One script with multiple personalities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  BASEdest=/mnt/Download_Space/YTDL/&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Individual_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists podcasts courses&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;$1&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=&amp;quot;$BASEdest&amp;quot;&amp;quot;_Playlists_/&amp;quot;&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
      echo $URL&lt;br /&gt;
      echo $WeirdID&lt;br /&gt;
      echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            echo VID $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            echo LIST $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                  echo CHAN $WeirdID $ACK &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4107</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4107"/>
		<updated>2025-10-05T22:30:34Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Gettin&amp;#039; Fancy... One script with multiple personalities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/$1&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Playlists_/&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
echo $URL&lt;br /&gt;
echo $WeirdID&lt;br /&gt;
echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4106</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4106"/>
		<updated>2025-10-05T22:29:16Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Gettin&amp;#039; Fancy... One script with multiple personalities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
# Playlists&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/$1&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Playlists_/&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
echo $URL&lt;br /&gt;
echo $WeirdID&lt;br /&gt;
echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4105</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4105"/>
		<updated>2025-10-05T22:08:16Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Gettin&amp;#039; Fancy... One script with multiple personalities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
# Playlists&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
#    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;mv: cannot stat \&amp;#039;*\&amp;#039;: No such file or directory\&amp;quot;&lt;br /&gt;
    echo -e \\t Don\&amp;#039;t panic. This one\&amp;#039;s just a bit of residue from the playlist folder cleanup&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/$1&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Playlists_/&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
echo $URL&lt;br /&gt;
echo $WeirdID&lt;br /&gt;
echo &amp;quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo $WeirdID &amp;gt;&amp;gt; $ARCHfile&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`find . -maxdepth 1 -regextype posix-extended -regex &amp;#039;./0+_.*&amp;#039; -type f   `&lt;br /&gt;
&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo &amp;quot;$Listname&amp;quot; already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv &amp;quot;$NAME&amp;quot; ../&amp;quot;$Listname/000 $Listname.description&amp;quot;&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4104</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4104"/>
		<updated>2025-10-05T02:55:15Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* About the weirdness that is YouTube naming conventions... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
# Playlists&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
#    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
# Possible playlist errors&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/$1&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Playlists_/&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo $URL&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`ls 0*`&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            echo &amp;quot;---$Listname---&amp;quot;&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= About the weirdness that is YouTube naming conventions =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4103</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4103"/>
		<updated>2025-10-05T02:53:37Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* About the weirdness that is YouTube naming conventions... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
# Playlists&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
#    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
# Possible playlist errors&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/$1&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Playlists_/&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo $URL&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`ls 0*`&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            echo &amp;quot;---$Listname---&amp;quot;&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= About the weirdness that is YouTube naming conventions... =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;oizvS01ovHE&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&amp;amp;list=&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
Bonus fun bit: The &amp;lt;span style=&amp;quot;color: rgb(22, 145, 121);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;bold green&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt; part is actually the name of the video being watched inside that playlist.&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4102</id>
		<title>YT-DLP Scripting</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=YT-DLP_Scripting&amp;diff=4102"/>
		<updated>2025-10-05T02:43:37Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* About the weirdness that is YouTube naming conventions... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= YTchan =&lt;br /&gt;
&lt;br /&gt;
A script for downloading entire channels...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder using the channel name(s) )&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTchan \[...option\(s\)...\] ChannelName ChannelName ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t ChannelName = The name of the channel \(as defined by YouTube\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple channels&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
  echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
  echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
  echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
#TYPES=&amp;quot;videos&amp;quot;&lt;br /&gt;
TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    CHANNEL=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on channel: $CHANNEL&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/\@$CHANNEL&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/$CHANNEL&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
        if [ -z $BOBstyle ]; then&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            mkdir $DEST/$ACK&lt;br /&gt;
          done&lt;br /&gt;
        fi&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
        for ACK in $TYPES&lt;br /&gt;
          do&lt;br /&gt;
            echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd $ACK&lt;br /&gt;
            fi&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
            # Clear out .part files&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              cd ..&lt;br /&gt;
            fi&lt;br /&gt;
          done&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this channel does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= YTvid =&lt;br /&gt;
&lt;br /&gt;
A script for downloading separate videos...&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and creates a subfolder named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
For the potentially required cookie file, see [https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies Exporting YouTube cookies]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ &amp;quot; $0 $@ &amp;quot;~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: YTvid \[...option\(s\)...\] VideoHash VideoHash ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t VideoHash = The name YouTube has given to the individual video&lt;br /&gt;
  echo -e \\t\\t \(This is gonna take some work to explain...\)&lt;br /&gt;
  echo -e \\t\\t You can specify multiple videos&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
  echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  if [ ${1} = &amp;quot;-c&amp;quot; ]; then&lt;br /&gt;
    echo Using Cookies: $COOKIEfile&lt;br /&gt;
    WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-s&amp;quot; ]; then&lt;br /&gt;
    echo Simulating&lt;br /&gt;
    SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  elif [ ${1} = &amp;quot;-r&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    LIMITrate=&amp;quot;-r $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Rate Limiting $LIMITrate&lt;br /&gt;
  elif [ ${1} = &amp;quot;-p&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    Pmin=$1&lt;br /&gt;
    shift&lt;br /&gt;
    Pmax=$1&lt;br /&gt;
    PAUSEbetween=&amp;quot;--sleep-interval $Pmin --max-sleep-interval $Pmax&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-e&amp;quot; ]; then&lt;br /&gt;
    shift&lt;br /&gt;
    TIMEspan=&amp;quot;--dateafter $1&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
    echo Time Span $TIMEspan to current&lt;br /&gt;
  elif [ ${1} = &amp;quot;-BOB&amp;quot; ]; then&lt;br /&gt;
    echo Grant Style Folder Structure&lt;br /&gt;
    BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
    shift&lt;br /&gt;
  else&lt;br /&gt;
    vidID=$1&lt;br /&gt;
    shift&lt;br /&gt;
    echo&lt;br /&gt;
    echo Working on video: $vidID&lt;br /&gt;
    echo ========================================&lt;br /&gt;
&lt;br /&gt;
URL=https://www.youtube.com/watch\?v=$vidID&lt;br /&gt;
&lt;br /&gt;
    if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
    # Weirdly, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
    # Then it gives an error while attempting the download.&lt;br /&gt;
    # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
      DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
&lt;br /&gt;
      if [ -d $DEST ]; then&lt;br /&gt;
        echo $DEST exists&lt;br /&gt;
      else&lt;br /&gt;
        echo no $DEST... Building it...&lt;br /&gt;
        mkdir $DEST&lt;br /&gt;
      fi&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      cd $DEST&lt;br /&gt;
      echo -e \(storing in $DEST\)&lt;br /&gt;
      echo&lt;br /&gt;
&lt;br /&gt;
      /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
    else&lt;br /&gt;
      echo YouTube says this video does not exist.&lt;br /&gt;
    fi   &lt;br /&gt;
  fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Clear out .part files&lt;br /&gt;
    rm -f *.part&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gettin&amp;#039; Fancy... One script with multiple personalities =&lt;br /&gt;
Yup...&lt;br /&gt;
&lt;br /&gt;
Looks even more complicated. In fact, it might even be considered kinda silly.&lt;br /&gt;
&lt;br /&gt;
(assumes your base for downloading YouTube videos is at &amp;#039;&amp;#039;&amp;#039;/mnt/Download_Space/YTDL/&amp;#039;&amp;#039;&amp;#039; and contains subfolders named &amp;#039;&amp;#039;&amp;#039;_Individual_&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;_Playlists_&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
Save this script as &amp;#039;&amp;#039;&amp;#039;YTall&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then make symbolic links to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTc&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTv&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ln -s YTall YTl&amp;lt;/code&amp;gt;&lt;br /&gt;
Call it as &amp;#039;&amp;#039;&amp;#039;YTc&amp;#039;&amp;#039;&amp;#039; for doing whole channels, &amp;#039;&amp;#039;&amp;#039;YTv&amp;#039;&amp;#039;&amp;#039; for individual videos, &amp;amp; &amp;#039;&amp;#039;&amp;#039;YTl&amp;#039;&amp;#039;&amp;#039; for playlists.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Bash&amp;quot; line copy&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
BASENAME=$(basename &amp;quot;$0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
echo -e &amp;quot;~~~~~~~ $BASENAME $@ ~~~~~~~ &amp;quot;\\n&lt;br /&gt;
&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;VideoHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the individual video&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple videos&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    TYPE=&amp;quot;ChannelName&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name of the channel \(as defined by YouTube\)&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t You can specify multiple channels&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
# Playlists&lt;br /&gt;
    TYPE=&amp;quot;ListHash&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = The name YouTube has given to the playlist&amp;quot;&lt;br /&gt;
    DESC+=&amp;quot;\n\\t\\t (This is gonna take some work to explain...)&amp;quot;&lt;br /&gt;
#    DESC+=&amp;quot;\n\\t\\t You can specify multiple lists&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
  *)&lt;br /&gt;
    TYPE=&amp;quot;poop&amp;quot;&lt;br /&gt;
    DESC=&amp;quot;$TYPE = Some crap&amp;quot;&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
&lt;br /&gt;
if [ $# -eq 0 ] || [ $1 = &amp;quot;-u&amp;quot; ] || [ $1 = &amp;quot;-?&amp;quot; ]; then&lt;br /&gt;
  echo -e USAGE: $(basename &amp;quot;$0&amp;quot;) \[...option\(s\)...\] $TYPE $TYPE ...&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e OPTIONS:&lt;br /&gt;
  echo -e \\t -BOB = Grant Style Folder Structure&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \\t -s = simulate this run&lt;br /&gt;
  echo -e \\t -c = use a cookie file exported from your browser to identify yourself.&lt;br /&gt;
  echo -e \\t -r RATE = Limit bandwidth&lt;br /&gt;
  echo -e \\t\\t Maximum download rate in bytes per second,&lt;br /&gt;
  echo -e \\t\\t\\t e.g. 50K or 4.2M&lt;br /&gt;
  echo -e \\t -p MIN MAX = Sleep interval \(pause\) between downloads \(in seconds\)&lt;br /&gt;
  echo -e \\t\\t \(will result in a random pause between MIN \&amp;amp; MAX seconds long\)&lt;br /&gt;
  echo -e \\t -e DATE = Earliest video upload date to grab.&lt;br /&gt;
  echo -e \\t\\t see https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#video-selection for format info&lt;br /&gt;
  echo -e \\t\\t \(Simplest is YYYYMMDD but fancier options exist\)&lt;br /&gt;
  echo -e \\t $DESC&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e The following \&amp;quot;ERROR\&amp;quot;s will also appear in 00000000-ERRORS&lt;br /&gt;
  echo -e \(Unfortunately, without indications of which files caused them...\)&lt;br /&gt;
  echo&lt;br /&gt;
  echo -e \&amp;quot;ERROR: unable to download video data: HTTP Error 403: Forbidden\&amp;quot;&lt;br /&gt;
  echo -e \\t Means you may need to supply cookies.&lt;br /&gt;
  echo -e \\t Often caused by things like age restrictions.&lt;br /&gt;
  echo -e \\t May also be caused by YouTube noticing you\&amp;#039;ve been downloading a bunch...&lt;br /&gt;
case $BASENAME in&lt;br /&gt;
  &amp;quot;YTc&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e \&amp;quot;ERROR: \[youtube\] oizvS01ovH0: Video unavailable\&amp;quot;&lt;br /&gt;
    echo -e \\t Most likely caused by a typo in the VideoHash&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTv&amp;quot;)&lt;br /&gt;
    echo&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a videos tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a shorts tab\&amp;quot;&lt;br /&gt;
    echo -e  \&amp;quot;ERROR: \[youtube:tab\] \@ChannelName: This channel does not have a streams tab\&amp;quot;&lt;br /&gt;
    echo -e \\t Is simply indicating that the channel doesn\&amp;#039;t have that type of content.&lt;br /&gt;
    echo -e \\t \(All 3 means the channel doesn\&amp;#039;t actually have any content... :P \)&lt;br /&gt;
  ;;&lt;br /&gt;
  &amp;quot;YTl&amp;quot;)&lt;br /&gt;
# Possible playlist errors&lt;br /&gt;
  ;;&lt;br /&gt;
esac&lt;br /&gt;
echo&lt;br /&gt;
&lt;br /&gt;
  exit&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
  COOKIEfile=/mnt/Download_Space/YTDL/www.youtube.com_cookies.txt&lt;br /&gt;
&lt;br /&gt;
  SIMULATE=&amp;quot;&amp;quot;&lt;br /&gt;
  WITHcookies=&amp;quot;&amp;quot;&lt;br /&gt;
  LIMITrate=&amp;quot;&amp;quot;&lt;br /&gt;
  PAUSEbetween=&amp;quot;&amp;quot;&lt;br /&gt;
  TIMEspan=&amp;quot;&amp;quot;&lt;br /&gt;
  BOBstyle=&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
while (( &amp;quot;$#&amp;quot; ));&lt;br /&gt;
do&lt;br /&gt;
  case $1 in&lt;br /&gt;
    &amp;quot;-c&amp;quot;)&lt;br /&gt;
      echo Using Cookies: $COOKIEfile&lt;br /&gt;
      WITHcookies=&amp;quot;--cookies &amp;quot;$COOKIEfile&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-s&amp;quot;)&lt;br /&gt;
      echo Simulating&lt;br /&gt;
      SIMULATE=&amp;quot;-s&amp;quot;&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-r&amp;quot;)&lt;br /&gt;
      LIMITrate=&amp;quot;-r $2&amp;quot;&lt;br /&gt;
      echo Rate Limiting $2&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-p&amp;quot;)&lt;br /&gt;
      PAUSEbetween=&amp;quot;--sleep-interval $2 --max-sleep-interval $3&amp;quot;&lt;br /&gt;
      echo Random pause between $2 \&amp;amp; $3 seconds&lt;br /&gt;
      shift 3&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-e&amp;quot;)&lt;br /&gt;
      TIMEspan=&amp;quot;--dateafter $2&amp;quot;&lt;br /&gt;
      echo Time Span $2 to current&lt;br /&gt;
      shift 2&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;-BOB&amp;quot;)&lt;br /&gt;
      BOBstyle=&amp;quot;True&amp;quot;&lt;br /&gt;
      echo Using Grant Style Folder Structure&lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
    *)&lt;br /&gt;
      case $BASENAME in&lt;br /&gt;
        &amp;quot;YTv&amp;quot;) # Video&lt;br /&gt;
          echo Working on video: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/watch\?v=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Individual_/&lt;br /&gt;
          FORMAT=&amp;quot;%(uploader_id)s - %(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTc&amp;quot;) # Channel&lt;br /&gt;
          echo Working on Channel: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/\@$1&lt;br /&gt;
          TYPES=&amp;quot;videos shorts streams&amp;quot;&lt;br /&gt;
#          TYPES=&amp;quot;videos shorts streams playlists&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/$1&lt;br /&gt;
          FORMAT=&amp;quot;%(upload_date)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;YTl&amp;quot;) # Playlist&lt;br /&gt;
          echo Working on playlist: $1&lt;br /&gt;
          echo ========================================&lt;br /&gt;
          WeirdID=$1&lt;br /&gt;
          URL=https://www.youtube.com/playlist\?list=$1&lt;br /&gt;
          TYPES=&amp;quot;&amp;quot;&lt;br /&gt;
          DEST=/mnt/Download_Space/YTDL/_Playlists_/&lt;br /&gt;
          FORMAT=&amp;quot;%(playlist_index)s_%(playlist_count)s %(uploader_id)s - %(title)s.%(ext)s&amp;quot;&lt;br /&gt;
        ;;&lt;br /&gt;
      esac&lt;br /&gt;
&lt;br /&gt;
      ERRfile=$DEST/00000000-ERRORS&lt;br /&gt;
      ARCHfile=$DEST/11111111-ARCHIVE&lt;br /&gt;
&lt;br /&gt;
      OPTIONS=&amp;quot;$SIMULATE $LIMITrate $TIMEspan $WITHcookies $PAUSEbetween&amp;quot;&lt;br /&gt;
      OPTIONS+=&amp;quot; --no-overwrites --write-description -t mp4&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo $URL&lt;br /&gt;
&lt;br /&gt;
      if wget --spider --quiet $URL &amp;gt; /dev/null 2&amp;gt;&amp;amp;1; then&lt;br /&gt;
        # Weirdly, for individual videos, YouTube says the URL is valid even if it doesn&amp;#039;t exist when asking about videos...&lt;br /&gt;
        # Then it gives an error while attempting the download.&lt;br /&gt;
        # Not fatal, just annoying...&lt;br /&gt;
&lt;br /&gt;
        echo -en &amp;quot;(storing in $DEST&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        case $BASENAME in&lt;br /&gt;
          &amp;quot;YTv&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTl&amp;quot;)&lt;br /&gt;
            echo &amp;quot;$WeirdID)&amp;quot;&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
            if [ -d $DEST/$WeirdID ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST$WeirdID... Building it...&lt;br /&gt;
              mkdir $DEST$WeirdID&lt;br /&gt;
            fi&lt;br /&gt;
            cd $WeirdID&lt;br /&gt;
            pwd&lt;br /&gt;
            /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
            rm -f *.part&lt;br /&gt;
&lt;br /&gt;
            NAME=`ls 0*`&lt;br /&gt;
            Listname=`echo ${NAME::-12} | cut -d&amp;#039;@&amp;#039; -f 2`&lt;br /&gt;
&lt;br /&gt;
            echo &amp;quot;---$Listname---&amp;quot;&lt;br /&gt;
&lt;br /&gt;
            if [ -d ../&amp;quot;$Listname&amp;quot; ]; then&lt;br /&gt;
              echo already exists&lt;br /&gt;
            else&lt;br /&gt;
              mkdir ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            mv * ../&amp;quot;$Listname&amp;quot;&lt;br /&gt;
            cd ..&lt;br /&gt;
            rmdir $WeirdID&lt;br /&gt;
          ;;&lt;br /&gt;
          &amp;quot;YTc&amp;quot;)&lt;br /&gt;
            echo &amp;quot;)&amp;quot;&lt;br /&gt;
            if [ -d $DEST ]; then&lt;br /&gt;
              echo $DEST exists&lt;br /&gt;
            else&lt;br /&gt;
              echo no $DEST... Building it...&lt;br /&gt;
              mkdir $DEST&lt;br /&gt;
              if [ -z $BOBstyle ]; then&lt;br /&gt;
                for ACK in $TYPES&lt;br /&gt;
                  do&lt;br /&gt;
                    mkdir $DEST/$ACK&lt;br /&gt;
                  done&lt;br /&gt;
              fi&lt;br /&gt;
            fi&lt;br /&gt;
&lt;br /&gt;
            cd $DEST&lt;br /&gt;
            pwd&lt;br /&gt;
&lt;br /&gt;
            if [ -z $BOBstyle ]; then&lt;br /&gt;
              echo -e &amp;quot;(using subfolders...)&amp;quot;&lt;br /&gt;
            else&lt;br /&gt;
              echo -e &amp;quot;(using Grant format...)&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
            echo&lt;br /&gt;
&lt;br /&gt;
            for ACK in $TYPES&lt;br /&gt;
              do&lt;br /&gt;
                echo &amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; &amp;quot; $URL/$ACK&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd $ACK&lt;br /&gt;
                fi&lt;br /&gt;
&lt;br /&gt;
                /usr/local/bin/yt-dlp $OPTIONS --download-archive $ARCHfile -o &amp;quot;$FORMAT&amp;quot; $URL/$ACK 2&amp;gt; &amp;gt;(/usr/bin/tee -a $ERRfile)&lt;br /&gt;
&lt;br /&gt;
                # Clear out .part files&lt;br /&gt;
                rm -f *.part&lt;br /&gt;
&lt;br /&gt;
                if [ -z $BOBstyle ]; then&lt;br /&gt;
                  cd ..&lt;br /&gt;
                fi&lt;br /&gt;
              done&lt;br /&gt;
          ;;&lt;br /&gt;
        esac&lt;br /&gt;
      else&lt;br /&gt;
        echo YouTube says this channel does not exist.&lt;br /&gt;
      fi   &lt;br /&gt;
      shift&lt;br /&gt;
    ;;&lt;br /&gt;
&lt;br /&gt;
  esac&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= About the weirdness that is YouTube naming conventions... =&lt;br /&gt;
When looking at a channel page:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/@&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot; &amp;gt;Tinker001&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot; &amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the channel name&lt;br /&gt;
----&lt;br /&gt;
When watching a video:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot; &amp;gt;y8o7qkmiDso&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot; &amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the video name&lt;br /&gt;
----&lt;br /&gt;
When watching a playlist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;https://www.youtube.com/watch?v=oizvS01ovHE&amp;amp;list=&amp;lt;/nowiki&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot; &amp;gt;PLLG8IgBGD4eUG2n6p3GGfkQ-KPceDuuWj&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;amp;pp=gAQB&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot; &amp;gt;bold purple&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039; part is the playlist name&lt;br /&gt;
&lt;br /&gt;
= Even more options? =&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot; &amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;span style=&amp;quot;font-size: 24pt;&amp;quot; &amp;gt;WIP&amp;lt;/span&amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
</feed>