Version 1.5

- NOTICE: config.default.php has changed, re-create your config.php!!
- [fix] No longer caches empty results
- [fix] No longer make a request if the search query is empty
- [fix] Movie highlight/box office cache now works
- [fix] Language selector for Qwant, Wikipedia and Duckduckgo
- [fix] Season and Episode filter for tv show searches
- [fix] Safe search filter now actually works
- [fix] Magnet Search category exclusion filter now actually works
- [fix] Image size filter works more reliably
- [fix] Handling of doublequotes in search queries
- [fix] Search sources now show result amounts accurately
- [fix] Old cache files are now actually deleted when expired
- [fix] Search tabs not properly centered on smaller screens
- [new] Box Office page with latest/new downloads from a few supported torrent websites
- [new] News page with the latest news from major outlets
- [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 Brave
- [new] Image results from Qwant Image API
- [new] News results from Hackernews
- [new] News results from Yahoo! News
- [new] News results from Brave News
- [new] News results from Qwant News API
- [new] Magnet results from Sukebei.nyaa.si
- [new] Special search for IP Lookups via ipify (Search for "ip" or "myip")
- [new] Safe search switch for Yahoo! Images
- [new] Image size switch for Qwant Images
- [new] Merge missing magnet meta data from duplicate results if it doesn't already exist in the matched previous result
- [new] Detect meta data for Magnet Search results such as sound and video quality.
- [tweak] Cache ttl is now in hours (was minutes)
- [tweak] Optimizations in CSS, HTML separators and more
- [tweak] Moved icons into CSS so they can be colored using colorschemes
- [tweak] Better handling of image results
- [tweak] Better handling of empty/incomplete results for all engines
- [tweak] Better handling of empty/missing meta data for all magnet engines
- [tweak] Better category detection for Limetorrent magnets
- [tweak] Raised Magnet search limit to 200 (was 50)
- [tweak] Raised Wikipedia search limit to 20 (was 10)
- [tweak] Hide magnet results with 0 seeders by default
- [tweak] Uniform array formatting for all engines
- [tweak] Consistent use of single-quotes and double-qoutes
- [tweak] File size string conversion and formatting for all image and magnet engines
- [tweak] Update checks are now done weekly(ish) via the Cron job
- [tweak] Updated .htaccess caching rules
- [removed] CSS for 320px viewport
This commit is contained in:
Arnan de Gans 2024-06-19 18:08:00 -06:00
parent 7ff643872e
commit a5740b3dea
78 changed files with 4742 additions and 2104 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/.DS_Store vendored Normal file

Binary file not shown.

BIN
assets/css/.DS_Store vendored Normal file

Binary file not shown.

2
assets/css/auto.css Normal file
View file

@ -0,0 +1,2 @@
@import "dark.css" (prefers-color-scheme: dark);
@import "default.css" (prefers-color-scheme: light);

33
assets/css/dark.css Normal file
View file

@ -0,0 +1,33 @@
:root {
/* Main colors */
--color-accent: #1fa4d1; /* Blue */
--background: #232323; /* Almost black */
--background-alt: #1f242b; /* Almost black */
--text: #eff1f7; /* Almost white */
--text-alt: #eff1f7; /* Almost white */
--border: #5f6368; /* Grey */
--border-alt: #466f82; /* Dark blue */
--button-bg: #1fa4d1; /* Blue */
--button-text: #f0f6fc; /* Almost white */
--button-hover: #466f82; /* Dark blue */
--link: #2f8ad0; /* Blue */
--link-visited: #6d59a3; /* Purple */
--link-source: #eff1f7; /* Almost white */
--meta: #999; /* Grey */
--result-special-background: #ebf3fa; /* Light blue */
/* Front page (Also used on oAUTH page) */
--startpage-border: #545a5f; /* Grey */
--startpage-border-alt: #6c747a; /* Lighter grey */
--startpage-button-bg: #2b323b; /* Blueish grey */
--startpage-button-bg-alt: #363e4a; /* Lighter blueish grey */
/* Misc */
--green: #518257; /* Green */
--red: #b30000; /* Red */
--yellow: #ffb900; /* Golden yellow */
--warning: #b37d00; /* Dark yellow */
--warning-background: #ffffb3; /* Yellow */
--error: #b30000; /* Red */
--error-background: #ffcccc; /* red */
}

33
assets/css/default.css Normal file
View file

@ -0,0 +1,33 @@
:root {
/* Main colors */
--color-accent: #1fa4d1; /* Blue */
--background: #fff; /* White */
--background-alt: #1f242b; /* Almost black */
--text: #494949; /* Dark grey */
--text-alt: #f0f6fc; /* Almost white */
--border: #5f6368; /* Grey */
--border-alt: #466f82; /* Dark blue */
--button-bg: #1fa4d1; /* Blue */
--button-text: #f0f6fc; /* Almost white */
--button-hover: #466f82; /* Dark blue */
--link: #4495d4; /* Blue */
--link-visited: #6d59a3; /* Purple */
--link-source: #3f6e35; /* Green */
--meta: #666; /* Grey */
--result-special-background: #ebf3fa; /* Light blue */
/* Front page (Also used on oAUTH page) */
--startpage-border: #545a5f; /* Grey */
--startpage-border-alt: #6c747a; /* Lighter grey */
--startpage-button-bg: #2b323b; /* Blueish grey */
--startpage-button-bg-alt: #363e4a; /* Lighter blueish grey */
/* Misc */
--green: #518257; /* Green */
--red: #c00; /* Red */
--yellow: #ffb900; /* Golden yellow */
--warning: #db9900; /* Dark yellow */
--warning-background: #ffffe0; /* Yellow */
--error: #c00; /* Red */
--error-background: #ffebe8; /* Faded red */
}

33
assets/css/light.css Normal file
View file

@ -0,0 +1,33 @@
:root {
/* Main colors */
--color-accent: #1fa4d1; /* Blue */
--background: #fff; /* White */
--background-alt: #ebf3fa; /* Light blue */
--text: #494949; /* Dark grey */
--text-alt: #494949; /* Dark grey */
--border: #5f6368; /* Grey */
--border-alt: #466f82; /* Dark blue */
--button-bg: #1fa4d1; /* Blue */
--button-text: #f0f6fc; /* Almost white */
--button-hover: #466f82; /* Dark blue */
--link: #4495d4; /* Blue */
--link-visited: #6d59a3; /* Purple */
--link-source: #3f6e35; /* Green */
--meta: #666; /* Grey */
--result-special-background: #ebf3fa; /* Light blue */
/* Front page (Also used on oAUTH page) */
--startpage-border: #545a5f; /* Grey */
--startpage-border-alt: #6c747a; /* Lighter grey */
--startpage-button-bg: #2b323b; /* Blueish grey */
--startpage-button-bg-alt: #363e4a; /* Lighter blueish grey */
/* Misc */
--green: #518257; /* Green */
--red: #c00; /* Red */
--yellow: #ffb900; /* Golden yellow */
--warning: #db9900; /* Dark yellow */
--warning-background: #ffffe0; /* Yellow */
--error: #c00; /* Red */
--error-background: #ffebe8; /* Faded red */
}

View file

@ -1,234 +1,225 @@
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
* 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.
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
body { margin: 0; padding: 0; background-color: #fff; font-family: Arial, Helvetica, sans-serif; font-size: 16px; color: #222; line-height: 1.2; }
div { margin: 0; padding: 0; border: 0; vertical-align: baseline; }
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; }
h2, h3, h4, h5, h6 { font-weight: normal; }
h2, h3, h4, h5, h6, p, ul, ol, blockquote { margin: 0; padding-top: .5em; padding-bottom: .5em; }
ol, ol > li { margin: 0; padding: 0; list-style: none; }
input, button { outline: none; }
button { cursor: pointer; }
p { font-size: 18px; color: #494949; }
a { text-decoration: none; color: #4495d4; }
small, sub, sup { padding: 5px 0; color: #666; font-size: 12px; }
sub, sup { font-style: italic; }
pre, code { word-wrap: break-word; overflow-wrap: break-word; }
a:hover { text-decoration: underline; }
input[type="text"]: invalid ~ input[type="submit"] { opacity: 0.5; pointer-events: none; }
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; -webkit-mask-image: url("data: image/svg+xml;utf8,<svg xmlns='http: //www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23777'><path d='M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/></svg>"); }
body { 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); }
div { margin:0; padding:0; border:0; vertical-align:baseline; }
h2, h3, h4, h5, h6 { margin:0; padding-top:.1em; padding-bottom:.3em; font-weight:400; }
h1 { font-size:4em; }
h2 { font-size:2em; }
h3 { font-size:1.5em; }
h4, h5, h6 { font-size:1em; }
p, ul, ol { margin:0; padding-top:.2em; padding-bottom:.5em; }
ul, ul > li { margin:0; padding:0; list-style:none; }
input, button { outline:none; }
button { cursor:pointer; }
a { text-decoration:none; color:var(--link); }
a:hover { text-decoration:underline; }
small { padding:5px 0; color:var(--meta); font-size:.8rem; }
input[type="text"]:invalid ~ input[type="submit"] { opacity:0.5; pointer-events:none; }
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance:none; -webkit-mask-image:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMy40MSwxMmw0LjMtNC4yOWExLDEsMCwxLDAtMS40Mi0xLjQyTDEyLDEwLjU5LDcuNzEsNi4yOUExLDEsMCwwLDAsNi4yOSw3LjcxTDEwLjU5LDEybC00LjMsNC4yOWExLDEsMCwwLDAsMCwxLjQyLDEsMSwwLDAsMCwxLjQyLDBMMTIsMTMuNDFsNC4yOSw0LjNhMSwxLDAsMCwwLDEuNDIsMCwxLDEsMCwwLDAsMC0xLjQyWiIgZmlsbD0iIzY1NjNmZiIvPjwvc3ZnPg=="); }
/* Page structure */
body { min-height: 100vh; display: flex; flex-direction: column; }
.header { padding-top: 16px; width: 100%; }
.content { margin: 0 158px; padding: 15px 0; }
.footer { bottom: 0; margin-top: auto; padding: 0; width: 100%; }
body { min-height:100vh; display:flex; flex-direction:column; }
.header { padding:0; width:100%; }
.header form { margin:35px 0; }
.content { margin:15px 158px; padding:0; }
.footer { box-sizing:border-box; bottom:0; margin-top:auto; padding:10px 5px; width:100%; }
/* Flex grid (Box office, footer) */
.grid-container { display:flex; flex-direction:row; }
.list-grid, .footer-grid { flex:1; width:50%; }
.list-grid:first-child, .footer-grid:first-child { margin-right:20px; }
.footer-grid:nth-child(2) { text-align:right; }
/* Start page */
.startpage { background-color: #1f242b; color: #f0f6fc; }
.startpage-search, .password-generator { text-align: center; margin-top: 10%; }
.startpage-search h1 { font-size: 4rem; }
.startpage-search .search, .password-generator .password { padding: 10px 20px; width: 600px; color: #f0f6fc; background-color: #333333; font-size: 2rem; font-family: sans-serif; border: 1px solid #3C4043; border-radius: 10px; }
.startpage-search .search[type="search"]::-webkit-search-cancel-button { background-size: 28px 28px; height: 28px; width: 28px; background-color: #f0f6fc; }
.search-buttons button { margin: 30px 20px 10px 20px; padding: 13px 10px 13px 10px; min-width: 130px; color: #f0f6fc; background-color: #333333; font-size: 1rem; border: 1px solid #3C4043; border-radius: 6px; }
.startpage-search .search:focus, .password-generator .password:focus, .search-buttons button:hover { border: 1px solid #5f6368; }
.startpage { background-color:var(--background-alt); color:var(--text-alt); }
.startpage .content { text-align:center; margin-top:10%; }
.startpage .search-field, .password-generator .password { padding:10px 20px; width:600px; color:var(--text-alt); background-color:var(--background-alt); font-size:2rem; border:1px solid var(--startpage-border); border-radius:10px; }
.startpage .search-field:focus, .password-generator .password:focus { border:1px solid var(--startpage-border-alt); }
.startpage .search-field[type="search"]::-webkit-search-cancel-button { background-size:28px 28px; height:28px; width:28px; background:var(--text-alt); }
.startpage .web-search, .startpage .image-search, .startpage .magnet-search, .startpage .box-office { display:inline-block; box-sizing:border-box; margin:30px 20px 10px 20px; padding:13px 10px; min-width:130px; min-height:48px; vertical-align:middle; text-align:center; font-size:1rem; font-weight:400; background-color:var(--startpage-button-bg); color:var(--text-alt); border:1px solid var(--startpage-border); border-radius:6px; }
.startpage .magnet-search { margin-right:0; border-radius:6px 0 0 6px; }
.startpage .box-office { margin-left:0; border-left:1px solid var(--startpage-button-bg); border-radius:0 6px 6px 0; }
.startpage .web-search:hover, .startpage .image-search:hover, .startpage .magnet-search:hover, .startpage .box-office:hover { border:1px solid var(--startpage-border-alt); background-color:var(--startpage-button-bg-alt); text-decoration:none; }
.password-generator { margin: 30px auto; padding: 0; }
.password-generator .password { margin: 10px auto; width: 300px; text-align: center; font-size: 0.8rem; }
.password-generator { margin:30px auto; padding:0; }
.password-generator .password { margin:10px auto; width:300px; text-align:center; font-size:.8rem; }
/* oAUTH page*/
.oauthpage { background-color: #1f242b; color: #f0f6fc; }
.oauth-form { text-align: center; margin-top: 20px; }
.oauth-form h1 { font-size: 4rem; }
.oauth-form p, .oauth-form small { margin-bottom: 15px; color: #f0f6fc; }
.oauth-form .field { padding: 5px 10px; width: 300px; color: #f0f6fc; background-color: #333333; font-size: 1rem; font-family: sans-serif; border: 1px solid #3C4043; border-radius: 10px; }
.oauth-buttons button { margin: 30px 20px 10px 20px; padding: 13px 10px 13px 10px; min-width: 130px; color: #f0f6fc; background-color: #333333; font-size: 1rem; border: 1px solid #3C4043; border-radius: 6px; }
.oauth-buttons button:hover { border: 1px solid #5f6368; }
/* Page header (Search results, Help, Box office) */
.header { background-color:var(--background-alt); color:var(--text-alt); border-bottom:3px solid var(--color-accent); }
.header .logo { position:absolute; margin:0 18px; font-size:2rem; }
.header .logo a, .header .logo a:hover { text-decoration:none; color:var(--text-alt); cursor:pointer; }
.header .search-field, .header .button { display:inline-block; box-sizing:border-box; vertical-align:middle; height:40px; font-size:1.2rem }
.header .search-field { margin:0 0 0 158px; padding:5px 5px 5px 15px; width:580px; color:var(--text-alt); background-color:var(--background-alt); border:1px solid var(--border); border-left:right; border-radius:10px 0 0 10px; }
.header .search-field[type="search"]::-webkit-search-cancel-button { background-size:20px 20px; height:20px; width:20px; background-color:var(--text-alt); }
.header .button { margin:0 10px 0 0; padding:5px 20px 5px 15px; color:var(--button-text); background-color:var(--button-bg); border:none; border-radius:0 10px 10px 0; }
/* Results page header */
.header { background-color: #1f242b; color: #f0f6fc; border-bottom: 2px solid #1fa4d1; }
.header .search, .header .button { position: relative; height: 40px; color: #f0f6fc; font-size: 1rem; font-weight: 400; }
.header .search { margin: 28px 0 28px 158px; padding: 5px 5px 5px 15px; width: 580px; background-color: #1f242b; border: 1px solid #5f6368; border-radius: 10px 0 0 10px; }
.header .search[type="search"]::-webkit-search-cancel-button { background-size: 20px 20px; height: 20px; width: 20px; background-color: #f0f6fc; }
.header .button { margin: 28px 10px 28px 0; padding: 5px 20px 5px 15px; background-color: #1fa4d1; border: none; border-radius: 0 10px 10px 0; }
.header .navigation { margin-left:158px; margin-bottom:8px; } /* Margin-bottom must match with padding-bottom on line 79 */
.header .navigation img { margin-right:5px; height:16px; vertical-align:middle; }
.header .navigation a { margin-right:20px; border:none; cursor:pointer; text-decoration:none; }
.header .navigation a:visited { color:var(--link); }
.header .navigation a:hover { color:var(--text-alt); }
.header .navigation .active { padding-bottom:8px; border-bottom:4px solid var(--color-accent); }
.navigation { margin-left: 158px; margin-bottom: 10px; }
.navigation img { margin-right: 5px; height: 16px; vertical-align: middle; }
.navigation a { margin-right: 20px; border: none; font-size: 1rem; cursor: pointer; text-decoration: none; }
.navigation a:hover { color: #ebf3fa; }
.navigation a: visited { color: #1fa4d1; }
.navigation .active { padding-bottom: 8px; border-bottom: 4px solid #1fa4d1; }
/* Navigation icons (https://www.iconfinder.com/search/icons?family=unicons-line) */
.navigation a.tab-search::before { content:""; display:inline-block; width:20px; height:20px; background:var(--color-accent); vertical-align:middle; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMiwyMEg1YTEsMSwwLDAsMS0xLTFWNUExLDEsMCwwLDEsNSw0aDVWN2EzLDMsMCwwLDAsMywzaDN2MWExLDEsMCwwLDAsMiwwVjlzMCwwLDAtLjA2YTEuMzEsMS4zMSwwLDAsMC0uMDYtLjI3bDAtLjA5YTEuMDcsMS4wNywwLDAsMC0uMTktLjI4aDBsLTYtNmgwYTEuMDcsMS4wNywwLDAsMC0uMjgtLjE5LjMyLjMyLDAsMCwwLS4wOSwwQS44OC44OCwwLDAsMCwxMS4wNSwySDVBMywzLDAsMCwwLDIsNVYxOWEzLDMsMCwwLDAsMywzaDdhMSwxLDAsMCwwLDAtMlpNMTIsNS40MSwxNC41OSw4SDEzYTEsMSwwLDAsMS0xLTFaTTcsOGExLDEsMCwwLDAsMCwySDhBMSwxLDAsMCwwLDgsOFpNMjEuNzEsMjAuMjlsLTEuMTctMS4xNkEzLjQ0LDMuNDQsMCwwLDAsMjAsMTVoMEEzLjQ5LDMuNDksMCwwLDAsMTQsMTcuNDlhMy40NiwzLjQ2LDAsMCwwLDUuMTMsMy4wNWwxLjE2LDEuMTdhMSwxLDAsMCwwLDEuNDIsMEExLDEsMCwwLDAsMjEuNzEsMjAuMjlabS0zLjE3LTEuNzVhMS41NCwxLjU0LDAsMCwxLTIuMTEsMEExLjUsMS41LDAsMCwxLDE2LDE3LjQ5YTEuNDYsMS40NiwwLDAsMSwuNDQtMS4wNiwxLjQ4LDEuNDgsMCwwLDEsMS0uNDNBMS40NywxLjQ3LDAsMCwxLDE5LDE3LjQ5LDEuNSwxLjUsMCwwLDEsMTguNTQsMTguNTRaTTEzLDEySDdhMSwxLDAsMCwwLDAsMmg2YTEsMSwwLDAsMCwwLTJabS0yLDZhMSwxLDAsMCwwLDAtMkg3YTEsMSwwLDAsMCwwLDJaIiBmaWxsPSIjNjU2M2ZmIi8+PC9zdmc+'); }
.navigation a.tab-image::before { content:""; display:inline-block; width:20px; height:20px; background:var(--color-accent); vertical-align:middle; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xOSwxM2ExLDEsMCwwLDAtMSwxdi4zOWwtMS40OC0xLjQ4YTIuNzksMi43OSwwLDAsMC0zLjkzLDBsLS43LjdMOS40MSwxMS4xMmEyLjg3LDIuODcsMCwwLDAtMy45MywwTDQsMTIuNjFWN0ExLDEsMCwwLDEsNSw2SDlBMSwxLDAsMCwwLDksNEg1QTMsMywwLDAsMCwyLDdWMTlhMywzLDAsMCwwLDMsM0gxN2EzLDMsMCwwLDAsMy0zVjE0QTEsMSwwLDAsMCwxOSwxM1pNNSwyMGExLDEsMCwwLDEtMS0xVjE1LjQzbDIuOS0yLjg5YS43OS43OSwwLDAsMSwxLjA5LDBsMy4xNywzLjE3LDAsMEwxNS40NSwyMFptMTMtMWExLDEsMCwwLDEtLjE4LjU0TDEzLjMxLDE1bC43LS42OWEuNzcuNzcsMCwwLDEsMS4xLDBMMTgsMTcuMjJabTMuNzEtOC43MUwyMCw4LjU3YTQuMzEsNC4zMSwwLDEsMC02LjcyLjc5LDQuMjcsNC4yNywwLDAsMCwzLDEuMjZBNC4zNCw0LjM0LDAsMCwwLDE4LjU3LDEwbDEuNzIsMS43M2ExLDEsMCwwLDAsMS40MiwwQTEsMSwwLDAsMCwyMS43MSwxMC4yOVpNMTgsOGEyLjMyLDIuMzIsMCwxLDEsMC0zLjI3QTIuMzIsMi4zMiwwLDAsMSwxOCw4WiIgZmlsbD0iIzY1NjNmZiIvPjwvc3ZnPg=='); }
.navigation a.tab-news::before { content:""; display:inline-block; width:20px; height:20px; background:var(--color-accent); vertical-align:middle; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNywxMUgxNmExLDEsMCwwLDAsMCwyaDFhMSwxLDAsMCwwLDAtMlptMCw0SDE2YTEsMSwwLDAsMCwwLDJoMWExLDEsMCwwLDAsMC0yWk0xMSw5aDZhMSwxLDAsMCwwLDAtMkgxMWExLDEsMCwwLDAsMCwyWk0yMSwzSDdBMSwxLDAsMCwwLDYsNFY3SDNBMSwxLDAsMCwwLDIsOFYxOGEzLDMsMCwwLDAsMywzSDE4YTQsNCwwLDAsMCw0LTRWNEExLDEsMCwwLDAsMjEsM1pNNiwxOGExLDEsMCwwLDEtMiwwVjlINlptMTQtMWEyLDIsMCwwLDEtMiwySDcuODJBMywzLDAsMCwwLDgsMThWNUgyMFptLTktNGgxYTEsMSwwLDAsMCwwLTJIMTFhMSwxLDAsMCwwLDAsMlptMCw0aDFhMSwxLDAsMCwwLDAtMkgxMWExLDEsMCwwLDAsMCwyWiIgZmlsbD0iIzY1NjNmZiIvPjwvc3ZnPg=='); }
.navigation a.tab-magnet::before { content:""; display:inline-block; width:20px; height:20px; background:var(--color-accent); vertical-align:middle; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0yMCw4Ljk0YTEuMzEsMS4zMSwwLDAsMC0uMDYtLjI3bDAtLjA5YTEuMDcsMS4wNywwLDAsMC0uMTktLjI4aDBsLTYtNmgwYTEuMDcsMS4wNywwLDAsMC0uMjgtLjE5bC0uMSwwQTEuMSwxLjEsMCwwLDAsMTMuMDYsMkg3QTMsMywwLDAsMCw0LDVWMTlhMywzLDAsMCwwLDMsM0gxN2EzLDMsMCwwLDAsMy0zVjlTMjAsOSwyMCw4Ljk0Wk0xNCw1LjQxLDE2LjU5LDhIMTVhMSwxLDAsMCwxLTEtMVpNMTgsMTlhMSwxLDAsMCwxLTEsMUg3YTEsMSwwLDAsMS0xLTFWNUExLDEsMCwwLDEsNyw0aDVWN2EzLDMsMCwwLDAsMywzaDNabS00LjcxLTQuNzEtLjI5LjNWMTJhMSwxLDAsMCwwLTIsMHYyLjU5bC0uMjktLjNhMSwxLDAsMCwwLTEuNDIsMS40MmwyLDJhMSwxLDAsMCwwLC4zMy4yMS45NC45NCwwLDAsMCwuNzYsMCwxLDEsMCwwLDAsLjMzLS4yMWwyLTJhMSwxLDAsMCwwLTEuNDItMS40MloiIGZpbGw9IiM2NTYzZmYiLz48L3N2Zz4='); }
/* Search results spacing */
.content .meta { padding: 10px 0 0 0; }
.content .sources { padding: 0 0 10px 0; font-size: 0.75rem; color: #666; }
.content .suggestion { padding: 15px 0; }
.content .result { margin: 0 0 25px 0; }
.content .result-special { margin: 15px 0 25px 0; padding: 10px; }
.content .result.image { margin: 0; }
/* Search results (web, image, magnet, box office) */
.resultspage .timer { margin:10px 0 0 0; }
.resultspage .sources { font-size:.8rem; color:var(--meta); }
.resultspage .result, .boxofficepage .result, .resultspage .result-special, .resultspage .result.shared, .resultspage .sources, .resultspage .suggestion { margin:0 0 25px 0; }
.resultspage .result-grid .result, .resultspage .result.image { margin:0; }
.resultspage .result-special, .resultspage .result.shared { padding:10px; }
/* Search results (web, image and magnet) */
.content .result { border: 1px solid #fefefe; border-radius: 8px; }
.content .result div.url, .content .result-special div.source { max-width: 100%; font-size: 1rem; line-height: 1.6; letter-spacing: .2px; white-space: nowrap; overflow: hidden; }
.content .result div.url a, .content .result-special div.source a { color: #3f6e35; cursor: pointer; text-decoration: none; }
.content .result div.title, .content .result-special div.title { margin-bottom: 5px; }
.content .result div.title h2 { padding: 0; position: relative; font-size: 1.46rem; letter-spacing: -.01px; }
.content .result div.title h2:hover { text-decoration: underline; }
.content .result div.title a { display: block; cursor: pointer; }
.content .result div.title a: visited { color: #6d59a3; }
.content .result div.description { line-height: 1.4; font-size: 1rem; color: #494949; }
.content .result div.engine { padding: 2px 0; font: 12px italic; color: #666; }
.content .result div.description .seeders { color: #518257; }
.content .result div.description .leechers { color: #c00; }
/* Results formatting */
div.title, div.description, div.text, div.url, div.source { word-wrap:break-word; }
.content .result-special { position: relative; background-color: #fefefe; overflow: hidden; border: 1px solid #aeaeae; border-radius: 8px; color: #222; }
.content .result-special div.title h2 { padding: 0; font-size: 1.5rem; font-weight: 600; word-wrap: break-word; color: #222; }
.content .result-special div.title h2:hover { text-decoration: none; }
.content .result-special div.title a { display: block; color: #6c00a2; cursor: pointer; }
.content .result-special div.title a: visited { color: #6d59a3; }
.content .result-special div.text, .content .result-special div.source { position: relative; font-style: normal; }
.result div.url, .result-special div.source { line-height:1.6; letter-spacing:.2px; }
.result div.url a, .result-special div.source a { cursor:pointer; text-decoration:none; color:var(--link-source); }
.result div.title h2 { position:relative; letter-spacing:-.01px; font-size:1.5rem; }
.result div.title h2:hover { text-decoration:underline; }
.result div.title a { display:block; cursor:pointer; }
.result div.title a:visited { color:var(--link-visited); }
.result div.description { line-height:1.4; }
.result div.description p { padding-top:0; padding-bottom:0; }
.result div.meta { padding:5px 0; font-size:.8rem; color:var(--meta); }
.result div.engines { padding:2px 0; font-size:.8rem; color:var(--meta); }
.result.news h2 { padding-top:0; padding-bottom:0; }
.result.news { clear:both; overflow:auto; }
/* Special results and shared magnet result */
.result.shared, .result-special { overflow:hidden; background-color:var(--result-special-background); border:1px solid var(--border-alt); border-radius:10px; }
.result.shared div.title h2, .result-special div.title h2 { padding-top:0; text-decoration:none; }
.boxofficepage .result { border:1px solid var(--result-border); border-radius:8px; }
.boxofficepage .result div.title h2 { font-size:1.2rem; }
.boxofficepage .result div.title h2:hover { text-decoration:underline; }
.boxofficepage .result div.title a { display:block; cursor:pointer; }
.boxofficepage .result div.title a:visited { color:var(--link-visited); }
/* Grids (image and magnet highlights) */
@supports (display: grid) {
.image-grid ol, .magnet-grid ol { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); grid-gap: 1rem; }
@supports (display:grid) {
.result-grid ul { display:grid; grid-template-columns:repeat(auto-fill, minmax(8rem, 1fr)); grid-gap:1rem; }
}
@supports not (display: grid) {
.image-grid ol > *, .magnet-grid ol > * { max-width: 8rem; margin-left: auto; margin-right: auto; }
.image-grid ol .result, .magnet-grid ol .result { display: inline-block; margin: .75rem; width: 12.5%; }
.image-grid ol > * + *, .magnet-grid ol > * + * { margin-top: 1rem; }
@supports not (display:grid) {
.result-grid ul > * { max-width:8rem; margin-left:auto; margin-right:auto; }
.result-grid ul .result { display:inline-block; margin:.75rem; width:12.5%; }
.result-grid ul > * + * { margin-top:1rem; }
}
/* Image results */
.image-grid { width: 100%; margin: 25px 0; }
.image-grid ol .result .image-box { position: relative; }
.image-grid ol .result .image-box::after { display: block; padding-bottom: 100%; content: ""; }
.image-grid ol .result .image-box img { position: absolute; object-fit: cover; width: 100%; height: 100%; border-radius: 10px; }
.image-grid ol .result .image-box img:hover { outline: none; border-color: #3C4043; box-shadow: 0 0 10px #3C4043; }
.image-grid ol .result span { padding: 5px 0 0 0; color: #666; font-size: 0.75rem; }
/* Grid results */
.result-grid { width:100%; margin:0 0 25px 0; }
.result-grid ul .result .result-box { position:relative; }
.result-grid ul .result.image .result-box::after, .result-grid ul .result.eztv .result-box::after { display:block; padding-bottom:100%; content:""; }
.result-grid ul .result.image .result-box img, .result-grid ul .result.eztv .result-box img { position:absolute; object-fit:cover; width:100%; height:100%; border-radius:10px; }
.result-grid ul .result.yts .result-box img { width:100%; height:100%; border-radius:10px; }
.result-grid ul .result .result-box img:hover { outline:none; border-color:var(--border); border-radius:10px; box-shadow:0 0 10px var(--border); }
/* Magnet highlights */
.magnet-grid { width: 100%; margin: 25px 0; }
.magnet-grid ol .result .magnet-box { position: relative; }
.magnet-grid ol .result .magnet-box::after { display: block; content: ""; }
.magnet-grid ol .result .magnet-box img { width: 100%; height: 100%; border-radius: 10px; }
.magnet-grid ol .result .magnet-box p { visibility: hidden; opacity: 0; position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: #1f242b; transition: opacity .1s, visibility .1s; padding: 10px; line-height: 1.4; text-align: center; font-size: 0.8rem; color: #f0f6fc; }
.magnet-grid ol .result .magnet-box a { display: block; position: relative; margin: 5px 0 5px 0; padding: 5px 20px; background-color: #1fa4d1; border: 1px solid #466f82; border-radius: 10px; color: #f0f6fc; font-weight: 800; text-align: center; }
.magnet-grid ol .result .magnet-box a:hover { text-decoration: none; }
.magnet-grid ol .result .magnet-box:hover p { visibility: visible; opacity: .90; outline: none; border-color: #3C4043; border-radius: 10px; box-shadow: 0 0 10px #3C4043; }
/* Magnet highlight/Share/Boxoffice popup */
.goosebox { display:none; position:fixed; inset:0; z-index:10000; overflow:auto; background-color:rgb(0, 0, 0, .75); }
.goosebox.open { display:block; }
.goosebox-body { margin:50px auto; padding:20px; width:50%; background:var(--background); 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; }
.goosebox-body button:hover { text-decoration:none; background-color:var(--button-hover); }
.goosebox-body .share-field, .goosebox-body .share-button { box-sizing:border-box; position:relative; padding:5px 10px; width:100%; height:40px; font-size:1rem; }
.goosebox-body .share-field { margin:10px auto 0 auto; color:var(--text); background-color:var(--background); border:1px solid var(--border-alt); border-bottom: none; border-radius:10px 10px 0 0; }
.goosebox-body .share-button { margin:0 auto 10px auto; border-radius:0 0 10px 10px; }
.goosebox-body .success, .goosebox-body .fail { font-weight:600; }
/* Misc */
.logo { position: absolute; margin: 28px 18px; }
.logo a { color: #f0f6fc; cursor: pointer; }
.no-decoration, .no-decoration:hover { text-decoration: none; }
.hide { display: none; }
.G { color: #1fa4d1; }
.warning { position: relative; overflow: hidden; margin: 20px 0; padding: 10px; color: #db9900; background-color: #ffffe0; border: 1px solid #e6db55; border-radius: 10px; }
.error { position: relative; overflow: hidden; margin: 20px 0; padding: 10px; color: #c00; background-color: #ffebe8; border: 1px solid #c00; border-radius: 10px; }
.auth-success { margin-top: 15%; font-size: 1rem; text-align: center; color: #f0f6fc; }
.auth-error { margin-top: 15%; font-size: 2rem; text-align: center; color: #f0f6fc; }
a.update { color: #c90; font-weight: bold; }
/* oAUTH page */
.oauthpage { background-color:var(--background-alt); color:var(--text-alt); }
.oauthpage .oauth-form { text-align:center; margin-top:20px; }
.oauthpage .oauth-form p, .oauth-form small { margin-bottom:15px; color:var(--text-alt); }
.oauthpage .oauth-form .field { padding:5px 10px; width:300px; color:#f0f6fc; background-color:var(--background-alt); font-size:1.2rem; border:1px solid var(--startpage-border); border-radius:10px; }
.oauthpage .oauth-buttons button { margin:30px 20px 10px 20px; padding:13px 10px; min-width:130px; color:var(--text-alt); background-color:var(--startpage-button-bg); border:1px solid var(--startpage-border); font-size:1.2rem; border-radius:6px; }
.oauthpage .oauth-buttons button:hover { border:1px solid var(--startpage-border-alt); background-color:var(--startpage-button-bg-alt); text-decoration:none; }
/* Footer */
.footer { background-color: #161616; color: #f0f6fc; border-top: 1px solid #1fa4d1; }
.footer a { color: #f0f6fc; }
.footer-left, .footer-right { display: inline-block; padding: 10px; }
.footer-right { float: right; }
.footer { background-color:var(--background-alt); color:var(--text-alt); border-top:2px solid var(--color-accent); font-size:.9rem; }
.footer a { color:var(--text-alt); }
@media only screen and (max-width: 960px) { /* tablet, landscape iPad, lo-res/smaller laptops */
/* Misc */
.goosle-g { color:var(--color-accent); }
.green { color:var(--green); }
.red { color:var(--red); }
.yellow { color:var(--yellow); }
.star { font-weight:800; }
img.help { padding:0 .5rem .5rem 0; float:left; border-radius:20px; }
.warning { position:relative; overflow:hidden; margin:20px 0; padding:10px; color:var(--warning); background-color:var(--warning-background); border:1px solid var(--warning); border-radius:10px; }
.error { position:relative; overflow:hidden; margin:20px 0; padding:10px; color:var(--error); background-color:var(--error-background); border:1px solid var(--error); border-radius:10px; }
.auth-success { margin-top:15%; text-align:center; color:var(--text-alt); }
.auth-error { margin-top:15%; font-size:2rem; text-align:center; color:var(--text-alt); }
a.update { color:var(--red); font-weight:600; }
@media only screen and (max-width:960px) { /* Tablet, landscape iPad, lo-res/smaller laptops */
/* Page structure */
.content { position: relative; margin: 0 48px; }
.footer-left, .footer-right { display: block; padding: 5px 5px 0 5px; text-align: center; }
.footer-right { float: none; padding: 0px 5px 5px 5px; }
.header form { margin:15px 0 0 0; }
.content { position:relative; margin:15px 48px; }
.footer-left, .footer-right { display:block; text-align:center; }
/* Start page */
.startpage-search { margin-top: 10%; }
.startpage-search .search { width: 80%; }
.search-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
.startpage .content { margin-top:0; }
.startpage .search-field { width:80%; }
.startpage .web-search, .startpage .image-search { display:table-row; margin:30px 0 0 0; width:80%; }
.startpage .magnet-search, .startpage .box-office { display:inline-block; margin:30px 0 0 0; width:40%; }
/* Search Results - Header */
.header { margin-left: auto; margin-right: auto; text-align: center; }
.header .search { margin: 10px 0px 28px 48px; width: 400px; }
.header .search, .header .button { margin: 10px 0px 28px 0px; }
/* Search results - Header Navigation */
.navigation { margin: 0 auto 10px auto; padding: 0; align-items: baseline; }
/* Page header (Search results, Help, Box office) */
.header { margin-left:auto; margin-right:auto; text-align:center; }
.header .logo { position:relative; display:block; margin:10px auto; float:none; font-size:1.8rem; }
.header .search-field { margin:10px 0 28px 48px; width:400px; }
.header .search-field, .header .button { margin:10px 0 28px 0; }
.header .navigation { margin:0 auto 10px auto; padding:0; align-items:baseline; }
.header .navigation a:last-child { margin-right:0; }
/* Misc */
.logo { position: relative; display: block;margin: 0 auto; float: none; padding: 10px; font-size: 1.75rem; }
/* Magnet highlight info popup */
.goosebox-body { margin:25px auto; width:75%; }
/* Box Office */
.grid-container { flex-direction:column; }
.list-grid:first-child, .footer-grid:first-child { margin-right:0; }
.list-grid { width:100%; }
.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 */
/* Page structure */
.content { position: relative; margin: 0 10px; }
.footer-left, .footer-right { display: block; padding: 5px 5px 0 5px; text-align: center; }
.footer-right { float: none; padding: 0px 5px 5px 5px; }
.header form { margin:15px 0 10px 0; }
.content { position:relative; margin:10px 10px; }
/* Start page */
.startpage-search { margin-top: 10%; }
.startpage-search .search { width: 80%; }
.search-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
/* Page header (Search results, Help, Box office) */
.header .search-field, .header .button { margin:0 0 10px 0; width:80%; border-radius:25px; }
/* Search Results - Header */
.header { margin-left: auto; margin-right: auto; text-align: center; }
.header .search, .header .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation { margin: 0 auto 10px auto; padding: 0; align-items: baseline; }
/* Grids (image and magnet highlights) */
@supports (display:grid) {
.result-grid ul { grid-gap:0.75rem; }
}
/* Magnet highlight info popup */
.goosebox-body { margin:15px auto; width:90%; }
/* Misc */
.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 1.75rem; }
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. */
/* Page structure */
.content { position: relative; margin: 0 10px; }
.footer-left, .footer-right { display: block; padding: 5px 5px 0 5px; text-align: center; }
.footer-right { float: none; padding: 0px 5px 5px 5px; }
@media only screen and (max-width:480px) { /* Portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */
/* Start page */
.startpage-search { margin-top: 10%; }
.startpage-search h1 { font-size: 2.5rem; }
.startpage-search .search { width: 80%; }
.search-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header { margin-left: auto; margin-right: auto; text-align: center; }
.header .search, .header .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation { margin: 0 auto 10px auto; padding: 0; align-items: baseline; }
/* Misc */
.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 1.75rem; }
}
@media only screen and (max-width: 320px) { /* smartphones, iPhone, portrait 480x320 phones, split screen devices */
/* Page structure */
.content { position: relative; margin: 0 10px; }
.footer-left, .footer-right { display: block; padding: 5px 5px 0 5px; text-align: center; }
.footer-right { float: none; padding: 0px 5px 5px 5px; }
/* Start page */
.startpage-search { margin-top: 40px; }
.startpage-search h1 { font-size: 2.5rem; }
.startpage-search .search { width: 80%; }
.search-buttons button { display: table-row; margin: 20px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header { margin-left: auto; margin-right: auto; text-align: center; }
.header .search, .header .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation { margin: 0 auto 10px auto; padding: 0; align-items: baseline; }
/* Misc */
.logo { position: relative; float: none; display: block; margin: 0 auto; padding: 10px; font-size: 1.75rem; }
.startpage h1 { font-size:2.5rem; }
}

BIN
assets/images/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,004 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/js/.DS_Store vendored Normal file

Binary file not shown.

62
assets/js/goose.js Normal file
View file

@ -0,0 +1,62 @@
/* ------------------------------------------------------------------------------------
* 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.
------------------------------------------------------------------------------------ */
/*--------------------------------------
Share magnet results to the clipboard
--------------------------------------*/
function clipboard(id) {
// Get the text field element and set up a response
var share_string = document.getElementById(id);
var success, message;
// Select the text field
share_string.select();
share_string.setSelectionRange(0, share_string.value.length);
// Copy the text inside the text field to the clipboard
success = navigator.clipboard.writeText(share_string.value);
// Visual response
if(success) {
message = "<span class=\"success green\">Link copied to the clipboard.</span><br />Paste the link anywhere you want with ctrl+v (or cmd+v on macOS).<br />Or use the paste function in your app."
} else {
message = "<span class=\"fail red\">Copying is not supported or got blocked.</span><br />Copy the link by pressing ctrl+c (or cmd+c on macOS).<br />Or use the select and copy functions from the context menu."
}
response = document.getElementById(id + '-response');
response.innerHTML = message;
// Set up a timer to remove the visual response after a few seconds
setTimeout(function() {
response.innerHTML = "";
}, 10000);
}
/*--------------------------------------
Handle magnet share, highlight and box office popups
--------------------------------------*/
function openpopup(id) {
document.getElementById(id).classList.add('open');
document.body.classList.add('goosebox-open');
}
function closepopup() {
document.querySelector('.goosebox.open').classList.remove('open');
document.body.classList.remove('goosebox-open');
}
// close modals on background click
window.addEventListener('load', function() {
document.addEventListener('click', event => {
if (event.target.classList.contains('goosebox')) {
closepopup();
}
});
});

241
box-office.php Normal file
View file

@ -0,0 +1,241 @@
<?php
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
date_default_timezone_set('UTC');
require ABSPATH.'functions/tools.php';
require ABSPATH.'functions/tools-magnet.php';
require ABSPATH.'functions/tools-update.php';
require ABSPATH.'engines/boxoffice/yts.php';
require ABSPATH.'engines/boxoffice/eztv.php';
require ABSPATH.'engines/boxoffice/thepiratebay.php';
require ABSPATH.'engines/boxoffice/nyaa.php';
// Blue pixel
$blank_thumb = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOUX3LxDAAE4AJiVKIoaQAAAABJRU5ErkJggg==';
$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 Box Office</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="View the latest magnet links available for download!" />
<meta property="og:site_name" content="Goosle Search Box Office" />
<meta property="og:title" content="Goosle Search Box Office" />
<meta property="og:description" content="View the latest magnet links available for download!" />
<meta property="og:url" content="<?php echo get_base_url($opts->siteurl); ?>/box-office.php" />
<meta property="og:image" content="<?php echo get_base_url($opts->siteurl); ?>/assets/images/goosle.webp" />
<meta property="og:type" content="website" />
<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); ?>/box-office.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"/>
<script src="<?php echo get_base_url($opts->siteurl); ?>/assets/js/goose.js" id="goosle-js"></script>
</head>
<body class="boxofficepage">
<?php
if(verify_hash($opts->hash_auth, $opts->hash, $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($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>">
</form>
<div class="navigation">
<a class="<?php echo ($opts->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=0">Search</a>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($opts->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=1" >Images</a>
<?php } ?>
<?php if($opts->enable_news_search == 'on') { ?>
<a class="<?php echo ($opts->type == '2') ? 'active ' : ''; ?>tab-news" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=2">News</a>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<a class="<?php echo ($opts->type == '9') ? 'active ' : ''; ?>tab-magnet" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=9">Magnet links</a>
<?php } ?>
</div>
</div>
<div class="content">
<h2>The Box Office</h2>
<div class="result-grid">
<p>Click on any movie poster for more information and available download links. All other results are direct download links.</p>
<h3>Recently added movies on YTS</h3>
<?php
$highlights = array_slice(yts_boxoffice($opts, 'date_added'), 0, 24);
?>
<ul>
<?php
foreach($highlights as $highlight) {
$thumb = (!empty($highlight['thumbnail'])) ? $highlight['thumbnail'] : $blank_thumb;
$search_query = urlencode($highlight['name']." ".$highlight['year']);
echo "<li class=\"result highlight yts id-".$highlight['id']."\">";
echo " <div class=\"result-box\">";
echo " <a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['name']."\"><img src=\"".$thumb."\" alt=\"".$highlight['name']."\" /></a>";
echo " </div>";
echo " <span><center><a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['name']."\">".$highlight['name']."</a></center></span>";
// HTML for popup
echo " <div id=\"highlight-".$highlight['id']."\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>".$highlight['name']."</h2>";
echo " <p>".$highlight['summary']."</p>";
echo " <p><a href=\"./results.php?q=".$search_query."&a=".$opts->hash."&t=0\" title=\"Search on Goosle Web Search!\">Search on Goosle</a> &bull; <a href=\"./results.php?q=".$search_query."&a=".$opts->hash."&t=9\" title=\"Search on Goosle Magnet Search! For new additions results may be limited.\">Find more Magnet links</a></p>";
echo " <p><strong>Genre:</strong> ".$highlight['category']."<br /><strong>Released:</strong> ".$highlight['year']."<br /><strong>Rating:</strong> ".movie_star_rating($highlight['rating'])." <small>(".$highlight['rating']." / 10)</small></p>";
// List downloads
echo " <h3>Downloads:</h3>";
echo " <p>";
foreach($highlight['magnet_links'] as $magnet) {
if(!is_null($magnet['quality'])) $meta[] = $magnet['quality'];
if(!is_null($magnet['type'])) $meta[] = $magnet['type'];
$meta[] = human_filesize($magnet['filesize']);
echo "<button class=\"download\" onclick=\"location.href=".$magnet['magnet']."\">".implode(' / ', $meta)."</button>";
unset($meta);
}
echo " </p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo " </div>";
echo "</li>";
unset($highlight, $thumb, $search_query, $magnet);
}
unset($highlights);
?>
</ul>
<h3>Latest TV Show releases from EZTV</h3>
<?php
$highlights = array_slice(eztv_boxoffice($opts), 0, 24);
?>
<ul>
<?php
foreach($highlights as $highlight) {
$thumb = (!empty($highlight['thumbnail'])) ? $highlight['thumbnail'] : $blank_thumb;
echo "<li class=\"result highlight eztv id-".$highlight['id']."\">";
echo " <div class=\"result-box\">";
echo " <a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['name']."\"><img src=\"".$thumb."\" alt=\"".$highlight['name']."\" /></a>";
echo " </div>";
echo " <span><center><a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['name']."\">".$highlight['name']."</a></center></span>";
// HTML for popup
echo " <div id=\"highlight-".$highlight['id']."\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>".$highlight['name']."</h2>";
echo " <p><a href=\"./results.php?q=".urlencode($highlight['name'])."&a=".$opts->hash."&t=0\" title=\"Search on Goosle Web Search!\">Search on Goosle</a> &bull; <a href=\"./results.php?q=".urlencode($highlight['name'])."&a=".$opts->hash."&t=9\" title=\"Search on Goosle Magnet Search! For new additions results may be limited.\">Find more Magnet links</a></p>";
// List downloads
echo " <h3>Downloads:</h3>";
echo " <p>";
foreach($highlight['magnet_links'] as $magnet) {
if(!is_null($magnet['quality'])) $meta[] = $magnet['quality'];
$meta[] = human_filesize($magnet['filesize']);
echo "<button class=\"download\" onclick=\"location.href=".$magnet['magnet']."\">".implode(' / ', $meta)."</button>";
unset($meta);
}
echo " </p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo " </div>";
echo "</li>";
unset($highlight, $thumb, $magnet);
}
unset($highlights);
?>
</ul>
</div>
<div class="grid-container">
<div class="list-grid piratebay">
<h3>Newest downloads on ThePirateBay</h3>
<ol>
<?php
foreach(piratebay_boxoffice($opts, 10) as $highlight) {
echo "<li class=\"result magnet id-".$highlight['id']."\">";
echo "<div class=\"title\"><a href=\"".$highlight['magnet']."\"><h2>".stripslashes($highlight['name'])."</h2></a></div>";
echo "<div class=\"description\"><strong>Seeds:</strong> <span class=\"green\">".$highlight['seeders']."</span> - <strong>Peers:</strong> <span class=\"red\">".$highlight['leechers']."</span> - <strong>Size:</strong> ".human_filesize($highlight['filesize'])."<br /><strong>Category:</strong> ".$highlight['category']."</div>";
echo "</li>";
unset($highlight);
}
?>
</ol>
</div>
<div class="list-grid nyaa">
<h3>Newest downloads on Nyaa</h3>
<ol>
<?php
foreach(nyaa_boxoffice($opts, 10) as $highlight) {
echo "<li class=\"result magnet id-".$highlight['id']."\">";
echo "<div class=\"title\"><a href=\"".$highlight['magnet']."\"><h2>".stripslashes($highlight['name'])."</h2></a></div>";
echo "<div class=\"description\"><strong>Seeds:</strong> <span class=\"green\">".$highlight['seeders']."</span> - <strong>Peers:</strong> <span class=\"red\">".$highlight['leechers']."</span> - <strong>Size:</strong> ".human_filesize($highlight['filesize'])."<br /><strong>Category:</strong> ".$highlight['category']."</div>";
echo "</li>";
unset($highlight);
}
?>
</ol>
</div>
</div>
<center><small>Goosle does not index, offer or distribute torrent files.</small></center>
</div>
<div class="footer grid-container">
<div class="footer-grid">
&copy; <?php echo date('Y'); ?> <?php echo show_version(); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
</div>
<div class="footer-grid">
<a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./box-office.php?a=<?php echo $opts->hash; ?>&t=9">Box office</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a>
</div>
</div>
<?php
} else {
echo "<div class=\"auth-error\">Goosle</div>";
}
?>
</body>
</html>

BIN
cache/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -14,19 +14,30 @@
SITEURL:
Set the base domain name for your Goosle setup (ex. example.com, something.example.com, example.com/something/) so that internal links will work correctly.
COLORSCHEME:
Set a default colorscheme.
'default' A dark headers and main backgrounds with light search results.
'light' More light elements.
'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.
Name the file something like 'mycolorscheme.css', place it in /assets/css/ and use the keyword 'mycolorscheme' in this setting for it to work.
HASH:
A simple lowercase passphrase, something simple like: j9fg-i2du-er6m or 1846.
Used for caching results and optionally for accessing Goosle (See HASH_AUTH option).
HASH_AUTH:
Use the above hash as a simple passphrase.
Using it as a passphrase lets you host Goosle on a public facing server without providing a public service.
Using a passphrase lets you host Goosle on a public facing server without providing a public service.
This is useful for if just you and some friends or family should be able to use Goosle from anywhere.
"off" Don't use the hash as a password.
"on" Use the hash as a password.
'off' Don't use the hash as a password.
'on' Use the hash as a password.
Usage: https://example.com/?a=1234567890
Usage: https://example.com/?a=j9fg-i2du-er6m
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:
@ -35,26 +46,29 @@ CACHE_TYPE:
Caching can be done in memory with APCu or as temporary files in the /cache/ folder.
"off" No caching.
"file" Store results in text files (Default).
"apcu" Faster, utilizes memory.
'off' No caching.
'file' Store results in text files (Default).
'apcu' Faster, utilizes memory.
CACHE_TIME:
Minutes the result should be cached. Accepts a numeric value between 1 and 720.
APCu stores in memory, using a longer time takes up more of it. It is recommended to not exceed 30 minutes for APCu.
APCu stores in memory, using a longer cache time takes up more of it. It is recommended to not exceed a few hours for APCu.
The file cache is only limited by your hosting storage space and can safely be much much longer if you want.
To not show outdated results the 'limit' is 720 minutes, which equals 12 hours.
To not show outdated results the 'limit' is 48 hours.
Ignored if above 'CACHE_TYPE' option is set to off.
/* ------------------------------------------------------------------------------------
LANGUAGE:
DuckDuckGo and Google are mostly language agnostic.
To not fit the USA mold, Goosle defaults to the United Kingdom for english results.
DuckDuckGo and Google are mostly language agnostic.
Invalid values either cause the search 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/.
Wikipedia needs to be told which language you want. This changes the search url. Use any of their supported languages (en, es, fr, nl, etc.)
Qwant uses a locale similar to DuckDuckGo. Available locales are: bg_bg, br_fr, ca_ad, ca_es, ca_fr, co_fr, cs_cz, cy_gb, da_dk, de_at, de_ch, de_de, ec_ca, el_gr, en_au, en_ca, en_gb, en_ie, en_my, en_nz, en_us, es_ad, es_ar, es_cl, es_co, es_es, es_mx, es_pe, et_ee, eu_es, eu_fr, fc_ca, fi_fi, fr_ad, fr_be, fr_ca, fr_ch, fr_fr, gd_gb, he_il, hu_hu, it_ch, it_it, ko_kr, nb_no, nl_be, nl_nl, pl_pl, pt_ad, pt_pt, ro_ro, sv_se, th_th, zh_cn, zh_hk.
Qwant uses a locale similar to DuckDuckGo and defaults to the United Kingdom as well.
Available locales are: bg_bg, br_fr, ca_ad, ca_es, ca_fr, co_fr, cs_cz, cy_gb, da_dk, de_at, de_ch, de_de, ec_ca, el_gr, en_au, en_ca, en_gb, en_ie, en_my, en_nz, en_us, es_ad, es_ar, es_cl, es_co, es_es, es_mx, es_pe, et_ee, eu_es, eu_fr, fc_ca, fi_fi, fr_ad, fr_be, fr_ca, fr_ch, fr_fr, gd_gb, he_il, hu_hu, it_ch, it_it, ko_kr, nb_no, nl_be, nl_nl, pl_pl, pt_ad, pt_pt, ro_ro, sv_se, th_th, zh_cn, zh_hk.
SOCIAL MEDIA RELEVANCE:
Show social media results lower in the combined results if you don't value such results.
@ -82,87 +96,91 @@ MAGNET TRACKERS:
------------------------------------------------------------------------------------ */
return (object) array(
// ALL OPTIONS ARE REQUIRED, EVEN IF YOU DO NOT USE THE FEATURE. EMPTY VALUES OR MISSING SETTINGS CAUSE ISSUES!!!
"siteurl" => "example.com", // Make sure this is accurate
"hash" => "j9fg-i2du-er6m", // 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" => 30, // Default: 30 (Minutes)
'siteurl' => 'example.com', // Make sure this is accurate
'colorscheme' => 'default', // Default colorscheme to use
'hash' => 'j9fg-i2du-er6m', // 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)
'timezone' => 'UTC', // Default: 'UTC (London. Enter UTC+1, UTC-6 etc. for your timezone)
"enable_duckduckgo" => "on", // Default: on
"enable_google" => "on", // Default: on
"enable_qwantnews" => "on", // Default: on
"enable_wikipedia" => "on", // Default: on
'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_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 for details)
"enable_qwant" => "on", // Default: on
'enable_news_search' => 'on', // Default: on (Disables all news search regardless of settings for individual engines, results are mixed in with regular search)
'enable_qwantnews' => 'on', // Default: on
'enable_yahoonews' => 'on', // Default: on
'enable_bravenews' => 'on', // Default: on
'enable_hackernews' => 'on', // Default: on
"enable_magnet_search" => "on", // Default: on (Disables all image search regardless of settings for individual engines)
"enable_eztv" => "on", // Default: on
"enable_limetorrents" => "on", // Default: on
"enable_nyaa" => "on", // Default: on
"enable_piratebay" => "on", // Default: on
"enable_yts" => "on", // Default: on
'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 for details)
'enable_qwantimages' => 'on', // Default: on
"duckduckgo_language" => "uk-en", // Default: uk-en (United Kingdom)
"wikipedia_language" => "en", // Default: en (English)
"qwant_language" => "en_gb", // Default: en_gb (United Kingdom)
'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
"social_media_relevance" => 8, // Default: 8
"show_search_source" => "on", // Default: on
"show_search_rank" => "off", // Default: off
"imdb_id_search" => "off", // Default: off
"password_generator" => "on", // Default: on
'duckduckgo_language' => 'uk-en', // Default: uk-en (United Kingdom)
'wikipedia_language' => 'en', // Default: en (English)
'qwant_language' => 'en_gb', // Default: en_gb (United Kingdom)
"special" => array(
"currency" => "on", // Default: on, Currency converter
"definition" => "on", // Default: on, Word dictionary
"phpnet" => "on", // Default: on, PHP-dot-net highlight
"yts" => "on", // Default: on, Show latest, or highlighted movies from YTS
"eztv" => "on" // Default: on, Show latest TV Show episodes from EZTV
'social_media_relevance' => 8, // Default: 8
'show_search_source' => 'on', // Default: on
'show_search_rank' => 'off', // Default: off
'imdb_id_search' => 'off', // Default: off, Requires Magnet search to also be on
'password_generator' => 'on', // Default: on
'special' => array(
'currency' => 'on', // Default: on, Currency converter
'definition' => 'on', // Default: on, Word dictionary
'ipaddress' => 'on', // Default: on, Look up your IP Address
'phpnet' => 'on', // Default: on, PHP-dot-net highlight
),
"show_zero_seeders" => "on", // Default: on
"yts_highlight" => "date_added", // Default: "date_added"
"piratebay_categories_blocked" => array(206, 210), // Default: 206, 210
"yts_categories_blocked" => array("horror"), // Default: "horror"
'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; 'action', 'drama', 'sci-fi' etc.. There is no defined list, so block keywords that you see and don't like)
"user_agents" => array(
"Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1", // Linux, Lynx browser 2.8.5
"Lynx/2.8.9rel.1 libwww-FM/2.14 SSL-MM/1.4.1", // Linux, Lynx browser 2.8.9
"Lynx/2.8.6rel.4 libwww-FM/2.14 SSL-MM/1.4.1", // Linux, Lynx browser 2.8.6
"TinyBrowser/2.0 (TinyBrowser Comment; rv:1.9.1a2pre) Gecko/20201231", // Linux, Tinybrowser 2
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) DuckDuckGo/7 Safari/605.1.15", // macOS 10.15, DuckDuckGo 7
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15) Gecko/20100101 Firefox/119.0", // macOS 10.15, Firefox 119
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/116.0", // Windows 10, Firefox 116
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64) Gecko/20100101 Firefox/83.0", // Linux Ubuntu, Firefox 83
"Mozilla/5.0 (X11; Linux i686) Gecko/20100101 Firefox/119.0", // Linux Generic, Firefox 119
'user_agents' => array(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15) Gecko/20100101 Firefox/119.0', // macOS 10.15, Firefox 119
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/116.0', // Windows 10, Firefox 116
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64) Gecko/20100101 Firefox/83.0', // Linux Ubuntu, Firefox 83
'Mozilla/5.0 (X11; Linux i686) Gecko/20100101 Firefox/119.0', // Linux Generic, Firefox 119
),
"magnet_trackers" => array(
"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",
'magnet_trackers' => array(
'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',
)
);
?>

BIN
engines/.DS_Store vendored Normal file

Binary file not shown.

BIN
engines/boxoffice/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,97 @@
<?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.
------------------------------------------------------------------------------------ */
function eztv_boxoffice($opts) {
$api_url = 'https://eztvx.to/api/get-torrents?'.http_build_query(array('limit' => 100));
// If there is a cached result use that instead
if($opts->cache_type !== 'off' && has_cached_results($opts->cache_type, $opts->hash, $api_url, $opts->cache_time)) {
return fetch_cached_results($opts->cache_type, $opts->hash, $api_url);
}
$response = do_curl_request(
$api_url, // (string) Where?
array('Accept: application/json, */*;q=0.7', 'User-Agent: '.$opts->user_agents[0].';'), // (array) User agent + Headers
'get', // (string) post/get
null // (assoc array|null) Post body
);
$json_response = json_decode($response, true);
$results = $results_temp = array();
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response['torrents_count'] == 0) return $results;
foreach($json_response['torrents'] as $result) {
$name = sanitize($result['title']);
$hash = strtolower(sanitize($result['hash']));
$thumbnail = sanitize($result['small_screenshot']);
$magnet_link = sanitize($result['magnet_url']);
$filesize = sanitize($result['size_bytes']);
// Get extra data
$quality = find_video_quality($name);
$codec = find_video_codec($name);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
// Clean up show name
$name = (preg_match('/.+?(?=[0-9]{3,4}p|xvid|divx|(x|h)26(4|5))/i', $name, $clean_name)) ? $clean_name[0] : $name; // Break off show name before video resolution
$name = trim(str_replace(array('S0E0', 'S00E00'), '', $name)); // Strip spaces and empty season/episode indicator from name
// Group the same episodes in one result
if(count($results) > 0) {
// Do a match
$result_urls = array_column($results, 'name', 'id');
$found_id = array_search($name, $result_urls); // Return the result ID
} else {
$found_id = false;
}
if($found_id !== false) {
// Add the download to a previous result
$results[$found_id]['magnet_links'][] = array(
'hash' => $hash,
'magnet' => $magnet_link,
'filesize' => $filesize,
'quality' => $quality
);
} else {
$result_id = md5($name); // Predictable/repeatable 'unique' string
// First/new result
$results[$result_id] = array (
'id' => $result_id, // string
'name' => $name, // string
'thumbnail' => $thumbnail, // string
'magnet_links' => array(array( // Yes, two array...
'hash' => $hash, // string
'magnet' => $magnet_link, // string
'filesize' => $filesize, // int
'quality' => $quality, // string
))
);
}
unset($result, $result_urls, $found_id, $result_id, $name, $hash, $thumbnail, $magnet_link, $quality, $codec);
}
unset($response, $json_response);
// Cache last request if there is something to cache
if($opts->cache_type !== 'off') {
if(count($results) > 0) store_cached_results($opts->cache_type, $opts->hash, $api_url, $results, $opts->cache_time);
}
return $results;
}
?>

View file

@ -0,0 +1,83 @@
<?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.
------------------------------------------------------------------------------------ */
function nyaa_boxoffice($opts, $amount) {
$api_url = 'https://nyaa.si/';
$results = array();
// If there is a cached result use that instead
if($opts->cache_type !== 'off' && has_cached_results($opts->cache_type, $opts->hash, $api_url, $opts->cache_time)) {
return fetch_cached_results($opts->cache_type, $opts->hash, $api_url);
}
$response = do_curl_request(
$api_url, // (string) Where?
array('Accept: text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7', 'User-Agent: '.$opts->user_agents[0].';'), // (array) User agent + Headers
'get', // (string) post/get
null // (assoc array|null) Post body
);
$xpath = get_xpath($response);
$results = array();
// No response
if(!$xpath) return $results;
// Scrape the results
$limit = $amount + 16;
$scrape = $xpath->query("//tbody/tr[position() <= $limit]");
// No results
if(count($scrape) == 0) return $results;
foreach($scrape as $result) {
$meta = $xpath->evaluate(".//td[@class='text-center']", $result);
$name = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result);
if($name->length == 0) continue;
$magnet = $xpath->evaluate(".//a[2]/@href", $meta[0]);
if($magnet->length == 0) $magnet = $xpath->evaluate(".//a/@href", $meta[0]);
if($magnet->length == 0) continue;
$name = sanitize($name[0]->textContent);
$magnet = sanitize($magnet[0]->textContent);
parse_str(parse_url($magnet, PHP_URL_QUERY), $hash_parameters);
$hash = strtolower(str_replace('urn:btih:', '', $hash_parameters['xt']));
$seeders = sanitize($meta[3]->textContent);
$leechers = sanitize($meta[4]->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))))));
$category = sanitize($xpath->evaluate(".//td[1]//a/@title", $result)[0]->textContent);
$category = str_replace(' - ', '/', $category);
$results[] = array (
'id' => uniqid(rand(0, 9999)), // Semi random string to separate results on the results page
'name' => $name, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
'category' => $category, // string
);
unset($result, $meta, $name, $magnet, $seeders, $leechers, $filesize, $category);
}
unset($response, $xpath, $scrape, $limit);
$results = array_slice($results, 0, $amount);
// Cache last request if there is something to cache
if($opts->cache_type !== 'off') {
if(count($results) > 0) store_cached_results($opts->cache_type, $opts->hash, $api_url, $results, $opts->cache_time);
}
return $results;
}
?>

View file

@ -0,0 +1,134 @@
<?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.
------------------------------------------------------------------------------------ */
function piratebay_boxoffice($opts, $amount) {
$api_url = 'https://apibay.org/precompiled/data_top100_recent.json';
// If there is a cached result use that instead
if($opts->cache_type !== 'off' && has_cached_results($opts->cache_type, $opts->hash, $api_url, $opts->cache_time)) {
return fetch_cached_results($opts->cache_type, $opts->hash, $api_url);
}
$response = do_curl_request(
$api_url, // (string) Where?
array('Accept: application/json, */*;q=0.7', 'User-Agent: '.$opts->user_agents[0].';'), // (array) User agent + Headers
'get', // (string) post/get
null // (assoc array|null) Post body
);
$json_response = json_decode($response, true);
$results = array();
// No response
if(empty($json_response)) return $results;
// No results
if($json_response[0]['name'] == 'No results returned') return $results;
$categories = array(
100 => 'Audio',
101 => 'Music',
102 => 'Audio Book',
103 => 'Sound Clips',
104 => 'Audio FLAC',
199 => 'Audio Other',
200 => 'Video',
201 => 'Movie',
202 => 'Movie DVDr',
203 => 'Music Video',
204 => 'Movie Clip',
205 => 'TV Show',
206 => 'Handheld',
207 => 'HD Movie',
208 => 'HD TV Show',
209 => '3D Movie',
210 => 'CAM/TS',
211 => 'UHD/4K Movie',
212 => 'UHD/4K TV Show',
299 => 'Video Other',
300 => 'Applications',
301 => 'Apps Windows',
302 => 'Apps Apple',
303 => 'Apps Unix',
304 => 'Apps Handheld',
305 => 'Apps iOS',
306 => 'Apps Android',
399 => 'Apps Other OS',
400 => 'Games',
401 => 'Games PC',
402 => 'Games Apple',
403 => 'Games PSx',
404 => 'Games XBOX360',
405 => 'Games Wii',
406 => 'Games Handheld',
407 => 'Games iOS',
408 => 'Games Android',
499 => 'Games Other OS',
500 => 'Porn',
501 => 'Porn Movie',
502 => 'Porn Movie DVDr',
503 => 'Porn Pictures',
504 => 'Porn Games',
505 => 'Porn HD Movie',
506 => 'Porn Movie Clip',
507 => 'Porn UHD/4K Movie',
599 => 'Porn Other',
600 => 'Other',
601 => 'Other E-Book',
602 => 'Other Comic',
603 => 'Other Pictures',
604 => 'Other Covers',
605 => 'Other Physibles',
699 => 'Other Other'
);
foreach($json_response as $result) {
$name = sanitize($result['name']);
$hash = strtolower(sanitize($result['info_hash']));
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($name).'&tr='.implode('&tr=', $opts->magnet_trackers);
$seeders = sanitize($result['seeders']);
$leechers = sanitize($result['leechers']);
$filesize = sanitize($result['size']);
$category = sanitize($result['category']);
// Block these categories
if(in_array($category, $opts->piratebay_categories_blocked)) continue;
// Set actual category
$category = $categories[$category];
$results[] = array(
'id' => uniqid(rand(0, 9999)), // Semi random string to separate results on the results page
'name' => $name, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
'category' => $category // string
);
unset($result, $name, $magnet, $seeders, $leechers, $filesize, $category);
}
unset($response, $json_response, $categories);
$results = array_slice($results, 0, $amount);
// Cache last request if there is something to cache
if($opts->cache_type !== 'off') {
if(count($results) > 0) store_cached_results($opts->cache_type, $opts->hash, $api_url, $results, $opts->cache_time);
}
return $results;
}
?>

93
engines/boxoffice/yts.php Normal file
View file

@ -0,0 +1,93 @@
<?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.
------------------------------------------------------------------------------------ */
function yts_boxoffice($opts, $what) {
$api_url = 'https://yts.mx/api/v2/list_movies.json?'.http_build_query(array('limit' => 40, 'sort_by' => $what));
// If there is a cached result use that instead
if($opts->cache_type !== 'off' && has_cached_results($opts->cache_type, $opts->hash, $api_url, $opts->cache_time)) {
return fetch_cached_results($opts->cache_type, $opts->hash, $api_url);
}
$response = do_curl_request(
$api_url, // (string) Where?
array('Accept: application/json, */*;q=0.7', 'User-Agent: '.$opts->user_agents[0].';'), // (array) User agent + Headers
'get', // (string) post/get
null // (assoc array|null) Post body
);
$json_response = json_decode($response, true);
$results = array();
// No response
if(empty($json_response)) return $results;
// No results
if($json_response['data']['movie_count'] == 0) return $results;
foreach($json_response['data']['movies'] as $result) {
$name = sanitize($result['title']);
$year = (array_key_exists('year', $result)) ? sanitize($result['year']) : 0;
$category = (array_key_exists('genres', $result)) ? $result['genres'] : array();
$rating = (array_key_exists('rating', $result)) ? sanitize($result['rating']) : 0;
$summary = (array_key_exists('summary', $result)) ? sanitize($result['summary']) : "No summary provided";
$thumbnail = (array_key_exists('medium_cover_image', $result)) ? sanitize($result['medium_cover_image']) : "";
// Block these categories
if(count(array_uintersect($category, $opts->yts_categories_blocked, 'strcasecmp')) > 0) continue;
// Set actual category
$category = sanitize(implode(', ', $category));
foreach($result['torrents'] as $download) {
$hash = strtolower(sanitize($download['hash']));
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($name).'&tr='.implode('&tr=', $opts->magnet_trackers);
$filesize = filesize_to_bytes(sanitize($download['size']));
$type = (array_key_exists('type', $download)) ? sanitize(strtolower($download['type'])) : null;
$quality = (array_key_exists('quality', $download)) ? sanitize($download['quality']) : null;
$codec = (array_key_exists('video_codec', $download)) ? sanitize($download['video_codec']) : null;
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
$downloads[] = array (
'hash' => $hash,
'magnet' => $magnet,
'filesize' => $filesize,
'type' => $type,
'quality' => $quality
);
unset($download, $hash, $magnet, $filesize, $type, $quality, $codec);
}
$results[] = array (
'id' => uniqid(rand(0, 9999)), // Semi random string to separate results on the results page
'name' => $name, // string
'year' => $year, // int(4)
'category' => $category, // string
'rating' => $rating, // float|int
'summary' => $summary, // string
'thumbnail' => $thumbnail, // string|empty
'magnet_links' => $downloads // array
);
unset($result, $name, $thumbnail, $year, $category, $rating, $url, $summary, $downloads);
}
unset($response, $json_response);
// Cache last request if there is something to cache
if($opts->cache_type !== 'off') {
if(count($results) > 0) store_cached_results($opts->cache_type, $opts->hash, $api_url, $results, $opts->cache_time);
}
return $results;
}
?>

BIN
engines/image/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,29 +11,28 @@
------------------------------------------------------------------------------------ */
class OpenverseRequest extends EngineRequest {
public function get_request_url() {
$query_terms = substr($this->query, 0, 200);
$query = str_replace('%22', '\"', $this->query);
// Safe search override
$safe = "0"; // No mature results
if(strpos($query_terms[0], "safe") !== false) {
$switch = explode(":", $query_terms[0]);
if(!is_numeric($switch[1])) {
$safe = (strtolower($switch[1]) == "off") ? "1" : "0";
$this->query = implode(" ", array_slice($query_terms, 1));
}
$safe = '0'; // No mature results
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
if($matches[2] == 'on') $safe = '0';
if($matches[2] == 'off') $safe = '1';
$query = str_replace($matches[0], '', $query);
}
unset($matches);
// q = query
// format = json
// mature = 1 / 0
// page_size = 80 (int)
// Is there no query left? Bail!
if(empty($query)) return false;
$args = array("q" => $query_terms, "format" => "json", "mature" => $safe, "page_size" => 50);
$url = "https://api.openverse.org/v1/images/?".http_build_query($args);
$url = 'https://api.openverse.org/v1/images/?'.http_build_query(array(
'q' => $query, // Search query
'format' => 'json', // Response format
'mature' => $safe, // Safe search (1 = ON, 0 = OFF)
'page_size' => 50 // How many results to get
));
unset($query_terms, $switch, $safe, $max_results, $args);
unset($query, $safe);
return $url;
}
@ -48,7 +47,6 @@ class OpenverseRequest extends EngineRequest {
'Authorization' => 'Bearer '.$token['openverse']['access_token'],
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
@ -56,56 +54,70 @@ class OpenverseRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Set base rank and result amound
$rank = $results['amount'] = count($json_response['results']);
if(empty($json_response)) return $engine_temp;
// Nothing found
if($results['amount'] == 0) return $results;
// Figure out results and base rank
$number_of_results = $rank = $json_response['result_count'];
// No results
if($number_of_results == 0) return $engine_temp;
// Use API result
foreach ($json_response['results'] as $result) {
// Deal with optional or missing data
$dimensions_w = (!empty($result['width'])) ? sanitize($result['width']) : "";
$dimensions_h = (!empty($result['height'])) ? sanitize($result['height']) : "";
$filesize = (!empty($result['filesize'])) ? sanitize($result['filesize']) : "";
$link = (!empty($result['url'])) ? sanitize($result['url']) : "";
$image_full = (!empty($result['foreign_landing_url'])) ? sanitize($result['foreign_landing_url']) : "";
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;
$alt = (!empty($result['title'])) ? sanitize($result['title']) : "";
$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;
$creator = (!empty($result['creator'])) ? " by ".sanitize($result['creator']) : null;
// Add attribution to alt text?
$creator = (!empty($result['creator'])) ? " by ".sanitize($result['creator']) : "";
$alt = (!empty($creator)) ? $alt.$creator : $alt;
// Skip broken results
if(empty($image_thumb)) continue;
if(empty($image_full)) continue;
if(empty($url)) continue;
// Process result
$filesize = intval(preg_replace('/[^0-9]/', '', $filesize));
// Process data
if(!is_null($creator)) $alt = $alt.$creator;
if(!is_null($filesize)) $filesize = intval(preg_replace('/[^0-9]+/', '', $filesize));
// filter duplicate IMAGE urls/results
if(!empty($results['search'])) {
if(in_array($image_full, array_column($results['search'], "image_full"))) continue;
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
$results['search'][] = array ("id" => uniqid(rand(0, 9999)), "source" => "Openverse", "image_thumb" => $image_thumb, "alt" => $alt, "image_full" => $image_full, "width" => $dimensions_w, "height" => $dimensions_h, "filesize" => $filesize, "webpage_url" => $link, "engine_rank" => $rank);
$rank -= 1;
unset($url_data, $usable_data, $dimensions_w, $dimensions_h, $filesize, $link, $image_full, $alt, $image_thumb);
}
unset($json_response, $rank);
// Add error if there are no search results
if(empty($results['search'])) {
$results['error'] = array(
"message" => "No results found. Please try with less or different keywords!"
$engine_temp[] = array (
// Required
'image_full' => $image_full, // string
'image_thumb' => $image_thumb, // string
'url' => $url, // string
'engine_rank' => $rank, // int
// Optional
'alt' => $alt, // string | null
'width' => $dimensions_w, // int | null
'height' => $dimensions_h, // int | null
'filesize' => $filesize, // int | null
);
$rank -= 1;
}
return $results;
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Openverse';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $rank);
return $engine_result;
}
}
?>
?>

View file

@ -0,0 +1,132 @@
<?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 QwantImageRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
// Safe search override
$safe = '1'; // Moderate results
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
if($matches[2] == 'on') $safe = '2';
if($matches[2] == 'off') $safe = '0';
$query = str_replace($matches[0], '', $query);
}
unset($matches);
// Size override
$size = 'all'; // All sizes
if(preg_match('/(size:)(small|medium|large|xlarge)/i', $query, $matches)) {
$size = $matches[1];
$query = str_replace($matches[0], '', $query);
// Engine specific
if($size == 'xlarge') $size = 'large';
}
unset($matches);
// Set locale
$language = (strlen($this->opts->qwant_language) > 0 && strlen($this->opts->qwant_language < 6)) ? $this->opts->qwant_language : 'en_gb';
// Is there no query left? Bail!
if(empty($query)) return false;
$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)
'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?
'safesearch' => $safe // Safe search filter (0 = off, 1 = normal, 2 = strict)
));
unset($query, $safe, $size, $language);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'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)) return $engine_temp;
// Figure out results and base rank
$number_of_results = $rank = $json_response['data']['result']['total'];
// No results
if($number_of_results == 0) return $engine_temp;
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']);
$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;
// Skip broken results
if(empty($image_full)) continue;
if(empty($image_thumb)) continue;
if(empty($url)) continue;
// Process data
if(!is_null($filesize)) $filesize = intval(preg_replace('/[^0-9]+/', '', $filesize));
// 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
'url' => $url, // string
'engine_rank' => $rank, // int
// Optional
'alt' => $alt, // string | null
'width' => $dimensions_w, // int | null
'height' => $dimensions_h, // int | null
'filesize' => $filesize, // int | null
);
$rank -= 1;
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Qwant';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $rank);
return $engine_result;
}
}
?>

View file

@ -1,106 +0,0 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class QwantImageRequest extends EngineRequest {
public function get_request_url() {
// Split the query
$query_terms = explode(" ", strtolower($this->query));
// Safe search override
$safe = "1"; // Moderate results
if(strpos($query_terms[0], "safe") !== false) {
$switch = explode(":", $query_terms[0]);
if(!is_numeric($switch[1])) {
$safe = (strtolower($switch[1]) == "off") ? "0" : "2";
$this->query = implode(" ", array_slice($query_terms, 1));
}
}
$language = (strlen($this->opts->qwant_language) > 0 && strlen($this->opts->qwant_language < 6)) ? $this->opts->qwant_language : "en_gb";
// q = query
// t = Type of search, Images
// count = Up-to how many images to return (Max 50)
// locale = In which language should the search be done
// device = What kind of device are we searching from?
// safesearch = Safe search filter (0 = off, 1 = normal, 2 = strict)
$args = array("q" => $this->query, "t" => 'images', 'count' => 50, 'locale' => $language, 'device' => 'desktop', 'safesearch' => $safe);
$url = "https://api.qwant.com/v3/search/images?".http_build_query($args);
unset($query_terms, $switch, $safe, $language, $args);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
);
}
public function parse_results($response) {
$results = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response["status"] != "success") return $results;
// Set base rank and result amound
$rank = $results['amount'] = $json_response["data"]["result"]["total"];
// Use API result
foreach ($json_response["data"]["result"]["items"] as $result) {
// Deal with optional or missing data
$dimensions_w = (!empty($result['width'])) ? sanitize($result['width']) : "";
$dimensions_h = (!empty($result['height'])) ? sanitize($result['height']) : "";
$filesize = (!empty($result['size'])) ? sanitize($result['size']) : "";
$link = (!empty($result['url'])) ? sanitize($result['url']) : "";
$image_full = (!empty($result['media'])) ? sanitize($result['media']) : "";
$image_thumb = (!empty($result['thumbnail'])) ? sanitize($result['thumbnail']) : $image_full;
$alt = (!empty($result['title'])) ? sanitize($result['title']) : "";
// Process result
$filesize = intval(preg_replace('/[^0-9]/', '', $filesize));
// filter duplicate IMAGE urls/results
if(!empty($results['search'])) {
if(in_array($image_full, array_column($results['search'], "image_full"))) continue;
}
$results['search'][] = array ("id" => uniqid(rand(0, 9999)), "source" => "Qwant", "image_thumb" => $image_thumb, "alt" => $alt, "image_full" => $image_full, "width" => $dimensions_w, "height" => $dimensions_h, "filesize" => $filesize, "webpage_url" => $link, "engine_rank" => $rank);
$rank -= 1;
unset($url_data, $usable_data, $dimensions_w, $dimensions_h, $filesize, $link, $image_full, $alt, $image_thumb);
}
unset($json_response, $rank);
// Add error if there are no search results
if(empty($results['search'])) {
$results['error'] = array(
"message" => "No results found. Please try with less or different keywords!"
);
}
return $results;
}
}
?>

View file

@ -0,0 +1,169 @@
<?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 YahooImageRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
// Safe search override
$safe = ''; // No mature results
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
if($matches[2] == 'on') $safe = '';
if($matches[2] == 'off') $safe = '0';
$query = str_replace($matches[0], '', $query);
}
unset($matches);
// Size override
$size = ''; // All sizes
if(preg_match('/(size:)(small|medium|large|xlarge)/i', $query, $matches)) {
$size = $matches[1];
$query = str_replace($matches[0], '', $query);
// Engine specific
if($size == 'xlarge') $size = 'wallpaper';
}
unset($matches);
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://images.search.yahoo.com/search/images?'.http_build_query(array(
'p' => $query, // Search query
'imgsz' => $size, // Image size (small|medium|large|wallpaper)
'safe' => $safe // Safe search filter (0 = off, "" = on)
));
unset($query, $size, $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) return $engine_temp;
// Scrape the results
// $scrape = $xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'slotting'))][position() < 101]");
$scrape = $xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'ignore'))][position() < 101]");
// Figure out results and base rank
$number_of_results = $rank = count($scrape);
// No results
if($number_of_results == 0) return $engine_temp;
// Scrape recommended
$didyoumean = $xpath->query(".//section[@class='dym-c']/section/h3/a")[0];
if(!is_null($didyoumean)) {
$engine_result['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//section[@class='dym-c']/section/h5/a")[0];
if(!is_null($search_specific)) {
$engine_result['search_specific'] = $search_specific->textContent;
}
foreach($scrape as $result) {
// Find data
$image_thumb = $xpath->evaluate(".//img/@src", $result);
$url_data = $xpath->evaluate(".//a/@href", $result);
// 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)
// rurl = Url to page where the image is used
// size = Image size (413.1KB)
// tt = Website title (Used for image alt text)
foreach(explode('&', strstr($url_data[0]->textContent, '?')) as &$meta) {
if(!empty($meta)) {
$value = explode('=', trim($meta));
if(!empty($value[0]) && !empty($value[1])) {
$usable_data[$value[0]] = urldecode($value[1]);
}
}
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']);
$alt = (array_key_exists('tt', $usable_data)) ? sanitize($usable_data['tt']) : null;
$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;
// Fix incomplete image url
if(!is_null($image_full)) {
$is_https = parse_url($url);
if($is_https['scheme'] == 'https') {
$image_full = 'https://'.$image_full;
} else if($is_https['scheme'] == 'http') {
$image_full = 'http://'.$image_full;
} else {
$image_full = '//'.$image_full;
}
}
// 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
'url' => $url, // string
'engine_rank' => $rank, // int
// Optional
'alt' => $alt, // string | null
'width' => $dimensions_w, // int | null
'height' => $dimensions_h, // int | null
'filesize' => $filesize, // int | null
);
$rank -= 1;
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Yahoo! Images';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $rank);
return $engine_result;
}
}
?>

View file

@ -1,137 +0,0 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class YahooImageRequest extends EngineRequest {
public function get_request_url() {
// Split the query
$query_terms = explode(" ", strtolower($this->query));
// Size override
$size = "";
if($query_terms[0] == 'size') {
$switch = explode(":", $query_terms[0]);
if((strlen($switch[1]) >= 3 && strlen($switch[1]) <= 6) && !is_numeric($switch[1])) {
if($switch[1] == "med") $switch[1] = "medium";
if($switch[1] == "lrg") $switch[1] = "large";
if($switch[1] == "xlrg") $switch[1] = "wallpaper";
if($switch[1] == "small" || $switch[1] == "medium" || $switch[1] == "large" || $switch[1] == "wallpaper") {
$size = $switch[1];
}
$this->query = implode(" ", array_slice($query_terms, 1));
}
}
// p = query
// imgsz = Image size (small|medium|large|wallpaper)
$args = array("p" => $this->query, "imgsz" => $size);
$url = "https://images.search.yahoo.com/search/images?".http_build_query($args);
unset($query_terms, $switch, $size, $args);
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) {
$results = array();
$xpath = get_xpath($response);
if(!$xpath) return array();
// Scrape recommended
$didyoumean = $xpath->query(".//section[@class='dym-c']/section/h3/a")[0];
if(!is_null($didyoumean)) {
$results['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//section[@class='dym-c']/section/h5/a")[0];
if(!is_null($search_specific)) {
$results['search_specific'] = $search_specific->textContent;
}
// Scrape the results
// $scrape = $xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'slotting'))][position() < 101]");
$scrape = $xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'ignore'))][position() < 101]");
// Set base rank and result amound
$rank = $results['amount'] = count($scrape);
// Nothing found
if($results['amount'] == 0) return $results;
foreach($scrape as $result) {
$image_thumb = $xpath->evaluate(".//img/@src", $result)[0];
if(is_null($image_thumb)) continue;
$url_data = $xpath->evaluate(".//a/@href", $result)[0];
if(is_null($url_data)) 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)
// rurl = Url to page where the image is used
// size = Image size (413.1KB)
// tt = Website title (Used for image alt text)
foreach(explode("&", strstr($url_data->textContent, '?')) as &$meta) {
if(!is_null($meta) || !empty($meta)) {
$value = explode("=", trim($meta));
if(!empty($value[0]) && !empty($value[1])) {
$usable_data[$value[0]] = urldecode($value[1]);
}
}
unset($meta, $value);
}
// Deal with optional or missing data
$dimensions_w = (!array_key_exists('w', $usable_data)) ? "" : sanitize($usable_data['w']);
$dimensions_h = (!array_key_exists('h', $usable_data)) ? "" : sanitize($usable_data['h']);
$image_full = (!array_key_exists('imgurl', $usable_data)) ? "" : "//".sanitize($usable_data['imgurl']);
$link = (!array_key_exists('rurl', $usable_data)) ? "" : sanitize($usable_data['rurl']);
$filesize = (!array_key_exists('size', $usable_data)) ? "" : sanitize($usable_data['size']);
$alt = (!array_key_exists('tt', $usable_data)) ? "" : sanitize($usable_data['tt']);
// Process result
$image_thumb = sanitize($image_thumb->textContent);
$filesize = intval(preg_replace('/[^0-9.]/', '', $filesize) * 1000);
// filter duplicate IMAGE urls/results
if(!empty($results['search'])) {
if(in_array($image_full, array_column($results['search'], "image_full"))) continue;
}
$results['search'][] = array ("id" => uniqid(rand(0, 9999)), "source" => "Yahoo! Images", "image_thumb" => $image_thumb, "alt" => $alt, "image_full" => $image_full, "width" => $dimensions_w, "height" => $dimensions_h, "filesize" => $filesize, "webpage_url" => $link, "engine_rank" => $rank);
$rank -= 1;
unset($url_data, $usable_data, $dimensions_w, $dimensions_h, $filesize, $link, $image_full, $alt, $image_thumb);
}
unset($response, $xpath, $scrape, $rank);
// Add error if there are no search results
if(empty($results['search'])) {
$results['error'] = array(
"message" => "No results found. Please try with less or different keywords!"
);
}
return $results;
}
}
?>

BIN
engines/magnet/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,16 +11,18 @@
------------------------------------------------------------------------------------ */
class EZTVRequest extends EngineRequest {
public function get_request_url() {
$query = preg_replace('/[^0-9]/', '', $this->query);
if(strlen($query) == 0) $query = "0000";
$query = preg_replace('/[^0-9]+/', '', $this->query);
// Is there no query left? Bail!
if(empty($query)) return false;
// Is eztvx.to blocked for you? Use one of these urls as an alternative
// eztv1.xyz, eztv.wf, eztv.tf, eztv.yt
$url = "https://eztvx.to/api/get-torrents?".http_build_query(array("imdb_id" => $query));
unset($query);
return $url;
// Try: eztv1.xyz, eztv.wf, eztv.tf, eztv.yt
$url = 'https://eztvx.to/api/get-torrents?imdb_id='.urlencode($query);
unset($query);
return $url;
}
public function get_request_headers() {
@ -28,7 +30,6 @@ class EZTVRequest extends EngineRequest {
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
@ -36,53 +37,81 @@ class EZTVRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response['torrents_count'] == 0) return $results;
// Use API result
if(empty($json_response)) return $engine_temp;
// No results
if($json_response['torrents_count'] == 0) return $engine_temp;
foreach($json_response['torrents'] as $result) {
$name = sanitize($result['title']);
$magnet = sanitize($result['magnet_url']);
$hash = strtolower(sanitize($result['hash']));
$magnet = sanitize($result['magnet_url']);
$seeders = sanitize($result['seeds']);
$leechers = sanitize($result['peers']);
$size = sanitize($result['size_bytes']);
$filesize = human_filesize(sanitize($result['size_bytes']));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
// Get extra data
$quality = (preg_match('/(480p|720p|1080p|2160p)/i', $name, $quality)) ? $quality[0] : "";
$codec = (preg_match('/(x264|h264|x265|h265|xvid)/i', $name, $codec)) ? $codec[0] : "";
$date_added = sanitize($result['date_released_unix']);
// Filter by Season (S01) or Season and Episode (S01E01)
// Where [0][0] = Season and [0][1] = Episode
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Clean up season and episode number
$season = sanitize($result['season']);
if($season < 10) $season = '0'.$season;
$episode = sanitize($result['episode']);
if($episode < 10) $episode = '0'.$episode;
if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/i", $this->query, $filter_episode)) {
if(str_ireplace("s0", "", $filter_episode[0][0]) != $season || (array_key_exists(1, $filter_episode[0]) && str_ireplace("e0", "", $filter_episode[0][1]) != $episode)) {
continue;
}
}
$results[] = array (
// Throw out mismatched episodes
if(!is_season_or_episode($this->query, 'S'.$season.'E'.$episode)) continue;
// Get extra data
$date_added = (array_key_exists('date_released_unix', $result)) ? timezone_offset($result['date_released_unix'], $this->opts->timezone) : null;
$quality = find_video_quality($name);
$codec = find_video_codec($name);
$audio = find_audio_codec($name);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
// Clean up show name
$name = (preg_match('/.+?(?=[0-9]{3,4}p)|xvid|divx|(x|h)26(4|5)/i', $name, $clean_name)) ? $clean_name[0] : $name; // Break off show name before video resolution
$name = str_replace(array('S0E0', 'S00E00'), '', $name); // Strip empty season/episode indicator from name
$engine_temp[] = array (
// Required
"id" => uniqid(rand(0, 9999)), "source" => "EZTV", "name" => $name, "magnet" => $magnet, "hash" => $hash, "seeders" => $seeders, "leechers" => $leechers, "size" => human_filesize($size),
// Extra
"quality" => $quality, "codec" => $codec, "date_added" => $date_added
'hash' => $hash, // string
'name' => $name, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'date_added' => $date_added, // int(timestamp)|null
'category' => null, // string|null
'url' => null // string|null
);
unset($result, $season, $episode, $name, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $date_added);
}
unset($json_response);
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'EZTV';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $engine_temp);
return $results;
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,10 +11,18 @@
------------------------------------------------------------------------------------ */
class LimeRequest extends EngineRequest {
public function get_request_url() {
$this->query = preg_replace("/[^a-z0-9- ]+/", "", $this->query);
$this->query = str_replace(" ", "-", $this->query);
$url = "https://www.limetorrents.lol/search/all/".$this->query."/";
return $url;
$query = str_replace('%22', '\"', $this->query);
$query = preg_replace('/[^a-z0-9- ]+/', '', $query);
$query = strtolower(str_replace(' ', '-', $query));
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://www.limetorrents.lol/search/all/'.$query.'/';
unset($query);
return $url;
}
public function get_request_headers() {
@ -24,44 +32,106 @@ class LimeRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// Failed to load page
if(!$xpath) return $results;
// No response
if(!$xpath) return $engine_temp;
// Scrape the page
foreach($xpath->query("//table[@class='table2']//tr[position()>1]") as $result) {
$name = sanitize($xpath->evaluate(".//td[@class='tdleft']//a[2]", $result)[0]->textContent);
$hash = sanitize($xpath->evaluate(".//td[@class='tdleft']//a[1]/@href", $result)[0]->textContent);
$hash = explode("/", substr($hash, 0, strpos($hash, ".torrent?")));
// Scrape the results
$scrape = $xpath->query("//table[@class='table2']//tr[position() > 1]");
// No results
if(count($scrape) == 0) return $engine_temp;
foreach($scrape as $result) {
// Find data
$name = $xpath->evaluate(".//td[@class='tdleft']//a[2]", $result);
$hash = $xpath->evaluate(".//td[@class='tdleft']//a[1]/@href", $result);
$seeders = $xpath->evaluate(".//td[@class='tdseed']", $result);
$leechers = $xpath->evaluate(".//td[@class='tdleech']", $result);
$filesize = $xpath->evaluate(".//td[@class='tdnormal'][2]", $result);
// Skip broken results
if($name->length == 0) continue;
if($hash->length == 0) continue;
// Process data
$name = sanitize($name[0]->textContent);
$hash = sanitize($hash[0]->textContent);
$hash = explode('/', substr($hash, 0, strpos($hash, '.torrent?')));
$hash = strtolower($hash[array_key_last($hash)]);
$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->magnet_trackers);
$seeders = sanitize($xpath->evaluate(".//td[@class='tdseed']", $result)[0]->textContent);
$leechers = sanitize($xpath->evaluate(".//td[@class='tdleech']", $result)[0]->textContent);
$size = sanitize($xpath->evaluate(".//td[@class='tdnormal'][2]", $result)[0]->textContent);
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($name).'&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;
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Get extra data
$category = explode(" ", trim(sanitize($xpath->evaluate(".//td[@class='tdnormal'][1]", $result)[0]->textContent), ".,"));
$category = $category[array_key_last($category)];
$url = "https://www.limetorrents.lol".sanitize($xpath->evaluate(".//td[@class='tdleft']//a[2]/@href", $result)[0]->textContent);
// Filter episodes
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->query, $name)) continue;
$results[] = array (
// Find extra data
$category = $xpath->evaluate(".//td[@class='tdnormal'][1]", $result);
$url = $xpath->evaluate(".//td[@class='tdleft']//a[2]/@href", $result);
// Process extra data
if($category->length > 0) {
$category = explode(' - ', sanitize($category[0]->textContent));
$category = str_replace('in ', '', $category[array_key_last($category)]);
$category = (preg_match('/[a-z0-9 -]+/i', $category, $category)) ? $category[0] : null;
} else {
$category = null;
}
$url = ($url->length > 0) ? 'https://www.limetorrents.lol'.sanitize($url[0]->textContent) : null;
$quality = $codec = $audio = null;
if(in_array(strtolower($category), array('movies', 'tv shows', 'anime'))) {
$quality = find_video_quality($name);
$codec = find_video_codec($name);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
}
if(in_array(strtolower($category), array('music', 'movies', 'tv shows', 'anime'))) {
$audio = find_audio_codec($name);
}
$engine_temp[] = array (
// Required
"id" => uniqid(rand(0, 9999)), "source" => "limetorrents.lol", "name" => $name, "magnet" => $magnet, "hash" => $hash, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
// Extra
"category" => $category, "url" => $url
'hash' => $hash, // string
'name' => $name, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'date_added' => null, // int(timestamp)|null
'category' => $category, // string|null
'url' => $url // string|null
);
unset($result, $name, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $audio, $category, $url);
}
unset($response, $xpath);
return $results;
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'limetorrents.lol';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,11 +11,15 @@
------------------------------------------------------------------------------------ */
class NyaaRequest extends EngineRequest {
public function get_request_url() {
$args = array("q" => $this->query);
$url = "https://nyaa.si/?".http_build_query($args);
$query = str_replace('%22', '\"', $this->query);
unset($args);
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://nyaa.si/?q='.urlencode($query);
unset($query);
return $url;
}
@ -26,49 +30,100 @@ class NyaaRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// Failed to load page
if(!$xpath) return $results;
// No response
if(!$xpath) return $engine_temp;
// Scrape the page
foreach($xpath->query("//tbody/tr") as $result) {
// Scrape the results
$scrape = $xpath->query("//tbody/tr");
// No results
if(count($scrape) == 0) return $engine_temp;
foreach($scrape as $result) {
// Find data
$meta = $xpath->evaluate(".//td[@class='text-center']", $result);
$name = sanitize($xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result)[0]->textContent);
$magnet = sanitize($xpath->evaluate(".//a[2]/@href", $meta[0])[0]->textContent);
$hash = parse_url($magnet, PHP_URL_QUERY);
parse_str($hash, $hash_parameters);
$hash = strtolower(str_replace("urn:btih:", "", $hash_parameters['xt']));
$name = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result);
$magnet = $xpath->evaluate(".//a[2]/@href", $meta[0]);
// Skip broken results
if($name->length == 0) continue;
if($magnet->length == 0) $magnet = $xpath->evaluate(".//a/@href", $meta[0]); // This matches if no torrent file is provided on the page
if($magnet->length == 0) continue;
// Process data
$name = sanitize($name[0]->textContent);
$magnet = sanitize($magnet[0]->textContent);
parse_str(parse_url($magnet, PHP_URL_QUERY), $hash_parameters);
$hash = strtolower(str_replace('urn:btih:', '', $hash_parameters['xt']));
$seeders = sanitize($meta[3]->textContent);
$leechers = sanitize($meta[4]->textContent);
$size = str_replace("GiB", "GB", str_replace("MiB", "MB", sanitize($meta[1]->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)))))));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Get extra data
$category = sanitize($xpath->evaluate(".//td[1]//a/@title", $result)[0]->textContent);
$category = str_replace(" - ", "/", $category);
$url = "https://nyaa.si".sanitize($xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result)[0]->textContent);
$date_added = sanitize($meta[2]->textContent);
$date_added = explode("-", substr($date_added, 0, 10));
$date_added = mktime(0, 0, 0, intval($date_added[1]), intval($date_added[2]), intval($date_added[0]));
// Filter episodes
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->query, $name)) continue;
$results[] = array (
// Required
"id" => uniqid(rand(0, 9999)), "source" => "nyaa.si", "name" => $name, "magnet" => $magnet, "hash" => $hash, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
// Extra
"category" => $category, "url" => $url, "date_added" => $date_added
);
}
unset($response, $xpath);
// Find extra data
$category = $xpath->evaluate(".//td[1]//a/@title", $result);
$url = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result);
return $results;
// Process extra data
$category = ($category->length > 0) ? str_replace(' - ', '/', sanitize($category[0]->textContent)) : null;
$url = ($url->length > 0) ? 'https://nyaa.si'.sanitize($url[0]->textContent) : null;
$date_added = explode('-', substr(sanitize($meta[2]->textContent), 0, 10));
$date_added = timezone_offset(gmmktime(0, 0, 0, intval($date_added[1]), intval($date_added[2]), intval($date_added[0])), $this->opts->timezone);
$quality = $codec = $audio = null;
if(in_array(strtolower($category), array('anime/anime music video', 'anime/non-english-translated', 'anime/english-translated', 'anime/raw', 'live action/english-translated', 'live action/non-english-translated', 'live action/idol/promotional video', 'live action/raw'))) {
$quality = find_video_quality($name);
$codec = find_video_codec($name);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
}
if(in_array(strtolower($category), array('audio/lossless', 'audio/lossy', 'anime/anime music video', 'anime/non-english-translated', 'anime/english-translated', 'anime/raw', 'live action/english-translated', 'live action/non-english-translated', 'live action/idol/promotional video', 'live action/raw'))) {
$audio = find_audio_codec($name);
}
$engine_temp[] = array (
// Required
'hash' => $hash, // string
'name' => $name, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'date_added' => $date_added, // int(timestamp)|null
'category' => $category, // string|null
'url' => $url // string|null
);
unset($result, $name, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $audio, $category, $url, $date_added);
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'nyaa.si';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $engine_temp);
return $engine_result;
}
}
?>

126
engines/magnet/sukebei.php Normal file
View file

@ -0,0 +1,126 @@
<?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 SukebeiRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://sukebei.nyaa.si/?q='.urlencode($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',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) return $engine_temp;
// Scrape the results
$scrape = $xpath->query("//tbody/tr");
// No results
if(count($scrape) == 0) return $engine_temp;
foreach($scrape as $result) {
// Find data
$meta = $xpath->evaluate(".//td[@class='text-center']", $result);
$name = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result);
$magnet = $xpath->evaluate(".//a[2]/@href", $meta[0]);
// Skip broken results
if($name->length == 0) continue;
if($magnet->length == 0) $magnet = $xpath->evaluate(".//a/@href", $meta[0]); // This matches if no torrent file is provided on the page
if($magnet->length == 0) continue;
// Process data
$name = sanitize($name[0]->textContent);
$magnet = sanitize($magnet[0]->textContent);
parse_str(parse_url($magnet, PHP_URL_QUERY), $hash_parameters);
$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)))))));
// 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->query, $name)) continue;
// Find extra data
$category = $xpath->evaluate(".//td[1]//a/@title", $result);
$url = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result);
// Process extra data
$category = ($category->length > 0) ? str_replace(' - ', '/', sanitize($category[0]->textContent)) : null;
$url = ($url->length > 0) ? 'https://sukebei.nyaa.si'.sanitize($url[0]->textContent) : null;
$date_added = explode('-', substr(sanitize($meta[2]->textContent), 0, 10));
$date_added = timezone_offset(gmmktime(0, 0, 0, intval($date_added[1]), intval($date_added[2]), intval($date_added[0])), $this->opts->timezone);
$quality = $codec = $audio = null;
if(in_array(strtolower($category), array('art/anime', 'real life/videos'))) {
$quality = find_video_quality($name);
$codec = find_video_codec($name);
$audio = find_audio_codec($name);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
}
$engine_temp[] = array (
// Required
'hash' => $hash, // string
'name' => $name, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'date_added' => $date_added, // int(timestamp)|null
'category' => $category, // string|null
'url' => $url // string|null
);
unset($result, $name, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $audio, $category, $url, $date_added);
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'sukebei.nyaa.si';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,11 +11,15 @@
------------------------------------------------------------------------------------ */
class PirateBayRequest extends EngineRequest {
public function get_request_url() {
$args = array("q" => $this->query);
$url = "https://apibay.org/q.php?".http_build_query($args);
$query = str_replace('%22', '\"', $this->query);
unset($args);
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://apibay.org/q.php?q='.urlencode($query);
unset($query);
return $url;
}
@ -24,7 +28,6 @@ class PirateBayRequest extends EngineRequest {
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
@ -32,110 +35,153 @@ class PirateBayRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
if(empty($json_response)) return $engine_temp;
// No results
if($json_response[0]['name'] == 'No results returned') return $engine_temp;
$categories = array(
100 => "Audio",
101 => "Music",
102 => "Audio Book",
103 => "Sound Clips",
104 => "Audio FLAC",
199 => "Audio Other",
100 => 'Audio',
101 => 'Music',
102 => 'Audio Book',
103 => 'Sound Clips',
104 => 'Audio FLAC',
199 => 'Audio Other',
200 => "Video",
201 => "Movie",
202 => "Movie DVDr",
203 => "Music Video",
204 => "Movie Clip",
205 => "TV Show",
206 => "Handheld",
207 => "HD Movie",
208 => "HD TV Show",
209 => "3D Movie",
210 => "CAM/TS",
211 => "UHD/4K Movie",
212 => "UHD/4K TV Show",
299 => "Video Other",
200 => 'Video',
201 => 'Movie',
202 => 'Movie DVDr',
203 => 'Music Video',
204 => 'Movie Clip',
205 => 'TV Show',
206 => 'Handheld',
207 => 'HD Movie',
208 => 'HD TV Show',
209 => '3D Movie',
210 => 'CAM/TS',
211 => 'UHD/4K Movie',
212 => 'UHD/4K TV Show',
299 => 'Video Other',
300 => "Applications",
301 => "Apps Windows",
302 => "Apps Apple",
303 => "Apps Unix",
304 => "Apps Handheld",
305 => "Apps iOS",
306 => "Apps Android",
399 => "Apps Other OS",
300 => 'Applications',
301 => 'Apps Windows',
302 => 'Apps Apple',
303 => 'Apps Unix',
304 => 'Apps Handheld',
305 => 'Apps iOS',
306 => 'Apps Android',
399 => 'Apps Other OS',
400 => "Games",
401 => "Games PC",
402 => "Games Apple",
403 => "Games PSx",
404 => "Games XBOX360",
405 => "Games Wii",
406 => "Games Handheld",
407 => "Games iOS",
408 => "Games Android",
499 => "Games Other OS",
400 => 'Games',
401 => 'Games PC',
402 => 'Games Apple',
403 => 'Games PSx',
404 => 'Games XBOX360',
405 => 'Games Wii',
406 => 'Games Handheld',
407 => 'Games iOS',
408 => 'Games Android',
499 => 'Games Other OS',
500 => "Porn",
501 => "Porn Movie",
502 => "Porn Movie DVDr",
503 => "Porn Pictures",
504 => "Porn Games",
505 => "Porn HD Movie",
506 => "Porn Movie Clip",
507 => "Porn UHD/4K Movie",
599 => "Porn Other",
500 => 'Porn',
501 => 'Porn Movie',
502 => 'Porn Movie DVDr',
503 => 'Porn Pictures',
504 => 'Porn Games',
505 => 'Porn HD Movie',
506 => 'Porn Movie Clip',
507 => 'Porn UHD/4K Movie',
599 => 'Porn Other',
600 => "Other",
601 => "Other E-Book",
602 => "Other Comic",
603 => "Other Pictures",
604 => "Other Covers",
605 => "Other Physibles",
699 => "Other Other"
600 => 'Other',
601 => 'Other E-Book',
602 => 'Other Comic',
603 => 'Other Pictures',
604 => 'Other Covers',
605 => 'Other Physibles',
699 => 'Other Other'
);
// Use API result
foreach($json_response as $result) {
// Nothing found
if($result['name'] == "No results returned") break;
// Find and process data
$name = sanitize($result['name']);
$hash = strtolower(sanitize($result['info_hash']));
$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->magnet_trackers);
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($name).'&tr='.implode('&tr=', $this->opts->magnet_trackers);
$seeders = sanitize($result['seeders']);
$leechers = sanitize($result['leechers']);
$size = sanitize($result['size']);
$filesize = human_filesize(sanitize($result['size']));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Get extra data
$category = sanitize($result['category']);
$url = "https://thepiratebay.org/description.php?id=".sanitize($result['id']);
$date_added = sanitize($result['added']);
// Block these categories
if(in_array($category, $this->opts->piratebay_categories_blocked)) continue;
// Filter episodes
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->query, $name)) continue;
$results[] = array(
// Required
"id" => uniqid(rand(0, 9999)), "source" => "thepiratebay.org", "name" => $name, "magnet" => $magnet, "hash" => $hash, "seeders" => $seeders, "leechers" => $leechers, "size" => human_filesize($size),
// Extra
"category" => $categories[$category], "url" => $url, "date_added" => $date_added,
);
}
unset($json_response);
// Find extra data
$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;
$date_added = (array_key_exists('added', $result)) ? timezone_offset(sanitize($result['added']), $this->opts->timezone) : null;
return $results;
// Process extra data
if(!is_null($category)) {
// Block these categories
if(in_array($category, $this->opts->piratebay_categories_blocked)) continue;
// Detect technical data
$quality = $codec = $audio = null;
if(($category >= 200 && $category < 300) || ($category >= 500 && $category < 600)) {
$quality = find_video_quality($name);
$codec = find_video_codec($name);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
}
if(($category >= 100 && $category < 200) || ($category >= 200 && $category < 300) || ($category >= 500 && $category < 600)) {
$audio = find_audio_codec($name);
}
// Set actual category
$category = $categories[$category];
}
$engine_temp[] = array(
// Required
'hash' => $hash, // string
'name' => $name, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'date_added' => $date_added, // int(timestamp)|null
'category' => $category, // string|null
'url' => $url // string|null
);
unset($result, $name, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $audio, $category, $url, $date_added);
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'thepiratebay.org';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $engine_temp, $categories);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,8 +11,15 @@
------------------------------------------------------------------------------------ */
class YTSRequest extends EngineRequest {
public function get_request_url() {
$url = "https://yts.mx/api/v2/list_movies.json?".http_build_query(array("query_term" => $this->query));
$query = str_replace('%22', '\"', $this->query);
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://yts.mx/api/v2/list_movies.json?query_term='.urlencode($query);
unset($query);
return $url;
}
@ -21,7 +28,6 @@ class YTSRequest extends EngineRequest {
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
@ -29,61 +35,89 @@ class YTSRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
// $response = curl_multi_getcontent($this->ch);
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response['status'] != "ok" || $json_response['data']['movie_count'] == 0) return $results;
// Use API result
foreach ($json_response['data']['movies'] as $result) {
// Prevent gaps
if(!array_key_exists("year", $result)) $result['year'] = 0;
if(!array_key_exists("genres", $result)) $result['genres'] = array();
if(!array_key_exists("runtime", $result)) $result['runtime'] = 0;
if(!array_key_exists("url", $result)) $result['url'] = '';
// Block these categories
if(count(array_uintersect($result['genres'], $this->opts->yts_categories_blocked, "strcasecmp")) > 0) continue;
if(empty($json_response)) return $engine_temp;
// No results
if($json_response['data']['movie_count'] == 0) return $engine_temp;
foreach($json_response['data']['movies'] as $result) {
// Find and process data
$name = sanitize($result['title']);
// Find extra data
$year = (array_key_exists('year', $result)) ? sanitize($result['year']) : null;
$category = (array_key_exists('genres', $result)) ? $result['genres'] : null; // Sanitized later
$runtime = (array_key_exists('runtime', $result)) ? date('H:i', mktime(0, sanitize($result['runtime']))) : null;
$url = (array_key_exists('url', $result)) ? sanitize($result['url']) : null;
$date_added = (array_key_exists('date_uploaded_unix', $result)) ? timezone_offset(sanitize($result['date_uploaded_unix']), $this->opts->timezone) : null;
// Get extra data
$year = sanitize($result['year']);
$category = sanitize(implode(', ', $result['genres']));
$runtime = sanitize($result['runtime']);
$url = sanitize($result['url']);
$date_added = sanitize($result['date_uploaded_unix']);
// Process extra data
if(!is_null($category)) {
// Block these categories
if(count(array_uintersect($category, $this->opts->yts_categories_blocked, 'strcasecmp')) > 0) continue;
// Set actual category
$category = sanitize(implode(', ', $category));
}
foreach ($result['torrents'] as $download) {
// Find and process data
$hash = strtolower(sanitize($download['hash']));
$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->magnet_trackers);
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($name).'&tr='.implode('&tr=', $this->opts->magnet_trackers);
$seeders = sanitize($download['seeds']);
$leechers = sanitize($download['peers']);
$size = sanitize($download['size']);
$filesize = human_filesize(filesize_to_bytes(sanitize($download['size'])));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Get extra data
$quality = sanitize($download['quality']);
$codec = sanitize($download['video_codec']);
$results[] = array (
// Required
"id" => uniqid(rand(0, 9999)), "source" => "yts.mx", "name" => $name, "magnet" => $magnet, "hash" => $hash, "seeders" => $seeders, "leechers" => $leechers, "size" => $size,
// Extra
"quality" => $quality, "codec" => $codec, "year" => $year, "category" => $category, "runtime" => $runtime, "url" => $url, "date_added" => $date_added
);
}
}
unset($json_response);
// Find extra data
$quality = (array_key_exists('quality', $download)) ? sanitize(strtolower($download['quality'])) : null;
$codec = (array_key_exists('video_codec', $download)) ? sanitize(strtolower($download['video_codec'])) : null;
$type = (array_key_exists('type', $download)) ? ucfirst(sanitize(strtolower($download['type']))) : null;
$audio = (array_key_exists('audio_channels', $download)) ? sanitize('AAC '.$download['audio_channels']) : null;
return $results;
// Process extra data
if(!empty($codec)) $quality = $quality.' '.$codec;
$engine_temp[] = array (
// Required
'hash' => $hash, // string
'name' => $name, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'quality' => $quality, // string|null
'type' => $type, // string|null
'audio' => $audio, // string|null
'year' => $year, // int(4)|null
'category' => $category, // string|null
'runtime' => $runtime, // int(timestamp)|null
'url' => $url, // string|null
'date_added' => $date_added // int(timestamp)|null
);
unset($download, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $type, $audio);
}
unset($result, $name, $year, $category, $runtime, $url, $date_added);
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'yts.mx';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $engine_temp);
return $engine_result;
}
}
?>
?>

BIN
engines/news/.DS_Store vendored Normal file

Binary file not shown.

135
engines/news/brave-news.php Normal file
View file

@ -0,0 +1,135 @@
<?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 BraveNewsRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
$query_terms = explode(' ', $query);
$query_terms[0] = strtolower($query_terms[0]);
// Safe search ignore (not supported)
if($query_terms[0] == 'safe:on' || $query_terms[0] == 'safe:off') {
$query = trim(str_replace($query_terms[0], '', $query));
}
// Search range
$today = time() - 86400;
if($query_terms[0] == 'now' || $query_terms[0] == 'today' || $query_terms[0] == 'yesterday') {
// Last 24 hours
$this->opts->result_range = $today;
$age = 'pd';
} else if($query_terms[0] == 'week' || ($query_terms[0] == 'this' && $query_terms[1] == 'week') || $query_terms[0] == 'recent') {
// Last 7 days
$this->opts->result_range = $today - (6 * 86400);
$age = 'pw';
} else if($query_terms[0] == 'year' || ($query_terms[0] == 'this' && $query_terms[1] == 'year')) {
// This year
$this->opts->result_range = timezone_offset(gmmktime(0, 0, 0, 1, 1, gmdate('Y')), $this->opts->timezone);
$age = 'py';
} else {
// This month (default)
$this->opts->result_range = timezone_offset(gmmktime(0, 0, 0, gmdate('m'), 1, gmdate('Y')), $this->opts->timezone);
$age = 'pm';
}
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://search.brave.com/news?'.http_build_query(array(
'q' => $query, // Search query
'offset' => 0, // Start on 'page' 1 of results (0 = 1)
'spellcheck' => 0, // No spellcheck on your query
'source' => 'web', // Where are you searching from? (Web)
'tf' => $age // How old may the article be?
));
unset($query, $query_terms, $today, $age);
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) return $engine_temp;
// Scrape the results (Max 30)
$scrape = $xpath->query("//main[contains(@class, 'main-column')]//div[contains(@class, 'snippet')][position() < 30]");
// Figure out results and base rank
$number_of_results = $rank = count($scrape);
// No results
if($number_of_results == 0) return $engine_temp;
foreach($scrape as $result) {
// Find data
$title = $xpath->evaluate(".//a[contains(@class, 'result-header')]//span[contains(@class, 'snippet-title')]", $result);
$url = $xpath->evaluate(".//a[contains(@class, 'result-header')]/@href", $result);
$description = $xpath->evaluate(".//p[contains(@class, 'snippet-description')]", $result);
$date_added = $xpath->evaluate(".//cite[contains(@class, 'snippet-url')]/span[2]", $result);
// Skip broken results
if($title->length == 0) continue;
if($url->length == 0) continue;
// Process data
$title = strip_newlines(sanitize($title[0]->textContent));
$url = sanitize($url[0]->textContent);
// $url = (strpos($url, "/a/redirect?click_url=", 0) !== false) ? "https://search.brave.com".$url : $url;
$description = ($description->length == 0) ? "No description was provided for this site." : limit_string_length(strip_newlines(sanitize($description[0]->textContent)));
$source = str_replace('www.', '', strtolower(parse_url($url, PHP_URL_HOST)));
$date_added = ($date_added->length == 0) ? null : timezone_offset(strtotime(sanitize($date_added[0]->textContent)), $this->opts->timezone);
// filter duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
// Ignore results that are too old
if(isset($this->opts->result_range) && !is_null($date_added)) {
if($date_added < $this->opts->result_range) continue;
}
$engine_temp[] = array(
'title' => $title, // string
'url' => $url, // string
'description' => $description, // string
'source' => $source, // string
'date_added' => $date_added, // int (timestamp)
'engine_rank' => $rank // int
);
$rank -= 1;
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Brave News';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

132
engines/news/hackernews.php Normal file
View file

@ -0,0 +1,132 @@
<?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 HackernewsRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
$query_terms = explode(' ', $query);
$query_terms[0] = strtolower($query_terms[0]);
// Safe search ignore (not supported)
if($query_terms[0] == 'safe:on' || $query_terms[0] == 'safe:off') {
$query = trim(str_replace($query_terms[0], '', $query));
}
// Search range
$today = time() - 86400;
if($query_terms[0] == 'now' || $query_terms[0] == 'today' || $query_terms[0] == 'yesterday') {
// Last 24 hours
$this->opts->result_range = $today;
$age = 'created_at_i>'.$this->opts->result_range.',created_at_i<'.$today; // Yesterday
} else if($query_terms[0] == 'week' || ($query_terms[0] == 'this' && $query_terms[1] == 'week') || $query_terms[0] == 'recent') {
// Last 7 days
$this->opts->result_range = $today - (6 * 86400);
$age = 'created_at_i>'.$this->opts->result_range; // This week
} else if($query_terms[0] == 'year' || ($query_terms[0] == 'this' && $query_terms[1] == 'year')) {
// This year
$this->opts->result_range = timezone_offset(gmmktime(0, 0, 0, 1, 1, gmdate('Y')), $this->opts->timezone);
$age = 'created_at_i>'.$this->opts->result_range;
} else {
// This month (default)
$this->opts->result_range = timezone_offset(gmmktime(0, 0, 0, gmdate('m'), 1, gmdate('Y')), $this->opts->timezone);
$age = 'created_at_i>'.$this->opts->result_range;
}
// Is there no query left? Bail!
if(empty($query)) return false;
// More info on https://hn.algolia.com/api
$url = 'http://hn.algolia.com/api/v1/search_by_date?'.http_build_query(array(
'query' => $query, // Search query
'tags' => 'story', // What type of results to show? (story = News stories)
'hitsPerPage' => 30, // How many results to return?
'restrictSearchableAttributes' => 'title,url', // Only match on URLs
'attributesToRetrieve' => '_tags,title,url,author,created_at_i', // Data to retrieve
'numericFilters' => $age // How old may the article be?
));
unset($query, $query_terms, $today, $age);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'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)) return $engine_temp;
// Figure out results and base rank
$number_of_results = $rank = count($json_response['hits']);
// No results
if($number_of_results == 0) return $engine_temp;
foreach($json_response['hits'] as $result) {
// Skip broken/wrong results
if(!empty(array_intersect(array('ask_hn', 'show_hn'), $result['_tags']))) continue;
if(!array_key_exists('url', $result)) continue;
// Find and process data
$title = strip_newlines(sanitize($result['title']));
$url = sanitize($result['url']);
$description = (array_key_exists('story_text', $result)) ? limit_string_length(strip_newlines(sanitize($result['story_text']))) : $title;
$source = str_replace('www.', '', strtolower(parse_url($url, PHP_URL_HOST)));
$date_added = timezone_offset(sanitize($result['created_at_i']), $this->opts->timezone);
// Skip duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
// Ignore results that are too old
if(isset($this->opts->result_range)) {
if($date_added < $this->opts->result_range) continue;
}
$engine_temp[] = array (
'title' => $title, // string
'url' => $url, // string
'description' => $description, // string
'source' => $source, // string
'date_added' => $date_added, // int (timestamp)
'engine_rank' => $rank // int
);
$rank -= 1;
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Hackernews';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

4
engines/news/index.php Normal file
View file

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

133
engines/news/qwant-news.php Normal file
View file

@ -0,0 +1,133 @@
<?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 QwantNewsRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
// Safe search override
$safe = '1'; // Moderate results
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
if($matches[2] == 'on') $safe = '2';
if($matches[2] == 'off') $safe = '0';
$query = trim(str_replace($matches[0], '', $query));
}
unset($matches);
// Set locale
$language = (preg_match('/[a-z]{2}_[a-z]{2}/i', $this->opts->qwant_language) && strlen($this->opts->qwant_language) == 5) ? strtolower($this->opts->qwant_language) : 'en_gb';
$query_terms = explode(' ', $query);
$query_terms[0] = strtolower($query_terms[0]);
// Search range
$today = time() - 86400;
if($query_terms[0] == 'now' || $query_terms[0] == 'today' || $query_terms[0] == 'yesterday') {
// Last 24 hours
$this->opts->result_range = $today;
$age = 'day';
} else if($query_terms[0] == 'week' || ($query_terms[0] == 'this' && $query_terms[1] == 'week') || $query_terms[0] == 'recent') {
// Last 7 days
$this->opts->result_range = $today - (6 * 86400);
$age = 'week';
} else if($query_terms[0] == 'year' || ($query_terms[0] == 'this' && $query_terms[1] == 'year')) {
// This year
$this->opts->result_range = timezone_offset(gmmktime(0, 0, 0, 1, 1, gmdate('Y')), $this->opts->timezone);
$age = 'all';
} else {
// This month
$this->opts->result_range = timezone_offset(gmmktime(0, 0, 0, gmdate('m'), 1, gmdate('Y')), $this->opts->timezone);
$age = 'month';
}
// Is there no query left? Bail!
if(empty($query)) return false;
// Based on https://github.com/locness3/qwant-api-docs and variables from qwant website
$url = 'https://api.qwant.com/v3/search/news?'.http_build_query(array(
'q' => $query, // Search query
't' => 'news', // News search
'safesearch' => $safe, // Safe search filter (0 = off, 1 = normal, 2 = strict)
'locale' => $language, // Language region
'count' => 30, // How many results? (Maximum 50)
'device' => 'desktop', // Where are you searching from
'source' => 'all', // Where to get the news from (All)
'freshness' => $age, // How old may the article be?
'order' => 'date' // Sort by date
));
unset($query, $query_terms, $safe, $language, $age);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'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)) return $engine_temp;
// Figure out results and base rank
$number_of_results = $rank = $json_response['data']['result']['total'];
// No results
if($number_of_results == 0 || $json_response['status'] == 'error') return $engine_temp;
foreach($json_response['data']['result']['items'] as $result) {
// Find and process data
$title = sanitize($result['title']);
$url = strip_newlines(sanitize($result['url']));
$description = limit_string_length(strip_newlines(sanitize($result['desc'])));
$source = str_replace('www.', '', strtolower(parse_url($url, PHP_URL_HOST)));
$date_added = timezone_offset(sanitize($result['date']), $this->opts->timezone);
// Ignore results that are too old
if(isset($this->opts->result_range)) {
if($date_added < $this->opts->result_range) continue;
}
$engine_temp[] = array(
'title' => $title, // string
'url' => $url, // sting
'description' => $description, // string
'source' => $source, // string
'date_added' => $date_added, // int (timestamp)
'engine_rank' => $rank // int
);
$rank -= 1;
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Qwant News';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

133
engines/news/yahoo-news.php Normal file
View file

@ -0,0 +1,133 @@
<?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 YahooNewsRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
// Safe search override
$safe = ''; // No mature results
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
if($matches[2] == 'on') $safe = '';
if($matches[2] == 'off') $safe = '0';
$query = str_replace($matches[0], '', $query);
}
unset($matches);
$query_terms = explode(' ', $query);
$query_terms[0] = strtolower($query_terms[0]);
// Search range
$today = time() - 86400;
if($query_terms[0] == 'now' || $query_terms[0] == 'today' || $query_terms[0] == 'yesterday') {
// Last 24 hours
$this->opts->result_range = $today;
} else if($query_terms[0] == 'week' || ($query_terms[0] == 'this' && $query_terms[1] == 'week') || $query_terms[0] == 'recent') {
// Last 7 days
$this->opts->result_range = $today - (6 * 86400);
} else if($query_terms[0] == 'year' || ($query_terms[0] == 'this' && $query_terms[1] == 'year')) {
// This year
$this->opts->result_range = timezone_offset(gmmktime(0, 0, 0, 1, 1, gmdate('Y')), $this->opts->timezone);
} else {
// This month
$this->opts->result_range = timezone_offset(gmmktime(0, 0, 0, gmdate('m'), 1, gmdate('Y')), $this->opts->timezone);
}
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://news.search.yahoo.com/search?'.http_build_query(array(
'p' => $query, // Search query
'safe' => $safe // Safe search filter (0 = off, "" = on)
));
unset($query, $query_terms, $safe, $today);
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) return $engine_temp;
// Scrape the results (Max 30)
$scrape = $xpath->query("//div[@id='web']/ol/li[position() < 30]");
// Figure out results and base rank
$number_of_results = $rank = count($scrape);
// No results
if($number_of_results == 0) return $engine_temp;
foreach($scrape as $result) {
// Find data
$title = $xpath->evaluate("./div/ul/li/a[contains(@class, 'thmb')]/@title", $result);
$url = $xpath->evaluate("./div/ul/li/h4[contains(@class, 's-title')]/a/@href", $result);
$description = $xpath->evaluate("./div/ul/li/p[contains(@class, 's-desc')]", $result);
$date_added = $xpath->evaluate("./div/ul/li/span[contains(@class, 's-time')]", $result);
// Skip broken results
if($title->length == 0) continue;
if($url->length == 0) continue;
// Process data
$title = strip_newlines(sanitize($title[0]->textContent));
$url = (preg_match('/\/ru=(.+)(%3ffr|\/rk)/i', $url[0]->textContent, $found_url)) ? urldecode($found_url[1]) : $url[0]->textContent;
$url = (preg_match('/\??&?(utm_).+?(&|$)$/i', $url, $found_url)) ? urldecode($found_url[1]) : $url;
$url = sanitize(str_replace('?fr=sycsrp_catchall', '', $url));
$description = ($description->length == 0) ? "No description was provided for this site." : limit_string_length(strip_newlines(sanitize($description[0]->textContent)));
$source = str_replace('www.', '', strtolower(parse_url($url, PHP_URL_HOST)));
$date_added = ($date_added->length == 0) ? null : timezone_offset(strtotime(sanitize(preg_replace('/[^a-z0-9 ]+/i', '', $date_added[0]->textContent))), $this->opts->timezone);
// filter duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
// Ignore results that are too old
if(isset($this->opts->result_range) && !is_null($date_added)) {
if($date_added < $this->opts->result_range) continue;
}
$engine_temp[] = array(
'title' => $title, // string
'url' => $url, // string
'description' => $description, // string
'source' => $source, // string
'date_added' => $date_added, // int (timestamp)
'engine_rank' => $rank // int
);
$rank -= 1;
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Yahoo News';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -15,18 +15,18 @@ class ImageSearch extends EngineRequest {
public function __construct($opts, $mh) {
$this->requests = array();
if($opts->enable_yahooimages == "on") {
require ABSPATH."engines/image/yahoo.php";
if($opts->enable_yahooimages == 'on') {
require ABSPATH.'engines/image/yahoo-images.php';
$this->requests[] = new YahooImageRequest($opts, $mh);
}
if($opts->enable_openverse == "on") {
require ABSPATH."engines/image/openverse.php";
if($opts->enable_openverse == 'on') {
require ABSPATH.'engines/image/openverse.php';
$this->requests[] = new OpenverseRequest($opts, $mh);
}
if($opts->enable_qwant == "on") {
require ABSPATH."engines/image/qwant.php";
if($opts->enable_qwantimages == 'on') {
require ABSPATH.'engines/image/qwant-images.php';
$this->requests[] = new QwantImageRequest($opts, $mh);
}
}
@ -34,69 +34,78 @@ class ImageSearch extends EngineRequest {
public function parse_results($response) {
$results = array();
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) {
if(array_key_exists('did_you_mean', $engine_result)) {
$results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(array_key_exists('search_specific', $engine_result)) {
$results['search_specific'][] = $engine_result['search_specific'];
}
if(array_key_exists('search', $engine_result)) {
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(array_key_exists('search', $results)) {
$result_urls = array_column($results['search'], "webpage_url", "id");
$found_id = array_search($result['webpage_url'], $result_urls);
} else {
$found_id = false;
}
if($found_id !== false) {
// Duplicate result from another source, merge and rank accordingly
$results['search'][$found_id]['goosle_rank'] += $result['engine_rank'];
} else {
// First find, rank and add to results
$query_terms = explode(" ", preg_replace("/[^a-z0-9 ]+/", "", strtolower($request->query)));
$match_rank = match_count($result['alt'], $query_terms);
// $match_rank += match_count($result['url'], $query_terms);
$match_rank += match_count($result['webpage_url'], $query_terms);
$result['goosle_rank'] = $result['engine_rank'] + $match_rank;
$results['search'][$result['id']] = $result;
}
if(count($this->requests) !== 0) {
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
if(!empty($engine_result)) {
if(array_key_exists('did_you_mean', $engine_result)) {
$results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(array_key_exists('search_specific', $engine_result)) {
$results['search_specific'][] = $engine_result['search_specific'];
}
if(array_key_exists('search', $engine_result)) {
// Count results per source
$results['sources'][$engine_result['source']] = $engine_result['amount'];
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(array_key_exists('search', $results)) {
$result_urls = array_column($results['search'], 'image_full', 'id');
$found_id = array_search($result['image_full'], $result_urls); // Return the result ID, or false if not found
} else {
$found_id = false;
}
if($found_id !== false) {
// Duplicate result from another engine
$results['search'][$found_id]['goosle_rank'] += $result['engine_rank'];
$results['search'][$found_id]['combo_source'][] = $engine_result['source'];
} else {
// First find, rank and add to results
// Replace anything but alphanumeric with a space
$query_terms = explode(' ', preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', strtolower($request->query)));
$match_rank = match_count($result['url'], $query_terms);
$match_rank += match_count($result['alt'], $query_terms);
$result['goosle_rank'] = $result['engine_rank'] + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['image_full']);
$results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank, $query_terms);
}
}
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : '';
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array('title' => get_class($request)." failed with error ".$request_result['http_code'], 'body' => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", 'labels' => 'request-error'));
$results['error'][] = array(
'message' => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<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>."
);
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array("title" => get_class($request)." failed with error ".$request_result['http_code'], "body" => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", "labels" => 'request-error'));
$results['error'][] = array(
"message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<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);
}
unset($request);
}
} else {
$results['error'][] = array(
'message' => "<strong>Configuration issue!</strong> It appears that all Image Search engines are disabled. Please enable at least one in your config.php file.<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>."
);
}
if(array_key_exists('search', $results)) {
// Re-order results based on rank
$keys = array_column($results['search'], 'goosle_rank');
array_multisort($keys, SORT_DESC, $results['search']);
// Count results per source
$results['sources'] = array_count_values(array_column($results['search'], 'source'));
unset($keys);
} else {
// Add error if there are no search results
@ -119,44 +128,43 @@ print_r($results);
echo '</pre>';
*/
if(array_key_exists("search", $results)) {
echo "<ol>";
if(array_key_exists('search', $results)) {
echo "<ul>";
// Elapsed time
$number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
echo "<li class=\"timer\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Format sources
echo "<li class=\"sources\">Includes ".search_sources($results['sources'])."</li>";
echo "<li class=\"sources\">".search_sources($results['sources'])."</li>";
// Did you mean/Search suggestion
if(array_key_exists("did_you_mean", $results)) {
echo "<li class=\"suggestion\">Did you mean <a href=\"./results.php?q=".urlencode($results['did_you_mean'])."&t=".$opts->type."&a=".$opts->hash."\">".$results['did_you_mean']."</a>?".search_suggestion($opts, $results)."</li>";
}
echo "</ol>";
echo "</ul>";
// Search results
echo "<div class=\"image-grid\">";
echo "<ol>";
echo "<div class=\"result-grid\">";
echo "<ul>";
foreach($results['search'] as $result) {
// Extra data
$meta = $links = array();
if(!empty($result['height']) && !empty($result['width'])) $meta[] = $result['width']."&times;".$result['height'];
if(!empty($result['height']) && !is_null($result['width'])) $meta[] = $result['width']."&times;".$result['height'];
if(!empty($result['filesize'])) $meta[] = human_filesize($result['filesize']);
$links[] = "<a href=\"".$result['webpage_url']."\" target=\"_blank\">Website</a>";
if(!empty($result['image_full'])) $links[] = "<a href=\"".$result['image_full']."\" target=\"_blank\">Image</a>";
// Put result together
echo "<li class=\"result image rs-".$result['goosle_rank']." id-".$result['id']."\"><div class=\"image-box\">";
echo "<a href=\"".$result['webpage_url']."\" target=\"_blank\" title=\"".$result['alt']."\"><img src=\"".$result['image_thumb']."\" alt=\"".$result['alt']."\" /></a>";
echo "</div><span>".implode(" - ", $meta)."<br />".implode(" - ", $links)."</span>";
echo "<li class=\"result image rank-".$result['goosle_rank']." id-".$result['id']."\">";
echo " <div class=\"result-box\">";
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\">".implode(" - ", $meta)."<br /><a href=\"".$result['url']."\" target=\"_blank\">Website</a> - <a href=\"".$result['image_full']."\" target=\"_blank\">Image</a></div>";
echo "</li>";
}
echo "</ol>";
echo "</ul>";
echo "</div>";
echo "<center><small>Goosle does not store or distribute image files.</small></center>";
}

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -10,119 +10,135 @@
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class MagnetSearch extends EngineRequest {
protected $requests, $special_request;
protected $requests, $boxoffice;
public function __construct($opts, $mh) {
$this->requests = array();
if($opts->enable_limetorrents == "on") {
require ABSPATH."engines/magnet/lime.php";
// Extra functions to process magnet results
require ABSPATH.'functions/tools-magnet.php';
if($opts->enable_limetorrents == 'on') {
require ABSPATH.'engines/magnet/lime.php';
$this->requests[] = new LimeRequest($opts, $mh);
}
if($opts->enable_piratebay == "on") {
require ABSPATH."engines/magnet/thepiratebay.php";
if($opts->enable_piratebay == 'on') {
require ABSPATH.'engines/magnet/thepiratebay.php';
$this->requests[] = new PirateBayRequest($opts, $mh);
}
if($opts->enable_yts == "on") {
require ABSPATH."engines/magnet/yts.php";
if($opts->enable_yts == 'on') {
require ABSPATH.'engines/magnet/yts.php';
$this->requests[] = new YTSRequest($opts, $mh);
}
if($opts->enable_nyaa == "on") {
require ABSPATH."engines/magnet/nyaa.php";
if($opts->enable_nyaa == 'on') {
require ABSPATH.'engines/magnet/nyaa.php';
$this->requests[] = new NyaaRequest($opts, $mh);
}
if($opts->enable_eztv == "on") {
if(substr(strtolower($opts->query), 0, 2) == "tt") {
require ABSPATH."engines/magnet/eztv.php";
if($opts->enable_sukebei == 'on') {
require ABSPATH.'engines/magnet/sukebei.php';
$this->requests[] = new SukebeiRequest($opts, $mh);
}
if($opts->enable_eztv == 'on') {
if(substr(strtolower($opts->query), 0, 2) == 'tt') {
require ABSPATH.'engines/magnet/eztv.php';
$this->requests[] = new EZTVRequest($opts, $mh);
}
}
// Special search
$this->special_request = special_magnet_request($opts, $mh);
}
public function parse_results($response) {
$results = $results_temp = array();
$results = array();
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) {
// Merge duplicates and apply relevance scoring
foreach($engine_result as $result) {
if(count($results_temp) > 1 && !is_null($result['hash'])) {
$result_urls = array_column($results_temp, "hash", "id");
$found_id = array_search($result['hash'], $result_urls);
} else {
$found_id = false;
}
if($found_id !== false) {
// Duplicate result from another source
// If seeders and/or leechers mismatch, assume they're different peers
if($results_temp[$found_id]['seeders'] != $result['seeders']) $results_temp[$found_id]['combo_seeders'] += intval($result['seeders']);
if($results_temp[$found_id]['leechers'] != $result['leechers']) $results_temp[$found_id]['combo_leechers'] += intval($result['leechers']);
$results_temp[$found_id]['combo_source'][] = $result['source'];
} else {
// First find - rank (by combo_seeders instead of internal ranking) and add to results
$result['combo_seeders'] = intval($result['seeders']);
$result['combo_leechers'] = intval($result['leechers']);
$result['combo_source'][] = $result['source'];
$results_temp[$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
}
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array("title" => get_class($request)." failed with error ".$request_result['http_code'], "body" => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", "labels" => 'request-error'));
$results['error'][] = array(
"message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
);
}
unset($request);
}
// Check for Special result
if(count($this->special_request) > 0) {
foreach($this->special_request as $source => $highlight) {
$results['special'][$source] = $highlight->get_results();
}
}
if(count($results_temp) > 0) {
// Sort by highest seeders
$seeders = array_column($results_temp, "combo_seeders");
array_multisort($seeders, SORT_DESC, $results_temp);
if(count($this->requests) !== 0) {
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
// Cap results to 50
$results['search'] = array_slice($results_temp, 0, 50);
if(!empty($engine_result)) {
if(array_key_exists('search', $engine_result)) {
// Count results per source
$results['sources'][$engine_result['source']] = $engine_result['amount'];
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(array_key_exists('search', $results)) {
$result_urls = array_column($results['search'], 'hash', 'id');
$found_id = array_search($result['hash'], $result_urls); // Return the result ID, or false if not found
} else {
$found_id = false;
}
if($found_id !== false) {
// Duplicate result from another engine
// If seeders or leechers mismatch, assume they're different peers
if($results['search'][$found_id]['seeders'] != $result['seeders']) $results['search'][$found_id]['combo_seeders'] += intval($result['seeders']);
if($results['search'][$found_id]['leechers'] != $result['leechers']) $results['search'][$found_id]['combo_leechers'] += intval($result['leechers']);
$results['search'][$found_id]['combo_source'][] = $engine_result['source'];
// If duplicate result has more info, add it
if(is_null($results['search'][$found_id]['year']) && !is_null($result['year'])) $results['search'][$found_id]['year'] = $result['year'];
if(is_null($results['search'][$found_id]['category']) && !is_null($result['category'])) $results['search'][$found_id]['category'] = $result['category'];
if(is_null($results['search'][$found_id]['runtime']) && !is_null($result['runtime'])) $results['search'][$found_id]['runtime'] = $result['runtime'];
if(is_null($results['search'][$found_id]['url']) && !is_null($result['url'])) $results['search'][$found_id]['url'] = $result['url'];
if(is_null($results['search'][$found_id]['date_added']) && !is_null($result['date_added'])) $results['search'][$found_id]['date_added'] = $result['date_added'];
if(is_null($results['search'][$found_id]['quality']) && !is_null($result['quality'])) $results['search'][$found_id]['quality'] = $result['quality'];
if(is_null($results['search'][$found_id]['type']) && !is_null($result['type'])) $results['search'][$found_id]['type'] = $result['type'];
if(is_null($results['search'][$found_id]['audio']) && !is_null($result['audio'])) $results['search'][$found_id]['audio'] = $result['audio'];
} else {
// First find, rank and add to results
// Ranks by combo_seeders instead of regular ranking
$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
$results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
}
}
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array('title' => get_class($request)." failed with error ".$request_result['http_code'], 'body' => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", 'labels' => 'request-error'));
$results['error'][] = array(
'message' => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<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);
}
} else {
$results['error'][] = array(
'message' => "<strong>Configuration issue!</strong> It appears that all Magnet Search engines are disabled. Please enable at least one in your config.php file.<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>."
);
}
// Count results per source
$results['sources'] = array_count_values(array_column($results['search'], 'source'));
if(array_key_exists('search', $results)) {
// Re-order results based on seeders
$keys = array_column($results['search'], 'combo_seeders');
array_multisort($keys, SORT_DESC, $results['search']);
unset($sources);
// Cap results
$results['search'] = array_slice($results['search'], 0, 200);
unset($keys);
} else {
// Add error if there are no search results
$results['error'][] = array(
"message" => "No results found. Please try with more specific or different keywords!"
'message' => "No results found. Please try with more specific or different keywords!"
);
}
unset($results_temp);
return $results;
}
@ -137,103 +153,150 @@ print_r($results);
echo '</pre>';
*/
// Special results
if(array_key_exists("special", $results)) {
echo "<div class=\"magnet-grid\">";
if(array_key_exists("yts", $results['special'])) {
if($opts->yts_highlight == "date_added") echo "<h2>Latest releases from YTS</h2>";
if($opts->yts_highlight == "rating") echo "<h2>Highest rated on YTS</h2>";
if($opts->yts_highlight == "download_count") echo "<h2>Most downloaded from YTS</h2>";
if($opts->yts_highlight == "seeds") echo "<h2>Most seeded on YTS</h2>";
echo "<ol>";
// Latest additions to yts
if($opts->show_yts_highlight == 'on') {
require ABSPATH.'engines/boxoffice/yts.php';
echo "<div class=\"result-grid\">";
echo "<h2>Latest releases from YTS</h2>";
echo "<p>View these and more new releases on the <a href=\"./box-office.php?q=".$opts->query."&t=9&a=".$opts->hash."\">box office</a> page!</p>";
echo "<ul>";
$highlights = array_slice(yts_boxoffice($opts, 'date_added'), 0, 8);
foreach($highlights as $highlight) {
$thumb = (!empty($highlight['thumbnail'])) ? $highlight['thumbnail'] : $blank_thumb;
echo "<li class=\"result highlight yts\">";
echo " <div class=\"result-box\">";
echo " <a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['name']."\"><img src=\"".$thumb."\" alt=\"".$highlight['name']."\" /></a>";
echo " </div>";
echo " <span><center><a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['name']."\">".$highlight['name']."</a></center></span>";
// HTML for popup
echo " <div id=\"highlight-".$highlight['id']."\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>".$highlight['name']."</h2>";
echo " <p>".$highlight['summary']."</p>";
echo " <p><a href=\"./results.php?q=".urlencode($highlight['name']." ".$highlight['year'])."&a=".$opts->hash."&t=0\" title=\"Search on Goosle Web Search!\">Search on Goosle</a> &bull; <a href=\"./results.php?q=".urlencode($highlight['name']." ".$highlight['year'])."&a=".$opts->hash."&t=9\" title=\"Search on Goosle Magnet Search! For new additions results may be limited.\">Find more Magnet links</a></p>";
echo " <p><strong>Genre:</strong> ".$highlight['category']."<br /><strong>Released:</strong> ".$highlight['year']."<br /><strong>Rating:</strong> ".movie_star_rating($highlight['rating'])." <small>(".$highlight['rating']." / 10)</small></p>";
// List downloads
echo " <h3>Downloads:</h3>";
echo " <p>";
foreach($highlight['magnet_links'] as $magnet) {
if(!is_null($magnet['quality'])) $meta[] = $magnet['quality'];
if(!is_null($magnet['type'])) $meta[] = $magnet['type'];
$meta[] = human_filesize($magnet['filesize']);
foreach($results['special']['yts'] as $highlight) {
echo "<li class=\"result yts\">";
echo "<div class=\"magnet-box\">";
echo "<img src=\"".$highlight['thumbnail']."\" alt=\"".$highlight['name']."\" />";
echo "<p><strong>Genre:</strong> ".$highlight['category']."<br />";
echo "<strong>Released:</strong> ".$highlight['year']."<br />";
echo "<strong>Rating:</strong> ".$highlight['rating']." / 10<br />";
echo "<strong>Downloads:</strong> ";
foreach($highlight['magnet_links'] as $magnet) {
echo "<a href=\"".$magnet['magnet']."\">".$magnet['quality']." ".$magnet['codec']."</a>";
}
echo "</p>";
echo "</div>";
echo "<strong><center><a href=\"".$highlight['url']."\" target=\"_blank\">".$highlight['name']."</a></center></strong>";
echo "</li>";
echo "<button class=\"download\" onclick=\"location.href='".$magnet['magnet']."'\">".implode(' / ', $meta)."</button>";
unset($meta);
}
unset($highlight);
echo "</ol>";
echo " </p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo " </div>";
echo "</li>";
unset($highlight, $magnet);
}
if(array_key_exists("eztv", $results['special'])) {
echo "<h2>Latest releases from EZTV</h2>";
echo "<ol>";
foreach($results['special']['eztv'] as $highlight) {
echo "<li class=\"result eztv\">";
echo "<div class=\"magnet-box\">";
if(!empty($highlight['thumbnail'])) {
echo "<img src=\"".$highlight['thumbnail']."\" alt=\"".$highlight['name']."\" />";
} else {
echo "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOUX3LxDAAE4AJiVKIoaQAAAABJRU5ErkJggg==\" style=\"max-height: 80px;\">";
}
echo "<p>".$highlight['quality']."<br />";
echo "<a href=\"".$highlight['magnet_link']."\">Download</a></p>";
echo "</div>";
echo "<strong>".$highlight['name']." S".$highlight['season']."E".$highlight['episode']."</strong>";
echo "</li>";
}
unset($highlight);
echo "</ol>";
}
echo "</ul>";
echo "</div>";
}
// Main content
if(array_key_exists("search", $results)) {
echo "<ol>";
if(array_key_exists('search', $results)) {
// Is this a shared search? Move shared result to position 1
if($opts->show_share_option == 'on' && !empty($opts->share)) {
$keys = array_keys($results['search']);
$found_id = array_search(md5($opts->share), $keys); // Return the shared key ID
$found_id = $keys[$found_id]; // Get the shared ID
$first = array($found_id => $results['search'][$found_id]);
unset($results['search'][$found_id], $keys, $found_id);
$results['search'] = array_merge($first, $results['search']);
}
echo "<ul>";
// Elapsed time
$number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
echo "<li class=\"timer\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Format sources
echo "<li class=\"sources\">Includes ".search_sources($results['sources'])."</li>";
echo "<li class=\"sources\">".search_sources($results['sources'])."</li>";
// Search results
foreach($results['search'] as $result) {
// Extra data
$meta = array();
if(array_key_exists('quality', $result)) $meta[] = "<strong>Quality:</strong> ".$result['quality'];
if(array_key_exists('codec', $result)) $meta[] = "<strong>Codec:</strong> ".$result['codec'];
if(array_key_exists('year', $result)) $meta[] = "<strong>Year:</strong> ".$result['year'];
if(array_key_exists('category', $result)) $meta[] = "<strong>Category:</strong> ".$result['category'];
if(array_key_exists('runtime', $result)) $meta[] = "<strong>Runtime:</strong> ".date('H:i', mktime(0, $result['runtime']));
if(array_key_exists('date_added', $result)) $meta[] = "<strong>Added on:</strong> ".date('M d, Y', $result['date_added']);
$base = $meta = array();
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['date_added'])) $base[] = "<strong>Added on:</strong> ".date("M d, Y", $result['date_added']);
// If available, add the url to the first found torrent page
$url = (array_key_exists('url', $result)) ? " - <a href=\"".$result['url']."\" target=\"_blank\" title=\"Careful - Site may contain intrusive popup ads and malware!\">torrent page</a>" : "";
if(!empty($result['category'])) $meta[] = "<strong>Category:</strong> ".$result['category'];
if(!empty($result['year'])) $meta[] = "<strong>Year:</strong> ".$result['year'];
if(!empty($result['runtime'])) $meta[] = "<strong>Runtime:</strong> ".$result['runtime'];
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') {
if(!empty($opts->share) && $result['hash'] == $opts->share) {
$class = " shared";
} else {
$base[] = "<a onclick=\"openpopup('result-".$result['id']."')\" title=\"Share magnet result\">Share</a>";
}
}
// Put result together
echo "<li class=\"result magnet id-".$result['id']."\">";
echo "<div class=\"title\"><a href=\"".$result['magnet']."\"><h2>".stripslashes($result['name'])."</h2></a></div>";
echo "<div class=\"description\"><strong>Seeds:</strong> <span class=\"seeders\">".$result['combo_seeders']."</span> - <strong>Peers:</strong> <span class=\"leechers\">".$result['combo_leechers']."</span> - <strong>Size:</strong> ".$result['size']."<br />".implode(" - ", $meta)."</div>";
if($opts->show_search_source == "on") echo "<div class=\"description\"><strong>Found on:</strong> ".replace_last_comma(implode(", ", $result['combo_source'])).'.'.$url."</div>";
echo "<li class=\"result magnet id-".$result['id'].$class."\">";
echo " <div class=\"title\"><a href=\"".$result['magnet']."\"><h2>".stripslashes($result['name'])."</h2></a></div>";
echo " <div class=\"description\">";
echo " <p>".implode(" &bull; ", $base)."</p>";
echo " <p>".implode(" &bull; ", $meta)."</p>";
echo " </div>";
// Result sources
if($opts->show_search_source == 'on') {
// If available, add a link to the found torrent page
$url = (array_key_exists('url', $result)) ? " &bull; <a href=\"".$result['url']."\" target=\"_blank\" title=\"Careful - Site may contain intrusive popup ads and malware!\">torrent page</a>" : "";
echo " <div class=\"meta\">Found on ".replace_last_comma(implode(', ', $result['combo_source'])).$url."</div>";
}
// Share popup
if($opts->show_share_option == 'on' && $result['hash'] != $opts->share) {
echo " <div id=\"result-".$result['id']."\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>Share magnet result</h2>";
echo " <p>Tap or click on the field below to copy the magnet result to your clipboard.</p>";
echo " <h3>Sharing: ".stripslashes($result['name'])."</h3>";
echo " <p><input tabindex=\"2\" type=\"text\" id=\"share-result-".$result['id']."\" class=\"share-field\" value=\"".share_encode($opts, $result['hash'])."\" /><button tabindex=\"1\" class=\"share-button\" onclick=\"clipboard('share-result-".$result['id']."')\">Copy magnet link</button></p>";
echo " <p><span id=\"share-result-".$result['id']."-response\"></span></p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo " </div>";
}
echo "</li>";
unset($result, $meta, $url);
unset($result, $base, $meta, $class, $url);
}
echo "</ol>";
echo "</ul>";
echo "<center><small>Goosle does not index, offer or distribute torrent files.</small></center>";
}
// No results found
if(array_key_exists("error", $results)) {
if(array_key_exists('error', $results)) {
foreach($results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}

201
engines/search-news.php Normal file
View file

@ -0,0 +1,201 @@
<?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 NewsSearch extends EngineRequest {
protected $requests, $special_request;
public function __construct($opts, $mh) {
$this->requests = array();
if($opts->enable_qwantnews == 'on') {
require ABSPATH.'engines/news/qwant-news.php';
$this->requests[] = new QwantNewsRequest($opts, $mh);
}
if($opts->enable_yahoonews == 'on') {
require ABSPATH.'engines/news/yahoo-news.php';
$this->requests[] = new YahooNewsRequest($opts, $mh);
}
if($opts->enable_bravenews == 'on') {
require ABSPATH.'engines/news/brave-news.php';
$this->requests[] = new BraveNewsRequest($opts, $mh);
}
if($opts->enable_hackernews == 'on') {
require ABSPATH.'engines/news/hackernews.php';
$this->requests[] = new HackernewsRequest($opts, $mh);
}
}
public function parse_results($response) {
$results = array();
if(count($this->requests) !== 0) {
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) {
if(array_key_exists('did_you_mean', $engine_result)) {
$results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(array_key_exists('search_specific', $engine_result)) {
$results['search_specific'][] = $engine_result['search_specific'];
}
if(array_key_exists('search', $engine_result)) {
// Count results per source
$results['sources'][$engine_result['source']] = $engine_result['amount'];
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(array_key_exists('search', $results)) {
$result_urls = array_column($results['search'], 'url', 'id');
$found_id = array_search($result['url'], $result_urls); // Return the result ID, or false if not found
} else {
$found_id = false;
}
$social_media_multiplier = (is_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * floatval($social_media_multiplier));
if($found_id !== false) {
// Duplicate result from another engine
$results['search'][$found_id]['goosle_rank'] += $goosle_rank;
$results['search'][$found_id]['combo_source'][] = $engine_result['source'];
} else {
// First find, rank and add to results
// Replace anything but alphanumeric with a space
$query_terms = explode(' ', preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', strtolower($request->query)));
$match_rank = match_count($result['title'], $query_terms);
$match_rank += match_count($result['description'], $query_terms);
$match_rank += match_count($result['url'], $query_terms);
if($result['date_added'] > $request->opts->result_range) {
$time_rank = time() - $result['date_added'];
if($time_rank > 7776001) { // More than 3 months old
$match_rank += 1;
} elseif($time_rank > 3888001 && $time_rank < 7776000) {
$match_rank += 2;
} elseif($time_rank > 1209600 && $time_rank < 3888000) {
$match_rank += 4;
} elseif($time_rank > 604801 && $time_rank < 1209600) {
$match_rank += 6;
} elseif($time_rank > 86401 && $time_rank < 604800) {
$match_rank += 8;
} elseif($time_rank > 43201 && $time_rank < 86400) {
$match_rank += 10;
} elseif($time_rank > 32601 && $time_rank < 43200) {
$match_rank += 12;
} else { // Less than 6 hours old
$match_rank += 14;
}
}
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['url']);
$results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank, $time_rank, $query_terms);
}
}
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : '';
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array('title' => get_class($request)." failed with error ".$request_result['http_code'], 'body' => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", 'labels' => 'request-error'));
$results['error'][] = array(
'message' => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<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);
}
} else {
$results['error'][] = array(
'message' => "<strong>Configuration issue!</strong> It appears that all Web Search engines are disabled. Please enable at least one in your config.php file.<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>."
);
}
if(array_key_exists('search', $results)) {
// Re-order results based on rank
$keys = array_column($results['search'], 'goosle_rank');
array_multisort($keys, SORT_DESC, $results['search']);
unset($keys);
} else {
// Add error if there are no search results
$results['error'][] = array(
'message' => "No results found. Please try with more specific or different keywords!"
);
}
return $results;
}
public static function print_results($results, $opts) {
/*
// Uncomment for debugging
echo '<pre>Settings: ';
print_r($opts);
echo '</pre>';
echo '<pre>Search results: ';
print_r($results);
echo '</pre>';
*/
if(array_key_exists('search', $results)) {
echo "<ul>";
// Elapsed time
$number_of_results = count($results['search']);
echo "<li class=\"timer\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Format sources
echo "<li class=\"sources\">".search_sources($results['sources'])."</li>";
// Search results
foreach($results['search'] as $result) {
// Extra data
$base = array();
if(!empty($result['source'])) $base[] = "<strong>Source:</strong> ".$result['source'];
if(!empty($result['date_added'])) $base[] = "<strong>Posted:</strong> ".date("M d, Y", $result['date_added']);
if($opts->show_search_source == 'on') $base[] = replace_last_comma(implode(', ', $result['combo_source']));
if($opts->show_search_rank == 'on') $base[] = "Rank: ".$result['goosle_rank'];
echo "<li class=\"result news rank-".$result['goosle_rank']." id-".$result['id']."\">";
echo " <div class=\"title\"><a href=\"".$result['url']."\" target=\"_blank\"><h2>".$result['title']."</h2></a></div>";
echo " <div class=\"description\">";
echo " <p><small>".implode(' &bull; ', $base)."</small></p>";
if(!empty($result['description'])) echo " <p>".$result['description']."</p>";
echo " </div>";
echo "</li>";
}
echo "</ul>";
}
// Some error occured
if(array_key_exists('error', $results)) {
foreach($results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}
}
unset($results);
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -15,92 +15,135 @@ class Search extends EngineRequest {
public function __construct($opts, $mh) {
$this->requests = array();
if($opts->enable_duckduckgo == "on") {
require ABSPATH."engines/search/duckduckgo.php";
if($opts->enable_duckduckgo == 'on') {
require ABSPATH.'engines/search/duckduckgo.php';
$this->requests[] = new DuckDuckGoRequest($opts, $mh);
}
if($opts->enable_google == "on") {
require ABSPATH."engines/search/google.php";
if($opts->enable_google == 'on') {
require ABSPATH.'engines/search/google.php';
$this->requests[] = new GoogleRequest($opts, $mh);
}
if($opts->enable_qwantnews == "on") {
require ABSPATH."engines/search/qwantnews.php";
$this->requests[] = new QwantNewsRequest($opts, $mh);
if($opts->enable_qwant == 'on') {
require ABSPATH.'engines/search/qwant.php';
$this->requests[] = new QwantRequest($opts, $mh);
}
if($opts->enable_wikipedia == "on") {
require ABSPATH."engines/search/wikipedia.php";
if($opts->enable_brave == 'on') {
require ABSPATH.'engines/search/brave.php';
$this->requests[] = new BraveRequest($opts, $mh);
}
if($opts->enable_wikipedia == 'on') {
require ABSPATH.'engines/search/wikipedia.php';
$this->requests[] = new WikiRequest($opts, $mh);
}
// Special search
$this->special_request = special_search_request($opts);
// Special searches
$query_terms = explode(' ', $opts->query);
$query_terms[0] = strtolower($query_terms[0]);
// Currency converter
if($opts->special['currency'] == 'on' && count($query_terms) == 4 && (is_numeric($query_terms[0]) && ($query_terms[2] == 'to' || $query_terms[2] == 'in'))) {
require ABSPATH.'engines/special/currency.php';
$this->special_request = new CurrencyRequest($opts, null);
}
// Dictionary
if($opts->special['definition'] == 'on' && count($query_terms) == 2 && ($query_terms[0] == 'define' || $query_terms[0] == 'd' || $query_terms[0] == 'mean' || $query_terms[0] == 'meaning')) {
require ABSPATH.'engines/special/definition.php';
$this->special_request = new DefinitionRequest($opts, null);
}
// IP Lookup
if($opts->special['ipaddress'] == 'on' && ($query_terms[0] == 'ip' || $query_terms[0] == 'myip' || $query_terms[0] == 'ipaddress')) {
require ABSPATH.'engines/special/ipify.php';
$this->special_request = new ipRequest($opts, null);
}
// php.net search
if($opts->special['phpnet'] == 'on' && count($query_terms) == 2 && $query_terms[0] == 'php') {
require ABSPATH.'engines/special/php.php';
$this->special_request = new PHPnetRequest($opts, null);
}
unset($query_terms);
}
public function parse_results($response) {
$results = array();
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) {
if(array_key_exists('did_you_mean', $engine_result)) {
$results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(array_key_exists('search_specific', $engine_result)) {
$results['search_specific'][] = $engine_result['search_specific'];
}
if(array_key_exists('search', $engine_result)) {
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(array_key_exists('search', $results)) {
$result_urls = array_column($results['search'], "url", "id");
$found_id = array_search($result['url'], $result_urls);
} else {
$found_id = false;
}
$social_media_multiplier = (is_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * floatval($social_media_multiplier));
if(count($this->requests) !== 0) {
foreach($this->requests as $request) {
if($request->request_successful()) {
$engine_result = $request->get_results();
if($found_id !== false) {
// Duplicate result from another source, merge and rank accordingly
$results['search'][$found_id]['goosle_rank'] += $goosle_rank;
$results['search'][$found_id]['combo_source'][] = $result['source'];
} else {
// First find, rank and add to results
$query_terms = explode(" ", preg_replace("/[^a-z0-9 ]+/", "", strtolower($request->query)));
$match_rank = match_count($result['title'], $query_terms);
$match_rank += match_count($result['description'], $query_terms);
// $match_rank += match_count($result['url'], $query_terms);
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $result['source'];
$results['search'][$result['id']] = $result;
}
if(!empty($engine_result)) {
if(array_key_exists('did_you_mean', $engine_result)) {
$results['did_you_mean'] = $engine_result['did_you_mean'];
}
if(array_key_exists('search_specific', $engine_result)) {
$results['search_specific'][] = $engine_result['search_specific'];
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
if(array_key_exists('search', $engine_result)) {
// Count results per source
$results['sources'][$engine_result['source']] = $engine_result['amount'];
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(array_key_exists('search', $results)) {
$result_urls = array_column($results['search'], 'url', 'id');
$found_id = array_search($result['url'], $result_urls); // Return the result ID, or false if not found
} else {
$found_id = false;
}
$social_media_multiplier = (is_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * floatval($social_media_multiplier));
if($found_id !== false) {
// Duplicate result from another engine
$results['search'][$found_id]['goosle_rank'] += $goosle_rank;
$results['search'][$found_id]['combo_source'][] = $engine_result['source'];
} else {
// First find, rank and add to results
// Replace anything but alphanumeric with a space
$query_terms = explode(' ', preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', strtolower($request->query)));
$match_rank = match_count($result['title'], $query_terms);
$match_rank += match_count($result['description'], $query_terms);
$match_rank += match_count($result['url'], $query_terms);
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['url']);
$results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank, $query_terms);
}
}
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : '';
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array('title' => get_class($request).' failed with error '.$request_result['http_code'], 'body' => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", 'labels' => 'request-error'));
$results['error'][] = array(
'message' => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<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>."
);
}
} else {
$request_result = curl_getinfo($request->ch);
$http_code_info = ($request_result['http_code'] > 200 && $request_result['http_code'] < 600) ? " - <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/".$request_result['http_code']."\" target=\"_blank\">What's this</a>?" : "";
$github_issue_url = "https://github.com/adegans/Goosle/discussions/new?category=general&".http_build_query(array("title" => get_class($request)." failed with error ".$request_result['http_code'], "body" => "```\nEngine: ".get_class($request)."\nError Code: ".$request_result['http_code']."\nRequest url: ".$request_result['url']."\n```", "labels" => 'request-error'));
$results['error'][] = array(
"message" => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<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);
}
unset($request);
}
} else {
$results['error'][] = array(
'message' => "<strong>Configuration issue!</strong> It appears that all Web Search engines are disabled. Please enable at least one in your config.php file.<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>."
);
}
// Check for Special result
if($this->special_request) {
@ -117,15 +160,12 @@ class Search extends EngineRequest {
// Re-order results based on rank
$keys = array_column($results['search'], 'goosle_rank');
array_multisort($keys, SORT_DESC, $results['search']);
// Count results per source
$results['sources'] = array_count_values(array_column($results['search'], 'source'));
unset($keys);
} else {
// Add error if there are no search results
$results['error'][] = array(
"message" => "No results found. Please try with more specific or different keywords!"
'message' => "No results found. Please try with more specific or different keywords!"
);
}
@ -135,68 +175,72 @@ class Search extends EngineRequest {
public static function print_results($results, $opts) {
/*
// Uncomment for debugging
echo '<pre>Settings: ';
echo "<pre>Settings: ";
print_r($opts);
echo '</pre>';
echo '<pre>Search results: ';
echo "</pre>";
echo "<pre>Search results: ";
print_r($results);
echo '</pre>';
echo "</pre>";
*/
if(array_key_exists("search", $results)) {
echo "<ol>";
if(array_key_exists('search', $results)) {
echo "<ul>";
// Elapsed time
$number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
echo "<li class=\"timer\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Format sources
echo "<li class=\"sources\">Includes ".search_sources($results['sources'])."</li>";
echo "<li class=\"sources\">".search_sources($results['sources'])."</li>";
// Did you mean/Search suggestion
if(array_key_exists("did_you_mean", $results)) {
if(array_key_exists('did_you_mean', $results)) {
echo "<li class=\"suggestion\">Did you mean <a href=\"./results.php?q=".urlencode($results['did_you_mean'])."&t=".$opts->type."&a=".$opts->hash."\">".$results['did_you_mean']."</a>?".search_suggestion($opts, $results)."</li>";
}
// Special results
if(array_key_exists("special", $results)) {
echo "<li class=\"result-special\">";
echo "<div class=\"title\"><h2>".$results['special']['title']."</h2></div>";
echo "<div class=\"text\">".$results['special']['text']."</div>";
if(array_key_exists("source", $results['special'])) {
echo "<div class=\"source\"><a href=\"".$results['special']['source']."\" target=\"_blank\">".$results['special']['source']."</a></div>";
// Special result
if(array_key_exists('special', $results)) {
echo "<li class=\"result-special web\">";
echo " <div class=\"title\"><h2>".$results['special']['title']."</h2></div>";
echo " <div class=\"description\">".$results['special']['text']."</div>"; // <p> is in the engine files
if(array_key_exists('source', $results['special'])) {
echo " <div class=\"source\"><a href=\"".$results['special']['source']."\" target=\"_blank\">".$results['special']['source']."</a></div>";
}
echo "</li>";
}
// Search results
foreach($results['search'] as $result) {
if($opts->imdb_id_search == "on") {
if(stristr($result['url'], "imdb.com") !== false && preg_match_all("/(?:tt[0-9]+)/i", $result['url'], $imdb_result)) {
$result['description'] = $result['description']."<br /><strong>Goosle detected an IMDb ID for this result, search for <a href=\"./results.php?q=".$imdb_result[0][0]."&a=".$opts->hash."&t=9\">magnet links</a>?</strong>";
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)) {
$result['description'] .= "<br /><strong>Goosle detected an IMDb ID for this result, search for <a href=\"./results.php?q=".$imdb_result[0][0]."&a=".$opts->hash."&t=9\" title=\"A Magnet link is a method of downloading movies and tv-shows.\">Magnet links</a>?</strong>";
}
}
echo "<li class=\"result web rs-".$result['goosle_rank']." id-".$result['id']."\">";
echo "<div class=\"url\"><a href=\"".$result['url']."\" target=\"_blank\">".get_formatted_url($result['url'])."</a></div>";
echo "<div class=\"title\"><a href=\"".$result['url']."\" target=\"_blank\"><h2>".$result['title']."</h2></a></div>";
echo "<div class=\"description\">".$result['description']."</div>";
echo "<li class=\"result web rank-".$result['goosle_rank']." id-".$result['id']."\">";
echo " <div class=\"url\"><a href=\"".$result['url']."\" target=\"_blank\">".get_formatted_url($result['url'])."</a></div>";
echo " <div class=\"title\"><a href=\"".$result['url']."\" target=\"_blank\"><h2>".$result['title']."</h2></a></div>";
echo " <div class=\"description\">";
echo " <p>".$result['description']."</p>";
echo " </div>";
if($opts->show_search_source == "on") {
echo "<div class=\"engine\">";
echo "Found on ".replace_last_comma(implode(", ", $result['combo_source'])).".";
if($opts->show_search_rank == "on") echo " [rank: ".$result['goosle_rank']."]";
echo "</div>";
if($opts->show_search_source == 'on') {
echo " <div class=\"meta\">";
echo " Found on ".replace_last_comma(implode(', ', $result['combo_source'])).".";
if($opts->show_search_rank == 'on') {
echo " [rank: ".$result['goosle_rank']."]";
}
echo " </div>";
}
echo "</li>";
}
echo "</ol>";
echo "</ul>";
}
// Some error occured
if(array_key_exists("error", $results)) {
if(array_key_exists('error', $results)) {
foreach($results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}

BIN
engines/search/.DS_Store vendored Normal file

Binary file not shown.

103
engines/search/brave.php Normal file
View file

@ -0,0 +1,103 @@
<?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 BraveRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
// Safe search ignore (not supported)
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
$query = trim(str_replace($matches[0], '', $query));
}
unset($matches);
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://search.brave.com/search?'.http_build_query(array(
'q' => $query, // Search query
'offset' => 0, // Start on 'page' 1 of results (0 = 1)
'show_local' => 0, // Localize results (0 = no localization)
'spellcheck' => 0, // No spellcheck on your query
'source' => 'web' // Where are you searching from? (Web)
));
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',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) return $engine_temp;
// Scrape the results
$scrape = $xpath->query("//div[@id='results']//div[contains(@class, 'snippet')]");
// Figure out results and base rank
$number_of_results = $rank = count($scrape);
// No results
if($number_of_results == 0) return $engine_temp;
foreach($scrape as $result) {
// Find data
$url = $xpath->evaluate(".//a[contains(@class, 'h')]//@href", $result);
$title = $xpath->evaluate(".//a[contains(@class, 'h')]//div[contains(@class, 'title')]", $result);
$description = $xpath->evaluate(".//div[contains(@class, 'snippet-content')]//div[contains(@class, 'snippet-description')]", $result);
// Skip broken results
if($url->length == 0) continue;
if($title->length == 0) continue;
// Process data
$url = sanitize($url[0]->textContent);
$url = (strpos($url, '/a/redirect?click_url=', 0) !== false) ? "https://search.brave.com".$url : $url;
$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
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Brave';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,40 +11,44 @@
------------------------------------------------------------------------------------ */
class DuckDuckGoRequest extends EngineRequest {
public function get_request_url() {
// Split the query
$query_terms = explode(" ", strtolower($this->query), 2);
$query_terms[0] = strtolower($query_terms[0]);
$query = str_replace('%22', '\"', $this->query);
// Safe search override
$safe = "-1";
if(strpos($query_terms[0], "safe") !== false) {
$switch = explode(":", $query_terms[0]);
if(!is_numeric($switch[1])) {
$safe = (strtolower($switch[1]) == "off") ? "-2" : "1";
$this->query = implode(" ", array_slice($query_terms, 1));
}
$safe = '-1';
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
if($matches[2] == 'on') $safe = '1';
if($matches[2] == 'off') $safe = '-2';
$query = trim(str_replace($matches[0], '', $query));
}
unset($matches);
// Is there no query left? Bail!
if(empty($query)) return false;
// Set locale
$language = (preg_match('/[a-z]{2}-[a-z]{2}/i', $this->opts->duckduckgo_language) && strlen($this->opts->duckduckgo_language) == 5) ? strtolower($this->opts->duckduckgo_language) : 'en_gb';
// Is there no query left? Bail!
if(empty($query)) return false;
// All parameters and values: https://duckduckgo.com/duckduckgo-help-pages/settings/params/
// q = query
// kp = Safe search (1 = on, -1 = moderate, -2 = off (may include nsfw/illegal content))
// kl = Search results language (Works as a region setting, see params page for more supported regions: en-us, en-uk, nl-nl, es-es, fr-fr, etc.)
// kz = Instant answers (1 = on, -1 = off)
// kc = Autoload images (1 = on, -1 = off)
// kav = Autoload results (1 = on, -1 = off)
// kf = Favicons (1 = on, -1 = off)
// kaf = Full URLs (1 = on, -1 = off)
// kac = Auto suggest (1 = on, -1 = off)
// kd = Redirects (1 = on, -1 = off)
// kh = HTTPS (1 = on, -1 = off)
// kg = Get/Post (g = GET, p = POST)
// k1 = Ads (1 = on, -1 = off)
$url = 'https://html.duckduckgo.com/html/?'.http_build_query(array(
'q' => $query, // Search query
'kp' => $safe, // Safe search (1 = on, -1 = moderate, -2 = off
'kl' => $language, // Language region
'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)
));
$args = array("q" => $this->query, "kl" => $this->opts->duckduckgo_language, "kp" => $safe, "kz" => "-1", "kc" => "-1", "kav" => "-1", "kf" => "-1", "kaf" => "1", "kac" => "-1", "kd" => "-1", "kh" => "1", "kg" => "g", "k1" => "-1");
$url = "https://html.duckduckgo.com/html/?".http_build_query($args);
unset($query_terms, $safe, $switch, $args);
unset($query, $safe, $language);
return $url;
}
@ -56,48 +60,71 @@ class DuckDuckGoRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
if(!$xpath) return $results;
// No response
if(!$xpath) return $engine_temp;
// Scrape the results
$scrape = $xpath->query("/html/body/div[1]/div[".count($xpath->query("/html/body/div[1]/div"))."]/div/div/div[contains(@class, 'web-result')]/div");
// Figure out results and base rank
$number_of_results = $rank = count($scrape);
// No results
if($number_of_results == 0) return $engine_temp;
// Scrape recommended
$didyoumean = $xpath->query(".//div[@id='did_you_mean']/a[1]")[0];
if(!is_null($didyoumean)) {
$results['did_you_mean'] = $didyoumean->textContent;
$engine_result['did_you_mean'] = $didyoumean->textContent;
}
$search_specific = $xpath->query(".//div[@id='did_you_mean']/a[2]")[0];
if(!is_null($search_specific)) {
$results['search_specific'] = $search_specific->textContent;
$engine_result['search_specific'] = $search_specific->textContent;
}
// Scrape the results
$scrape = $xpath->query("/html/body/div[1]/div[".count($xpath->query('/html/body/div[1]/div'))."]/div/div/div[contains(@class, 'web-result')]/div");
$rank = $results['amount'] = count($scrape);
foreach($scrape as $result) {
$url = $xpath->evaluate(".//h2[@class='result__title']//a/@href", $result)[0];
if(is_null($url)) continue;
// Find data
$url = $xpath->evaluate(".//h2[@class='result__title']//a/@href", $result);
$title = $xpath->evaluate(".//h2[@class='result__title']", $result);
$description = $xpath->evaluate(".//a[@class='result__snippet']", $result);
$title = $xpath->evaluate(".//h2[@class='result__title']", $result)[0];
if(is_null($title)) continue;
// Skip broken results
if($url->length == 0) continue;
if($title->length == 0) continue;
$description = $xpath->evaluate(".//a[@class='result__snippet']", $result)[0];
$description = (is_null($description)) ? "No description was provided for this site." : sanitize($description->textContent);
$url = sanitize($url->textContent);
$title = sanitize($title->textContent);
// 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($results['search'])) {
if(in_array($url, array_column($results['search'], "url"))) continue;
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
$results['search'][] = array("id" => uniqid(rand(0, 9999)), "source" => "DuckDuckGo", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
$engine_temp[] = array(
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;
}
unset($response, $xpath, $scrape, $rank);
return $results;
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'DuckDuckGo';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,35 +11,33 @@
------------------------------------------------------------------------------------ */
class GoogleRequest extends EngineRequest {
public function get_request_url() {
// Split the query
$query_terms = explode(" ", strtolower($this->query), 2);
$query_terms[0] = strtolower($query_terms[0]);
$query = str_replace('%22', '\"', $this->query);
// Safe search override
$safe = 1;
if(strpos($query_terms[0], "safe") !== false) {
$switch = explode(":", $query_terms[0]);
if(!is_numeric($switch[1])) {
$safe = (strtolower($switch[1]) == "off") ? "0" : "2";
$this->query = implode(" ", array_slice($query_terms, 1));
}
$safe = '1';
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
if($matches[2] == 'on') $safe = '2';
if($matches[2] == 'off') $safe = '0';
$query = trim(str_replace($matches[0], '', $query));
}
unset($matches);
// Is there no query left? Bail!
if(empty($query)) return false;
// q = query
// safe = Safe search (Default 1) 0 = off (may include nsfw/illegal content), 1 = moderate, 2 = on/strict
// pws = Personal search results 0 = off
// tbs = In Goosle used for 'verbatim' search, adding this enables it
// complete = Instant results related, 0 = off
// num = Number of results per page (number, multiple of 10 usually)
// sclient = where are you searching from
// Including the preferred language variable breaks the page result, and with that the crawler!
$args = array("q" => $this->query, "safe" => $safe, "pws" => "0", "tbs" => "li:1", "complete" => "0", "num" => "30", "sclient" => "web");
$url = "https://www.google.com/search?".http_build_query($args);
$url = 'https://www.google.com/search?'.http_build_query(array(
'q' => $query, // Search query
'safe' => $safe, // Safe search (0 = off, 1 = moderate, 2 = on/strict)
'num' => 30, // Number of results per page
'pws' => 0, // Personalized search results (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
));
unset($query_terms, $safe, $switch, $args);
unset($query, $safe);
return $url;
}
@ -51,49 +49,72 @@ class GoogleRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
if(!$xpath) return $results;
// No response
if(!$xpath) return $engine_temp;
// Scrape the results
$scrape = $xpath->query("//div[@id='search']//div[@class='MjjYud']");
// Figure out results and base rank
$number_of_results = $rank = count($scrape);
// No results
if($number_of_results == 0) return $engine_temp;
// Scrape recommended
$didyoumean = $xpath->query(".//a[@class='gL9Hy']")[0];
if(!is_null($didyoumean)) {
$results['did_you_mean'] = $didyoumean->textContent;
$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
$results['search_specific'] = "\"".$search_specific->textContent."\"";
$engine_result['search_specific'] = "\"".$search_specific->textContent."\"";
}
// Scrape the results
$scrape = $xpath->query("//div[@id='search']//div[@class='MjjYud']");
$rank = $results['amount'] = count($scrape);
foreach($scrape as $result) {
$url = $xpath->evaluate(".//div[@class='yuRUbf']//a/@href", $result)[0];
if(is_null($url)) continue;
$title = $xpath->evaluate(".//h3", $result)[0];
if(is_null($title)) continue;
$description = $xpath->evaluate(".//div[contains(@class, 'VwiC3b')]", $result)[0];
$description = (is_null($description)) ? "No description was provided for this site." : sanitize($description->textContent);
// Find data
$url = $xpath->evaluate(".//div[@class='yuRUbf']//a/@href", $result);
$title = $xpath->evaluate(".//h3", $result);
$description = $xpath->evaluate(".//div[contains(@class, 'VwiC3b')]", $result);
$url = sanitize($url->textContent);
$title = sanitize($title->textContent);
// 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($results['search'])) {
if(in_array($url, array_column($results['search'], "url"))) continue;
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, "url"))) continue;
}
$results['search'][] = array("id" => uniqid(rand(0, 9999)), "source" => "Google", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
$engine_temp[] = array(
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;
}
unset($response, $xpath, $scrape, $rank);
return $results;
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Google';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

104
engines/search/qwant.php Normal file
View file

@ -0,0 +1,104 @@
<?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 QwantRequest extends EngineRequest {
public function get_request_url() {
$query = str_replace('%22', '\"', $this->query);
// Safe search override
$safe = '1'; // Moderate results
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
if($matches[2] == 'on') $safe = '2';
if($matches[2] == 'off') $safe = '0';
$query = trim(str_replace($matches[0], '', $query));
}
unset($matches);
// Set locale
$language = (preg_match('/[a-z]{2}_[a-z]{2}/i', $this->opts->qwant_language) && strlen($this->opts->qwant_language) == 5) ? strtolower($this->opts->qwant_language) : 'en_gb';
// Is there no query left? Bail!
if(empty($query)) return false;
// Based on https://github.com/locness3/qwant-api-docs and variables from qwant website
$url = 'https://api.qwant.com/v3/search/web?'.http_build_query(array(
'q' => $query, // Search query
't' => 'web', // Type of search, web search
'safesearch' => $safe, // Safe search filter (0 = off, 1 = normal, 2 = strict)
'locale' => $language, // In which language should the search be done
'count' => 10, // How many results? (Maximum 10)
'device' => 'desktop' // What kind of device are we searching from?
));
unset($query, $safe, $language);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'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)) return $engine_temp;
// Figure out results and base rank
$number_of_results = $rank = $json_response['data']['result']['total'];
// No results
if($number_of_results == 0 || $json_response['status'] == 'error') return $engine_temp;
$rank = $json_response['data']['result']['total'];
foreach($json_response['data']['result']['items']['mainline'] as $mainline) {
if($mainline['type'] != 'web') continue;
foreach ($mainline['items'] as $result) {
// Find and process data
$title = strip_newlines(sanitize($result['title']));
$url = sanitize($result['url']);
$description = limit_string_length(strip_newlines(sanitize($result['desc'])));
$engine_temp[] = array (
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;
}
}
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Qwant';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,84 +0,0 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class QwantNewsRequest extends EngineRequest {
public function get_request_url() {
// Split the query
$query_terms = explode(" ", strtolower($this->query));
// Safe search override
$safe = "1"; // Moderate results
if(strpos($query_terms[0], "safe") !== false) {
$switch = explode(":", $query_terms[0]);
if(!is_numeric($switch[1])) {
$safe = (strtolower($switch[1]) == "off") ? "0" : "2";
$this->query = implode(" ", array_slice($query_terms, 1));
}
}
$language = (strlen($this->opts->qwant_language) > 0 && strlen($this->opts->qwant_language < 6)) ? $this->opts->qwant_language : "en_gb";
// q = query
// t = Type of search, Images
// locale = In which language should the search be done
// source = Where to get the news from (All)
// freshness = How old may the article be? (1 month)
// device = What kind of device are we searching from?
// safesearch = Safe search filter (0 = off, 1 = normal, 2 = strict)
$args = array("q" => $this->query, "t" => 'news', 'locale' => $language, 'source' => 'all', 'freshness' => 'month', 'device' => 'desktop', 'safesearch' => $safe);
$url = "https://api.qwant.com/v3/search/news?".http_build_query($args);
unset($query_terms, $switch, $safe, $language, $args);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
);
}
public function parse_results($response) {
$results = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response["status"] != "success") return $results;
// Set base rank and result amound
$rank = $results['amount'] = $json_response["data"]["result"]["total"];
foreach ($json_response["data"]["result"]["items"] as $result) {
$title = sanitize($result['title']);
$url = sanitize($result['url']);
$description = date('M d, Y H:i', sanitize($result['date']))." &sdot; ".sanitize($result['desc']);
$results['search'][] = array ("id" => uniqid(rand(0, 9999)), "source" => "Qwant News", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
$rank -= 1;
}
unset($response, $json_response, $rank);
return $results;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,8 +11,30 @@
------------------------------------------------------------------------------------ */
class WikiRequest extends EngineRequest {
public function get_request_url() {
$args = array("srsearch" => $this->query, "action" => "query", "format" => "json", "list" => "search", "limit" => "10");
$url = "https://".$this->opts->wikipedia_language.".wikipedia.org/w/api.php?".http_build_query($args);
$query = str_replace('%22', '\"', $this->query);
// Safe search ignore
if(preg_match('/(safe:)(on|off)/i', $query, $matches)) {
$query = trim(str_replace($matches[0], '', $query));
}
unset($matches);
// Set locale
$language = (strlen($this->opts->wikipedia_language) == 2) ? strtolower($this->opts->wikipedia_language) : 'en';
// Is there no query left? Bail!
if(empty($query)) return false;
// Variables based on https://www.mediawiki.org/wiki/API:Search
$url = 'https://'.$language.'.wikipedia.org/w/api.php?'.http_build_query(array(
'srsearch' => $query, // Search query
'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)
));
unset($query, $language);
return $url;
}
@ -22,7 +44,6 @@ class WikiRequest extends EngineRequest {
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
@ -30,26 +51,44 @@ class WikiRequest extends EngineRequest {
}
public function parse_results($response) {
$results = array();
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
if(empty($json_response)) return $results;
// No response
if(empty($json_response)) return $engine_temp;
// Figure out results and base rank
$number_of_results = $rank = ($json_response['query']['searchinfo']['totalhits'] > 20) ? 20 : $json_response['query']['searchinfo']['totalhits'];
// No results
if($json_response['query']['searchinfo']['totalhits'] == 0) return $results;
$rank = $results['amount'] = count($json_response['query']['search']);
if($number_of_results == 0) return $engine_temp;
foreach($json_response['query']['search'] as $result) {
$title = sanitize($result['title']);
$url = "https://".$this->opts->wikipedia_language.".wikipedia.org/wiki/".sanitize(str_replace(" ", "_", $result['title']));
$description = sanitize(strip_tags($result['snippet']));
// Find and process data
$title = strip_newlines(sanitize($result['title']));
$url = 'https://'.$this->opts->wikipedia_language.'.wikipedia.org/wiki/'.sanitize(str_replace(' ', '_', $result['title']));
$description = html_entity_decode(limit_string_length(strip_newlines(sanitize($result['snippet']))));
$results['search'][] = array ("id" => uniqid(rand(0, 9999)), "source" => "Wikipedia", "title" => $title, "url" => $url, "description" => $description, "engine_rank" => $rank);
$engine_temp[] = array (
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;
}
unset($response, $json_response, $rank);
// Base info
$number_of_results = count($engine_temp);
if($number_of_results > 0) {
$engine_result['source'] = 'Wikipedia';
$engine_result['amount'] = $number_of_results;
$engine_result['search'] = $engine_temp;
}
unset($response, $json_response, $number_of_results, $rank, $engine_temp);
return $results;
return $engine_result;
}
}
?>

BIN
engines/special/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,7 +11,9 @@
------------------------------------------------------------------------------------ */
class CurrencyRequest extends EngineRequest {
public function get_request_url() {
return "https://cdn.moneyconvert.net/api/latest.json";
$url = 'https://cdn.moneyconvert.net/api/latest.json';
return $url;
}
public function get_request_headers() {
@ -19,7 +21,6 @@ class CurrencyRequest extends EngineRequest {
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
@ -27,41 +28,45 @@ class CurrencyRequest extends EngineRequest {
}
public function parse_results($response) {
$json_response = json_decode($response, true);
$engine_result = array();
$json_response = json_decode($response, true);
if(!empty($json_response)) {
$result = $json_response['rates'];
// No response
if(empty($json_response)) return $engine_result;
// Process query
// [0] = AMOUNT
// [1] = FROM CURRENCY
// [2] = (to|in)
// [3] = TO CURRENCY
$query_terms = explode(" ", $this->query);
$amount = floatval($query_terms[0]);
$amount_currency = strtoupper($query_terms[1]);
$conversion_currency = strtoupper($query_terms[3]);
// No results
if(count($json_response['rates']) == 0) return $engine_result;
// Unknown/misspelled currencies
if (!array_key_exists($amount_currency, $result) || !array_key_exists($conversion_currency, $result)) {
return array();
}
// Calculate exchange rate
$conversion = round(($result[$conversion_currency] / $result[$amount_currency]) * $amount, 4);
// Process query
// [0] = AMOUNT
// [1] = FROM CURRENCY
// [2] = (to|in)
// [3] = TO CURRENCY
$query_terms = explode(' ', $this->query);
$amount = floatval($query_terms[0]);
$amount_currency = strtoupper($query_terms[1]);
$conversion_currency = strtoupper($query_terms[3]);
$last_update = date('M d, Y H:i:s', timezone_offset(strtotime(sanitize($json_response['lastupdate'])), $this->opts->timezone));
return array(
"title" => "Currency conversion:",
"text" => "$amount $amount_currency = $conversion $conversion_currency",
"source" => "https://moneyconvert.net/"
);
} else {
return array(
"title" => "Uh-oh...",
"text" => "No exchange rates could be loaded. Try again later."
);
// Unknown/misspelled currencies
if(!array_key_exists($amount_currency, $json_response['rates']) || !array_key_exists($conversion_currency, $json_response['rates'])) {
return $engine_result;
}
// Calculate exchange rate
$conversion = round(($json_response['rates'][$conversion_currency] / $json_response['rates'][$amount_currency]) * $amount, 2);
$one_to_n = round(($json_response['rates'][$conversion_currency] / $json_response['rates'][$amount_currency]) * 1, 2);
$engine_result = array(
'title' => "Currency conversion: ".$amount." ".$amount_currency." = ".$conversion." ".$conversion_currency,
'text' => "<p>1 $amount_currency = $one_to_n $conversion_currency</p><p><small>Updated: $last_update (GMT/UTC+0)</small></p>",
'source' => "https://moneyconvert.net/"
);
unset($response, $json_response, $query_terms, $amount, $amount_currency, $conversion, $one_to_n, $conversion_currency, $last_update);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,12 +11,20 @@
------------------------------------------------------------------------------------ */
class DefinitionRequest extends EngineRequest {
public function get_request_url() {
$query_terms = explode(" ", $this->query);
$query = str_replace('%22', '\"', $this->query);
$query_terms = explode(' ', $query);
// [0] = (define|d|mean|meaning)
// [1] = WORD
return "https://api.dictionaryapi.dev/api/v2/entries/en/".$query_terms[1];
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://api.dictionaryapi.dev/api/v2/entries/en/'.$query_terms[1];
unset($query, $query_terms);
return $url;
}
public function get_request_headers() {
@ -24,7 +32,6 @@ class DefinitionRequest extends EngineRequest {
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
@ -32,39 +39,57 @@ class DefinitionRequest extends EngineRequest {
}
public function parse_results($response) {
$engine_result = array();
$json_response = json_decode($response, true);
if(!empty($json_response)) {
// Word not found
if (array_key_exists("title", $json_response)) {
return array(
"title" => strip_tags(trim($json_response['title'])),
"text" => strip_tags(trim($json_response['message']))
);
}
// Grab first result if there are multiple
$result = $json_response[0];
$definitions = array_slice($result['meanings'][0]['definitions'], 0, 3);
// Word found
$formatted_response = strip_tags(trim($result['meanings'][0]['partOfSpeech']))."<br /><ol class=\"word-definitions\">";
foreach($definitions as $key => $def) {
$formatted_response .= "<li>".strip_tags(trim($def['definition']))."</li>";
// No response
if(empty($json_response)) return $engine_result;
// No results
if(array_key_exists('title', $json_response)) return $engine_result;
// Grab first result if there are multiple
$result = $json_response[0];
// Find a phonetic spelling
if(isset($result['phonetic'])) {
$phonetic = $result['phonetic'];
} else if(isset($result['phonetics'])) {
$phonetic = array_column($result['phonetics'], 'text');
$phonetic = (count($phonetic) > 0) ? $phonetic[0] : $result['word'];
} else {
$phonetic = $result['word'];
}
// List definitions
$formatted_response = "";
foreach($result['meanings'] as $meaning) {
$formatted_response .= "<p>".sanitize($meaning['partOfSpeech'])."</p>";
$definitions = array_slice($meaning['definitions'], 0, 3);
$formatted_response .= "<ol class=\"word-definitions\">";
foreach($definitions as $definition) {
$formatted_response .= "<li>";
$formatted_response .= " ".sanitize($definition['definition']);
$formatted_response .= (array_key_exists("example", $definition)) ? " <br /><small><strong>Example:</strong> ".sanitize($definition['example'])."</small>" : "";
$formatted_response .= "</li>";
unset($definition);
}
$formatted_response .= "</ol>";
return array(
"title" => strip_tags(trim($result['word']))." <span>[".strip_tags(trim($result['phonetic']))."]</span>",
"text" => $formatted_response,
"source" => strip_tags(trim($result['sourceUrls'][0]))
);
} else {
return array(
"title" => "Whoops...",
"text" => "No definitions could be loaded. Try again later."
);
unset($meaning);
}
$engine_result = array(
'title' => "Definition for: ".sanitize($result['word'])." <span>[".sanitize($phonetic)."]</span>",
'text' => $formatted_response,
'source' => sanitize($result['sourceUrls'][0])
);
unset($response, $json_response, $result, $phonetic, $definitions, $formatted_response);
return $engine_result;
}
}
?>

View file

@ -1,67 +0,0 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class eztvhighlights extends EngineRequest {
public function get_request_url() {
$url = "https://eztvx.to/api/get-torrents?".http_build_query(array("limit" => "16"));
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
);
}
public function parse_results($response) {
$results = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response['torrents_count'] == 0) return $results;
// Use API result
foreach($json_response['torrents'] as $result) {
$name = sanitize($result['title']);
$thumbnail = sanitize($result['small_screenshot']);
$season = sanitize($result['season']);
$episode = sanitize($result['episode']);
$magnet_link = sanitize($result['magnet_url']);
$quality = (preg_match('/(480p|720p|1080p|2160p)/i', $name, $quality)) ? $quality[0] : "";
$codec = (preg_match('/(x264|h264|x265|h265|xvid)/i', $name, $codec)) ? $codec[0] : "";
// Clean up show name
$name = (preg_match("/.+?(?=S[0-9]{1,3}E[0-9]{1,3})/i", $name, $clean_name)) ? $clean_name[0] : $name;
// Set up codec for quality
if(!empty($codec)) $quality = $quality." ".$codec;
$results[] = array (
"name" => $name, "thumbnail" => $thumbnail, "season" => $season, "episode" => $episode, "magnet_link" => $magnet_link, "quality" => $quality
);
unset($result, $name, $clean_name, $thumbnail, $season, $episode, $magnet_link, $quality, $codec);
}
unset($json_response);
return array_slice($results, 0, 16);
}
}
?>

48
engines/special/ipify.php Normal file
View file

@ -0,0 +1,48 @@
<?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 ipRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://api64.ipify.org?format=json';
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
);
}
public function parse_results($response) {
$engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $engine_result;
$engine_result = array(
'title' => "Your IP Address: ".$_SERVER["REMOTE_ADDR"],
'text' => "<p>All requests via Goosle use this as your IP Address: ".sanitize($json_response['ip'])."<br /><small>Goosle is not a proxy server. This test does <em>NOT</em> guarantee any degree of privacy. Any site that you visit through Goosle Search Results will see your actual IP Address.</small></p>",
'source' => "https://www.ipify.org/"
);
unset($response, $json_response);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,43 +11,62 @@
------------------------------------------------------------------------------------ */
class PHPnetRequest extends EngineRequest {
public function get_request_url() {
$this->query = str_replace("_", "-", str_replace("php ", "", $this->query));
$query = str_replace('%22', '\"', $this->query);
$query = str_replace('php ', '', $query);
$query = str_replace('_', '-', $query);
return "https://www.php.net/manual/function.".urlencode($this->query);
// Is there no query left? Bail!
if(empty($query)) return false;
$url = 'https://www.php.net/manual/function.'.urlencode($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',
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7'
);
}
public function parse_results($response) {
$results = array();
$engine_result = array();
$xpath = get_xpath($response);
if($xpath) {
// Scrape the page
$title = $xpath->query("//div/section/div[@class='refentry']/div/h1[@class='refname']")[0]->textContent;
if(is_null($title)) return array();
$php_versions = $xpath->query("//div/section/div[@class='refentry']/div/p[@class='verinfo']")[0]->textContent;
$purpose = $xpath->query("//div/section/div[@class='refentry']/div/p[@class='refpurpose']")[0]->textContent;
$usage = $xpath->query("//div/section/div[@class='refentry']/div[@class='refsect1 description']/div[@class='methodsynopsis dc-description']")[0]->textContent;
// No response
if(!$xpath) return $engine_result;
$response = array (
// Scrape the results
$scrape = $xpath->query("//div/section/div[@class='refentry']");
// No results
if(count($scrape) == 0) return $engine_result;
$query = str_replace('%22', '', $this->query);
$query = str_replace('php ', '', $query);
$query = str_replace('_', '-', $query);
foreach($scrape as $result) {
$title = $xpath->query(".//div/h1[@class='refname']")[0]->textContent;
if(is_null($title)) return $engine_result;
$php_versions = $xpath->query(".//div/p[@class='verinfo']")[0]->textContent;
$purpose = $xpath->query(".//div/p[@class='refpurpose']")[0]->textContent;
$usage = $xpath->query(".//div[@class='refsect1 description']/div[@class='methodsynopsis dc-description']")[0]->textContent;
$summary = $xpath->query(".//div[@class='refsect1 description']/p[@class='para rdfs-comment']")[0]->textContent;
$engine_result = array (
// Required
"title" => sanitize($title),
"text" => "<p><em><small>".$php_versions."</small></em></p><p>".$purpose."</p><p>".highlight_string("<?php ".trim($usage)." ?>", 1)."</p>",
"source" => "https://www.php.net/manual/function.".urlencode($this->query)
'title' => "Function: ".sanitize($title),
'text' => "<p><em><small>".sanitize($php_versions)."</small></em></p><p>".sanitize($purpose)."</p><p>".highlight_string("<?php ".sanitize($usage)." ?>", 1)."</p><p>".$summary."</p>",
'source' => "https://www.php.net/manual/function.".urlencode($query)
);
return $response;
} else {
return array(
"title" => "Oof...",
"text" => "PHP.net didn't provide any answers. Try again later."
);
}
unset($response, $xpath, $scrape);
return $engine_result;
}
}
?>

View file

@ -1,79 +0,0 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class ytshighlights extends EngineRequest {
public function get_request_url() {
$url = "https://yts.mx/api/v2/list_movies.json?".http_build_query(array("limit" => "16", "sort_by" => $this->opts->yts_highlight));
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'application/json, */*;q=0.8',
'Accept-Language' => null,
'Accept-Encoding' => null,
'Connection' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
);
}
public function parse_results($response) {
$results = array();
// $response = curl_multi_getcontent($this->ch);
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response['status'] != "ok" || $json_response['data']['movie_count'] == 0) return $results;
// Use API result
foreach ($json_response['data']['movies'] as $result) {
// Prevent gaps
if(!array_key_exists("year", $result)) $result['year'] = "0000";
if(!array_key_exists("genres", $result)) $result['genres'] = array();
if(!array_key_exists("rating", $result)) $result['rating'] = "0";
// Block these categories
if(count(array_uintersect($result['genres'], $this->opts->yts_categories_blocked, "strcasecmp")) > 0) continue;
$name = sanitize($result['title']);
$thumbnail = sanitize($result['medium_cover_image']);
$year = sanitize($result['year']);
$category = sanitize(implode(', ', array_slice($result['genres'], 0, 2)));
$url = sanitize($result['url']);
$rating = sanitize($result['rating']);
foreach($result['torrents'] as $download) {
$hash = sanitize($download['hash']);
$magnet = "magnet:?xt=urn:btih:".$hash."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->magnet_trackers);
$quality = sanitize($download['quality']);
$codec = sanitize($download['video_codec']);
$downloads[] = array (
"magnet" => $magnet, "quality" => $quality, "codec" => $codec
);
}
$results[] = array (
"name" => $name, "thumbnail" => $thumbnail, "year" => $year, "category" => $category, "rating" => $rating, "magnet_links" => $downloads, "url" => $url
);
unset($result, $name, $thumbnail, $year, $category, $rating, $hash, $download, $quality, $codec, $downloads, $url);
}
unset($json_response);
return array_slice($results, 0, 8);
}
}
?>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
functions/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -1,59 +0,0 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
/*--------------------------------------
// Curl requests for oAUTH
--------------------------------------*/
function oath_curl_request($url, $user_agent, $method, $header, $post) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if($method == "post") {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
} else {
curl_setopt($ch, CURLOPT_HTTPGET, 1);
}
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(array('Accept: application/json, */*;q=0.8'), $header));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
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 json_decode($response, true);
}
/*--------------------------------------
// Store generated tokens
--------------------------------------*/
function oath_store_token($token_file, $connect, $token) {
if(!is_file($token_file)){
// Create token file
file_put_contents($token_file, serialize(array($connect => $token)));
} else {
// Update token file
$tokens = unserialize(file_get_contents($token_file));
$tokens[$connect] = $token;
file_put_contents($token_file, serialize($tokens));
}
}
?>

View file

@ -1,13 +1,12 @@
<?php
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
require ABSPATH."functions/tools.php";
require ABSPATH."functions/oauth-functions.php";
require ABSPATH.'functions/tools.php';
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -32,87 +31,97 @@ $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
<link rel="apple-touch-icon" href="../apple-touch-icon.png" />
<link rel="canonical" href="<?php echo get_base_url($opts->siteurl); ?>/functions/oauth.php" />
<link rel="stylesheet" type="text/css" href="../assets/css/styles.css"/>
<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, $auth)) {
$connect = (isset($_REQUEST['oa'])) ? sanitize($_REQUEST['oa']) : "";
// Openverse
$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)) {
if(verify_hash($opts->hash_auth, $opts->hash, $auth)) {
?>
<div class="oauth-form">
<h1><span class="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.php" method="get" autocomplete="off">
<h2>(re)New registration</h2>
<p>Email address:<br /><input tabindex="10" type="text" class="field" name="oae" /><br /><small>(Required for verification)</small></p>
<h2>Recovering a previous registration?</h2>
<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>
<div class="content">
<?php
$connect = (isset($_REQUEST['oa'])) ? sanitize($_REQUEST['oa']) : '';
// Openverse
$email = (isset($_REQUEST['oae'])) ? sanitize($_REQUEST['oae']) : '';
$client_id = (isset($_REQUEST['oaid'])) ? sanitize($_REQUEST['oaid']) : '';
$client_secret = (isset($_REQUEST['oacs'])) ? sanitize($_REQUEST['oacs']) : '';
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>
if(empty($connect)) {
?>
<div class="oauth-buttons">
<button tabindex="100" name="oa" value="openverse" type="submit">Connect to Openverse</button>
</div>
</form>
</div>
<?php
} else {
$token_file = ABSPATH.'cache/token.data';
<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.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>
if(empty($client_id) AND empty($client_secret) AND !empty($email)) {
$registration = oath_curl_request(
'https://api.openverse.org/v1/auth_tokens/register/', // Where?
$opts->user_agents[0], // Who?
'post', // post/get
array(), // Additional headers
array('name' => 'Goosle Meta Search '.md5(get_base_url($opts->siteurl)), 'description' => 'Goosle Meta Search for '.get_base_url($opts->siteurl), 'email' => $email) // Payload
);
// 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.php?a=".$opts->hash."\">Try again</a></div>";
exit;
}
}
<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 {
$registration = array('client_id' => $client_id, 'client_secret' => $client_secret);
$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.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);
}
?>
$new_token = oath_curl_request(
'https://api.openverse.org/v1/auth_tokens/token/', // Where?
$opts->user_agents[0], // Who?
'post', // post/get
array('Authorization: Bearer'.$registration['client_id']), // Additional headers
'grant_type=client_credentials&client_id='.$registration['client_id'].'&client_secret='.$registration['client_secret'] // Payload
);
$new_token['expires_in'] = time() + ($new_token['expires_in'] - 3600);
oath_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\">SUCCESS!<br />Goosle is now authorized and you can enable Openverse in your config.php if you haven't already!<br />If this is your first time authorizing with this email address you'll get an email from Openverse in a few moments with a verification link that you need to click.<br /><br />To be able to recover your registration save these values:<br />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 {

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -23,7 +23,7 @@ abstract class EngineRequest {
if(!$this->url) return;
// Skip if there is a cached result (from earlier search)
if($this->opts->cache_type !== "off" && has_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, (intval($this->opts->cache_time) * 60))) return;
if($this->opts->cache_type !== 'off' && has_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, $this->opts->cache_time)) return;
// Default headers for the curl request
$default_headers = array(
@ -52,7 +52,7 @@ abstract class EngineRequest {
$this->headers = $default_headers;
}
unset($default_headers, $extra_headers, $key, $value);
unset($default_headers, $extra_headers);
// Curl
$this->ch = curl_init();
@ -61,7 +61,7 @@ abstract class EngineRequest {
curl_setopt($this->ch, CURLOPT_HTTPGET, 1); // Redundant? Probably...
curl_setopt($this->ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($this->ch, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($this->ch, CURLOPT_ENCODING, 'gzip,deflate');
curl_setopt($this->ch, CURLOPT_HTTPHEADER, $this->headers);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, true);
@ -77,14 +77,14 @@ abstract class EngineRequest {
// Get search engine url
--------------------------------------*/
public function get_request_url() {
return "";
return '';
}
/*--------------------------------------
// Check if a request to a search engine was successful
--------------------------------------*/
public function request_successful() {
if((isset($this->ch) && curl_getinfo($this->ch)['http_code'] == '200') || has_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, (intval($this->opts->cache_time) * 60))) {
if((isset($this->ch) && curl_getinfo($this->ch)['http_code'] == '200') || ($this->opts->cache_type !== 'off' && has_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, $this->opts->cache_time))) {
return true;
}
@ -101,10 +101,8 @@ abstract class EngineRequest {
return $this->parse_results(null);
}
$ttl = intval($this->opts->cache_time) * 60;
// If there is a cached result from an earlier search use that instead
if($this->opts->cache_type !== "off" && has_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, $ttl)) {
if($this->opts->cache_type !== 'off' && has_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, $this->opts->cache_time)) {
return fetch_cached_results($this->opts->cache_type, $this->opts->hash, $this->url);
}
@ -117,12 +115,12 @@ abstract class EngineRequest {
$results = $this->parse_results($response) ?? array();
// Cache last request
if($this->opts->cache_type !== "off") {
if(!empty($results)) store_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, $results, $ttl);
// 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($ttl);
if($this->opts->cache_type == 'file') delete_cached_results($this->opts->cache_time);
}
return $results;
@ -130,55 +128,4 @@ abstract class EngineRequest {
public static function print_results($results, $opts) {}
}
/*--------------------------------------
// Process special searches
--------------------------------------*/
function special_search_request($opts) {
$special_request = null;
$query_terms = explode(" ", $opts->query);
$query_terms[0] = strtolower($query_terms[0]);
// Currency converter
if($opts->special['currency'] == "on" && count($query_terms) == 4 && (is_numeric($query_terms[0]) && ($query_terms[2] == 'to' || $query_terms[2] == 'in'))) {
require ABSPATH."engines/special/currency.php";
$special_request = new CurrencyRequest($opts, null);
}
// Dictionary
if($opts->special['definition'] == "on" && count($query_terms) == 2 && ($query_terms[0] == 'define' || $query_terms[0] == 'd' || $query_terms[0] == 'mean' || $query_terms[0] == 'meaning')) {
require ABSPATH."engines/special/definition.php";
$special_request = new DefinitionRequest($opts, null);
}
// php.net search
if($opts->special['phpnet'] == "on" && count($query_terms) == 2 && $query_terms[0] == 'php') {
require ABSPATH."engines/special/php.php";
$special_request = new PHPnetRequest($opts, null);
}
return $special_request;
}
/*--------------------------------------
// Process special magnet search features
--------------------------------------*/
function special_magnet_request($opts, $mh) {
$special_request = array();
// Latest additions to yts
if($opts->special['yts'] == "on") {
require ABSPATH."engines/special/yts_highlights.php";
$special_request['yts'] = new ytshighlights($opts, $mh);
}
// Latest additions to eztv
if($opts->special['eztv'] == "on") {
require ABSPATH."engines/special/eztv_highlights.php";
$special_request['eztv'] = new eztvhighlights($opts, $mh);
}
return $special_request;
}
?>
?>

158
functions/tools-magnet.php Normal file
View file

@ -0,0 +1,158 @@
<?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.
------------------------------------------------------------------------------------ */
/*--------------------------------------
// Depect video quality (720p/1080i etc.)
// Try to standardize terms
--------------------------------------*/
function find_video_quality($string) {
$match = (preg_match('/[0-9]{3,4}[pi]{1}/i', $string, $match)) ? $match[0] : null;
if(empty($match)) $match = (preg_match('/(3d|4k|5k|8k)/i', $string, $match)) ? $match[0] : null;
if(!is_null($match)) {
$match = trim(strtolower($match));
if($match == '3d') $match = '3D';
if($match == '4k') $match = '2160p (4K)';
if($match == '5k') $match = '2880p (5K)';
if($match == '8k') $match = '4320p (8K)';
}
return $match;
}
/*--------------------------------------
// Detect the video codec
// Try to standardize terms
--------------------------------------*/
function find_video_codec($string) {
$return = array();
// H.265/HEVC
$codec = (preg_match('/\bhevc|(h|x) ?265\b/i', $string, $codec)) ? $codec[0] : null;
// H.264/AVC
if(empty($codec)) $codec = (preg_match('/\bavc|(h|x) ?264\b/i', $string, $codec)) ? $codec[0] : null;
// DIVx/xVID
if(empty($codec)) $codec = (preg_match('/\bx?(vid|div)x?\b/i', $string, $codec)) ? $codec[0] : null;
// Other
if(empty($codec)) $codec = (preg_match('/\bvp9|av1\b/i', $string, $codec)) ? $codec[0] : null;
if(!is_null($codec)) {
$codec = trim(strtolower($codec));
if($codec == 'hevc' || $codec == 'h265') $codec = 'x265'; // Maybe it should be h.265?
if($codec == 'avc' || $codec == 'h264') $codec = 'x264'; // Maybe it should be h.264?
if($codec == 'xvid') $codec = 'XviD';
if($codec == 'divx') $codec = 'DivX';
if($codec == 'av1') $codec = 'AV1';
if($codec == 'vp9') $codec = 'VP9';
$return[] = $codec;
}
// Maybe a bitrate?
$bitrate = (preg_match('/\b(8|10|12)-?bit\b/i', $string, $bitrate)) ? $bitrate[0] : null;
if(!is_null($bitrate)) {
$return[] = trim(strtolower($bitrate));
}
// Maybe HDR?
$hdr = (preg_match('/\bhdr|uhd|imax\b/i', $string, $hdr)) ? $hdr[0] : null;
if(!is_null($hdr)) {
$return[] = trim(strtoupper($hdr));
}
return implode(' ', $return);
}
/*--------------------------------------
// Detect audio type
// Try to standardize terms
--------------------------------------*/
function find_audio_codec($string) {
$return = array();
// Common movie codecs
$codec = (preg_match('/\b(dts(-?hd)?|aac|e?ac3|dolby([ -]?pro[ -]?logic i{1,2})?|truehd|ddp|dd)/i', $string, $audio)) ? $audio[0] : null;
// Common music codecs
if(empty($codec)) $codec = (preg_match('/\b(flac|wav|mp3|ogg|pcm|wma|aiff)\b/i', $string, $codec)) ? $codec[0] : null;
if(!is_null($codec)) {
$codec = trim(strtoupper($codec));
if($codec == 'EAC3' || $codec == 'DDPA' || $codec == 'DDP') $codec = 'Dolby Digital Plus';
if($codec == 'DD') $codec = 'Dolby Digital';
if($codec == 'DOLBY PRO LOGIC I') $codec = 'Dolby Pro Logic I';
if($codec == 'DOLBY PRO LOGIC II') $codec = 'Dolby Pro Logic II';
if($codec == 'DTSHD') $codec = 'DTS-HD';
if($codec == 'TRUEHD') $codec = 'TrueHD';
$return[] = $codec;
}
// Try to add channels
$channels = (preg_match('/(2|5|7|9)[ \.](0|1|2)\b/i', $string, $channels)) ? $channels[0] : null;
if(empty($channels)) $channels = (preg_match('/(2|6|8) ?(ch|channel)/i', $string, $channels)) ? $channels[0] : null;
if(!is_null($channels)) {
$return[] = trim(str_replace(' ', '.', strtoupper($channels)));
}
// Try to add bitrate
$bitrate = (preg_match('/[0-9]{2,3} ?kbp?s/i', $string, $bitrate)) ? $bitrate[0] : null;
if(!is_null($bitrate)) {
$return[] = trim(str_replace('kbs', 'kbps', str_replace(' ', '', strtolower($bitrate))));
}
// Maybe sub-codec?
$codec2 = (preg_match('/\batmos\b/i', $string, $codec2)) ? $codec2[0] : null;
if(!is_null($codec2)) {
$return[] = ucfirst(trim(strtolower($codec2)));
}
return implode(' ', $return);
}
/*--------------------------------------
// Create visual star rating for some magnet results
--------------------------------------*/
function movie_star_rating($rating) {
$rating = round($rating);
$star_rating = '';
for($i = 1; $i <= 10; $i++) {
$star_rating .= ($i <= $rating) ? "<span class=\"star yellow\">&#9733;</span>" : "<span class=\"star\">&#9733;</span>";
}
return $star_rating;
}
/*--------------------------------------
// Detect TV show Seasons and Episodes in results
--------------------------------------*/
function is_season_or_episode($search_query, $result_query) {
// Check if you searched for a tv show and result is a tv show
if(preg_match_all('/.+?(?=S[0-9]{1,4}E[0-9]{1,3})/', strtoupper($search_query), $match_query) && preg_match_all('/.+?(?=S[0-9]{1,4}E[0-9]{1,3})/', strtoupper($result_query), $match_result)) {
// If a match: [0][0] = Season and [0][1] = Episode
if($match_query[0][0] != $match_result[0][0] || (array_key_exists(1, $match_query[0]) && $match_query[0][1] != $match_result[0][1])) {
return false; // Not the tv show (episode) you're looking for
}
}
return true;
}
?>

View file

@ -0,0 +1,77 @@
<?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.
------------------------------------------------------------------------------------ */
/*--------------------------------------
// Do periodic update check
--------------------------------------*/
function check_update() {
$cache_file = ABSPATH.'cache/version.data';
// Currently installed version
$current_version = "1.5";
if(!is_file($cache_file)) {
// Create update cache file if it doesn't exist
$version = array('current' => $current_version, 'latest' => '0.0', 'checked' => 0, 'url' => '');
file_put_contents($cache_file, serialize($version));
} else {
// Get update information
$version = unserialize(file_get_contents($cache_file));
}
// Update check, every week
if($version['checked'] < time() - 604800) {
$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/'.$version['current'].';'), // (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' => $version['current'], 'latest' => $json_response['tag_name'], 'checked' => time(), 'url' => $json_response['html_url']);
file_put_contents($cache_file, serialize($version));
}
}
}
/*--------------------------------------
// Show version in footer
--------------------------------------*/
function show_version() {
$cache_file = ABSPATH.'cache/version.data';
if(is_file($cache_file)) {
// Get update information
$version = unserialize(file_get_contents($cache_file));
// TODO: Remove in a future version
if(!isset($version['current'])) $version['current'] = "1.5";
// Format current version for footer
$show_version = "<a href=\"https://github.com/adegans/Goosle/\" target=\"_blank\">Goosle ".$version['current']."</a>.";
// Check if a newer version is available and add it to the version display
if(version_compare($version['current'], $version['latest'], '<')) {
$show_version .= " <a href=\"".$version['url']."\" target=\"_blank\" class=\"update\">Version ".$version['latest']." is available!</a>";
}
} else {
// If the update cache doesn't exist...
$show_version = "<a href=\"https://github.com/adegans/Goosle/\" target=\"_blank\">Goosle</a>.";
}
return $show_version;
}
?>

View file

@ -1,6 +1,6 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -13,8 +13,8 @@
/*--------------------------------------
// Verify the hash, or not, and let people in, or not
--------------------------------------*/
function verify_hash($opts, $auth) {
if(($opts->hash_auth == "on" && strtolower($opts->hash) === strtolower($auth)) || $opts->hash_auth == "off") return true;
function verify_hash($use_hash, $hash, $auth) {
if(($use_hash == 'on' && strtolower($hash) === strtolower($auth)) || $use_hash == 'off') return true;
return false;
}
@ -23,25 +23,81 @@ function verify_hash($opts, $auth) {
// Load and make config available, pass around variables
--------------------------------------*/
function load_opts() {
$opts = require ABSPATH."config.php";
$config_file = ABSPATH.'config.php';
if(!is_file($config_file)) {
echo "<h3>config.php is missing!</h3>";
echo "<p>Please check the readme.md file for complete installation instructions.</p>";
echo "<p>Configure Goosle properly by copying config.default.php to config.php. In config.php you can set your preferences.</p>";
die();
} else {
$opts = require $config_file;
// From the url/request
if(!isset($_REQUEST['s'])) {
$opts->query = (isset($_REQUEST['q'])) ? trim($_REQUEST['q']) : '';
$opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : '';
$opts->share = '';
} else {
$share_string = explode('||', base64_url_decode(sanitize($_REQUEST['s'])));
if(is_array($share_string) && count($share_string) === 4) {
$opts->query = trim($share_string[2]);
$opts->type = sanitize($share_string[0]);
$opts->user_auth = sanitize($share_string[1]);
$opts->share = sanitize($share_string[3]);
}
unset($share_string);
}
// From the url/request
$opts->query = (isset($_REQUEST['q'])) ? trim($_REQUEST['q']) : "";
$opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : "";
// Force a few defaults and safeguards
if(empty($opts->colorscheme)) $opts->colorscheme = 'default';
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->enable_image_search == 'off' && $opts->type == 1) $opts->type = 0;
if($opts->enable_magnet_search == 'off' && $opts->type == 9) $opts->type = 0;
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->social_media_relevance) || ($opts->social_media_relevance > 10 || $opts->social_media_relevance < 0)) $opts->social_media_relevance = 8;
// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
if(substr($opts->query, 0, 1) == '!') $opts->query = substr($opts->query, 1);
return $opts;
}
}
/*--------------------------------------
// Standardized cURL requests that support both POST and GET
// For Box Office, Update checks and oAUTH
// NOT (YET?) USED FOR ENGINE REQUESTS!!
// NOT (YET?) USED FOR ENGINE REQUESTS!!
--------------------------------------*/
function do_curl_request($url, $headers, $method, $post_fields) {
$ch = curl_init();
// 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->enable_image_search == "off" && $opts->type == 1) $opts->type = 0;
if($opts->enable_magnet_search == "off" && $opts->type == 9) $opts->type = 0;
if(!is_numeric($opts->cache_time) || ($opts->cache_time > 720 || $opts->cache_time < 1)) $opts->cache_time = 30;
if(!is_numeric($opts->social_media_relevance) || ($opts->social_media_relevance > 10 || $opts->social_media_relevance < 0)) $opts->social_media_relevance = 8;
curl_setopt($ch, CURLOPT_URL, $url);
if($method == 'post' && !empty($post_fields)) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
} else {
curl_setopt($ch, CURLOPT_HTTPGET, 1);
}
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_VERBOSE, false);
// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
if(substr($opts->query, 0, 1) == "!") $opts->query = substr($opts->query, 1);
$response = curl_exec($ch);
curl_close($ch);
return $opts;
return $response;
}
/*--------------------------------------
@ -62,15 +118,17 @@ function get_xpath($response) {
--------------------------------------*/
function get_formatted_url($url) {
$url = parse_url($url);
$formatted_url = $url['scheme'] . "://" . $url['host'];
$formatted_url .= str_replace('/', ' &rsaquo; ', urldecode(str_replace('%20', ' ', rtrim($url['path'], '/'))));
$formatted_url = $url['scheme'] . '://' . $url['host'];
if(array_key_exists('path', $url)) {
$formatted_url .= str_replace('/', ' &rsaquo; ', urldecode(str_replace('%20', ' ', rtrim($url['path'], '/'))));
}
return $formatted_url;
}
/*--------------------------------------
// Get websites url/page
// Get Goosle's base url
--------------------------------------*/
function get_base_url($siteurl) {
// Figure out server protocol
@ -79,16 +137,33 @@ function get_base_url($siteurl) {
return $protocol.'://'.$siteurl;
}
/*--------------------------------------
// URL Safe base64 encoding
--------------------------------------*/
function base64_url_encode($input) {
return strtr(base64_encode($input), '+/=', '-_.');
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_.', '+/='));
}
function share_encode($opts, $magnet_hash) {
return get_base_url($opts->siteurl).'/results.php?s='.base64_url_encode($opts->type.'||'.$opts->hash.'||'.$opts->query.'||'.$magnet_hash);
}
/*--------------------------------------
// Result Caching
--------------------------------------*/
function has_cached_results($cache_type, $hash, $url, $ttl) {
if($cache_type == "apcu") {
return apcu_exists("$hash:$url");
$ttl = intval($ttl * 3600); // Make it hours
if($cache_type == 'apcu') {
return apcu_exists($hash.':'.$url);
}
if($cache_type == "file") {
$cache_file = ABSPATH.'cache/'.md5("$hash:$url").'.result';
if($cache_type == 'file') {
$cache_file = ABSPATH.'cache/'.md5($hash.':'.$url).'.result';
if(is_file($cache_file)) {
if(filemtime($cache_file) >= (time() - $ttl)) {
return true;
@ -100,23 +175,25 @@ function has_cached_results($cache_type, $hash, $url, $ttl) {
}
function store_cached_results($cache_type, $hash, $url, $results, $ttl) {
if($cache_type == "apcu" && !empty($results)) {
apcu_store("$hash:$url", $results, $ttl);
$ttl = intval($ttl * 3600); // Make it hours
if($cache_type == 'apcu') {
apcu_store($hash.':'.$url, $results, $ttl);
}
if($cache_type == "file") {
$cache_file = ABSPATH.'cache/'.md5("$hash:$url").'.result';
if($cache_type == 'file') {
$cache_file = ABSPATH.'cache/'.md5($hash.':'.$url).'.result';
file_put_contents($cache_file, serialize($results));
}
}
function fetch_cached_results($cache_type, $hash, $url) {
if($cache_type == "apcu") {
return apcu_fetch("$hash:$url");
if($cache_type == 'apcu') {
return apcu_fetch($hash.':'.$url);
}
if($cache_type == "file") {
$cache_file = ABSPATH.'cache/'.md5("$hash:$url").'.result';
if($cache_type == 'file') {
$cache_file = ABSPATH.'cache/'.md5($hash.':'.$url).'.result';
if(is_file($cache_file)) {
return unserialize(file_get_contents($cache_file));
}
@ -126,21 +203,44 @@ function fetch_cached_results($cache_type, $hash, $url) {
}
function delete_cached_results($ttl) {
$folder = opendir(ABSPATH.'cache/');
while($file_name = readdir($folder)) {
$extension = pathinfo($file_name, PATHINFO_EXTENSION);
if($file_name == "." OR $file_name == ".." OR $extension != "result") continue;
if(is_file($folder.$file_name)) {
if(filemtime($folder.$file_name) < (time() - $ttl)) {
unlink($folder.$file_name);
}
}
$ttl = intval($ttl * 3600); // Make it hours
$folder = ABSPATH.'cache/';
if(is_dir($folder)) {
if($handle = opendir($folder)) {
// Loop through all files
while(($file = readdir($handle)) !== false) {
// Skip some of them
$extension = pathinfo($file, PATHINFO_EXTENSION);
if($file == '.' OR $file == '..' OR $extension != 'result') continue;
// Delete if expired
if(filemtime($folder.$file) < (time() - $ttl)) {
unlink($folder.$file);
}
}
closedir($handle);
}
}
}
/*--------------------------------------
// Sanitize variables
// Store generated tokens
--------------------------------------*/
function oauth_store_token($token_file, $connect, $token) {
if(!is_file($token_file)){
// Create token file
file_put_contents($token_file, serialize(array($connect => $token)));
} else {
// Update token file
$tokens = unserialize(file_get_contents($token_file));
$tokens[$connect] = $token;
file_put_contents($token_file, serialize($tokens));
}
}
/*--------------------------------------
// Sanitize/format variables
--------------------------------------*/
function sanitize($variable) {
switch(gettype($variable)) {
@ -162,48 +262,43 @@ function sanitize($variable) {
return $variable;
}
function strip_newlines($string) {
return preg_replace('/<br>|\n/', '', $string);
}
function limit_string_length($string, $length = 100, $append = '&hellip;') {
$string = trim($string);
if(str_word_count($string, 0) > $length) {
$words = str_word_count($string, 2);
$pos = array_keys($words);
$string = substr($string, 0, $pos[$length]) . $append;
}
return $string;
}
/*--------------------------------------
// Search result match counter
--------------------------------------*/
function match_count($string, $query) {
if(empty($string)) return 0;
$string = strtolower($string);
if(filter_var($string, FILTER_VALIDATE_URL)) {
$string = preg_replace("/[^a-z0-9]+/", " ", $string);
$string = preg_replace('/[^a-z0-9]+/', ' ', $string);
}
$string = preg_replace("/[^a-z0-9 ]+/", "", $string);
$string = preg_replace("/\s{2,}/", " ", $string);
// 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 = array_intersect(array_filter(array_unique(explode(' ', $string))), $query);
$matches = count($matches);
return $matches;
}
/*--------------------------------------
// Detect Season and Episodes in results
--------------------------------------*/
function is_season_or_episode($search_query, $result_name) {
$search_query = strtolower($search_query);
$result_name = strtolower($result_name);
// Filter by Season (S01) or Season and Episode (S01E01)
// Where [0][0] = Season and [0][1] = Episode
if(preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/", $search_query, $query_episode) && preg_match_all("/(S[0-9]{1,3})|(E[0-9]{1,3})/", $result_name, $result_episode)) {
if($query_episode[0][0] != $result_episode[0][0]
|| (array_key_exists(1, $query_episode[0])
&& array_key_exists(1, $result_episode[0])
&& $query_episode[0][1] != $result_episode[0][1]
)
) {
return false;
}
}
return true;
}
/*--------------------------------------
// Detect social media results
--------------------------------------*/
@ -211,20 +306,20 @@ 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)
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;
return false;
@ -234,20 +329,20 @@ function is_social_media($string) {
// Search suggestions
--------------------------------------*/
function search_suggestion($opts, $results) {
$specific_result = $specific_result2 = "";
$specific_result = $specific_result2 = '';
if(array_key_exists("search_specific", $results)) {
if(array_key_exists('search_specific', $results)) {
if($opts->type == 3 && count($results['search_specific']) > 1) {
// Format query url
$search_specific_url2 = "./results.php?q=".urlencode($results['search_specific'][1])."&t=".$opts->type."&a=".$opts->hash;
$specific_result2 = " or <a href=\"".$search_specific_url2."\">".$results['search_specific'][1]."</a>";
$search_specific_url2 = './results.php?q='.urlencode($results['search_specific'][1]).'&t='.$opts->type.'&a='.$opts->hash;
$specific_result2 = ' or <a href="'.$search_specific_url2.'">'.$results['search_specific'][1].'</a>';
}
// Format query url
$search_specific_url = "./results.php?q=".urlencode($results['search_specific'][0])."&t=".$opts->type."&a=".$opts->hash;
$specific_result = "<br /><small>Or instead search for <a href=\"".$search_specific_url."\">".$results['search_specific'][0]."</a>".$specific_result2.".</small>";
$search_specific_url = './results.php?q='.urlencode($results['search_specific'][0]).'&t='.$opts->type.'&a='.$opts->hash;
$specific_result = '<br /><small>Or instead search for <a href="'.$search_specific_url.'">'.$results['search_specific'][0].'</a>'.$specific_result2.'.</small>';
unset($search_specific, $search_specific_url, $search_specific2, $search_specific_url2, $specific_result2);
unset($search_specific_url, $search_specific_url2, $specific_result2);
}
return $specific_result;
@ -259,11 +354,14 @@ function search_suggestion($opts, $results) {
function search_sources($results) {
$sources = array();
foreach($results as $source => $amount) {
$plural = ($amount > 1) ? "results" : "result";
$sources[] = $amount." ".$plural." from ".$source;
$plural = ($amount > 1) ? 'results' : 'result';
$sources[] = $amount.' '.$plural.' from '.$source;
}
return $sources = replace_last_comma(implode(', ', $sources)).'.';
$sources = replace_last_comma(implode(', ', $sources));
$sources = 'Includes '.$sources.'.';
return $sources;
}
/*--------------------------------------
@ -279,7 +377,7 @@ function replace_last_comma($string) {
}
/*--------------------------------------
// Human readable file sizes
// Human readable file sizes from bytes
--------------------------------------*/
function human_filesize($bytes, $dec = 2) {
$size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
@ -289,81 +387,71 @@ function human_filesize($bytes, $dec = 2) {
}
/*--------------------------------------
// Generate random strings for passwords
// Apply timezone setting
--------------------------------------*/
function string_generator() {
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$password = array();
$length = strlen($characters) - 1;
for($i = 0; $i < 24; $i++) {
$n = rand(0, $length);
$password[] = $characters[$n];
}
array_splice($password, 6, 0, '-');
array_splice($password, 13, 0, '-');
array_splice($password, 20, 0, '-');
return implode($password);
function timezone_offset($timestamp, $timezone_offset) {
if(strpos($timezone_offset, 'UTC') === false) return $timestamp;
if($timezone_offset == 'UTC') return $timestamp;
$timezone_offset = intval(substr($timezone_offset, 3));
if($timezone_offset > 0) {
return abs($timestamp + (intval(substr($timezone_offset, 1)) * 3600));
}
if($timezone_offset < 0) {
return abs($timestamp - (intval(substr($timezone_offset, 1)) * 3600));
}
}
/*--------------------------------------
// Show version in footer and do periodic update check
// Turn a string size (600 MB) into bytes (int)
--------------------------------------*/
function show_version() {
$cache_file = ABSPATH.'cache/version.data';
// Currently installed version
$current_version = "1.4";
function filesize_to_bytes($num) {
preg_match('/(b|kb|mb|gb|tb|pb|eb|zb|yb)/', strtolower($num), $match);
// Format current version for footer
$show_version = "<a href=\"https://github.com/adegans/Goosle/\" target=\"_blank\">Goosle ".$current_version."</a>.";
$num = floatval(preg_replace('/[^0-9.]+/', '', $num));
$match = $match[0];
if(!is_file($cache_file)){
// Create update cache file
$version = array('latest' => "0.0", "checked" => 0, "url" => "");
file_put_contents($cache_file, serialize($version));
if($match == 'kb') {
$num = $num * 1024;
} else if($match == 'mb') {
$num = $num * pow(1024, 2);
} else if($match == 'gb') {
$num = $num * pow(1024, 3);
} else if($match == 'tb') {
$num = $num * pow(1024, 4);
} else if($match == 'pb') {
$num = $num * pow(1024, 5);
} else if($match == 'eb') {
$num = $num * pow(1024, 6);
} else if($match == 'zb') {
$num = $num * pow(1024, 7);
} else if($match == 'yb') {
$num = $num * pow(1024, 8);
} else {
// Get update information
$version = unserialize(file_get_contents($cache_file));
$num = $num;
}
return intval($num);
}
/*--------------------------------------
// Generate random strings for passwords
--------------------------------------*/
function string_generator($length, $separator) {
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$password = array();
$rand = strlen($characters) - 1;
for($i = 0; $i < $length; $i++) {
$n = rand(0, $rand);
$password[] = $characters[$n];
}
if(!empty($separator)) {
array_splice($password, 6, 0, $separator);
array_splice($password, 13, 0, $separator);
array_splice($password, 20, 0, $separator);
}
// Update check, every week
if($version['checked'] < time() - 604800) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.github.com/repos/adegans/goosle/releases/latest');
curl_setopt($ch, CURLOPT_HTTPGET, 1); // Redundant? Probably...
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json, */*;q=0.7', 'User-Agent: goosle/'.$current_version.';'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
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);
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $show_version;
// Update version info
$version = array('latest' => $json_response['tag_name'], "checked" => time(), "url" => $json_response['html_url']);
file_put_contents($cache_file, serialize($version));
}
// Check if a newer version is available and add it to the version display
if(version_compare($current_version, $version['latest'], "<")) {
$show_version .= " <a href=\"".$version['url']."\" target=\"_blank\" class=\"update\">Version ".$version['latest']." is available!</a>";
}
return $show_version;
return implode($password);
}
?>

View file

@ -1,12 +1,14 @@
<?php
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
date_default_timezone_set('UTC');
require ABSPATH."functions/tools.php";
require ABSPATH.'functions/tools.php';
require ABSPATH.'functions/tools-update.php';
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -16,48 +18,50 @@ $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
* liability that might arise from its use.
---------------------------------------------------------------------------------------
* Includes:
* - Checking for updates.
* - Clearing out old cached results when using the file cache.
* - Renewing access token for Openverse (Expires every 12 hours)
------------------------------------------------------------------------------------ */
if(verify_hash($opts, $auth)) {
// Clear out old cached files?
if($opts->cache_type == "file") {
$ttl = intval($opts->cache_time) * 60;
if(verify_hash($opts->hash_auth, $opts->hash, $auth)) {
// Check for updates
check_update();
echo "Update cached updated!<br />";
delete_cached_results($ttl);
// Clear out old cached files?
if($opts->cache_type == 'file') {
delete_cached_results($opts->cache_time);
echo "Cache deleted!<br />";
echo "Expired file cache results deleted!<br />";
}
// Possibly renew the Openverse access token
if($opts->enable_image_search == "on" && $opts->enable_openverse == "on") {
require ABSPATH."functions/oauth-functions.php";
if($opts->enable_image_search == 'on' && $opts->enable_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()) {
// Is the token expired?
$new_token = oath_curl_request(
'https://api.openverse.org/v1/auth_tokens/token/', // Where?
$opts->user_agents[0], // Who?
'post', // post/get
array('Authorization: Bearer'.$registration['client_id']), // Additional headers
'grant_type=client_credentials&client_id='.$registration['client_id'].'&client_secret='.$registration['client_secret'] // Payload
$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);
oath_store_token($token_file, 'openverse', array("client_id" => $registration['client_id'], "client_secret" => $registration['client_secret'], "access_token" => $new_token['access_token'], "expires" => $new_token['expires_in']));
oauth_store_token($token_file, 'openverse', array('client_id' => $registration['client_id'], 'client_secret' => $registration['client_secret'], 'access_token' => $new_token['access_token'], 'expires' => $new_token['expires_in']));
echo "New Openverse token stored!<br />";
}
}
}
echo "No errors on this page? We're done!<br />";
} else {
echo "Unauthorized!";
}

200
help.php
View file

@ -1,12 +1,14 @@
<?php
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
date_default_timezone_set('UTC');
require ABSPATH."functions/tools.php";
require ABSPATH.'functions/tools.php';
require ABSPATH.'functions/tools-update.php';
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -25,113 +27,169 @@ $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
<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!" />
<meta name="description" content="Learn how to use Goosle, the best meta search engine!" />
<meta property="og:site_name" content="Goosle Search Help" />
<meta property="og:title" content="Goosle Search Help" />
<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" />
<meta property="og:type" content="website" />
<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); ?>/help.php" />
<link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<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>
<body class="helppage">
<?php
if(verify_hash($opts, $auth)) {
if(verify_hash($opts->hash_auth, $opts->hash, $auth)) {
?>
<div class="header">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a class="no-decoration" href="./?a=<?php echo $opts->hash; ?>"><span class="G">G</span>oosle</a></h1>
<input tabindex="1" class="search" type="search" value="<?php echo (strlen($opts->query) > 0) ? $opts->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($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>">
</form>
<div class="navigation">
<a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="Search results" />Search</a>
<div class="navigation">
<a class="<?php echo ($opts->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=0">Search</a>
<?php if($opts->enable_image_search == "on") { ?>
<a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/image.png" alt="Image results" />Images</a>
<?php } ?>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($opts->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=1" >Images</a>
<?php } ?>
<?php if($opts->enable_magnet_search == "on") { ?>
<a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/magnet.png" alt="Magnet results" />Magnet links</a>
<?php } ?>
</div>
</form>
<?php if($opts->enable_news_search == 'on') { ?>
<a class="<?php echo ($opts->type == '2') ? 'active ' : ''; ?>tab-news" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=2">News</a>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<a class="<?php echo ($opts->type == '9') ? 'active ' : ''; ?>tab-magnet" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=9">Magnet links</a>
<?php } ?>
</div>
</div>
<div class="content">
<h2>How to use Goosle</h2>
<p>DuckDuckGo and Google are mostly language agnostic and will try to figure out on their own what language to use based on your search query.</p>
<p>Searching defaults to Moderate Safe mode. To override the safe mode, prefix your search with <strong>safe:on</strong> or <strong>safe:off</strong>.<br /><strong>On</strong> will use 'Strict' mode, while <strong>off</strong> will disable safe searching, this may yield results that are unsuitable for work or minors.</p>
<?php if($opts->enable_google == "on") { ?>
<p>Google results are not personalized by default, using Google's own option for it.</p>
<?php } ?>
<?php if($opts->enable_duckduckgo == "on") { ?>
<p>DuckDuckGo search bangs are not supported and the <strong>!</strong> to trigger them is stripped out to prevent issues.</em></p>
<?php } ?>
<?php if($opts->enable_wikipedia == "on") { ?>
<p>Goosle can search directly on Wikipedia. This will yield results linking to Wikipedia pages in the language of your choice. Configure your language in config.php or have it default to english.</p>
<?php } ?>
<p>If you're tired of traditional results from sites like Google search or DuckDuckGo and you want to have more varied results, or just everything at once, Goosle has your back! Goosle searches on multiple search engines at the same time and shows you the most relevant results through a neat, clean interface.</p>
<h3>Result ranking</h3>
<p>To try and provide the best results first, if a website is found through multiple search engines it will show higher in the results on Goosle. Also the amount of matching words in the title and SEO description is considered. A better match will show higher in the results.</p>
<p>Result ranking is applied to web search and image search.</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 to 80 images. If you've enabled Openverse you can set a limit for Openverse images of up to 200 images per search.</p>
<p>Contrary to regular image search such as Google Image Search which opens a popup/slider with more information. Goosle Image Search links directly to the page where the image is displayed, but also to the actual image itself. You'll see the links for it below each image.</p>
<p>You can search for images in a general size by adding <strong>size:small</strong>, <strong>size:medium</strong> or <strong>size:large</strong> to your search query.</p>
<?php } ?>
<p><em>If you can't find it on page one, you're using the wrong search query!</em></p>
<h2>Special Searches</h2>
<?php if($opts->special['currency'] == "on") { ?>
<h3>Currency converter</h3>
<p>Goosle tries to provide you with the right answer on page one and is designed to be as easy to use and function as logical as possible. 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>
<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>
<h2>Web search</h2>
<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:on white goose</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>
<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['phpnet'] == "on") { ?>
<h3>PHP.net Search</h3>
<?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 any of the following keywords; <strong>d</strong>, <strong>define</strong>, <strong>mean</strong> or <strong>meaning</strong>.<br />
For example: Searching for <strong>define 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['definition'] == "on") { ?>
<h3>Word Definition</h3>
<p>You can easily look up the meaning of single words. Prefix the word you want to look up with any of the following keywords; <strong>d</strong>, <strong>define</strong>, <strong>mean</strong> or <strong>meaning</strong>.<br />
For example: Searching for <strong>define search</strong> will search for that as normal, but also show the dictionary definition highlighted above the search results.</p>
<p><em><strong>Note:</strong> Special Searches do not work for image and magnet search.</em></p>
<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>Image 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>
<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_magnet_search == "on") { ?>
<h2>Magnet Search</h2>
<p>Search for anything torrent sites have on offer the direct search result should give you the magnet link.<br />Results are gathered from 1337x, Nyaa, The Pirate Bay, EZTV and YTS and are ranked by most seeders. The number of results is limited to 50.</p>
<p>The search scripts will try to provide useful data which may include; Seeders/Leechers, A link to the torrent page, Download Category, Release year, Movie quality (720p, 4K etc.), Movie Runtime and the Download Size. Not every website makes this available and all results take a best effort approach.</p>
<?php if($opts->imdb_id_search == "on") { ?>
<h3>Searching TV Shows</h3>
<p>To do a specific search on The Pirate Bay and EZTV you can search for IMDb Title IDs. These are numeric IDs prefixed with <strong>tt</strong>. This kind of search is useful when you're looking for a tv show that doesn't have a unique name, or simply if you want to use a specialized tracker for tv shows.</p>
<p> If you already know the Title ID you can enter it directly in the Magnet Link search as your search query.<br />
If you don't know the Title ID you can do a regular search for <strong>imdb [tv show name]</strong>, for example <strong>imdb Jack Ryan</strong>.<br />
Goosle will detect the IMDb ID from the search results and include a highlight in the result that offers you to search for downloads through a magnet link search.</p>
<?php } ?>
<h3>Filtering TV Show episodes</h3>
<p>To help you narrow down results you can search for specific seasons and episodes. For example: If you search for <strong>tt5057054 S02</strong> or <strong>Jack Ryan S02</strong> you'll get filtered results for Jack Ryan Season 2. Searching for <strong>tt5057054 S02E03</strong> or <strong>Jack Ryan S02E03</strong> should find Season 2 Episode 3 and so on.</p>
<p>Likewise if you want a specific quality of a movie or tv show you can add that directly in your search. For example: If you search for <strong>Arrietty 720p</strong> you should primarily find that movie in 720p quality if it's available. Common screensizes are 480p, 720p, 1080p, 2160p (4K) and terms like HD-DVD, FULLHD, etc..</p>
<p><em><strong>Note:</strong> If you like, or found a use for, what you downloaded, you should buy a legal copy of it.</em></p>
<?php if($opts->enable_news_search == 'on') { ?>
<h2>News search</h2>
<p>Look for current and revent news through News Search. Search for any topic and you'll find news from the last month.</p>
<p>For current news prefix your search with <strong>today</strong>, <strong>now</strong> or <strong>yesterday</strong> or simply search for those single words if you want 'global' news for today. For example <strong>today where is the goose</strong>. You can also use <strong>recent</strong>, <strong>week</strong>, <strong>month</strong>, <strong>this month</strong>, <strong>year</strong> or <strong>this year</strong>. For example: <strong>recent geese migration</strong>.</p>
<p>Keep in mind: Using these limiting prefixes Goosle will filter out any results that are outside of your search which may result in less or no results at all.</p>
<?php } ?>
<p><small><strong>Acknowledgements:</strong><br />Goosle started as a fork of LibreY, and takes some design cues from DuckDuckGo.com. Goosle is created by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a> with the intent to make search fun and productive.</small></p>
<?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>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>
<?php if($opts->imdb_id_search == 'on') { ?>
<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>
<p>If you already know the Title ID you can search for it through the Magnet search.<br />
If you don't know the Title ID you can do a regular search for <strong>imdb [tv show name]</strong>, for example <strong>imdb Duck and Goose</strong>.<br />
Goosle will detect the IMDb ID from the search results and highlight it in the result as a link. This link offers you to search for downloads through a Magnet Search.</p>
<?php } ?>
<?php if($opts->show_share_option == 'on') { ?>
<h3>Sharing results</h3>
<p>You can share a specific Magnet result by clicking on the <strong>share</strong> link that's behind the result information. In the little popup that opens you can copy the result and share or store it anywhere you can paste text - For example in a messenger. This special link will perform the same search as you did yourself and highlight the result that you want to share. Keep in mind that if you run a private installation of Goosle you might be giving uninvited guests access to it, so be mindful of where you post the link.</p>
<?php } ?>
<h3>Finding specific TV Show episodes and seasons</h3>
<p>To help you narrow down results you can search for specific seasons and episodes. For example: If you search for <strong>tt7999864 S01</strong> or <strong>Duck and Goose S01</strong> you'll get filtered results for Duck & Goose Season 1. Searching for <strong>tt7999864 S01E02</strong> or <strong>Duck and Goose S01E02</strong> should find Season 1 Episode 2 and so on.</p>
<h3>Filtering Movie and TV Show results</h3>
<p>Likewise if you want a specific quality of a movie or tv show you can add that directly in your search. For example: If you search for <strong>Goose on the loose 720p</strong> you should primarily find that movie in 720p quality if it's available. Common screensizes are 480p, 720p, 1080p, 2160p (4K) and terms like HD-DVD, FULLHD, BLURAY etc..</p>
<p>You can do searches by year as well. Searching for <strong>1080p 2006</strong> should yield mostly movies from that year in the specified quality.</p>
<h3>The box office</h3>
<p>Along with Magnet search a Box Office page also appears. This is an overview page of the latest movies and other new downloads available on a few supported torrent sites. The shown results are cached just like regular search results.</p>
<p><em><strong>Note:</strong> The things you find through magnet search are not always legal to download due to copyright or local restrictions. If possible, always try to get a legal copy if you found a use for what you downloaded!</em></p>
<?php } ?>
<h2>Default search engine</h2>
<p>In some browsers you can add a custom search engine. To do so 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>.</p>
<p>Most browsers ask that you 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. If you don't like the selected colorscheme you can override it with the <strong>c</strong> argument in your search url. For example: <strong>https://example.com/?c=dark</strong>.</p>
<p>You can add this to your bookmark too to always override the colorscheme.</p>
<h3>Available colorschemes are:</h3>
<ol>
<li>"default" A dark headers and main backgrounds with light search results.</li>
<li>"light" More light elements.</li>
<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 your device its darkmode setting.</li>
</ol>
<p><small><strong>Acknowledgements:</strong><br />Goosle started as a fork of LibreY, and takes some design cues from DuckDuckGo.com. Goosle is created by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a> with the intent to make search more productive and fun.</small></p>
</div>
<div class="footer">
<div class="footer-left">
<div class="footer grid-container">
<div class="footer-grid">
&copy; <?php echo date('Y'); ?> <?php echo show_version(); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
</div>
<div class="footer-right">
<a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a>
<div class="footer-grid">
<a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./box-office.php?a=<?php echo $opts->hash; ?>&t=9">Box office</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a>
</div>
</div>

View file

@ -1,12 +1,12 @@
<?php
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
require ABSPATH."functions/tools.php";
require ABSPATH.'functions/tools.php';
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -25,48 +25,55 @@ $auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
<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!" />
<meta name="description" content="Get your Goosle on! - The best meta search engine for private and fast search results!" />
<meta property="og:site_name" content="Goosle Search" />
<meta property="og:title" content="Goosle Search" />
<meta property="og:description" content="Get your Goosle on! - The best meta search engine for private and fast search results!" />
<meta property="og:url" content="<?php echo get_base_url($opts->siteurl); ?>/" />
<meta property="og:image" content="<?php echo get_base_url($opts->siteurl); ?>/assets/images/goosle.webp" />
<meta property="og:type" content="website" />
<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); ?>" />
<link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<link rel="canonical" href="<?php echo get_base_url($opts->siteurl); ?>/" />
<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="startpage">
<?php
if(verify_hash($opts, $auth)) {
if(verify_hash($opts->hash_auth, $opts->hash, $auth)) {
?>
<div class="startpage-search">
<h1><span class="G">G</span>oosle</h1>
<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" name="q" autofocus />
<input tabindex="10" type="search" class="search-field" name="q" autofocus />
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>
<div class="search-buttons">
<button tabindex="20" name="t" value="0" type="submit">Web search</button>
<button tabindex="20" name="t" value="0" type="submit" class="web-search">Web search</button>
<?php if($opts->enable_image_search == "on") { ?>
<button tabindex="40" name="t" value="1" type="submit">Image search</button>
<?php if($opts->enable_image_search == 'on') { ?>
<button tabindex="40" name="t" value="1" type="submit" class="image-search">Image search</button>
<?php } ?>
<?php if($opts->enable_magnet_search == "on") { ?>
<button tabindex="50" name="t" value="9" type="submit">Magnet search</button>
<?php if($opts->enable_magnet_search == 'on') { ?>
<button tabindex="50" name="t" value="9" type="submit" class="magnet-search">Magnet search</button><a href="./box-office.php?a=<?php echo $opts->hash; ?>&t=9" class="box-office">Box office</a>
<?php } ?>
</div>
</form>
</div>
<?php if($opts->password_generator == "on") { ?>
<div class="password-generator">
<form method="get" action="./" autocomplete="off">
Password Generator<br/><input class="password" type="text" name="pw" maxlength="27" value="<?php echo string_generator(); ?>" autocomplete="0" />
</form>
<?php if($opts->password_generator == "on") { ?>
<div class="password-generator">
<form method="get" action="./" autocomplete="off">
Password Generator<br/><input class="password" type="text" name="pw" maxlength="27" value="<?php echo string_generator(24, '-'); ?>" autocomplete="0" />
</form>
</div>
<?php } ?>
</div>
<?php } ?>
<?php
} else {

125
readme.md
View file

@ -1,10 +1,10 @@
<h1><center>Goosle</center></h1>
<h2><center>The best Meta Search Engine to find everything.</center></h2>
<h2><center>The best Meta Search Engine to find everything</center></h2>
Goosle is a fast, privacy oriented search tool that just works. \
It's kept simple so everyone can use it and to make sure it works on most webservers.
If you're tired of traditional results from one site like Google search or DuckDuckGo and want to see more at once, 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** distractions, **no** trackers, **no** cookies and **no** javascript or other things to slow you down.
If you're tired of traditional results from one site like Google search or DuckDuckGo and want to see more at once, 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** distractions, **no** trackers, **no** cookies and **no** bloated libraries, frameworks, dependencies or other things that slow you down.
Goosle does Image search which shows results from Yahoo! Images and Openverse.
@ -18,26 +18,24 @@ 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
- Get search results from DuckDuckGo
- Get search results from Google
- Get search results from Qwant
- Get search results from Wikipedia
- Search results from DuckDuckGo, Google, Qwant, Brave, Wikipedia
- Image search through Yahoo! Images, Qwant 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 on the results page
- Algorithm for ranking search results for relevancy
- Option to down-rank the biggest social media sites such as facebook, instagram, twitter, tiktok, reddit, snapchat and a few others.
- Special searches for; Currency conversion, Dictionary and php.net
- Special searches for; Currency conversion, Dictionary, IP Lookup and php.net
- Randomized user-agents for to prevent profiling by search providers
- Non-personalized Google results without instant results or other non-sense
- Optional: Speed up repeat searches with APCu cache if your server has it or a basic file cache
- Optional: Access key as a basic way to keep your server to yourself
- Optional: Speed up repeat searches with APCu cache or file cache
- Optional: Basic access key as a basic way to keep your server to yourself
- Optional: Instant password generator on the start page
What Goosle does **not** have.
- Trackers and Cookies
- Ads, malware and distractions
- User profiles or user controllable settings
- Javascripts or Frameworks
- Libraries, dependencies or Frameworks
And yet it just works... fast!
@ -52,43 +50,39 @@ If you like Goosle, or found a use for it, please support my work and [donate](h
## Requirements
Any basic webserver/webhosting package with PHP7.4 or newer. \
No special requirements other than APCu for caching (Optional). \
Tested to work on Apache with PHP8.0.24 and 8.2.x.
Developed on Apache with PHP8.2.
## Installation
1. Download and unzip Goosle.
2. In the main directory. Copy config.default.php to config.php.
2. In the main directory copy config.default.php to config.php.
3. Edit the config.php file and set your preferences.
4. Upload all files to your webserver. (eg. example.com or search.example.com or a sub-folder such as example.com/search/)
5. Rename goosle.htaccess to .htaccess or add its contents to your existing .htaccess file.
6. Load Goosle in your browser. If you've enabled the access hash, add *?a=YOUR_HASH* to the url.
7. Let me know where you installed Goosle :-)
7. Set up a background task (Cronjob) as described below. This runs a background task to delete old cache files and renews authorization tokens and checks for updates.
8. Let me know where you installed Goosle in the 'Show your Goosle' discussion on Github :-)
## Updating Goosle to a newer version
1. Download and unzip the latest release of Goosle.
2. Check your config.php file and compare it to config.default.php. Go over your preferences. Make sure any new settings or changed values are present in your config.php. (Or reconfigure Goosle with a new copy from config.default.php)
3. Upload all files to your webserver, overwriting all files except perhaps config.php.
2. Reconfigure Goosle with a new copy from config.default.php (Or, compare your config.php file with config.default.php and make sure any new settings or changed values are present)
3. Upload all the files to your webserver, overwriting all files except perhaps config.php.
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!
## 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 register Goosle with Openverse.
At the end, please save the Client ID and Client Secret somewhere on your computer, in a note or something. Should the token file Goosle creates get lost you'll need those strings to continue using Openverse.
This procedure generates an access token, this token expires every 12 hours. Yeah, annoying! \
To automatically renew the token you can set up the Goosle cronjob as described below.
## Setting up a cronjob
## 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 couple of hours.
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 day.
For low traffic setups or if you do not use Openverse a longer interval of two or three times a day is fine.
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.
If you've enabled the access hash as a password, don't forget to include ?a=YOUR_HASH to the url.
Cron jobs are usually 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.
### Usage examples
Example for 10 minutes past every 3 hours \
`10 */3 * * * wget -qO - https://example.com/goosle-cron.php?a=YOUR_HASH`
@ -98,24 +92,87 @@ Example for 5 minutes past every 8 hours (I use this on my Goosle) \
Example for every midnight \
`0 0 * * * wget -qO - https://example.com/goosle-cron.php?a=YOUR_HASH`
### Notes:
Why a few minutes past the hour? Because commonly 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.
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.
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
- 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.
- 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.
Have fun finding things! Tell your friends!
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"
- 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 service limitation on their end.
- 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.
- Sometimes TV Show episodes on the box office are not properly merged despite all required data matching.
## Changelog
1.5 - June ??, 2024
- NOTICE: config.default.php has changed, re-create your config.php!!
- [fix] No longer caches empty results
- [fix] No longer make a request if the search query is empty
- [fix] Movie highlight/box office cache now works
- [fix] Language selector for Qwant, Wikipedia and Duckduckgo
- [fix] Season and Episode filter for tv show searches
- [fix] Safe search filter now actually works
- [fix] Magnet Search category exclusion filter now actually works
- [fix] Image size filter works more reliably
- [fix] Handling of doublequotes in search queries
- [fix] Search sources now show result amounts accurately
- [fix] Old cache files are now actually deleted when expired
- [fix] Search tabs not properly centered on smaller screens
- [new] Box Office page with latest/new downloads from a few supported torrent websites
- [new] News page with the latest news from major outlets
- [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 Brave
- [new] Image results from Qwant Image API
- [new] News results from Hackernews
- [new] News results from Yahoo! News
- [new] News results from Brave News
- [new] News results from Qwant News API
- [new] Magnet results from Sukebei.nyaa.si
- [new] Special search for IP Lookups via ipify (Search for "ip" or "myip")
- [new] Safe search switch for Yahoo! Images
- [new] Image size switch for Qwant Images
- [new] Merge missing magnet meta data from duplicate results if it doesn't already exist in the matched previous result
- [new] Detect meta data for Magnet Search results such as sound and video quality.
- [tweak] Cache ttl is now in hours (was minutes)
- [tweak] Optimizations in CSS, HTML separators and more
- [tweak] Moved icons into CSS so they can be colored using colorschemes
- [tweak] Better handling of image results
- [tweak] Better handling of empty/incomplete results for all engines
- [tweak] Better handling of empty/missing meta data for all magnet engines
- [tweak] Better category detection for Limetorrent magnets
- [tweak] Raised Magnet search limit to 200 (was 50)
- [tweak] Raised Wikipedia search limit to 20 (was 10)
- [tweak] Hide magnet results with 0 seeders by default
- [tweak] Uniform array formatting for all engines
- [tweak] Consistent use of single-quotes and double-qoutes
- [tweak] File size string conversion and formatting for all image and magnet engines
- [tweak] Update checks are now done weekly(ish) via the Cron job
- [tweak] Updated .htaccess caching rules
- [removed] CSS for 320px viewport
1.4 - May 16, 2024
- NOTICE: config.default.php has changed, re-create your config.php!!
- [fix] Footer no longer overlaps results
@ -123,7 +180,7 @@ You can post your questions on Github Discussions or say hi on [Mastodon](https:
- [fix] Double search type when searching from start page
- [new] Filter for additional/different headers per cURL request
- [new] Image search via Openverse API (Access token and cronjob required, see installation instructions)
- [new] Image search via Qwant API
- [new] Image search via Qwant
- [new] Web (recent news) search via Qwant API
- [tweak] Merged 'cache' option into 'cache-type', see config.default.php for details
- [tweak] Better filtering for duplicate web results

View file

@ -1,14 +1,19 @@
<?php
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
date_default_timezone_set('UTC');
require ABSPATH."functions/tools.php";
require ABSPATH."functions/search_engine.php";
require ABSPATH.'functions/tools.php';
require ABSPATH.'functions/search_engine.php';
require ABSPATH.'functions/tools-update.php';
// Blue pixel
$blank_thumb = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOUX3LxDAAE4AJiVKIoaQAAAABJRU5ErkJggg==';
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
$start_time = microtime(true);
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
* Goosle - The fast, privacy oriented search tool that just works.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -21,45 +26,62 @@ $start_time = microtime(true);
<!DOCTYPE html>
<html lang="en">
<head>
<title><?php echo $opts->query; ?> - 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="Get your Goosle on! - The best meta search engine for private and fast internet fun!" />
<meta name="description" content="Check out these Goosle search results!" />
<meta property="og:site_name" content="Goosle Search results" />
<meta property="og:title" content="The best meta search engine" />
<meta property="og:description" content="Check out these Goosle search results!" />
<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" />
<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); ?>/results.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"/>
<link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<?php
if($opts->type == "9") {
echo " <script src='".get_base_url($opts->siteurl)."/assets/js/goose.js' id='goosebox-js'></script>";
}
?>
</head>
<body>
<body class="resultspage">
<?php
if(verify_hash($opts, $auth)) {
if(verify_hash($opts->hash_auth, $opts->hash, $auth)) {
?>
<div class="header">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a class="no-decoration" href="./?a=<?php echo $opts->hash; ?>"><span class="G">G</span>oosle</a></h1>
<input tabindex="1" class="search" type="search" value="<?php echo (strlen($opts->query) > 0) ? $opts->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($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>">
<div class="navigation">
<a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="Search results" />Search</a>
<?php if($opts->enable_image_search == "on") { ?>
<a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/image.png" alt="Image results" />Images</a>
<?php } ?>
<?php if($opts->enable_magnet_search == "on") { ?>
<a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/magnet.png" alt="Magnet results" />Magnet links</a>
<?php } ?>
</div>
</form>
<div class="navigation">
<a class="<?php echo ($opts->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=0">Search</a>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($opts->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=1" >Images</a>
<?php } ?>
<?php if($opts->enable_news_search == 'on') { ?>
<a class="<?php echo ($opts->type == '2') ? 'active ' : ''; ?>tab-news" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=2">News</a>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<a class="<?php echo ($opts->type == '9') ? 'active ' : ''; ?>tab-magnet" href="./results.php?q=<?php echo $opts->query; ?>&a=<?php echo $opts->hash; ?>&t=9">Magnet links</a>
<?php } ?>
</div>
</div>
<div class="content">
@ -70,13 +92,16 @@ if(!empty($opts->query)) {
// Load search script
if($opts->type == 0) {
require ABSPATH."engines/search.php";
require ABSPATH.'engines/search.php';
$search = new Search($opts, $mh);
} else if($opts->type == 1) {
require ABSPATH."engines/search-image.php";
require ABSPATH.'engines/search-image.php';
$search = new ImageSearch($opts, $mh);
} else if($opts->type == 2) {
require ABSPATH.'engines/search-news.php';
$search = new NewsSearch($opts, $mh);
} else if($opts->type == 9) {
require ABSPATH."engines/search-magnet.php";
require ABSPATH.'engines/search-magnet.php';
$search = new MagnetSearch($opts, $mh);
}
@ -99,17 +124,20 @@ if(!empty($opts->query)) {
// Echoes results and special searches
$search->print_results($results, $opts);
} else {
echo "<div class=\"warning\">Search query can not be empty!<br />Not sure what went wrong? Learn more about <a href=\"./help.php?a=".$opts->hash."\">how to use Goosle</a>.</div>";
echo "<div class=\"warning\">";
echo " <h3>Search query can not be empty!</h3>";
echo " <p>Not sure what went wrong? Learn more about <a href=\"./help.php?a=".$opts->hash."\" title=\"how to use Goosle!\">how to use Goosle</a>.</p>";
echo "</div>";
}
?>
</div>
<div class="footer">
<div class="footer-left">
<div class="footer grid-container">
<div class="footer-grid">
&copy; <?php echo date('Y'); ?> <?php echo show_version(); ?> By <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
</div>
<div class="footer-right">
<a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a>
<div class="footer-grid">
<a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./box-office.php?a=<?php echo $opts->hash; ?>&t=9">Box office</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a>
</div>
</div>