Initial release

The first public release of Goosle.
This commit is contained in:
Arnan de Gans 2023-12-05 16:11:28 -06:00
parent e054b6da22
commit 6e7114a205
29 changed files with 2255 additions and 0 deletions

BIN
apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

198
assets/css/styles.css Normal file
View file

@ -0,0 +1,198 @@
/* ------------------------------------------------------------------------------------
* 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.
------------------------------------------------------------------------------------ */
body { position: relative; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; color: #222; background-color: #ffffff; line-height: 1; }
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; }
h2, h3, h4, h5, h6, p, ul, ol, blockquote { padding-top: .5em; padding-bottom: .5em; }
ol, ol > li { margin: 0; padding: 0; list-style: none; }
input, button { outline: none; }
button { cursor: pointer; }
p { font-size: 18px; color: #494949; }
a { text-decoration: none; color: #4495d4; }
a:hover { text-decoration: underline; }
input[type="text"]:invalid ~ input[type="submit"] { opacity: 0.5; pointer-events: none; }
/* Page structure */
.wrap { min-height: 100vh; overflow: hidden; }
.header-wrap { display: block; padding-top: 16px; width: 100%; }
.results-wrap { position: relative; display: flex; margin: 0 158px 50px 158px; }
.footer-wrap { position: absolute; bottom: 0; display: block; margin-top: 15px; padding: 0; width: 100%; }
/* 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-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-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; }
/* 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; }
/* 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:hover { color: #ebf3fa; }
.navigation-header a:visited { color: #1fa4d1; }
.navigation-header .active { padding-bottom: 8px; border-bottom: 4px #1fa4d1 solid; }
/* 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 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; }
.main-column ol li article div.url { 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; }
.main-column ol li article div.url a { margin: 0; color: #3f6e35; cursor: pointer; text-decoration: none; }
.main-column ol li article div.title, .main-column ol li.special-result article div.title { margin-top: .146rem; margin-bottom: .28451rem; }
.main-column ol li article div.title h2 { margin: 0; padding: 0; position: relative; font-size: 1.46rem; letter-spacing: -.01px; }
.main-column ol li article div.title h2:hover { text-decoration: underline; }
.main-column ol li article div.title a { margin: 0; display: block; cursor: pointer; }
.main-column ol li article div.title a:visited { color: #6d59a3; }
.main-column ol li article div.description { margin: 0; line-height: 1.4; font-size: 1rem; color: #494949; }
.main-column ol li article div.description .seeders { color: #518257; }
.main-column ol li article div.description .leechers { color: #c00; }
/* Image results - Main column */
.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; }
.image-grid li.result { display: inline-block; margin: .75rem; width: 12.5%; }
.image-grid > * + * { margin-top: 1rem; }
}
@supports (display: grid) {
.main-column ol.image-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); grid-gap: 1rem; }
}
.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%; }
/* Special results - Main column */
.main-column ol .special-result { background-color: #fefefe; }
.main-column ol li.special-result article { padding: .5rem 10px; position: relative; overflow: hidden; border: 1px solid #aeaeae; border-radius: 8px; color: #222; }
.main-column ol li.special-result article div.title h2 { margin: 0; padding: 0; font-size: 1.5rem; font-weight: 600; word-wrap: break-word; color: #222; }
.main-column ol li.special-result article div.title h2:hover { text-decoration: none; }
.main-column ol li.special-result article div.title a { margin: 0; display: block; color: #6c00a2; cursor: pointer; }
.main-column ol li.special-result article div.title a:visited { color: #6d59a3; }
.main-column ol li.special-result article div.text, .main-column ol li article div.source { padding-top: 10px; position: relative; font-style: normal; }
.main-column ol li.special-result article div.text img { padding: 0 0 10px 10px; }
.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; }
/* Misc */
.logo { position: absolute; margin: 28px 18px; }
.logo a { color: #f0f6fc; cursor: pointer; }
.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; }
.auth-error { margin-top: 15%; font-size: 32px; text-align: center; color: #eaeaea; }
/* Footer bar */
.footer-wrap { background-color: #161616; color: #f0f6fc; border-top: 2px solid #303134; }
.footer { padding: 10px; }
.footer a { color: #f0f6fc; }
@media only screen and (max-width:960px) { /* tablet, landscape iPad, lo-res laptops ands desktops */
/* Page structure */
.results-wrap { position: relative; display: flex; margin: 0 48px 20px 48px; }
/* Main page */
.search-box-main { margin-top: 10%; }
.search-box-main input { width: 80%; }
.search-box-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header-wrap { margin-left: auto; margin-right: auto; text-align: center; }
.header-wrap .search { margin: 10px 0px 28px 48px; width: 400px; }
.header-wrap .search, .header-wrap .button { margin: 10px 0px 28px 0px; }
/* Search results - Header Navigation */
.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
.navigation-header a { margin: 0 auto; padding: 0; }
/* Misc */
.logo { position: relative; display: block;margin: 0 auto; float: none; padding: 10px; font-size: 28px; }
}
@media only screen and (max-width:640px) { /* portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones */
/* Page structure */
.results-wrap { position: relative; display: flex; margin: 0 10px 10px 10px; }
/* Main page */
.search-box-main { margin-top: 10%; }
.search-box-main input { width: 80%; }
.search-box-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header-wrap { margin-left: auto; margin-right: auto; text-align: center; }
.header-wrap .search, .header-wrap .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
.navigation-header a { margin: 0 auto; padding: 0; }
/* Misc */
.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 28px; }
}
@media only screen and (max-width:480px) { /* portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */
/* Page structure */
.results-wrap { position: relative; display: flex; margin: 0 10px 10px 10px; }
/* Main page */
.search-box-main { margin-top: 10%; }
.search-box-main input { width: 80%; }
.search-box-main h1 { font-size: 45px; }
.search-box-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header-wrap { margin-left: auto; margin-right: auto; text-align: center; }
.header-wrap .search, .header-wrap .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
.navigation-header a { margin: 0 auto; padding: 0; }
/* Misc */
.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 28px; }
}
@media only screen and (max-width:320px) { /* smartphones, iPhone, portrait 480x320 phones */
/* Page structure */
.results-wrap { position: relative; display: flex; margin: 0 10px 10px 10px; }
/* Main page */
.search-box-main { margin-top: 40px; }
.search-box-main input { width: 80%; }
.search-box-main h1 { font-size: 45px; }
.search-box-buttons button { display: table-row; margin: 20px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header-wrap { margin-left: auto; margin-right: auto; text-align: center; }
.header-wrap .search, .header-wrap .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
.navigation-header a { margin: 0 auto; padding: 0; }
/* Misc */
.logo { position: relative; float: none; display: block; margin: 0 auto; padding: 10px; font-size: 28px; }
}

BIN
assets/images/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/images/search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/images/torrent.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

114
config.php Normal file
View file

@ -0,0 +1,114 @@
<?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.
------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------
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.
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
"off" Disables cache, useful for testing or if your server lacks APCu support
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.
"on" (Default)
"off"
ENABLE IMAGE SEARCH:
Enable or disable image searches - Search results are provided by Qwant.
"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 a server/script.
Safari and Internet Explorer may be a limiting factor on results as they are lesser supported browsers. But should otherwise be fine.
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.
BLOCK 1337x CATEGORIES:
Add category IDs of 1337x categories, check /engines/torrent/1337x.php for a list of known categories.
BLOCK PIRATEBAY CATEGORIES:
Add category IDs of Pirate Bay categories, check /engines/torrent/thepiratebay.php for a list of known categories.
BLOCK YTS CATEGORIES:
Add category names as keywords, eg; "thriller", "war".
Movies can be in multiple categories, if a movie is in 5 categories it only has to match one to be filtered out.
TORRENT TRACKERS:
Only used for The Pirate Bay and YTS.
These are added to the magnet links Goosle creates. You can add more or replace the existing ones.
------------------------------------------------------------------------------------ */
return (object) array(
"hash" => "blja-3jaq-34eg",
"cache" => "off",
"cache_time" => 30, // (Default: 30)
"hash_auth" => "off", // Default: off)
"raw_output" => "off", // (Default: off)
"enable_torrent_search" => "on", // (Default: on)
"enable_image_search" => "on", // (Default: on)
"special" => array(
"currency" => "on", // Currency converter
"definition" => "on", // Word dictionary
"wikipedia" => "on", // Wikipedia highlight
"phpnet" => "on", // PHP-dot-net highlight
"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
),
"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",
"udp://open.stealth.si:80/announce",
"udp://tracker.opentrackr.org:1337/announce",
"udp://exodus.desync.com:6969/announce",
"udp://tracker.torrent.eu.org:451/announce",
),
"version" => "1.0",
"released" => "Nov 28, 2023"
);
?>

93
engines/duckduckgo.php Normal file
View file

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

112
engines/google.php Normal file
View file

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

117
engines/search-image.php Normal file
View file

@ -0,0 +1,117 @@
<?php
class ImageSearch extends EngineRequest {
public function get_request_url() {
$results = array();
// Split the query
$query_terms = explode(" ", strtolower($this->query));
// Size override
$size = "";
if($query_terms[0] == 'size') {
$switch = explode(":", $query_terms[0]);
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] == "small" || $switch[1] == "medium" || $switch[1] == "large") {
$size = $switch[1];
}
$this->query = implode(" ", array_slice($query_terms, 1));
}
}
// q = query
// t = Search type (images)
// size = Preferred image size (small|medium|large)
$args = array("q" => $this->query, "t" => "images", "size" => $size);
$url = "https://lite.qwant.com?".http_build_query($args);
unset($query_terms, $switch, $args, $size);
return $url;
}
public function parse_results($response) {
$results = array("search" => array());
$xpath = get_xpath($response);
if(!$xpath) return $results;
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,
));
}
}
// Add warning if there are no results, or a text if there is no search query.
if(empty($results['search'])) {
$results["error"] = array(
"message" => "No results found. Please try with less or different keywords!"
);
}
return $results;
}
public static function print_results($results, $opts) {
if($opts->raw_output == "on") {
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 "<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;
// 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 "</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>";
}
}
?>

109
engines/search-torrent.php Normal file
View file

@ -0,0 +1,109 @@
<?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 TorrentSearch extends EngineRequest {
protected $requests;
public function __construct($opts, $mh) {
$this->opts = $opts;
$this->url = 'torrent'; // Dummy value to satisfy EngineRequest::get_results()
require "engines/torrent/1337x.php";
require "engines/torrent/nyaa.php";
require "engines/torrent/thepiratebay.php";
require "engines/torrent/yts.php";
$this->requests = array(
new LeetxRequest($opts, $mh), // 1337x
new NyaaRequest($opts, $mh),
new PirateBayRequest($opts, $mh),
new YTSRequest($opts, $mh)
);
}
public function parse_results($response) {
$results = $results_temp = array();
foreach ($this->requests as $request) {
if($request->request_successful()) {
$results_temp = array_merge($results_temp, $request->get_results());
}
}
if(count($results_temp) > 0) {
// Ensure highest seeders are shown first
$seeders = array_column($results_temp, "seeders");
array_multisort($seeders, SORT_DESC, $results_temp);
// Cap results
$results['search'] = array_slice($results_temp, 0, 50);
unset($results_temp);
}
// Add warning if there are no results
if(empty($results)) {
$results["error"] = array(
"message" => "No results found. Please try with less or different keywords!"
);
}
return $results;
}
public static function print_results($results, $opts) {
if($opts->raw_output == "on") {
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)) {
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>";
// Put result together
echo "<li class=\"result\"><article>";
echo "<div class=\"url\"><a href=\"".$result["magnet"]."\" target=\"_blank\">".$result["source"]."</a></div>";
echo "<div class=\"title\"><a href=\"".$result["magnet"]."\" target=\"_blank\"><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>";
}
}
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>";
}
}
?>

164
engines/search.php Normal file
View file

@ -0,0 +1,164 @@
<?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 TextSearch extends EngineRequest {
protected $engine, $engine_request, $special_request;
public function __construct($opts, $mh) {
$this->query = $opts->query;
$this->opts = $opts;
if($this->opts->type == 0) {
require "engines/duckduckgo.php";
$this->engine_request = new DuckDuckGoRequest($opts, $mh);
}
if($this->opts->type == 1) {
require "engines/google.php";
$this->engine_request = new GoogleRequest($opts, $mh);
}
// Special search
$this->special_request = special_search_request($opts);
}
public function parse_results($response) {
$results = array();
// Abort if no results from search engine
if(!isset($this->engine_request)) return $results;
// Add search results
$success = $this->engine_request->request_successful();
if($success == "ok") {
$search_result = $this->engine_request->get_results();
if($search_result) {
$results['search'] = $search_result;
}
unset($search_result);
} else {
$results["error"] = array(
"message" => $success
);
}
// Check for Special result
if($this->special_request) {
$special_result = $this->special_request->get_results();
if($special_result) {
$results['special'] = $special_result;
}
unset($special_result);
}
// Add warning if there are no results, or a text if there is no search query.
if(empty($results)) {
$results["error"] = array(
"message" => "No results found. Please try with less or different keywords!"
);
}
return $results;
}
public static function print_results($results, $opts) {
if($opts->raw_output == "on") {
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
}
echo "<section class=\"main-column\">";
echo "<ol>";
// Elapsed time
if(array_key_exists("search", $results)) {
$number_of_results = count($results['search']);
echo "<li class=\"meta-time\">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("search", $results)) {
$specific_result = "";
if(array_key_exists("did_you_mean", $results['search'][0])) {
if(array_key_exists("search_specific", $results['search'][1])) {
// Add double quotes to Google search
$search_specific = ($opts->type == 1) ? "\"".$results['search'][1]['search_specific']."\"" : $results['search'][1]['search_specific'];
$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>";
unset($results['search'][1], $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;
echo "<li class=\"meta-did-you-mean\">Did you mean <a href=\"$didyoumean_url\">$didyoumean</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>';
}
// 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>";
}
// Search results
if(array_key_exists("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 "</article></li>";
}
}
echo "</ol>";
echo "</section>";
}
}
?>

View file

@ -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 CurrencyRequest extends EngineRequest {
public function get_request_url() {
return "https://cdn.moneyconvert.net/api/latest.json";
}
public function parse_results($response) {
$json_response = json_decode($response, true);
if(!empty($json_response)) {
$result = $json_response["rates"];
// Process query
// [0] = AMOUNT
// [1] = FROM CURRENCY
// [2] = (to|in)
// [3] = TO CURRENCY
$query_terms = explode(" ", $this->query);
$amount = floatval($query_terms[0]);
$amount_currency = strtoupper($query_terms[1]);
$conversion_currency = strtoupper($query_terms[3]);
// Unknown/misspelled currencies
if (!array_key_exists($amount_currency, $result) || !array_key_exists($conversion_currency, $result)) {
return array();
}
// Calculate exchange rate
$conversion = round(($result[$conversion_currency] / $result[$amount_currency]) * $amount, 4);
return array(
"title" => "Currency conversion:",
"text" => "$amount $amount_currency = $conversion $conversion_currency",
"source" => "https://moneyconvert.net/"
);
} else {
return array(
"title" => "Uh-oh...",
"text" => "No exchange rates could be loaded. Try again later."
);
}
}
}
?>

View file

@ -0,0 +1,58 @@
<?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 DefinitionRequest extends EngineRequest {
public function get_request_url() {
$query_terms = explode(" ", $this->query);
// [0] = (define|d|mean|meaning)
// [1] = WORD
return "https://api.dictionaryapi.dev/api/v2/entries/en/".$query_terms[1];
}
public function parse_results($response) {
$json_response = json_decode($response, true);
if(!empty($json_response)) {
// Word not found
if (array_key_exists("title", $json_response)) {
return array(
"title" => strip_tags(trim($json_response['title'])),
"text" => strip_tags(trim($json_response['message']))
);
}
// Grab first result if there are multiple
$result = $json_response[0];
$definitions = array_slice($result['meanings'][0]['definitions'], 0, 3);
// Word found
$formatted_response = strip_tags(trim($result['meanings'][0]['partOfSpeech']))."<br /><ol class=\"word-definitions\">";
foreach($definitions as $key => $def) {
$formatted_response .= "<li>".strip_tags(trim($def['definition']))."</li>";
}
$formatted_response .= "</ol>";
return array(
"title" => strip_tags(trim($result['word']))." <span>[".strip_tags(trim($result['phonetic']))."]</span>",
"text" => $formatted_response,
"source" => strip_tags(trim($result['sourceUrls'][0]))
);
} else {
return array(
"title" => "Whoops...",
"text" => "No definitions could be loaded. Try again later."
);
}
}
}
?>

47
engines/special/php.php Normal file
View file

@ -0,0 +1,47 @@
<?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 PHPnetRequest extends EngineRequest {
public function get_request_url() {
$this->query = str_replace("_", "-", str_replace("php ", "", $this->query));
return "https://www.php.net/manual/function.".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
if($xpath) {
// Scrape the page
$title = $xpath->query("//div/section/div[@class='refentry']/div/h1[@class='refname']")[0]->textContent;
if(is_null($title)) return array();
$php_versions = $xpath->query("//div/section/div[@class='refentry']/div/p[@class='verinfo']")[0]->textContent;
$purpose = $xpath->query("//div/section/div[@class='refentry']/div/p[@class='refpurpose']")[0]->textContent;
$usage = $xpath->query("//div/section/div[@class='refentry']/div[@class='refsect1 description']/div[@class='methodsynopsis dc-description']")[0]->textContent;
$response = array (
// Required
"title" => sanitize($title),
"text" => "<p>".$purpose." <em><small>".$php_versions."</small></em></p><p>".highlight_string("<?php ".trim($usage)." ?>", 1)."</p>",
"source" => "https://www.php.net/manual/function.".urlencode($this->query)
);
return $response;
} else {
return array(
"title" => "Oof...",
"text" => "PHP.net didn't provide any answers. Try again later."
);
}
}
}
?>

View file

@ -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 WikipediaRequest extends EngineRequest {
public function get_request_url() {
$query_terms = explode(" ", $this->query);
// [0] = (wiki|w)
// [1] = SEARCH TERM
unset($query_terms[0]); // Remove first item (w or wiki) from array and encode the rest for Wikipedia
$this->query = implode(" ", $query_terms);
return "https://wikipedia.org/w/api.php?format=json&action=query&prop=extracts%7Cpageimages&exintro&explaintext&redirects=1&pithumbsize=500&titles=".urlencode($this->query);
}
public function parse_results($response) {
$json_response = json_decode($response, true);
if(!empty($json_response)) {
$result = $json_response['query']['pages'];
// Abort on invalid response
if (!is_array($result)) return array();
// Grab first result if there are multiple
$result = $result[array_key_first($result)];
// Page not found
if (array_key_exists("missing", $result)) {
return array(
"title" => "Wiki page not found",
"text" => "Maybe the page doesn't exist. Try searching on Wikipedia with the link below or search for something else.",
"source" => "https://wikipedia.org/wiki/Special:Search?go=Go&search=".urlencode($this->query)
);
}
// Page found
$response = array(
"title" => strip_tags(trim($result['title'])),
"text" => strip_tags(trim($result['extract'])),
"source" => "https://wikipedia.org/wiki/".urlencode($this->query)
);
if (array_key_exists("thumbnail", $result)) {
$response["image"] = strip_tags(trim($result["thumbnail"]["source"]));
}
return $response;
} else {
return array(
"title" => "Sigh...",
"text" => "Wikipedia could not be loaded. Try again later."
);
}
}
}
?>

142
engines/torrent/1337x.php Normal file
View file

@ -0,0 +1,142 @@
<?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 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;
$categories = array(
1 => "DVD",
2 => "Divx/Xvid",
3 => "SVCD/VCD",
4 => "Dubs/Dual Audio",
5 => "DVD",
6 => "Divx/Xvid",
7 => "SVCD/VCD",
9 => "Documentary",
10 => "PC Game",
11 => "PS2",
12 => "PSP",
13 => "Xbox",
14 => "Xbox360",
15 => "PS1",
16 => "Dreamcast",
17 => "Other (Gaming)",
18 => "PC Software",
19 => "Mac Software",
20 => "Linux Software",
21 => "Other (Software)",
22 => "MP3",
23 => "Lossless Audio",
24 => "DVD (Music)",
25 => "Music Video",
26 => "Radio",
27 => "Other (Audio)",
28 => "Anime",
33 => "Emulation",
34 => "Tutorials",
35 => "Sounds",
36 => "E-Books",
37 => "Images",
38 => "Mobile Phone",
39 => "Comics",
40 => "Other",
41 => "HD (Video)",
42 => "HD (Video)",
43 => "PS3",
44 => "Wii",
45 => "DS",
46 => "GameCube",
47 => "Nulled Script",
48 => "Video",
49 => "Picture",
50 => "Magazine",
51 => "Hentai",
52 => "Audiobook",
53 => "Album (Music)",
54 => "h.264/x264",
55 => "Mp4",
56 => "Android",
57 => "iOS",
58 => "Box Set (Music)",
59 => "Discography",
60 => "Single (Music)",
66 => "3D",
67 => "Games",
68 => "Concerts",
69 => "AAC (Music)",
70 => "HEVC/x265",
71 => "HEVC/x265",
72 => "3DS",
73 => "Bollywood",
74 => "Cartoon",
75 => "SD (Video)",
76 => "UHD",
77 => "PS4",
78 => "Dual Audio (Video)",
79 => "Dubbed (Video)",
80 => "Subbed",
81 => "Raw",
82 => "Switch",
);
// 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, date("m", strtotime($date_added[0])), 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);
$size = $size_unformatted[0] . " " . preg_replace("/[0-9]+/", "", $size_unformatted[1]);
array_push($results, array (
// Required
"source" => "1337x.to",
"name" => sanitize($name),
"magnet" => "./engines/torrent/magnetize_1337x.php?url=".$url,
"seeders" => sanitize($seeders),
"leechers" => sanitize($leechers),
"size" => sanitize($size),
// Optional values
"category" => $categories[sanitize($category[2])],
"url" => $url,
"date_added" => $date_added
));
}
return $results;
}
}
?>

View file

@ -0,0 +1,49 @@
<?php
require "../../misc/tools.php";
$opts = require "../../config.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.
------------------------------------------------------------------------------------ */
$ch = curl_init();
curl_setopt($this->ch, CURLOPT_URL, $_REQUEST["url"]);
curl_setopt($this->ch, CURLOPT_HTTPGET, 1); // Redundant? Probably...
curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($this->ch, CURLOPT_VERBOSE, false);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->ch, CURLOPT_USERAGENT, $opts->user_agents[array_rand($opts->user_agents)]);
curl_setopt($this->ch, 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',
'Upgrade-Insecure-Requests: 1'
));
curl_setopt($this->ch, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($this->ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl_setopt($this->ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($this->ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($this->ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($this->ch, CURLOPT_TIMEOUT, 3);
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);
$xpath = get_xpath($response);
// No results
if(!$xpath) die();
$magnet = $xpath->query("//main/div/div/div/div/div/ul/li/a/@href")[0]->textContent;
$magnet = trim($magnet);
header("Location: $magnet")
?>

56
engines/torrent/nyaa.php Normal file
View file

@ -0,0 +1,56 @@
<?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 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;
// 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));
$date_added = mktime(0, 0, 0, $date_added[1], $date_added[2], $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),
// Optional values
"category" => str_replace(" - ", "/", sanitize($category)),
"url" => "https://nyaa.si".sanitize($url),
"date_added" => $date_added
));
}
return $results;
}
}
?>

View file

@ -0,0 +1,115 @@
<?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 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);
// No response
if(empty($json_response)) return $results;
$categories = array(
100 => "Audio",
101 => "Music",
102 => "Audio Book",
103 => "Sound Clips",
104 => "Audio FLAC",
199 => "Audio Other",
200 => "Video",
201 => "Movie",
202 => "Movie DVDr",
203 => "Music Video",
204 => "Movie Clip",
205 => "TV Show",
206 => "Handheld",
207 => "HD Movie",
208 => "HD TV Show",
209 => "3D Movie",
210 => "CAM/TS",
211 => "UHD/4K Movie",
212 => "UHD/4K TV Show",
299 => "Video Other",
300 => "Applications",
301 => "Apps Windows",
302 => "Apps Apple",
303 => "Apps Unix",
304 => "Apps Handheld",
305 => "Apps iOS",
306 => "Apps Android",
399 => "Apps Other OS",
400 => "Games",
401 => "Games PC",
402 => "Games Apple",
403 => "Games PSx",
404 => "Games XBOX360",
405 => "Games Wii",
406 => "Games Handheld",
407 => "Games iOS",
408 => "Games Android",
499 => "Games Other OS",
500 => "Porn",
501 => "Porn Movie",
502 => "Porn Movie DVDr",
503 => "Porn Pictures",
504 => "Porn Games",
505 => "Porn HD Movie",
506 => "Porn Movie Clip",
507 => "Porn UHD/4K Movie",
599 => "Porn Other",
600 => "Other",
601 => "Other E-Book",
602 => "Other Comic",
603 => "Other Pictures",
604 => "Other Covers",
605 => "Other Physibles",
699 => "Other Other"
);
// Use API result
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"])),
// Optional
"category" => $categories[sanitize($response["category"])],
"url" => "https://thepiratebay.org/description.php?id=".sanitize($response["id"]),
"date_added" => sanitize($response["added"]),
));
}
return $results;
}
}
?>

66
engines/torrent/yts.php Normal file
View file

@ -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 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);
// 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 $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'] = '';
// 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
"source" => "yts.mx",
"name" => $name,
"magnet" => $magnet,
"seeders" => sanitize($torrent["seeds"]),
"leechers" => sanitize($torrent["peers"]),
"size" => sanitize($torrent["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"])
));
}
}
return $results;
}
}
?>

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

188
functions/search_engine.php Normal file
View file

@ -0,0 +1,188 @@
<?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.
------------------------------------------------------------------------------------ */
abstract class EngineRequest {
protected $url, $query, $opts, $mh, $ch;
function __construct($opts, $mh) {
$this->query = $opts->query;
$this->mh = $mh;
// Must be in this order :-/
$this->opts = $opts;
$this->url = $this->get_request_url();
// No search engine url
if(!$this->url) return;
// Skip if there is a cached result (from earlier search)
if($this->opts->cache == "on" && has_cached_results($this->url, $this->opts->hash)) return;
// Curl
$this->ch = curl_init();
curl_setopt($this->ch, CURLOPT_URL, $this->url);
curl_setopt($this->ch, CURLOPT_HTTPGET, 1); // Redundant? Probably...
curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($this->ch, CURLOPT_VERBOSE, false);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->ch, CURLOPT_USERAGENT, $this->opts->user_agents[array_rand($this->opts->user_agents)]);
curl_setopt($this->ch, 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',
'Upgrade-Insecure-Requests: 1'
));
curl_setopt($this->ch, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($this->ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl_setopt($this->ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($this->ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($this->ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($this->ch, CURLOPT_TIMEOUT, 3);
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, true);
if($mh) curl_multi_add_handle($mh, $this->ch);
}
/*--------------------------------------
// Get search engine url
--------------------------------------*/
public function get_request_url() {
return "";
}
/*--------------------------------------
// Check if a request to a search engine was successful
--------------------------------------*/
public function request_successful() {
if((isset($this->ch) && curl_getinfo($this->ch)['http_code'] == '200') || has_cached_results($this->url, $this->opts->hash)) {
$return = "ok";
} else {
$return = "Error code ".curl_getinfo($this->ch)['http_code']." for ".curl_getinfo($this->ch)['url'].". <a href=\"".curl_getinfo($this->ch)['url']."\" target=\"_blank\">Go there now</a>.";
}
return $return;
}
abstract function parse_results($response);
/*--------------------------------------
// Load search results
--------------------------------------*/
public function get_results() {
if(!isset($this->url)) return $this->parse_results(null);
// Skip if there is a cached result (from earlier search)
if($this->opts->cache == "on" && has_cached_results($this->url, $this->opts->hash)) return fetch_cached_results($this->url, $this->opts->hash);
if(!isset($this->ch)) return $this->parse_results(null);
$response = ($this->mh) ? curl_multi_getcontent($this->ch) : curl_exec($this->ch);
$results = $this->parse_results($response) ?? array();
// Cache last request
if($this->opts->cache == "on" && !empty($results)) store_cached_results($this->url, $this->opts->hash, $results, ($this->opts->cache_time * 60));
return $results;
}
public static function print_results($results, $opts) {}
}
/*--------------------------------------
// 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"]) : "";
// 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;
}
/*--------------------------------------
// Try to get some search results
--------------------------------------*/
function fetch_search_results($opts) {
$start_time = microtime(true);
// 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, '.', '');
$search->print_results($results, $opts);
return $results;
}
/*--------------------------------------
// Process special searches
--------------------------------------*/
function special_search_request($opts) {
$special_request = null;
$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')) {
require "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";
$special_request = new DefinitionRequest($opts, null);
}
// Wikipedia search
if($opts->special['wikipedia'] == "on" && count($query_terms) >= 2 && ($query_terms[0] == 'wiki' || $query_terms[0] == 'w')) {
require "engines/special/wikipedia.php";
$special_request = new WikipediaRequest($opts, null);
}
// php.net search
if($opts->special['phpnet'] == "on" && count($query_terms) == 2 && $query_terms[0] == 'php') {
require "engines/special/php.php";
$special_request = new PHPnetRequest($opts, null);
}
return $special_request;
}
?>

127
functions/tools.php Normal file
View file

@ -0,0 +1,127 @@
<?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.
------------------------------------------------------------------------------------ */
/*--------------------------------------
// Verify the hash, or not, and let people in, or not
--------------------------------------*/
function verify_hash($opts, $auth) {
if(($opts->hash_auth == "on" && strtolower($opts->hash) === strtolower($auth)) || $opts->hash_auth == "off") return true;
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
--------------------------------------*/
function get_xpath($response) {
if(!$response)
return null;
$htmlDom = new DOMDocument;
@$htmlDom->loadHTML($response);
$xpath = new DOMXPath($htmlDom);
return $xpath;
}
/*--------------------------------------
// APCu Caching
--------------------------------------*/
function has_cached_results($url, $hash) {
if(function_exists("apcu_exists")) {
return apcu_exists("$hash:$url");
}
return false;
}
function store_cached_results($url, $hash, $results, $ttl = 0) {
if(function_exists("apcu_store") && !empty($results)) {
return apcu_store("$hash:$url", $results, $ttl);
}
}
function fetch_cached_results($url, $hash) {
if(function_exists("apcu_fetch")) {
return apcu_fetch("$hash:$url");
}
return array();
}
/*--------------------------------------
// Sanitize variables
--------------------------------------*/
function sanitize($thing) {
switch(gettype($thing)) {
case 'string':
$thing = stripslashes(strip_tags(trim($thing)));
break;
case 'boolean':
$thing = ($thing === FALSE) ? 0 : 1;
break;
default:
$thing = ($thing === NULL) ? 'NULL' : strip_tags(trim($thing));
break;
}
return $thing;
}
/*--------------------------------------
// Human readable file sizes
--------------------------------------*/
function human_filesize($bytes, $dec = 2) {
$size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$dec}f ", $bytes / pow(1024, $factor)) . @$size[$factor];
}
/*--------------------------------------
// Generate random strings for passwords
--------------------------------------*/
function string_generator() {
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$password = array();
$length = strlen($characters) - 1;
for ($i = 0; $i < 24; $i++) {
$n = rand(0, $length);
$password[] = $characters[$n];
}
array_splice($password, 6, 0, '-');
array_splice($password, 13, 0, '-');
array_splice($password, 20, 0, '-');
return implode($password);
}
?>

44
goosle.htaccess Normal file
View file

@ -0,0 +1,44 @@
# mod_rewrite
RewriteEngine on
# FORCE SSL
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# Redirect 404 to homepage
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . / [L,R=301]
# Use UTF-8 encoding for anything served text/plain or text/html
AddDefaultCharset UTF-8
AddCharset UTF-8 .css .js
# Cache Control
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType application/font-woff "access plus 1 year"
ExpiresByType text/css "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
# Failsaves
ExpiresByType application/octet-stream "access plus 1 year"
ExpiresByType text/plain "access plus 1 year"
ExpiresDefault "access 30 days"
# Gzip compression
SetOutputFilter DEFLATE
# Dont compress images and other uncompressible content
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png|rar|zip|exe|flv|mov|wma|mp3|avi|swf|mp?g|mp4|webm|webp)$ no-gzip dont-vary
# Compress all output labeled with one of the following MIME-types
AddOutputFilterByType DEFLATE application/atom+xml application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/xhtml+xml application/xml font/ttf font/otf font/opentype image/svg+xml image/x-icon text/css text/html text/plain text/x-component text/xml
Header append Vary: Accept-Encoding
# Force deflate for mangled headers
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding

129
help.php Normal file
View file

@ -0,0 +1,129 @@
<?php
require "functions/tools.php";
require "functions/search_engine.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.
------------------------------------------------------------------------------------ */
?>
<!DOCTYPE html >
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="UTF-8"/>
<meta name="description" content="A private meta search engine!"/>
<meta name="referrer" content="no-referrer"/>
<link rel="apple-touch-icon" href="apple-touch-icon.png">
<link rel="icon" href="favicon.ico" type="image/x-icon"/>
<link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<title><?php echo $opts->query; ?> - Goosle Search</title>
</head>
<body>
<?php
if(verify_hash($opts, $auth)) {
?>
<div class="wrap">
<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 type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>">
<div class="navigation-header">
<a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="DuckDuckGo results" />DuckDuckGo</a>
<a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/search.png" alt="Google results" />Google</a>
<?php if($opts->enable_image_search == "on") { ?>
<a <?php echo ($opts->type == "2") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=2"><img src="assets/images/image.png" alt="Image results" />Image</a>
<?php } ?>
<?php if($opts->enable_torrent_search == "on") { ?>
<a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/torrent.png" alt="Torrent results" />Torrent</a>
<?php } ?>
</div>
</form>
</div>
<div class="results-wrap">
<section class="main-column">
<h2>DuckDuckGo features</h2>
<p>DuckDuckGo is mostly language agnostic and will try to figure out on it's own what language to use.</p>
<p>Searching defaults to Moderate Safe mode. To override the safe mode prefix your search with <strong>safe:on</strong> or <strong>safe:off</strong>.<br /><strong>On</strong> will use 'Strict' mode, while <strong>off</strong> will disable safe searching, this may yield results that are unsuitable for work or minors.</p>
<p><em><strong>Note:</strong> Search bangs are not supported and the <strong>!</strong> to trigger them is stripped out to prevent issues.</em></p>
<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>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>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 } ?>
<h2>Special Searches</h2>
<?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>
<?php } ?>
<?php if($opts->special['wikipedia'] == "on") { ?>
<h3>Wikipedia Search</h3>
<p>Prefix your search with <strong>w</strong> or <strong>wiki</strong> to search on Wikipedia for a page match. This works best for English searches as Wikipedia defaults to English.<br />
For example: Searching for <strong>wiki beach ball</strong> will show you a excerpt from that page above the search results or suggest the most likely alternative if Wikipedia knows what your search query means.</p>
<?php } ?>
<?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>
<?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><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>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 } ?>
<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>Version:</strong> <?php echo $opts->version; ?> / <strong>Released:</strong> <?php echo $opts->released; ?></small></p>
</section>
</div>
</div>
<div class="footer-wrap">
<div class="footer">
&copy; <?php echo date('Y'); ?> <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>. All rights reserved.
<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>
<?php
} else {
echo "<div class=\"auth-error\">Nope, go away!</div>";
}
?>
</body>
</html>

72
index.php Normal file
View file

@ -0,0 +1,72 @@
<?php
require "functions/tools.php";
require "functions/search_engine.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.
------------------------------------------------------------------------------------ */
?>
<!DOCTYPE html >
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="UTF-8"/>
<meta name="description" content="Goosle - A meta search engine for private and fast internet fun!"/>
<meta name="referrer" content="no-referrer"/>
<link rel="apple-touch-icon" href="apple-touch-icon.png">
<link rel="icon" href="favicon.ico" type="image/x-icon"/>
<link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<title>Goosle Search</title>
</head>
<body class="main">
<?php
if(verify_hash($opts, $auth)) {
?>
<div class="wrap">
<div class="search-box-main">
<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 type="hidden" name="t" value="0"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>
<div class="search-box-buttons">
<button tabindex="20" name="t" value="0" type="submit">DuckDuckGo</button>
<button tabindex="30" name="t" value="1" type="submit">Google</button>
<?php if($opts->enable_image_search == "on") { ?>
<button tabindex="40" name="t" value="2" type="submit">Image</button>
<?php } ?>
<?php if($opts->enable_torrent_search == "on") { ?>
<button tabindex="50" name="t" value="9" type="submit">Torrent</button>
<?php } ?>
</div>
</form>
</div>
<?php if($opts->special['password_generator'] == "on") { ?>
<div class="password-generator">
<form method="get" action="./" autocomplete="off">
Password Generator:<br/><input class="password" type="text" name="pw" maxlength="27" value="<?php echo string_generator(); ?>" autocomplete="0" />
</form>
</div>
<?php } ?>
</div>
<?php
} else {
echo "<div class=\"auth-error\">Nope, go away!</div>";
}
?>
</body>
</html>

58
readme.md Normal file
View file

@ -0,0 +1,58 @@
# Goosle
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.
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
- 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
- Randomized user-agents for to prevent profiling by search providers
- Works on *any* hosting package that does PHP7.4 or newer
- Optional: Access key as a very basic way to keep your server to yourself
- Optional: Speed up repeat searches with APCu cache if your server has it
What Goosle does *not* have.
- Trackers and Cookies
- User profiles or user controllable settings
- Javascripts or Frameworks
And yet it just works...
## Requirements
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.
### Notes:
- The .htaccess file has a redirect to force HTTPS as well as browser caching instructions 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 access hash is NOT meant as a super secure measure and only works for surface level prying eyes.
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 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.
## 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/).
## Changelog
1.0 - December 5, 2023
- Initial release

74
results.php Normal file
View file

@ -0,0 +1,74 @@
<?php
require "functions/tools.php";
require "functions/search_engine.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.
------------------------------------------------------------------------------------ */
?>
<!DOCTYPE html >
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="UTF-8"/>
<meta name="description" content="A private meta search engine!"/>
<meta name="referrer" content="no-referrer"/>
<link rel="apple-touch-icon" href="apple-touch-icon.png">
<link rel="icon" href="favicon.ico" type="image/x-icon"/>
<link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<title><?php echo $opts->query; ?> - Goosle Search</title>
</head>
<body>
<?php
if(verify_hash($opts, $auth)) {
?>
<div class="wrap">
<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 type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>">
<div class="navigation-header">
<a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="DuckDuckGo results" />DuckDuckGo</a>
<a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/search.png" alt="Google results" />Google</a>
<?php if($opts->enable_image_search == "on") { ?>
<a <?php echo ($opts->type == "2") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=2"><img src="assets/images/image.png" alt="Image results" />Image</a>
<?php } ?>
<?php if($opts->enable_torrent_search == "on") { ?>
<a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/torrent.png" alt="Torrent results" />Torrent</a>
<?php } ?>
</div>
</form>
</div>
<div class="results-wrap">
<?php fetch_search_results($opts); ?>
</div>
</div>
<div class="footer-wrap">
<div class="footer">
&copy; <?php echo date('Y'); ?> <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>. All rights reserved.
<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>
<?php
} else {
echo "<div class=\"auth-error\">Nope, go away!</div>";
}
?>
</body>
</html>

2
robots.txt Normal file
View file

@ -0,0 +1,2 @@
User-agent: *
Disallow: /