I lost an important VCVRack patch a couple days before Mountain Skies 2019. It was based on a patch I’d gotten from patchstorage.com, but I couldn’t remember which patch it was. I tried paging through the patches on the infinite scroll, but it wasn’t helping me much. I knew the patch had Clocked and the Impromptu 16-step sequencer, but I couldn’t remember anything else about it after seriously altering it for my needs.
I decided the only option was going to have to be automated if I was going to find the base patch again in time to recreate my performance patch. I hammered out the following short Perl script to download the patches:
use strict;
use warnings;
use WWW::Mechanize;
use WWW::Mechanize::TreeBuilder;
$|++;
my $base_url = "https://patchstorage.com/platform/vcv-rack/page/";
my $mech = WWW::Mechanize->new(autocheck=>0);
WWW::Mechanize::TreeBuilder->meta->apply($mech);
use constant SLEEP_TIME => 2;
my $seq = 1;
my $working = 1;
while ($working) {
print "page $seq\n";
$mech->get($base_url.$seq);
sleep(SLEEP_TIME);
my @patch_pages = $mech->look_down('_tag', 'a');
my @patch_links = grep {
defined $_ and
!m[/upload\-a\-patch\/] and
!m[/login/] and
!m[/new\-tutorial/] and
!m[/explore/] and
!m[/registration/] and
!m[/new\-question/] and
!m[/explore/] and
!m[/platform/] and
!m[/tag/] and
!m[/author/] and
!m[/wp\-content/] and
!m[/category/] and
!/\#$/ and
!/\#respond/ and
!/\#comments/ and
!/mailto:/ and
!/\/privacy\-policy/ and
!/discord/ and
!/https:\/\/vcvrack/ and
!/javascript:/ and
!/action=lostpassword/ and
!/patchstorage.com\/$/ and
! $_ eq ''} map {$_->attr('href')} @patch_pages;
my %links;
@links{@patch_links} = ();
@patch_links = keys %links;
print scalar @patch_links, " links found\n";
for my $link (@patch_links) {
next unless $link;
print $link;
my @parts = split /\//, $link;
my $patch_name = $parts[-1];
if (-f "/Users/jmcmahon/Downloads/$patch_name") {
print "...skipped\n";
next;
}
print "\n";
$mech->get($link);
sleep(SLEEP_TIME);
my @patches = $mech->look_down('id', "DownloadPatch");
for my $patch (@patches) {
my $p_link = $patch->attr('href');
next unless $p_link;
print "$patch_name...";
$mech->get($patch->attr('href'));
sleep(SLEEP_TIME);
open my $fh, ">", "/Users/jmcmahon/Downloads/$patch_name" or die "Can't open $patch_name: $!";
print $fh $mech->content;
close $fh;
print "saved\n";
}
}
$seq++;
}
Notable items here:
- The infinite scroll is actually a chunk of Javascript wrapped around a standard WordPress page setup, so I can “page” back through the patches for Rack by incrementing the page number and pulling off the links to the actual posts with the patches in them.
- That giant grep and map cleans up the links I get off the individual pages to just the ones that are actually links to patches.
- I have a couple checks in there for “have I already downloaded this?” to allow me to restart the script if it dies partway through the process.
- The script kills itself off once it gets a page with no links on it. I haven’t actually gotten that far yet, but I think it should work.
Patchstorage folks: I apologize for scraping the site, but this is for my own use only; I”m not republishing. If I weren’t desperate to retrieve the patch for Friday I would have just left it alone.

