Version 1.7

This commit is contained in:
Arnan de Gans 2024-08-07 14:56:01 -06:00
parent 4d9a2859f3
commit cb85c4bc1c
37 changed files with 1273 additions and 732 deletions

4
assets/css/index.php Normal file
View file

@ -0,0 +1,4 @@
<?php
header("Location: /");
die();
?>

View file

@ -5,10 +5,10 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
---------------------------------------------------------------------------------------
* All icons are borrowed from IconFinder (https://www.iconfinder.com/search/icons?family=unicons-line)
* All icons are borrowed from IconFinder (https://www.iconfinder.com/search/icons?family=unicons-line)
------------------------------------------------------------------------------------ */
body { min-height:100vh; display:flex; flex-direction:column; margin:0; padding:0; line-height:1.2; font-family:Arial, Helvetica, sans-serif; font-weight:400; font-size:1rem; background-color:var(--background); color:var(--text); }
@ -135,7 +135,6 @@ input[type="search"]::-webkit-search-cancel-button { -webkit-appearance:none; -w
.goosebox-body { margin:50px auto; padding:20px; width:50%; background:var(--background-popup); border:1px solid var(--border); border-radius:10px; }
.goosebox-body h2 { padding:0 0 .3em 0; }
.goosebox-body h3 { font-size:1.2rem; }
.goosebox-body p { padding-top:.1em; padding-bottom:.2em; }
.goosebox-body a { cursor:pointer; }
.goosebox-body a:visited { color:var(--link); }
.goosebox-body button { margin:5px auto; padding:5px 10px; width:100%; height:35px; border:1px solid var(--border-alt); border-radius:10px; color:var(--button-text); background-color:var(--button-bg); text-align:center; font-size:1rem; }
@ -148,7 +147,7 @@ input[type="search"]::-webkit-search-cancel-button { -webkit-appearance:none; -w
/* Stats display (stats page) */
.statspage .content h1 { margin-bottom:10px; padding:0; text-align:center; font-size:2.5em; font-weight:400; }
.statspage .content h2 { margin-bottom:10px; padding:0; text-align:center; font-size:1.5em; }
.statspage p { font-family:'american typewriter'; }
.statspage p { font-family:'Courier New'; }
/* oAUTH page */
.oauthpage { background-color:var(--background-alt); color:var(--text-alt); }
@ -162,6 +161,10 @@ input[type="search"]::-webkit-search-cancel-button { -webkit-appearance:none; -w
.tooltip-question::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--link); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMS4yOSwxNS4yOWExLjU4LDEuNTgsMCwwLDAtLjEyLjE1Ljc2Ljc2LDAsMCwwLS4wOS4xOC42NC42NCwwLDAsMC0uMDYuMTgsMS4zNiwxLjM2LDAsMCwwLDAsLjIuODQuODQsMCwwLDAsLjA4LjM4LjkuOSwwLDAsMCwuNTQuNTQuOTQuOTQsMCwwLDAsLjc2LDAsLjkuOSwwLDAsMCwuNTQtLjU0QTEsMSwwLDAsMCwxMywxNmExLDEsMCwwLDAtLjI5LS43MUExLDEsMCwwLDAsMTEuMjksMTUuMjlaTTEyLDJBMTAsMTAsMCwxLDAsMjIsMTIsMTAsMTAsMCwwLDAsMTIsMlptMCwxOGE4LDgsMCwxLDEsOC04QTgsOCwwLDAsMSwxMiwyMFpNMTIsN0EzLDMsMCwwLDAsOS40LDguNWExLDEsMCwxLDAsMS43MywxQTEsMSwwLDAsMSwxMiw5YTEsMSwwLDAsMSwwLDIsMSwxLDAsMCwwLTEsMXYxYTEsMSwwLDAsMCwyLDB2LS4xOEEzLDMsMCwwLDAsMTIsN1oiIGZpbGw9IiM2NTYzZmYiLz48L3N2Zz4='); }
.tooltip-alert::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--red); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMiwxNmExLDEsMCwxLDAsMSwxQTEsMSwwLDAsMCwxMiwxNlptMTAuNjcsMS40Ny04LjA1LTE0YTMsMywwLDAsMC01LjI0LDBsLTgsMTRBMywzLDAsMCwwLDMuOTQsMjJIMjAuMDZhMywzLDAsMCwwLDIuNjEtNC41M1ptLTEuNzMsMmExLDEsMCwwLDEtLjg4LjUxSDMuOTRhMSwxLDAsMCwxLS44OC0uNTEsMSwxLDAsMCwxLDAtMWw4LTE0YTEsMSwwLDAsMSwxLjc4LDBsOC4wNSwxNEExLDEsMCwwLDEsMjAuOTQsMTkuNDlaTTEyLDhhMSwxLDAsMCwwLTEsMXY0YTEsMSwwLDAsMCwyLDBWOUExLDEsMCwwLDAsMTIsOFoiIGZpbGw9IiM2NTYzZmYiLz48L3N2Zz4='); }
/* Verified magnet */
.magnet-verified::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--link); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xOS42MywzLjY1YTEsMSwwLDAsMC0uODQtLjIsOCw4LDAsMCwxLTYuMjItMS4yNywxLDEsMCwwLDAtMS4xNCwwQTgsOCwwLDAsMSw1LjIxLDMuNDVhMSwxLDAsMCwwLS44NC4yQTEsMSwwLDAsMCw0LDQuNDN2Ny40NWE5LDksMCwwLDAsMy43Nyw3LjMzbDMuNjUsMi42YTEsMSwwLDAsMCwxLjE2LDBsMy42NS0yLjZBOSw5LDAsMCwwLDIwLDExLjg4VjQuNDNBMSwxLDAsMCwwLDE5LjYzLDMuNjVaTTE4LDExLjg4YTcsNywwLDAsMS0yLjkzLDUuN0wxMiwxOS43Nyw4LjkzLDE3LjU4QTcsNywwLDAsMSw2LDExLjg4VjUuNThhMTAsMTAsMCwwLDAsNi0xLjM5LDEwLDEwLDAsMCwwLDYsMS4zOVpNMTMuNTQsOS41OWwtMi42OSwyLjctLjg5LS45YTEsMSwwLDAsMC0xLjQyLDEuNDJsMS42LDEuNmExLDEsMCwwLDAsMS40MiwwTDE1LDExYTEsMSwwLDAsMC0xLjQyLTEuNDJaIiBmaWxsPSIjNjU2M2ZmIi8+PC9zdmc+'); }
.magnet-not-verified::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--red); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMS4yOSwxNC42NmExLDEsMCwwLDAtLjI5LjcsMSwxLDAsMCwwLC4wOC4zOUExLDEsMCwwLDAsMTMsMTUuMzZhMSwxLDAsMCwwLS4yOS0uN0ExLDEsMCwwLDAsMTEuMjksMTQuNjZabTguMzQtMTFhMSwxLDAsMCwwLS44NC0uMiw4LDgsMCwwLDEtNi4yMi0xLjI3LDEsMSwwLDAsMC0xLjE0LDBBOCw4LDAsMCwxLDUuMjEsMy40NWExLDEsMCwwLDAtLjg0LjJBMSwxLDAsMCwwLDQsNC40M3Y3LjQ1YTksOSwwLDAsMCwzLjc3LDcuMzNsMy42NSwyLjZhMSwxLDAsMCwwLDEuMTYsMGwzLjY1LTIuNkE5LDksMCwwLDAsMjAsMTEuODhWNC40M0ExLDEsMCwwLDAsMTkuNjMsMy42NVpNMTgsMTEuODhhNyw3LDAsMCwxLTIuOTMsNS43TDEyLDE5Ljc3LDguOTMsMTcuNThBNyw3LDAsMCwxLDYsMTEuODhWNS41OGExMCwxMCwwLDAsMCw2LTEuMzksMTAsMTAsMCwwLDAsNiwxLjM5Wk0xMiw3LjM2YTMsMywwLDAsMC0yLjYsMS41LDEsMSwwLDAsMCwxLjczLDFBMSwxLDAsMSwxLDEyLDExLjM2YTEsMSwwLDAsMCwwLDIsMywzLDAsMSwwLDAtNloiIGZpbGw9IiM2NTYzZmYiLz48L3N2Zz4='); }
/* Pagination */
.pagination { text-align:center; }
.pagination a { font-size:1.2em; padding:0 8px; }
@ -170,9 +173,9 @@ input[type="search"]::-webkit-search-cancel-button { -webkit-appearance:none; -w
.arrow-right::before { content:""; display:inline-block; width:1.2em; height:1.2em; background:var(--link); vertical-align:text-top; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZGF0YS1uYW1lPSJMYXllciAxIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE3LjkyLDExLjYyYTEsMSwwLDAsMC0uMjEtLjMzbC01LTVhMSwxLDAsMCwwLTEuNDIsMS40MkwxNC41OSwxMUg3YTEsMSwwLDAsMCwwLDJoNy41OWwtMy4zLDMuMjlhMSwxLDAsMCwwLDAsMS40MiwxLDEsMCwwLDAsMS40MiwwbDUtNWExLDEsMCwwLDAsLjIxLS4zM0ExLDEsMCwwLDAsMTcuOTIsMTEuNjJaIiBmaWxsPSIjNjU2M2ZmIi8+PC9zdmc+'); }
/* Flex grid (footer) */
.footer { display:flex; flex-direction:row; }
.footer-grid { flex:1; width:50%; }
.footer-grid:first-child { margin-right:20px; }
.footer { display:flex; flex-direction:row; }
.footer-grid { flex:1; width:50%; }
.footer-grid:first-child { margin-right:20px; }
.footer-grid:nth-child(2) { text-align:right; }
/* Footer */
@ -202,7 +205,7 @@ img.help { padding:0 .5rem .5rem 0; float:left; border-radius:20px; }
.auth-error { margin-top:15%; font-size:2rem; text-align:center; color:var(--text-alt); }
a.update { color:var(--yellow); font-weight:600; }
@media only screen and (max-width:960px) { /* Tablet, landscape iPad, lo-res/smaller laptops */
@media only screen and (max-width:960px) { /* Tablet, landscape iPad, lo-res/smaller laptops */
.content { position:relative; margin:15px 48px; }
/* Start page */
@ -226,10 +229,10 @@ a.update { color:var(--yellow); font-weight:600; }
/* Footer */
.footer { flex-direction:column; }
.footer-left, .footer-right { display:block; text-align:center; }
.footer-grid, .footer-grid:nth-child(2) { width:100%; text-align:center; }
.footer-grid, .footer-grid:nth-child(2) { width:100%; text-align:center; }
}
@media only screen and (max-width:640px) { /* Portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones */
@media only screen and (max-width:640px) { /* Portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones */
.content { position:relative; margin:10px 10px; }
/* Page header (Search results, Help, Box office) */
@ -241,6 +244,7 @@ a.update { color:var(--yellow); font-weight:600; }
.result-grid { grid-template-columns:repeat(auto-fill, minmax(8rem, 1fr)); row-gap:.5rem; column-gap:.5rem; }
}
.result-grid .result { margin:0 0 15px 0; }
.result-grid .result.image .thumb, .result-grid .result.highlight .thumb { width:120px; height: 120px; }
/* Magnet highlight info popup */
@ -250,7 +254,7 @@ a.update { color:var(--yellow); font-weight:600; }
img.help { padding:0 .25rem .25rem 0; }
}
@media only screen and (max-width:480px) { /* Portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */
@media only screen and (max-width:480px) { /* Portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */
/* Start page */
.startpage h1 { font-size:2.5rem; }
}
}

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
@ -54,15 +54,17 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
?>
<div class="header">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a href="./?a=<?php echo $opts->user_auth; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->query) > 0) ? htmlspecialchars($search->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<h1 class="logo"><a href="./?a=<?php echo $opts->user_auth; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->nice_query) > 0) ? htmlspecialchars($search->nice_query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $search->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->user_auth; ?>">
</form>
<div class="navigation">
<?php if($opts->enable_web_search == 'on') { ?>
<a class="<?php echo ($search->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=0">Search</a>
<?php } ?>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($search->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=1" >Images</a>
@ -77,7 +79,7 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php } ?>
</div>
</div>
<div class="content">
<h2>The Box Office</h2>
@ -102,7 +104,7 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
echo highlight_popup($opts->user_auth, $highlight);
echo "</li>";
unset($highlight, $thumb);
}
unset($highlights);
@ -117,7 +119,7 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php
foreach($highlights as $highlight) {
$thumb = (!empty($highlight['thumbnail'])) ? $highlight['thumbnail'] : $opts->pixel;
echo "<li class=\"result highlight eztv id-".$highlight['id']."\">";
echo " <div class=\"thumb\">";
echo " <a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['title']."\"><img src=\"".$thumb."\" alt=\"".$highlight['title']."\" /></a>";
@ -128,7 +130,7 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
echo highlight_popup($opts->user_auth, $highlight);
echo "</li>";
unset($highlight, $thumb);
}
unset($highlights);
@ -153,4 +155,4 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php } ?>
</body>
</html>
</html>

View file

@ -1,13 +1,37 @@
# Goosle
## The best Meta Search Engine to find everything
### 1.7 - August 7, 2024
- NOTICE: config.default.php has changed, update your config.php!!
- [new] Mojeek search results
- [new] Pixabay Image results (Requires free API key, see installation instructions)
- [new] Keyword multiplier for result ranking
- [new] Web search can be turned off
- [new] Cache News results for an hour only, regardless of the cache setting
- [new] Dynamic SEO description for results page (Should be visible when sharing the page)
- [new] 'Verified' label for magnet results where supported
- [update] Added x.com for social media detection
- [update] Added more keywords for nsfw detection in magnet results
- [change] Raised Qwant Images limit from 50 to 150
- [change] Raised Hackernews and Qwant News limit from 30 to 50
- [change] Lowered Wikipedia results from 10 to maximum 5
- [change] Replaced 'porn' with 'nsfw' for safe search switch
- [change] Removed 'xxx' as an keyword to disable safe search
- [change] Don't search on nyaa.si and YTS if you search with safemode off
- [change] Moved image size override into search object
- [change] Added a little space between rows for image results on mobile
- [change] Stats font is now 'Courier'
- [fix] Google search query not providing good results
- [fix] Search query not always properly urlencoded
- [removed] Removed search suggestions as they didn't work
### 1.6.1 - July 19, 2024
- NOTICE: config.default.php has changed, update your config.php!!
- [new] Query logger for debugging (See config.default.php for details)
- [tweak] Scrape query for DuckDuckGo to be more direct
- [tweak] Added url arguments to the formatted url of search results
- [tweak] Improved tooltips to be popups with better explanations
- [tweak] Improved spacing for pagination links
- [update] Added url arguments to the formatted url of search results
- [change] Scrape query for DuckDuckGo to be more direct
- [change] Improved tooltips to be popups with better explanations
- [fix] Improved spacing for pagination links
- [fix] More accurately show the current version in the footer
- [fix] Current version not properly stored
- [fix] Pagination offset off by one result
@ -73,7 +97,7 @@
- [new] Popup with movie info and download links for YTS Movie Highlights
- [new] CSS colorschemes configurable in config.php
- [new] Easily share magnet links with other Goosle users
- [new] Search results from Quant API
- [new] Search results from Qwant API
- [new] Search results from Brave
- [new] Image results from Qwant Image API
- [new] News results from Hackernews
@ -223,3 +247,7 @@
### 1.0 - December 5, 2023
- Initial release
## Support
Goosle comes with limited support. \
You can post your questions on Github Discussions or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnandegans).

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
@ -22,7 +22,7 @@ COLORSCHEME:
'dark' More dark elements, some apps would call this dark mode.
'auto' Let the browser decide what to use, uses dark.css for Darkmode. default.css for regular viewing.
For advanced users: You can create your own colorschemes this way too.
For advanced users: You can create your own colorschemes this way too.
Duplicate the file /assets/css/default.css and name it something like 'mycolorscheme.css'.
Edit the color variables to your liking.
To use the colorscheme, use the filename without extension in this setting.
@ -40,7 +40,7 @@ HASH_AUTH:
'on' Use the hash as a password.
Usage: https://example.com/?a=goose1234
Disclaimer: This is not meant to 'hack proof' or truly secure the setup. Just a simple token to keep surface level prying eyes out.
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_TYPE:
It is highly recommended to enable caching as it will speed up repeat searches by a lot.
@ -60,21 +60,12 @@ CACHE_TIME:
To not show outdated results the 'limit' is 48 hours.
Ignored if above 'CACHE_TYPE' option is set to off.
QUERYLOG:
The query log is useful if you make common requests and for some reason one engine returns no result and no error. Enabling the querylog lets you see if a request was made and how many results were found/scraped/retrieved. But also how many are left after initial processing.
The querylog logs requests per day into a file in /cache/. This function is not meant to be on for production use. Only for debugging or understanding results.
Example: [18-07-2024 22:15:05][s] GoogleRequest: 30 -> 4, https://www.google.com/search?q=the+wild+goose+chase&safe=1&num=30&pws=0&udm=14&tbs=li%3A1&complete=0&sclient=web
Here a query is made to Google web search, Goosle scraped 30 results but after initial filtering only 4 remained. This can mean a lot of duplicate links were found (unlikely). More likely is that an inconsistent scrape was done. This can indicate that the website has changed its layout structure and Goosle needs to be updated.
Example: [18-07-2024 23:06:58][a] QwantRequest: No results -> 0, https://api.qwant.com/v3/search/web?q=the+wild+goose+chase&t=web&safesearch=1&locale=en_gb&count=10&device=desktop
Here a query is made to Qwant web search via their API and no results were found at all. API calls can not make scrape errors. This likely means there simply were no results to begin with.
/* ------------------------------------------------------------------------------------
LANGUAGE:
To not fit the USA mold, Goosle defaults to the United Kingdom for english results.
DuckDuckGo and Google are language agnostic.
Invalid values either cause the search engine to fail or will default to English depending on how wrong the value is.
Google has no language setting because as soon as you specify it all 'anonymous' settings stop working.
DuckDuckGo uses language regions and defaults to the United Kingdom. To change it see if your region is available - https://duckduckgo.com/duckduckgo-help-pages/settings/params/.
@ -94,7 +85,7 @@ USER AGENTS:
Add more or less user agents to the list but keep at least one!
On every search Goosle picks a user agent at random to identify as.
Keep them generic to prevent profiling, but also so that the request comes off as a generic boring browser and not as a server/crawler.
Safari, Firefox and Internet Explorer (Yes that's old!) should be safe to use.
Chrome may attract attention because of the lack of Chrome information (tracking) aside from the user agent. The search engine may know something is 'weird'.
Opera/Edge/Brave and many others use Chrome under the hood and are not a good pick for that reason.
@ -104,7 +95,7 @@ USER AGENTS:
MAGNET TRACKERS:
Add more or less magnet trackers to the list but keep at least five or so!
These are added to the magnet links Goosle creates by itself.
These are added to the magnet links Goosle creates by itself.
Generally you do not need to change these.
------------------------------------------------------------------------------------ */
@ -112,48 +103,64 @@ return (object) array(
'siteurl' => 'example.com', // Make sure this is accurate (ex. example.com, goosle.example.com, example.com/goosle/)
'colorscheme' => 'default', // Default colorscheme to use
'hash' => '123456', // Some kind of alphanumeric password-like string, used for caching and optionally for access to Goosle
'hash_auth' => 'off', // Default: off
'cache_type' => 'file', // Default: file
'cache_time' => 8, // Default: 8 (Hours), see the recommendations above.
'hash_auth' => 'off', // Default: off
'cache_type' => 'file', // Default: file
'cache_time' => 8, // Default: 8 (Hours), see the recommendations above.
'timezone' => 'UTC', // Default: UTC (Enter UTC+1, UTC-6 etc. for your timezone - Find yours https://time.is/UTC)
'querylog' => 'off', // Default: off (Log remote queries to see if they are made and how much results they find and end up with)
'enable_duckduckgo' => 'on', // Default: on
'enable_google' => 'on', // Default: on
'enable_qwant' => 'on', // Default: on
'enable_brave' => 'on', // Default: on
'enable_wikipedia' => 'on', // Default: on
'enable_web_search' => 'on', // Default: on (Disables all web search regardless of settings for individual engines)
'web' => array(
'duckduckgo' => 'on', // Default: on
'mojeek' => 'on', // Default: on
'qwant' => 'on', // Default: on
'google' => 'on', // Default: on
'brave' => 'on', // Default: on
'wikipedia' => 'on' // Default: on
),
'enable_news_search' => 'on', // Default: on (Disables all news search regardless of settings for individual engines)
'enable_qwantnews' => 'on', // Default: on
'enable_yahoonews' => 'on', // Default: on
'enable_bravenews' => 'on', // Default: on
'enable_hackernews' => 'on', // Default: on
'enable_image_search' => 'on', // Default: on (Disables all image search regardless of settings for individual engines)
'image' => array(
'yahooimages' => 'on', // Default: on
'qwantimages' => 'on', // Default: on
'pixabay' => 'off', // Default: off (Requires free account from Pixabay.com, see readme for set up instructions)
'openverse' => 'off', // Default: off (Requires oAuth token, see readme for set up instructions)
),
'enable_image_search' => 'on', // Default: on (Disables all image search regardless of settings for individual engines)
'enable_yahooimages' => 'on', // Default: on
'enable_openverse' => 'off', // Default: off (Requires API token, see readme.md for details)
'enable_qwantimages' => 'on', // Default: on
'enable_news_search' => 'on', // Default: on (Disables all news search regardless of settings for individual engines)
'news' => array(
'qwantnews' => 'on', // Default: on
'yahoonews' => 'on', // Default: on
'bravenews' => 'on', // Default: on
'hackernews' => 'on', // Default: on
),
'enable_magnet_search' => 'on', // Default: on (Disables all magnet search regardless of settings for individual engines as well as the box office page)
'enable_eztv' => 'on', // Default: on
'enable_limetorrents' => 'on', // Default: on
'enable_nyaa' => 'on', // Default: on
'enable_sukebei' => 'on', // Default: on
'enable_piratebay' => 'on', // Default: on
'enable_yts' => 'on', // Default: on
'enable_magnet_search' => 'on', // Default: on (Disables all magnet search regardless of settings for individual engines as well as the box office page)
'magnet' => array(
'limetorrents' => 'on', // Default: on (Anything)
'piratebay' => 'on', // Default: on (Anything)
'yts' => 'on', // Default: on (Movies)
'eztv' => 'on', // Default: on (TV-Shows)
'nyaa' => 'on', // Default: on (Anime)
'sukebei' => 'on', // Default: on (NSFW Anime)
),
'duckduckgo_language' => 'uk-en', // Default: uk-en (United Kingdom)
'wikipedia_language' => 'en', // Default: en (English)
'duckduckgo_language' => 'uk-en', // Default: uk-en (United Kingdom)
'mojeek_language' => 'en', // Default: en (English)
'google_search_region' => 'uk', // Default: uk (United Kingdom)
'qwant_language' => 'en_gb', // Default: en_gb (United Kingdom)
'wikipedia_language' => 'en', // Default: en (English)
'search_results_per_page' => 24, // Default: 24 (Any number between 8 and 160, preferably a multiple of 8. Ignored if caching is off)
'social_media_relevance' => 8, // Default: 8
'show_search_source' => 'on', // Default: on
'show_search_rank' => 'off', // Default: off (Mostly for debugging)
'pixabay_api_key' => '', // Default: '' (Requires free account from Pixabay.com, see readme for set up instructions)
'search_results_per_page' => 24, // Default: 24 (Any number between 8 and 160, preferably a multiple of 8. Ignored if caching is off)
'social_media_relevance' => 8, // Default: 8
'show_search_source' => 'on', // Default: on
'imdb_id_search' => 'off', // Default: off, (Requires enable_magnet_search to also be on)
'password_generator' => 'on', // Default: on
'show_search_rank' => 'off', // Default: off (Useful for debugging)
'querylog' => 'off', // Default: off (Create a log of queries in /cache/*.log to see if they are made and how much results they find and end up with after processing)
'special' => array(
'currency' => 'on', // Default: on, Currency converter
'definition' => 'on', // Default: on, Word dictionary
@ -162,12 +169,12 @@ return (object) array(
'wordpress' => 'off' // Default: off, Wordpress functions highlight
),
'show_nsfw_magnets' => 'off', // Default: off (Set to 'off' to try and hide adult content. Override with 'safe:off', 'xxx' or 'porn')
'show_zero_seeders' => 'off', // Default: off
'show_yts_highlight' => 'on', // Default: off (Show latest YTS movies above Magnet search results)
'show_share_option' => 'on', // Default: on (Show a share option for Magnet results)
'piratebay_categories_blocked' => array(206, 210), // Default: 206, 210 (Comma separated numbers, see /engines/magnet/thepiratebay.php for all categories)
'yts_categories_blocked' => array('horror'), // Default: 'horror' (Comma separated keywords; array('action', 'drama', 'sci-fi') etc.. There is no defined list, so block keywords that you see on results and don't like)
'show_nsfw_magnets' => 'off', // Default: off (Set to 'off' to try and hide adult content. Override with 'safe:off' or 'nsfw')
'show_zero_seeders' => 'off', // Default: off
'show_yts_highlight' => 'on', // Default: off (Show latest YTS movies above Magnet search results)
'show_share_option' => 'on', // Default: on (Show a share option for Magnet results)
'piratebay_categories_blocked' => array(206, 210), // Default: 206, 210 (Comma separated numbers, see /engines/magnet/thepiratebay.php for all categories)
'yts_categories_blocked' => array('horror'), // Default: 'horror' (Comma separated keywords; array('action', 'drama', 'sci-fi') etc.. There is no defined list, so block keywords that you see on results and don't like)
// Keep at-least 1
'user_agents' => array(
@ -178,35 +185,35 @@ return (object) array(
),
// Keep at-least 5
'magnet_trackers' => array(
'udp://tracker.coppersurfer.tk:6969',
'udp://tracker.leechers-paradise.org:6969',
'udp://p4p.arenabg.ch:1337',
'udp://tracker.internetwarriors.net:1337',
'udp://glotorrents.pw:6969/announce',
'udp://torrent.gresille.org:80/announce',
'udp://tracker.openbittorrent.com:80',
'http://nyaa.tracker.wf:7777/announce',
'udp://tracker.opentrackr.org:1337/announce',
'udp://exodus.desync.com:6969/announce',
'udp://tracker.torrent.eu.org:451/announce',
'udp://opentracker.i2p.rocks:6969/announce',
'udp://open.demonii.com:1337/announce',
'udp://open.stealth.si:80/announce',
'udp://tracker.moeking.me:6969/announce',
'udp://explodie.org:6969/announce',
'udp://tracker1.bt.moack.co.kr:80/announce',
'udp://tracker.theoks.net:6969/announce',
'udp://tracker-udp.gbitt.info:80/announce',
'https://tracker.tamersunion.org:443/announce',
'https://tracker.gbitt.info:443/announce',
'udp://tracker.tiny-vps.com:6969/announce',
'udp://tracker.dump.cl:6969/announce',
'udp://tamas3.ynh.fr:6969/announce',
'udp://retracker01-msk-virt.corbina.net:80/announce',
'udp://open.free-tracker.ga:6969/announce',
'udp://epider.me:6969/announce',
'magnet_trackers' => array(
'udp://tracker.coppersurfer.tk:6969',
'udp://tracker.leechers-paradise.org:6969',
'udp://p4p.arenabg.ch:1337',
'udp://tracker.internetwarriors.net:1337',
'udp://glotorrents.pw:6969/announce',
'udp://torrent.gresille.org:80/announce',
'udp://tracker.openbittorrent.com:80',
'http://nyaa.tracker.wf:7777/announce',
'udp://tracker.opentrackr.org:1337/announce',
'udp://exodus.desync.com:6969/announce',
'udp://tracker.torrent.eu.org:451/announce',
'udp://opentracker.i2p.rocks:6969/announce',
'udp://open.demonii.com:1337/announce',
'udp://open.stealth.si:80/announce',
'udp://tracker.moeking.me:6969/announce',
'udp://explodie.org:6969/announce',
'udp://tracker1.bt.moack.co.kr:80/announce',
'udp://tracker.theoks.net:6969/announce',
'udp://tracker-udp.gbitt.info:80/announce',
'https://tracker.tamersunion.org:443/announce',
'https://tracker.gbitt.info:443/announce',
'udp://tracker.tiny-vps.com:6969/announce',
'udp://tracker.dump.cl:6969/announce',
'udp://tamas3.ynh.fr:6969/announce',
'udp://retracker01-msk-virt.corbina.net:80/announce',
'udp://open.free-tracker.ga:6969/announce',
'udp://epider.me:6969/announce',
'udp://bt2.archive.org:6969/announce',
)
)
);
?>
?>

View file

@ -6,11 +6,17 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class OpenverseRequest extends EngineRequest {
public function get_request_url() {
$query = $this->search->query;
// Max 200 chars
$query = (strlen($query) > 200) ? substr($query, 0, 200) : $query;
$query = implode(',', make_tags_from_string($query));
// Safe search override
if($this->search->safe == 0) {
$safe = '1';
@ -18,14 +24,23 @@ class OpenverseRequest extends EngineRequest {
$safe = '0';
}
// Size override
$size = 'small,medium,large';
if($this->search->size == 1) $size = 'small';
if($this->search->size == 2) $size = 'medium';
if($this->search->size >= 3) $size = 'large';
// All parameters and values: https://api.openverse.org/v1/#tag/images/operation/images_search
$url = 'https://api.openverse.org/v1/images/?'.http_build_query(array(
'q' => $this->search->query, // Search query
'q' => $query, // Search query
'category' => 'photograph', // Only photos
'size' => $size,
'format' => 'json', // Response format
'page_size' => 50, // How many results to get
'page_size' => 50, // How many results to get (Max 50)
'mature' => $safe // Safe search (1 = ON, 0 = OFF)
));
unset($safe);
unset($query, $safe, $size);
return $url;
}
@ -33,7 +48,7 @@ class OpenverseRequest extends EngineRequest {
public function get_request_headers() {
$token_file = ABSPATH.'cache/token.data';
$token = unserialize(file_get_contents($token_file));
return array(
'Accept' => 'application/json, */*;q=0.8',
'Content-type' => 'application/x-www-form-urlencoded',
@ -58,7 +73,7 @@ class OpenverseRequest extends EngineRequest {
// Figure out results and base rank
$number_of_results = $rank = $json_response['result_count'];
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
@ -68,40 +83,42 @@ class OpenverseRequest extends EngineRequest {
// Use API result
foreach($json_response['results'] as $result) {
// Find data and process data
$image_full = sanitize($result['url']);
$image_thumb = (!empty($result['thumbnail'])) ? sanitize($result['thumbnail']) : $image_full;
$url = sanitize($result['foreign_landing_url']);
$alt = (!is_null($result['title'])) ? sanitize($result['title']) : null;
$dimensions_w = (!is_null($result['width'])) ? sanitize($result['width']) : null;
$dimensions_h = (!is_null($result['height'])) ? sanitize($result['height']) : null;
$filesize = (!is_null($result['filesize'])) ? sanitize($result['filesize']) : null;
$image_thumb = (!empty($result['thumbnail'])) ? sanitize($result['thumbnail']) : null;
$image_full = (!empty($result['url'])) ? sanitize($result['url']) : null;
$url = (!empty($result['foreign_landing_url'])) ? sanitize($result['foreign_landing_url']) : null;
$alt = (!empty($result['title'])) ? sanitize($result['title']) : null;
$creator = (!empty($result['creator'])) ? " by ".sanitize($result['creator']) : null;
$tags = (count($result['tags']) > 0) ? array_column($result['tags'], 'name') : make_tags_from_string($alt);
// Skip broken results
if(empty($image_thumb)) continue;
if(empty($image_full)) continue;
if(empty($url)) continue;
// Process data
if(!is_null($creator)) $alt = $alt.$creator;
if(!is_null($filesize)) $filesize = intval(preg_replace('/[^0-9]+/', '', $filesize));
// Optional
$dimensions_w = (!empty($result['width'])) ? sanitize($result['width']) : null;
$dimensions_h = (!empty($result['height'])) ? sanitize($result['height']) : null;
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
// Prepare data
if(!is_null($creator)) $alt = $alt.$creator;
$tags = array_unique($tags);
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
$engine_temp[] = array (
// Required
'image_full' => $image_full, // string
'image_thumb' => $image_thumb, // string
'image_full' => $image_full, // string
'url' => $url, // string
'alt' => $alt, // string
'tags' => $tags, // array
'engine_rank' => $rank, // int
// Optional
'alt' => $alt, // string | null
'width' => $dimensions_w, // int | null
'height' => $dimensions_h, // int | null
'filesize' => $filesize, // int | null
'height' => $dimensions_h // int | null
);
$rank -= 1;
}
@ -119,4 +136,4 @@ class OpenverseRequest extends EngineRequest {
return $engine_result;
}
}
?>
?>

150
engines/image/pixabay.php Normal file
View file

@ -0,0 +1,150 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works.
*
* 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 PixabayRequest extends EngineRequest {
public function get_request_url() {
$query = $this->search->query;
// Max 100 chars
$query = (strlen($query) > 100) ? substr($query, 0, 100) : $query;
$query = implode(',', make_tags_from_string($query));
// Safe search override
if($this->search->safe == 0) {
$safe = true;
} else {
$safe = false;
}
// Size override
$min_width = 1280;
$min_height = 720;
if($this->search->size == 1) {
$min_width = 640;
$min_height = 360;
}
if($this->search->size == 2) {
$min_width = 1280;
$min_height = 720;
}
if($this->search->size == 3) {
$min_width = 1600;
$min_height = 900;
}
if($this->search->size == 4) {
$min_width = 2560;
$min_height = 1440;
}
// All parameters and values: https://pixabay.com/api/docs/
$url = 'https://pixabay.com/api/?'.http_build_query(array(
'key' => $this->opts->pixabay_api_key, // Api Key for authentification
'q' => $query, // Search query
'image_type' => 'photo', // Only photos
'per_page' => 100, // How many results to get (Max 200)
'min_width' => $min_width, // Minimum width
'min_height' => $min_height, // Minimum height
'safesearch' => $safe // Safe search (1 = ON, 0 = OFF)
));
unset($query, $safe, $min_height, $min_width);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'Content-type' => 'application/x-www-form-urlencoded',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// Figure out results and base rank
$number_of_results = $rank = count($json_response['hits']);
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
// Use API result
foreach($json_response['hits'] as $result) {
// Find data and process data
$image_thumb = (!empty($result['previewURL'])) ? sanitize($result['previewURL']) : null;
$image_full = (!empty($result['largeImageURL'])) ? sanitize($result['largeImageURL']) : null;
$url = (!empty($result['pageURL'])) ? sanitize($result['pageURL']) : null;
$alt = (!empty($image_thumb)) ? substr(strrchr($image_thumb, "/"), 1) : null;
$creator = (!empty($result['user'])) ? " by ".sanitize($result['user']) : null;
$tags = (!empty($result['tags'])) ? explode(', ', $result['tags']) : make_tags_from_string($alt);
// Skip broken results
if(empty($image_thumb)) continue;
if(empty($image_full)) continue;
if(empty($url)) continue;
// Optional
$dimensions_w = (!empty($result['imageWidth'])) ? sanitize($result['imageWidth']) : null;
$dimensions_h = (!empty($result['imageHeight'])) ? sanitize($result['imageHeight']) : null;
// Process data
if(!is_null($creator)) $alt = $alt.$creator;
$tags = array_unique($tags);
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
$engine_temp[] = array (
// Required
'image_thumb' => $image_thumb, // string
'image_full' => $image_full, // string
'url' => $url, // string
'alt' => $alt, // string
'tags' => $tags, // array
'engine_rank' => $rank, // int
// Optional
'width' => $dimensions_w, // int | null
'height' => $dimensions_h // int | null
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Pixabay';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $number_of_results, count($engine_temp));
unset($response, $json_response, $number_of_results, $rank);
return $engine_result;
}
}
?>

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class QwantImageRequest extends EngineRequest {
@ -14,15 +14,10 @@ class QwantImageRequest extends EngineRequest {
$query = $this->search->query;
// Size override
$size = 'all'; // All sizes
if(preg_match('/(size:)(small|medium|large|xlarge)/i', $this->search->query_terms[0], $matches)) {
$size = $matches[1];
$query = str_replace($this->search->query_terms[0], '', $query);
// Engine specific
if($size == 'xlarge') $size = 'large';
}
unset($matches);
$size = 'all';
if($this->search->size == 1) $size = 'small';
if($this->search->size == 2) $size = 'medium';
if($this->search->size >= 3) $size = 'large';
// Set locale
$language = (strlen($this->opts->qwant_language) > 0 && strlen($this->opts->qwant_language < 6)) ? $this->opts->qwant_language : 'en_gb';
@ -31,7 +26,7 @@ class QwantImageRequest extends EngineRequest {
$url = 'https://api.qwant.com/v3/search/images?'.http_build_query(array(
'q' => $query, // Search query
't' => 'images', // Type of search, Images
'count' => 50, // Up-to how many images to return (Max 50)
'count' => 150, // Up-to how many images to return (Max 150)
'size' => $size, // General image size
'locale' => $language, // In which language should the search be done
'device' => 'desktop', // What kind of device are we searching from?
@ -75,38 +70,40 @@ class QwantImageRequest extends EngineRequest {
foreach($json_response['data']['result']['items'] as $result) {
// Find data and process data
$image_full = sanitize($result['media']);
$image_thumb = (!empty($result['thumbnail'])) ? sanitize($result['thumbnail']) : $image_full;
$url = sanitize($result['url']);
$image_thumb = (!empty($result['thumbnail'])) ? sanitize($result['thumbnail']) : null;
$image_full = (!empty($result['media'])) ? sanitize($result['media']) : null;
$url = (!empty($result['url'])) ? sanitize($result['url']) : null;
$alt = (!empty($result['title'])) ? sanitize($result['title']) : null;
$dimensions_w = (!empty($result['width'])) ? sanitize($result['width']) : null;
$dimensions_h = (!empty($result['height'])) ? sanitize($result['height']) : null;
$filesize = (!empty($result['size'])) ? sanitize($result['size']) : null;
$tags = (!empty($alt)) ? make_tags_from_string($alt) : array();
// Skip broken results
if(empty($image_full)) continue;
if(empty($image_thumb)) continue;
if(empty($image_full)) continue;
if(empty($url)) continue;
// Optional
$dimensions_w = (!empty($result['width'])) ? sanitize($result['width']) : null;
$dimensions_h = (!empty($result['height'])) ? sanitize($result['height']) : null;
// Process data
if(!is_null($filesize)) $filesize = intval(preg_replace('/[^0-9]+/', '', $filesize));
$tags = array_unique($tags);
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
$engine_temp[] = array (
// Required
'image_full' => $image_full, // string
'image_thumb' => $image_thumb, // string
'image_full' => $image_full, // string
'url' => $url, // string
'alt' => $alt, // string
'tags' => $tags, // array
'engine_rank' => $rank, // int
// Optional
'alt' => $alt, // string | null
'width' => $dimensions_w, // int | null
'height' => $dimensions_h, // int | null
'filesize' => $filesize, // int | null
'height' => $dimensions_h // int | null
);
$rank -= 1;
}
@ -124,4 +121,4 @@ class QwantImageRequest extends EngineRequest {
return $engine_result;
}
}
?>
?>

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class YahooImageRequest extends EngineRequest {
@ -21,15 +21,11 @@ class YahooImageRequest extends EngineRequest {
}
// Size override
$size = ''; // All sizes
if(preg_match('/(size:)(small|medium|large|xlarge)/i', $this->search->query_terms[0], $matches)) {
$size = $matches[1];
$query = str_replace($this->search->query_terms[0], '', $query);
// Engine specific
if($size == 'xlarge') $size = 'wallpaper';
}
unset($matches);
$size = '';
if($this->search->size == 1) $size = 'small';
if($this->search->size == 2) $size = 'medium';
if($this->search->size == 3) $size = 'large';
if($this->search->size == 4) $size = 'wallpaper';
$url = 'https://images.search.yahoo.com/search/images?'.http_build_query(array(
'p' => $query, // Search query
@ -51,7 +47,7 @@ class YahooImageRequest extends EngineRequest {
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
@ -67,7 +63,7 @@ class YahooImageRequest extends EngineRequest {
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
@ -89,15 +85,15 @@ class YahooImageRequest extends EngineRequest {
// Skip broken results
if($image_thumb->length == 0) continue;
if($url_data->length == 0) continue;
// Get and prepare meta data
// -- Relevant $url_data (there is more, but unused by Goosle)
// w = Image width (1280)
// h = Image height (720)
// imgurl = Actual full size image (Used in Yahoo preview/popup)
// w = Image width
// h = Image height
// imgurl = 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)
// size = Image size
// tt = Website title
foreach(explode('&', strstr($url_data[0]->textContent, '?')) as &$meta) {
if(!empty($meta)) {
$value = explode('=', trim($meta));
@ -109,19 +105,22 @@ class YahooImageRequest extends EngineRequest {
unset($meta, $value);
}
// Skip broken results
if(!array_key_exists('imgurl', $usable_data)) continue;
if(!array_key_exists('rurl', $usable_data)) continue;
// Process data
$image_full = (array_key_exists('imgurl', $usable_data)) ? sanitize($usable_data['imgurl']) : null;
$image_thumb = sanitize($image_thumb[0]->textContent);
$url = sanitize($usable_data['rurl']);
$image_full = (array_key_exists('imgurl', $usable_data)) ? sanitize($usable_data['imgurl']) : null;
$url = (array_key_exists('rurl', $usable_data)) ? sanitize($usable_data['rurl']) : null;
$alt = (array_key_exists('tt', $usable_data)) ? sanitize($usable_data['tt']) : null;
$tags = (!empty($alt)) ? make_tags_from_string($alt) : array();
// Skip broken results
if(empty($image_full)) continue;
if(empty($url)) continue;
// Optional
$dimensions_w = (array_key_exists('w', $usable_data)) ? sanitize($usable_data['w']) : null;
$dimensions_h = (array_key_exists('h', $usable_data)) ? sanitize($usable_data['h']) : null;
$filesize = (array_key_exists('size', $usable_data)) ? intval(preg_replace('/[^0-9]+/', '', sanitize($usable_data['size']))) : null;
// Process data
// Fix incomplete image url
if(!is_null($image_full)) {
$is_https = parse_url($url);
@ -133,23 +132,24 @@ class YahooImageRequest extends EngineRequest {
$image_full = '//'.$image_full;
}
}
$tags = array_unique($tags);
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
$engine_temp[] = array (
// Required
'image_full' => $image_full, // string
'image_thumb' => $image_thumb, // string
'image_full' => $image_full, // string
'url' => $url, // string
'alt' => $alt, // string
'tags' => $tags, // array
'engine_rank' => $rank, // int
// Optional
'alt' => $alt, // string | null
'width' => $dimensions_w, // int | null
'height' => $dimensions_h, // int | null
'filesize' => $filesize, // int | null
'height' => $dimensions_h // int | null
);
$rank -= 1;
}
@ -167,4 +167,4 @@ class YahooImageRequest extends EngineRequest {
return $engine_result;
}
}
?>
?>

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class EZTVRequest extends EngineRequest {
@ -16,9 +16,9 @@ class EZTVRequest extends EngineRequest {
// Is eztvx.to blocked for you? Use one of these urls as an alternative
// Try: eztv1.xyz, eztv.wf, eztv.tf, eztv.yt
$url = 'https://eztvx.to/api/get-torrents?imdb_id='.urlencode($query);
unset($query);
return $url;
}
@ -36,7 +36,7 @@ class EZTVRequest extends EngineRequest {
public function parse_results($response) {
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
@ -45,7 +45,7 @@ class EZTVRequest extends EngineRequest {
// No results
if($json_response['torrents_count'] == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
@ -55,8 +55,8 @@ class EZTVRequest extends EngineRequest {
$magnet = sanitize($result['magnet_url']);
$seeders = sanitize($result['seeds']);
$leechers = sanitize($result['peers']);
$filesize = human_filesize(sanitize($result['size_bytes']));
$filesize = sanitize($result['size_bytes']);
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
@ -65,7 +65,7 @@ class EZTVRequest extends EngineRequest {
if($season < 10) $season = '0'.$season;
$episode = sanitize($result['episode']);
if($episode < 10) $episode = '0'.$episode;
// Throw out mismatched episodes
if(!is_season_or_episode($this->search->query, 'S'.$season.'E'.$episode)) continue;
@ -74,7 +74,7 @@ class EZTVRequest extends EngineRequest {
$quality = find_video_quality($title);
$codec = find_video_codec($title);
$audio = find_audio_codec($title);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
@ -91,6 +91,7 @@ class EZTVRequest extends EngineRequest {
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => 'yes', // string|null
'nsfw' => false, // bool
'quality' => $quality, // string|null
'type' => null, // string|null
@ -116,7 +117,7 @@ class EZTVRequest extends EngineRequest {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $json_response['torrents_count'], count($engine_temp));
unset($response, $json_response, $engine_temp);
return $engine_result;
}
}

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class LimeRequest extends EngineRequest {
@ -15,12 +15,12 @@ class LimeRequest extends EngineRequest {
$query = strtolower(str_replace(' ', '-', $query));
$url = 'https://www.limetorrents.lol/search/all/'.$query.'/';
unset($query);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
@ -30,7 +30,7 @@ class LimeRequest extends EngineRequest {
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
@ -42,7 +42,7 @@ class LimeRequest extends EngineRequest {
// No results
if(count($scrape) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
@ -66,19 +66,23 @@ class LimeRequest extends EngineRequest {
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($title).'&tr='.implode('&tr=', $this->opts->magnet_trackers);
$seeders = ($seeders->length > 0) ? sanitize($seeders[0]->textContent) : 0;
$leechers = ($leechers->length > 0) ? sanitize($leechers[0]->textContent) : 0;
$filesize = ($filesize->length > 0) ? human_filesize(filesize_to_bytes(sanitize($filesize[0]->textContent))) : 0;
$filesize = ($filesize->length > 0) ? filesize_to_bytes(sanitize($filesize[0]->textContent)) : 0;
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->search->query, $title)) continue;
// Find extra data
$verified = $xpath->evaluate(".//td[@class='tdleft'][1]//div[@class='tt-vdown']//img/@title", $result);
$category = $xpath->evaluate(".//td[@class='tdnormal'][1]", $result);
$url = $xpath->evaluate(".//td[@class='tdleft']//a[2]/@href", $result);
// Process extra data
$verified = ($verified->length > 0) ? sanitize($verified[0]->textContent) : null;
if($verified == 'Verified torrent') $verified = 'yes';
if($category->length > 0) {
$category = explode(' - ', sanitize($category[0]->textContent));
$category = str_replace('in ', '', $category[array_key_last($category)]);
@ -111,6 +115,7 @@ class LimeRequest extends EngineRequest {
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => $verified, // string|null
'nsfw' => $nsfw, // bool
'quality' => $quality, // string|null
'type' => null, // string|null
@ -140,4 +145,4 @@ class LimeRequest extends EngineRequest {
return $engine_result;
}
}
?>
?>

View file

@ -6,16 +6,16 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class NyaaRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://nyaa.si/?q='.urlencode($this->search->query);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
@ -25,19 +25,19 @@ class NyaaRequest extends EngineRequest {
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//tbody/tr");
// No results
if(count($scrape) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
@ -59,20 +59,30 @@ class NyaaRequest extends EngineRequest {
$hash = strtolower(str_replace('urn:btih:', '', $hash_parameters['xt']));
$seeders = sanitize($meta[3]->textContent);
$leechers = sanitize($meta[4]->textContent);
$filesize = human_filesize(filesize_to_bytes(str_replace('TiB', 'TB', str_replace('GiB', 'GB', str_replace('MiB', 'MB', str_replace('KiB', 'KB', sanitize($meta[1]->textContent)))))));
$filesize = filesize_to_bytes(str_replace('TiB', 'TB', str_replace('GiB', 'GB', str_replace('MiB', 'MB', str_replace('KiB', 'KB', sanitize($meta[1]->textContent))))));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->search->query, $title)) continue;
// Find extra data
$verified = $xpath->evaluate("./@class", $result);
$category = $xpath->evaluate(".//td[1]//a/@title", $result);
$url = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result);
$date_added = $xpath->evaluate(".//td[@class='text-center']/@data-timestamp", $result);
// Process extra data
$verified = ($verified->length > 0) ? sanitize($verified[0]->textContent) : null;
if($verified == 'success') {
$verified = 'yes';
} else if($verified == 'danger') {
$verified = 'no';
} else {
$verified = null;
}
$category = ($category->length > 0) ? str_replace(' - ', '/', sanitize($category[0]->textContent)) : null;
$url = ($url->length > 0) ? 'https://nyaa.si'.sanitize($url[0]->textContent) : null;
$timestamp = sanitize($date_added[0]->textContent);
@ -100,6 +110,7 @@ class NyaaRequest extends EngineRequest {
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => $verified, // string|null
'nsfw' => $nsfw, // bool
'quality' => $quality, // string|null
'type' => null, // string|null

View file

@ -6,16 +6,16 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class SukebeiRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://sukebei.nyaa.si/?q='.urlencode($this->search->query);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
@ -25,19 +25,19 @@ class SukebeiRequest extends EngineRequest {
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//tbody/tr");
// No results
if(count($scrape) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
@ -59,20 +59,30 @@ class SukebeiRequest extends EngineRequest {
$hash = strtolower(str_replace('urn:btih:', '', $hash_parameters['xt']));
$seeders = sanitize($meta[3]->textContent);
$leechers = sanitize($meta[4]->textContent);
$filesize = human_filesize(filesize_to_bytes(str_replace('TiB', 'TB', str_replace('GiB', 'GB', str_replace('MiB', 'MB', str_replace('KiB', 'KB', sanitize($meta[1]->textContent)))))));
$filesize = filesize_to_bytes(str_replace('TiB', 'TB', str_replace('GiB', 'GB', str_replace('MiB', 'MB', str_replace('KiB', 'KB', sanitize($meta[1]->textContent))))));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->search->query, $title)) continue;
// Find extra data
$verified = $xpath->evaluate(".//@class", $result);
$category = $xpath->evaluate(".//td[1]//a/@title", $result);
$url = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result);
$date_added = $xpath->evaluate(".//td[@class='text-center']/@data-timestamp", $result);
// Process extra data
$verified = ($verified->length > 0) ? sanitize($verified[0]->textContent) : null;
if($verified == 'success') {
$verified = 'yes';
} else if($verified == 'danger') {
$verified = 'no';
} else {
$verified = null;
}
$category = ($category->length > 0) ? str_replace(' - ', '/', sanitize($category[0]->textContent)) : null;
$url = ($url->length > 0) ? 'https://sukebei.nyaa.si'.sanitize($url[0]->textContent) : null;
$timestamp = sanitize($date_added[0]->textContent);
@ -97,6 +107,7 @@ class SukebeiRequest extends EngineRequest {
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => $verified, // string|null
'nsfw' => true, // bool
'quality' => $quality, // string|null
'type' => null, // string|null

View file

@ -6,13 +6,13 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class PirateBayRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://apibay.org/q.php?q='.urlencode($this->search->query);
return $url;
}
@ -30,16 +30,16 @@ class PirateBayRequest extends EngineRequest {
public function parse_results($response) {
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// No results
if($json_response[0]['name'] == 'No results returned') {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
@ -65,7 +65,7 @@ class PirateBayRequest extends EngineRequest {
211 => 'UHD/4K Movie',
212 => 'UHD/4K TV Show',
299 => 'Video Other',
300 => 'Applications',
301 => 'Apps Windows',
302 => 'Apps Apple',
@ -85,7 +85,7 @@ class PirateBayRequest extends EngineRequest {
407 => 'Games iOS',
408 => 'Games Android',
499 => 'Games Other OS',
500 => 'Porn',
501 => 'Porn Movie',
502 => 'Porn Movie DVDr',
@ -112,20 +112,23 @@ class PirateBayRequest extends EngineRequest {
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($title).'&tr='.implode('&tr=', $this->opts->magnet_trackers);
$seeders = sanitize($result['seeders']);
$leechers = sanitize($result['leechers']);
$filesize = human_filesize(sanitize($result['size']));
$filesize = sanitize($result['size']);
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->search->query, $title)) continue;
// Find extra data
$verified = (array_key_exists('status', $result)) ? sanitize($result['status']) : null;
$category = (array_key_exists('category', $result)) ? sanitize($result['category']) : null;
$url = (array_key_exists('id', $result)) ? 'https://thepiratebay.org/description.php?id='.sanitize($result['id']) : null;
$timestamp = (isset($result['added'])) ? sanitize($result['added']) : null;
// Process extra data
$verified = ($verified == 'vip' || $verified == 'moderator' || $verified == 'trusted') ? 'yes' : null;
if(!is_null($category)) {
// Block these categories
if(in_array($category, $this->opts->piratebay_categories_blocked)) continue;
@ -137,7 +140,7 @@ class PirateBayRequest extends EngineRequest {
$quality = find_video_quality($title);
$codec = find_video_codec($title);
$audio = find_audio_codec($title);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
} else if($category >= 100 && $category <= 199) {
@ -157,6 +160,7 @@ class PirateBayRequest extends EngineRequest {
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => $verified, // string|null
'nsfw' => $nsfw, // bool
'quality' => $quality, // string|null
'type' => null, // string|null

View file

@ -6,13 +6,13 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class YTSRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://yts.mx/api/v2/list_movies.json?query_term='.urlencode($this->search->query);
return $url;
}
@ -30,7 +30,7 @@ class YTSRequest extends EngineRequest {
public function parse_results($response) {
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
@ -39,7 +39,7 @@ class YTSRequest extends EngineRequest {
// No results
if($json_response['data']['movie_count'] == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
@ -55,12 +55,12 @@ class YTSRequest extends EngineRequest {
$timestamp = (!empty($result['date_uploaded_unix'])) ? sanitize($result['date_uploaded_unix']) : null;
$language = (!empty($result['language'])) ? sanitize($result['language']) : null;
$url = (!empty($result['url'])) ? sanitize($result['url']) : null;
// Process extra data
if(is_array($category)) {
// Block these categories
if(count(array_uintersect($category, $this->opts->yts_categories_blocked, 'strcasecmp')) > 0) continue;
// Set actual category
$category = sanitize(implode(', ', $category));
}
@ -71,11 +71,11 @@ class YTSRequest extends EngineRequest {
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($title).'&tr='.implode('&tr=', $this->opts->magnet_trackers);
$seeders = sanitize($download['seeds']);
$leechers = sanitize($download['peers']);
$filesize = human_filesize(filesize_to_bytes(sanitize($download['size'])));
$filesize = filesize_to_bytes(sanitize($download['size']));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Find extra data
$quality = (!empty($download['quality'])) ? sanitize(strtolower($download['quality'])) : null;
$codec = (!empty($download['video_codec'])) ? sanitize(strtolower($download['video_codec'])) : null;
@ -96,6 +96,7 @@ class YTSRequest extends EngineRequest {
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => 'yes', // string|null
'nsfw' => false, // bool
'quality' => $quality, // string|null
'type' => $type, // string|null
@ -126,4 +127,4 @@ class YTSRequest extends EngineRequest {
return $engine_result;
}
}
?>
?>

View file

@ -18,7 +18,7 @@ class HackernewsRequest extends EngineRequest {
$url = 'https://hn.algolia.com/api/v1/search_by_date?'.http_build_query(array(
'query' => $this->search->query, // Search query
'tags' => 'story', // What type of results to show? (story = News stories)
'hitsPerPage' => 30, // How many results to return?
'hitsPerPage' => 50, // How many results to return?
'numericFilters' => 'created_at_i>'.$article_date // How old may the article be?
));

View file

@ -20,7 +20,7 @@ class QwantNewsRequest extends EngineRequest {
't' => 'news', // News search
'safesearch' => $this->search->safe, // Safe search filter (0 = off, 1 = normal, 2 = strict)
'locale' => $language, // Language region
'count' => 30, // How many results? (Maximum 50)
'count' => 50, // How many results? (Maximum 50)
'device' => 'desktop', // Where are you searching from
'source' => 'all', // Where to get the news from (All)
'freshness' => 'month', // How old may the article be?

View file

@ -6,29 +6,34 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class ImageSearch extends EngineRequest {
protected $requests;
public function __construct($search, $opts, $mh) {
$this->requests = array();
if($opts->enable_image_search == 'on') {
if($opts->enable_yahooimages == 'on') {
if($opts->image['yahooimages'] == 'on') {
require ABSPATH.'engines/image/yahoo-images.php';
$this->requests[] = new YahooImageRequest($search, $opts, $mh);
$this->requests[] = new YahooImageRequest($search, $opts, $mh);
}
if($opts->enable_openverse == 'on') {
require ABSPATH.'engines/image/openverse.php';
$this->requests[] = new OpenverseRequest($search, $opts, $mh);
}
if($opts->enable_qwantimages == 'on') {
if($opts->image['qwantimages'] == 'on') {
require ABSPATH.'engines/image/qwant-images.php';
$this->requests[] = new QwantImageRequest($search, $opts, $mh);
$this->requests[] = new QwantImageRequest($search, $opts, $mh);
}
if($opts->image['pixabay'] == 'on') {
require ABSPATH.'engines/image/pixabay.php';
$this->requests[] = new PixabayRequest($search, $opts, $mh);
}
if($opts->image['openverse'] == 'on') {
require ABSPATH.'engines/image/openverse.php';
$this->requests[] = new OpenverseRequest($search, $opts, $mh);
}
}
}
@ -40,21 +45,21 @@ class ImageSearch extends EngineRequest {
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) {
if(isset($engine_result['did_you_mean'])) {
$goosle_results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(isset($engine_result['search_specific'])) {
$goosle_results['search_specific'][] = $engine_result['search_specific'];
}
if(isset($engine_result['search'])) {
if(isset($engine_result['search'])) {
$how_many_results = 0;
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
foreach($engine_result['search'] as $key => $result) {
if(isset($goosle_results['search'])) {
$result_urls = array_column($goosle_results['search'], 'image_full', 'id');
$found_id = array_search($result['image_full'], $result_urls); // Return the result ID, or false if not found
@ -63,27 +68,28 @@ class ImageSearch extends EngineRequest {
}
$how_many_results++;
$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));
$social_media_multiplier = (detect_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * $social_media_multiplier);
if($found_id !== false) {
// Duplicate result from another engine
$goosle_results['search'][$found_id]['goosle_rank'] += $result['engine_rank'];
$goosle_results['search'][$found_id]['goosle_rank'] += $goosle_rank;
$goosle_results['search'][$found_id]['combo_source'][] = $engine_result['source'];
} else {
// First find, rank and add to results
$match_rank = match_count($result['url'], $request->search->query_terms);
$match_rank += match_count($result['alt'], $request->search->query_terms);
$match_rank = match_count($result['tags'], $request->search->query_terms, 2);
// $match_rank += match_count($result['alt'], $request->search->query_terms);
$match_rank += match_count($result['url'], $request->search->query_terms, 0.5);
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['image_full']);
// Add result to final results
$goosle_results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank, $query_terms);
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
}
// Count results per source
@ -96,12 +102,12 @@ class ImageSearch extends EngineRequest {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : '';
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array('title' => get_class($request)." failed with error ".$request_result['http_code'], 'body' => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", 'labels' => 'request-error'));
$goosle_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']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
);
}
unset($request);
}
@ -112,12 +118,12 @@ class ImageSearch extends EngineRequest {
// Count all results
$goosle_results['number_of_results'] = count($goosle_results['search']);
unset($keys);
} else {
// Add error if there are no search results
$goosle_results['error'][] = array(
"message" => "No results found. Please try with more specific or different keywords!"
"message" => "No results found. Please try with more specific or different keywords!"
);
}
} else {
@ -126,7 +132,7 @@ class ImageSearch extends EngineRequest {
);
}
return $goosle_results;
return $goosle_results;
}
public static function print_results($goosle_results, $search, $opts) {
@ -160,34 +166,25 @@ echo "</pre>";
}
echo "</li>";
// Search suggestions
if(array_key_exists('did_you_mean', $goosle_results)) {
echo "<li class=\"meta\">";
echo " <p class=\"didyoumean\">Did you mean <a href=\"./results.php?q=".urlencode($goosle_results['did_you_mean'])."&t=".$search->type."&a=".$opts->hash."\">".$goosle_results['did_you_mean']."</a>?</p>";
if(array_key_exists('search_specific', $goosle_results)) {
echo " <p class=\"suggestion\">".search_suggestion($search, $opts, $goosle_results)."</p>";
}
echo "</li>";
}
echo "</ul>";
// Search results
echo "<ul class=\"result-grid\">";
foreach($goosle_results['search'] as $result) {
// Extra data
$meta = array();
if(!empty($result['height']) && !is_null($result['width'])) $meta[] = $result['width']."&times;".$result['height'];
if(!empty($result['filesize'])) $meta[] = human_filesize($result['filesize']);
foreach($goosle_results['search'] as $result) {
// Put result together
echo "<li class=\"result image rank-".$result['goosle_rank']." id-".$result['id']."\">";
echo " <div class=\"thumb\">";
echo " <a href=\"".$result['url']."\" target=\"_blank\" title=\"".$result['alt']."\"><img src=\"".$result['image_thumb']."\" alt=\"".$result['alt']."\" /></a>";
echo " </div>";
echo " <div class=\"meta\"><p>".implode(" &bull; ", $meta)."</p><p><a href=\"".$result['url']."\" target=\"_blank\" title=\"Open website\">Website</a> &bull; <a href=\"".$result['image_full']."\" target=\"_blank\" title=\"Open image\">Image</a></p></div>";
echo " <div class=\"meta\">";
if(!empty($result['height']) && !empty($result['width'])) echo " <p>".$result['width']."&times;".$result['height']."</p>";
echo " <p><a href=\"".$result['url']."\" target=\"_blank\" title=\"Open website\">Website</a> &bull; <a href=\"".$result['image_full']."\" target=\"_blank\" title=\"Open image\">Image</a></p>";
if($opts->show_search_rank == 'on') echo " <p>Rank: ".$result['goosle_rank']."</p>";
echo " </div>";
echo "</li>";
unset($meta);
}
echo "</ul>";
@ -210,4 +207,4 @@ echo "</pre>";
unset($goosle_results);
}
}
?>
?>

View file

@ -6,49 +6,51 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class MagnetSearch extends EngineRequest {
protected $requests;
public function __construct($search, $opts, $mh) {
$this->requests = array();
if($opts->enable_magnet_search == 'on') {
// Extra functions to process magnet results
require ABSPATH.'functions/tools-magnet.php';
if($opts->enable_limetorrents == 'on') {
if($opts->magnet['limetorrents'] == 'on') {
require ABSPATH.'engines/magnet/lime.php';
$this->requests[] = new LimeRequest($search, $opts, $mh);
}
if($opts->enable_piratebay == 'on') {
if($opts->magnet['piratebay'] == 'on') {
require ABSPATH.'engines/magnet/thepiratebay.php';
$this->requests[] = new PirateBayRequest($search, $opts, $mh);
}
if($opts->enable_yts == 'on') {
if($opts->magnet['yts'] == 'on') {
if($search->safe !== 0) {
require ABSPATH.'engines/magnet/yts.php';
$this->requests[] = new YTSRequest($search, $opts, $mh);
}
}
if($opts->enable_nyaa == 'on') {
require ABSPATH.'engines/magnet/nyaa.php';
$this->requests[] = new NyaaRequest($search, $opts, $mh);
if($opts->magnet['nyaa'] == 'on') {
if($search->safe !== 0) {
require ABSPATH.'engines/magnet/nyaa.php';
$this->requests[] = new NyaaRequest($search, $opts, $mh);
}
}
if($opts->enable_sukebei == 'on') {
if($opts->magnet['sukebei'] == 'on') {
if($opts->show_nsfw_magnets == 'on' || ($opts->show_nsfw_magnets == 'off' && $search->safe === 0)) {
require ABSPATH.'engines/magnet/sukebei.php';
$this->requests[] = new SukebeiRequest($search, $opts, $mh);
}
}
if($opts->enable_eztv == 'on') {
if($opts->magnet['eztv'] == 'on') {
if(substr(strtolower($search->query), 0, 2) == 'tt') {
require ABSPATH.'engines/magnet/eztv.php';
$this->requests[] = new EZTVRequest($search, $opts, $mh);
@ -64,9 +66,9 @@ class MagnetSearch extends EngineRequest {
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) {
if(isset($engine_result['search'])) {
if(isset($engine_result['search'])) {
$how_many_results = 0;
// Merge duplicates and apply relevance scoring
@ -80,7 +82,7 @@ class MagnetSearch extends EngineRequest {
} else {
$found_id = false;
}
$how_many_results++;
if($found_id !== false) {
@ -88,9 +90,9 @@ class MagnetSearch extends EngineRequest {
// If seeders or leechers mismatch, assume they're different peers
if($goosle_results['search'][$found_id]['seeders'] != $result['seeders']) $goosle_results['search'][$found_id]['combo_seeders'] += intval($result['seeders']);
if($goosle_results['search'][$found_id]['leechers'] != $result['leechers']) $goosle_results['search'][$found_id]['combo_leechers'] += intval($result['leechers']);
$goosle_results['search'][$found_id]['combo_source'][] = $engine_result['source'];
// If duplicate result has more info, add it
if(is_null($goosle_results['search'][$found_id]['year']) && !is_null($result['year'])) $goosle_results['search'][$found_id]['year'] = $result['year'];
if(is_null($goosle_results['search'][$found_id]['category']) && !is_null($result['category'])) $goosle_results['search'][$found_id]['category'] = $result['category'];
@ -106,12 +108,12 @@ class MagnetSearch extends EngineRequest {
$result['combo_seeders'] = intval($result['seeders']);
$result['combo_leechers'] = intval($result['leechers']);
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['hash']); // Predictable/repeatable 'unique' string
$result['id'] = md5($result['hash']); // Predictable/repeatable 'unique' string
// Add result to final results
$goosle_results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
}
@ -125,12 +127,12 @@ class MagnetSearch extends EngineRequest {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array('title' => get_class($request)." failed with error ".$request_result['http_code'], 'body' => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", 'labels' => 'request-error'));
$goosle_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']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
);
}
unset($request);
}
@ -141,12 +143,12 @@ class MagnetSearch extends EngineRequest {
// Count all results
$goosle_results['number_of_results'] = count($goosle_results['search']);
unset($keys);
} else {
// Add error if there are no search results
$goosle_results['error'][] = array(
'message' => "No results found. Please try with more specific or different keywords!"
'message' => "No results found. Please try with more specific or different keywords!"
);
}
} else {
@ -155,7 +157,7 @@ class MagnetSearch extends EngineRequest {
);
}
return $goosle_results;
return $goosle_results;
}
public static function print_results($goosle_results, $search, $opts) {
@ -175,13 +177,14 @@ echo "</pre>";
// Latest additions to yts
if($opts->show_yts_highlight == 'on') {
require ABSPATH.'engines/boxoffice/yts.php';
echo "<h2>Latest releases from YTS</h2>";
echo "<p>View these and more new releases on the <a href=\"./box-office.php?q=".$search->query."&t=9&a=".$opts->hash."\">box office</a> page!</p>";
echo "<ul class=\"result-grid\">";
$highlights = array_slice(yts_boxoffice($opts, 'date_added'), 0, 8);
foreach($highlights as $highlight) {
$thumb = (!empty($highlight['thumbnail'])) ? $highlight['thumbnail'] : $opts->pixel;
@ -194,7 +197,7 @@ echo "</pre>";
// HTML for popup
echo highlight_popup($opts->hash, $highlight);
echo "</li>";
echo "</li>";
unset($highlight);
}
@ -240,9 +243,14 @@ echo "</pre>";
foreach($goosle_results['search'] as $result) {
// Extra data
$base = $meta = array();
if(!empty($result['verified_uploader'])) {
$icon = ($result['verified_uploader'] == 'yes') ? 'magnet-verified' : 'magnet-not-verified';
$base[] = "<a onclick=\"openpopup('info-torrentverified')\" title=\"".$icon." - Click for more information\"><span class=\"".$icon."\"></span></a>";
}
if(!empty($result['combo_seeders'])) $base[] = "<strong>Seeds:</strong> <span class=\"green\">".$result['combo_seeders']."</span>";
if(!empty($result['combo_leechers'])) $base[] = "<strong>Peers:</strong> <span class=\"red\">".$result['combo_leechers']."</span>";
if(!empty($result['filesize'])) $base[] = "<strong>Size:</strong> ".$result['filesize'];
if(!empty($result['filesize'])) $base[] = "<strong>Size:</strong> ".human_filesize($result['filesize']);
if(!empty($result['timestamp'])) $base[] = "<strong>Added on:</strong> ".the_date("M d, Y", $result['timestamp']);
if(!empty($result['mpa_rating'])) $base[] = "<strong>MPA Rating:</strong> ".$result['mpa_rating'];
@ -252,7 +260,6 @@ echo "</pre>";
if(!empty($result['quality'])) $meta[] = "<strong>Quality:</strong> ".$result['quality'];
if(!empty($result['type'])) $meta[] = "<strong>Type:</strong> ".$result['type'];
if(!empty($result['audio'])) $meta[] = "<strong>Audio:</strong> ".$result['audio'];
// Highlight the shared result
$class = "";
if($opts->show_share_option == 'on') {
@ -262,7 +269,7 @@ echo "</pre>";
$base[] = "<a onclick=\"openpopup('result-".$result['id']."')\" title=\"Share magnet result\">Share</a>";
}
}
// Put result together
echo "<li class=\"result magnet id-".$result['id'].$class."\">";
echo " <div class=\"title\"><a href=\"".$result['magnet']."\"><h2>".stripslashes($result['title'])."</h2></a></div>";
@ -272,9 +279,8 @@ echo "</pre>";
// Result sources
if($opts->show_search_source == 'on') {
// If available, add a link to the found torrent page
// $url = (!is_null($result['url'])) ? " &bull; <a href=\"".$result['url']."\" target=\"_blank\" title=\"Visit torrent page\">torrent page</a>" : "";
$url = (!is_null($result['url'])) ? " &bull; <a href=\"".$result['url']."\" target=\"_blank\" title=\"Visit torrent page\">torrent page</a> <a onclick=\"openpopup('info-torrentpagelink')\" title=\"Click for more information\"><span class=\"tooltip-alert\"></span></a>" : "";
echo " <p><small>Found on ".replace_last_comma(implode(', ', $result['combo_source'])).$url."</small></p>";
}
echo " </div>";
@ -311,11 +317,22 @@ echo "</pre>";
echo "<p class=\"text-center\"><small>Goosle does not index, offer or distribute torrent files.</small></p>";
// Popup (Normally hidden)
// Torrent site warning popup (Normally hidden)
echo "<div id=\"info-torrentpagelink\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>Be careful with torrent sites</h2>";
echo " <p>Many torrent websites have intrusive popup ads and malware! Be careful what you click on and close any popups that appear.</p>";
echo " <h2>Be careful when you visit torrent sites</h2>";
echo " <p>Many torrent websites have intrusive popup ads and malware! Be careful what you click on and close any popups/redirects that appear.</p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo "</div>";
// Verified magnet info popup (Normally hidden)
echo "<div id=\"info-torrentverified\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>Trusted uploaders</h2>";
echo " <p>Some websites have a group of verified and/or trusted uploaders. These are users that are known to provide good quality downloads.</p>";
echo " <p><span class=\"magnet-verified\"></span> Downloads with a blue shield and checkmark are uploaded by a verified or trusted user according to the torrent site.</p>";
echo " <p><span class=\"magnet-not-verified\"></span> Downloads with a red shield and questionmark indicate that the user is <em>not</em> verified by the website providing the download. This can mean this is a new user, or that the file is provided from an anonymous source. Unverified magnet links are not necessarily bad but may contain low quality or misleading content or simply have a poorly written title.</p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo "</div>";
@ -329,4 +346,4 @@ echo "</pre>";
}
}
}
?>
?>

View file

@ -6,34 +6,34 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class NewsSearch extends EngineRequest {
protected $requests, $special_request;
public function __construct($search, $opts, $mh) {
$this->requests = array();
if($opts->enable_news_search == 'on') {
if($opts->enable_qwantnews == 'on') {
if($opts->news['qwantnews'] == 'on') {
require ABSPATH.'engines/news/qwant-news.php';
$this->requests[] = new QwantNewsRequest($search, $opts, $mh);
$this->requests[] = new QwantNewsRequest($search, $opts, $mh);
}
if($opts->enable_yahoonews == 'on') {
if($opts->news['yahoonews'] == 'on') {
require ABSPATH.'engines/news/yahoo-news.php';
$this->requests[] = new YahooNewsRequest($search, $opts, $mh);
$this->requests[] = new YahooNewsRequest($search, $opts, $mh);
}
if($opts->enable_bravenews == 'on') {
if($opts->news['bravenews'] == 'on') {
require ABSPATH.'engines/news/brave-news.php';
$this->requests[] = new BraveNewsRequest($search, $opts, $mh);
$this->requests[] = new BraveNewsRequest($search, $opts, $mh);
}
if($opts->enable_hackernews == 'on') {
if($opts->news['hackernews'] == 'on') {
require ABSPATH.'engines/news/hackernews.php';
$this->requests[] = new HackernewsRequest($search, $opts, $mh);
$this->requests[] = new HackernewsRequest($search, $opts, $mh);
}
}
}
@ -45,9 +45,9 @@ class NewsSearch extends EngineRequest {
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) {
if(isset($engine_result['search'])) {
if(isset($engine_result['search'])) {
$how_many_results = 0;
$time = time();
@ -59,47 +59,47 @@ class NewsSearch extends EngineRequest {
} else {
$found_id = false;
}
$how_many_results++;
$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));
$social_media_multiplier = (detect_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * $social_media_multiplier);
if($found_id !== false) {
// Duplicate result from another engine
$goosle_results['search'][$found_id]['goosle_rank'] += $goosle_rank;
$goosle_results['search'][$found_id]['combo_source'][] = $engine_result['source'];
} else {
// First find, rank and add to results
$match_rank = match_count($result['title'], $request->search->query_terms);
$match_rank = match_count($result['title'], $request->search->query_terms, 1.2);
$match_rank += match_count($result['description'], $request->search->query_terms);
$match_rank += match_count($result['url'], $request->search->query_terms);
$match_rank += match_count($result['url'], $request->search->query_terms, 0.5);
$time_rank = $time - $result['timestamp'];
if($time_rank > 21600) { // Less than 6 hours old
$match_rank += 8;
} elseif($time_rank > 86400 && $time_rank < 21600) { // About a day old
$match_rank += 6;
} elseif($time_rank > 604800 && $time_rank < 86400) { // Less than a week old, but more than a day
$match_rank += 4;
} elseif($time_rank > 2592000 && $time_rank < 604800) { // Less than a month old, but more than a week
$match_rank += 4;
} elseif($time_rank > 31536000 && $time_rank < 2592000) { // Less than a year old, but more than a month
$match_rank += 2;
$age_rank = $time - $result['timestamp'];
if($age_rank > 21600) { // Less than 6 hours old
$match_rank += 8;
} elseif($age_rank > 86400 && $age_rank < 21600) { // About a day old
$match_rank += 6;
} elseif($age_rank > 604800 && $age_rank < 86400) { // Less than a week old, but more than a day
$match_rank += 4;
} elseif($age_rank > 2592000 && $age_rank < 604800) { // Less than a month old, but more than a week
$match_rank += 4;
} elseif($age_rank > 31536000 && $age_rank < 2592000) { // Less than a year old, but more than a month
$match_rank += 2;
} else { // More than a year old
$match_rank += 1;
$match_rank += 1;
}
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['url']);
// Add result to final results
$goosle_results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank, $time_rank, $query_terms);
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank, $age_rank);
}
// Count results per source
$goosle_results['sources'][$engine_result['source']] = $how_many_results;
@ -110,12 +110,12 @@ class NewsSearch extends EngineRequest {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : '';
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array('title' => get_class($request)." failed with error ".$request_result['http_code'], 'body' => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", 'labels' => 'request-error'));
$goosle_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']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
);
}
unset($request);
}
@ -126,12 +126,12 @@ class NewsSearch extends EngineRequest {
// Count all results
$goosle_results['number_of_results'] = count($goosle_results['search']);
unset($keys);
} else {
// Add error if there are no search results
$goosle_results['error'][] = array(
'message' => "No results found. Please try with more specific or different keywords!"
'message' => "No results found. Please try with more specific or different keywords!"
);
}
} else {
@ -140,7 +140,7 @@ class NewsSearch extends EngineRequest {
);
}
return $goosle_results;
return $goosle_results;
}
public static function print_results($goosle_results, $search, $opts) {
@ -195,7 +195,7 @@ echo "</pre>";
echo " </div>";
echo " </div>";
echo "</li>";
unset($meta, $thumb);
}
@ -216,4 +216,4 @@ echo "</pre>";
unset($goosle_results);
}
}
?>
?>

View file

@ -6,40 +6,46 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class Search extends EngineRequest {
protected $requests, $special_request;
public function __construct($search, $opts, $mh) {
$this->requests = array();
if($opts->enable_duckduckgo == 'on') {
require ABSPATH.'engines/search/duckduckgo.php';
$this->requests[] = new DuckDuckGoRequest($search, $opts, $mh);
}
if($opts->enable_google == 'on') {
require ABSPATH.'engines/search/google.php';
$this->requests[] = new GoogleRequest($search, $opts, $mh);
}
if($opts->enable_web_search == 'on') {
if($opts->web['duckduckgo'] == 'on') {
require ABSPATH.'engines/search/duckduckgo.php';
$this->requests[] = new DuckDuckGoRequest($search, $opts, $mh);
}
if($opts->enable_qwant == 'on') {
require ABSPATH.'engines/search/qwant.php';
$this->requests[] = new QwantRequest($search, $opts, $mh);
}
if($opts->enable_brave == 'on') {
require ABSPATH.'engines/search/brave.php';
$this->requests[] = new BraveRequest($search, $opts, $mh);
}
if($opts->web['mojeek'] == 'on') {
require ABSPATH.'engines/search/mojeek.php';
$this->requests[] = new MojeekRequest($search, $opts, $mh);
}
if($opts->enable_wikipedia == 'on') {
require ABSPATH.'engines/search/wikipedia.php';
$this->requests[] = new WikiRequest($search, $opts, $mh);
if($opts->web['google'] == 'on') {
require ABSPATH.'engines/search/google.php';
$this->requests[] = new GoogleRequest($search, $opts, $mh);
}
if($opts->web['qwant'] == 'on') {
require ABSPATH.'engines/search/qwant.php';
$this->requests[] = new QwantRequest($search, $opts, $mh);
}
if($opts->web['brave'] == 'on') {
require ABSPATH.'engines/search/brave.php';
$this->requests[] = new BraveRequest($search, $opts, $mh);
}
if($opts->web['wikipedia'] == 'on') {
require ABSPATH.'engines/search/wikipedia.php';
$this->requests[] = new WikiRequest($search, $opts, $mh);
}
}
/* --- SPECIAL SEARCHES --- */
// Currency converter
@ -49,7 +55,7 @@ class Search extends EngineRequest {
$this->special_request = new CurrencyRequest($search, $opts, $mh);
}
}
// Dictionary
if($opts->special['definition'] == 'on') {
if($search->count_terms == 2 && ($search->query_terms[0] == 'def' || $search->query_terms[0] == 'define' || $search->query_terms[0] == 'meaning')) {
@ -57,7 +63,7 @@ class Search extends EngineRequest {
$this->special_request = new DefinitionRequest($search, $opts, $mh);
}
}
// IP Lookup
if($opts->special['ipaddress'] == 'on') {
if($search->count_terms == 1 && ($search->query_terms[0] == 'ip' || $search->query_terms[0] == 'myip' || $search->query_terms[0] == 'ipaddress')) {
@ -65,7 +71,7 @@ class Search extends EngineRequest {
$this->special_request = new ipRequest($search, $opts, $mh);
}
}
// php.net search
if($opts->special['phpnet'] == 'on') {
if($search->count_terms == 2 && $search->query_terms[0] == 'php') {
@ -73,7 +79,7 @@ class Search extends EngineRequest {
$this->special_request = new PHPnetRequest($search, $opts, $mh);
}
}
// wordpress.org search
if($opts->special['wordpress'] == 'on') {
if(($search->count_terms == 2 && ($search->query_terms[0] == 'wordpress' || $search->query_terms[0] == 'wp')) || ($search->count_terms == 3 && ($search->query_terms[0] == 'wordpress' || $search->query_terms[0] == 'wp') && $search->query_terms[1] == 'hook')) {
@ -90,17 +96,17 @@ class Search extends EngineRequest {
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) {
if(isset($engine_result['did_you_mean'])) {
$goosle_results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(isset($engine_result['search_specific'])) {
$goosle_results['search_specific'][] = $engine_result['search_specific'];
}
if(isset($engine_result['search'])) {
if(isset($engine_result['search'])) {
$how_many_results = 0;
// Merge duplicates and apply relevance scoring
@ -111,11 +117,11 @@ class Search extends EngineRequest {
} else {
$found_id = false;
}
$how_many_results++;
$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));
$social_media_multiplier = (detect_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * $social_media_multiplier);
if($found_id !== false) {
// Duplicate result from another engine
$goosle_results['search'][$found_id]['goosle_rank'] += $goosle_rank;
@ -123,18 +129,18 @@ class Search extends EngineRequest {
} else {
// First find, rank and add to results
$match_rank = match_count($result['title'], $request->search->query_terms);
$match_rank += match_count($result['description'], $request->search->query_terms);
$match_rank += match_count($result['url'], $request->search->query_terms);
$match_rank += match_count($result['description'], $request->search->query_terms, 2);;
$match_rank += match_count($result['url'], $request->search->query_terms, 0.5);
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['url']);
// Add result to final results
$goosle_results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank, $query_terms);
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
}
// Count results per source
@ -147,26 +153,26 @@ class Search extends EngineRequest {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : '';
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array('title' => get_class($request).' failed with error '.$request_result['http_code'], 'body' => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", 'labels' => 'request-error'));
$goosle_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']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
);
}
unset($request);
}
// Check for Special result
if($this->special_request) {
$special_result = $this->special_request->get_results();
if($special_result) {
$goosle_results['special'] = $special_result;
}
unset($special_result);
}
if(array_key_exists('search', $goosle_results)) {
// Re-order results based on rank
$keys = array_column($goosle_results['search'], 'goosle_rank');
@ -179,7 +185,7 @@ class Search extends EngineRequest {
} else {
// Add error if there are no search results
$goosle_results['error'][] = array(
'message' => "No results found. Please try with more specific or different keywords!"
'message' => "No results found. Please try with more specific or different keywords!"
);
}
} else {
@ -188,7 +194,7 @@ class Search extends EngineRequest {
);
}
return $goosle_results;
return $goosle_results;
}
public static function print_results($goosle_results, $search, $opts) {
@ -222,16 +228,6 @@ echo "</pre>";
}
echo "</li>";
// Search suggestions
if(array_key_exists('did_you_mean', $goosle_results)) {
echo "<li class=\"meta\">";
echo " <p class=\"didyoumean\">Did you mean <a href=\"./results.php?q=".urlencode($goosle_results['did_you_mean'])."&t=".$search->type."&a=".$opts->hash."\">".$goosle_results['did_you_mean']."</a>?</p>";
if(array_key_exists('search_specific', $goosle_results)) {
echo " <p class=\"suggestion\">".search_suggestion($search, $opts, $goosle_results)."</p>";
}
echo "</li>";
}
// Special result
if(array_key_exists('special', $goosle_results)) {
echo "<li class=\"result-special web\">";
@ -258,7 +254,6 @@ echo "</pre>";
echo " <p>".$result['description']."</p>";
if($opts->enable_magnet_search == 'on' && $opts->imdb_id_search == 'on') {
if(stristr($result['url'], 'imdb.com') !== false && preg_match_all('/(?:tt[0-9]+)/i', $result['url'], $imdb_result)) {
// echo " <p><strong>Goosle detected an IMDb ID for this result, search for <a href=\"./results.php?q=".$imdb_result[0][0]."&a=".$opts->hash."&t=9\" title=\"Search for Magnet links\">Magnet links</a>?</strong></p>";
echo " <p><strong>Goosle detected an IMDb ID for this result, search for <a href=\"./results.php?q=".$imdb_result[0][0]."&a=".$opts->hash."&t=9\" title=\"Search for Magnet links\">Magnet links</a>?</strong> <a onclick=\"openpopup('info-magnetresult')\" title=\"Click for more information\"><span class=\"tooltip-question\"></span></a></p>";
}
}
@ -296,4 +291,4 @@ echo "</pre>";
unset($goosle_results);
}
}
?>
?>

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class DuckDuckGoRequest extends EngineRequest {
@ -28,13 +28,12 @@ class DuckDuckGoRequest extends EngineRequest {
'kz' => '-1', // Instant answers (1 = on, -1 = off)
'kc' => '-1', // Autoload images (1 = on, -1 = off)
'kav' => '-1', // Autoload results (1 = on, -1 = off)
'kf' => '-1', // Favicons (1 = on, -1 = off)
'kaf' => '1', // Full URLs (1 = on, -1 = off)
'kac' => '-1', // Auto suggest (1 = on, -1 = off)
'kd' => '-1', // Redirects (1 = on, -1 = off)
'kh' => '1', // HTTPS (1 = on, -1 = off)
'kg' => 'g', // Get/Post (g = GET, p = POST)
'k1' => '-1' // Ads (1 = on, -1 = off)
'k1' => '-1' // Ads (1 = on, -1 = off)
));
unset($safe);
@ -67,20 +66,10 @@ class DuckDuckGoRequest extends EngineRequest {
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
// Scrape recommended
$didyoumean = $xpath->query(".//div[@id='did_you_mean']/a[1]")[0];
if(!is_null($didyoumean)) {
$engine_result['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//div[@id='did_you_mean']/a[2]")[0];
if(!is_null($search_specific)) {
$engine_result['search_specific'] = $search_specific->textContent;
}
foreach($scrape as $result) {
// Find data
$url = $xpath->evaluate(".//h2[@class='result__title']//a/@href", $result);
@ -90,21 +79,21 @@ class DuckDuckGoRequest extends EngineRequest {
// Skip broken results
if($url->length == 0) continue;
if($title->length == 0) continue;
// Process data
$url = sanitize($url[0]->textContent);
$title = strip_newlines(sanitize($title[0]->textContent));
$description = ($description->length == 0) ? "No description was provided for this site." : limit_string_length(strip_newlines(sanitize($description[0]->textContent)));
// filter duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
$engine_temp[] = array(
'title' => $title,
'url' => $url,
'description' => $description,
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;

View file

@ -6,21 +6,22 @@
* 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
* 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() {
// Including the preferred language variable breaks the page result, and with that the crawler!
$url = 'https://www.google.com/search?'.http_build_query(array(
'q' => $this->search->query, // Search query
'oq' => $this->search->query, // (Original) Search query
'safe' => $this->search->safe, // Safe search (0 = off, 1 = moderate, 2 = on/strict)
'num' => 30, // Number of results per page
'pws' => 0, // Personalized search results (0 = off)
'gl' => $this->opts->google_search_region, // Primarily search in this region
'num' => 50, // Number of results per page
'pws' => 0, // Personalized search (0 = off)
'udm' => 14, // A view for simpler/non-ai results
'tbs' => 'li:1', // 'verbatim' search, adding this enables it
'complete' => '0', // Instant results related (0 = off)
'sclient' => 'web' // Where are you searching from
'complete' => '0', // Instant search (0 = off)
'source' => 'web', // Where are you searching from
'sclient' => 'gws-wiz' // Search client (Google currently seems to prefer 'gws-wiz' or 'gws-wiz-serp', previously 'web')
));
return $url;
@ -50,21 +51,10 @@ class GoogleRequest extends EngineRequest {
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
// Scrape recommended
$didyoumean = $xpath->query(".//a[@class='gL9Hy']")[0];
if(!is_null($didyoumean)) {
$engine_result['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
$engine_result['search_specific'] = "\"".$search_specific->textContent."\"";
}
foreach($scrape as $result) {
// Find data
$url = $xpath->evaluate(".//div[@class='yuRUbf']//a/@href", $result);
@ -74,7 +64,7 @@ class GoogleRequest extends EngineRequest {
// Skip broken results
if($url->length == 0) continue;
if($title->length == 0) continue;
// Process data
$url = sanitize($url[0]->textContent);
$title = strip_newlines(sanitize($title[0]->textContent));
@ -86,9 +76,9 @@ class GoogleRequest extends EngineRequest {
}
$engine_temp[] = array(
'title' => $title,
'url' => $url,
'description' => $description,
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;

114
engines/search/mojeek.php Normal file
View file

@ -0,0 +1,114 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works.
*
* 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 MojeekRequest extends EngineRequest {
public function get_request_url() {
// Safe search override
if($this->search->safe == 0) {
$safe = '';
} else if($this->search->safe == 2) {
$safe = '1';
} else {
$safe = '';
}
// All parameters and values: https://www.mojeek.com/preferences
$url = 'https://www.mojeek.com/search?'.http_build_query(array(
'q' => $this->search->query, // Search query
'safe' => $safe, // Safe search (1 = on, 0 = off
'lb' => strtolower($this->opts->mojeek_language), // Results language
'arc' => 'none', // Region search bias
't' => '40', // How many results
'tn' => '0', // No news results (Goes in a separate column)
'si' => '4', // Max same site results
'tlen' => '100', // Title length
'dlen' => '300', // Description length
'ib' => '0', // No result info boxes
'sumt' => '0', // Hide summary tab
'sumb' => '0' // Hide summary button
));
unset($safe);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//ul[contains(@class, 'results-standard')]/li");
// Figure out results and base rank
$number_of_results = $rank = count($scrape);
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
foreach($scrape as $result) {
// Find data
$url = $xpath->evaluate(".//h2/a/@href", $result);
$title = $xpath->evaluate(".//h2", $result);
$description = $xpath->evaluate(".//p[@class='s']", $result);
// Skip broken results
if($url->length == 0) continue;
if($title->length == 0) continue;
// Process data
$url = sanitize($url[0]->textContent);
$title = strip_newlines(sanitize($title[0]->textContent));
$description = ($description->length == 0) ? "No description was provided for this site." : limit_string_length(strip_newlines(sanitize($description[0]->textContent)));
// filter duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
$engine_temp[] = array(
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Mojeek';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, $number_of_results, count($engine_temp));
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -17,7 +17,7 @@ class QwantRequest extends EngineRequest {
't' => 'web', // Type of search, web search
'safesearch' => $this->search->safe, // Safe search filter (0 = off, 1 = normal, 2 = strict)
'locale' => strtolower($this->opts->qwant_language), // In which language should the search be done
'count' => 10, // How many results? (Maximum 10)
'count' => 10, // How many results? (Max 10)
'device' => 'desktop' // What kind of device are we searching from?
));

View file

@ -17,7 +17,7 @@ class WikiRequest extends EngineRequest {
'action' => 'query', // Search type (via a query?)
'list' => 'search', // Full text search
'format' => 'json', // Return format (Must be json)
'srlimit' => 10 // How many search results to get, ideally as few as possible since it's just static wiki pages (max 500)
'srlimit' => 5 // How many search results to get, ideally as few as possible since it's just static wiki pages (max 500)
));
return $url;

View file

@ -6,16 +6,16 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class CurrencyRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://cdn.moneyconvert.net/api/latest.json';
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
@ -48,7 +48,7 @@ class CurrencyRequest extends EngineRequest {
// [1] = FROM CURRENCY
// [2] = (to|in)
// [3] = TO CURRENCY
$amount = floatval($this->search->query_terms[0]);
$amount_currency = strtoupper($this->search->query_terms[1]);
$conversion_currency = strtoupper($this->search->query_terms[3]);

View file

@ -0,0 +1,131 @@
<?php
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
require ABSPATH.'functions/tools.php';
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
/* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Goosle Search oAUTH</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<meta name="robots" content="noodp,noydir" />
<meta name="referrer" content="no-referrer"/>
<meta name="description" content="Get your Goosle on! - The best meta search engine for private and fast internet fun!" />
<link rel="icon" href="../favicon.ico" />
<link rel="apple-touch-icon" href="../apple-touch-icon.png" />
<link rel="canonical" href="<?php echo get_base_url($opts->siteurl); ?>/functions/oauth-openverse.php" />
<link rel="stylesheet" type="text/css" href="<?php echo get_base_url($opts->siteurl); ?>/assets/css/styles.css"/>
<link rel="stylesheet" type="text/css" href="<?php echo get_base_url($opts->siteurl); ?>/assets/css/<?php echo $opts->colorscheme; ?>.css"/>
</head>
<body class="oauthpage">
<?php
if(verify_hash($opts->hash_auth, $opts->hash, $auth)) {
?>
<div class="content">
<?php
$connect = (isset($_REQUEST['oa'])) ? sanitize($_REQUEST['oa']) : '';
$email = (isset($_REQUEST['oae'])) ? sanitize($_REQUEST['oae']) : '';
$client_id = (isset($_REQUEST['oaid'])) ? sanitize($_REQUEST['oaid']) : '';
$client_secret = (isset($_REQUEST['oacs'])) ? sanitize($_REQUEST['oacs']) : '';
if(empty($connect)) {
?>
<div class="oauth-form">
<h1><span class="goosle-g">G</span>oosle</h1>
<p>Use this page to set up an authorization token for Openverse.<br />
Fill in the relevant fields and click the button at the bottom to continue.</p>
<form action="oauth-openverse.php" method="get" autocomplete="off">
<h2>Registration</h2>
<p>Email address:<br /><input tabindex="10" type="text" class="field" name="oae" /><br /><small>(Always required for verification)</small></p>
<h3>Recovering a previous registration?</h3>
<p>Client ID:<br /><input tabindex="20" type="text" class="field" name="oaid" /></p>
<p>Client Secret:<br /><input tabindex="30" type="text" class="field" name="oacs" /></p>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>
<div class="oauth-buttons">
<button tabindex="100" name="oa" value="openverse" type="submit">Connect to Openverse</button>
</div>
<a href="/">Back to Goosle</a>
</form>
</div>
<?php
} else {
$token_file = ABSPATH.'cache/token.data';
if(empty($client_id) AND empty($client_secret) AND !empty($email)) {
$registration = do_curl_request(
'https://api.openverse.org/v1/auth_tokens/register/', // (string) Where?
array('Accept: application/json, */*;q=0.8', 'User-Agent: '.$opts->user_agents[0].';'), // (array) Headers
'post', // (string) post/get
array('name' => 'Goosle Meta Search '.md5(get_base_url($opts->siteurl)), 'description' => 'Goosle Meta Search for '.get_base_url($opts->siteurl), 'email' => $email) // (assoc array) Post body
);
$registration = json_decode($registration, true);
// Site already exists, get new token
if(stristr($registration['name'][0], 'this name already exists')) {
if(is_file($token_file)) {
$tokens = unserialize(file_get_contents($token_file));
$registration = $tokens['openverse'];
} else {
echo "<div class=\"auth-error\">Error - Token file is missing. Please recover your registration with the Client ID and Client Secret.<br /><a href=\"/functions/oauth-openverse.php?a=".$opts->hash."\">Try again</a></div>";
exit;
}
}
} else {
$registration = array('client_id' => $client_id, 'client_secret' => $client_secret);
}
$new_token = do_curl_request(
'https://api.openverse.org/v1/auth_tokens/token/', // (string) Where?
array('Accept: application/json, */*;q=0.8', 'User-Agent: '.$opts->user_agents[0].';', 'Authorization: Bearer'.$registration['client_id']), // (array) Headers
'post', // (string) post/get
array('grant_type' => 'client_credentials', 'client_id' => $registration['client_id'], 'client_secret' => $registration['client_secret']) // (assoc array) Post body
);
$new_token = json_decode($new_token, true);
$new_token['expires_in'] = time() + ($new_token['expires_in'] - 3600);
oauth_store_token($token_file, $connect, array('client_id' => $registration['client_id'], 'client_secret' => $registration['client_secret'], 'access_token' => $new_token['access_token'], 'expires' => $new_token['expires_in']));
echo "<div class=\"auth-success\"><p>SUCCESS!</p>";
echo "<p>Goosle is now authorized and you can enable Openverse in your config.php!<br />If this is your first time authorizing with this email address you will receive an email from Openverse in a few minutes with a verification link that you need to click.</p>";
echo "<p>To be able to recover your registration save these values:</p>";
echo "<p>Used Email Address: ".$email."<br />Client ID: ".$registration['client_id']."<br />Client Secret: ".$registration['client_secret']."<br /><br /><a href=\"/results.php?a=".$opts->hash."&q=goose&t=1\">Continue to Goosle</div>";
unset($registration, $new_token);
}
?>
</div>
<?php } else { ?>
<div class="auth-error">Redirecting</div>
<meta http-equiv="refresh" content="1; url=<?php echo get_base_url($opts->siteurl); ?>/error.php" />
<?php } ?>
</body>
</html>

View file

@ -116,10 +116,8 @@ abstract class EngineRequest {
// Cache last request if there is something to cache
if($this->opts->cache_type !== 'off') {
if(count($results) > 0) store_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, $results, $this->opts->cache_time);
// Maybe delete old file cache
if($this->opts->cache_type == 'file') delete_cached_results($this->opts->cache_time);
$ttl = ($this->search->type == 2) ? 1 : $this->opts->cache_time;
if(count($results) > 0) store_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, $results, $ttl);
}
return $results;

View file

@ -64,11 +64,13 @@ function highlight_popup($opts_hash, $highlight) {
// True = nsfw, false = not nsfw
--------------------------------------*/
function detect_nsfw($string) {
$string = strtolower($string);
// Forbidden terms
//Basic pattern: ^cum[-_\s]?play(ing|ed|s)?
$nsfw_keywords = array(
'/(deepthroat|gangbang|cowgirl|dildo|fuck|cuckold|anal|hump|finger|kiss|pegg|fist|ballbust|twerk|dogg|squirt)(ing|ed|s)?/',
'/(yaoi|porn|gonzo|erotica|blowbang|bukkake|gokkun|onlyfans|fansly|manyvids|softcore|hardcore|latex|lingerie|interracial|bdsm|chastity|hogtied|kinky|bondage|shibari|hitachi|upskirt)/',
'/(deepthroat|gangbang|cowgirl|dildo|fuck|cuckold|anal|hump|finger|pegg|fist|ballbust|twerk|dogg|squirt|dick|orgasm)(ing|ed|s)?/',
'/(yaoi|porn|gonzo|erotica|blowbang|bukkake|gokkun|softcore|hardcore|latex|lingerie|interracial|bdsm|chastity|kinky|bondage|shibari|hitachi|upskirt)/',
'/(cock|creampie|cameltoe|enema|nipple|sybian|vibrator|cougar|threesome|foursome|pornstar|escort)(s)?/',
'/(cmnf|cfnm|pov|cbt|bbw|pawg|ssbbw|joi|cei)/',
'/(blow|rim|foot|hand)job(s)?/',
@ -77,7 +79,7 @@ function detect_nsfw($string) {
'/jerk(ing)?[-_\s]?off/',
'/tw(i|u)nk(s)?/',
'/cum(bot|ming|s)?/',
'/porn(hub)?/',
'/porn(hub)?|xhamster|youporn|faphouse|sexually(\s)?broken|adulttime|transfixed|tsseduction|waterbondage|fuckingmachines|monstersofcock|deeplush|hotandmean|onlyfans|fansly|manyvids|transangels|premiumhdv|genderx|evil(\s)?angel|thetrainingofo|rocco(\s)?siffredi|electrosluts|ultimatesurrender|whippedass|insex|herlimit|analdays|bangbus|faketaxi|horrorporn|neighboraffair|naughtybookworms|sexandsubmission|housewife1on1|devicebondage|tspussyhunters|everythingbutt|theupperfloor|public(\s)?disgrace|fuckedandbound|alterotic|divinebitches|wiredpussy/',
'/(m|g)ilf(s)?/',
'/clit(oris|s)?/',
'/tit(ties|s)/',
@ -86,12 +88,10 @@ function detect_nsfw($string) {
'/doggy(style)?/',
'/(masturbat|penetrat)(e|ion|ing|ed)/',
'/face(fuck|sit)?(ing|ting|ed|s)?/',
'/gap(e|ing|ed)?/',
'/scissor(ing|ed)?/',
'/(gap|scissor)(e|ing|ed)?/',
'/(fetish|penis|ass)(es)?/',
'/(fem|lez|male)dom/',
'/futa(nari)?/',
'/orgasm(ing|ed|s)?/',
'/(slave|pet)[-_\s]?play(ing|ed|s)?/',
'/submissive(d|s)?/',
'/tied[-_\s]?(up)?/',
@ -99,8 +99,8 @@ function detect_nsfw($string) {
'/swing(er|ers|ing)?/',
);
// Replace everything but letters with a space
$string = preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', strtolower($string));
// Replace everything but alphanumeric with a space
$string = preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', $string);
preg_replace($nsfw_keywords, '*', $string, -1 , $count);

View file

@ -6,12 +6,12 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
// Current Goosle version
$current_version = '1.6.1';
$current_version = '1.7';
/*--------------------------------------
// Verify the hash, or not, and let people in, or not
@ -36,18 +36,25 @@ function load_opts() {
die();
} else {
$opts = require $config_file;
// From the url/request
// From the url/request
$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : '';
$opts->pixel = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
// Force a few defaults and safeguards
if($opts->cache_type == 'file' && !is_dir(ABSPATH.'cache/')) $opts->cache_type = 'off';
if($opts->cache_type == 'apcu' && !function_exists('apcu_exists')) $opts->cache_type = 'off';
if($opts->cache_type == 'apcu' && !function_exists('apcu_exists')) $opts->cache_type = 'off';
if($opts->cache_time < 1 || ($opts->cache_type == 'apcu' && $opts->cache_time > 8) || ($opts->cache_type == 'file' && $opts->cache_time > 48)) $opts->cache_time = 8;
if(!is_numeric($opts->search_results_per_page) || ($opts->search_results_per_page < 8 || $opts->search_results_per_page > 160)) $opts->social_media_relevance = 24;
if(!is_numeric($opts->social_media_relevance) || ($opts->social_media_relevance > 10 || $opts->social_media_relevance < 0)) $opts->social_media_relevance = 8;
// Disable the search type if no engines available
if($opts->web['duckduckgo'] == 'off' && $opts->web['mojeek'] == 'off' && $opts->web['qwant'] == 'off' && $opts->web['google'] == 'off' && $opts->web['brave'] == 'off' && $opts->web['wikipedia'] == 'off') $opts->enable_web_search = 'off';
if($opts->image['yahooimages'] == 'off' && $opts->image['qwantimages'] == 'off' && $opts->image['pixabay'] == 'off' && $opts->image['openverse'] == 'off') $opts->enable_image_search = 'off';
if($opts->news['qwantnews'] == 'off' && $opts->news['yahoonews'] == 'off' && $opts->news['bravenews'] == 'off' && $opts->news['hackernews'] == 'off') $opts->enable_news_search = 'off';
if($opts->magnet['limetorrents'] == 'off' && $opts->magnet['piratebay'] == 'off' && $opts->magnet['nyaa'] == 'off' && $opts->magnet['sukebei'] == 'off' && $opts->magnet['yta'] == 'off' && $opts->magnet['eztv'] == 'off') $opts->enable_magnet_search = 'off';
return $opts;
}
}
@ -58,7 +65,7 @@ function load_opts() {
function load_search() {
$search = new stdClass();
// From the url/request
// From the url/request
if(!isset($_REQUEST['s'])) {
// Regular search
$search->query = (isset($_REQUEST['q'])) ? trim($_REQUEST['q']) : '';
@ -84,10 +91,9 @@ function load_search() {
// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
if(substr($search->query, 0, 1) == '!') $search->query = substr($search->query, 1);
// Preserve quotes
$search->query = str_replace('%22', '\"', $search->query);
// Special searches and filters
$search->query_terms = explode(' ', strtolower($search->query)); // Break up query
$search->count_terms = count($search->query_terms); // How many keywords?
@ -99,15 +105,44 @@ function load_search() {
$search->safe = 2;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
if($search->query_terms[0] == 'safe:off' || $search->query_terms[0] == 'xxx' || $search->query_terms[0] == 'porn') {
if($search->query_terms[0] == 'safe:off' || $search->query_terms[0] == 'nsfw') {
$search->safe = 0;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
// Size search override (For image search only)
// 0 = all, 1 = small, 2 = medium, 3 = large, 4 extra large
$search->size = 0;
if($search->type == 1) {
if($search->query_terms[0] == 'size:small') {
$search->size = 1;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
if($search->query_terms[0] == 'size:medium') {
$search->size = 2;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
if($search->query_terms[0] == 'size:large') {
$search->size = 3;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
if($search->query_terms[0] == 'size:xlarge') {
$search->size = 4;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
}
// Create a 'human-readable' and Urlencoded query
$search->nice_query = $search->query;
$search->query = urlencode($search->query);
// Maybe count stats?
if(!empty($search->query)) count_stats();
return $search;
}
@ -116,7 +151,7 @@ function load_search() {
--------------------------------------*/
function load_stats() {
$stats_file = ABSPATH.'cache/stats.data';
if(!is_file($stats_file)) {
// Create stats file if it doesn't exist
$stats = array('started' => mktime(0, 0, 0, date('m'), date('d'), date('Y')), 'days_active' => 0, 'all_queries' => 0, 'avg_per_day' => 0);
@ -125,7 +160,7 @@ function load_stats() {
// Get stats
$stats = unserialize(file_get_contents($stats_file));
}
return $stats;
}
@ -152,13 +187,13 @@ function count_stats() {
--------------------------------------*/
function show_update_notification() {
global $current_version;
$version_file = ABSPATH.'cache/version.data';
if(is_file($version_file)) {
// Get version information
$version = unserialize(file_get_contents($version_file));
// Check if a newer version is available and add it to the version display
if(version_compare($current_version, $version['latest'], '<')) {
return "<a href=\"".$version['url']."\" target=\"_blank\" class=\"update\">Version ".$version['latest']." is available!</a>";
@ -174,7 +209,7 @@ function show_update_notification() {
--------------------------------------*/
function do_curl_request($url, $headers, $method, $post_fields) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if($method == 'post' && !empty($post_fields)) {
curl_setopt($ch, CURLOPT_POST, 1);
@ -192,10 +227,10 @@ function do_curl_request($url, $headers, $method, $post_fields) {
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_VERBOSE, false);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
@ -205,11 +240,11 @@ function do_curl_request($url, $headers, $method, $post_fields) {
--------------------------------------*/
function get_xpath($response) {
if(!$response) return null;
$htmlDom = new DOMDocument;
@$htmlDom->loadHTML($response);
$xpath = new DOMXPath($htmlDom);
return $xpath;
}
@ -218,8 +253,8 @@ function get_xpath($response) {
--------------------------------------*/
function get_base_url($siteurl) {
// Figure out server protocol
$protocol = empty($_SERVER['HTTPS']) ? 'http' : 'https';
$protocol = empty($_SERVER['HTTPS']) ? 'http' : 'https';
return $protocol.'://'.$siteurl;
}
@ -296,7 +331,7 @@ function delete_cached_results($ttl) {
$extension = pathinfo($file, PATHINFO_EXTENSION);
// Only delete cache files (*.result)
if($file == '.' OR $file == '..' OR $extension != 'result') continue;
if($file == '.' OR $file == '..' OR $extension != 'result') continue;
// Delete if expired
if(filemtime($folder.$file) < (time() - $ttl)) {
@ -321,7 +356,7 @@ function oauth_store_token($token_file, $connect, $token) {
$tokens[$connect] = $token;
file_put_contents($token_file, serialize($tokens));
}
}
}
/*--------------------------------------
// Log requests
@ -329,14 +364,14 @@ function oauth_store_token($token_file, $connect, $token) {
function querylog($engine, $type, $request_url, $scraped_results, $final_results) {
$log_file = ABSPATH.'cache/querylog_'.the_date('d_m_Y').'.log';
file_put_contents($log_file, '['.the_date('d-m-Y H:i:s').']['.$type.'] '.$engine.': '.$scraped_results.' -> '.$final_results.', '.$request_url."\n", FILE_APPEND);
}
}
/*--------------------------------------
// Sanitize/format variables
--------------------------------------*/
function sanitize($variable) {
switch(gettype($variable)) {
case 'string':
case 'string':
$variable = htmlspecialchars(trim($variable), ENT_QUOTES);
break;
case 'integer':
@ -346,7 +381,7 @@ function sanitize($variable) {
case 'boolean':
$variable = ($variable === FALSE) ? 0 : 1;
break;
default:
default:
$variable = ($variable === NULL) ? 'NULL' : htmlspecialchars(strip_tags(trim($variable)), ENT_QUOTES);
break;
}
@ -371,71 +406,95 @@ function limit_string_length($string, $length = 200, $append = '&hellip;') {
}
/*--------------------------------------
// Search result match counter
// Count matching keywords between result and search query
--------------------------------------*/
function match_count($string, $query) {
if(empty($string)) return 0;
function match_count($result_terms, $query_terms, $multiplier = 1) {
if(empty($result_terms)) return 0;
$string = strtolower($string);
if(filter_var($string, FILTER_VALIDATE_URL)) {
$string = preg_replace('/[^a-z0-9]+/', ' ', $string);
if(!is_array($result_terms)) {
$result_terms = make_tags_from_string($result_terms);
}
// Replace anything but alphanumeric with a space
$string = preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', $string);
$matches = array_intersect(array_filter(array_unique(explode(' ', $string))), $query);
$matches = count($matches);
$matches = array_intersect($result_terms, $query_terms);
$matches = count($matches) * $multiplier;
return $matches;
}
/*--------------------------------------
// Detect social media results
// Turn a string (title or something) into an array of words (tags)
--------------------------------------*/
function is_social_media($string) {
$string = strtolower($string);
// Borrowed from https://github.com/lorey/social-media-profiles-regexs
if(preg_match('/(?:https?:)?\/\/(?:www\.)?(?:facebook|fb)\.com\/(?P<profile>(?![A-z]+\.php)(?!marketplace|gaming|watch|me|messages|help|search|groups)[A-z0-9_\-\.]+)\/?/', $string)
|| preg_match('/(?:https?:)?\/\/(?:www\.)facebook\.com\/(?:profile.php\?id=)?(?P<id>[0-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)
|| preg_match('/(?:https?:)?\/\/(?:[A-z]+\.)?youtube\.com\/(?:c(?:hannel)?)\/(?P<id>[A-z0-9-\_]+)\/?/', $string)
|| preg_match('/(?:https?:)?\/\/(?:[A-z]+\.)?youtube\.com\/(?:u(?:ser)?)\/(?P<username>[A-z0-9]+)\/?/', $string)
|| preg_match('/(?:https?:)?\/\/(?:(?:www\.)?youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)(?P<id>[A-z0-9\-\_]+)/', $string)
) return true;
function make_tags_from_string($string) {
if(empty($string)) return array();
return false;
$string = strtolower($string);
// Replace anything but alphanumeric with a space
$string = preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', $string);
$keywords = array_filter(array_unique(explode(' ', $string)));
// Get rid of short words and letters
foreach($keywords as $k => $word) {
if(strlen($word) < 3) unset($keywords[$k]);
}
// Get rid of filler words (English)
$filler_words = array('and', 'ago', 'but', 'for', 'get', 'gets', 'have', 'haves', 'has', 'into', 'nor', 'off', 'onto', 'the', 'with', 'yet');
$keywords = array_diff($keywords, $filler_words);
return $keywords;
}
/*--------------------------------------
// Search suggestions
// Output and format dates in local time
--------------------------------------*/
function search_suggestion($search, $opts, $results) {
$specific_result = $specific_result2 = '';
function the_date($format, $timestamp = null) {
global $opts;
if(($search->type == 0 || $search->type == 1) && count($results['search_specific']) > 1) {
// Format query url
$search_specific_url2 = "./results.php?q=".urlencode($results['search_specific'][1])."&t=".$search->type."&a=".$opts->hash;
$specific_result2 = " or <a href=\"".$search_specific_url2."\">".$results['search_specific'][1]."</a>";
}
$offset = preg_replace('/UTC\+?/i', '', $opts->timezone);
if(empty($offset)) $offset = 0;
// Format query url
$search_specific_url = "./results.php?q=".urlencode($results['search_specific'][0])."&t=".$search->type."&a=".$opts->hash;
$specific_result = "Or instead search for <a href=\"".$search_specific_url."\">".$results['search_specific'][0]."</a>".$specific_result2.".";
if(is_null($timestamp) || !is_numeric($timestamp)) $timestamp = time();
unset($search_specific_url, $search_specific_url2, $specific_result2);
$hours = (int) $offset;
$minutes = ($offset - $hours);
return $specific_result;
$sign = ($offset < 0) ? '-' : '+';
$abs_hour = abs($hours);
$abs_mins = abs($minutes * 60);
$datetime = date_create('@'.$timestamp);
$datetime->setTimezone(new DateTimeZone(sprintf('%s%02d:%02d', $sign, $abs_hour, $abs_mins)));
return $datetime->format($format);
}
/*--------------------------------------
// Detect social media results
--------------------------------------*/
function detect_social_media($string) {
$string = strtolower($string);
// (Some) Based on regexes from https://github.com/lorey/social-media-profiles-regexs
$social_media = array(
'/(?:facebook|fb)\.com\/([A-z0-9_\-\.]+)\/?/',
'/(?:instagram\.com|instagr\.am)\/([A-Za-z0-9_])/',
'/twitter\.com\/@?([A-z0-9_]+)(\/status\/[0-9]+)?\/?/',
'/x\.com\/@?([A-z0-9_]+)(\/status\/[0-9]+)?\/?/',
'/reddit\.com\/(u|r)?(ser)?\/([A-z0-9\-\_]*)\/?/',
'/snapchat\.com\/add\/([A-z0-9\.\_\-]+)\/?/',
'/tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video)\/|\?shareId=|\&item_id=)(\d+))|\w+)/',
'/linkedin\.com\/(company|school)\/([A-z0-9-À-ÿ\.]+)\/?/',
'/linkedin\.com\/feed\/update\/urn:li:activity:([0-9]+)\/?/',
'/linkedin\.com\/in\/([\w\-\_À-ÿ%]+)\/?/',
'/youtube\.com\/c?(hannel)?\/([A-z0-9-\_]+)\/?/',
'/youtube\.com\/u?(ser)?\/([A-z0-9]+)\/?/',
'/youtube\.com\/(watch\?v=|embed\/|youtu\.be\/)([A-z0-9\-\_]+)/'
);
preg_replace($social_media, '*', $string, -1 , $count);
return ($count > 0) ? true : false;
}
/*--------------------------------------
@ -450,7 +509,7 @@ function search_sources($results) {
$sources = replace_last_comma(implode(', ', $sources));
$sources = 'Includes '.$sources.'.';
return $sources;
}
@ -467,7 +526,7 @@ function search_formatted_url($url) {
if(array_key_exists('query', $url)) {
$formatted_url .= ' &rsaquo; '.urldecode(str_replace('&', ' &rsaquo; ', str_replace('=', ':', str_replace('%20', ' ', trim($url['query'])))));
}
return $formatted_url;
}
@ -478,22 +537,22 @@ function search_pagination($search, $opts, $number_of_results) {
$number_of_pages = ceil($number_of_results / $opts->search_results_per_page);
$pagination = "";
if($search->page > 1) {
$prev = $search->page - 1;
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".urlencode($search->query)."&t=".$search->type."&a=".$opts->hash."&p=".$prev."\" title=\"Previous page\"><span class=\"arrow-left\"></span></a> ";
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".$search->query."&t=".$search->type."&a=".$opts->hash."&p=".$prev."\" title=\"Previous page\"><span class=\"arrow-left\"></span></a> ";
}
for($page = 1; $page <= $number_of_pages; $page++) {
$class = ($search->page == $page) ? "current" : "";
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".urlencode($search->query)."&t=".$search->type."&a=".$opts->hash."&p=".$page."\" class=\"".$class."\" title=\"To page ".$page."\">".$page."</a> ";
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".$search->query."&t=".$search->type."&a=".$opts->hash."&p=".$page."\" class=\"".$class."\" title=\"To page ".$page."\">".$page."</a> ";
}
if($search->page < $number_of_pages) {
$next = $search->page + 1;
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".urlencode($search->query)."&t=".$search->type."&a=".$opts->hash."&p=".$next."\" title=\"Next page\"><span class=\"arrow-right\"></span></a> ";
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".$search->query."&t=".$search->type."&a=".$opts->hash."&p=".$next."\" title=\"Next page\"><span class=\"arrow-right\"></span></a> ";
}
return $pagination;
}
@ -519,31 +578,6 @@ function human_filesize($bytes, $dec = 2) {
return sprintf("%.{$dec}f ", $bytes / pow(1024, $factor)) . @$size[$factor];
}
/*--------------------------------------
// Output and format dates in local time
--------------------------------------*/
function the_date($format, $timestamp = null) {
global $opts;
$offset = preg_replace('/UTC\+?/i', '', $opts->timezone);
if(empty($offset)) $offset = 0;
if(is_null($timestamp) || !is_numeric($timestamp)) $timestamp = time();
$hours = (int) $offset;
$minutes = ($offset - $hours);
$sign = ($offset < 0) ? '-' : '+';
$abs_hour = abs($hours);
$abs_mins = abs($minutes * 60);
$datetime = date_create('@'.$timestamp);
$datetime->setTimezone(new DateTimeZone(sprintf('%s%02d:%02d', $sign, $abs_hour, $abs_mins)));
return $datetime->format($format);
}
/*--------------------------------------
// Turn a string size (600 MB) into bytes (int)
--------------------------------------*/
@ -572,7 +606,7 @@ function filesize_to_bytes($num) {
} else {
$num = $num;
}
return intval($num);
}
@ -596,4 +630,4 @@ function string_generator($length, $separator) {
return implode($password);
}
?>
?>

View file

@ -12,7 +12,7 @@ $opts = load_opts();
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
---------------------------------------------------------------------------------------
* Includes:
@ -27,7 +27,7 @@ if(verify_hash('on', $opts->hash, $opts->user_auth)) {
--------------------------------------*/
global $current_version;
$version_file = ABSPATH.'cache/version.data';
if(!is_file($version_file)) {
// Create update cache file if it doesn't exist
$version = array('current' => $current_version, 'latest' => '0.0', 'checked' => 0, 'url' => '');
@ -39,20 +39,20 @@ if(verify_hash('on', $opts->hash, $opts->user_auth)) {
// Update check, every week
if($version['checked'] < time() - 604800) {
$response = do_curl_request(
$response = do_curl_request(
'https://api.github.com/repos/adegans/goosle/releases/latest', // (string) Where?
array('Accept: application/json, */*;q=0.7', 'User-Agent: goosle/'.$current_version.';'), // (array) User agent + Headers
'get', // (string) post/get
null // (assoc array|null) Post body
);
$json_response = json_decode($response, true);
// Got a response? Store it!
if(!empty($json_response)) {
// Update version info
$version = array('current' => $current_version, 'latest' => $json_response['tag_name'], 'checked' => time(), 'url' => $json_response['html_url']);
file_put_contents($version_file, serialize($version));
echo "<p>- Checked for updates and update cache updated!</p>";
}
}
@ -62,20 +62,20 @@ if(verify_hash('on', $opts->hash, $opts->user_auth)) {
--------------------------------------*/
if($opts->cache_type == 'file') {
delete_cached_results($opts->cache_time);
echo "<p>- Expired file cache results deleted!</p>";
}
/*--------------------------------------
// Renew the Openverse access token
--------------------------------------*/
if($opts->enable_image_search == 'on' && $opts->enable_openverse == 'on') {
if($opts->enable_image_search == 'on' && $opts->image['openverse'] == 'on') {
$token_file = ABSPATH.'cache/token.data';
if(is_file($token_file)) {
$tokens = unserialize(file_get_contents($token_file));
$registration = $tokens['openverse'];
// Is the token expired?
if($registration['expires'] < time()) {
$response = do_curl_request(
@ -85,16 +85,16 @@ if(verify_hash('on', $opts->hash, $opts->user_auth)) {
array('grant_type' => 'client_credentials', 'client_id' => $registration['client_id'], 'client_secret' => $registration['client_secret']) // (assoc array) Post body
);
$json_response = json_decode($response, true);
// Got a response
if(!empty($json_response)) {
// Got some data?
if(array_key_exists('access_token', $json_response)) {
$json_response['expires_in'] = time() + ($json_response['expires_in'] - 3600);
oauth_store_token($token_file, 'openverse', array('client_id' => $registration['client_id'], 'client_secret' => $registration['client_secret'], 'access_token' => $json_response['access_token'], 'expires' => $json_response['expires_in']));
echo "<p>- New Openverse token stored!</p>";
}
}
@ -105,7 +105,7 @@ if(verify_hash('on', $opts->hash, $opts->user_auth)) {
echo "<p><strong>Are there no errors on this page? We're done, you can close the tab/browser.</strong></p>";
} else {
echo "<p>!! Unauthorized !!</p>";
}
}
exit;
?>
?>

120
help.php
View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
@ -21,7 +21,7 @@ $search = load_search();
<!DOCTYPE html>
<html lang="en">
<head>
<title>Goosle Search Help</title>
<title>Goosle Search | How to use Goosle</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
@ -30,7 +30,7 @@ $search = load_search();
<meta name="description" content="Learn how to use Goosle, the best meta search engine!" />
<meta property="og:site_name" content="Goosle Search" />
<meta property="og:title" content="Goosle Search Help" />
<meta property="og:title" content="How to use Goosle" />
<meta property="og:description" content="Learn how to use Goosle, the best meta search engine!" />
<meta property="og:url" content="<?php echo get_base_url($opts->siteurl); ?>/help.php" />
<meta property="og:image" content="<?php echo get_base_url($opts->siteurl); ?>/assets/images/goosle.webp" />
@ -49,15 +49,17 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
?>
<div class="header">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a href="./?a=<?php echo $opts->hash; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->query) > 0) ? htmlspecialchars($search->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<h1 class="logo"><a href="./?a=<?php echo $opts->hash; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->nice_query) > 0) ? htmlspecialchars($search->nice_query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $search->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->user_auth; ?>">
</form>
<div class="navigation">
<?php if($opts->enable_web_search == 'on') { ?>
<a class="<?php echo ($search->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=0">Search</a>
<?php } ?>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($search->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=1" >Images</a>
@ -72,68 +74,75 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php } ?>
</div>
</div>
<div class="content">
<h2>How to use Goosle</h2>
<p>Goosle tries to provide you with the right search results where-ever they may come from. An easy to use UI and no clutter go a long way in providing a pleasuring search experience. You will not find any unnessesary features or complex settings in Goosle. After-all, navigating the internet is hard and frustrating enough. Search engines should make that more easy, not harder!</p>
<p> Goosle has an easy to use UI, free of clutter and distractions. Hopefully this provides a pleasurable search experience. You will not find any unnessesary features or complex settings in Goosle. After-all, navigating the internet is hard and frustrating enough. Search engines should make that more easy, not harder!</p>
<p>All external links <em>always</em> open in a new tab. That way you never loose your current search results. And to make search results more useful Goosle tries to format them in a neat and clean way so they're easy to read and use.</p>
<p>Goosle is created by <a href="https://www.arnan.me/" target="_blank">Arnan de Gans</a> with the intent to make search more productive and fun.</p>
<h3>Result ranking</h3>
<p>To try and provide the best results first. Goosle has a simple algorithm to rank results for Web and Image search. It works a little like a scoring system. A result with more points gets a higher ranking.</p>
<p>If a website or image is found through multiple search engines it will score higher. Also the amount of matching words in the title and SEO description and a few other bits and bops from the results are considered.</p>
<p>Goosle tries to provide you with search results in the right order no matter which search engine provides them. To try and provide the best results first Goosle has a basic algorithm to rank results.</p>
<?php if($opts->enable_web_search == 'on' || $opts->enable_image_search == 'on') { ?>
<p>For Web and Image search. If a website or image is found through multiple search engines it will rank higher. Also the amount of matching words in the title and SEO description are considered.</p>
<?php } ?>
<?php if($opts->enable_news_search == 'on') { ?>
<p>News search is ranked by your keywords and how many times a certain link is found, but also by publish date. Newer results rank higher.</p>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<p>Magnet results are sorted by most seeders (eg: availability of the download).</p>
<?php } ?>
<h3>Safe search</h3>
<p>Search defaults to Moderate Safe mode. To override the safe mode, prefix your search with <strong>safe:on</strong> or <strong>safe:off</strong> (example: <strong>safe:off geese gone wild</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 workspaces or minors.</p>
<?php if($opts->show_nsfw_magnets == 'off') { ?>
<p>The Not Suitable For Work (NSFW) filter for Magnet results is enabled. This is an attempt to hide adult content from results. Some search engines have categories that can be filtered out. Others rely on keyword matches. Goosle has an extensive list of 'dirty' keywords to try and find adult content and then ignore it. To override the setting use the <strong>safe:off</strong>, <strong>xxx</strong> or <strong>porn</strong> prefix.<br />
For example: Search for <strong>xxx goose on goose action</strong> or <strong>safe:off dirty geese</strong> to include adult content in the results.</p>
<p>The Not Suitable For Work (NSFW) filter for Magnet results is enabled. This is an attempt to hide adult content from results. Some search engines have categories that can be filtered out. Others rely on keyword matches. Goosle has an extensive list of 'dirty' keywords to try and find adult content and then ignore it. To override the setting use the <strong>safe:off</strong> or <strong>nsfw</strong> prefix.<br />
For example: Search for <strong>nsfw goose on goose action</strong> or <strong>safe:off dirty geese</strong> to include adult content in the results.</p>
<?php } ?>
<h2>Web search</h2>
<?php if($opts->enable_web_search == 'on') { ?>
<h2>Web search</h2>
<p>Goosle Web Search gathers links through search engines and search API and shows them in a neat and organised results page. Results are ranked by relevance to your current search.</p>
<h3>Special Searches</h3>
<?php if($opts->special['currency'] == 'on') { ?>
<h4>Currency converter</h4>
<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 Goosle will search for it, but also a local conversion is done in a highlighted result.</p>
<?php } ?>
<?php if($opts->special['definition'] == 'on') { ?>
<h4>Word Definition</h4>
<p>Look up the meaning of single words. Prefix the word you want to look up with <strong>define</strong>, <strong>def</strong> or <strong>meaning</strong>.<br />
For example: Searching for <strong>define goose</strong> will do a web search for 'goose' but will also show a dictionary definition highlighted above the search results.</p>
<?php } ?>
<?php if($opts->special['ipaddress'] == 'on') { ?>
<h4>IP Address lookup</h4>
<p>Search for <strong>ip</strong>, <strong>myip</strong> or <strong>ipaddress</strong> to look up your IP Address.<br />
Goosle knows your IP Address but the searches you do via Goosle will hide your IP address from the target sites such as Google or Limetorrents. You can see and verify the difference with this tool.</p>
<?php } ?>
<?php if($opts->special['phpnet'] == 'on') { ?>
<h4>PHP.net Search</h4>
<p>Prefix your search with <strong>php</strong> to search on php.net for a PHP function.<br />
For example: Searching for <strong>php in_array</strong> or <strong>php trim</strong> will show you a brief description, compatible PHP versions and the basic syntax for that function.</p>
<?php } ?>
<?php if($opts->special['wordpress'] == 'on') { ?>
<h4>WordPress documentation Search</h4>
<p>Prefix your search with <strong>wordpress</strong> or <strong>wp</strong> to search on wordpress.org for a WordPress function. You can also search for hooks or filters by adding 'hook' as the 2nd keyword.<br />
<?php if($opts->special['currency'] == 'on') { ?>
<h4>Currency converter</h4>
<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 Goosle will search for it, but also a local conversion is done in a highlighted result.</p>
<?php } ?>
<?php if($opts->special['definition'] == 'on') { ?>
<h4>Word Definition</h4>
<p>Look up the meaning of single words. Prefix the word you want to look up with <strong>define</strong>, <strong>def</strong> or <strong>meaning</strong>.<br />
For example: Searching for <strong>define goose</strong> will do a web search for 'goose' but will also show a dictionary definition highlighted above the search results.</p>
<?php } ?>
<?php if($opts->special['ipaddress'] == 'on') { ?>
<h4>IP Address lookup</h4>
<p>Search for <strong>ip</strong>, <strong>myip</strong> or <strong>ipaddress</strong> to look up your IP Address.<br />
Goosle knows your IP Address but the searches you do via Goosle will hide your IP address from the target sites such as Google or Limetorrents. You can see and verify the difference with this tool.</p>
<?php } ?>
<?php if($opts->special['phpnet'] == 'on') { ?>
<h4>PHP.net Search</h4>
<p>Prefix your search with <strong>php</strong> to search on php.net for a PHP function.<br />
For example: Searching for <strong>php in_array</strong> or <strong>php trim</strong> will show you a brief description, compatible PHP versions and the basic syntax for that function.</p>
<?php } ?>
<?php if($opts->special['wordpress'] == 'on') { ?>
<h4>WordPress documentation Search</h4>
<p>Prefix your search with <strong>wordpress</strong> or <strong>wp</strong> to search on wordpress.org for a WordPress function. You can also search for hooks or filters by adding 'hook' as the 2nd keyword.<br />
For example: Searching for <strong>wordpress the_content</strong> or <strong>wp hook admin_init</strong> will show you a brief description and the basic syntax for that function or hook/filter.</p>
<?php } ?>
<?php } ?>
<p><em><strong>Note:</strong> Special Searches do not work for image, news and magnet search.</em></p>
<?php if($opts->enable_image_search == 'on') { ?>
<h2>Image Search</h2>
<p>The number of results is not limited but typically yields about 60-100 images. If you've enabled Openverse and Qwant this number in creases a lot, optimally up-to about 150 images.</p>
<p>Goosle Image Search links directly to the web page where the image is displayed, but also tries to link to the actual image itself.</p>
<p>You can search for images in a general size by adding <strong>size:small</strong>, <strong>size:medium</strong>, <strong>size:large</strong> or <strong>size:xlarge</strong> to the beginning of your search query (example: <strong>size:small huge goose</strong>).</p>
<p>The result counts for may seem off, for example you get 50 results with 20 from Qwant Images and 60 from Yahoo! Images. Logically this should mean you should see 80 results. However, this simply means that 30 results were found on both search engines and were merged, resulting in 50 results.</p>
<?php } ?>
<?php if($opts->enable_news_search == 'on') { ?>
<h2>News search</h2>
<p>Look for current and recent news through News Search. Search for any topic and you'll find news from the last 30 days. Search is loosely ranked by post date. Newer news ranks higher.<p>
@ -141,10 +150,9 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php if($opts->enable_magnet_search == 'on') { ?>
<h2>Magnet Search</h2>
<p>Magnet Search provides Magnet links, these are special links to download content from the internet. Things like Movies, TV-Shows, EBooks, Music, Games, Software and more. You'll need a Bittorrent client that accepts Magnet links to download the search results.</p>
<p>Magnet Search provides Magnet links, these are special links from Torrent sites to download content from the internet. Things like Movies, TV-Shows, EBooks, Music, Games, Software and more. You'll need a Bittorrent client that accepts Magnet links to download the search results.</p>
<p>There are many <a href="./results.php?q=Torrent+clients+Magnet+links&a=<?php echo $opts->hash; ?>&t=0" target="_blank">Torrent clients that support Magnet links</a> but if you don't know which one to choose, give <a href="https://transmissionbt.com/" target="_blank" title="Transmission Bittorrent">Transmission BT</a> a go as it's easy to set up and use.</p>
<p>Goosle will try to provide useful information about the download, which includea; Seeders/Leechers, A link to the torrent page, Download Category, Release year. But may also include the Movie quality (720p, 4K etc.), Movie Runtime and the Download Size along with some other bits and bops if available. Not every website makes this available and all results take a best effort approach.</p>
<p>Goosle will try to provide useful information about the download, which includes; Seeders, Leechers, A link to the torrent page, Download Category and Release year. Extra information may also include the Movie quality (720p, 4K etc.), Movie Runtime and the Download Size along with some other bits and bops if available. Not every website makes this available and all results take a best effort approach.</p>
<h3>Searching for TV Shows</h3>
<p>To do a specific search on The Pirate Bay and EZTV you 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>
@ -179,12 +187,12 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<h2>Default search engine</h2>
<p>In some browsers you can add a custom search engine. To do so follow the browsers instruction and use the following link: <strong>https://example.com/results.php?q=%s</strong>.</p>
<p>Or if you use the Auth Hash as a password add the <strong>a</strong> argument, like so: <strong>https://example.com/results.php?a=YOUR_HASH&q=%s</strong>. Obviously replace example.com with your actual goosle addesss.</p>
<p>Most browsers will instruct you to add <strong>%s</strong> for the search query as shown in the examples. If your browser has a different value for this simply replace %s with what your browser requires.
<h2>Colorschemes</h2>
<p>Goose comes with several colorschemes, configurable through the config.php file.</p>
<h3>Available colorschemes are:</h3>
<ol>
<li>"default" A dark headers and main backgrounds with light search results.</li>
@ -192,7 +200,7 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<li>"dark" More dark elements, some apps would call this dark mode.</li>
<li>"auto" Let the browser decide what to use. This is typically linked to the darkmode setting of your device.</li>
</ol>
<h4>Acknowledgements:</h4>
<p><small>All icons are borrowed from the IconFinder <a href="https://www.iconfinder.com/search/icons?family=unicons-line" target="_blank">Unicons Set</a>.<br />
The Goose icon is borrowed from the Flaticon <a href="https://www.flaticon.com/packs/farm-19" target="_blank">Farm pack</a>.<br />
@ -214,4 +222,4 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php } ?>
</body>
</html>
</html>

View file

@ -1,4 +1,4 @@
<?php
<?php
/* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works.
*
@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
@ -48,13 +48,15 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<div class="content">
<h1><span class="goosle-g">G</span>oosle</h1>
<form action="results.php" method="get" autocomplete="off">
<input tabindex="10" type="search" class="search-field" name="q" required autofocus />
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>
<div class="search-buttons">
<?php if($opts->enable_web_search == 'on') { ?>
<button tabindex="20" name="t" value="0" type="submit" class="web-search">Web search</button>
<?php } ?>
<?php if($opts->enable_image_search == 'on') { ?>
<button tabindex="40" name="t" value="1" type="submit" class="image-search">Image search</button>
@ -90,4 +92,4 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php } ?>
</body>
</html>
</html>

View file

@ -4,7 +4,7 @@
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 webservers.
If you're looking for more varied results that are not laced with AI results and other non-features most people do not care for. Or if you're simply looking for traditional results from more than one search engine, Goosle has your back! Goosle searches on several search engine at the same time and shows you the most relevant results through a neat, clean interface. Goosle has **no** ads or sponsored results, **no** distractions, **no** trackers, **no** cookies and **no** bloated libraries, frameworks, dependencies or other things that slow you down.
If you're looking for more varied results that are not laced with AI results and other non-features most people do not care for. Or if you're simply looking for traditional results from more than one search engine, Goosle has your back! Goosle searches on several search engine at the same time and shows you the most relevant results through a neat, clean interface. Goosle has **no** ads or sponsored results, **no** distractions, **no** trackers, **no** cookies and **no** bloated libraries, frameworks, dependencies or other things that slow you down.
Goosle does Image and News search. Collecting information from various sources and also shown in a simple easy to use manner.
@ -19,7 +19,7 @@ After-all, finding things should be easy and not turn into a chore.
## Features
- Works on **any** hosting package that does PHP7.4 or newer
- Search results from DuckDuckGo, Google, Qwant, Brave, Wikipedia
- Image search through Yahoo! Images, Qwant and Openverse
- Image search through Yahoo! Images, Qwant, Pixabay and Openverse
- Recent news via Qwant news, Yahoo! News, Brave and Hackernews
- Search for magnet links on popular Torrent sites
- Algorithm for ranking search results for relevancy
@ -72,18 +72,20 @@ Developed on Apache with PHP8.2.
4. Load Goosle in your browser. If you've enabled the access hash don't forget to add *?a=YOUR_HASH* to the url.
5. Enjoy your updated search experience!
Take a look at the [changelog](changelog.md) for every update here. \
## Setting up a Cronjob / background task
For a number of background tasks like clearing up the file cache and/or renewing your Openverse access token you need to set up a cronjob. \
Execute this cronjob a couple of times per day, recommended is every 8 hours.
Without it, Openverse access will expire and you have to generate a new key every few hours.
Without it, Openverse access will expire and you have to generate a new key every few hours. \
For low traffic setups or if you do not use Openverse a longer interval of once a day is fine.
The access hash is always required as an access token, don't forget to include ?a=YOUR_HASH to the url.
Cron jobs are commonly set up from your hosting dashboard, or through something like DirectAdmin, cPanel or WHM.
The access hash is always required as an access token, don't forget to include ?a=YOUR_HASH to the url. \
Cron jobs are commonly set up from your hosting dashboard, or through something like DirectAdmin, cPanel or WHM. \
Ask your hosting provider where to find the Cron job scheduler or have them set it up for you if you don't see it.
You can also use something like [cron-job.org](https://cron-job.org/) to trigger the background task remotely.
You can also use something like [cron-job.org](https://cron-job.org/) to trigger the background task remotely. \
To test, you can also load the url in your browser and trigger the script that way. Look for the onscreen prompts to see what routines are executed.
### Usage examples
@ -99,29 +101,44 @@ Example for every midnight \
Why a few minutes past the hour? Because most people run stuff exactly on the hour or some other predictable interval like 15 or 30 minutes. Running things a few minutes later spreads server load.
## Authorizing access to the Openverse search API
This is required to use Openverse Image Search.
In your browser navigate to your goosle setup and add /functions/oauth.php to the url (ex. example.com/functions/oauth.php or example.com/functions/oauth.php?a=YOUR_HASH). \
Follow the onscreen prompts to get an authorization token to use Openverse.
OpenVerse image search provides (mostly) royalty free images. \
Millions of high quality photos from photographers from all over the world. \
If you're into high quality photo backgrounds, need images for blogs and articles or just like to look at high-res anything, then Openverse is a useful engine to use.
At the end, please save the Client ID and Client Secret somewhere on your computer, in a note or something. Should the token file that Goosle creates get lost you'll need these values to continue using Openverse.
To use Openverse Image Search you'll need to register Goosle for an oAUTH access token.
Goosle includes a oAuth routine to easily register for an access token. \
- In your browser navigate to your goosle setup and add /functions/oauth-openverse.php to the url (ex. example.com/functions/oauth-openverse.php or example.com/functions/oauth-openverse.php?a=YOUR_HASH).
- Follow the onscreen prompts to get an authorization token to use Openverse.
- When prompted save the Client ID and Client Secret somewhere on your computer, in a note or something. Should the token file that Goosle creates get lost you'll need these strings to continue using Openverse.
- An email from Openverse will arrive within a few minutes with a confirmation link to finalize the set up.
- Once activated, enable openverse in your config.php and you're all set!
This procedure generates an access token which is stored in /cache/token.data, this token expires every 12 hours. Yeah, annoying! \
To automatically renew the token you can set up the Goosle cronjob as described elsewhere in this readme.
### Notes
## API access to the Pixabay search API
Pixabay is a high quality photo and illustration database with (generally) royalty-free images. \
Pixabay has a database of hundreds of thousands of images provided by Photographers from all over the world. \
If you're a content creator who regularly need images for blogs and articles or just like to look at high-res photography, Pixabay is for you.
To get image results from Pixabay you'll need a free account to get a free API key. \
Register an account here: [https://pixabay.com](https://pixabay.com) (Click the Join button in the top right)
Once registered and logged in, you can find your API key in the Documentation here: [https://pixabay.com/api/docs/](https://pixabay.com/api/docs/), look for the first parameter specification (looks like a list), the Key will be highlighted in green at the top of it. Copy this key to your config.php into the pixabay_api_key option.
## Support
You can post your questions on Github Discussions or say hi on [Mastodon](https://mas.to/@arnan) or through my [website](https://www.arnan.me).
## Notes
- When using file caching you should set up a cronjob to execute goosle-cron.php every few hours. This deletes 'old' results.
- When you use Openverse for your image searches you should set up a cron job to execute goosle-cron.php every 11 hours or less. This will automagically renew the access token.
- When you use Openverse for your image searches you should set up a cron job to execute goosle-cron.php every 11 hours or so. This will automagically renew the access token.
- If you want update notifications in the footer of Goosle set up the cron job so Goosle can ping Github weekly to see what's new.
- The .htaccess file has a redirect to force HTTPS, catch 404 errors with a redirect as well as browser caching rules ready to go.
- The robots.txt has a rule to tell all crawlers to not crawl Goosle. But keep in mind that not every crawler obeys this file.
- The access hash is NOT meant as a super secure measure and only works for surface level prying eyes.
- Results provided by Openverse and Pixabay are simplistic keyword matches which are not necessarily accurately sorted by relevancy.
Have fun finding things! And tell your friends!
## Support
Goosle comes with limited support. \
You can post your questions on Github Discussions or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnandegans).
### Known "issues"
## Known "issues"
- Duckduckgo sometimes returns a 202 header and no results. I'm not sure what causes that but suspect it's something to do with quotas or a service limitation on their end.
- Some crawlers for Magnet searches may return empty results. These are likely quota limits on their end.

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
@ -19,21 +19,24 @@ require ABSPATH.'functions/search_engine.php';
$opts = load_opts();
$search = load_search();
$start_time = microtime(true);
// SEO description
$description = (strlen($search->nice_query) > 0) ? "Check out these Goosle search results about: '".urldecode($search->nice_query)."'." : "Check out these Goosle search results!";
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Goosle Search Results</title>
<title>Goosle Search | Results</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<meta name="robots" content="noodp,noydir" />
<meta name="referrer" content="no-referrer"/>
<meta name="description" content="Check out these Goosle search results!" />
<meta name="description" content="<?php echo $description; ?>" />
<meta property="og:site_name" content="Goosle Search" />
<meta property="og:title" content="The best meta search engine" />
<meta property="og:description" content="Check out these Goosle search results!" />
<meta property="og:description" content="<?php echo $description; ?>" />
<meta property="og:url" content="<?php echo get_base_url($opts->siteurl); ?>/results.php" />
<meta property="og:image" content="<?php echo get_base_url($opts->siteurl); ?>/assets/images/goosle.webp" />
<meta property="og:type" content="website" />
@ -52,15 +55,17 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth, $search->share))
?>
<div class="header">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a href="./?a=<?php echo $opts->hash; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->query) > 0) ? htmlspecialchars($search->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<h1 class="logo"><a href="./?a=<?php echo $opts->hash; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->nice_query) > 0) ? htmlspecialchars($search->nice_query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $search->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->user_auth; ?>">
</form>
<div class="navigation">
<?php if($opts->enable_web_search == 'on') { ?>
<a class="<?php echo ($search->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=0">Search</a>
<?php } ?>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($search->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=1" >Images</a>
@ -139,4 +144,4 @@ if(!empty($search->query)) {
<?php } ?>
</body>
</html>
</html>

View file

@ -6,7 +6,7 @@
* 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
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
@ -22,7 +22,7 @@ $stats = load_stats();
<!DOCTYPE html>
<html lang="en">
<head>
<title>Goosle Search Usage Stats</title>
<title>Goosle Search | Usage Stats</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
@ -31,7 +31,7 @@ $stats = load_stats();
<meta name="description" content="How many searches did Google handle?" />
<meta property="og:site_name" content="Goosle Search" />
<meta property="og:title" content="Goosle Search Usage Stats" />
<meta property="og:title" content="Usage Stats" />
<meta property="og:description" content="How many searches did Google handle?" />
<meta property="og:url" content="<?php echo get_base_url($opts->siteurl); ?>/stats.php" />
<meta property="og:image" content="<?php echo get_base_url($opts->siteurl); ?>/assets/images/goosle.webp" />
@ -50,15 +50,17 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
?>
<div class="header">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a href="./?a=<?php echo $opts->hash; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->query) > 0) ? htmlspecialchars($search->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<h1 class="logo"><a href="./?a=<?php echo $opts->hash; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->nice_query) > 0) ? htmlspecialchars($search->nice_query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $search->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->user_auth; ?>">
</form>
<div class="navigation">
<?php if($opts->enable_web_search == 'on') { ?>
<a class="<?php echo ($search->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=0">Search</a>
<?php } ?>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($search->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=1" >Images</a>
@ -73,7 +75,7 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php } ?>
</div>
</div>
<div class="content">
<h1>Searches</h1>
<p class="text-xxl text-center"><?php echo number_format($stats['all_queries'], 0); ?></p>
@ -96,4 +98,4 @@ if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
<?php } ?>
</body>
</html>
</html>