FbIN Support 2026-05-05 23:11:04 +05:30
commit 0c23ab35bd
5 changed files with 187 additions and 326 deletions

View file

@ -6,11 +6,11 @@ https://fossq.com/about
## Totally unbiased comparison between alternatives ## Totally unbiased comparison between alternatives
| | FOSS-Q | searx(ng) | FbIN-LibreY | araa | hearch.co | | | FOSSQ | SearX(ng) | Whoogle | Degoog |
|----------------------------|-------------------------|-----------|-------------|-----------|-------------------| |----------------------------|-------------------------|-----------|------------|--------------------------------------|
| RAM usage | 200-400mb~ | 2GB~ | 200-400mb~ | 2GB~ | idk | | RAM usage | 100-400mb~ | 400mb-1GB | 100mb | 200mb-1GB |
| Does it work | no (debunked by snopes) | yes | yes | a little | better than searx | | Does it suck | no | yes | kind of? | its kinda cool but no search filters |
| Does it work | ye | sometimes | sometimes | sometimes | yes | | Does it work | yes | err | is dead | works right now... |
## Features ## Features
1. Rotating proxies on a per-scraper basis 1. Rotating proxies on a per-scraper basis
@ -24,25 +24,29 @@ tl;dr FOSS-Q is the best way to browse for stuff.
# Supported websites # Supported websites
| Web | Images | Videos | News | Music | Autocompleter | | web | images | videos | news | music | autocomplete |
|------------|--------------|--------------|------------|------------|---------------| |--------------|--------------|--------------|--------------|------------|--------------|
| DuckDuckGo | DuckDuckGo | YouTube | DuckDuckGo | Soundcloud | Brave | | DuckDuckGo | DuckDuckGo | YouTube | DuckDuckGo | SoundCloud | Brave |
| Brave | Brave | Sepia Search | Brave | | DuckDuckGo | | Brave | Yandex | Vimeo | Brave | Swisscows | DuckDuckGo |
| Yandex | Yandex | DuckDuckGo | Google | | Yandex | | Yandex | Brave | Sepia Search | Google | | Yandex |
| Google | Google | Brave | Startpage | | Google | | Google | Google | DuckDuckGo | Yahoo! JAPAN | | Google |
| Startpage | Startpage | Yandex | Qwant | | Startpage | | Google API | Google API | Brave | Startpage | | Startpage |
| Qwant | Qwant | Google | Mojeek | | Kagi | | Google CSE | Google CSE | Yandex | Qwant | | Kagi |
| Ghostery | Yep | Startpage | Baidu | | Qwant | | Yahoo! JAPAN | Yahoo! JAPAN | Google | Mojeek | | Qwant |
| Yep | Baidu | Qwant | | | Ghostery | | Startpage | Startpage | Yahoo! JAPAN | Baidu | | Ghostery |
| Greppr | Pinterest | Baidu | | | Yep | | Qwant | Qwant | Startpage | | | Yep |
| Crowdview | 500px | Coc Coc | | | Marginalia | | Ghostery | Baidu | Qwant | | | Marginalia |
| Mwmbl | VSCO | | | | YouTube | | Yep | Solofield | Baidu | | | YouTube |
| Mojeek | Imgur | | | | Soundcloud | | Mwmbl | Pinterest | Coc Coc | | | SoundCloud |
| Baidu | FindThatMeme | | | | | | Mojeek | Cara | Solofield | | | |
| Coc Coc | | | | | | | Baidu | Flickr | | | | |
| Marginalia | | | | | | | Coc Coc | Pexels | | | | |
| wiby | | | | | | | Solofield | Pixabay | | | | |
| Curlie | | | | | | | Marginalia | Unsplash | | | | |
| wiby | 500px | | | | |
| | VSCO | | | | |
| | Imgur | | | | |
| | FindThatMeme | | | | |
# Installation # Installation
Refer to the <a href="https://git.flossboxin.org.in/FbIN/fossq/src/branch/main/docs/">documentation index</a>. I recommend following the <a href="https://git.flossboxin.org.in/FbIN/fossq/src/branch/main/docs/apache2.md">apache2 guide</a>. Refer to the <a href="https://git.flossboxin.org.in/FbIN/fossq/src/branch/main/docs/">documentation index</a>. I recommend following the <a href="https://git.flossboxin.org.in/FbIN/fossq/src/branch/main/docs/apache2.md">apache2 guide</a>.

View file

@ -553,28 +553,21 @@ class fuckhtml{
case "\"": case "\"":
case "'": case "'":
if( // count preceding backslashes
$i !== 0 && // only check if a quote could be there $bsCount = 0;
( $j = $i - 1;
(
$json[$i - 1] === "\\" &&
(
$i === 2 ||
$json[$i - 2] === "\\"
)
) ||
$json[$i - 1] !== "\\"
)
){
// found a non-escaped quote
while($j >= 0 && $json[$j] === "\\"){
$bsCount++;
$j--;
}
// quote is NOT escaped if even number of backslashes
if($bsCount % 2 === 0){
if($in_quote === null){ if($in_quote === null){
// open quote // open quote
$in_quote = $json[$i]; $in_quote = $json[$i];
}elseif($in_quote === $json[$i]){ }elseif($in_quote === $json[$i]){
// close quote // close quote
$in_quote = null; $in_quote = null;
} }

View file

@ -347,11 +347,8 @@ class brave{
$q["spellcheck"] = "0"; $q["spellcheck"] = "0";
} }
} }
/*
$handle = fopen("scraper/brave.html", "r");
$html = fread($handle, filesize("scraper/brave.html"));
fclose($handle);*/
//$html = file_get_contents("scraper/brave.html");
try{ try{
$html = $html =
$this->get( $this->get(

View file

@ -297,6 +297,14 @@ class pinterest{
throw new Exception("Failed to decode JSON"); throw new Exception("Failed to decode JSON");
} }
if(
isset($json["client_context"]["is_bad_bot"]) &&
(int)$json["client_context"]["is_bad_bot"] === 1
){
throw new Exception("Pinterest blocked this instance or request proxy.");
}
$out = [ $out = [
"status" => "ok", "status" => "ok",
"npt" => null, "npt" => null,
@ -426,7 +434,7 @@ class pinterest{
] ]
], ],
"url" => "url" =>
$item["link"] === null ? !isset($item["link"]) ?
"https://ca.pinterest.com/pin/" . $item["id"] : "https://ca.pinterest.com/pin/" . $item["id"] :
$item["link"] $item["link"]
]; ];

View file

@ -390,7 +390,7 @@ class yandex{
$title[0]["innerHTML"] == "403" $title[0]["innerHTML"] == "403"
){ ){
throw new Exception("Yandex blocked this proxy or FOSS-Q instance."); throw new Exception("Yandex blocked this proxy or 4get instance.");
} }
// get nextpage // get nextpage
@ -733,7 +733,7 @@ class yandex{
$json["type"] == "captcha" $json["type"] == "captcha"
){ ){
throw new Exception("Yandex blocked this FOSS-Q instance. Please try again in ~7 minutes."); throw new Exception("Yandex blocked this 4get instance. Please try again in ~7 minutes.");
} }
$out = [ $out = [
@ -868,123 +868,71 @@ class yandex{
if($get["npt"]){ if($get["npt"]){
[$params, $proxy] = [$get, $proxy] =
$this->backend->get( $this->backend->get(
$get["npt"], $get["npt"],
"video" "video"
); );
$params = json_decode($params, true); $get = json_decode($get, true);
$nsfw = $params["nsfw"];
unset($params["nsfw"]);
}else{ }else{
$search = $get["s"]; if(strlen($get["s"]) === 0){
if(strlen($search) === 0){
throw new Exception("Search term is empty!"); throw new Exception("Search term is empty!");
} }
$proxy = $this->backend->get_ip(); $proxy = $this->backend->get_ip();
$nsfw = $get["nsfw"]; }
$time = $get["time"];
$duration = $get["duration"];
// https://yandex.com/video/search?text=skycamefalling&from=tabbar&format=json&ncrnd=7271&p=0&parent-reqid=&request={%22blocks%22%3A[{%22block%22%3A%22video-app%22%2C%22params%22%3A{}}]}&serpid=1777751040971457-16832445014469941403-balancer-l7leveler-kubr-yp-klg-151-BAL&yu=3091577281773194415&tmpl_version=releases-frontend-video-v1.1816.0__3bdc24e10a8a138a1194877428e220a3ca0dbc5a
// https://yandex.com/video/search // https://yandex.com/video/search
// ?tmpl_version=releases/frontend/video/v1.1168.0#8d942de0f4ebc4eb6b8f3c24ffbd1f8dbc5bbe63 // ?text=skycamefalling
// &format=json
// &request=
// {
// "blocks":[
// {"block":"extra-content","params":{},"version":2},
// {"block":"i-global__params:ajax","params":{},"version":2},
// {"block":"search2:ajax","params":{},"version":2},
// {"block":"vital-incut","params":{},"version":2},
// {"block":"content_type_search","params":{},"version":2},
// {"block":"serp-controller","params":{},"version":2},
// {"block":"cookies_ajax","params":{},"version":2}
// ],
// "metadata":{
// "bundles":{"lb":"^G]!q<X120"},
// "assets":{"las":"react-with-dom=1;185.0=1;73.0=1;145.0=1;5a502a.0=1;32c342.0=1;b84ac8.0=1"},
// "extraContent":{"names":["i-react-ajax-adapter"]}
// }
// }
// &yu=4861394161661655015
// &from=tabbar // &from=tabbar
// &reqid=1693106278500184-6825210746979814879-balancer-l7leveler-kubr-yp-sas-7-BAL-4237 // &format=json
// &suggest_reqid=486139416166165501562797413447032 // &ncrnd=7271
// &text=minecraft // &p=0
// &parent-reqid=
// &request={%22blocks%22%3A[{%22block%22%3A%22video-app%22%2C%22params%22%3A{}}]} {"blocks":[{"block":"video-app","params":{}}]}
// &serpid=1777751040971457-16832445014469941403-balancer-l7leveler-kubr-yp-klg-151-BAL
// &yu=3091577281773194415
// &tmpl_version=releases-frontend-video-v1.1816.0__3bdc24e10a8a138a1194877428e220a3ca0dbc5a
$params = [ $params = [
"tmpl_version" => "releases/frontend/video/v1.1168.0#8d942de0f4ebc4eb6b8f3c24ffbd1f8dbc5bbe63", "text" => $get["s"],
"from" => "tabbar",
"format" => "json", "format" => "json",
"request" => json_encode([ "ncrnd" => 7271,
"p" => 0,
"parent-reqid" => "",
"request" => json_encode((object)[
"blocks" => [ "blocks" => [
(object)[ (object)[
"block" => "extra-content", "block" => "video-app",
"params" => (object)[], "params" => (object)[]
"version" => 2
],
(object)[
"block" => "i-global__params:ajax",
"params" => (object)[],
"version" => 2
],
(object)[
"block" => "search2:ajax",
"params" => (object)[],
"version" => 2
],
(object)[
"block" => "vital-incut",
"params" => (object)[],
"version" => 2
],
(object)[
"block" => "content_type_search",
"params" => (object)[],
"version" => 2
],
(object)[
"block" => "serp-controller",
"params" => (object)[],
"version" => 2
],
(object)[
"block" => "cookies_ajax",
"params" => (object)[],
"version" => 2
]
],
"metadata" => (object)[
"bundles" => (object)[
"lb" => "^G]!q<X120"
],
"assets" => (object)[
"las" => "react-with-dom=1;185.0=1;73.0=1;145.0=1;5a502a.0=1;32c342.0=1;b84ac8.0=1"
],
"extraContent" => (object)[
"names" => [
"i-react-ajax-adapter"
]
] ]
] ]
]), ]),
"text" => $search "serpid" => "1777751040971457-16832445014469941403-balancer-l7leveler-kubr-yp-klg-151-BAL",
"yu" => 3091577281773194415,
"tmpl_version" => "releases-frontend-video-v1.1816.0__3bdc24e10a8a138a1194877428e220a3ca0dbc5a"
]; ];
if($duration != "any"){ if(isset($get["p"])){
$params["duration"] = $duration; $params["p"] = $get["p"];
} }
if($time != "any"){ if($get["duration"] != "any"){
$params["within"] = $time; $params["duration"] = $get["duration"];
} }
if($get["time"] != "any"){
$params["within"] = $get["time"];
} }
/* /*
$handle = fopen("scraper/yandex-video.json", "r"); $handle = fopen("scraper/yandex-video.json", "r");
$json = fread($handle, filesize("scraper/yandex-video.json")); $json = fread($handle, filesize("scraper/yandex-video.json"));
@ -996,7 +944,7 @@ class yandex{
$proxy, $proxy,
"https://yandex.com/video/search", "https://yandex.com/video/search",
$params, $params,
$nsfw, $get["nsfw"],
"yandex_v" "yandex_v"
); );
}catch(Exception $error){ }catch(Exception $error){
@ -1011,9 +959,9 @@ class yandex{
throw new Exception("Could not parse JSON"); throw new Exception("Could not parse JSON");
} }
if(!isset($json["blocks"])){ if(!isset($json["results"]["clips"]["items"])){
throw new Exception("Yandex blocked this FOSS-Q instance. Please try again in 7~ minutes."); throw new Exception("Yandex blocked this 4get instance. Please try again in 7~ minutes.");
} }
$out = [ $out = [
@ -1026,209 +974,120 @@ class yandex{
"reel" => [] "reel" => []
]; ];
$html = null; foreach($json["results"]["clips"]["items"] as $k => $data){
foreach($json["blocks"] as $block){
if(isset($block["html"])){ if(isset($data["preview"]["posterSrc"])){
$html .= $block["html"]; $poster = $data["preview"]["posterSrc"];
}
if(
preg_match(
'/^\/\//',
$data["preview"]["posterSrc"]
)
){
$poster = "https:" . $poster;
} }
$this->fuckhtml->load($html); $thumb = [
"ratio" => "16:9",
"url" => $poster
];
}else{
$div = $thumb = [
$this->fuckhtml "ratio" => null,
->getElementsByTagName("div"); "url" => null
];
}
/* $out["video"][] = [
Get nextpage "title" => $data["relatedParams"]["text"],
*/ "description" => $this->titledots($data["description"]),
$npt = "author" => [
$this->fuckhtml "name" =>
->getElementsByClassName( isset($json["results"]["clips"]["dups"][$k]["host"]["secondPart"]["name"]) ?
"more more_direction_next i-bem", $json["results"]["clips"]["dups"][$k]["host"]["secondPart"]["name"] : null,
$div "url" =>
); isset($json["results"]["clips"]["dups"][$k]["host"]["secondPart"]["origUrl"]) ?
$json["results"]["clips"]["dups"][$k]["host"]["secondPart"]["origUrl"] : null,
"avatar" => null
],
"date" =>
isset($json["results"]["clips"]["dups"][$k]["date"]) ?
strtotime($json["results"]["clips"]["dups"][$k]["date"]) : null,
"duration" =>
isset($json["results"]["clips"]["dups"][$k]["duration"]["value"]) ?
(int)$json["results"]["clips"]["dups"][$k]["duration"]["value"] : null,
"views" =>
isset($json["results"]["clips"]["dups"][$k]["views"]["text"]) ?
$this->parseviews($json["results"]["clips"]["dups"][$k]["views"]["text"]) : null,
"thumb" => $thumb,
"url" =>
preg_replace(
'/^http:\/\//',
"https://",
$data["relatedParams"]["related_url"]
)
];
}
if(count($npt) !== 0){ // get npt
if($json["results"]["search"]["hasNextPage"]){
$get["p"] = (int)$json["results"]["search"]["currentPage"] + 1;
$params["p"] = "1";
$params["nsfw"] = $nsfw;
$out["npt"] = $out["npt"] =
$this->backend->store( $this->backend->store(
json_encode($params), json_encode($get),
"video", "video",
$proxy $proxy
); );
} }
$items =
$this->fuckhtml
->getElementsByClassName(
"serp-item",
$div
);
foreach($items as $item){
$data =
json_decode(
$this->fuckhtml
->getTextContent(
$item["attributes"]["data-video"]
),
true
);
$this->fuckhtml->load($item);
$thumb =
$this->fuckhtml
->getElementsByClassName(
"thumb-image__image",
"img"
);
$c = 1;
if(count($thumb) === 0){
$thumb = [
"url" => null,
"ratio" => null
];
}else{
$thumb = [
"url" =>
str_replace(
"//",
"https://",
$this->fuckhtml
->getTextContent(
$thumb
[0]
["attributes"]
["src"]
),
$c
),
"ratio" => "16:9"
];
}
$smallinfos =
$this->fuckhtml
->getElementsByClassName(
"serp-item__sitelinks-item",
"div"
);
$date = null;
$views = null;
$first = true;
foreach($smallinfos as $info){
if($first){
$first = false;
continue;
}
$info =
$this->fuckhtml
->getTextContent(
$info
);
if($temp_date = strtotime($info)){
$date = $temp_date;
}else{
$views = $this->parseviews($info);
}
}
$description =
$this->fuckhtml
->getElementsByClassName(
"serp-item__text serp-item__text_visibleText_always",
"div"
);
if(count($description) === 0){
$description = null;
}else{
$description =
$this->titledots(
$this->fuckhtml
->getTextContent(
$description[0]
)
);
}
$out["video"][] = [
"title" =>
$this->fuckhtml
->getTextContent(
$this->titledots(
$data["title"]
)
),
"description" => $description,
"author" => [
"name" => null,
"url" => null,
"avatar" => null
],
"date" => $date,
"duration" =>
(int)$data
["counters"]
["toHostingLoaded"]
["stredParams"]
["duration"],
"views" => $views,
"thumb" => $thumb,
"url" =>
str_replace(
"http://",
"https://",
$this->fuckhtml
->getTextContent(
$data["counters"]
["toHostingLoaded"]
["postfix"]
["href"]
),
$c
)
];
}
return $out; return $out;
} }
private function parseviews($text){ private function parseviews($number){
$text = explode(" ", $text); // decimal should always be 1 number long
$number = explode(" ", $number, 2);
$number = $number[0];
$num = (float)$text[0]; $unit = strtolower($number[strlen($number) - 1]);
$mod = $text[1];
switch($mod){ $tmp = explode(".", $number, 2);
$number = (int)$number;
case "bln.": $num = $num * 1000000000; break; if(count($tmp) === 2){
case "mln.": $num = $num * 1000000; break;
case "thsd.": $num = $num * 1000; break; $decimal = (int)$tmp[1];
}else{
$decimal = 0;
} }
return $num; switch($unit){
case "k":
$exponant = 1000;
break;
case "m":
$exponant = 1000000;
break;
case "b";
$exponant = 1000000000;
break;
default:
$exponant = 1;
break;
}
return ($number * $exponant) + ($decimal * ($exponant / 10));
} }
private function titledots($title){ private function titledots($title){