LibreY

- privacy respecting meta search engine
git clone git://git.acid.vegas/LibreY.git
Log | Files | Refs | Archive | README | LICENSE

commit 1ffb41a09a465c0613768af39dfc6c278f8f7b9d
parent a9450fb013f50bf9cd8fba79d9638564f39b15ab
Author: acidvegas <acid.vegas@acid.vegas>
Date: Sun, 12 Nov 2023 16:08:50 -0500

Updated to the latest version

Diffstat:
MREADME.md | 9+++++++--
Mapi.php | 1+
Mdonate.php | 11++++-------
Mengines/ahmia/hidden_service.php | 2+-
Mengines/bittorrent/get_magnet_1337x.php | 7+++----
Mengines/bittorrent/merge.php | 2+-
Mengines/bittorrent/yts.php | 2+-
Mengines/librex/fallback.php | 4+++-
Mengines/qwant/image.php | 14+++++++++-----
Mengines/special/definition.php | 9++++++---
Mengines/special/special.php | 2+-
Mengines/special/wikipedia.php | 2++
Mengines/text/duckduckgo.php | 5++---
Mengines/text/google.php | 9+++------
Mimage_proxy.php | 2+-
Mindex.php | 3+--
Minstances.json | 71+++++++++++++++++++++++++----------------------------------------------
Minstances.php | 2+-
Alocale/en.php | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Alocale/localization.php | 28++++++++++++++++++++++++++++
Alocale/nl.php | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Alocale/sv.php | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmisc/footer.php | 4++--
Mmisc/header.php | 3++-
Mmisc/search_engine.php | 4++--
Mmisc/tools.php | 6++----
Aopensearch.xml.example | 11+++++++++++
Msearch.php | 2+-
Msettings.php | 24++++++++++++------------

29 files changed, 290 insertions(+), 107 deletions(-)

diff --git a/README.md b/README.md
@@ -13,6 +13,10 @@
 
 <br>
 
+## Matrix
+
+If there's an important announcement, we do have a Matrix chatroom which you can join over at #librey:ahwx.org.
+
 ### Instances
 
 You can find a list of instances on any LibreY instance by accessing /instances.php.<br>
@@ -25,8 +29,10 @@ Instance list on [@codedipper](https://github.com/codedipper)'s instance:<br>
 [Tor](http://librex.revvybrr6pvbx4n3j4475h4ghw4elqr4t5xo2vtd3gfpu2nrsnhh57id.onion/instances.php)<br>
 [I2P](http://revekebotog64xrrammtsmjwtwlg3vqyzwdurzt2pu6botg4bejq.b32.i2p/instances.php)<br>
 <br>
-[@Ahwxorg](https://github.com/Ahwxorg)'s instance:<br>
+[@Ahwxorg](https://github.com/Ahwxorg)'s instances:<br>
 [search.ahwx.org](https://search.ahwx.org/instances.php)<br>
+[Tor](http://wn5jl6fxlzzfenlyu3lc4q7jpw2saplrywxvxtvqbguotwd4y5cjeuqd.onion/instances.php)<br>
+[search2.ahwx.org](https://search.ahwx.org/instances.php)<br>
 [Tor](http://hyy7rcvknwb22v4nnoar635wntiwr4uwzhiuyimemyl4fz6k7tahj5id.onion/instances.php)<br>
 <br>
 [@davidovski](https://github.com/davidovski)'s instance:<br>
@@ -46,4 +52,3 @@ LibreY gives you text results from DuckDuckGo or Google, images from Qwant, and 
 | LibreY | ✅ | ✅ | ✅ | ✅ | ✅ |
 | SearXNG | ❓ Not user friendly | ❓ Only host can set it | ✅ | ✅ | ❌ |
 | Whoogle | ✅ | ❓ Only host can set it | ❌ | ❌ | ❌ |
-
diff --git a/api.php b/api.php
@@ -1,6 +1,7 @@
 <?php
     require "misc/tools.php";
     require "misc/search_engine.php";
+    require "locale/localization.php";
 
     $opts = load_opts();
 
diff --git a/donate.php b/donate.php
@@ -10,8 +10,7 @@
     <div class="donate-container">
       <!-- librex dev -->
       <h2>
-        Donate to the original developer of Libre<span class="Y">X</span>, a
-        project LibreY tries to improve.
+<?php printftext("donate_original_developer", "Libre<span class=\"Y\">X</span>")?>
       </h2>
 
       <div class="flexbox-column">
@@ -46,11 +45,9 @@
         <hr class="small-line" />
 
         <!-- librey dev -->
-        <h2>
-          Donate to the person that forked LibreX into Libre<span class="Y"
-            >Y</span
-          >
-        </h2>
+      <h2>
+<?php printftext("donate_fork", "Libre<span class=\"Y\">X</span>")?>
+      </h2>
 
         <div class="qr-box">
           <div class="inner-wrap">
diff --git a/engines/ahmia/hidden_service.php b/engines/ahmia/hidden_service.php
@@ -21,7 +21,7 @@
 
                 array_push($results,
                     array (
-                        "title" => $title ? htmlspecialchars($title) : "No description provided",
+                        "title" => $title ? htmlspecialchars($title) : TEXTS["result_no_description"],
                         "url" =>  htmlspecialchars($url),
                         // base_url is to be removed in the future, see #47
                         "base_url" => htmlspecialchars(get_base_url($url)),
diff --git a/engines/bittorrent/get_magnet_1337x.php b/engines/bittorrent/get_magnet_1337x.php
@@ -4,12 +4,12 @@
 
     $url = $_REQUEST["url"];
 
-    $response = request($url);
+    $response = request($url, $config->curl_settings);
     $xpath = get_xpath($response);
-
+    
     $magnet = $xpath->query("//main/div/div/div/div/div/ul/li/a/@href")[0]->textContent;
     $magnet_without_tracker = explode("&tr=", $magnet)[0];
     $magnet = $magnet_without_tracker . $config->bittorent_trackers;
 
     header("Location: $magnet")
-?>
-\ No newline at end of file
+?>
diff --git a/engines/bittorrent/merge.php b/engines/bittorrent/merge.php
@@ -38,7 +38,7 @@
             echo "<div class=\"text-result-container\">";
 
             if (empty($results)) {
-                echo "<p>There are no results. Please try different keywords!</p>";
+                echo "<p>" . TEXTS["failure_empty"] . "</p>";
                 return;
             }
 
diff --git a/engines/bittorrent/yts.php b/engines/bittorrent/yts.php
@@ -25,7 +25,7 @@
                         $leechers = $torrent["peers"];
                         $size = $torrent["size"];
 
-                        $magnet = "magnet:?xt=urn:btih:$hash&dn=$name_encoded$this->opts->bittorrent_trackers";
+                        $magnet = "magnet:?xt=urn:btih:$hash&dn=$name_encoded" . $this->opts->bittorrent_trackers;
 
                         array_push($results,
                             array (
diff --git a/engines/librex/fallback.php b/engines/librex/fallback.php
@@ -49,6 +49,8 @@
             if (!$instance)
                 break;
 
+            if (!filter_var($instance, FILTER_VALIDATE_URL) || !filter_var($_SERVER["HTTP_HOST"], FILTER_VALIDATE_URL))
+                continue;
             if (parse_url($instance)["host"] == parse_url($_SERVER['HTTP_HOST'])["host"])
                 continue;
 
@@ -67,7 +69,7 @@
 
         return array(
             "error" => array(
-                "message" => "No results found. Unable to fallback to other instances."
+                "message" => TEXTS["failure_fallback"]
             )
         );
     }
diff --git a/engines/qwant/image.php b/engines/qwant/image.php
@@ -3,7 +3,7 @@
         public function get_request_url() {
             $page = $this->page / 10 + 1; // qwant has a different page system
             $query = urlencode($this->query);
-            
+
             return "https://lite.qwant.com/?q=$query&t=images&p=$page";
         }
 
@@ -15,7 +15,7 @@
                 return $results;
 
             foreach($xpath->query("//a[@rel='noopener']") as $result)
-            {       
+            {
                     $image = $xpath->evaluate(".//img", $result)[0];
 
                     if ($image)
@@ -28,25 +28,29 @@
                         $alt = $image->getAttribute("alt");
                         $thumbnail = urlencode($image->getAttribute("src"));
 
-                        array_push($results, 
+                        array_push($results,
                             array (
                                 "thumbnail" => urldecode(htmlspecialchars($thumbnail)),
                                 "alt" => htmlspecialchars($alt),
                                 "url" => htmlspecialchars($real_url)
                             )
                         );
-        
+
                     }
             }
 
             return $results;
         }
-        
+
         public static function print_results($results, $opts) {
             echo "<div class=\"image-result-container\">";
 
                 foreach($results as $result)
                 {
+                    if (!$result 
+                        || !array_key_exists("url", $result)
+                        || !array_key_exists("alt", $result))
+                        continue;
                     $thumbnail = urlencode($result["thumbnail"]);
                     $alt = $result["alt"];
                     $url = $result["url"];
diff --git a/engines/special/definition.php b/engines/special/definition.php
@@ -4,13 +4,16 @@
         public function get_request_url() {
             $split_query = explode(" ", $this->query);
             $reversed_split_q = array_reverse($split_query);
-            $word_to_define = $reversed_split_q[1];
+            $word_to_define = $reversed_split_q[1] == "define" ? $reversed_split_q[0] : $reversed_split_q[1];
             return "https://api.dictionaryapi.dev/api/v2/entries/en/$word_to_define";
         }
-        
+
         public function parse_results($response) {
             $json_response = json_decode($response, true);
 
+            if (!$json_response)
+                return array();
+
             if (!array_key_exists("title", $json_response))
             {
                 $definition = $json_response[0]["meanings"][0]["definitions"][0]["definition"];
@@ -23,7 +26,7 @@
                     )
                 );
             }
-        
+
         }
     }
 ?>
diff --git a/engines/special/special.php b/engines/special/special.php
@@ -13,7 +13,7 @@
             if ($amount_to_convert != 0)
                 return 1;
          }
-         else if (strpos($query_lower, "mean") && count($split_query) >= 2) // definition
+         else if ((strpos($query_lower, "mean")  || str_starts_with($query_lower, "define")) && count($split_query) >= 2) // definition
          {
              return 2;
          }
diff --git a/engines/special/wikipedia.php b/engines/special/wikipedia.php
@@ -14,6 +14,8 @@
 
         public function parse_results($response) {
             $json_response = json_decode($response, true);
+            if (!$json_response)
+                return array();
 
             $first_page = array_values($json_response["query"]["pages"])[0];
 
diff --git a/engines/text/duckduckgo.php b/engines/text/duckduckgo.php
@@ -1,7 +1,6 @@
 <?php
     class DuckDuckGoRequest extends EngineRequest {
-        function get_request_url()
-        {
+        public function get_request_url() {
             $query_encoded = str_replace("%22", "\"", urlencode($this->query));
             $results = array();
 
@@ -53,7 +52,7 @@
                         // base_url is to be removed in the future, see #47
                         "base_url" => htmlspecialchars(get_base_url($url)),
                         "description" =>  $description == null ?
-                                          "No description was provided for this site." :
+                                          TEXTS["result_no_description"] :
                                           htmlspecialchars($description->textContent)
                     )
                 );
diff --git a/engines/text/google.php b/engines/text/google.php
@@ -46,11 +46,8 @@
                 if ($url == null)
                     continue;
 
-                if (!empty($results)) // filter duplicate results, ignore special result
-                {
-                    if (end($results)["url"] == $url->textContent)
+                    if (!empty($results) && array_key_exists("url", $results) && end($results)["url"] == $url->textContent)
                         continue;
-                }
 
                 $url = $url->textContent;
 
@@ -64,7 +61,7 @@
                         // base_url is to be removed in the future, see #47
                         "base_url" => htmlspecialchars(get_base_url($url)),
                         "description" =>  $description == null ?
-                                          "No description was provided for this site." :
+                                          TEXTS["result_no_description"] :
                                           htmlspecialchars($description->textContent)
                     )
                 );
@@ -72,7 +69,7 @@
 
             if (empty($results) && !str_contains($response, "Our systems have detected unusual traffic from your computer network.")) {
                 $results["error"] = array(
-                    "message" => "There are no results. Please try different keywords!"
+                    "message" => TEXTS["failure_empty"]
                 );
             }
 
diff --git a/image_proxy.php b/image_proxy.php
@@ -11,7 +11,7 @@
     if (in_array($requested_root_domain, $allowed_domains))
     {
       $image = $url;
-      $image_src = request($image);
+      $image_src = request($image, $config->curl_settings);
 
       header("Content-Type: image/png");
       echo $image_src;
diff --git a/index.php b/index.php
@@ -1,4 +1,3 @@
-
 <?php require "misc/header.php"; ?>
     <title>SuperLibreX</title>
     </head>
@@ -10,7 +9,7 @@
                 <input type="hidden" name="t" value="0"/>
                 <input type="submit" class="hide"/>
                 <div class="search-button-wrapper">
-                    <button name="t" value="0" type="submit">Surfs Up 🏄‍♂️🌊</button>
+                    <button name="t" value="0" type="submit">Surfs Up 🏄♂🌊</button>
                 </div>
         </form>
 <?php require "misc/footer.php"; ?>
diff --git a/instances.json b/instances.json
@@ -29,20 +29,20 @@
               "librey": true
           },
           {
-              "clearnet": "https://librex.zzls.xyz/",
-              "tor": "http://librex.zzlsghu6mvvwyy75mvga6gaf4znbp3erk5xwfzedb4gg6qqh2j6rlvid.onion/",
-              "i2p": "http://zzlsaymhcfla7vibo3a223bybeecu3bd5z6rmw2u4y76maqeu76q.b32.i2p/",
-              "country": "CL",
-              "librey": true
+            "clearnet": "https://ly.owo.si/",
+            "tor": "http://ly.pk47sgwhncn5cgidm7bofngmh7lc7ukjdpk5bjwfemmyp27ovl25ikyd.onion/",
+            "i2p": "http://d4vi3tvfui2rfzsxr33tin4a6542heulf4mhkokdpbhbcejlg3la.b32.i2p/",
+            "country": "DE",
+            "librey": true
           },
-          {
-              "clearnet": "https://lx.vern.cc/",
-              "tor": "http://lx.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion/",
-              "i2p": "http://vernziqfqvweijfaacmwazohgpdo2bt2ib2jlupt2pwwu27bhgxq.b32.i2p/",
-              "country": "US",
-              "librey": true
+	  {
+            "clearnet": "https://librey.danyaal.xyz/",
+            "tor": "http://libreytvcxak42f3p7nxh3filsp2pjqesjii5f5e4eivs2gpcn77tdid.onion/",
+            "i2p": "http://libreyqmoa2iuihoyyscolhaymrxxgdrmkgmiufnyaukwub2c7ya.b32.i2p/",
+            "country": "GB",
+            "librey": true
           },
-          {
+           {
               "clearnet": "https://librey.org/",
               "tor": "http://jxhkfulu6wpdl4apuy4dyivuowmpprvsd7e3el2z73crq7fmyv7rjkyd.onion/",
               "i2p": null,
@@ -50,24 +50,17 @@
               "librey": true
           },
           {
-              "clearnet": "https://search.davidovski.xyz/",
-              "tor": null,
-              "i2p": null,
-              "country": "GB",
-              "librey": true
-          },
-          {
-              "clearnet": "https://librey.spaceint.fr/",
-              "tor": null,
+              "clearnet": "https://librex.supernets.org/",
+              "tor": "http://ouosr2fq3lktngcvbz4r4op2lab5hbiz5y6g6toorsgieb7elet76jad.onion/",
               "i2p": null,
-              "country": "FR",
+              "country": "US",
               "librey": true
           },
           {
-              "clearnet": "https://librey.bloatcat.tk/",
+              "clearnet": "https://search.davidovski.xyz/",
               "tor": null,
               "i2p": null,
-              "country": "IS",
+              "country": "GB",
               "librey": true
           },
           {
@@ -106,11 +99,11 @@
               "librey": true
           },
           {
-            "clearnet": "https://librex.yogeshlamichhane.com.np/",
-            "tor": null,
-            "i2p": null,
-            "country": "FI",
-            "librey": true
+              "clearnet": "https://librex.yogeshlamichhane.com.np/",
+              "tor": null,
+              "i2p": null,
+              "country": "FI",
+              "librey": true
           },
           {
               "clearnet": "https://librey.baczek.me/",
@@ -127,25 +120,11 @@
               "librey": true
           },
           {
-              "clearnet": "https://librex.supernets.org/",
-              "tor": "http://ouosr2fq3lktngcvbz4r4op2lab5hbiz5y6g6toorsgieb7elet76jad.onion/",
-              "i2p": null,
-              "country": "US",
-              "librey": true
-          },
-          {
-              "clearnet": "https://lx.owo.si/",
-              "tor": "http://lx.pk47sgwhncn5cgidm7bofngmh7lc7ukjdpk5bjwfemmyp27ovl25ikyd.onion/",
-              "i2p": "http://d4vi3tvfui2rfzsxr33tin4a6542heulf4mhkokdpbhbcejlg3la.b32.i2p/",
-              "country": "DE",
-              "librey": false
-          },
-          {
-              "clearnet": "https://search.tildevarsh.in/",
+              "clearnet": "https://search.seitan-ayoub.lol/",
               "tor": null,
               "i2p": null,
-              "country": "IN",
-              "librey": false
+              "country": "DE",
+              "librey": true
           },
           {
               "clearnet": "https://librex.myroware.eu/",
diff --git a/instances.php b/instances.php
@@ -51,7 +51,7 @@
                 list_instances($librey_instances);
             ?>
 
-            <p>The following instances are running the older <a href="https://github.com/hnhx/librex">LibreX</a>:</p>
+                <p><?php printftext("instances_librex", "<a href=\"https://github.com/hnhx/librex\">LibreX</a>")?>:</p>
             <?php
                 list_instances($librex_instances);
             ?>
diff --git a/locale/en.php b/locale/en.php
@@ -0,0 +1,53 @@
+<?php
+
+return array(
+    "page_title" => "LibreY search",
+    "search_button" => "Search with LibreY",
+    "torrent_search_button" => "Search torrents with LibreY",
+
+    "source_code_link" => "Source",
+    "instances_link" => "Instances",
+    "settings_link" => "Settings",
+    "api_link" => "API",
+    "donate_link" => "Donate ❤️",
+
+    "latest_commit" => "Latest commit: %s",
+
+    "category_general" => "General",
+    "category_images" => "Images",
+    "category_videos" => "Videos",
+    "category_torrents" => "Torrents",
+    "category_tor" => "Tor",
+
+    "feature_disabled" => "The host has disabled this feature :C",
+
+    "settings_title" => "Settings",
+    "settings_theme" => "Theme",
+    "settings_special_disabled" => "Disable special queries (e.g.: currency conversion)",
+
+    "settings_frontends" => "Privacy friendly frontends",
+    "settings_frontends_description" => "For an example if you want to view YouTube without getting spied on, click on \"Invidious\", find the instance that is most suitable for you then paste it in (correct format: https://example.com)",
+    "settings_frontends_disable" => "Disable frontends",
+
+    "settings_search_settings" => "Search settings",
+    "settings_language" => "Language",
+
+    "settings_number_of_results" => "Number of results per page",
+
+    "settings_safe_search" => "Safe search",
+    "settings_save" => "Save",
+    "settings_reset" => "Reset",
+
+
+    "failure_fallback" => "No results found. Unable to fallback to other instances.",
+    "failure_empty" => "No results found. Please try different keywords!",
+    "result_no_description" => "No description was provided for this site.",
+
+    "instances_librex" => "The following instances are running the older %s",
+
+    "donate_original_developer" => "Donate to the original developer of %s, a
+        project LibreY tries to improve.",
+    "donate_fork" => "Donate to the person that forked %s into LibreY"
+);
+
+?>
diff --git a/locale/localization.php b/locale/localization.php
@@ -0,0 +1,28 @@
+<?php
+
+function printtext($key) {
+    echo TEXTS[$key];
+}
+
+function printftext() {
+    $argv = func_get_args();
+    $key = array_shift($argv);
+    vprintf(TEXTS[$key], $argv);
+}
+
+// default to language "en"
+$locale = "en";
+
+if (array_key_exists("HTTP_ACCEPT_LANGUAGE", $_SERVER)) {
+    $accept_language_header = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
+
+    foreach(explode(",", explode(";", $accept_language_header)[0]) as $header_language) {
+        if (file_exists("locale/$header_language.php")) {
+            $locale = $header_language;
+            break;
+        }
+    }
+}
+
+define("TEXTS", require "locale/$locale.php");
+?>
diff --git a/locale/nl.php b/locale/nl.php
@@ -0,0 +1,52 @@
+<?php
+
+return array(
+    "page_title" => "LibreY search",
+    "search_button" => "Zoek met LibreY",
+    "torrent_search_button" => "Zoek naar torrents met LibreY",
+
+    "source_code_link" => "Broncode",
+    "instances_link" => "Instances",
+    "settings_link" => "Instellingen",
+    "api_link" => "API",
+    "donate_link" => "Doneer ❤️",
+
+    "latest_commit" => "Laatste commit: %s",
+
+    "category_general" => "Algemeem",
+    "category_images" => "Foto's",
+    "category_videos" => "Videos",
+    "category_torrents" => "Torrents",
+    "category_tor" => "Tor",
+
+    "feature_disabled" => "De host heeft deze functie uitgeschakeld :C",
+
+    "settings_title" => "Instellingen",
+    "settings_theme" => "Thema",
+    "settings_special_disabled" => "Schakel speciale zoekopdrachten uit (bijvoorbeeld: valutaconversie)",
+
+    "settings_frontends" => "Privacyvriendelijke frontends",
+    "settings_frontends_description" => "Als je - bijvoorbeeld - naar YouTube wil kijken zonder bespioneerd te worden, klik dan op \"Invidious\", zoek een instance die het best voor jou is en plak de URL hier in (correct formaat: https://example.com)",
+    "settings_frontends_disable" => "Frontends uitschakelen",
+
+    "settings_search_settings" => "Zoek-gerelateerde instellingen",
+    "settings_language" => "Taal",
+
+    "settings_number_of_results" => "Resulaten per pagina (in nummers)",
+
+    "settings_safe_search" => "Safe search",
+    "settings_save" => "Opslaan",
+    "settings_reset" => "Reset",
+
+
+    "failure_fallback" => "Geen resultaten gevonden. Kan niet terugvallen op andere instances.",
+    "failure_empty" => "Geen resultaten gevonden. Probeer een andere zoekterm/andere keywords!",
+    "result_no_description" => "Voor deze website is geen omschrijving gegeven.",
+
+    "instances_librex" => "De volgende instances draaien de oudere versie; %s",
+
+    "donate_original_developer" => "Doneer aan de originele ontwikkelaar van %s, een project dat LibreY probeert te verbeteren.",
+    "donate_fork" => "Doneer aan de persoon die %s heeft geforkt naar LibreY"
+);
+
+?>
diff --git a/locale/sv.php b/locale/sv.php
@@ -0,0 +1,53 @@
+<?php
+
+return array(
+    "page_title" => "LibreY search",
+    "search_button" => "Sök med LibreY",
+    "torrent_search_button" => "Sök torrents med LibreY",
+
+    "source_code_link" => "Källkod",
+    "instances_link" => "Instanser",
+    "settings_link" => "Inställningar",
+    "api_link" => "API",
+    "donate_link" => "Donera ❤️",
+
+    "latest_commit" => "Senaste commit: %s",
+
+    "category_general" => "Allmänt",
+    "category_images" => "Bilder",
+    "category_videos" => "Videor",
+    "category_torrents" => "Torrents",
+    "category_tor" => "Tor",
+
+    "feature_disabled" => "Funktionen är inaktiverad av serverägaren :C",
+
+    "settings_title" => "Inställningar",
+    "settings_theme" => "Tema",
+    "settings_special_disabled" => "Inaktivera specialförfrågningar (t.ex. valutaomvandlare)",
+
+    "settings_frontends" => "Privata frontends",
+    "settings_frontends_description" => "För om du vill titta på YouTube utan att bli spionerad på, klicka på \"Invidious\", hitta den instans som passar dig bäst och klistra in (korrekt format: https://example.com)",
+    "settings_frontends_disable" => "Stäng av frontends",
+
+    "settings_search_settings" => "Sökinställningar",
+    "settings_language" => "Språk",
+
+    "settings_number_of_results" => "Antal resultat per sida",
+
+    "settings_safe_search" => "Safe search",
+    "settings_save" => "Spara",
+    "settings_reset" => "Återställ",
+
+
+    "failure_fallback" => "Inga resultat hittades. Gick inte att använda andra instanser som reservlösning.",
+    "failure_empty" => "Inga resultat hittades. Var god försök med andra nyckelord!",
+    "result_no_description" => "Ingen beskrivning finns för denna webbplats.",
+
+    "instances_librex" => "Följande instanser kör den äldre %s",
+
+    "donate_original_developer" => "Donera till orginalutvecklaren av %s, ett
+        projekt som LibreY försöker förbättra.",
+    "donate_fork" => "Donera till personen som forkade %s till LibreY"
+);
+
+?>
diff --git a/misc/footer.php b/misc/footer.php
@@ -3,8 +3,8 @@
     <a href="./settings.php">Settings</a>
     <a href="./api.php" target="_blank">API</a>
     <a href="./donate.php">Donate</a>
-	<a href="http://ouosr2fq3lktngcvbz4r4op2lab5hbiz5y6g6toorsgieb7elet76jad.onion/">Onion</a>
-	<a href="https://supernets.org/">SuperNETs</a>
+    <a href="http://ouosr2fq3lktngcvbz4r4op2lab5hbiz5y6g6toorsgieb7elet76jad.onion/">Onion</a>
+    <a href="https://supernets.org/">SuperNETs</a>
 </div>
 </body>
 </html>
diff --git a/misc/header.php b/misc/header.php
@@ -1,3 +1,4 @@
+<?php require "locale/localization.php"; ?>
 <!DOCTYPE html >
 <html lang="en">
     <head>
@@ -6,7 +7,7 @@
         <meta name="description" content="A privacy respecting meta search engine."/>
         <meta name="referrer" content="no-referrer"/>
         <link rel="stylesheet" type="text/css" href="static/css/styles.css"/>
-        <link title="LibreY search" type="application/opensearchdescription+xml" href="opensearch.xml?method=POST" rel="search"/>
+        <link title="<?php printtext("page_title"); ?>" type="application/opensearchdescription+xml" href="opensearch.xml?method=POST" rel="search"/>
         <link rel="stylesheet" type="text/css" href="<?php
 $theme = $_REQUEST["theme"] ?? trim(htmlspecialchars($_COOKIE["theme"] ?? "dark"));
                 echo "static/css/" . $theme . ".css";
diff --git a/misc/search_engine.php b/misc/search_engine.php
@@ -120,7 +120,7 @@
 
             case 3:
                 if ($opts->disable_bittorent_search) {
-                    echo "<p class=\"text-result-container\">The host disabled this feature! :C</p>";
+                    echo "<p class=\"text-result-container\">" . TEXTS["feature_disabled"] . "</p>";
                     break;
                 }
 
@@ -129,7 +129,7 @@
 
             case 4:
                 if ($opts->disable_hidden_service_search) {
-                    echo "<p class=\"text-result-container\">The host disabled this feature! :C</p>";
+                    echo "<p class=\"text-result-container\">" . TEXTS["feature_disabled"] . "</p>";
                     break;
                 }
                 require "engines/ahmia/hidden_service.php";
diff --git a/misc/tools.php b/misc/tools.php
@@ -77,11 +77,9 @@
         return $xpath;
     }
 
-    function request($url) {
-        $config ??= require "config.php";
-
+    function request($url, $conf) {
         $ch = curl_init($url);
-        curl_setopt_array($ch, $config->curl_settings);
+        curl_setopt_array($ch, $conf);
         $response = curl_exec($ch);
 
         return $response;
diff --git a/opensearch.xml.example b/opensearch.xml.example
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+  <ShortName>LibreY</ShortName>
+  <Description>Framework and javascript free privacy respecting meta search engine</Description>
+  <InputEncoding>UTF-8</InputEncoding>
+  <LongName>LibreY search</LongName>
+  <Url rel="results" type="text/html" method="get" template="http://localhost:80/search.php?q={searchTerms}" />
+  <Url type="application/opensearchdescription+xml"
+      rel="self"
+      template="/opensearch.xml?method=GET" />
+</OpenSearchDescription>
diff --git a/search.php b/search.php
@@ -65,7 +65,7 @@
                             continue;
                         }
 
-                        echo "<a " . (($category_index == $opts->type) ? "class=\"active\" " : "") . "href=\"./search.php?q=" . urlencode($opts->query) . "&p=0&t=" . $category_index . "\"><img src=\"static/images/" . $category . "_result.png\" alt=\"" . $category . " result\" />" . ucfirst($category)  . "</a>";
+                        echo "<a " . (($category_index == $opts->type) ? "class=\"active\" " : "") . "href=\"./search.php?q=" . urlencode($opts->query) . "&p=0&t=" . $category_index . "\"><img src=\"static/images/" . $category . "_result.png\" alt=\"" . $category . " result\" />" . TEXTS["category_$category"]  . "</a>";
                     }
                 ?>
             </div>
diff --git a/settings.php b/settings.php
@@ -33,14 +33,14 @@
         require "misc/header.php";
 ?>
 
-    <title>LibreY - Settings</title>
+    <title>LibreY - <?php printtext("settings_title");?></title>
     </head>
     <body>
         <div class="misc-container">
             <h1>Settings</h1>
             <form method="post" enctype="multipart/form-data" autocomplete="off">
               <div>
-                <label for="theme">Theme:</label>
+                <label for="theme"><?php printtext("settings_theme");?>:</label>
                 <select name="theme">
                 <?php
                     $themes = "<option value=\"dark\">Dark</option>
@@ -70,12 +70,12 @@
                 </select>
                 </div>
                 <div>
-                    <label>Disable special queries (e.g.: currency conversion)</label>
+                    <label><?php printtext("settings_special_disabled");?></label>
                     <input type="checkbox" name="disable_special" <?php echo $opts->disable_special ? "checked"  : ""; ?> >
                 </div>
 
-                <h2>Privacy friendly frontends</h2>
-                <p>For an example if you want to view YouTube without getting spied on, click on "Invidious", find the instance that is most suitable for you then paste it in (correct format: https://example.com)</p>
+                <h2><?php printtext("settings_frontends");?></h2>
+                <p><?php printtext("settings_frontends_description");?></p>
                 <div class="settings-textbox-container">
                       <?php
                            foreach($opts->frontends as $frontend => $data)
@@ -90,14 +90,14 @@
                       ?>
                 </div>
                 <div>
-                    <label>Disable frontends</label>
+                    <label><?php printtext("settings_frontends_disable");?></label>
                     <input type="checkbox" name="disable_frontends" <?php echo $opts->disable_frontends ? "checked"  : ""; ?> >
                 </div>
 
-                <h2>Search settings</h2>
+                <h2><?php printtext("settings_search_settings");?></h2>
                 <div class="settings-textbox-container">
                     <div>
-                        <span>Language</span>
+                        <span><?php printtext("settings_language");?></span>
                         <select name="language">
                         <?php
 
@@ -116,18 +116,18 @@
                         </select>
                     </div>
                     <div>
-                        <label>Number of results per page</label>
+                        <label><?php printtext("settings_number_of_results");?></label>
                         <input type="number" name="number_of_results" value="<?php echo htmlspecialchars($opts->number_of_results ?? "10") ?>" >
                     </div>
                 </div>
                 <div>
-                    <label>Safe search</label>
+                    <label><?php printtext("settings_safe_search");?></label>
                     <input type="checkbox" name="safe_search" <?php echo $opts->safe_search ? "checked"  : ""; ?> >
                 </div>
 
                 <div>
-                  <button type="submit" name="save" value="1">Save</button>
-                  <button type="submit" name="reset" value="1">Reset</button>
+                  <button type="submit" name="save" value="1"><?php printtext("settings_save");?></button>
+                  <button type="submit" name="reset" value="1"><?php printtext("settings_reset");?></button>
                 </div>
             </form>
         </div>