summaryrefslogtreecommitdiff
path: root/lib/farside.ex
blob: 1dc291898eec00097f87c5be1124a3e7d36c39e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
defmodule Farside do
  @service_prefix Application.fetch_env!(:farside, :service_prefix)
  @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
  @youtube_regex ~r/youtu(.be|be.com)|invidious|piped/
  @reddit_regex ~r/reddit.com|libreddit|teddit/
  @instagram_regex ~r/instagram.com|bibliogram/
  @twitter_regex ~r/twitter.com|nitter/
  @wikipedia_regex ~r/wikipedia.org|wikiless/
  @medium_regex ~r/medium.com|scribe/
  @odysee_regex ~r/odysee.com|librarian/
  @imgur_regex ~r/imgur.com|rimgo/
  @gtranslate_regex ~r/translate.google.com|lingva/
  @tiktok_regex ~r/tiktok.com|proxitok/
  @imdb_regex ~r/imdb.com|libremdb/
  @quora_regex ~r/quora.com|quetre/
  @google_regex ~r/google.com|whoogle/

  @parent_services %{
    @youtube_regex => ["invidious", "piped"],
    @reddit_regex => ["libreddit", "teddit"],
    @instagram_regex => ["bibliogram"],
    @twitter_regex => ["nitter"],
    @wikipedia_regex => ["wikiless"],
    @medium_regex => ["scribe"],
    @odysee_regex => ["librarian"],
    @imgur_regex => ["rimgo"],
    @gtranslate_regex => ["lingva"],
    @tiktok_regex => ["proxitok"],
    @imdb_regex => ["libremdb"],
    @quora_regex => ["quetre"],
    @google_regex => ["whoogle"]
  }

  def get_services_map do
    service_list = CubDB.select(CubDB)
                   |> Stream.map(fn {key, _value} -> key end)
                   |> Stream.filter(fn key -> String.starts_with?(key, @service_prefix) end)
                   |> Enum.to_list

    # Match service name to list of available instances
    Enum.reduce(service_list, %{}, fn service, acc ->
      instance_list = CubDB.get(CubDB, service)

      Map.put(
        acc,
        String.replace_prefix(
          service,
          @service_prefix,
          ""
        ),
        instance_list
      )
    end)
  end

  def get_service(service) do
    # Check if service has an entry in the db, otherwise try to
    # match against available parent services
    service_name = cond do
      !check_service(service) ->
        Enum.find_value(
          @parent_services,
          fn {k, v} ->
            String.match?(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
    instances = CubDB.get(CubDB, "#{@service_prefix}#{service}")

    instances != nil && Enum.count(instances) > 0
  end

  def last_instance(service) do
    # Fetches the last selected instance for a particular service
    CubDB.get(CubDB, "#{service}#{@previous_suffix}")
  end

  def pick_instance(service) do
    instances = CubDB.get(CubDB, "#{@service_prefix}#{service}")

    # Either pick a random available instance,
    # or fall back to the default one
    instance =
      if instances != nil && Enum.count(instances) > 0 do
        if Enum.count(instances) == 1 do
          # If there's only one instance, just return that one...
          List.first(instances)
        else
          # ...otherwise pick a random one from the list, ensuring
          # that the same instance is never picked twice in a row.
          instance =
            Enum.filter(instances, &(&1 != last_instance(service)))
            |> Enum.random()

          CubDB.put(CubDB, "#{service}#{@previous_suffix}", instance)

          instance
        end
      else
        CubDB.get(CubDB, "#{service}#{@fallback_suffix}")
      end
    instance
  end

  def amend_instance(instance, service, path) do
    cond do
      String.match?(service, @instagram_regex) ->
        # Bibliogram doesn't have a 1:1 matching to Instagram URLs for users,
        # so a "/u" is appended if the requested path doesn't explicitly include
        # "/p" for a post or an empty path for the home page.
        if String.length(path) > 0 and
           !String.starts_with?(path, "p/") and
           !String.starts_with?(path, "u/") do
          "#{instance}/u"
        else
          instance
        end
      true ->
        instance
    end
  end

  def get_last_updated do
    CubDB.get(CubDB, "last_updated")
  end
end