瀏覽代碼

Version 1.2.2

- [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] 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] Blocked category filter for YTS results now actually works
Arnan de Gans 1 年之前
父節點
當前提交
f7971ae5ca

+ 43 - 18
assets/css/styles.css

@@ -9,8 +9,9 @@
 *  liability that might arise from its use.
 ------------------------------------------------------------------------------------ */
 
+html { font-size: 16px; }
 body { position: relative; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; color: #222; background-color: #ffffff; line-height: 1.2; }
-div { margin: 0; padding: 0; border: 0; font-size: 100%; vertical-align: baseline; }
+div { margin: 0; padding: 0; border: 0; vertical-align: baseline; }
 article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; }
 h2, h3, h4, h5, h6 { font-weight: normal; }
 h2, h3, h4, h5, h6, p, ul, ol, blockquote { margin: 0; padding-top: .5em; padding-bottom: .5em; }
@@ -34,18 +35,18 @@ input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; -
 /* Main page */
 body.main { background-color: #1f242b; color: #f0f6fc; }
 .search-box-main, .password-generator { text-align: center; margin-top: 10%; }
-.search-box-main h1 { font-size: 70px; }
-.search-box-main .search, .password-generator .password { padding: 10px 20px; width: 600px; color: #f0f6fc; background-color: #333333; font-size: 32px; font-family: sans-serif; border: 1px solid #3C4043; border-radius: 10px; }
+.search-box-main h1 { font-size: 4rem; }
+.search-box-main .search, .password-generator .password { padding: 10px 20px; width: 600px; color: #f0f6fc; background-color: #333333; font-size: 2rem; font-family: sans-serif; border: 1px solid #3C4043; border-radius: 10px; }
 .search-box-main .search[type="search"]::-webkit-search-cancel-button { background-size: 28px 28px; height: 28px; width: 28px; background-color: #f0f6fc; }
-.search-box-buttons button { margin: 30px 20px 10px 20px; padding: 13px 10px 13px 10px; min-width: 130px; color: #f0f6fc; background-color: #333333; font-size: 14px; border: 1px solid #3C4043; border-radius: 6px; }
+.search-box-buttons button { margin: 30px 20px 10px 20px; padding: 13px 10px 13px 10px; min-width: 130px; color: #f0f6fc; background-color: #333333; font-size: 0.8rem; border: 1px solid #3C4043; border-radius: 6px; }
 .search-box-buttons button:hover { border: 1px solid #5f6368; }
 
 .password-generator { margin: 30px auto; padding: 0; }
-.password-generator .password { margin: 10px auto; width: 300px; text-align: center; font-size: 14px; }
+.password-generator .password { margin: 10px auto; width: 300px; text-align: center; font-size: 0.8rem; }
 
 /* Search Results - Header */
 .header-wrap { background-color: #1f242b; color: #f0f6fc; border-bottom: 2px solid #1fa4d1; }
-.header-wrap .search, .header-wrap .button { position: relative; height: 40px; color: #f0f6fc; font-size: 100%; font-weight: 400; }
+.header-wrap .search, .header-wrap .button { position: relative; height: 40px; color: #f0f6fc; font-size: 1rem; font-weight: 400; }
 .header-wrap .search { margin: 28px 0 28px 158px; padding: 5px 5px 5px 15px; width: 580px; background-color: #1f242b; border: 1px solid #303842; border-radius: 10px 0 0 10px; }
 .header-wrap .search[type="search"]::-webkit-search-cancel-button { background-size: 20px 20px; height: 20px; width: 20px; background-color: #f0f6fc; }
 .header-wrap .button { margin: 28px 10px 28px 0; padding: 5px 20px 5px 15px; background-color: #1fa4d1; border: none; border-radius: 0 10px 10px 0; }
@@ -53,15 +54,15 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
 /* Search results - Header Navigation */
 .navigation-header { margin-left: 165px; margin-bottom: 10px; }
 .navigation-header img { margin-right: 5px; height: 16px; vertical-align: middle; }
-.navigation-header a { margin-right: 20px; border: none; font-size: 16px; cursor: pointer; text-decoration: none; }
+.navigation-header a { margin-right: 20px; border: none; font-size: 1rem; cursor: pointer; text-decoration: none; }
 .navigation-header a:hover { color: #ebf3fa; }
 .navigation-header a:visited { color: #1fa4d1; }
 .navigation-header .active { padding-bottom: 8px; border-bottom: 4px #1fa4d1 solid; }
 
-/* Search results - Main column */
+/* Search results */
 .main-column { width: 100%; }
 .main-column ol .meta { margin: .75rem 0 .05rem 0; padding: .5rem 10px 0 10px; }
-.main-column ol .sources { margin: .05rem 0 .75rem 0; padding: 0 10px .5rem 10px; font-size: 12px; color: #666; }
+.main-column ol .sources { margin: .05rem 0 .75rem 0; padding: 0 10px .5rem 10px; font-size: 0.75rem; color: #666; }
 
 .main-column ol .special-result { margin: .75rem 0 .25rem 0; padding: .5rem 10px; }
 .main-column ol .result { margin: .50rem 0 .50rem 0; padding: 0; }
@@ -80,7 +81,7 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
 .main-column ol li article div.description .seeders { color: #518257; }
 .main-column ol li article div.description .leechers { color: #c00; }
 
-/* Image results - Main column */
+/* Image results */
 .main-column .image-wrapper { width: 100%; margin: .75rem 0 .75rem 0; }
 @supports not (display: grid) {
 	.image-grid > * { max-width: 8rem; margin-left: auto; margin-right: auto; }
@@ -94,7 +95,7 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
 .main-column ol.image-grid .result .image-box::after { display: block; padding-bottom: 100%; content: ""; }
 .main-column ol.image-grid .result .image-box img { position: absolute; object-fit: cover; width: 100%; height: 100%; border-radius: 10px; }
 .main-column ol.image-grid .result .image-box img:hover { outline: none; border-color: #3C4043; box-shadow: 0 0 10px #3C4043; }
-.main-column ol.image-grid .result span { padding: 5px 0 0 0; color: #666; font-size: 12px; }
+.main-column ol.image-grid .result span { padding: 5px 0 0 0; color: #666; font-size: 0.75rem; }
 
 /* Special results - Main column */
 .main-column ol .special-result { background-color: #fefefe; }
@@ -108,6 +109,24 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
 .main-column ol li.special-result article div.source { display: inline-block; margin: 0; max-width: 100%; color: #666; font-size: 1rem; line-height: 1.6; letter-spacing: .2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-decoration: inherit; }
 .main-column ol li.special-result article div.source a { margin: 0; color: #3f6e35; text-decoration: none; }
 
+/* Magnet highlights */
+.main-column .magnet-wrapper { width: 100%; margin: .75rem 0 .75rem 0; }
+@supports not (display: grid) {
+	.magnet-grid > * { max-width: 8rem; margin-left: auto; margin-right: auto; }
+	.magnet-grid li.result { display: inline-block; margin: .75rem; width: 12.5%; }
+	.magnet-grid > * + * { margin-top: 1rem; }
+}
+@supports (display: grid) {
+	.main-column ol.magnet-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); grid-gap: 1rem; padding: .5rem 10px; }
+}
+.main-column ol.magnet-grid .result .magnet-box { position: relative; }
+.main-column ol.magnet-grid .result .magnet-box::after { display: block; content: ""; }
+.main-column ol.magnet-grid .result .magnet-box img { width: 100%; height: 100%; border-radius: 10px; }
+.main-column ol.magnet-grid .result .magnet-box p { visibility: hidden; opacity: 0; position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: #1f242b; transition: opacity .1s, visibility .1s; padding: 10px; line-height: 1.4; text-align: center; font-size: 0.8rem; color: #f0f6fc; }
+.main-column ol.magnet-grid .result .magnet-box a { display: block; position: relative; margin: 5px 0 5px 0; padding: 5px 20px; background-color: #1fa4d1; border: 1px solid #466f82; border-radius: 10px; color: #f0f6fc; font-weight: 800; text-align: center; }
+.main-column ol.magnet-grid .result .magnet-box a:hover { text-decoration: none; }
+.main-column ol.magnet-grid .result .magnet-box:hover p { visibility: visible; opacity: .90; outline: none; border-color: #3C4043; border-radius: 10px; box-shadow: 0 0 10px #3C4043; }
+
 /* Misc */
 .logo { position: absolute; margin: 28px 18px; }
 .logo a { color: #f0f6fc; cursor: pointer; }
@@ -116,7 +135,7 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
 .G { color: #1fa4d1; }
 .warning { position: relative; overflow: hidden; margin: 1rem 0 1rem 0; padding: .5rem 10px; color: #db9900; background-color: #ffffe0; border: 1px solid #e6db55; border-radius: 10px; }
 .error { position: relative; overflow: hidden; margin: 1rem 0 1rem 0; padding: .5rem 10px; color: #c00; background-color: #ffebe8; border: 1px solid #c00; border-radius: 10px; }
-.auth-error { margin-top: 15%; font-size: 32px; text-align: center; color: #eaeaea; }
+.auth-error { margin-top: 15%; font-size: 2rem; text-align: center; color: #eaeaea; }
 
 /* Footer bar */
 .footer-wrap { background-color: #161616; color: #f0f6fc; border-top: 2px solid #303134; }
@@ -143,7 +162,7 @@ a.update { color: #c90; font-weight: bold; }
 	.navigation-header a { margin: 0 auto; padding: 0; }
 
 	/* Misc */
-	.logo { position: relative; display: block;margin: 0 auto; float: none; padding: 10px; font-size: 28px; }
+	.logo { position: relative; display: block;margin: 0 auto; float: none; padding: 10px; font-size: 1.75rem; }
 }
 
 @media only screen and (max-width:640px)  { /* portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones */ 
@@ -164,7 +183,7 @@ a.update { color: #c90; font-weight: bold; }
 	.navigation-header a { margin: 0 auto; padding: 0; }
 
 	/* Misc */
-	.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 28px; }
+	.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 1.75rem; }
 }
 
 @media only screen and (max-width:480px)  { /* portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */ 
@@ -174,7 +193,7 @@ a.update { color: #c90; font-weight: bold; }
 	/* Main page */
 	.search-box-main { margin-top: 10%; }
 	.search-box-main input { width: 80%; }
-	.search-box-main h1 { font-size: 45px; }
+	.search-box-main h1 { font-size: 2.5rem; }
 	.search-box-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
 
 	/* Search Results - Header */
@@ -185,8 +204,11 @@ a.update { color: #c90; font-weight: bold; }
 	.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
 	.navigation-header a { margin: 0 auto; padding: 0; }
 
+	/* Magnet highlights */
+	.main-column .magnet-wrapper { display: none; }
+
 	/* Misc */
-	.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 28px; }
+	.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 1.75rem; }
 }
 
 @media only screen and (max-width:320px)  { /* smartphones, iPhone, portrait 480x320 phones */ 
@@ -196,7 +218,7 @@ a.update { color: #c90; font-weight: bold; }
 	/* Main page */
 	.search-box-main { margin-top: 40px; }
 	.search-box-main input { width: 80%; }
-	.search-box-main h1 { font-size: 45px; }
+	.search-box-main h1 { font-size: 2.5rem; }
 	.search-box-buttons button { display: table-row; margin: 20px 0px 0px 0px; width: 80%; }
 
 	/* Search Results - Header */
@@ -207,6 +229,9 @@ a.update { color: #c90; font-weight: bold; }
 	.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
 	.navigation-header a { margin: 0 auto; padding: 0; }
 
+	/* Magnet highlights */
+	.main-column .magnet-wrapper { display: none; }
+
 	/* Misc */
-	.logo { position: relative; float: none; display: block; margin: 0 auto; padding: 10px; font-size: 28px; }
+	.logo { position: relative; float: none; display: block; margin: 0 auto; padding: 10px; font-size: 1.75rem; }
 }

+ 69 - 50
config.default.php

@@ -24,8 +24,13 @@ HASH AUTH:
 	
 CACHE:
 	It is highly recommended to enable caching as it'll speed up repeat searches by a lot.
-	"on" (Recommended)
-	"off" Disables cache
+
+CACHE_TYPE:
+	Choose how to cache results. The cache is NOT unique per user but shared between all users. Different users searching for the exact same thing get the same results.
+	Default caching method is APCu. Alternatively, you can store the results in text files in the /cache/ folder.
+	Ignored if above 'cache' option is set to off.
+	"apcu" (Recommended) faster, utilize memory.
+	"file" Store results in text files.
 
 CACHE_TIME:
 	Minutes the result should be cached. Accepts a numeric value between 1 and 720.
@@ -34,12 +39,21 @@ CACHE_TIME:
 	To not show outdated results the 'limit' is 720 minutes, which equals 12 hours.
 	Ignored if above 'cache' option is set to off.
 
-CACHE_TYPE:
-	Choose how to cache results. The cache is NOT unique per user but shared between all users. Different users searching for the exact same thing get the same results.
-	Default caching method is APCu. Alternatively, you can store the results in text files in the /cache/ folder.
-	Ignored if above 'cache' option is set to off.
-	"apcu" (Recommended) faster, utilize memory.
-	"file" Store results in text files.
+
+
+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 SEARCH ENGINES:
+	Enable or disable search engines.
+
+ENABLE MAGNET CRAWLERS:
+	Enable or disable crawlers to pull magnet links from.
+
+
 
 LANGUAGE:
 	DuckDuckGo, Google and Ecosia are language agnostic. But they DO profile you for your locale.
@@ -55,56 +69,34 @@ SOCIAL MEDIA RELEVANCE:
 	!!CAREFUL!! This is a blanket setting, if what you're searching for primarily has social media links then less relevant results may show first.
 	Accepts a numeric value between 1 and 10. With 10 having *NO* effect on the rank, and 0 not ranking the link at all (shows very very low in the results)
 
-ENABLE IMAGE SEARCH:
-	Enable or disable image searches - Search results are provided by Yahoo! Images.
-	"on" (Default)
-	"off"
-
-ENABLE TORRENT SEARCH:
-	Enable or disable searching for torrent downloads.
-	"on" (Default)
-	"off"
-
 SHOW SEARCH SOURCE:
 	Show which search engine(s) came up with the result.
-	"on" (Default)
-	"off"
 
 SHOW SEARCH RANK:
 	When search source is enabled, show the rank Goosle gave the result.
-	"on"
-	"off" (Default)
 
 IMDB ID SEARCH:
-	Highlight imdb results if it's a tv-show.
+	Highlight imdb results if it's a tv-show or movie.
 	Handy for finding better results for specific tv-shows through EZTV and The Pirate Bay.
-	"on"
-	"off" (Default)
 
 PASSWORD GENERATOR
 	Show a password generator on the Goosle home page.
-	"on" (Default)
-	"off"
+
+
 		
 SPECIAL:
 	Enable or disable special searches that show up before search results.
-	"on" (Default)
-	"off" Disable this special search
 
-USER AGENTS:
-	Add more or less user agents to the list. Keep at least one!
-	On every search Goosle picks one at random to identify as.
-	Keep them generic to prevent profiling, but also so that the request comes off as a generic boring browser and not as a server/crawler.
-	
-	Safari, Firefox and Internet Explorer/Edge should be safe to use.
-	Chrome may attract attention because of the lack of Chrome information (tracking) aside from the user agent. The search engine may know something is 'weird'.
-	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.
+
 
 SHOW ZERO SEEDERS:
 	Set to "on" to include results with 0 seeders (slow or stale downloads). Off to exclude these results.
-	"on" (Default)
-	"off"
+
+YTS HIGHLIGHT:
+	If you've enabled the YTS special search, you can also choose what it should show. The 8 most [insert choice] movies.
+	"date_added" = Newest movies (Default).
+	"rating" = Highest rated movies as per imdb.
+	"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.
@@ -119,6 +111,18 @@ BLOCK YTS CATEGORIES:
 	Movies can be in multiple categories, if a movie is in 5 categories it only has to match one to be filtered out.
 	Accepts a basic array of keywords, comma separated.
 
+
+
+USER AGENTS:
+	Add more or less user agents to the list. Keep at least one!
+	On every search Goosle picks one at random to identify as.
+	Keep them generic to prevent profiling, but also so that the request comes off as a generic boring browser and not as a server/crawler.
+	
+	Safari, Firefox and Internet Explorer/Edge should be safe to use.
+	Chrome may attract attention because of the lack of Chrome information (tracking) aside from the user agent. The search engine may know something is 'weird'.
+	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:
 	Only used for The Pirate Bay, LimeTorrents and YTS.
 	Generally you do not need to change these.
@@ -133,14 +137,25 @@ return (object) array(
     "cache_type" => "apcu", // Default: apcu
     "cache_time" => 30, // Default: 30 (Minutes)
 
-    "duckduckgo_language" => "uk-en", // Default: uk-en (United Kingdom)
-    "wikipedia_language" => "en", // Default: en (English)
-
-    "social_media_relevance" => 8, // Default: 8
-
     "enable_image_search" => "on", // Default: on
     "enable_torrent_search" => "on", // Default: on
+    "enable_duckduckgo" => "on", // Default: on
+    "enable_google" => "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?)
+
+    "enable_limetorrents" => "on", // Default: on
+    "enable_piratebay" => "on", // Default: on
+    "enable_yts" => "on", // Default: on
+    "enable_nyaa" => "on", // Default: on	
+    "enable_eztv" => "on", // Default: on
+    "enable_l33tx" => "off", // Default: off
+    	// Site now uses cloudflare preventing crawler from working since Jan 20, 2024, remove support in future release?)
 
+    "duckduckgo_language" => "uk-en", // Default: uk-en (United Kingdom)
+    "wikipedia_language" => "en", // Default: en (English)
+    "social_media_relevance" => 8, // Default: 8
     "show_search_source" => "on", // Default: on
     "show_search_rank" => "off", // Default: off
 	"imdb_id_search" => "off", // Default: off
@@ -149,9 +164,17 @@ return (object) array(
 	"special" => array(
 		"currency" => "on", // Default: on, Currency converter
 		"definition" => "on", // Default: on, Word dictionary
-		"phpnet" => "off" // Default: off, PHP-dot-net highlight
+		"phpnet" => "on", // Default: on, PHP-dot-net highlight
+		"yts" => "on", // Default: on, Show latest, or highlighted movies from YTS
+		"eztv" => "on" // Default: on, Show latest TV Show episodes from EZTV
 	),
 
+    "show_zero_seeders" => "on", // Default: on
+    "yts_highlight" => "date_added", // Default: "date_added"
+    "leetx_categories_blocked" => array(3, 7, 47), // Default: 3, 7, 47
+    "piratebay_categories_blocked" => array(206, 210), // Default: 206, 210
+    "yts_categories_blocked" => array("horror"), // Default: "horror"
+
 	"user_agents" => array(
 		"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15) Gecko/20100101 Firefox/119.0", // macOS 10.15, Firefox 119
 		"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/116.0", // Windows 10, Firefox 116
@@ -159,10 +182,6 @@ return (object) array(
 		"Mozilla/5.0 (X11; Linux i686) Gecko/20100101 Firefox/119.0", // Linux Generic, Firefox 119
 	),
 
-    "show_zero_seeders" => "on", // Default: on
-    "leetx_categories_blocked" => array(3, 7, 47), // Default: 3, 7, 47
-    "piratebay_categories_blocked" => array(206, 210), // Default: 206, 210
-    "yts_categories_blocked" => array("horror"), // Default: "horror"
     "torrent_trackers" => array(
     	"http://nyaa.tracker.wf:7777/announce", 
 		"http://tracker.openbittorrent.com:80/announce",

+ 3 - 2
engines/search-image.php

@@ -13,7 +13,7 @@ class ImageSearch extends EngineRequest {
 	protected $requests;
 	
 	public function __construct($opts, $mh) {
-		require "engines/image/yahoo.php";
+		require ABSPATH."engines/image/yahoo.php";
 		
 		$this->requests = array(
 			new YahooImageRequest($opts, $mh),
@@ -67,9 +67,10 @@ class ImageSearch extends EngineRequest {
 			} else {
 				$request_result = curl_getinfo($request->ch);
 				$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
+				$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array("title" => get_class($request)." failed with error ".$request_result['http_code'], "body" => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", "labels" => 'request-error'));
 				
 	            $results['error'][] = array(
-	                "message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."."
+	                "message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
 	            );
 			}
 			

+ 104 - 22
engines/search-torrent.php

@@ -10,24 +10,45 @@
 *  liability that might arise from its use.
 ------------------------------------------------------------------------------------ */
 class TorrentSearch extends EngineRequest {
-	protected $requests;
+	protected $requests, $special_request;
 	
 	public function __construct($opts, $mh) {
-		require "engines/torrent/1337x.php";
-		require "engines/torrent/lime.php";
-		require "engines/torrent/thepiratebay.php";
-		require "engines/torrent/yts.php";
-		require "engines/torrent/nyaa.php";
-		require "engines/torrent/eztv.php";
+		$this->requests = array();
+
+		if($opts->enable_limetorrents == "on") {
+			require ABSPATH."engines/torrent/lime.php";
+			$this->requests[] = new LimeRequest($opts, $mh);
+		}
+
+		if($opts->enable_piratebay == "on") {
+			require ABSPATH."engines/torrent/thepiratebay.php";
+			$this->requests[] = new PirateBayRequest($opts, $mh);
+		}
+
+		if($opts->enable_yts == "on") {
+			require ABSPATH."engines/torrent/yts.php";
+			$this->requests[] = new YTSRequest($opts, $mh);
+		}
+
+		if($opts->enable_nyaa == "on") {
+			require ABSPATH."engines/torrent/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";
+				$this->requests[] = new EZTVRequest($opts, $mh);
+			}
+		}
+
+		if($opts->enable_l33tx == "on") {
+			require ABSPATH."engines/torrent/1337x.php";
+			$this->requests[] = new LeetxRequest($opts, $mh);
+		}
 		
-		$this->requests = array(
-			new LeetxRequest($opts, $mh), // 1337x
-			new LimeRequest($opts, $mh), // Limetorrents
-			new PirateBayRequest($opts, $mh),
-			new YTSRequest($opts, $mh),
-			new NyaaRequest($opts, $mh),
-			new EZTVRequest($opts, $mh)
-		);
+		// Special search
+		$this->special_request = special_torrent_request($opts, $mh);
 	}
 
     public function parse_results($response) {
@@ -38,9 +59,6 @@ class TorrentSearch extends EngineRequest {
 				$engine_result = $request->get_results();
 
 				if(!empty($engine_result)) {
-					// No merging of results
-//					$results_temp = array_merge($results_temp, $engine_result);
-
 					// Merge duplicates and apply relevance scoring
 					foreach($engine_result as $result) {
 						if(count($results_temp) > 1 && !is_null($result['hash'])) {
@@ -71,16 +89,24 @@ class TorrentSearch extends EngineRequest {
 				}
 			} else {
 				$request_result = curl_getinfo($request->ch);
-				$http_code_info = ($request_result['http_code'] >= 200 && $request_result['http_code'] <= 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
+				$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
+				$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array("title" => get_class($request)." failed with error ".$request_result['http_code'], "body" => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", "labels" => 'request-error'));
 				
 	            $results['error'][] = array(
-	                "message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."."
+	                "message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
 	            );
             }
             
             unset($request);
         }
 
+		// Check for Special result
+        if(count($this->special_request) > 0) {
+            foreach($this->special_request as $source => $highlight) {
+            	$results['special'][$source] = $highlight->get_results();
+            }
+        }
+
 		if(count($results_temp) > 0) {
 			// Sort by highest seeders
 	        $seeders = array_column($results_temp, "combo_seeders");
@@ -117,6 +143,59 @@ print_r($results);
 echo '</pre>';
 */
 
+		// Special results
+		if(array_key_exists("special", $results)) {
+			echo "<div class=\"magnet-wrapper\">";
+			if(array_key_exists("yts", $results['special'])) {
+				if($opts->yts_highlight == "date_added") echo "<h2>Latest releases from YTS</h2>";
+				if($opts->yts_highlight == "rating") echo "<h2>Highest rated on YTS</h2>";
+				if($opts->yts_highlight == "download_count") echo "<h2>Most downloaded from YTS</h2>";
+				if($opts->yts_highlight == "seeds") echo "<h2>Most seeded on YTS</h2>";
+				echo "<ol class=\"magnet-grid\">";
+		
+				foreach($results['special']['yts'] as $highlight) {
+					echo "<li class=\"result\">";
+					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>";
+					}
+					echo "</p>";
+					echo "</div>";
+					echo "<strong>".$highlight['name']."</strong>";
+					echo "</li>";	
+				}
+				unset($highlight);
+		
+		        echo "</ol>";
+			}
+
+			if(array_key_exists("eztv", $results['special'])) {
+				echo "<h2>Latest releases from EZTV</h2>";
+				echo "<ol class=\"magnet-grid\">";
+		
+				foreach($results['special']['eztv'] as $highlight) {
+					echo "<li class=\"result\">";
+					echo "<div class=\"magnet-box\">";
+					echo "<img src=\"".$highlight['thumbnail']."\" alt=\"".$highlight['name']."\" />";
+			       	echo "<p>".$highlight['quality']."<br />";
+			       	echo "<a href=\"".$highlight['magnet']."\">Download</a></p>";
+					echo "</div>";
+					echo "<strong>".$highlight['name']." S".$highlight['season']."E".$highlight['episode']."</strong>";
+					echo "</li>";	
+				}
+				unset($highlight);
+
+		        echo "</ol>";
+			}
+	        echo "</div>";
+		}
+
+		// Main content
 		if(array_key_exists("search", $results)) {
 			echo "<ol>";
 
@@ -132,11 +211,14 @@ echo '</pre>';
 				// Extra data
 				$meta = array();
 				if(array_key_exists('quality', $result)) $meta[] = "<strong>Quality:</strong> ".$result['quality'];
+				if(array_key_exists('codec', $result)) $meta[] = "<strong>Codec:</strong> ".$result['codec'];
 				if(array_key_exists('year', $result)) $meta[] = "<strong>Year:</strong> ".$result['year'];
 				if(array_key_exists('category', $result)) $meta[] = "<strong>Category:</strong> ".$result['category'];
 				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(array_key_exists('url', $result)) $url = " - <a href=\"".$result['url']."\" target=\"_blank\" title=\"Careful - Site may contain intrusive popup ads and malware!\">torrent page</a>";
+
+				// If available, add the url to the first found torrent result 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
 				echo "<li class=\"result\"><article>";
@@ -145,7 +227,7 @@ echo '</pre>';
 				if($opts->show_search_source == "on") echo "<div class=\"description\"><strong>Found on:</strong> ".replace_last_comma(implode(", ", $result['combo_source'])).$url."</div>";
 				echo "</article></li>";
 
-				unset($result, $meta);
+				unset($result, $meta, $url);
 			}
 
 			echo "</ol>";

+ 41 - 15
engines/search.php

@@ -13,18 +13,28 @@ class Search extends EngineRequest {
 	protected $requests, $special_request;
 	
 	public function __construct($opts, $mh) {
-		require "engines/search/duckduckgo.php";
-		require "engines/search/google.php";
-		require "engines/search/wikipedia.php";
-		require "engines/search/ecosia.php";
+		$this->requests = array();
 		
-		$this->requests = array(
-			new DuckDuckGoRequest($opts, $mh),
-			new GoogleRequest($opts, $mh),
-			new WikiRequest($opts, $mh),
-			new EcosiaRequest($opts, $mh),
-		);
+		if($opts->enable_duckduckgo == "on") {
+			require ABSPATH."engines/search/duckduckgo.php";
+			$this->requests[] = new DuckDuckGoRequest($opts, $mh);	
+		}
+
+		if($opts->enable_google == "on") {
+			require ABSPATH."engines/search/google.php";
+			$this->requests[] = new GoogleRequest($opts, $mh);	
+		}
+
+		if($opts->enable_wikipedia == "on") {
+			require ABSPATH."engines/search/wikipedia.php";
+			$this->requests[] = new WikiRequest($opts, $mh);	
+		}
 
+		if($opts->enable_ecosia == "on") {
+			require ABSPATH."engines/search/ecosia.php";
+			$this->requests[] = new EcosiaRequest($opts, $mh);	
+		}
+		
 		// Special search
 		$this->special_request = special_search_request($opts);
 	}
@@ -32,7 +42,6 @@ class Search extends EngineRequest {
     public function parse_results($response) {
         $results = array();
 
-		// Merge all results together
         foreach($this->requests as $request) {
 			if($request->request_successful()) {
 				$engine_result = $request->get_results();
@@ -83,9 +92,10 @@ class Search extends EngineRequest {
 			} else {
 				$request_result = curl_getinfo($request->ch);
 				$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
-				
+				$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array("title" => get_class($request)." failed with error ".$request_result['http_code'], "body" => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", "labels" => 'request-error'));
+
 	            $results['error'][] = array(
-	                "message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."."
+	                "message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
 	            );
 			}
 			
@@ -148,20 +158,36 @@ echo '</pre>';
 			search_suggestion($opts, $results);
 
 			// Special results
-			special_search_result($opts, $results);
-
+			if(array_key_exists("special", $results)) {
+				echo "<li class=\"special-result\"><article>";
+				echo "<div class=\"title\"><h2>".$results['special']['title']."</h2></div>";
+				echo "<div class=\"text\">".$results['special']['text']."</div>";
+				if(array_key_exists("source", $results['special'])) {
+					echo "<div class=\"source\"><a href=\"".$results['special']['source']."\" target=\"_blank\">".$results['special']['source']."</a></div>";
+				}
+				echo "</article></li>";
+			}
+		
 			// Search results
 	        foreach($results['search'] as $result) {
+				if($opts->imdb_id_search == "on") {
+					if(stristr($result['url'], "imdb.com") !== false && preg_match_all("/(?:tt[0-9]+)/i", $result['url'], $imdb_result)) {
+						$result['description'] = $result['description']."<br /><strong>Goosle detected an IMDb ID for this result, search for <a href=\"./results.php?q=".$imdb_result[0][0]."&a=".$opts->hash."&t=9\">magnet links</a>?</strong>";
+					}
+				}
+
 				echo "<li class=\"result rs-".$result['goosle_rank']." id-".$result['id']."\"><article>";
 				echo "<div class=\"url\"><a href=\"".$result['url']."\" target=\"_blank\">".get_formatted_url($result['url'])."</a></div>";
 				echo "<div class=\"title\"><a href=\"".$result['url']."\" target=\"_blank\"><h2>".$result['title']."</h2></a></div>";
 				echo "<div class=\"description\">".$result['description']."</div>";
+
 				if($opts->show_search_source == "on") {
 					echo "<div class=\"engine\">";
 					echo "Found on ".replace_last_comma(implode(", ", $result['combo_source'])).".";
 					if($opts->show_search_rank == "on") echo " [rank: ".$result['goosle_rank']."]";
 					echo "</div>";
 				}
+
 				echo "</article></li>";
 	        }
 

+ 1 - 1
engines/search/ecosia.php

@@ -11,7 +11,7 @@
 ------------------------------------------------------------------------------------ */
 class EcosiaRequest extends EngineRequest {
     public function get_request_url() {
-		$args = array("q" => $this->query, "addon" => "opensearch");
+		$args = array("q" => $this->query, "method" => "index", "addon" => "opensearch");
         $url = "https://www.ecosia.org/search/?".http_build_query($args);
 
         return $url;

+ 55 - 0
engines/special/eztv_highlights.php

@@ -0,0 +1,55 @@
+<?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 eztvhighlights extends EngineRequest {
+    public function get_request_url() {
+        $url = "https://eztvx.to/api/get-torrents?".http_build_query(array("limit" => "16"));
+        return $url;
+    }
+    
+    public function parse_results($response) {
+		$results = array();
+		$json_response = json_decode($response, true);
+		
+		// No response
+		if(empty($json_response)) return $results;
+		
+		// Nothing found
+		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']);
+			$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] : "";
+
+			// Clean up show name
+			$name = (preg_match("/.+?(?=S[0-9]{1,3}E[0-9]{1,3})/i", $name, $clean_name)) ? $clean_name[0] : $name;
+			
+			// Set up codec for quality
+			if(!empty($codec)) $quality = $quality." ".$codec;
+
+			$results[] = array (
+				"name" => $name, "thumbnail" => $thumbnail, "season" => $season, "episode" => $episode, "magnet" => $highlight, "quality" => $quality
+			);
+
+			unset($highlight, $name, $clean_name, $thumbnail, $season, $episode, $highlight, $quality, $codec);
+		}
+		unset($json_response);
+
+		return array_slice($results, 0, 16);
+    }
+}
+?>

+ 66 - 0
engines/special/yts_highlights.php

@@ -0,0 +1,66 @@
+<?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 ytshighlights extends EngineRequest {
+    public function get_request_url() {
+        $url = "https://yts.mx/api/v2/list_movies.json?".http_build_query(array("limit" => "20", "sort_by" => $this->opts->yts_highlight));
+        return $url;
+    }
+    
+    public function parse_results($response) {
+		$results = $torrents = array();
+		$response = curl_multi_getcontent($this->ch);
+		$json_response = json_decode($response, true);
+		
+		// No response
+		if(empty($json_response)) return $results;
+		
+		// Nothing found
+		if($json_response['status'] != "ok" || $json_response['data']['movie_count'] == 0) return $results;
+		
+		// Use API result
+		foreach ($json_response['data']['movies'] as $highlight) {
+			// 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";
+
+			// Block these categories
+			if(count(array_uintersect($highlight['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']);
+
+			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']);
+			
+				$torrents[] = array (
+					"magnet" => $magnet, "quality" => $quality, "codec" => $codec
+				);
+			}
+
+			$results[] = array (
+				"name" => $name, "thumbnail" => $thumbnail, "year" => $year, "category" => $category, "rating" => $rating, 'torrents' => $torrents
+			);
+			unset($highlight, $name, $thumbnail, $year, $category, $rating, $hash, $magnet, $quality, $codec, $torrents);
+		}
+		unset($json_response);
+
+		return array_slice($results, 0, 8);
+    }
+}
+?>

+ 2 - 2
engines/torrent/1337x.php

@@ -112,8 +112,8 @@ class LeetxRequest extends EngineRequest {
 			$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;
-			$seeders = sanitize_numeric(sanitize($xpath->evaluate(".//td[@class='coll-2 seeds']", $result)[0]->textContent));
-			$leechers = sanitize_numeric(sanitize($xpath->evaluate(".//td[@class='coll-3 leeches']", $result)[0]->textContent));
+			$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));
 			$size = $size_unformatted[0] . " " . preg_replace("/[0-9]+/", "", $size_unformatted[1]);
 			

+ 15 - 16
engines/torrent/eztv.php

@@ -16,11 +16,9 @@ class EZTVRequest extends EngineRequest {
 
 		// Is eztvx.to blocked for you? Use one of these urls as an alternative
 		// eztv1.xyz, eztv.wf, eztv.tf, eztv.yt
+        $url = "https://eztvx.to/api/get-torrents?".http_build_query(array("imdb_id" => $query));
 
-		$args = array("imdb_id" => $query);
-        $url = "https://eztvx.to/api/get-torrents?".http_build_query($args);
-
-        unset($query, $args);
+        unset($query);
 
         return $url;
 	}
@@ -36,25 +34,26 @@ class EZTVRequest extends EngineRequest {
 		if($json_response['torrents_count'] == 0) return $results;
 		
 		// Use API result
-		foreach($json_response['torrents'] as $episode) {
-			$name = sanitize($episode['title']);
-			$magnet = sanitize($episode['magnet_url']);
-			$hash = sanitize($episode['hash']);
-			$seeders = sanitize_numeric(sanitize($episode['seeds']));
-			$leechers = sanitize_numeric(sanitize($episode['peers']));
-			$size = sanitize($episode['size_bytes']);
+		foreach($json_response['torrents'] as $result) {
+			$name = sanitize($result['title']);
+			$magnet = sanitize($result['magnet_url']);
+			$hash = sanitize($result['hash']);
+			$seeders = sanitize($result['seeds']);
+			$leechers = sanitize($result['peers']);
+			$size = sanitize($result['size_bytes']);
 			
 			// Ignore results with 0 seeders?
 			if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
 			
 			// Get extra data
-			$quality = (preg_match('/(480p|720p|1080p|2160p)/i', $name, $quality)) ? $quality[0] : "Unknown";
-			$date_added = sanitize($episode['date_released_unix']);
+			$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] : "";
+			$date_added = sanitize($result['date_released_unix']);
 			
 			// Filter by Season (S01) or Season and Episode (S01E01)
 			// Where [0][0] = Season and [0][1] = Episode
-			$season = sanitize($episode['season']);
-			$episode = sanitize($episode['episode']);
+			$season = sanitize($result['season']);
+			$episode = sanitize($result['episode']);
 			
 			if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $filter_episode)) {
 				if(str_ireplace("s0", "", $filter_episode[0][0]) != $season || (array_key_exists(1, $filter_episode[0]) && str_ireplace("e0", "", $filter_episode[0][1]) != $episode)) {
@@ -68,7 +67,7 @@ class EZTVRequest extends EngineRequest {
 				// Required
 				"id" => $id, "source" => "EZTV", "name" => $name, "magnet" => $magnet, "hash" => $hash, "seeders" => $seeders, "leechers" => $leechers, "size" => human_filesize($size),
 				// Extra
-				"quality" => $quality, "date_added" => $date_added
+				"quality" => $quality, "codec" => $codec, "date_added" => $date_added
 			);
 		}
 		unset($json_response);

+ 2 - 2
engines/torrent/lime.php

@@ -31,8 +31,8 @@ class LimeRequest extends EngineRequest {
 			$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);
-			$seeders = sanitize_numeric(sanitize($xpath->evaluate(".//td[@class='tdseed']", $result)[0]->textContent));
-			$leechers = sanitize_numeric(sanitize($xpath->evaluate(".//td[@class='tdleech']", $result)[0]->textContent));
+			$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);
 
 			// Ignore results with 0 seeders?

+ 2 - 2
engines/torrent/nyaa.php

@@ -35,8 +35,8 @@ class NyaaRequest extends EngineRequest {
 			$hash = parse_url($magnet, PHP_URL_QUERY);
 			parse_str($hash, $hash_parameters);
 			$hash = str_replace("urn:btih:", "", $hash_parameters['xt']);
-			$seeders = sanitize_numeric(sanitize($meta[3]->textContent));
-			$leechers = sanitize_numeric(sanitize($meta[4]->textContent));
+			$seeders = sanitize($meta[3]->textContent);
+			$leechers = sanitize($meta[4]->textContent);
 			$size =  str_replace("GiB", "GB", str_replace("MiB", "MB", sanitize($meta[1]->textContent)));
 
 			// Ignore results with 0 seeders?

+ 2 - 2
engines/torrent/thepiratebay.php

@@ -97,8 +97,8 @@ class PirateBayRequest extends EngineRequest {
 			$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);
-			$seeders = sanitize_numeric(sanitize($response['seeders']));
-			$leechers = sanitize_numeric(sanitize($response['leechers']));
+			$seeders = sanitize($response['seeders']);
+			$leechers = sanitize($response['leechers']);
 			$size = sanitize($response['size']);
 			
 			// Ignore results with 0 seeders?

+ 6 - 8
engines/torrent/yts.php

@@ -11,10 +11,7 @@
 ------------------------------------------------------------------------------------ */
 class YTSRequest extends EngineRequest {
 	public function get_request_url() {
-		$args = array("query_term" => $this->query);
-        $url = "https://yts.mx/api/v2/list_movies.json?".http_build_query($args);
-
-        unset($args);
+        $url = "https://yts.mx/api/v2/list_movies.json?".http_build_query(array("query_term" => $this->query));
 
         return $url;
 	}
@@ -39,7 +36,7 @@ class YTSRequest extends EngineRequest {
 			if(!array_key_exists("url", $movie)) $movie['url'] = '';
 			
 			// Block these categories
-			if(array_intersect($movie['genres'], $this->opts->yts_categories_blocked)) continue;
+			if(count(array_uintersect($movie['genres'], $this->opts->yts_categories_blocked, "strcasecmp")) > 0) continue;
 			
 			$name = sanitize($movie['title']);
 			
@@ -53,8 +50,8 @@ class YTSRequest extends EngineRequest {
 			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_numeric(sanitize($torrent['seeds']));
-				$leechers = sanitize_numeric(sanitize($torrent['peers']));
+				$seeders = sanitize($torrent['seeds']);
+				$leechers = sanitize($torrent['peers']);
 				$size = sanitize($torrent['size']);
 				
 				// Ignore results with 0 seeders?
@@ -62,13 +59,14 @@ class YTSRequest extends EngineRequest {
 				
 				// Get extra data
 				$quality = sanitize($torrent['quality']);
+				$codec = sanitize($torrent['video_codec']);
 				$id = uniqid(rand(0, 9999));
 			
 				$results[] = array (
 					// Required
 					"id" => $id, "source" => "yts.mx", "name" => $name, "magnet" => $magnet, "hash" => $hash, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
 					// Extra
-					"quality" => $quality, "year" => $year, "category" => $category, "runtime" => $runtime, "url" => $url, "date_added" => $date_added
+					"quality" => $quality, "codec" => $codec, "year" => $year, "category" => $category, "runtime" => $runtime, "url" => $url, "date_added" => $date_added
 				);
 			}
 		}

+ 28 - 32
functions/search_engine.php

@@ -88,31 +88,6 @@ abstract class EngineRequest {
 	public static function print_results($results, $opts) {}
 }
 
-/*--------------------------------------
-// Load and make config available, pass around variables
---------------------------------------*/
-function load_opts() {
-	$opts = require "config.php";
-	
-	// From the url/request	
-	$opts->query = (isset($_REQUEST['q'])) ? trim($_REQUEST['q']) : "";
-	$opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
-	$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : "";
-	
-	// Force a few defaults and safeguards
-	if($opts->cache_type == "file" && !is_dir(dirname(__DIR__).'/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(!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;
-	
-	// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
-	if(substr($opts->query, 0, 1) == "!") $opts->query = substr($opts->query, 1);
-	
-	return $opts;
-}
-
 /*--------------------------------------
 // Try to get some search results
 --------------------------------------*/
@@ -127,13 +102,13 @@ function fetch_search_results($opts) {
 
 		// Load search script
 	    if($opts->type == 0) {
-	        require "engines/search.php";
+	        require ABSPATH."engines/search.php";
 	        $search = new Search($opts, $mh);
 		} else if($opts->type == 1) {
-		    require "engines/search-image.php";
+		    require ABSPATH."engines/search-image.php";
 	        $search = new ImageSearch($opts, $mh);
 		} else if($opts->type == 9) {
-		    require "engines/search-torrent.php";
+		    require ABSPATH."engines/search-torrent.php";
 	        $search = new TorrentSearch($opts, $mh);
 	    }
 	
@@ -144,7 +119,7 @@ function fetch_search_results($opts) {
 	    } while ($running);
 	
 	    $results = $search->get_results();
-	
+
 		curl_multi_close($mh);
 	
 		// Add elapsed time to results
@@ -164,27 +139,48 @@ function fetch_search_results($opts) {
 --------------------------------------*/
 function special_search_request($opts) {
 	$special_request = null;
+
     $query_terms = explode(" ", $opts->query);
 	$query_terms[0] = strtolower($query_terms[0]);
 
 	// Currency converter
 	if($opts->special['currency'] == "on" && count($query_terms) == 4 && (is_numeric($query_terms[0]) && ($query_terms[2] == 'to' || $query_terms[2] == 'in'))) {
-        require "engines/special/currency.php";
+        require ABSPATH."engines/special/currency.php";
         $special_request = new CurrencyRequest($opts, null);
 	}
 	
 	// Dictionary
 	if($opts->special['definition'] == "on" && count($query_terms) == 2 && ($query_terms[0] == 'define' || $query_terms[0] == 'd' || $query_terms[0] == 'mean' || $query_terms[0] == 'meaning')) {
-        require "engines/special/definition.php";
+        require ABSPATH."engines/special/definition.php";
         $special_request = new DefinitionRequest($opts, null);
 	}
 
 	// php.net search
 	if($opts->special['phpnet'] == "on" && count($query_terms) == 2 && $query_terms[0] == 'php') {
-        require "engines/special/php.php";
+        require ABSPATH."engines/special/php.php";
         $special_request = new PHPnetRequest($opts, null);
 	}
 	
 	return $special_request;
 }
+
+/*--------------------------------------
+// Process special torrent features
+--------------------------------------*/
+function special_torrent_request($opts, $mh) {
+	$special_request = array();
+
+	// Latest additions to yts
+	if($opts->special['yts'] == "on") {
+        require ABSPATH."engines/special/yts_highlights.php";
+        $special_request['yts'] = new ytshighlights($opts, $mh);
+	}
+
+	if($opts->special['eztv'] == "on") {
+        require ABSPATH."engines/special/eztv_highlights.php";
+        $special_request['eztv'] = new eztvhighlights($opts, $mh);
+	}
+	
+	return $special_request;
+}
 ?>

+ 39 - 46
functions/tools.php

@@ -19,28 +19,51 @@ function verify_hash($opts, $auth) {
     return false;
 }
 
+/*--------------------------------------
+// Load and make config available, pass around variables
+--------------------------------------*/
+function load_opts() {
+	$opts = require ABSPATH."config.php";
+	
+	// From the url/request	
+	$opts->query = (isset($_REQUEST['q'])) ? trim($_REQUEST['q']) : "";
+	$opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
+	$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : "";
+	
+	// Force a few defaults and safeguards
+	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(!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;
+	
+	// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
+	if(substr($opts->query, 0, 1) == "!") $opts->query = substr($opts->query, 1);
+	
+	return $opts;
+}
+
 /*--------------------------------------
 // Set curl options
 --------------------------------------*/
 function set_curl_options($curl, $url, $user_agents) {
-	$referer_url = parse_url($url);
-
 	curl_setopt($curl, CURLOPT_URL, $url);
 	curl_setopt($curl, CURLOPT_HTTPGET, 1); // Redundant? Probably...
 	curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
 	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
 	curl_setopt($curl, CURLOPT_USERAGENT, $user_agents[array_rand($user_agents)]);
+	curl_setopt($curl, CURLOPT_ENCODING, "gzip,deflate");
 	curl_setopt($curl, CURLOPT_HTTPHEADER, array(
 	    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 	    'Accept-Language: en-US,en;q=0.5',
+	    'Accept-Encoding: gzip, deflate',
+	    'Connection: keep-alive',
 	    'Upgrade-Insecure-Requests: 1',
 	    'Sec-Fetch-Dest: document',
 		'Sec-Fetch-Mode: navigate',
-		'Sec-Fetch-Site: none',
-		'Referer: '.$referer_url["scheme"].'://'.$referer_url["host"].'/',
+		'Sec-Fetch-Site: none'
 	));
-	curl_setopt($curl, CURLOPT_ENCODING, "gzip,deflate");
-	curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
 	curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
 	curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
 	curl_setopt($curl, CURLOPT_MAXREDIRS, 5);
@@ -83,7 +106,7 @@ function has_cached_results($cache_type, $hash, $url, $ttl) {
 	}
 
 	if($cache_type == "file") {
-		$cache_file = dirname(__DIR__).'/cache/'.md5("$hash:$url").'.data';
+		$cache_file = ABSPATH.'cache/'.md5("$hash:$url").'.data';
 		if(is_file($cache_file)) {
 			if(filemtime($cache_file) >= (time() - $ttl)) {
 				return true;
@@ -100,7 +123,7 @@ function store_cached_results($cache_type, $hash, $url, $results, $ttl) {
 	}
 
 	if($cache_type == "file") {
-		$cache_file = dirname(__DIR__).'/cache/'.md5("$hash:$url").'.data';
+		$cache_file = ABSPATH.'cache/'.md5("$hash:$url").'.data';
 		file_put_contents($cache_file, serialize($results));
 	}
 }
@@ -111,7 +134,7 @@ function fetch_cached_results($cache_type, $hash, $url) {
 	}
 
 	if($cache_type == "file") {
-		$cache_file = dirname(__DIR__).'/cache/'.md5("$hash:$url").'.data';
+		$cache_file = ABSPATH.'cache/'.md5("$hash:$url").'.data';
 		if(is_file($cache_file)) {
 			return unserialize(file_get_contents($cache_file));
 		}
@@ -121,7 +144,7 @@ function fetch_cached_results($cache_type, $hash, $url) {
 }
 
 function delete_cached_results($ttl) {
-	$folder = opendir(dirname(__DIR__).'/cache/');	
+	$folder = opendir(ABSPATH.'cache/');	
 	while($file_name = readdir($folder)) {
 		$extension = pathinfo($file_name, PATHINFO_EXTENSION);
 		if($file_name == "." OR $file_name == ".." OR $extension != "data") continue; 
@@ -142,6 +165,10 @@ function sanitize($variable) {
 		case 'string': 
 			$variable = htmlspecialchars(trim($variable), ENT_QUOTES);
 		break;
+		case 'integer':
+			$variable = preg_replace('/[^0-9]/', '', $variable);
+			if(strlen($variable) == 0) $variable = 0;
+		break;
 		case 'boolean':
 			$variable = ($variable === FALSE) ? 0 : 1;
 		break;
@@ -153,13 +180,6 @@ function sanitize($variable) {
     return $variable;
 }
 
-function sanitize_numeric($variable) {
-	$variable = preg_replace('/[^0-9]/', '', $variable);
-	if(strlen($variable) == 0) $variable = 0;
-
-	return $variable;
-}
-
 /*--------------------------------------
 // Search result match counter
 --------------------------------------*/
@@ -246,33 +266,6 @@ function search_sources($results) {
 	unset($sources);
 }
 
-/*--------------------------------------
-// Special Search result
---------------------------------------*/
-function special_search_result($opts, $results) {
-	if($opts->imdb_id_search == "on") {
-		$found = false;
-		foreach($results['search'] as $search_result) {
-			if(!$found && preg_match_all("/(imdb.com|tt[0-9]+)/i", $search_result['url'], $imdb_result) && stristr($search_result['title'], "tv series") !== false) {
-				$results['special'] = array(
-					"title" => $search_result['title'], 
-					"text" => "Goosle found an IMDb ID for this TV Show in your results (".$imdb_result[0][1].") - <a href=\"./results.php?q=".$imdb_result[0][1]."&a=".$opts->hash."&t=9\">search for magnet links</a>?<br /><sub>An IMDb ID is detected when a TV Show is present in the results. The first match is highlighted here.</sub>"
-				);
-				$found = true;
-			}
-		}
-	}
-	if(array_key_exists("special", $results)) {
-		echo "<li class=\"special-result\"><article>";
-		echo "<div class=\"title\"><h2>".$results['special']['title']."</h2></div>";
-		echo "<div class=\"text\">".$results['special']['text']."</div>";
-		if(array_key_exists("source", $results['special'])) {
-			echo "<div class=\"source\"><a href=\"".$results['special']['source']."\" target=\"_blank\">".$results['special']['source']."</a></div>";
-		}
-		echo "</article></li>";
-	}
-}
-
 /*--------------------------------------
 // Find and replace the last comma in a string
 --------------------------------------*/
@@ -318,11 +311,11 @@ function string_generator() {
 /*--------------------------------------
 // Show version in footer and do periodic update check
 --------------------------------------*/
-function show_version($opts) {
+function show_version() {
 	$cache_file = dirname(__DIR__).'/version.data';
 	
 	// Currently installed version
-	$current_version = "1.2.1";
+	$current_version = "1.2.2";
 
 	if(!is_file($cache_file)){
 		// Create update cache file

+ 44 - 0
goosle-cron.php

@@ -0,0 +1,44 @@
+<?php
+if(!defined('ABSPATH')) define('ABSPATH', dirname(__FILE__) . '/');
+
+require ABSPATH."functions/tools.php";
+
+$opts = load_opts();
+$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
+/* ------------------------------------------------------------------------------------
+*  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.
+---------------------------------------------------------------------------------------
+* Includes:
+* - Clearing out old cached results when using the file cache.
+---------------------------------------------------------------------------------------
+* Execute this file with a cron once or twice a day.
+* If you've enabled the access hash, don't forget to include ?a=YOUR_HASH to the url.
+* 
+* Example for 5 minutes past every midnight and noon: 
+* 		5 0,12 * * * wget -qO - https://example.com/goosle-cron.php?a=YOUR_HASH
+*
+* Example for every midnight: 
+* 		0 0 * * * wget -qO - https://example.com/goosle-cron.php?a=YOUR_HASH
+------------------------------------------------------------------------------------ */
+
+if(verify_hash($opts, $auth)) {
+	// Clear out old cached files?
+	if($opts->cache == "on" && $opts->cache_type == "file") {
+		$ttl = intval($opts->cache_time) * 60;
+		delete_cached_results($ttl);
+	}
+
+	echo "Done!";
+} else {
+	echo "Unauthorized!";
+} 
+
+exit;
+?>

+ 5 - 3
help.php

@@ -1,6 +1,8 @@
 <?php
-require "functions/tools.php";
-require "functions/search_engine.php";
+if(!defined('ABSPATH')) define('ABSPATH', dirname(__FILE__) . '/');
+
+require ABSPATH."functions/tools.php";
+require ABSPATH."functions/search_engine.php";
 
 $opts = load_opts();
 $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
@@ -113,7 +115,7 @@ if(verify_hash($opts, $auth)) {
 
 <div class="footer-wrap">
 	<div class="footer">
-		&copy; <?php echo date('Y'); ?> <?php echo show_version($opts); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
+		&copy; <?php echo date('Y'); ?> <?php echo show_version(); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
 		<span style="float:right;"><a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a> - Your IP: <?php echo $_SERVER["REMOTE_ADDR"]; ?></span>
 	</div>
 </div>

+ 4 - 2
index.php

@@ -1,6 +1,8 @@
 <?php 
-require "functions/tools.php";
-require "functions/search_engine.php";
+if(!defined('ABSPATH')) define('ABSPATH', dirname(__FILE__) . '/');
+
+require ABSPATH."functions/tools.php";
+require ABSPATH."functions/search_engine.php";
 
 $opts = load_opts();
 $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;

+ 22 - 6
readme.md

@@ -29,7 +29,7 @@ After-all, finding things should be easy and not turn into a chore.
 - Special searches for; Currency conversion, Dictionary and php.net
 - Randomized user-agents for to prevent profiling by search providers
 - Non-personalized Google results without instant results or other non-sense
-- Optional: Speed up repeat searches with APCu cache if your server has it
+- Optional: Speed up repeat searches with APCu cache if your server has it or a basic file cache
 - Optional: Access key as a basic way to keep your server to yourself
 - Optional: Instant password generator on the start page
 
@@ -57,21 +57,22 @@ Tested to work on Apache with PHP8.0.24-8.2.x.
 1. Unzip the download.
 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. search.example.com) or a sub-folder on your main site (eg. example.com/search/)
+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/)
 5. Rename goosle.htaccess to .htaccess
-6. Load the site in your browser. If you've enabled the access hash add ?a=YOURHASH to the url.
+6. Load the site in your browser. If you've enabled the access hash add *?a=YOURHASH* to the url.
 7. Let me know where you installed Goosle :-)
 
-## Updates
+## Updating Goosle to a newer version
 1. Unzip the download.
-2. Check your config.php file and 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)
+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.
 5. Enjoy your updated search experience!
 
 ### Notes:
+- If you use file caching you can set up a cron job to execute goosle-cron.php every 12 or 24 hours. Check that file for details and usage examples.
 - The .htaccess file has a redirect to force HTTPS as well as browser caching rules ready to go.
-- The robots.txt has a rule to prevent all crawlers from crawling Goosle. But keep in mind that not every crawler obeys this file.
+- The robots.txt has a rule to tell all crawlers to not crawl Goosle. But keep in mind that not every crawler obeys this file.
 - The access hash is NOT meant as a super secure measure and only works for surface level prying eyes.
 
 Have fun finding things! And tell your friends!
@@ -82,6 +83,21 @@ 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.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] 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] Blocked category filter for YTS results now actually works
+
 1.2.1 - January 15, 2024
 - [new] Merge identical downloads (determined by info hash) from different torrent sites that provide hashes
 - [new] Option to cache to flat files instead of APCu, files stored in /cache/ folder

+ 5 - 3
results.php

@@ -1,6 +1,8 @@
 <?php
-require "functions/tools.php";
-require "functions/search_engine.php";
+if(!defined('ABSPATH')) define('ABSPATH', dirname(__FILE__) . '/');
+
+require ABSPATH."functions/tools.php";
+require ABSPATH."functions/search_engine.php";
 
 $opts = load_opts();
 $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
@@ -60,7 +62,7 @@ if(verify_hash($opts, $auth)) {
 
 <div class="footer-wrap">
 	<div class="footer">
-		&copy; <?php echo date('Y'); ?> <?php echo show_version($opts); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
+		&copy; <?php echo date('Y'); ?> <?php echo show_version(); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
 		<span style="float:right;"><a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a> - Your IP: <?php echo $_SERVER["REMOTE_ADDR"]; ?></span>
 	</div>
 </div>