#!/usr/bin/perl -w
# dvdlist.pl, a perl CGI script to display a list of DVDs on a web page
# Copyright (C) 2005-2020  Christian Wolff
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# Or, download it from http://www.gnu.org/copyleft/gpl.html
#
# You can reach the author via email: sub-gpl <at> scara.com
#

# Format of the DB file:
# - One line per movie
# - Entries separated by Tabs:
#   - [0] Title (name of the movie, or show and season)
#   - [1] Release details (such as Distributor, Special Edition, etc.)
#   - [2] Aspect Ratio(s), separated by '/', e.g. 1.33, 1.78, 1.37, 1.66, 1.85, 2.35, each followed by:
#       's' if standard definition (default, if no letter)
#       'a' if anamorphic widescreen
#       'h' if HighDefinition 1080p
#       'u' if UltraHD 2160p
#       'p' if 720p
#       'w' if 1080p 21:9
#       'i' for 1080i
#       'u' optionally followed by 'h' for HDR10
#       'ud' for Dolby Vision
#       'up' for HDR10+
#       'ut' for Technicolor HDR
#       'ug' for HLG;
#   - [3] Running Time (H:MM or minutes)
#   - [4] Number of Discs, followed by Type (optional, default DVD):
#       'D' for DVD
#       'R' for DVD-R / MoD
#       'C' for CD
#       'S' for SuperAudioCD
#       'B' for Blu-ray
#       'T' for Blu-ray 3D
#       'U' for UltraHD Blu-ray
#       'H' for HD-DVD
#       'L' for Laser Disc
#       'M' for Video CD
#       'V' for VHS Tape
#       'A' for UltraViolet/MoviesAnywhere
#       'I' for iTunes
#       'Y' for other digital copy
#   - [5] Standard/Region (N or P for NTSC/60Hz or PAL/50Hz, followed by list of regions(0=all, 1/A=northamerica, 2/B=europe&japan), '?' if unknown, or '-' if copy)
#   - [6] Audio Track Language(s). Each followed optionally by sound format: ([XX][n.m[.h]][ addl.info]), XX: see below; n=floor speaker, m=subs, h=height)
#       PC=PCM
#       DD=Dolby Digital (AC3)
#       DP=DD-Plus (E-AC-3)
#       AD=DD-Plus Atmos
#       TH=TrueHD
#       AT=Dolby TrueHD Atmos
#       DT=DTS
#       HR=DTS-HD High Resolution
#       MA=DTS-HD Master Audio
#       DX=DTS:X
#       DH=DTS Headphone:X
#       AU=Auro3D
#       MH=MPEG-H 3D Audio
#   - [7] Subtitle Language(s). Each followed optionally by type: ([addl.info]), addl.info: SDH, etc.
#     Audio and Subtitle Track Language format:
#     - Multiple tracks are separated by '/'
#     - A track can have a description (e.g. audio codec for audio track, SDH for subtitles), following in parenthesis, separated by an optional space
#     - Multiple tracks can share one description if concatenated by ',' ahead of description
#       - Each description starting with 2 uppercase characters will have those two matched against the audio codec list (see sound format above) and expanded
#     - Each track can contain multiple languages, separated by '+'
#       - Each language can have an optional region appended, separated by '-'
#       - Each region consisting of 2 characters will be matched to the ISO-3166 country codes and expanded
#       - Each language consisting of 2 or 3 characters will be matched to the ISO-639 language codes and expanded
#     Examples:
#       Multiple language tracks (English, French and Spanish): en/fr/es
#       Single track with multiple languages (both French and Italian): fr+it
#       Language with regional specifier (Brazilan Portugese): pt-br
#       Language track with description (English Subtitles for the Deaf and Hard-of-hearing): en(SDH)
#       Audio track with audio coding information (English Dolby Digital 5.1): en(DD5.1)
#       Audio track with combined audio coding information and description (English PCM, descriptive audio): en(PC Descr.)
#       Multiple tracks with shared description (Mandarin and Cantonese, each as PCM 2.0): cmn,yue(PC2.0)
#       Combination: en(MA7.1)/en(DD2.0 Commentary)/fr,es,pt-br(DD2.0)/hy+az+ka(PC1.0)
#   - [8] URL to info about the content (movie, show, etc) (imdb, tv.com, or special site)
#   - [9] date (ISO 8601 format: YYYY-MM-DD, for sorting, e.g. aquisition date)
#   - [10] cost (i.e. how much was spent to acquire this item)
#   - [11] ASIN (Amazon.com product ID number), prepended by country and a slash ('us/', 'de/', etc.) Default: US.
#   - [12] URL to info about the disk release (e.g. on blu-ray.com)

# URL controls:
#  file=FILENAME.EXT: Use database file other than dvd_list.txt
#  all=1: Show all items, including copied ones (with region = '-')
#  cost=1: Show cost of each item, and summary at the end
#  sort=COLUMN: Sort entries by colum, 0..11
#  revsort=1: Sort in descending order, instead of ascending
#  raw=1: Display plain text, without links
#  filter=DISCTYPES: Only show items that match one of the disc types, e.g. 'filter=tb' shows all Blu-rays and Blu-ray 3D
# 


use URI::Escape;



#
# Global variables
#

# background colors:
my @bgcolor = (
	'#F0F0F0',   # dark line
	'#B0B0D0',   # title line (blue-grey)
	'#E0FFE0',   # section summary (lime green)
	'#D0E0D0');  # total summary (green-grey)

# path to the DB file, if not in same directory as script
my $dbpath = '';

# User query from HTTP
my ($query, %query) = ('', ());

# Expansion pattern for languages through ISO-639 Language Codes (2 and 3 letters)
# Use 'iso-639-3_download.sh' to download most recent ISO 639-3 table
#my $iso639_table = 'iso-639-3_Latin1.tab'; # Windows-1252 Latin 1
my $iso639_table = 'iso-639-3.tab'; # UTF8
my $iso639_url = 'https://scarabaeus.org/' . $iso639_table;
# ISO-639 tables at https://iso639-3.sil.org/code_tables/download_tables
# - UTF8:   https://iso639-3.sil.org/sites/iso639-3/files/downloads/iso-639-3.tab
# - Latin1: https://iso639-3.sil.org/sites/iso639-3/files/downloads/iso-639-3_Latin1.tab
# tab-delimited:
#         Id      char(3) NOT NULL,  -- The three-letter 639-3 identifier
#         Part2B  char(3) NULL,      -- Equivalent 639-2 identifier of the bibliographic applications 
#                                    -- code set, if there is one
#         Part2T  char(3) NULL,      -- Equivalent 639-2 identifier of the terminology applications code 
#                                    -- set, if there is one
#         Part1   char(2) NULL,      -- Equivalent 639-1 identifier, if there is one    
#         Scope   char(1) NOT NULL,  -- I(ndividual), M(acrolanguage), S(pecial)
#         Type    char(1) NOT NULL,  -- A(ncient), C(onstructed),  
#                                    -- E(xtinct), H(istorical), L(iving), S(pecial)
#         Ref_Name   varchar(150) NOT NULL,   -- Reference language name 
#         Comment    varchar(150) NULL)       -- Comment relating to one or more of the columns

# Parse file of ISO-639 codes into hash table
my %lang = ();
if (open LANG, "<${iso639_table}") {
	my $header = 1;
	while (<LANG>) {
		chomp;
		my @line = split "\t";
		#print "ID:$line[0], 2B:$line[1], 2T:$line[2], 1:$line[3], Scope:$line[4], Type:$line[5], Name:$line[6], Comment:$line[7]<br>\n";
		if ($header) {
			$header = 0; # Skip header line
		} else {
			$line[6] =~ s/\s*\(.*\)//;
			$lang{$line[3]} = $line[6] if $line[3] ne '';
			$lang{$line[2]} = $line[6] if $line[2] ne '';
			$lang{$line[1]} = $line[6] if $line[1] ne '';
			$lang{$line[0]} = $line[6];
		}
	}
	close LANG;
	$lang{'cmn'} = 'Mandarin'; # replace 'Mandarin Chinese'
	$lang{'yue'} = 'Yue Cantonese'; # Cantonese (Hong-Kong), replace 'Yue Chinese'
}
$lang{'-'} = 'none';

# Expansion pattern for countries through ISO-3166 Country Codes (2 letters)
# -- How to get latest ISO-3166 country code data set --
# 1. Browse w/ Firefox to 'https://www.iso.org/obp/ui/#search/code/'
# 2. Select menu: "Tools" --> "Web Developer" --> "Network", developer tools window will open at bottom of page
# 3. On page, top right, select "Results per page": 300
# 4. In developer tools window at bottom, right-click on last "POST" entry (Type "json", about 120 kByte)
# 5. Select "Copy" --> "Copy Response"
# 6. Paste into text file and save as 'iso-3166-1.json' into cgi-bin directory
# 7. Run 'iso-3166-1_parse.pl' in cgi-bin directory to create .tab files
#my $iso3166_table = 'iso-3166-1_full.tab'; # tab-separated values, complete, see instructions above
my $iso3166_table = 'iso-3166-1.tab'; # tab-separated values, abridged (columns #4 and #6), see instructions above
my $iso3166_url = 'https://scarabaeus.org/' . $iso3166_table;
# tab-delimited:
#         ID      char(2)        -- The two-letter 3166 identifier
#         Name    varchar(150)   -- Reference country name 

# Parse file of ISO-3166 codes into hash table
my %country = ();
if (open CTRY, "<${iso3166_table}") {
	my $header = 1;
	while (<CTRY>) {
		chomp;
		my @line = split "\t";
		#print "ID:$line[0], Country:$line[1]<br>\n";
		if ($header) {
			$header = 0; # Skip header line
		} else {
			$country{uc($line[0])} = $line[1] if ($line[0]);
		}
	}
	close CTRY;
}

# Expansion pattern for audio codec. Short tag has to appear at the start of the description, followed by an optional space.
my %audio_codec = (
	'PC', 'PCM', 
	'DD', 'Dolby Digital', 
	'DP', 'Dolby Digital Plus', 
	'AD', 'Dolby Digital Plus / Atmos', 
	'TH', 'Dolby TrueHD', 
	'AT', 'Dolby TrueHD / Atmos', 
	'DT', 'DTS', 
	'HR', 'DTS-HD High Resolution', 
	'MA', 'DTS-HD Master Audio', 
	'DX', 'DTS:X MA', 
	'HX', 'DTS:X HR', 
	'DH', 'DTS Headphone:X', 
	'AU', 'Auro3D', 
	'MH', 'MPEG-H 3D Audio');

my %video_format = (
	'',  '4:3', 
	's', '4:3', 
	'a', '16:9', 
	'p', '16:9,720p', 
	'i', '16:9,1080i', 
	'h', '16:9,1080p', 
	'w', '21:9,1080p', 
	'u', '16:9,2160p');

my %hdr_format = (
	'',  ',SDR', 
	's', ',SDR', 
	'h', ',HDR10', 
	'd', ',Dolby Vision', 
	'p', ',HDR10+', 
	't', ',Technicolor HDR', 
	'g', ',HLG');



#
# Helper Functions
#

# Expansion function for audio and subtitle track descriptions
sub expand_lang
{
	my ($value) = @_;
	my $lang = ''; # Language(s) of audio or subtitle tracks
	my ($tracks, $track, $language);
	my $count = 0;
	for $tracks (split /\//, $value) { # separate language tracks by '/'
		my $descr = '';
		$descr = $1 if ($tracks=~s/ ?\((.*)\)//); # extract description, appended in '()'
		# expand audio coding type at beginning of description
		foreach $codec (keys %audio_codec) {
			last if $descr=~s/^${codec} ?/$audio_codec{$codec} /i;
		}
		for $track (split /,/, $tracks) { # separate tracks that share an add-on by ','
			my $multilang = ''; # one or more language in the track
			my $separator = '';
			for $language (split /\+/, $track) { # separate multi-language track by '+' into ISO language codes
				my $region = '';
				if ($language=~/^(.*)-(.*)$/) { # separate region, if appended to language, with '-' as separator
					$language = $1;
					$region = $2;
				}
				if ($language=~/^[a-zA-Z]{2}[a-zA-Z]?$/) {
					my $iso = lc($language);
					$language = $lang{$iso}; # expand 2 or 3 letter ISO 639 code to language name
					$language = '<font color="red"><b>' . $iso . '</b></font>' unless (defined($language) && ($language ne '')); # mark unknown language tag in bold red
				}
				$language .= "($country{uc($region)})" if ($region); # expand 2 letter ISO 3166 code to country name
				$multilang .= $separator . $language;
				$separator = '+';
			}
			$descr=~s/\s*$//;
			$multilang .= ' (' . $descr . ')' if $descr; # attach description
			$lang .= (($count > 0) ? '<br>' : '') . $multilang; # gather list of tracks
			$count++;
		}
	}
	if ($count > 3) { # in excess of 3 tracks, make it a size 3 selector
		my $select = '';
		for $track (split /<br>/, $lang) {
			my $style = '';
			$style = ' style="font-weight:bold;color:red;"' if $track=~/<b>/; # have to switch overall text of selection to red
			$select .= '<option' . $style . '>' . $track . '</option>';
		}
		$lang = '<form action=""><select size="3">' . $select . '</select></form>';
	}
	return $lang;
}

sub expand_vf
{
	my ($vf) = @_;
	
	if ($vf=~/(\d+\.\d+)(\w?)(\w?)(\w?)(\w?)\s*(.*)$/) {
		return 
			(
				"$1:1<font size=\"-1\">[" . 
				($video_format{$2} ? $video_format{$2} : $2) . 
				((($2 eq 'u') || ($3 ne '')) ? $hdr_format{'h'} : '') . 
				((($3 ne '') && ($3 ne 'h')) ? ($hdr_format{$3} ? $hdr_format{$3} : $3) : '') . 
				(($4 ne '') ? ($hdr_format{$4} ? $hdr_format{$4} : $4) : '') . 
				(($5 ne '') ? ($hdr_format{$5} ? $hdr_format{$5} : $5) : '') . 
				"]<\/font>" . 
				($6 ? " $6" : '')
			,
				$2=~/[hwu]/ ? 24 : 0
			);
	} else {
		return ($vf, 0);
	}
}

# allow flexible line break at occurrences of '/'
sub break
{
	my ($link) = @_;
	$link=~s/\//\/<wbr>/g if $link=~/[^\s]{10,}/;
	return $link;
}

# Create search field, used multiple times on the page
# Uses global vars $query, %query
sub search
{
	unless (defined($query{'raw'})) {
		my $q = '&' . $query;
		$q =~ s/\&search=[^&]*//;
		$q =~ s/^\&//;
		print "<p><form name=\"Search\">\n";
		my $search = '';
		$search = $query{'search'} if defined ($query{'search'});
		print "\t<a name=\"Search\">Search</a>: <input name=\"search\" type=\"text\" size=\"20\" value=\"${search}\" >\n";
		for my $key (keys %query) {
			print "\t<input name=\"$key\" type=\"hidden\" value=\"$query{$key}\" >\n" unless ($key=~/^search$/);
		}
		print "</form></p>\n";
	}
}



#
# Start of HTML
#

# get CGI parameter
%query = ();
$query{'file'} = 'dvd_list.txt';
$query = $ENV{'QUERY_STRING'};
chomp $query;
for (split (/&/, $query)) {
	if (/=/) {
		my ($param,$content) = split(/=/, $_, 2);
		$content =~ tr/+/ /;
		$content =~ s/%([0-9a-fA-F]{2})/pack('c',hex($1))/ge;
		$query{$param} = $content;
	} elsif ($_) {
		$query{'file'} = $_;
	}
}

$dbfile = $query{'file'};
$dbfile=~s/^.*\///; # Delete everything up to and including the last slash
$dbfile=~s/\/.*$//; 
$dbfile = $dbpath . $dbfile;

$title .= " Reverse" if (defined($query{'revsort'}));
$title .= " Sorted by Col. $query{'sort'}" if (defined($query{'sort'}));

# print HTTP header
print "MIME-Version: 1.0\nContent-Type: text/html\n\n";

my $title = 'Media List';

# print HTML header
#	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
print <<END;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
	<meta http-equiv="content-type" content="text/html; charset=utf-8">
	<title>${title}</title>
</head>
<body>
END

#foreach $ctr (sort keys %country) {
#	print "'${ctr}': '$country{$ctr}'<br>\n";
#}

search();

my (
	$items, $total_items, 
	$items_dvd, $total_items_dvd, 
	$items_cd, $total_items_cd, 
	$items_bd, $total_items_bd, 
	$items_3d, $total_items_3d, 
	$items_uhd, $total_items_uhd, 
	$items_hd, $total_items_hd, 
	$items_ld, $total_items_ld, 
	$items_vcd, $total_items_vcd, 
	$items_vhs, $total_items_vhs, 
	$items_dig, $total_items_dig, 
	$discs, $total_discs, 
	$discs_dvd, $total_discs_dvd, 
	$discs_cd, $total_discs_cd, 
	$discs_bd, $total_discs_bd, 
	$discs_3d, $total_discs_3d, 
	$discs_uhd, $total_discs_uhd, 
	$discs_hd, $total_discs_hd, 
	$discs_ld, $total_discs_ld, 
	$discs_vcd, $total_discs_vcd, 
	$discs_vhs, $total_discs_vhs, 
	$discs_dig, $total_discs_dig, 
	$times, $total_times
) = (0, 0, 0, 0, 0,  0, 0, 0, 0, 0,   0, 0, 0, 0, 0,  0, 0, 0, 0, 0,   0, 0, 0, 0, 0,  0, 0, 0, 0, 0,   0, 0, 0, 0, 0,  0, 0, 0, 0, 0,   0, 0, 0, 0, 0,  0);
my ($dollars, $total_dollars) = (0.00, 0.00);

my @lines = ();
my @sections = ();
my $td = 'th valign="baseline" align="left"';
my $firstseg = 1;
open LIST, "<${dbfile}" or die "list file '${dbfile}' not found!";
print "<table border=0 cellspacing=0 cellpadding=2>\n";
while (<LIST>) {
	chomp;
	s/^\#.*$//;
	next if /^\s*$/;
	next if ($td!~/^th/) && $query{'search'} && !/$query{'search'}/i && !/^--/;
	my @line = split "\t";
	if ($#line < 7) {  # Convert legacy file format
		for (my $i = 12; $i > 0; $i--) {
			$line[$i] = ($i < 4) ? '' : $line[$i - 3];
		}
	}
	while ($#line < 12) {
		push @line, '';
	}
	next if ((! defined($query{'all'})) && defined($line[5]) && ($line[5] =~ /-/));
	my $line = "\t<tr>";
	my $dollar = 0.00;
	my @key = ();
	my $imdbsearch = $line[0];
	my $fps = 0;
	if (defined($query{'sort'})) {
		@key = @line;
		# Remove article from title
		$key[0] =~ s/^\s*a\s+//i;
		$key[0] =~ s/^\s*an\s+//i;
		$key[0] =~ s/^\s*the\s+//i;
		$key[0] =~ s/^\s*der\s+//i;
		$key[0] =~ s/^\s*die\s+//i;
		$key[0] =~ s/^\s*das\s+//i;
		# Expand numbers in Title and Release to 8 digits
		$key[0] =~ s/(\d+)/sprintf "%08d", $1/eg;
		$key[1] =~ s/(\d+)/sprintf "%08d", $1/eg if defined($key[1]);
		# Remove anything besides letters, digits and white space from title and release
		$key[0] =~ s/[^\w\d\s]//;
		$key[1] =~ s/[^\w\d\s]// if defined($key[1]);
		# Simplify URLs
		$key[8] =~ s/(https?\:\/\/)(www\.)?// if defined($key[8]);
		$key[12] =~ s/(https?\:\/\/)(www\.)?// if defined($key[12]);
	}
	unless (/^--/) {
		push @line, '' while ($#line < 7);
		$line[0] =~s/^\*{3}\s+(.*)$/<b>$1<\/b>/;
		if ($td!~/^th/) {
			$line[0] = "<b>$line[0]</b>";
			if ($line[2]) {
				# Aspect Ratio (x.xx --> x.xx:1) and video format
				my @video_format = ();
				for $vf (split /\//, $line[2]) {
					my ($format, $rate) = expand_vf($vf);
					push @video_format, $format;
					$fps = 24 if ($rate == 24); # cumulative, any 24 fps or none
				}
				$line[2] = join('<br>', @video_format);
			}
			if (defined($line[5])) {
				$line[5] =~ s/^p/P<font size=\"-1\">AL<\/font>/i;
				$line[5] =~ s/^n/N<font size=\"-1\">TSC<\/font>/i;
				$line[5] =~ s/([\d\-A-F\?]+\??)$/\/Reg.$1/;
			}
			#$line[6] = break($line[6]);
			#$line[7] = break($line[7]);
			$line[6] = expand_lang($line[6]) if defined($line[6]);
			$line[7] = expand_lang($line[7]) if defined($line[7]);
		}
	} else {  # start of new segment == end of previous segment, print summary
		my $section = $line[0];
		$section =~s/^--\s*(.*)\s*/$1/;
		push @sections, $section;
		my $tag = $section;
		$tag =~ s/[^a-zA-Z0-9_]//g;
		$line[0] = "<b>-- <a name=\"${tag}\">" . $section . "</a></b>";
		if (defined($query{'raw'})) {
			$td = ($td eq 'td') ? 'td' : "td bgcolor=\"$bgcolor[0]\"";
		} else {
			$td = "td bgcolor=\"$bgcolor[2]\""; # unless defined($query{'raw'});
		}
		unless (defined($query{'sort'}) || defined($query{'raw'}) || $firstseg) {
			$line .= " <${td} colspan=3>${items} (${items_dvd} DVD, ${items_cd} CD, ${items_bd} Blu-ray (${items_3d} 3D), ${items_uhd} UltraHD Blu-ray, ${items_hd} HD-DVD, ${items_ld} Laser Disc, ${items_vcd} VideoCD, ${items_vhs} VHS, ${items_dig} DigCopy)</${td}> ";
			if ($times) {
				$times = sprintf("%d day%s, %d:%02d&nbsp;(%d&nbsp;min.)", $times / 1440, (int($times / 1440) == 1) ? '' : 's', ($times / 60) % 24, $times % 60, $times);
				$line .= "<${td}>${times}</${td}> ";
			} else {
				$line .= "<${td}></td> ";
			}
			$dollars = sprintf("%0.2f", $dollars);
			$line .= "<${td} colspan=4>${discs} (${discs_dvd} DVD, ${discs_cd} CD, ${discs_bd} Blu-ray (${discs_3d} 3D), ${discs_uhd} UltraHD Blu-ray, ${discs_hd} HD-DVD, ${discs_ld} Laser Disc, ${discs_vcd} VideoCD, ${discs_vhs} VHS, ${discs_dig} DigCopy, )</${td}> <${td} colspan=1></td> " . (defined($query{'cost'}) ? "<${td}>\$${dollars}</td> " : '') . "<${td} colspan=1></td> </tr>\n";
			$line .= "\t<tr> <td colspan=9></td> </tr>\n\n\t<tr>";
		}
		# Add segment counts to totals
		$total_discs_dvd += $discs_dvd;
		$total_discs_cd += $discs_cd;
		$total_discs_bd += $discs_bd;
		$total_discs_3d += $discs_3d;
		$total_discs_uhd += $discs_uhd;
		$total_discs_hd += $discs_hd;
		$total_discs_ld += $discs_ld;
		$total_discs_vcd += $discs_vcd;
		$total_discs_vhs += $discs_vhs;
		$total_discs_dig += $discs_dig;
		# Reset counts for next segment
		$items = 0;
		$items_dvd = 0;
		$items_cd = 0;
		$items_bd = 0;
		$items_3d = 0;
		$items_uhd = 0;
		$items_hd = 0;
		$items_ld = 0;
		$items_vcd = 0;
		$items_vhs = 0;
		$items_dig = 0;
		$discs = 0;
		$discs_dvd = 0;
		$discs_cd = 0;
		$discs_bd = 0;
		$discs_3d = 0;
		$discs_uhd = 0;
		$discs_hd = 0;
		$discs_ld = 0;
		$discs_vcd = 0;
		$discs_vhs = 0;
		$discs_dig = 0;
		$times = 0;
		$dollars = 0.00;
		$firstseg = 0;
		next if defined($query{'raw'});
	}
	if ($td=~/^th/) {
		my $q = '&' . $ENV{'QUERY_STRING'};
#		next if defined($query{'raw'});
		$q =~ s/\&revsort=\d+//;
		$q =~ s/\&sort=\d+//;
		$q =~ s/^\&//;
		for (my $i = 0; $i < 12; $i ++) {
			if (defined($query{'sort'}) && ($query{'sort'} == $i)) {
				if (defined($query{'revsort'})) {
					$line[$i] = "<u><a href=\"$ENV{SCRIPT_NAME}" . ($q ? '?' : '') . "${q}\">$line[$i]</a></u>";
				} else {
					$line[$i] = "<a href=\"$ENV{SCRIPT_NAME}?${q}" . ($q ? '&' : '') . "sort=${i}\&revsort=1\">$line[$i]</a>";
				}
			} else {
				$line[$i] = "<a href=\"$ENV{SCRIPT_NAME}?${q}" . ($q ? '&' : '') . "sort=${i}\">$line[$i]</a>";
			}
		}
		$line[6] .= "<sup><a href=\"${iso639_url}\">language</a></sup>";
		$line[7] .= "<sup><a href=\"${iso3166_url}\">country</a></sup>";
	} else {
		
		# Media type (Disc type, digital format)
		$key[4] = 0;
		if (defined($line[4]) && ($line[4] ne '')) {
			my $first = 1;
			my $first_3d = 1;
			my $first_dig = 1;
			my $got_bd = 0;
			my $skip = 0;
			$skip = 1 if defined($query{'filter'});
			if ($line[4] =~ /\D/) {  # number(s) with qualifier(s)
				my $num = $line[4];
				my ($t, $n);
				$line[4] = '';
				while ($num =~ /(\d+)(\D*)(.*)$/) {
					$line[4] .= ", " if ($line[4]);
					($n, $t, $num) = ($1, $2, $3);
					if ($t =~ /^c/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /c/i));
						next if $skip;
						$t = 'CD';
						$discs_cd += $n;
						$items_cd ++ if $first;
						$total_items_cd ++ if $first;
					} elsif ($t =~ /^s/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /s/i));
						next if $skip;
						$t = 'SACD';
						$discs_cd += $n;
						$items_cd ++ if $first;
						$total_items_cd ++ if $first;
					} elsif ($t =~ /^b/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /b/i));
						next if $skip;
						$t = 'Blu-ray';
						$discs_bd += $n;
						$items_bd ++ if $first;
						$total_items_bd ++ if $first;
						$got_bd = 1;
					} elsif ($t =~ /^t/i) { # Count Blu-Ray 3D items as both Blu-Ray and Blu-Ray 3D
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /t/i));
						next if $skip;
						$t = 'Blu-ray 3D';
						$discs_3d += $n;
						$items_3d ++ if ($first || $first_3d);
						$total_items_3d ++ if ($first || $first_3d);
						$items_bd ++ if ($first || ($first_3d && (! $got_bd)));
						$total_items_bd ++ if ($first || ($first_3d && (! $got_bd)));
						$first_3d = 0;
					} elsif ($t =~ /^u/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /u/i));
						next if $skip;
						$t = 'UltraHD Blu-ray';
						$discs_uhd += $n;
						$items_uhd ++ if $first;
						$total_items_uhd ++ if $first;
					} elsif ($t =~ /^h/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /h/i));
						next if $skip;
						if ($t =~ /d/i) {
							$t = 'HD-DVD/DVD';
						} else {
							$t = 'HD-DVD';
						}
						$discs_hd += $n;
						$items_hd ++ if $first;
						$total_items_hd ++ if $first;
					} elsif ($t =~ /^l/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /l/i));
						next if $skip;
						$t = 'Laser Disc';
						$discs_ld += $n;
						$items_ld ++ if $first;
						$total_items_ld ++ if $first;
					} elsif ($t =~ /^m/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /m/i));
						next if $skip;
						$t = 'VideoCD';
						$discs_vcd += $n;
						$items_vcd ++ if $first;
						$total_items_vcd ++ if $first;
					} elsif ($t =~ /^v/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /v/i));
						next if $skip;
						$t = 'VHS';
						$discs_vhs += $n;
						$items_vhs ++ if $first;
						$total_items_vhs ++ if $first;
					} elsif ($t =~ /^a/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /a/i));
						next if $skip;
						$t = 'UV/MA';
						$discs_dig += $n;
						$items_dig ++ if $first_dig;
						$total_items_dig ++ if $first_dig;
						$first_dig = 0;
					} elsif ($t =~ /^i/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /i/i));
						next if $skip;
						$t = 'iTunes';
						$discs_dig += $n;
						$items_dig ++ if $first_dig;
						$total_items_dig ++ if $first_dig;
						$first_dig = 0;
					} elsif ($t =~ /^y/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /y/i));
						next if $skip;
						$t = 'DigCopy';
						$discs_dig += $n;
						$items_dig ++ if $first_dig;
						$total_items_dig ++ if $first_dig;
						$first_dig = 0;
					} elsif ($t =~ /^a/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /a/i));
						next if $skip;
						$t = 'DVD Audio';
						$discs_dvd += $n;
						$items_dvd ++ if $first;
						$total_items_dvd ++ if $first;
					} elsif ($t =~ /^r/i) {
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /r/i));
						next if $skip;
						$t = 'DVD-R';
						$discs_dvd += $n;
						$items_dvd ++ if $first;
						$total_items_dvd ++ if $first;
					} else { # 'd' or unknown designator, default to DVD
						$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /d/i));
						next if $skip;
						$t = 'DVD';
						$discs_dvd += $n;
						$items_dvd ++ if $first;
						$total_items_dvd ++ if $first;
					}
					$key[4] += $n;
					$discs += $n;
					$total_discs += $n;
					$line[4] .= '<br>' if ($line[4]);
					$line[4] .= $n . '&nbsp;' . $t . (($n == 1) ? '' : 's');
					$first = 0;
				}
				next if $skip;
			} else {  # just a number, assume DVD
				$skip = 0 if (defined($query{'filter'}) && ($query{'filter'} =~ /d/i));
				next if $skip;
				my $dvd_count = 1;
				$dvd_count = $line[4] if defined($line[4]) && ($line[4] > 0);
				$key[4] += $dvd_count;
				$discs += $dvd_count;
				$discs_dvd += $dvd_count;
				$items_dvd ++;
				$total_discs += $dvd_count;
				$total_items_dvd ++;
				$line[4] .= '&nbsp;DVD' . (($dvd_count == 1) ? '' : 's');
			}
			$items ++;
			$total_items ++;
		} else { # No info, assume DVD without specific number of discs
			next if (defined($query{'filter'}) && ($query{'filter'} =~ /d/i));
			next if (defined($query{'raw'}));
		}
		
		# Running time (2:2 pulldown adjustment)
		if ($line[3] =~/\d/) {
			my $time_line = '';
			$key[3] = 0;
			for $rt (split /\//, $line[3]) {
				my $runtime = defined($rt) ? $rt : 0;
				if ($runtime =~/(\d+)\:(\d+)/) {
					$runtime = $1 * 60 + $2;
				} elsif ($runtime =~/\D/) {
					$runtime = 0;
				}
				my $time_entry = sprintf("%d:%02d&nbsp;", $runtime / 60, $runtime % 60);
				if (($line[5]=~/P/) && ($fps != 24)) {
					$time_entry .= sprintf("(%d[%d]&nbsp;min.)", $runtime, $runtime * 25 / 24);
				} else {
					$time_entry .= sprintf("(%d&nbsp;min.)", $runtime);
				}
				$time_line .= '<br>' if ($time_line);
				$time_line .= $time_entry;
				$key[3] = $runtime if (defined($query{'sort'}) && ! $key[3]);
				$times += $runtime;
				$total_times += $runtime;
			}
			$line[3] = $time_line;
		}
		
		# Cost (currency conversion, 2018)
		if (defined($query{'cost'}) && defined($line[10])) {
			my ($currency, $amount) = ('D', 0);
			if ($line[10] =~ /^([A-Z]?)(.*)$/) {
				$currency = $1 if defined($1);
				$amount = $2 if defined($2);
				$amount = 0 unless ($amount =~ /\d+\.\d{2}/);
			}
			if ($currency =~ /^E/) {
				$dollar = ($amount * 1.1);
				$line[10] =~ s/^E/&euro;/;
				$line[10] .= sprintf(" (~\$%0.2f)", $dollar);
			} elsif ($currency =~ /^P/) {
				$dollar = ($amount * 1.3);
				$line[10] =~ s/^P/&pound;/;
				$line[10] .= sprintf(" (~\$%0.2f)", $dollar);
			} elsif ($amount) {
				$dollar = $amount;
				$line[10] = sprintf("\$%0.2f", $dollar);
			}
			$key[10] = $dollar;
			$dollars += $dollar;
			$total_dollars += $dollar;
		} else {
			$key[10] = 0;
		}
		
		# ASIN
		if (defined($line[11]) && ($line[11] ne "") && (! defined($query{'raw'}))) {
			if ($line[11] =~ /\//) { # Optional: prefix with Amazon country (e.g. "de/" for amazon.de)
				my ($country, $asin) = split('/', $line[11]);
				if ($country eq 'de') { # Germany
					$line[11] = "<a href=\"http://amazon.de/dp/${asin}/\">${asin}</a>";
				} elsif ($country eq 'jp') { # Japan
					$line[11] = "<a href=\"http://amazon.co.jp/dp/${asin}/\">${asin}</a>";
				} elsif ($country eq 'uk') { # UK
					$line[11] = "<a href=\"http://amazon.co.uk/dp/${asin}/\">${asin}</a>";
				} elsif ($country eq 'fr') { # France
					$line[11] = "<a href=\"http://amazon.fr/dp/${asin}/\">${asin}</a>";
				} elsif ($country eq 'it') { # Italy
					$line[11] = "<a href=\"http://amazon.it/dp/${asin}/\">${asin}</a>";
				} elsif ($country eq 'ca') { # Canada
					$line[11] = "<a href=\"http://amazon.ca/dp/${asin}/\">${asin}</a>";
				} elsif ($country eq 'us') { # USA
					$line[11] = "<a href=\"http://amazon.com/dp/${asin}/\">${asin}</a>";
				} else {
					$line[11] = "<a href=\"http://amazon.${country}/dp/${asin}/\">${asin}</a>";
				}
			} else {
				my $asin = $line[11];
				$line[11] = "<a href=\"http://amzn.com/${asin}/\">${asin}</a><sup><a href=\"https://catalog-retail.amazon.com/abis/syh/DisplayCondition/?asin=${asin}\">*</a></sup>";
			}
			# http://www.amazon.com/gp/offer-listing/${asin}/?condition=new
			# http://www.amazon.com/gp/offer-listing/${asin}/?condition=used
			# https://catalog-retail.amazon.com/abis/syh/DisplayCondition/?asin=${asin}
		}
		
	}
	if ($line[0]=~/^<b>--/) {
		next if defined($query{'raw'});
		$td = "td bgcolor=\"$bgcolor[1]\"";
		$line .= " <${td}>$line[0]</${td}> =====";
	} else {
		if ($td!~/^th/) {
			$line[0] =~ s/( [-\/] )/$1\<br\>&nbsp;&nbsp;/g;
			$line[0] =~ s/: /:\<br\>&nbsp;&nbsp;/g;
			$line[0] =~ s/  / \<br\>&nbsp;&nbsp;/g;
			$line[1] =~ s/( [-\/] )/$1\<br\>&nbsp;&nbsp;/g;
			$line[1] =~ s/: /:\<br\>&nbsp;&nbsp;/g;
			if ((! defined($query{'raw'})) && defined($line[8]) && ($line[8] =~ /(https?\:\/\/)(www\.)?(\S*?)(\/?)(\s*)$/)) {
				my $url = '';
				my $link = '';
				my $spacing = '';
				$url = $1 if defined($1);
				$url .= $2 if defined($2);
				$url .= $3 if defined($3);
				$url .= $4 if defined($4);
				$link .= $3 if defined($3);
				$spacing = $5 if defined($5);
				$line[8] =~ s/https?\:\/\/(www\.)?\S*?\/?\s*$/"<a href=\"${url}\">" . break(${link}) . "<\/a>${spacing}"/ge;
				$line[0] = "<a href=\"${url}\">" . $line[0]. "<\/a>";
			} elsif (! defined($query{'raw'})) {
				$imdbsearch =~ s/ - .*$//;
				$imdbsearch =~ s/ /+/g;
				$line[0] = "<a href=\"https://imdb.com/find?q=${imdbsearch}&s=all\">" . $line[0]. "<\/a>";
			}
			if ((! defined($query{'raw'})) && defined($line[12]) && ($line[12] =~ s/(https?\:\/\/)(www\.)?(\S*?)(\/?)(\s*)$/"<a href=\"$1$2$3$4\">" . break($3) . "<\/a>$5"/ge)) {
				$line[1] = "<a href=\"$1$2$3$4\">" . $line[1]. "<\/a>";
			}
		}
		
		#my $w = ' width="25%"';
		my $w = ' nowrap="nowrap"';
		for (my $i = 0; $i < 12; $i ++) {
			if (($i != 10) || defined($query{'cost'})) {
				$line .= defined($line[$i]) ? " <${td}${w}>$line[$i]</${td}>" : " <${td}></${td}>" if ($query{'url'} || ($i != 8));
				#$w = ' nowrap="nowrap"';
				#$w = '';
			}
		}
	}
	$line .= " </tr>\n";
	if (($td!~/^th/) && defined($query{'sort'})) {
		unless (/^--/ || /^\*\*\*/) {
			my $sort_key = '';
			$sort_key = $key[$query{'sort'}] if defined($key[$query{'sort'}]);
			push @lines, $key[0] . "\t" . $sort_key . $line; # Always sort by Title in second order
		}
	} else {
		push @lines, $line;
	}
	$td = ($td eq 'td') ? "td bgcolor=\"$bgcolor[0]\"" : 'td';
}
close LIST;

sub bykeys {
	my ($a0, $a1, $b0, $b1) = ('', '', '', '');
	($a0, $a1) = ($1, $2) if ($a =~ /^(.*?)\t(.*?)\t/);
	($b0, $b1) = ($1, $2) if ($b =~ /^(.*?)\t(.*?)\t/);
	(lc($a1) cmp lc($b1)) || (lc($a0) cmp lc($b0));
}

sub bykeysnum {
	my ($a0, $a1, $b0, $b1) = ('', '', '', '');
	($a0, $a1) = ($1, $2) if ($a =~ /^(.*?)\t(.*?)\t/);
	($b0, $b1) = ($1, $2) if ($b =~ /^(.*?)\t(.*?)\t/);
	$a1 = 0 unless $a1;
	$b1 = 0 unless $b1;
	($a1 <=> $b1) || (lc($a0) cmp lc($b0));
}

if (defined($query{'sort'})) {
	my @sorted;
	# By Duration, Disc count, or Price: Numerical sort, otherwise alphabetical
	if (($query{'sort'} == 3) || ($query{'sort'} == 4) || ($query{'sort'} == 10)) {
		if (defined($query{'revsort'})) {
			@sorted = reverse sort bykeysnum @lines;
		} else {
			@sorted = sort bykeysnum @lines;
		}
	} else {
		if (defined($query{'revsort'})) {
			@sorted = reverse sort bykeys @lines;
		} else {
			@sorted = sort bykeys @lines;
		}
	}
	if (defined($query{'revsort'})) {
		my $header = pop @sorted;
		unshift @sorted, $header;
	}
	$td = 'td';
	for (@sorted) {
		s/^.*?\t.*?\t/\t/;
		$td = ($td eq 'td') ? "td bgcolor=\"$bgcolor[0]\"" : 'td';
		s/td bgcolor=\"$bgcolor[0]\"/td/g;
		s/<td/<${td}/g;
		print;
	}
} elsif (defined($query{'raw'})) {
	for (@lines) {
		print;
	}
} else {
	my $jump = "<td colspan=" . (defined($query{'cost'}) ? '10' : '9') . " bgcolor=\"$bgcolor[1]\">[<font size=\"-1\"><a href=\"#\">Top</a>]";
	for (@sections) {
		my $tag = $_;
		$tag =~ s/[^a-zA-Z0-9_]//g;
		$jump .= " -- <a href=\"#${tag}\">$_</a>";
	}
	$jump .= " -- [<script type=\"text/javascript\">document.write(\"<a href=\\\"javascript:document.forms.Search.elements.search.focus();\\\">\");</script><noscript><a href=\"#Search\"></noscript>Search</a></font>]";
	$jump .= " -- [<script type=\"text/javascript\">document.write(\"<a href=\\\"javascript:document.forms.new_entry.elements.new_title.focus();\\\">\");</script><noscript><a href=\"#NewEntry\"></noscript>New Entry</a></font>]";
	$jump .= "</td>";
	for (@lines) {
		s/=====/$jump/;
		print;
	}
	# print last segment summary
	$td = "td bgcolor=\"$bgcolor[2]\"";
	print "\t<tr> <${td} colspan=3>${items} (${items_dvd} DVD, ${items_cd} CD, ${items_bd} Blu-ray (${items_3d} 3D), ${items_uhd} UltraHD Blu-ray, ${items_hd} HD-DVD, ${items_ld} Laser Disc, ${items_vcd} VideoCD, ${items_vhs} VHS, ${items_dig} DigCopy, )</${td}> ";
	if ($times) {
		$times = sprintf("%d day%s, %d:%02d&nbsp;(%d&nbsp;min.)", $times / 1440, (int($times / 1440) == 1) ? '' : 's', ($times / 60) % 24, $times % 60, $times);
		print "<${td}>${times}</${td}> ";
	} else {
		print "<${td}></td> ";
	}
	$dollars = sprintf("%0.2f", $dollars);
	print "<${td} colspan=4>${discs} (${discs_dvd} DVD, ${discs_cd} CD, ${discs_bd} Blu-ray (${discs_3d} 3D), ${discs_uhd} UltraHD Blu-ray, ${discs_hd} HD-DVD, ${discs_ld} Laser Disc, ${discs_vcd} VideoCD, ${discs_vhs} VHS, ${discs_dig} DigCopy)</${td}> <${td} colspan=1></td> " . (defined($query{'cost'}) ? "<${td}>\$${dollars}</td> " : '') . "<${td} colspan=1></td> </tr>\n\t<tr>";
}

# Add last segment counts to totals
$total_discs_dvd += $discs_dvd;
$total_discs_cd += $discs_cd;
$total_discs_bd += $discs_bd;
$total_discs_3d += $discs_3d;
$total_discs_uhd += $discs_uhd;
$total_discs_hd += $discs_hd;
$total_discs_ld += $discs_ld;
$total_discs_vcd += $discs_vcd;
$total_discs_vhs += $discs_vhs;
$total_discs_dig += $discs_dig;

# print file summary
$td = "td bgcolor=\"$bgcolor[3]\"";
print " <${td} colspan=3>${total_items} (${total_items_dvd} DVD, ${total_items_cd} CD, ${total_items_bd} Blu-ray (${total_items_3d} 3D), ${total_items_uhd} UltraHD Blu-ray, ${total_items_hd} HD-DVD, ${total_items_ld} Laser Disc, ${total_items_vcd} VideoCD, ${total_items_vhs} VHS, ${total_items_dig} DigCopy)</${td}> ";
if ($total_times) {
	$total_times = sprintf("%d day%s, %d:%02d&nbsp;(%d&nbsp;min.)", $total_times / 1440, (int($total_times / 1440) == 1) ? '' : 's', ($total_times / 60) % 24, $total_times % 60, $total_times);
	print "<${td}>${total_times}</${td}> ";
} else {
	print "<${td}></td> ";
}
$total_dollars = sprintf("%0.2f", $total_dollars);
print "<${td} colspan=4>${total_discs} (${total_discs_dvd} DVD, ${total_discs_cd} CD, ${total_discs_bd} Blu-ray (${total_discs_3d} 3D), ${total_discs_uhd} UltraHD Blu-ray, ${total_discs_hd} HD-DVD, ${total_discs_ld} Laser Disc, ${total_discs_vcd} VideoCD, ${total_discs_vhs} VHS, ${total_discs_dig} DigCopy)</${td}> <${td} colspan=1></${td}> " . (defined($query{'cost'}) ? "<${td}>\$${total_dollars}</td> " : '') . "<${td} colspan=1></td> </tr>\n";
print "</table>\n";

search();

print <<EXPL unless defined($query{'raw'});
<p>
Common film aspect ratios are 1.37:1 (Full Frame), 1.66:1 (European 
and Disney productions), 1.85:1 (Matted Wide Screen) and 2.39:1 (Panavision, 
Anamorphic Widescreen). Historic film aspect ratios are 1.75:1 (Alternative 
Matted Wide Screen), 2.35:1 (Cinemascope, Techniscope), 2.20:1 (70mm) and 
2.76:1 (Ultra Panavision 70).
A DVD can encode pictures either "normal" with a 4:3 aspect ratio, or
anamorphic ("Enhanced for widescreen TVs") with a 16:9 aspect 
ratio. Video productions therefore usually have those 
aspect ratios, 1.33:1 and 1.78:1. Movies with 1.66:1, 1.85:1 
and 2.39:1 aspect ratios should be encoded as anamorphic 
video pictures, this increases the number of lines 
containing actual picture information. Movies shot on 
"Super 35" are intended to be shown at 2.39:1 or 1.85:1, 
but have enough image material above and below the frame 
to allow for a "fullscreen" 1.33:1 release as well.
</p>
<p>
The running time of PAL encoded movies is often shortened
due to the fact that the 24 fps film is encoded
without frame rate adaption on the 25 fps video 
system (2:2 pulldown). The duration time for PAL 
states the assumed film length in square brackets 
after the video running time.
</p>
<script type="text/javascript">
//<!--
//document.forms.Search.elements.search.focus();
//-->
</script>
EXPL

my $new_url_title_default = 'https://imdb.com/title//';
my $new_url_release_default = 'http://blu-ray.com/movies//';
my @new_fields = (
  'new_section', 
  'new_title', 
  'new_release', 
  'new_aspect_ratio', 
  'new_time', 
  'new_discs', 
  'new_std', 
  'new_lang', 
  'new_sub', 
  'new_url_title', 
  'new_date', 
  'new_cost', 
  'new_asin', 
  'new_url_release', 
  'new_timestamp', 
);
my %new_default = (
#  'new_time' => 'mmm or h:mm', 
  'new_url_title' => 'https://imdb.com/title//', 
  'new_url_release' => 'http://blu-ray.com/movies//', 
  'new_asin' => 'us/B000000000', 
);

foreach $name (@new_fields) {
  $new_default{$name} = '' unless defined($new_default{$name});
}

my $now = time();
my ($sec, $min, $hour, $day, $month, $year, $wday, $yday, $isdst) = gmtime($now);
$year += 1900;
$month++;
my $timestamp = sprintf("%04d%02d%02d%02d%02d%02d", $year, $month, $day, $hour, $min, $sec);
$new_default{'new_timestamp'} = $timestamp;
$new_default{'new_date'} = sprintf("%04d-%02d-%02d", $year, $month, $day);

my %new_entry = ();
my ($buffer, @pairs, $pair, $name, $value);
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "POST") {
  print "New entries:<br>\n";
  read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
  @pairs = split(/&/, $buffer);
  foreach $pair (@pairs) {
    ($name, $value) = split(/=/, $pair);
    $value =~ tr/+/ /;
    $value =~ s/%(..)/pack("C", hex($1))/eg;
    $new_entry{$name} = $value;
    $new_default{'new_date'} = $new_entry{'prev_default_date'} if ($new_entry{'prev_default_date'});
    if ($new_entry{$name} eq $new_default{$name}) {
      $new_entry{$name} = '';
    }
    print "&nbsp;&nbsp;'$name' = '$new_entry{$name}'<br>\n";
  }
  print "End of new entries<br>\n";
  # TODO
  
  $new_entry{'new_aspect_ratio'} = ($new_entry{'new_aspect_ratio'} ? $new_entry{'new_aspect_ratio'} : $new_entry{'new_aspect_select'}) . $new_entry{'new_aspect_format'};
  my $line = '';
  foreach $name (@new_fields) {
    $line .= $new_entry{$name} . "\t";
  }
  $line=~s/\t/|/g;
  print "New line: '$line'<br>\n";
}

my %default_entry = ();
foreach $name (keys %new_default) {
  $default_entry{$name} = $new_entry{$name} ? $new_entry{$name} : $new_default{$name} ? $new_default{$name} : '';
  #print "Def.: '$name' = '$default_entry{$name}'<br>\n";
}

print <<FORM unless defined($query{'raw'});
<p>
<form name="new_entry" method="post">
<a name="NewEntry"><h3>Add New Entry (under construction)</h3></a>
<table border=0>
<tr>
  <th bgcolor="$bgcolor[0]" align="left">Item</th>
  <th bgcolor="$bgcolor[0]" align="left">Value</th>
  <th bgcolor="$bgcolor[0]" align="left">Format / Description</th>
</tr>
<tr>
  <td> Section:</td>
  <td><input type="text" name="new_section" value="$default_entry{'new_section'}" size="64" /></td>
  <td>Genre / Category</td>
</tr>
<tr>
  <td bgcolor="$bgcolor[0]"> Title:</td>
  <td bgcolor="$bgcolor[0]"><input type="text" name="new_title" value="$default_entry{'new_title'}" size="64" /></td>
  <td bgcolor="$bgcolor[0]">Title of the Movie, or Show and Season</td>
</tr>
<tr>
  <td> Release:</td>
  <td><input type="text" name="new_release" value="$default_entry{'new_release'}" size="64" /></td>
  <td>Media Release Studio - Special Edition</td>
</tr>
<tr>
  <td bgcolor="$bgcolor[0]"> Aspect Ratio:</td>
  <td bgcolor="$bgcolor[0]"><input type="text" name="new_aspect_ratio"      value="$default_entry{'new_aspect_ratio'}" size="12" /></td>
  <td bgcolor="$bgcolor[0]">'x.xx[f][/x.xx[f]...]' Aspect Ratio x.xx:1; f=Format, one of [ahipu]: none=Full-Format SD, a=Anamorphic SD, h=1080p HD, i=1080i HD, p=720p HD, u=2160p UHD  </td>
</tr>
<tr>
  <td> Running Time:</td>
  <td><input type="text" name="new_time"        value="$default_entry{'new_time'}" size="6" /></td>
  <td>h:mm or mmm </td>
</tr>
<tr>
  <td bgcolor="$bgcolor[0]"> Media Items:</td>
  <td bgcolor="$bgcolor[0]"><input type="text" name="new_discs"       value="$default_entry{'new_discs'}" size="12" /></td>
  <td bgcolor="$bgcolor[0]">nX[nX[nX...]] n=Number, X=Media Type, one of [D|C|S|B|T|U|H|L|V|A|I|Y], 'D'=DVD, 'C'=CD, 'S'=SuperAudioCD, 'B'=Blu-ray, 'T'=Blu-ray 3D, 'U'=UltraHD Blu-ray, 'H'=HD-DVD, 'L'=Laser Disc, 'V'=Video CD, 'A'=UV/MA, 'I'=iTunes, 'Y'=other digital copy  </td>
</tr>
<tr>
  <td> Standard and Region:</td>
  <td><input type="text" name="new_std"         value="$default_entry{'new_std'}" size="3" /></td>
  <td>[SR], S=Standard, one of [N|P]: NTSC or PAL; R=Region, 0=Free, -=Copy, 1..8 for DVD, A..C for Blu-ray  </td>
</tr>
<tr>
  <td bgcolor="$bgcolor[0]"> Audio:</td>
  <td bgcolor="$bgcolor[0]"><input type="text" name="new_lang"        value="$default_entry{'new_lang'}" size="12" /></td>
  <td bgcolor="$bgcolor[0]">[LL|LLL[-CC]][([XX][C.L][ D])][/...] LL=ISO639-2, LLL=ISO639-3 <a href=\"${iso639_url}\">Language Code</a>; CC=ISO3166 <a href=\"${iso3166_url}\">Country Code</a>; XX=Audio Coding Type: PC=PCM, DD=Dolby Digital, DP=DDPlus, AD=DDPlus Atmos, TH=TrueHD, AT=Dolby TrueHD Atmos, DT=DTS, HR=DTS-HD High Resolution, MA=DTS-HD Master Audio, DX=DTS:X, DH=DTS Headphone:X, AU=Auro3D, MH=MPEG-H 3D Audio; C.L=Channels.LFE; D=Description, e.g. DVS, Descr., EX, latenight, Neo:X, etc.  </td>
</tr>
<tr>
  <td> Subtiles:</td>
  <td><input type="text" name="new_sub"         value="$default_entry{'new_sub'}" size="12" /></td>
  <td>[LL|LLL[-CC][(D)][/...]] LL=ISO639-2, LLL=ISO639-3 <a href=\"${iso639_url}\">Language Code</a>; CC=ISO3166 <a href=\"${iso3166_url}\">Country Code</a>; D=Description, e.g. SDH  </td>
</tr>
<tr>
  <td bgcolor="$bgcolor[0]"> URL (Title):</td>
  <td bgcolor="$bgcolor[0]"><input type="text" name="new_url_title"   value="$default_entry{'new_url_title'}" size="64" /></td>
  <td bgcolor="$bgcolor[0]">URL about the Movie / Show (e.g. IMDB link)</td>
</tr>
<tr>
  <td> Date:</td>
  <td><input type="text" name="new_date"        value="$default_entry{'new_date'}" size="11" /></td>
  <td>YYYY-MM-DD: Acquisition (i.e. arrival) Date</td>
</tr>
<tr>
  <td bgcolor="$bgcolor[0]"> Cost:</td>
  <td bgcolor="$bgcolor[0]"><input type="text" name="new_cost"        value="$default_entry{'new_cost'}" size="6" /></td>
  <td bgcolor="$bgcolor[0]">Total cost, En.nn for Euro, Pn.nn for Pounds, otherwise Dollars</td>
</tr>
<tr>
  <td> ASIN:</td>
  <td><input type="text" name="new_asin"        value="$default_entry{'new_asin'}" size="14" /></td>
  <td>Amazon Product ID, prepended by country and a slash ('us/', 'de/', etc.) Default: US.</td>
</tr>
<tr>
  <td bgcolor="$bgcolor[0]"> URL (Release):</td>
  <td bgcolor="$bgcolor[0]"><input type="text" name="new_url_release" value="$default_entry{'new_url_release'}" size="64" />  </td>
  <td bgcolor="$bgcolor[0]">URL about the release (e.g. blu-ray.com link)</td>
</tr>
<tr>
  <td> Timestamp:</td>
  <td><input type="hidden" name="new_timestamp" value="$default_entry{'new_timestamp'}" />$default_entry{'new_timestamp'}</td>
  <td><input type="hidden" name="prev_default_date" value="$default_entry{'new_date'}" /></td>
</tr>
<tr>
  <td bgcolor="$bgcolor[0]"></td>
  <td bgcolor="$bgcolor[0]"><button type="submit">Add</button></td>
  <td bgcolor="$bgcolor[0]"></td>
</tr>
</table>
</form>
</p>
FORM

my $aspect=<<ASP;
<tr><td> Aspect Ratio (future):</td><td>
  <select name="new_aspect_select" size="1" onSelect="document.forms.new_entry.elements.new_aspect_ratio.focus();">
    <option value="">Unknown</option>
    <option value="1.33">1.33:1, 4:3</option>
    <option value="1.37">1.37:1</option>
    <option value="1.66">1.66:1</option>
    <option selected value="1.78">1.78:1, 16:9</option>
    <option value="1.85">1.85:1</option>
    <option value="2.20">2.20:1</option>
    <option value="2.35">2.35:1</option>
    <option value="2.39">2.39:1, 2.40:1, 2.4:1</option>
    <option value="2.76">2.76:1</option>
    <option value="">Custom</option>
  </select>
  <input type="text" name="new_aspect_ratio" value="$default_entry{'new_aspect_ratio'}" size="4" />:1                
  <select name="new_aspect_format" size="1">
    <option value="">Unknown</option>
    <option value="">Full-Format SD</option>
    <option value="a">Anamorphic SD</option>
    <option selected value="h">1080p HD</option>
    <option value="i">1080i HD</option>
    <option value="p">720p HD</option>
    <option value="u">2160p UHD</option>
  </select>
</td></tr>
ASP

print "</body>\n";

