aboutsummaryrefslogtreecommitdiff
path: root/lib/MasterWebInterface
diff options
context:
space:
mode:
authorDarkelarious <github@333networks.com>2025-03-08 15:56:30 +0100
committerDarkelarious <github@333networks.com>2025-03-08 15:56:30 +0100
commit6bd235f3e62251d8763a552ab0042d59584de842 (patch)
tree2ff943b6ddb8aa8980a3ed1fb4a1f869fc787d1c /lib/MasterWebInterface
parent318a5a20a930192df788dbac54b1f9c60e1b98b8 (diff)
downloadWebInterface-Perl-6bd235f3e62251d8763a552ab0042d59584de842.tar.gz
WebInterface-Perl-6bd235f3e62251d8763a552ab0042d59584de842.zip
Metadata and update to hotfix 4.
Display thumbnails / snippets in 3rd party apps (like discord) and add map thumbnails + icons for multiple games. Minor fixes/optimisations.
Diffstat (limited to 'lib/MasterWebInterface')
-rwxr-xr-xlib/MasterWebInterface/Database/Games.pm8
-rwxr-xr-xlib/MasterWebInterface/Database/Servers.pm5
-rwxr-xr-xlib/MasterWebInterface/Handler/ErrorPages.pm4
-rwxr-xr-xlib/MasterWebInterface/Handler/Games.pm9
-rwxr-xr-xlib/MasterWebInterface/Handler/Json/JsonServerInfo.pm26
-rwxr-xr-xlib/MasterWebInterface/Handler/Json/JsonServerList.pm17
-rwxr-xr-xlib/MasterWebInterface/Handler/ServInfo.pm109
-rwxr-xr-xlib/MasterWebInterface/Handler/Servers.pm28
-rwxr-xr-xlib/MasterWebInterface/Util/AdvancedFilterBox.pm23
-rwxr-xr-xlib/MasterWebInterface/Util/FilterBox.pm2
-rwxr-xr-xlib/MasterWebInterface/Util/Layout.pm11
11 files changed, 174 insertions, 68 deletions
diff --git a/lib/MasterWebInterface/Database/Games.pm b/lib/MasterWebInterface/Database/Games.pm
index 02b6ad9..c9dab95 100755
--- a/lib/MasterWebInterface/Database/Games.pm
+++ b/lib/MasterWebInterface/Database/Games.pm
@@ -18,6 +18,12 @@ sub dbGameListGet
# search criteria
my %where = (
$o{search} ? ('lower(label) LIKE lower(?)' => "%$o{search}%") : (),
+ $o{search} ? ('lower(label) LIKE lower(?) OR lower(gamename) LIKE lower(?)' => ["%$o{search}%","%$o{search}%"]) : (),
+
+
+ #$o{search} ? ('LOWER(hostname) LIKE LOWER(?) OR LOWER(maptitle) LIKE LOWER(?) OR LOWER(mapname) LIKE LOWER(?)' => ["%$o{search}%", "%$o{search}%", "%$o{search}%"]) : (),
+
+
!$o{all} ? ( 'num_total > ?' => 0) : (),
);
@@ -55,7 +61,7 @@ sub dbGameListGet
sub dbGetGameDesc
{
my ($self, $gn) = @_;
- return $self->dbAll("SELECT label FROM gameinfo WHERE gamename = ?", $gn)->[0]{label};
+ return $self->dbAll("SELECT label FROM gameinfo WHERE gamename = ? LIMIT 1", $gn)->[0]{label};
}
1;
diff --git a/lib/MasterWebInterface/Database/Servers.pm b/lib/MasterWebInterface/Database/Servers.pm
index 99b4f1e..f8a4b66 100755
--- a/lib/MasterWebInterface/Database/Servers.pm
+++ b/lib/MasterWebInterface/Database/Servers.pm
@@ -16,8 +16,9 @@ sub dbServerListGet {
my %where = (
# gamename and char are "all" or value
+ $o{gamename} !~ /all/ ? ('serverlist.gamename = ?' => $o{gamename}) : (),
$o{updated} ? ('dt_updated > ?' => (time-$o{updated})) : (),
- $o{gamename} ? ('serverlist.gamename = ?' => $o{gamename}) : (),
+ #$o{gamename} ? ('serverlist.gamename = ?' => $o{gamename}) : (),
$o{nolist} ? ('serverlist.gamename <> ?' => $o{nolist}) : (),
$o{search} ? ('LOWER(hostname) LIKE LOWER(?)' => "%$o{search}%") : (),
$o{popserv} ? ('numplayers > ?' => 0) : (),
@@ -25,7 +26,7 @@ sub dbServerListGet {
#advanced search
$o{hostname} ? ('LOWER(hostname) LIKE LOWER(?)' => "%$o{hostname}%") : (),
- $o{gametype} ? ('LOWER(gametype) LIKE LOWER(?)' => $o{gametype}) : (),
+ $o{gametype} ? ('LOWER(gametype) LIKE LOWER(?)' => "%$o{gametype}%") : (),
$o{mapname} ? ('(LOWER(mapname) LIKE LOWER(?) OR LOWER(maptitle) LIKE LOWER(?))' => ["%$o{mapname}%", "%$o{mapname}%"]) : (),
$o{country} ? ('country LIKE UPPER(?)' => $o{country}) : (),
diff --git a/lib/MasterWebInterface/Handler/ErrorPages.pm b/lib/MasterWebInterface/Handler/ErrorPages.pm
index 1678acc..81e4091 100755
--- a/lib/MasterWebInterface/Handler/ErrorPages.pm
+++ b/lib/MasterWebInterface/Handler/ErrorPages.pm
@@ -31,7 +31,7 @@ sub handle404
}
$self->resStatus(404);
- $self->htmlHeader(title => '404 - Not Found');
+ $self->htmlHeader(title => '404 - Not Found', meta_desc => "The page at this link was not found. Try the homepage and find it from there?");
$self->htmlFilterBox(title => "Servers", action => "/s", sel => 's', fq => '');
div class => "mainbox warning";
@@ -71,7 +71,7 @@ sub handle500
}
$self->resStatus(500);
- $self->htmlHeader(title => '500 - Internal Server Error');
+ $self->htmlHeader(title => '500 - Internal Server Error', meta_desc => "Catastrophic failure. Try again later or ping the website admin.");
$self->htmlFilterBox(title => "Servers", action => "/s", sel => 's', fq => '');
div class => "mainbox warning";
diff --git a/lib/MasterWebInterface/Handler/Games.pm b/lib/MasterWebInterface/Handler/Games.pm
index cec7ab1..31090a2 100755
--- a/lib/MasterWebInterface/Handler/Games.pm
+++ b/lib/MasterWebInterface/Handler/Games.pm
@@ -7,7 +7,7 @@ use Exporter 'import';
TUWF::register(
qr{g} => \&gamelist,
- qr{g/all} => \&gamelist,
+ qr{g/(all)} => \&gamelist,
);
#
@@ -37,7 +37,7 @@ sub gamelist
all => $all,
);
- $self->htmlHeader(title => "Browse Games");
+ $self->htmlHeader(title => "Browse Games", meta_desc => "Browse through all games that currently have servers online uplinking to the masterserver.");
$self->htmlFilterBox(title => "Games", action => "/g/all", sel => 'g', fq => $f->{q});
#
@@ -94,7 +94,10 @@ sub gamelist
}
else
{
- td $gn;
+ td class => "tc2 icon",
+ style => "background-image: url(/icon32/333networks.png);",
+ title => $gn,
+ '';
}
# number of beacons / servers
diff --git a/lib/MasterWebInterface/Handler/Json/JsonServerInfo.pm b/lib/MasterWebInterface/Handler/Json/JsonServerInfo.pm
index a3b2d08..519017e 100755
--- a/lib/MasterWebInterface/Handler/Json/JsonServerInfo.pm
+++ b/lib/MasterWebInterface/Handler/Json/JsonServerInfo.pm
@@ -2,11 +2,14 @@ package MasterWebInterface::Handler::Json::JsonServerInfo;
use strict;
use TUWF ':html';
use Exporter 'import';
+use Socket;
use JSON;
TUWF::register(
qr{json/([\w]{1,20})/(\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}):(\d{1,5})} => \&json_serverinfo, # ipv6
qr{json/([\w]{1,20})/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{1,5})} => \&json_serverinfo, # ipv4
+ qr{json/([\w]{1,20})/([\w\.]{3,63}):(\d{1,5})} => \&json_serverinfo, #domain name
+
);
#
@@ -14,7 +17,16 @@ TUWF::register(
#
sub json_serverinfo
{
- my ($self, $gamename, $ip, $port) = @_;
+ my ($self, $gamename, $addr, $port) = @_;
+
+ # domain name check
+ my $ip = $addr;
+ if ($addr =~ m/[a-z]/ig )
+ {
+ # $addr holds a value that is a domain. try to resolve.
+ my $packed_ip = gethostbyname($ip);
+ $ip = inet_ntoa($packed_ip) if (defined $packed_ip);
+ }
# select server from database
my $info = $self->dbGetServerInfo(
@@ -45,6 +57,11 @@ sub json_serverinfo
for (my $i=0; defined $pl_list->[$i]->{name}; $i++)
{
+
+ # fix html "injection" (quick fix, ask Yorhel for better suited solution)
+ s/</&lt;/g for values %{$pl_list->[$i]};
+ s/>/&gt;/g for values %{$pl_list->[$i]};
+
$players{"player_$i"} = $pl_list->[$i];
}
@@ -53,6 +70,9 @@ sub json_serverinfo
# find the correct thumbnail, otherwise game default, otherwise 333 default
my $mapname = lc $info->{mapname};
+
+ # FIXME
+ $info->{debug_map_path} = "$self->{root}/s/map/$info->{gamename}/$mapname.jpg";
# if map figure exists, use it
if (-e "$self->{root}/s/map/$info->{gamename}/$mapname.jpg")
@@ -72,6 +92,10 @@ sub json_serverinfo
# 333networks default
$info->{mapurl} = "/map/default/333networks.jpg";
}
+
+ # fix html "injection" (quick fix, ask Yorhel for better suited solution)
+ s/</&lt;/g for values %{$info};
+ s/>/&gt;/g for values %{$info};
# response as json data
$self->resJSON($info);
diff --git a/lib/MasterWebInterface/Handler/Json/JsonServerList.pm b/lib/MasterWebInterface/Handler/Json/JsonServerList.pm
index e108066..d02455f 100755
--- a/lib/MasterWebInterface/Handler/Json/JsonServerList.pm
+++ b/lib/MasterWebInterface/Handler/Json/JsonServerList.pm
@@ -21,10 +21,16 @@ sub serverlist_json
{ get => 's', required => 0, default => 'gamename', enum => [qw|hostname gamename country added gametype numplayers mapname|] },
{ get => 'o', required => 0, default => 'a', enum => ['a','d'] },
{ get => 'p', required => 0, default => 1, template => 'page' },
- { get => 'r', required => 0, default => 100, template => 'page' },
+ { get => 'r', required => 0, default => 50, template => 'page' },
{ get => 'q', required => 0, default => '', maxlength => 90 },
{ get => 'g', required => 0, default => '', maxlength => 90 },
{ get => 'a', required => 0, default => '', maxlength => 200 },
+
+ #{ get => 'gamename', required => 0, default => '', maxlength => 90 }, # gamename in advanced search
+ { get => 'gametype', required => 0, default => '', maxlength => 90 }, # gametype
+ { get => 'hostname', required => 0, default => '', maxlength => 90 }, # hostname (replaces q in advanced search)
+ { get => 'mapname', required => 0, default => '', maxlength => 90 }, # mapname
+ { get => 'country', required => 0, default => '', maxlength => 90 }, # country (code)
);
# allow all outside sources to access the json api
@@ -56,13 +62,20 @@ sub serverlist_json
# parse extra request parameters for ubrowser.333networks.com
($f->{a} =~ m/popserv/ig) ? (popserv => 1) : (),
($f->{a} =~ m/utdemo/ig) ? (utdemo => 1) : (),
+
+ gametype => $f->{gametype},
+ hostname => $f->{hostname},
+ mapname => $f->{mapname},
+ country => $f->{country},
);
# get total number of players in selected page(s)
my $pl = 0;
for (@{$list})
{
- $pl += $_->{numplayers}
+ $pl += $_->{numplayers};
+ s/</&lt;/g for values %{$_};
+ s/>/&gt;/g for values %{$_};
}
# response as json data
diff --git a/lib/MasterWebInterface/Handler/ServInfo.pm b/lib/MasterWebInterface/Handler/ServInfo.pm
index 8b3d7d8..e22b4a6 100755
--- a/lib/MasterWebInterface/Handler/ServInfo.pm
+++ b/lib/MasterWebInterface/Handler/ServInfo.pm
@@ -2,6 +2,7 @@ package MasterWebInterface::Handler::ServInfo;
use strict;
use warnings;
use utf8;
+use Socket;
use TUWF ':html';
use POSIX 'strftime';
use Exporter 'import';
@@ -9,15 +10,25 @@ use Exporter 'import';
TUWF::register(
qr{([\w]{1,20})/(\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}:\w{4}):(\d{1,5})} => \&show_server, #ipv6
qr{([\w]{1,20})/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d{1,5})} => \&show_server, #ipv4
+ qr{([\w]{1,20})/([\w\.]{3,63}):(\d{1,5})} => \&show_server, #domain name
);
-
+
#
# Display server information
#
################################################################################
sub show_server
{
- my ($self, $gamename, $ip, $port) = @_;
+ my ($self, $gamename, $addr, $port) = @_;
+
+ # domain name check
+ my $ip = $addr;
+ if ($addr =~ m/[a-z]/ig )
+ {
+ # $addr holds a value that is a domain. try to resolve.
+ my $packed_ip = gethostbyname($ip);
+ $ip = inet_ntoa($packed_ip) if (defined $packed_ip);
+ }
# select server from database
my $info = $self->dbGetServerInfo(
@@ -43,8 +54,13 @@ sub show_server
return;
}
+ # meta data
+ my $img = (-e "$self->{root}/s/map/default/$gamename.jpg")
+ ? "/map/default/$gamename.jpg" : "/map/default/333networks.jpg";
+ my $desc = "It seems the server you were looking for does not exist in our database, perhaps our search function may yield results? You tried to access ".($ip // "[no ip]")." in $gamename.";
+
# otherwise not found in database, soft error page (no 404 status)
- $self->htmlHeader(title => 'Server not found');
+ $self->htmlHeader(title => 'Server not found', meta_desc => $desc, meta_img => $img);
$self->htmlFilterBox(
sel => 's',
fq => '',
@@ -66,11 +82,20 @@ sub show_server
p;
txt "You tried to access ";
- span class => "hilit", $ip // "[no ip]";
+ span class => "hilit";
+ txt ($addr // "");
+ if ($addr =~ m/[a-z]/ig )
+ {
+ txt " (";
+ txt ($ip // "[no ip]");
+ txt ")";
+ }
+ end;
txt " in ";
span class => "hilit", $gamename;
txt ".";
end;
+
end;
end;
$self->htmlFooter;
@@ -83,10 +108,50 @@ sub show_server
# info exists. sanity checks
$gamename = $info->{gamename} // $gamename;
my $gamedescription = $self->dbGetGameDesc($info->{gamename}) // $info->{gamename};
+
+ my $mapfig = "/map/default/333networks.jpg";
+ my $mapfile = lc ($info->{mapname} // "");
+
+ # some games may be merged gamename-wise
+ my $gamenamedir = ($gamename =~ m/mohaa/) ? "mohaa" : $gamename;
+
+ # if map figure exists, use it
+ if (-e "$self->{root}/s/map/$gamenamedir/$mapfile.jpg")
+ {
+ # map image
+ $mapfig = "/map/$gamenamedir/$mapfile.jpg";
+ }
+ # if not, game default image
+ elsif (-e "$self->{root}/s/map/default/$gamename.jpg")
+ {
+ # game image
+ $mapfig = "/map/default/$gamename.jpg";
+ }
+ # otherwise 333networks default
+ else
+ {
+ # 333networks default
+ $mapfig = "/map/default/333networks.jpg";
+ }
+
+ # map title/name (not lowercase)
+ my $mapname = $info->{mapname} // $info->{maptitle} // "Untitled";
+ my $maptitle = ( $info->{maptitle} && lc $info->{maptitle} ne "untitled" )
+ ? $info->{maptitle} : $mapname;
+
+
+ my ($flag, $country) = $self->countryflag($info->{country} // "");
+
+ #meta description
+ my $desc = "Address: ". ($info->{ip} // "0.0.0.0"). ":" . ($info->{hostport} // 0) . " ($country)
+ Players: ". ($info->{numplayers} // 0) ."/". ($info->{maxplayers} // 0) ."
+ GameType: " . ($info->{gametype} // "") . "
+ Map: $maptitle";
#
# generate info page
- $self->htmlHeader(title => $info->{hostname} // "Server");
+ $self->htmlHeader(title => $info->{hostname} // "Server", meta_img => $mapfig, meta_desc => $desc);
+
$self->htmlFilterBox(
gamename => $gamename,
sel => 's',
@@ -133,34 +198,6 @@ sub show_server
# find the correct thumbnail, otherwise game default, otherwise 333 default
div class => "thumbnail";
- my $mapfig = "/map/default/333networks.jpg";
- my $mapfile = lc ($info->{mapname} // "");
-
- # if map figure exists, use it
- if (-e "$self->{root}/s/map/$gamename/$mapfile.jpg")
- {
- # map image
- $mapfig = "/map/$gamename/$mapfile.jpg";
- }
- # if not, game default image
- elsif (-e "$self->{root}/s/map/default/$gamename.jpg")
- {
- # game image
- $mapfig = "/map/default/$gamename.jpg";
- }
- # otherwise 333networks default
- else
- {
- # 333networks default
- $mapfig = "/map/default/333networks.jpg";
- }
-
- # map title/name (not lowercase)
- my $mapname = $info->{mapname} // $info->{maptitle} // "Untitled";
- my $maptitle = ( $info->{maptitle} && lc $info->{maptitle} ne "untitled" )
- ? $info->{maptitle}
- : $mapname;
-
img src => $mapfig,
alt => $mapfig,
title => $mapname;
@@ -235,8 +272,6 @@ sub show_server
# location data
Tr;
td class => "wc1", "Location:";
-
- my ($flag, $country) = $self->countryflag($info->{country} // "");
td;
img class => "flag", src => "/flag/$flag.svg";
txt " ". $country;
@@ -381,6 +416,7 @@ sub show_server
end;
end;
}
+
end; # playerinfo
# disable stats that are considered irrelevant. can be re-enabled with "if (1)"
@@ -448,6 +484,8 @@ sub show_server
($self->{site_url} . "/json/" . $gamename . "/" . ($info->{ip} // "0.0.0.0") . ":" . ($info->{hostport} // 0) );
end;
+ if (0) # disable PNG banners because perfomance issues
+ {
Tr;
th;
txt "Server Banner:";
@@ -457,6 +495,7 @@ sub show_server
a href => ($self->{site_url} . "/png/" . $gamename . "/" . ( $info->{ip} // "0.0.0.0" ) . ":" . ($info->{hostport} // 0)),
($self->{site_url} . "/png/" . $gamename . "/" . ( $info->{ip} // "0.0.0.0" ) . ":" . ($info->{hostport} // 0));
end;
+ }
end;
end; # mainbox details
diff --git a/lib/MasterWebInterface/Handler/Servers.pm b/lib/MasterWebInterface/Handler/Servers.pm
index 34c0182..f1c50d2 100755
--- a/lib/MasterWebInterface/Handler/Servers.pm
+++ b/lib/MasterWebInterface/Handler/Servers.pm
@@ -13,9 +13,11 @@ TUWF::register(
#
# Generate a list of selected games in the database per game (arg: gamename)
#
-sub serverlist
+sub serverlist
{
my($self, $adv, $gamename) = @_;
+ $adv = "s" unless $adv;
+ $gamename = "all" unless $gamename;
# sorting, page
my $f = $self->formValidate(
@@ -54,8 +56,14 @@ sub serverlist
!($gamename eq "333networks" or $f->{gamename} eq "333networks") ? ( nolist => "333networks") : (),
);
+ # meta data
+ my $img = (-e "$self->{root}/s/map/default/$gamename.jpg")
+ ? "/map/default/$gamename.jpg" : "/map/default/333networks.jpg";
+ my $label = $self->dbGetGameDesc($gamename) // "";
+ my $desc = "There are $p $label servers currently listed online.";
+
# Write page
- $self->htmlHeader(title => "Servers");
+ $self->htmlHeader(title => "$label Serverlist", meta_desc => $desc, meta_img => $img);
# search box type: simple or advanced
if ($adv eq 'adv')
@@ -118,10 +126,10 @@ sub serverlist
# country flag
# TODO: advanced filter by country only
- my ($flag, $country) = $self->countryflag($l->{country});
+ my ($flag, $country) = $self->countryflag($l->{country} // "");
td class => "tc1",
style => "background-image: url(/flag/$flag.svg);",
- title => $country,
+ title => $country // "",
'';
# server name (and defaults)
@@ -145,14 +153,18 @@ sub serverlist
}
else
{
- td $gn;
+ td class => "tc3 icon",
+ style => "background-image: url(/icon32/333networks.png);",
+ title => $l->{label};
+ a href => "/$adv/$gn", "";
+ end;
}
# game type (hover: raw, display: parsed)
# TODO: advanced filter by gametype only
td class => "tc4",
- title => $l->{gametype},
- $self->better_gametype($l->{gametype});
+ title => $l->{gametype} // "",
+ $self->better_gametype($l->{gametype} // "");
# number of players / maximum players
td class => "tc5";
@@ -162,7 +174,7 @@ sub serverlist
end;
# map title/name
- my $maplabel = ($l->{maptitle} && lc $l->{maptitle} ne "untitled" ? $l->{maptitle} : $l->{mapname});
+ my $maplabel = ($l->{maptitle} && lc $l->{maptitle} ne "untitled" ? $l->{maptitle} : $l->{mapname} // "");
td class => "tc6", title => $maplabel // "---", $maplabel // "---";
end;
},
diff --git a/lib/MasterWebInterface/Util/AdvancedFilterBox.pm b/lib/MasterWebInterface/Util/AdvancedFilterBox.pm
index a496a04..24382a2 100755
--- a/lib/MasterWebInterface/Util/AdvancedFilterBox.pm
+++ b/lib/MasterWebInterface/Util/AdvancedFilterBox.pm
@@ -19,7 +19,7 @@ use Data::Dumper 'Dumper';
# TODO: allow searching by IP, in combination with expired servers (and sanity check in javascript?)
sub htmlAdvancedFilterBox
{
- my($self, %opt) = @_;
+ my ($self, %opt) = @_;
div class => 'mainbox';
div class => "header";
@@ -31,6 +31,16 @@ sub htmlAdvancedFilterBox
txt ".";
end;
end;
+
+ if (0)
+ {
+ div class => "codeblock";
+ p "No worries, Darkelarious is debugging an issue right now. Please ignore this code block.";
+ pre;
+ txt Dumper \%opt;
+ end;
+ end;
+ }
# advanced filter form
form action => "/adv", 'accept-charset' => 'UTF-8', method => 'get', class => "advancedfilter";
@@ -182,17 +192,6 @@ sub htmlAdvancedFilterBox
end 'fieldset';
end; # form
- # debugging box
- if ( 0 )
- {
- h2 "Debug information";
- div class => "codeblock";
- pre;
- txt Dumper \%opt;
- end;
- end;
- }
-
# return to simple filter/layout
div class => "simpleadvanced";
a href => $opt{gamename} ? "/s/$opt{gamename}" : "/s";
diff --git a/lib/MasterWebInterface/Util/FilterBox.pm b/lib/MasterWebInterface/Util/FilterBox.pm
index 8db7a60..40218ac 100755
--- a/lib/MasterWebInterface/Util/FilterBox.pm
+++ b/lib/MasterWebInterface/Util/FilterBox.pm
@@ -22,7 +22,7 @@ sub htmlFilterBox
end;
# filter box
- form action => $opt{gamename} ? "/s/$opt{gamename}" : "/s", 'accept-charset' => 'UTF-8', method => 'get';
+ form action => $opt{action}, 'accept-charset' => 'UTF-8', method => 'get';
fieldset class => 'simple';
a href => '/g', $opt{sel} eq 'g' ? (class => 'sel') : (), 'Games';
a href => '/s', $opt{sel} eq 's' ? (class => 'sel') : (), 'Servers';
diff --git a/lib/MasterWebInterface/Util/Layout.pm b/lib/MasterWebInterface/Util/Layout.pm
index fe7b5c5..4862f93 100755
--- a/lib/MasterWebInterface/Util/Layout.pm
+++ b/lib/MasterWebInterface/Util/Layout.pm
@@ -18,9 +18,18 @@ sub htmlHeader
title "$o{title} :: $self->{site_name} masterserver";
Link type => 'image/x-icon', rel => 'shortcut icon', href => "/favicon.ico";
Link type => "text/css", rel => 'stylesheet', href => "/style/$self->{style}/style.css", media => "all";
+
+ # metadata for previews
+ meta property => "theme-color", content => ($self->{meta_color} // "#111111");
+ meta property => "og:type", content => "website";
+ meta property => "og:site_name", content => $self->{site_name};
+ meta property => "og:title", content => substr($o{title},0,50);
+ meta property => "og:description", content => ($o{meta_desc} // "");
+ meta property => "og:image", content => ($o{meta_img } // "/map/default/333networks.jpg");
+
if ( $o{noindex} )
{
- meta name => 'robots', content => 'noindex,nofollow,nosnippet,noodp,noarchive,noimageindex';end;
+ meta name => 'robots', content => 'noindex,nofollow,nosnippet,noodp,noarchive,noimageindex';
}
end 'head';