Version 1.2

1.2 - January 2, 2024
- [new] Preferred language setting for DuckDuckGo results in config.php.
- [new] Preferred language setting for Wikipedia results in config.php.
- [new] Combined DuckDuckGo, Google, Wikipedia and Ecosia (Bing) results into one page.
- [new] Ranking algorithm for search results.
- [new] Option to down-rank certain social media sites in results (Makes them show lower down the page).
- [new] Option to show the Goosle rank along with the search source.
- [new] Crawler for results from Limetorrents.lol.
- [new] Periodic check for updates in footer.
- [change] Moved duckduckgo.php and google.php into the engines/search/ folder.
- [change] Removed Wikipedia special search in favor of actual search results.
- [change] Removed 'Date Added' from 1337x results.
- [change] Removed Chrome based and Mobile user-agents, as they don't work for the WikiPedia API.
- [change] Added more trackers for generating magnet links.
- [tweak] 30-50% faster parsing of search results (couple of ms per search query).
- [tweak] Expanded the season/episode filter to all sources that support TV Shows.
- [tweak] More sensible santization of variables (Searching for html tags/basic code should now work).
- [tweak] Moved 'imdb_id_search' out from special results into its 'own' setting.
- [tweak] Moved 'password_generator' out from special results into its 'own' setting.
- [tweak] More accurate and faster Google scrape.
- [tweak] Reduced paragraph margins.
- [tweak] More code cleanup, making it more uniform.
- [fix] Prevents searching on disabled methods by 'cheating' the search type in the url.
- [fix] Better decoding for special characters in urls for search results.
- [fix] Better validation for special searches trigger words.
- [fix] Better sanitization for DuckDuckGo and Google results.
This commit is contained in:
Arnan de Gans 2024-01-02 00:24:27 -06:00
parent 86d0d57dc8
commit 92a70e6d28
24 changed files with 1239 additions and 551 deletions

View file

@ -13,7 +13,7 @@ body { position: relative; margin: 0; padding: 0; font-family: Arial, Helvetica,
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; }
h2, h3, h4, h5, h6, p, ul, ol, blockquote { margin: 0; padding-top: .5em; padding-bottom: .5em; }
ol, ol > li { margin: 0; padding: 0; list-style: none; }
input, button { outline: none; }
button { cursor: pointer; }
@ -60,19 +60,23 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
/* Search results - Main column */
.main-column { width: 100%; }
.main-column ol .meta { margin: .75rem 0 .05rem 0; padding: .5rem 10px 0 10px; }
.main-column ol .sources { margin: .05rem 0 .75rem 0; padding: 0 10px .5rem 10px; font-size: 12px; color: #666; }
.main-column ol .special-result { margin: .75rem 0 .25rem 0; padding: .5rem 10px; }
.main-column ol .result { margin: .50rem 0 .50rem 0; padding: 0; }
.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; }
.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, .main-column ol li.special-result article div.title { margin-bottom: .29rem; }
.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.engine { padding: 2px 0; font: 12px italic; color: #666; }
.main-column ol li article div.description .seeders { color: #518257; }
.main-column ol li article div.description .leechers { color: #c00; }
@ -99,7 +103,7 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
.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, .main-column ol li article div.source { 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; }
@ -118,6 +122,7 @@ body.main { background-color: #1f242b; color: #f0f6fc; }
.footer-wrap { background-color: #161616; color: #f0f6fc; border-top: 2px solid #303134; }
.footer { padding: 10px; }
.footer a { color: #f0f6fc; }
a.update { color: #c90; font-weight: bold; }
@media only screen and (max-width:960px) { /* tablet, landscape iPad, lo-res laptops ands desktops */
/* Page structure */

View file

@ -23,15 +23,30 @@ HASH AUTH:
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.
If you have ACPu enabled in your server it is highly recommended to enable caching as it'll speed up repeat searches 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.
Accepts a numeric value between 1 and 30.
LANGUAGE:
DuckDuckGo, Google and Ecosia are language agnostic. But they DO profile you for your locale.
For example: Me searching with english terms has me seeing Spanish results because I live in Mexico. This setting should minimize that for supported engines.
DuckDuckGo uses language regions as opposed to a simpler language choice. See if your region is available - https://duckduckgo.com/duckduckgo-help-pages/settings/params/.
Google's language option breaks reasonable results and other options like verbatim mode and some other settings. So you'll have to rely on Google picking up on the query language.
Wikipedia needs to be told which language you want. This changes the search url. Use any of their supported languages (en, es, fr, nl, etc.)
SOCIAL MEDIA RELEVANCE:
Show social media results lower in the combined results if you don't value such results.
Downranked results include: Facebook, Instagram, Twitter, Snapchat, TikTok, LinkedIn and Reddit.
!!CAREFUL!! This is a blanket setting, if what you're searching for primarily has social media links then less relevant results may show first.
Accepts a numeric value between 1 and 10. With 10 having *NO* effect on the rank, and 0 not ranking the link at all (shows very very low in the results)
ENABLE IMAGE SEARCH:
Enable or disable image searches - Search results are provided by Qwant.
Enable or disable image searches - Search results are provided by Yahoo! Images.
"on" (Default)
"off"
@ -40,6 +55,27 @@ ENABLE TORRENT SEARCH:
"on" (Default)
"off"
SHOW SEARCH SOURCE:
Show which search engine(s) came up with the result.
"on" (Default)
"off"
SHOW SEARCH RANK:
When search source is enabled, show the rank Goosle gave the result.
"on"
"off" (Default)
IMDB ID SEARCH:
Highlight imdb results if it's a tv-show.
Handy for finding better results for specific tv-shows through EZTV and The Pirate Bay.
"on"
"off" (Default)
PASSWORD GENERATOR
Show a password generator on the Goosle home page.
"on" (Default)
"off"
SPECIAL:
Enable or disable special searches that show up before search results.
"on" (Default)
@ -48,46 +84,61 @@ SPECIAL:
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.
Keep them generic to prevent profiling, but also so that the request comes off as a generic boring browser and not as a server/crawler.
Safari 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.
Safari, Firefox and Internet Explorer/Edge should be safe to use.
Chrome may attract attention because of the lack of Chrome information (tracking) aside from the user agent. The search engine will know something is wrong.
Opera/Edge/Brave and many others use Chrome under the hood and are not a good pick for that reason.
Mobile agents may work, but some services like Wikipedia are a bit picky when it comes to answering API calls. Mobile users generally do not use APIs, so they may block your search.
SHOW ZERO SEEDERS:
Set to "on" to include results with 0 seeders (slow or stale downloads). Off to exclude these results.
"on" (Default)
"off"
BLOCK 1337x CATEGORIES:
Add category IDs of 1337x categories, check /engines/torrent/1337x.php for a list of known categories.
Accepts a basic numeric array, comma separated.
BLOCK PIRATEBAY CATEGORIES:
Add category IDs of Pirate Bay categories, check /engines/torrent/thepiratebay.php for a list of known categories.
Accepts a basic numeric array, comma separated.
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.
Accepts a basic array of keywords, comma separated.
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.
Only used for The Pirate Bay, LimeTorrents and YTS.
Generally you do not need to change these.
These are added to the magnet links Goosle creates. You can add more or replace the existing ones if you know what you're doing.
Accepts a basic array of strings (tracker urls), comma separated.
------------------------------------------------------------------------------------ */
return (object) array(
"hash" => "j9fg-i2du-er6m",
"hash_auth" => "off", // Default: off
"cache" => "off", // Default: off
"cache_time" => 30, // Default: 30
"cache_time" => 30, // Default: 30 (Minutes)
"duckduckgo_language" => "uk-en", // Default: uk-en (United Kingdom)
"wikipedia_language" => "en", // Default: en (English)
"social_media_relevance" => 8, // Default: 8
"enable_image_search" => "on", // Default: on
"enable_torrent_search" => "on", // Default: on
"show_search_source" => "on", // Default: on
"show_search_rank" => "off", // Default: off
"imdb_id_search" => "off", // Default: off
"password_generator" => "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
"currency" => "on", // Default: on, Currency converter
"definition" => "on", // Default: on, Word dictionary
"phpnet" => "off" // Default: off, PHP-dot-net highlight
),
"user_agents" => array(
@ -95,11 +146,6 @@ return (object) array(
"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
@ -108,12 +154,15 @@ return (object) array(
"yts_categories_blocked" => array("horror"), // Default: "horror"
"torrent_trackers" => array(
"http://nyaa.tracker.wf:7777/announce",
"udp://open.stealth.si:80/announce",
"http://tracker.openbittorrent.com:80/announce",
"udp://tracker.opentrackr.org:1337/announce",
"udp://exodus.desync.com:6969/announce",
"udp://tracker.torrent.eu.org:451/announce",
),
"version" => "1.1b2" // Please don't change this
"udp://tracker.yify-torrents.com/announce",
"udp://coppersurfer.tk:6969/announce",
"udp://opentracker.i2p.rocks:6969/announce",
"udp://tracker.internetwarriors.net:1337/announce",
"udp://tracker.zer0day.to:1337/announce",
)
);
?>

115
engines/image/yahoo.php Normal file
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 YahooImageRequest extends EngineRequest {
public function get_request_url() {
// 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] == "xlrg") $switch[1] = "wallpaper";
if($switch[1] == "small" || $switch[1] == "medium" || $switch[1] == "large" || $switch[1] == "wallpaper") {
$size = $switch[1];
}
$this->query = implode(" ", array_slice($query_terms, 1));
}
}
// p = query
// imgsz = Image size (small|medium|large|wallpaper)
$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);
return $url;
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
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
$scrape = $xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'slotting'))][position() < 101]");
$rank = $results['amount'] = count($scrape);
foreach($scrape as $result) {
$image = $xpath->evaluate(".//img/@src", $result)[0];
if($image == null) continue;
$url_data = $xpath->evaluate(".//a/@href", $result)[0];
if($url_data == null) continue;
// Get meta data
// -- Relevant $url_data (there is more, but unused by Goosle)
// 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);
// Deal with optional or missing data
$dimensions_w = (!array_key_exists('w', $url_data) || empty($url_data['w'])) ? "" : htmlspecialchars($url_data['w']);
$dimensions_h = (!array_key_exists('h', $url_data) || empty($url_data['h'])) ? "" : htmlspecialchars($url_data['h']);
$filesize = (!array_key_exists('size', $url_data) || empty($url_data['size'])) ? "" : htmlspecialchars($url_data['size']);
$link = (!array_key_exists('imgurl', $url_data) || empty($url_data['imgurl'])) ? "" : "//".htmlspecialchars($url_data['imgurl']);
// Process result
$image = htmlspecialchars($image->textContent);
$url = htmlspecialchars($url_data['rurl']);
$alt = htmlspecialchars($url_data['tt']);
// filter duplicate urls/results
if(!empty($results['search'])) {
$result_urls = array_column($results['search'], "direct_link");
if(in_array($link, $result_urls)) continue;
}
$id = uniqid(rand(0, 9999));
$results['search'][] = array ("id" => $id, "source" => "Yahoo! Images", "image" => $image, "alt" => $alt, "url" => $url, "width" => $dimensions_w, "height" => $dimensions_h, "filesize" => $filesize, "direct_link" => $link, "engine_rank" => $rank);
$rank -= 1;
}
// Add error if there are no search results
if(empty($results['search'])) {
$results['error'] = array(
"message" => "No results found. Please try with less or different keywords!"
);
}
return $results;
}
}
?>

View file

@ -1,113 +1,111 @@
<?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 ImageSearch extends EngineRequest {
public function get_request_url() {
protected $requests;
public function __construct($opts, $mh) {
require "engines/image/yahoo.php";
$this->requests = array(
new YahooImageRequest($opts, $mh),
);
}
public function parse_results($response) {
$results = array();
// Split the query
$query_terms = explode(" ", strtolower($this->query));
// Merge all results together
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
// Size override
$size = "";
if($query_terms[0] == 'size') {
$switch = explode(":", $query_terms[0]);
if(!empty($engine_result)) {
if(array_key_exists('search', $engine_result)) {
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(array_key_exists('did_you_mean', $engine_result)) {
$results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(array_key_exists('search_specific', $engine_result)) {
$results['search_specific'][] = $engine_result['search_specific'];
}
if($switch[1] == "small" || $switch[1] == "medium" || $switch[1] == "large" || $switch[1] == "wallpaper") {
$size = $switch[1];
$query_terms = explode(" ", preg_replace("/[^a-z0-9 ]+/", "", strtolower($request->query)));
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(array_key_exists('search', $results)) {
$result_urls = array_column($results['search'], "direct_link", "id");
$found_key = array_search($result['direct_link'], $result_urls);
} else {
$found_key = false;
}
if($found_key !== false) {
// Duplicate result from another source, merge and rank accordingly
$results['search'][$found_key]['goosle_rank'] += $result['engine_rank'];
} else {
// First find, rank and add to results
$match_rank = match_count($result['alt'], $query_terms);
$result['goosle_rank'] = $result['engine_rank'] + $match_rank;
$results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_key, $social_media_multiplier, $goosle_rank, $match_rank);
}
}
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
$this->query = implode(" ", array_slice($query_terms, 1));
$results['error'][] = array(
"message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."."
);
}
}
// p = query
// imgsz = Image size (small|medium|large|wallpaper)
$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);
return $url;
}
public function parse_results($response) {
$results = array("search" => array());
$xpath = get_xpath($response);
// 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;
unset($request);
}
// 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;
if(array_key_exists('search', $results)) {
// Re-order results based on rank
$keys = array_column($results['search'], 'goosle_rank');
array_multisort($keys, SORT_DESC, $results['search']);
// 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
));
// Count results per source
$results['sources'] = array_count_values(array_column($results['search'], 'source'));
unset($keys);
} else {
// Add error if there are no search results
$results['error'][] = array(
"message" => "No results found. Please try with more specific or different keywords!"
);
}
// Add error if there are no search results
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) {
return $results;
}
public static function print_results($results, $opts) {
/*
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
// Uncomment for debugging
echo '<pre>Settings: ';
print_r($opts);
echo '</pre>';
echo '<pre>Search results: ';
print_r($results);
echo '</pre>';
*/
if(array_key_exists("search", $results)) {
@ -117,27 +115,12 @@ class ImageSearch extends EngineRequest {
$number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Format sources
search_sources($results['sources']);
// Did you mean/Search suggestion
if(array_key_exists("did_you_mean", $results)) {
$specific_result = "";
search_suggestion($opts, $results);
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
@ -145,13 +128,11 @@ class ImageSearch extends EngineRequest {
echo "<ol class=\"image-grid\">";
foreach($results['search'] as $result) {
// Extra data
$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>";
@ -160,20 +141,20 @@ class ImageSearch extends EngineRequest {
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>";
}
// No results found
if(array_key_exists("error", $results)) {
echo "<div class=\"error\">".$results['error']['message']."</div>";
foreach($results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}
}
unset($results);
}
}
?>

View file

@ -13,20 +13,19 @@ 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/lime.php";
require "engines/torrent/thepiratebay.php";
require "engines/torrent/yts.php";
require "engines/torrent/nyaa.php";
require "engines/torrent/eztv.php";
$this->requests = array(
new LeetxRequest($opts, $mh), // 1337x
new NyaaRequest($opts, $mh),
new LimeRequest($opts, $mh), // Limetorrents
new PirateBayRequest($opts, $mh),
new YTSRequest($opts, $mh),
new NyaaRequest($opts, $mh),
new EZTVRequest($opts, $mh)
);
}
@ -36,74 +35,74 @@ class TorrentSearch extends EngineRequest {
foreach($this->requests as $request) {
if($request->request_successful()) {
$results_temp = array_merge($results_temp, $request->get_results());
$engine_result = $request->get_results();
if(!empty($engine_result)) {
$results_temp = array_merge($results_temp, $engine_result);
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] >= 200 && $request_result['http_code'] <= 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
$results['error'][] = array(
"message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."."
);
}
unset($request);
}
if(count($results_temp) > 0) {
// Ensure highest seeders are shown first
// Sort by highest seeders
$seeders = array_column($results_temp, "seeders");
array_multisort($seeders, SORT_DESC, $results_temp);
// Cap results
// Cap results to 50
$results['search'] = array_slice($results_temp, 0, 50);
// Count results per site
// Count results per source
$sources = array_count_values(array_column($results['search'], 'source'));
if(count($sources) > 0) $results['sources'] = $sources;
unset($sources);
} else {
// Add error if there are no search results
$results['error'][] = array(
"message" => "No results found. Please try with more specific or different keywords!"
);
}
unset($results_temp);
// Add error if there are no search results
if(empty($results)) {
$results['error'] = array(
"message" => "No results found. Please try with more specific or different keywords!"
);
}
return $results;
}
public static function print_results($results, $opts) {
/*
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
// Uncomment for debugging
echo '<pre>Settings: ';
print_r($opts);
echo '</pre>';
echo '<pre>Search results: ';
print_r($results);
echo '</pre>';
*/
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>";
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Format sources
search_sources($results['sources']);
// Search results
foreach($results['search'] as $result) {
// Extra data
$meta = array();
// Optional data
if($opts->show_search_source == "on") $meta[] = "<strong>Source:</strong> ".$result['source'];
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'];
@ -113,7 +112,6 @@ class TorrentSearch extends EngineRequest {
// 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=\"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>";
@ -122,12 +120,14 @@ class TorrentSearch extends EngineRequest {
}
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 "<center><small>Goosle does not index, offer or distribute torrent files.</small></center>";
}
// No results found
if(array_key_exists("error", $results)) {
echo "<div class=\"error\">".$results['error']['message']."</div>";
foreach($results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}
}
}
}

View file

@ -9,47 +9,90 @@
* 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);
}
class Search extends EngineRequest {
protected $requests, $special_request;
public function __construct($opts, $mh) {
require "engines/search/duckduckgo.php";
require "engines/search/google.php";
require "engines/search/wikipedia.php";
require "engines/search/ecosia.php";
$this->requests = array(
new DuckDuckGoRequest($opts, $mh),
new GoogleRequest($opts, $mh),
new WikiRequest($opts, $mh),
new EcosiaRequest($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;
// Merge all results together
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_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(!empty($engine_result)) {
if(array_key_exists('search', $engine_result)) {
if($search_result) {
$results = $search_result;
if(array_key_exists('did_you_mean', $engine_result)) {
$results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(array_key_exists('search_specific', $engine_result)) {
$results['search_specific'][] = $engine_result['search_specific'];
}
$query_terms = explode(" ", preg_replace("/[^a-z0-9 ]+/", "", strtolower($request->query)));
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(array_key_exists('search', $results)) {
$result_urls = array_column($results['search'], "url", "id");
$found_key = array_search($result['url'], $result_urls);
} else {
$found_key = false;
}
$social_media_multiplier = (is_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * floatval($social_media_multiplier));
if($found_key !== false) {
// Duplicate result from another source, merge and rank accordingly
$results['search'][$found_key]['goosle_rank'] += $goosle_rank;
$results['search'][$found_key]['combo_source'][] = $result['source'];
} else {
// First find, rank and add to results
$match_rank = match_count($result['title'], $query_terms);
$match_rank += match_count($result['description'], $query_terms);
// $match_rank += match_count($result['url'], $query_terms);
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $result['source'];
$results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_key, $social_media_multiplier, $goosle_rank, $match_rank);
}
}
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
$results['error'][] = array(
"message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."."
);
}
unset($search_result);
} else {
$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."
);
}
unset($request);
}
// Check for Special result
if($this->special_request) {
@ -62,21 +105,34 @@ class TextSearch extends EngineRequest {
unset($special_result);
}
// 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!"
);
if(array_key_exists('search', $results)) {
// Re-order results based on rank
$keys = array_column($results['search'], 'goosle_rank');
array_multisort($keys, SORT_DESC, $results['search']);
// Count results per source
$results['sources'] = array_count_values(array_column($results['search'], 'source'));
unset($keys);
} else {
// Add error if there are no search results
$results['error'][] = array(
"message" => "No results found. Please try with more specific or different keywords!"
);
}
return $results;
return $results;
}
public static function print_results($results, $opts) {
public static function print_results($results, $opts) {
/*
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
// Uncomment for debugging
echo '<pre>Settings: ';
print_r($opts);
echo '</pre>';
echo '<pre>Search results: ';
print_r($results);
echo '</pre>';
*/
if(array_key_exists("search", $results)) {
@ -86,91 +142,40 @@ class TextSearch extends EngineRequest {
$number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Format sources
search_sources($results['sources']);
// Did you mean/Search suggestion
if(array_key_exists("did_you_mean", $results)) {
$specific_result = "";
if(array_key_exists("search_specific", $results)) {
// Add double quotes to Google search
$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 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);
}
search_suggestion($opts, $results);
// 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;
}
}
}
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>";
}
special_search_result($opts, $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 "<li class=\"result rs-".$result['goosle_rank']." id-".$result['id']."\"><article>";
echo "<div class=\"url\"><a href=\"".$result['url']."\" target=\"_blank\">".get_formatted_url($result['url'])."</a></div>";
echo "<div class=\"title\"><a href=\"".$result['url']."\" target=\"_blank\"><h2>".$result['title']."</h2></a></div>";
echo "<div class=\"description\">".$result['description']."</div>";
if($opts->show_search_source == "on") {
echo "<div class=\"engine\">";
echo "Found on ".replace_last_comma(implode(", ", $result['combo_source'])).".";
if($opts->show_search_rank == "on") echo " [rank: ".$result['goosle_rank']."]";
echo "</div>";
}
echo "</article></li>";
unset($result);
}
echo "</ol>";
}
// No results found
// Some error occured
if(array_key_exists("error", $results)) {
echo "<div class=\"error\">".$results['error']['message']."</div>";
foreach($results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}
}
}
unset($results);
}
}
?>
?>

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() {
// Split the query
$query_terms = explode(" ", strtolower($this->query), 2);
$query_terms[0] = strtolower($query_terms[0]);
// Safe search override
$safe = "-1";
if(strpos($query_terms[0], "safe") !== false) {
$switch = explode(":", $query_terms[0]);
if(!is_numeric($switch[1])) {
$safe = (strtolower($switch[1]) == "off") ? "-2" : "1";
$this->query = implode(" ", array_slice($query_terms, 1));
}
}
// All parameters and values: https://duckduckgo.com/duckduckgo-help-pages/settings/params/
// q = query
// kp = Safe search (1 = on, -1 = moderate, -2 = off (may include nsfw/illegal content))
// kl = Search results language (Works as a region setting, see params page for more supported regions: en-us, en-uk, nl-nl, es-es, fr-fr, etc.)
// 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)
// k1 = Ads (1 = on, -1 = off)
$args = array("q" => $this->query, "kl" => $this->opts->duckduckgo_language, "kp" => $safe, "kz" => "-1", "kc" => "-1", "kav" => "-1", "kf" => "-1", "kaf" => "1", "kac" => "-1", "kd" => "-1", "kh" => "1", "kg" => "g", "k1" => "-1");
$url = "https://html.duckduckgo.com/html/?".http_build_query($args);
unset($query_terms, $safe, $switch, $args);
return $url;
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
if(!$xpath) return $results;
// Scrape recommended
$didyoumean = $xpath->query(".//div[@id='did_you_mean']/a[1]")[0];
if(!is_null($didyoumean)) {
$results['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//div[@id='did_you_mean']/a[2]")[0];
if(!is_null($search_specific)) {
$results['search_specific'] = $search_specific->textContent;
}
// Scrape the results
$scrape = $xpath->query("/html/body/div[1]/div[".count($xpath->query('/html/body/div[1]/div'))."]/div/div/div[contains(@class, 'web-result')]/div");
$rank = $results['amount'] = count($scrape);
foreach($scrape as $result) {
$url = $xpath->evaluate(".//h2[@class='result__title']//a/@href", $result)[0];
if($url == null) continue;
$title = $xpath->evaluate(".//h2[@class='result__title']", $result)[0];
if($title == null) continue;
$description = $xpath->evaluate(".//a[@class='result__snippet']", $result)[0];
$description = ($description == null) ? "No description was provided for this site." : htmlspecialchars(trim($description->textContent));
$url = htmlspecialchars(trim($url->textContent));
$title = htmlspecialchars(trim($title->textContent));
$id = uniqid(rand(0, 9999));
$results['search'][] = array ("id" => $id, "source" => "DuckDuckGo", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
$rank -= 1;
}
unset($response, $xpath, $scrape, $rank);
return $results;
}
}
?>

51
engines/search/ecosia.php Normal file
View file

@ -0,0 +1,51 @@
<?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 EcosiaRequest extends EngineRequest {
public function get_request_url() {
$args = array("q" => $this->query, "addon" => "opensearch");
$url = "https://www.ecosia.org/search/?".http_build_query($args);
return $url;
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
if(!$xpath) return $results;
// Scrape the results
$scrape = $xpath->query("//article[@class='result web-result mainline__result']");
$rank = $results['amount'] = count($scrape);
foreach($scrape as $result) {
$url = $xpath->evaluate(".//a[@class='result__link']/@href", $result)[0];
if($url == null) continue;
$title = $xpath->evaluate(".//h2[@class='result-title__heading']", $result)[0];
if($title == null) continue;
$description = $xpath->evaluate(".//p[@class='web-result__description']", $result)[0];
$description = ($description == null) ? "No description was provided for this site." : htmlspecialchars(trim($description->textContent));
$url = htmlspecialchars(trim($url->textContent));
$title = htmlspecialchars(trim($title->textContent));
$id = uniqid(rand(0, 9999));
$results['search'][] = array ("id" => $id, "source" => "Ecosia", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
$rank -= 1;
}
unset($response, $xpath, $scrape, $rank);
return $results;
}
}
?>

89
engines/search/google.php Normal file
View file

@ -0,0 +1,89 @@
<?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() {
// Split the query
$query_terms = explode(" ", strtolower($this->query), 2);
$query_terms[0] = strtolower($query_terms[0]);
// Safe search override
$safe = 1;
if(strpos($query_terms[0], "safe") !== false) {
$switch = explode(":", $query_terms[0]);
if(!is_numeric($switch[1])) {
$safe = (strtolower($switch[1]) == "off") ? "0" : "2";
$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
// pws = Personal search results 0 = off
// tbs = In Goosle used for 'verbatim' search, adding this enables it
// complete = Instant results related, 0 = off
// num = Number of results per page (number, multiple of 10 usually)
// sclient = where are you searching from
// Including the preferred language variable breaks the page result, and with that the crawler!
$args = array("q" => $this->query, "safe" => $safe, "pws" => "0", "tbs" => "li:1", "complete" => "0", "num" => "30", "sclient" => "web");
$url = "https://www.google.com/search?".http_build_query($args);
unset($query_terms, $safe, $switch, $args);
return $url;
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
if(!$xpath) return $results;
// Scrape recommended
$didyoumean = $xpath->query(".//a[@class='gL9Hy']")[0];
if(!is_null($didyoumean)) {
$results['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//a[@class='spell_orig']")[0];
if(!is_null($search_specific)) {
// Google doesn't add quotes by itself
$results['search_specific'] = "\"".$search_specific->textContent."\"";
}
// Scrape the results
$scrape = $xpath->query("//div[@id='search']//div[@class='MjjYud']");
$rank = $results['amount'] = count($scrape);
foreach($scrape as $result) {
$url = $xpath->evaluate(".//div[@class='yuRUbf']//a/@href", $result)[0];
if($url == null) continue;
$title = $xpath->evaluate(".//h3", $result)[0];
if($title == null) continue;
$description = $xpath->evaluate(".//div[contains(@class, 'VwiC3b')]", $result)[0];
$description = ($description == null) ? "No description was provided for this site." : htmlspecialchars(trim($description->textContent));
$url = htmlspecialchars(trim($url->textContent));
$title = htmlspecialchars(trim($title->textContent));
$id = uniqid(rand(0, 9999));
$results['search'][] = array ("id" => $id, "source" => "Google", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
$rank -= 1;
}
unset($response, $xpath, $scrape, $rank);
return $results;
}
}
?>

View file

@ -0,0 +1,44 @@
<?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 WikiRequest extends EngineRequest {
public function get_request_url() {
$args = array("srsearch" => $this->query, "action" => "query", "format" => "json", "list" => "search", "limit" => "10");
$url = "https://".$this->opts->wikipedia_language.".wikipedia.org/w/api.php?".http_build_query($args);
return $url;
}
public function parse_results($response) {
$results = array();
$json_response = json_decode($response, true);
if(empty($json_response)) return $results;
// No results
if($json_response['query']['searchinfo']['totalhits'] == 0) return $results;
$rank = $results['amount'] = count($json_response['query']['search']);
foreach($json_response['query']['search'] as $result) {
$title = htmlspecialchars(trim($result['title']));
$url = "https://".$this->opts->wikipedia_language.".wikipedia.org/wiki/".htmlspecialchars(str_replace(" ", "_", trim($result['title'])));
$description = htmlspecialchars(strip_tags(trim($result['snippet'])));
$id = uniqid(rand(0, 9999));
$results['search'][] = array ("id" => $id, "source" => "Wikipedia", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
$rank -= 1;
}
unset($response, $json_response, $rank);
return $results;
}
}
?>

View file

@ -31,7 +31,7 @@ class PHPnetRequest extends EngineRequest {
$response = array (
// Required
"title" => sanitize($title),
"text" => "<p>".$purpose." <em><small>".$php_versions."</small></em></p><p>".highlight_string("<?php ".trim($usage)." ?>", 1)."</p>",
"text" => "<p><em><small>".$php_versions."</small></em></p><p>".$purpose."</p><p>".highlight_string("<?php ".trim($usage)." ?>", 1)."</p>",
"source" => "https://www.php.net/manual/function.".urlencode($this->query)
);

View file

@ -11,7 +11,10 @@
------------------------------------------------------------------------------------ */
class LeetxRequest extends EngineRequest {
public function get_request_url() {
return "https://1337x.to/search/".urlencode($this->query)."/1/";
$url = "https://1337x.to/search/".urlencode($this->query)."/1/";
return $url;
}
public function parse_results($response) {
@ -107,38 +110,37 @@ class LeetxRequest extends EngineRequest {
// Scrape the page
foreach($xpath->query("//table/tbody/tr") as $result) {
$name = sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a", $result)[1]->textContent);
$url = "https://1337x.to".sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a/@href", $result)[1]->textContent);
$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]);
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
// Get extra data
$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;
// Filter by Season (S01) or Season and Episode (S01E01)
if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $name, $match_episode)) {
if($query_episode[0][0] != $match_episode[0][0] || (array_key_exists(1, $query_episode[0]) && array_key_exists(1, $match_episode[0]) && $query_episode[0][1] != $match_episode[0][1])) {
continue;
}
}
array_push($results, array (
$results[] = array (
// Required
"source" => "1337x.to",
"name" => $name,
"magnet" => "./engines/torrent/magnetize_1337x.php?url=".$url,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional values
"category" => $categories[$category],
"url" => $url,
"date_added" => $date_added
));
"source" => "1337x.to", "name" => $name, "magnet" => "./engines/torrent/magnetize_1337x.php?url=".$url, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
// Extra
"category" => $categories[$category], "url" => $url
);
unset($name, $seeders, $leechers, $size_unformatted, $size, $category, $url, $date_added);
unset($name, $seeders, $leechers, $size_unformatted, $size, $category, $url);
}
return $results;

View file

@ -11,23 +11,22 @@
------------------------------------------------------------------------------------ */
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 "";
$query = preg_replace('/[^0-9]/', '', $this->query);
if(strlen($query) == 0) $query = "0000";
// 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);
$args = array("imdb_id" => $query);
$url = "https://eztvx.to/api/get-torrents?".http_build_query($args);
unset($query, $args);
return $url;
}
public function parse_results($response) {
$results = array();
$response = curl_multi_getcontent($this->ch);
$json_response = json_decode($response, true);
// No response
@ -44,40 +43,29 @@ class EZTVRequest extends EngineRequest {
$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";
}
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
// Get extra data
$quality = (preg_match('/(480p|720p|1080p|2160p)/i', $name, $quality)) ? $quality[0] : "Unknown";
$date_added = sanitize($episode['date_released_unix']);
// 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)) {
if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $filter_episode)) {
if(str_ireplace("s0", "", $filter_episode[0][0]) != $season || (array_key_exists(1, $filter_episode[0]) && str_ireplace("e0", "", $filter_episode[0][1]) != $episode)) {
continue;
}
}
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
$results[] = array (
// Required
"source" => "EZTV",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => human_filesize($size),
// Optional
"quality" => $quality,
"date_added" => $date_added
));
"source" => "EZTV", "name" => $name, "magnet" => $magnet, "seeders" => $seeders, "leechers" => $leechers, "size" => human_filesize($size),
// Extra
"quality" => $quality, "date_added" => $date_added
);
unset($name, $magnet, $seeders, $leechers, $size, $quality, $category, $date_added, $season, $episode);
}

65
engines/torrent/lime.php Normal file
View file

@ -0,0 +1,65 @@
<?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 LimeRequest extends EngineRequest {
public function get_request_url() {
$this->query = preg_replace("/[^a-z0-9- ]+/", "", $this->query);
$this->query = str_replace(" ", "-", $this->query);
$url = "https://www.limetorrents.lol/search/all/".$this->query."/";
return $url;
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
// Failed to load page
if(!$xpath) return $results;
// Scrape the page
foreach($xpath->query("//table[@class='table2']//tr[position()>1]") as $result) {
$name = sanitize($xpath->evaluate(".//td[@class='tdleft']//a[2]", $result)[0]->textContent);
$hash = sanitize($xpath->evaluate(".//td[@class='tdleft']//a[1]/@href", $result)[0]->textContent);
$hash = explode("/", substr($hash, 0, strpos($hash, ".torrent?")));
$magnet = "magnet:?xt=urn:btih:".$hash[array_key_last($hash)]."&dn=".$name."&tr=".implode("&tr=", $this->opts->torrent_trackers);
$seeders = sanitize($xpath->evaluate(".//td[@class='tdseed']", $result)[0]->textContent);
$leechers = sanitize($xpath->evaluate(".//td[@class='tdleech']", $result)[0]->textContent);
$size = sanitize($xpath->evaluate(".//td[@class='tdnormal'][2]", $result)[0]->textContent);
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
// Get extra data
$category = explode(" ", sanitize($xpath->evaluate(".//td[@class='tdnormal'][1]", $result)[0]->textContent));
$category = $category[array_key_last($category)];
$url = "https://www.limetorrents.lol".sanitize($xpath->evaluate(".//td[@class='tdleft']//a[2]/@href", $result)[0]->textContent);
// Filter by Season (S01) or Season and Episode (S01E01)
if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $name, $match_episode)) {
if($query_episode[0][0] != $match_episode[0][0] || (array_key_exists(1, $query_episode[0]) && array_key_exists(1, $match_episode[0]) && $query_episode[0][1] != $match_episode[0][1])) {
continue;
}
}
$results[] = array (
// Required
"source" => "limetorrents.lol", "name" => $name, "magnet" => $magnet, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
// Extra
"category" => $category, "url" => $url
);
unset($name, $seeders, $leechers, $size, $hash, $magnet, $category, $url);
}
return $results;
}
}
?>

View file

@ -14,26 +14,7 @@ $opts = require "../../config.php";
------------------------------------------------------------------------------------ */
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST["url"]);
curl_setopt($ch, CURLOPT_HTTPGET, 1); // Redundant? Probably...
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $opts->user_agents[array_rand($opts->user_agents)]);
curl_setopt($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($ch, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
set_curl_options($ch, $_REQUEST["url"], $opts->user_agents);
$response = curl_exec($ch);
curl_close($ch);

View file

@ -11,7 +11,12 @@
------------------------------------------------------------------------------------ */
class NyaaRequest extends EngineRequest {
public function get_request_url() {
return "https://nyaa.si/?q=".urlencode($this->query);
$args = array("q" => $this->query);
$url = "https://nyaa.si/?".http_build_query($args);
unset($args);
return $url;
}
public function parse_results($response) {
@ -31,28 +36,30 @@ class NyaaRequest extends EngineRequest {
$leechers = sanitize($meta[4]->textContent);
$size = sanitize($meta[1]->textContent);
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
// Get extra data
$category = sanitize($xpath->evaluate(".//td[1]//a/@title", $result)[0]->textContent);
$url = sanitize($xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result)[0]->textContent);
$category = str_replace(" - ", "/", $category);
$url = "https://nyaa.si".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]));
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
// Filter by Season (S01) or Season and Episode (S01E01)
if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $name, $match_episode)) {
if($query_episode[0][0] != $match_episode[0][0] || (array_key_exists(1, $query_episode[0]) && array_key_exists(1, $match_episode[0]) && $query_episode[0][1] != $match_episode[0][1])) {
continue;
}
}
array_push($results, array (
$results[] = array (
// Required
"source" => "nyaa.si",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional values
"category" => str_replace(" - ", "/", $category),
"url" => "https://nyaa.si".$url,
"date_added" => $date_added
));
"source" => "nyaa.si", "name" => $name, "magnet" => $magnet, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
// Extra
"category" => $category, "url" => $url, "date_added" => $date_added
);
unset($name, $magnet, $seeders, $leechers, $size, $category, $url, $date_added, $meta);
}

View file

@ -11,7 +11,12 @@
------------------------------------------------------------------------------------ */
class PirateBayRequest extends EngineRequest {
public function get_request_url() {
return "https://apibay.org/q.php?q=".urlencode($this->query);
$args = array("q" => $this->query);
$url = "https://apibay.org/q.php?".http_build_query($args);
unset($args);
return $url;
}
public function parse_results($response) {
@ -94,31 +99,32 @@ class PirateBayRequest extends EngineRequest {
$leechers = sanitize($response['leechers']);
$size = sanitize($response['size']);
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
// Get extra data
$category = sanitize($response['category']);
$id = sanitize($response['id']);
$url = "https://thepiratebay.org/description.php?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;
// Filter by Season (S01) or Season and Episode (S01E01)
if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $name, $match_episode)) {
if($query_episode[0][0] != $match_episode[0][0] || (array_key_exists(1, $query_episode[0]) && array_key_exists(1, $match_episode[0]) && $query_episode[0][1] != $match_episode[0][1])) {
continue;
}
}
array_push($results, array(
$results[] = array(
// Required
"source" => "thepiratebay.org",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => human_filesize($size),
// Optional
"category" => $categories[$category],
"url" => "https://thepiratebay.org/description.php?id=".$id,
"date_added" => $date_added,
));
"source" => "thepiratebay.org", "name" => $name, "magnet" => $magnet, "seeders" => $seeders, "leechers" => $leechers, "size" => human_filesize($size),
// Extra
"category" => $categories[$category], "url" => $url, "date_added" => $date_added,
);
unset($name, $magnet, $seeders, $leechers, $size, $category, $id, $date_added);
unset($name, $magnet, $seeders, $leechers, $size, $category, $url, $date_added);
}
return $results;

View file

@ -11,7 +11,12 @@
------------------------------------------------------------------------------------ */
class YTSRequest extends EngineRequest {
public function get_request_url() {
return "https://yts.mx/api/v2/list_movies.json?query_term=".urlencode($this->query);
$args = array("query_term" => $this->query);
$url = "https://yts.mx/api/v2/list_movies.json?".http_build_query($args);
unset($args);
return $url;
}
public function parse_results($response) {
@ -38,6 +43,7 @@ class YTSRequest extends EngineRequest {
$name = sanitize($movie['title']);
// Get extra data
$year = sanitize($movie['year']);
$category = sanitize(implode(', ', $movie['genres']));
$runtime = sanitize($movie['runtime']);
@ -50,32 +56,21 @@ class YTSRequest extends EngineRequest {
$leechers = sanitize($torrent['peers']);
$size = sanitize($torrent['size']);
$quality = sanitize($torrent['quality']);
// Remove results with 0 seeders?
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Get extra data
$quality = sanitize($torrent['quality']);
$results[] = array (
// Required
"source" => "yts.mx",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional
"quality" => $quality,
"year" => $year,
"category" => $category,
"runtime" => $runtime,
"url" => $url,
"date_added" => $date_added
));
unset($magnet, $seeders, $leechers, $size, $quality);
"source" => "yts.mx", "name" => $name, "magnet" => $magnet, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
// Extra
"quality" => $quality, "year" => $year, "category" => $category, "runtime" => $runtime, "url" => $url, "date_added" => $date_added
);
}
unset($name, $year, $category, $runtime, $url, $date_added);
unset($name, $magnet, $seeders, $leechers, $size, $quality, $year, $category, $runtime, $url, $date_added);
}
return $results;

View file

@ -24,29 +24,11 @@ abstract class EngineRequest {
// 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();
set_curl_options($this->ch, $this->url, $this->opts->user_agents);
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);
}
@ -88,7 +70,7 @@ abstract class EngineRequest {
$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));
if($this->opts->cache == "on" && !empty($results)) store_cached_results($this->url, $this->opts->hash, $results, (intval($this->opts->cache_time) * 60));
return $results;
}
@ -103,10 +85,16 @@ function load_opts() {
$opts = require "config.php";
// From the url/request
$opts->query = (isset($_REQUEST['q'])) ? sanitize($_REQUEST['q']) : "";
$opts->query = (isset($_REQUEST['q'])) ? trim($_REQUEST['q']) : "";
$opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : "";
// Force a few defaults and safeguards
if($opts->enable_image_search == "off" && $opts->type == 1) $opts->type = 0;
if($opts->enable_torrent_search == "off" && $opts->type == 9) $opts->type = 0;
if(!is_numeric($opts->cache_time) || ($opts->cache_time > 30 || $opts->cache_time < 1)) $opts->cache_time = 30;
if(!is_numeric($opts->social_media_relevance) || ($opts->social_media_relevance > 10 || $opts->social_media_relevance < 0)) $opts->social_media_relevance = 8;
// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
if(substr($opts->query, 0, 1) == "!") $opts->query = substr($opts->query, 1);
@ -124,12 +112,12 @@ function fetch_search_results($opts) {
if(!empty($opts->query)) {
// Curl
$mh = curl_multi_init();
// Load search script
if($opts->type == 0 || $opts->type == 1) {
if($opts->type == 0) {
require "engines/search.php";
$search = new TextSearch($opts, $mh);
} else if($opts->type == 2) {
$search = new Search($opts, $mh);
} else if($opts->type == 1) {
require "engines/search-image.php";
$search = new ImageSearch($opts, $mh);
} else if($opts->type == 9) {
@ -165,6 +153,7 @@ function fetch_search_results($opts) {
function special_search_request($opts) {
$special_request = null;
$query_terms = explode(" ", $opts->query);
$query_terms[0] = strtolower($query_terms[0]);
// Currency converter
if($opts->special['currency'] == "on" && count($query_terms) == 4 && (is_numeric($query_terms[0]) && ($query_terms[2] == 'to' || $query_terms[2] == 'in'))) {
@ -178,12 +167,6 @@ function special_search_request($opts) {
$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";

View file

@ -19,6 +19,36 @@ function verify_hash($opts, $auth) {
return false;
}
/*--------------------------------------
// Set curl options
--------------------------------------*/
function set_curl_options($curl, $url, $user_agents) {
$referer_url = parse_url($url);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPGET, 1); // Redundant? Probably...
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_USERAGENT, $user_agents[array_rand($user_agents)]);
curl_setopt($curl, CURLOPT_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',
'Sec-Fetch-Dest: document',
'Sec-Fetch-Mode: navigate',
'Sec-Fetch-Site: none',
'Referer: '.$referer_url["scheme"].'://'.$referer_url["host"].'/',
));
curl_setopt($curl, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_MAXREDIRS, 5);
curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($curl, CURLOPT_TIMEOUT, 3);
curl_setopt($curl, CURLOPT_VERBOSE, false);
}
/*--------------------------------------
// Load pages into a DOM
--------------------------------------*/
@ -33,22 +63,16 @@ 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);
$url = parse_url($url);
return $url['scheme'] . "://" . $url['host'] . str_replace('/', ' &rsaquo; ', str_replace('%20', ' ', rtrim($url['path'], '/')));
$formatted_url = $url['scheme'] . "://" . $url['host'];
$formatted_url .= str_replace('/', ' &rsaquo; ', urldecode(str_replace('%20', ' ', rtrim($url['path'], '/'))));
return $formatted_url;
}
/*--------------------------------------
@ -79,20 +103,145 @@ function fetch_cached_results($url, $hash) {
/*--------------------------------------
// Sanitize variables
--------------------------------------*/
function sanitize($thing) {
switch(gettype($thing)) {
function sanitize($variable) {
switch(gettype($variable)) {
case 'string':
$thing = stripslashes(strip_tags(trim($thing)));
$variable = htmlspecialchars(trim($variable), ENT_QUOTES);
break;
case 'boolean':
$thing = ($thing === FALSE) ? 0 : 1;
$variable = ($variable === FALSE) ? 0 : 1;
break;
default:
$thing = ($thing === NULL) ? 'NULL' : strip_tags(trim($thing));
$variable = ($variable === NULL) ? 'NULL' : htmlspecialchars(strip_tags(trim($variable)), ENT_QUOTES);
break;
}
return $thing;
return $variable;
}
/*--------------------------------------
// Search result match counter
--------------------------------------*/
function match_count($string, $query) {
$string = strtolower($string);
if(filter_var($string, FILTER_VALIDATE_URL)) {
$string = preg_replace("/[^a-z0-9]+/", " ", $string);
}
$string = preg_replace("/[^a-z0-9 ]+/", "", $string);
$string = preg_replace("/\s{2,}/", " ", $string);
$matches = array_intersect(array_filter(array_unique(explode(" ", $string))), $query);
$matches = count($matches);
return $matches;
}
/*--------------------------------------
// Detect social media results
--------------------------------------*/
function is_social_media($string) {
$string = strtolower($string);
if(preg_match("/(?:https?:)?\/\/(?:www\.)?(?:facebook|fb)\.com\/(?P<profile>(?![A-z]+\.php)(?!marketplace|gaming|watch|me|messages|help|search|groups)[A-z0-9_\-\.]+)\/?/", $string)
|| preg_match("/(?:https?:)?\/\/(?:www\.)?(?:instagram\.com|instagr\.am)\/(?P<username>[A-Za-z0-9_](?:(?:[A-Za-z0-9_]|(?:\.(?!\.))){0,28}(?:[A-Za-z0-9_]))?)/", $string)
|| preg_match("/(?:https?:)?\/\/(?:[A-z]+\.)?twitter\.com\/@?(?P<username>[A-z0-9_]+)\/status\/(?P<tweet_id>[0-9]+)\/?/", $string)
|| preg_match("/(?:https?:)?\/\/(?:[A-z]+\.)?twitter\.com\/@?(?!home|share|privacy|tos)(?P<username>[A-z0-9_]+)\/?/", $string)
|| preg_match("/(?:https?:)?\/\/(?:[a-z]+\.)?reddit\.com\/(?:u(?:ser)?)\/(?P<username>[A-z0-9\-\_]*)\/?/", $string)
|| preg_match("/(?:https?:)?\/\/(?:www\.)?snapchat\.com\/add\/(?P<username>[A-z0-9\.\_\-]+)\/?/", $string)
|| preg_match("/^.*https:\/\/(?:m|www|vm)?\.?tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video)\/|\?shareId=|\&item_id=)(\d+))|\w+)/", $string)
|| preg_match("/(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/(?P<company_type>(company)|(school))\/(?P<company_permalink>[A-z0-9-À-ÿ\.]+)\/?/", $string)
|| preg_match("/(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/feed\/update\/urn:li:activity:(?P<activity_id>[0-9]+)\/?/", $string)
|| preg_match("/(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/in\/(?P<permalink>[\w\-\_À-ÿ%]+)\/?/", $string)
) return true;
return false;
}
/*--------------------------------------
// Search suggestions
--------------------------------------*/
function search_suggestion($opts, $results) {
if(array_key_exists("did_you_mean", $results)) {
$specific_result = $specific_result2 = "";
if(array_key_exists("search_specific", $results)) {
if($opts->type == 3 && count($results['search_specific']) > 1) {
// Format query url
$search_specific_url2 = "./results.php?q=".urlencode($results['search_specific'][1])."&t=".$opts->type."&a=".$opts->hash;
$specific_result2 = " or <a href=\"".$search_specific_url2."\">".$results['search_specific'][1]."</a>";
}
// Format query url
$search_specific_url = "./results.php?q=".urlencode($results['search_specific'][0])."&t=".$opts->type."&a=".$opts->hash;
$specific_result = "<br /><small>Or instead search for <a href=\"".$search_specific_url."\">".$results['search_specific'][0]."</a>".$specific_result2.".</small>";
unset($search_specific, $search_specific_url, $search_specific2, $search_specific_url2);
}
$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, $specific_result2);
}
}
/*--------------------------------------
// Count and format search sources
--------------------------------------*/
function search_sources($results) {
$sources = array();
foreach($results as $source => $amount) {
$plural = ($amount > 1) ? "results" : "result";
$sources[] = $amount." ".$plural." from ".$source;
}
$sources = replace_last_comma(implode(', ', $sources));
echo "<li class=\"sources\">".$sources.".</li>";
unset($sources);
}
/*--------------------------------------
// Special Search result
--------------------------------------*/
function special_search_result($opts, $results) {
if($opts->imdb_id_search == "on") {
$found = false;
foreach($results['search'] as $search_result) {
if(!$found && preg_match_all("/(imdb.com|tt[0-9]+)/i", $search_result['url'], $imdb_result) && stristr($search_result['title'], "tv series") !== false) {
$results['special'] = array(
"title" => $search_result['title'],
"text" => "Goosle found an IMDb ID for this TV Show in your results (".$imdb_result[0][1].") - <a href=\"./results.php?q=".$imdb_result[0][1]."&a=".$opts->hash."&t=9\">search for magnet links</a>?<br /><sub>An IMDb ID is detected when a TV Show is present in the results. The first match is highlighted here.</sub>"
);
$found = true;
}
}
}
if(array_key_exists("special", $results)) {
echo "<li class=\"special-result\"><article>";
echo "<div class=\"title\"><h2>".$results['special']['title']."</h2></div>";
echo "<div class=\"text\">".$results['special']['text']."</div>";
if(array_key_exists("source", $results['special'])) {
echo "<div class=\"source\"><a href=\"".$results['special']['source']."\" target=\"_blank\">".$results['special']['source']."</a></div>";
}
echo "</article></li>";
}
}
/*--------------------------------------
// Find and replace the last comma in a string
--------------------------------------*/
function replace_last_comma($string) {
$last_comma = strrpos($string, ', ');
if($last_comma !== false) {
$string = substr_replace($string, ' and ', $last_comma, 2);
}
return $string;
}
/*--------------------------------------
@ -124,4 +273,46 @@ function string_generator() {
return implode($password);
}
/*--------------------------------------
// Show version in footer and do periodic update check
--------------------------------------*/
function show_version($opts) {
$cache_file = dirname(__DIR__).'/version.data';
if(!is_file($cache_file)){
// Create update cache file
$version = array('version' => "1.2", 'latest' => "0.0", "checked" => 0, "url" => "");
file_put_contents($cache_file, serialize($version));
} else {
// Get update information
$version = unserialize(file_get_contents($cache_file));
}
// Current version
$show_version = "<a href=\"https://github.com/adegans/Goosle/\" target=\"_blank\">Goosle ".$version['version']."</a>.";
if($version['checked'] < time() - 604800) {
$ch = curl_init();
set_curl_options($ch, "https://api.github.com/repos/adegans/goosle/releases/latest", $opts->user_agents);
$response = curl_exec($ch);
curl_close($ch);
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $show_version;
// Update version info
$version = array('version' => $version['version'], 'latest' => $json_response['tag_name'], "checked" => time(), "url" => $json_response['html_url']);
file_put_contents($cache_file, serialize($version));
}
// Check if a newer version is available and add it to the version display
if(version_compare($version['version'], $version['latest'], "<")) {
$show_version .= " <a href=\"".$version['url']."\" target=\"_blank\" class=\"update\">Version ".$version['latest']." is available!</a>";
}
return $show_version;
}
?>

View file

@ -15,17 +15,17 @@ $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
?>
<!DOCTYPE html >
<!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="description" content="Goosle - The best 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><?php echo $opts->query; ?> - Goosle Search</title>
<title>Goosle Search Help</title>
</head>
<body>
<?php
@ -35,16 +35,15 @@ 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="search" value="<?php echo (strlen($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input tabindex="1" class="search" type="search" value="<?php echo (strlen($opts->query) > 0) ? $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; ?>">
<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>
<a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="Search results" />Search</a>
<?php if($opts->enable_image_search == "on") { ?>
<a <?php echo ($opts->type == "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>
<a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/image.png" alt="Image results" />Image</a>
<?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>
@ -55,21 +54,17 @@ if(verify_hash($opts, $auth)) {
<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>
<h2>General usage</h2>
<p>Goosle searches for your query on DuckDuckGo, Google, Wikipedia and Ecosia at the same time. All results are merged and ranked on what Goosle considers is the most relevant.</p>
<p>DuckDuckGo, Google and Ecosia are mostly language agnostic and will try to figure out on their own what language to use.</p>
<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>Google results are not personalized by default, using Google's own option for it.</p>
<p><em><strong>Note:</strong> DuckDuckGo search bangs are not supported and the <strong>!</strong> to trigger them is stripped out to prevent issues.</em></p>
<?php if($opts->enable_image_search == "on") { ?>
<h2>Image Search</h2>
<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>The number of results is not limited but generally yields around 60 to 80 images.</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 displayed, but also to the actual image itself. You'll see the links for it below each image.</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,13 +72,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>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") { ?>
<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>
For example: Search for <strong>20 EUR in HKD</strong> or <strong>14 USD to MXN</strong> and Goosle will search for it, but also a local conversion is done in a highlighted result.</p>
<?php } ?>
<?php if($opts->special['phpnet'] == "on") { ?>
@ -95,24 +84,26 @@ if(verify_hash($opts, $auth)) {
<?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> 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>
For example: Searching for <strong>define search</strong> will search for that as normal, but also show the dictionary definition highlighted above the search results.</p>
<p><em><strong>Note:</strong> Special Searches do not work for image and torrent searches.</em></p>
<?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, EZTV 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 ranked by most seeders. The number of results is limited to 50.</p>
<p>The search scripts will try to provide useful data which may include; Seeders/Leechers, A link to the torrent page, Download Category, Release year, Movie quality (720p, 4K etc.), Movie Runtime and the Download Size. Not every website makes this available and all results take a best effort approach.</p>
<?php if($opts->special['imdb_id_search'] == "on") { ?>
<?php if($opts->imdb_id_search == "on") { ?>
<h3>Searching TV Shows</h3>
<p>To do a specific search on The Pirate Bay and EZTV you can search for IMDb Title IDs. These are numeric IDs prefixed with <strong>tt</strong>. This kind of search is useful if you're looking a tv show that doesn't have a unique name.</p>
<p>To do a specific search on The Pirate Bay and EZTV you can search for IMDb Title IDs. These are numeric IDs prefixed with <strong>tt</strong>. This kind of search is useful when you're looking for a tv show that doesn't have a unique name, or simply if you want to use a specialized tracker for tv shows.</p>
<p> If you already know the Title ID you can enter it directly in the Torrent search as your search query.<br />
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 />
If you don't know the Title ID you can do a regular search for <strong>imdb [tv show name]</strong>, for example <strong>imdb Jack Ryan</strong>.<br />
Goosle will detect the IMDb ID from the search results and show a special search result that offers you to search for Magnet Links through a torrent search.</p>
<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>
<h3>Filtering TV Show episodes</h3>
<p>To help you narrow down results you can search for specific seasons and episodes. For example: If you search for <strong>tt5057054 S02</strong> or <strong>Jack Ryan S02</strong> you'll get filtered results for Jack Ryan Season 2. Searching for <strong>tt5057054 S02E03</strong> or <strong>Jack Ryan S02E03</strong> should find Season 2 Episode 3 and so on.</p>
<p>Likewise if you want a specific quality of a movie or tv show you can add that directly in your search. For example: If you search for <strong>Arrietty 720p</strong> you should primarily find that movie in 720p quality if it's available. Common screensizes are 480p, 720p, 1080p, 2160p (4K) and terms like HD-DVD, FULLHD, etc..</p>
<p><em><strong>Note:</strong> If you like, or found a use for, what you downloaded, you should buy a legal copy of it.</em></p>
<?php } ?>
<p><small><strong>Acknowledgements:</strong><br />Goosle started as a fork of LibreY, and takes some design cues from DuckDuckGo.com. Goosle is created by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a> with the intent to make search fun again.</small></p>
@ -122,7 +113,7 @@ if(verify_hash($opts, $auth)) {
<div class="footer-wrap">
<div class="footer">
&copy; <?php echo date('Y'); ?> <a href="https://github.com/adegans/Goosle/" target="_blank">Goosle <?php echo $opts->version; ?></a>, by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
&copy; <?php echo date('Y'); ?> <?php echo show_version($opts); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
<span style="float:right;"><a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a> - Your IP: <?php echo $_SERVER["REMOTE_ADDR"]; ?></span>
</div>
</div>

View file

@ -15,12 +15,12 @@ $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
?>
<!DOCTYPE html >
<!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="description" content="Goosle - The best 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"/>
@ -42,10 +42,9 @@ if(verify_hash($opts, $auth)) {
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>
<div class="search-box-buttons">
<button tabindex="20" name="t" value="0" type="submit">DuckDuckGo</button>
<button tabindex="30" name="t" value="1" type="submit">Google</button>
<button tabindex="20" name="t" value="0" type="submit">Search</button>
<?php if($opts->enable_image_search == "on") { ?>
<button tabindex="40" name="t" value="2" type="submit">Image</button>
<button tabindex="40" name="t" value="1" type="submit">Image</button>
<?php } ?>
<?php if($opts->enable_torrent_search == "on") { ?>
<button tabindex="50" name="t" value="9" type="submit">Torrent</button>
@ -55,7 +54,7 @@ if(verify_hash($opts, $auth)) {
</form>
</div>
<?php if($opts->special['password_generator'] == "on") { ?>
<?php if($opts->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" />

View file

@ -1,6 +1,14 @@
# 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.
<h1><center>Goosle</center></h1>
<h2><center>The best Meta Search Engine to find everything.</center></h2>
Goosle is a fast, privacy oriented search tool that just works. \
It's kept simple so everyone can use it and to make sure it works on most (basic) webservers.
Replace Google search, replace DuckDuckGo and Ecosia but do not give up on it's search results! Goosle uses it all and shows you the most relevant results through a neat, clean interface. Goosle has **no** distractions, **no** trackers, **no** cookies and **no** javascript or other things to slow you down.
On top of that, Goosle has a basic Image search tab which for now shows image results from Yahoo! Image Search.
And, also very useful, a safe and clean Torrent search tab. Find anything you like in seconds without malware, ads or other site-breaking nonsense that would otherwise require a VPN to safely use Torrent sites. Results are sourced from some of the largest torrent providers, compiled and ordered in by the most seeders.
Host for yourself and friends, with a access hash key. Or set up a public search website.
@ -9,25 +17,31 @@ After-all, finding things should be easy and not turn into a chore.
[![Goosle Mainpage](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage-960x593.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage.png)
## Features
- Search on DuckDuckGo
- Search on Google.com
- Works on **any** hosting package that does PHP7.4 or newer
- Get search results from DuckDuckGo
- Get search results from Google
- Get search results from Wikipedia
- Get search results from Ecosia (Bing)
- Image search through Yahoo! Images
- Algorithm for ranking search results on the results page
- Option to down-rank the biggest social media sites such as facebook, instagram, twitter, tiktok, snapchat and some others.
- 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
- Special searches for; Currency conversion, Dictionary and php.net
- 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
- Non-personalized Google results without instant results or other non-sense
- Optional: Speed up repeat searches with APCu cache if your server has it
- Optional: Access key as a basic way to keep your server to yourself
- Optional: Instant password generator on the start page
What Goosle does *not* have.
What Goosle does **not** have.
- Trackers and Cookies
- Ads, malware and distractions
- User profiles or user controllable settings
- Javascripts or Frameworks
And yet it just works...
And yet it just works... fast!
If you like Goosle, or found a use for it, please support my work and [donate](https://www.arnan.me/donate.html?mtm_campaign=goosle_readme).
If you like Goosle, or found a use for it, please support my work and [donate](https://www.arnan.me/donate.html?mtm_campaign=goosle_readme) and tell everyone about its existence.
## Screenshots
[![Goosle Mainpage](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage-150x150.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage.png)
@ -36,7 +50,8 @@ If you like Goosle, or found a use for it, please support my work and [donate](h
## Requirements
Any basic webserver/webhosting package with PHP7.4 or newer. \
Tested to work on Apache with PHP8.2.
No special requirments other than APCu for caching. \
Tested to work on Apache with PHP8.0.24-8.2.x.
## Installation
1. Unzip the download.
@ -47,26 +62,53 @@ Tested to work on Apache with PHP8.2.
6. Load the site in your browser. If you've enabled the access hash add ?a=YOURHASH to the url.
7. Let me know where you installed Goosle :-)
## Updates
1. Unzip the download.
2. Check your config.php file and go over your preferences. Make sure any new settings or changed values are present in your config.php. (Or reconfigure Goosle with a new copy from config.default.php)
3. Upload all files to your webserver, overwriting all files except perhaps config.php.
4. Load the site in your browser. If you've enabled the access hash don't forget to add *?a=YOURHASH* to the url.
5. Enjoy your updated search experience!
### Notes:
- The .htaccess file has a redirect to force HTTPS as well as browser caching instructions ready to go.
- The .htaccess file has a redirect to force HTTPS as well as browser caching rules ready to go.
- The robots.txt has a rule to prevent all crawlers from crawling Goosle. But keep in mind that not every crawler obeys this file.
- The 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.
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:
Have fun finding things! And tell your friends!
## 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).
You can post your questions on Github Discussions or on my support forum on [ajdg.solutions](https://ajdg.solutions/support/?mtm_campaign=goosle_readme). \
Or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnandegans).
## Changelog
1.2 - January 2, 2024
- [new] Preferred language setting for DuckDuckGo results in config.php.
- [new] Preferred language setting for Wikipedia results in config.php.
- [new] Combined DuckDuckGo, Google, Wikipedia and Ecosia (Bing) results into one page.
- [new] Ranking algorithm for search results.
- [new] Option to down-rank certain social media sites in results (Makes them show lower down the page).
- [new] Option to show the Goosle rank along with the search source.
- [new] Crawler for results from Limetorrents.lol.
- [new] Periodic check for updates in footer.
- [change] Moved duckduckgo.php and google.php into the engines/search/ folder.
- [change] Removed Wikipedia special search in favor of actual search results.
- [change] Removed 'Date Added' from 1337x results.
- [change] Removed Chrome based and Mobile user-agents, as they don't work for the WikiPedia API.
- [change] Added more trackers for generating magnet links.
- [tweak] 30-50% faster parsing of search results (couple of ms per search query).
- [tweak] Expanded the season/episode filter to all sources that support TV Shows.
- [tweak] More sensible santization of variables (Searching for html tags/basic code should now work).
- [tweak] Moved 'imdb_id_search' out from special results into its 'own' setting.
- [tweak] Moved 'password_generator' out from special results into its 'own' setting.
- [tweak] More accurate and faster Google scrape.
- [tweak] Reduced paragraph margins.
- [tweak] More code cleanup, making it more uniform.
- [fix] Prevents searching on disabled methods by 'cheating' the search type in the url.
- [fix] Better decoding for special characters in urls for search results.
- [fix] Better validation for special searches trigger words.
- [fix] Better sanitization for DuckDuckGo and Google results.
1.1 - December 21, 2023
- [new] API search for EZTV TV Shows.
- [new] config.default.php with default settings.
@ -101,3 +143,10 @@ Or say hi on [Telegram](https://t.me/arnandegans).
1.0 - December 5, 2023
- Initial release
## Acknowledgements and stuff
Goosle started as a fork of LibreY, and ended up as a rewrite and something different completely. While the code structure remains largely the same, most functions have been rewritten or altered to work as I need it to. \
Search results take design cues from DuckDuckGo and the torrent search has been modified to show more useful information where possible. \
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:

View file

@ -15,17 +15,17 @@ $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
?>
<!DOCTYPE html >
<!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="description" content="Goosle - The best 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><?php echo $opts->query; ?> - Goosle Search</title>
<title><?php echo $opts->query; ?> - Goosle Search Results</title>
</head>
<body>
<?php
@ -35,17 +35,16 @@ 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="search" value="<?php echo (strlen($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input tabindex="1" class="search" type="search" value="<?php echo (strlen($opts->query) > 0) ? $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; ?>">
<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>
<a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="Search results" />Search</a>
<?php if($opts->enable_image_search == "on") { ?>
<a <?php echo ($opts->type == "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>
<a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/image.png" alt="Image results" />Image</a>
<?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>
@ -61,7 +60,7 @@ if(verify_hash($opts, $auth)) {
<div class="footer-wrap">
<div class="footer">
&copy; <?php echo date('Y'); ?> <a href="https://github.com/adegans/Goosle/" target="_blank">Goosle <?php echo $opts->version; ?></a>, by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
&copy; <?php echo date('Y'); ?> <?php echo show_version($opts); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
<span style="float:right;"><a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a> - Your IP: <?php echo $_SERVER["REMOTE_ADDR"]; ?></span>
</div>
</div>