<?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-07-03T13:10:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=PVE_LXC_Containers&amp;diff=4157</id>
		<title>PVE LXC Containers</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=PVE_LXC_Containers&amp;diff=4157"/>
		<updated>2026-06-11T03:58:44Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Using a VPN (OpenVPN or TailScale) on an LXC */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Successful-Containers.png{{!}}300px{{!}}right{{!}}thumb]]&lt;br /&gt;
&lt;br /&gt;
So far, LXC containers are just like regular Linux (for the most part...) &amp;amp; the same procedures apply when building.&lt;br /&gt;
&lt;br /&gt;
In fact, I have created a large set of containers on my testbed server simply by following the [[Server Building{{!}}Server Building]] outlines here on this site.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;Heck... These days, I tend to default to Debian LXC containers unless there&amp;#039;s a VERY good reason to do otherwise...&amp;#039;&amp;#039;&lt;br /&gt;
= Building a Container =&lt;br /&gt;
== Templates ==&lt;br /&gt;
LXC Containers start with a template.&lt;br /&gt;
&lt;br /&gt;
For our example here, we&amp;#039;re going to start with a basic Debian 11 template.&lt;br /&gt;
&lt;br /&gt;
This means we need to ensure we have the template on the PVE host.&lt;br /&gt;
&lt;br /&gt;
* Sign into the PVE UI &amp;amp; select your &amp;#039;&amp;#039;&amp;#039;Local&amp;#039;&amp;#039;&amp;#039; datastore&lt;br /&gt;
* Select the &amp;#039;&amp;#039;&amp;#039;CT Templates&amp;#039;&amp;#039;&amp;#039; storage&lt;br /&gt;
* Click the &amp;#039;&amp;#039;&amp;#039;Templates&amp;#039;&amp;#039;&amp;#039; button&lt;br /&gt;
* Select a template package (we&amp;#039;re going with &amp;#039;&amp;#039;&amp;#039;debian-11-standard&amp;#039;&amp;#039;&amp;#039;) then hit the &amp;#039;&amp;#039;&amp;#039;Download&amp;#039;&amp;#039;&amp;#039; button&lt;br /&gt;
&lt;br /&gt;
== Creating the Container ==&lt;br /&gt;
=== Web UI method ===&lt;br /&gt;
Now that you have a template to start from, you can hit the &amp;#039;&amp;#039;&amp;#039;Create CT&amp;#039;&amp;#039;&amp;#039; button.&lt;br /&gt;
&lt;br /&gt;
For now, we&amp;#039;ll create a very basic container. I&amp;#039;ve found that most of the defaults are fine for single service applications. The only resource I&amp;#039;ve found a need to increase so far is CPU cores.&amp;amp;nbsp; Memory can be increased later if needed (as can CPU cores) and actual data storage should be handled outside of the boot disk anyhow.&lt;br /&gt;
&lt;br /&gt;
* 1st screen: choose an &amp;#039;&amp;#039;&amp;#039;ID#&amp;#039;&amp;#039;&amp;#039; and a &amp;#039;&amp;#039;&amp;#039;hostname&amp;#039;&amp;#039;&amp;#039; for the container. Then enter the password for root on this container (twice...). Then hit &amp;#039;&amp;#039;&amp;#039;Next&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 2nd screen: select the template we downloaded above. Then hit &amp;#039;&amp;#039;&amp;#039;Next&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 3rd screen: choose a storage location &amp;amp; boot disk size. Then hit &amp;#039;&amp;#039;&amp;#039;Next&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 4th screen: how many CPU cores you want available to the container. Then hit &amp;#039;&amp;#039;&amp;#039;Next&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 5th screen: how much memory you want available to the container. Then hit &amp;#039;&amp;#039;&amp;#039;Next&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 6th screen: set up networking (you&amp;#039;ll note it defaults to static addressing...&amp;amp;nbsp; silly...) Then hit &amp;#039;&amp;#039;&amp;#039;Next&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 7th screen: set up DNS (Why in heck this isn&amp;#039;t considered part of networking...) Then hit &amp;#039;&amp;#039;&amp;#039;Next&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* 8th (final) screen: Look things over to make sure they&amp;#039;re the way you want them.&amp;amp;nbsp; Possibly check the &amp;#039;&amp;#039;&amp;#039;Start after created&amp;#039;&amp;#039;&amp;#039; box. Then hit &amp;#039;&amp;#039;&amp;#039;Finish&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
=== CLI method ===&lt;br /&gt;
* &amp;lt;code&amp;gt;pct create &amp;#039;&amp;#039;&amp;#039;VMID&amp;#039;&amp;#039;&amp;#039; &amp;#039;&amp;#039;&amp;#039;TEMPLATE&amp;#039;&amp;#039;&amp;#039; --hostname &amp;#039;&amp;#039;&amp;#039;HOSTNAME&amp;#039;&amp;#039;&amp;#039; --password &amp;#039;&amp;#039;&amp;#039;PASSWORD&amp;#039;&amp;#039;&amp;#039; --rootfs &amp;#039;&amp;#039;&amp;#039;LOCATION&amp;#039;&amp;#039;&amp;#039;:&amp;#039;&amp;#039;&amp;#039;SIZE&amp;#039;&amp;#039;&amp;#039; --cores &amp;#039;&amp;#039;&amp;#039;CORES&amp;#039;&amp;#039;&amp;#039; --memory &amp;#039;&amp;#039;&amp;#039;RAM&amp;#039;&amp;#039;&amp;#039; --swap &amp;#039;&amp;#039;&amp;#039;SWAP&amp;#039;&amp;#039;&amp;#039; --unprivileged &amp;#039;&amp;#039;&amp;#039;&amp;lt;1{{!}}0&amp;gt;&amp;#039;&amp;#039;&amp;#039; --features &amp;#039;&amp;#039;&amp;#039;nesting=&amp;lt;1{{!}}0&amp;gt;&amp;#039;&amp;#039;&amp;#039; --net0 name=&amp;#039;&amp;#039;&amp;#039;eth0&amp;#039;&amp;#039;&amp;#039;,bridge=&amp;#039;&amp;#039;&amp;#039;BRIDGE&amp;#039;&amp;#039;&amp;#039;,firewall=&amp;#039;&amp;#039;&amp;#039;&amp;lt;1{{!}}0&amp;gt;&amp;#039;&amp;#039;&amp;#039;,ip=&amp;#039;&amp;#039;&amp;#039;&amp;amp;lt;(IPv4/CIDR{{!}}dhcp{{!}}manual)&amp;amp;gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* EXAMPLE (same as defaults in UI, but DHCP for IPv4 &amp;amp; unique identifiers...):&lt;br /&gt;
** &amp;lt;code&amp;gt;pct create &amp;#039;&amp;#039;&amp;#039;666&amp;#039;&amp;#039;&amp;#039; &amp;#039;&amp;#039;&amp;#039;local:vztmpl/debian-11-standard_11.6-1_amd64.tar.zst&amp;#039;&amp;#039;&amp;#039; --hostname &amp;#039;&amp;#039;&amp;#039;LXC-test&amp;#039;&amp;#039;&amp;#039; --password &amp;#039;&amp;#039;&amp;#039;nuggit&amp;#039;&amp;#039;&amp;#039; --rootfs &amp;#039;&amp;#039;&amp;#039;local-lvm&amp;#039;&amp;#039;&amp;#039;:&amp;#039;&amp;#039;&amp;#039;8&amp;#039;&amp;#039;&amp;#039; --cores &amp;#039;&amp;#039;&amp;#039;1&amp;#039;&amp;#039;&amp;#039; --memory &amp;#039;&amp;#039;&amp;#039;512&amp;#039;&amp;#039;&amp;#039; --swap &amp;#039;&amp;#039;&amp;#039;512&amp;#039;&amp;#039;&amp;#039; --unprivileged &amp;#039;&amp;#039;&amp;#039;1&amp;#039;&amp;#039;&amp;#039; --features &amp;#039;&amp;#039;&amp;#039;nesting=1&amp;#039;&amp;#039;&amp;#039; --net0 name=&amp;#039;&amp;#039;&amp;#039;eth0&amp;#039;&amp;#039;&amp;#039;,bridge=&amp;#039;&amp;#039;&amp;#039;vmbr0&amp;#039;&amp;#039;&amp;#039;,firewall=&amp;#039;&amp;#039;&amp;#039;1&amp;#039;&amp;#039;&amp;#039;,ip=&amp;#039;&amp;#039;&amp;#039;dhcp&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Many more options to be found in the man page for &amp;lt;code&amp;gt;pct&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuring &amp;amp; Using the Container ==&lt;br /&gt;
Congratulations!&lt;br /&gt;
&lt;br /&gt;
You have an LXC container.&lt;br /&gt;
&lt;br /&gt;
The only user account currently configured is root.&lt;br /&gt;
&lt;br /&gt;
There will be minor oddities, but basically, it&amp;#039;s a lightweight VM.&lt;br /&gt;
&lt;br /&gt;
At this point,, for all intents and purposes, it works just like a normal Linux VM. You can sign in at its console and set it up like you would a VM.&lt;br /&gt;
&lt;br /&gt;
I&amp;#039;d suggest adding a regular user so that you can then SSH into the container.&lt;br /&gt;
&lt;br /&gt;
I have a set of configurations that I do to pretty much every LXC container I build. Check [[CopyPasta#For_doing_basic_setup_of_an_LXC_(or_pretty_much_any_Linux_VM...):{{!}}this entry]].&lt;br /&gt;
&lt;br /&gt;
=== Root Access via SSH ===&lt;br /&gt;
By default a Proxmox LXC container allows root login only with public key authentication.&lt;br /&gt;
&lt;br /&gt;
ATM... To my knowledge, you either have to set up the public key during build of the LXC or mess about grabbing it from your work machine from inside the LXC itself.&lt;br /&gt;
&lt;br /&gt;
To login to a container with username/password login to your Proxmox host and attach to the container with the following command.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;lxc-attach --name &amp;#039;&amp;#039;&amp;#039;VMID&amp;#039;&amp;#039;&amp;#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
(Where VMID is the number of the container)&lt;br /&gt;
&lt;br /&gt;
Edit &amp;#039;&amp;#039;&amp;#039;sshd_config&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;vi /etc/ssh/sshd_config&amp;lt;/code&amp;gt;&lt;br /&gt;
and change the line &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;#PermitRootLogin without-password&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; to &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;PermitRootLogin yes&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Restart ssh service for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;service ssh restart&amp;lt;/code&amp;gt;&lt;br /&gt;
(In theory, you should be able to [[HowTo -_ssh#Make_it_easier_to_connect{{!}}set up the public key normally]] now &amp;amp; then revert the ssh_config change.)&lt;br /&gt;
&lt;br /&gt;
== Further Tricks ==&lt;br /&gt;
One useful trick is to add storage to the LXC that&amp;#039;s not managed by PVE directly. (For instance, I&amp;#039;m building an LXC for use in backing up &amp;amp; reconfiguring local machines &amp;amp; VMs. I&amp;#039;d like to use a dedicated drive in a hot-swap bay on my server.)&lt;br /&gt;
&lt;br /&gt;
Apparently, either [https://pve.proxmox.com/wiki/Linux_Container#_bind_mount_points &amp;quot;Bind Mount Points&amp;quot;] or [https://pve.proxmox.com/wiki/Linux_Container#_device_mount_points &amp;quot;Device Mount Points&amp;quot;] are the solution...&lt;br /&gt;
&lt;br /&gt;
[https://forum.proxmox.com/threads/mount-external-hdd-in-lxc-container.50897/ This thread] and [https://forum.proxmox.com/threads/container-with-physical-disk.42280/ this one] have some helpful discussion...&lt;br /&gt;
&lt;br /&gt;
= Pre-Built Containers =&lt;br /&gt;
PVE has a bunch of templates available by a company called [https://www.turnkeylinux.org/ Turnkey Linux].&amp;amp;nbsp; I&amp;#039;ve tried a couple...&amp;amp;nbsp; Not overly impressed so far, but YMMV.&lt;br /&gt;
&lt;br /&gt;
= Stumbling Blocks &amp;amp; Oddities =&lt;br /&gt;
== Time Zone Settings ==&lt;br /&gt;
Apparently, LXCs default to UTC even if your server is set to your local timezone.&lt;br /&gt;
&lt;br /&gt;
Fortunately, it&amp;#039;s not difficult to correct this.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo dpkg-reconfigure tzdata&amp;lt;/code&amp;gt;&lt;br /&gt;
or&lt;br /&gt;
* pick another method from [https://itslinuxguide.com/debian-set-timezone/ this web page].&lt;br /&gt;
&lt;br /&gt;
== DHCP / DNS Difficulties ==&lt;br /&gt;
For some reason, If I set up a container with both IPv4 &amp;amp; IPv6 using &amp;#039;&amp;#039;&amp;#039;DHCP&amp;#039;&amp;#039;&amp;#039;, resolved will &amp;lt;span style=&amp;quot;text-decoration: underline;&amp;quot;&amp;gt;ONLY use IPv6&amp;lt;/span&amp;gt;. This is kind of an issue if I want to use IPv4 DNS...&lt;br /&gt;
&lt;br /&gt;
Fortunately, simply setting IPv6 to &amp;#039;&amp;#039;&amp;#039;Static&amp;#039;&amp;#039;&amp;#039; fixes the issue.&lt;br /&gt;
&lt;br /&gt;
== Console connection from the PVE UI ==&lt;br /&gt;
LXC containers seem to default to &amp;#039;&amp;#039;&amp;#039;xterm.js&amp;#039;&amp;#039;&amp;#039; rather than the &amp;#039;&amp;#039;&amp;#039;noVNC&amp;#039;&amp;#039;&amp;#039; console standard with regular VMs.&lt;br /&gt;
&lt;br /&gt;
This isn&amp;#039;t a bad thing... Just surprised me.&lt;br /&gt;
&lt;br /&gt;
== Standard LXC containers built upon Debian seem to block non-root users from using ping... ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;ping: socket: Operation not permitted&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
[https://www.suse.com/support/kb/doc/?id=000020581 Discussion &amp;amp; a solution]&lt;br /&gt;
&lt;br /&gt;
Solution #3 seems most appropriate...&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chmod u+s /usr/bin/ping&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== LXC containers built on Debian don&amp;#039;t seem to get usbutils ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install usbutils&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Container Building Tips =&lt;br /&gt;
== Converting unpriveledged container to priveledged ==&lt;br /&gt;
# Backup the container&lt;br /&gt;
# shutdown the container&lt;br /&gt;
# restore from the backup and select &amp;quot;Priveledged&amp;quot; in the dialog.&lt;br /&gt;
&lt;br /&gt;
== Adding NFS to an LXC ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;MUST BE A PRIVELEDGED CONTAINER&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
in: Options / Features&amp;lt;br&amp;gt;enable &amp;#039;&amp;#039;&amp;#039;Nesting&amp;#039;&amp;#039;&amp;#039; and &amp;#039;&amp;#039;&amp;#039;NFS&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Then go ahead &amp;amp; [[Setting up NFS for file sharing{{!}}set up NFS as normal]].&lt;br /&gt;
&lt;br /&gt;
== Using a VPN (OpenVPN or TailScale) on an LXC ==&lt;br /&gt;
LXCs do not give access to a &amp;#039;&amp;#039;&amp;#039;/dev/tun&amp;#039;&amp;#039;&amp;#039; device &amp;amp; this is needed for Tailscale to work.&lt;br /&gt;
&lt;br /&gt;
If you&amp;#039;re running the LXC on Proxmox, You can add this feature by editing the containers configuration file.&lt;br /&gt;
&lt;br /&gt;
The following instructions are copied (and/or adapted) from [https://tailscale.com/kb/1130/lxc-unprivileged this page].&lt;br /&gt;
&lt;br /&gt;
For example, using Proxmox to host an LXC with ID 112, the following lines would be added to /etc/pve/lxc/112.conf:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;vi /etc/pve/lxc/112.conf&amp;lt;/code&amp;gt;&lt;br /&gt;
 lxc.cgroup2.devices.allow: c 10:200 rwm&lt;br /&gt;
 lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file&lt;br /&gt;
If the LXC is already running it will need to be shut down and started again for this change to take effect.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;pct reboot 112&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Side note about custom LXC templates ===&lt;br /&gt;
Sadly, if you generate a template from an LXC that you&amp;#039;ve done this with, this modification does NOT get applied to LXCs made using that template. You&amp;#039;ll have to edit the conf file of any LXC you create from that template.&lt;br /&gt;
&lt;br /&gt;
= PVE CLI Tools for LXC work... =&lt;br /&gt;
* pct (Proxmox Container Toolkit)&lt;br /&gt;
* pveam (Proxmox VE Appliance Manager)&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4156</id>
		<title>Quick Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4156"/>
		<updated>2026-06-10T20:03:15Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Tips: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sections here are really just placeholders with enough information to get started on building actual articles...&lt;br /&gt;
&lt;br /&gt;
= rDNS =&lt;br /&gt;
This is gonna get interesting...&lt;br /&gt;
&lt;br /&gt;
What does it take to make rDNS work from outside the network?&lt;br /&gt;
== Local Mail Service ==&lt;br /&gt;
(This will depend on whether rDNS works out...)&lt;br /&gt;
&lt;br /&gt;
= Better Permissions Handling =&lt;br /&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;
{{!}}      &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mkdir /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chown -R :users /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chmod -R g+ws /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m g:users:rwx /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
Now, the directory &amp;#039;&amp;#039;&amp;#039;/FOOBAR&amp;#039;&amp;#039;&amp;#039; is writeable by anyone in the &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; group.&lt;br /&gt;
&lt;br /&gt;
Do keep in mind that &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; is a default group that all accounts are a member of. You could also create specific groups and add each user to specific groups for finer granularity.&lt;br /&gt;
== Some Links ==&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Setuid Wikipedia : setuid]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Access-control_list Wikipedia : Access-control list]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/115631/getting-new-files-to-inherit-group-permissions-on-linux/115632#115632 StackExchange : Getting new files to inherit group permissions on Linux]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/93868/using-setfacl-to-create-recursive-permissions-for-apache-with-rsync/93871#93871 StackExchange : Using setfacl to create recursive permissions for Apache with rsync]&lt;br /&gt;
&lt;br /&gt;
= Linux USERs and GROUPs =&lt;br /&gt;
Eventually to be an article about how granular access control works on Linux...&lt;br /&gt;
= Development Testing for a Backup Server =&lt;br /&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;
{{!}}          &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
This will eventually be fully fleshed out as instructions for building proper backup servers on separate machines including off-site backups.&lt;br /&gt;
&lt;br /&gt;
Currently testing on a pair of LXCs, both configured as priveledged containers (tho this may not be needed).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;Interesting side-quest:&amp;#039;&amp;#039;&amp;#039; Apparently, unpriviledged containers do a bit of weirdness with bind-mount ownerships. There are &amp;lt;/span&amp;gt;[https://pve.proxmox.com/wiki/Unprivileged_LXC_containers instructions]&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt; to work around this, but I have yet to work through this... For the moment, I&amp;#039;m using priviledged containers to work around it.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VMID 999001: storage&lt;br /&gt;
* VMID 999002: backup&lt;br /&gt;
I&amp;#039;ve created a user named &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; with specific responsibility for handling backups.(because remote access by &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;root&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; is stupid...) &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; has an equivalent account on ALL involved machines and is set up with ssh keys to avoid the use of password-based access.&lt;br /&gt;
&lt;br /&gt;
== On the PVE Server: ==&lt;br /&gt;
(setting up the storage for the test LXCs...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-0 /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-1 /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;vi /etc/fstab&amp;lt;/code&amp;gt;&lt;br /&gt;
 LABEL=Storage-0     /mnt/Storage-0    ext4   defaults 0 0&lt;br /&gt;
 LABEL=Storage-1     /mnt/Storage-1    ext4   defaults 0 0&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999001 -mp0 /mnt/Storage-0,mp=/mnt/Storage	# storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999002 -mp0 /mnt/Storage-1,mp=/mnt/Storage	# backup&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;storage&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@backup&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;backup&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing &amp;#039;&amp;#039;&amp;#039;rsync&amp;#039;&amp;#039;&amp;#039; commands ==&lt;br /&gt;
In order to test things, I&amp;#039;ve basically dumped a copy of my Documents folder into &amp;#039;&amp;#039;&amp;#039;/mnt/Storage&amp;#039;&amp;#039;&amp;#039; on the &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; LXC. This is around 25GB of incredibley mixed &amp;amp; sloppy crap varying from zero-length placeholders to USB binaries...&lt;br /&gt;
&lt;br /&gt;
Everything from here on is done while logged in to &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** copies all files to the backup machine&lt;br /&gt;
*** Took about 7 minutes... (measured by wrapping the command in a &amp;#039;&amp;#039;&amp;#039;time&amp;#039;&amp;#039;&amp;#039; command)&lt;br /&gt;
** (&amp;amp; if you run it again, only copies NEW or CHANGED files)&lt;br /&gt;
*** Every change I made took substantially under 1 second...&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz --delete * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** Will actually synchronize. (i.e. It will &amp;#039;&amp;#039;&amp;#039;DELETE&amp;#039;&amp;#039;&amp;#039; any files from the destination that have been removed on the source.)&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;DANGER...DANGER...DANGER&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
*** This may NOT be exactly what you want to do in a backup situation.&lt;br /&gt;
*** (But it might... Your choice...)&lt;br /&gt;
&lt;br /&gt;
= Custom LXC Templates =&lt;br /&gt;
&lt;br /&gt;
* Create an LXC&lt;br /&gt;
** My example is an NFS capable LXC with VMID 666...&amp;lt;br&amp;gt; (You do you...)&lt;br /&gt;
* Configure it&lt;br /&gt;
** Install your preferred standard set of apps &amp;amp; such...&amp;lt;br&amp;gt; (Basically, pretend it&amp;#039;s your finished LXC &amp;amp; configure it.)&lt;br /&gt;
&lt;br /&gt;
== From the PVE command line: ==&lt;br /&gt;
* remove the network interface&lt;br /&gt;
** &amp;lt;code&amp;gt;pct set 666 --delete net0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Do a backup&lt;br /&gt;
** Gonna need a bunch of available space (I mount a spare 2TB drive specifically for the purpose on the machine where I build these and &amp;#039;&amp;#039;&amp;#039;cd&amp;#039;&amp;#039;&amp;#039; to that drive before this step...)&lt;br /&gt;
** &amp;lt;code&amp;gt;vzdump 666 --mode stop --compress zstd --dumpdir .&amp;lt;/code&amp;gt;&lt;br /&gt;
* Rename the backup to a more useful name&lt;br /&gt;
** (You&amp;#039;ll need to take a look &amp;amp; work out the exact name of the created backup file...)&lt;br /&gt;
** &amp;lt;code&amp;gt;mv &amp;#039;&amp;#039;&amp;#039;vzdump-lxc-666-2025_02_04-14_19_43.tar.zst&amp;#039;&amp;#039;&amp;#039; Deb-12-NFS.tar.zst&amp;lt;/code&amp;gt;&lt;br /&gt;
* Copy it to someplace you can access it from the PVE UI&lt;br /&gt;
** Option 1: For direct &amp;#039;&amp;#039;&amp;#039;Upload&amp;#039;&amp;#039;&amp;#039; (Some oddities happen... More research needed)&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mydesktopmachine&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:~&amp;lt;/code&amp;gt;&lt;br /&gt;
** Option 2: For &amp;#039;&amp;#039;&amp;#039;Download from URL&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mywebserver&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:/var/www/html/LXCtemplates/&amp;lt;/code&amp;gt;&lt;br /&gt;
Now you can add it to your &amp;#039;&amp;#039;&amp;#039;CT Templates&amp;#039;&amp;#039;&amp;#039; storage on any PVE server you&amp;#039;re working on.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;NOTE:&amp;#039;&amp;#039;&amp;#039; You can also directly add it to the available templates on the machine you are currently logged into...&lt;br /&gt;
* &amp;lt;code&amp;gt;cp Deb-12-NFS.tar.zst /var/lib/vz/template/cache/&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tips: ==&lt;br /&gt;
If you want to put the original back onto the network for further development, you&amp;#039;ll need to give it a new network interface. (assuming here that you&amp;#039;re using DHCP...)&lt;br /&gt;
&lt;br /&gt;
From the PVE command line:&lt;br /&gt;
*&amp;lt;code&amp;gt;pct set 666 -net0 name=net0,bridge=vmbr0,ip=dhcp&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then sign into the LXC itself and:&lt;br /&gt;
&lt;br /&gt;
(useful tip: &amp;lt;code&amp;gt;pct enter 666&amp;lt;/code&amp;gt;)&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo dhcpcd net0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Teaching RSYNC =&lt;br /&gt;
A nice little [https://www.youtube.com/watch?v=QKCIi-NxJEo intro video] by Veronica&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4155</id>
		<title>Quick Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4155"/>
		<updated>2026-06-10T19:24:41Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Custom LXC Templates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sections here are really just placeholders with enough information to get started on building actual articles...&lt;br /&gt;
&lt;br /&gt;
= rDNS =&lt;br /&gt;
This is gonna get interesting...&lt;br /&gt;
&lt;br /&gt;
What does it take to make rDNS work from outside the network?&lt;br /&gt;
== Local Mail Service ==&lt;br /&gt;
(This will depend on whether rDNS works out...)&lt;br /&gt;
&lt;br /&gt;
= Better Permissions Handling =&lt;br /&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;
{{!}}      &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mkdir /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chown -R :users /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chmod -R g+ws /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m g:users:rwx /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
Now, the directory &amp;#039;&amp;#039;&amp;#039;/FOOBAR&amp;#039;&amp;#039;&amp;#039; is writeable by anyone in the &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; group.&lt;br /&gt;
&lt;br /&gt;
Do keep in mind that &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; is a default group that all accounts are a member of. You could also create specific groups and add each user to specific groups for finer granularity.&lt;br /&gt;
== Some Links ==&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Setuid Wikipedia : setuid]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Access-control_list Wikipedia : Access-control list]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/115631/getting-new-files-to-inherit-group-permissions-on-linux/115632#115632 StackExchange : Getting new files to inherit group permissions on Linux]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/93868/using-setfacl-to-create-recursive-permissions-for-apache-with-rsync/93871#93871 StackExchange : Using setfacl to create recursive permissions for Apache with rsync]&lt;br /&gt;
&lt;br /&gt;
= Linux USERs and GROUPs =&lt;br /&gt;
Eventually to be an article about how granular access control works on Linux...&lt;br /&gt;
= Development Testing for a Backup Server =&lt;br /&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;
{{!}}          &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
This will eventually be fully fleshed out as instructions for building proper backup servers on separate machines including off-site backups.&lt;br /&gt;
&lt;br /&gt;
Currently testing on a pair of LXCs, both configured as priveledged containers (tho this may not be needed).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;Interesting side-quest:&amp;#039;&amp;#039;&amp;#039; Apparently, unpriviledged containers do a bit of weirdness with bind-mount ownerships. There are &amp;lt;/span&amp;gt;[https://pve.proxmox.com/wiki/Unprivileged_LXC_containers instructions]&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt; to work around this, but I have yet to work through this... For the moment, I&amp;#039;m using priviledged containers to work around it.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VMID 999001: storage&lt;br /&gt;
* VMID 999002: backup&lt;br /&gt;
I&amp;#039;ve created a user named &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; with specific responsibility for handling backups.(because remote access by &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;root&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; is stupid...) &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; has an equivalent account on ALL involved machines and is set up with ssh keys to avoid the use of password-based access.&lt;br /&gt;
&lt;br /&gt;
== On the PVE Server: ==&lt;br /&gt;
(setting up the storage for the test LXCs...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-0 /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-1 /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;vi /etc/fstab&amp;lt;/code&amp;gt;&lt;br /&gt;
 LABEL=Storage-0     /mnt/Storage-0    ext4   defaults 0 0&lt;br /&gt;
 LABEL=Storage-1     /mnt/Storage-1    ext4   defaults 0 0&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999001 -mp0 /mnt/Storage-0,mp=/mnt/Storage	# storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999002 -mp0 /mnt/Storage-1,mp=/mnt/Storage	# backup&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;storage&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@backup&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;backup&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing &amp;#039;&amp;#039;&amp;#039;rsync&amp;#039;&amp;#039;&amp;#039; commands ==&lt;br /&gt;
In order to test things, I&amp;#039;ve basically dumped a copy of my Documents folder into &amp;#039;&amp;#039;&amp;#039;/mnt/Storage&amp;#039;&amp;#039;&amp;#039; on the &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; LXC. This is around 25GB of incredibley mixed &amp;amp; sloppy crap varying from zero-length placeholders to USB binaries...&lt;br /&gt;
&lt;br /&gt;
Everything from here on is done while logged in to &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** copies all files to the backup machine&lt;br /&gt;
*** Took about 7 minutes... (measured by wrapping the command in a &amp;#039;&amp;#039;&amp;#039;time&amp;#039;&amp;#039;&amp;#039; command)&lt;br /&gt;
** (&amp;amp; if you run it again, only copies NEW or CHANGED files)&lt;br /&gt;
*** Every change I made took substantially under 1 second...&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz --delete * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** Will actually synchronize. (i.e. It will &amp;#039;&amp;#039;&amp;#039;DELETE&amp;#039;&amp;#039;&amp;#039; any files from the destination that have been removed on the source.)&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;DANGER...DANGER...DANGER&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
*** This may NOT be exactly what you want to do in a backup situation.&lt;br /&gt;
*** (But it might... Your choice...)&lt;br /&gt;
&lt;br /&gt;
= Custom LXC Templates =&lt;br /&gt;
&lt;br /&gt;
* Create an LXC&lt;br /&gt;
** My example is an NFS capable LXC with VMID 666...&amp;lt;br&amp;gt; (You do you...)&lt;br /&gt;
* Configure it&lt;br /&gt;
** Install your preferred standard set of apps &amp;amp; such...&amp;lt;br&amp;gt; (Basically, pretend it&amp;#039;s your finished LXC &amp;amp; configure it.)&lt;br /&gt;
&lt;br /&gt;
== From the PVE command line: ==&lt;br /&gt;
* remove the network interface&lt;br /&gt;
** &amp;lt;code&amp;gt;pct set 666 --delete net0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Do a backup&lt;br /&gt;
** Gonna need a bunch of available space (I mount a spare 2TB drive specifically for the purpose on the machine where I build these and &amp;#039;&amp;#039;&amp;#039;cd&amp;#039;&amp;#039;&amp;#039; to that drive before this step...)&lt;br /&gt;
** &amp;lt;code&amp;gt;vzdump 666 --mode stop --compress zstd --dumpdir .&amp;lt;/code&amp;gt;&lt;br /&gt;
* Rename the backup to a more useful name&lt;br /&gt;
** (You&amp;#039;ll need to take a look &amp;amp; work out the exact name of the created backup file...)&lt;br /&gt;
** &amp;lt;code&amp;gt;mv &amp;#039;&amp;#039;&amp;#039;vzdump-lxc-666-2025_02_04-14_19_43.tar.zst&amp;#039;&amp;#039;&amp;#039; Deb-12-NFS.tar.zst&amp;lt;/code&amp;gt;&lt;br /&gt;
* Copy it to someplace you can access it from the PVE UI&lt;br /&gt;
** Option 1: For direct &amp;#039;&amp;#039;&amp;#039;Upload&amp;#039;&amp;#039;&amp;#039; (Some oddities happen... More research needed)&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mydesktopmachine&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:~&amp;lt;/code&amp;gt;&lt;br /&gt;
** Option 2: For &amp;#039;&amp;#039;&amp;#039;Download from URL&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mywebserver&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:/var/www/html/LXCtemplates/&amp;lt;/code&amp;gt;&lt;br /&gt;
Now you can add it to your &amp;#039;&amp;#039;&amp;#039;CT Templates&amp;#039;&amp;#039;&amp;#039; storage on any PVE server you&amp;#039;re working on.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;NOTE:&amp;#039;&amp;#039;&amp;#039; You can also directly add it to the available templates on the machine you are currently logged into...&lt;br /&gt;
* &amp;lt;code&amp;gt;cp Deb-12-NFS.tar.zst /var/lib/vz/template/cache/&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tips: ==&lt;br /&gt;
If you want to put the original back onto the network for further development, you&amp;#039;ll need to give it a new network interface. (assuming here that you&amp;#039;re using DHCP...)&lt;br /&gt;
&lt;br /&gt;
From the PVE command line:&lt;br /&gt;
*&amp;lt;code&amp;gt;pct set 666 -net0 name=net0,bridge=vmbr0,ip=dhcp&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then sign into the LXC itself and:&lt;br /&gt;
*&amp;lt;code&amp;gt;sudo dhcpcd net0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Teaching RSYNC =&lt;br /&gt;
A nice little [https://www.youtube.com/watch?v=QKCIi-NxJEo intro video] by Veronica&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4154</id>
		<title>Quick Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4154"/>
		<updated>2026-06-10T18:21:28Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* From the PVE command line: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sections here are really just placeholders with enough information to get started on building actual articles...&lt;br /&gt;
&lt;br /&gt;
= rDNS =&lt;br /&gt;
This is gonna get interesting...&lt;br /&gt;
&lt;br /&gt;
What does it take to make rDNS work from outside the network?&lt;br /&gt;
== Local Mail Service ==&lt;br /&gt;
(This will depend on whether rDNS works out...)&lt;br /&gt;
&lt;br /&gt;
= Better Permissions Handling =&lt;br /&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;
{{!}}      &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mkdir /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chown -R :users /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chmod -R g+ws /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m g:users:rwx /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
Now, the directory &amp;#039;&amp;#039;&amp;#039;/FOOBAR&amp;#039;&amp;#039;&amp;#039; is writeable by anyone in the &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; group.&lt;br /&gt;
&lt;br /&gt;
Do keep in mind that &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; is a default group that all accounts are a member of. You could also create specific groups and add each user to specific groups for finer granularity.&lt;br /&gt;
== Some Links ==&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Setuid Wikipedia : setuid]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Access-control_list Wikipedia : Access-control list]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/115631/getting-new-files-to-inherit-group-permissions-on-linux/115632#115632 StackExchange : Getting new files to inherit group permissions on Linux]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/93868/using-setfacl-to-create-recursive-permissions-for-apache-with-rsync/93871#93871 StackExchange : Using setfacl to create recursive permissions for Apache with rsync]&lt;br /&gt;
&lt;br /&gt;
= Linux USERs and GROUPs =&lt;br /&gt;
Eventually to be an article about how granular access control works on Linux...&lt;br /&gt;
= Development Testing for a Backup Server =&lt;br /&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;
{{!}}          &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
This will eventually be fully fleshed out as instructions for building proper backup servers on separate machines including off-site backups.&lt;br /&gt;
&lt;br /&gt;
Currently testing on a pair of LXCs, both configured as priveledged containers (tho this may not be needed).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;Interesting side-quest:&amp;#039;&amp;#039;&amp;#039; Apparently, unpriviledged containers do a bit of weirdness with bind-mount ownerships. There are &amp;lt;/span&amp;gt;[https://pve.proxmox.com/wiki/Unprivileged_LXC_containers instructions]&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt; to work around this, but I have yet to work through this... For the moment, I&amp;#039;m using priviledged containers to work around it.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VMID 999001: storage&lt;br /&gt;
* VMID 999002: backup&lt;br /&gt;
I&amp;#039;ve created a user named &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; with specific responsibility for handling backups.(because remote access by &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;root&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; is stupid...) &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; has an equivalent account on ALL involved machines and is set up with ssh keys to avoid the use of password-based access.&lt;br /&gt;
&lt;br /&gt;
== On the PVE Server: ==&lt;br /&gt;
(setting up the storage for the test LXCs...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-0 /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-1 /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;vi /etc/fstab&amp;lt;/code&amp;gt;&lt;br /&gt;
 LABEL=Storage-0     /mnt/Storage-0    ext4   defaults 0 0&lt;br /&gt;
 LABEL=Storage-1     /mnt/Storage-1    ext4   defaults 0 0&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999001 -mp0 /mnt/Storage-0,mp=/mnt/Storage	# storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999002 -mp0 /mnt/Storage-1,mp=/mnt/Storage	# backup&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;storage&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@backup&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;backup&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing &amp;#039;&amp;#039;&amp;#039;rsync&amp;#039;&amp;#039;&amp;#039; commands ==&lt;br /&gt;
In order to test things, I&amp;#039;ve basically dumped a copy of my Documents folder into &amp;#039;&amp;#039;&amp;#039;/mnt/Storage&amp;#039;&amp;#039;&amp;#039; on the &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; LXC. This is around 25GB of incredibley mixed &amp;amp; sloppy crap varying from zero-length placeholders to USB binaries...&lt;br /&gt;
&lt;br /&gt;
Everything from here on is done while logged in to &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** copies all files to the backup machine&lt;br /&gt;
*** Took about 7 minutes... (measured by wrapping the command in a &amp;#039;&amp;#039;&amp;#039;time&amp;#039;&amp;#039;&amp;#039; command)&lt;br /&gt;
** (&amp;amp; if you run it again, only copies NEW or CHANGED files)&lt;br /&gt;
*** Every change I made took substantially under 1 second...&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz --delete * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** Will actually synchronize. (i.e. It will &amp;#039;&amp;#039;&amp;#039;DELETE&amp;#039;&amp;#039;&amp;#039; any files from the destination that have been removed on the source.)&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;DANGER...DANGER...DANGER&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
*** This may NOT be exactly what you want to do in a backup situation.&lt;br /&gt;
*** (But it might... Your choice...)&lt;br /&gt;
&lt;br /&gt;
= Custom LXC Templates =&lt;br /&gt;
&lt;br /&gt;
* Create an LXC&lt;br /&gt;
** My example is an NFS capable LXC with VMID 666...&amp;lt;br&amp;gt; (You do you...)&lt;br /&gt;
* Configure it&lt;br /&gt;
** Install your preferred standard set of apps &amp;amp; such...&amp;lt;br&amp;gt; (Basically, pretend it&amp;#039;s your finished LXC &amp;amp; configure it.)&lt;br /&gt;
&lt;br /&gt;
== From the PVE command line: ==&lt;br /&gt;
* remove the network interface&lt;br /&gt;
** &amp;lt;code&amp;gt;pct set 666 --delete net0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Do a backup&lt;br /&gt;
** Gonna need a bunch of available space (I mount a spare 2TB drive specifically for the purpose on the machine where I build these and &amp;#039;&amp;#039;&amp;#039;cd&amp;#039;&amp;#039;&amp;#039; to that drive before this step...)&lt;br /&gt;
** &amp;lt;code&amp;gt;vzdump 666 --mode stop --compress zstd --dumpdir .&amp;lt;/code&amp;gt;&lt;br /&gt;
* Rename the backup to a more useful name&lt;br /&gt;
** (You&amp;#039;ll need to take a look &amp;amp; work out the exact name of the created backup file...)&lt;br /&gt;
** &amp;lt;code&amp;gt;mv &amp;#039;&amp;#039;&amp;#039;vzdump-lxc-666-2025_02_04-14_19_43.tar.zst&amp;#039;&amp;#039;&amp;#039; Deb-12-NFS.tar.zst&amp;lt;/code&amp;gt;&lt;br /&gt;
* Copy it to someplace you can access it from the PVE UI&lt;br /&gt;
** Option 1: For direct &amp;#039;&amp;#039;&amp;#039;Upload&amp;#039;&amp;#039;&amp;#039; (Some oddities happen... More research needed)&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mydesktopmachine&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:~&amp;lt;/code&amp;gt;&lt;br /&gt;
** Option 2: For &amp;#039;&amp;#039;&amp;#039;Download from URL&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mywebserver&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:/var/www/html/LXCtemplates/&amp;lt;/code&amp;gt;&lt;br /&gt;
Now you can add it to your &amp;#039;&amp;#039;&amp;#039;CT Templates&amp;#039;&amp;#039;&amp;#039; storage on any PVE server you&amp;#039;re working on.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;NOTE:&amp;#039;&amp;#039;&amp;#039; You can also directly add it to the available templates on the machine you are currently logged into...&lt;br /&gt;
* &amp;lt;code&amp;gt;cp Deb-12-NFS.tar.zst /var/lib/vz/template/cache/&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Teaching RSYNC =&lt;br /&gt;
A nice little [https://www.youtube.com/watch?v=QKCIi-NxJEo intro video] by Veronica&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4153</id>
		<title>Quick Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4153"/>
		<updated>2026-06-10T18:11:24Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* Custom LXC Templates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sections here are really just placeholders with enough information to get started on building actual articles...&lt;br /&gt;
&lt;br /&gt;
= rDNS =&lt;br /&gt;
This is gonna get interesting...&lt;br /&gt;
&lt;br /&gt;
What does it take to make rDNS work from outside the network?&lt;br /&gt;
== Local Mail Service ==&lt;br /&gt;
(This will depend on whether rDNS works out...)&lt;br /&gt;
&lt;br /&gt;
= Better Permissions Handling =&lt;br /&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;
{{!}}      &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mkdir /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chown -R :users /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chmod -R g+ws /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m g:users:rwx /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
Now, the directory &amp;#039;&amp;#039;&amp;#039;/FOOBAR&amp;#039;&amp;#039;&amp;#039; is writeable by anyone in the &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; group.&lt;br /&gt;
&lt;br /&gt;
Do keep in mind that &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; is a default group that all accounts are a member of. You could also create specific groups and add each user to specific groups for finer granularity.&lt;br /&gt;
== Some Links ==&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Setuid Wikipedia : setuid]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Access-control_list Wikipedia : Access-control list]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/115631/getting-new-files-to-inherit-group-permissions-on-linux/115632#115632 StackExchange : Getting new files to inherit group permissions on Linux]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/93868/using-setfacl-to-create-recursive-permissions-for-apache-with-rsync/93871#93871 StackExchange : Using setfacl to create recursive permissions for Apache with rsync]&lt;br /&gt;
&lt;br /&gt;
= Linux USERs and GROUPs =&lt;br /&gt;
Eventually to be an article about how granular access control works on Linux...&lt;br /&gt;
= Development Testing for a Backup Server =&lt;br /&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;
{{!}}          &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
This will eventually be fully fleshed out as instructions for building proper backup servers on separate machines including off-site backups.&lt;br /&gt;
&lt;br /&gt;
Currently testing on a pair of LXCs, both configured as priveledged containers (tho this may not be needed).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;Interesting side-quest:&amp;#039;&amp;#039;&amp;#039; Apparently, unpriviledged containers do a bit of weirdness with bind-mount ownerships. There are &amp;lt;/span&amp;gt;[https://pve.proxmox.com/wiki/Unprivileged_LXC_containers instructions]&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt; to work around this, but I have yet to work through this... For the moment, I&amp;#039;m using priviledged containers to work around it.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VMID 999001: storage&lt;br /&gt;
* VMID 999002: backup&lt;br /&gt;
I&amp;#039;ve created a user named &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; with specific responsibility for handling backups.(because remote access by &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;root&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; is stupid...) &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; has an equivalent account on ALL involved machines and is set up with ssh keys to avoid the use of password-based access.&lt;br /&gt;
&lt;br /&gt;
== On the PVE Server: ==&lt;br /&gt;
(setting up the storage for the test LXCs...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-0 /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-1 /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;vi /etc/fstab&amp;lt;/code&amp;gt;&lt;br /&gt;
 LABEL=Storage-0     /mnt/Storage-0    ext4   defaults 0 0&lt;br /&gt;
 LABEL=Storage-1     /mnt/Storage-1    ext4   defaults 0 0&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999001 -mp0 /mnt/Storage-0,mp=/mnt/Storage	# storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999002 -mp0 /mnt/Storage-1,mp=/mnt/Storage	# backup&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;storage&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@backup&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;backup&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing &amp;#039;&amp;#039;&amp;#039;rsync&amp;#039;&amp;#039;&amp;#039; commands ==&lt;br /&gt;
In order to test things, I&amp;#039;ve basically dumped a copy of my Documents folder into &amp;#039;&amp;#039;&amp;#039;/mnt/Storage&amp;#039;&amp;#039;&amp;#039; on the &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; LXC. This is around 25GB of incredibley mixed &amp;amp; sloppy crap varying from zero-length placeholders to USB binaries...&lt;br /&gt;
&lt;br /&gt;
Everything from here on is done while logged in to &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** copies all files to the backup machine&lt;br /&gt;
*** Took about 7 minutes... (measured by wrapping the command in a &amp;#039;&amp;#039;&amp;#039;time&amp;#039;&amp;#039;&amp;#039; command)&lt;br /&gt;
** (&amp;amp; if you run it again, only copies NEW or CHANGED files)&lt;br /&gt;
*** Every change I made took substantially under 1 second...&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz --delete * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** Will actually synchronize. (i.e. It will &amp;#039;&amp;#039;&amp;#039;DELETE&amp;#039;&amp;#039;&amp;#039; any files from the destination that have been removed on the source.)&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;DANGER...DANGER...DANGER&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
*** This may NOT be exactly what you want to do in a backup situation.&lt;br /&gt;
*** (But it might... Your choice...)&lt;br /&gt;
&lt;br /&gt;
= Custom LXC Templates =&lt;br /&gt;
&lt;br /&gt;
* Create an LXC&lt;br /&gt;
** My example is an NFS capable LXC with VMID 666...&amp;lt;br&amp;gt; (You do you...)&lt;br /&gt;
* Configure it&lt;br /&gt;
** Install your preferred standard set of apps &amp;amp; such...&amp;lt;br&amp;gt; (Basically, pretend it&amp;#039;s your finished LXC &amp;amp; configure it.)&lt;br /&gt;
&lt;br /&gt;
== From the PVE command line: ==&lt;br /&gt;
* remove the network interface&lt;br /&gt;
** &amp;lt;code&amp;gt;pct set 666 --delete net0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Do a backup&lt;br /&gt;
** Gonna need a bunch of available space (I mount a spare 2TB drive specifically for the purpose on the machine where I build these and &amp;#039;&amp;#039;&amp;#039;cd&amp;#039;&amp;#039;&amp;#039; to that drive before this step...)&lt;br /&gt;
** &amp;lt;code&amp;gt;vzdump 666 --mode stop --compress zstd --dumpdir .&amp;lt;/code&amp;gt;&lt;br /&gt;
* Rename the backup to a more useful name&lt;br /&gt;
** &amp;lt;code&amp;gt;mv vzdump-lxc-666-2025_02_04-14_19_43.tar.zst Deb-12-NFS.tar.zst&amp;lt;/code&amp;gt;&lt;br /&gt;
* Copy it to someplace you can access it from the PVE UI&lt;br /&gt;
** Option 1: For direct &amp;#039;&amp;#039;&amp;#039;Upload&amp;#039;&amp;#039;&amp;#039; (Some oddities happen... More research needed)&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mydesktopmachine&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:~&amp;lt;/code&amp;gt;&lt;br /&gt;
** Option 2: For &amp;#039;&amp;#039;&amp;#039;Download from URL&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mywebserver&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:/var/www/html/LXCtemplates/&amp;lt;/code&amp;gt;&lt;br /&gt;
Now you can add it to your &amp;#039;&amp;#039;&amp;#039;CT Templates&amp;#039;&amp;#039;&amp;#039; storage on any PVE server you&amp;#039;re working on.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;NOTE:&amp;#039;&amp;#039;&amp;#039; You can also directly add it to the available templates on the machine you are currently logged into...&lt;br /&gt;
* &amp;lt;code&amp;gt;cp Deb-12-NFS.tar.zst /var/lib/vz/template/cache/&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Teaching RSYNC =&lt;br /&gt;
A nice little [https://www.youtube.com/watch?v=QKCIi-NxJEo intro video] by Veronica&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<entry>
		<id>https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4152</id>
		<title>Quick Notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.nerdmage.ca/index.php?title=Quick_Notes&amp;diff=4152"/>
		<updated>2026-06-10T18:09:17Z</updated>

		<summary type="html">&lt;p&gt;Tinker: /* From the PVE command line: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sections here are really just placeholders with enough information to get started on building actual articles...&lt;br /&gt;
&lt;br /&gt;
= rDNS =&lt;br /&gt;
This is gonna get interesting...&lt;br /&gt;
&lt;br /&gt;
What does it take to make rDNS work from outside the network?&lt;br /&gt;
== Local Mail Service ==&lt;br /&gt;
(This will depend on whether rDNS works out...)&lt;br /&gt;
&lt;br /&gt;
= Better Permissions Handling =&lt;br /&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;
{{!}}      &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo mkdir /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chown -R :users /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo chmod -R g+ws /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m g:users:rwx /FOOBAR&amp;lt;/code&amp;gt;&lt;br /&gt;
Now, the directory &amp;#039;&amp;#039;&amp;#039;/FOOBAR&amp;#039;&amp;#039;&amp;#039; is writeable by anyone in the &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; group.&lt;br /&gt;
&lt;br /&gt;
Do keep in mind that &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; is a default group that all accounts are a member of. You could also create specific groups and add each user to specific groups for finer granularity.&lt;br /&gt;
== Some Links ==&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Setuid Wikipedia : setuid]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Access-control_list Wikipedia : Access-control list]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/115631/getting-new-files-to-inherit-group-permissions-on-linux/115632#115632 StackExchange : Getting new files to inherit group permissions on Linux]&lt;br /&gt;
* [https://unix.stackexchange.com/questions/93868/using-setfacl-to-create-recursive-permissions-for-apache-with-rsync/93871#93871 StackExchange : Using setfacl to create recursive permissions for Apache with rsync]&lt;br /&gt;
&lt;br /&gt;
= Linux USERs and GROUPs =&lt;br /&gt;
Eventually to be an article about how granular access control works on Linux...&lt;br /&gt;
= Development Testing for a Backup Server =&lt;br /&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;
{{!}}          &amp;lt;br&amp;gt;&lt;br /&gt;
{{!}}}&lt;br /&gt;
This will eventually be fully fleshed out as instructions for building proper backup servers on separate machines including off-site backups.&lt;br /&gt;
&lt;br /&gt;
Currently testing on a pair of LXCs, both configured as priveledged containers (tho this may not be needed).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;Interesting side-quest:&amp;#039;&amp;#039;&amp;#039; Apparently, unpriviledged containers do a bit of weirdness with bind-mount ownerships. There are &amp;lt;/span&amp;gt;[https://pve.proxmox.com/wiki/Unprivileged_LXC_containers instructions]&amp;lt;span style=&amp;quot;color: rgb(132, 63, 161);&amp;quot;&amp;gt; to work around this, but I have yet to work through this... For the moment, I&amp;#039;m using priviledged containers to work around it.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* VMID 999001: storage&lt;br /&gt;
* VMID 999002: backup&lt;br /&gt;
I&amp;#039;ve created a user named &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; with specific responsibility for handling backups.(because remote access by &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;root&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; is stupid...) &lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039; has an equivalent account on ALL involved machines and is set up with ssh keys to avoid the use of password-based access.&lt;br /&gt;
&lt;br /&gt;
== On the PVE Server: ==&lt;br /&gt;
(setting up the storage for the test LXCs...)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mkdir /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-0 /mnt/Storage-0&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;mount -L Storage-1 /mnt/Storage-1&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;vi /etc/fstab&amp;lt;/code&amp;gt;&lt;br /&gt;
 LABEL=Storage-0     /mnt/Storage-0    ext4   defaults 0 0&lt;br /&gt;
 LABEL=Storage-1     /mnt/Storage-1    ext4   defaults 0 0&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999001 -mp0 /mnt/Storage-0,mp=/mnt/Storage	# storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;pct set 999002 -mp0 /mnt/Storage-1,mp=/mnt/Storage	# backup&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;storage&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@backup&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On &amp;quot;backup&amp;quot; ==&lt;br /&gt;
(logged in as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;)&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-keygen&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;ssh-copy-id &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo apt install acl rsync&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;sudo setfacl -R -m u:&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:rwx /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Testing &amp;#039;&amp;#039;&amp;#039;rsync&amp;#039;&amp;#039;&amp;#039; commands ==&lt;br /&gt;
In order to test things, I&amp;#039;ve basically dumped a copy of my Documents folder into &amp;#039;&amp;#039;&amp;#039;/mnt/Storage&amp;#039;&amp;#039;&amp;#039; on the &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; LXC. This is around 25GB of incredibley mixed &amp;amp; sloppy crap varying from zero-length placeholders to USB binaries...&lt;br /&gt;
&lt;br /&gt;
Everything from here on is done while logged in to &amp;#039;&amp;#039;&amp;#039;storage&amp;#039;&amp;#039;&amp;#039; as &amp;#039;&amp;#039;&amp;#039;draal&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* &amp;lt;code&amp;gt;cd /mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** copies all files to the backup machine&lt;br /&gt;
*** Took about 7 minutes... (measured by wrapping the command in a &amp;#039;&amp;#039;&amp;#039;time&amp;#039;&amp;#039;&amp;#039; command)&lt;br /&gt;
** (&amp;amp; if you run it again, only copies NEW or CHANGED files)&lt;br /&gt;
*** Every change I made took substantially under 1 second...&lt;br /&gt;
* &amp;lt;code&amp;gt;rsync -Aaiz --delete * backup:/mnt/Storage&amp;lt;/code&amp;gt;&lt;br /&gt;
** Will actually synchronize. (i.e. It will &amp;#039;&amp;#039;&amp;#039;DELETE&amp;#039;&amp;#039;&amp;#039; any files from the destination that have been removed on the source.)&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color: rgb(186, 55, 42);&amp;quot;&amp;gt;&amp;#039;&amp;#039;&amp;#039;DANGER...DANGER...DANGER&amp;#039;&amp;#039;&amp;#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
*** This may NOT be exactly what you want to do in a backup situation.&lt;br /&gt;
*** (But it might... Your choice...)&lt;br /&gt;
&lt;br /&gt;
= Custom LXC Templates =&lt;br /&gt;
&lt;br /&gt;
* Create an LXC&lt;br /&gt;
** My example is an NFS capable LXC with VMID 666...&lt;br /&gt;
* Configure it&lt;br /&gt;
** Install your preferred standard set of apps &amp;amp; such...&lt;br /&gt;
&lt;br /&gt;
== From the PVE command line: ==&lt;br /&gt;
* remove the network interface&lt;br /&gt;
** &amp;lt;code&amp;gt;pct set 666 --delete net0&amp;lt;/code&amp;gt;&lt;br /&gt;
* Do a backup&lt;br /&gt;
** Gonna need a bunch of available space (I mount a spare 2TB drive specifically for the purpose on the machine where I build these and &amp;#039;&amp;#039;&amp;#039;cd&amp;#039;&amp;#039;&amp;#039; to that drive before this step...)&lt;br /&gt;
** &amp;lt;code&amp;gt;vzdump 666 --mode stop --compress zstd --dumpdir .&amp;lt;/code&amp;gt;&lt;br /&gt;
* Rename the backup to a more useful name&lt;br /&gt;
** &amp;lt;code&amp;gt;mv vzdump-lxc-666-2025_02_04-14_19_43.tar.zst Deb-12-NFS.tar.zst&amp;lt;/code&amp;gt;&lt;br /&gt;
* Copy it to someplace you can access it from the PVE UI&lt;br /&gt;
** Option 1: For direct &amp;#039;&amp;#039;&amp;#039;Upload&amp;#039;&amp;#039;&amp;#039; (Some oddities happen... More research needed)&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mydesktopmachine&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:~&amp;lt;/code&amp;gt;&lt;br /&gt;
** Option 2: For &amp;#039;&amp;#039;&amp;#039;Download from URL&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
*** &amp;lt;code&amp;gt;scp Deb-12-NFS.tar.zst &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;user&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;@&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;mywebserver&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;:/var/www/html/LXCtemplates/&amp;lt;/code&amp;gt;&lt;br /&gt;
Now you can add it to your &amp;#039;&amp;#039;&amp;#039;CT Templates&amp;#039;&amp;#039;&amp;#039; storage on any PVE server you&amp;#039;re working on.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;NOTE:&amp;#039;&amp;#039;&amp;#039; You can also directly add it to the available templates on the machine you are currently logged into...&lt;br /&gt;
* &amp;lt;code&amp;gt;cp Deb-12-NFS.tar.zst /var/lib/vz/template/cache/&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Teaching RSYNC =&lt;br /&gt;
A nice little [https://www.youtube.com/watch?v=QKCIi-NxJEo intro video] by Veronica&lt;/div&gt;</summary>
		<author><name>Tinker</name></author>
	</entry>
	<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>
</feed>