This is anything but a one-liner, but it's what I use to rotate
my desktop image. It walks a file tree looking for subdirs and image
files, keeping them separate so the chance of descent remains stable
reagrdless of how many items there are in a given directory. It also
lets you put weights on files, and mark files/directories you want to
ignore.
This version happens to link the selected file from a known location, but it would be easy to replace that with code that redirects browsers the file's URL.
#!/usr/local/bin/perl -w
## set up some globals
$BASE = '/base/of-the/image/path'; ## base image directory
$LINK = "$BASE/desktop.jpg"; ## the target image
$GO_DOWN = 0.70; ## dig deeper 70% of the time
$TRY_LIMIT = 1000; ## stop after 1000 tries, max
$current = "$BASE";
## set up a path heirarchy
@P = ($current);
## set up a loop counter
$N = 0;
while (($N++ < $TRY_LIMIT) && (-d $current)) {
## read the directory
opendir (DIR, $current) or die qq(can't read "$current": $!);
@D = grep {
(!/^\./) && ## exclude hidden files
(!/^#/) ## exclude user-selected files
} readdir DIR;
closedir DIR;
## get a list of subirs
$d = []; @$d = grep { -d "$current/$_" } @D;
## get a list of '*.jpg' files
$j = []; @$j = grep { /.jpg$/i } @D;
## assemble a list of weights..
#
# the basic idea is to give some items a higher chance
# of being chosen than others. if a filename begins
# with a number N, the program's decision table will
# contain N copies of that filename.
#
# we start by building a table with N-1 entries for
# each item that does start with a number, then finish
# off by adding the whole file list to the table.
#
@w = ();
for $f (@$d) {
if ($f =~ /^(\d+)/) {
push @w, ($f) x ($1 - 1);
}
}
push @$d, @w;
## decide whether to choose a file from this directory,
## or to pick a random directory and drill down again.
#
# note that we may end up choosing an empty list..
# therefore we check the list we choose to make sure
# it does contain something, and if it doesn't, we
# deal with it.
#
# the first stage of dealing with it is to fall back
# to the other option.. if we chose to drill deeper and
# in a directory with no subdirs, we fall back to
# selecting a random image. if we chose to select an
# image in a directory that only contains subdirs, we
# fall back to drilling deeper.
#
# the second stage of dealing with it.. which occurs
# if we hit an empty directory.. is to back out one
# level and try again.
#
# in the pathological case, where you run this loop
# on the base of a file tree that contains no .jpg
# files at all, the loop counter will force termination
# after $TRY_LIMIT tries.
#
($l, $r) = (rand() < $GO_DOWN) ? ($d, $j) : ($j, $d);
$list = (@$l) ? $l : $r;
if (@$list) {
push @P, $list->[ rand (@$list) ];
} else {
pop @P;
}
$current = join ('/', @P);
}
unlink $LINK;
link $current, $LINK if (-f $current);
|