Quellcode durchsuchen

Auto select frontend for links to "parent" service

Farside now supports redirecting based on a provided link to a "parent"
service, if such a parent service is supported.

For example, a link such as:

farside.link/https://www.youtube.com/watch?v=dQw4w9WgXcQ

will now redirect to any of the available YouTube related frontends.

This works by matching against a mapping of "parent" service domains
("youtube.com", "reddit.com", etc) to a list of their respective frontend
alternatives (["invidious", "piped"], ["libreddit", "teddit"], etc). A
random element is chosen from this list, and the remainder of Farside's
routing logic proceeds as if the user had chosen the service directly to
begin with.

Closes #37
Ben Busby vor 3 Jahren
Ursprung
Commit
5006b97dfa
4 geänderte Dateien mit 88 neuen und 3 gelöschten Zeilen
  1. 2 0
      .gitignore
  2. 50 0
      lib/farside.ex
  3. 18 3
      lib/farside/router.ex
  4. 18 0
      test/farside_test.exs

+ 2 - 0
.gitignore

@@ -13,3 +13,5 @@ erl_crash.dump
 .update-result*
 
 *.rdb
+.idea/
+*.iml

+ 50 - 0
lib/farside.ex

@@ -3,6 +3,21 @@ defmodule Farside do
   @fallback_suffix Application.fetch_env!(:farside, :fallback_suffix)
   @previous_suffix Application.fetch_env!(:farside, :previous_suffix)
 
+  # Define relation between available services and their parent service.
+  # This enables Farside to redirect with links such as:
+  # farside.link/https://www.youtube.com/watch?v=dQw4w9WgXcQ
+  @parent_services %{
+    "youtube.com" => ["invidious", "piped"],
+    "reddit.com" => ["libreddit", "teddit"],
+    "instagram.com" => ["bibliogram"],
+    "twitter.com" => ["nitter"],
+    "wikipedia.org" => ["wikiless"],
+    "medium.com" => ["scribe"],
+    "odysee.com" => ["librarian"],
+    "imgur.com" => ["rimgo"],
+    "translate.google.com" => ["lingva"]
+  }
+
   def get_services_map do
     {:ok, service_list} = Redix.command(:redix, ["KEYS", "#{@service_prefix}*"])
 
@@ -26,7 +41,42 @@ defmodule Farside do
     end)
   end
 
+  def get_service(service) do
+    # Check if service has an entry in Redis, otherwise try to
+    # match against available parent services
+    service_name = cond do
+      !check_service(service) ->
+        Enum.find_value(
+          @parent_services,
+          fn {k, v} ->
+            service =~ k && Enum.random(v)
+          end)
+      true ->
+        service
+    end
+
+    service_name
+  end
+
+  def check_service(service) do
+    # Checks to see if a specific service has instances available
+    # in redis
+    {:ok, instances} =
+      Redix.command(
+        :redix,
+        [
+          "LRANGE",
+          "#{@service_prefix}#{service}",
+          "0",
+          "-1"
+        ]
+      )
+
+    Enum.count(instances) > 0
+  end
+
   def last_instance(service) do
+    # Fetches the last selected instance for a particular service
     {:ok, previous} =
       Redix.command(
         :redix,

+ 18 - 3
lib/farside/router.ex

@@ -39,12 +39,27 @@ defmodule Farside.Router do
   end
 
   get "/:service/*glob" do
-    path = Enum.join(glob, "/")
+    service_name = cond do
+      service =~ "http" ->
+        List.first(glob)
+      true ->
+        service
+    end
+
+    path = cond do
+      service_name != service ->
+        Enum.join(Enum.slice(glob, 1..-1), "/")
+      true ->
+        Enum.join(glob, "/")
+    end
+
     instance = cond do
       conn.assigns[:throttle] != nil ->
-        Farside.last_instance(service)
+        Farside.get_service(service_name)
+        |> Farside.last_instance
       true ->
-        Farside.pick_instance(service)
+        Farside.get_service(service_name)
+        |> Farside.pick_instance
     end
 
     params =

+ 18 - 0
test/farside_test.exs

@@ -77,4 +77,22 @@ defmodule FarsideTest do
       assert first_redirect != second_redirect
     end)
   end
+
+  test "/https://..." do
+    parent_service = "https://www.youtube.com"
+    parent_path = "watch?v=dQw4w9WgXcQ"
+    conn = test_conn("/#{parent_service}/#{parent_path}")
+
+    redirect = elem(List.last(conn.resp_headers), 1)
+
+    IO.puts("")
+    IO.puts("    /#{parent_service}/#{parent_path}")
+    IO.puts("    redirected to")
+    IO.puts("    #{redirect}")
+
+    assert conn.state == :set
+    assert conn.status == 302
+    assert redirect =~ parent_path
+    assert !(redirect =~ parent_service)
+  end
 end