Compare commits

..

No commits in common. "main" and "1.1" have entirely different histories.
main ... 1.1

82 changed files with 2077 additions and 6957 deletions

23
.gitignore vendored
View file

@ -1,23 +0,0 @@
# Project specific
*.data
*.result
*.log
.htaccess
config.php
# Github stuff
/.git
/.github
.distignore
.gitignore
.gitattributes
# OS generated files & misc
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
.nova
ehthumbs.db
Thumbs.db

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View file

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

View file

@ -1,35 +0,0 @@
:root {
/* Main colors */
--color-accent: #1fa4d1; /* Blue */
--background: #232323; /* Almost black */
--background-alt: #1f242b; /* Blueish black */
--background-popup: #1f242b; /* Blueish black */
--text: #d6dbdf; /* Almost white */
--text-alt: #eaecee; /* 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: #3498db; /* 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-text: #f0f6fc; /* Almost white */
--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 */
}

View file

@ -1,35 +0,0 @@
:root {
/* Main colors */
--color-accent: #1fa4d1; /* Blue */
--background: #fff; /* White */
--background-alt: #1f242b; /* Almost black */
--background-popup: #ebf5fb; /* Blueish white */
--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-text: #f0f6fc; /* Almost white */
--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,4 +0,0 @@
<?php
header("Location: /");
die();
?>

View file

@ -1,35 +0,0 @@
:root {
/* Main colors */
--color-accent: #1fa4d1; /* Blue */
--background: #fff; /* White */
--background-alt: #d6eaf8; /* Light blue */
--background-popup: #ebf5fb; /* Blueish white */
--text: #494949; /* Dark grey */
--text-alt: #494949; /* Dark grey */
--border: #808b96; /* 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: #808b96; /* Grey */
--startpage-border-alt: #808b96; /* Lighter grey */
--startpage-button-text: #f0f6fc; /* Almost white */
--startpage-button-bg: #2980B9; /* Blueish grey */
--startpage-button-bg-alt: #7FB3D5; /* 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,5 +1,5 @@
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -7,254 +7,201 @@
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT. * COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any * By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use. * liability that might arise from its use.
---------------------------------------------------------------------------------------
* All icons are borrowed from IconFinder (https://www.iconfinder.com/search/icons?family=unicons-line)
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
body { min-height:100vh; display:flex; flex-direction:column; margin:0; padding:0; line-height:1.2; font-family:Arial, Helvetica, sans-serif; font-weight:400; font-size:1rem; background-color:var(--background); color:var(--text); } body { position: relative; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; color: #222; background-color: #ffffff; line-height: 1.2; }
div { margin:0; padding:0; border:0; vertical-align:baseline; } div { margin: 0; padding: 0; border: 0; font-size: 100%; vertical-align: baseline; }
h2, h3, h4, h5, h6 { margin:0; padding-top:.1em; padding-bottom:.3em; font-weight:500; } article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; }
h1 { font-size:4em; } h2, h3, h4, h5, h6 { font-weight: normal; }
h2 { font-size:2em; } h2, h3, h4, h5, h6, p, ul, ol, blockquote { padding-top: .5em; padding-bottom: .5em; }
h3 { font-size:1.5em; } ol, ol > li { margin: 0; padding: 0; list-style: none; }
h4, h5, h6 { font-size:1.2em; } input, button { outline: none; }
p { margin:0; padding-top:.2em; padding-bottom:.5em; } button { cursor: pointer; }
ul, ul > li { margin:0; padding:0; list-style:none; } p { font-size: 18px; color: #494949; }
input, button { outline:none; } a { text-decoration: none; color: #4495d4; }
button { cursor:pointer; } small, sub, sup { padding: 5px 0; color: #666; font-size: 12px; }
a { text-decoration:none; color:var(--link); } sub, sup { font-style: italic; }
a:hover { text-decoration:underline; } a:hover { text-decoration: underline; }
small { color:var(--meta); font-size:.8rem; } input[type="text"]:invalid ~ input[type="submit"] { opacity: 0.5; pointer-events: none; }
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>"); }
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance:none; -webkit-mask-image:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMy40MSwxMmw0LjMtNC4yOWExLDEsMCwxLDAtMS40Mi0xLjQyTDEyLDEwLjU5LDcuNzEsNi4yOUExLDEsMCwwLDAsNi4yOSw3LjcxTDEwLjU5LDEybC00LjMsNC4yOWExLDEsMCwwLDAsMCwxLjQyLDEsMSwwLDAsMCwxLjQyLDBMMTIsMTMuNDFsNC4yOSw0LjNhMSwxLDAsMCwwLDEuNDIsMCwxLDEsMCwwLDAsMC0xLjQyWiIgZmlsbD0iIzY1NjNmZiIvPjwvc3ZnPg=="); } /* Page structure */
.wrap { min-height: 100vh; overflow: hidden; }
.header-wrap { display: block; padding-top: 16px; width: 100%; }
.results-wrap { position: relative; display: flex; margin: 0 158px 50px 158px; }
.footer-wrap { position: absolute; bottom: 0; display: block; margin-top: 15px; padding: 0; width: 100%; }
.content { margin:25px 158px; padding:0; } /* Main page */
body.main { background-color: #1f242b; color: #f0f6fc; }
.search-box-main, .password-generator { text-align: center; margin-top: 10%; }
.search-box-main h1 { font-size: 70px; }
.search-box-main .search, .password-generator .password { padding: 10px 20px; width: 600px; color: #f0f6fc; background-color: #333333; font-size: 32px; font-family: sans-serif; border: 1px solid #3C4043; border-radius: 10px; }
.search-box-main .search[type="search"]::-webkit-search-cancel-button { background-size: 28px 28px; height: 28px; width: 28px; background-color: #f0f6fc; }
.search-box-buttons button { margin: 30px 20px 10px 20px; padding: 13px 10px 13px 10px; min-width: 130px; color: #f0f6fc; background-color: #333333; font-size: 14px; border: 1px solid #3C4043; border-radius: 6px; }
.search-box-buttons button:hover { border: 1px solid #5f6368; }
/* Start page */ .password-generator { margin: 30px auto; padding: 0; }
.startpage { background-color:var(--background-alt); color:var(--text-alt); } .password-generator .password { margin: 10px auto; width: 300px; text-align: center; font-size: 14px; }
.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(--startpage-button-text); 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; }
.startpage .footer { border-top:1px solid var(--color-accent); } /* Search Results - Header */
.header-wrap { background-color: #1f242b; color: #f0f6fc; border-bottom: 2px solid #1fa4d1; }
.header-wrap .search, .header-wrap .button { position: relative; height: 40px; color: #f0f6fc; font-size: 100%; font-weight: 400; }
.header-wrap .search { margin: 28px 0 28px 158px; padding: 5px 5px 5px 15px; width: 580px; background-color: #1f242b; border: 1px solid #303842; border-radius: 10px 0 0 10px; }
.header-wrap .search[type="search"]::-webkit-search-cancel-button { background-size: 20px 20px; height: 20px; width: 20px; background-color: #f0f6fc; }
.header-wrap .button { margin: 28px 10px 28px 0; padding: 5px 20px 5px 15px; background-color: #1fa4d1; border: none; border-radius: 0 10px 10px 0; }
.password-generator { margin:30px auto; padding:0; } /* Search results - Header Navigation */
.password-generator .password { margin:10px auto; width:300px; text-align:center; font-size:.8rem; } .navigation-header { margin-left: 165px; margin-bottom: 10px; }
.navigation-header img { margin-right: 5px; height: 16px; vertical-align: middle; }
.navigation-header a { margin-right: 20px; border: none; font-size: 16px; cursor: pointer; text-decoration: none; }
.navigation-header a:hover { color: #ebf3fa; }
.navigation-header a:visited { color: #1fa4d1; }
.navigation-header .active { padding-bottom: 8px; border-bottom: 4px #1fa4d1 solid; }
/* Page header (Search results, Help, Box office) */ /* Search results - Main column */
.header { padding:0; width:100%; background-color:var(--background-alt); color:var(--text-alt); border-bottom:3px solid var(--color-accent); } .main-column { width: 100%; }
.header form { margin:35px 0; } .main-column ol .result { margin: .50rem 0 .50rem 0; padding: 0; }
.header .logo { position:absolute; margin:0 18px; font-size:2rem; } .main-column ol .special-result, .main-column ol .meta { margin: .75rem 0 .75rem 0; padding: .5rem 10px; }
.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; }
.header .navigation { margin-left:158px; margin-bottom:10px; } .main-column ol li article { padding: .5rem 10px; border: 1px solid #fefefe; border-radius: 8px; }
.header .navigation a { margin-right:20px; border:none; cursor:pointer; text-decoration:none; } .main-column ol li article div.url:first-child, .main-column ol li.special-result article div.source:first-child { flex-grow: 0; }
.header .navigation a:visited { color:var(--link); } .main-column ol li article div.url { display: inline-block; margin: 0; max-width: 100%; color: #666; font-size: 1rem; line-height: 1.6; letter-spacing: .2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.header .navigation a:hover { color:var(--text-alt); } .main-column ol li article div.url a { margin: 0; color: #3f6e35; cursor: pointer; text-decoration: none; }
.header .navigation .active { padding-bottom:8px; border-bottom:4px solid var(--color-accent); } .main-column ol li article div.title, .main-column ol li.special-result article div.title { margin-top: .146rem; margin-bottom: .28451rem; }
.main-column ol li article div.title h2 { margin: 0; padding: 0; position: relative; font-size: 1.46rem; letter-spacing: -.01px; }
.main-column ol li article div.title h2:hover { text-decoration: underline; }
.main-column ol li article div.title a { margin: 0; display: block; cursor: pointer; }
.main-column ol li article div.title a:visited { color: #6d59a3; }
.main-column ol li article div.description { margin: 0; line-height: 1.4; font-size: 1rem; color: #494949; }
.main-column ol li article div.description .seeders { color: #518257; }
.main-column ol li article div.description .leechers { color: #c00; }
/* Navigation icons */ /* Image results - Main column */
.navigation a.tab-search::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--color-accent); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMiwyMEg1YTEsMSwwLDAsMS0xLTFWNUExLDEsMCwwLDEsNSw0aDVWN2EzLDMsMCwwLDAsMywzaDN2MWExLDEsMCwwLDAsMiwwVjlzMCwwLDAtLjA2YTEuMzEsMS4zMSwwLDAsMC0uMDYtLjI3bDAtLjA5YTEuMDcsMS4wNywwLDAsMC0uMTktLjI4aDBsLTYtNmgwYTEuMDcsMS4wNywwLDAsMC0uMjgtLjE5LjMyLjMyLDAsMCwwLS4wOSwwQS44OC44OCwwLDAsMCwxMS4wNSwySDVBMywzLDAsMCwwLDIsNVYxOWEzLDMsMCwwLDAsMywzaDdhMSwxLDAsMCwwLDAtMlpNMTIsNS40MSwxNC41OSw4SDEzYTEsMSwwLDAsMS0xLTFaTTcsOGExLDEsMCwwLDAsMCwySDhBMSwxLDAsMCwwLDgsOFpNMjEuNzEsMjAuMjlsLTEuMTctMS4xNkEzLjQ0LDMuNDQsMCwwLDAsMjAsMTVoMEEzLjQ5LDMuNDksMCwwLDAsMTQsMTcuNDlhMy40NiwzLjQ2LDAsMCwwLDUuMTMsMy4wNWwxLjE2LDEuMTdhMSwxLDAsMCwwLDEuNDIsMEExLDEsMCwwLDAsMjEuNzEsMjAuMjlabS0zLjE3LTEuNzVhMS41NCwxLjU0LDAsMCwxLTIuMTEsMEExLjUsMS41LDAsMCwxLDE2LDE3LjQ5YTEuNDYsMS40NiwwLDAsMSwuNDQtMS4wNiwxLjQ4LDEuNDgsMCwwLDEsMS0uNDNBMS40NywxLjQ3LDAsMCwxLDE5LDE3LjQ5LDEuNSwxLjUsMCwwLDEsMTguNTQsMTguNTRaTTEzLDEySDdhMSwxLDAsMCwwLDAsMmg2YTEsMSwwLDAsMCwwLTJabS0yLDZhMSwxLDAsMCwwLDAtMkg3YTEsMSwwLDAsMCwwLDJaIiBmaWxsPSIjNjU2M2ZmIi8+PC9zdmc+'); } .main-column .image-wrapper { width: 100%; margin: .75rem 0 .75rem 0; }
.navigation a.tab-image::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--color-accent); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xOSwxM2ExLDEsMCwwLDAtMSwxdi4zOWwtMS40OC0xLjQ4YTIuNzksMi43OSwwLDAsMC0zLjkzLDBsLS43LjdMOS40MSwxMS4xMmEyLjg3LDIuODcsMCwwLDAtMy45MywwTDQsMTIuNjFWN0ExLDEsMCwwLDEsNSw2SDlBMSwxLDAsMCwwLDksNEg1QTMsMywwLDAsMCwyLDdWMTlhMywzLDAsMCwwLDMsM0gxN2EzLDMsMCwwLDAsMy0zVjE0QTEsMSwwLDAsMCwxOSwxM1pNNSwyMGExLDEsMCwwLDEtMS0xVjE1LjQzbDIuOS0yLjg5YS43OS43OSwwLDAsMSwxLjA5LDBsMy4xNywzLjE3LDAsMEwxNS40NSwyMFptMTMtMWExLDEsMCwwLDEtLjE4LjU0TDEzLjMxLDE1bC43LS42OWEuNzcuNzcsMCwwLDEsMS4xLDBMMTgsMTcuMjJabTMuNzEtOC43MUwyMCw4LjU3YTQuMzEsNC4zMSwwLDEsMC02LjcyLjc5LDQuMjcsNC4yNywwLDAsMCwzLDEuMjZBNC4zNCw0LjM0LDAsMCwwLDE4LjU3LDEwbDEuNzIsMS43M2ExLDEsMCwwLDAsMS40MiwwQTEsMSwwLDAsMCwyMS43MSwxMC4yOVpNMTgsOGEyLjMyLDIuMzIsMCwxLDEsMC0zLjI3QTIuMzIsMi4zMiwwLDAsMSwxOCw4WiIgZmlsbD0iIzY1NjNmZiIvPjwvc3ZnPg=='); } @supports not (display: grid) {
.navigation a.tab-news::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--color-accent); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNywxMUgxNmExLDEsMCwwLDAsMCwyaDFhMSwxLDAsMCwwLDAtMlptMCw0SDE2YTEsMSwwLDAsMCwwLDJoMWExLDEsMCwwLDAsMC0yWk0xMSw5aDZhMSwxLDAsMCwwLDAtMkgxMWExLDEsMCwwLDAsMCwyWk0yMSwzSDdBMSwxLDAsMCwwLDYsNFY3SDNBMSwxLDAsMCwwLDIsOFYxOGEzLDMsMCwwLDAsMywzSDE4YTQsNCwwLDAsMCw0LTRWNEExLDEsMCwwLDAsMjEsM1pNNiwxOGExLDEsMCwwLDEtMiwwVjlINlptMTQtMWEyLDIsMCwwLDEtMiwySDcuODJBMywzLDAsMCwwLDgsMThWNUgyMFptLTktNGgxYTEsMSwwLDAsMCwwLTJIMTFhMSwxLDAsMCwwLDAsMlptMCw0aDFhMSwxLDAsMCwwLDAtMkgxMWExLDEsMCwwLDAsMCwyWiIgZmlsbD0iIzY1NjNmZiIvPjwvc3ZnPg=='); } .image-grid > * { max-width: 8rem; margin-left: auto; margin-right: auto; }
.navigation a.tab-magnet::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--color-accent); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0yMCw4Ljk0YTEuMzEsMS4zMSwwLDAsMC0uMDYtLjI3bDAtLjA5YTEuMDcsMS4wNywwLDAsMC0uMTktLjI4aDBsLTYtNmgwYTEuMDcsMS4wNywwLDAsMC0uMjgtLjE5bC0uMSwwQTEuMSwxLjEsMCwwLDAsMTMuMDYsMkg3QTMsMywwLDAsMCw0LDVWMTlhMywzLDAsMCwwLDMsM0gxN2EzLDMsMCwwLDAsMy0zVjlTMjAsOSwyMCw4Ljk0Wk0xNCw1LjQxLDE2LjU5LDhIMTVhMSwxLDAsMCwxLTEtMVpNMTgsMTlhMSwxLDAsMCwxLTEsMUg3YTEsMSwwLDAsMS0xLTFWNUExLDEsMCwwLDEsNyw0aDVWN2EzLDMsMCwwLDAsMywzaDNabS00LjcxLTQuNzEtLjI5LjNWMTJhMSwxLDAsMCwwLTIsMHYyLjU5bC0uMjktLjNhMSwxLDAsMCwwLTEuNDIsMS40MmwyLDJhMSwxLDAsMCwwLC4zMy4yMS45NC45NCwwLDAsMCwuNzYsMCwxLDEsMCwwLDAsLjMzLS4yMWwyLTJhMSwxLDAsMCwwLTEuNDItMS40MloiIGZpbGw9IiM2NTYzZmYiLz48L3N2Zz4='); } .image-grid li.result { display: inline-block; margin: .75rem; width: 12.5%; }
.image-grid > * + * { margin-top: 1rem; }
/* Search results (web, image, magnet, box office) */
.resultspage .meta { margin:0 0 15px 0; }
.resultspage .timer, .resultspage .didyoumean { margin:0; padding:0; }
.resultspage .sources, .resultspage .suggestion { padding:0; font-size:.8rem; color:var(--meta); }
.resultspage .result, .resultspage .result-special, .resultspage .result.shared, .boxofficepage .result { margin:0 0 25px 0; }
.resultspage .result-special, .resultspage .result.shared { padding:10px; }
/* Results formatting */
.resultspage .title, .resultspage .description, .resultspage .text, .resultspage .url, .resultspage .source, .resultspage .note { word-wrap:break-word; }
.resultspage .result .url, .resultspage .result-special .source { letter-spacing:.2px; }
.resultspage .result .url a, .resultspage .result-special .source a { cursor:pointer; text-decoration:none; color:var(--link-source); }
.resultspage .result .title h2 { position:relative; letter-spacing:-.01px; font-size:1.5rem; }
.resultspage .result .title h2:hover { text-decoration:underline; }
.resultspage .result .title a { display:block; cursor:pointer; }
.resultspage .result .title a:visited { color:var(--link-visited); }
.resultspage .result .description p, .resultspage .result .meta p { padding-top:0; padding-bottom:0; }
.resultspage .result .meta { padding:0; font-size:.8rem; color:var(--meta); text-align:center; }
.resultspage .result.image .meta { margin:5px 0 0 0; }
.resultspage .result .engines { padding:2px 0; font-size:.8rem; color:var(--meta); }
.resultspage .result.news { display:flex; flex-direction:row; column-gap:1rem; width:100%; }
.resultspage .result.news .title h2, .resultspage .result.magnet .title h2 { padding-top:0; padding-bottom:.2em; }
.resultspage .result.news .image { position:relative; overflow:hidden; width:140px; min-width:140px; height: 100px; border-radius:10px; }
.resultspage .result.news .image::before { content:""; position:absolute; height:100%; width:100%; background-color:var(--color-accent); background-image:url('/assets/images/goosle-nobg.webp'); background-position:center; background-repeat:no-repeat; border-radius:10px; z-index:-1; }
.resultspage .result.news .image img { object-fit:cover; object-position:center; width:100%; height:100%; border-radius:10px; }
.resultspage .result-special .note { text-align:right; }
/* Special results and shared magnet result */
.resultspage .result.shared, .resultspage .result-special { overflow:hidden; background-color:var(--result-special-background); border:1px solid var(--border-alt); border-radius:10px; }
.resultspage .result.shared div.title h2, .resultspage .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) {
.result-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(8rem, 1fr)); row-gap:2rem; column-gap:1rem; }
} }
@supports not (display:grid) { @supports (display: grid) {
.result-grid > * { max-width:8rem; margin-left:auto; margin-right:auto; } .main-column ol.image-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); grid-gap: 1rem; }
.result-grid .result { display:inline-block; margin:.75rem; width:12.5%; }
.result-grid > * + * { margin-top:1rem; }
} }
.main-column ol.image-grid .result .image-box { position: relative; }
.main-column ol.image-grid .result .image-box::after { display: block; padding-bottom: 100%; content: ""; }
.main-column ol.image-grid .result .image-box img { position: absolute; object-fit: cover; width: 100%; height: 100%; border-radius: 10px; }
.main-column ol.image-grid .result .image-box img:hover { outline: none; border-color: #3C4043; box-shadow: 0 0 10px #3C4043; }
.main-column ol.image-grid .result span { padding: 5px 0 0 0; color: #666; font-size: 12px; }
/* Grid results */ /* Special results - Main column */
.result-grid { margin:0 0 25px 0; } .main-column ol .special-result { background-color: #fefefe; }
.result-grid .result.image .thumb, .result-grid .result.highlight .thumb { position:relative; overflow:hidden; height: 140px; border-radius:10px; } .main-column ol li.special-result article { padding: .5rem 10px; position: relative; overflow: hidden; border: 1px solid #aeaeae; border-radius: 8px; color: #222; }
.result-grid .result.yts .thumb { height: 210px;; } .main-column ol li.special-result article div.title h2 { margin: 0; padding: 0; font-size: 1.5rem; font-weight: 600; word-wrap: break-word; color: #222; }
.result-grid .result.image .thumb::before, .result-grid .result.highlight .thumb::before { position:absolute; height:100%; width:100%; background-color:var(--color-accent); background-image:url('/assets/images/goosle-nobg.webp'); background-position:center; background-repeat:no-repeat; border-radius:10px; content:""; z-index:-1; } .main-column ol li.special-result article div.title h2:hover { text-decoration: none; }
.result-grid .result.image .thumb img, .result-grid .result.highlight .thumb img { object-fit:cover; object-position:center; width:100%; height:100%; border-radius:10px; } .main-column ol li.special-result article div.title a { margin: 0; display: block; color: #6c00a2; cursor: pointer; }
.result-grid .result.image .thumb:hover, .result-grid .result.highlight .thumb:hover { outline:none; border-color:var(--border); border-radius:10px; box-shadow:0 0 10px var(--border); } .main-column ol li.special-result article div.title a:visited { color: #6d59a3; }
.result-grid .result, .result-grid .meta { margin:0; padding:0; } .main-column ol li.special-result article div.text, .main-column ol li article div.source { padding-top: 10px; position: relative; font-style: normal; }
.main-column ol li.special-result article div.text img { padding: 0 0 10px 10px; }
/* Magnet highlight/Share/Boxoffice popup */ .main-column ol li.special-result article div.source { display: inline-block; margin: 0; max-width: 100%; color: #666; font-size: 1rem; line-height: 1.6; letter-spacing: .2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-decoration: inherit; }
.goosebox { display:none; position:fixed; inset:0; z-index:10000; overflow:auto; background-color:rgb(0, 0, 0, .75); } .main-column ol li.special-result article div.source a { margin: 0; color: #3f6e35; text-decoration: none; }
.goosebox.open { display:block; }
.goosebox-body { margin:50px auto; padding:20px; width:50%; background:var(--background-popup); border:1px solid var(--border); border-radius:10px; }
.goosebox-body h2 { padding:0 0 .3em 0; }
.goosebox-body h3 { font-size:1.2rem; }
.goosebox-body 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; }
/* Stats display (stats page) */
.statspage .content h1 { margin-bottom:10px; padding:0; text-align:center; font-size:2.5em; font-weight:400; }
.statspage .content h2 { margin-bottom:10px; padding:0; text-align:center; font-size:1.5em; }
.statspage p { font-family:'Courier New'; }
/* 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; }
/* Tooltips */
.tooltip-question::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--link); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMS4yOSwxNS4yOWExLjU4LDEuNTgsMCwwLDAtLjEyLjE1Ljc2Ljc2LDAsMCwwLS4wOS4xOC42NC42NCwwLDAsMC0uMDYuMTgsMS4zNiwxLjM2LDAsMCwwLDAsLjIuODQuODQsMCwwLDAsLjA4LjM4LjkuOSwwLDAsMCwuNTQuNTQuOTQuOTQsMCwwLDAsLjc2LDAsLjkuOSwwLDAsMCwuNTQtLjU0QTEsMSwwLDAsMCwxMywxNmExLDEsMCwwLDAtLjI5LS43MUExLDEsMCwwLDAsMTEuMjksMTUuMjlaTTEyLDJBMTAsMTAsMCwxLDAsMjIsMTIsMTAsMTAsMCwwLDAsMTIsMlptMCwxOGE4LDgsMCwxLDEsOC04QTgsOCwwLDAsMSwxMiwyMFpNMTIsN0EzLDMsMCwwLDAsOS40LDguNWExLDEsMCwxLDAsMS43MywxQTEsMSwwLDAsMSwxMiw5YTEsMSwwLDAsMSwwLDIsMSwxLDAsMCwwLTEsMXYxYTEsMSwwLDAsMCwyLDB2LS4xOEEzLDMsMCwwLDAsMTIsN1oiIGZpbGw9IiM2NTYzZmYiLz48L3N2Zz4='); }
.tooltip-alert::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--red); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMiwxNmExLDEsMCwxLDAsMSwxQTEsMSwwLDAsMCwxMiwxNlptMTAuNjcsMS40Ny04LjA1LTE0YTMsMywwLDAsMC01LjI0LDBsLTgsMTRBMywzLDAsMCwwLDMuOTQsMjJIMjAuMDZhMywzLDAsMCwwLDIuNjEtNC41M1ptLTEuNzMsMmExLDEsMCwwLDEtLjg4LjUxSDMuOTRhMSwxLDAsMCwxLS44OC0uNTEsMSwxLDAsMCwxLDAtMWw4LTE0YTEsMSwwLDAsMSwxLjc4LDBsOC4wNSwxNEExLDEsMCwwLDEsMjAuOTQsMTkuNDlaTTEyLDhhMSwxLDAsMCwwLTEsMXY0YTEsMSwwLDAsMCwyLDBWOUExLDEsMCwwLDAsMTIsOFoiIGZpbGw9IiM2NTYzZmYiLz48L3N2Zz4='); }
/* Verified magnet */
.magnet-verified::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--link); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xOS42MywzLjY1YTEsMSwwLDAsMC0uODQtLjIsOCw4LDAsMCwxLTYuMjItMS4yNywxLDEsMCwwLDAtMS4xNCwwQTgsOCwwLDAsMSw1LjIxLDMuNDVhMSwxLDAsMCwwLS44NC4yQTEsMSwwLDAsMCw0LDQuNDN2Ny40NWE5LDksMCwwLDAsMy43Nyw3LjMzbDMuNjUsMi42YTEsMSwwLDAsMCwxLjE2LDBsMy42NS0yLjZBOSw5LDAsMCwwLDIwLDExLjg4VjQuNDNBMSwxLDAsMCwwLDE5LjYzLDMuNjVaTTE4LDExLjg4YTcsNywwLDAsMS0yLjkzLDUuN0wxMiwxOS43Nyw4LjkzLDE3LjU4QTcsNywwLDAsMSw2LDExLjg4VjUuNThhMTAsMTAsMCwwLDAsNi0xLjM5LDEwLDEwLDAsMCwwLDYsMS4zOVpNMTMuNTQsOS41OWwtMi42OSwyLjctLjg5LS45YTEsMSwwLDAsMC0xLjQyLDEuNDJsMS42LDEuNmExLDEsMCwwLDAsMS40MiwwTDE1LDExYTEsMSwwLDAsMC0xLjQyLTEuNDJaIiBmaWxsPSIjNjU2M2ZmIi8+PC9zdmc+'); }
.magnet-not-verified::before { content:""; display:inline-block; width:1.1em; height:1.1em; background:var(--red); vertical-align:text-bottom; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMS4yOSwxNC42NmExLDEsMCwwLDAtLjI5LjcsMSwxLDAsMCwwLC4wOC4zOUExLDEsMCwwLDAsMTMsMTUuMzZhMSwxLDAsMCwwLS4yOS0uN0ExLDEsMCwwLDAsMTEuMjksMTQuNjZabTguMzQtMTFhMSwxLDAsMCwwLS44NC0uMiw4LDgsMCwwLDEtNi4yMi0xLjI3LDEsMSwwLDAsMC0xLjE0LDBBOCw4LDAsMCwxLDUuMjEsMy40NWExLDEsMCwwLDAtLjg0LjJBMSwxLDAsMCwwLDQsNC40M3Y3LjQ1YTksOSwwLDAsMCwzLjc3LDcuMzNsMy42NSwyLjZhMSwxLDAsMCwwLDEuMTYsMGwzLjY1LTIuNkE5LDksMCwwLDAsMjAsMTEuODhWNC40M0ExLDEsMCwwLDAsMTkuNjMsMy42NVpNMTgsMTEuODhhNyw3LDAsMCwxLTIuOTMsNS43TDEyLDE5Ljc3LDguOTMsMTcuNThBNyw3LDAsMCwxLDYsMTEuODhWNS41OGExMCwxMCwwLDAsMCw2LTEuMzksMTAsMTAsMCwwLDAsNiwxLjM5Wk0xMiw3LjM2YTMsMywwLDAsMC0yLjYsMS41LDEsMSwwLDAsMCwxLjczLDFBMSwxLDAsMSwxLDEyLDExLjM2YTEsMSwwLDAsMCwwLDIsMywzLDAsMSwwLDAtNloiIGZpbGw9IiM2NTYzZmYiLz48L3N2Zz4='); }
/* Pagination */
.pagination { text-align:center; }
.pagination a { font-size:1.2em; padding:0 8px; }
.pagination a.current { font-size:1.4em; font-weight:400; text-decoration:underline; }
.arrow-left::before { content:""; display:inline-block; width:1.2em; height:1.2em; background:var(--link); vertical-align:text-top; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZGF0YS1uYW1lPSJMYXllciAxIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE3LDExSDkuNDFsMy4zLTMuMjlhMSwxLDAsMSwwLTEuNDItMS40MmwtNSw1YTEsMSwwLDAsMC0uMjEuMzMsMSwxLDAsMCwwLDAsLjc2LDEsMSwwLDAsMCwuMjEuMzNsNSw1YTEsMSwwLDAsMCwxLjQyLDAsMSwxLDAsMCwwLDAtMS40Mkw5LjQxLDEzSDE3YTEsMSwwLDAsMCwwLTJaIiBmaWxsPSIjNjU2M2ZmIi8+PC9zdmc+'); }
.arrow-right::before { content:""; display:inline-block; width:1.2em; height:1.2em; background:var(--link); vertical-align:text-top; mask-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZGF0YS1uYW1lPSJMYXllciAxIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE3LjkyLDExLjYyYTEsMSwwLDAsMC0uMjEtLjMzbC01LTVhMSwxLDAsMCwwLTEuNDIsMS40MkwxNC41OSwxMUg3YTEsMSwwLDAsMCwwLDJoNy41OWwtMy4zLDMuMjlhMSwxLDAsMCwwLDAsMS40MiwxLDEsMCwwLDAsMS40MiwwbDUtNWExLDEsMCwwLDAsLjIxLS4zM0ExLDEsMCwwLDAsMTcuOTIsMTEuNjJaIiBmaWxsPSIjNjU2M2ZmIi8+PC9zdmc+'); }
/* Flex grid (footer) */
.footer { display:flex; flex-direction:row; }
.footer-grid { flex:1; width:50%; }
.footer-grid:first-child { margin-right:20px; }
.footer-grid:nth-child(2) { text-align:right; }
/* Footer */
.footer { box-sizing:border-box; bottom:0; margin-top:auto; padding:10px 25px; width:100%; background-color:var(--background-alt); color:var(--text-alt); border-top:2px solid var(--color-accent); }
.footer a { color:var(--text-alt); }
/* MPA rating colors */
.mpa-g { color:#518257; }
.mpa-pg { color:#EB984E; }
.mpa-pg13 { color:#8E44AD; }
.mpa-r { color:#C0392B; }
.mpa-nc17 { color:#1A5276; }
/* Misc */ /* Misc */
.goosle-g { color:var(--color-accent); } .logo { position: absolute; margin: 28px 18px; }
.green { color:var(--green); } .logo a { color: #f0f6fc; cursor: pointer; }
.red { color:var(--red); } .no-decoration, .no-decoration:hover { text-decoration: none; }
.yellow { color:var(--yellow); } .hide { display: none; }
.star { font-weight:800; } .G { color: #1fa4d1; }
img.help { padding:0 .5rem .5rem 0; float:left; border-radius:20px; } .warning { position: relative; overflow: hidden; margin: 1rem 0 1rem 0; padding: .5rem 10px; color: #db9900; background-color: #ffffe0; border: 1px solid #e6db55; border-radius: 10px; }
.text-xxl { font-size:8em; } .error { position: relative; overflow: hidden; margin: 1rem 0 1rem 0; padding: .5rem 10px; color: #c00; background-color: #ffebe8; border: 1px solid #c00; border-radius: 10px; }
.text-xl { font-size:3em; } .auth-error { margin-top: 15%; font-size: 32px; text-align: center; color: #eaeaea; }
.text-center { text-align:center; }
.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(--yellow); font-weight:600; }
@media only screen and (max-width:960px) { /* Tablet, landscape iPad, lo-res/smaller laptops */ /* Footer bar */
.content { position:relative; margin:15px 48px; } .footer-wrap { background-color: #161616; color: #f0f6fc; border-top: 2px solid #303134; }
.footer { padding: 10px; }
.footer a { color: #f0f6fc; }
/* Start page */ @media only screen and (max-width:960px) { /* tablet, landscape iPad, lo-res laptops ands desktops */
.startpage .content { margin-top:0; } /* Page structure */
.startpage .search-field { width:80%; } .results-wrap { position: relative; display: flex; margin: 0 48px 20px 48px; }
.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%; }
/* Page header (Search results, Help, Box office) */ /* Main page */
.header { margin-left:auto; margin-right:auto; text-align:center; } .search-box-main { margin-top: 10%; }
.header form { margin:15px 0 0 0; } .search-box-main input { width: 80%; }
.header .logo { position:relative; display:block; margin:10px auto; float:none; font-size:1.8rem; } .search-box-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
.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; }
/* Magnet highlight info popup */ /* Search Results - Header */
.goosebox-body { margin:25px auto; width:75%; } .header-wrap { margin-left: auto; margin-right: auto; text-align: center; }
.header-wrap .search { margin: 10px 0px 28px 48px; width: 400px; }
.header-wrap .search, .header-wrap .button { margin: 10px 0px 28px 0px; }
/* Footer */ /* Search results - Header Navigation */
.footer { flex-direction:column; } .navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
.footer-left, .footer-right { display:block; text-align:center; } .navigation-header a { margin: 0 auto; padding: 0; }
.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 */
.content { position:relative; margin:10px 10px; }
/* Page header (Search results, Help, Box office) */
.header form { margin:15px 0 10px 0; }
.header .search-field, .header .button { margin:0 0 10px 0; width:80%; border-radius:25px; }
/* Grids (image and magnet highlights) */
@supports (display:grid) {
.result-grid { grid-template-columns:repeat(auto-fill, minmax(8rem, 1fr)); row-gap:.5rem; column-gap:.5rem; }
}
.result-grid .result { margin:0 0 15px 0; }
.result-grid .result.image .thumb, .result-grid .result.highlight .thumb { width:120px; height: 120px; }
/* Magnet highlight info popup */
.goosebox-body { margin:15px auto; width:90%; }
/* Misc */ /* Misc */
img.help { padding:0 .25rem .25rem 0; } .logo { position: relative; display: block;margin: 0 auto; float: none; padding: 10px; font-size: 28px; }
} }
@media only screen and (max-width:480px) { /* Portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */ @media only screen and (max-width:640px) { /* portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones */
/* Start page */ /* Page structure */
.startpage h1 { font-size:2.5rem; } .results-wrap { position: relative; display: flex; margin: 0 10px 10px 10px; }
/* Main page */
.search-box-main { margin-top: 10%; }
.search-box-main input { width: 80%; }
.search-box-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header-wrap { margin-left: auto; margin-right: auto; text-align: center; }
.header-wrap .search, .header-wrap .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
.navigation-header a { margin: 0 auto; padding: 0; }
/* Misc */
.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 28px; }
}
@media only screen and (max-width:480px) { /* portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */
/* Page structure */
.results-wrap { position: relative; display: flex; margin: 0 10px 10px 10px; }
/* Main page */
.search-box-main { margin-top: 10%; }
.search-box-main input { width: 80%; }
.search-box-main h1 { font-size: 45px; }
.search-box-buttons button { display: table-row; margin: 30px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header-wrap { margin-left: auto; margin-right: auto; text-align: center; }
.header-wrap .search, .header-wrap .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
.navigation-header a { margin: 0 auto; padding: 0; }
/* Misc */
.logo { position: relative; display: block; float: none; margin: 0 auto; padding: 10px; font-size: 28px; }
}
@media only screen and (max-width:320px) { /* smartphones, iPhone, portrait 480x320 phones */
/* Page structure */
.results-wrap { position: relative; display: flex; margin: 0 10px 10px 10px; }
/* Main page */
.search-box-main { margin-top: 40px; }
.search-box-main input { width: 80%; }
.search-box-main h1 { font-size: 45px; }
.search-box-buttons button { display: table-row; margin: 20px 0px 0px 0px; width: 80%; }
/* Search Results - Header */
.header-wrap { margin-left: auto; margin-right: auto; text-align: center; }
.header-wrap .search, .header-wrap .button { margin: 0px 0px 10px 0px; width: 80%; border-radius: 25px; }
/* Search results - Header Navigation */
.navigation-header { display: flex; margin: 0; padding: 0; align-items: baseline; }
.navigation-header a { margin: 0 auto; padding: 0; }
/* Misc */
.logo { position: relative; float: none; display: block; margin: 0 auto; padding: 10px; font-size: 28px; }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

BIN
assets/images/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

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

BIN
assets/images/search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/images/torrent.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

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

View file

@ -1,62 +0,0 @@
/* ------------------------------------------------------------------------------------
* 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();
}
});
});

View file

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

View file

@ -1,158 +0,0 @@
<?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.
------------------------------------------------------------------------------------ */
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.'engines/boxoffice/yts.php';
require ABSPATH.'engines/boxoffice/eztv.php';
$opts = load_opts();
$search = load_search();
?>
<!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" />
<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, $opts->user_auth)) {
?>
<div class="header">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a href="./?a=<?php echo $opts->user_auth; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->nice_query) > 0) ? htmlspecialchars($search->nice_query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $search->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->user_auth; ?>">
</form>
<div class="navigation">
<?php if($opts->enable_web_search == 'on') { ?>
<a class="<?php echo ($search->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=0">Search</a>
<?php } ?>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($search->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=1" >Images</a>
<?php } ?>
<?php if($opts->enable_news_search == 'on') { ?>
<a class="<?php echo ($search->type == '2') ? 'active ' : ''; ?>tab-news" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=2">News</a>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<a class="<?php echo ($search->type == '9') ? 'active ' : ''; ?>tab-magnet" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=9">Magnet links</a>
<?php } ?>
</div>
</div>
<div class="content">
<h2>The Box Office</h2>
<p>Click on any movie poster for more information and available download links.</p>
<h3>Recently added movies on YTS</h3>
<?php
$highlights = array_slice(yts_boxoffice($opts, 'date_added'), 0, 24);
?>
<ul class="result-grid">
<?php
foreach($highlights as $highlight) {
$thumb = (!empty($highlight['thumbnail'])) ? $highlight['thumbnail'] : $opts-pixel;
echo "<li class=\"result highlight yts id-".$highlight['id']."\">";
echo " <div class=\"thumb\">";
echo " <a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['title']."\"><img src=\"".$thumb."\" alt=\"".$highlight['title']."\" /></a>";
echo " </div>";
echo " <span><center><a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['title']."\">".$highlight['title']."</a></center></span>";
// HTML for popup
echo highlight_popup($opts->user_auth, $highlight);
echo "</li>";
unset($highlight, $thumb);
}
unset($highlights);
?>
</ul>
<h3>Latest TV Show releases from EZTV</h3>
<?php
$highlights = array_slice(eztv_boxoffice($opts), 0, 24);
?>
<ul class="result-grid">
<?php
foreach($highlights as $highlight) {
$thumb = (!empty($highlight['thumbnail'])) ? $highlight['thumbnail'] : $opts->pixel;
echo "<li class=\"result highlight eztv id-".$highlight['id']."\">";
echo " <div class=\"thumb\">";
echo " <a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['title']."\"><img src=\"".$thumb."\" alt=\"".$highlight['title']."\" /></a>";
echo " </div>";
echo " <span><center><a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['title']."\">".$highlight['title']."</a></center></span>";
// HTML for popup
echo highlight_popup($opts->user_auth, $highlight);
echo "</li>";
unset($highlight, $thumb);
}
unset($highlights);
?>
</ul>
<p class="text-center"><small>Goosle does not index, offer or distribute torrent files.</small></p>
</div>
<div class="footer grid-container">
<div class="footer-grid">
&copy; <?php echo the_date('Y'); ?> Goosle <?php echo $current_version; ?> <?php echo show_update_notification(); ?>
</div>
<div class="footer-grid">
<a href="./?a=<?php echo $opts->user_auth; ?>">Start</a> - <a href="./box-office.php?a=<?php echo $opts->user_auth; ?>&t=9">Box office</a> - <a href="./help.php?a=<?php echo $opts->user_auth; ?>">Help</a> - <a href="./stats.php?a=<?php echo $opts->hash; ?>">Stats</a>
</div>
</div>
<?php } else { ?>
<div class="auth-error">Redirecting</div>
<meta http-equiv="refresh" content="1; url=<?php echo get_base_url($opts->siteurl); ?>/error.php" />
<?php } ?>
</body>
</html>

4
cache/index.php vendored
View file

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

View file

@ -1,253 +0,0 @@
# Goosle
## The best Meta Search Engine to find everything
### 1.7 - August 7, 2024
- NOTICE: config.default.php has changed, update your config.php!!
- [new] Mojeek search results
- [new] Pixabay Image results (Requires free API key, see installation instructions)
- [new] Keyword multiplier for result ranking
- [new] Web search can be turned off
- [new] Cache News results for an hour only, regardless of the cache setting
- [new] Dynamic SEO description for results page (Should be visible when sharing the page)
- [new] 'Verified' label for magnet results where supported
- [update] Added x.com for social media detection
- [update] Added more keywords for nsfw detection in magnet results
- [change] Raised Qwant Images limit from 50 to 150
- [change] Raised Hackernews and Qwant News limit from 30 to 50
- [change] Lowered Wikipedia results from 10 to maximum 5
- [change] Replaced 'porn' with 'nsfw' for safe search switch
- [change] Removed 'xxx' as an keyword to disable safe search
- [change] Don't search on nyaa.si and YTS if you search with safemode off
- [change] Moved image size override into search object
- [change] Added a little space between rows for image results on mobile
- [change] Stats font is now 'Courier'
- [fix] Google search query not providing good results
- [fix] Search query not always properly urlencoded
- [removed] Removed search suggestions as they didn't work
### 1.6.1 - July 19, 2024
- NOTICE: config.default.php has changed, update your config.php!!
- [new] Query logger for debugging (See config.default.php for details)
- [update] Added url arguments to the formatted url of search results
- [change] Scrape query for DuckDuckGo to be more direct
- [change] Improved tooltips to be popups with better explanations
- [fix] Improved spacing for pagination links
- [fix] More accurately show the current version in the footer
- [fix] Current version not properly stored
- [fix] Pagination offset off by one result
- [fix] Unnecessary global in load_search()
- [fix] Typo in wordpress search
- [fix] Qwant initial total hits and ranking more accurate
- [fix] Goosle header title not bold on stats page
- [fix] Visual fixes to the design of Goosle
### 1.6 - July 15, 2024
- NOTICE: config.default.php has changed, update your config.php!!
- [change] Moved magnet popups into combined function
- [change] Better handling of EZTV TV Show data
- [change] Better handling of YTS movie data
- [change] Added 6 new public trackers for Magnets
- [change] Removed regularly unresponsive trackers for Magnets
- [change] Search query string processed before search so all engines don't have to do it individually
- [change] Updated help page
- [new] Special searches can have a note/disclaimer in the lower right corner
- [new] Results pagination for all search tabs (Requires caching to be enabled)
- [new] WordPress function, hook and filter lookup as a special search (See help page)
- [new] Language meta data for some Magnet results
- [new] Try to detect audio codec for EZTV results
- [new] Show MPA Rating for some movie results
- [new] Filter to include NSFW Magnet results or not
- [new] Override NSFW filter with prefix keywords (see config.php)
- [new] Simple search stat counter (Link in footer)
- [tweak] Muted the blue and white text in dark theme a tiny bit
- [tweak] Better light blue header in light theme
- [tweak] Added title and alt attributes to relevant links/images
- [tweak] Removed Magnet search limit of 200 results
- [fix] HTML rendering issues for `<center>` tags in paragraphs
- [fix] Start page buttons in light theme now use the right css variables
- [fix] Properly decode quotes in code snippers for PHP special search
- [fix] Image, News and Magnet search no longer work if they're disabled in config.php
- [fix] 2nd search suggestion not showing if it's available
- [fix] Removed non-functional checking if query is empty in every engine
- [fix] Correctly uses user provided auth hash to keep searching
- [fix] Correctly 'expire' share links for guests so they can not use Goosle beyond seeing the shared results
### 1.5.1 - June 22, 2024
- [fix] Updated help.php, removed incorrect colorscheme information
- [fix] Typo in text output for goosle-cron.php
- [fix] Various php errors/warnings in goosle-cron.php
- [fix] Url formatting for php function special searches
### 1.5 - June 19, 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 Qwant 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
- [fix] Search navigation no longer bunched up on smaller displays
- [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
- [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
- [tweak] File size formatting for images more uniform
- [tweak] Optimized curl_multi_exec handling
- [tweak] Improved SEO headers
- [tweak] Layout tweaks and optimizations for search results, header and footer
- [tweak] Removed redundant HTML, CSS and some PHP
- [tweak] MagnetDL search disabled by default because of Cloudflare (Will probably be removed in future version)
- [tweak] Removed non-functional magnet trackers
- [tweak] Added 15 extra public magnet trackers
- [change] Removed Ecosia support
- [change] Removed Reddit support
- [change] Removed 1337x support
- [change] Removed MagnetDL support
### 1.3 - April 11, 2024
- [fix] Image search crawler filters out non-image results better
- [new] Crawler for results from magnetdl.com
- [new] Direct Reddit.com search, search for 'Top Posts' created in the past year
- [new] YTS movie highlights now link to YTS website when clicking the title
- [new] Placeholder image for missing eztv highlight thumbnails
- [tweak] Better hash matching for duplicate magnet results
- [tweak] Better checking for missing/empty values in image search results
- [tweak] Code cleanup
- [tweak] More uniform code/variable names
- [change] Naming overhaul - Replaced 'Torrent' with 'Magnet' throughout most of Goosle
### 1.2.2 - February 16, 2024
- [new] Individual on/off setting for each search engine and torrent site
- [new] YTS Highlights for latest releases, highest rated or most downloaded movies
- [new] EZTV Highlights for latest TV Show episode releases
- [new] Goosle-cron.php file for if you want to clear the file cache in the background
- [change] l33tx search disabled by default - They use Cloudflare now, preventing the crawler from working reliably
- [change] Ecosia search disabled by default - They use some kind of bot detector now, preventing the crawler from working once caught
- [change] Now uses an ABSPATH global for file inclusions and paths
- [change] More discrete TV Show and Movie result detection in text search
- [tweak] Filter for eztv search, only include eztv if the search term starts with 'tt' (case insensitive)
- [tweak] Better ecosia link formatting to (hopefully) not get blocked by their bot detector
- [tweak] cURL headers to be (even) more browser-like
- [fix] Variable $url sometimes empty for certain magnet results
- [fix] Blocked category filter for YTS results now actually works
### 1.2.1 - January 15, 2024
- [new] Merge identical downloads (determined by info hash) from different torrent sites that provide hashes
- [new] Option to cache to flat files instead of APCu, files stored in /cache/ folder
- [new] Blank index.php files in all subfolders to shield from prying eyes
- [tweak] Improved version check
- [fix] Stray periods in some Limetorrent categories
- [fix] Inconsistent size indication for magnet results
### 1.2 - January 2, 2024
- [new] Preferred language setting for DuckDuckGo results in config.php.
- [new] Preferred language setting for Wikipedia results in config.php.
- [new] Combined DuckDuckGo, Google, Wikipedia and Ecosia (Bing) results into one page.
- [new] Ranking algorithm for search results.
- [new] Option to down-rank certain social media sites in results (Makes them show lower down the page).
- [new] Option to show the Goosle rank along with the search source.
- [new] Crawler for results from Limetorrents.lol.
- [new] Periodic check for updates in footer.
- [change] Moved duckduckgo.php and google.php into the engines/search/ folder.
- [change] Removed Wikipedia special search in favor of actual search results.
- [change] Removed 'Date Added' from 1337x results.
- [change] Removed Chrome based and Mobile user-agents, as they don't work for the WikiPedia API.
- [change] Added more trackers for generating magnet links.
- [tweak] 30-50% faster parsing of search results (couple of ms per search query).
- [tweak] Expanded the season/episode filter to all sources that support TV Shows.
- [tweak] More sensible santization of variables (Searching for html tags/basic code should now work).
- [tweak] Moved 'imdb_id_search' out from special results into its 'own' setting.
- [tweak] Moved 'password_generator' out from special results into its 'own' setting.
- [tweak] More accurate and faster Google scrape.
- [tweak] Reduced paragraph margins.
- [tweak] More code cleanup, making it more uniform.
- [fix] Prevents searching on disabled methods by 'cheating' the search type in the url.
- [fix] Better decoding for special characters in urls for search results.
- [fix] Better validation for special searches trigger words.
- [fix] Better sanitization for DuckDuckGo and Google results.
### 1.1 - December 21, 2023
- [new] API search for EZTV TV Shows.
- [new] config.default.php with default settings.
- [new] New option 'imdb_id_search' in 'special' settings in config.php.
- [new] New option 'show_zero_seeders' in config.php.
- [new] Special result and redirect for IMDb IDs.
- [new] Replaced image search with Yahoo! Images.
- [new] Styled 'reset' button for search fields.
- [tweak] Removed 'raw_output' option.
- [tweak] Re-arranged results array to be more logical/easy to use.
- [tweak] Re-arranged code for results to do no double checks for search results.
- [tweak] Added more user-agents.
- [tweak] Magnet results page.
- [tweak] Sanitize scraped data earlier in the process.
- [tweak] Consistent single quotes for arrays.
- [tweak] Consistent spaces, tabs and newlines.
- [fix] Inconsistent input height for search field vs search button.
- [fix] Better check if a search is currency conversion or not.
- [fix] Typos in help.php.
### 1.0.2 - December 7, 2023
- [change] More useful error response when search doesn't work.
- [change] EngineRequest::request_successful() now provides a boolean response.
- [change] Removed versioning indicator from help page.
- [change] Added version indicator to results.php and help.php footer.
- [change] 'Nope, Go away!' for unauthorized users changed to 'Goosle'.
- [fix] Magnet links no longer opening in new tabs.
### 1.0.1 - December 5, 2023
- [fix] mktime() getting intermittent strings in 1337x crawler.
- [fix] mktime() getting intermittent strings in nyaa crawler.
### 1.0 - December 5, 2023
- Initial release
## Support
Goosle comes with limited support. \
You can post your questions on Github Discussions or say hi on [Mastodon](https://mas.to/@arnan) or [Telegram](https://t.me/arnandegans).

View file

@ -1,6 +1,6 @@
<?php <?php
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,209 +11,109 @@
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
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.
Duplicate the file /assets/css/default.css and name it something like 'mycolorscheme.css'.
Edit the color variables to your liking.
To use the colorscheme, use the filename without extension in this setting.
HASH: HASH:
A simple lowercase passphrase, something simple like: goose1234 or 1846. A simple lowercase passphrase (something simple like: j9fg-i2du-er6m or 1846) used for caching results. This helps to differentiate between instances on the same server.
Used for caching search results and optionally for accessing Goosle (See HASH_AUTH option). You can also add it to your url/bookmark as a simple passphrase to keep unwanted users out.
HASH_AUTH: HASH AUTH:
Use the HASH option as a simple passphrase. Use the above hash as a simple passphrase.
Using a passphrase lets you host Goosle on a public facing server without providing a public service. Using it as a passphrase lets you host Goosle on a public 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. Usage: https://example.com/?a=1234567890
'on' Use the hash as a password.
Usage: https://example.com/?a=goose1234
Disclaimer: This is not meant to 'hack proof' or truly secure the setup. Just a simple token to keep surface level prying eyes out. Disclaimer: This is not meant to 'hack proof' or truly secure the setup. Just a simple token to keep surface level prying eyes out.
CACHE_TYPE: CACHE:
It is highly recommended to enable caching as it will speed up repeat searches by a lot. If you have ACPu it is highly recommended to enable caching as it'll speed up repeatable searched by a lot.
The cache is NOT unique per user but shared between all users. Different users searching for the exact same thing get the same results. "on" (Recommended) for active sites, requires APCu
Results loaded from the cache are much much faster to load. "off" Disables cache, useful for testing or if your server lacks APCu support
Caching can be done in memory with APCu or as temporary files in the /cache/ folder.
Enabling caching also enables pagination for search results.
'off' No caching.
'file' Store results in text files (Default).
'apcu' Faster, requires more memory.
CACHE_TIME: CACHE_TIME:
APCu stores in memory, using a longer cache time takes up more of it. It is recommended to not exceed a few (1 or 2?) hours for APCu. Minutes the result should be cached in ACPu.
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 48 hours.
Ignored if above 'CACHE_TYPE' option is set to off.
/* ------------------------------------------------------------------------------------ ENABLE IMAGE SEARCH:
LANGUAGE: Enable or disable image searches - Search results are provided by Qwant.
To not fit the USA mold, Goosle defaults to the United Kingdom for english results. "on" (Default)
DuckDuckGo and Google are language agnostic. "off"
Invalid values either cause the search engine to fail or will default to English depending on how wrong the value is.
Google has no language setting because as soon as you specify it all 'anonymous' settings stop working. ENABLE TORRENT SEARCH:
Enable or disable searching for torrent downloads.
"on" (Default)
"off"
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/. SPECIAL:
Enable or disable special searches that show up before search results.
"on" (Default)
"off" Disable this special search
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 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 results if you don't value such results.
This includes websites like Facebook, Instagram, Twitter/X, Snapchat, TikTok, LinkedIn and Reddit.
!! CAREFUL !! This is a blanket setting, if what (or who) you're searching for primarily has social media links then less relevant results may show first.
Accepts a numeric value between 1 and 10. With 10 having *NO* effect on the rank, and 0 not ranking the link at all (shows very very low in the results).
/* ------------------------------------------------------------------------------------
USER AGENTS: USER AGENTS:
Add more or less user agents to the list but keep at least one! Add more or less user agents to the list. Keep at least one.
On every search Goosle picks a user agent at random to identify as. On every search Goosle picks one at random to identify as.
Keep them generic to prevent profiling, but also so that the request comes off as a generic boring browser and not as a server/crawler. Keep them generic to prevent profiling, but also so that the request comes off as a generic boring browser and not a server/script.
Safari, Firefox and Internet Explorer (Yes that's old!) should be safe to use. Safari and Internet Explorer may be a limiting factor on results as they are lesser supported browsers. But should otherwise be fine.
Chrome may attract attention because of the lack of Chrome information (tracking) aside from the user agent. The search engine may know something is 'weird'. Chrome may attract attention because of the lack of Chrome information (tracking) aside from the user agent.
Opera/Edge/Brave and many others use Chrome under the hood and are not a good pick for that reason. Opera/Edge/Brave and many others use Chrome under the hood and are not a good pick for that reason.
Do not use user agents for mobile devices. Where possible Goosle explicitly tells the service it's a desktop computer to get a certain format for results. SHOW ZERO SEEDERS:
Contradicting the request with a mobile user agent may get your banned. Set to "on" to include results with 0 seeders (slow or stale downloads). Off to exclude these results.
MAGNET TRACKERS: BLOCK 1337x CATEGORIES:
Add more or less magnet trackers to the list but keep at least five or so! Add category IDs of 1337x categories, check /engines/torrent/1337x.php for a list of known categories.
These are added to the magnet links Goosle creates by itself.
Generally you do not need to change these. BLOCK PIRATEBAY CATEGORIES:
Add category IDs of Pirate Bay categories, check /engines/torrent/thepiratebay.php for a list of known categories.
BLOCK YTS CATEGORIES:
Add category names as keywords, eg; "thriller", "war".
Movies can be in multiple categories, if a movie is in 5 categories it only has to match one to be filtered out.
TORRENT TRACKERS:
Only used for The Pirate Bay and YTS.
These are added to the magnet links Goosle creates. You can add more or replace the existing ones.
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
return (object) array( return (object) array(
'siteurl' => 'example.com', // Make sure this is accurate (ex. example.com, goosle.example.com, example.com/goosle/) "hash" => "j9fg-i2du-er6m",
'colorscheme' => 'default', // Default colorscheme to use "hash_auth" => "off", // Default: off
'hash' => '123456', // Some kind of alphanumeric password-like string, used for caching and optionally for access to Goosle "cache" => "off", // Default: off
'hash_auth' => 'off', // Default: off "cache_time" => 30, // Default: 30
'cache_type' => 'file', // Default: file
'cache_time' => 8, // Default: 8 (Hours), see the recommendations above.
'timezone' => 'UTC', // Default: UTC (Enter UTC+1, UTC-6 etc. for your timezone - Find yours https://time.is/UTC)
'enable_web_search' => 'on', // Default: on (Disables all web search regardless of settings for individual engines) "enable_image_search" => "on", // Default: on
'web' => array( "enable_torrent_search" => "on", // Default: on
'duckduckgo' => 'on', // Default: on
'mojeek' => 'on', // Default: on "special" => array(
'qwant' => 'on', // Default: on "currency" => "on", // Currency converter
'google' => 'on', // Default: on "definition" => "on", // Word dictionary
'brave' => 'on', // Default: on "wikipedia" => "on", // Wikipedia highlight
'wikipedia' => 'on' // Default: on "phpnet" => "on", // PHP-dot-net highlight
"imdb_id_search" => "on", // Highlight IMDB IDs for tv shows, to use for torrent searches
"password_generator" => "on" // Password generator on homepage
), ),
'enable_image_search' => 'on', // Default: on (Disables all image search regardless of settings for individual engines) "user_agents" => array(
'image' => array( "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15) Gecko/20100101 Firefox/119.0", // macOS 10.15, Firefox 119
'yahooimages' => 'on', // Default: on "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/116.0", // Windows 10, Firefox 116
'qwantimages' => 'on', // Default: on "Mozilla/5.0 (X11; Ubuntu; Linux x86_64) Gecko/20100101 Firefox/83.0", // Linux Ubuntu, Firefox 83
'pixabay' => 'off', // Default: off (Requires free account from Pixabay.com, see readme for set up instructions) "Mozilla/5.0 (X11; Linux i686) Gecko/20100101 Firefox/119.0", // Linux Generic, Firefox 119
'openverse' => 'off', // Default: off (Requires oAuth token, see readme for set up instructions) "Mozilla/5.0 (Linux; Android 5.0.2; AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/3.3 Chrome/38.0.2125.102 Safari/537.36", // Android 5, Samsungbrowser 3
"Mozilla/5.0 (Linux; Android 7.0; AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36", // Android 7, Chrome 60
"Mozilla/5.0 (Linux; U; Android 4.2.2; he-il; AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30", // Android 4. Some webkit browser (Chrome?)
"Mozilla/5.0 (iPhone12,1; U; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/15E148 Safari/602.1", // iOS 13, Safari
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/13.2b11866 Mobile/16A366 Safari/605.1.15", // iOS 12, Firefox 13
), ),
'enable_news_search' => 'on', // Default: on (Disables all news search regardless of settings for individual engines) "show_zero_seeders" => "on", // Default: on
'news' => array( "leetx_categories_blocked" => array(3, 7, 47), // Default: 3, 7, 47
'qwantnews' => 'on', // Default: on "piratebay_categories_blocked" => array(206, 210), // Default: 206, 210
'yahoonews' => 'on', // Default: on "yts_categories_blocked" => array("horror"), // Default: "horror"
'bravenews' => 'on', // Default: on "torrent_trackers" => array(
'hackernews' => 'on', // Default: on "http://nyaa.tracker.wf:7777/announce",
"udp://open.stealth.si:80/announce",
"udp://tracker.opentrackr.org:1337/announce",
"udp://exodus.desync.com:6969/announce",
"udp://tracker.torrent.eu.org:451/announce",
), ),
'enable_magnet_search' => 'on', // Default: on (Disables all magnet search regardless of settings for individual engines as well as the box office page) "version" => "1.1b2" // Please don't change this
'magnet' => array(
'limetorrents' => 'on', // Default: on (Anything)
'piratebay' => 'on', // Default: on (Anything)
'yts' => 'on', // Default: on (Movies)
'eztv' => 'on', // Default: on (TV-Shows)
'nyaa' => 'on', // Default: on (Anime)
'sukebei' => 'on', // Default: on (NSFW Anime)
),
'duckduckgo_language' => 'uk-en', // Default: uk-en (United Kingdom)
'mojeek_language' => 'en', // Default: en (English)
'google_search_region' => 'uk', // Default: uk (United Kingdom)
'qwant_language' => 'en_gb', // Default: en_gb (United Kingdom)
'wikipedia_language' => 'en', // Default: en (English)
'pixabay_api_key' => '', // Default: '' (Requires free account from Pixabay.com, see readme for set up instructions)
'search_results_per_page' => 24, // Default: 24 (Any number between 8 and 160, preferably a multiple of 8. Ignored if caching is off)
'social_media_relevance' => 8, // Default: 8
'show_search_source' => 'on', // Default: on
'imdb_id_search' => 'off', // Default: off, (Requires enable_magnet_search to also be on)
'password_generator' => 'on', // Default: on
'show_search_rank' => 'off', // Default: off (Useful for debugging)
'querylog' => 'off', // Default: off (Create a log of queries in /cache/*.log to see if they are made and how much results they find and end up with after processing)
'special' => array(
'currency' => 'on', // Default: on, Currency converter
'definition' => 'on', // Default: on, Word dictionary
'ipaddress' => 'on', // Default: on, Look up your IP Address
'phpnet' => 'on', // Default: on, PHP-dot-net functions highlight
'wordpress' => 'off' // Default: off, Wordpress functions highlight
),
'show_nsfw_magnets' => 'off', // Default: off (Set to 'off' to try and hide adult content. Override with 'safe:off' or 'nsfw')
'show_zero_seeders' => 'off', // Default: off
'show_yts_highlight' => 'on', // Default: off (Show latest YTS movies above Magnet search results)
'show_share_option' => 'on', // Default: on (Show a share option for Magnet results)
'piratebay_categories_blocked' => array(206, 210), // Default: 206, 210 (Comma separated numbers, see /engines/magnet/thepiratebay.php for all categories)
'yts_categories_blocked' => array('horror'), // Default: 'horror' (Comma separated keywords; array('action', 'drama', 'sci-fi') etc.. There is no defined list, so block keywords that you see on results and don't like)
// Keep at-least 1
'user_agents' => array(
'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
),
// Keep at-least 5
'magnet_trackers' => array(
'udp://tracker.coppersurfer.tk:6969',
'udp://tracker.leechers-paradise.org:6969',
'udp://p4p.arenabg.ch:1337',
'udp://tracker.internetwarriors.net:1337',
'udp://glotorrents.pw:6969/announce',
'udp://torrent.gresille.org:80/announce',
'udp://tracker.openbittorrent.com:80',
'http://nyaa.tracker.wf:7777/announce',
'udp://tracker.opentrackr.org:1337/announce',
'udp://exodus.desync.com:6969/announce',
'udp://tracker.torrent.eu.org:451/announce',
'udp://opentracker.i2p.rocks:6969/announce',
'udp://open.demonii.com:1337/announce',
'udp://open.stealth.si:80/announce',
'udp://tracker.moeking.me:6969/announce',
'udp://explodie.org:6969/announce',
'udp://tracker1.bt.moack.co.kr:80/announce',
'udp://tracker.theoks.net:6969/announce',
'udp://tracker-udp.gbitt.info:80/announce',
'https://tracker.tamersunion.org:443/announce',
'https://tracker.gbitt.info:443/announce',
'udp://tracker.tiny-vps.com:6969/announce',
'udp://tracker.dump.cl:6969/announce',
'udp://tamas3.ynh.fr:6969/announce',
'udp://retracker01-msk-virt.corbina.net:80/announce',
'udp://open.free-tracker.ga:6969/announce',
'udp://epider.me:6969/announce',
'udp://bt2.archive.org:6969/announce',
)
); );
?> ?>

View file

@ -1,110 +0,0 @@
<?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)) {
if($opts->querylog == 'on') querylog('BoxofficeEZTV', 'a', $api_url, 'No response', 0);
return $results;
}
// No Results
if($json_response['torrents_count'] == 0) {
if($opts->querylog == 'on') querylog('BoxofficeEZTV', 'a', $api_url, 'No Results', 0);
return $results;
}
foreach($json_response['torrents'] as $result) {
$title = (!empty($result['title'])) ? sanitize($result['title']) : null;
$year = (!empty($result['date_released_unix'])) ? gmdate('Y', sanitize($result['date_released_unix'])) : null;
$hash = (!empty($result['hash'])) ? strtolower(sanitize($result['hash'])) : null;
$thumbnail = (!empty($result['small_screenshot'])) ? sanitize($result['small_screenshot']) : null;
$magnet_link = (!empty($result['magnet_url'])) ? sanitize($result['magnet_url']) : null;
$filesize = (!empty($result['size_bytes'])) ? sanitize($result['size_bytes']) : null;
// Get extra data
$quality = find_video_quality($title);
$codec = find_video_codec($title);
$audio = find_audio_codec($title);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
// Clean up show name
$title = (preg_match('/.+?(?=[0-9]{3,4}p|xvid|divx|(x|h)26(4|5))/i', $title, $clean_name)) ? $clean_name[0] : $title; // Break off show name before video resolution
$title = trim(str_replace(array('S0E0', 'S00E00'), '', $title)); // 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, 'title', 'id');
$found_id = array_search($title, $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,
'audio' => $audio
);
} else {
$result_id = md5($title); // Predictable/repeatable 'unique' string, can't be md5($hash) other nothing will match/merge!
// First/new result
$results[$result_id] = array (
'id' => $result_id, // string
'title' => $title, // string
'year' => $year, // int(4)
'thumbnail' => $thumbnail, // string
'magnet_links' => array(array( // Yes, two array (For merging results)...
'hash' => $hash, // string
'magnet' => $magnet_link, // string
'filesize' => $filesize, // int
'quality' => $quality, // string
'audio' => $audio // string
))
);
}
unset($result, $result_urls, $found_id, $result_id, $title, $hash, $thumbnail, $magnet_link, $quality, $codec);
}
unset($response, $json_response);
if($opts->querylog == 'on') querylog('BoxofficeEZTV', 'a', $api_url, 'up-to 100', count($results));
// 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

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

View file

@ -1,117 +0,0 @@
<?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)) {
if($opts->querylog == 'on') querylog('BoxofficeYTS', 'a', $api_url, 'No response', 0);
return $results;
}
// No Results
if($json_response['data']['movie_count'] == 0) {
if($opts->querylog == 'on') querylog('BoxofficeYTS', 'a', $api_url, 'No Results', 0);
return $results;
}
foreach($json_response['data']['movies'] as $result) {
$title = sanitize($result['title']);
$year = (!empty($result['year'])) ? sanitize($result['year']) : 0;
$category = (!empty($result['genres'])) ? $result['genres'] : null;
$language = (!empty($result['language'])) ? sanitize($result['language']) : null;
$rating = (!empty($result['rating'])) ? sanitize($result['rating']) : null;
$mpa_rating = (!empty($result['mpa_rating'])) ? sanitize($result['mpa_rating']) : null;
$summary = (!empty($result['summary'])) ? sanitize($result['summary']) : null;
if(is_null($summary)) $summary = (!empty($result['synopsis'])) ? sanitize($result['synopsis']) : "No summary provided";
$thumbnail = (!empty($result['medium_cover_image'])) ? sanitize($result['medium_cover_image']) : null;
if(is_null($thumbnail)) $thumbnail = (!empty($result['small_cover_image'])) ? sanitize($result['small_cover_image']) : "";
// Process extra data
if(is_array($category)) {
// 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($title).'&tr='.implode('&tr=', $opts->magnet_trackers);
$filesize = filesize_to_bytes(sanitize($download['size']));
$type = (!empty($download['type'])) ? sanitize(strtolower($download['type'])) : null;
$quality = (!empty($download['quality'])) ? sanitize($download['quality']) : null;
$codec = (!empty($download['video_codec'])) ? sanitize($download['video_codec']) : null;
$bitrate = (!empty($download['bit_depth'])) ? sanitize($download['bit_depth']) : null;
$audio = (!empty($download['audio_channels'])) ? sanitize('AAC '.$download['audio_channels']) : null;
// Add codec and bitrate to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
if(!empty($bitrate)) $quality = $quality.' '.$bitrate.'bit';
$downloads[] = array (
'hash' => $hash,
'magnet' => $magnet,
'filesize' => $filesize,
'type' => $type,
'quality' => $quality,
'audio' => $audio
);
unset($download, $hash, $magnet, $filesize, $type, $quality, $codec, $bitrate, $audio);
}
$result_id = md5($title);
$results[$result_id] = array (
'id' => $result_id, // Semi random string to separate results
'title' => $title, // string
'year' => $year, // int(4)
'category' => $category, // string|null
'language' => $language, // string|null
'rating' => $rating, // float|null
'mpa_rating' => $mpa_rating, // string|null
'summary' => $summary, // string
'thumbnail' => $thumbnail, // string|empty
'magnet_links' => $downloads // array
);
unset($result, $title, $thumbnail, $year, $category, $language, $rating, $url, $summary, $downloads);
}
unset($response, $json_response);
if($opts->querylog == 'on') querylog('BoxofficeYTS', 'a', $api_url, 'up-to 40', count($results));
// 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;
}
?>

95
engines/duckduckgo.php Normal file
View file

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

114
engines/google.php Normal file
View file

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

View file

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

View file

@ -1,139 +0,0 @@
<?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 OpenverseRequest extends EngineRequest {
public function get_request_url() {
$query = $this->search->query;
// Max 200 chars
$query = (strlen($query) > 200) ? substr($query, 0, 200) : $query;
$query = implode(',', make_tags_from_string($query));
// Safe search override
if($this->search->safe == 0) {
$safe = '1';
} else {
$safe = '0';
}
// Size override
$size = 'small,medium,large';
if($this->search->size == 1) $size = 'small';
if($this->search->size == 2) $size = 'medium';
if($this->search->size >= 3) $size = 'large';
// All parameters and values: https://api.openverse.org/v1/#tag/images/operation/images_search
$url = 'https://api.openverse.org/v1/images/?'.http_build_query(array(
'q' => $query, // Search query
'category' => 'photograph', // Only photos
'size' => $size,
'format' => 'json', // Response format
'page_size' => 50, // How many results to get (Max 50)
'mature' => $safe // Safe search (1 = ON, 0 = OFF)
));
unset($query, $safe, $size);
return $url;
}
public function get_request_headers() {
$token_file = ABSPATH.'cache/token.data';
$token = unserialize(file_get_contents($token_file));
return array(
'Accept' => 'application/json, */*;q=0.8',
'Content-type' => 'application/x-www-form-urlencoded',
'Authorization' => 'Bearer '.$token['openverse']['access_token'],
'Accept-Language' => null,
'Accept-Encoding' => null,
'Sec-Fetch-Dest' => null,
'Sec-Fetch-Mode' => null,
'Sec-Fetch-Site' => null
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// Figure out results and base rank
$number_of_results = $rank = $json_response['result_count'];
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
// Use API result
foreach($json_response['results'] as $result) {
// Find data and process data
$image_thumb = (!empty($result['thumbnail'])) ? sanitize($result['thumbnail']) : null;
$image_full = (!empty($result['url'])) ? sanitize($result['url']) : null;
$url = (!empty($result['foreign_landing_url'])) ? sanitize($result['foreign_landing_url']) : null;
$alt = (!empty($result['title'])) ? sanitize($result['title']) : null;
$creator = (!empty($result['creator'])) ? " by ".sanitize($result['creator']) : null;
$tags = (count($result['tags']) > 0) ? array_column($result['tags'], 'name') : make_tags_from_string($alt);
// Skip broken results
if(empty($image_thumb)) continue;
if(empty($image_full)) continue;
if(empty($url)) continue;
// Optional
$dimensions_w = (!empty($result['width'])) ? sanitize($result['width']) : null;
$dimensions_h = (!empty($result['height'])) ? sanitize($result['height']) : null;
// Prepare data
if(!is_null($creator)) $alt = $alt.$creator;
$tags = array_unique($tags);
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
$engine_temp[] = array (
// Required
'image_thumb' => $image_thumb, // string
'image_full' => $image_full, // string
'url' => $url, // string
'alt' => $alt, // string
'tags' => $tags, // array
'engine_rank' => $rank, // int
// Optional
'width' => $dimensions_w, // int | null
'height' => $dimensions_h // int | null
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Openverse';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $number_of_results, count($engine_temp));
unset($response, $json_response, $number_of_results, $rank);
return $engine_result;
}
}
?>

View file

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

View file

@ -1,124 +0,0 @@
<?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 = $this->search->query;
// Size override
$size = 'all';
if($this->search->size == 1) $size = 'small';
if($this->search->size == 2) $size = 'medium';
if($this->search->size >= 3) $size = 'large';
// Set locale
$language = (strlen($this->opts->qwant_language) > 0 && strlen($this->opts->qwant_language < 6)) ? $this->opts->qwant_language : 'en_gb';
// Based on https://github.com/locness3/qwant-api-docs and variables from qwant website
$url = 'https://api.qwant.com/v3/search/images?'.http_build_query(array(
'q' => $query, // Search query
't' => 'images', // Type of search, Images
'count' => 150, // Up-to how many images to return (Max 150)
'size' => $size, // General image size
'locale' => $language, // In which language should the search be done
'device' => 'desktop', // What kind of device are we searching from?
'safesearch' => $this->search->safe // Safe search filter (0 = off, 1 = normal, 2 = strict)
));
unset($query, $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)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// Figure out results and base rank
$number_of_results = $rank = $json_response['data']['result']['total'];
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
foreach($json_response['data']['result']['items'] as $result) {
// Find data and process data
$image_thumb = (!empty($result['thumbnail'])) ? sanitize($result['thumbnail']) : null;
$image_full = (!empty($result['media'])) ? sanitize($result['media']) : null;
$url = (!empty($result['url'])) ? sanitize($result['url']) : null;
$alt = (!empty($result['title'])) ? sanitize($result['title']) : null;
$tags = (!empty($alt)) ? make_tags_from_string($alt) : array();
// Skip broken results
if(empty($image_thumb)) continue;
if(empty($image_full)) continue;
if(empty($url)) continue;
// Optional
$dimensions_w = (!empty($result['width'])) ? sanitize($result['width']) : null;
$dimensions_h = (!empty($result['height'])) ? sanitize($result['height']) : null;
// Process data
$tags = array_unique($tags);
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
$engine_temp[] = array (
// Required
'image_thumb' => $image_thumb, // string
'image_full' => $image_full, // string
'url' => $url, // string
'alt' => $alt, // string
'tags' => $tags, // array
'engine_rank' => $rank, // int
// Optional
'width' => $dimensions_w, // int | null
'height' => $dimensions_h // int | null
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Qwant';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $number_of_results, count($engine_temp));
unset($response, $json_response, $number_of_results, $rank);
return $engine_result;
}
}
?>

View file

@ -1,170 +0,0 @@
<?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 = $this->search->query;
// Safe search override
if($this->search->safe == 0) {
$safe = '0';
} else {
$safe = '';
}
// Size override
$size = '';
if($this->search->size == 1) $size = 'small';
if($this->search->size == 2) $size = 'medium';
if($this->search->size == 3) $size = 'large';
if($this->search->size == 4) $size = 'wallpaper';
$url = 'https://images.search.yahoo.com/search/images?'.http_build_query(array(
'p' => $query, // Search query
'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) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// 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) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
// 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
// h = Image height
// imgurl = Full size image (Used in Yahoo preview/popup)
// rurl = Url to page where the image is used
// size = Image size
// tt = Website title
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);
}
// Process data
$image_thumb = sanitize($image_thumb[0]->textContent);
$image_full = (array_key_exists('imgurl', $usable_data)) ? sanitize($usable_data['imgurl']) : null;
$url = (array_key_exists('rurl', $usable_data)) ? sanitize($usable_data['rurl']) : null;
$alt = (array_key_exists('tt', $usable_data)) ? sanitize($usable_data['tt']) : null;
$tags = (!empty($alt)) ? make_tags_from_string($alt) : array();
// Skip broken results
if(empty($image_full)) continue;
if(empty($url)) continue;
// Optional
$dimensions_w = (array_key_exists('w', $usable_data)) ? sanitize($usable_data['w']) : null;
$dimensions_h = (array_key_exists('h', $usable_data)) ? sanitize($usable_data['h']) : null;
// Process data
// 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;
}
}
$tags = array_unique($tags);
// Skip duplicate IMAGE urls/results
if(!empty($engine_temp)) {
if(in_array($image_full, array_column($engine_temp, 'image_full'))) continue;
}
$engine_temp[] = array (
// Required
'image_thumb' => $image_thumb, // string
'image_full' => $image_full, // string
'url' => $url, // string
'alt' => $alt, // string
'tags' => $tags, // array
'engine_rank' => $rank, // int
// Optional
'width' => $dimensions_w, // int | null
'height' => $dimensions_h // int | null
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Yahoo Images';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, $number_of_results, count($engine_temp));
unset($response, $xpath, $scrape, $number_of_results, $rank);
return $engine_result;
}
}
?>

View file

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

View file

@ -1,124 +0,0 @@
<?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 EZTVRequest extends EngineRequest {
public function get_request_url() {
$query = preg_replace('/[^0-9]+/', '', $this->search->query);
// Is eztvx.to blocked for you? Use one of these urls as an alternative
// Try: eztv1.xyz, eztv.wf, eztv.tf, eztv.yt
$url = 'https://eztvx.to/api/get-torrents?imdb_id='.urlencode($query);
unset($query);
return $url;
}
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)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// No results
if($json_response['torrents_count'] == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
foreach($json_response['torrents'] as $result) {
$title = sanitize($result['title']);
$hash = strtolower(sanitize($result['hash']));
$magnet = sanitize($result['magnet_url']);
$seeders = sanitize($result['seeds']);
$leechers = sanitize($result['peers']);
$filesize = sanitize($result['size_bytes']);
// Ignore results with 0 seeders?
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;
// Throw out mismatched episodes
if(!is_season_or_episode($this->search->query, 'S'.$season.'E'.$episode)) continue;
// Get extra data
$timestamp = (isset($result['date_released_unix'])) ? sanitize($result['date_released_unix']) : null;
$quality = find_video_quality($title);
$codec = find_video_codec($title);
$audio = find_audio_codec($title);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
// Clean up show name
$title = (preg_match('/.+?(?=[0-9]{3,4}p)|xvid|divx|(x|h)26(4|5)/i', $title, $clean_name)) ? $clean_name[0] : $title; // Break off show name before video resolution
$title = str_replace(array('S0E0', 'S00E00'), '', $title); // Strip empty season/episode indicator from name
$engine_temp[] = array (
// Required
'hash' => $hash, // string
'title' => $title, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => 'yes', // string|null
'nsfw' => false, // bool
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'timestamp' => $timestamp, // int(timestamp)|null
'category' => null, // string|null
'mpa_rating' => null, // string|null
'language' => null, // string|null
'url' => null // string|null
);
unset($result, $season, $episode, $title, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $date_added);
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'EZTV';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $json_response['torrents_count'], count($engine_temp));
unset($response, $json_response, $engine_temp);
return $engine_result;
}
}
?>

View file

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

View file

@ -1,148 +0,0 @@
<?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 LimeRequest extends EngineRequest {
public function get_request_url() {
$query = preg_replace('/[^a-z0-9- ]+/', '', $this->search->query);
$query = strtolower(str_replace(' ', '-', $query));
$url = 'https://www.limetorrents.lol/search/all/'.$query.'/';
unset($query);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//table[@class='table2']//tr[position() > 1]");
// No results
if(count($scrape) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
foreach($scrape as $result) {
// Find data
$title = $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($title->length == 0) continue;
if($hash->length == 0) continue;
// Process data
$title = sanitize($title[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($title).'&tr='.implode('&tr=', $this->opts->magnet_trackers);
$seeders = ($seeders->length > 0) ? sanitize($seeders[0]->textContent) : 0;
$leechers = ($leechers->length > 0) ? sanitize($leechers[0]->textContent) : 0;
$filesize = ($filesize->length > 0) ? filesize_to_bytes(sanitize($filesize[0]->textContent)) : 0;
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->search->query, $title)) continue;
// Find extra data
$verified = $xpath->evaluate(".//td[@class='tdleft'][1]//div[@class='tt-vdown']//img/@title", $result);
$category = $xpath->evaluate(".//td[@class='tdnormal'][1]", $result);
$url = $xpath->evaluate(".//td[@class='tdleft']//a[2]/@href", $result);
// Process extra data
$verified = ($verified->length > 0) ? sanitize($verified[0]->textContent) : null;
if($verified == 'Verified torrent') $verified = 'yes';
if($category->length > 0) {
$category = explode(' - ', sanitize($category[0]->textContent));
$category = str_replace('in ', '', $category[array_key_last($category)]);
$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;
// Find meta data for certain categories
$nsfw = (detect_nsfw($title)) ? true : false;
$quality = $codec = $audio = null;
if(in_array(strtolower($category), array('movies', 'tv shows', 'anime'))) {
$quality = find_video_quality($title);
$codec = find_video_codec($title);
$audio = find_audio_codec($title);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
} else if(in_array(strtolower($category), array('music'))) {
$audio = find_audio_codec($title);
}
$engine_temp[] = array (
// Required
'hash' => $hash, // string
'title' => $title, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => $verified, // string|null
'nsfw' => $nsfw, // bool
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'timestamp' => null, // int(timestamp)|null
'category' => $category, // string|null
'mpa_rating' => null, // string|null
'language' => null, // string|null
'url' => $url // string|null
);
unset($result, $title, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $audio, $category, $url);
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'limetorrents.lol';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, count($scrape), count($engine_temp));
unset($response, $xpath, $scrape, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,143 +0,0 @@
<?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 NyaaRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://nyaa.si/?q='.urlencode($this->search->query);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//tbody/tr");
// No results
if(count($scrape) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
foreach($scrape as $result) {
// Find data
$meta = $xpath->evaluate(".//td[@class='text-center']", $result);
$title = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result);
$magnet = $xpath->evaluate(".//a[2]/@href", $meta[0]);
// Skip broken results
if($title->length == 0) continue;
if($magnet->length == 0) $magnet = $xpath->evaluate(".//a/@href", $meta[0]); // This matches if no torrent file is provided
if($magnet->length == 0) continue;
// Process data
$title = sanitize($title[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))))));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->search->query, $title)) continue;
// Find extra data
$verified = $xpath->evaluate("./@class", $result);
$category = $xpath->evaluate(".//td[1]//a/@title", $result);
$url = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result);
$date_added = $xpath->evaluate(".//td[@class='text-center']/@data-timestamp", $result);
// Process extra data
$verified = ($verified->length > 0) ? sanitize($verified[0]->textContent) : null;
if($verified == 'success') {
$verified = 'yes';
} else if($verified == 'danger') {
$verified = 'no';
} else {
$verified = null;
}
$category = ($category->length > 0) ? str_replace(' - ', '/', sanitize($category[0]->textContent)) : null;
$url = ($url->length > 0) ? 'https://nyaa.si'.sanitize($url[0]->textContent) : null;
$timestamp = sanitize($date_added[0]->textContent);
// Find meta data for certain categories
$nsfw = (detect_nsfw($title)) ? true : false;
$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($title);
$codec = find_video_codec($title);
$audio = find_audio_codec($title);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
} else if(in_array(strtolower($category), array('audio/lossless', 'audio/lossy'))) {
$audio = find_audio_codec($title);
}
$engine_temp[] = array (
// Required
'hash' => $hash, // string
'title' => $title, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => $verified, // string|null
'nsfw' => $nsfw, // bool
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'timestamp' => $timestamp, // int(timestamp)|null
'category' => $category, // string|null
'mpa_rating' => null, // string|null
'language' => null, // string|null
'url' => $url // string|null
);
unset($result, $title, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $audio, $category, $url, $date_added);
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'nyaa.si';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, count($scrape), count($engine_temp));
unset($response, $xpath, $scrape, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,140 +0,0 @@
<?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() {
$url = 'https://sukebei.nyaa.si/?q='.urlencode($this->search->query);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//tbody/tr");
// No results
if(count($scrape) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
foreach($scrape as $result) {
// Find data
$meta = $xpath->evaluate(".//td[@class='text-center']", $result);
$title = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result);
$magnet = $xpath->evaluate(".//a[2]/@href", $meta[0]);
// Skip broken results
if($title->length == 0) continue;
if($magnet->length == 0) $magnet = $xpath->evaluate(".//a/@href", $meta[0]); // This matches if no torrent file is provided
if($magnet->length == 0) continue;
// Process data
$title = sanitize($title[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))))));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->search->query, $title)) continue;
// Find extra data
$verified = $xpath->evaluate(".//@class", $result);
$category = $xpath->evaluate(".//td[1]//a/@title", $result);
$url = $xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result);
$date_added = $xpath->evaluate(".//td[@class='text-center']/@data-timestamp", $result);
// Process extra data
$verified = ($verified->length > 0) ? sanitize($verified[0]->textContent) : null;
if($verified == 'success') {
$verified = 'yes';
} else if($verified == 'danger') {
$verified = 'no';
} else {
$verified = null;
}
$category = ($category->length > 0) ? str_replace(' - ', '/', sanitize($category[0]->textContent)) : null;
$url = ($url->length > 0) ? 'https://sukebei.nyaa.si'.sanitize($url[0]->textContent) : null;
$timestamp = sanitize($date_added[0]->textContent);
// Find meta data for certain categories
$quality = $codec = $audio = null;
if(in_array(strtolower($category), array('art/anime', 'real life/videos'))) {
$quality = find_video_quality($title);
$codec = find_video_codec($title);
$audio = find_audio_codec($title);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
}
$engine_temp[] = array (
// Required
'hash' => $hash, // string
'title' => $title, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => $verified, // string|null
'nsfw' => true, // bool
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'timestamp' => $timestamp, // int(timestamp)|null
'category' => $category, // string|null
'mpa_rating' => null, // string|null
'language' => null, // string|null
'url' => $url // string|null
);
unset($result, $title, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $audio, $category, $url, $date_added);
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'sukebei.nyaa.si';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, count($scrape), count($engine_temp));
unset($response, $xpath, $scrape, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,193 +0,0 @@
<?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 PirateBayRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://apibay.org/q.php?q='.urlencode($this->search->query);
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)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// No results
if($json_response[0]['name'] == 'No results returned') {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
$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) {
// Find and process data
$title = sanitize($result['name']);
$hash = strtolower(sanitize($result['info_hash']));
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($title).'&tr='.implode('&tr=', $this->opts->magnet_trackers);
$seeders = sanitize($result['seeders']);
$leechers = sanitize($result['leechers']);
$filesize = sanitize($result['size']);
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Throw out mismatched tv-show episodes when searching for tv shows
if(!is_season_or_episode($this->search->query, $title)) continue;
// Find extra data
$verified = (array_key_exists('status', $result)) ? sanitize($result['status']) : null;
$category = (array_key_exists('category', $result)) ? sanitize($result['category']) : null;
$url = (array_key_exists('id', $result)) ? 'https://thepiratebay.org/description.php?id='.sanitize($result['id']) : null;
$timestamp = (isset($result['added'])) ? sanitize($result['added']) : null;
// Process extra data
$verified = ($verified == 'vip' || $verified == 'moderator' || $verified == 'trusted') ? 'yes' : null;
if(!is_null($category)) {
// Block these categories
if(in_array($category, $this->opts->piratebay_categories_blocked)) continue;
// Find meta data for certain categories
$nsfw = ($category >= 500 && $category <= 599) ? true : false;
$quality = $codec = $audio = null;
if(($category >= 200 && $category <= 299) || ($category >= 500 && $category <= 599)) {
$quality = find_video_quality($title);
$codec = find_video_codec($title);
$audio = find_audio_codec($title);
// Add codec to quality
if(!empty($codec)) $quality = $quality.' '.$codec;
} else if($category >= 100 && $category <= 199) {
$audio = find_audio_codec($title);
}
// Set actual category
$category = $categories[$category];
}
$engine_temp[] = array(
// Required
'hash' => $hash, // string
'title' => $title, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => $verified, // string|null
'nsfw' => $nsfw, // bool
'quality' => $quality, // string|null
'type' => null, // string|null
'audio' => $audio, // string|null
'runtime' => null, // int(timestamp)|null
'year' => null, // int(4)|null
'timestamp' => $timestamp, // int(timestamp)|null
'category' => $category, // string|null
'language' => null, // string|null
'mpa_rating' => null, // string|null
'url' => $url // string|null
);
unset($result, $title, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $audio, $category, $url, $date_added);
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'thepiratebay.org';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, count($json_response), count($engine_temp));
unset($response, $json_response, $engine_temp, $categories);
return $engine_result;
}
}
?>

View file

@ -1,130 +0,0 @@
<?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 YTSRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://yts.mx/api/v2/list_movies.json?query_term='.urlencode($this->search->query);
return $url;
}
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)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// No results
if($json_response['data']['movie_count'] == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
foreach($json_response['data']['movies'] as $result) {
// Find and process data
$title = sanitize($result['title']);
// Find extra data
$runtime = (!empty($result['runtime'])) ? date('H:i', mktime(0, sanitize($result['runtime']))) : null;
$year = (!empty($result['year'])) ? sanitize($result['year']) : 0;
$category = (!empty($result['genres'])) ? $result['genres'] : null;
$mpa_rating = (!empty($result['mpa_rating'])) ? sanitize($result['mpa_rating']) : null;
$timestamp = (!empty($result['date_uploaded_unix'])) ? sanitize($result['date_uploaded_unix']) : null;
$language = (!empty($result['language'])) ? sanitize($result['language']) : null;
$url = (!empty($result['url'])) ? sanitize($result['url']) : null;
// Process extra data
if(is_array($category)) {
// Block these categories
if(count(array_uintersect($category, $this->opts->yts_categories_blocked, 'strcasecmp')) > 0) continue;
// Set actual category
$category = sanitize(implode(', ', $category));
}
foreach ($result['torrents'] as $download) {
// Find and process data
$hash = strtolower(sanitize($download['hash']));
$magnet = 'magnet:?xt=urn:btih:'.$hash.'&dn='.urlencode($title).'&tr='.implode('&tr=', $this->opts->magnet_trackers);
$seeders = sanitize($download['seeds']);
$leechers = sanitize($download['peers']);
$filesize = filesize_to_bytes(sanitize($download['size']));
// Ignore results with 0 seeders?
if($this->opts->show_zero_seeders == 'off' AND $seeders == 0) continue;
// Find extra data
$quality = (!empty($download['quality'])) ? sanitize(strtolower($download['quality'])) : null;
$codec = (!empty($download['video_codec'])) ? sanitize(strtolower($download['video_codec'])) : null;
$bitrate = (!empty($download['bit_depth'])) ? sanitize($download['bit_depth']) : null;
$type = (!empty($download['type'])) ? ucfirst(sanitize(strtolower($download['type']))) : null;
$audio = (!empty($download['audio_channels'])) ? sanitize('AAC '.$download['audio_channels']) : null;
// Process extra data
if(!empty($codec)) $quality = $quality.' '.$codec;
if(!empty($bitrate)) $quality = $quality.' '.$bitrate.'bit';
$engine_temp[] = array (
// Required
'hash' => $hash, // string
'title' => $title, // string
'magnet' => $magnet, // string
'seeders' => $seeders, // int
'leechers' => $leechers, // int
'filesize' => $filesize, // int
// Optional
'verified_uploader' => 'yes', // string|null
'nsfw' => false, // bool
'quality' => $quality, // string|null
'type' => $type, // string|null
'audio' => $audio, // string|null
'runtime' => $runtime, // int(timestamp)|null
'year' => $year, // int(4)|null
'timestamp' => $timestamp, // int(timestamp)|null
'category' => $category, // string|null
'mpa_rating' => $mpa_rating, // string|null
'language' => $language, // string|null
'url' => $url // string|null
);
unset($download, $hash, $magnet, $seeders, $leechers, $filesize, $quality, $codec, $bitrate, $type, $audio);
}
unset($result, $title, $year, $category, $language, $runtime, $url, $date_added);
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'yts.mx';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $json_response['data']['movie_count'], count($engine_temp));
unset($response, $json_response, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,104 +0,0 @@
<?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() {
$url = 'https://search.brave.com/news?'.http_build_query(array(
'q' => $this->search->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' => 'pm' // How old may the article be?
));
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results (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) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
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);
$image = $xpath->evaluate(".//div[contains(@class, 'image-wrapper')]/img/@src", $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)));
$image = ($image->length == 0) ? null : sanitize($image[0]->textContent);
$source = str_replace('www.', '', strtolower(parse_url($url, PHP_URL_HOST)));
$timestamp = ($date_added->length == 0) ? null : strtotime(sanitize($date_added[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, // string
'url' => $url, // string
'description' => $description, // string
'image' => $image, // string|null
'source' => $source, // string
'timestamp' => $timestamp, // int|null
'engine_rank' => $rank // int
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Brave News';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, $number_of_results, count($engine_temp));
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,102 +0,0 @@
<?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() {
// Search range (must be in GMT)
$article_date = time() - (30 * 86400);
// More info on https://hn.algolia.com/api
$url = 'https://hn.algolia.com/api/v1/search_by_date?'.http_build_query(array(
'query' => $this->search->query, // Search query
'tags' => 'story', // What type of results to show? (story = News stories)
'hitsPerPage' => 50, // How many results to return?
'numericFilters' => 'created_at_i>'.$article_date // How old may the article be?
));
unset($article_date);
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)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// Figure out results and base rank
$number_of_results = $rank = count($json_response['hits']);
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
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)));
$timestamp = sanitize($result['created_at_i']);
// Skip duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
$engine_temp[] = array (
'title' => $title, // string
'url' => $url, // string
'description' => $description, // string
'image' => null, // string|null
'source' => $source, // string
'timestamp' => $timestamp, // int|null
'engine_rank' => $rank // int
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Hackernews';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $number_of_results, count($engine_temp));
unset($response, $json_response, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

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

View file

@ -1,102 +0,0 @@
<?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() {
// 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';
// 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' => $this->search->query, // Search query
't' => 'news', // News search
'safesearch' => $this->search->safe, // Safe search filter (0 = off, 1 = normal, 2 = strict)
'locale' => $language, // Language region
'count' => 50, // How many results? (Maximum 50)
'device' => 'desktop', // Where are you searching from
'source' => 'all', // Where to get the news from (All)
'freshness' => 'month', // How old may the article be?
'order' => 'date' // Sort by date
));
unset($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)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// Figure out results and base rank
$number_of_results = $rank = $json_response['data']['result']['total'];
// No results
if($number_of_results == 0 || $json_response['status'] == 'error') {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
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'])));
$image = sanitize($result['media'][0]['pict']['url']);
$source = str_replace('www.', '', strtolower(parse_url($url, PHP_URL_HOST)));
$timestamp = sanitize($result['date']);
// Fix up the image
if($image == 'NULL') $image = null;
$engine_temp[] = array(
'title' => $title, // string
'url' => $url, // string
'description' => $description, // string
'image' => $image, // string|null
'source' => $source, // string
'timestamp' => $timestamp, // int|null
'engine_rank' => $rank // int
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Qwant News';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $number_of_results, count($engine_temp));
unset($response, $json_response, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,118 +0,0 @@
<?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() {
// Safe search override
if($this->search->safe == 0) {
$safe = '0';
} else {
$safe = '';
}
$url = 'https://news.search.yahoo.com/search?'.http_build_query(array(
'p' => $this->search->query, // Search query
'safe' => $safe // Safe search filter (0 = off, "" = on)
));
unset($safe);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results (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) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
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);
$image = $xpath->evaluate("./div/ul/li/a/img[@class='s-img']/@src", $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)));
$image = ($image->length == 0) ? null : sanitize($image[0]->textContent);
$source = str_replace('www.', '', strtolower(parse_url($url, PHP_URL_HOST)));
$timestamp = ($date_added->length == 0) ? null : strtotime(sanitize(preg_replace('/[^a-z0-9 ]+/i', '', $date_added[0]->textContent)));
// filter duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
// Fix up the image
if(!is_null($image)) {
$image = explode('/http', $image);
$image = parse_url('http'.$image[1]);
$image = $image['scheme'].'://'.$image['host'].$image['path'];
}
$engine_temp[] = array(
'title' => $title, // string
'url' => $url, // string
'description' => $description, // string
'image' => $image, // string|null
'source' => $source, // string
'timestamp' => $timestamp, // int|null
'engine_rank' => $rank // int
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Yahoo News';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, $number_of_results, count($engine_temp));
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,210 +1,179 @@
<?php <?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 ImageSearch extends EngineRequest { class ImageSearch extends EngineRequest {
protected $requests; public function get_request_url() {
$results = array();
public function __construct($search, $opts, $mh) { // Split the query
$this->requests = array(); $query_terms = explode(" ", strtolower($this->query));
if($opts->enable_image_search == 'on') { // Size override
if($opts->image['yahooimages'] == 'on') { $size = "";
require ABSPATH.'engines/image/yahoo-images.php'; if($query_terms[0] == 'size') {
$this->requests[] = new YahooImageRequest($search, $opts, $mh); $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];
} }
if($opts->image['qwantimages'] == 'on') { $this->query = implode(" ", array_slice($query_terms, 1));
require ABSPATH.'engines/image/qwant-images.php'; }
$this->requests[] = new QwantImageRequest($search, $opts, $mh);
} }
if($opts->image['pixabay'] == 'on') { // p = query
require ABSPATH.'engines/image/pixabay.php'; // imgsz = Image size (small|medium|large|wallpaper)
$this->requests[] = new PixabayRequest($search, $opts, $mh);
}
if($opts->image['openverse'] == 'on') { $args = array("p" => $this->query, "imgsz" => $size);
require ABSPATH.'engines/image/openverse.php'; $url = "https://images.search.yahoo.com/search/images?".http_build_query($args);
$this->requests[] = new OpenverseRequest($search, $opts, $mh);
} unset($query_terms, $switch, $args, $size);
}
return $url;
} }
public function parse_results($response) { public function parse_results($response) {
$goosle_results = array(); $results = array("search" => array());
$xpath = get_xpath($response);
if(count($this->requests) !== 0) { // Failed to load page
foreach($this->requests as $request) { if(!$xpath) return array();
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) { // Scrape recommended
if(isset($engine_result['did_you_mean'])) { $didyoumean = $xpath->query(".//section[@class='dym-c']/section/h3/a")[0];
$goosle_results['did_you_mean'] = $engine_result['did_you_mean']; 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;
} }
if(isset($engine_result['search_specific'])) { // Scrape the results
$goosle_results['search_specific'][] = $engine_result['search_specific']; foreach($xpath->query("//li[contains(@class, 'ld') and not(contains(@class, 'slotting'))][position() < 101]") as $result) {
$image = $xpath->evaluate(".//img/@src", $result)[0];
if($image == null) continue;
$url_data = $xpath->evaluate(".//a/@href", $result)[0];
if($url_data == null) continue;
// Get meta data
// -- Relevant $url_data (there is more, but unused by Goosle)
// w = Image width (1280)
// h = Image height (720)
// imgurl = Actual full size image (Used in Yahoo preview/popup)
// rurl = Url to page where the image is used
// size = Image size (413.1KB)
// tt = Website title (Used for image alt text)
parse_str($url_data->textContent, $url_data);
// filter duplicate urls/results
if(!empty($results['search'])) {
$result_urls = array_column($results['search'], "direct_link");
if(in_array($url_data['imgurl'], $result_urls)) continue;
} }
if(isset($engine_result['search'])) { // Deal with optional or missing data
$how_many_results = 0; $dimensions_w = (!array_key_exists('w', $url_data) || empty($url_data['w'])) ? 0 : htmlspecialchars($url_data['w']);
$dimensions_h = (!array_key_exists('h', $url_data) || empty($url_data['h'])) ? 0 : htmlspecialchars($url_data['h']);
$filesize = (!array_key_exists('size', $url_data) || empty($url_data['size'])) ? "" : htmlspecialchars($url_data['size']);
$link = (!array_key_exists('imgurl', $url_data) || empty($url_data['imgurl'])) ? "" : "//".htmlspecialchars($url_data['imgurl']);
// Merge duplicates and apply relevance scoring array_push($results['search'], array (
foreach($engine_result['search'] as $key => $result) { "image" => htmlspecialchars($image->textContent),
if(isset($goosle_results['search'])) { "alt" => htmlspecialchars($url_data['tt']),
$result_urls = array_column($goosle_results['search'], 'image_full', 'id'); "url" => htmlspecialchars($url_data['rurl']),
$found_id = array_search($result['image_full'], $result_urls); // Return the result ID, or false if not found "height" => $dimensions_w,
} else { "width" => $dimensions_h,
$found_id = false; "filesize" => $filesize,
"direct_link" => $link
));
} }
$how_many_results++;
$social_media_multiplier = (detect_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * $social_media_multiplier);
if($found_id !== false) {
// Duplicate result from another engine
$goosle_results['search'][$found_id]['goosle_rank'] += $goosle_rank;
$goosle_results['search'][$found_id]['combo_source'][] = $engine_result['source'];
} else {
// First find, rank and add to results
$match_rank = match_count($result['tags'], $request->search->query_terms, 2);
// $match_rank += match_count($result['alt'], $request->search->query_terms);
$match_rank += match_count($result['url'], $request->search->query_terms, 0.5);
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['image_full']);
// Add result to final results
$goosle_results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
}
// Count results per source
$goosle_results['sources'][$engine_result['source']] = $how_many_results;
unset($how_many_results);
}
}
} 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'));
$goosle_results['error'][] = array(
'message' => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
);
}
unset($request);
}
if(array_key_exists('search', $goosle_results)) {
// Re-order results based on rank
$keys = array_column($goosle_results['search'], 'goosle_rank');
array_multisort($keys, SORT_DESC, $goosle_results['search']);
// Count all results
$goosle_results['number_of_results'] = count($goosle_results['search']);
unset($keys);
} else {
// Add error if there are no search results // Add error if there are no search results
$goosle_results['error'][] = array( if(empty($results['search'])) {
"message" => "No results found. Please try with more specific or different keywords!" $results['error'] = array(
); "message" => "No results found. Please try with less or different keywords!"
}
} else {
$goosle_results['error'][] = array(
'message' => "It appears that all Image Search engines are disabled or that searching for images is disabled."
); );
} }
return $goosle_results; return $results;
} }
public static function print_results($goosle_results, $search, $opts) { public static function print_results($results, $opts) {
// Uncomment for debugging
/* /*
echo "<pre>Settings: "; echo '<pre>Results: ';
print_r($opts); print_r($results);
echo "</pre>"; echo '</pre>';
echo "<pre>Search data: ";
print_r($search);
echo "</pre>";
echo "<pre>Search results: ";
print_r($goosle_results);
echo "</pre>";
*/ */
if(array_key_exists('search', $goosle_results)) { if(array_key_exists("search", $results)) {
// Pagination offset echo "<ol>";
if($opts->cache_type !== 'off') {
$offset = ((($search->page - 1) * $opts->search_results_per_page)); // Elapsed time
$goosle_results['search'] = array_slice($goosle_results['search'], $offset, $opts->search_results_per_page); $number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Did you mean/Search suggestion
if(array_key_exists("did_you_mean", $results)) {
$specific_result = "";
if(array_key_exists("search_specific", $results)) {
// Format query url
$search_specific = "\"".$results['search_specific']."\"";
$search_specific_url = "./results.php?q=".urlencode($search_specific)."&t=".$opts->type."&a=".$opts->hash;
// Specific search
$specific_result = "<br /><small>Or instead search for <a href=\"".$search_specific_url."\">".$search_specific."</a>.</small>";
unset($search_specific, $search_specific_url);
} }
echo "<ul>"; $didyoumean_url = "./results.php?q=".urlencode($results['did_you_mean'])."&t=".$opts->type."&a=".$opts->hash;
// Elapsed time and search sources echo "<li class=\"meta\">Did you mean <a href=\"".$didyoumean_url."\">".$results['did_you_mean']."</a>?$specific_result</li>";
echo "<li class=\"meta\">";
echo " <p class=\"timer\">Fetched ".$goosle_results['number_of_results']." results in ".$goosle_results['time']." seconds.</p>"; unset($didyoumean_url, $specific_result);
if($opts->show_search_source == 'on') {
echo " <p class=\"sources\">".search_sources($goosle_results['sources'])."</p>";
} }
echo "</li>"; echo "</ol>";
echo "</ul>";
// Search results // Search results
echo "<ul class=\"result-grid\">"; echo "<div class=\"image-wrapper\">";
echo "<ol class=\"image-grid\">";
foreach($results['search'] as $result) {
$meta = $links = array();
// Optional data
if(!empty($result['height']) && !empty($result['width'])) $meta[] = $result['width']."&times;".$result['height'];
if(!empty($result['filesize'])) $meta[] = $result['filesize'];
// Links
$links[] = "<a href=\"".$result['url']."\" target=\"_blank\">Website</a>";
if(!empty($result['direct_link'])) $links[] = "<a href=\"".$result['direct_link']."\" target=\"_blank\">Image</a>";
foreach($goosle_results['search'] as $result) {
// Put result together // Put result together
echo "<li class=\"result image rank-".$result['goosle_rank']." id-".$result['id']."\">"; echo "<li class=\"result\"><div class=\"image-box\">";
echo " <div class=\"thumb\">"; echo "<a href=\"".$result['url']."\" target=\"_blank\" title=\"".$result['alt']."\"><img src=\"".$result['image']."\" alt=\"".$result['alt']."\" /></a>";
echo " <a href=\"".$result['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 " </div>";
echo " <div class=\"meta\">";
if(!empty($result['height']) && !empty($result['width'])) echo " <p>".$result['width']."&times;".$result['height']."</p>";
echo " <p><a href=\"".$result['url']."\" target=\"_blank\" title=\"Open website\">Website</a> &bull; <a href=\"".$result['image_full']."\" target=\"_blank\" title=\"Open image\">Image</a></p>";
if($opts->show_search_rank == 'on') echo " <p>Rank: ".$result['goosle_rank']."</p>";
echo " </div>";
echo "</li>"; echo "</li>";
unset($meta); unset($result, $meta, $links);
} }
echo "</ul>"; echo "</ol>";
echo "</div>";
// Pagination navigation echo "<center><small>Not what you're looking for? Try <a href=\"https://duckduckgo.com/?q=".urlencode($opts->query)."&iax=images&ia=images\" target=\"_blank\">DuckDuckGo</a>, <a href=\"https://images.search.yahoo.com/search/images?p=".urlencode($opts->query)."\" target=\"_blank\">Yahoo! Images</a> or <a href=\"https://www.google.com/search?q=".urlencode($opts->query)."&tbm=isch&pws=0\" target=\"_blank\">Google Images</a>.</small></center>";
if($opts->cache_type !== 'off' && $goosle_results['number_of_results'] > $opts->search_results_per_page) {
echo "<p class=\"pagination\">".search_pagination($search, $opts, $goosle_results['number_of_results'])."</p>";
}
echo "<p class=\"text-center\"><small>Goosle does not store or distribute image files.</small></p>";
} }
// No results found // No results found
if(array_key_exists("error", $goosle_results)) { if(array_key_exists("error", $results)) {
foreach($goosle_results['error'] as $error) { echo "<div class=\"error\">".$results['error']['message']."</div>";
echo "<div class=\"error\">".$error['message']."</div>";
}
} }
unset($goosle_results);
} }
} }
?> ?>

View file

@ -1,349 +0,0 @@
<?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 MagnetSearch extends EngineRequest {
protected $requests;
public function __construct($search, $opts, $mh) {
$this->requests = array();
if($opts->enable_magnet_search == 'on') {
// Extra functions to process magnet results
require ABSPATH.'functions/tools-magnet.php';
if($opts->magnet['limetorrents'] == 'on') {
require ABSPATH.'engines/magnet/lime.php';
$this->requests[] = new LimeRequest($search, $opts, $mh);
}
if($opts->magnet['piratebay'] == 'on') {
require ABSPATH.'engines/magnet/thepiratebay.php';
$this->requests[] = new PirateBayRequest($search, $opts, $mh);
}
if($opts->magnet['yts'] == 'on') {
if($search->safe !== 0) {
require ABSPATH.'engines/magnet/yts.php';
$this->requests[] = new YTSRequest($search, $opts, $mh);
}
}
if($opts->magnet['nyaa'] == 'on') {
if($search->safe !== 0) {
require ABSPATH.'engines/magnet/nyaa.php';
$this->requests[] = new NyaaRequest($search, $opts, $mh);
}
}
if($opts->magnet['sukebei'] == 'on') {
if($opts->show_nsfw_magnets == 'on' || ($opts->show_nsfw_magnets == 'off' && $search->safe === 0)) {
require ABSPATH.'engines/magnet/sukebei.php';
$this->requests[] = new SukebeiRequest($search, $opts, $mh);
}
}
if($opts->magnet['eztv'] == 'on') {
if(substr(strtolower($search->query), 0, 2) == 'tt') {
require ABSPATH.'engines/magnet/eztv.php';
$this->requests[] = new EZTVRequest($search, $opts, $mh);
}
}
}
}
public function parse_results($response) {
$goosle_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(isset($engine_result['search'])) {
$how_many_results = 0;
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
// Safe search, skip nsfw?
if($request->opts->show_nsfw_magnets == 'off' && $request->search->safe !== 0 && $result['nsfw']) continue;
if(isset($goosle_results['search'])) {
$result_urls = array_column($goosle_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;
}
$how_many_results++;
if($found_id !== false) {
// Duplicate result from another engine
// If seeders or leechers mismatch, assume they're different peers
if($goosle_results['search'][$found_id]['seeders'] != $result['seeders']) $goosle_results['search'][$found_id]['combo_seeders'] += intval($result['seeders']);
if($goosle_results['search'][$found_id]['leechers'] != $result['leechers']) $goosle_results['search'][$found_id]['combo_leechers'] += intval($result['leechers']);
$goosle_results['search'][$found_id]['combo_source'][] = $engine_result['source'];
// If duplicate result has more info, add it
if(is_null($goosle_results['search'][$found_id]['year']) && !is_null($result['year'])) $goosle_results['search'][$found_id]['year'] = $result['year'];
if(is_null($goosle_results['search'][$found_id]['category']) && !is_null($result['category'])) $goosle_results['search'][$found_id]['category'] = $result['category'];
if(is_null($goosle_results['search'][$found_id]['runtime']) && !is_null($result['runtime'])) $goosle_results['search'][$found_id]['runtime'] = $result['runtime'];
if(is_null($goosle_results['search'][$found_id]['url']) && !is_null($result['url'])) $goosle_results['search'][$found_id]['url'] = $result['url'];
if(is_null($goosle_results['search'][$found_id]['timestamp']) && !is_null($result['timestamp'])) $goosle_results['search'][$found_id]['timestamp'] = $result['timestamp'];
if(is_null($goosle_results['search'][$found_id]['quality']) && !is_null($result['quality'])) $goosle_results['search'][$found_id]['quality'] = $result['quality'];
if(is_null($goosle_results['search'][$found_id]['type']) && !is_null($result['type'])) $goosle_results['search'][$found_id]['type'] = $result['type'];
if(is_null($goosle_results['search'][$found_id]['audio']) && !is_null($result['audio'])) $goosle_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
// Add result to final results
$goosle_results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
}
// Count results per source
$goosle_results['sources'][$engine_result['source']] = $how_many_results;
unset($how_many_results);
}
}
} 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'));
$goosle_results['error'][] = array(
'message' => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
);
}
unset($request);
}
if(array_key_exists('search', $goosle_results)) {
// Re-order results based on seeders
$keys = array_column($goosle_results['search'], 'combo_seeders');
array_multisort($keys, SORT_DESC, $goosle_results['search']);
// Count all results
$goosle_results['number_of_results'] = count($goosle_results['search']);
unset($keys);
} else {
// Add error if there are no search results
$goosle_results['error'][] = array(
'message' => "No results found. Please try with more specific or different keywords!"
);
}
} else {
$goosle_results['error'][] = array(
'message' => "It appears that all Magnet Search engines are disabled or that searching for magnet links is disabled."
);
}
return $goosle_results;
}
public static function print_results($goosle_results, $search, $opts) {
// Uncomment for debugging
/*
echo "<pre>Settings: ";
print_r($opts);
echo "</pre>";
echo "<pre>Search data: ";
print_r($search);
echo "</pre>";
echo "<pre>Search results: ";
print_r($goosle_results);
echo "</pre>";
*/
// Latest additions to yts
if($opts->show_yts_highlight == 'on') {
require ABSPATH.'engines/boxoffice/yts.php';
echo "<h2>Latest releases from YTS</h2>";
echo "<p>View these and more new releases on the <a href=\"./box-office.php?q=".$search->query."&t=9&a=".$opts->hash."\">box office</a> page!</p>";
echo "<ul class=\"result-grid\">";
$highlights = array_slice(yts_boxoffice($opts, 'date_added'), 0, 8);
foreach($highlights as $highlight) {
$thumb = (!empty($highlight['thumbnail'])) ? $highlight['thumbnail'] : $opts->pixel;
echo "<li class=\"result highlight yts\">";
echo " <div class=\"thumb\">";
echo " <a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['title']."\"><img src=\"".$thumb."\" alt=\"".$highlight['title']."\" /></a>";
echo " </div>";
echo " <span><center><a onclick=\"openpopup('highlight-".$highlight['id']."')\" title=\"More info: ".$highlight['title']."\">".$highlight['title']."</a></center></span>";
// HTML for popup
echo highlight_popup($opts->hash, $highlight);
echo "</li>";
unset($highlight);
}
echo "</ul>";
}
// Main content
if(array_key_exists('search', $goosle_results)) {
// Is this a shared search? Move shared result to position 1
if($opts->show_share_option == 'on' && !empty($search->share)) {
$keys = array_keys($goosle_results['search']);
$found_id = array_search(md5($search->share), $keys); // Return the shared key ID
$found_id = $keys[$found_id]; // Get the actual shared ID
// Get the result
$first = array($found_id => $goosle_results['search'][$found_id]);
// Delete the result wherever it is
unset($goosle_results['search'][$found_id], $keys, $found_id);
// Add the result as the first item
$goosle_results['search'] = array_merge($first, $goosle_results['search']);
}
// Pagination offset
if($opts->cache_type !== 'off') {
$offset = ((($search->page - 1) * $opts->search_results_per_page));
$goosle_results['search'] = array_slice($goosle_results['search'], $offset, $opts->search_results_per_page);
}
echo "<ul>";
// Elapsed time and search sources
echo "<li class=\"meta\">";
echo " <p class=\"timer\">Fetched ".$goosle_results['number_of_results']." results in ".$goosle_results['time']." seconds.</p>";
if($opts->show_search_source == 'on') {
echo " <p class=\"sources\">".search_sources($goosle_results['sources'])."</p>";
}
echo "</li>";
// Search results
foreach($goosle_results['search'] as $result) {
// Extra data
$base = $meta = array();
if(!empty($result['verified_uploader'])) {
$icon = ($result['verified_uploader'] == 'yes') ? 'magnet-verified' : 'magnet-not-verified';
$base[] = "<a onclick=\"openpopup('info-torrentverified')\" title=\"".$icon." - Click for more information\"><span class=\"".$icon."\"></span></a>";
}
if(!empty($result['combo_seeders'])) $base[] = "<strong>Seeds:</strong> <span class=\"green\">".$result['combo_seeders']."</span>";
if(!empty($result['combo_leechers'])) $base[] = "<strong>Peers:</strong> <span class=\"red\">".$result['combo_leechers']."</span>";
if(!empty($result['filesize'])) $base[] = "<strong>Size:</strong> ".human_filesize($result['filesize']);
if(!empty($result['timestamp'])) $base[] = "<strong>Added on:</strong> ".the_date("M d, Y", $result['timestamp']);
if(!empty($result['mpa_rating'])) $base[] = "<strong>MPA Rating:</strong> ".$result['mpa_rating'];
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($search->share) && $result['hash'] == $search->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'].$class."\">";
echo " <div class=\"title\"><a href=\"".$result['magnet']."\"><h2>".stripslashes($result['title'])."</h2></a></div>";
echo " <div class=\"description\">";
echo " <p>".implode(" &bull; ", $base)."</p>";
echo " <p>".implode(" &bull; ", $meta)."</p>";
// Result sources
if($opts->show_search_source == 'on') {
// If available, add a link to the found torrent page
$url = (!is_null($result['url'])) ? " &bull; <a href=\"".$result['url']."\" target=\"_blank\" title=\"Visit torrent page\">torrent page</a> <a onclick=\"openpopup('info-torrentpagelink')\" title=\"Click for more information\"><span class=\"tooltip-alert\"></span></a>" : "";
echo " <p><small>Found on ".replace_last_comma(implode(', ', $result['combo_source'])).$url."</small></p>";
}
echo " </div>";
// Share popup
if($opts->show_share_option == 'on' && $result['hash'] != $search->share) {
// Generate an encoded hash for sharing
$share_url = base64_url_encode($search->query.'||'.$search->type.'||'.$result['hash']);
// The actual popup
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['title'])."</h3>";
echo " <p><input tabindex=\"2\" type=\"text\" id=\"share-result-".$result['id']."\" class=\"share-field\" value=\"".get_base_url($opts->siteurl)."/results.php?s=".$share_url."\" /><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, $base, $meta, $class, $url);
}
echo "</ul>";
// Pagination navigation
if($opts->cache_type !== 'off' && $goosle_results['number_of_results'] > $opts->search_results_per_page) {
echo "<p class=\"pagination\">".search_pagination($search, $opts, $goosle_results['number_of_results'])."</p>";
}
echo "<p class=\"text-center\"><small>Goosle does not index, offer or distribute torrent files.</small></p>";
// Torrent site warning popup (Normally hidden)
echo "<div id=\"info-torrentpagelink\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>Be careful when you visit torrent sites</h2>";
echo " <p>Many torrent websites have intrusive popup ads and malware! Be careful what you click on and close any popups/redirects that appear.</p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo "</div>";
// Verified magnet info popup (Normally hidden)
echo "<div id=\"info-torrentverified\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>Trusted uploaders</h2>";
echo " <p>Some websites have a group of verified and/or trusted uploaders. These are users that are known to provide good quality downloads.</p>";
echo " <p><span class=\"magnet-verified\"></span> Downloads with a blue shield and checkmark are uploaded by a verified or trusted user according to the torrent site.</p>";
echo " <p><span class=\"magnet-not-verified\"></span> Downloads with a red shield and questionmark indicate that the user is <em>not</em> verified by the website providing the download. This can mean this is a new user, or that the file is provided from an anonymous source. Unverified magnet links are not necessarily bad but may contain low quality or misleading content or simply have a poorly written title.</p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo "</div>";
}
// No results found
if(array_key_exists('error', $goosle_results)) {
foreach($goosle_results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}
}
}
}
?>

View file

@ -1,219 +0,0 @@
<?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($search, $opts, $mh) {
$this->requests = array();
if($opts->enable_news_search == 'on') {
if($opts->news['qwantnews'] == 'on') {
require ABSPATH.'engines/news/qwant-news.php';
$this->requests[] = new QwantNewsRequest($search, $opts, $mh);
}
if($opts->news['yahoonews'] == 'on') {
require ABSPATH.'engines/news/yahoo-news.php';
$this->requests[] = new YahooNewsRequest($search, $opts, $mh);
}
if($opts->news['bravenews'] == 'on') {
require ABSPATH.'engines/news/brave-news.php';
$this->requests[] = new BraveNewsRequest($search, $opts, $mh);
}
if($opts->news['hackernews'] == 'on') {
require ABSPATH.'engines/news/hackernews.php';
$this->requests[] = new HackernewsRequest($search, $opts, $mh);
}
}
}
public function parse_results($response) {
$goosle_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(isset($engine_result['search'])) {
$how_many_results = 0;
$time = time();
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(isset($goosle_results['search'])) {
$result_urls = array_column($goosle_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;
}
$how_many_results++;
$social_media_multiplier = (detect_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * $social_media_multiplier);
if($found_id !== false) {
// Duplicate result from another engine
$goosle_results['search'][$found_id]['goosle_rank'] += $goosle_rank;
$goosle_results['search'][$found_id]['combo_source'][] = $engine_result['source'];
} else {
// First find, rank and add to results
$match_rank = match_count($result['title'], $request->search->query_terms, 1.2);
$match_rank += match_count($result['description'], $request->search->query_terms);
$match_rank += match_count($result['url'], $request->search->query_terms, 0.5);
$age_rank = $time - $result['timestamp'];
if($age_rank > 21600) { // Less than 6 hours old
$match_rank += 8;
} elseif($age_rank > 86400 && $age_rank < 21600) { // About a day old
$match_rank += 6;
} elseif($age_rank > 604800 && $age_rank < 86400) { // Less than a week old, but more than a day
$match_rank += 4;
} elseif($age_rank > 2592000 && $age_rank < 604800) { // Less than a month old, but more than a week
$match_rank += 4;
} elseif($age_rank > 31536000 && $age_rank < 2592000) { // Less than a year old, but more than a month
$match_rank += 2;
} else { // More than a year old
$match_rank += 1;
}
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['url']);
// Add result to final results
$goosle_results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank, $age_rank);
}
// Count results per source
$goosle_results['sources'][$engine_result['source']] = $how_many_results;
unset($how_many_results, $time);
}
}
} 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'));
$goosle_results['error'][] = array(
'message' => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
);
}
unset($request);
}
if(array_key_exists('search', $goosle_results)) {
// Re-order results based on rank
$keys = array_column($goosle_results['search'], 'goosle_rank');
array_multisort($keys, SORT_DESC, $goosle_results['search']);
// Count all results
$goosle_results['number_of_results'] = count($goosle_results['search']);
unset($keys);
} else {
// Add error if there are no search results
$goosle_results['error'][] = array(
'message' => "No results found. Please try with more specific or different keywords!"
);
}
} else {
$goosle_results['error'][] = array(
'message' => "It appears that all News Search engines are disabled or that searching for news is disabled."
);
}
return $goosle_results;
}
public static function print_results($goosle_results, $search, $opts) {
// Uncomment for debugging
/*
echo "<pre>Settings: ";
print_r($opts);
echo "</pre>";
echo "<pre>Search data: ";
print_r($search);
echo "</pre>";
echo "<pre>Search results: ";
print_r($goosle_results);
echo "</pre>";
*/
if(array_key_exists('search', $goosle_results)) {
// Pagination offset
if($opts->cache_type !== 'off') {
$offset = ((($search->page - 1) * $opts->search_results_per_page));
$goosle_results['search'] = array_slice($goosle_results['search'], $offset, $opts->search_results_per_page);
}
echo "<ul>";
// Elapsed time and search sources
echo "<li class=\"meta\">";
echo " <p class=\"timer\">Fetched ".$goosle_results['number_of_results']." results in ".$goosle_results['time']." seconds.</p>";
if($opts->show_search_source == 'on') {
echo " <p class=\"sources\">".search_sources($goosle_results['sources'])."</p>";
}
echo "</li>";
// Search results
foreach($goosle_results['search'] as $result) {
// Extra data
$meta = array();
if(!empty($result['source'])) $meta[] = "<strong>Source:</strong> ".$result['source'];
if(!empty($result['timestamp'])) $meta[] = "<strong>Posted:</strong> ".the_date("M d, Y", $result['timestamp']);
if($opts->show_search_source == 'on') $meta[] = replace_last_comma(implode(', ', $result['combo_source']));
if($opts->show_search_rank == 'on') $meta[] = "Rank: ".$result['goosle_rank'];
$thumb = (!empty($result['image'])) ? $result['image'] : $opts->pixel;
echo "<li class=\"result news rank-".$result['goosle_rank']." id-".$result['id']."\">";
echo " <div class=\"image\"><a href=\"".$result['url']."\" target=\"_blank\" title=\"".$result['title']."\"><img src=\"".$thumb."\" /></a></div>";
echo " <div>";
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; ', $meta)."</small></p>";
echo " <p>".$result['description']."</p>";
echo " </div>";
echo " </div>";
echo "</li>";
unset($meta, $thumb);
}
echo "</ul>";
// Pagination navigation
if($opts->cache_type !== 'off' && $goosle_results['number_of_results'] > $opts->search_results_per_page) {
echo "<p class=\"pagination\">".search_pagination($search, $opts, $goosle_results['number_of_results'])."</p>";
}
}
// Some error occured
if(array_key_exists('error', $goosle_results)) {
foreach($goosle_results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}
}
unset($goosle_results);
}
}
?>

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

@ -0,0 +1,134 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class TorrentSearch extends EngineRequest {
protected $requests;
public function __construct($opts, $mh) {
$this->opts = $opts;
$this->url = 'torrent'; // Dummy value to satisfy EngineRequest::get_results()
require "engines/torrent/1337x.php";
require "engines/torrent/nyaa.php";
require "engines/torrent/thepiratebay.php";
require "engines/torrent/yts.php";
require "engines/torrent/eztv.php";
$this->requests = array(
new LeetxRequest($opts, $mh), // 1337x
new NyaaRequest($opts, $mh),
new PirateBayRequest($opts, $mh),
new YTSRequest($opts, $mh),
new EZTVRequest($opts, $mh)
);
}
public function parse_results($response) {
$results = $results_temp = array();
foreach($this->requests as $request) {
if($request->request_successful()) {
$results_temp = array_merge($results_temp, $request->get_results());
}
}
if(count($results_temp) > 0) {
// Ensure highest seeders are shown first
$seeders = array_column($results_temp, "seeders");
array_multisort($seeders, SORT_DESC, $results_temp);
// Cap results
$results['search'] = array_slice($results_temp, 0, 50);
// Count results per site
$sources = array_count_values(array_column($results['search'], 'source'));
if(count($sources) > 0) $results['sources'] = $sources;
unset($sources);
}
unset($results_temp);
// Add error if there are no search results
if(empty($results)) {
$results['error'] = array(
"message" => "No results found. Please try with more specific or different keywords!"
);
}
return $results;
}
public static function print_results($results, $opts) {
/*
echo '<pre>Results: ';
print_r($results);
echo '</pre>';
*/
if(array_key_exists("search", $results)) {
echo "<ol>";
// Format sources
$sources = "";
if(array_key_exists("sources", $results)) {
$sources = array();
foreach($results['sources'] as $source => $amount) {
$plural = ($amount > 1) ? "results" : "result";
$sources[] = $amount." ".$plural." from ".$source;
}
$sources = implode(', ', $sources);
$last_comma = strrpos($sources, ', ');
if($last_comma !== false) {
$sources = substr_replace($sources, ' and ', $last_comma, 2);
}
$sources = "<br /><small>Including ".$sources.". Links with the most seeders are listed first.</small>";
}
// Elapsed time
$number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.".$sources."</li>";
// Search results
foreach($results['search'] as $result) {
$meta = array();
// Optional data
if(array_key_exists('quality', $result)) $meta[] = "<strong>Quality:</strong> ".$result['quality'];
if(array_key_exists('year', $result)) $meta[] = "<strong>Year:</strong> ".$result['year'];
if(array_key_exists('category', $result)) $meta[] = "<strong>Category:</strong> ".$result['category'];
if(array_key_exists('runtime', $result)) $meta[] = "<strong>Runtime:</strong> ".date('H:i', mktime(0, $result['runtime']));
if(array_key_exists('date_added', $result)) $meta[] = "<strong>Added:</strong> ".date('M d, Y', $result['date_added']);
if(array_key_exists('url', $result)) $meta[] = "<a href=\"".$result['url']."\" target=\"_blank\" title=\"Careful - Site may contain intrusive popup ads and malware!\">Torrent page</a>";
// Put result together
echo "<li class=\"result\"><article>";
echo "<div class=\"url\"><a href=\"".$result['magnet']."\">".$result['source']."</a></div>";
echo "<div class=\"title\"><a href=\"".$result['magnet']."\"><h2>".stripslashes($result['name'])."</h2></a></div>";
echo "<div class=\"description\"><strong>Seeds:</strong> <span class=\"seeders\">".$result['seeders']."</span> - <strong>Peers:</strong> <span class=\"leechers\">".$result['leechers']."</span> - <strong>Size:</strong> ".$result['size']."<br />".implode(" - ", $meta)."</div>";
echo "</article></li>";
unset($result, $meta);
}
echo "</ol>";
echo "<center><small>Showing up to 50 results, sorted by most seeders.<br />Goosle does not index, offer or distribute torrent files.</small></center>";
}
// No results found
if(array_key_exists("error", $results)) {
echo "<div class=\"error\">".$results['error']['message']."</div>";
}
}
}
?>

View file

@ -1,6 +1,6 @@
<?php <?php
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -9,286 +9,168 @@
* By using this code you agree to indemnify Arnan de Gans from any * By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use. * liability that might arise from its use.
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
class Search extends EngineRequest { class TextSearch extends EngineRequest {
protected $requests, $special_request; protected $engine, $engine_request, $special_request;
public function __construct($search, $opts, $mh) { public function __construct($opts, $mh) {
$this->requests = array(); $this->query = $opts->query;
$this->opts = $opts;
if($opts->enable_web_search == 'on') { if($this->opts->type == 0) {
if($opts->web['duckduckgo'] == 'on') { require "engines/duckduckgo.php";
require ABSPATH.'engines/search/duckduckgo.php'; $this->engine_request = new DuckDuckGoRequest($opts, $mh);
$this->requests[] = new DuckDuckGoRequest($search, $opts, $mh);
} }
if($opts->web['mojeek'] == 'on') { if($this->opts->type == 1) {
require ABSPATH.'engines/search/mojeek.php'; require "engines/google.php";
$this->requests[] = new MojeekRequest($search, $opts, $mh); $this->engine_request = new GoogleRequest($opts, $mh);
} }
if($opts->web['google'] == 'on') { // Special search
require ABSPATH.'engines/search/google.php'; $this->special_request = special_search_request($opts);
$this->requests[] = new GoogleRequest($search, $opts, $mh);
}
if($opts->web['qwant'] == 'on') {
require ABSPATH.'engines/search/qwant.php';
$this->requests[] = new QwantRequest($search, $opts, $mh);
}
if($opts->web['brave'] == 'on') {
require ABSPATH.'engines/search/brave.php';
$this->requests[] = new BraveRequest($search, $opts, $mh);
}
if($opts->web['wikipedia'] == 'on') {
require ABSPATH.'engines/search/wikipedia.php';
$this->requests[] = new WikiRequest($search, $opts, $mh);
}
}
/* --- SPECIAL SEARCHES --- */
// Currency converter
if($opts->special['currency'] == 'on') {
if($search->count_terms == 4 && (is_numeric($search->query_terms[0]) && ($search->query_terms[2] == 'to' || $search->query_terms[2] == 'in'))) {
require ABSPATH.'engines/special/currency.php';
$this->special_request = new CurrencyRequest($search, $opts, $mh);
}
}
// Dictionary
if($opts->special['definition'] == 'on') {
if($search->count_terms == 2 && ($search->query_terms[0] == 'def' || $search->query_terms[0] == 'define' || $search->query_terms[0] == 'meaning')) {
require ABSPATH.'engines/special/definition.php';
$this->special_request = new DefinitionRequest($search, $opts, $mh);
}
}
// IP Lookup
if($opts->special['ipaddress'] == 'on') {
if($search->count_terms == 1 && ($search->query_terms[0] == 'ip' || $search->query_terms[0] == 'myip' || $search->query_terms[0] == 'ipaddress')) {
require ABSPATH.'engines/special/ipify.php';
$this->special_request = new ipRequest($search, $opts, $mh);
}
}
// php.net search
if($opts->special['phpnet'] == 'on') {
if($search->count_terms == 2 && $search->query_terms[0] == 'php') {
require ABSPATH.'engines/special/php.php';
$this->special_request = new PHPnetRequest($search, $opts, $mh);
}
}
// wordpress.org search
if($opts->special['wordpress'] == 'on') {
if(($search->count_terms == 2 && ($search->query_terms[0] == 'wordpress' || $search->query_terms[0] == 'wp')) || ($search->count_terms == 3 && ($search->query_terms[0] == 'wordpress' || $search->query_terms[0] == 'wp') && $search->query_terms[1] == 'hook')) {
require ABSPATH.'engines/special/wordpress.php';
$this->special_request = new WordPressRequest($search, $opts, $mh);
}
}
} }
public function parse_results($response) { public function parse_results($response) {
$goosle_results = array(); $results = array();
if(count($this->requests) !== 0) { // Abort if no results from search engine
foreach($this->requests as $request) { if(!isset($this->engine_request)) return $results;
if($request->request_successful()) {
$engine_result = $request->get_results();
if(!empty($engine_result)) { // Add search results if there are any, otherwise add error
if(isset($engine_result['did_you_mean'])) { if($this->engine_request->request_successful()) {
$goosle_results['did_you_mean'] = $engine_result['did_you_mean']; $search_result = $this->engine_request->get_results();
if($search_result) {
$results = $search_result;
} }
if(isset($engine_result['search_specific'])) { unset($search_result);
$goosle_results['search_specific'][] = $engine_result['search_specific'];
}
if(isset($engine_result['search'])) {
$how_many_results = 0;
// Merge duplicates and apply relevance scoring
foreach($engine_result['search'] as $result) {
if(isset($goosle_results['search'])) {
$result_urls = array_column($goosle_results['search'], 'url', 'id');
$found_id = array_search($result['url'], $result_urls); // Return the result ID, or false if not found
} else { } else {
$found_id = false; $results['error'] = array(
} "message" => "Error code ".curl_getinfo($this->engine_request->ch)['http_code']." for ".curl_getinfo($this->engine_request->ch)['url'].".<br />Try again in a few seconds or <a href=\"".curl_getinfo($this->engine_request->ch)['url']."\" target=\"_blank\">visit the search engine</a> in a new tab."
$how_many_results++;
$social_media_multiplier = (detect_social_media($result['url'])) ? ($request->opts->social_media_relevance / 10) : 1;
$goosle_rank = floor($result['engine_rank'] * $social_media_multiplier);
if($found_id !== false) {
// Duplicate result from another engine
$goosle_results['search'][$found_id]['goosle_rank'] += $goosle_rank;
$goosle_results['search'][$found_id]['combo_source'][] = $engine_result['source'];
} else {
// First find, rank and add to results
$match_rank = match_count($result['title'], $request->search->query_terms);
$match_rank += match_count($result['description'], $request->search->query_terms, 2);;
$match_rank += match_count($result['url'], $request->search->query_terms, 0.5);
$result['goosle_rank'] = $goosle_rank + $match_rank;
$result['combo_source'][] = $engine_result['source'];
$result['id'] = md5($result['url']);
// Add result to final results
$goosle_results['search'][$result['id']] = $result;
}
unset($result, $result_urls, $found_id, $social_media_multiplier, $goosle_rank, $match_rank);
}
// Count results per source
$goosle_results['sources'][$engine_result['source']] = $how_many_results;
unset($how_many_results);
}
}
} 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'));
$goosle_results['error'][] = array(
'message' => "<strong>Ohno! A search query ran into some trouble.</strong> Usually you can try again in a few seconds to get a result!<br /><strong>Engine:</strong> ".get_class($request)."<br /><strong>Error code:</strong> ".$request_result['http_code'].$http_code_info."<br /><strong>Request url:</strong> ".$request_result['url']."<br /><strong>Need help?</strong> Find <a href=\"https://github.com/adegans/Goosle/discussions\" target=\"_blank\">similar issues</a>, or <a href=\"".$github_issue_url."\" target=\"_blank\">ask your own question</a>."
); );
} }
unset($request);
}
// Check for Special result // Check for Special result
if($this->special_request) { if($this->special_request) {
$special_result = $this->special_request->get_results(); $special_result = $this->special_request->get_results();
if($special_result) { if($special_result) {
$goosle_results['special'] = $special_result; $results['special'] = $special_result;
} }
unset($special_result); unset($special_result);
} }
if(array_key_exists('search', $goosle_results)) {
// Re-order results based on rank
$keys = array_column($goosle_results['search'], 'goosle_rank');
array_multisort($keys, SORT_DESC, $goosle_results['search']);
// Count all results
$goosle_results['number_of_results'] = count($goosle_results['search']);
unset($keys);
} else {
// Add error if there are no search results // Add error if there are no search results
$goosle_results['error'][] = array( if(empty($results)) {
'message' => "No results found. Please try with more specific or different keywords!" $results['error'] = array(
); "message" => "No results found. Please try with less or different keywords!"
}
} else {
$goosle_results['error'][] = array(
'message' => "It appears that all Web Search engines are disabled. Please enable at least one in your config.php file."
); );
} }
return $goosle_results; return $results;
} }
public static function print_results($goosle_results, $search, $opts) { public static function print_results($results, $opts) {
// Uncomment for debugging
/* /*
echo "<pre>Settings: "; echo '<pre>Results: ';
print_r($opts); print_r($results);
echo "</pre>"; echo '</pre>';
echo "<pre>Search data: ";
print_r($search);
echo "</pre>";
echo "<pre>Search results: ";
print_r($goosle_results);
echo "</pre>";
*/ */
if(array_key_exists('search', $goosle_results)) { if(array_key_exists("search", $results)) {
// Pagination offset echo "<ol>";
if($opts->cache_type !== 'off') {
$offset = ((($search->page - 1) * $opts->search_results_per_page)); // Elapsed time
$goosle_results['search'] = array_slice($goosle_results['search'], $offset, $opts->search_results_per_page); $number_of_results = count($results['search']);
echo "<li class=\"meta\">Fetched ".$number_of_results." results in ".$results['time']." seconds.</li>";
// Did you mean/Search suggestion
if(array_key_exists("did_you_mean", $results)) {
$specific_result = "";
if(array_key_exists("search_specific", $results)) {
// Add double quotes to Google search
$search_specific = ($opts->type == 1) ? "\"".$results['search_specific']."\"" : $results['search_specific'];
// Format query url
$search_specific_url = "./results.php?q=" . urlencode($search_specific)."&t=".$opts->type."&a=".$opts->hash;
// Specific search
$specific_result = "<br /><small>Or instead search for <a href=\"".$search_specific_url."\">".$search_specific."</a>.</small>";
unset($search_specific, $search_specific_url);
} }
echo "<ul>"; $didyoumean_url = "./results.php?q=" . urlencode($results['did_you_mean'])."&t=".$opts->type."&a=".$opts->hash;
// Elapsed time and search sources echo "<li class=\"meta\">Did you mean <a href=\"".$didyoumean_url."\">".$results['did_you_mean']."</a>?".$specific_result."</li>";
echo "<li class=\"meta\">";
echo " <p class=\"timer\">Fetched ".$goosle_results['number_of_results']." results in ".$goosle_results['time']." seconds.</p>";
if($opts->show_search_source == 'on') {
echo " <p class=\"sources\">".search_sources($goosle_results['sources'])."</p>";
}
echo "</li>";
// Special result unset($didyoumean_url, $specific_result);
if(array_key_exists('special', $goosle_results)) {
echo "<li class=\"result-special web\">";
echo " <div class=\"title\"><h2>".$goosle_results['special']['title']."</h2></div>";
echo " <div class=\"description\">".$goosle_results['special']['text']."</div>"; // <p> is in the engine files
echo " <div class=\"source\"><a href=\"".$goosle_results['special']['source']."\" target=\"_blank\">".$goosle_results['special']['source']."</a></div>";
if(array_key_exists('note', $goosle_results['special'])) {
echo " <div class=\"note\"><small><em>".$goosle_results['special']['note']."</em></small></div>";
} }
echo "</li>";
// Special results
if($opts->special['imdb_id_search'] == "on") {
$found = false;
foreach($results['search'] as $search_result) {
if(!$found && preg_match_all("/(imdb.com|tt[0-9]+)/i", $search_result['url'], $imdb_result) && stristr($search_result['title'], "tv series") !== false) {
$results['special'] = array(
"title" => $search_result['title'],
"text" => "Goosle found an IMDb ID for this TV Show in your results (".$imdb_result[0][1].") - <a href=\"./results.php?q=".$imdb_result[0][1]."&a=".$opts->hash."&t=9\">search for magnet links</a>?<br /><sub>An IMDb ID is detected when a TV Show is present in the results. The first match is highlighted here.</sub>"
);
$found = true;
}
}
}
if(array_key_exists("special", $results)) {
echo "<li class=\"special-result\"><article>";
// Maybe shorten text
if(strlen($results['special']['text']) > 1250) {
$results['special']['text'] = substr($results['special']['text'], 0, strrpos(substr($results['special']['text'], 0, 1300), ". "));
$results['special']['text'] .= '. <a href="'.$results['special']['source'].'" target="_blank">[...]</a>';
}
// Add image to text
if(array_key_exists("image", $results['special'])) {
$image_specs = getimagesize($results['special']['image']);
$width = $image_specs[0] / 2;
$height = $image_specs[1] / 2;
$special_image = "<img src=\"".$results['special']['image']."\" align=\"right\" width=\"".$width."\" height=\"".$height."\" />";
$results['special']['text'] = $special_image.$results['special']['text'];
unset($image_specs, $width, $height, $special_image);
}
echo "<div class=\"title\"><h2>".$results['special']['title']."</h2></div>";
echo "<div class=\"text\">".$results['special']['text']."</div>";
if(array_key_exists("source", $results['special'])) {
echo "<div class=\"source\"><a href=\"".$results['special']['source']."\" target=\"_blank\">".$results['special']['source']."</a></div>";
}
echo "</article></li>";
} }
// Search results // Search results
foreach($goosle_results['search'] as $result) { foreach($results['search'] as $result) {
// Extra data if(array_key_exists("did_you_mean", $result)) continue;
$meta = array();
if($opts->show_search_source == 'on') $meta[] = replace_last_comma(implode(', ', $result['combo_source'])).".";
if($opts->show_search_rank == 'on') $meta[] = "Rank: ".$result['goosle_rank'];
echo "<li class=\"result web rank-".$result['goosle_rank']." id-".$result['id']."\">"; // Put result together
echo " <div class=\"url\"><a href=\"".$result['url']."\" target=\"_blank\">".search_formatted_url($result['url'])."</a></div>"; echo "<li class=\"result\"><article>";
echo " <div class=\"title\"><a href=\"".$result['url']."\" target=\"_blank\"><h2>".$result['title']."</h2></a></div>"; echo "<div class=\"url\"><a href=\"".$result['url']."\" target=\"_blank\">".get_formatted_url($result['url'])."</a></div>";
echo " <div class=\"description\">"; echo "<div class=\"title\"><a href=\"".$result['url']."\" target=\"_blank\"><h2>".$result['title']."</h2></a></div>";
echo " <p>".$result['description']."</p>"; echo "<div class=\"description\">".$result['description']."</div>";
if($opts->enable_magnet_search == 'on' && $opts->imdb_id_search == 'on') { echo "</article></li>";
if(stristr($result['url'], 'imdb.com') !== false && preg_match_all('/(?:tt[0-9]+)/i', $result['url'], $imdb_result)) {
echo " <p><strong>Goosle detected an IMDb ID for this result, search for <a href=\"./results.php?q=".$imdb_result[0][0]."&a=".$opts->hash."&t=9\" title=\"Search for Magnet links\">Magnet links</a>?</strong> <a onclick=\"openpopup('info-magnetresult')\" title=\"Click for more information\"><span class=\"tooltip-question\"></span></a></p>"; unset($result);
}
} }
echo " <p><small>".implode(' &bull; ', $meta)."</small></p>"; echo "</ol>";
echo " </div>";
echo "</li>";
unset($meta);
} }
echo "</ul>"; // No results found
if(array_key_exists("error", $results)) {
// Pagination navigation echo "<div class=\"error\">".$results['error']['message']."</div>";
if($opts->cache_type !== 'off' && $goosle_results['number_of_results'] > $opts->search_results_per_page) {
echo "<p class=\"pagination\">".search_pagination($search, $opts, $goosle_results['number_of_results'])."</p>";
} }
// Popup (Normally hidden)
echo "<div id=\"info-magnetresult\" class=\"goosebox\">";
echo " <div class=\"goosebox-body\">";
echo " <h2>Magnet links</h2>";
echo " <p>A Magnet link is a special link that torrent clients can use to find and download software, music, movies and tv-shows.</p>";
echo " <p>Magnet links are part of the Magnet Search function. You'll need a Bittorrent client that accepts Magnet links in order to use these search results. You can find more information about how to use Magnet Search on the <a href=\"./help.php?a=".$opts->hash."\">Help page</a>.</p>";
echo " <p><a onclick=\"closepopup()\">Close</a></p>";
echo " </div>";
echo "</div>";
}
// Some error occured
if(array_key_exists('error', $goosle_results)) {
foreach($goosle_results['error'] as $error) {
echo "<div class=\"error\">".$error['message']."</div>";
}
}
unset($goosle_results);
} }
} }
?> ?>

View file

@ -1,96 +0,0 @@
<?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() {
$url = 'https://search.brave.com/search?'.http_build_query(array(
'q' => $this->search->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)
));
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//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) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
foreach($scrape as $result) {
// Find data
$url = $xpath->evaluate(".//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
if(!empty($engine_temp)) {
$engine_result['source'] = 'Brave';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, $number_of_results, count($engine_temp));
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,115 +0,0 @@
<?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 DuckDuckGoRequest extends EngineRequest {
public function get_request_url() {
// Safe search override
if($this->search->safe == 0) {
$safe = '-2';
} else if($this->search->safe == 2) {
$safe = '1';
} else {
$safe = '-1';
}
// All parameters and values: https://duckduckgo.com/duckduckgo-help-pages/settings/params/
$url = 'https://html.duckduckgo.com/html/?'.http_build_query(array(
'q' => $this->search->query, // Search query
'kp' => $safe, // Safe search (1 = on, -1 = moderate, -2 = off
'kl' => strtolower($this->opts->duckduckgo_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)
'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)
));
unset($safe);
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
// $scrape = $xpath->query("/html/body/div[1]/div[".count($xpath->query("/html/body/div[1]/div"))."]/div/div/div[contains(@class, 'web-result')]/div");
$scrape = $xpath->query("//div[contains(@class, 'result__body')]");
// Figure out results and base rank
$number_of_results = $rank = count($scrape);
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
foreach($scrape as $result) {
// Find data
$url = $xpath->evaluate(".//h2[@class='result__title']//a/@href", $result);
$title = $xpath->evaluate(".//h2[@class='result__title']", $result);
$description = $xpath->evaluate(".//a[@class='result__snippet']", $result);
// Skip broken results
if($url->length == 0) continue;
if($title->length == 0) continue;
// Process data
$url = sanitize($url[0]->textContent);
$title = strip_newlines(sanitize($title[0]->textContent));
$description = ($description->length == 0) ? "No description was provided for this site." : limit_string_length(strip_newlines(sanitize($description[0]->textContent)));
// filter duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, 'url'))) continue;
}
$engine_temp[] = array(
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'DuckDuckGo';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, $number_of_results, count($engine_temp));
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,100 +0,0 @@
<?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 GoogleRequest extends EngineRequest {
public function get_request_url() {
$url = 'https://www.google.com/search?'.http_build_query(array(
'q' => $this->search->query, // Search query
'oq' => $this->search->query, // (Original) Search query
'safe' => $this->search->safe, // Safe search (0 = off, 1 = moderate, 2 = on/strict)
'gl' => $this->opts->google_search_region, // Primarily search in this region
'num' => 50, // Number of results per page
'pws' => 0, // Personalized search (0 = off)
'udm' => 14, // A view for simpler/non-ai results
'complete' => '0', // Instant search (0 = off)
'source' => 'web', // Where are you searching from
'sclient' => 'gws-wiz' // Search client (Google currently seems to prefer 'gws-wiz' or 'gws-wiz-serp', previously 'web')
));
return $url;
}
public function get_request_headers() {
return array(
'Accept' => 'text/html, application/xhtml+xml, application/xml;q=0.8, */*;q=0.7',
);
}
public function parse_results($response) {
$engine_temp = $engine_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//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) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
foreach($scrape as $result) {
// Find data
$url = $xpath->evaluate(".//div[@class='yuRUbf']//a/@href", $result);
$title = $xpath->evaluate(".//h3", $result);
$description = $xpath->evaluate(".//div[contains(@class, 'VwiC3b')]", $result);
// Skip broken results
if($url->length == 0) continue;
if($title->length == 0) continue;
// Process data
$url = sanitize($url[0]->textContent);
$title = strip_newlines(sanitize($title[0]->textContent));
$description = ($description->length == 0) ? "No description was provided for this site." : limit_string_length(strip_newlines(sanitize($description[0]->textContent)));
// filter duplicate urls/results
if(!empty($engine_temp)) {
if(in_array($url, array_column($engine_temp, "url"))) continue;
}
$engine_temp[] = array(
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Google';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, $number_of_results, count($engine_temp));
unset($response, $xpath, $scrape, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

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

View file

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

View file

@ -1,98 +0,0 @@
<?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() {
// 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' => $this->search->query, // Search query
't' => 'web', // Type of search, web search
'safesearch' => $this->search->safe, // Safe search filter (0 = off, 1 = normal, 2 = strict)
'locale' => strtolower($this->opts->qwant_language), // In which language should the search be done
'count' => 10, // How many results? (Max 10)
'device' => 'desktop' // What kind of device are we searching from?
));
unset($query);
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_mess = $engine_result = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// Sort out the messy response from Qwant
foreach($json_response['data']['result']['items']['mainline'] as $mainline) {
if($mainline['type'] != 'web') continue;
foreach($mainline['items'] as $result) {
$engine_mess[] = $result;
}
unset($mainline, $result);
}
// Figure out results and base rank
$number_of_results = $rank = count($engine_mess);
// No results
if($number_of_results == 0 || $json_response['status'] == 'error') {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
foreach($engine_mess 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
if(!empty($engine_temp)) {
$engine_result['source'] = 'Qwant';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $number_of_results, count($engine_temp));
unset($response, $json_response, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,83 +0,0 @@
<?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 WikiRequest extends EngineRequest {
public function get_request_url() {
// Variables based on https://www.mediawiki.org/wiki/API:Search
$url = 'https://'.strtolower($this->opts->wikipedia_language).'.wikipedia.org/w/api.php?'.http_build_query(array(
'srsearch' => $this->search->query, // Search query
'action' => 'query', // Search type (via a query?)
'list' => 'search', // Full text search
'format' => 'json', // Return format (Must be json)
'srlimit' => 5 // How many search results to get, ideally as few as possible since it's just static wiki pages (max 500)
));
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)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// Figure out results and base rank
$number_of_results = $rank = ($json_response['query']['searchinfo']['totalhits'] > 20) ? 20 : $json_response['query']['searchinfo']['totalhits'];
// No results
if($number_of_results == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
foreach($json_response['query']['search'] as $result) {
// 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']))));
$engine_temp[] = array (
'title' => $title,
'url' => $url,
'description' => $description,
'engine_rank' => $rank
);
$rank -= 1;
}
// Base info
if(!empty($engine_temp)) {
$engine_result['source'] = 'Wikipedia';
$engine_result['search'] = $engine_temp;
}
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, $number_of_results, count($engine_temp));
unset($response, $json_response, $number_of_results, $rank, $engine_temp);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php <?php
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,37 +11,14 @@
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
class CurrencyRequest extends EngineRequest { class CurrencyRequest extends EngineRequest {
public function get_request_url() { public function get_request_url() {
$url = 'https://cdn.moneyconvert.net/api/latest.json'; return "https://cdn.moneyconvert.net/api/latest.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) { public function parse_results($response) {
$engine_result = array();
$json_response = json_decode($response, true); $json_response = json_decode($response, true);
// No response if(!empty($json_response)) {
if(empty($json_response)) { $result = $json_response['rates'];
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// No results
if(count($json_response['rates']) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0);
return $engine_result;
}
// Process query // Process query
// [0] = AMOUNT // [0] = AMOUNT
@ -49,32 +26,30 @@ class CurrencyRequest extends EngineRequest {
// [2] = (to|in) // [2] = (to|in)
// [3] = TO CURRENCY // [3] = TO CURRENCY
$amount = floatval($this->search->query_terms[0]); $query_terms = explode(" ", $this->query);
$amount_currency = strtoupper($this->search->query_terms[1]); $amount = floatval($query_terms[0]);
$conversion_currency = strtoupper($this->search->query_terms[3]); $amount_currency = strtoupper($query_terms[1]);
$last_update = the_date('M d, Y H:i', strtotime(sanitize($json_response['lastupdate']))); $conversion_currency = strtoupper($query_terms[3]);
// Unknown/misspelled currencies // Unknown/misspelled currencies
if(!array_key_exists($amount_currency, $json_response['rates']) || !array_key_exists($conversion_currency, $json_response['rates'])) { if (!array_key_exists($amount_currency, $result) || !array_key_exists($conversion_currency, $result)) {
return $engine_result; return array();
} }
// Calculate exchange rate // Calculate exchange rate
$conversion = round(($json_response['rates'][$conversion_currency] / $json_response['rates'][$amount_currency]) * $amount, 2); $conversion = round(($result[$conversion_currency] / $result[$amount_currency]) * $amount, 4);
$one_to_n = round(($json_response['rates'][$conversion_currency] / $json_response['rates'][$amount_currency]) * 1, 2);
// Return result return array(
$engine_result = array( "title" => "Currency conversion:",
'title' => "Currency conversion: ".$amount." ".$amount_currency." = ".$conversion." ".$conversion_currency, "text" => "$amount $amount_currency = $conversion $conversion_currency",
'text' => "<p>1 ".$amount_currency." = ".$one_to_n." ".$conversion_currency."</p><p><small>Updated: ".$last_update."</small></p>", "source" => "https://moneyconvert.net/"
'source' => "https://moneyconvert.net/"
); );
} else {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 1, 1); return array(
"title" => "Uh-oh...",
unset($response, $json_response, $amount, $amount_currency, $conversion, $one_to_n, $conversion_currency, $last_update); "text" => "No exchange rates could be loaded. Try again later."
);
return $engine_result; }
} }
} }
?> ?>

View file

@ -1,6 +1,6 @@
<?php <?php
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,89 +11,48 @@
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
class DefinitionRequest extends EngineRequest { class DefinitionRequest extends EngineRequest {
public function get_request_url() { public function get_request_url() {
// [0] = (define|meaning) $query_terms = explode(" ", $this->query);
// [0] = (define|d|mean|meaning)
// [1] = WORD // [1] = WORD
$url = 'https://api.dictionaryapi.dev/api/v2/entries/en/'.$this->search->query_terms[1];
return $url; return "https://api.dictionaryapi.dev/api/v2/entries/en/".$query_terms[1];
}
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) { public function parse_results($response) {
$engine_result = array();
$json_response = json_decode($response, true); $json_response = json_decode($response, true);
// No response if(!empty($json_response)) {
if(empty($json_response)) { // Word not found
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0); if (array_key_exists("title", $json_response)) {
return $engine_result; 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);
// No results // Word found
if(isset($json_response['title']) && $json_response['title'] == 'No Definitions Found') { $formatted_response = strip_tags(trim($result['meanings'][0]['partOfSpeech']))."<br /><ol class=\"word-definitions\">";
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No results', 0); foreach($definitions as $key => $def) {
return $engine_result; $formatted_response .= "<li>".strip_tags(trim($def['definition']))."</li>";
}
$result = $json_response[0]; // Always grab the first result
// Incomplete listing? Bail!
if(!array_key_exists('word', $result)) return $engine_result;
// 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>"; $formatted_response .= "</ol>";
unset($meaning); return array(
} "title" => strip_tags(trim($result['word']))." <span>[".strip_tags(trim($result['phonetic']))."]</span>",
"text" => $formatted_response,
// Return result "source" => strip_tags(trim($result['sourceUrls'][0]))
$engine_result = array(
'title' => "Definition for: ".sanitize($result['word'])." <span>[".sanitize($phonetic)."]</span>",
'text' => $formatted_response,
'source' => sanitize($result['sourceUrls'][0])
); );
} else {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 1, 1); return array(
"title" => "Whoops...",
unset($response, $json_response, $result, $phonetic, $definitions, $formatted_response); "text" => "No definitions could be loaded. Try again later."
);
return $engine_result; }
} }
} }
?> ?>

View file

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

View file

@ -1,56 +0,0 @@
<?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)) {
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 'No response', 0);
return $engine_result;
}
// Return 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'])."</p>",
'source' => "https://www.ipify.org/",
'note' => "Goosle is not a proxy server. Any website that you visit through Goosle Search Results will see your actual IP Address."
);
if($this->opts->querylog == 'on') querylog(get_class($this), 'a', $this->url, 1, 1);
unset($response, $json_response);
return $engine_result;
}
}
?>

View file

@ -1,6 +1,6 @@
<?php <?php
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -11,75 +11,37 @@
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
class PHPnetRequest extends EngineRequest { class PHPnetRequest extends EngineRequest {
public function get_request_url() { public function get_request_url() {
// Format query/url for php.net $this->query = str_replace("_", "-", str_replace("php ", "", $this->query));
$query = str_replace('_', '-', $this->search->query_terms[1]);
$url = 'https://www.php.net/manual/function.'.urlencode($query).'.php'; return "https://www.php.net/manual/function.".urlencode($this->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) { public function parse_results($response) {
$engine_result = array(); $results = array();
$xpath = get_xpath($response); $xpath = get_xpath($response);
// No response if($xpath) {
if(!$xpath) { // Scrape the page
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0); $title = $xpath->query("//div/section/div[@class='refentry']/div/h1[@class='refname']")[0]->textContent;
return $engine_result; 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;
// Scrape the results $response = array (
$scrape = $xpath->query("//div[@class='refentry']");
// No results
if(count($scrape) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
$query = str_replace('_', '-', $this->search->query_terms[1]);
// Process scrape
$title = $xpath->evaluate(".//div/h1[@class='refname']", $scrape[0]);
if($title->length == 0) return $engine_result;
$php_versions = $xpath->evaluate(".//div/p[@class='verinfo']", $scrape[0]);
$purpose = $xpath->evaluate(".//div/p[@class='refpurpose']", $scrape[0]);
$usage = $xpath->evaluate(".//div[@class='refsect1 description']/div[@class='methodsynopsis dc-description']", $scrape[0]);
$summary = $xpath->evaluate(".//div[@class='refsect1 description']/p[@class='para rdfs-comment']", $scrape[0]);
$title = sanitize($title[0]->textContent);
$php_versions = ($php_versions->length > 0) ? sanitize($php_versions[0]->textContent) : "";
$purpose = ($purpose->length > 0) ? sanitize($purpose[0]->textContent) : "";
$usage = ($usage->length > 0) ? sanitize($usage[0]->textContent) : "";
$summary = ($summary->length > 0) ? sanitize($summary[0]->textContent) : "";
// Clean up string
$usage = preg_replace(array('/\s{2,}/', '/[\t\n]/'), ' ', $usage);
// Return result
$engine_result = array (
// Required // Required
'title' => "Function: ".$title, "title" => sanitize($title),
'text' => "<p><em><small>".$php_versions."</small></em></p><p>".$purpose."</p><p>".highlight_string("<?php ".htmlspecialchars_decode($usage)." ?>", 1)."</p><p>".$summary."</p>", "text" => "<p>".$purpose." <em><small>".$php_versions."</small></em></p><p>".highlight_string("<?php ".trim($usage)." ?>", 1)."</p>",
'source' => "https://www.php.net/manual/function.".urlencode($query).".php", "source" => "https://www.php.net/manual/function.".urlencode($this->query)
'note' => "Description may be incomplete. Always check the documentation page for more information."
); );
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 1, 1); return $response;
} else {
unset($response, $xpath, $scrape); return array(
"title" => "Oof...",
return $engine_result; "text" => "PHP.net didn't provide any answers. Try again later."
);
}
} }
} }
?> ?>

View file

@ -0,0 +1,66 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class WikipediaRequest extends EngineRequest {
public function get_request_url() {
$query_terms = explode(" ", $this->query);
// [0] = (wiki|w)
// [1] = SEARCH TERM
unset($query_terms[0]); // Remove first item (w or wiki) from array and encode the rest for Wikipedia
$this->query = implode(" ", $query_terms);
return "https://wikipedia.org/w/api.php?format=json&action=query&prop=extracts%7Cpageimages&exintro&explaintext&redirects=1&pithumbsize=500&titles=".urlencode($this->query);
}
public function parse_results($response) {
$json_response = json_decode($response, true);
if(!empty($json_response)) {
$result = $json_response['query']['pages'];
// Abort on invalid response
if (!is_array($result)) return array();
// Grab first result if there are multiple
$result = $result[array_key_first($result)];
// Page not found
if (array_key_exists("missing", $result)) {
return array(
"title" => "Wiki page not found",
"text" => "Maybe the page doesn't exist. Try searching on Wikipedia with the link below or search for something else.",
"source" => "https://wikipedia.org/wiki/Special:Search?go=Go&search=".urlencode($this->query)
);
}
// Page found
$response = array(
"title" => strip_tags(trim($result['title'])),
"text" => strip_tags(trim($result['extract'])),
"source" => "https://wikipedia.org/wiki/".urlencode($this->query)
);
if (array_key_exists("thumbnail", $result)) {
$response['image'] = strip_tags(trim($result['thumbnail']['source']));
}
return $response;
} else {
return array(
"title" => "Sigh...",
"text" => "Wikipedia could not be loaded. Try again later."
);
}
}
}
?>

View file

@ -1,99 +0,0 @@
<?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 WordPressRequest extends EngineRequest {
public function get_request_url() {
// What are we looking for?
if($this->search->query_terms[1] == 'hook') {
// https://developer.wordpress.org/reference/hooks/HOOK_OR_FILTER_NAME/
$type = 'hooks';
$query = $this->search->query_terms[2];
} else {
// https://developer.wordpress.org/reference/functions/FUNCTION_NAME/
$type = 'functions';
$query = $this->search->query_terms[1];
}
$url = 'https://developer.wordpress.org/reference/'.$type.'/'.urlencode($query).'/';
unset($query, $type);
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_result = array();
$xpath = get_xpath($response);
// No response
if(!$xpath) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No response', 0);
return $engine_result;
}
// Scrape the results
$scrape = $xpath->query("//div/main/article");
// No results
if(count($scrape) == 0) {
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 'No results', 0);
return $engine_result;
}
if($this->search->query_terms[1] == 'hook') {
$type = 'hooks';
$query = $this->search->query_terms[2];
} else {
$type = 'functions';
$query = $this->search->query_terms[1];
}
// Process scrape
$usage = $xpath->evaluate(".//h1[@class='wp-block-wporg-code-reference-title']", $scrape[0]);
if($usage->length == 0) return $engine_result;
$purpose = $xpath->evaluate(".//section[@class='wp-block-wporg-code-reference-summary']", $scrape[0]);
$description = $xpath->evaluate(".//section[contains(@class, 'wp-block-wporg-code-reference-explanation')]/p[1]", $scrape[0]);
if($description->length == 0) $description = $xpath->evaluate(".//section[contains(@class, 'wp-block-wporg-code-reference-description')]/p[1]", $scrape[0]);
$introduced = $xpath->evaluate(".//section[@class='wp-block-wporg-code-reference-changelog']//tbody", $scrape[0]);
$title = sanitize($query);
$purpose = ($purpose->length > 0) ? sanitize($purpose[0]->textContent) : "";
$description = ($description->length > 0) ? sanitize($description[0]->textContent) : "";
$usage = ($usage->length > 0) ? sanitize($usage[0]->textContent) : "";
$introduced = ($introduced->length > 0) ? sanitize($introduced[0]->lastChild->firstElementChild->textContent) : "(Unknown)";
// Clean up string
$usage = preg_replace(array('/\s{2,}/', '/[\t\n]/'), ' ', $usage);
// Return result
$engine_result = array (
// Required
'title' => ucfirst($type).": ".$title,
'text' => "<p><em><small>Since WordPress ".$introduced."</small></em></p><p>".$purpose."</p><p>".highlight_string("<?php ".htmlspecialchars_decode($usage)." ?>", 1)."</p><p>".$description."</p>",
'source' => "https://developer.wordpress.org/reference/".$type."/".urlencode($query)."/",
'note' => "Description may be incomplete. Always check the documentation page for more information."
);
if($this->opts->querylog == 'on') querylog(get_class($this), 's', $this->url, 1, 1);
unset($response, $xpath, $scrape);
return $engine_result;
}
}
?>

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

@ -0,0 +1,147 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class LeetxRequest extends EngineRequest {
public function get_request_url() {
return "https://1337x.to/search/".urlencode($this->query)."/1/";
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
// Failed to load page
if(!$xpath) return $results;
$categories = array(
1 => "DVD",
2 => "Divx/Xvid",
3 => "SVCD/VCD",
4 => "Dubs/Dual Audio",
5 => "DVD",
6 => "Divx/Xvid",
7 => "SVCD/VCD",
9 => "Documentary",
10 => "PC Game",
11 => "PS2",
12 => "PSP",
13 => "Xbox",
14 => "Xbox360",
15 => "PS1",
16 => "Dreamcast",
17 => "Other (Gaming)",
18 => "PC Software",
19 => "Mac Software",
20 => "Linux Software",
21 => "Other (Software)",
22 => "MP3",
23 => "Lossless Audio",
24 => "DVD (Music)",
25 => "Music Video",
26 => "Radio",
27 => "Other (Audio)",
28 => "Anime",
33 => "Emulation",
34 => "Tutorials",
35 => "Sounds",
36 => "E-Books",
37 => "Images",
38 => "Mobile Phone",
39 => "Comics",
40 => "Other",
41 => "HD (Video)",
42 => "HD (Video)",
43 => "PS3",
44 => "Wii",
45 => "DS",
46 => "GameCube",
47 => "Nulled Script",
48 => "Video",
49 => "Picture",
50 => "Magazine",
51 => "Hentai",
52 => "Audiobook",
53 => "Album (Music)",
54 => "h.264/x264",
55 => "Mp4",
56 => "Android",
57 => "iOS",
58 => "Box Set (Music)",
59 => "Discography",
60 => "Single (Music)",
66 => "3D",
67 => "Games",
68 => "Concerts",
69 => "AAC (Music)",
70 => "HEVC/x265",
71 => "HEVC/x265",
72 => "3DS",
73 => "Bollywood",
74 => "Cartoon",
75 => "SD (Video)",
76 => "UHD",
77 => "PS4",
78 => "Dual Audio (Video)",
79 => "Dubbed (Video)",
80 => "Subbed",
81 => "Raw",
82 => "Switch",
);
// Scrape the page
foreach($xpath->query("//table/tbody/tr") as $result) {
$name = sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a", $result)[1]->textContent);
$seeders = sanitize($xpath->evaluate(".//td[@class='coll-2 seeds']", $result)[0]->textContent);
$leechers = sanitize($xpath->evaluate(".//td[@class='coll-3 leeches']", $result)[0]->textContent);
$size_unformatted = explode(" ", sanitize($xpath->evaluate(".//td[contains(@class, 'coll-4 size')]", $result)[0]->textContent));
$size = $size_unformatted[0] . " " . preg_replace("/[0-9]+/", "", $size_unformatted[1]);
$category = explode("/", sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a/@href", $result)[0]->textContent));
$category = $category[2];
$url = "https://1337x.to".sanitize($xpath->evaluate(".//td[@class='coll-1 name']/a/@href", $result)[1]->textContent);
$date_added = explode(" ", sanitize($xpath->evaluate(".//td[@class='coll-date']", $result)[0]->textContent));
$date_added = mktime(0, 0, 0, intval(date("m", strtotime($date_added[0]))), intval(preg_replace('/[^\d.]+/', '', $date_added[1])), intval('20'.preg_replace('/[^\d.]+/', '', $date_added[2])));
// Block these categories
if(in_array($category, $this->opts->leetx_categories_blocked)) continue;
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Required
"source" => "1337x.to",
"name" => $name,
"magnet" => "./engines/torrent/magnetize_1337x.php?url=".$url,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional values
"category" => $categories[$category],
"url" => $url,
"date_added" => $date_added
));
unset($name, $seeders, $leechers, $size_unformatted, $size, $category, $url, $date_added);
}
return $results;
}
}
?>

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

@ -0,0 +1,88 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class EZTVRequest extends EngineRequest {
public function get_request_url() {
// Make reasonably sure it's an IMDb id and abort if it's not
$query_terms = explode(" ", $this->query);
if(substr(strtolower($query_terms[0]), 0, 2) !== "tt") return "";
// Prepare a search query by stripping out everything but numbers and abort if nothing is left
$query = preg_replace('/[^0-9]/', '', $query_terms[0]);
if(strlen($query) == 0) return "";
// Is eztvx.to blocked for you? Use one of these urls as an alternative
// eztv1.xyz, eztv.wf, eztv.tf, eztv.yt
return "https://eztvx.to/api/get-torrents?imdb_id=".urlencode($query);
}
public function parse_results($response) {
$results = array();
$response = curl_multi_getcontent($this->ch);
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response['torrents_count'] == 0) return $results;
// Use API result
foreach ($json_response['torrents'] as $episode) {
$name = sanitize($episode['title']);
$magnet = sanitize($episode['magnet_url']);
$seeders = sanitize($episode['seeds']);
$leechers = sanitize($episode['peers']);
$size = sanitize($episode['size_bytes']);
// Find actual quality of episode
if(preg_match('/(480p|720p|1080p|2160p)/i', $name, $quality)) {
$quality = $quality[0];
} else {
$quality = "Unknown";
}
$date_added = sanitize($episode['date_released_unix']);
// Filter by Season (S01) or Season and Episode (S01E01)
$season = sanitize($episode['season']);
$episode = sanitize($episode['episode']);
if(preg_match_all("/(S[0-9]{1,3}|E[0-9]{1,3})/i", $this->query, $filter_episode)) {
if(str_ireplace("s0", "", $filter_episode[0][0]) != $season || (array_key_exists(1, $filter_episode[1]) && str_ireplace("e0", "", $filter_episode[0][1]) != $episode)) {
continue;
}
}
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Required
"source" => "EZTV",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => human_filesize($size),
// Optional
"quality" => $quality,
"date_added" => $date_added
));
unset($name, $magnet, $seeders, $leechers, $size, $quality, $category, $date_added, $season, $episode);
}
return $results;
}
}
?>

View file

@ -0,0 +1,48 @@
<?php
require "../../functions/tools.php";
$opts = require "../../config.php";
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST["url"]);
curl_setopt($ch, CURLOPT_HTTPGET, 1); // Redundant? Probably...
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $opts->user_agents[array_rand($opts->user_agents)]);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language: en-US,en;q=0.5',
'Upgrade-Insecure-Requests: 1'
));
curl_setopt($ch, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);
$xpath = get_xpath($response);
// No results
if(!$xpath) die();
$magnet = trim($xpath->query("//main/div/div/div/div/div/ul/li/a/@href")[0]->textContent);
header("Location: $magnet")
?>

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

@ -0,0 +1,63 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class NyaaRequest extends EngineRequest {
public function get_request_url() {
return "https://nyaa.si/?q=".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$xpath = get_xpath($response);
// Failed to load page
if(!$xpath) return $results;
// Scrape the page
foreach($xpath->query("//tbody/tr") as $result) {
$meta = $xpath->evaluate(".//td[@class='text-center']", $result);
$name = sanitize($xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@title", $result)[0]->textContent);
$magnet = sanitize($xpath->evaluate(".//a[2]/@href", $meta[0])[0]->textContent);
$seeders = sanitize($meta[3]->textContent);
$leechers = sanitize($meta[4]->textContent);
$size = sanitize($meta[1]->textContent);
$category = sanitize($xpath->evaluate(".//td[1]//a/@title", $result)[0]->textContent);
$url = sanitize($xpath->evaluate(".//td[@colspan='2']//a[not(contains(@class, 'comments'))]/@href", $result)[0]->textContent);
$date_added = sanitize($meta[2]->textContent);
$date_added = explode("-", substr($date_added, 0, 10));
$date_added = mktime(0, 0, 0, intval($date_added[1]), intval($date_added[2]), intval($date_added[0]));
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Required
"source" => "nyaa.si",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional values
"category" => str_replace(" - ", "/", $category),
"url" => "https://nyaa.si".$url,
"date_added" => $date_added
));
unset($name, $magnet, $seeders, $leechers, $size, $category, $url, $date_added, $meta);
}
return $results;
}
}
?>

View file

@ -0,0 +1,127 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class PirateBayRequest extends EngineRequest {
public function get_request_url() {
return "https://apibay.org/q.php?q=".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
$categories = array(
100 => "Audio",
101 => "Music",
102 => "Audio Book",
103 => "Sound Clips",
104 => "Audio FLAC",
199 => "Audio Other",
200 => "Video",
201 => "Movie",
202 => "Movie DVDr",
203 => "Music Video",
204 => "Movie Clip",
205 => "TV Show",
206 => "Handheld",
207 => "HD Movie",
208 => "HD TV Show",
209 => "3D Movie",
210 => "CAM/TS",
211 => "UHD/4K Movie",
212 => "UHD/4K TV Show",
299 => "Video Other",
300 => "Applications",
301 => "Apps Windows",
302 => "Apps Apple",
303 => "Apps Unix",
304 => "Apps Handheld",
305 => "Apps iOS",
306 => "Apps Android",
399 => "Apps Other OS",
400 => "Games",
401 => "Games PC",
402 => "Games Apple",
403 => "Games PSx",
404 => "Games XBOX360",
405 => "Games Wii",
406 => "Games Handheld",
407 => "Games iOS",
408 => "Games Android",
499 => "Games Other OS",
500 => "Porn",
501 => "Porn Movie",
502 => "Porn Movie DVDr",
503 => "Porn Pictures",
504 => "Porn Games",
505 => "Porn HD Movie",
506 => "Porn Movie Clip",
507 => "Porn UHD/4K Movie",
599 => "Porn Other",
600 => "Other",
601 => "Other E-Book",
602 => "Other Comic",
603 => "Other Pictures",
604 => "Other Covers",
605 => "Other Physibles",
699 => "Other Other"
);
// Use API result
foreach($json_response as $response) {
// Nothing found
if($response['name'] == "No results returned") break;
$name = sanitize($response['name']);
$magnet = "magnet:?xt=urn:btih:".sanitize($response['info_hash'])."&dn=".$name."&tr=".implode("&tr=", $this->opts->torrent_trackers);
$seeders = sanitize($response['seeders']);
$leechers = sanitize($response['leechers']);
$size = sanitize($response['size']);
$category = sanitize($response['category']);
$id = sanitize($response['id']);
$date_added = sanitize($response['added']);
// Block these categories
if(in_array($category, $this->opts->piratebay_categories_blocked)) continue;
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array(
// Required
"source" => "thepiratebay.org",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => human_filesize($size),
// Optional
"category" => $categories[$category],
"url" => "https://thepiratebay.org/description.php?id=".$id,
"date_added" => $date_added,
));
unset($name, $magnet, $seeders, $leechers, $size, $category, $id, $date_added);
}
return $results;
}
}
?>

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

@ -0,0 +1,84 @@
<?php
/* ------------------------------------------------------------------------------------
* Goosle - A meta search engine for private and fast internet fun.
*
* COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
*
* COPYRIGHT NOTICES AND ALL THE COMMENTS SHOULD REMAIN INTACT.
* By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use.
------------------------------------------------------------------------------------ */
class YTSRequest extends EngineRequest {
public function get_request_url() {
return "https://yts.mx/api/v2/list_movies.json?query_term=".urlencode($this->query);
}
public function parse_results($response) {
$results = array();
$response = curl_multi_getcontent($this->ch);
$json_response = json_decode($response, true);
// No response
if(empty($json_response)) return $results;
// Nothing found
if($json_response['status'] != "ok" || $json_response['data']['movie_count'] == 0) return $results;
// Use API result
foreach ($json_response['data']['movies'] as $movie) {
// Prevent gaps
if(!array_key_exists("year", $movie)) $movie['year'] = 0;
if(!array_key_exists("genres", $movie)) $movie['genres'] = array();
if(!array_key_exists("runtime", $movie)) $movie['runtime'] = 0;
if(!array_key_exists("url", $movie)) $movie['url'] = '';
// Block these categories
if(array_intersect($movie['genres'], $this->opts->yts_categories_blocked)) continue;
$name = sanitize($movie['title']);
$year = sanitize($movie['year']);
$category = sanitize(implode(', ', $movie['genres']));
$runtime = sanitize($movie['runtime']);
$url = sanitize($movie['url']);
$date_added = sanitize($movie['date_uploaded_unix']);
foreach ($movie['torrents'] as $torrent) {
$magnet = "magnet:?xt=urn:btih:".sanitize($torrent['hash'])."&dn=".urlencode($name)."&tr=".implode("&tr=", $this->opts->torrent_trackers);
$seeders = sanitize($torrent['seeds']);
$leechers = sanitize($torrent['peers']);
$size = sanitize($torrent['size']);
$quality = sanitize($torrent['quality']);
// Remove results with 0 seeders?
if($this->opts->show_zero_seeders == "off" AND $seeders == 0) continue;
array_push($results, array (
// Required
"source" => "yts.mx",
"name" => $name,
"magnet" => $magnet,
"seeders" => $seeders,
"leechers" => $leechers,
"size" => $size,
// Optional
"quality" => $quality,
"year" => $year,
"category" => $category,
"runtime" => $runtime,
"url" => $url,
"date_added" => $date_added
));
unset($magnet, $seeders, $leechers, $size, $quality);
}
unset($name, $year, $category, $runtime, $url, $date_added);
}
return $results;
}
}
?>

View file

@ -1,50 +0,0 @@
<?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.
------------------------------------------------------------------------------------ */
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
require ABSPATH.'functions/tools.php';
$opts = load_opts();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Goosle Search</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 search results!" />
<meta property="og:site_name" content="Goosle Search" />
<meta property="og:title" content="Goosle Search error page" />
<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); ?>/error.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); ?>/error.php" />
<link rel="stylesheet" type="text/css" href="<?php echo get_base_url($opts->siteurl); ?>/assets/css/styles.css"/>
<link rel="stylesheet" type="text/css" href="<?php echo get_base_url($opts->siteurl); ?>/assets/css/<?php echo $opts->colorscheme; ?>.css"/>
</head>
<body class="startpage">
<div class="auth-error">
<p>You can't use <span class="goosle-g">G</span>oosle without an authorization key!</p>
<p>Contact the website administrator for more information.</p>
</div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

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

View file

@ -1,6 +1,6 @@
<?php <?php
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -10,11 +10,12 @@
* liability that might arise from its use. * liability that might arise from its use.
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
abstract class EngineRequest { abstract class EngineRequest {
protected $ch, $mh, $search, $opts, $url, $headers; protected $url, $query, $opts, $mh, $ch;
function __construct($search, $opts, $mh) { function __construct($opts, $mh) {
$this->query = $opts->query;
$this->mh = $mh; $this->mh = $mh;
$this->search = $search; // Must be in this order :-/
$this->opts = $opts; $this->opts = $opts;
$this->url = $this->get_request_url(); $this->url = $this->get_request_url();
@ -22,52 +23,29 @@ abstract class EngineRequest {
if(!$this->url) return; if(!$this->url) return;
// Skip if there is a cached result (from earlier search) // 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, $this->opts->cache_time)) return; if($this->opts->cache == "on" && has_cached_results($this->url, $this->opts->hash)) return;
// Default headers for the curl request
$default_headers = array(
'Accept' => 'text/html, application/xhtml+xml, application/json;q=0.9, application/xml;q=0.8, */*;q=0.7',
'Accept-Language' => 'en-US,en;q=0.5',
'Accept-Encoding' => 'gzip, deflate',
// 'Connection' => 'keep-alive',
'Upgrade-Insecure-Requests' => '1',
'User-Agent' => $this->opts->user_agents[array_rand($this->opts->user_agents)],
'Sec-Fetch-Dest' => 'document',
'Sec-Fetch-Mode' => 'navigate',
'Sec-Fetch-Site' => 'none'
);
// Override or remove headers per curl request
$extra_headers = $this->get_request_headers();
if(count($extra_headers) > 0) {
$headers = array_filter(array_replace($default_headers, $extra_headers));
foreach($headers as $key => $value) {
$this->headers[] = $key.': '.$value;
}
unset($key, $value);
} else {
$this->headers = $default_headers;
}
unset($default_headers, $extra_headers);
// Curl // Curl
$this->ch = curl_init(); $this->ch = curl_init();
curl_setopt($this->ch, CURLOPT_URL, $this->url); curl_setopt($this->ch, CURLOPT_URL, $this->url);
curl_setopt($this->ch, CURLOPT_HTTPGET, 1); // Redundant? Probably... 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_SSL_VERIFYPEER, false);
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);
curl_setopt($this->ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($this->ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($this->ch, CURLOPT_TIMEOUT, 3);
curl_setopt($this->ch, CURLOPT_VERBOSE, false); curl_setopt($this->ch, CURLOPT_VERBOSE, false);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->ch, CURLOPT_USERAGENT, $this->opts->user_agents[array_rand($this->opts->user_agents)]);
curl_setopt($this->ch, CURLOPT_HTTPHEADER, array(
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language: en-US,en;q=0.5',
'Upgrade-Insecure-Requests: 1'
));
curl_setopt($this->ch, CURLOPT_ENCODING, "gzip,deflate");
curl_setopt($this->ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl_setopt($this->ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($this->ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP);
curl_setopt($this->ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($this->ch, CURLOPT_TIMEOUT, 3);
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, true);
if($mh) curl_multi_add_handle($mh, $this->ch); if($mh) curl_multi_add_handle($mh, $this->ch);
} }
@ -76,14 +54,14 @@ abstract class EngineRequest {
// Get search engine url // Get search engine url
--------------------------------------*/ --------------------------------------*/
public function get_request_url() { public function get_request_url() {
return ''; return "";
} }
/*-------------------------------------- /*--------------------------------------
// Check if a request to a search engine was successful // Check if a request to a search engine was successful
--------------------------------------*/ --------------------------------------*/
public function request_successful() { public function request_successful() {
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))) { if((isset($this->ch) && curl_getinfo($this->ch)['http_code'] == '200') || has_cached_results($this->url, $this->opts->hash)) {
return true; return true;
} }
@ -96,33 +74,122 @@ abstract class EngineRequest {
// Load search results // Load search results
--------------------------------------*/ --------------------------------------*/
public function get_results() { public function get_results() {
if(!isset($this->url)) {
return $this->parse_results(null); // It's a torrent search?
} if(!isset($this->url)) return $this->parse_results(null);
// If there is a cached result from an earlier search use that instead // 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, $this->opts->cache_time)) { if($this->opts->cache == "on" && has_cached_results($this->url, $this->opts->hash)) return fetch_cached_results($this->url, $this->opts->hash);
return fetch_cached_results($this->opts->cache_type, $this->opts->hash, $this->url);
}
// Curl request // Curl request
if(!isset($this->ch)) { if(!isset($this->ch)) return $this->parse_results(null);
return $this->parse_results(null);
}
$response = ($this->mh) ? curl_multi_getcontent($this->ch) : curl_exec($this->ch); $response = ($this->mh) ? curl_multi_getcontent($this->ch) : curl_exec($this->ch);
$results = $this->parse_results($response) ?? array(); $results = $this->parse_results($response) ?? array();
// Cache last request if there is something to cache // Cache last request
if($this->opts->cache_type !== 'off') { if($this->opts->cache == "on" && !empty($results)) store_cached_results($this->url, $this->opts->hash, $results, ($this->opts->cache_time * 60));
$ttl = ($this->search->type == 2) ? 1 : $this->opts->cache_time;
if(count($results) > 0) store_cached_results($this->opts->cache_type, $this->opts->hash, $this->url, $results, $ttl);
}
return $results; return $results;
} }
public static function print_results($results, $search, $opts) {} public static function print_results($results, $opts) {}
}
/*--------------------------------------
// Load and make config available, pass around variables
--------------------------------------*/
function load_opts() {
$opts = require "config.php";
// From the url/request
$opts->query = (isset($_REQUEST['q'])) ? sanitize($_REQUEST['q']) : "";
$opts->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : "";
// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
if(substr($opts->query, 0, 1) == "!") $opts->query = substr($opts->query, 1);
return $opts;
}
/*--------------------------------------
// Try to get some search results
--------------------------------------*/
function fetch_search_results($opts) {
$start_time = microtime(true);
echo "<section class=\"main-column\">";
if(!empty($opts->query)) {
// Curl
$mh = curl_multi_init();
// Load search script
if($opts->type == 0 || $opts->type == 1) {
require "engines/search.php";
$search = new TextSearch($opts, $mh);
} else if($opts->type == 2) {
require "engines/search-image.php";
$search = new ImageSearch($opts, $mh);
} else if($opts->type == 9) {
require "engines/search-torrent.php";
$search = new TorrentSearch($opts, $mh);
}
$running = null;
do {
curl_multi_exec($mh, $running);
} while ($running);
$results = $search->get_results();
curl_multi_close($mh);
// Add elapsed time to results
$results['time'] = number_format(microtime(true) - $start_time, 5, '.', '');
// Echoes results and special searches
$search->print_results($results, $opts);
} else {
echo "<div class=\"warning\">Search query can not be empty!<br />Not sure what went wrong? Learn more about <a href=\"./help.php?a=".$opts->hash."\">how to use Goosle</a>.</div>";
}
echo "</section>";
}
/*--------------------------------------
// Process special searches
--------------------------------------*/
function special_search_request($opts) {
$special_request = null;
$query_terms = explode(" ", $opts->query);
// 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 "engines/special/currency.php";
$special_request = new CurrencyRequest($opts, null);
}
// Dictionary
if($opts->special['definition'] == "on" && count($query_terms) == 2 && ($query_terms[0] == 'define' || $query_terms[0] == 'd' || $query_terms[0] == 'mean' || $query_terms[0] == 'meaning')) {
require "engines/special/definition.php";
$special_request = new DefinitionRequest($opts, null);
}
// Wikipedia search
if($opts->special['wikipedia'] == "on" && count($query_terms) >= 2 && ($query_terms[0] == 'wiki' || $query_terms[0] == 'w')) {
require "engines/special/wikipedia.php";
$special_request = new WikipediaRequest($opts, null);
}
// php.net search
if($opts->special['phpnet'] == "on" && count($query_terms) == 2 && $query_terms[0] == 'php') {
require "engines/special/php.php";
$special_request = new PHPnetRequest($opts, null);
}
return $special_request;
} }
?> ?>

View file

@ -1,289 +0,0 @@
<?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.
------------------------------------------------------------------------------------ */
/*--------------------------------------
// Magnet popup for movies and tv-shows
--------------------------------------*/
function highlight_popup($opts_hash, $highlight) {
$meta = $magnet_meta = array();
$search_query = urlencode($highlight['title']." ".$highlight['year']);
if(isset($highlight['category'])) $meta[] = "<strong>Genre:</strong> ".$highlight['category'];
if(isset($highlight['language'])) $meta[] = "<strong>Language:</strong> ".get_language($highlight['language']);
if(isset($highlight['year'])) $meta[] = "<strong>Released:</strong> ".$highlight['year'];
if(isset($highlight['rating'])) $meta[] = "<strong>Rating:</strong> ".movie_star_rating($highlight['rating'])." <small>(".$highlight['rating']." / 10)</small>";
if(isset($highlight['mpa_rating'])) $meta[] = "<strong>MPA Rating:</strong> ".movie_mpa_rating($highlight['mpa_rating']);
$output = "<div id=\"highlight-".$highlight['id']."\" class=\"goosebox\">";
$output .= " <div class=\"goosebox-body\">";
$output .= " <h2>".$highlight['title']."</h2>";
if(isset($highlight['summary'])) {
$output .= " <p>".$highlight['summary']."</p>";
}
$output .= " <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>";
if(!empty($meta)) {
$output .= " <p>".implode('<br />', $meta)."</p>";
}
unset($meta);
// List downloads
$output .= " <h3>Downloads:</h3>";
$output .= " <p>";
foreach($highlight['magnet_links'] as $magnet) {
if(isset($magnet['quality'])) $magnet_meta[] = $magnet['quality'];
if(isset($magnet['audio'])) $magnet_meta[] = $magnet['audio'];
if(isset($magnet['type'])) $magnet_meta[] = $magnet['type'];
$magnet_meta[] = human_filesize($magnet['filesize']);
$output .= "<button class=\"download\" onclick=\"location.href='".$magnet['magnet']."'\">".implode(' / ', $magnet_meta)."</button>";
unset($magnet_meta);
}
$output .= " </p>";
$output .= " <p><a onclick=\"closepopup()\">Close</a></p>";
$output .= " </div>";
$output .= "</div>";
unset($highlight, $magnet, $magnet_meta);
return $output;
}
/*--------------------------------------
// Detect NSFW results by keywords in the title
// True = nsfw, false = not nsfw
--------------------------------------*/
function detect_nsfw($string) {
$string = strtolower($string);
// Forbidden terms
//Basic pattern: ^cum[-_\s]?play(ing|ed|s)?
$nsfw_keywords = array(
'/(deepthroat|gangbang|cowgirl|dildo|fuck|cuckold|anal|hump|finger|pegg|fist|ballbust|twerk|dogg|squirt|dick|orgasm)(ing|ed|s)?/',
'/(yaoi|porn|gonzo|erotica|blowbang|bukkake|gokkun|softcore|hardcore|latex|lingerie|interracial|bdsm|chastity|kinky|bondage|shibari|hitachi|upskirt)/',
'/(cock|creampie|cameltoe|enema|nipple|sybian|vibrator|cougar|threesome|foursome|pornstar|escort)(s)?/',
'/(cmnf|cfnm|pov|cbt|bbw|pawg|ssbbw|joi|cei)/',
'/(blow|rim|foot|hand)job(s)?/',
'/(org|puss)(y|ies)\s?/',
'/hentai(ed)?/',
'/jerk(ing)?[-_\s]?off/',
'/tw(i|u)nk(s)?/',
'/cum(bot|ming|s)?/',
'/porn(hub)?|xhamster|youporn|faphouse|sexually(\s)?broken|adulttime|transfixed|tsseduction|waterbondage|fuckingmachines|monstersofcock|deeplush|hotandmean|onlyfans|fansly|manyvids|transangels|premiumhdv|genderx|evil(\s)?angel|thetrainingofo|rocco(\s)?siffredi|electrosluts|ultimatesurrender|whippedass|insex|herlimit|analdays|bangbus|faketaxi|horrorporn|neighboraffair|naughtybookworms|sexandsubmission|housewife1on1|devicebondage|tspussyhunters|everythingbutt|theupperfloor|public(\s)?disgrace|fuckedandbound|alterotic|divinebitches|wiredpussy/',
'/(m|g)ilf(s)?/',
'/clit(oris|s)?/',
'/tit(ties|s)/',
'/strap[-_\s]?on(ed|s)?/',
'/webcam(ming|s)?/',
'/doggy(style)?/',
'/(masturbat|penetrat)(e|ion|ing|ed)/',
'/face(fuck|sit)?(ing|ting|ed|s)?/',
'/(gap|scissor)(e|ing|ed)?/',
'/(fetish|penis|ass)(es)?/',
'/(fem|lez|male)dom/',
'/futa(nari)?/',
'/(slave|pet)[-_\s]?play(ing|ed|s)?/',
'/submissive(d|s)?/',
'/tied[-_\s]?(up)?/',
'/glory[-_\s]?hole(d|s)?/',
'/swing(er|ers|ing)?/',
);
// Replace everything but alphanumeric with a space
$string = preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', $string);
preg_replace($nsfw_keywords, '*', $string, -1 , $count);
return ($count > 0) ? true : false;
}
/*--------------------------------------
// 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));
}
if(count($return) > 0) return implode(' ', $return);
return null;
}
/*--------------------------------------
// 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)));
}
if(count($return) > 0) return implode(' ', $return);
return null;
}
/*--------------------------------------
// 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;
}
/*--------------------------------------
// Create visual MPA rating for some magnet results
--------------------------------------*/
function movie_mpa_rating($rating) {
// As described here: https://en.wikipedia.org/wiki/Motion_Picture_Association_film_rating_system
if($rating == "G") {
$rating = "<span class=\"mpa-g\"><strong>G - General Audiences</strong></span> &bull; <em>Suitable for all ages.</em>";
} else if("PG") {
$rating = "<span class=\"mpa-pg\"><strong>PG - Parental Guidance Suggested</strong></span> &bull; <em>May not be suitable for children.</em>";
} else if("PG-13") {
$rating = "<span class=\"mpa-pg13\"><strong>PG-13 - Parents Strongly Cautioned</strong></span> &bull; <em>May be inappropriate for children under 13.</em>";
} else if("R") {
$rating = "<span class=\"mpa-r\"><strong>R - Restricted</strong></span> &bull; <em>Persons under 17 require accompanying adult.</em>";
} else if("NC-17") {
$rating = "<span class=\"mpa-nc17\"><strong>NC-17 - Adults Only</strong></span> &bull; <em>Not suitable for persons under 17.</em>";
} else {
$rating = "<span>".$rating."</span>";
}
return $rating;
}
/*--------------------------------------
// Return the language based on the ISO name
--------------------------------------*/
function get_language($string) {
$languages = array("ab" => "Abkhaz", "aa" => "Afar", "af" => "Afrikaans", "ak" => "Akan", "sq" => "Albanian", "am" => "Amharic", "ar" => "Arabic", "an" => "Aragonese", "hy" => "Armenian", "as" => "Assamese", "av" => "Avaric", "ae" => "Avestan", "ay" => "Aymara", "az" => "Azerbaijani", "bm" => "Bambara", "ba" => "Bashkir", "eu" => "Basque", "be" => "Belarusian", "bn" => "Bengali", "bh" => "Bihari", "bi" => "Bislama", "bs" => "Bosnian", "br" => "Breton", "bg" => "Bulgarian", "my" => "Burmese", "ca" => "Catalan", "ch" => "Chamorro", "ce" => "Chechen", "ny" => "Nyanja", "zh" => "Chinese", "cn" => "Chinese", "cv" => "Chuvash", "kw" => "Cornish", "co" => "Corsican", "cr" => "Cree", "hr" => "Croatian", "cs" => "Czech", "da" => "Danish", "dv" => "Maldivian;", "nl" => "Dutch", "en" => "English", "eo" => "Esperanto", "et" => "Estonian", "ee" => "Ewe", "fo" => "Faroese", "fj" => "Fijian", "fi" => "Finnish", "fr" => "French", "ff" => "Fulah", "gl" => "Galician", "ka" => "Georgian", "de" => "German", "el" => "Greek, Modern", "gn" => "Guaraní", "gu" => "Gujarati", "ht" => "Haitian Creole", "ha" => "Hausa", "he" => "Hebrew (modern)", "hz" => "Herero", "hi" => "Hindi", "ho" => "Hiri Motu", "hu" => "Hungarian", "ia" => "Interlingua", "id" => "Indonesian", "ie" => "Interlingue", "ga" => "Irish", "ig" => "Igbo", "ik" => "Inupiaq", "io" => "Ido", "is" => "Icelandic", "it" => "Italian", "iu" => "Inuktitut", "ja" => "Japanese", "jv" => "Javanese", "kl" => "Kalaallisut", "kn" => "Kannada", "kr" => "Kanuri", "ks" => "Kashmiri", "kk" => "Kazakh", "km" => "Khmer", "ki" => "Kikuyu", "rw" => "Kinyarwanda", "ky" => "Kirghiz, Kyrgyz", "kv" => "Komi", "kg" => "Kongo", "ko" => "Korean", "ku" => "Kurdish", "kj" => "Kwanyama", "la" => "Latin", "lb" => "Luxembourgish", "lg" => "Luganda", "li" => "Limburgish, Limburgan, Limburger", "ln" => "Lingala", "lo" => "Lao", "lt" => "Lithuanian", "lu" => "Luba-Katanga", "lv" => "Latvian", "gv" => "Manx", "mk" => "Macedonian", "mg" => "Malagasy", "ms" => "Malay", "ml" => "Malayalam", "mt" => "Maltese", "mi" => "Māori", "mr" => "Marathi", "mh" => "Marshallese", "mn" => "Mongolian", "na" => "Nauru", "nv" => "Navajo, Navaho", "nb" => "Norwegian Bokmål", "nd" => "North Ndebele", "ne" => "Nepali", "ng" => "Ndonga", "nn" => "Norwegian Nynorsk", "no" => "Norwegian", "ii" => "Nuosu", "nr" => "South Ndebele", "oc" => "Occitan", "oj" => "Ojibwe, Ojibwa", "cu" => "Old Slavonic", "om" => "Oromo", "or" => "Oriya", "os" => "Ossetian", "pa" => "Punjabi", "pi" => "Pāli", "fa" => "Persian", "pl" => "Polish", "ps" => "Pashto, Pushto", "pt" => "Portuguese", "qu" => "Quechua", "rm" => "Romansh", "rn" => "Kirundi", "ro" => "Romanian", "ru" => "Russian", "sa" => "Sanskrit", "sc" => "Sardinian", "sd" => "Sindhi", "se" => "Northern Sami", "sm" => "Samoan", "sg" => "Sango", "sr" => "Serbian", "gd" => "Gaelic", "sn" => "Shona", "si" => "Sinhala", "sk" => "Slovak", "sl" => "Slovene", "so" => "Somali", "st" => "Southern Sotho", "es" => "Spanish", "su" => "Sundanese", "sw" => "Swahili", "ss" => "Swati", "sv" => "Swedish", "ta" => "Tamil", "te" => "Telugu", "tg" => "Tajik", "th" => "Thai", "ti" => "Tigrinya", "bo" => "Tibetan Standard, Tibetan, Central", "tk" => "Turkmen", "tl" => "Tagalog", "tn" => "Tswana", "to" => "Tonga", "tr" => "Turkish", "ts" => "Tsonga", "tt" => "Tatar", "tw" => "Twi", "ty" => "Tahitian", "ug" => "Uighur, Uyghur", "uk" => "Ukrainian", "ur" => "Urdu", "uz" => "Uzbek", "ve" => "Venda", "vi" => "Vietnamese", "vo" => "Volapük", "wa" => "Walloon", "cy" => "Welsh", "wo" => "Wolof", "fy" => "Western Frisian", "xh" => "Xhosa", "yi" => "Yiddish", "yo" => "Yoruba", "za" => "Zhuang, Chuang");
return $languages[$string];
}
/*--------------------------------------
// 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

@ -1,6 +1,6 @@
<?php <?php
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -10,236 +10,21 @@
* liability that might arise from its use. * liability that might arise from its use.
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
// Current Goosle version
$current_version = '1.7';
/*-------------------------------------- /*--------------------------------------
// Verify the hash, or not, and let people in, or not // Verify the hash, or not, and let people in, or not
--------------------------------------*/ --------------------------------------*/
function verify_hash($use_hash, $hash, $auth, $is_shared = null) { function verify_hash($opts, $auth) {
if(($use_hash == 'on' && strtolower($hash) === strtolower($auth)) || $use_hash == 'off' || !empty($is_shared)) return true; if(($opts->hash_auth == "on" && strtolower($opts->hash) === strtolower($auth)) || $opts->hash_auth == "off") return true;
return false; return false;
} }
/*--------------------------------------
// Load and make config available, pass around variables
--------------------------------------*/
function load_opts() {
$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 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
$opts->user_auth = (isset($_REQUEST['a'])) ? sanitize($_REQUEST['a']) : '';
$opts->pixel = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
// Force a few defaults and safeguards
if($opts->cache_type == 'file' && !is_dir(ABSPATH.'cache/')) $opts->cache_type = 'off';
if($opts->cache_type == 'apcu' && !function_exists('apcu_exists')) $opts->cache_type = 'off';
if($opts->cache_type == 'apcu' && !function_exists('apcu_exists')) $opts->cache_type = 'off';
if($opts->cache_time < 1 || ($opts->cache_type == 'apcu' && $opts->cache_time > 8) || ($opts->cache_type == 'file' && $opts->cache_time > 48)) $opts->cache_time = 8;
if(!is_numeric($opts->search_results_per_page) || ($opts->search_results_per_page < 8 || $opts->search_results_per_page > 160)) $opts->social_media_relevance = 24;
if(!is_numeric($opts->social_media_relevance) || ($opts->social_media_relevance > 10 || $opts->social_media_relevance < 0)) $opts->social_media_relevance = 8;
// Disable the search type if no engines available
if($opts->web['duckduckgo'] == 'off' && $opts->web['mojeek'] == 'off' && $opts->web['qwant'] == 'off' && $opts->web['google'] == 'off' && $opts->web['brave'] == 'off' && $opts->web['wikipedia'] == 'off') $opts->enable_web_search = 'off';
if($opts->image['yahooimages'] == 'off' && $opts->image['qwantimages'] == 'off' && $opts->image['pixabay'] == 'off' && $opts->image['openverse'] == 'off') $opts->enable_image_search = 'off';
if($opts->news['qwantnews'] == 'off' && $opts->news['yahoonews'] == 'off' && $opts->news['bravenews'] == 'off' && $opts->news['hackernews'] == 'off') $opts->enable_news_search = 'off';
if($opts->magnet['limetorrents'] == 'off' && $opts->magnet['piratebay'] == 'off' && $opts->magnet['nyaa'] == 'off' && $opts->magnet['sukebei'] == 'off' && $opts->magnet['yta'] == 'off' && $opts->magnet['eztv'] == 'off') $opts->enable_magnet_search = 'off';
return $opts;
}
}
/*--------------------------------------
// Process search query
--------------------------------------*/
function load_search() {
$search = new stdClass();
// From the url/request
if(!isset($_REQUEST['s'])) {
// Regular search
$search->query = (isset($_REQUEST['q'])) ? trim($_REQUEST['q']) : '';
$search->type = (isset($_REQUEST['t'])) ? sanitize($_REQUEST['t']) : 0;
$search->share = null;
} else {
// Shared result
$share_string = explode('||', base64_url_decode(sanitize($_REQUEST['s'])));
if(is_array($share_string) && count($share_string) === 3) {
$search->query = sanitize($share_string[0]);
$search->type = sanitize($share_string[1]);
$search->share = sanitize($share_string[2]);
} else {
$search->query = '';
$search->type = 0;
$search->share = null;
}
unset($share_string);
}
// Set pagination page
$search->page = (isset($_REQUEST['p'])) ? sanitize($_REQUEST['p']) : 1;
// Remove ! at the start of queries to prevent DDG Bangs (!g, !c and crap like that)
if(substr($search->query, 0, 1) == '!') $search->query = substr($search->query, 1);
// Preserve quotes
$search->query = str_replace('%22', '\"', $search->query);
// Special searches and filters
$search->query_terms = explode(' ', strtolower($search->query)); // Break up query
$search->count_terms = count($search->query_terms); // How many keywords?
// Safe search override
// 0 = off, 1 = normal (default), 2 = on/strict
$search->safe = 1;
if($search->query_terms[0] == 'safe:on') {
$search->safe = 2;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
if($search->query_terms[0] == 'safe:off' || $search->query_terms[0] == 'nsfw') {
$search->safe = 0;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
// Size search override (For image search only)
// 0 = all, 1 = small, 2 = medium, 3 = large, 4 extra large
$search->size = 0;
if($search->type == 1) {
if($search->query_terms[0] == 'size:small') {
$search->size = 1;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
if($search->query_terms[0] == 'size:medium') {
$search->size = 2;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
if($search->query_terms[0] == 'size:large') {
$search->size = 3;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
if($search->query_terms[0] == 'size:xlarge') {
$search->size = 4;
$search->query = trim(str_replace($search->query_terms[0], '', $search->query));
}
}
// Create a 'human-readable' and Urlencoded query
$search->nice_query = $search->query;
$search->query = urlencode($search->query);
// Maybe count stats?
if(!empty($search->query)) count_stats();
return $search;
}
/*--------------------------------------
// Do some stats
--------------------------------------*/
function load_stats() {
$stats_file = ABSPATH.'cache/stats.data';
if(!is_file($stats_file)) {
// Create stats file if it doesn't exist
$stats = array('started' => mktime(0, 0, 0, date('m'), date('d'), date('Y')), 'days_active' => 0, 'all_queries' => 0, 'avg_per_day' => 0);
file_put_contents($stats_file, serialize($stats));
} else {
// Get stats
$stats = unserialize(file_get_contents($stats_file));
}
return $stats;
}
function count_stats() {
$stats = load_stats();
// Calculate average searches per day
$new_day = (mktime(0, 0, 0, date('m'), date('d'), date('Y')) - $stats['started']) / 86400;
if($new_day > $stats['days_active']) {
$stats['days_active'] = $stats['days_active'] + 1;
$stats['avg_per_day'] = $stats['all_queries'] / $stats['days_active'];
}
// Count query
$stats['all_queries'] = $stats['all_queries'] + 1;
// Save stats
$stats_file = ABSPATH.'cache/stats.data';
file_put_contents($stats_file, serialize($stats));
}
/*--------------------------------------
// Show update notification in footer
--------------------------------------*/
function show_update_notification() {
global $current_version;
$version_file = ABSPATH.'cache/version.data';
if(is_file($version_file)) {
// Get version information
$version = unserialize(file_get_contents($version_file));
// Check if a newer version is available and add it to the version display
if(version_compare($current_version, $version['latest'], '<')) {
return "<a href=\"".$version['url']."\" target=\"_blank\" class=\"update\">Version ".$version['latest']." is available!</a>";
}
}
}
/*--------------------------------------
// 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();
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);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
/*-------------------------------------- /*--------------------------------------
// Load pages into a DOM // Load pages into a DOM
--------------------------------------*/ --------------------------------------*/
function get_xpath($response) { function get_xpath($response) {
if(!$response) return null; if(!$response)
return null;
$htmlDom = new DOMDocument; $htmlDom = new DOMDocument;
@$htmlDom->loadHTML($response); @$htmlDom->loadHTML($response);
@ -249,327 +34,69 @@ function get_xpath($response) {
} }
/*-------------------------------------- /*--------------------------------------
// Get Goosle's base url // Strip all extras from an url
--------------------------------------*/ --------------------------------------*/
function get_base_url($siteurl) { function get_base_url($url) {
// Figure out server protocol $url = parse_url($url);
$protocol = empty($_SERVER['HTTPS']) ? 'http' : 'https';
return $protocol.'://'.$siteurl; return $url['scheme'] . "://" . $url['host'] . "/";
}
/*--------------------------------------
// URL Safe base64 encoding and decoding
--------------------------------------*/
function base64_url_encode($input) {
return strtr(base64_encode($input), '+/=', '-_.');
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_.', '+/='));
}
/*--------------------------------------
// Result Caching
--------------------------------------*/
function has_cached_results($cache_type, $hash, $url, $ttl) {
$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(is_file($cache_file)) {
if(filemtime($cache_file) >= (time() - $ttl)) {
return true;
}
}
}
return false;
}
function store_cached_results($cache_type, $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';
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 == 'file') {
$cache_file = ABSPATH.'cache/'.md5($hash.':'.$url).'.result';
if(is_file($cache_file)) {
return unserialize(file_get_contents($cache_file));
}
}
return array();
}
function delete_cached_results($ttl) {
$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);
// Only delete cache files (*.result)
if($file == '.' OR $file == '..' OR $extension != 'result') continue;
// Delete if expired
if(filemtime($folder.$file) < (time() - $ttl)) {
unlink($folder.$file);
}
}
closedir($handle);
}
}
}
/*--------------------------------------
// 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));
}
}
/*--------------------------------------
// Log requests
--------------------------------------*/
function querylog($engine, $type, $request_url, $scraped_results, $final_results) {
$log_file = ABSPATH.'cache/querylog_'.the_date('d_m_Y').'.log';
file_put_contents($log_file, '['.the_date('d-m-Y H:i:s').']['.$type.'] '.$engine.': '.$scraped_results.' -> '.$final_results.', '.$request_url."\n", FILE_APPEND);
}
/*--------------------------------------
// Sanitize/format variables
--------------------------------------*/
function sanitize($variable) {
switch(gettype($variable)) {
case 'string':
$variable = htmlspecialchars(trim($variable), ENT_QUOTES);
break;
case 'integer':
$variable = preg_replace('/[^0-9]/', '', $variable);
if(strlen($variable) == 0) $variable = 0;
break;
case 'boolean':
$variable = ($variable === FALSE) ? 0 : 1;
break;
default:
$variable = ($variable === NULL) ? 'NULL' : htmlspecialchars(strip_tags(trim($variable)), ENT_QUOTES);
break;
}
return $variable;
}
function strip_newlines($string) {
return preg_replace('/<br>|\n/', '', $string);
}
function limit_string_length($string, $length = 200, $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;
}
/*--------------------------------------
// Count matching keywords between result and search query
--------------------------------------*/
function match_count($result_terms, $query_terms, $multiplier = 1) {
if(empty($result_terms)) return 0;
if(!is_array($result_terms)) {
$result_terms = make_tags_from_string($result_terms);
}
$matches = array_intersect($result_terms, $query_terms);
$matches = count($matches) * $multiplier;
return $matches;
}
/*--------------------------------------
// Turn a string (title or something) into an array of words (tags)
--------------------------------------*/
function make_tags_from_string($string) {
if(empty($string)) return array();
$string = strtolower($string);
// Replace anything but alphanumeric with a space
$string = preg_replace('/\s{2,}|[^a-z0-9]+/', ' ', $string);
$keywords = array_filter(array_unique(explode(' ', $string)));
// Get rid of short words and letters
foreach($keywords as $k => $word) {
if(strlen($word) < 3) unset($keywords[$k]);
}
// Get rid of filler words (English)
$filler_words = array('and', 'ago', 'but', 'for', 'get', 'gets', 'have', 'haves', 'has', 'into', 'nor', 'off', 'onto', 'the', 'with', 'yet');
$keywords = array_diff($keywords, $filler_words);
return $keywords;
}
/*--------------------------------------
// Output and format dates in local time
--------------------------------------*/
function the_date($format, $timestamp = null) {
global $opts;
$offset = preg_replace('/UTC\+?/i', '', $opts->timezone);
if(empty($offset)) $offset = 0;
if(is_null($timestamp) || !is_numeric($timestamp)) $timestamp = time();
$hours = (int) $offset;
$minutes = ($offset - $hours);
$sign = ($offset < 0) ? '-' : '+';
$abs_hour = abs($hours);
$abs_mins = abs($minutes * 60);
$datetime = date_create('@'.$timestamp);
$datetime->setTimezone(new DateTimeZone(sprintf('%s%02d:%02d', $sign, $abs_hour, $abs_mins)));
return $datetime->format($format);
}
/*--------------------------------------
// Detect social media results
--------------------------------------*/
function detect_social_media($string) {
$string = strtolower($string);
// (Some) Based on regexes from https://github.com/lorey/social-media-profiles-regexs
$social_media = array(
'/(?:facebook|fb)\.com\/([A-z0-9_\-\.]+)\/?/',
'/(?:instagram\.com|instagr\.am)\/([A-Za-z0-9_])/',
'/twitter\.com\/@?([A-z0-9_]+)(\/status\/[0-9]+)?\/?/',
'/x\.com\/@?([A-z0-9_]+)(\/status\/[0-9]+)?\/?/',
'/reddit\.com\/(u|r)?(ser)?\/([A-z0-9\-\_]*)\/?/',
'/snapchat\.com\/add\/([A-z0-9\.\_\-]+)\/?/',
'/tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video)\/|\?shareId=|\&item_id=)(\d+))|\w+)/',
'/linkedin\.com\/(company|school)\/([A-z0-9-À-ÿ\.]+)\/?/',
'/linkedin\.com\/feed\/update\/urn:li:activity:([0-9]+)\/?/',
'/linkedin\.com\/in\/([\w\-\_À-ÿ%]+)\/?/',
'/youtube\.com\/c?(hannel)?\/([A-z0-9-\_]+)\/?/',
'/youtube\.com\/u?(ser)?\/([A-z0-9]+)\/?/',
'/youtube\.com\/(watch\?v=|embed\/|youtu\.be\/)([A-z0-9\-\_]+)/'
);
preg_replace($social_media, '*', $string, -1 , $count);
return ($count > 0) ? true : false;
}
/*--------------------------------------
// Count and format search sources
--------------------------------------*/
function search_sources($results) {
$sources = array();
foreach($results as $source => $amount) {
$plural = ($amount > 1) ? 'results' : 'result';
$sources[] = $amount.' '.$plural.' from '.$source;
}
$sources = replace_last_comma(implode(', ', $sources));
$sources = 'Includes '.$sources.'.';
return $sources;
} }
/*-------------------------------------- /*--------------------------------------
// Format search result urls // Format search result urls
--------------------------------------*/ --------------------------------------*/
function search_formatted_url($url) { function get_formatted_url($url) {
$url = parse_url(strtolower($url)); $url = parse_url($url);
$formatted_url = $url['scheme'] . '://' . $url['host']; return $url['scheme'] . "://" . $url['host'] . str_replace('/', ' &rsaquo; ', str_replace('%20', ' ', rtrim($url['path'], '/')));
if(array_key_exists('path', $url)) {
$formatted_url .= str_replace('/', ' &rsaquo; ', urldecode(str_replace('%20', ' ', rtrim($url['path'], '/'))));
}
if(array_key_exists('query', $url)) {
$formatted_url .= ' &rsaquo; '.urldecode(str_replace('&', ' &rsaquo; ', str_replace('=', ':', str_replace('%20', ' ', trim($url['query'])))));
}
return $formatted_url;
} }
/*-------------------------------------- /*--------------------------------------
// Results pagination // APCu Caching
--------------------------------------*/ --------------------------------------*/
function search_pagination($search, $opts, $number_of_results) { function has_cached_results($url, $hash) {
$number_of_pages = ceil($number_of_results / $opts->search_results_per_page); if(function_exists("apcu_exists")) {
return apcu_exists("$hash:$url");
$pagination = "";
if($search->page > 1) {
$prev = $search->page - 1;
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".$search->query."&t=".$search->type."&a=".$opts->hash."&p=".$prev."\" title=\"Previous page\"><span class=\"arrow-left\"></span></a> ";
} }
for($page = 1; $page <= $number_of_pages; $page++) { return false;
$class = ($search->page == $page) ? "current" : ""; }
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".$search->query."&t=".$search->type."&a=".$opts->hash."&p=".$page."\" class=\"".$class."\" title=\"To page ".$page."\">".$page."</a> ";
function store_cached_results($url, $hash, $results, $ttl = 0) {
if(function_exists("apcu_store") && !empty($results)) {
return apcu_store("$hash:$url", $results, $ttl);
}
}
function fetch_cached_results($url, $hash) {
if(function_exists("apcu_fetch")) {
return apcu_fetch("$hash:$url");
} }
if($search->page < $number_of_pages) { return array();
$next = $search->page + 1;
$pagination .= "<a href=\"".get_base_url($opts->siteurl)."/results.php?q=".$search->query."&t=".$search->type."&a=".$opts->hash."&p=".$next."\" title=\"Next page\"><span class=\"arrow-right\"></span></a> ";
}
return $pagination;
} }
/*-------------------------------------- /*--------------------------------------
// Find and replace the last comma in a string // Sanitize variables
--------------------------------------*/ --------------------------------------*/
function replace_last_comma($string) { function sanitize($thing) {
$last_comma = strrpos($string, ', '); switch(gettype($thing)) {
if($last_comma !== false) { case 'string':
$string = substr_replace($string, ' and ', $last_comma, 2); $thing = stripslashes(strip_tags(trim($thing)));
break;
case 'boolean':
$thing = ($thing === FALSE) ? 0 : 1;
break;
default:
$thing = ($thing === NULL) ? 'NULL' : strip_tags(trim($thing));
break;
} }
return $string; return $thing;
} }
/*-------------------------------------- /*--------------------------------------
// Human readable file sizes from bytes // Human readable file sizes
--------------------------------------*/ --------------------------------------*/
function human_filesize($bytes, $dec = 2) { function human_filesize($bytes, $dec = 2) {
$size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); $size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
@ -578,55 +105,22 @@ function human_filesize($bytes, $dec = 2) {
return sprintf("%.{$dec}f ", $bytes / pow(1024, $factor)) . @$size[$factor]; return sprintf("%.{$dec}f ", $bytes / pow(1024, $factor)) . @$size[$factor];
} }
/*--------------------------------------
// Turn a string size (600 MB) into bytes (int)
--------------------------------------*/
function filesize_to_bytes($num) {
preg_match('/(b|kb|mb|gb|tb|pb|eb|zb|yb)/', strtolower($num), $match);
$num = floatval(preg_replace('/[^0-9.]+/', '', $num));
$match = $match[0];
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 {
$num = $num;
}
return intval($num);
}
/*-------------------------------------- /*--------------------------------------
// Generate random strings for passwords // Generate random strings for passwords
--------------------------------------*/ --------------------------------------*/
function string_generator($length, $separator) { function string_generator() {
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$password = array(); $password = array();
$rand = strlen($characters) - 1; $length = strlen($characters) - 1;
for($i = 0; $i < $length; $i++) { for ($i = 0; $i < 24; $i++) {
$n = rand(0, $rand); $n = rand(0, $length);
$password[] = $characters[$n]; $password[] = $characters[$n];
} }
if(!empty($separator)) {
array_splice($password, 6, 0, $separator); array_splice($password, 6, 0, '-');
array_splice($password, 13, 0, $separator); array_splice($password, 13, 0, '-');
array_splice($password, 20, 0, $separator); array_splice($password, 20, 0, '-');
}
return implode($password); return implode($password);
} }

View file

@ -1,111 +0,0 @@
<?php
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
date_default_timezone_set('UTC');
require ABSPATH.'functions/tools.php';
$opts = load_opts();
/* ------------------------------------------------------------------------------------
* 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.
---------------------------------------------------------------------------------------
* Includes:
* - Check for updates.
* - Clear out old cached results when using the file cache.
* - Renew access token for Openverse (Expires every 12 hours)
------------------------------------------------------------------------------------ */
if(verify_hash('on', $opts->hash, $opts->user_auth)) {
/*--------------------------------------
// Do update check
--------------------------------------*/
global $current_version;
$version_file = ABSPATH.'cache/version.data';
if(!is_file($version_file)) {
// Create update cache file if it doesn't exist
$version = array('current' => $current_version, 'latest' => '0.0', 'checked' => 0, 'url' => '');
file_put_contents($version_file, serialize($version));
} else {
// Get update information
$version = unserialize(file_get_contents($version_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/'.$current_version.';'), // (array) User agent + Headers
'get', // (string) post/get
null // (assoc array|null) Post body
);
$json_response = json_decode($response, true);
// Got a response? Store it!
if(!empty($json_response)) {
// Update version info
$version = array('current' => $current_version, 'latest' => $json_response['tag_name'], 'checked' => time(), 'url' => $json_response['html_url']);
file_put_contents($version_file, serialize($version));
echo "<p>- Checked for updates and update cache updated!</p>";
}
}
/*--------------------------------------
// Clear out old cached files?
--------------------------------------*/
if($opts->cache_type == 'file') {
delete_cached_results($opts->cache_time);
echo "<p>- Expired file cache results deleted!</p>";
}
/*--------------------------------------
// Renew the Openverse access token
--------------------------------------*/
if($opts->enable_image_search == 'on' && $opts->image['openverse'] == 'on') {
$token_file = ABSPATH.'cache/token.data';
if(is_file($token_file)) {
$tokens = unserialize(file_get_contents($token_file));
$registration = $tokens['openverse'];
// Is the token expired?
if($registration['expires'] < time()) {
$response = do_curl_request(
'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
);
$json_response = json_decode($response, true);
// Got a response
if(!empty($json_response)) {
// Got some data?
if(array_key_exists('access_token', $json_response)) {
$json_response['expires_in'] = time() + ($json_response['expires_in'] - 3600);
oauth_store_token($token_file, 'openverse', array('client_id' => $registration['client_id'], 'client_secret' => $registration['client_secret'], 'access_token' => $json_response['access_token'], 'expires' => $json_response['expires_in']));
echo "<p>- New Openverse token stored!</p>";
}
}
unset($response, $json_response);
}
}
}
echo "<p><strong>Are there no errors on this page? We're done, you can close the tab/browser.</strong></p>";
} else {
echo "<p>!! Unauthorized !!</p>";
}
exit;
?>

267
help.php
View file

@ -1,6 +1,11 @@
<?php <?php
require "functions/tools.php";
require "functions/search_engine.php";
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -9,217 +14,123 @@
* By using this code you agree to indemnify Arnan de Gans from any * By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use. * liability that might arise from its use.
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
date_default_timezone_set('UTC');
require ABSPATH.'functions/tools.php';
$opts = load_opts();
$search = load_search();
?> ?>
<!DOCTYPE html> <!DOCTYPE html >
<html lang="en"> <html lang="en">
<head> <head>
<title>Goosle Search | How to use Goosle</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="UTF-8"/>
<meta charset="utf-8" /> <meta name="description" content="A private meta search engine!"/>
<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="referrer" content="no-referrer"/>
<meta name="description" content="Learn how to use Goosle, the best meta search engine!" /> <link rel="apple-touch-icon" href="apple-touch-icon.png">
<link rel="icon" href="favicon.ico" type="image/x-icon"/>
<meta property="og:site_name" content="Goosle Search" /> <link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<meta property="og:title" content="How to use Goosle" /> <title><?php echo $opts->query; ?> - Goosle Search</title>
<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="<?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> </head>
<body>
<body class="helppage">
<?php <?php
if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) { if(verify_hash($opts, $auth)) {
?> ?>
<div class="header"> <div class="wrap">
<div class="header-wrap">
<form action="results.php" method="get" autocomplete="off"> <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> <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-field" type="search" value="<?php echo (strlen($search->nice_query) > 0) ? htmlspecialchars($search->nice_query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" /> <input tabindex="1" class="search" type="search" value="<?php echo (strlen($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $search->type; ?>"/> <input type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->user_auth; ?>"> <input type="hidden" name="a" value="<?php echo $opts->hash; ?>">
</form>
<div class="navigation"> <div class="navigation-header">
<?php if($opts->enable_web_search == 'on') { ?> <a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="DuckDuckGo results" />DuckDuckGo</a>
<a class="<?php echo ($search->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=0">Search</a> <a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/search.png" alt="Google results" />Google</a>
<?php if($opts->enable_image_search == "on") { ?>
<a <?php echo ($opts->type == "2") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=2"><img src="assets/images/image.png" alt="Image results" />Image</a>
<?php } ?> <?php } ?>
<?php if($opts->enable_torrent_search == "on") { ?>
<?php if($opts->enable_image_search == 'on') { ?> <a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/torrent.png" alt="Torrent results" />Torrent</a>
<a class="<?php echo ($search->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=1" >Images</a>
<?php } ?>
<?php if($opts->enable_news_search == 'on') { ?>
<a class="<?php echo ($search->type == '2') ? 'active ' : ''; ?>tab-news" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=2">News</a>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<a class="<?php echo ($search->type == '9') ? 'active ' : ''; ?>tab-magnet" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=9">Magnet links</a>
<?php } ?> <?php } ?>
</div> </div>
</div> </form>
</div>
<div class="content"> <div class="results-wrap">
<h2>How to use Goosle</h2> <section class="main-column">
<p> Goosle has an easy to use UI, free of clutter and distractions. Hopefully this provides a pleasurable search experience. You will not find any unnessesary features or complex settings in Goosle. After-all, navigating the internet is hard and frustrating enough. Search engines should make that more easy, not harder!</p> <h2>DuckDuckGo features</h2>
<p>All external links <em>always</em> open in a new tab. That way you never loose your current search results. And to make search results more useful Goosle tries to format them in a neat and clean way so they're easy to read and use.</p> <p>DuckDuckGo is mostly language agnostic and will try to figure out on it's own what language to use.</p>
<p>Searching defaults to Moderate Safe mode. To override the safe mode prefix your search with <strong>safe:on</strong> or <strong>safe:off</strong>.<br /><strong>On</strong> will use 'Strict' mode, while <strong>off</strong> will disable safe searching, this may yield results that are unsuitable for work or minors.</p>
<p><em><strong>Note:</strong> Search bangs are not supported and the <strong>!</strong> to trigger them is stripped out to prevent issues.</em></p>
<p>Goosle is created by <a href="https://www.arnan.me/" target="_blank">Arnan de Gans</a> with the intent to make search more productive and fun.</p> <h2>Google features</h2>
<p>Searching defaults to Moderate Safe mode. You can override safe mode by adding the prefix <strong>safe:on</strong> or <strong>safe:off</strong> to your search query.<br /><strong>On</strong> will use 'Strict' mode, while <strong>off</strong> will disable safe searching. this may yield results that are unsuitable for work or minors.</p>
<p>Google results are not personalized by default, using Google's option for it.</p>
<p>Google search is language agnostic and Google will try to figure out on it's own what language to use. To search in a specific language prefix your search with <strong>lang:fr</strong> for French or <strong>lang:es</strong> for Spanish. Any language that google supports will work as long as you use the ISO639-1:2002 language code. Commonly these are the 2 letter abbreviations for the language such as; en, fr, es, de, sk, and so on.</p>
<p>To do a category search, prefix your search with one of the following keywords; <strong>app</strong>, <strong>book</strong>, <strong>news</strong>, <strong>shop</strong> or <strong>patent</strong>. This will tell Google to look for results in that specific category.<br />For example: Searching for <strong>book trainspotting</strong> will (or should) show results related to the book Trainspotting.</p>
<h3>Result ranking</h3> <?php if($opts->enable_image_search == "on") { ?>
<p>Goosle tries to provide you with search results in the right order no matter which search engine provides them. To try and provide the best results first Goosle has a basic algorithm to rank results.</p> <h2>Image Search</h2>
<?php if($opts->enable_web_search == 'on' || $opts->enable_image_search == 'on') { ?> <p>Search for images through Yahoo! Image Search.<br />The number of results is limited to 100. So up to 100 images may appear.</p>
<p>For Web and Image search. If a website or image is found through multiple search engines it will rank higher. Also the amount of matching words in the title and SEO description are considered.</p> <p>Contrary to Google Image Search which opens a popup/slider with more information. Goosle Image Search links directly to the page where the image is hosted.</p>
<?php } ?> <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 if($opts->enable_news_search == 'on') { ?>
<p>News search is ranked by your keywords and how many times a certain link is found, but also by publish date. Newer results rank higher.</p>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<p>Magnet results are sorted by most seeders (eg: availability of the download).</p>
<?php } ?> <?php } ?>
<h3>Safe search</h3> <h2>Special Searches</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:off geese gone wild</strong>).<br /><strong>On</strong> will use 'Strict' mode, while <strong>off</strong> will disable safe searching, this may yield results that are unsuitable for workspaces or minors.</p> <?php if($opts->special['currency'] == "on") { ?>
<h3>Currency converter</h3>
<?php if($opts->show_nsfw_magnets == 'off') { ?>
<p>The Not Suitable For Work (NSFW) filter for Magnet results is enabled. This is an attempt to hide adult content from results. Some search engines have categories that can be filtered out. Others rely on keyword matches. Goosle has an extensive list of 'dirty' keywords to try and find adult content and then ignore it. To override the setting use the <strong>safe:off</strong> or <strong>nsfw</strong> prefix.<br />
For example: Search for <strong>nsfw goose on goose action</strong> or <strong>safe:off dirty geese</strong> to include adult content in the results.</p>
<?php } ?>
<?php if($opts->enable_web_search == 'on') { ?>
<h2>Web search</h2>
<p>Goosle Web Search gathers links through search engines and search API and shows them in a neat and organised results page. Results are ranked by relevance to your current search.</p>
<?php if($opts->special['currency'] == 'on') { ?>
<h4>Currency converter</h4>
<p>Convert currency with a simple query.<br /> <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> For example: Search for <strong>20 EUR in HKD</strong> or <strong>14 USD to MXN</strong> and DuckDuckGo or Google will search for it, but also a local conversion is done in a highlighted result.</p>
<?php } ?> <?php } ?>
<?php if($opts->special['definition'] == 'on') { ?> <?php if($opts->special['wikipedia'] == "on") { ?>
<h4>Word Definition</h4> <h3>Wikipedia Search</h3>
<p>Look up the meaning of single words. Prefix the word you want to look up with <strong>define</strong>, <strong>def</strong> or <strong>meaning</strong>.<br /> <p>Prefix your search with <strong>w</strong> or <strong>wiki</strong> to search on Wikipedia for a page match. This works best for English searches as Wikipedia defaults to English.<br />
For example: Searching for <strong>define goose</strong> will do a web search for 'goose' but will also show a dictionary definition highlighted above the search results.</p> For example: Searching for <strong>wiki beach ball</strong> will show you a excerpt from that page above the search results or suggest the most likely alternative if Wikipedia knows what your search query means.</p>
<?php } ?> <?php } ?>
<?php if($opts->special['ipaddress'] == 'on') { ?> <?php if($opts->special['phpnet'] == "on") { ?>
<h4>IP Address lookup</h4> <h3>PHP.net Search</h3>
<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 /> <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> 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 } ?>
<?php if($opts->special['wordpress'] == 'on') { ?> <?php if($opts->special['definition'] == "on") { ?>
<h4>WordPress documentation Search</h4> <h3>Word Definition</h3>
<p>Prefix your search with <strong>wordpress</strong> or <strong>wp</strong> to search on wordpress.org for a WordPress function. You can also search for hooks or filters by adding 'hook' as the 2nd keyword.<br /> <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>wordpress the_content</strong> or <strong>wp hook admin_init</strong> will show you a brief description and the basic syntax for that function or hook/filter.</p> For example: Searching for <strong>define search</strong> will search for that on Google or DuckDuckGo, but also show the dictionary definition highlighted above the search results.</p>
<?php } ?> <p><em><strong>Note:</strong> Special Searches do not work for torrent searches.</em></p>
<?php } ?> <?php } ?>
<?php if($opts->enable_image_search == 'on') { ?> <?php if($opts->enable_torrent_search == "on") { ?>
<h2>Image Search</h2> <h2>Torrent Search</h2>
<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>Search for anything torrent sites have on offer the direct search result should give you the magnet link.<br />Results are gathered from 1337x, Nyaa, The Pirate Bay, EZTV and YTS and are sorted by Seeders, highest first. The number of results is limited to 50.</p>
<p>You can search for images in a general size by adding <strong>size:small</strong>, <strong>size:medium</strong>, <strong>size:large</strong> or <strong>size:xlarge</strong> to the beginning of your search query (example: <strong>size:small huge goose</strong>).</p> <p>The search scripts will try to provide useful data which may include; Seeders/Leechers, A link to the torrent page, Download Category, Release year, Movie quality (720p, 4K etc.), Movie Runtime and the Download Size. Not every website makes this available and all results take a best effort approach.</p>
<?php if($opts->special['imdb_id_search'] == "on") { ?>
<h3>Searching TV Shows</h3>
<p>To do a specific search on The Pirate Bay and EZTV you can search for IMDb Title IDs. These are numeric IDs prefixed with <strong>tt</strong>. This kind of search is useful if you're looking a tv show that doesn't have a unique name.</p>
<p> If you already know the Title ID you can enter it directly in the Torrent search as your search query.<br />
If you don't know the Title ID you can search DuckDuckGo or Google for <strong>imdb [tv show name]</strong>, for example <strong>imdb game of thrones</strong>.<br />
Goosle will detect the IMDb ID from the search results and show a special search result that offers you to search for Magnet Links through a torrent search.</p>
<p>To help you narrow down seasons and episodes you can search for <strong>tt0944947 S08</strong> and get filtered results from EZTV for Game of Thrones Season 8. Searching for <strong>tt0944947 S08E05</strong> should find Season 8 Episode 5 and so on.</p>
<?php } ?>
<p><em><strong>Note:</strong> If you like, or found a use for, what you downloaded, you should probably buy a legal copy of it.</em></p>
<?php } ?> <?php } ?>
<?php if($opts->enable_news_search == 'on') { ?> <p><small><strong>Acknowledgements:</strong><br />Goosle started as a fork of LibreY, and takes some design cues from DuckDuckGo.com. Goosle is created by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a> with the intent to make search fun again.</small></p>
<h2>News search</h2> </section>
<p>Look for current and recent news through News Search. Search for any topic and you'll find news from the last 30 days. Search is loosely ranked by post date. Newer news ranks higher.<p>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<h2>Magnet Search</h2>
<p>Magnet Search provides Magnet links, these are special links from Torrent sites to download content from the internet. Things like Movies, TV-Shows, EBooks, Music, Games, Software and more. You'll need a Bittorrent client that accepts Magnet links to download the search results.</p>
<p>There are many <a href="./results.php?q=Torrent+clients+Magnet+links&a=<?php echo $opts->hash; ?>&t=0" target="_blank">Torrent clients that support Magnet links</a> but if you don't know which one to choose, give <a href="https://transmissionbt.com/" target="_blank" title="Transmission Bittorrent">Transmission BT</a> a go as it's easy to set up and use.</p>
<p>Goosle will try to provide useful information about the download, which includes; Seeders, Leechers, A link to the torrent page, Download Category and Release year. Extra information may also include the Movie quality (720p, 4K etc.), Movie Runtime and the Download Size along with some other bits and bops if available. Not every website makes this available and all results take a best effort approach.</p>
<h3>Searching for TV Shows</h3>
<p>To do a specific search on The Pirate Bay and EZTV you search for IMDb Title IDs. These are numeric IDs prefixed with <strong>tt</strong>. This kind of search is useful when you're looking for a tv show that doesn't have a unique name, or simply if you want to use a specialized tracker for tv shows.</p>
<p>If you know the IMDb Title ID you can search for it through the Magnet search.</p>
<?php if($opts->imdb_id_search == 'on') { ?>
<p>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 popup that opens you can copy the link and share or store it anywhere you can paste text - For example in a messenger or note. This special link will perform the same search as you did yourself and highlight the result that you want to share.</p>
<?php if($opts->hash_auth == 'off') { ?>
<p>The links can be shared with anyone since you do not run a private Goosle. Anyone who has the shared link can see the results.</p>
<?php } else { ?>
<p>The links can be shared with anyone but keep in mind that since you run a private installation you might be giving uninvited guests access to it. To prevent this from happening the share link does NOT include the passphrase hash. This means that any guests can see your shared results but searching for new things will not work for them.</p>
<?php } ?>
<?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, 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 follow the browsers instruction and use the following link: <strong>https://example.com/results.php?q=%s</strong>.</p>
<p>Or if you use the Auth Hash as a password add the <strong>a</strong> argument, like so: <strong>https://example.com/results.php?a=YOUR_HASH&q=%s</strong>. Obviously replace example.com with your actual goosle addesss.</p>
<p>Most browsers will instruct you to add <strong>%s</strong> for the search query as shown in the examples. If your browser has a different value for this simply replace %s with what your browser requires.
<h2>Colorschemes</h2>
<p>Goose comes with several colorschemes, configurable through the config.php file.</p>
<h3>Available colorschemes are:</h3>
<ol>
<li>"default" A dark headers and main backgrounds with light search results.</li>
<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 the darkmode setting of your device.</li>
</ol>
<h4>Acknowledgements:</h4>
<p><small>All icons are borrowed from the IconFinder <a href="https://www.iconfinder.com/search/icons?family=unicons-line" target="_blank">Unicons Set</a>.<br />
The Goose icon is borrowed from the Flaticon <a href="https://www.flaticon.com/packs/farm-19" target="_blank">Farm pack</a>.<br />
Goosle started as a fork of LibreY, and takes some design cues from DuckDuckGo.com.</small></p>
</div>
<div class="footer grid-container">
<div class="footer-grid">
&copy; <?php echo the_date('Y'); ?> Goosle <?php echo $current_version; ?> <?php echo show_update_notification(); ?>
</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> - <a href="./stats.php?a=<?php echo $opts->hash; ?>">Stats</a>
</div> </div>
</div> </div>
<?php } else { ?> <div class="footer-wrap">
<div class="auth-error">Redirecting</div> <div class="footer">
<meta http-equiv="refresh" content="1; url=<?php echo get_base_url($opts->siteurl); ?>/error.php" /> &copy; <?php echo date('Y'); ?> <a href="https://github.com/adegans/Goosle/" target="_blank">Goosle <?php echo $opts->version; ?></a>, by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
<?php } ?> <span style="float:right;"><a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a> - Your IP: <?php echo $_SERVER["REMOTE_ADDR"]; ?></span>
</div>
</div>
<?php
} else {
echo "<div class=\"auth-error\">Goosle</div>";
}
?>
</body> </body>
</html> </html>

103
index.php
View file

@ -1,6 +1,11 @@
<?php <?php
require "functions/tools.php";
require "functions/search_engine.php";
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -9,87 +14,59 @@
* By using this code you agree to indemnify Arnan de Gans from any * By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use. * liability that might arise from its use.
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
require ABSPATH.'functions/tools.php';
$opts = load_opts();
?> ?>
<!DOCTYPE html> <!DOCTYPE html >
<html lang="en"> <html lang="en">
<head> <head>
<title>Goosle Search</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="UTF-8"/>
<meta charset="utf-8" /> <meta name="description" content="Goosle - A meta search engine for private and fast internet fun!"/>
<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="referrer" content="no-referrer"/>
<meta name="description" content="Get your Goosle on! - The best meta search engine for private and fast search results!" /> <link rel="apple-touch-icon" href="apple-touch-icon.png">
<link rel="icon" href="favicon.ico" type="image/x-icon"/>
<meta property="og:site_name" content="Goosle Search" /> <link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<meta property="og:title" content="Goosle Search" /> <title>Goosle Search</title>
<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="<?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> </head>
<body class="main">
<body class="startpage">
<?php <?php
if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) { if(verify_hash($opts, $auth)) {
?> ?>
<div class="wrap">
<div class="content"> <div class="search-box-main">
<h1><span class="goosle-g">G</span>oosle</h1>
<form action="results.php" method="get" autocomplete="off"> <form action="results.php" method="get" autocomplete="off">
<input tabindex="10" type="search" class="search-field" name="q" required autofocus /> <h1><span class="G">G</span>oosle</h1>
<input tabindex="10" type="search" class="search" name="q" autofocus />
<input type="hidden" name="t" value="0"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/> <input type="hidden" name="a" value="<?php echo $opts->hash; ?>"/>
<div class="search-buttons"> <div class="search-box-buttons">
<?php if($opts->enable_web_search == 'on') { ?> <button tabindex="20" name="t" value="0" type="submit">DuckDuckGo</button>
<button tabindex="20" name="t" value="0" type="submit" class="web-search">Web search</button> <button tabindex="30" name="t" value="1" type="submit">Google</button>
<?php if($opts->enable_image_search == "on") { ?>
<button tabindex="40" name="t" value="2" type="submit">Image</button>
<?php } ?> <?php } ?>
<?php if($opts->enable_torrent_search == "on") { ?>
<?php if($opts->enable_image_search == 'on') { ?> <button tabindex="50" name="t" value="9" type="submit">Torrent</button>
<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" 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 } ?> <?php } ?>
</div> </div>
</form>
<?php if($opts->password_generator == "on") { ?> </form>
</div>
<?php if($opts->special['password_generator'] == "on") { ?>
<div class="password-generator"> <div class="password-generator">
<form method="get" action="./" autocomplete="off"> <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" /> Password Generator:<br/><input class="password" type="text" name="pw" maxlength="27" value="<?php echo string_generator(); ?>" autocomplete="0" />
</form> </form>
</div> </div>
<?php } ?> <?php } ?>
</div> </div>
<?php
<div class="footer grid-container"> } else {
<div class="footer-grid"> echo "<div class=\"auth-error\">Goosle</div>";
&copy; <?php echo the_date('Y'); ?> Goosle <?php echo $current_version; ?> <?php echo show_update_notification(); ?> }
</div> ?>
<div class="footer-grid">
<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> - <a href="./stats.php?a=<?php echo $opts->hash; ?>">Stats</a>
</div>
</div>
<?php } else { ?>
<div class="auth-error">Redirecting</div>
<meta http-equiv="refresh" content="1; url=<?php echo get_base_url($opts->siteurl); ?>/error.php" />
<?php } ?>
</body> </body>
</html> </html>

187
readme.md
View file

@ -1,144 +1,103 @@
# Goosle # Goosle
## The best Meta Search Engine to find everything A fast, privacy oriented meta search engine that just works. \
Kept simple so everyone can use it and to make sure it works on most (basic) webservers.
Goosle is a fast, privacy oriented search tool that just works. \
It's kept simple so everyone can use it and to make sure it works on most webservers.
If you're looking for more varied results that are not laced with AI results and other non-features most people do not care for. Or if you're simply looking for traditional results from more than one search engine, Goosle has your back! Goosle searches on several search engine at the same time and shows you the most relevant results through a neat, clean interface. Goosle has **no** ads or sponsored results, **no** distractions, **no** trackers, **no** cookies and **no** bloated libraries, frameworks, dependencies or other things that slow you down.
Goosle does Image and News search. Collecting information from various sources and also shown in a simple easy to use manner.
On top of that, Goosle provides a safe and clean Magnet Link search tab along with a Box Office page. Find any torrent you like in seconds without malware, ads or other browser-breaking dangers that would otherwise require a VPN to safely use Torrent sites. Results are sourced from some of the largest torrent providers, compiled and ordered by the most seeders.
Host for yourself and friends, with a access hash key. Or set up a public search website. Host for yourself and friends, with a access hash key. Or set up a public search website.
After-all, finding things should be easy and not turn into a chore. After-all, finding things should be easy and not turn into a chore.
[![Goosle Mainpage](https://ajdg.solutions/assets/goosle/homepage-950.webp)](https://ajdg.solutions/assets/goosle/homepage-950.webp) [![Goosle Mainpage](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage-960x593.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage.png)
## Features ## Features
- Works on **any** hosting package that does PHP7.4 or newer - Search on DuckDuckGo
- Search results from DuckDuckGo, Google, Qwant, Brave, Wikipedia - Search on Google.com
- Image search through Yahoo! Images, Qwant, Pixabay and Openverse - Image search through Yahoo! Images
- Recent news via Qwant news, Yahoo! News, Brave and Hackernews
- Search for magnet links on popular Torrent sites - Search for magnet links on popular Torrent sites
- Algorithm for ranking search results for relevancy - Special searches for; Currency conversion, Dictionary, Wikipedia and php.net
- Option to down-rank the biggest social media sites such as facebook, instagram, twitter, tiktok, reddit, snapchat and a few others. - Instant password generator on the home page
- Special searches for; Currency conversion, Dictionary, IP Lookup and php.net
- Randomized user-agents for to prevent profiling by search providers - Randomized user-agents for to prevent profiling by search providers
- Non-personalized Google results without instant results or other non-sense - Works on *any* hosting package that does PHP7.4 or newer
- Optional: Speed up repeat searches with APCu cache or file cache - Optional: Access key as a very basic way to keep your server to yourself
- Optional: Basic access key as a basic way to keep your server to yourself - Optional: Speed up repeat searches with APCu cache if your server has it
- Optional: Instant password generator on the start page
What Goosle does **not** have. What Goosle does *not* have.
- Trackers and Cookies - Trackers and Cookies
- Ads, malware and distractions
- User profiles or user controllable settings - User profiles or user controllable settings
- Libraries, dependencies or Frameworks - Javascripts or Frameworks
And yet it just works... fast! And yet it just works...
If you like Goosle, or found a use for it, please support my work and [donate](https://www.arnan.me/donate.html?mtm_campaign=goosle_readme) and tell everyone about its existence. If you like Goosle, or found a use for it, please support my work and [donate](https://www.arnan.me/donate.html?mtm_campaign=goosle_readme).
## Screenshots ## Screenshots
[![Goosle Mainpage](https://ajdg.solutions/assets/goosle/homepage-250.webp)](https://ajdg.solutions/assets/goosle/homepage.webp) [![Goosle Mainpage](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage-150x150.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-mainpage.png)
[![Goosle Web Search](https://ajdg.solutions/assets/goosle/web-search-250.webp)](https://ajdg.solutions/assets/goosle/web-search.webp) [![Goosle Search results](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-search-150x150.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-search.png)
[![Goosle Image Search](https://ajdg.solutions/assets/goosle/image-search-250.webp)](https://ajdg.solutions/assets/goosle/image-search.webp) [![Goosle Torrent results](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-torrentsearch-150x150.png)](https://ajdg.solutions/wp-content/uploads/2023/12/goosle-torrentsearch.png)
[![Goosle News Search](https://ajdg.solutions/assets/goosle/news-search-250.webp)](https://ajdg.solutions/assets/goosle/news-search.webp)
[![Goosle Magnet Search](https://ajdg.solutions/assets/goosle/magnet-search-250.webp)](https://ajdg.solutions/assets/goosle/magnet-search.webp)
[![Goosle Boxoffice releases](https://ajdg.solutions/assets/goosle/boxoffice-250.webp)](https://ajdg.solutions/assets/goosle/boxoffice.webp)
[![Goosle Usage stats](https://ajdg.solutions/assets/goosle/usage-stats-250.webp)](https://ajdg.solutions/assets/goosle/usage-stats.webp)
## Requirements ## Requirements
Any basic webserver/webhosting package with PHP7.4 or newer. \ 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.2.
Developed on Apache with PHP8.2.
## Installation ## Installation
1. Download and unzip Goosle. 1. Unzip the download.
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. 3. Edit 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/) 4. Upload all files to your webserver, for example to the root folder of a subdomain (eg. search.example.com) or a sub-folder on your main site (eg. example.com/search/)
5. Rename goosle.htaccess to .htaccess or add its contents to your existing .htaccess file. 5. Rename goosle.htaccess to .htaccess
6. Load Goosle in your browser. If you've enabled the access hash, add *?a=YOUR_HASH* to the url. 6. Load the site in your browser. If you've enabled the access hash add ?a=YOURHASH to the url.
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. 7. Let me know where you installed Goosle :-)
8. Let me know where you installed Goosle in the 'Show your Goosle' discussion on Github :-)
## Updating Goosle to a newer version ### Notes:
1. Download and unzip the latest release of Goosle. - The .htaccess file has a redirect to force HTTPS as well as browser caching instructions ready to go.
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) - The robots.txt has a rule to prevent all crawlers from crawling Goosle. But keep in mind that not every crawler obeys this file.
3. Upload all the files to your webserver, overwriting all files except perhaps config.php. - The access hash is NOT meant as a super secure measure and only works for surface level prying eyes.
4. Load Goosle in your browser. If you've enabled the access hash don't forget to add *?a=YOUR_HASH* to the url.
5. Enjoy your updated search experience!
Take a look at the [changelog](changelog.md) for every update here. \ Have fun finding things!
## Setting up a Cronjob / background task ## Disclaimer
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. \ Goosle started as a fork of LibreY, and ended up as a rewrite and something different completely. While the code structure remains largely the same, most functions have been rewritten or altered to work as I need it to. \
Execute this cronjob a couple of times per day, recommended is every 8 hours. Search results take design cues from DuckDuckGo and the torrent search has been modified to show more useful information where possible. \
Goosle does not index, store or distribute torrent files. If you like, or found a use for, what you downloaded, you should probably buy a legal copy of it.
Without it, Openverse access will expire and you have to generate a new key every few hours. \ The name Goosle is my last name with an L added in. Translate it from Dutch. Not in any way a derivation of Google and DuckDuckGo combined :wink:
For low traffic setups or if you do not use Openverse a longer interval of once a day is fine.
The access hash is always required as an access token, don't forget to include ?a=YOUR_HASH to the url. \
Cron jobs are commonly set up from your hosting dashboard, or through something like DirectAdmin, cPanel or WHM. \
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. \
To test, you can also load the url in your browser and trigger the script that way. Look for the onscreen prompts to see what routines are executed.
### Usage examples
Example for 10 minutes past every 3 hours \
`10 */3 * * * wget -qO - https://example.com/goosle-cron.php?a=YOUR_HASH`
Example for 5 minutes past every 8 hours (I use this on my Goosle) \
`5 */8 * * * wget -qO - https://example.com/goosle-cron.php?a=YOUR_HASH`
Example for every midnight \
`0 0 * * * wget -qO - https://example.com/goosle-cron.php?a=YOUR_HASH`
Why a few minutes past the hour? Because most people run stuff exactly on the hour or some other predictable interval like 15 or 30 minutes. Running things a few minutes later spreads server load.
## Authorizing access to the Openverse search API
OpenVerse image search provides (mostly) royalty free images. \
Millions of high quality photos from photographers from all over the world. \
If you're into high quality photo backgrounds, need images for blogs and articles or just like to look at high-res anything, then Openverse is a useful engine to use.
To use Openverse Image Search you'll need to register Goosle for an oAUTH access token.
Goosle includes a oAuth routine to easily register for an access token. \
- In your browser navigate to your goosle setup and add /functions/oauth-openverse.php to the url (ex. example.com/functions/oauth-openverse.php or example.com/functions/oauth-openverse.php?a=YOUR_HASH).
- Follow the onscreen prompts to get an authorization token to use Openverse.
- When prompted save the Client ID and Client Secret somewhere on your computer, in a note or something. Should the token file that Goosle creates get lost you'll need these strings to continue using Openverse.
- An email from Openverse will arrive within a few minutes with a confirmation link to finalize the set up.
- Once activated, enable openverse in your config.php and you're all set!
This procedure generates an access token which is stored in /cache/token.data, this token expires every 12 hours. Yeah, annoying! \
To automatically renew the token you can set up the Goosle cronjob as described elsewhere in this readme.
## API access to the Pixabay search API
Pixabay is a high quality photo and illustration database with (generally) royalty-free images. \
Pixabay has a database of hundreds of thousands of images provided by Photographers from all over the world. \
If you're a content creator who regularly need images for blogs and articles or just like to look at high-res photography, Pixabay is for you.
To get image results from Pixabay you'll need a free account to get a free API key. \
Register an account here: [https://pixabay.com](https://pixabay.com) (Click the Join button in the top right)
Once registered and logged in, you can find your API key in the Documentation here: [https://pixabay.com/api/docs/](https://pixabay.com/api/docs/), look for the first parameter specification (looks like a list), the Key will be highlighted in green at the top of it. Copy this key to your config.php into the pixabay_api_key option.
## Support ## Support
You can post your questions on Github Discussions or say hi on [Mastodon](https://mas.to/@arnan) or through my [website](https://www.arnan.me). Goosle comes with limited support. \
You can post your questions on Github or on my support forum on [ajdg.solutions](https://ajdg.solutions/support/?mtm_campaign=goosle_readme). \
Or say hi on [Telegram](https://t.me/arnandegans).
## Notes ## Changelog
- When using file caching you should set up a cronjob to execute goosle-cron.php every few hours. This deletes 'old' results. 1.1 - December 21, 2023
- When you use Openverse for your image searches you should set up a cron job to execute goosle-cron.php every 11 hours or so. This will automagically renew the access token. - [new] API search for EZTV TV Shows.
- 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. - [new] config.default.php with default settings.
- The .htaccess file has a redirect to force HTTPS, catch 404 errors with a redirect as well as browser caching rules ready to go. - [new] New option 'imdb_id_search' in 'special' settings in config.php.
- 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. - [new] New option 'show_zero_seeders' in config.php.
- The access hash is NOT meant as a super secure measure and only works for surface level prying eyes. - [new] Special result and torrent redirect for IMDb IDs.
- Results provided by Openverse and Pixabay are simplistic keyword matches which are not necessarily accurately sorted by relevancy. - [new] Replaced image search with Yahoo! Images.
- [new] Styled 'reset' button for search fields.
- [tweak] Removed 'raw_output' option.
- [tweak] Re-arranged results array to be more logical/easy to use.
- [tweak] Re-arranged code for results to do no double checks for search results.
- [tweak] Added more user-agents.
- [tweak] Torrent results page.
- [tweak] Sanitize scraped data earlier in the process.
- [tweak] Consistent single quotes for arrays.
- [tweak] Consistent spaces, tabs and newlines.
- [fix] Inconsistent input height for search field vs search button.
- [fix] Better check if a search is currency conversion or not.
- [fix] Typos in help.php.
## Known "issues" 1.0.2 - December 7, 2023
- 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. - [change] More useful error response when search doesn't work.
- Some crawlers for Magnet searches may return empty results. These are likely quota limits on their end. - [change] EngineRequest::request_successful() now provides a boolean response.
- [change] Removed versioning indicator from help page.
- [change] Added version indicator to results.php and help.php footer.
- [change] 'Nope, Go away!' for unauthorized users changed to 'Goosle'.
- [fix] Magnet links for torrents no longer opening in new tabs.
1.0.1 - December 5, 2023
- [fix] mktime() getting intermittent strings in 1337x crawler.
- [fix] mktime() getting intermittent strings in nyaa crawler.
1.0 - December 5, 2023
- Initial release

View file

@ -1,6 +1,11 @@
<?php <?php
require "functions/tools.php";
require "functions/search_engine.php";
$opts = load_opts();
$auth = (isset($_GET['a'])) ? sanitize($_GET['a']) : $opts->user_auth;
/* ------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------
* Goosle - The fast, privacy oriented search tool that just works. * Goosle - A meta search engine for private and fast internet fun.
* *
* COPYRIGHT NOTICE * COPYRIGHT NOTICE
* Copyright 2023-2024 Arnan de Gans. All Rights Reserved. * Copyright 2023-2024 Arnan de Gans. All Rights Reserved.
@ -9,139 +14,62 @@
* By using this code you agree to indemnify Arnan de Gans from any * By using this code you agree to indemnify Arnan de Gans from any
* liability that might arise from its use. * liability that might arise from its use.
------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------ */
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
date_default_timezone_set('UTC');
require ABSPATH.'functions/tools.php';
require ABSPATH.'functions/search_engine.php';
$opts = load_opts();
$search = load_search();
$start_time = microtime(true);
// SEO description
$description = (strlen($search->nice_query) > 0) ? "Check out these Goosle search results about: '".urldecode($search->nice_query)."'." : "Check out these Goosle search results!";
?> ?>
<!DOCTYPE html> <!DOCTYPE html >
<html lang="en"> <html lang="en">
<head> <head>
<title>Goosle Search | Results</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="UTF-8"/>
<meta charset="utf-8" /> <meta name="description" content="A private meta search engine!"/>
<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="referrer" content="no-referrer"/>
<meta name="description" content="<?php echo $description; ?>" /> <link rel="apple-touch-icon" href="apple-touch-icon.png">
<link rel="icon" href="favicon.ico" type="image/x-icon"/>
<meta property="og:site_name" content="Goosle Search" /> <link rel="stylesheet" type="text/css" href="assets/css/styles.css"/>
<meta property="og:title" content="The best meta search engine" /> <title><?php echo $opts->query; ?> - Goosle Search</title>
<meta property="og:description" content="<?php echo $description; ?>" />
<meta property="og:url" content="<?php echo get_base_url($opts->siteurl); ?>/results.php" />
<meta property="og:image" content="<?php echo get_base_url($opts->siteurl); ?>/assets/images/goosle.webp" />
<meta property="og:type" content="website" />
<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"/>
<script src="<?php echo get_base_url($opts->siteurl);?>/assets/js/goose.js" id="goosebox-js"></script>
</head> </head>
<body>
<body class="resultspage">
<?php <?php
if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth, $search->share)) { if(verify_hash($opts, $auth)) {
?> ?>
<div class="header"> <div class="wrap">
<div class="header-wrap">
<form action="results.php" method="get" autocomplete="off"> <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> <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-field" type="search" value="<?php echo (strlen($search->nice_query) > 0) ? htmlspecialchars($search->nice_query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" /> <input tabindex="1" class="search" type="search" value="<?php echo (strlen($opts->query) > 0) ? htmlspecialchars($opts->query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $search->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->user_auth; ?>"> <input type="hidden" name="t" value="<?php echo $opts->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->hash; ?>">
<div class="navigation-header">
<a <?php echo ($opts->type == "0") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=0"><img src="assets/images/search.png" alt="DuckDuckGo results" />DuckDuckGo</a>
<a <?php echo ($opts->type == "1") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=1"><img src="assets/images/search.png" alt="Google results" />Google</a>
<?php if($opts->enable_image_search == "on") { ?>
<a <?php echo ($opts->type == "2") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=2"><img src="assets/images/image.png" alt="Image results" />Image</a>
<?php } ?>
<?php if($opts->enable_torrent_search == "on") { ?>
<a <?php echo ($opts->type == "9") ? "class=\"active\" " : ""; ?> href="./results.php?q=<?php echo urlencode($opts->query); ?>&a=<?php echo $opts->hash; ?>&t=9"><img src="assets/images/torrent.png" alt="Torrent results" />Torrent</a>
<?php } ?>
</div>
</form> </form>
</div>
<div class="navigation"> <div class="results-wrap">
<?php if($opts->enable_web_search == 'on') { ?> <?php fetch_search_results($opts); ?>
<a class="<?php echo ($search->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=0">Search</a> </div>
<?php } ?> </div>
<?php if($opts->enable_image_search == 'on') { ?> <div class="footer-wrap">
<a class="<?php echo ($search->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=1" >Images</a> <div class="footer">
<?php } ?> &copy; <?php echo date('Y'); ?> <a href="https://github.com/adegans/Goosle/" target="_blank">Goosle <?php echo $opts->version; ?></a>, by <a href="https://ajdg.solutions/" target="_blank">Arnan de Gans</a>.
<span style="float:right;"><a href="./?a=<?php echo $opts->hash; ?>">Start</a> - <a href="./help.php?a=<?php echo $opts->hash; ?>">Help</a> - Your IP: <?php echo $_SERVER["REMOTE_ADDR"]; ?></span>
<?php if($opts->enable_news_search == 'on') { ?>
<a class="<?php echo ($search->type == '2') ? 'active ' : ''; ?>tab-news" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=2">News</a>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<a class="<?php echo ($search->type == '9') ? 'active ' : ''; ?>tab-magnet" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=9">Magnet links</a>
<?php } ?>
</div> </div>
</div> </div>
<div class="content">
<?php <?php
if(!empty($search->query)) {
// Curl
$mh = curl_multi_init();
// Load search script
if($search->type == 0) {
require ABSPATH.'engines/search.php';
$search_results = new Search($search, $opts, $mh);
} else if($search->type == 1) {
require ABSPATH.'engines/search-image.php';
$search_results = new ImageSearch($search, $opts, $mh);
} else if($search->type == 2) {
require ABSPATH.'engines/search-news.php';
$search_results = new NewsSearch($search, $opts, $mh);
} else if($search->type == 9) {
require ABSPATH.'engines/search-magnet.php';
$search_results = new MagnetSearch($search, $opts, $mh);
}
$running = null;
do {
$status = curl_multi_exec($mh, $running);
if($running) {
curl_multi_select($mh);
}
} while ($running && $status == CURLM_OK);
$results = $search_results->get_results();
curl_multi_close($mh);
// Add elapsed time to results
$results['time'] = number_format(microtime(true) - $start_time, 5, '.', '');
// Echoes results and special searches
$search_results->print_results($results, $search, $opts);
} else { } else {
echo "<div class=\"warning\">"; echo "<div class=\"auth-error\">Goosle</div>";
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->user_auth."\" title=\"how to use Goosle!\">how to use Goosle</a>.</p>";
echo "</div>";
} }
?> ?>
</div>
<div class="footer grid-container">
<div class="footer-grid">
&copy; <?php echo the_date('Y'); ?> Goosle <?php echo $current_version; ?> <?php echo show_update_notification(); ?>
</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> - <a href="./stats.php?a=<?php echo $opts->hash; ?>">Stats</a>
</div>
</div>
<?php } else { ?>
<div class="auth-error">Redirecting</div>
<meta http-equiv="refresh" content="1; url=<?php echo get_base_url($opts->siteurl); ?>/error.php" />
<?php } ?>
</body> </body>
</html> </html>

101
stats.php
View file

@ -1,101 +0,0 @@
<?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.
------------------------------------------------------------------------------------ */
if(!defined('ABSPATH')) define('ABSPATH', $_SERVER['DOCUMENT_ROOT'] . '/');
date_default_timezone_set('UTC');
require ABSPATH.'functions/tools.php';
$opts = load_opts();
$search = load_search();
$stats = load_stats();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Goosle Search | Usage Stats</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="How many searches did Google handle?" />
<meta property="og:site_name" content="Goosle Search" />
<meta property="og:title" content="Usage Stats" />
<meta property="og:description" content="How many searches did Google handle?" />
<meta property="og:url" content="<?php echo get_base_url($opts->siteurl); ?>/stats.php" />
<meta property="og:image" content="<?php echo get_base_url($opts->siteurl); ?>/assets/images/goosle.webp" />
<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); ?>/stats.php" />
<link rel="stylesheet" type="text/css" href="<?php echo get_base_url($opts->siteurl); ?>/assets/css/styles.css"/>
<link rel="stylesheet" type="text/css" href="<?php echo get_base_url($opts->siteurl); ?>/assets/css/<?php echo $opts->colorscheme; ?>.css"/>
</head>
<body class="statspage">
<?php
if(verify_hash($opts->hash_auth, $opts->hash, $opts->user_auth)) {
?>
<div class="header">
<form action="results.php" method="get" autocomplete="off">
<h1 class="logo"><a href="./?a=<?php echo $opts->hash; ?>"><span class="goosle-g">G</span>oosle</a></h1>
<input tabindex="1" class="search-field" type="search" value="<?php echo (strlen($search->nice_query) > 0) ? htmlspecialchars($search->nice_query) : "" ; ?>" name="q" /><input tabindex="2" class="button" type="submit" value="Search" />
<input type="hidden" name="t" value="<?php echo $search->type; ?>"/>
<input type="hidden" name="a" value="<?php echo $opts->user_auth; ?>">
</form>
<div class="navigation">
<?php if($opts->enable_web_search == 'on') { ?>
<a class="<?php echo ($search->type == '0') ? 'active ' : ''; ?>tab-search" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=0">Search</a>
<?php } ?>
<?php if($opts->enable_image_search == 'on') { ?>
<a class="<?php echo ($search->type == '1') ? 'active ' : ''; ?>tab-image" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=1" >Images</a>
<?php } ?>
<?php if($opts->enable_news_search == 'on') { ?>
<a class="<?php echo ($search->type == '2') ? 'active ' : ''; ?>tab-news" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=2">News</a>
<?php } ?>
<?php if($opts->enable_magnet_search == 'on') { ?>
<a class="<?php echo ($search->type == '9') ? 'active ' : ''; ?>tab-magnet" href="./results.php?q=<?php echo $search->query; ?>&a=<?php echo $opts->user_auth; ?>&t=9">Magnet links</a>
<?php } ?>
</div>
</div>
<div class="content">
<h1>Searches</h1>
<p class="text-xxl text-center"><?php echo number_format($stats['all_queries'], 0); ?></p>
<h2>Average per day</h2>
<p class="text-xl text-center"><?php echo number_format($stats['avg_per_day'], 2); ?></p>
</div>
<div class="footer grid-container">
<div class="footer-grid">
&copy; <?php echo the_date('Y'); ?> Goosle <?php echo $current_version; ?> <?php echo show_update_notification(); ?>
</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> - <a href="./stats.php?a=<?php echo $opts->hash; ?>">Stats</a>
</div>
</div>
<?php } else { ?>
<div class="auth-error">Redirecting</div>
<meta http-equiv="refresh" content="1; url=<?php echo get_base_url($opts->siteurl); ?>/error.php" />
<?php } ?>
</body>
</html>