#!/usr/bin/perl -w # Copyright © 2001-2012 Jamie Zawinski # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation. No representations are made about the suitability of this # software for any purpose. It is provided "as is" without express or # implied warranty. # # Created: 3-Jul-01. require 5; use diagnostics; use strict; use POSIX qw(mktime); my $progname = $0; $progname =~ s@.*/@@g; my $version = q{ $Revision: 1.118 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/; my $verbose = 1; my $debug_p = 0; # this means "don't alter any files, print diffs instead" BEGIN { push @INC, "utils/"; } use Menuify; my $eighties_dir = "1985-1999"; $ENV{PATH} .= ":/opt/local/bin"; # for cron my @months = ("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"); my @days = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); # maps lower cased month names to numbers (1-12). # my %monthvals = ( 'jan' => 1, 'january' => 1, 'february' => 2, 'feb' => 2, 'march' => 3, 'mar' => 3, 'april' => 4, 'apr' => 4, 'may' => 5, 'jun' => 6, 'june' => 6, 'jul' => 7, 'july' => 7, 'august' => 8, 'aug' => 8, 'sep' => 9, 'sept' => 9, 'september' => 9, 'oct' => 10, 'october' => 10, 'nov' => 11, 'november' => 11, 'dec' => 12, 'december' => 12 ); my $dim_fg = "#666"; my $body_template = undef; my $store_file = "store/posters.html"; my $names_file = "calendar/names.txt"; my $rss_file = "calendar/dnalounge.rss"; my %image_files = (); # keys are image file names (full and thumb) my %posters; # which flyers are on sale in the store my %event_names; # maps dates to pretty event names my %tickets_on_sale; # maps event names to a list of dates on sale. my %ticket_of_date; # maps date to ticket ID. # For when the name of an event changed... # my %event_name_aliases = ( "n:CODE" => "d:CODE", "Pop Rocks" => "Pop Roxx", "Red Square" => "Qool", "Body Manipulations" => "Flying Tiger Circus", "Kinky Circus" => "Good Vibrations", "Atomic Jungle!" => "Spectacular! Spectacular!", "Zombie DNA" => "Spectacular! Spectacular!", "Spectacular! Spectacular!" => "Hubba Hubba Revue", ); # Given a date, returns the day of the week on which it falls (0-6, sun-sat) # sub dotw($$$) { my ($dotm, $month, $year) = @_; # From the sci.math FAQ: # # The following formula, which is for the Gregorian calendar only, may be # more convenient for computer programming. Note that in some programming # languages the remainder operation can yield a negative result if given # a negative operand, so "mod 7" may not translate to a simple remainder. # # W == (k + [2.6m - 0.2] - 2C + Y + [Y/4] + [C/4]) mod 7 # where [] denotes the integer floor function (round down), # k is day (1 to 31) # m is month (1 = March, ..., 10 = December, 11 = Jan, 12 = Feb) # Treat Jan & Feb as months of the preceding year # C is century (1987 has C = 19) # Y is year (1987 has Y = 87 except Y = 86 for Jan & Feb) # W is week day (0 = Sunday, ..., 6 = Saturday) # # Here the century & 400 year corrections are built into the formula. # The [2.6m-0.2] term relates to the repetitive pattern that the 30-day # months show when March is taken as the first month. my $k = $dotm; my $m = 1 + (($month + 9) % 12); # (1-12) => (11, 12, 1-10) my $y = $year - ($m >= 11 ? 1 : 0); # subtract a year for jan/feb my $C = int ($y/100); my $Y = int ($y%100); my $W = (($k + int ((2.6 * $m) - 0.2) - (2 * $C) + $Y + int ($Y / 4) + int ($C / 4) + 7) % 7); return $W; } # Loads the template file and constructs our etc from it. # sub load_template() { my $template_file = $DNA::Menuify::template_file; open (my $in, '<', $template_file) || error ("$template_file: $!"); print STDERR "$progname: reading $template_file\n" if ($verbose > 2); local $/ = undef; # read entire file $body_template = <$in>; close $in; # lose everything inside $body_template =~ s@(]*>).*(.*)$@$1\n $2@si; $body_template =~ s@^\s*\s*\n@@gmi; $body_template =~ s@%%ROOT%%@../../../@gs; $body_template = "\n" . $body_template; # We generate our own version of these. $body_template =~ s@^\s*]*>\n@@gmi; $body_template =~ s@^\s*]*>\n@@gmi; # Swap DOCTYPE and NOWRAP, if there is one. $body_template =~ s@^()\n()@$2\n$1@si; } # Populate the %posters table with the file names that are on sale. # sub load_posters() { my $count = 0; print STDERR "$progname: reading $store_file\n" if ($verbose > 2); open (my $in, '<', $store_file) || error ("$store_file: $!"); local $/ = undef; # read entire file my $body = <$in>; close $in; $body =~ s/^\s+/ /gm; $body =~ s/(\"]+)\"/si); next unless $href; my ($file) = ($href =~ m@(flyers/\d{4}/\d\d/\d\d[ab]?\.html)@); next unless $file; $posters{$file} = 1; $count++; } error ("no posters on sale?") unless $count; print STDERR "$progname: $count posters on sale\n" if ($verbose > 2); } # Populate the %event_names table. # sub load_event_names() { my $count = 0; print STDERR "$progname: reading $names_file\n" if ($verbose > 2); open (my $in, '<', $names_file) || error ("$names_file: $!"); my $body = ''; while (<$in>) { my ($date, $pres, $n) = m/^(\d{4}-\d\d-\d\d[ab]?)\t([^\t]*)\t\*?([^\t]+)/s; error ("unparsable: $_") unless ($n); my $n2 = $n; #### kludges for 2009-08-07, etc $n =~ s/ \+ .*$//si; # "Seabound + De/vision" => "Seabound", etc. $n =~ s/^(meat)\b.*/$1/si; # "Meat vs. DG" => "Meat" $n =~ s/^[nd]?:?(code)\b.*/$1/si; $n =~ s/: .*$//s; # lose everything after colon $event_names{$date} = [$n2, $n]; $count++; } #### kludge for flyers for events that aren't on the calendar $event_names{'2001-07-10'} = ['Private Pre-Opening Party']; $event_names{'2006-07-11'} = ['Pig']; close $in; error ("no names?") unless $count; print STDERR "$progname: $count names\n" if ($verbose > 2); } # Populate the %tickets_on_sale table. # sub load_tickets() { my $count = 0; print STDERR "$progname: reading $rss_file\n" if ($verbose > 2); open (my $in, '<', $rss_file) || error ("$rss_file: $!"); local $/ = undef; # read entire file my $body = <$in>; close $in; $body =~ s/(]*>([^<>]+)<@si; next unless $ticket; my ($title) = m@([^<>]+)<@si; my ($eid) = m@([^<>]+)<@si; $count++; $title =~ s/: .*//s; $title = lc($title); $title =~ s/&/&/si; my ($yyyy, $mm, $dd) = ($eid =~ m@^(\d{4})-(\d\d)-(\d\d[ab]?)$@si); $mm = $monthvals{lc($mm)}; my $ref = $tickets_on_sale{$title}; my @list = (defined($ref) ? @$ref : ()); ($ticket) = ($ticket =~ m@^https://[^/.]*\.dnalounge\.com.*item=(\d+)$@si); error ("$eid: unparsable ticket ID") unless $ticket; push @list, $eid; $tickets_on_sale{$title} = \@list; $ticket_of_date{$eid} = $ticket; } print STDERR "$progname: $count events on sale\n" if ($verbose > 2); } # Parse the HTML file for IMG tags and cache the sizes in them. # We trust these numbers if date of HTML >= date of JPEG. # my %image_html_size_cache = (); sub cache_image_sizes($$) { my ($dir, $file) = @_; open (my $in, '<', "$dir/$file") || error ("$dir/$file: $!"); print STDERR "$progname: reading $dir/$file\n" if ($verbose > 3); local $/ = undef; # read entire file my $html = <$in>; my $mtime = (stat($in))[9]; close $in; $html =~ s%]+)>%{ my $attrs = $1; my ($file2) = ($attrs =~ m/\bSRC="([^"]+)/si); if ($file2 && $file2 !~ m@/@s) { # no path component # # Ok: width=30> # width="30" # width:30 px # Not: width=30# (where # is pct sign, which I can't type here!) # my $w = ($1 || $2) if ($attrs =~ m/(?: \b width \s* = [\s"']* (\d+) [\s"'>] | \b width \s* : \s* (\d+) \s* px ) /six); my $h = ($1 || $2) if ($attrs =~ m/(?: \b height \s* = [\s"']* (\d+) [\s"'>] | \b height \s* : \s* (\d+) \s* px ) /six); if ($w && $h) { my @c = ($w, $h, $mtime); $image_html_size_cache{"$dir/$file2"} = \@c; } } $attrs; }%gsexi; } # returns a list of all flyer images under $dir, which is expected to # be the parent of the NNNN year directories. Thumbnail images are # excluded, but warnings about missing or extraneous thumbnails are # generated. Also populates %image_files with the flyers plus thumbs. # sub find_images($) { my ($dir) = @_; $dir .= "/" unless ($dir =~ m@/$@); print STDERR "$progname: scanning $dir\n" if ($verbose > 2); opendir (my $fdir, "$dir") || error ("$dir: $!"); my @ffiles = readdir ($fdir); closedir $fdir; $dir = "" if $dir eq "./"; my %thumbs; my %images; foreach my $year (@ffiles) { next unless ($year =~ m/^\d{4}$/); opendir(my $ydir, "$dir$year") || error ("$dir$year: $!"); my @yfiles = readdir ($ydir); closedir $ydir; foreach my $month (@yfiles) { next unless ($month =~ m/^\d\d$/); next if ($month < 1 || $month > 12); opendir (my $mdir, "$dir$year/$month") || error ("$dir$year/$month: $!"); my @mfiles = readdir ($mdir); closedir $mdir; foreach my $img (@mfiles) { cache_image_sizes ("$dir$year/$month", $img) if ($img =~ m/\.html$/s); next unless ($img =~ m/\.(jpg|gif)$/i); if ($img =~ m/^(\d\d[ab]?)-([\dm])(-thumb)?\.(jpg|gif)$/) { next if ($2 eq '0'); # skip the "-0.jpg" dual-flyers. next if ($2 eq 'm'); # skip the "-m.jpg" medium-sized flyers. my $f = "$year/$month/$img"; $image_files{$f} = 1; if ($img =~ m/-thumb/) { $thumbs{$f} = 1; } else { $images{$f} = 1; } } else { print STDERR "$progname: warning: unrecognised file: " . "$dir$year/$month/$img\n"; } } } } # Check for dangling thumbs... # print STDERR "$progname: checking for dangling thumbs\n" if ($verbose > 3); foreach my $thumb (keys (%thumbs)) { my $img1 = $thumb; $img1 =~ s/-thumb//; my $img2 = $img1; $img1 =~ s/\.(jpg|gif)$/.jpg/; $img2 =~ s/\.(jpg|gif)$/.gif/; if (! ($images{$img1} || $images{$img2})) { print STDERR "$progname: warning: dangling thumb: $thumb\n"; } } # Check for missing thumbs... # print STDERR "$progname: checking for missing thumbs\n" if ($verbose > 3); foreach my $img (keys (%images)) { my $thumb1 = $img; my $thumb2 = $img; $thumb1 =~ s/(\.[^.]+)$/-thumb.jpg/; $thumb2 =~ s/(\.[^.]+)$/-thumb.gif/; if (! ($thumbs{$thumb1} || $thumbs{$thumb2})) { print STDERR "$progname: warning: no thumb: $img\n" unless ($img eq '2003/04/26-3.jpg'); # kludge } } print STDERR "$progname: " . (keys(%images) + 0) . " images\n" if ($verbose > 2); return sort { $b cmp $a } (keys (%images)); } # Maps flyer images to the prev/next images for the like-named event. # # "BBBB/BB/BB-1.jpg" => \( "AAAA/AA/AA-1.jpg", "CCCC/CC/CC-1.jpg" ) # my %event_prev_next_table = (); sub compute_prev_next_events(@) { my (@images) = @_; my %name_table = (); %event_prev_next_table = (); # first, divide the images by event name... # foreach my $image (@images) { error ("unparsable file name: $image") unless ($image =~ m@^(\d{4})/(\d\d)/(\d\d)([ab]?)-(\d+)\.(jpg|gif)$@); my ($year, $month, $dotm, $ord, $count) = ($1, $2, $3, $4, $5); next unless ($count == 1); # only want the first image in the set my $P = $event_names{"$year-$month-$dotm$ord"}; my ($event_long, $event_name) = ($P ? @$P : ()); $event_name = $event_long unless $event_name; error ("no event name for $image") unless $event_name; $event_name = ($event_name_aliases{$event_name} || $event_name); my $ref = $name_table{$event_name}; my @list = (defined($ref) ? @$ref : ()); push @list, $image; $name_table{$event_name} = \@list; } # next, for each event, find the prev and next for each image. # foreach my $event_name (keys (%name_table)) { my @list = @{$name_table{$event_name}}; @list = sort @list; my $i = 0; foreach my $img (@list) { my $prev = ($i == 0 ? undef : $list[$i-1]); my $next = $list[$i+1]; my @prevnext = ($prev, $next); $event_prev_next_table{$img} = \@prevnext; $i++; } $name_table{$event_name} = undef; } %name_table = (); } my %image_size_cache = (); sub image_size($$) { my ($dir, $file) = @_; $file = $dir . $file; my $cache = $image_size_cache{$file}; return @{$cache} if $cache; my $mtime = (stat($file))[9]; error ("$file does not exist") unless $mtime; #return (0, 0) unless $mtime; # Trust the width/height values in the existing HTML files if the write # date on the HTML file was >= the write date on the image file. # $cache = $image_html_size_cache{$file}; if ($cache) { my ($w, $h, $mtime2) = @$cache; return ($w, $h) if ($mtime <= $mtime2); } my $cmd = ("identify -define jpeg:size=1x1 -format '%[width]x%[height]'" . " '$file'"); print STDERR "$progname: executing: $cmd\n" if ($verbose > 7); my $result = `$cmd`; print STDERR "$progname: ==> $result\n" if ($verbose > 7); my ($w, $h) = ($result =~ m/^(\d+)x(\d+)$/); error ("no size: $file") unless ($w && $h); my @c = ($w, $h); $image_size_cache{$file} = \@c; return ($w, $h); } # Given a file name (e.g., "deathguild") and a list of pretty names # (e.g., "Death Guild") return the one that seems like a match. # sub pick_name($@) { my ($fn, @names) = @_; return $names[0] if ($#names == 0); foreach my $name (@names) { my $lc = lc($name); $lc =~ s/[^a-z\d]//gs; # kludge. $lc = 'slick' if ($lc eq 'retrospectacle'); $lc = 'qool' if ($lc eq 'qolsaturdays'); return $name if ($lc =~ m/\Q$fn/); } error ("no match for \"$fn\" in: \"" . join('", ', @names) . "\""); } # writes a file containing the inlined, large flyer images. # The @images arg contains the front and back images of all flyers # for this date. # # $prev and $next are of the form NNNN/MM/DD-xxx-N.jpg, and are the # nearest flyer images that come before/after this batch of images. # # $prev2 and $next2 are of the same form, but name the prev/next flyer # image of *this same event*, if there is one. # # Returns the name of this event. # sub build_page($$$$$@) { my ($dir, $prev, $next, $prev2, $next2, @images) = @_; $dir .= "/" unless ($dir =~ m@/$@); $dir = "" if $dir eq "./"; error ("unparsable file name: $images[0]") unless ($images[0] =~ m@^(\d{4})/(\d\d)/(\d\d)([ab]?)-(\d+)\.(jpg|gif)$@); my ($year, $month, $dotm, $ord, $count) = ($1, $2, $3, $4, $5); my $P = $event_names{"$year-$month-$dotm$ord"}; my ($event_long, $event_name) = ($P ? @$P : ()); $event_name = $event_long unless $event_name; error ("no event name for $images[0]") unless $event_name; my $file = "$dir$images[0]"; $file =~ s/-\d+\.[^.]+$/.html/; my $poster_p = defined($posters{$file}); my $this_name; my $onsale_date; my $prev2_thumb; my $prev2_width = 0; my $next2_thumb; my $next2_width = 0; my $prev2_next2_width = 0; my $prev_link; my $next_link; my $dotw = $days[dotw ($dotm, $month, $year)]; my $month_name = $months[$month-1]; $dotw =~ s/^(...).*$/$1/; $month_name =~ s/^(...).*$/$1/; my $cal_file = "calendar/$year/$month-$dotm$ord.html"; my $cal_url = "../../../$cal_file"; $this_name = "$dotw, $dotm $month_name $year"; my $title = sprintf("DNA Lounge: %s, %d %s %04d (%s)", $event_long, $dotm, $month_name, $year, $dotw); $title =~ s@&@&@gs; # Copy the tag from the corresponding calendar page. # my $desc = $title; if (open (my $in, '<', "$cal_file")) { print STDERR "$progname: reading $cal_file\n" if ($verbose > 2); local $/ = undef; # read entire file my $cal = <$in>; close $in; $desc = $1 if ($cal =~ m@\n"; } if ($next) { $_ = $next; error ("unparsable next: $next") unless (m@^(\d{4})/(\d\d)/(\d\d)([ab]?)-@); my ($nyear, $nmonth, $ndotm, $nord) = ($1, $2, $3, $4); $next =~ s/\.(jpg|gif)$/.html/; $next =~ s@^\d{4}/\d\d/@@; $next =~ s@-\d+(\.[^.]+)$@$1@; if ($year != $nyear) { $next = "../../$nyear/$nmonth/$next"; } elsif ($month != $nmonth) { $next = "../$nmonth/$next"; } $nmonth = $months[$nmonth-1]; $nmonth =~ s/^(...).*$/$1/; my $ndate = "$ndotm $nmonth $nyear"; $next_link = " \n"; } if ($prev2) { $prev2_thumb = thumb_html ($dir, $event_name, 1, $prev2); $_ = $prev2; error ("unparsable prev2: $prev2") unless (m@^(\d{4})/(\d\d)/(\d\d)([ab]?)-@); my ($pyear, $pmonth, $pdotm, $pord) = ($1, $2, $3, $4); $prev2 =~ s/\.(jpg|gif)$/.html/; $prev2 =~ s@^\d{4}/\d\d/@@; $prev2 =~ s@-\d+(\.[^.]+)$@$1@; if ($year != $pyear) { $prev2 = "../../$pyear/$pmonth/$prev2"; } elsif ($month != $pmonth) { $prev2 = "../$pmonth/$prev2"; } # Put the right ../ nonsense on the thumb img. my ($d) = ($prev2 =~ m@^(.*/)@si); $prev2_thumb =~ s@(SRC=")@$1$d@si if $d; ($prev2_width) = ($prev2_thumb =~ m@WIDTH=(\d+)@si); } if ($next2) { $next2_thumb = thumb_html ($dir, $event_name, 1, $next2); $_ = $next2; error ("unparsable next2: $next2") unless (m@^(\d{4})/(\d\d)/(\d\d)([ab]?)-@); my ($nyear, $nmonth, $ndotm, $nord) = ($1, $2, $3, $4); $next2 =~ s/\.(jpg|gif)$/.html/; $next2 =~ s@^\d{4}/\d\d/@@; $next2 =~ s@-\d+(\.[^.]+)$@$1@; if ($year != $nyear) { $next2 = "../../$nyear/$nmonth/$next2"; } elsif ($month != $nmonth) { $next2 = "../$nmonth/$next2"; } # Put the right ../ nonsense on the thumb img. my ($d) = ($next2 =~ m@^(.*/)@si); $next2_thumb =~ s@(SRC=")@$1$d@si if $d; ($next2_width) = ($next2_thumb =~ m@WIDTH=(\d+)@si); } $prev2_next2_width = ($prev2_width > $next2_width ? $prev2_width : $next2_width); my $ticket = undef; # If some event with the same name as the event of this flyer is currently # on sale, mention it. If this flyer has the date of such an event that # is on sale, mention that event. Otherwise, mention the next-upcoming. # { my $ref = $tickets_on_sale{lc($event_name)}; if ($ref) { my $d = sprintf("%04d-%02d-%02d", $year, $month, $dotm); foreach my $date (@$ref) { if ($date eq $d || !$onsale_date) { $onsale_date = $date; $ticket = $ticket_of_date{$date}; } } } } my $photos = sprintf ("gallery/$year/%02d-%02d%s", $month, $dotm, $ord); $photos = undef unless (-d $photos); $prev = ($prev ? "<<" : "<<"); $next = ($next ? ">>" : ">>"); if ($cal_url =~ m@/2001/07-10@si) { # Kludge: pre-opening party wasn't on the calendar. $cal_url = "../../../backstage/log/2001/07/11.html"; } elsif ($cal_url =~ m@/2006/07-11@si) { # This event was canceled, but the flyer is too pretty to delete. $cal_url = "../../../calendar/$year/$month.html"; } my $body = ("
\n" . " $prev\n" . " $next\n" . " $this_name
\n" . "
\n" . " << flyers\n" . ($photos ? " photos\n" : "") . " " . "calendar >>\n" . "
\n"); my $hype = ''; if ($onsale_date) { # Point the Like button at the calendar page instead of the flyer page. my $url = "http://www.dnalounge.com/calendar/$year/$month-$dotm$ord.html"; my ($yyyy, $mm, $dd, $ord) = ($onsale_date =~ m/^(\d{4})-(\d\d)-(\d\d)([ab]?)$/s); my $dotw = $days[dotw ($dd, $mm, $yyyy)]; my $mmm = $months[$mm-1]; $dotw =~ s/^(...).*$/$1/; $mmm =~ s/^(...).*$/$1/; my $d = $dd + 0; my $e2 = uc($event_name); $e2 =~ s/&/&/gs; $url =~ s@:@%3A@gs; $url =~ s@/@%2F@gs; $hype .= ("" . "" . "Buy tickets now for\n" . "$e2\n" . "on $dotw, $mmm $d!
\n" . "Planning on attending? Tell your friends on\n" . "Twitter\n" . "and\n" . "Facebook.
\n" . "
\n" . # Note: iframe rewritten by DNA::Menuify. "\n" . # Note: plusone rewritten by DNA::Menuify. "
" . "
" . "
\n" . "
\n" ); } $hype .= ("

" . "" . "Buy a limited-edition poster of this image!" . "

\n") if ($poster_p); if ($hype) { $hype =~ s/^/ /gm; $hype = ("\n\n" . "

\n" . $hype . "
\n\n "); } # Find the width of the widest flyer image, taking into account the # fact that the first flyer image on the page has the two nav thumbs # next to it. This is the overall max width of the content. # my $line_width = 0; my $i = 0; foreach my $image (@images) { my ($w, $h) = image_size ($dir, $image); $w += (($prev2_next2_width + 4) * 2) # 4 for margins if ($prev2_next2_width && $i == 0); $line_width = $w if ($w > $line_width); $i++; } # Now that we know the max width, insert left/right thumb cells at the # front, their widths described in percentage of max width. # if ($prev2_next2_width > 0) { $prev2_thumb = '' unless $prev2_thumb; $next2_thumb = '' unless $next2_thumb; my ($limg) = ($prev2_thumb =~ m/\bSRC="([^<>"]+)"/si); my ($rimg) = ($next2_thumb =~ m/\bSRC="([^<>"]+)"/si); my ($lw) = ($prev2_thumb =~ m/\bWIDTH=(\d+)/si); my ($rw) = ($next2_thumb =~ m/\bWIDTH=(\d+)/si); my ($lh) = ($prev2_thumb =~ m/\bHEIGHT=(\d+)/si); my ($rh) = ($next2_thumb =~ m/\bHEIGHT=(\d+)/si); $lw = 0 unless $lw; $rw = 0 unless $rw; my $lw2 = int((100 * $prev2_next2_width / $line_width) + 0.5); my $rw2 = int((100 * $prev2_next2_width / $line_width) + 0.5); my $lw1 = int((100 * $lw / $prev2_next2_width) + 0.5); my $rw1 = int((100 * $rw / $prev2_next2_width) + 0.5); $body .= (" " . "" . "" . "" . "\n") if $limg; $body .= (" " . "" . "" . "" . "\n") if $rimg; } # Now the main flyer images, also with their widths described in # percentage of max width. # $i = 0; foreach my $image (@images) { my ($w, $h) = image_size ($dir, $image); my $himage = $image; $himage =~ s@^.*?([^/]+)$@$1@; my $w2 = int((100 * $w / $line_width) + 0.5); $body .= ("
" . $hype . "" . "" . "" . "
\n"); $hype = ''; $i++; } $body .= (#" $prev\n" . #" $next\n" . #"
\n" . "
\n"); my $links = ''; { my $img = $images[0]; $img =~ s@^.*/@@si; $links .= " \n"; $links .= " \n"; $links .= " \n"; $links .= " \n"; $links .= " \n"; $links .= " \n"; $links .= " \n"; $links .= $prev_link if $prev_link; $links .= $next_link if $next_link; $links .= " \n"; } { my $body2 = $body_template; $body2 =~ s@(]*>).*()@$1$title$2@s; $body2 =~ s@(\n[ \t]*]*>).*()@$1\n$body $2@s; $body = $body2; } $body =~ s/ +$//gm; $body =~ s/(\n\n)\n+/$1/gs; DNA::Menuify::write_file ($file, $body); $event_long =~ s/:\s+/

/si; return $event_long; } # generates all HTML pages for flyers under $dir, which is expected to # be the parent of the NNNN year directories. # sub wrap_images($) { my ($dir) = @_; load_template (); load_posters (); load_event_names (); load_tickets (); my @images = find_images($dir); compute_prev_next_events (@images); my $body = ""; my $prev; my $next; my $last_year; my $oyear; my $omonth; my $year_one; my $nlines = 0; while (@images) { my @imgs = (); my $img = $images[0]; error ("unparsable image? $img") unless ($img =~ m@^((\d{4})/(\d\d)/(\d\d)([ab]?)-)(\d)\.(jpg|gif)@); my ($head, $year, $month) = ($1, $2, $3); $year_one = $year unless defined($year_one); if ($oyear && ($year ne $oyear || $month ne $omonth)) { write_month_index ($dir, $oyear, $omonth, $body, $nlines); $body = ""; $nlines = 0; } $last_year = $year unless $last_year; if ($oyear && $year ne $oyear) { write_year_index ($dir, $oyear); } $oyear = $year; $omonth = $month; while ($#images >= 0 && $images[0] =~ m/^\Q$head/) { $img = shift @images; unshift @imgs, $img; } # look up the next/prev event with the same name my ($next2, $prev2); { my $key = $img; $key =~ s/(-\d+)(\.[^.]+)$/-1$2/; my $ref = $event_prev_next_table{$key}; ($next2, $prev2) = ($ref ? @$ref : ()); } $next = $images[0]; my $name = build_page ($dir, $next, $prev, $next2, $prev2, @imgs); $name =~ s@&@&@gs; my $thtml = thumb_html ($dir, $name, 0, @imgs); $body = $thtml . $body; $prev = $img; # Figure out how many lines of flyers were just written by counting TRs. my @L = split(/ 12) { $omonth -= 12; $oyear++; } my $oname = $months[$omonth-1]; my $oname2 = "$oname $oyear"; $oname =~ s/^(...).*$/$1/; my $odir = ($oyear == $year ? sprintf("../%02d/", $omonth) : sprintf("../../%04d/%02d/", $oyear, $omonth)); return ($oname, $oname2, $odir); } # Find the prev/next month that has flyers; if there isn't one within # three months of here, return the prev/next month with no directory name. # sub other_month($$$$) { my ($base, $month, $year, $next_p) = @_; my $sign = ($next_p ? 1 : -1); my ($oname, $oname2, $odir) = shift_month ($month, $year, $sign * 1); my $ooname = $oname; my $ooname2 = $oname2; return ($oname, $oname2, $odir) if (-d "$base/$odir"); ($oname, $oname2, $odir) = shift_month ($month, $year, $sign * 2); return ($oname, $oname2, $odir) if (-d "$base/$odir"); ($oname, $oname2, $odir) = shift_month ($month, $year, $sign * 3); return ($oname, $oname2, $odir) if (-d "$base/$odir"); return ($ooname, $ooname2, undef); } # Writes the HTML for the page listing all flyers in a given month: # the page that contains the thumbnail images (YYYY/MM/index.html). # sub write_month_index($$$$$) { my ($dir, $year, $month, $body, $nlines) = @_; $dir .= "/" unless ($dir =~ m@/$@); $dir = "" if $dir eq "./"; my $output = ""; my $month_name = $months[$month-1]; my $page_title = "DNA Lounge: Flyer Archive: $month_name $year"; $output .= "$page_title\n\n"; my ($prev_name, $prev_name2, $prev) = other_month ("$dir$year/$month", $month, $year, 0); my ($next_name, $next_name2, $next) = other_month ("$dir$year/$month", $month, $year, 1); $prev_name = "<< $prev_name"; $next_name = "$next_name >>"; $prev_name2 .= " Flyers"; $next_name2 .= " Flyers"; my $links = ''; $links .= " \n"; $links .= " \n"; $links .= " \n"; $links .= " \n" if ($prev); $links .= " \n" if ($next); $output .= $links; $prev = ($prev ? "$prev_name" : "$prev_name"); $next = ($next ? "$next_name" : "$next_name"); $output .= ("\n" . "

\n" . " $prev\n" . " $next\n" . "
\n" . " $year" . "
\n" . "
\n" . "\n"); $prev =~ s/("nav[LR])/${1}A/gs; # class "navL" => class "navLA" $next =~ s/("nav[LR])/${1}A/gs; $output .= ("\n" . "
\n" . " $prev\n" . " $next\n" . "
\n" . "\n" . "$month_name $year Flyers\n\n" . $body . "\n"); my $outfile = "$dir$year/$month/index.html"; DNA::Menuify::write_file ($outfile, $output); } # Writes the HTML for the page listing all months in a given year # the page that contains the month name links (YYYY/index.html). # sub write_year_index($$) { my ($dir, $year) = @_; $dir .= "/" unless ($dir =~ m@/$@); $dir = "" if $dir eq "./"; my $output = ""; my $page_title = "DNA Lounge: Flyer Archive: $year"; $output .= "$page_title\n\n"; my $prev_name = $year-1; my $next_name = $year+1; my $prev = "../$prev_name/"; my $next = "../$next_name/"; $prev = undef unless (-d "$dir$year/$prev"); $next = undef unless (-d "$dir$year/$next"); # Kludge for the ancient history... # if (!defined($prev)) { $prev = "../$eighties_dir/"; $prev_name = $eighties_dir; } my $prev_href1 = ($prev ? "" : ""); my $next_href1 = ($next ? "" : ""); my $prev_href2 = ($prev ? "" : ""); my $next_href2 = ($next ? "" : ""); my $links = ''; $links .= " \n"; $links .= " \n"; $links .= " \n"; $links .= " \n" if ($prev); $links .= " \n" if ($next); $output .= $links; $prev_name = "<< $prev_name"; $next_name = "$next_name >>"; $prev = ($prev ? "$prev_name" : "$prev_name"); $next = ($next ? "$next_name" : "$next_name"); $output .= ("\n" . "
\n" . " $prev\n" . " $next\n" . "
\n" . " up" . "
\n" . "
\n" . "\n"); $prev =~ s/("nav[LR])/${1}A/gs; # class "navL" => class "navLA" $next =~ s/("nav[LR])/${1}A/gs; $output .= ("\n" . "
\n" . " $prev\n" . " $next\n" . "
\n" . "\n" . "$year Flyers\n\n" . "

\n" . "\n"); for (my $y = 0; $y < 4; $y++) { $output .= " \n"; for (my $x = 0; $x < 3; $x++) { my $month = sprintf("%02d", (($x * 4) + $y) + 1); my $month_name = $months[$month-1]; my $align = ($x == 0 ? "RIGHT" : $x == 1 ? "CENTER" : "LEFT"); my $ok = (-d "$dir$year/$month"); my $href1 = ($ok ? "" : ""); my $href2 = ($ok ? "" : ""); $output .= " \n"; } $output .= " \n"; } $output .= "
$href1"; $output .= "$month_name$href2
\n"; $output .= "\n"; my $outfile = "$dir$year/index.html"; DNA::Menuify::write_file ($outfile, $output); } # Writes the HTML for the page listing all years (flyers/index.html). # sub write_years_index($$$) { my ($dir, $first, $last) = @_; $dir .= "/" unless ($dir =~ m@/$@); $dir = "" if $dir eq "./"; my $output = ""; my $page_title = "DNA Lounge: Flyer Archive"; my $td = ("TD VALIGN=TOP STYLE=\"font-size:larger; font-weight: bold;" . " padding: 0.1em 0.5em;\""); $output .= ("$page_title\n\n" . "\n" . "\n" . "$page_title\n\n" . "

\n" . "
\n" . "\n" . " \n" . " <$td ALIGN=CENTER COLSPAN=2>" . "$eighties_dir" . "\n" . " \n" . " \n" . " <$td ALIGN=RIGHT>\n"); my $i = 0; foreach my $year ($first .. $last) { $output .= " \n <$td ALIGN=LEFT>\n" if ($i == int(($last-$first)/2)+1); $output .= " $year
\n"; $i++; } $output .= ( "\n" . " \n" . " \n" . " <$td ALIGN=CENTER COLSPAN=2>
\n" . "Latest\n" . "\n" . " \n" . " \n" . " <$td ALIGN=CENTER COLSPAN=2>
" . "". "Alphabetically
by performer
" . "\n" . "\n" . "
\n" . "
\n" . "\n"); my $outfile = "${dir}index.html"; DNA::Menuify::write_file ($outfile, $output); } # Returns the HTML that renders the inlined thumbs of the given flyer images. # The @images arg names the front and back images of all flyers for this date. # (They are converted to -thumb versions.) # sub thumb_html($$$@) { my ($dir, $pname, $img_only_p, @images) = @_; $dir .= "/" unless ($dir =~ m@/$@); $dir = "" if $dir eq "./"; error ("unparsable image? $images[0]") unless ($images[0] =~ m@^(\d{4})/(\d\d)/(\d\d)([ab]?)-(\d)\.(jpg|gif)$@); my ($year, $month, $dotm, $ord, $count) = ($1, $2, $3, $4, $5); my $dotw = $days[dotw ($dotm, $month, $year)]; my $month_name = $months[$month-1]; $month_name =~ s/^(...).*$/$1/; my $body = ""; if (! $img_only_p) { $body .= ("
\n" . "
" . "$dotw
$dotm $month_name $year

" . "$pname" . "
\n" . "
\n\n"); } # pad the images: if the sequence is "1, 3, 4", change it to "1, '', 3, 4". { my @im2 = (); my $last = 0; foreach (@images) { my ($n) = m/-(\d+)\.[a-z]+$/; while ($last < ($n-1)) { push @im2, undef; $last++; } $last = $n; push @im2, $_; } @images = @im2; } my $L = $#images; my $fcount = 0; foreach my $image (@images) { if (!defined ($image)) { # spacer image $fcount++; next; } my $thumb = $image; $thumb =~ s/(\.[^.]+)$/-thumb.jpg/; $thumb =~ s/\.jpg$/.gif/ unless ($image_files{$thumb}); if ($fcount && !($fcount & 1) && !$img_only_p) { $body .= "
\n"; } my $next_image = $images[$fcount+1]; my $just_one = (!($fcount & 1) && !defined($next_image)); my $align = ($just_one ? "CENTER" : (($fcount & 1) == 0 ? "RIGHT" : "LEFT")); my $html = "$dotm$ord.html"; if ($image_files{$thumb}) { my ($w, $h) = image_size ($dir, $thumb); my $hthumb = $thumb; $hthumb =~ s@^.*?([^/]+)$@$1@; if ($img_only_p) { $body .= (""); } else { $body .= (" " . "" . "\n"); } } $fcount++; } if (!$img_only_p) { $body .= "
\n
\n"; } $body =~ s/\s*(
)/$1/gsi; return $body; } sub error($) { my ($err) = @_; print STDERR "$progname: $err\n"; exit 1; } sub usage() { print STDERR "usage: $progname [--verbose] [--debug] directory\n"; exit 1; } sub main() { my $dir = undef; error ("LANG is $ENV{LANG} -- UTF is no good, man!") if ($ENV{LANG} && $ENV{LANG} =~ m/utf/i); while ($_ = $ARGV[0]) { shift @ARGV; if (m/^--?verbose$/s) { $verbose++; } elsif (m/^-v+$/) { $verbose += length($_)-1; } elsif (m/^--?q(uiet)?$/s) { $verbose = 0; } elsif (m/^--?debug$/s) { $debug_p++; } elsif (m/^-./) { usage; } elsif (!defined($dir)) { $dir = $_; } else { usage; } } usage unless $dir; $dir =~ s@/+$@@; # When writing files, make permissions match the parent directory # by computing a umask from the directory's permissions. # umask (~((stat($dir))[2] & 0666) & 0666); $DNA::Menuify::verbose = $verbose; $DNA::Menuify::debug = $debug_p; $DNA::Menuify::validate = $debug_p; wrap_images ($dir); } main(); exit 0;