Version 1.1

A quality of life update - Mostly.

1.1 - December 21, 2023
- [new] API search for EZTV TV Shows.
- [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] 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] Sanitize scraped data earlier in the process.
- [tweak] Consistent single quotes for arrays.
- [tweak] Consistent spaces, tabs and newlines.
- [fix] Inconsistent input height for search field vs search button.
- [fix] Better check if a search is currency conversion or not.
- [fix] Typos in help.php.
This commit is contained in:
Arnan de Gans 2023-12-21 04:02:42 -06:00
parent 0340ccbdbe
commit 86d0d57dc8
20 changed files with 720 additions and 430 deletions

View file

@ -9,7 +9,7 @@
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
body { position: relative; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; color: #222; background-color: #ffffff; line-height: 1; }
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; }
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; }
h2, h3, h4, h5, h6 { font-weight: normal; }
@ -19,8 +19,11 @@ input, button { outline: none; }
button { cursor: pointer; }
p { font-size: 18px; color: #494949; }
a { text-decoration: none; color: #4495d4; }
small, sub, sup { padding: 5px 0; color: #666; font-size: 12px; }
sub, sup { font-style: italic; }
a:hover { text-decoration: underline; }
input[type="text"]:invalid ~ input[type="submit"] { opacity: 0.5; pointer-events: none; }
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23777'><path d='M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/></svg>"); }
/* Page structure */
.wrap { min-height: 100vh; overflow: hidden; }
@ -33,7 +36,8 @@ 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-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 #1c1c1c; border-radius: 6px; }
.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:hover { border: 1px solid #5f6368; }
.password-generator { margin: 30px auto; padding: 0; }
@ -41,8 +45,10 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
/* Search Results - Header */
.header-wrap { background-color: #1f242b; color: #f0f6fc; border-bottom: 2px solid #1fa4d1; }
.header-wrap .search { position: relative; margin: 28px 0 28px 158px; padding: 5px 5px 5px 15px; height: 30px; width: 580px; color: #f0f6fc; background-color: #1f242b; font-size: 100%; font-weight: 400; border: 1px solid #303842; border-radius: 10px 0 0 10px; }
.header-wrap .button { position: relative; margin: 28px 10px 28px 0; padding: 5px 20px 5px 15px; height: 40px; color: #f0f6fc; background-color: #1fa4d1; font-size: 100%; font-weight: 400; border: none; border-radius: 0 10px 10px 0; }
.header-wrap .search, .header-wrap .button { position: relative; height: 40px; color: #f0f6fc; font-size: 100%; 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; }
/* Search results - Header Navigation */
.navigation-header { margin-left: 165px; margin-bottom: 10px; }
@ -55,7 +61,7 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
/* Search results - Main column */
.main-column { width: 100%; }
.main-column ol .result { margin: .50rem 0 .50rem 0; padding: 0; }
.main-column ol .special-result, .main-column ol .meta-time, .main-column ol .meta-error, .main-column ol .meta-did-you-mean { margin: .75rem 0 .75rem 0; padding: .5rem 10px; }
.main-column ol .special-result, .main-column ol .meta { margin: .75rem 0 .75rem 0; padding: .5rem 10px; }
.main-column ol li article { padding: .5rem 10px; border: 1px solid #fefefe; border-radius: 8px; }
.main-column ol li article div.url:first-child, .main-column ol li.special-result article div.source:first-child { flex-grow: 0; }
@ -82,7 +88,9 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
}
.main-column ol.image-grid .result .image-box { position: relative; }
.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%; }
.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; }
/* Special results - Main column */
.main-column ol .special-result { background-color: #fefefe; }
@ -102,7 +110,8 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
.no-decoration, .no-decoration:hover { text-decoration: none; }
.hide { display: none; }
.G { color: #1fa4d1; }
.meta-error { position: relative; overflow: hidden; color: #c00; background-color: #ffebe8; border: 1px solid #c00; border-radius: 8px; }
.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; }
/* Footer bar */

View file

@ -15,6 +15,13 @@ HASH:
A simple lowercase passphrase (something simple like: j9fg-i2du-er6m or 1846) used for caching results. This helps to differentiate between instances on the same server.
You can also add it to your url/bookmark as a simple passphrase to keep unwanted users out.
HASH AUTH:
Use the above hash as a simple passphrase.
Using it as a passphrase lets you host Goosle on a public server without providing a public service.
Usage: https://example.com/?a=1234567890
Disclaimer: This is not meant to 'hack proof' or truly secure the setup. Just a simple token to keep surface level prying eyes out.
CACHE:
If you have ACPu it is highly recommended to enable caching as it'll speed up repeatable searched by a lot.
"on" (Recommended) for active sites, requires APCu
@ -23,24 +30,13 @@ CACHE:
CACHE_TIME:
Minutes the result should be cached in ACPu.
HASH AUTH:
Use the above hash as a simple passphrase.
Using it as a passphrase lets you host Goosle on a public server without providing a public service.
Usage: https://example.com/?a=1234567890
Disclaimer: This is not meant to 'hack proof' or truly secure the setup. Just a simple token to keep surface level prying eyes out.
RAW OUTPUT:
"off" (Recommended) for active sites
"on" Output the search results as an array instead of formatted with HTML
ENABLE TORRENT SEARCH:
Enable or disable searching for torrent downloads.
ENABLE IMAGE SEARCH:
Enable or disable image searches - Search results are provided by Qwant.
"on" (Default)
"off"
ENABLE IMAGE SEARCH:
Enable or disable image searches - Search results are provided by Qwant.
ENABLE TORRENT SEARCH:
Enable or disable searching for torrent downloads.
"on" (Default)
"off"
@ -58,6 +54,9 @@ USER AGENTS:
Chrome may attract attention because of the lack of Chrome information (tracking) aside from the user agent.
Opera/Edge/Brave and many others use Chrome under the hood and are not a good pick for that reason.
SHOW ZERO SEEDERS:
Set to "on" to include results with 0 seeders (slow or stale downloads). Off to exclude these results.
BLOCK 1337x CATEGORIES:
Add category IDs of 1337x categories, check /engines/torrent/1337x.php for a list of known categories.
@ -75,29 +74,35 @@ TORRENT TRACKERS:
return (object) array(
"hash" => "j9fg-i2du-er6m",
"cache" => "off",
"cache_time" => 30, // (Default: 30)
"hash_auth" => "off", // Default: off)
"raw_output" => "off", // (Default: off)
"hash_auth" => "off", // Default: off
"cache" => "off", // Default: off
"cache_time" => 30, // Default: 30
"enable_torrent_search" => "on", // (Default: on)
"enable_image_search" => "on", // (Default: on)
"enable_image_search" => "on", // Default: on
"enable_torrent_search" => "on", // Default: on
"special" => array(
"currency" => "on", // Currency converter
"definition" => "on", // Word dictionary
"wikipedia" => "on", // Wikipedia highlight
"phpnet" => "on", // PHP-dot-net highlight
"imdb_id_search" => "on", // Highlight IMDB IDs for tv shows, to use for torrent searches
"password_generator" => "on" // Password generator on homepage
),
"user_agents" => array(
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15) Gecko/20100101 Firefox/119.0", // macOS 10.15, FF 119
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/116.0", // Windows 10, FF 116
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64) Gecko/20100101 Firefox/83.0", // Linux Ubuntu, FF 83
"Mozilla/5.0 (X11; Linux i686) Gecko/20100101 Firefox/119.0", // Linux Generic, FF 119
"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
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64) Gecko/20100101 Firefox/83.0", // Linux Ubuntu, Firefox 83
"Mozilla/5.0 (X11; Linux i686) Gecko/20100101 Firefox/119.0", // Linux Generic, Firefox 119
"Mozilla/5.0 (Linux; Android 5.0.2; AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.3 Chrome/38.0.2125.102 Safari/537.36", // Android 5, Samsungbrowser 3
"Mozilla/5.0 (Linux; Android 7.0; AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36", // Android 7, Chrome 60
"Mozilla/5.0 (Linux; U; Android 4.2.2; he-il; AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30", // Android 4. Some webkit browser (Chrome?)
"Mozilla/5.0 (iPhone12,1; U; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/15E148 Safari/602.1", // iOS 13, Safari
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/13.2b11866 Mobile/16A366 Safari/605.1.15", // iOS 12, Firefox 13
),
"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"
@ -108,6 +113,7 @@ return (object) array(
"udp://exodus.desync.com:6969/announce",
"udp://tracker.torrent.eu.org:451/announce",
),
"version" => "1.0.2"
"version" => "1.1b2" // Please don't change this
);
?>

View file

@ -51,21 +51,23 @@ class DuckDuckGoRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$results = array("search" => array());
$xpath = get_xpath($response);
if(!$xpath) return $results;
if(!$xpath) return array();
// Scrape recommended
$didyoumean = $xpath->query(".//div[@id='did_you_mean']/a[1]")[0];
if(!is_null($didyoumean)) {
array_push($results, array("did_you_mean" => $didyoumean->textContent));
$results['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//div[@id='did_you_mean']/a[2]")[0];
if(!is_null($search_specific)) {
array_push($results, array("search_specific" => $search_specific->textContent));
$results['search_specific'] = $search_specific->textContent;
}
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) {
// 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;
@ -79,7 +81,7 @@ class DuckDuckGoRequest extends EngineRequest {
$description = $xpath->evaluate(".//a[@class='result__snippet']", $result)[0];
array_push($results, array (
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)

View file

@ -71,20 +71,22 @@ class GoogleRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$results = array("search" => array());
$xpath = get_xpath($response);
if(!$xpath) return $results;
if(!$xpath) return array();
// Scrape recommended
$didyoumean = $xpath->query(".//a[@class='gL9Hy']")[0];
if(!is_null($didyoumean)) {
array_push($results, array("did_you_mean" => $didyoumean->textContent));
$results['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//a[@class='spell_orig']")[0];
if(!is_null($search_specific)) {
array_push($results, array("search_specific" => $search_specific->textContent));
$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;
@ -99,7 +101,7 @@ class GoogleRequest extends EngineRequest {
$description = $xpath->evaluate(".//div[contains(@class, 'VwiC3b')]", $result)[0];
array_push($results, array (
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)

View file

@ -1,6 +1,5 @@
<?php
class ImageSearch extends EngineRequest {
public function get_request_url() {
$results = array();
@ -15,8 +14,9 @@ class ImageSearch extends EngineRequest {
if((strlen($switch[1]) >= 3 && strlen($switch[1]) <= 6) && !is_numeric($switch[1])) {
if($switch[1] == "med") $switch[1] = "medium";
if($switch[1] == "lrg") $switch[1] = "large";
if($switch[1] == "xlrg") $switch[1] = "wallpaper";
if($switch[1] == "small" || $switch[1] == "medium" || $switch[1] == "large") {
if($switch[1] == "small" || $switch[1] == "medium" || $switch[1] == "large" || $switch[1] == "wallpaper") {
$size = $switch[1];
}
@ -24,12 +24,11 @@ class ImageSearch extends EngineRequest {
}
}
// q = query
// t = Search type (images)
// size = Preferred image size (small|medium|large)
// p = query
// imgsz = Image size (small|medium|large|wallpaper)
$args = array("q" => $this->query, "t" => "images", "size" => $size);
$url = "https://lite.qwant.com?".http_build_query($args);
$args = array("p" => $this->query, "imgsz" => $size);
$url = "https://images.search.yahoo.com/search/images?".http_build_query($args);
unset($query_terms, $switch, $args, $size);
@ -40,35 +39,63 @@ class ImageSearch extends EngineRequest {
$results = array("search" => array());
$xpath = get_xpath($response);
if($xpath) {
foreach($xpath->query("//a[@rel='noopener']") as $result) {
$meta = $xpath->evaluate(".//img", $result)[0];
if($meta) {
$encoded_url = explode("?position", explode("==/", $result->getAttribute("href"))[1])[0];
$url = htmlspecialchars(urldecode(base64_decode($encoded_url)));
$alt_text = get_base_url($url)." - ".htmlspecialchars($meta->getAttribute("alt"));
$image = urldecode(htmlspecialchars(urlencode($meta->getAttribute("src"))));
// filter duplicate urls/results
if(!empty($results)) {
$result_urls = array_column($results, "url");
if(in_array($url, $result_urls) || in_array(get_base_url($url), $result_urls)) continue;
}
array_push($results["search"], array (
"alt" => $alt_text,
"image" => $image,
"url" => $url,
));
}
}
// Failed to load page
if(!$xpath) return array();
// Scrape recommended
$didyoumean = $xpath->query(".//section[@class='dym-c']/section/h3/a")[0];
if(!is_null($didyoumean)) {
$results['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//section[@class='dym-c']/section/h5/a")[0];
if(!is_null($search_specific)) {
$results['search_specific'] = $search_specific->textContent;
}
// Scrape the results
foreach($xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'slotting'))][position() < 101]") 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)
// 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);
// filter duplicate urls/results
if(!empty($results['search'])) {
$result_urls = array_column($results['search'], "direct_link");
if(in_array($url_data['imgurl'], $result_urls)) continue;
}
// Deal with optional or missing data
$dimensions_w = (!array_key_exists('w', $url_data) || empty($url_data['w'])) ? 0 : htmlspecialchars($url_data['w']);
$dimensions_h = (!array_key_exists('h', $url_data) || empty($url_data['h'])) ? 0 : 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']);
array_push($results['search'], array (
"image" => htmlspecialchars($image->textContent),
"alt" => htmlspecialchars($url_data['tt']),
"url" => htmlspecialchars($url_data['rurl']),
"height" => $dimensions_w,
"width" => $dimensions_h,
"filesize" => $filesize,
"direct_link" => $link
));
}
// Add warning if there are no results, or a text if there is no search query.
// Add error if there are no search results
if(empty($results['search'])) {
$results["error"] = array(
$results['error'] = array(
"message" => "No results found. Please try with less or different keywords!"
);
}
@ -77,41 +104,76 @@ class ImageSearch extends EngineRequest {
}
public static function print_results($results, $opts) {
if($opts->raw_output == "on") {
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
}
/*
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
*/
echo "<section class=\"main-column\">";
echo "<ol>";
// Elapsed time
if(array_key_exists("search", $results)) {
echo "<li class=\"meta-time\">Fetched the results in ".$results['time']." seconds.</li>";
}
echo "<ol>";
echo "</ol>";
// Elapsed time
$number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
echo "<div class=\"image-wrapper\">";
echo "<ol class=\"image-grid\">";
// Did you mean/Search suggestion
if(array_key_exists("did_you_mean", $results)) {
$specific_result = "";
if(array_key_exists("search_specific", $results)) {
// Format query url
$search_specific = "\"".$results['search_specific']."\"";
$search_specific_url = "./results.php?q=".urlencode($search_specific)."&t=".$opts->type."&a=".$opts->hash;
// Specific search
$specific_result = "<br /><small>Or instead search for <a href=\"".$search_specific_url."\">".$search_specific."</a>.</small>";
unset($search_specific, $search_specific_url);
}
$didyoumean_url = "./results.php?q=".urlencode($results['did_you_mean'])."&t=".$opts->type."&a=".$opts->hash;
echo "<li class=\"meta\">Did you mean <a href=\"".$didyoumean_url."\">".$results['did_you_mean']."</a>?$specific_result</li>";
unset($didyoumean_url, $specific_result);
}
echo "</ol>";
// Search results
echo "<div class=\"image-wrapper\">";
echo "<ol class=\"image-grid\">";
// Search results
if(array_key_exists("search", $results)) {
foreach($results['search'] as $result) {
if(!array_key_exists("url", $result) || !array_key_exists("alt", $result)) continue;
$meta = $links = array();
// Optional data
if(!empty($result['height']) && !empty($result['width'])) $meta[] = $result['width']."&times;".$result['height'];
if(!empty($result['filesize'])) $meta[] = $result['filesize'];
// Links
$links[] = "<a href=\"".$result['url']."\" target=\"_blank\">Website</a>";
if(!empty($result['direct_link'])) $links[] = "<a href=\"".$result['direct_link']."\" target=\"_blank\">Image</a>";
// Put result together
echo "<li class=\"result\"><div class=\"image-box\">";
echo "<a href=\"".$result["url"]."\" target=\"_blank\" title=\"".$result["alt"]."\"><img src=\"".$result["image"]."\" alt=\"".$result["alt"]."\" /></a>";
echo "</div></li>";
echo "<a href=\"".$result['url']."\" target=\"_blank\" title=\"".$result['alt']."\"><img src=\"".$result['image']."\" alt=\"".$result['alt']."\" /></a>";
echo "</div><span>".implode(" - ", $meta)."<br />".implode(" - ", $links)."</span>";
echo "</li>";
unset($result, $meta, $links);
}
echo "</ol>";
echo "</div>";
echo "<center><small>Not what you're looking for? Try <a href=\"https://duckduckgo.com/?q=".urlencode($opts->query)."&iax=images&ia=images\" target=\"_blank\">DuckDuckGo</a>, <a href=\"https://images.search.yahoo.com/search/images?p=".urlencode($opts->query)."\" target=\"_blank\">Yahoo! Images</a> or <a href=\"https://www.google.com/search?q=".urlencode($opts->query)."&tbm=isch&pws=0\" target=\"_blank\">Google Images</a>.</small></center>";
}
echo "</ol>";
echo "</div>";
echo "<center><small>Not what you're looking for? Try <a href=\"https://duckduckgo.com/?q=".urlencode($opts->query)."&iax=images&ia=images\" target=\"_blank\">DuckDuckGo</a> or <a href=\"https://www.google.com/search?q=".urlencode($opts->query)."&tbm=isch&pws=0\" target=\"_blank\">Google Images</a>.</small></center>";
echo "</section>";
// No results found
if(array_key_exists("error", $results)) {
echo "<div class=\"error\">".$results['error']['message']."</div>";
}
}
}
?>

View file

@ -20,19 +20,21 @@ class TorrentSearch extends EngineRequest {
require "engines/torrent/nyaa.php";
require "engines/torrent/thepiratebay.php";
require "engines/torrent/yts.php";
require "engines/torrent/eztv.php";
$this->requests = array(
new LeetxRequest($opts, $mh), // 1337x
new NyaaRequest($opts, $mh),
new PirateBayRequest($opts, $mh),
new YTSRequest($opts, $mh)
new YTSRequest($opts, $mh),
new EZTVRequest($opts, $mh)
);
}
public function parse_results($response) {
$results = $results_temp = array();
foreach ($this->requests as $request) {
foreach($this->requests as $request) {
if($request->request_successful()) {
$results_temp = array_merge($results_temp, $request->get_results());
}
@ -45,13 +47,20 @@ class TorrentSearch extends EngineRequest {
// Cap results
$results['search'] = array_slice($results_temp, 0, 50);
unset($results_temp);
// Count results per site
$sources = array_count_values(array_column($results['search'], 'source'));
if(count($sources) > 0) $results['sources'] = $sources;
unset($sources);
}
// Add warning if there are no results
unset($results_temp);
// Add error if there are no search results
if(empty($results)) {
$results["error"] = array(
"message" => "No results found. Please try with less or different keywords!"
$results['error'] = array(
"message" => "No results found. Please try with more specific or different keywords!"
);
}
@ -59,51 +68,67 @@ class TorrentSearch extends EngineRequest {
}
public static function print_results($results, $opts) {
if($opts->raw_output == "on") {
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
}
/*
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
*/
echo "<section class=\"main-column\">";
echo "<ol>";
// Elapsed time
echo "<li class=\"meta-time\">Fetched the results in ".$results['time']." seconds.</li>";
// No results found
if(array_key_exists("error", $results)) {
echo "<li class=\"meta-error\">".$results['error']['message']."</li>";
}
// Search results
if(array_key_exists("search", $results)) {
echo "<ol>";
// Format sources
$sources = "";
if(array_key_exists("sources", $results)) {
$sources = array();
foreach($results['sources'] as $source => $amount) {
$plural = ($amount > 1) ? "results" : "result";
$sources[] = $amount." ".$plural." from ".$source;
}
$sources = implode(', ', $sources);
$last_comma = strrpos($sources, ', ');
if($last_comma !== false) {
$sources = substr_replace($sources, ' and ', $last_comma, 2);
}
$sources = "<br /><small>Including ".$sources.". Links with the most seeders are listed first.</small>";
}
// Elapsed time
$number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.".$sources."</li>";
// Search results
foreach($results['search'] as $result) {
$meta = array();
// Optional data
if(array_key_exists('quality', $result)) $meta[] = "<strong>Quality:</strong> ".$result['quality'];
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:</strong> ".date('M d, Y', $result['date_added']);
if(array_key_exists('url', $result)) $meta[] = "<a href=\"".$result["url"]."\" target=\"_blank\" title=\"Careful - Site may contain intrusive popup ads and malware!\">Torrent page</a>";
if(array_key_exists('url', $result)) $meta[] = "<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>";
echo "<div class=\"url\"><a href=\"".$result["magnet"]."\">".$result["source"]."</a></div>";
echo "<div class=\"title\"><a href=\"".$result["magnet"]."\"><h2>".stripslashes($result["name"])."</h2></a></div>";
echo "<div class=\"url\"><a href=\"".$result['magnet']."\">".$result['source']."</a></div>";
echo "<div class=\"title\"><a href=\"".$result['magnet']."\"><h2>".stripslashes($result['name'])."</h2></a></div>";
echo "<div class=\"description\"><strong>Seeds:</strong> <span class=\"seeders\">".$result['seeders']."</span> - <strong>Peers:</strong> <span class=\"leechers\">".$result['leechers']."</span> - <strong>Size:</strong> ".$result['size']."<br />".implode(" - ", $meta)."</div>";
echo "</article></li>";
unset($result, $meta);
}
echo "</ol>";
echo "<center><small>Showing up to 50 results, sorted by most seeders.<br />Goosle does not index, offer or distribute torrent files.</small></center>";
}
echo "<li class=\"result\"><article>";
echo "<small>Goosle does not store, index, offer or distribute torrent files.</small>";
echo "</article></li>";
echo "</ol>";
echo "<center><small>Showing 50 results, sorted by most seeders.</small></center>";
echo "</section>";
// No results found
if(array_key_exists("error", $results)) {
echo "<div class=\"error\">".$results['error']['message']."</div>";
}
}
}
?>

View file

@ -36,17 +36,17 @@ class TextSearch extends EngineRequest {
// Abort if no results from search engine
if(!isset($this->engine_request)) return $results;
// Add search results
// Add search results if there are any, otherwise add error
if($this->engine_request->request_successful()) {
$search_result = $this->engine_request->get_results();
if($search_result) {
$results['search'] = $search_result;
$results = $search_result;
}
unset($search_result);
} else {
$results["error"] = array(
$results['error'] = array(
"message" => "Error code ".curl_getinfo($this->engine_request->ch)['http_code']." for ".curl_getinfo($this->engine_request->ch)['url'].".<br />Try again in a few seconds or <a href=\"".curl_getinfo($this->engine_request->ch)['url']."\" target=\"_blank\">visit the search engine</a> in a new tab."
);
}
@ -62,9 +62,9 @@ class TextSearch extends EngineRequest {
unset($special_result);
}
// Add warning if there are no results, or a text if there is no search query.
// Add error if there are no search results
if(empty($results)) {
$results["error"] = array(
$results['error'] = array(
"message" => "No results found. Please try with less or different keywords!"
);
}
@ -73,93 +73,104 @@ class TextSearch extends EngineRequest {
}
public static function print_results($results, $opts) {
if($opts->raw_output == "on") {
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
}
/*
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
*/
echo "<section class=\"main-column\">";
echo "<ol>";
// Elapsed time
if(array_key_exists("search", $results)) {
echo "<ol>";
// Elapsed time
$number_of_results = count($results['search']);
echo "<li class=\"meta-time\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
}
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// No results found
if(array_key_exists("error", $results)) {
echo "<li class=\"meta-error\">".$results['error']['message']."</li>";
}
// Did you mean/Search suggestion
if(array_key_exists("did_you_mean", $results)) {
$specific_result = "";
// Did you mean/Search suggestion
if(array_key_exists("search", $results)) {
$specific_result = "";
if(array_key_exists("did_you_mean", $results['search'][0])) {
if(array_key_exists("search_specific", $results['search'][1])) {
if(array_key_exists("search_specific", $results)) {
// Add double quotes to Google search
$search_specific = ($opts->type == 1) ? "\"".$results['search'][1]['search_specific']."\"" : $results['search'][1]['search_specific'];
$search_specific = ($opts->type == 1) ? "\"".$results['search_specific']."\"" : $results['search_specific'];
// Format query url
$search_specific_url = "./results.php?q=" . urlencode($search_specific)."&t=".$opts->type."&a=".$opts->hash;
$specific_result = "<br /><small>Or instead search for <a href=\"$search_specific_url\">$search_specific</a>.</small>";
// Specific search
$specific_result = "<br /><small>Or instead search for <a href=\"".$search_specific_url."\">".$search_specific."</a>.</small>";
unset($results['search'][1], $search_specific, $search_specific_url);
unset($search_specific, $search_specific_url);
}
$didyoumean = $results['search'][0]['did_you_mean'];
$didyoumean_url = "./results.php?q=" . urlencode($didyoumean)."&t=".$opts->type."&a=".$opts->hash;
$didyoumean_url = "./results.php?q=" . urlencode($results['did_you_mean'])."&t=".$opts->type."&a=".$opts->hash;
echo "<li class=\"meta-did-you-mean\">Did you mean <a href=\"$didyoumean_url\">$didyoumean</a>?$specific_result</li>";
echo "<li class=\"meta\">Did you mean <a href=\"".$didyoumean_url."\">".$results['did_you_mean']."</a>?".$specific_result."</li>";
unset($results['search'][0], $didyoumean, $didyoumean_url, $specific_result);
}
}
// Special result
if(array_key_exists("special", $results)) {
echo "<li class=\"special-result\"><article>";
// Maybe shorten text
if(strlen($results['special']['text']) > 1250) {
$results['special']['text'] = substr($results['special']['text'], 0, strrpos(substr($results['special']['text'], 0, 1300), ". "));
$results['special']['text'] .= '. <a href="'.$results['special']['source'].'" target="_blank">[...]</a>';
unset($didyoumean_url, $specific_result);
}
// Add image to text
if(array_key_exists("image", $results['special'])) {
$image_specs = getimagesize($results['special']['image']);
$width = $image_specs[0] / 2;
$height = $image_specs[1] / 2;
$special_image = "<img src=\"".$results['special']['image']."\" align=\"right\" width=\"".$width."\" height=\"".$height."\" />";
$results['special']['text'] = $special_image.$results['special']['text'];
unset($image_specs, $width, $height, $special_image);
// Special results
if($opts->special['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;
}
}
}
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>";
if(array_key_exists("special", $results)) {
echo "<li class=\"special-result\"><article>";
// Maybe shorten text
if(strlen($results['special']['text']) > 1250) {
$results['special']['text'] = substr($results['special']['text'], 0, strrpos(substr($results['special']['text'], 0, 1300), ". "));
$results['special']['text'] .= '. <a href="'.$results['special']['source'].'" target="_blank">[...]</a>';
}
// Add image to text
if(array_key_exists("image", $results['special'])) {
$image_specs = getimagesize($results['special']['image']);
$width = $image_specs[0] / 2;
$height = $image_specs[1] / 2;
$special_image = "<img src=\"".$results['special']['image']."\" align=\"right\" width=\"".$width."\" height=\"".$height."\" />";
$results['special']['text'] = $special_image.$results['special']['text'];
unset($image_specs, $width, $height, $special_image);
}
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>";
}
echo "</article></li>";
}
// Search results
if(array_key_exists("search", $results)) {
// Search results
foreach($results['search'] as $result) {
if(array_key_exists("did_you_mean", $result)) continue;
// Put result together
echo "<li class=\"result\"><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>";
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>";
echo "</article></li>";
unset($result);
}
echo "</ol>";
}
echo "</ol>";
echo "</section>";
// No results found
if(array_key_exists("error", $results)) {
echo "<div class=\"error\">".$results['error']['message']."</div>";
}
}
}
?>

View file

@ -18,7 +18,7 @@ class CurrencyRequest extends EngineRequest {
$json_response = json_decode($response, true);
if(!empty($json_response)) {
$result = $json_response["rates"];
$result = $json_response['rates'];
// Process query
// [0] = AMOUNT

View file

@ -51,7 +51,7 @@ class WikipediaRequest extends EngineRequest {
);
if (array_key_exists("thumbnail", $result)) {
$response["image"] = strip_tags(trim($result["thumbnail"]["source"]));
$response['image'] = strip_tags(trim($result['thumbnail']['source']));
}
return $response;

View file

@ -10,17 +10,17 @@
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class LeetxRequest extends EngineRequest {
public function get_request_url() {
return "https://1337x.to/search/".urlencode($this->query)."/1/";
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
// Failted to load page
if(!$xpath) return $results;
public function get_request_url() {
return "https://1337x.to/search/".urlencode($this->query)."/1/";
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
// Failed to load page
if(!$xpath) return $results;
$categories = array(
1 => "DVD",
2 => "Divx/Xvid",
@ -105,38 +105,43 @@ class LeetxRequest extends EngineRequest {
);
// Scrape the page
foreach($xpath->query("//table/tbody/tr") as $result) {
$category = $xpath->evaluate(".//td[@class='coll-1 name']/a/@href", $result)[0]->textContent;
$category = explode("/", trim($category));
// Block these categories
if(in_array($category[2], $this->opts->leetx_categories_blocked)) continue;
$name = $xpath->evaluate(".//td[@class='coll-1 name']/a", $result)[1]->textContent;
$seeders = $xpath->evaluate(".//td[@class='coll-2 seeds']", $result)[0]->textContent;
$leechers = $xpath->evaluate(".//td[@class='coll-3 leeches']", $result)[0]->textContent;
$date_added = explode(" ", sanitize($xpath->evaluate(".//td[@class='coll-date']", $result)[0]->textContent));
$date_added = mktime(0, 0, 0, intval(date("m", strtotime($date_added[0]))), intval(preg_replace('/[^\d.]+/', '', $date_added[1])), intval('20'.preg_replace('/[^\d.]+/', '', $date_added[2])));
$url = "https://1337x.to".sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a/@href", $result)[1]->textContent);
$size_unformatted = explode(" ", $xpath->evaluate(".//td[contains(@class, 'coll-4 size')]", $result)[0]->textContent);
foreach($xpath->query("//table/tbody/tr") as $result) {
$name = sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a", $result)[1]->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]);
$category = explode("/", sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a/@href", $result)[0]->textContent));
$category = $category[2];
$url = "https://1337x.to".sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a/@href", $result)[1]->textContent);
$date_added = explode(" ", sanitize($xpath->evaluate(".//td[@class='coll-date']", $result)[0]->textContent));
$date_added = mktime(0, 0, 0, intval(date("m", strtotime($date_added[0]))), intval(preg_replace('/[^\d.]+/', '', $date_added[1])), intval('20'.preg_replace('/[^\d.]+/', '', $date_added[2])));
// Block these categories
if(in_array($category, $this->opts->leetx_categories_blocked)) continue;
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Required
// Required
"source" => "1337x.to",
"name" => sanitize($name),
"name" => $name,
"magnet" => "./engines/torrent/magnetize_1337x.php?url=".$url,
"seeders" => sanitize($seeders),
"leechers" => sanitize($leechers),
"size" => sanitize($size),
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional values
"category" => $categories[sanitize($category[2])],
"category" => $categories[$category],
"url" => $url,
"date_added" => $date_added
));
}
return $results;
}
unset($name, $seeders, $leechers, $size_unformatted, $size, $category, $url, $date_added);
}
return $results;
}
}
?>

88
engines/torrent/eztv.php Normal file
View file

@ -0,0 +1,88 @@
<?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 EZTVRequest extends EngineRequest {
public function get_request_url() {
// Make reasonably sure it's an IMDb id and abort if it's not
$query_terms = explode(" ", $this->query);
if(substr(strtolower($query_terms[0]), 0, 2) !== "tt") return "";
// Prepare a search query by stripping out everything but numbers and abort if nothing is left
$query = preg_replace('/[^0-9]/', '', $query_terms[0]);
if(strlen($query) == 0) return "";
// Is eztvx.to blocked for you? Use one of these urls as an alternative
// eztv1.xyz, eztv.wf, eztv.tf, eztv.yt
return "https://eztvx.to/api/get-torrents?imdb_id=".urlencode($query);
}
public function parse_results($response) {
$results = 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['torrents_count'] == 0) return $results;
// Use API result
foreach ($json_response['torrents'] as $episode) {
$name = sanitize($episode['title']);
$magnet = sanitize($episode['magnet_url']);
$seeders = sanitize($episode['seeds']);
$leechers = sanitize($episode['peers']);
$size = sanitize($episode['size_bytes']);
// Find actual quality of episode
if(preg_match('/(480p|720p|1080p|2160p)/i', $name, $quality)) {
$quality = $quality[0];
} else {
$quality = "Unknown";
}
$date_added = sanitize($episode['date_released_unix']);
// Filter by Season (S01) or Season and Episode (S01E01)
$season = sanitize($episode['season']);
$episode = sanitize($episode['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[1]) && str_ireplace("e0", "", $filter_episode[0][1]) != $episode)) {
continue;
}
}
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Required
"source" => "EZTV",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => human_filesize($size),
// Optional
"quality" => $quality,
"date_added" => $date_added
));
unset($name, $magnet, $seeders, $leechers, $size, $quality, $category, $date_added, $season, $episode);
}
return $results;
}
}
?>

View file

@ -10,47 +10,54 @@
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class NyaaRequest extends EngineRequest {
public function get_request_url() {
return "https://nyaa.si/?q=".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
// Failted to load page
if(!$xpath) return $results;
public function get_request_url() {
return "https://nyaa.si/?q=".urlencode($this->query);
}
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("//tbody/tr") as $result) {
$category = $xpath->evaluate(".//td[1]//a/@title", $result)[0]->textContent;
$name = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result)[0]->textContent;
$url = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result)[0]->textContent;
$meta = $xpath->evaluate(".//td[@class='text-center']", $result);
$seeders = $meta[3]->textContent;
$leechers = $meta[4]->textContent;
$size = $meta[1]->textContent;
$date_added = $meta[2]->textContent;
$date_added = explode("-", substr(sanitize($date_added), 0, 10));
foreach($xpath->query("//tbody/tr") as $result) {
$meta = $xpath->evaluate(".//td[@class='text-center']", $result);
$name = sanitize($xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result)[0]->textContent);
$magnet = sanitize($xpath->evaluate(".//a[2]/@href", $meta[0])[0]->textContent);
$seeders = sanitize($meta[3]->textContent);
$leechers = sanitize($meta[4]->textContent);
$size = sanitize($meta[1]->textContent);
$category = sanitize($xpath->evaluate(".//td[1]//a/@title", $result)[0]->textContent);
$url = sanitize($xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result)[0]->textContent);
$date_added = sanitize($meta[2]->textContent);
$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]));
$magnet = $xpath->evaluate(".//a[2]/@href", $meta[0])[0]->textContent;
array_push($results, array (
// Required
"source" => "nyaa.si",
"name" => sanitize($name),
"magnet" => sanitize($magnet),
"seeders" => sanitize($seeders),
"leechers" => sanitize($leechers),
"size" => sanitize($size),
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Required
"source" => "nyaa.si",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional values
"category" => str_replace(" - ", "/", sanitize($category)),
"url" => "https://nyaa.si".sanitize($url),
"category" => str_replace(" - ", "/", $category),
"url" => "https://nyaa.si".$url,
"date_added" => $date_added
));
}
));
return $results;
}
unset($name, $magnet, $seeders, $leechers, $size, $category, $url, $date_added, $meta);
}
return $results;
}
}
?>

View file

@ -10,17 +10,17 @@
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class PirateBayRequest extends EngineRequest {
public function get_request_url() {
return "https://apibay.org/q.php?q=".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$json_response = json_decode($response, true);
public function get_request_url() {
return "https://apibay.org/q.php?q=".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
if(empty($json_response)) return $results;
$categories = array(
100 => "Audio",
101 => "Music",
@ -84,32 +84,44 @@ class PirateBayRequest extends EngineRequest {
);
// Use API result
foreach($json_response as $response) {
foreach($json_response as $response) {
// Nothing found
if($response["name"] == "No results returned") break;
// Block these categories
if(in_array($response["category"], $this->opts->piratebay_categories_blocked)) continue;
$name = sanitize($response["name"]);
$magnet = "magnet:?xt=urn:btih:".sanitize($response["info_hash"])."&dn=".$name."&tr=".implode("&tr=", $this->opts->torrent_trackers);
array_push($results, array (
// Required
"source" => "thepiratebay.org",
"name" => $name,
"magnet" => $magnet,
"seeders" => sanitize($response["seeders"]),
"leechers" => sanitize($response["leechers"]),
"size" => human_filesize(sanitize($response["size"])),
if($response['name'] == "No results returned") break;
$name = sanitize($response['name']);
$magnet = "magnet:?xt=urn:btih:".sanitize($response['info_hash'])."&dn=".$name."&tr=".implode("&tr=", $this->opts->torrent_trackers);
$seeders = sanitize($response['seeders']);
$leechers = sanitize($response['leechers']);
$size = sanitize($response['size']);
$category = sanitize($response['category']);
$id = sanitize($response['id']);
$date_added = sanitize($response['added']);
// Block these categories
if(in_array($category, $this->opts->piratebay_categories_blocked)) continue;
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array(
// Required
"source" => "thepiratebay.org",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => human_filesize($size),
// Optional
"category" => $categories[sanitize($response["category"])],
"url" => "https://thepiratebay.org/description.php?id=".sanitize($response["id"]),
"date_added" => sanitize($response["added"]),
));
}
"category" => $categories[$category],
"url" => "https://thepiratebay.org/description.php?id=".$id,
"date_added" => $date_added,
));
return $results;
}
unset($name, $magnet, $seeders, $leechers, $size, $category, $id, $date_added);
}
return $results;
}
}
?>

View file

@ -10,55 +10,73 @@
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class YTSRequest extends EngineRequest {
public function get_request_url() {
return "https://yts.mx/api/v2/list_movies.json?query_term=".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$response = curl_multi_getcontent($this->ch);
$json_response = json_decode($response, true);
public function get_request_url() {
return "https://yts.mx/api/v2/list_movies.json?query_term=".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$response = curl_multi_getcontent($this->ch);
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
if(empty($json_response)) return $results;
// Nothing found
if($json_response["status"] != "ok" || $json_response["data"]["movie_count"] == 0) return $results;
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 $movie) {
// 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", $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'] = '';
// Block these categories
if(array_intersect($movie['genres'], $this->opts->yts_categories_blocked)) continue;
$name = sanitize($movie['title']);
$year = sanitize($movie['year']);
$category = sanitize(implode(', ', $movie['genres']));
$runtime = sanitize($movie['runtime']);
$url = sanitize($movie['url']);
$date_added = sanitize($movie['date_uploaded_unix']);
// Block these categories
if(array_intersect($movie["genres"], $this->opts->yts_categories_blocked)) continue;
$name = sanitize($movie["title"]);
foreach ($movie["torrents"] as $torrent) {
$magnet = "magnet:?xt=urn:btih:".sanitize($torrent["hash"])."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->torrent_trackers);
array_push($results, array (
// Required
foreach ($movie['torrents'] as $torrent) {
$magnet = "magnet:?xt=urn:btih:".sanitize($torrent['hash'])."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->torrent_trackers);
$seeders = sanitize($torrent['seeds']);
$leechers = sanitize($torrent['peers']);
$size = sanitize($torrent['size']);
$quality = sanitize($torrent['quality']);
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Required
"source" => "yts.mx",
"name" => $name,
"magnet" => $magnet,
"seeders" => sanitize($torrent["seeds"]),
"leechers" => sanitize($torrent["peers"]),
"size" => sanitize($torrent["size"]),
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional
"quality" => sanitize($torrent["quality"]),
"year" => sanitize($movie["year"]),
"category" => sanitize(implode(', ', $movie["genres"])),
"runtime" => sanitize($movie["runtime"]),
"url" => sanitize($movie["url"]),
"date_added" => sanitize($movie["date_uploaded_unix"])
"quality" => $quality,
"year" => $year,
"category" => $category,
"runtime" => $runtime,
"url" => $url,
"date_added" => $date_added
));
}
}
unset($magnet, $seeders, $leechers, $size, $quality);
}
unset($name, $year, $category, $runtime, $url, $date_added);
}
return $results;
}

View file

@ -75,11 +75,13 @@ abstract class EngineRequest {
--------------------------------------*/
public function get_results() {
// It's a torrent search?
if(!isset($this->url)) return $this->parse_results(null);
// Skip if there is a cached result (from earlier search)
// If there is a cached result from an earlier search use that instead
if($this->opts->cache == "on" && has_cached_results($this->url, $this->opts->hash)) return fetch_cached_results($this->url, $this->opts->hash);
// Curl request
if(!isset($this->ch)) return $this->parse_results(null);
$response = ($this->mh) ? curl_multi_getcontent($this->ch) : curl_exec($this->ch);
@ -98,17 +100,17 @@ abstract class EngineRequest {
// Load and make config available, pass around variables
--------------------------------------*/
function load_opts() {
$opts = require "config.php";
$opts->query = (isset($_REQUEST['q'])) ? sanitize($_REQUEST["q"]) : "";
$opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST["t"]) : 0;
$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST["a"]) : "";
$opts = require "config.php";
// From the url/request
$opts->query = (isset($_REQUEST['q'])) ? sanitize($_REQUEST['q']) : "";
$opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : "";
// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
$has_exclamation_mark = substr($opts->query, 0, 1);
if($has_exclamation_mark == "!") $opts->query = ltrim($opts->query, "!");
return $opts;
if(substr($opts->query, 0, 1) == "!") $opts->query = substr($opts->query, 1);
return $opts;
}
/*--------------------------------------
@ -117,37 +119,44 @@ function load_opts() {
function fetch_search_results($opts) {
$start_time = microtime(true);
// Curl
$mh = curl_multi_init();
echo "<section class=\"main-column\">";
// Load search script
if($opts->type == 0 || $opts->type == 1) {
require "engines/search.php";
$search = new TextSearch($opts, $mh);
} else if($opts->type == 2) {
require "engines/search-image.php";
$search = new ImageSearch($opts, $mh);
} else if($opts->type == 9) {
require "engines/search-torrent.php";
$search = new TorrentSearch($opts, $mh);
if(!empty($opts->query)) {
// Curl
$mh = curl_multi_init();
// Load search script
if($opts->type == 0 || $opts->type == 1) {
require "engines/search.php";
$search = new TextSearch($opts, $mh);
} else if($opts->type == 2) {
require "engines/search-image.php";
$search = new ImageSearch($opts, $mh);
} else if($opts->type == 9) {
require "engines/search-torrent.php";
$search = new TorrentSearch($opts, $mh);
}
$running = null;
do {
curl_multi_exec($mh, $running);
} while ($running);
$results = $search->get_results();
curl_multi_close($mh);
// Add elapsed time to results
$results['time'] = number_format(microtime(true) - $start_time, 5, '.', '');
// Echoes results and special searches
$search->print_results($results, $opts);
} else {
echo "<div class=\"warning\">Search query can not be empty!<br />Not sure what went wrong? Learn more about <a href=\"./help.php?a=".$opts->hash."\">how to use Goosle</a>.</div>";
}
$running = null;
do {
curl_multi_exec($mh, $running);
} while ($running);
$results = $search->get_results();
curl_multi_close($mh);
// Add elapsed time to results
$results['time'] = number_format(microtime(true) - $start_time, 5, '.', '');
$search->print_results($results, $opts);
return $results;
echo "</section>";
}
/*--------------------------------------
@ -158,7 +167,7 @@ function special_search_request($opts) {
$query_terms = explode(" ", $opts->query);
// Currency converter
if($opts->special['currency'] == "on" && is_numeric($query_terms[0]) && ($query_terms[2] == 'to' || $query_terms[2] == 'in')) {
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";
$special_request = new CurrencyRequest($opts, null);
}

View file

@ -19,24 +19,6 @@ function verify_hash($opts, $auth) {
return false;
}
/*--------------------------------------
// Strip all extras from an url
--------------------------------------*/
function get_base_url($url) {
$parsed = parse_url($url);
return $parsed["scheme"] . "://" . $parsed["host"] . "/";
}
/*--------------------------------------
// Format search result urls
--------------------------------------*/
function get_formatted_url($url) {
$parsed = parse_url($url);
return $parsed["scheme"] . "://" . $parsed["host"] . str_replace('/', ' &rsaquo; ', str_replace('%20', ' ', rtrim($parsed['path'], '/')));
}
/*--------------------------------------
// Load pages into a DOM
--------------------------------------*/
@ -51,6 +33,24 @@ function get_xpath($response) {
return $xpath;
}
/*--------------------------------------
// Strip all extras from an url
--------------------------------------*/
function get_base_url($url) {
$url = parse_url($url);
return $url['scheme'] . "://" . $url['host'] . "/";
}
/*--------------------------------------
// Format search result urls
--------------------------------------*/
function get_formatted_url($url) {
$url = parse_url($url);
return $url['scheme'] . "://" . $url['host'] . str_replace('/', ' &rsaquo; ', str_replace('%20', ' ', rtrim($url['path'], '/')));
}
/*--------------------------------------
// APCu Caching
--------------------------------------*/

View file

@ -35,7 +35,7 @@ if(verify_hash($opts, $auth)) {
<div class="header-wrap">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a class="no-decoration" href="./?a=<?php echo $opts->hash; ?>"><span class="G">G</span>oosle</a></h1>
<input tabindex="1" class="search" type="text" value="<?php echo (strlen($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" required /><input tabindex="2" class="button" type="submit" value="Search" />
<input tabindex="1" class="search" type="search" value="<?php echo (strlen($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>">
@ -63,12 +63,12 @@ if(verify_hash($opts, $auth)) {
<h2>Google features</h2>
<p>Searching defaults to Moderate Safe mode. You can override safe mode by adding the prefix <strong>safe:on</strong> or <strong>safe:off</strong> to your search query.<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>
<p>Google results are not personalized by default, using Google's option for it.</p>
<p>Google search is language agnostic and Google will try to figure out on it's own what language to use. To search in a specific language prefix your search with <strong>lang fr</strong> for French or <strong>lang:es</strong> for Spanish. Any language that google supports will work as long as you use the ISO639-1:2002 language code. Commonly these are the 2 letter abbreviations for the language such as; en, fr, es, de, sk, and so on.</p>
<p>Google search is language agnostic and Google will try to figure out on it's own what language to use. To search in a specific language prefix your search with <strong>lang:fr</strong> for French or <strong>lang:es</strong> for Spanish. Any language that google supports will work as long as you use the ISO639-1:2002 language code. Commonly these are the 2 letter abbreviations for the language such as; en, fr, es, de, sk, and so on.</p>
<p>To do a category search, prefix your search with one of the following keywords; <strong>app</strong>, <strong>book</strong>, <strong>news</strong>, <strong>shop</strong> or <strong>patent</strong>. This will tell Google to look for results in that specific category.<br />For example: Searching for <strong>book trainspotting</strong> will (or should) show results related to the book Trainspotting.</p>
<?php if($opts->enable_image_search == "on") { ?>
<h2>Image Search</h2>
<p>Search for images through Qwant Image Search.<br />The number of results is limited to 50.</p>
<p>Search for images through Yahoo! Image Search.<br />The number of results is limited to 100. So up to 100 images may appear.</p>
<p>Contrary to Google Image Search which opens a popup/slider with more information. Goosle Image Search links directly to the page where the image is hosted.</p>
<p>You can search for images in a general size by adding <strong>size:small</strong>, <strong>size:medium</strong> or <strong>size:large</strong> to your search query.</p>
<?php } ?>
@ -77,7 +77,7 @@ if(verify_hash($opts, $auth)) {
<?php if($opts->special['currency'] == "on") { ?>
<h3>Currency converter</h3>
<p>Convert currency with a simple query.<br />
For example: Search for <strong>20 EUR in HKD</strong> or <strong>20 USD to MXN</strong> and DuckDuckGo or Google will search for it, but also a local conversion is done in a highlighted result.</p>
For example: Search for <strong>20 EUR in HKD</strong> or <strong>14 USD to MXN</strong> and DuckDuckGo or Google will search for it, but also a local conversion is done in a highlighted result.</p>
<?php } ?>
<?php if($opts->special['wikipedia'] == "on") { ?>
@ -89,24 +89,33 @@ if(verify_hash($opts, $auth)) {
<?php if($opts->special['phpnet'] == "on") { ?>
<h3>PHP.net Search</h3>
<p>Prefix your search with <strong>php</strong> to search on php.net for a PHP function.<br />
For example: Searching for <strong>php in_array</strong> or <strong>php trim</strong> will show you a brief description, compatible PHP versions and a usage example for that function.</p>
For example: Searching for <strong>php in_array</strong> or <strong>php trim</strong> will show you a brief description, compatible PHP versions and the basic syntax for that function.</p>
<?php } ?>
<?php if($opts->special['definition'] == "on") { ?>
<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>, <strong>meaning</strong>.<br />
For example: Searching for <strong>define search</strong> will search for that on Google or DuckDuckGo, but also show the definition highlighted above the search results.</p>
<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 on Google or DuckDuckGo, but also show the dictionary definition highlighted above the search results.</p>
<p><em><strong>Note:</strong> Special Searches do not work for torrent searches.</em></p>
<?php } ?>
<?php if($opts->enable_torrent_search == "on") { ?>
<h2>Torrent 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 and YTS and are sorted by Seeders, highest first. The number of results is limited to 50.</p>
<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 sorted by Seeders, highest first. 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>
<p><em><strong>Disclaimer:</strong> If you like, or found a use for, what you downloaded, you should probably buy a legal copy of it.</em></p>
<?php if($opts->special['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 if you're looking a tv show that doesn't have a unique name.</p>
<p> If you already know the Title ID you can enter it directly in the Torrent search as your search query.<br />
If you don't know the Title ID you can search DuckDuckGo or Google for <strong>imdb [tv show name]</strong>, for example <strong>imdb game of thrones</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>
<p>To help you narrow down seasons and episodes you can search for <strong>tt0944947 S08</strong> and get filtered results from EZTV for Game of Thrones Season 8. Searching for <strong>tt0944947 S08E05</strong> should find Season 8 Episode 5 and so on.</p>
<?php } ?>
<p><em><strong>Note:</strong> If you like, or found a use for, what you downloaded, you should probably 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>.</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 again.</small></p>
</section>
</div>
</div>

View file

@ -36,7 +36,7 @@ if(verify_hash($opts, $auth)) {
<form action="results.php" method="get" autocomplete="off">
<h1><span class="G">G</span>oosle</h1>
<input tabindex="10" type="text" class="search" name="q" autofocus required />
<input tabindex="10" type="search" class="search" name="q" autofocus />
<input type="hidden" name="t" value="0"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>

View file

@ -1,5 +1,5 @@
# Goosle
A fast, privacy oriented meta search engine that just works.
A fast, privacy oriented meta search engine that just works. \
Kept simple so everyone can use it and to make sure it works on most (basic) webservers.
Host for yourself and friends, with a access hash key. Or set up a public search website.
@ -11,7 +11,7 @@ After-all, finding things should be easy and not turn into a chore.
## Features
- Search on DuckDuckGo
- Search on Google.com
- Image search through Qwant
- Image search through Yahoo! Images
- Search for magnet links on popular Torrent sites
- Special searches for; Currency conversion, Dictionary, Wikipedia and php.net
- Instant password generator on the home page
@ -27,22 +27,25 @@ What Goosle does *not* have.
And yet it just works...
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).
## 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)
## Requirements
Any basic webserver/webhosting package with PHP7.4 or newer.
Any basic webserver/webhosting package with PHP7.4 or newer. \
Tested to work on Apache with PHP8.2.
## Installation
1. Unzip the download.
2. Edit the config.php file with your preferences.
3. 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. Rename goosle.htaccess to .htaccess
5. Load the site in your browser. If you've enabled the access hash add ?a=YOURHASH to the url.
6. Let me know where you installed 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. search.example.com) or a sub-folder on your main site (eg. 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.
7. Let me know where you installed Goosle :-)
### Notes:
- The .htaccess file has a redirect to force HTTPS as well as browser caching instructions ready to go.
@ -51,25 +54,46 @@ Tested to work on Apache with PHP8.2.
Have fun finding things!
## Disclaimer
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.
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. \
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:.
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:
## Support
Goosle comes with limited support. You can post your questions on Github or on my support forum on [ajdg.solutions](https://ajdg.solutions/support/).
Goosle comes with limited support. \
You can post your questions on Github or on my support forum on [ajdg.solutions](https://ajdg.solutions/support/?mtm_campaign=goosle_readme). \
Or say hi on [Telegram](https://t.me/arnandegans).
## Changelog
1.1 - December 21, 2023
- [new] API search for EZTV TV Shows.
- [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] 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] Sanitize scraped data earlier in the process.
- [tweak] Consistent single quotes for arrays.
- [tweak] Consistent spaces, tabs and newlines.
- [fix] Inconsistent input height for search field vs search button.
- [fix] Better check if a search is currency conversion or not.
- [fix] Typos in help.php.
1.0.2 - December 7, 2023
- [fix] Magnet links for torrents no longer opening in new tabs.
- [change] More useful error response when search doesn't work.
- [change] EngineRequest::request_successful() now provides a boolean response.
- [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.
1.0.1 - December 5, 2023
- [fix] mktime() getting intermittent strings in 1337x crawler.

View file

@ -35,8 +35,9 @@ if(verify_hash($opts, $auth)) {
<div class="header-wrap">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a class="no-decoration" href="./?a=<?php echo $opts->hash; ?>"><span class="G">G</span>oosle</a></h1>
<input tabindex="1" class="search" type="text" value="<?php echo (strlen($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" required /><input tabindex="2" class="button" type="submit" value="Search" />
<input tabindex="1" class="search" type="search" value="<?php echo (strlen($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>">