Просмотр исходного кода

Version 1.3

- [fix] Image search crawler filters out non-image results better
- [new] Crawler for results from magnetdl.com
- [new] Direct Reddit.com search, search for 'Top Posts' created in the past year
- [new] Added NSFW filter for Reddit results in config.default.php
- [new] YTS movie highlights now link to YTS website when clicking the title
- [new] Placeholder image for missing eztv highlight thumbnails
- [tweak] Better hash matching for duplicate magnet results
- [tweak] Better checking for missing/empty values in image search results
- [tweak] Code cleanup
- [tweak] More uniform code/variable names
- [change] Naming overhaul - Replaced 'Torrent' with 'Magnet' throughout most of Goosle
Arnan de Gans 1 год назад
Родитель
Сommit
aab57e1be0

+ 0 - 0
assets/images/torrent.png → assets/images/magnet.png


+ 10 - 7
config.default.php

@@ -44,8 +44,8 @@ CACHE_TIME:
 ENABLE IMAGE SEARCH:
 	Enable or disable image searches - Search results are provided by Yahoo! Images.
 
-ENABLE TORRENT SEARCH:
-	Enable or disable searching for torrent downloads.
+ENABLE MAGNET SEARCH:
+	Enable or disable searching for magnet links on torrent websites.
 
 ENABLE SEARCH ENGINES:
 	Enable or disable search engines.
@@ -99,11 +99,11 @@ YTS HIGHLIGHT:
 	"download_count" = Most downloaded movies.
 
 BLOCK 1337x CATEGORIES:
-	Add category IDs of 1337x categories, check /engines/torrent/1337x.php for a list of known categories.
+	Add category IDs of 1337x categories, check /engines/magnet/1337x.php for a list of known categories.
 	Accepts a basic numeric array, comma separated.
 
 BLOCK PIRATEBAY CATEGORIES:
-	Add category IDs of Pirate Bay categories, check /engines/torrent/thepiratebay.php for a list of known categories.
+	Add category IDs of Pirate Bay categories, check /engines/magnet/thepiratebay.php for a list of known categories.
 	Accepts a basic numeric array, comma separated.
 
 BLOCK YTS CATEGORIES:
@@ -123,7 +123,7 @@ USER AGENTS:
 	Opera/Edge/Brave and many others use Chrome under the hood and are not a good pick for that reason.
 	Mobile agents may work, but some services like Wikipedia are a bit picky when it comes to answering API calls. Mobile users generally do not use APIs, so they may block your search.
 
-TORRENT TRACKERS:
+MAGNET TRACKERS:
 	Only used for The Pirate Bay, LimeTorrents and YTS.
 	Generally you do not need to change these.
 	These are added to the magnet links Goosle creates. You can add more or replace the existing ones if you know what you're doing.
@@ -138,9 +138,10 @@ return (object) array(
     "cache_time" => 30, // Default: 30 (Minutes)
 
     "enable_image_search" => "on", // Default: on
-    "enable_torrent_search" => "on", // Default: on
+    "enable_magnet_search" => "on", // Default: on
     "enable_duckduckgo" => "on", // Default: on
     "enable_google" => "on", // Default: on
+    "enable_reddit" => "on", // Default: on
     "enable_wikipedia" => "on", // Default: on
     "enable_ecosia" => "off", // Default: on	
     	// Site uses some kind of bot detector preventing crawler from working reliably since Feb 1, 2024, remove support in future release?)
@@ -148,6 +149,7 @@ return (object) array(
     "enable_limetorrents" => "on", // Default: on
     "enable_piratebay" => "on", // Default: on
     "enable_yts" => "on", // Default: on
+    "enable_magnetdl" => "on", // Default: on	
     "enable_nyaa" => "on", // Default: on	
     "enable_eztv" => "on", // Default: on
     "enable_l33tx" => "off", // Default: off
@@ -156,6 +158,7 @@ return (object) array(
     "duckduckgo_language" => "uk-en", // Default: uk-en (United Kingdom)
     "wikipedia_language" => "en", // Default: en (English)
     "social_media_relevance" => 8, // Default: 8
+    "show_reddit_nsfw" => "on", // Default: on
     "show_search_source" => "on", // Default: on
     "show_search_rank" => "off", // Default: off
 	"imdb_id_search" => "off", // Default: off
@@ -182,7 +185,7 @@ return (object) array(
 		"Mozilla/5.0 (X11; Linux i686) Gecko/20100101 Firefox/119.0", // Linux Generic, Firefox 119
 	),
 
-    "torrent_trackers" => array(
+    "magnet_trackers" => array(
     	"http://nyaa.tracker.wf:7777/announce", 
 		"http://tracker.openbittorrent.com:80/announce",
     	"udp://tracker.opentrackr.org:1337/announce", 

+ 0 - 95
engines/duckduckgo.php

@@ -1,95 +0,0 @@
-<?php
-/* ------------------------------------------------------------------------------------
-*  Goosle - A meta search engine for private and fast internet fun.
-*
-*  COPYRIGHT NOTICE
-*  Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
-*
-*  COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
-*  By using this code you agree to indemnify Arnan de Gans from any 
-*  liability that might arise from its use.
------------------------------------------------------------------------------------- */
-class DuckDuckGoRequest extends EngineRequest {
-    public function get_request_url() {
-        $results = array();
-
-		// Split the query
-	    $query_terms = explode(" ", strtolower($this->query));
-
-		// Safe search override
-		$safe = "-1";
-		if(strpos($query_terms[0], "safe") !== false) {
-			$switch = explode(":", $query_terms[0]);
-
-			if(!is_numeric($switch[1])) {
-				$safe = ($switch[1] == "on") ? "1" : "-2";
-
-				$this->query = implode(" ", array_slice($query_terms, 1));
-			}
-		}
-
-		// q = query
-		// kz = Instant answers (1 = on, -1 = off)
-		// kc = Autoload images (1 = on, -1 = off)
-		// kav = Autoload results (1 = on, -1 = off)
-		// kf = Favicons (1 = on, -1 = off)
-		// kaf = Full URLs (1 = on, -1 = off)
-		// kac = Auto suggest (1 = on, -1 = off)
-		// kd = Redirects (1 = on, -1 = off)
-		// kh = HTTPS (1 = on, -1 = off)
-		// kg = Get/Post (g = GET, p = POST)
-		// kp = Safe search  (1 = on, -1 = moderate, -2 = off (may include nsfw/illegal content))
-		// k1 = Ads (1 = on, -1 = off)
-		// More here: https://duckduckgo.com/duckduckgo-help-pages/settings/params/
-
-		$args = array("q" => $this->query, "kz" => "-1", "kc" => "-1", "kav" => "-1", "kf" => "-1", "kaf" => "1", "kac" => "-1", "kd" => "-1", "kh" => "1", "kg" => "g", "kp" => $safe, "k1" => "-1");
-        $url = "https://html.duckduckgo.com/html/?".http_build_query($args);
-
-        unset($query_terms, $switch, $args, $safe);
-
-        return $url;
-    }
-
-    public function parse_results($response) {
-		$results = array("search" => array());
-		$xpath = get_xpath($response);
-
-		if(!$xpath) return array();
- 
-		// Scrape recommended
-		$didyoumean = $xpath->query(".//div[@id='did_you_mean']/a[1]")[0];
-		if(!is_null($didyoumean)) {
-			$results['did_you_mean'] = $didyoumean->textContent;
-		}
-        $search_specific = $xpath->query(".//div[@id='did_you_mean']/a[2]")[0];
-        if(!is_null($search_specific)) {
-			$results['search_specific'] = $search_specific->textContent;
-        }
- 
-		// Scrape the results
-		foreach($xpath->query("/html/body/div[1]/div['. count($xpath->query('/html/body/div[1]/div')) .']/div/div/div[contains(@class, 'web-result')]/div") as $result) {
-            $url = $xpath->evaluate(".//h2[@class='result__title']//a/@href", $result)[0];
-            if($url == null) continue;
-
-            if(!empty($results)) { // filter duplicate urls/results
-		        $result_urls = array_column($results, "url");
-                if(in_array($url->textContent, $result_urls) || in_array(get_base_url($url->textContent), $result_urls)) continue;
-            }
-
-			$title = $xpath->evaluate(".//h2[@class='result__title']", $result)[0];
-			if($title == null) continue;
-
-			$description = $xpath->evaluate(".//a[@class='result__snippet']", $result)[0];
-
-            array_push($results['search'], array (
-                "title" => htmlspecialchars($title->textContent),
-                "url" =>  htmlspecialchars($url->textContent),
-                "description" =>  $description == null ? 'No description was provided for this site.' : htmlspecialchars($description->textContent)
-            ));
-		}
-
-		return $results;
-    }
-
-}
-?>

+ 0 - 114
engines/google.php

@@ -1,114 +0,0 @@
-<?php
-/* ------------------------------------------------------------------------------------
-*  Goosle - A meta search engine for private and fast internet fun.
-*
-*  COPYRIGHT NOTICE
-*  Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
-*
-*  COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
-*  By using this code you agree to indemnify Arnan de Gans from any 
-*  liability that might arise from its use.
------------------------------------------------------------------------------------- */
-class GoogleRequest extends EngineRequest {
-    public function get_request_url() {
-        $results = array();
-
-		// Split the query
-	    $query_terms = explode(" ", strtolower($this->query));
-	
-		// Category search
-		$cat = null;
-		if($query_terms[0] == 'app') {
-			$cat = 'app';
-		} else if($query_terms[0] == 'book') {
-			$cat = 'bks';
-		} else if($query_terms[0] == 'news') {
-			$cat = 'nws';
-		} else if($query_terms[0] == 'shop') {
-			$cat = 'shop';
-		} else if($query_terms[0] == 'patent') {
-			$cat = 'pts';
-		}
-		
-		// Language override
-		$lang = null;
-		if(strpos($query_terms[0], "lang") !== false) {
-			$switch = explode(":", $query_terms[0]);
-
-			if(strlen($switch[1]) == 2 && !is_numeric($switch[1])) {
-				$lang = "lang_".$switch[1];
-
-				$this->query = implode(" ", array_slice($query_terms, 1));
-			}
-		}
-
-		// Safe search override
-		$safe = 1;
-		if(strpos($query_terms[0], "safe") !== false) {
-			$switch = explode(":", $query_terms[0]);
-
-			if(!is_numeric($switch[1])) {
-				$safe = ($switch[1] == "on") ? "2" : "0";
-
-				$this->query = implode(" ", array_slice($query_terms, 1));
-			}
-		}
-
-		// q = query
-		// safe = Safe search (Default 1) 0 = off (may include nsfw/illegal content), 1 = moderate, 2 = on/strict
-		// lr = Language (lang_XX, optional)
-		// tbm = Category search (app, bks (books), isch (images), vid, nws (News), shop, pts (Patents))
-		// pws = Personal search results on|off (Default 0, off)
-		// num = Number of results per page (number, multiple on 10 usually)
-		// start = Start position in search (Kind of like pages) (number, multiple on 10|15 usually)
-
-		$args = array("q" => $this->query, "safe" => $safe, "lr" => (!is_null($lang)) ? $lang : '', "tbm" => (!is_null($cat)) ? $cat : '', "pws" => 0, "num" => 20, "start" => 0);
-        $url = "https://www.google.com/search?".http_build_query($args);
-
-        unset($query_terms, $switch, $args, $cat, $lang, $safe);
-
-        return $url;
-    }
-
-    public function parse_results($response) {
-		$results = array("search" => array());
-        $xpath = get_xpath($response);
-
-        if(!$xpath) return array();
-
-		// Scrape recommended
-        $didyoumean = $xpath->query(".//a[@class='gL9Hy']")[0];
-        if(!is_null($didyoumean)) {
-			$results['did_you_mean'] = $didyoumean->textContent;
-        }
-        $search_specific = $xpath->query(".//a[@class='spell_orig']")[0];
-        if(!is_null($search_specific)) {
-			$results['search_specific'] = $search_specific->textContent;
-        }
-
-		// Scrape the results
-        foreach($xpath->query("//div[@id='search']//div[contains(@class, 'g')]") as $result) {
-            $url = $xpath->evaluate(".//div[@class='yuRUbf']//a/@href", $result)[0];
-			if($url == null) continue;
-
-            if(!empty($results)) { // filter duplicate urls/results
-		        $result_urls = array_column($results, "url");
-                if(in_array($url->textContent, $result_urls) OR in_array(get_base_url($url->textContent), $result_urls)) continue;
-            }
-
-			$title = $xpath->evaluate(".//h3", $result)[0];
-			if($title == null) continue;
-
-			$description = $xpath->evaluate(".//div[contains(@class, 'VwiC3b')]", $result)[0];
-
-            array_push($results['search'], array (
-                "title" => htmlspecialchars($title->textContent),
-                "url" =>  htmlspecialchars($url->textContent),
-                "description" =>  $description == null ? 'No description was provided for this site.' : htmlspecialchars($description->textContent)
-            ));
-        }
-
-        return $results;
-    }
-}
-?>

+ 28 - 15
engines/image/yahoo.php

@@ -60,35 +60,47 @@ class YahooImageRequest extends EngineRequest {
         }
 		
 		// Scrape the results
-		$scrape = $xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'slotting'))][position() < 101]");
+//		$scrape = $xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'slotting'))][position() < 101]");
+		$scrape = $xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'ignore'))][position() < 101]");
 		$rank = $results['amount'] = count($scrape);
-        foreach($scrape as $result) {
- 			$image = $xpath->evaluate(".//img/@src", $result)[0];
-            if($image == null) continue;
 
- 			$url_data = $xpath->evaluate(".//a/@href", $result)[0];
-            if($url_data == null) continue;
 
- 			// Get meta data
- 			// -- Relevant $url_data (there is more, but unused by Goosle)
+        foreach($scrape as $result) {
+			$image = $xpath->evaluate(".//img/@src", $result)[0];
+			if($image == null) continue;
+			
+			$url_data = $xpath->evaluate(".//a/@href", $result)[0];
+			if($url_data == null) continue;
+			
+			// Get and prepare meta data
+			// -- Relevant $url_data (there is more, but unused by Goosle)
 			// w = Image width (1280)
 			// h = Image height (720)
 			// imgurl = Actual full size image (Used in Yahoo preview/popup)
 			// rurl = Url to page where the image is used
 			// size = Image size (413.1KB)
 			// tt = Website title (Used for image alt text)
-			parse_str($url_data->textContent, $url_data);
+			foreach(explode("&", strstr($url_data->textContent, '?')) as &$meta) {
+				if(!is_null($meta) || !empty($meta)) {
+					$value = explode("=", trim($meta));
+
+					if(!empty($value[0]) && !empty($value[1])) {
+						$usable_data[$value[0]] = urldecode($value[1]);
+					}
+				}
+				unset($meta, $value);
+			}
 
 			// Deal with optional or missing data
-			$dimensions_w = (!array_key_exists('w', $url_data) || empty($url_data['w'])) ? "" : htmlspecialchars($url_data['w']);
-			$dimensions_h = (!array_key_exists('h', $url_data) || empty($url_data['h'])) ? "" : htmlspecialchars($url_data['h']);
-			$filesize = (!array_key_exists('size', $url_data) || empty($url_data['size'])) ? "" : htmlspecialchars($url_data['size']);
-			$link = (!array_key_exists('imgurl', $url_data) || empty($url_data['imgurl'])) ? "" : "//".htmlspecialchars($url_data['imgurl']);
+			$dimensions_w = (!array_key_exists('w', $usable_data)) ? "" : htmlspecialchars($usable_data['w']);
+			$dimensions_h = (!array_key_exists('h', $usable_data)) ? "" : htmlspecialchars($usable_data['h']);
+			$link = (!array_key_exists('imgurl', $usable_data)) ? "" : "//".htmlspecialchars($usable_data['imgurl']);
+			$url = (!array_key_exists('rurl', $usable_data)) ? "" : htmlspecialchars($usable_data['rurl']);
+			$filesize = (!array_key_exists('size', $usable_data)) ? "" : htmlspecialchars($usable_data['size']);
+			$alt = (!array_key_exists('tt', $usable_data)) ? "" : htmlspecialchars($usable_data['tt']);
 
 			// Process result
 			$image = htmlspecialchars($image->textContent);
-			$url = htmlspecialchars($url_data['rurl']);
-			$alt = htmlspecialchars($url_data['tt']);
 
 			// filter duplicate urls/results
             if(!empty($results['search'])) {
@@ -100,6 +112,7 @@ class YahooImageRequest extends EngineRequest {
 
 			$results['search'][] = array ("id" => $id, "source" => "Yahoo! Images", "image" => $image, "alt" => $alt, "url" => $url, "width" => $dimensions_w, "height" => $dimensions_h, "filesize" => $filesize, "direct_link" => $link, "engine_rank" => $rank);
 			$rank -= 1;
+			unset($url_data, $usable_data, $dimensions_w, $dimensions_h, $filesize, $link, $url, $alt, $image);
 		}
 		unset($response, $xpath, $scrape, $rank);
 

+ 4 - 9
engines/torrent/1337x.php → engines/magnet/1337x.php

@@ -111,7 +111,7 @@ class LeetxRequest extends EngineRequest {
 		foreach($xpath->query("//table/tbody/tr") as $result) {
 			$name = sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a", $result)[1]->textContent);
 			$url = "https://1337x.to".sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a/@href", $result)[1]->textContent);
-			$magnet = "./engines/torrent/magnetize_1337x.php?url=".$url;
+			$magnet = "./engines/magnet/magnetize_1337x.php?url=".$url;
 			$seeders = sanitize($xpath->evaluate(".//td[@class='coll-2 seeds']", $result)[0]->textContent);
 			$leechers = sanitize($xpath->evaluate(".//td[@class='coll-3 leeches']", $result)[0]->textContent);
 			$size_unformatted = explode(" ", sanitize($xpath->evaluate(".//td[contains(@class, 'coll-4 size')]", $result)[0]->textContent));
@@ -127,14 +127,9 @@ class LeetxRequest extends EngineRequest {
 			// Block these categories
 			if(in_array($category, $this->opts->leetx_categories_blocked)) continue;
 			
-			// Filter by Season (S01) or Season and Episode (S01E01)
-			// Where [0][0] = Season and [0][1] = Episode
-			if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $name, $match_episode)) {
-				if($query_episode[0][0] != $match_episode[0][0] || (array_key_exists(1, $query_episode[0]) && array_key_exists(1, $match_episode[0]) && $query_episode[0][1] != $match_episode[0][1])) {
-					continue;
-				}
-			}
-
+			// Filter episodes
+			if(!is_season_or_episode($this->query, $name)) continue;
+			
 			$id = uniqid(rand(0, 9999));
 			
 			$results[] = array (

+ 1 - 1
engines/torrent/eztv.php → engines/magnet/eztv.php

@@ -37,7 +37,7 @@ class EZTVRequest extends EngineRequest {
 		foreach($json_response['torrents'] as $result) {
 			$name = sanitize($result['title']);
 			$magnet = sanitize($result['magnet_url']);
-			$hash = sanitize($result['hash']);
+			$hash = strtolower(sanitize($result['hash']));
 			$seeders = sanitize($result['seeds']);
 			$leechers = sanitize($result['peers']);
 			$size = sanitize($result['size_bytes']);

+ 0 - 0
engines/torrent/index.php → engines/magnet/index.php


+ 5 - 10
engines/torrent/lime.php → engines/magnet/lime.php

@@ -29,8 +29,8 @@ class LimeRequest extends EngineRequest {
 			$name = sanitize($xpath->evaluate(".//td[@class='tdleft']//a[2]", $result)[0]->textContent);
 			$hash = sanitize($xpath->evaluate(".//td[@class='tdleft']//a[1]/@href", $result)[0]->textContent);
 			$hash = explode("/", substr($hash, 0, strpos($hash, ".torrent?")));
-			$hash = $hash[array_key_last($hash)];
-			$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->torrent_trackers);
+			$hash = strtolower($hash[array_key_last($hash)]);
+			$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->magnet_trackers);
 			$seeders = sanitize($xpath->evaluate(".//td[@class='tdseed']", $result)[0]->textContent);
 			$leechers = sanitize($xpath->evaluate(".//td[@class='tdleech']", $result)[0]->textContent);
 			$size = sanitize($xpath->evaluate(".//td[@class='tdnormal'][2]", $result)[0]->textContent);
@@ -43,14 +43,9 @@ class LimeRequest extends EngineRequest {
 			$category = $category[array_key_last($category)];
 			$url = "https://www.limetorrents.lol".sanitize($xpath->evaluate(".//td[@class='tdleft']//a[2]/@href", $result)[0]->textContent);
 			
-			// Filter by Season (S01) or Season and Episode (S01E01)
-			// Where [0][0] = Season and [0][1] = Episode
-			if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $name, $match_episode)) {
-				if($query_episode[0][0] != $match_episode[0][0] || (array_key_exists(1, $query_episode[0]) && array_key_exists(1, $match_episode[0]) && $query_episode[0][1] != $match_episode[0][1])) {
-					continue;
-				}
-			}
-
+			// Filter episodes
+			if(!is_season_or_episode($this->query, $name)) continue;
+			
 			$id = uniqid(rand(0, 9999));
 			
 			$results[] = array (

+ 64 - 0
engines/magnet/magnetdl.php

@@ -0,0 +1,64 @@
+<?php
+/* ------------------------------------------------------------------------------------
+*  Goosle - A meta search engine for private and fast internet fun.
+*
+*  COPYRIGHT NOTICE
+*  Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
+*
+*  COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
+*  By using this code you agree to indemnify Arnan de Gans from any 
+*  liability that might arise from its use.
+------------------------------------------------------------------------------------ */
+class MagnetDLRequest extends EngineRequest {
+	public function get_request_url() {
+        $url = "https://www.magnetdl.com/".substr($this->query, 0, 1)."/".str_replace(' ', '-', $this->query);
+
+        return $url;
+	}
+	
+	public function parse_results($response) {
+		$results = array();
+		$xpath = get_xpath($response);
+		
+		// Failed to load page
+		if(!$xpath) return $results;
+		
+		// Scrape the page
+		foreach($xpath->query("//table[@class='download']/tbody/tr") as $result) {			
+			// Skip page navigation and incompatible rows
+			if(is_null($xpath->evaluate(".//td[2]", $result)[0])) continue;
+
+			$name = sanitize($xpath->evaluate(".//td[2]/a/@title", $result)[0]->textContent);
+			$magnet = sanitize($xpath->evaluate(".//td[1]/a/@href", $result)[0]->textContent);
+			$hash = parse_url($magnet, PHP_URL_QUERY);
+			parse_str($hash, $hash_parameters);
+			$hash = strtolower(str_replace("urn:btih:", "", $hash_parameters['xt']));
+			$seeders = sanitize($xpath->evaluate(".//td[7]", $result)[0]->textContent);
+			$leechers = sanitize($xpath->evaluate(".//td[8]", $result)[0]->textContent);
+			$size = sanitize($xpath->evaluate(".//td[6]", $result)[0]->textContent);
+
+			// Ignore results with 0 seeders?
+			if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
+			
+			// Get extra data
+			$category = sanitize($xpath->evaluate(".//td[4]", $result)[0]->textContent);
+			$url = "https://www.magnetdl.com".sanitize($xpath->evaluate(".//td[2]//a/@href", $result)[0]->textContent);
+			
+			// Filter episodes
+			if(!is_season_or_episode($this->query, $name)) continue;
+			
+			$id = uniqid(rand(0, 9999));
+			
+			$results[] = array (
+				// Required
+				"id" => $id, "source" => "magnetdl.com", "name" => $name, "magnet" => $magnet, "hash" => $hash, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
+				// Extra
+				"category" => $category, "url" => $url
+			);
+		}
+		unset($response, $xpath);
+
+		return $results;
+	}
+}
+?>

+ 0 - 0
engines/torrent/magnetize_1337x.php → engines/magnet/magnetize_1337x.php


+ 3 - 8
engines/torrent/nyaa.php → engines/magnet/nyaa.php

@@ -34,7 +34,7 @@ class NyaaRequest extends EngineRequest {
 			$magnet = sanitize($xpath->evaluate(".//a[2]/@href", $meta[0])[0]->textContent);
 			$hash = parse_url($magnet, PHP_URL_QUERY);
 			parse_str($hash, $hash_parameters);
-			$hash = str_replace("urn:btih:", "", $hash_parameters['xt']);
+			$hash = strtolower(str_replace("urn:btih:", "", $hash_parameters['xt']));
 			$seeders = sanitize($meta[3]->textContent);
 			$leechers = sanitize($meta[4]->textContent);
 			$size =  str_replace("GiB", "GB", str_replace("MiB", "MB", sanitize($meta[1]->textContent)));
@@ -50,13 +50,8 @@ class NyaaRequest extends EngineRequest {
 			$date_added = explode("-", substr($date_added, 0, 10));
 			$date_added = mktime(0, 0, 0, intval($date_added[1]), intval($date_added[2]), intval($date_added[0]));
 			
-			// Filter by Season (S01) or Season and Episode (S01E01)
-			// Where [0][0] = Season and [0][1] = Episode
-			if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $name, $match_episode)) {
-				if($query_episode[0][0] != $match_episode[0][0] || (array_key_exists(1, $query_episode[0]) && array_key_exists(1, $match_episode[0]) && $query_episode[0][1] != $match_episode[0][1])) {
-					continue;
-				}
-			}
+			// Filter episodes
+			if(!is_season_or_episode($this->query, $name)) continue;
 			
 			$id = uniqid(rand(0, 9999));
 			

+ 4 - 10
engines/torrent/thepiratebay.php → engines/magnet/thepiratebay.php

@@ -93,10 +93,9 @@ class PirateBayRequest extends EngineRequest {
 			// Nothing found
 			if($response['name'] == "No results returned") break;
 			
-
 			$name = sanitize($response['name']);
-			$hash = sanitize($response['info_hash']);
-			$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->torrent_trackers);
+			$hash = strtolower(sanitize($response['info_hash']));
+			$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->magnet_trackers);
 			$seeders = sanitize($response['seeders']);
 			$leechers = sanitize($response['leechers']);
 			$size = sanitize($response['size']);
@@ -112,13 +111,8 @@ class PirateBayRequest extends EngineRequest {
 			// Block these categories
 			if(in_array($category, $this->opts->piratebay_categories_blocked)) continue;
 			
-			// Filter by Season (S01) or Season and Episode (S01E01)
-			// Where [0][0] = Season and [0][1] = Episode
-			if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $name, $match_episode)) {
-				if($query_episode[0][0] != $match_episode[0][0] || (array_key_exists(1, $query_episode[0]) && array_key_exists(1, $match_episode[0]) && $query_episode[0][1] != $match_episode[0][1])) {
-					continue;
-				}
-			}
+			// Filter episodes
+			if(!is_season_or_episode($this->query, $name)) continue;
 			
 			$id = uniqid(rand(0, 9999));
 			

+ 20 - 20
engines/torrent/yts.php → engines/magnet/yts.php

@@ -28,38 +28,38 @@ class YTSRequest extends EngineRequest {
 		if($json_response['status'] != "ok" || $json_response['data']['movie_count'] == 0) return $results;
 		
 		// Use API result
-		foreach ($json_response['data']['movies'] as $movie) {
+		foreach ($json_response['data']['movies'] as $result) {
 			// Prevent gaps
-			if(!array_key_exists("year", $movie)) $movie['year'] = 0;
-			if(!array_key_exists("genres", $movie)) $movie['genres'] = array();
-			if(!array_key_exists("runtime", $movie)) $movie['runtime'] = 0;
-			if(!array_key_exists("url", $movie)) $movie['url'] = '';
+			if(!array_key_exists("year", $result)) $result['year'] = 0;
+			if(!array_key_exists("genres", $result)) $result['genres'] = array();
+			if(!array_key_exists("runtime", $result)) $result['runtime'] = 0;
+			if(!array_key_exists("url", $result)) $result['url'] = '';
 			
 			// Block these categories
-			if(count(array_uintersect($movie['genres'], $this->opts->yts_categories_blocked, "strcasecmp")) > 0) continue;
+			if(count(array_uintersect($result['genres'], $this->opts->yts_categories_blocked, "strcasecmp")) > 0) continue;
 			
-			$name = sanitize($movie['title']);
+			$name = sanitize($result['title']);
 			
 			// Get extra data
-			$year = sanitize($movie['year']);
-			$category = sanitize(implode(', ', $movie['genres']));
-			$runtime = sanitize($movie['runtime']);
-			$url = sanitize($movie['url']);
-			$date_added = sanitize($movie['date_uploaded_unix']);
+			$year = sanitize($result['year']);
+			$category = sanitize(implode(', ', $result['genres']));
+			$runtime = sanitize($result['runtime']);
+			$url = sanitize($result['url']);
+			$date_added = sanitize($result['date_uploaded_unix']);
 
-			foreach ($movie['torrents'] as $torrent) {
-				$hash = sanitize($torrent['hash']);
-				$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->torrent_trackers);
-				$seeders = sanitize($torrent['seeds']);
-				$leechers = sanitize($torrent['peers']);
-				$size = sanitize($torrent['size']);
+			foreach ($result['torrents'] as $download) {
+				$hash = strtolower(sanitize($download['hash']));
+				$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->magnet_trackers);
+				$seeders = sanitize($download['seeds']);
+				$leechers = sanitize($download['peers']);
+				$size = sanitize($download['size']);
 				
 				// Ignore results with 0 seeders?
 				if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
 				
 				// Get extra data
-				$quality = sanitize($torrent['quality']);
-				$codec = sanitize($torrent['video_codec']);
+				$quality = sanitize($download['quality']);
+				$codec = sanitize($download['video_codec']);
 				$id = uniqid(rand(0, 9999));
 			
 				$results[] = array (

+ 36 - 27
engines/search-torrent.php → engines/search-magnet.php

@@ -9,46 +9,51 @@
 *  By using this code you agree to indemnify Arnan de Gans from any 
 *  liability that might arise from its use.
 ------------------------------------------------------------------------------------ */
-class TorrentSearch extends EngineRequest {
+class MagnetSearch extends EngineRequest {
 	protected $requests, $special_request;
 	
 	public function __construct($opts, $mh) {
 		$this->requests = array();
 
 		if($opts->enable_limetorrents == "on") {
-			require ABSPATH."engines/torrent/lime.php";
+			require ABSPATH."engines/magnet/lime.php";
 			$this->requests[] = new LimeRequest($opts, $mh);
 		}
 
 		if($opts->enable_piratebay == "on") {
-			require ABSPATH."engines/torrent/thepiratebay.php";
+			require ABSPATH."engines/magnet/thepiratebay.php";
 			$this->requests[] = new PirateBayRequest($opts, $mh);
 		}
 
 		if($opts->enable_yts == "on") {
-			require ABSPATH."engines/torrent/yts.php";
+			require ABSPATH."engines/magnet/yts.php";
 			$this->requests[] = new YTSRequest($opts, $mh);
 		}
 
+		if($opts->enable_magnetdl == "on") {
+			require ABSPATH."engines/magnet/magnetdl.php";
+			$this->requests[] = new MagnetDLRequest($opts, $mh);
+		}
+
 		if($opts->enable_nyaa == "on") {
-			require ABSPATH."engines/torrent/nyaa.php";
+			require ABSPATH."engines/magnet/nyaa.php";
 			$this->requests[] = new NyaaRequest($opts, $mh);
 		}
 
 		if($opts->enable_eztv == "on") {
 			if(substr(strtolower($opts->query), 0, 2) == "tt") {
-				require ABSPATH."engines/torrent/eztv.php";
+				require ABSPATH."engines/magnet/eztv.php";
 				$this->requests[] = new EZTVRequest($opts, $mh);
 			}
 		}
 
 		if($opts->enable_l33tx == "on") {
-			require ABSPATH."engines/torrent/1337x.php";
+			require ABSPATH."engines/magnet/1337x.php";
 			$this->requests[] = new LeetxRequest($opts, $mh);
 		}
 		
 		// Special search
-		$this->special_request = special_torrent_request($opts, $mh);
+		$this->special_request = special_magnet_request($opts, $mh);
 	}
 
     public function parse_results($response) {
@@ -63,28 +68,28 @@ class TorrentSearch extends EngineRequest {
 					foreach($engine_result as $result) {
 						if(count($results_temp) > 1 && !is_null($result['hash'])) {
 							$result_urls = array_column($results_temp, "hash", "id");
-							$found_key = array_search($result['hash'], $result_urls);
+							$found_id = array_search($result['hash'], $result_urls);
 						} else {
-							$found_key = false;
+							$found_id = false;
 						}
 
-						if($found_key !== false) {
+						if($found_id !== false) {
 							// Duplicate result from another source
-							// If seeders and/or leechers mismatch, assume they're different users
-							if($results_temp[$found_key]['seeders'] != $result['seeders']) $results_temp[$found_key]['combo_seeders'] += $result['seeders'];
-							if($results_temp[$found_key]['leechers'] != $result['leechers']) $results_temp[$found_key]['combo_leechers'] += $result['leechers'];
+							// If seeders and/or leechers mismatch, assume they're different peers
+							if($results_temp[$found_id]['seeders'] != $result['seeders']) $results_temp[$found_id]['combo_seeders'] += intval($result['seeders']);
+							if($results_temp[$found_id]['leechers'] != $result['leechers']) $results_temp[$found_id]['combo_leechers'] += intval($result['leechers']);
 
-							$results_temp[$found_key]['combo_source'][] = $result['source'];
+							$results_temp[$found_id]['combo_source'][] = $result['source'];
 						} else {
-							// First find, rank and add to results
-							$result['combo_seeders'] = $result['seeders'];
-							$result['combo_leechers'] = $result['leechers'];
+							// First find - rank and add to results
+							$result['combo_seeders'] = intval($result['seeders']);
+							$result['combo_leechers'] = intval($result['leechers']);
 							$result['combo_source'][] = $result['source'];
 
 							$results_temp[$result['id']] = $result;
 						}
 
-						unset($result, $result_urls, $found_key, $social_media_multiplier, $goosle_rank, $match_rank);
+						unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
 					}
 				}
 			} else {
@@ -154,19 +159,19 @@ echo '</pre>';
 				echo "<ol class=\"magnet-grid\">";
 		
 				foreach($results['special']['yts'] as $highlight) {
-					echo "<li class=\"result\">";
+					echo "<li class=\"result yts\">";
 					echo "<div class=\"magnet-box\">";
 					echo "<img src=\"".$highlight['thumbnail']."\" alt=\"".$highlight['name']."\" />";
 			       	echo "<p><strong>Genre:</strong> ".$highlight['category']."<br />";
 			       	echo "<strong>Released:</strong> ".$highlight['year']."<br />";
 			       	echo "<strong>Rating:</strong> ".$highlight['rating']." / 10<br />";
 					echo "<strong>Downloads:</strong> ";
-					foreach($highlight['torrents'] as $torrent) {
-						echo "<a href=\"".$torrent['magnet']."\">".$torrent['quality']." ".$torrent['codec']."</a>";
+					foreach($highlight['magnet_links'] as $magnet) {
+						echo "<a href=\"".$magnet['magnet']."\">".$magnet['quality']." ".$magnet['codec']."</a>";
 					}
 					echo "</p>";
 					echo "</div>";
-					echo "<strong>".$highlight['name']."</strong>";
+					echo "<strong><center><a href=\"".$highlight['url']."\" target=\"_blank\">".$highlight['name']."</a></center></strong>";
 					echo "</li>";	
 				}
 				unset($highlight);
@@ -179,11 +184,15 @@ echo '</pre>';
 				echo "<ol class=\"magnet-grid\">";
 		
 				foreach($results['special']['eztv'] as $highlight) {
-					echo "<li class=\"result\">";
+					echo "<li class=\"result eztv\">";
 					echo "<div class=\"magnet-box\">";
-					echo "<img src=\"".$highlight['thumbnail']."\" alt=\"".$highlight['name']."\" />";
+					if(!empty($highlight['thumbnail'])) {
+						echo "<img src=\"".$highlight['thumbnail']."\" alt=\"".$highlight['name']."\" />";
+					} else {
+						echo "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOUX3LxDAAE4AJiVKIoaQAAAABJRU5ErkJggg==\" style=\"max-height: 80px;\">";
+					}
 			       	echo "<p>".$highlight['quality']."<br />";
-			       	echo "<a href=\"".$highlight['magnet']."\">Download</a></p>";
+			       	echo "<a href=\"".$highlight['magnet_link']."\">Download</a></p>";
 					echo "</div>";
 					echo "<strong>".$highlight['name']." S".$highlight['season']."E".$highlight['episode']."</strong>";
 					echo "</li>";	
@@ -217,7 +226,7 @@ echo '</pre>';
 				if(array_key_exists('runtime', $result)) $meta[] = "<strong>Runtime:</strong> ".date('H:i', mktime(0, $result['runtime']));
 				if(array_key_exists('date_added', $result)) $meta[] = "<strong>Added on:</strong> ".date('M d, Y', $result['date_added']);
 
-				// If available, add the url to the first found torrent result page
+				// If available, add the url to the first found torrent page
 				$url = (array_key_exists('url', $result)) ? " - <a href=\"".$result['url']."\" target=\"_blank\" title=\"Careful - Site may contain intrusive popup ads and malware!\">torrent page</a>" : "";
 	
 				// Put result together

+ 5 - 0
engines/search.php

@@ -25,6 +25,11 @@ class Search extends EngineRequest {
 			$this->requests[] = new GoogleRequest($opts, $mh);	
 		}
 
+		if($opts->enable_reddit == "on") {
+			require ABSPATH."engines/search/reddit.php";
+			$this->requests[] = new RedditRequest($opts, $mh);	
+		}
+
 		if($opts->enable_wikipedia == "on") {
 			require ABSPATH."engines/search/wikipedia.php";
 			$this->requests[] = new WikiRequest($opts, $mh);	

+ 60 - 0
engines/search/reddit.php

@@ -0,0 +1,60 @@
+<?php
+/* ------------------------------------------------------------------------------------
+*  Goosle - A meta search engine for private and fast internet fun.
+*
+*  COPYRIGHT NOTICE
+*  Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
+*
+*  COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
+*  By using this code you agree to indemnify Arnan de Gans from any 
+*  liability that might arise from its use.
+------------------------------------------------------------------------------------ */
+class RedditRequest extends EngineRequest {
+    public function get_request_url() {
+		$args = array("q" => $this->query, "type" => "link", "sort" => "top", "t" => "year");
+        $url = "https://www.reddit.com/search.json?".http_build_query($args);
+
+        return $url;
+    }
+
+	public function parse_results($response) {
+		$results = array();
+		$json_response = json_decode($response, true);
+		
+		if(empty($json_response)) return $results;
+		
+		// No results
+		if($json_response['data']['dist'] == 0) return $results;
+		
+		$rank = $results['amount'] = count($json_response['data']['children']);
+		foreach($json_response['data']['children'] as $result) {
+			$result = $result['data'];
+
+			$nsfw = sanitize($result['over_18']);
+			
+			// Ignore NSFW results
+			if($this->opts->show_reddit_nsfw == "off" && $nsfw === 1) continue;
+			
+			$title = trim($result['title']);
+			$url = "https://www.reddit.com".sanitize($result['permalink']);
+			
+			$postdate = date('M d, Y', sanitize($result['created']));
+			$author = sanitize($result['author']);
+			$reddit = sanitize($result['subreddit']);
+			$votes = sanitize($result['score']);
+			$comments = sanitize($result['num_comments']);
+			$nsfw = ($nsfw === 1) ? "<span style=\"color:#cc0033;\">[NSFW 18+] Caution, this result contains mature content!</span><br />" : "";
+			
+			$description = $nsfw."In <a href=\"https://www.reddit.com/r/".$reddit."\" target=\"_blank\">r/".$reddit."</a> &sdot; ".$postdate." &sdot; <a href=\"https://www.reddit.com/user/".$author."\" target=\"_blank\">".$author."</a> &sdot; ".$votes." votes &sdot; ".$comments." comments";
+
+			$id = uniqid(rand(0, 9999));
+		
+			$results['search'][] = array ("id" => $id, "source" => "Reddit", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
+			$rank -= 1;
+		}
+		unset($response, $json_response, $rank);
+		
+		return $results;
+	}
+}
+?>

+ 8 - 8
engines/special/eztv_highlights.php

@@ -26,12 +26,12 @@ class eztvhighlights extends EngineRequest {
 		if($json_response['torrents_count'] == 0) return $results;
 		
 		// Use API result
-		foreach($json_response['torrents'] as $highlight) {
-			$name = sanitize($highlight['title']);
-			$thumbnail = sanitize($highlight['small_screenshot']);
-			$season = sanitize($highlight['season']);
-			$episode = sanitize($highlight['episode']);
-			$highlight = sanitize($highlight['magnet_url']);
+		foreach($json_response['torrents'] as $result) {
+			$name = sanitize($result['title']);
+			$thumbnail = sanitize($result['small_screenshot']);
+			$season = sanitize($result['season']);
+			$episode = sanitize($result['episode']);
+			$magnet_link = sanitize($result['magnet_url']);
 			$quality = (preg_match('/(480p|720p|1080p|2160p)/i', $name, $quality)) ? $quality[0] : "";
 			$codec = (preg_match('/(x264|h264|x265|h265|xvid)/i', $name, $codec)) ? $codec[0] : "";
 
@@ -42,10 +42,10 @@ class eztvhighlights extends EngineRequest {
 			if(!empty($codec)) $quality = $quality." ".$codec;
 
 			$results[] = array (
-				"name" => $name, "thumbnail" => $thumbnail, "season" => $season, "episode" => $episode, "magnet" => $highlight, "quality" => $quality
+				"name" => $name, "thumbnail" => $thumbnail, "season" => $season, "episode" => $episode, "magnet_link" => $magnet_link, "quality" => $quality
 			);
 
-			unset($highlight, $name, $clean_name, $thumbnail, $season, $episode, $highlight, $quality, $codec);
+			unset($result, $name, $clean_name, $thumbnail, $season, $episode, $magnet_link, $quality, $codec);
 		}
 		unset($json_response);
 

+ 0 - 66
engines/special/wikipedia.php

@@ -1,66 +0,0 @@
-<?php
-/* ------------------------------------------------------------------------------------
-*  Goosle - A meta search engine for private and fast internet fun.
-*
-*  COPYRIGHT NOTICE
-*  Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
-*
-*  COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
-*  By using this code you agree to indemnify Arnan de Gans from any 
-*  liability that might arise from its use.
------------------------------------------------------------------------------------- */
-class WikipediaRequest extends EngineRequest {
-	public function get_request_url() {
-        $query_terms = explode(" ", $this->query);
- 
- 		// [0] = (wiki|w)
-		// [1] = SEARCH TERM
-
-		unset($query_terms[0]); // Remove first item (w or wiki) from array and encode the rest for Wikipedia	
-		$this->query = implode(" ", $query_terms);
-	
-		return "https://wikipedia.org/w/api.php?format=json&action=query&prop=extracts%7Cpageimages&exintro&explaintext&redirects=1&pithumbsize=500&titles=".urlencode($this->query);
-	}
-	
-	public function parse_results($response) {
-		$json_response = json_decode($response, true);
-
-		if(!empty($json_response)) {
-			$result = $json_response['query']['pages'];
-			
-			// Abort on invalid response
-			if (!is_array($result)) return array();
-	
-			// Grab first result if there are multiple
-			$result = $result[array_key_first($result)];
-
-			// Page not found
-			if (array_key_exists("missing", $result)) {
-				return array(
-					"title" => "Wiki page not found", 
-					"text" => "Maybe the page doesn't exist. Try searching on Wikipedia with the link below or search for something else.", 
-					"source" => "https://wikipedia.org/wiki/Special:Search?go=Go&search=".urlencode($this->query)
-				);
-			}
-
-			// Page found
-			$response = array(
-				"title" => strip_tags(trim($result['title'])),
-				"text" => strip_tags(trim($result['extract'])),
-				"source" => "https://wikipedia.org/wiki/".urlencode($this->query)
-			);
-			
-			if (array_key_exists("thumbnail",  $result)) {
-				$response['image'] = strip_tags(trim($result['thumbnail']['source']));
-			}
-			
-			return $response;
-	    } else {
-	        return array(
-                "title" => "Sigh...",
-                "text" => "Wikipedia could not be loaded. Try again later."
-	        );
-		}
-	}
-}
-?>

+ 20 - 19
engines/special/yts_highlights.php

@@ -16,7 +16,7 @@ class ytshighlights extends EngineRequest {
     }
     
     public function parse_results($response) {
-		$results = $torrents = array();
+		$results = array();
 		$response = curl_multi_getcontent($this->ch);
 		$json_response = json_decode($response, true);
 		
@@ -27,36 +27,37 @@ class ytshighlights extends EngineRequest {
 		if($json_response['status'] != "ok" || $json_response['data']['movie_count'] == 0) return $results;
 		
 		// Use API result
-		foreach ($json_response['data']['movies'] as $highlight) {
+		foreach ($json_response['data']['movies'] as $result) {
 			// Prevent gaps
-			if(!array_key_exists("year", $highlight)) $highlight['year'] = "0000";
-			if(!array_key_exists("genres", $highlight)) $highlight['genres'] = array();
-			if(!array_key_exists("rating", $highlight)) $highlight['rating'] = "0";
+			if(!array_key_exists("year", $result)) $result['year'] = "0000";
+			if(!array_key_exists("genres", $result)) $result['genres'] = array();
+			if(!array_key_exists("rating", $result)) $result['rating'] = "0";
 
 			// Block these categories
-			if(count(array_uintersect($highlight['genres'], $this->opts->yts_categories_blocked, "strcasecmp")) > 0) continue;
+			if(count(array_uintersect($result['genres'], $this->opts->yts_categories_blocked, "strcasecmp")) > 0) continue;
 			
-			$name = sanitize($highlight['title']);
-			$thumbnail = sanitize($highlight['medium_cover_image']);
-			$year = sanitize($highlight['year']);
-			$category = sanitize(implode(', ', array_slice($highlight['genres'], 0, 2)));
-			$rating = sanitize($highlight['rating']);
+			$name = sanitize($result['title']);
+			$thumbnail = sanitize($result['medium_cover_image']);
+			$year = sanitize($result['year']);
+			$category = sanitize(implode(', ', array_slice($result['genres'], 0, 2)));
+			$url = sanitize($result['url']);
+			$rating = sanitize($result['rating']);
 
-			foreach($highlight['torrents'] as $torrent) {
-				$hash = sanitize($torrent['hash']);
-				$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->torrent_trackers);
-				$quality = sanitize($torrent['quality']);
-				$codec = sanitize($torrent['video_codec']);
+			foreach($result['torrents'] as $download) {
+				$hash = sanitize($download['hash']);
+				$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->magnet_trackers);
+				$quality = sanitize($download['quality']);
+				$codec = sanitize($download['video_codec']);
 			
-				$torrents[] = array (
+				$downloads[] = array (
 					"magnet" => $magnet, "quality" => $quality, "codec" => $codec
 				);
 			}
 
 			$results[] = array (
-				"name" => $name, "thumbnail" => $thumbnail, "year" => $year, "category" => $category, "rating" => $rating, 'torrents' => $torrents
+				"name" => $name, "thumbnail" => $thumbnail, "year" => $year, "category" => $category, "rating" => $rating, "magnet_links" => $downloads, "url" => $url
 			);
-			unset($highlight, $name, $thumbnail, $year, $category, $rating, $hash, $magnet, $quality, $codec, $torrents);
+			unset($result, $name, $thumbnail, $year, $category, $rating, $hash, $download, $quality, $codec, $downloads, $url);
 		}
 		unset($json_response);
 

+ 4 - 4
functions/search_engine.php

@@ -108,8 +108,8 @@ function fetch_search_results($opts) {
 		    require ABSPATH."engines/search-image.php";
 	        $search = new ImageSearch($opts, $mh);
 		} else if($opts->type == 9) {
-		    require ABSPATH."engines/search-torrent.php";
-	        $search = new TorrentSearch($opts, $mh);
+		    require ABSPATH."engines/search-magnet.php";
+	        $search = new MagnetSearch($opts, $mh);
 	    }
 	
 	    $running = null;
@@ -165,9 +165,9 @@ function special_search_request($opts) {
 }
 
 /*--------------------------------------
-// Process special torrent features
+// Process special magnet search features
 --------------------------------------*/
-function special_torrent_request($opts, $mh) {
+function special_magnet_request($opts, $mh) {
 	$special_request = array();
 
 	// Latest additions to yts

+ 31 - 7
functions/tools.php

@@ -34,7 +34,7 @@ function load_opts() {
 	if($opts->cache_type == "file" && !is_dir(ABSPATH.'cache/')) $opts->cache = "off";
 	if($opts->cache_type == "apcu" && !function_exists("apcu_exists")) $opts->cache = "off";
 	if($opts->enable_image_search == "off" && $opts->type == 1) $opts->type = 0;
-	if($opts->enable_torrent_search == "off" && $opts->type == 9) $opts->type = 0;
+	if($opts->enable_magnet_search == "off" && $opts->type == 9) $opts->type = 0;
 	if(!is_numeric($opts->cache_time) || ($opts->cache_time > 720 || $opts->cache_time < 1)) $opts->cache_time = 30;
 	if(!is_numeric($opts->social_media_relevance) || ($opts->social_media_relevance > 10 || $opts->social_media_relevance < 0)) $opts->social_media_relevance = 8;
 	
@@ -199,12 +199,36 @@ function match_count($string, $query) {
     return $matches;
 }
 
+/*--------------------------------------
+// Detect Season and Episodes in results
+--------------------------------------*/
+function is_season_or_episode($search_query, $result_name) {
+	$search_query = strtolower($search_query);
+	$result_name = strtolower($result_name);
+	
+	// Filter by Season (S01) or Season and Episode (S01E01)
+	// Where [0][0] = Season and [0][1] = Episode
+	if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/", $search_query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/", $result_name, $result_episode)) {
+		if($query_episode[0][0] != $result_episode[0][0] 
+			|| (array_key_exists(1, $query_episode[0]) 
+				&& array_key_exists(1, $result_episode[0]) 
+				&& $query_episode[0][1] != $result_episode[0][1]
+			)
+		) {
+			return false;
+		}
+	}
+
+    return true;
+}
+
 /*--------------------------------------
 // Detect social media results
 --------------------------------------*/
 function is_social_media($string) {
 	$string = strtolower($string);
 	
+	// Borrowed from https://github.com/lorey/social-media-profiles-regexs
 	if(preg_match("/(?:https?:)?\/\/(?:www\.)?(?:facebook|fb)\.com\/(?P<profile>(?![A-z]+\.php)(?!marketplace|gaming|watch|me|messages|help|search|groups)[A-z0-9_\-\.]+)\/?/", $string)
 		|| preg_match("/(?:https?:)?\/\/(?:www\.)?(?:instagram\.com|instagr\.am)\/(?P<username>[A-Za-z0-9_](?:(?:[A-Za-z0-9_]|(?:\.(?!\.))){0,28}(?:[A-Za-z0-9_]))?)/", $string)
 		|| preg_match("/(?:https?:)?\/\/(?:[A-z]+\.)?twitter\.com\/@?(?P<username>[A-z0-9_]+)\/status\/(?P<tweet_id>[0-9]+)\/?/", $string)
@@ -282,7 +306,7 @@ function replace_last_comma($string) {
 // Human readable file sizes
 --------------------------------------*/
 function human_filesize($bytes, $dec = 2) {
-    $size   = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
+    $size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
     $factor = floor((strlen($bytes) - 1) / 3);
 
     return sprintf("%.{$dec}f ", $bytes / pow(1024, $factor)) . @$size[$factor];
@@ -296,7 +320,7 @@ function string_generator() {
     $password = array();
     $length = strlen($characters) - 1;
 
-    for ($i = 0; $i < 24; $i++) {
+    for($i = 0; $i < 24; $i++) {
         $n = rand(0, $length);
         $password[] = $characters[$n];
     }
@@ -315,7 +339,10 @@ function show_version() {
 	$cache_file = dirname(__DIR__).'/version.data';
 	
 	// Currently installed version
-	$current_version = "1.2.2";
+	$current_version = "1.3";
+
+	// Format current version for footer
+	$show_version = "<a href=\"https://github.com/adegans/Goosle/\" target=\"_blank\">Goosle ".$current_version."</a>.";
 
 	if(!is_file($cache_file)){
 		// Create update cache file
@@ -343,9 +370,6 @@ function show_version() {
 		file_put_contents($cache_file, serialize($version));
 	}
 
-	// Format version for footer
-	$show_version = "<a href=\"https://github.com/adegans/Goosle/\" target=\"_blank\">Goosle ".$current_version."</a>.";
-
 	// Check if a newer version is available and add it to the version display
 	if(version_compare($current_version, $version['latest'], "<")) {
 		$show_version .= " <a href=\"".$version['url']."\" target=\"_blank\" class=\"update\">Version ".$version['latest']." is available!</a>";

+ 26 - 13
help.php

@@ -45,10 +45,10 @@ if(verify_hash($opts, $auth)) {
 	        <div class="navigation-header">
 		        <a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="Search results" />Search</a>
 		        <?php if($opts->enable_image_search == "on") { ?>
-		        <a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/image.png" alt="Image results" />Image</a>
+		        <a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/image.png" alt="Image results" />Images</a>
 		        <?php } ?>
-		        <?php if($opts->enable_torrent_search == "on") { ?>
-		        <a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/torrent.png" alt="Torrent results" />Torrent</a>
+		        <?php if($opts->enable_magnet_search == "on") { ?>
+		        <a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/magnet.png" alt="Magnet results" />Magnet links</a>
 		        <?php } ?>
 			</div>
 		</form>
@@ -56,12 +56,25 @@ if(verify_hash($opts, $auth)) {
 	
 	<div class="results-wrap">
 		<section class="main-column">
-			<h2>General usage</h2>
-			<p>Goosle searches for your query on DuckDuckGo, Google, Wikipedia and Ecosia at the same time. All results are merged and ranked on what Goosle considers is the most relevant.</p>
-			<p>DuckDuckGo, Google and Ecosia are mostly language agnostic and will try to figure out on their own what language to use.</p>
+			<h2>How to use Goosle</h2>
+			<p>DuckDuckGo, Google and Ecosia are mostly language agnostic and will try to figure out on their own what language to use based on your search query.</p>
 			<p>Searching defaults to Moderate Safe mode. To override the safe mode, prefix your search with <strong>safe:on</strong> or <strong>safe:off</strong>.<br /><strong>On</strong> will use 'Strict' mode, while <strong>off</strong> will disable safe searching, this may yield results that are unsuitable for work or minors.</p>
+			<?php if($opts->enable_google == "on") { ?>
 			<p>Google results are not personalized by default, using Google's own option for it.</p>
-			<p><em><strong>Note:</strong> DuckDuckGo search bangs are not supported and the <strong>!</strong> to trigger them is stripped out to prevent issues.</em></p>
+			<?php } ?>
+			<?php if($opts->enable_duckduckgo == "on") { ?>
+			<p>DuckDuckGo search bangs are not supported and the <strong>!</strong> to trigger them is stripped out to prevent issues.</em></p>
+			<?php } ?>
+			<?php if($opts->enable_reddit == "on") { ?>
+			<p>Reddit results will find 'Top Posts' in any subreddit posted in the last year. NSFW or mature content will be visibly marked. Alternatively Goosle has an option to ignore Reddit content labelled as NSFW.</p>
+			<?php } ?>
+			<?php if($opts->enable_wikipedia == "on") { ?>
+			<p>Goosle can search directly on Wikipedia. This will yield results linking to Wikipedia pages in the language of your choice. Configure your language in config.php or have it default to english.</p>
+			<?php } ?>
+
+			<h3>Result ranking</h3>
+			<p>To try and provide the best results first, if a website is found through multiple search engines it will show higher in the results on Goosle. Also the amount of matching words in the title and SEO description is considered. A better match will show higher in the results.</p>
+			<p>Result ranking is applied to web search and image search.</p>
 
 			<?php if($opts->enable_image_search == "on") { ?>
 				<h2>Image Search</h2>
@@ -87,19 +100,19 @@ if(verify_hash($opts, $auth)) {
 				<h3>Word Definition</h3>
 				<p>You can easily look up the meaning of single words. Prefix the word you want to look up with any of the following keywords; <strong>d</strong>, <strong>define</strong>, <strong>mean</strong> or <strong>meaning</strong>.<br />
 				For example: Searching for <strong>define search</strong> will search for that as normal, but also show the dictionary definition highlighted above the search results.</p>
-				<p><em><strong>Note:</strong> Special Searches do not work for image and torrent searches.</em></p>
+				<p><em><strong>Note:</strong> Special Searches do not work for image and magnet search.</em></p>
 			<?php } ?>
 			
-			<?php if($opts->enable_torrent_search == "on") { ?>
-				<h2>Torrent Search</h2>
+			<?php if($opts->enable_magnet_search == "on") { ?>
+				<h2>Magnet Search</h2>
 				<p>Search for anything torrent sites have on offer the direct search result should give you the magnet link.<br />Results are gathered from 1337x, Nyaa, The Pirate Bay, EZTV and YTS and are ranked by most seeders. The number of results is limited to 50.</p>
 				<p>The search scripts will try to provide useful data which may include; Seeders/Leechers, A link to the torrent page, Download Category, Release year, Movie quality (720p, 4K etc.), Movie Runtime and the Download Size. Not every website makes this available and all results take a best effort approach.</p>
 				<?php if($opts->imdb_id_search == "on") { ?>
 					<h3>Searching TV Shows</h3>
 					<p>To do a specific search on The Pirate Bay and EZTV you can search for IMDb Title IDs. These are numeric IDs prefixed with <strong>tt</strong>. This kind of search is useful when you're looking for a tv show that doesn't have a unique name, or simply if you want to use a specialized tracker for tv shows.</p>
-					<p>	If you already know the Title ID you can enter it directly in the Torrent search as your search query.<br />
+					<p>	If you already know the Title ID you can enter it directly in the Magnet Link search as your search query.<br />
 					If you don't know the Title ID you can do a regular search for <strong>imdb [tv show name]</strong>, for example <strong>imdb Jack Ryan</strong>.<br />
-					Goosle will detect the IMDb ID from the search results and show a special search result that offers you to search for Magnet Links through a torrent search.</p>
+					Goosle will detect the IMDb ID from the search results and include a highlight in the result that offers you to search for downloads through a magnet link search.</p>
 					
 				<?php } ?>
 				<h3>Filtering TV Show episodes</h3>
@@ -108,7 +121,7 @@ if(verify_hash($opts, $auth)) {
 				<p><em><strong>Note:</strong> If you like, or found a use for, what you downloaded, you should buy a legal copy of it.</em></p>
 			<?php } ?>
 
-			<p><small><strong>Acknowledgements:</strong><br />Goosle started as a fork of LibreY, and takes some design cues from DuckDuckGo.com. Goosle is created by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a> with the intent to make search fun again.</small></p>
+			<p><small><strong>Acknowledgements:</strong><br />Goosle started as a fork of LibreY, and takes some design cues from DuckDuckGo.com. Goosle is created by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a> with the intent to make search fun and productive.</small></p>
 		</section>
 	</div>
 </div>

+ 4 - 4
index.php

@@ -44,12 +44,12 @@ if(verify_hash($opts, $auth)) {
 	        <input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>
 	
 	        <div class="search-box-buttons">
-		        <button tabindex="20" name="t" value="0" type="submit">Search</button>
+		        <button tabindex="20" name="t" value="0" type="submit">Web search</button>
 		        <?php if($opts->enable_image_search == "on") { ?>
-		        <button tabindex="40" name="t" value="1" type="submit">Image</button>
+		        <button tabindex="40" name="t" value="1" type="submit">Image search</button>
 		        <?php } ?>
-		        <?php if($opts->enable_torrent_search == "on") { ?>
-		        <button tabindex="50" name="t" value="9" type="submit">Torrent</button>
+		        <?php if($opts->enable_magnet_search == "on") { ?>
+		        <button tabindex="50" name="t" value="9" type="submit">Magnet search</button>
 		        <?php } ?>
 	        </div>
 	

+ 30 - 15
readme.md

@@ -8,7 +8,7 @@ Replace Google search, replace DuckDuckGo and Ecosia but do not give up on it's
 
 On top of that, Goosle has a basic Image search tab which for now shows image results from Yahoo! Image Search.
 
-And, also very useful, a safe and clean Torrent search tab. Find anything you like in seconds without malware, ads or other site-breaking nonsense that would otherwise require a VPN to safely use Torrent sites. Results are sourced from some of the largest torrent providers, compiled and ordered in by the most seeders.
+And, also very useful, a safe and clean magnet link search tab. Find anything you like in seconds without malware, ads or other site-breaking nonsense that would otherwise require a VPN to safely use Torrent sites. Results are sourced from some of the largest torrent providers, compiled and ordered in by the most seeders.
 
 Host for yourself and friends, with a access hash key. Or set up a public search website.
 
@@ -20,6 +20,7 @@ After-all, finding things should be easy and not turn into a chore.
 - Works on **any** hosting package that does PHP7.4 or newer
 - Get search results from DuckDuckGo
 - Get search results from Google
+- Get search results from Reddit
 - Get search results from Wikipedia
 - Get search results from Ecosia (Bing)
 - Image search through Yahoo! Images
@@ -44,17 +45,18 @@ And yet it just works... fast!
 If you like Goosle, or found a use for it, please support my work and [donate](https://www.arnan.me/donate.html?mtm_campaign=goosle_readme) and tell everyone about its existence.
 
 ## Screenshots
-[![Goosle Mainpage](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage-150x150.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage.png)
-[![Goosle Search results](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-search-150x150.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-search.png)
-[![Goosle Torrent results](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-torrentsearch-150x150.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-torrentsearch.png)
+[![Goosle Mainpage](https://ajdg.solutions/wp-content/uploads/2024/01/goosle-main-150x150.jpg)](https://ajdg.solutions/wp-content/uploads/2024/01/goosle-main.jpg)
+[![Goosle Web Search](https://ajdg.solutions/wp-content/uploads/2024/01/goosle-search-150x150.jpg)](https://ajdg.solutions/wp-content/uploads/2024/01/goosle-search.jpg)
+[![Goosle Image Search](https://ajdg.solutions/wp-content/uploads/2024/01/goosle-images-150x150.jpg)](https://ajdg.solutions/wp-content/uploads/2024/01/goosle-images.jpg)
+[![Goosle Magnet Search](https://ajdg.solutions/wp-content/uploads/2024/01/goosle-torrents-150x150.jpg)](https://ajdg.solutions/wp-content/uploads/2024/01/goosle-torrents.jpg)
 
 ## Requirements
 Any basic webserver/webhosting package with PHP7.4 or newer. \
-No special requirments other than APCu for caching. \
-Tested to work on Apache with PHP8.0.24-8.2.x.
+No special requirements other than APCu for caching (Optional). \
+Tested to work on Apache with PHP8.0.24 and 8.2.x.
 
 ## Installation
-1. Unzip the download.
+1. Download and unzip Goosle.
 2. In the main directory. Copy config.default.php to config.php.
 3. Edit config.php file and set your preferences.
 4. Upload all files to your webserver, for example to the root folder of a subdomain (eg. example.com or search.example.com or a sub-folder such as example.com/search/)
@@ -63,7 +65,7 @@ Tested to work on Apache with PHP8.0.24-8.2.x.
 7. Let me know where you installed Goosle :-)
 
 ## Updating Goosle to a newer version
-1. Unzip the download.
+1. Download and unzip the latest release of Goosle.
 2. Check your config.php file and compare it to config.default.php. Go over your preferences. Make sure any new settings or changed values are present in your config.php. (Or reconfigure Goosle with a new copy from config.default.php)
 3. Upload all files to your webserver, overwriting all files except perhaps config.php.
 4. Load the site in your browser. If you've enabled the access hash don't forget to add *?a=YOURHASH* to the url.
@@ -83,19 +85,32 @@ You can post your questions on Github Discussions or on my support forum on [ajd
 Or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnandegans).
 
 ## Changelog
+1.3 - April 11, 2024
+- [fix] Image search crawler filters out non-image results better
+- [new] Crawler for results from magnetdl.com
+- [new] Direct Reddit.com search, search for 'Top Posts' created in the past year
+- [new] Added NSFW filter for Reddit results in config.default.php
+- [new] YTS movie highlights now link to YTS website when clicking the title
+- [new] Placeholder image for missing eztv highlight thumbnails
+- [tweak] Better hash matching for duplicate magnet results
+- [tweak] Better checking for missing/empty values in image search results
+- [tweak] Code cleanup
+- [tweak] More uniform code/variable names
+- [change] Naming overhaul - Replaced 'Torrent' with 'Magnet' throughout most of Goosle
+
 1.2.2 - February 16, 2024
 - [new] Individual on/off setting for each search engine and torrent site
 - [new] YTS Highlights for latest releases, highest rated or most downloaded movies
 - [new] EZTV Highlights for latest TV Show episode releases
 - [new] Goosle-cron.php file for if you want to clear the file cache in the background
-- [change] l33tx torrents disabled by default - They use Cloudflare now, preventing the crawler from working reliably
+- [change] l33tx search disabled by default - They use Cloudflare now, preventing the crawler from working reliably
 - [change] Ecosia search disabled by default - They use some kind of bot detector now, preventing the crawler from working once caught
 - [change] Now uses an ABSPATH global for file inclusions and paths
 - [change] More discrete TV Show and Movie result detection in text search
 - [tweak] Filter for eztv search, only include eztv if the search term starts with 'tt' (case insensitive)
 - [tweak] Better ecosia link formatting to (hopefully) not get blocked by their bot detector
 - [tweak] cURL headers to be (even) more browser-like
-- [fix] Variable $url sometimes empty for certain torrent results
+- [fix] Variable $url sometimes empty for certain magnet results
 - [fix] Blocked category filter for YTS results now actually works
 
 1.2.1 - January 15, 2024
@@ -104,7 +119,7 @@ Or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnand
 - [new] Blank index.php files in all subfolders to shield from prying eyes
 - [tweak] Improved version check
 - [fix] Stray periods in some Limetorrent categories
-- [fix] Inconsistent size indication for torrent results
+- [fix] Inconsistent size indication for magnet results
 
 1.2 - January 2, 2024
 - [new] Preferred language setting for DuckDuckGo results in config.php.
@@ -138,14 +153,14 @@ Or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnand
 - [new] config.default.php with default settings.
 - [new] New option 'imdb_id_search' in 'special' settings in config.php.
 - [new] New option 'show_zero_seeders' in config.php.
-- [new] Special result and torrent redirect for IMDb IDs.
+- [new] Special result and redirect for IMDb IDs.
 - [new] Replaced image search with Yahoo! Images.
 - [new] Styled 'reset' button for search fields.
 - [tweak] Removed 'raw_output' option.
 - [tweak] Re-arranged results array to be more logical/easy to use.
 - [tweak] Re-arranged code for results to do no double checks for search results.
 - [tweak] Added more user-agents.
-- [tweak] Torrent results page.
+- [tweak] Magnet results page.
 - [tweak] Sanitize scraped data earlier in the process.
 - [tweak] Consistent single quotes for arrays.
 - [tweak] Consistent spaces, tabs and newlines.
@@ -159,7 +174,7 @@ Or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnand
 - [change] Removed versioning indicator from help page.
 - [change] Added version indicator to results.php and help.php footer.
 - [change] 'Nope, Go away!' for unauthorized users changed to 'Goosle'.
-- [fix] Magnet links for torrents no longer opening in new tabs.
+- [fix] Magnet links no longer opening in new tabs.
 
 1.0.1 - December 5, 2023
 - [fix] mktime() getting intermittent strings in 1337x crawler.
@@ -170,7 +185,7 @@ Or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnand
 
 ## Acknowledgements and stuff
 Goosle started as a fork of LibreY, and ended up as a rewrite and something different completely. While the code structure remains largely the same, most functions have been rewritten or altered to work as I need it to. \
-Search results take design cues from DuckDuckGo and the torrent search has been modified to show more useful information where possible. \
+Search results take design cues from DuckDuckGo and the magnet search has been modified to show more useful information where possible. \
 Goosle does not index, store or distribute torrent files. If you like, or found a use for, what you downloaded, you should probably buy a legal copy of it.
 
 The name Goosle is my last name with an L added in. Translate it from Dutch. Not in any way a derivation of Google and DuckDuckGo combined :wink:

+ 3 - 3
results.php

@@ -46,10 +46,10 @@ if(verify_hash($opts, $auth)) {
 	        <div class="navigation-header">
 		        <a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="Search results" />Search</a>
 		        <?php if($opts->enable_image_search == "on") { ?>
-		        <a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/image.png" alt="Image results" />Image</a>
+		        <a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/image.png" alt="Image results" />Images</a>
 		        <?php } ?>
-		        <?php if($opts->enable_torrent_search == "on") { ?>
-		        <a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/torrent.png" alt="Torrent results" />Torrent</a>
+		        <?php if($opts->enable_magnet_search == "on") { ?>
+		        <a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/magnet.png" alt="Magnet results" />Magnet links</a>
 		        <?php } ?>
 	       </div>
 		</form>