#!/usr/bin/perl -w
#
# --- WORK IN PROGRESS ---
#
# medialist (nee dvdlist.pl), a perl CGI script to display a list of movie media on a web page
#
# License: MIT https://opensource.org/licenses/MIT
#
# Copyright 2005-2020  Christian Wolff sub-medialist <at> scara <dot> com
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to 
# deal in the Software without restriction, including without limitation the 
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
#

my (sql_user, sql_passwd) = ('medialist', 'M3d1aL157');

# MySQL setup
#
# As mysql admin (mysql -u root):
#   CREATE USER 'medialist'@'localhost' IDENTIFIED WITH mysql_native_password BY 'M3d1aL157' PASSWORD EXPIRE NEVER;
# Then:
#   CREATE DATABASE medialist;
# 
# Maintenance:
#   ALTER USER 'medialist'@'localhost' IDENTIFIED WITH mysql_native_password BY 'M3d1aL157' PASSWORD EXPIRE NEVER;
#   SHOW GRANTS FOR 'medialist'@'localhost';
#   
# 
# As mysql user (mysql -u medialist -pM3d1aL157):
# Switch to new db:
#   USE medialist
# Or run: mysql -u medialist -pM3d1aL157 medialist
#
# CREATE TABLE media (
#   added DATE
#   title TEXT, 
#   titleyear YEAR, 
#   titleinfo URL(?)
#   release TEXT,
#   releaseyear YEAR, 
#   releaseinfo URL
#   count
#   region
#   duration TIME, 
#   aspectratio 
#   audio
#   subtitles
#   cost
#   asin
#   location
#   access DATE
#   );

# 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) (1.33, 1.78, 1.37, 1.66, 1.85, 2.35 followed by 's' if standard definition, 'a' if anamorphic widescreen, 'h' if HighDefinition 1080p, 'u' if UltraHD 2160p, 'p' if 720p, 'w' if 1080p 21:9, or 'i' for 1080i; 'u' optionally followed by 'h' for HDR10, 'd' for Dolby Vision, 'p' for HDR10+, 't' for Technicolor HDR, 'g' for HLG; separated by '/')
#   - [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] Language(s) (ISO 639-1 or ISO 639-3, separated by '/'. 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(s) (ISO 639-1 or ISO 639-3, separated by '/'). Each followed optionally by type: ([addl.info]), addl.info: SDH, etc.
#   - [8] URL to info about the content (movie, show, etc) (imdb, tv.com, or special site)
#   - [9] date (ISO 8601 format, 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 $isotable = 'iso-639-3_Latin1.tab'; # Windows-1252 Latin 1
my $isotable = 'iso-639-3.tab'; # UTF8
my $isourl = 'https://scarabaeus.org/' . $isotable;
# 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
# Format:
#   Multiple language tracks (English, French ans Spanish): en/fr/es
#   Single track with multiple languages (French and Italian): fr-it
#   Language track with description (English Sustitles 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,fr-it(DD2.0)/hy-az-ka(PC1.0)
my %lang = ();
if (open LANG, "<${isotable}") {
	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'
my $country_json = 'iso-3166-1.json'; # Raw dump, see instructions above
my %country = ();
if (open JSON, "<${country_json}") {
	while (<JSON>) {
		chomp;
		my @entries = split "\{\"k\":";
		foreach $entry (@entries) {
			if ($entry =~ /.*\,\"d\":\{(.*)\},\"cs\":\{.*/) {
				my @row = ();
				for $item (split /,\"/, $1) { # "
					if ($item =~/\d+\":\"(.*)\"/) {
						push @row, $1;
					}
				}
				$country{$row[3]} = $row[5] if ($row[3]);
			}
		}
	}
	close JSON;
}

# 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
#

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
				if ($language=~/^[a-z]{2}[a-z]?$/) {
					my $iso = $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
				}
				$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;
}

# 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

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];
	if (defined($query{'sort'})) {
		@key = @line;
		$key[0] =~ s/^\s*a\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;
		$key[0] =~ s/[^\w\d\s]//;
		$key[1] =~ s/[^\w\d\s]// if defined($key[1]);
		$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]) {
					if ($vf=~/(\d+\.\d+)(\w?)(\w?)\s*(.*)$/) {
						push @video_format, 
							"$1:1<font size=\"-1\">[" . 
							($video_format{$2} ? $video_format{$2} : $2) . 
							((($2 eq 'u') || ($3 ne '')) ? ($hdr_format{$3} ? $hdr_format{$3} : $3) : '') . 
							"]<\/font>" . 
							($4 ? " $4" : '');
					} else {
						push @video_format, $vf;
					}
				}
				$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=\"${isourl}\">1</a></sup>";
		$line[7] .= "<sup><a href=\"${isourl}\">1</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/) && ( {
					$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;
		}
	} 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;
	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][([XX][C.L][ D])][/...] LL=ISO639-2, LLL=ISO639-3 <a href=\"${isourl}\">Language 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[(D)][/...]] LL=ISO639-2, LLL=ISO639-3 <a href=\"${isourl}\">Language 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";

