diff --git a/app/MetaGer.php b/app/MetaGer.php index 99ee104a9ca397d1e2530426e50758ebbec2f966..eb940ed97add72a2c57c1b1d2a094659049c5916 100644 --- a/app/MetaGer.php +++ b/app/MetaGer.php @@ -4,11 +4,11 @@ namespace App; use App; use Cache; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Redis; use Jenssegers\Agent\Agent; use LaravelLocalization; use Log; use Predis\Connection\ConnectionException; -use Illuminate\Support\Facades\Redis; class MetaGer { @@ -24,7 +24,7 @@ class MetaGer protected $site; protected $hostBlacklist = []; protected $domainBlacklist = []; - private $urlBlacklist = []; + private $urlBlacklist = []; protected $stopWords = []; protected $phrases = []; protected $engines = []; @@ -141,6 +141,15 @@ class MetaGer ->with('suspendheader', "yes") ->with('browser', (new Agent())->browser()); break; + case 'rich': + return view('metager3rich') + ->with('eingabe', $this->eingabe) + ->with('mobile', $this->mobile) + ->with('warnings', $this->warnings) + ->with('errors', $this->errors) + ->with('metager', $this) + ->with('browser', (new Agent())->browser()); + break; case 'rss20': return view('metager3resultsrss20') ->with('results', $viewResults) @@ -541,7 +550,7 @@ class MetaGer if ($this->requestIsCached($request)) { $engines = $this->getCachedEngines($request); # We need to edit some Options of the Cached Search Engines - foreach($engines as $engine){ + foreach ($engines as $engine) { $engine->setResultHash($this->getHashCode()); } } else { @@ -800,33 +809,38 @@ class MetaGer public function waitForResults($enginesToLoad, $overtureEnabled, $canBreak) { - $timeStart = microtime(true); - $results = null; + $timeStart = microtime(true); + $results = null; while (true) { $results = Redis::hgetall('search.' . $this->getHashCode()); $ready = true; - // When every + // When every $connected = true; - foreach($results as $key => $value){ - if($value === "waiting" || $value === "connected"){ + foreach ($results as $key => $value) { + if ($value === "waiting" || $value === "connected") { $ready = false; } - if($value === "waiting"){ + if ($value === "waiting") { $connected = false; } } // If $ready is false at this point, we're waiting for more searchengines // But we have to check for the timeout, too - if(!$connected) $timeStart = microtime(true); + if (!$connected) { + $timeStart = microtime(true); + } + $time = (microtime(true) - $timeStart) * 1000; // We will apply the timeout only if it's not Yahoo we're waiting for since they are one the most // important search engines. $canTimeout = !((isset($results["overture"]) && $results["overture"] === "waiting") || (isset($results["overtureAds"]) && $results["overtureAds"] === "waiting")); - if($time > $this->time && $canTimeout) $ready = true; + if ($time > $this->time && $canTimeout) { + $ready = true; + } - if($ready){ + if ($ready) { break; } usleep(50000); @@ -981,7 +995,7 @@ class MetaGer } $this->out = $request->input('out', "html"); # Standard output format html - if ($this->out !== "html" && $this->out !== "json" && $this->out !== "results" && $this->out !== "results-with-style" && $this->out !== "result-count" && $this->out !== "rss20") { + if ($this->out !== "html" && $this->out !== "json" && $this->out !== "results" && $this->out !== "results-with-style" && $this->out !== "result-count" && $this->out !== "rss20" && $this->out !== "rich") { $this->out = "html"; } # Wir schalten den Cache aus, wenn die Ergebniszahl überprüft werden soll @@ -1076,7 +1090,7 @@ class MetaGer foreach ($this->urlBlacklist as $url) { $urlString .= $url . ", "; } - $urlString = rtrim($urlString, ", "); + $urlString = rtrim($urlString, ", "); $this->warnings[] = trans('metaGer.formdata.urlBlacklist', ['url' => $urlString]); } } diff --git a/public/css/material-default.css b/public/css/material-default.css new file mode 100644 index 0000000000000000000000000000000000000000..e7fa43eaeb3742ba5e15d5bb61a965aa3453dcac --- /dev/null +++ b/public/css/material-default.css @@ -0,0 +1,271 @@ +/* Mobile styles */ + +body { + display: flex; + flex-direction: column; + align-items: stretch; + margin: 0px; + padding: 0px; + background-color: #FAFAFA; + font-family: Roboto,"Noto Sans",sans-serif; +} + +.card { + background-color: #FFFFFF; + margin: 8px; + padding: 8px; + border-radius: 2px; + display: block; +} +.card-inline { + background-color: #FFFFFF; + margin: 8px; + padding: 8px; + border-radius: 2px; +} + +.elevation-1 { + box-shadow: 0px 1px 1.5px 0px rgba(0,0,0,0.12), 1px 0px 1px 0px rgba(0,0,0,0.24); +} +.elevation-2 { + box-shadow: 0px 3px 3px 0px rgba(0,0,0,0.16), 3px 0px 3px 0px rgba(0,0,0,0.23); +} + +.search-card { + height: 30px; + display: flex; + justify-content: space-between; + + position: sticky; + top: 10px; + + z-index: 100; +} + +.persistent-search { + top: 0px; + position: sticky; + z-index: 100; + background: linear-gradient(to bottom, rgba(255,255,255,1) 0%,rgba(255,255,255,1) 50%,rgba(255,255,255,0) 60%,rgba(255,255,255,0) 100%); +} + +.search-card button, .search-card input { + border: none; + background: none; + margin: 0px; + padding: 0px; +} + +.search-card input[type=text] { + font-size: 18px; + overflow-x: hidden; +} + +.search-card .back { + height: 100%; + margin-right:8px; +} + +.search-button { + width: 50px; +} + +.search-button img { + height: 100%; +} + +.search-card .back img { + height: 100%; +} + +.search-card .query-input { + flex-grow: 1; +} + +.results-container { + z-index: 10; +} + +.search-result { + position:relative; +} + +.result-content { + margin: 16px 8px 8px 8px; +} + +.result-title { + font-size: 18px; + font-weight: 500; + color: hsl(0, 0%, 13%); + margin: 0px; + padding: 0px; +} +.result-display-link { + color: hsl(0, 0%, 13%); + font-size: 14px; + font-weight: 400; + margin: 0px; + padding: 0px; +} + +.result-description { + font-size: 16px; +} + +.result-source { + display: none; + +} + +.result-thumbnail { + position: absolute; + right: 16px; + top: 16px; + max-width: 80px; + max-height: 80px; +} + +.result-action-area { + display: flex; + flex-wrap: wrap; + align-items: baseline; + margin: 0px; + padding: 0px; +} + +.result-action { + color: hsl(0, 0%, 13%); + font-size: 14px; + font-weight: 500; + text-decoration: none; + text-transform: uppercase; + margin: 0px 0px 0px 0px; + padding: 8px; + border-radius: 2px; +} + +.result-action:hover, .result-action:focus { + background-color: hsla(0, 0%, 13%, 12%); +} +.result-action:active { + background-color: hsla(0, 0%, 13%, 40%); +} + +.result-action:first-child.primary { + color: hsl(21, 100%, 50%); +} + +.result-action:first-child.primary:hover, .result-action:first-child.primary:focus { + background-color: hsla(21, 100%, 50%, 12%); +} +.result-action:first-child.primary:active { + background-color: hsla(21, 100%, 50%, 40%); +} + +.result-action.more { + float:right; +} + +.footer-text { + margin-top: 20px; + margin-bottom: 10px; + color: hsl(0, 0%, 46%); + text-align: center; +} + +.pagenav-button-next{ + color: hsl(0, 0%, 13%); + font-size: 20px; + text-decoration: none; + padding: 12px; + height:27px; + display: flex; + justify-content: space-between; + align-items: baseline; + +} +.pagenav-button-first{ + color: hsl(0, 0%, 13%); + font-size: 20px; + text-decoration: none; + height:27px; + padding: 12px; + align-self: flex-start; +} + +.pagenav-following { + display: flex; + justify-content: space-between; + align-items: baseline; +} + +.pagenav-current { + color: hsl(0, 0%, 46%); + font-size: 18px; + padding: 12px; +} + + +.icon-right { + margin-left: 5px; +} + +.focus-card { + background-color: hsl(0,0%,50%); +} + +.focus-cell { + line-height: 34px; + display: flex; + justify-content: space-between; +} + +.focus-cell-label b { + font-weight: 500; +} + +.focus-cell-action { + font-size: 14px; + text-decoration: none; + text-transform: uppercase; +} + +.focus-cell { + text-decoration: none; + background-color: hsl(0,0%,50%); + color: rgba(255, 255, 255, 1); + padding: 0px 5px; +} + +li .focus-cell:hover { + background-color: hsl(0,0%,55%); +} + +.focus-card[open] .focus-cell .focus-cell-action { + display: none; +} + +.focus-list { + list-style-type: none; + margin-top: 0px; + margin-bottom: 0px; + padding-left: 0px; +} + +@media (max-width: 330px) { /*für sehr kleine mobile Viewports (z.B. iPhone 5S)*/ + .result-action { + font-size: 13px; +} + +.pagenav-current-annotation { + display: none; +} +.pagenav-current { + color: hsl(0, 0%, 46%); + font-size: 20px; + padding: 12px; +} +} + + diff --git a/public/css/material-inverse.css b/public/css/material-inverse.css new file mode 100644 index 0000000000000000000000000000000000000000..fa4c61246d85258d7fc66f784f28d68428c04dd6 --- /dev/null +++ b/public/css/material-inverse.css @@ -0,0 +1,275 @@ +/* Mobile styles */ + +body { + display: flex; + flex-direction: column; + align-items: stretch; + margin: 0px; + padding: 0px; + color: #fff; + background-color: #050505; + font-family: Roboto,"Noto Sans",sans-serif; +} + +.card { + background-color: hsl(0, 0%, 20%);; + margin: 8px; + padding: 8px; + border-radius: 2px; + display: block; +} +.card-inline { + background-color: #000; + margin: 8px; + padding: 8px; + border-radius: 2px; +} + +.elevation-1 { + + box-shadow: 0px 1px 1.5px 0px rgba(255,255,255,0.12), 1px 0px 1px 0px rgba(255,255,255,0.24); +} +.elevation-2 { + box-shadow: 0px 3px 3px 0px rgba(255,255,255,0.16), 3px 0px 3px 0px rgba(255,255,255,0.23); +} + +.search-card { + height: 30px; + display: flex; + justify-content: space-between; + + position: sticky; + top: 10px; + + z-index: 100; +} + +.persistent-search { + top: 0px; + position: sticky; + z-index: 100; + background: linear-gradient(to bottom, rgba(0,0,0,1) 0%,rgba(0,0,0,1) 50%,rgba(0,0,0,0) 60%,rgba(0,0,0,0) 100%); +} + +.search-card button, .search-card input { + border: none; + background: none; + margin: 0px; + padding: 0px; +} + +.search-card input[type=text] { + font-size: 18px; + overflow-x: hidden; + color: #fff; +} + +.search-card .back { + height: 100%; + margin-right:8px; +} + +.search-button { + width: 50px; + color: #fff; +} + +.search-button img { + height: 100%; +} + +.search-card .back img { + height: 100%; +} + +.search-card .query-input { + flex-grow: 1; +} + +.results-container { + z-index: 10; +} + +.search-result { + position:relative; +} + +.result-content { + margin: 16px 8px 8px 8px; +} + +.result-title { + font-size: 18px; + font-weight: 500; + color: hsl(0, 0%, 87%); + margin: 0px; + padding: 0px; +} +.result-display-link { + color: hsl(0, 0%, 87%); + font-size: 14px; + font-weight: 400; + margin: 0px; + padding: 0px; +} + +.result-description { + font-size: 16px; +} + +.result-source { + display: none; + +} + +.result-thumbnail { + position: absolute; + right: 16px; + top: 16px; + max-width: 80px; + max-height: 80px; +} + +.result-action-area { + display: flex; + flex-wrap: wrap; + align-items: baseline; + margin: 0px; + padding: 0px; +} + +.result-action { + color: hsl(0, 0%, 87%); + font-size: 14px; + font-weight: 500; + text-decoration: none; + text-transform: uppercase; + margin: 0px 0px 0px 0px; + padding: 8px; + border-radius: 2px; +} + +.result-action:hover, .result-action:focus { + background-color: hsla(0, 0%, 87%, 12%); +} +.result-action:active { + background-color: hsla(0, 0%, 87%, 40%); +} + +.result-action:first-child.primary { + color: hsl(21, 100%, 50%); +} + +.result-action:first-child.primary:hover, .result-action:first-child.primary:focus { + background-color: hsla(21, 100%, 50%, 12%); +} +.result-action:first-child.primary:active { + background-color: hsla(21, 100%, 50%, 40%); +} + +.result-action.more { + float:right; +} + +.footer-text { + margin-top: 20px; + margin-bottom: 10px; + color: hsl(0, 0%, 54%); + text-align: center; +} + +.pagenav-button-next{ + color: hsl(0, 0%, 87%); + font-size: 20px; + text-decoration: none; + padding: 12px; + height:27px; + display: flex; + justify-content: space-between; + align-items: baseline; + +} +.pagenav-button-first{ + color: hsl(0, 0%, 87%); + font-size: 20px; + text-decoration: none; + height:27px; + padding: 12px; + align-self: flex-start; +} + +.pagenav-following { + display: flex; + justify-content: space-between; + align-items: baseline; +} + +.pagenav-current { + color: hsl(0, 0%, 64%); + font-size: 18px; + padding: 12px; +} + + +.icon-right { + margin-left: 5px; +} + +.focus-card { + background-color: hsl(0,0%,50%); +} + +.focus-cell { + line-height: 34px; + display: flex; + justify-content: space-between; +} + +.focus-cell-label b { + font-weight: 500; +} + +.focus-cell-action { + font-size: 14px; + text-decoration: none; + text-transform: uppercase; +} + +.focus-cell { + text-decoration: none; + background-color: hsl(0,0%,50%); + color: rgba(255, 255, 255, 1); + padding: 0px 5px; +} + +li .focus-cell:hover { + background-color: hsl(0,0%,45%); +} + +.focus-card[open] .focus-cell .focus-cell-action { + display: none; +} + +.focus-list { + list-style-type: none; + margin-top: 0px; + margin-bottom: 0px; + padding-left: 0px; +} + +@media (max-width: 330px) { /*für sehr kleine mobile Viewports (z.B. iPhone 5S)*/ + .result-action { + font-size: 13px; +} + +.pagenav-current-annotation { + display: none; +} +.pagenav-current { + color: hsl(0, 0%, 54%); + font-size: 20px; + padding: 12px; +} +} + + diff --git a/public/img/Logo-square-inverted.svg b/public/img/Logo-square-inverted.svg new file mode 100644 index 0000000000000000000000000000000000000000..f405ae6925c29ea40a70804679ea8c94f25534a6 --- /dev/null +++ b/public/img/Logo-square-inverted.svg @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="512" + height="512" + viewBox="0 0 511.99999 512" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="Logo-square-inverted.svg" + inkscape:export-filename="/home/phil/Bilder/MetaGer Logo/Square/Logo-square-inverted.svg.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1" + inkscape:cx="-11.05704" + inkscape:cy="206.19977" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1920" + inkscape:window-height="1015" + inkscape:window-x="1920" + inkscape:window-y="0" + inkscape:window-maximized="1" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + showguides="true" + inkscape:guide-bbox="true" + units="px"> + <inkscape:grid + type="xygrid" + id="grid4155" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Ebene 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-540.36218)"> + <flowRoot + xml:space="preserve" + id="flowRoot3343" + style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion + id="flowRegion3345"><rect + id="rect3347" + width="223" + height="70" + x="0.33978271" + y="0.11816262" /></flowRegion><flowPara + id="flowPara3349" /></flowRoot> <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:476.30328369px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:810.30267334px;fill:#ff8000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;" + x="18.431213" + y="973.66028" + id="text3351" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + x="18.431213" + y="973.66028" + style="font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:476.30328369px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold Italic';word-spacing:810.30267334px;fill:#ff8000;fill-opacity:1;" + dx="0" + id="tspan4415"><tspan + style="word-spacing:0px;fill:#ff8000;" + id="tspan4161" + dx="0">M</tspan></tspan></text> + </g> +</svg> diff --git a/resources/views/metager3rich.blade.php b/resources/views/metager3rich.blade.php new file mode 100644 index 0000000000000000000000000000000000000000..11a6f1a7ed3c02cb8aadc9ec8f8de01a1c016ec4 --- /dev/null +++ b/resources/views/metager3rich.blade.php @@ -0,0 +1,78 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta charset="UTF-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <title>{{ $eingabe }} - MetaGer</title> + <link rel="stylesheet" title="Material" href="/css/material-default.css" /> + <link rel="stylesheet" title="Material-Invers" href="/css/material-inverse.css" /> + <link href="/font-awesome/css/font-awesome.min.css" rel="stylesheet" /> + <link href="/favicon.ico" rel="icon" type="image/x-icon" /> + <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" /> + <meta content="width=device-width, initial-scale=1.0, user-scalable=no" name="viewport" /> + <meta HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE" /> + <link rel="search" type="application/opensearchdescription+xml" title="{!! trans('resultPage.opensearch') !!}" href="{{ LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), action('StartpageController@loadPlugin', ['params' => base64_encode(serialize(Request::all()))])) }}"> + </head> + <body> + <header class="persistent-search"> + <form class="search-card card elevation-2"> + <a href="/" class="back"> + <img src="/img/Logo-square-inverted.svg" alt="MetaGer" title="MetaGer, die sichere Suchmaschine" /> + </a> + <input type="text" name="eingabe" placeholder="MetaGer-Suche" value="{{ $eingabe }}" class="query-input"/> + <button type="submit" class="search-button fa"></button> + @foreach( $metager->request->all() as $key => $value) + @if($key !== "eingabe" && $key !== "page" && $key !== "next") + <input type='hidden' name='{{ $key }}' value='{{ $value }}' form='submitForm' /> + @endif + @endforeach + </form> + </header> + <details class="focus-card card elevation-1"> + + @if( $metager->getFokus() === "web" ) + <summary class="focus-cell"><div class="focus-cell-label"><span class="icon fa" aria-hidden="true"></span> <b>Web</b></div></summary> + @endif + </details> + <main class="results-container"> + @foreach($metager->getResults() as $result) + @if($result->number % 7 === 0) + @include('layouts.ad', ['ad' => $metager->popAd()]) + @endif + <article class="search-result card elevation-1"> + <div class="result-content"> + <h1 class="result-title">{{ $result->titel }}</h1> + <h2 class="result-display-link">{{ $result->anzeigeLink }}</h2> + <p class="result-description">{{ $result->descr }}</p> + <p class="result-source">gefunden von {!! $result->gefVon !!}</p> + @if( isset($result->logo) ) + <img class="result-thumbnail" src="{{ $metager->getImageProxyLink($result->logo) }}" alt="" /> + @endif + </div> + <div class="result-action-area"> + <a class="result-action primary" href="{{ $result->link }}">Öffnen</a> + <a class="result-action primary" target="_blank" href="{{ $result->link }}">Neuer Tab</a> + <a class="result-action" target="_blank" href="{{ $result->proxyLink }}">Anonym Öffnen</a> + </div> + </article> + @endforeach + </main> + @if($metager->getPage() === 1) + <nav class="pagenav-first"> + <a class="pagenav-button-next card elevation-1" href="{{ $metager->nextSearchLink() }}"><span class="card-button-text">Weitersuchen</span><span class="icon-right">►</span></a> + </nav> + @else + <nav class="pagenav-following"> + <div> + <a class="pagenav-button-first card-inline elevation-1" href="javascript:history.back()">◄</a> + </div> + <div class="pagenav-current"><span class="pagenav-current-annotation">Seite </span>{{ $metager->getPage() }}</div> + <a class="pagenav-button-next card-inline elevation-1" href="{{ $metager->nextSearchLink() }}"><span class="card-button-text">Weitersuchen</span><span class="icon-right">►</span></a> + </nav> + @endif + <footer class="footer-text"> + <a href="https://metager.de/impressum" target="_blank">Impressum</a> + </footer> + <img src="{{ action('ImageController@generateImage')}}?site={{ urlencode(url()->current()) }}" class="hidden" /> + </body> +</html>