diff --git a/.gitignore b/.gitignore index 87fe868..e4f7466 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ erl_crash.dump .update-result* *.rdb +.idea/ +*.iml diff --git a/lib/farside.ex b/lib/farside.ex index 16dc074..97a14bc 100644 --- a/lib/farside.ex +++ b/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, diff --git a/lib/farside/router.ex b/lib/farside/router.ex index 2419055..e2902f6 100644 --- a/lib/farside/router.ex +++ b/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 = diff --git a/test/farside_test.exs b/test/farside_test.exs index 05497f3..25828c6 100644 --- a/test/farside_test.exs +++ b/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