diff --git a/app/Http/Controllers/MetaGerSearch.php b/app/Http/Controllers/MetaGerSearch.php index 56566146f0fe230de59a8bfffd0d38079661392f..3596d29bf5139c25a6d2f80d816d0046716b43d8 100644 --- a/app/Http/Controllers/MetaGerSearch.php +++ b/app/Http/Controllers/MetaGerSearch.php @@ -4,7 +4,10 @@ namespace App\Http\Controllers; use App; use App\MetaGer; +use Cache; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Redis; +use View; const TIP_SERVER = 'http://metager3.de:63825/tips.xml'; @@ -19,13 +22,6 @@ class MetaGerSearch extends Controller return redirect()->to('https://maps.metager.de/map/' . $searchinput . '/1240908.5493525574,6638783.2192695495,6'); } - /*if ($focus !== "angepasst" && $this->startsWith($focus, "focus_")) { - $metager->parseFormData($request); - return $metager->createView(); - }*/ - - #die($request->header('User-Agent')); - $time = microtime(); # Mit gelieferte Formulardaten parsen und abspeichern: $metager->parseFormData($request); @@ -39,19 +35,132 @@ class MetaGerSearch extends Controller # auf Ergebnisse warten und die Ergebnisse laden $metager->createSearchEngines($request); + $metager->startSearch(); + + $metager->waitForMainResults(); + + $metager->retrieveResults(); + # Versuchen die Ergebnisse der Quicktips zu laden $quicktipResults = $quicktips->loadResults(); - # Alle Ergebnisse vor der Zusammenführung ranken: $metager->rankAll(); # Ergebnisse der Suchmaschinen kombinieren: $metager->prepareResults(); + # Save the results in Redis + $redis = Redis::connection(env('REDIS_RESULT_CONNECTION')); + $pipeline = $redis->pipeline(); + foreach ($metager->getResults() as $result) { + $pipeline->rpush($metager->getRedisCurrentResultList(), base64_encode(serialize($result))); + } + $pipeline->expire($metager->getRedisCurrentResultList(), env('REDIS_RESULT_CACHE_DURATION')); + $pipeline->execute(); + # Die Ausgabe erstellen: return $metager->createView($quicktipResults); } + public function loadMore(Request $request) + { + /** + * There are three forms of requests to the resultpage + * 1. Initial Request: Loads the fastest searchengines and sends them to the user + * 2. Load more results (with JS): Loads new search engines that answered after the initial request was send + * 3. Load more results (without JS): Loads new search engines that answered within 1s timeout + */ + if ($request->filled('loadMore') && $request->filled('script') && $request->input('script') === "yes") { + return $this->loadMoreJS($request); + } + + } + + private function loadMoreJS(Request $request) + { + # Create a MetaGer Instance with the supplied hash + $hash = $request->input('loadMore', ''); + + $metager = new MetaGer($hash); + $redis = Redis::connection(env('REDIS_RESULT_CONNECTION')); + + $result = []; + # Check if there should be more results + $stats = $redis->hgetall($metager->getRedisEngineResult() . "status"); + $stats["startTime"] = floatval($stats["startTime"]); + $stats["engineCount"] = intval($stats["engineCount"]); + $stats["engineAnswered"] = intval($stats["engineAnswered"]); + $stats["engineDelivered"] = intval($stats["engineDelivered"]); + + $result["finished"] = true; + $result["engineCount"] = $stats["engineCount"]; + $result["engineAnswered"] = $stats["engineAnswered"]; + $result["engineDelivered"] = $stats["engineDelivered"]; + $result["timeWaiting"] = microtime(true) - $stats["startTime"]; + + # Check if we can abort + if ($stats["engineAnswered"] > $stats["engineDelivered"]/*&& $result["timeWaiting"] <= 10 */) { + $metager->parseFormData($request); + # Nach Spezialsuchen überprüfen: + $metager->checkSpecialSearches($request); + + # Read which search engines are new + $newEngines = []; + + while (($engine = $redis->lpop($metager->getRedisResultWaitingKey())) != null) { + $result["engineDelivered"]++; + $newEngines[$engine] = $metager->getSumaFile()->sumas->{$engine}; + } + $cache = Cache::get($hash); + if ($cache != null) { + $metager->setNext(unserialize($cache)["engines"]); + } + + # Check if this request is not for page one + $metager->setEngines($request, $newEngines); + + # Add the results already delivered to the user + $results = $redis->lrange($metager->getRedisCurrentResultList(), 0, -1); + foreach ($results as $index => $oldResult) { + $results[$index] = unserialize(base64_decode($oldResult)); + $results[$index]->new = false; + } + $metager->setResults($results); + $metager->retrieveResults(); + $metager->rankAll(); + $metager->prepareResults(); + $result["nextSearchLink"] = $metager->nextSearchLink(); + $results = $metager->getResults(); + foreach ($results as $index => $resultTmp) { + if ($resultTmp->new) { + if ($metager->getFokus() !== "bilder") { + $view = View::make('layouts.result', ['result' => $resultTmp, 'metager' => $metager]); + $html = $view->render(); + $result['newResults'][$index] = $html; + $result["imagesearch"] = false; + } else { + $view = View::make('layouts.image_result', ['result' => $resultTmp, 'metager' => $metager]); + $html = $view->render(); + $result['newResults'][$index] = $html; + $result["imagesearch"] = true; + } + } + } + # Save the results in Redis + $pipeline = $redis->pipeline(); + $pipeline->hincrby($metager->getRedisEngineResult() . "status", "engineDelivered", sizeof($newEngines)); + $pipeline->hset($metager->getRedisEngineResult() . "status", "nextSearchLink", $result["nextSearchLink"]); + foreach ($metager->getResults() as $resultTmp) { + $resultTmp->new = false; + $pipeline->rpush($metager->getRedisCurrentResultList(), base64_encode(serialize($resultTmp))); + } + $pipeline->expire($metager->getRedisCurrentResultList(), env('REDIS_RESULT_CACHE_DURATION')); + $pipeline->execute(); + + } + return response()->json($result); + } + public function botProtection($redirect) { $hash = md5(date('YmdHi')); diff --git a/app/Jobs/Searcher.php b/app/Jobs/Searcher.php index ec82937b42b85994833d0d930a46ef08deeb002c..2271c7bde5610ead4f2515013c941b8ab3e7a751 100644 --- a/app/Jobs/Searcher.php +++ b/app/Jobs/Searcher.php @@ -85,8 +85,7 @@ class Searcher implements ShouldQueue $url = base64_decode($mission[1]); // The url to fetch $timeout = $mission[2]; // Timeout from the MetaGer process in ms $medianFetchTime = $this->getFetchTime(); // The median Fetch time of the search engine in ms - Redis::hset('search.' . $hashValue, $this->name, "connected"); - + Redis::hset('search.' . $hashValue . ".results." . $this->name, "status", "connected"); $result = $this->retrieveUrl($url); $this->storeResult($result, $poptime, $hashValue); @@ -99,7 +98,7 @@ class Searcher implements ShouldQueue // In sync mode every Searcher may only retrieve one result because it would block // the execution of the remaining code otherwise: - if (getenv("QUEUE_DRIVER") === "sync" + if (getenv("QUEUE_CONNECTION") === "sync" || $this->counter > $this->MAX_REQUESTS || (microtime(true) - $this->startTime) > $this->MAX_TIME) { break; @@ -161,16 +160,24 @@ class Searcher implements ShouldQueue // Set this URL to the Curl handle curl_setopt($this->ch, CURLOPT_URL, $url); $result = curl_exec($this->ch); - $this->connectionInfo = curl_getinfo($this->ch); return $result; } private function storeResult($result, $poptime, $hashValue) { - Redis::hset('search.' . $hashValue, $this->name, $result); + $redis = Redis::connection(env('REDIS_RESULT_CONNECTION')); + $pipeline = $redis->pipeline(); + $pipeline->hset('search.' . $hashValue . ".results." . $this->name, "response", $result); + $pipeline->hset('search.' . $hashValue . ".results." . $this->name, "delivered", "0"); + $pipeline->hincrby('search.' . $hashValue . ".results.status", "engineAnswered", 1); // After 60 seconds the results should be read by the MetaGer Process and stored in the Cache instead - Redis::expire('search.' . $hashValue, 60); + $pipeline->expire('search.' . $hashValue . ".results." . $this->name, env('REDIS_RESULT_CACHE_DURATION')); + $pipeline->rpush('search.' . $hashValue . ".ready", $this->name); + $pipeline->expire('search.' . $hashValue . ".ready", env('REDIS_RESULT_CACHE_DURATION')); + $pipeline->sadd('search.' . $hashValue . ".engines", $this->name); + $pipeline->expire('search.' . $hashValue . ".engines", env('REDIS_RESULT_CACHE_DURATION')); + $pipeline->execute(); $this->lastTime = microtime(true); } diff --git a/app/MetaGer.php b/app/MetaGer.php index 0a80fce1853d32dde0460dbc2ca1885c4b58c620..19d7606956058b7bcc423a6c9fbbefa9f456a141 100644 --- a/app/MetaGer.php +++ b/app/MetaGer.php @@ -46,6 +46,7 @@ class MetaGer protected $agent; protected $apiKey = ""; protected $apiAuthorized = false; + protected $next = []; # Konfigurationseinstellungen: protected $sumaFile; protected $mobile; @@ -59,8 +60,10 @@ class MetaGer protected $languageDetect; protected $verificationId; protected $verificationCount; + protected $searchUid; + protected $redisResultWaitingKey, $redisResultEngineList, $redisEngineResult, $redisCurrentResultList; - public function __construct() + public function __construct($hash = "") { # Timer starten $this->starttime = microtime(true); @@ -90,6 +93,21 @@ class MetaGer } catch (ConnectionException $e) { $this->canCache = false; } + if ($hash === "") { + $this->searchUid = md5(uniqid()); + } else { + $this->searchUid = $hash; + } + $redisPrefix = "search"; + # This is a list on which the MetaGer process can do a blocking pop to wait for new results + $this->redisResultWaitingKey = $redisPrefix . "." . $this->searchUid . ".ready"; + # This is a list of searchengines which have delivered results for this search + $this->redisResultEngineList = $redisPrefix . "." . $this->searchUid . ".engines"; + # This is the key where the results of the engine are stored as well as some statistical data + $this->redisEngineResult = $redisPrefix . "." . $this->searchUid . ".results."; + # A list of all search results already delivered to the user (sorted of course) + $this->redisCurrentResultList = $redisPrefix . "." . $this->searchUid . ".currentResults"; + } # Erstellt aus den gesammelten Ergebnissen den View @@ -217,21 +235,8 @@ class MetaGer public function prepareResults() { $engines = $this->engines; - // combine - $combinedResults = $this->combineResults($engines); - - # Wir bestimmen die Sprache eines jeden Suchergebnisses - $this->results = $this->addLangCodes($this->results); - - // sort - //$sortedResults = $this->sortResults($engines); - // filter - // augment (boost&adgoal) - // authorize - if ($this->apiKey) { - $this->apiAuthorized = $this->authorize($this->apiKey); - } + $this->combineResults($engines); // misc (WiP) if ($this->fokus == "nachrichten") { $this->results = array_filter($this->results, function ($v, $k) { @@ -274,40 +279,6 @@ class MetaGer $counter = 0; $firstRank = 0; - if (isset($this->startForwards)) { - $this->startCount = $this->startForwards; - } elseif (isset($this->startBackwards)) { - $this->startCount = $this->startBackwards - count($this->results) - 1; - } else { - $this->startCount = 0; - } - - foreach ($this->results as $result) { - if ($counter === 0) { - $firstRank = $result->rank; - } - - $counter++; - $result->number = $counter + $this->startCount; - $confidence = 0; - if ($firstRank > 0) { - $confidence = $result->rank / $firstRank; - } else { - $confidence = 0; - } - - if ($confidence > 0.65) { - $result->color = "#FF4000"; - } elseif ($confidence > 0.4) { - $result->color = "#FF0080"; - } elseif ($confidence > 0.2) { - $result->color = "#C000C0"; - } else { - $result->color = "#000000"; - } - - } - if (count($this->results) <= 0) { if (strlen($this->site) > 0) { $no_sitesearch_query = str_replace(urlencode("site:" . $this->site), "", $this->fullUrl); @@ -321,62 +292,15 @@ class MetaGer $page = $this->page + 1; $this->next = [ 'page' => $page, - 'startForwards' => $this->results[count($this->results) - 1]->number, 'engines' => $this->next, ]; - Cache::put(md5(serialize($this->next)), serialize($this->next), 60); + Cache::put($this->getSearchUid(), serialize($this->next), 60); } else { $this->next = []; } } - private function addLangCodes($results) - { - # Wenn es keine Ergebnisse gibt, brauchen wir uns gar nicht erst zu bemühen - if (sizeof($results) === 0) { - return $results; - } - - # Bei der Spracheinstellung "all" wird nicht gefiltert - if ($this->getLang() === "all") { - return $results; - } else { - # Ansonsten müssen wir jedem Result einen Sprachcode hinzufügen - $id = 0; - $langStrings = []; - foreach ($results as $result) { - # Wir geben jedem Ergebnis eine ID um später die Sprachcodes zuordnen zu können - $result->id = $id; - - $langStrings["result_" . $id] = utf8_encode($result->getLangString()); - - $id++; - } - # Wir schreiben die Strings in eine temporäre JSON-Datei, - # Da das Array unter umständen zu groß ist für eine direkte Übergabe an das Skript - $filename = "/tmp/" . getmypid(); - file_put_contents($filename, json_encode($langStrings)); - $langDetectorPath = app_path() . "/Models/lang.pl"; - $lang = exec("echo '$filename' | $langDetectorPath"); - $lang = json_decode($lang, true); - - # Wir haben nun die Sprachcodes der einzelnen Ergebnisse. - # Diese müssen wir nur noch korrekt zuordnen, dann sind wir fertig. - foreach ($lang as $key => $langCode) { - # Prefix vom Key entfernen: - $id = intval(str_replace("result_", "", $key)); - foreach ($this->results as $result) { - if ($result->id === $id) { - $result->langCode = $langCode; - break; - } - } - } - return $results; - } - } - public function combineResults($engines) { foreach ($engines as $engine) { @@ -407,6 +331,9 @@ class MetaGer $tldList = ""; try { foreach ($results as $result) { + if (!$result->new) { + continue; + } $link = $result->anzeigeLink; if (strpos($link, "http") !== 0) { $link = "http://" . $link; @@ -431,7 +358,7 @@ class MetaGer $hash = $el[1]; foreach ($results as $result) { - if ($hoster === $result->tld && !$result->partnershop) { + if ($result->new && $hoster === $result->tld && !$result->partnershop) { # Hier ist ein Advertiser: # Das Logo hinzufügen: if ($result->image !== "") { @@ -512,7 +439,7 @@ class MetaGer public function createQuicktips() { # Die quicktips werden als job erstellt und zur Abarbeitung freigegeben - $quicktips = new \App\Models\Quicktips\Quicktips($this->q, $this->lang, $this->getTime(), $this->getHashCode()); + $quicktips = new \App\Models\Quicktips\Quicktips($this->q, $this->lang, $this->getTime()); return $quicktips; } @@ -534,7 +461,6 @@ class MetaGer if (empty($this->sumaFile->foki->{$this->fokus})) { $this->fokus = "web"; } - foreach ($this->sumaFile->foki->{$this->fokus}->sumas as $suma) { # Check if this engine is disabled and can't be used $disabled = empty($this->sumaFile->sumas->{$suma}->disabled) ? false : $this->sumaFile->sumas->{$suma}->disabled; @@ -589,8 +515,6 @@ class MetaGer $this->enabledSearchengines["yahoo-ads"] = $this->sumaFile->sumas->{"yahoo-ads"}; } - #die(var_dump($this->enabledSearchengines)); - if (sizeof($this->enabledSearchengines) === 0) { $filter = ""; foreach ($this->queryFilter as $queryFilter => $filterPhrase) { @@ -601,53 +525,36 @@ class MetaGer 'filter' => $filter]); $this->errors[] = $error; } - $engines = []; $typeslist = []; $counter = 0; + $this->setEngines($request); + } + public function setEngines(Request $request, $enabledSearchengines = []) + { if ($this->requestIsCached($request)) { + # If this is a page other than 1 the request is "cached" $engines = $this->getCachedEngines($request); # We need to edit some Options of the Cached Search Engines foreach ($engines as $engine) { - $engine->setResultHash($this->getHashCode()); + $engine->setResultHash($this->getSearchUid()); } + $this->engines = $engines; } else { - $engines = $this->actuallyCreateSearchEngines($this->enabledSearchengines); + if (sizeof($enabledSearchengines) > 0) { + $this->enabledSearchengines = $enabledSearchengines; + } + $this->actuallyCreateSearchEngines($this->enabledSearchengines); } + } + public function startSearch() + { # Wir starten alle Suchen - foreach ($engines as $engine) { + foreach ($this->engines as $engine) { $engine->startSearch($this); } - - /* Wir warten auf die Antwort der Suchmaschinen - * Die Verbindung steht zu diesem Zeitpunkt und auch unsere Requests wurden schon gesendet. - * Wir zählen die Suchmaschinen, die durch den Cache beantwortet wurden: - * $enginesToLoad zählt einerseits die Suchmaschinen auf die wir warten und andererseits - * welche Suchmaschinen nicht rechtzeitig geantwortet haben. - */ - - $enginesToLoad = []; - $canBreak = false; - foreach ($engines as $engine) { - if ($engine->cached) { - if ($overtureEnabled && ($engine->name === "overture" || $engine->name === "overtureAds")) { - $canBreak = true; - } - } else { - $enginesToLoad[$engine->name] = false; - } - } - - $this->waitForResults($enginesToLoad, $overtureEnabled, $canBreak); - - $this->retrieveResults($engines); - foreach ($engines as $engine) { - if (!empty($engine->totalResults) && $engine->totalResults > $this->totalResults) { - $this->totalResults = $engine->totalResults; - } - } } # Spezielle Suchen und Sumas @@ -696,7 +603,7 @@ class MetaGer $engines[] = $tmp; } - return $engines; + $this->engines = $engines; } public function getAvailableParameterFilter() @@ -779,128 +686,75 @@ class MetaGer $next = unserialize(Cache::get($request->input('next'))); $this->page = $next['page']; $engines = $next['engines']; - if (isset($next['startForwards'])) { - $this->startForwards = $next['startForwards']; - } - if (isset($next['startBackwards'])) { - $this->startBackwards = $next['startBackwards']; - } return $engines; } - # Passt den Suchfokus an, falls für einen Fokus genau alle vorhandenen Sumas eingeschaltet sind - public function adjustFocus($sumas, $enabledSearchengines) + public function waitForMainResults() { - # Findet für alle Foki die enthaltenen Sumas - $foki = []; # [fokus][suma] => [suma] - foreach ($sumas as $suma) { - if ((!$this->sumaIsDisabled($suma)) && (!isset($suma['userSelectable']) || $suma['userSelectable']->__toString() === "1")) { - if (isset($suma['type'])) { - # Wenn foki für diese Suchmaschine angegeben sind - $focuses = explode(",", $suma['type']->__toString()); - foreach ($focuses as $foc) { - if (isset($suma['minismCollection'])) { - $foki[$foc][] = "minism"; - } else { - $foki[$foc][] = $suma['name']->__toString(); - } - } - } else { - # Wenn keine foki für diese Suchmaschine angegeben sind - if (isset($suma['minismCollection'])) { - $foki["andere"][] = "minism"; - } else { - $foki["andere"][] = $suma['name']->__toString(); - } + $redis = Redis::connection(env('REDIS_RESULT_CONNECTION')); + $engines = $this->engines; + $enginesToWaitFor = []; + $mainEngines = $this->sumaFile->foki->{$this->fokus}->main; + foreach ($mainEngines as $mainEngine) { + foreach ($engines as $engine) { + if (!$engine->cached && $engine->name === $mainEngine) { + $enginesToWaitFor[] = $engine; } } } - # Findet die Namen der aktuell eingeschalteten Sumas - $realEngNames = []; - foreach ($enabledSearchengines as $realEng) { - $nam = $realEng["name"]->__toString(); - if ($nam !== "qualigo" && $nam !== "overtureAds") { - $realEngNames[] = $nam; - } - } + $timeStart = microtime(true); + $answered = []; + $results = null; - # Anschließend werden diese beiden Listen verglichen (jeweils eine der Fokuslisten für jeden Fokus), um herauszufinden ob sie vielleicht identisch sind. Ist dies der Fall, so hat der Nutzer anscheinend Suchmaschinen eines kompletten Fokus eingestellt. Der Fokus wird dementsprechend angepasst. - foreach ($foki as $fok => $engines) { - $isFokus = true; - $fokiEngNames = []; - foreach ($engines as $eng) { - $fokiEngNames[] = $eng; - } - # Jede eingeschaltete Engine ist für diesen Fokus geeignet - foreach ($fokiEngNames as $fen) { - # Bei Bildersuchen ist uns egal, ob alle Suchmaschinen aus dem Suchfokus eingeschaltet sind, da wir sie eh als Bildersuche anzeigen müssen - if (!in_array($fen, $realEngNames) && $fok !== "bilder") { - $isFokus = false; - } - } - # Jede im Fokus erwartete Engine ist auch eingeschaltet - foreach ($realEngNames as $ren) { - if (!in_array($ren, $fokiEngNames)) { - $isFokus = false; - } - } - # Wenn die Listen identisch sind, setze den Fokus um - if ($isFokus) { - $this->fokus = $fok; - } + # If there is no main searchengine to wait for or if the only main engine is yahoo-ads we will define a timeout of 1s + $forceTimeout = null; + if (sizeof($enginesToWaitFor) === 0 || (sizeof($enginesToWaitFor) === 1 && $enginesToWaitFor[0]->name === "yahoo-ads")) { + $forceTimeout = 1; } - } - - public function waitForResults($enginesToLoad, $overtureEnabled, $canBreak) - { - $timeStart = microtime(true); - $results = null; - while (true) { - $results = Redis::hgetall('search.' . $this->getHashCode()); - - $ready = true; - // When every - $connected = true; - foreach ($results as $key => $value) { - if ($value === "waiting" || $value === "connected") { - $ready = false; - } - if ($value === "waiting") { - $connected = false; + while (sizeof($enginesToWaitFor) > 0 || ($forceTimeout !== null && (microtime(true) - $timeStart) < $forceTimeout)) { + $newEngine = $redis->blpop($this->redisResultWaitingKey, 1); + if ($newEngine === null || sizeof($newEngine) !== 2) { + continue; + } else { + $newEngine = $newEngine[1]; + foreach ($enginesToWaitFor as $index => $engine) { + if ($engine->name === $newEngine) { + unset($enginesToWaitFor[$index]); + break; + } } + $answered[] = $newEngine; } - - // 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 ((microtime(true) - $timeStart) >= 2) { + break; } + } - $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; - } + # Now we can add an entry to Redis which defines the starting time and how many engines should answer this request - if ($ready) { - break; + $pipeline = $redis->pipeline(); + $pipeline->hset($this->getRedisEngineResult() . "status", "startTime", $timeStart); + $pipeline->hset($this->getRedisEngineResult() . "status", "engineCount", sizeof($engines)); + $pipeline->hset($this->getRedisEngineResult() . "status", "engineDelivered", sizeof($answered)); + # Add the cached engines as answered + foreach ($engines as $engine) { + if ($engine->cached) { + $pipeline->hincrby($this->getRedisEngineResult() . "status", "engineDelivered", 1); + $pipeline->hincrby($this->getRedisEngineResult() . "status", "engineAnswered", 1); } - usleep(50000); } - - # Wir haben nun so lange wie möglich gewartet. Wir registrieren nun noch die Suchmaschinen, die geanwortet haben. - foreach ($results as $key => $value) { - $enginesToLoad[$key] = true; + foreach ($answered as $engine) { + $pipeline->hset($this->getRedisEngineResult() . $engine, "delivered", "1"); } - $this->enginesToLoad = $enginesToLoad; + $pipeline->execute(); + } - public function retrieveResults($engines) + public function retrieveResults() { + $engines = $this->engines; # Von geladenen Engines die Ergebnisse holen foreach ($engines as $engine) { if (!$engine->loaded) { @@ -910,9 +764,10 @@ class MetaGer Log::error($e); } } + if (!empty($engine->totalResults) && $engine->totalResults > $this->totalResults) { + $this->totalResults = $engine->totalResults; + } } - - $this->engines = $engines; } /* @@ -1037,6 +892,9 @@ class MetaGer $this->apiKey = ""; } } + if ($this->apiKey) { + $this->apiAuthorized = $this->authorize($this->apiKey); + } // Remove Inputs that are not used $this->request = $request->replace($request->except(['verification_id', 'uid', 'verification_count'])); @@ -1262,7 +1120,7 @@ class MetaGer if ($this->request->input('out', '') !== "results" && $this->request->input('out', '') !== '') { $requestData["out"] = $this->request->input('out'); } - $requestData['next'] = md5(serialize($this->next)); + $requestData['next'] = $this->getSearchUid(); $link = action('MetaGerSearch@search', $requestData); } else { $link = "#"; @@ -1358,6 +1216,11 @@ class MetaGer } } + public function setNext($next) + { + $this->next = $next; + } + public function addLink($link) { if (strpos($link, "http://") === 0) { @@ -1472,10 +1335,9 @@ class MetaGer return $link; } - public function getHashCode() + public function getSearchUid() { - $string = url()->full(); - return md5($string); + return $this->searchUid; } # Einfache Getter @@ -1485,6 +1347,11 @@ class MetaGer return $this->verificationId; } + public function getNext() + { + return $this->next; + } + public function getVerificationCount() { return $this->verificationCount; @@ -1500,6 +1367,11 @@ class MetaGer return $this->newtab; } + public function setResults($results) + { + $this->results = $results; + } + public function getResults() { return $this->results; @@ -1628,4 +1500,23 @@ class MetaGer { return $this->startCount; } + + public function getRedisResultWaitingKey() + { + return $this->redisResultWaitingKey; + } + + public function getRedisResultEngineList() + { + return $this->redisResultEngineList; + } + + public function getRedisEngineResult() + { + return $this->redisEngineResult; + } + public function getRedisCurrentResultList() + { + return $this->redisCurrentResultList; + } } diff --git a/app/Models/Quicktips/Quicktips.php b/app/Models/Quicktips/Quicktips.php index 6e5c053bc7d76e962af777366be8b71f4373cc79..1b7b7e046ea4523727db90379496333bb70eb812 100644 --- a/app/Models/Quicktips/Quicktips.php +++ b/app/Models/Quicktips/Quicktips.php @@ -3,7 +3,6 @@ namespace App\Models\Quicktips; use App\Jobs\Searcher; -use Cache; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Support\Facades\Redis; use Log; @@ -12,8 +11,8 @@ class Quicktips { use DispatchesJobs; - const QUICKTIP_URL = "http://localhost:63825/1.1/quicktips.xml"; - const QUICKTIP_NAME = "quicktips"; + const QUICKTIP_URL = "http://localhost:63825/1.1/quicktips.xml"; + const QUICKTIP_NAME = "quicktips"; const CACHE_DURATION = 60; private $hash; @@ -26,18 +25,17 @@ class Quicktips public function startSearch($search, $locale, $max_time) { $url = self::QUICKTIP_URL . "?search=" . $this->normalize_search($search) . "&locale=" . $locale; - - $hash = md5($url); - # TODO anders weitergeben - $this->hash = $hash; + $this->hash = md5($url); # TODO cache wieder einbauen (eventuell) if ( /*!Cache::has($hash)*/true) { - Redis::hset("search." . $hash, self::QUICKTIP_NAME, "waiting"); + $redis = Redis::connection(env('REDIS_RESULT_CONNECTION')); + + $redis->hset("search." . $this->hash . ".results." . self::QUICKTIP_NAME, "status", "waiting"); // Queue this search - $mission = $hash . ";" . base64_encode($url) . ";" . $max_time; + $mission = $this->hash . ";" . base64_encode($url) . ";" . $max_time; Redis::rpush(self::QUICKTIP_NAME . ".queue", $mission); // Check the current status of Searchers for QUICKTIP_NAME @@ -85,14 +83,11 @@ class Quicktips public function retrieveResults($hash) { $body = ""; - #if (Cache::has($hash)) { - $body = Cache::get($hash); - #} elseif (Redis::hexists('search.' . $hash, self::QUICKTIP_NAME)) { - $body = Redis::hget('search.' . $hash, self::QUICKTIP_NAME); - Redis::hdel('search.' . $hash, self::QUICKTIP_NAME); - Cache::put($hash, $body, self::CACHE_DURATION); - #} + $redis = Redis::connection(env('REDIS_RESULT_CONNECTION')); + $body = $redis->hget('search.' . $hash . ".results." . self::QUICKTIP_NAME, "response"); + $redis->del('search.' . $hash . ".results." . self::QUICKTIP_NAME); + $redis->del('search.' . $hash . ".ready"); if ($body !== "") { return $body; } else { @@ -157,14 +152,14 @@ class Quicktips $descr = $quicktip_xml->content->__toString(); // Details - $details = []; + $details = []; $details_xpath = $quicktip_xml->xpath('mg:details'); if (sizeof($details_xpath) > 0) { foreach ($details_xpath[0] as $detail_xml) { $details_title = $detail_xml->title->__toString(); - $details_link = $detail_xml->url->__toString(); + $details_link = $detail_xml->url->__toString(); $details_descr = $detail_xml->text->__toString(); - $details[] = new \App\Models\Quicktips\Quicktip_detail( + $details[] = new \App\Models\Quicktips\Quicktip_detail( $details_title, $details_link, $details_descr diff --git a/app/Models/Result.php b/app/Models/Result.php index 529788464d4021f4f3739c7181e594243059e58d..127626bb9241bf7d6d4cb4dc86b381d9a2b12472 100644 --- a/app/Models/Result.php +++ b/app/Models/Result.php @@ -27,6 +27,7 @@ class Result public $strippedDomain; # Die Domain in Form "bar.de" public $strippedLink; # Der Link in Form "foo.bar.de/test" public $rank; # Das Ranking für das Ergebnis + public $new = true; # Erstellt ein neues Ergebnis public function __construct($provider, $titel, $link, $anzeigeLink, $descr, $gefVon, $gefVonLink, $sourceRank, $additionalInformation = []) @@ -67,6 +68,7 @@ class Result $this->price = isset($additionalInformation["price"]) ? $additionalInformation["price"] : 0; $this->price_text = $this->price_to_text($this->price); $this->additionalInformation = $additionalInformation; + $this->hash = spl_object_hash($this); } private function price_to_text($price) diff --git a/app/Models/Searchengine.php b/app/Models/Searchengine.php index 03b5840485d244b565a6fb2a807e5a73c82289ac..f6bacb0969824ad4d4a414946dd7225cd3973a97 100644 --- a/app/Models/Searchengine.php +++ b/app/Models/Searchengine.php @@ -87,7 +87,7 @@ abstract class Searchengine $this->getString = $this->generateGetString($q); $this->hash = md5($this->engine->host . $this->getString . $this->engine->port . $this->name); - $this->resultHash = $metager->getHashCode(); + $this->resultHash = $metager->getSearchUid(); $this->canCache = $metager->canCache(); } @@ -102,13 +102,15 @@ abstract class Searchengine # Prüft, ob die Suche bereits gecached ist, ansonsted wird sie als Job dispatched public function startSearch(\App\MetaGer $metager) { - if ($this->canCache && Cache::has($this->hash)) { $this->cached = true; $this->retrieveResults($metager); } else { + $redis = Redis::connection(env('REDIS_RESULT_CONNECTION')); // We will push the confirmation of the submission to the Result Hash - Redis::hset('search.' . $this->resultHash, $this->name, "waiting"); + $redis->hset($metager->getRedisEngineResult() . $this->name, "status", "waiting"); + $redis->expire($metager->getRedisEngineResult() . $this->name, env('REDIS_RESULT_CACHE_DURATION')); + // We need to submit a action that one of our workers can understand // The missions are submitted to a redis queue in the following string format // <ResultHash>;<URL to fetch> @@ -190,10 +192,6 @@ abstract class Searchengine { foreach ($this->results as $result) { $result->rank($eingabe); - if (str_contains($this->engine->{"display-name"}, "Yahoo")) { - #die(var_dump($result)); - } - } } @@ -210,12 +208,12 @@ abstract class Searchengine } $body = ""; + $redis = Redis::connection(env('REDIS_RESULT_CONNECTION')); if ($this->canCache && $this->cacheDuration > 0 && Cache::has($this->hash)) { $body = Cache::get($this->hash); - } elseif (Redis::hexists('search.' . $this->resultHash, $this->name)) { - $body = Redis::hget('search.' . $this->resultHash, $this->name); - Redis::hdel('search.' . $this->resultHash, $this->name); + } elseif ($redis->hexists($metager->getRedisEngineResult() . $this->name, "response")) { + $body = $redis->hget($metager->getRedisEngineResult() . $this->name, "response"); if ($this->canCache && $this->cacheDuration > 0) { Cache::put($this->hash, $body, $this->cacheDuration); } @@ -251,13 +249,7 @@ abstract class Searchengine # Append the Query String $getString .= "&" . $this->engine->{"query-parameter"} . "=" . $this->urlEncode($query); -/* -die(var_dump($getString)); -# Affildata -if (strpos($getString, "<<AFFILDATA>>")) { -$getString = str_replace("<<AFFILDATA>>", $this->getOvertureAffilData($url), $getString); -}*/ return $getString; } diff --git a/app/Models/lang.pl b/app/Models/lang.pl deleted file mode 100755 index 2be7f502cb792c45d2ff8c9a34602b7cfbc9a9e3..0000000000000000000000000000000000000000 --- a/app/Models/lang.pl +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/perl - -use Lingua::Identify qw(:language_identification); -use JSON; -use warnings; -use strict; -binmode STDOUT, ":utf8"; -binmode STDIN, ":utf8"; -use utf8; - -chomp(my $filename = <STDIN>); - -# Lets open the given file: -open(my $fh, "<", $filename) - or die "Can't open < $filename: $!"; -my $json = <$fh>; -close $fh; - -# Decode the JSON String -my $data = JSON->new->utf8->decode($json); - -# Wir durchlaufen den Hash: -foreach my $key (keys %{$data}){ - $data->{$key} = langof($data->{$key}); -} - -$data = encode_json($data); - -# Nur noch die temporäre Datei löschen: -unlink($filename); - -print $data; diff --git a/app/Models/parserSkripte/ProdSearch.php b/app/Models/parserSkripte/ProdSearch.php new file mode 100644 index 0000000000000000000000000000000000000000..b4d5381e8595897c6757e34e941fa20141b98dcf --- /dev/null +++ b/app/Models/parserSkripte/ProdSearch.php @@ -0,0 +1,52 @@ +<?php + +namespace app\Models\parserSkripte; + +use App\Models\Searchengine; + +class ProdSearch extends Searchengine +{ + public $results = []; + + public function __construct($name, \StdClass $engine, \App\MetaGer $metager) + { + parent::__construct($name, $engine, $metager); + } + + public function loadResults($result) + { + $results = json_decode($result, true); + foreach ($results as $result) { + if ($this->counter >= 10) { + break; + } + + $title = $result["title"]; + $link = $result["product-link"]; + $anzeigeLink = $link; + $price = 0; + $descr = ""; + if (isset($result['price_cents'])) { + $price = intval($result['price_cents']); + $descr .= "<p>Preis: " . (intval($result['price_cents']) / 100.0) . " €</p>"; + } + if (isset($result['image-url'])) { + $image = $result['image-url']; + } + + $this->counter++; + $this->results[] = new \App\Models\Result( + $this->engine, + $title, + $link, + $anzeigeLink, + $descr, + $this->engine->{"display-name"},$this->engine->homepage, + $this->counter, + [ + 'price' => $price, + 'image' => $image] + ); + } + } +} diff --git a/readme.md b/readme.md index b2ac2b86c6cb647420b9f9a0fec8cf60832cc7a5..26920c06bbc130723e345b62d23b8f86db019eda 100644 --- a/readme.md +++ b/readme.md @@ -18,9 +18,6 @@ * php-gd * sqlite3 * redis-server -* Die Perl-Pakete - * Lingua::Identify (http://search.cpan.org/~ambs/Lingua-Identify-0.56/lib/Lingua/Identify.pm) - * JSON (http://search.cpan.org/~makamaka/JSON-2.90/lib/JSON.pm) --- [<img src="public/img/Browserstack-logo_2x.png" width="250px" alt="Browserstack Logo" />](https://www.browserstack.com) <br /> diff --git a/resources/js/scriptResultPage.js b/resources/js/scriptResultPage.js index d2c1491b31aca9769d1e3b58bce4ae35ac0d4e19..dd140c82180bdc03f0a6f9d5009f3b5e614432f7 100644 --- a/resources/js/scriptResultPage.js +++ b/resources/js/scriptResultPage.js @@ -1,7 +1,7 @@ $(document).ready(function () { botProtection(); - enableFormResetter(); + loadMoreResults(); }); function botProtection() { @@ -50,4 +50,72 @@ function enableFormResetter() { timeout = null; }, 500); }); +} + +function loadMoreResults() { + var searchKey = $("meta[name=searchkey]").attr("content"); + var updateUrl = document.location.href; + updateUrl += "&loadMore=" + searchKey + "&script=yes"; + + updateUrl = updateUrl.replace("/meta.ger3", "/loadMore"); + + var expectedEngines = -1; + var deliveredEngines = -1; + + var currentlyLoading = false; + + // Regularily check for not yet delivered Results + var resultLoader = window.setInterval(function () { + if (!currentlyLoading) { + currentlyLoading = true; + $.getJSON(updateUrl, function (data) { + // Check if we can clear the interval (once every searchengine has answered) + if (data.engineDelivered == data.engineCount || data.timeWaiting > 15) { + clearInterval(resultLoader); + } + // If there are new results we can add them + if (typeof data.newResults != "undefined") { + for (var key in data.newResults) { + var value = data.newResults[key]; + + // If there are more results than the given index we will prepend otherwise we will append the result + if (!data.imagesearch) { + var results = $(".result:not(.ad)"); + if (key == 0) { + if ($(".result.ad").length > 0) { + $(value).insertAfter($($(".result.ad")[$(".result.ad").length - 1])); + } else { + $("#results").prepend(value); + } + } else if (typeof results[key] != "undefined") { + $(value).insertBefore($(results[key])); + } else if (typeof results[key - 1] != "undefined") { + $(value).insertAfter($(results[key - 1])); + } + } else { + var results = $(".image-container > .image"); + if (key == 0) { + $(".image-container").prepend(value); + } else if (typeof results[key] != "undefined") { + $(value).insertBefore($(results[key])); + } else if (typeof results[key - 1] != "undefined") { + $(value).insertAfter($(results[key - 1])); + } + } + } + if ($(".no-results-error").length > 0 && ($(".image-container > .image").length > 0) || $(".result:not(.ad)").length > 0) { + $(".no-results-error").remove(); + if ($(".alert.alert-danger > ul").children().length == 0) { + $(".alert.alert-danger").remove(); + } + } + console.log(data); + } + currentlyLoading = false; + }); + } + }, 1000); + //clearInterval(resultLoader); + console.log(updateUrl); + } \ No newline at end of file diff --git a/resources/lang/de/faq.php b/resources/lang/de/faq.php deleted file mode 100644 index 84c9adff047abc86fb4bb0922e804aaefcd50e20..0000000000000000000000000000000000000000 --- a/resources/lang/de/faq.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php - -return [ - 'achtung' => 'Achtung, da unsere Suchmaschine ständig weiterentwickelt und verbessert wird, kann es dazu kommen, dass sich immer wieder Änderungen an Aufbau und Funktion ergeben. Wir versuchen zwar die Hilfe schnellstmöglich den Änderungen entsprechend anzupassen, können jedoch nicht ausschließen, dass es zu temporären Unstimmigkeiten in Teilen der Erklärungen kommt.', - 'title' => 'MetaGer - FAQ', - - 'faq.1.h' => 'Was ist MetaGer?', - 'faq.1.b' => 'MetaGer ist eine <strong>Suchmaschine</strong>, die Suchdienste parallel nach den von Ihnen eingegebenen Suchworten absucht und alle Ergebnisse zusammenfasst. MetaGer arbeitet die Ergebnisse sinnvoll auf. Dabei werden etwa (möglichst) alle doppelten Treffer (Doubletten) zu einem zusammengefasst. Eine vollständige Erkennung von Doubletten ist allerdings unmöglich. So etwas nennt man eine <strong>Meta-Suchmaschine</strong>. Wenn man also sinnvoll suchen will, dann muss man etliche Suchmaschinen nacheinander "von Hand" absuchen und alle Ergebnisse vergleichen und zusammenführen. Diese Arbeit kann einem ein Automat - die Metasuchmaschine – abnehmen.', - 'faq.1.b2' => 'Dazu kommt der höhere Abdeckungsgrad, denn nicht jede Suchmaschine kennt das ganze Internet. Näheres zu Metasuchmaschinen finden Sie bei <a href="https://de.wikipedia.org/wiki/Metasuchmaschine" target="_blank" rel="noopener">Wikipedia</a>. Vielleicht genügen Ihnen die Ergebnisse, die Ihnen MetaGer präsentiert, vielleicht möchten Sie mit einer einzelnen Suchmaschine nochmals suchen. In der Ergebnisliste sehen Sie an jedem Ergebnis, woher es kam und können auch direkt klicken. Viele weitere Suchmaschinen finden Sie zum Beispiel hier: <a href="http://www.klug-suchen.de/" target="_blank" rel="noopener">klug-suchen.de</a>.', - - 'faq.2.1.h' => 'Warum können wir Suchmaschinen abfragen und trotzdem die Anonymität der Nutzer wahren?', - 'faq.2.1.b' => 'Wir als Meta-Suchmaschine stehen zwischen Ihnen und der Abfrage, die bspw. an Yahoo weiter geleitet wird. Das bedeutet, wenn Sie eine Suchabfrage abschicken, schicken sie diese Abfrage an uns. Wir entziehen dieser dann alle Informationen, welche sie identifizieren könnten und leiten eine anonyme Abfrage an Yahoo weiter. Yahoo schickt die Antwort dann wiederum an uns und wir leiten diese an Sie weiter. So handhaben wir dies mit allen Suchmaschinen, welche bei uns verwendet werden können. So können wir garantieren, dass Ihre Privatsphäre gegenüber allen bei uns abgefragten Suchmaschinen gewahrt bleibt. Darüber hinaus können wir auch garantieren, dass Ihre Daten auch bei uns nicht abgespeichert werden. Dies ist sogar für die Öffentlichkeit nachvollziehbar, da der gesamte Quelltext von MetaGer unter einer freien Lizenz veröffentlicht wurde <a href="https://gitlab.metager3.de/open-source/MetaGer">(https://gitlab.metager3.de/open-source/MetaGer)</a>.', - - 'faq.4.h' => 'Warum fragt Ihr den Suchdienst XY [nicht ab | nicht mehr ab | doch ab]?', - 'faq.4.b' => 'Wenn wir einen Suchdienst nicht mehr abfragen, den wir früher dabei hatten, dann hat das entweder technische, konzeptionelle oder "politische Gründe" (die Verbindung dorthin ist zu schwach, der dortige Rechner zu klein, die Ergebnisse passen nicht richtig, dieser Suchdienst bietet z.B. keine Option für eine deutschsprachige Suche, dieser Suchdienstbetreiber "mag" uns nicht -was wir selbstverständlich respektieren müssen).', - - 'faq.6.h' => 'Fragwürdige Inhalte', - 'faq.6.b.1' => 'Ich habe "Treffer" erhalten, die finde ich nicht nur ärgerlich, sondern die enthalten meiner Meinung nach illegale Inhalte!', - 'faq.6.b.2' => 'Wenn Sie im Internet etwas finden, das Sie für illegal oder jugendgefährdend halten, dann können Sie sich per Mail an <a href="mailto:hotline@jugendschutz.net" target="_blank" rel="noopener">hotline@jugendschutz.net</a> wenden oder Sie gehen auf <a href="http://www.jugendschutz.net/" target="_blank" rel="noopener">www.jugendschutz.net</a> und füllen das dort zu findende Beschwerdeformular aus. Sinnvoll ist ein kurzer Hinweis, was Sie konkret für unzulässig halten und wie Sie auf dieses Angebot gestoßen sind. Direkt an uns können Sie fragwürdige Inhalte auch melden. Schreiben Sie dazu eine Mail an unseren Jugendschutzbeauftragten (<a href="mailto:jugendschutz@metager.de" target="_blank" rel="noopener">jugendschutz@metager.de</a>).', - - 'faq.7.h' => 'Kann ich MetaGer in meine eigene Homepage einbauen?', - 'faq.7.b' => 'Gerne! Genauere Informationen dazu finden Sie unter <a href=":widget-link" target="_blank">Widget</a>.', - - 'faq.8.h' => 'Wo kann ich bei MetaGer meine Homepage/URL/etc. Anmelden ?', - 'faq.8.b' => 'Gar nicht. MetaGer ist eine Meta-Suchmaschine. Sie sucht nicht selber, sondern lässt andere Suchdienste suchen. Wenn Sie Ihre eigenen WWW-Seiten den Suchmaschinen bekannt geben wollen, dann müssen Sie die Suchmaschinen einzeln aufsuchen, bei denen Sie Ihre Seiten anmelden wollen.', - - 'faq.9.h' => 'Wie genau funktioniert das Ranking bei MetaGer?', - 'faq.9.b' => 'Finden Sie es heraus! MetaGer ist Open-Source: <a href="https://gitlab.metager3.de/open-source/MetaGer" target="_blank">MetaGer Quellcode</a>', - - 'faq.10.h' => 'Mit meinem XYZ-Browser und dem XYZ-Betriebssystem kann ich MetaGer nicht abfragen. Was tun?', - 'faq.10.b' => 'Versuchen Sie bitte zuerst, das aktuelle Plugin zu installieren. Zum Installieren einfach auf den Link direkt unter dem Suchfeld klicken. Dort sollte Ihr Browser schon erkannt worden sein. Wenn Sie dann noch Probleme haben sollten, wenden Sie sich bitte an uns: <a href="mailto:office@suma-ev.de" target="_blank" rel="noopener">office@suma-ev.de</a>', - - 'faq.11.h' => 'Wo habt ihr eigentlich all’ die klugen Sprüche her?', - 'faq.11.b' => 'Sie sind aus Quellen im Internet zusammengesucht. Den größten Teil hatte uns netterweise Alexander Hammer zur Verfügung gestellt. Schönen Dank! Nebenbei bemerkt: Wir teilen keineswegs die inhaltliche Meinung, die in jedem Spruch zum Ausdruck kommt! Sprüche sollen und müssen kontroverses darstellen.', - - 'faq.12.h' => 'Wie kann ich die Anzeige meiner vorherigen Suchen löschen?', - 'faq.12.b' => 'Die Suchvorschläge liefert Ihnen Ihr Webbrowser, sie müssen die Suchvorschläge also auch in ihrem Browser ausschalten. Meist geht das über die Chronik. Unser Service hat damit jedoch nichts zu tun, wir können ihnen also nicht weiter helfen.', - - 'faq.13.h' => 'Wie haltet ihr es eigentlich mit dem Datenschutz, wie lange wird bei euch was gespeichert?', - 'faq.13.b.1' => 'Der Schutz persönlicher Daten ist uns so wichtig, dass wir alles, was dem zuwiderlaufen könnte, gar nicht erst machen: es gibt bei uns keine Tracking-Cookies, Session-IDs oder ähnliches. Genaueres erfahren Sie unter <a href="/datenschutz/" target="_blank" rel="noopener">Datenschutz</a>.', - 'faq.13.b.2' => 'Was es bei jeder Suchmaschine gibt (und wogegen auch wir nichts tun können), das sind die bei den Abfragen mitgesendeten IP-Adressen. Auch dies können personenbezogene Daten sein. Darum speichern wir auch diese Adressen NICHT (Ausnahme: Kurzfristige Speicherung gegen Hacking- und Bot-Attacken) - und zwar überhaupt nicht, auch nicht tageweise, und schon gar nicht für Jahre. Die IP-Adressen werden bereits während Ihre Suche noch läuft, anonymisiert und in dieser anonymen Form an die von MetaGer abgefragten Suchdienste weitergegeben. Nach unseren Erfahrungen kommt der Betrieb von Suchmaschinen sehr gut OHNE Speicherung von IP-Adressen aus. Was tun wir zusätzlich?', - 'faq.13.b.3' => 'Wenn Sie generell (unabhängig von MetaGer) ohne Speicherung Ihrer IP-Adresse im Internet surfen wollen, dann können Sie am einfachsten einen der freien und werbefinanzierten Proxies benutzen, einen kommerziellen anmieten, oder den für Sie kostenlosen MetaGer-Proxy verwenden. Genauere Informationen dazu finden Sie auf unserer Hilfeseite.', - 'faq.13.b.4' => 'Wenn Sie Ihre Anonymität noch weiter absichern wollen, dann können Sie Teilnehmer am Tor-Netzwerk werden. Genauere Informationen dazu finden Sie unter der Überschrift "Dienste".', - 'faq.13.b.5' => 'Selbstverständlich erfolgt der Zugang zu MetaGer immer automatisch nur über das verschlüsselnde https-Protokoll. Damit sind Ihre Suchabfragen auch auf dem Übertragungsweg von Ihrem PC zum MetaGer-Server sicher.', - - 'faq.14.h' => 'Über welche Wege kann eine Zuordnung zu Personen hergestellt werden?', - 'faq.14.b.1' => 'Die Zuordnung kann dann hergestellt werden, wenn sich ein Nutzer bei einem Dienst eines Anbieters (z.B. Google-Mail) persönlich angemeldet hat. Dann wird ein Cookie für diesen Anmelder gesetzt. Bei einer späteren Suche ist dann dieser Anmelder anhand des Cookies identifiziert. Es sein denn: der (schlaue) Anwender löscht den Cookie ;-) Aber die wenigsten tun das.', - 'faq.14.b.2' => 'Eine exakte Zuordnung über die IP-Adresse zur Person ist nur mit Hilfe des Providers möglich. Dies wird im Normalfall wahrscheinlich nicht geschehen. Aber es gibt weitere Indizien: auch anhand einer wechselnden IP ist ohne Mithilfe des Providers eine ungefähre geografische Zuordnung möglich.', - 'faq.14.b.3' => 'Darüber hinaus sendet der Browser weitere Daten, wie z.B. den User-Agent, dessen genaue Version und Arbeitsumgebung, das Betriebssystem und dessen exakte Version und ggf. Patch-Level. Auch mit diesen Daten ist eine Zuordnung zur Person des Anmelders, wenn dessen Daten durch die Anmeldung zu einem Dienst erst einmal bekannt sind, mit hoher Wahrscheinlichkeit möglich.', - - 'faq.15.h' => 'Wie ist MetaGer eigentlich entstanden, wie ist die Geschichte von MetaGer?', - 'faq.15.b' => 'MetaGer gibt es seit 1996, die Einzelheiten der Entstehungsgeschichte kann man hier in einem Interview nachlesen: <a href="http://blog.suma-ev.de/node/207" target="_blank" rel="noopener">http://blog.suma-ev.de/node/207</a>.', - - 'faq.16.h' => 'Darf ich MetaGer verlinken?', - 'faq.16.b' => 'Ja! Sie dürfen tausende von Links auf uns setzen! Sie dürfen das selbst dann, wenn Sie über manche Dinge des Lebens eine andere Meinung haben als wir, selbst dann, wenn Sie nicht die gleiche Partei wählen oder eine andere Meinung über die einzig richtige Art der Rechtschreibung haben. Sie dürfen Links auf alles von uns setzen, was Sie wollen. Je mehr, je besser! Noch lieber wäre es uns natürlich, wenn Sie (vielleicht im Rahmen der Verbesserung Ihrer Webseiten) unser Widget nutzen würden. Bitte schauen Sie unter dem Punkt "Dienste" nach.', - - 'faq.18.h' => 'Warum werden !bangs nicht direkt geöffnet?', - 'faq.18.b' => 'Die !bang-„Weiterleitungen“ sind bei uns ein Teil unserer Quicktips und benötigen einen zusätzlichen „Klick“. Das war für uns eine schwierige Entscheidung, da die !bang dadurch weniger nützlich sind. Jedoch ist es leider nötig, da die Links, auf die weitergeleitet wird, nicht von uns stammen, sondern von einem Drittanbieter, DuckDuckGo.<p>Wir achten stehts darauf, dass unsere Nutzer jederzeit die Kontrolle behalten. Wir schützen daher auf zwei Arten: Zum Einen wird der eingegebene Suchbegriff niemals an DuckDuckGo übertragen, sondern nur das !bang. Zum Anderen bestätigt der Nutzer den Besuch des !bang-Ziels explizit. Leider können wir derzeit aus Personalgründen nicht alle diese !bangs prüfen oder selbst pflegen.', - - 'faq.21.h' => 'Warum stellt MetaGer Umlaute falsch dar?', - 'faq.21.b' => 'Wenn die Umlaute bei MetaGer nicht richtig dargestellt werden, dann liegt es üblicherweise:<p><ul><li>An einem veralteten Plugin: Falls das bei Ihrem Browser der Fall ist:<br>Bitte deinstallieren Sie es und klicken Sie auf der <a href="https://metager.de" target="_blank">MetaGer-Startseite</a> auf „MetaGer-Plugin hinzufügen“.<li>Daran, dass nicht die offizielle <a href="https://metager.de" target="_blank">MetaGer-Startseite</a> benutzt wird, sondern eine uralt-Version „MetaGer-Klassik“ (oder eine andere uns unbekannte Version). Falls es so sein sollte:<br>Bitte benutzen Sie nur <a href="https://metager.de" target="_blank">https://metager.de</a>.</ul><p>Damit sollte alles behoben sein. Falls nicht:<br>Melden Sie sich bitte unter: <a href="mailto:office@suma-ev.de">office@suma-ev.de</a>', -]; diff --git a/resources/lang/de/hilfe.php b/resources/lang/de/hilfe.php index 3e837eed564a45c975d73652720a621f4f9adea7..94e357d79d799f6f5f1793ec64fbfa8d0ac42427 100644 --- a/resources/lang/de/hilfe.php +++ b/resources/lang/de/hilfe.php @@ -1,8 +1,8 @@ <?php return [ - "achtung" => "Achtung, da unsere Suchmaschine ständig weiterentwickelt und verbessert wird, kann es dazu kommen, dass sich immer wieder Änderungen an Aufbau und Funktion ergeben. Wir versuchen zwar die Hilfe schnellstmöglich den Änderungen entsprechend anzupassen, können jedoch nicht ausschließen, dass es zu temporären Unstimmigkeiten in Teilen der Erklärungen kommt.", - "title" => "MetaGer - Hilfe", + "achtung" => 'Achtung, da unsere Suchmaschine ständig weiterentwickelt und verbessert wird, kann es dazu kommen, dass sich immer wieder Änderungen an Aufbau und Funktion ergeben. Wir versuchen zwar die Hilfe schnellstmöglich den Änderungen entsprechend anzupassen, können jedoch nicht ausschließen, dass es zu temporären Unstimmigkeiten in Teilen der Erklärungen kommt.', + "title" => 'MetaGer - Hilfe', "searchfield.title" => 'Das Suchfeld', "searchfield.info" => 'Das Suchfeld besteht aus mehreren Teilen:', @@ -11,8 +11,8 @@ return [ "searchfield.search" => 'Der Lupe: Starten Sie die Suche.', "result.top" => 'Auf der Ergebnisseite: Klicken / drücken Sie auf das Filterzeichen, um alle Filterfunktionen benutzen zu können.', - "stopworte.title" => "Stoppworte", - "stopworte.1" => "Wenn Sie unter den MetaGer-Suchergebnissen solche ausschließen wollen, in denen bestimmte Worte (Ausschlussworte / Stopworte) vorkommen, dann erreichen Sie das, indem Sie diese Worte mit einem Minus versehen.", + "stopworte.title" => 'Stoppworte', + "stopworte.1" => "Wenn Sie unter den MetaGer-Suchergebnissen solche ausschließen wollen, in denen bestimmte Worte (Ausschlussworte / Stoppworte) vorkommen, dann erreichen Sie das, indem Sie diese Worte mit einem Minus versehen.", "stopworte.2" => "Beispiel: Sie suchen ein neues Auto, aber auf keinen Fall einen BMW. Ihre Eingabe lautet also:", "stopworte.3" => "auto neu -bmw", @@ -47,7 +47,9 @@ return [ 'urls.example.2' => '<i>meine suche</i> -url:hund', "bang.title" => "!bangs", - "bang.1" => "MetaGer unterstützt in geringem Umfang eine Schreibweise, die oft als „!bang“-Syntax bezeichnet wird.<br>Ein solches „!bang“ beginnt immer mit einem Ausrufezeichen und enthält keine Leerzeichen. Beispiele sind hier „!twitter“ oder „!facebook“.<br>Wird ein !bang, das wir unterstützen, in der Suchanfrage verwendet, erscheint in unseren Quicktips ein Eintrag, über den man die Suche auf Knopfdruck mit dem jeweiligen Dienst (hier Twitter oder Facebook) fortführen kann.<p>Warum sich unser Vorgehen hier von anderen Anbietern unterscheidet lesen Sie in <a href=\"/faq/#bangs\" target=\"_blank\" rel=\"noopener\">unseren FAQ</a>.", + "bang.1" => "MetaGer unterstützt in geringem Umfang eine Schreibweise, die oft als „!bang“-Syntax bezeichnet wird.<br>Ein solches „!bang“ beginnt immer mit einem Ausrufezeichen und enthält keine Leerzeichen. Beispiele sind hier „!twitter“ oder „!facebook“.<br>Wird ein !bang, das wir unterstützen, in der Suchanfrage verwendet, erscheint in unseren Quicktips ein Eintrag, über den man die Suche auf Knopfdruck mit dem jeweiligen Dienst (hier Twitter oder Facebook) fortführen kann.<p>Warum sich unser Vorgehen hier von anderen Anbietern unterscheidet lesen Sie in <a href=\"/hilfe/#bangs\" target=\"_blank\" rel=\"noopener\">unseren FAQ</a>.", + 'faq.18.h' => 'Warum werden !bangs nicht direkt geöffnet?', + 'faq.18.b' => 'Die !bang-„Weiterleitungen“ sind bei uns ein Teil unserer Quicktips und benötigen einen zusätzlichen „Klick“. Das war für uns eine schwierige Entscheidung, da die !bang dadurch weniger nützlich sind. Jedoch ist es leider nötig, da die Links, auf die weitergeleitet wird, nicht von uns stammen, sondern von einem Drittanbieter, DuckDuckGo.<p>Wir achten stehts darauf, dass unsere Nutzer jederzeit die Kontrolle behalten. Wir schützen daher auf zwei Arten: Zum Einen wird der eingegebene Suchbegriff niemals an DuckDuckGo übertragen, sondern nur das !bang. Zum Anderen bestätigt der Nutzer den Besuch des !bang-Ziels explizit. Leider können wir derzeit aus Personalgründen nicht alle diese !bangs prüfen oder selbst pflegen.', "searchinsearch.title" => "Suche in der Suche", "searchinsearch.1" => "Auf die Funktion der Suche in der Suche kann mit Hilfe des MEHR Knopfes rechts unten im Ergebniskasten zugegriffen werden. Beim Klick auf diesen öffnet sich ein Menü, in dem \"Ergebnis speichern\" an erster Stelle steht. Mit dieser Option wird das jeweilige Ergebnis in einem separaten Speicher abgelegt. Der Inhalt dieses Speichers wird rechts neben den Ergebnissen unter den Quicktips angezeigt (Auf zu kleinen Bildschirmen werden gespeicherte Ergebnisse aus Platzmangel nicht angezeigt). Dort können Sie die gespeicherten Ergebnisse nach Schlüsselworten filtern oder umsortieren lassen. @@ -75,8 +77,8 @@ return [ "datenschutz.faktencheck.body.1" => '<a href="http://www.password-online.de/?wysija-page=1&controller=email&action=view&email_id=280" target="_blanK" rel="noopener">Ausführliche Anleitung und Beschreibung</a> von <a href="http://www.ude.de/" target="_blanK" rel="noopener">Albrecht Ude</a>', "datenschutz.faktencheck.body.2" => '<a href="/hilfe/faktencheck">Fakten-Checkliste</a>', - "datenschutz.1" => "Tracking-Cookies, Session-IDs und IP-Adressen", - "datenschutz.2" => "Nichts von alldem wird hier bei MetaGer verwendet, gespeichert, aufgehoben oder sonst irgendwie verarbeitet (Ausnahme: Kurzfristige Speicherung gegen Hacking- und Bot-Attacken). Weil wir diese Thematik für extrem wichtig halten, haben wir auch Möglichkeiten geschaffen, die Ihnen helfen können, hier ein Höchstmaß an Sicherheit zu erreichen: den MetaGer-TOR-Hidden-Service und unseren anonymisierenden Proxyserver.", + "datenschutz.1" => 'Tracking-Cookies, Session-IDs und IP-Adressen', + "datenschutz.2" => 'Nichts von alldem wird hier bei MetaGer verwendet, gespeichert, aufgehoben oder sonst irgendwie verarbeitet (Ausnahme: Kurzfristige Speicherung gegen Hacking- und Bot-Attacken). Weil wir diese Thematik für extrem wichtig halten, haben wir auch Möglichkeiten geschaffen, die Ihnen helfen können, hier ein Höchstmaß an Sicherheit zu erreichen: den MetaGer-TOR-Hidden-Service und unseren anonymisierenden Proxyserver.', "datenschutz.3" => "Mehr Informationen finden Sie weiter unten. Die Funktionen sind unter \"Dienste\" in der Navigationsleiste erreichbar.", "tor.title" => "Tor-Hidden-Service", @@ -86,13 +88,31 @@ return [ "proxy.title" => "Anonymisierender MetaGer-Proxyserver", "proxy.1" => "Um ihn zu verwenden, müssen Sie auf der MetaGer-Ergebnisseite nur auf \"ANONYM ÖFFNEN\" am unteren Rand des Ergebnisses klicken. Dann wird Ihre Anfrage an die Zielwebseite über unseren anonymisierenden Proxy-Server geleitet und Ihre persönlichen Daten bleiben weiterhin völlig geschützt. Wichtig: wenn Sie ab dieser Stelle den Links auf den Seiten folgen, bleiben Sie durch den Proxy geschützt. Sie können aber oben im Adressfeld keine neue Adresse ansteuern. In diesem Fall verlieren Sie den Schutz. Ob Sie noch geschützt sind, sehen Sie ebenfalls im Adressfeld. Es zeigt: https://proxy.suma-ev.de/?url=hier steht die eigentlich Adresse.", - "infobutton.title" => "Was bedeutet das <i class=\"fa fa-info-circle info-details-available\" aria-hidden=\"true\"></i>, das ich an manchen Stellen sehe ?", - "infobutton.1" => "Hier können Sie mit einem Klick weitere Informationen ausklappen, zum Beispiel detaillierte Wetterdaten.", - "maps.title" => "MetaGer Maps", "maps.1" => "Die Sicherung der Privatsphäre im Zeitalter der globalen Datenkraken hat uns auch bewogen, <a href=\"https://maps.metager.de\" target=\"_blank\">https://maps.metager.de</a> zu entwickeln: Der (unseres Wissens) einzige Routenplaner, der die vollen Funktionalitäten via Browser und App bietet - ohne dass Nutzer-Standorte gespeichert werden. All dies ist nachprüfbar, denn unsere Softwaren sind Open-Source. Für die Nutzung von maps.metager.de empfehlen wir unsere schnelle App-Version. Unsere Apps können Sie unter <a href=\"https://metager.de/app\" target=\"_blank\">https://metager.de/app</a> downloaden (oder natürlich auch über den Play-Store).", "maps.2" => "Diese Kartenfunktion kann auch von der MetaGer-Suche aufgerufen werden (und umgekehrt). Sobald Sie bei MetaGer nach einem Begriff gesucht haben, sehen Sie oben rechts einen neuen Suchfokus \"Maps.metager.de\". Beim Klick darauf gelangen Sie zu einer dazugehörigen Karte. Sie können die Funktion unter Einstellungen (Zahnradsymbol) auch dauerhaft einschalten. Wenn Sie sie speichern, so erhalten Sie ab diesem Moment einen Kartenausschnitt in der MetaGer-Ergebnisliste.", "maps.3" => "Die Karte zeigt nach dem Aufrufen die auch in der Spalte rechts wiedergegebenen von MetaGer gefundenen Punkte (POIs = Points of Interest). Beim Zoomen passt sich diese Liste an den Kartenausschnitt an. Wenn Sie die Maus über eine Markierung in der Karte oder in der Liste halten, wird das jeweilige Gegenstück hervorgehoben. Klicken Sie auf \"Details\", um genauere Informationen zu diesem Punkt aus der darunter liegenden Datenbank zu erhalten.", - "maps.4" => "Die Karten sind mit Ausnahme der drei letzten Zoomstufen vorgerendert und damit schnell verfügbar. Die Zoomstufe steuern Sie mit dem Mausrad oder mit den Plus-Minus-Buttons oben links in der Karte.", - "sucheingabe" => "Sucheingabe", + + 'faq.title' => 'FAQ', + 'metager.title' => 'Allgemeines zu MetaGer', + 'metager.explanation.1' => 'MetaGer ist eine schon href="http://blog.suma-ev.de/node/207" target="_blank" rel="noopener">im Jahr 1996 gegründete</a> <strong>Suchmaschine</strong>, die Suchdienste parallel nach den von Ihnen eingegebenen Suchworten absucht und alle Ergebnisse zusammenfasst. MetaGer arbeitet die Ergebnisse sinnvoll auf. Dabei werden etwa (möglichst) alle doppelten Treffer (Doubletten) zu einem zusammengefasst. Eine vollständige Erkennung von Doubletten ist allerdings unmöglich. So etwas nennt man eine <strong>Meta-Suchmaschine</strong>. Wenn man also sinnvoll suchen will, dann muss man etliche Suchmaschinen nacheinander "von Hand" absuchen und alle Ergebnisse vergleichen und zusammenführen. Diese Arbeit kann einem ein Automat - die Metasuchmaschine – abnehmen.', + 'metager.explanation.2' => 'Dazu kommt der höhere Abdeckungsgrad, denn nicht jede Suchmaschine kennt das ganze Internet. Näheres zu Metasuchmaschinen finden Sie bei <a href="https://de.wikipedia.org/wiki/Metasuchmaschine" target="_blank" rel="noopener">Wikipedia</a>. Vielleicht genügen Ihnen die Ergebnisse, die Ihnen MetaGer präsentiert, vielleicht möchten Sie mit einer einzelnen Suchmaschine nochmals suchen. In der Ergebnisliste sehen Sie an jedem Ergebnis, woher es kam und können auch direkt klicken. Wir haben die uns zur Verfügung stehenden Suchdienste sinnvoll gruppiert und daraus die verschiedenen Suchfoki erstellt.', + + 'searchengine.title' => 'Warum können wir Suchmaschinen abfragen und trotzdem die Anonymität der Nutzer wahren?', + 'searchengine.explanation' => 'Wir als Meta-Suchmaschine stehen zwischen Ihnen und der Abfrage, die bspw. an Yahoo weiter geleitet wird. Das bedeutet, wenn Sie eine Suchabfrage abschicken, schicken sie diese Abfrage an uns. Wir entziehen dieser dann alle Informationen, welche sie identifizieren könnten und leiten eine anonyme Abfrage an Yahoo weiter. Yahoo schickt die Antwort dann wiederum an uns und wir leiten diese an Sie weiter. So handhaben wir dies mit allen Suchmaschinen, die wir abfragen. So können wir garantieren, dass Ihre Privatsphäre gegenüber allen bei uns abgefragten Suchmaschinen gewahrt bleibt. Darüber hinaus können wir auch garantieren, dass Ihre Daten auch bei uns nicht abgespeichert werden (Ausnahme: Kurzfristige Speicherung gegen Hacking- und Bot-Attacken) Genauer ersichtlich wird das in unserer <a href="/datenschutz/" target="_blank" rel="noopener">Datenschutzerklärung</a>. Dies ist sogar für die Öffentlichkeit nachvollziehbar, da der gesamte Quelltext von MetaGer unter einer freien Lizenz veröffentlicht wurde <a href="https://gitlab.metager3.de/open-source/MetaGer">(https://gitlab.metager3.de/open-source/MetaGer)</a>. Wenn Sie eine eigene Website haben, dann können Sie auf ihr auch einmal auf einfache Weise mit dem <a href=":widget-link" target="_blank">MetaGer-Widget</a> experimentieren. Sie dürfen das Widget mit Logo frei auf Ihren Webseiten verwenden und auch Links auf MetaGer.de setzen, wenn Sie wollen.', + + 'content.title' => 'Fragwürdige Inhalte / Jugendschutz', + 'content.explanation.1' => 'Ich habe "Treffer" erhalten, die finde ich nicht nur ärgerlich, sondern die enthalten meiner Meinung nach illegale Inhalte!', + 'content.explanation.2' => 'Wenn Sie im Internet etwas finden, das Sie für illegal oder jugendgefährdend halten, dann können Sie sich per Mail an <a href="mailto:hotline@jugendschutz.net" target="_blank" rel="noopener">hotline@jugendschutz.net</a> wenden oder Sie gehen auf <a href="http://www.jugendschutz.net/" target="_blank" rel="noopener">www.jugendschutz.net</a> und füllen das dort zu findende Beschwerdeformular aus. Sinnvoll ist ein kurzer Hinweis, was Sie konkret für unzulässig halten und wie Sie auf dieses Angebot gestoßen sind. Direkt an uns können Sie fragwürdige Inhalte auch melden. Schreiben Sie dazu eine Mail an unseren Jugendschutzbeauftragten (<a href="mailto:jugendschutz@metager.de" target="_blank" rel="noopener">jugendschutz@metager.de</a>).', + + 'selist.title' => 'Ich möchte MetaGer zur Suchmaschinenliste meines Browsers hinzufügen.', + 'selist.explanation.1' => 'Versuchen Sie bitte zuerst, das aktuelle Plugin zu installieren. Zum Installieren einfach auf den Link direkt unter dem Suchfeld klicken. Dort sollte Ihr Browser schon erkannt worden sein.', + 'selist.explanation.2' => 'Manche Browser erwarten die Eingabe einer URL; diese lautet "https://metager.de/meta/meta.ger3?eingabe=%s" ohne Gänsefüßchen eintragen. Die URL können Sie selbst erzeugen, wenn Sie mit metager.de nach irgendetwas suchen und dann das, was oben im Adressfeld hinter "eingabe=" steht, mit %s ersetzen. Wenn Sie dann noch Probleme haben sollten, wenden Sie sich bitte an uns: <a href="mailto:office@suma-ev.de" target="_blank" rel="noopener">office@suma-ev.de</a>', + + 'proposal.title' => 'Wie kann ich die Anzeige meiner vorherigen Suchen löschen?', + 'proposal.explanation' => 'Die Suchvorschläge liefert Ihnen Ihr Webbrowser, sie müssen die Suchvorschläge also auch in ihrem Browser ausschalten. Meist geht das über die Chronik, immer ein wenig anders, aber abschalten können Sie das in jedem Browser.', + + 'assignment.title' => 'Über welche Wege kann eine Zuordnung zu Personen hergestellt werden?', + 'assignment.explanation.1' => 'Die Zuordnung kann dann hergestellt werden, wenn sich ein Nutzer bei einem Dienst eines Anbieters (z.B. Google-Mail) persönlich angemeldet hat. Dann wird ein Cookie für diesen Anmelder gesetzt. Bei einer späteren Suche ist dann dieser Anmelder anhand des Cookies identifiziert. Löschen Sie regelmäßig Cookies von nicht vertrauenswürdigen oder unbekannten Quellen. Eine exakte Zuordnung über die IP-Adresse zur Person ist nur mit Hilfe des Providers möglich. Dies wird im Normalfall wahrscheinlich nicht geschehen. Aber es gibt weitere Indizien: auch anhand einer wechselnden IP ist ohne Mithilfe des Providers eine ungefähre geografische Zuordnung möglich.', + 'assignment.explanation.2' => 'Darüber hinaus sendet der Browser weitere Daten, wie z.B. den User-Agent, dessen genaue Version und Arbeitsumgebung, das Betriebssystem und dessen exakte Version und ggf. Patch-Level. Auch mit diesen Daten ist eine Zuordnung zur Person des Anmelders, wenn dessen Daten durch die Anmeldung zu einem Dienst erst einmal bekannt sind, mit hoher Wahrscheinlichkeit möglich.', ]; diff --git a/resources/lang/de/sidebar.php b/resources/lang/de/sidebar.php index 8f144f21d4339a86d94218cd60f0c8d83aebeef4..4bd8650fc2b560c0cb5c34a9af867f464b99d01b 100644 --- a/resources/lang/de/sidebar.php +++ b/resources/lang/de/sidebar.php @@ -1,31 +1,30 @@ <?php return [ - 'nav1' => 'Suche', - 'nav2' => 'Spenden', - 'nav3' => 'Datenschutz', - 'nav4' => 'Forum', - 'nav5' => 'Kontakt', - 'nav6' => 'Team', - 'nav7' => 'Über uns', - 'nav8' => 'Impressum', - 'nav9' => 'Hilfe', - 'nav10' => 'Widget', - 'nav11' => 'Assoziator', - 'nav14' => 'TOR-Hidden-Service', - 'nav15' => 'Dienste', - 'nav16' => 'Fördern', - 'nav17' => 'MetaGer-Fördershops', - 'nav18' => 'Kontakt', - 'nav19' => 'Sprache', - 'nav20' => 'Hilfe', - 'nav21' => 'FAQ', - 'nav22' => 'Zitatsuche', - 'nav23' => 'Mitglied werden', - 'nav24' => 'MetaGer Quellcode', - 'nav25' => 'MetaGer App', - 'nav26' => 'MetaGer-Fanshop', + 'nav1' => 'Suche', + 'nav2' => 'Spenden', + 'nav3' => 'Datenschutz', + 'nav4' => 'Forum', + 'nav5' => 'Kontakt', + 'nav6' => 'Team', + 'nav7' => 'Über uns', + 'nav8' => 'Impressum', + 'nav9' => 'Hilfe', + 'nav10' => 'Widget', + 'nav11' => 'Assoziator', + 'nav14' => 'TOR-Hidden-Service', + 'nav15' => 'Dienste', + 'nav16' => 'Fördern', + 'nav17' => 'MetaGer-Fördershops', + 'nav18' => 'Kontakt', + 'nav19' => 'Sprache', + 'nav20' => 'Hilfe', + 'nav22' => 'Zitatsuche', + 'nav23' => 'Mitglied werden', + 'nav24' => 'MetaGer Quellcode', + 'nav25' => 'MetaGer App', + 'nav26' => 'MetaGer-Fanshop', 'navigationToggle' => 'Navigation anzeigen', - 'titles.tips' => 'Tips', - 'plugin' => 'MetaGer Plugin', + 'titles.tips' => 'Tips', + 'plugin' => 'MetaGer Plugin', ]; diff --git a/resources/lang/en/faq.php b/resources/lang/en/faq.php deleted file mode 100644 index 20e3b6026634203fae7e1ce7a459a78484fa864b..0000000000000000000000000000000000000000 --- a/resources/lang/en/faq.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php - -return [ - "achtung" => "Warning! Structure and functionality of our website are subject to constant development and changes. We try to update our help pages as quickly as possible, but can not prevent temporary mistakes.", - "title" => "MetaGer - FAQ", - "faq.1.h" => "What is MetaGer?", - "faq.1.b" => "MetaGer is primarily a meta search engine. Besides that MetaGer maintains a number of specialized crawlers and indexers of its own.", - 'faq.1.b2' => 'Additionally: meta search engines provide a wider coverage and a better overview, because none of the searchengines knows the whole internet (Read more: <a href="https://de.wikipedia.org/wiki/Metasuchmaschine" target="_blank" rel="noopener">Wikipedia</a>. You see its origin attached to every single result. Where can I find more search engines? Try here: <a href="http://www.klug-suchen.de/" target="_blank" rel="noopener">klug-suchen.de</a>', - "faq.2.1.h" => "How does MetaGer query other search engines while preserving user anonymity?", - "faq.2.1.b" => "Since MetaGer is a meta-search engine, every search request you send to us will be stripped of information which could lead to your identification before being sent to e.g. Yahoo. Yahoo will send their response to us which we will then forward to you. This is how we handle every search request sent to us, no matter which one of the offered search engines you use. By doing this we commit ourselves to guarantee your privacy and do not save any personal data. It is possible to verify this, since the source code of MetaGer has been released under a free license <a href=\"https://gitlab.metager3.de/open-source/MetaGer\">(https://gitlab.metager3.de/open-source/MetaGer)</a>.", - "faq.4.h" => "Why don't you metacrawl search engine XY anymore?", - "faq.4.b" => "If we do not query a search engine which we did query before, then this has technical or \\\"political\\\" reasons.", - - "faq.6.h" => "Inappropriate Content", - "faq.6.b.1" => "I found results with illegal content.", - "faq.6.b.2" => "If some content (found by MetaGer) seems to be illegal, please email us to <a href=\\\"mailto:jugendschutz@metager.de\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">jugendschutz@metager.de</a>.", - "faq.7.h" => "Is it possible to integrate MetaGer into my own website?", - "faq.7.b" => "No problem! We have a <a href=\\\"/en/widget\\\" target=_blank>widget</a> that you can use free of charge.", - "faq.8.h" => "How can I register my homepage on MetaGer?", - "faq.8.b" => "You can't. MetaGer is a metasearch engine. If you want to propagate your website, you have to register at all the other search engines for that purpose.", - "faq.9.h" => "How does the MetaGer ranking work?", - "faq.9.b" => "You can check <a href=\\\"https://gitlab.metager3.de/open-source/MetaGer\\\" target=_blank>our source code</a> to find out.", - "faq.10.h" => "I can't use MetaGer with my browser X and operating system Y. I need help!", - "faq.10.b" => "Please try first to install the newest available plugin. Just use the link below the searchfield, it has an automatic browserdetection. If it is still not working, please let us know: <a href=\\\"mailto:office@suma-ev.de\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">office@suma-ev.de</a>", - "faq.11.h" => "Where did you get all these nice sayings?", - "faq.11.b" => "We find some in the web but we've got the most of them from Alexander Hammer. We don't provide them in english....", - "faq.12.h" => "How can I delete the search suggestions?", - "faq.12.b" => "This is provided by your webbrowser. Try to customize the history settings.", - "faq.13.h" => "What is about the privacy and how long / what do you store?", - "faq.13.b.1" => "The protection of private data is our general principle. Everything we do is subordinated to this principle. Therefore we do not work with tracking-ookies, Session IDs or anything else. More exact information: <a href=\\\"/datenschutz/\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">https://metager.de/en/datenschutz/</a>", - "faq.13.b.2" => "Besides: we do not store and we do not even know your IP-address (For the purpose of securing our servers against Hacking- and Bot-Attacks, we need to store these information for a short period of time. It will be then automatically deleted afterwards). We use serversided anonymization for the communication with the prompted search services. We think that searchengines work well without storing IP-addresses. What do we do additionally?", - "faq.13.b.3" => "You may wish to hide your IP-address generally. We provide a free proxyservice. Click \\\"Help\\\" for more exact information: ", - "faq.13.b.4" => "Please use the Tor-network or the MetaGer Tor-branch for advanced anonymization. Please click \\\"Tools\\\" for further information.", - "faq.13.b.5" => "Needless to say: we use the https protocol at any time. All your queries are safe between your personal computer and the MetaGer servers.", - "faq.14.h" => "How can one match data to indviduals ?", - "faq.14.b.1" => "1.) This could be done by using cookies. For example a cookie can be set as a part of making an account. You give your data, a cookie is made out of it and is stored on your PC. Next time using the same service it will know you very well. This kind of data is managed by the webbrowser. It is easy to find and erase all cookies. You should do this routinely.", - "faq.14.b.2" => "2.) The webproviders manage internet connections by assigning IP-addresses to individuals. This is ruled by law and is different in all countries.", - "faq.14.b.3" => "3.) The webbrowser sends a heap of data to a website, like the user agent, exact version numbers, the work invironment, the operating system and so on. Maybe there is a matching of data to individuals possible, too.", - "faq.15.h" => "How was MetaGer started, what is the story behind MetaGer?", - "faq.15.b" => "It was started in 1996. Take a look at the historically documented origin story here: <a href=\\\"http://blog.suma-ev.de/node/207\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\">http://blog.suma-ev.de/node/207</a>.", - "faq.16.h" => "Is it allowed to hyperlink MetaGer ?", - "faq.16.b" => "Yes, sure. You can do this as you like. This refers to all pages of our site. But: we would like it more if you would use our widget (for the improvement of your own website). See \\\"Tools\\\".", - "faq.18.h" => "Why are the !bangs not opended directly?", - "faq.18.b" => "The !bang -\\\"redirections\\\" are part of our quicktips and they need an additional click. We had to decide between easy-to-use and keep-control-of-data. We find it necessary to show that the links are third party property (DuckDuckGo). So there is a two way protection: first we do not transfer your searchwords but only the !bang to DuckDuckGo. On the other hand the user confirms the !bang-target explicit. We don't have the ressources to maintain all this !bangs, we are sorry.", - "faq.21.h" => "Why is MetaGer presenting the umlauts in a wrong way?", - "faq.21.b" => "A wrong presentation of umlauts is commonly caused by an outdated Plugin. If so: please deinstall the old one an then click \\\"Add MetaGer-Plugin\\\" on <a href=\\\"https://metager.de\\\" target=\\\"_blank\\\">MetaGer-Startpage</a>. Perhaps, there is another reason: you didn't use the correct startpage. Always use <a href=\\\"https://metager.de\\\" target=\\\"_blank\\\">MetaGer.de</a>.\\r\\nIf all this doesn't work, please contact us: <a href=\\\"mailto:office@suma-ev.de\\\">office@suma-ev.de</a>", -]; diff --git a/resources/lang/en/hilfe.php b/resources/lang/en/hilfe.php index 52fd274ce5de52c910b399c1f158a856c40711da..ca0c8e0052bf842adf8f46af983399a88055df81 100644 --- a/resources/lang/en/hilfe.php +++ b/resources/lang/en/hilfe.php @@ -47,7 +47,9 @@ return [ "urls.example.2" => "Type <i>my search words</i> -url:dog", "bang.title" => "!bangs", - "bang.1" => "MetaGer uses a little a special spelling called \"!bang syntax\". A !bang starts with the \"!\" and doesn't contain blanks (\"!twitter\", \"!facebook\" for example). If you use a !bang supported by MetaGer you will see a new entry in the \"Quicktips\". We direct then to the specified service (click the button). Read more about our method departing from others: <a href=\"/faq/#bangs\" target=\"_blank\" rel=\"noopener\"> FAQ</a>", + "bang.1" => "MetaGer uses a little a special spelling called \"!bang syntax\". A !bang starts with the \"!\" and doesn't contain blanks (\"!twitter\", \"!facebook\" for example). If you use a !bang supported by MetaGer you will see a new entry in the \"Quicktips\". We direct then to the specified service (click the button). Read more about our method departing from others: <a href=\"/en/hilfe/#bangs\" target=\"_blank\" rel=\"noopener\"> FAQ</a>", + "faq.18.h" => "Why are the !bangs not opended directly?", + "faq.18.b" => "The !bang -\\\"redirections\\\" are part of our quicktips and they need an additional click. We had to decide between easy-to-use and keep-control-of-data. We find it necessary to show that the links are third party property (DuckDuckGo). So there is a two way protection: first we do not transfer your searchwords but only the !bang to DuckDuckGo. On the other hand the user confirms the !bang-target explicit. We don't have the ressources to maintain all this !bangs, we are sorry.", "searchinsearch.title" => "Search in search", "searchinsearch.1" => "The result will be stored in a new TAB appearing at the right side of the screen. It is called \"Saved results\". You can store here single results from several searches. The TAB persists. Entering this TAB you get your personal result list with tools to filter and sort the results. Click another TAB to go back for further searches. You won´t have this if the screen is too small. More info (only german so far): <a href=\"http://blog.suma-ev.de/node/225\" target=\"_blank\" rel=\"noopener\"> http://blog.suma-ev.de/node/225</a>.", @@ -85,11 +87,32 @@ return [ "proxy.title" => "MetaGer proxy server", "proxy.1" => "Looking at the MetaGer result page, you will find a link \"open anonymously\" marked by a small lock at the right of every single result. Use this link to hide behind the MetaGer proxy server. The provided protection is limited to the website you reached from our result page. Protection persists while you see https://proxy.suma-ev.de/?url=...in your webbrowser‘s address field.", - "infobutton.title" => "I see a <i class=\"fa fa-info-circle info-details-available\" aria-hidden=\"true\"></i> in some spots. What is it?", - "infobutton.1" => "You gain more information on the specific theme by clicking it (e.g. weather data or something).", - "maps.title" => "MetaGer maps", "maps.1" => "MetaGer provides a map function: On a result page you see a new focus on the upper right, called \"maps.MetaGer.de\". You receive a map according to your search by click. Use the \"customize\" page for toggling maps function \"show/hide\", you will get a durably embedded small map on the result page, then.", "maps.2" => "After loading the map shows POIs according to the MetaGer results. You see them in the right column too. Mouseover a POI highlights its counterpart. Click \"Details\" to get further information (Nominatim data base) to this POI.", "maps.3" => "The maps are rendered before (except for the last three ones) and fast available. Affect the zoom level by mouse-wheel or the \"+ / -\" buttons in the upper left corner of the map.", + + 'faq.title' => 'FAQ', + + 'metager.title' => 'MetaGer - General remarks', + 'metager.explanation.1' => 'MetaGer is primarily a meta search engine (founded in 1996). Besides that MetaGer maintains a number of specialized crawlers and indexers of its own.', + 'metager.explanation.2' => 'Additionally: meta search engines provide a wider coverage and a better overview, because none of the searchengines knows the whole internet (Read more: <a href="https://en.wikipedia.org/wiki/Metasearch_engine" target="_blank" rel="noopener">Wikipedia</a>. Every result shows its origin in the right top corner. You may try this specific search engine to look for further results. We have grouped all available search services to several search focuses.', + + 'searchengine.title' => 'How does MetaGer query other search engines while preserving user anonymity?', + 'searchengine.explanation' => 'Since MetaGer is a meta-search engine, every search request you send to us will be stripped of information which could lead to your identification before being sent to e.g. Yahoo. Yahoo will send their response to us which we will then forward to you. This is how we handle every search request sent to us, no matter which one of the offered search engines you use. By doing this we commit ourselves to guarantee your privacy and do not save any personal data. It is possible to verify this, since the source code of MetaGer has been released under a free license <a href=\"https://gitlab.metager3.de/open-source/MetaGer\">(https://gitlab.metager3.de/open-source/MetaGer)</a>. If you have your own website you could try and find out how our <a href=":widget-link" target="_blank">MetaGer-Widget</a> works. You are also free to create links to our search engine.', + + 'content.title' => 'Inappropriate Content / youth protection', + 'content.explanation.1' => 'I found results with illegal content.', + 'content.explanation.2' => 'If some content (presented by MetaGer) seems to be illegal, please email us to <a href="mailto:jugendschutz@metager.de" target="_blank" rel="noopener">jugendschutz@metager.de</a>.', + + 'selist.title' => 'I want to add metager.de to the search engines list of my browser.', + 'selist.explanation.1' => 'Please try first to install the newest available plugin. Just use the link below the searchfield, it has an automatic browserdetection.', + 'selist.explanation.2' => 'Some browser need an URL. Please use "https://metager.de/meta/meta.ger3?eingabe=%s" without qoutation marks. If there are still problems, please <a href="mailto:office@suma-ev.de" target="_blank" rel="noopener">write an email.</a>', + + 'proposal.title' => 'How can I delete the search suggestions?', + 'proposal.explanation' => 'This is provided by your webbrowser. Try to customize the history settings.', + + 'assignment.title' => 'How can one match data to indviduals ?', + 'assignment.explanation.1' => 'This could be done by cookies. For example a cookie can be set as a part of making an account. You give your data, a cookie is made out of it and is stored on your PC. Next time using the same service it will know you very well. This kind of data is managed by the webbrowser. It is easy to find and erase all cookies from unknown or not confidable origins. You should do this routinely.', + 'assignment.explanation.2' => 'The webbrowser sends a heap of data to a website, like the user agent, exact version numbers, the work invironment, the operating system and so on. Maybe there is a matching of data to individuals possible, too.', ]; diff --git a/resources/lang/en/key.php b/resources/lang/en/key.php index 6f65d1bf22b8e540116b686d683e95bbccf5d80e..a76348a5844f1881900c6cbe12e4f17a9ece0fac 100644 --- a/resources/lang/en/key.php +++ b/resources/lang/en/key.php @@ -2,12 +2,12 @@ return [ 'h1' => "Key for your ad-free search", - 'p1' => 'MetaGer offers <a href=":url1">SUMA-EV members</a> and generous <a href=":url2">donors</a> a key that allows the search engine to be used completely ad-free.', + 'p1' => 'MetaGer offers <a href=":url1">SUMA-EV members</a> and generous <a href=":url2">donors</a> a key that allows to use the search engine completely ad-free.', 'p2' => 'On this page you can enter your key (if known). We save it with the help of a cookie on your PC. This way, your browser automatically sends the key to us every time you search, so we can remove the ad for you.', 'p3' => 'If you look at the cookie there is "key = xxxx" in there. We do not use it for tracking purposes. It is also never stored or logged by us in any way.', 'p4' => 'Important: In order to use this function, you must have allowed cookies in your browser. The setting will remain saved as long as your browser saves cookies.', - 'placeholder1' => 'Enter key ...', - 'removeKey' => 'remove current key', - 'invalidKey' => 'The entered key is invalid', - 'backLink' => 'Back to the last page', + 'placeholder1' => 'Enter key ...', + 'removeKey' => 'Remove current key', + 'invalidKey' => 'The entered key is invalid', + 'backLink' => 'Back to the last page', ]; diff --git a/resources/lang/en/result.php b/resources/lang/en/result.php index 65b25b2c682b32fbb228964f4c6d7f74cab54d7a..407f98ed17ecc938418ffe4b2c6a140a6d683b00 100644 --- a/resources/lang/en/result.php +++ b/resources/lang/en/result.php @@ -11,5 +11,7 @@ return [ 'options.6' => 'OPEN IN NEW TAB', 'options.7' => 'OPEN', 'options.more' => 'MORE', - 'proxytext' => 'Result link is opened anonymously. Your data will not be transfered to destination servers. Some links may not work as usual.' + 'options.less' => 'LESS', + 'gefVon' => 'by', + 'proxytext' => 'Result link is opened anonymously. Your data will not be transferred to destination servers. Some webpages may not work as usual.' ]; \ No newline at end of file diff --git a/resources/lang/en/sidebar.php b/resources/lang/en/sidebar.php index 11e6290be0119299d2a99796a5ea922c7ae1b0ac..7641fac3220493ace9c57855ba754e6156d4dac9 100644 --- a/resources/lang/en/sidebar.php +++ b/resources/lang/en/sidebar.php @@ -19,7 +19,6 @@ return [ "nav18" => "Contact", "nav19" => "Language", "nav20" => "Help", - "nav21" => "FAQ", "nav22" => "Citation Search", "nav23" => "Become a member", "nav24" => "MetaGer source code", diff --git a/resources/lang/es/sidebar.php b/resources/lang/es/sidebar.php index 92d4f47245f7651001fd9314842841d03c29a525..6ccd3ad6c42b009c8583c61654cc804876bdb7dc 100644 --- a/resources/lang/es/sidebar.php +++ b/resources/lang/es/sidebar.php @@ -1,28 +1,27 @@ <?php return [ - "nav1" => "Búsqueda", - "nav2" => "Donaciones", - "nav3" => "Protección de datos", - "nav4" => "Foro", - "nav5" => "Contacto", - "nav6" => "Equipo", - "nav7" => "Sobre nosotros", - "nav8" => "Aviso legal", - "nav9" => "Ayuda", - "nav10" => "Widget", - "nav11" => "Asociador", - "nav14" => "TOR-Hidden-Service", - "nav15" => "Servicios", - "nav16" => "Patrocinar", - "nav17" => "Comprar en tiendas que patrocinan a MetaGer", - "nav18" => "Contacto", - "nav19" => "Idioma", - "nav20" => "Ayuda", - "nav21" => "FAQ", - "nav22" => "Búsqueda de citas", - "nav23" => "Formulario de afiliación SUMA-EV", - "nav24" => "Codigo fuente MetaGer", - "nav25" => "MetaGer App", + "nav1" => "Búsqueda", + "nav2" => "Donaciones", + "nav3" => "Protección de datos", + "nav4" => "Foro", + "nav5" => "Contacto", + "nav6" => "Equipo", + "nav7" => "Sobre nosotros", + "nav8" => "Aviso legal", + "nav9" => "Ayuda", + "nav10" => "Widget", + "nav11" => "Asociador", + "nav14" => "TOR-Hidden-Service", + "nav15" => "Servicios", + "nav16" => "Patrocinar", + "nav17" => "Comprar en tiendas que patrocinan a MetaGer", + "nav18" => "Contacto", + "nav19" => "Idioma", + "nav20" => "Ayuda", + "nav22" => "Búsqueda de citas", + "nav23" => "Formulario de afiliación SUMA-EV", + "nav24" => "Codigo fuente MetaGer", + "nav25" => "MetaGer App", "navigationToggle" => "Mostrar navegación", ]; diff --git a/resources/less/metager/pages/resultpage/result.less b/resources/less/metager/pages/resultpage/result.less index 2b7df531d0a8dd4f5d2d649bc8f4c6a3d5e87fdb..2f5e720cdac6a4278cc29b598f88ff25a8aca3fa 100644 --- a/resources/less/metager/pages/resultpage/result.less +++ b/resources/less/metager/pages/resultpage/result.less @@ -19,8 +19,8 @@ padding: 0px 8px; width: 100%; .result-header { - display: flex; - flex-wrap: wrap; + max-width: 100%; + overflow: hidden; .result-headline { width: 100%; display: flex; @@ -103,6 +103,7 @@ } .result-body { margin-top: 1px; + max-width:100%; display: flex; text-align: justify; .result-image { @@ -145,6 +146,7 @@ } .result-footer { margin-top: 2px; + max-width: 100%; display: flex; flex-wrap: wrap; &>* { @@ -230,6 +232,7 @@ color: #777; } &>.result-options { + max-width: 100%; &>.options { font-size: @result-font-small; border-top: 1px solid #ccc; diff --git a/resources/views/faq.blade.php b/resources/views/faq.blade.php deleted file mode 100644 index 5afbcac84f6e49e7eb61d5fecf47c06e254cecde..0000000000000000000000000000000000000000 --- a/resources/views/faq.blade.php +++ /dev/null @@ -1,144 +0,0 @@ -@extends('layouts.subPages', ['page' => 'faq']) - -@section('title', $title ) - -@section('content') - <div class="alert alert-warning" role="alert">{!! trans('faq.achtung') !!}</div> - <h1 class="page-title">{!! trans('faq.title') !!}</h1> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.1.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.1.b') !!}</p> - <p>{!! trans('faq.faq.1.b2') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.2.1.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.2.1.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.4.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.4.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.6.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.6.b.1') !!}</p> - <p>{!! trans('faq.faq.6.b.2') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.7.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.7.b', ["widget-link" => LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), "widget") ]) !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.8.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.8.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.9.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.9.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.10.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.10.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.11.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.11.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.12.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.12.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.13.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.13.b.1') !!}</p> - <p>{!! trans('faq.faq.13.b.2') !!}</p> - <p>{!! trans('faq.faq.13.b.3') !!}</p> - <p>{!! trans('faq.faq.13.b.4') !!}</p> - <p>{!! trans('faq.faq.13.b.5') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.14.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.14.b.1') !!}</p> - <p>{!! trans('faq.faq.14.b.2') !!}</p> - <p>{!! trans('faq.faq.14.b.3') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.15.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.15.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.16.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.16.b') !!}</p> - </div> - </section> - <section id="bangs"> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.18.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.18.b') !!}</p> - </div> - </section> - <section> - <div class="panel-heading"> - <h3>{!! trans('faq.faq.21.h') !!}</h3> - </div> - <div class="panel-body"> - <p>{!! trans('faq.faq.21.b') !!}</p> - </div> - </section> -@endsection diff --git a/resources/views/hilfe.blade.php b/resources/views/hilfe.blade.php index fc4686aac4c12bd50670b4702e43c2b871dc6394..5f516bbcb9a1806ddec4b2d106ff39174b6febe3 100644 --- a/resources/views/hilfe.blade.php +++ b/resources/views/hilfe.blade.php @@ -85,7 +85,7 @@ </ul> </div> </section> - <section> + <section id="bangs"> <h3>{!! trans('hilfe.bang.title') !!}</h3> <div> <p>{!! trans('hilfe.bang.1') !!}</p> @@ -155,12 +155,7 @@ <p>{!! trans('hilfe.proxy.1') !!}</p> </div> </section> - <section> - <h3>{!! trans('hilfe.infobutton.title') !!}</h3> - <div> - <p>{!! trans('hilfe.infobutton.1') !!}</p> - </div> - </section> + <section> <h3>{!! trans('hilfe.maps.title') !!}</h3> <div> @@ -169,4 +164,34 @@ <p>{!! trans('hilfe.maps.3') !!}</p> </div> </section> + <h2>{!! trans('hilfe.faq.title') !!}</h2> + <section> + <h3>{!! trans('hilfe.metager.title') !!}</h3> + <p>{!! trans('hilfe.metager.explanation.1') !!}</p> + <p>{!! trans('hilfe.metager.explanation.2') !!}</p> + </section> + <section> + <h3>{!! trans('hilfe.searchengine.title') !!}</h3> + <p>{!! trans('hilfe.searchengine.explanation') !!}</p> + </section> + <section> + <h3>{!! trans('hilfe.content.title') !!}</h3> + <p>{!! trans('hilfe.content.explanation.1') !!}</p> + <p>{!! trans('hilfe.content.explanation.2') !!}</p> + </section> + <section> + <h3>{!! trans('hilfe.selist.title') !!}</h3> + <p>{!! trans('hilfe.selist.explanation.1') !!}</p> + <p>{!! trans('hilfe.selist.explanation.2') !!}</p> + </section> + <section> + <h3>{!! trans('hilfe.proposal.title') !!}</h3> + <p>{!! trans('hilfe.proposal.explanation') !!}</p> + </section> + <section> + <h3>{!! trans('hilfe.assignment.title') !!}</h3> + <p>{!! trans('hilfe.assignment.explanation.1') !!}</p> + <p>{!! trans('hilfe.assignment.explanation.2') !!}</p> + </section> + @endsection diff --git a/resources/views/layouts/image_result.blade.php b/resources/views/layouts/image_result.blade.php new file mode 100644 index 0000000000000000000000000000000000000000..01c48941306fc8cd8947e66de1bd64a52cdbf5d5 --- /dev/null +++ b/resources/views/layouts/image_result.blade.php @@ -0,0 +1,8 @@ +<div class="image"> + <a href="{{ $result->link }}" target="_blank"> + <div title="{{ $result->titel }}"> + <img src="{{ $metager->getImageProxyLink($result->image)}}" alt="{{ $result->titel }}"/> + <div>{{ $result->gefVon }}</div> + </div> + </a> +</div> diff --git a/resources/views/layouts/result.blade.php b/resources/views/layouts/result.blade.php index a8f0eb2da387b305580d694f661d4bfa2ff4616e..347fb056b5a98dbf12a68c25ab96601faaadfd28 100644 --- a/resources/views/layouts/result.blade.php +++ b/resources/views/layouts/result.blade.php @@ -1,4 +1,4 @@ -<div class="result" data-count="{{ $result->number }}"> +<div class="result" data-count="{{ $result->hash }}"> <div class="result-header"> <div class="result-headline"> <h2 class="result-title" title="{{ $result->titel }}"> @@ -47,7 +47,7 @@ </div> @endif </div> - <input type="checkbox" id="result-toggle-{{$result->number}}" class="result-toggle" style="display: none"> + <input type="checkbox" id="result-toggle-{{$result->hash}}" class="result-toggle" style="display: none"> <div class="result-footer"> <a class="result-open" href="{{ $result->link }}" target="_self" rel="noopener"> {!! trans('result.options.7') !!} @@ -58,10 +58,10 @@ <a class="result-open-proxy" onmouseover="$(this).popover('show');" onmouseout="$(this).popover('hide');" data-toggle="popover" data-placement="auto right" data-container="body" data-content="@lang('result.proxytext')" href="{{ $result->proxyLink }}" target="{{ $metager->getNewtab() }}" rel="noopener"> {!! trans('result.options.5') !!} </a> - <label class="open-result-options navigation-element" for="result-toggle-{{$result->number}}"> + <label class="open-result-options navigation-element" for="result-toggle-{{$result->hash}}"> {{ trans('result.options.more')}} </label> - <label class="close-result-options navigation-element" for="result-toggle-{{$result->number}}"> + <label class="close-result-options navigation-element" for="result-toggle-{{$result->hash}}"> {{ trans('result.options.less')}} </label> </div> @@ -69,7 +69,7 @@ <div class="options"> <ul class="option-list list-unstyled small"> <li class="js-only"> - <a href="javascript:resultSaver({{ $result->number }});" class="saver"> + <a href="javascript:resultSaver("{{ $result->hash }}");" class="saver"> <nobr><i class="fa fa-floppy-o"></i> {!! trans('result.options.savetab') !!}</nobr> </a> </li> diff --git a/resources/views/layouts/resultPage.blade.php b/resources/views/layouts/resultPage.blade.php index 00a2cd2070d41d4b6882e7e3b3b2a75e7089e409..3450762bae67b736997cfbf7b656ff55076fa721 100644 --- a/resources/views/layouts/resultPage.blade.php +++ b/resources/views/layouts/resultPage.blade.php @@ -11,6 +11,7 @@ <meta name="l" content="{{ LaravelLocalization::getCurrentLocale() }}" /> <meta name="mm" content="{{ $metager->getVerificationId() }}" /> <meta name="mn" content="{{ $metager->getVerificationCount() }}" /> + <meta name="searchkey" content="{{ $metager->getSearchUid() }}" /> <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()))])) }}"> <link type="text/css" rel="stylesheet" href="{{ mix('css/fontawesome.css') }}" /> <link type="text/css" rel="stylesheet" href="{{ mix('css/fontawesome-solid.css') }}" /> diff --git a/resources/views/parts/errors.blade.php b/resources/views/parts/errors.blade.php index f40b8b0ef270f70b8e273adad4d8abbe7449deac..cdd23071526943ee0aea6815e7bb1d30127129e6 100644 --- a/resources/views/parts/errors.blade.php +++ b/resources/views/parts/errors.blade.php @@ -3,7 +3,7 @@ <div class="alert alert-danger"> <ul> @foreach($errors as $error) - <li>{!! $error !!}</li> + <li @if($error === trans('metaGer.results.failed')) class="no-results-error" @endif>{!! $error !!}</li> @endforeach </ul> </div> diff --git a/resources/views/parts/pager.blade.php b/resources/views/parts/pager.blade.php index 5dd39e50ccdae4cbe1c5779cd1983ffb0a20f42f..5bb3011ca9911019820cf0c06f4c652da82320c9 100644 --- a/resources/views/parts/pager.blade.php +++ b/resources/views/parts/pager.blade.php @@ -3,7 +3,7 @@ <div @if($metager->getPage() === 1) class="disabled" @endif> <a @if($metager->getPage() !== 1) href="javascript:history.back()" @endif>{{ trans('results.zurueck') }}</a> </div> - <div @if($metager->nextSearchLink() === "#") class="disabled" @endif> + <div id="next-search-link" @if($metager->nextSearchLink() === "#") class="disabled" @endif> <a @if($metager->nextSearchLink() !== "#") href="{{ $metager->nextSearchLink() }}" @endif>{{ trans('results.weiter') }}</a> </div> -</nav> \ No newline at end of file +</nav> diff --git a/resources/views/parts/sidebar.blade.php b/resources/views/parts/sidebar.blade.php index 32198d127be4422b7d445b705893142cf7329074..5b7132d7e84e6dbb5032cede158b9adc371b4b71 100644 --- a/resources/views/parts/sidebar.blade.php +++ b/resources/views/parts/sidebar.blade.php @@ -17,19 +17,12 @@ <span>{{ trans('sidebar.nav3') }}</span> </a> </li> - <hr> <li> <a href="{{ LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), "/hilfe/") }}" > <i class="fa fa-info" aria-hidden="true"></i> <span>{{ trans('sidebar.nav20') }}</span> </a> </li> - <li> - <a href="{{ LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), "/faq/") }}" > - <i class="fa fa-question" aria-hidden="true"></i> - <span>{{ trans('sidebar.nav21') }}</span> - </a> - </li> <hr> <li> <a href="{{ LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), "/spende/") }}" > diff --git a/resources/views/resultpages/results.blade.php b/resources/views/resultpages/results.blade.php index e9e717e563763926b7577a6e060a484c737c05c7..8b242029225455afe9dbd2f59015fd5c841efb84 100644 --- a/resources/views/resultpages/results.blade.php +++ b/resources/views/resultpages/results.blade.php @@ -7,17 +7,17 @@ @endfor @endif {{-- Create results and ongoing ads --}} - @foreach($metager->getResults() as $result) + @foreach($metager->getResults() as $index => $result) @if($mobile) - @if($result->number % 4 === 0) + @if($index % 4 === 0) @include('layouts.ad', ['ad' => $metager->popAd()]) @endif @else - @if($result->number % 7 === 0) + @if($index % 7 === 0) @include('layouts.ad', ['ad' => $metager->popAd()]) @endif @endif @include('layouts.result', ['result' => $result]) @endforeach @include('parts.pager') -</div> \ No newline at end of file +</div> diff --git a/resources/views/resultpages/results_images.blade.php b/resources/views/resultpages/results_images.blade.php index 2eedcf6514223f165c186a0007be622ae736f28d..78c4338e50f380dc92ed1404171970bae5e2dbc9 100644 --- a/resources/views/resultpages/results_images.blade.php +++ b/resources/views/resultpages/results_images.blade.php @@ -1,15 +1,6 @@ -@include('parts.errors') -@include('parts.warnings') <div id="container" class="image-container"> @foreach($metager->getResults() as $result) - <div class="image"> - <a href="{{ $result->link }}" target="_blank"> - <div title="{{ $result->titel }}"> - <img src="{{ $metager->getImageProxyLink($result->image)}}" alt="{{ $result->titel }}"/> - <div>{{ $result->gefVon }}</div> - </div> - </a> - </div> + @include('layouts.image_result', ['result' => $result]) @endforeach </div> @include('parts.pager') diff --git a/routes/web.php b/routes/web.php index 913101e1db25268d425378ba067d2976a13ea8e3..f3a25d0c1b139309dd80593b11f537a1dd814617 100644 --- a/routes/web.php +++ b/routes/web.php @@ -118,9 +118,7 @@ Route::group( }); Route::get('faq', function () { - return view('faq') - ->with('title', trans('titles.faq')) - ->with('navbarFocus', 'hilfe'); + return redirect(LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), '/hilfe')); }); Route::get('widget', function () { @@ -179,6 +177,7 @@ Route::group( Route::get('settings', 'StartpageController@loadSettings'); Route::match(['get', 'post'], 'meta/meta.ger3', 'MetaGerSearch@search')->middleware('humanverification'); + Route::get('meta/loadMore', 'MetaGerSearch@loadMore'); Route::post('img/cat.jpg', 'HumanVerification@remove'); Route::get('r/metager/{mm}/{pw}/{url}', ['as' => 'humanverification', 'uses' => 'HumanVerification@removeGet']); Route::post('img/dog.jpg', 'HumanVerification@whitelist');