| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- <?php
- class sepiasearch{
-
- public function __construct(){
-
- include "lib/backend.php";
- $this->backend = new backend("sepiasearch");
- }
-
- public function getfilters($page){
-
- return [
- "nsfw" => [
- "display" => "NSFW",
- "option" => [
- "yes" => "Yes", // &sensitiveContent=both
- "no" => "No" // &sensitiveContent=false
- ]
- ],
- "language" => [
- "display" => "Language", // &language=
- "option" => [
- "any" => "Any language",
- "en" => "English",
- "fr" => "Français",
- "ar" => "العربية",
- "ca" => "Català",
- "cs" => "Čeština",
- "de" => "Deutsch",
- "el" => "ελληνικά",
- "eo" => "Esperanto",
- "es" => "Español",
- "eu" => "Euskara",
- "fa" => "فارسی",
- "fi" => "Suomi",
- "gd" => "Gàidhlig",
- "gl" => "Galego",
- "hr" => "Hrvatski",
- "hu" => "Magyar",
- "is" => "Íslenska",
- "it" => "Italiano",
- "ja" => "日本語",
- "kab" => "Taqbaylit",
- "nl" => "Nederlands",
- "no" => "Norsk",
- "oc" => "Occitan",
- "pl" => "Polski",
- "pt" => "Português (Brasil)",
- "pt-PT" => "Português (Portugal)",
- "ru" => "Pусский",
- "sk" => "Slovenčina",
- "sq" => "Shqip",
- "sv" => "Svenska",
- "th" => "ไทย",
- "tok" => "Toki Pona",
- "tr" => "Türkçe",
- "uk" => "украї́нська мо́ва",
- "vi" => "Tiếng Việt",
- "zh-Hans" => "简体中文(中国)",
- "zh-Hant" => "繁體中文(台灣)"
- ]
- ],
- "type" => [
- "display" => "Result type", // i handle this
- "option" => [
- "videos" => "Videos",
- "playlists" => "Playlists",
- "channels" => "Channels"
- ]
- ],
- "sort" => [
- "display" => "Sort by",
- "option" => [
- "best" => "Best match", // no filter
- "-publishedAt" => "Newest", // sort=-publishedAt
- "publishedAt" => "Oldest" // sort=publishedAt
- ]
- ],
- "newer" => [ // &startDate=2025-07-26T04:00:00.000Z
- "display" => "Newer than",
- "option" => "_DATE"
- ],
- "duration" => [
- "display" => "Duration",
- "option" => [
- "any" => "Any duration",
- "short" => "Short (0-4mins)", // &durationRange=short
- "medium" => "Medium (4-10 mins)",
- "long" => "Long (10+ mins)",
- ]
- ],
- "category" => [
- "display" => "Category", // &categoryOneOf[]=
- "option" => [
- "any" => "Any category",
- "1" => "Music",
- "2" => "Films",
- "3" => "Vehicles",
- "4" => "Art",
- "5" => "Sports",
- "6" => "Travels",
- "7" => "Gaming",
- "8" => "People",
- "9" => "Comedy",
- "10" => "Entertainment",
- "11" => "News & Politics",
- "12" => "How To",
- "13" => "Education",
- "14" => "Activism",
- "15" => "Science & Technology",
- "16" => "Animals",
- "17" => "Kids",
- "18" => "Food"
- ]
- ],
- "display" => [
- "display" => "Display",
- "option" => [
- "any" => "Everything",
- "true" => "Live videos", // &isLive=true
- "false" => "VODs" // &isLive=false
- ]
- ],
- "license" => [
- "display" => "License", // &license=
- "option" => [
- "any" => "Any license",
- "1" => "Attribution",
- "2" => "Attribution - Share Alike",
- "3" => "Attribution - No Derivatives",
- "4" => "Attribution - Non Commercial",
- "5" => "Attribution - Non Commercial - Share Alike",
- "6" => "Attribution - Non Commercial - No Derivatives",
- "7" => "Public Domain Dedication"
- ]
- ]
- ];
- }
-
- private function get($proxy, $url, $get = []){
-
- $curlproc = curl_init();
-
- if($get !== []){
- $get = http_build_query($get);
- $url .= "?" . $get;
- }
-
- curl_setopt($curlproc, CURLOPT_URL, $url);
- curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
-
- curl_setopt(
- $curlproc,
- CURLOPT_HTTPHEADER,
- ["User-Agent: " . config::USER_AGENT,
- "Accept: */*",
- "Accept-Language: en-US,en;q=0.5",
- "Accept-Encoding: gzip",
- "Cookie: PREF=tz=America.New_York",
- "Referer: https://youtube.com.com/",
- "Content-Type: application/json",
- "DNT: 1",
- "Connection: keep-alive",
- "Sec-Fetch-Dest: empty",
- "Sec-Fetch-Mode: same-origin",
- "Sec-Fetch-Site: same-origin"]
- );
-
- curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
- curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
- curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
- curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
- $this->backend->assign_proxy($curlproc, $proxy);
-
- $data = curl_exec($curlproc);
-
- if(curl_errno($curlproc)){
-
- throw new Exception(curl_error($curlproc));
- }
-
- curl_close($curlproc);
- return $data;
- }
-
- public function video($get){
-
- if($get["npt"]){
-
- [$npt, $proxy] =
- $this->backend
- ->get(
- $get["npt"],
- "videos"
- );
-
- $npt = json_decode($npt, true);
- $type = $npt["type"];
- $npt = $npt["npt"];
- }else{
-
- $proxy = $this->backend->get_ip();
-
- $npt = [
- "search" => $get["s"],
- "start" => 0,
- "count" => 20
- ];
-
- if($get["type"] == "videos"){
-
- //
- // Parse video filters
- //
- switch($get["nsfw"]){
-
- case "yes": $npt["nsfw"] = "both"; break;
- case "no": $npt["nsfw"] = "false"; break;
- }
-
- $npt["boostLanguages[]"] = "en";
- if($get["language"] != "any"){
-
- $npt["languageOneOf[]"] = $get["language"];
- }
-
- if($get["sort"] != "best"){
-
- $npt["sort"] = $get["sort"];
- }
-
- if($get["newer"] !== false){
-
- $date = new DateTime("@{$get["newer"]}");
- $date->setTimezone(new DateTimeZone("UTC"));
- $formatted = $date->format("Y-m-d\TH:i:s.000\Z");
-
- $npt["startDate"] = $formatted;
- }
-
- switch($get["duration"]){
-
- case "short":
- $npt["durationMax"] = 240;
- break;
-
- case "medium":
- $npt["durationMin"] = 240;
- $npt["durationMax"] = 600;
- break;
-
- case "long":
- $npt["durationMin"] = 600;
- break;
- }
-
- if($get["category"] != "any"){
-
- $npt["categoryOneOf[]"] = $get["category"];
- }
-
- if($get["display"] != "any"){
-
- $npt["isLive"] = $get["display"];
- }
-
- if($get["license"] != "any"){
-
- // typo in license, lol
- $npt["licenceOneOf[]"] = $get["license"];
- }
- }
-
- $type = $get["type"];
- }
-
- switch($type){
-
- case "videos":
- $url = "https://sepiasearch.org/api/v1/search/videos";
- break;
-
- case "channels":
- $url = "https://sepiasearch.org/api/v1/search/video-channels";
- break;
-
- case "playlists":
- $url = "https://sepiasearch.org/api/v1/search/video-playlists";
- break;
- }
-
- //$json = file_get_contents("scraper/sepia.json");
- try{
-
- $json =
- $this->get(
- $proxy,
- $url,
- $npt
- );
- }catch(Exception $error){
-
- throw new Exception("Failed to fetch JSON");
- }
-
- $json = json_decode($json, true);
-
- if($json === null){
-
- throw new Exception("Failed to parse JSON");
- }
-
- if(isset($json["errors"])){
-
- $msg = [];
- foreach($json["errors"] as $error){
-
- if(isset($error["msg"])){
-
- $msg[] = $error["msg"];
- }
- }
-
- throw new Exception("Sepia Search returned error(s): " . implode(", ", $msg));
- }
-
- if(!isset($json["data"])){
-
- throw new Exception("Sepia Search did not return a data object");
- }
-
- $out = [
- "status" => "ok",
- "npt" => null,
- "video" => [],
- "author" => [],
- "livestream" => [],
- "playlist" => [],
- "reel" => []
- ];
-
-
- switch($get["type"]){
-
- case "videos":
- foreach($json["data"] as $video){
-
- if(count($video["account"]["avatars"]) !== 0){
-
- $avatar =
- $video["account"]["avatars"][count($video["account"]["avatars"]) - 1]["url"];
- }else{
-
- $avatar = null;
- }
-
- if($video["thumbnailUrl"] === null){
-
- $thumb = [
- "ratio" => null,
- "url" => null
- ];
- }else{
-
- $thumb = [
- "ratio" => "16:9",
- "url" => $video["thumbnailUrl"]
- ];
- }
-
- if($video["isLive"]){
-
- $append = "livestream";
- }else{
-
- $append = "video";
- }
-
- $out[$append][] = [
- "title" => $video["name"],
- "description" =>
- $this->limitstrlen(
- $this->titledots(
- $video["description"]
- )
- ),
- "author" => [
- "name" => $video["account"]["displayName"] . " ({$video["account"]["name"]})",
- "url" => $video["account"]["url"],
- "avatar" => $avatar
- ],
- "date" => strtotime($video["publishedAt"]),
- "duration" => $video["isLive"] ? "_LIVE" : $video["duration"],
- "views" => $video["views"],
- "thumb" => $thumb,
- "url" => $video["url"]
- ];
- }
- break;
-
- case "playlists":
- foreach($json["data"] as $playlist){
-
- if(count($playlist["ownerAccount"]["avatars"]) !== 0){
-
- $avatar =
- $playlist["ownerAccount"]["avatars"][count($playlist["ownerAccount"]["avatars"]) - 1]["url"];
- }else{
-
- $avatar = null;
- }
-
- if($playlist["thumbnailUrl"] === null){
-
- $thumb = [
- "ratio" => null,
- "url" => null
- ];
- }else{
-
- $thumb = [
- "ratio" => "16:9",
- "url" => $playlist["thumbnailUrl"]
- ];
- }
-
- $out["playlist"][] = [
- "title" => $playlist["displayName"],
- "description" =>
- $this->limitstrlen(
- $this->titledots(
- $playlist["description"]
- )
- ),
- "author" => [
- "name" => $playlist["ownerAccount"]["displayName"] . " ({$playlist["ownerAccount"]["name"]})",
- "url" => $playlist["ownerAccount"]["url"],
- "avatar" => $avatar
- ],
- "date" => strtotime($playlist["createdAt"]),
- "duration" => $playlist["videosLength"],
- "views" => null,
- "thumb" => $thumb,
- "url" => $playlist["url"]
- ];
- }
- break;
-
- case "channels":
- foreach($json["data"] as $channel){
-
- if(count($channel["avatars"]) !== 0){
-
- $thumb = [
- "ratio" => "1:1",
- "url" => $channel["avatars"][count($channel["avatars"]) - 1]["url"]
- ];
- }else{
-
- $thumb = [
- "ratio" => null,
- "url" => null
- ];
- }
-
- $out["author"][] = [
- "title" => $channel["displayName"] . " ({$channel["name"]})",
- "followers" => $channel["followersCount"],
- "description" =>
- $channel["videosCount"] . " videos. " .
- $this->limitstrlen(
- $this->titledots(
- $channel["description"]
- )
- ),
- "thumb" => $thumb,
- "url" => $channel["url"]
- ];
- }
- break;
- }
-
- // get next page
- if($json["total"] - 20 > $npt["start"]){
-
- $npt["start"] += 20;
-
- $npt = [
- "type" => $get["type"],
- "npt" => $npt
- ];
-
- $out["npt"] =
- $this->backend
- ->store(
- json_encode($npt),
- "videos",
- $proxy
- );
- }
-
- return $out;
- }
-
- private function titledots($title){
-
- $substr = substr($title, -3);
-
- if(
- $substr == "..." ||
- $substr == "…"
- ){
-
- return trim(substr($title, 0, -3), " \n\r\t\v\x00\0\x0B\xc2\xa0");
- }
-
- return trim($title, " \n\r\t\v\x00\0\x0B\xc2\xa0");
- }
-
- private function limitstrlen($text){
-
- return
- explode(
- "\n",
- wordwrap(
- str_replace(
- ["\n\r", "\r\n", "\n", "\r"],
- " ",
- $text
- ),
- 300,
- "\n"
- ),
- 2
- )[0];
- }
- }
|