aboutsummaryrefslogtreecommitdiff
path: root/lib/audio/util.ex
blob: f45af4ef265e949e51467e317f47c7dab02029ae (plain) (blame)
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
defmodule Thulani.Audio.Util do
  @spec stream_type(Nostrum.Voice.play_input()) ::
          {:ok, Nostrum.Voice.play_type()} | {:error, atom()}

  def stream_type(ref) when is_binary(ref) do
    cond do
      ytdl_link?(ref) -> {:ok, :ytdl}
      streamlink?(ref) -> {:ok, :stream}
      valid_url?(ref) -> {:ok, :url}
      true -> {:ok, :pipe}
    end
  end

  def stream_type(_ref) do
    {:error, :invalid}
  end

  @spec ytdl_link?(String.t()) :: boolean
  def ytdl_link?(s) when is_binary(s) do
    valid_url?(s) and
      ytdl_checks()
      |> any_check?(s)
  end

  def ytdl_link?(_s), do: false

  @spec streamlink?(String.t()) :: boolean
  def streamlink?(s) when is_binary(s) do
    valid_url?(s) and streamlink_checks() |> any_check?(s)
  end

  def streamlink?(_s), do: false

  def valid_url?(s), do: String.match?(s, ~r/^https:\/\/.*/i)

  def ytdl_checks, do: [&youtube_link?/1, &vimeo_link?/1]
  def streamlink_checks, do: [&twitch_link?/1]

  def youtube_link?(s),
    do: String.match?(s, youtube_regex())

  def vimeo_link?(s),
    do: String.match?(s, vimeo_regex())

  def twitch_link?(s),
    do: String.match?(s, twitch_regex())

  def youtube_regex, do: ~r/^https?:\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\/.*/i
  def vimeo_regex, do: ~r/^https?:\/\/(?:www\.)?(?:vimeo\.com)\/.*/i
  def twitch_regex, do: ~r/^https?:\/\/(?:www\.)?(?:twitch\.com)\/.*/i

  defp any_check?(checks, s) do
    checks
    |> Stream.map(fn check -> check.(s) end)
    |> Enum.reduce(false, fn acc, x -> acc or x end)
  end

  def wait_ready(guild, interval \\ 100, count \\ 10) do
    wait_for(guild, interval, count, &Nostrum.Voice.ready?/1)
  end

  def wait_playing(guild, interval \\ 200, count \\ 30) do
    wait_for(guild, interval, count, &Nostrum.Voice.playing?/1)
  end

  def wait_no_channel(guild, interval \\ 200, count \\ 30) do
    wait_for(guild, interval, count, fn guild -> no_channel?(guild) end)
  end

  def wait_disconnected(guild, interval \\ 200, count \\ 30) do
    wait_for(guild, interval, count, fn guild -> disconnected?(guild) end)
  end

  defp wait_for(guild, interval, count, check) do
    unless check.(guild) do
      [playing] =
        Stream.unfold(0, fn i ->
          Process.sleep(interval)
          playing_state = check.(guild)
          {playing_state, i + 1}
        end)
        |> Thulani.Util.Stream.take_until(&Function.identity/1)
        |> Stream.take(count)
        |> Enum.take(-1)

      playing
    else
      true
    end
  end

  def connected?(guild) do
    voice_state = Nostrum.Voice.get_voice(guild)
    !is_nil(voice_state) && !is_nil(voice_state.channel_id)
  end

  def disconnect(guild) do
    voice_state = Nostrum.Voice.get_voice(guild)
    Nostrum.Voice.leave_channel(guild)

    if not is_nil(voice_state) do
      Nostrum.Voice.Session.close_connection(voice_state.session_pid)
    end
  end

  def disconnected?(guild) do
    Nostrum.Voice.get_voice(guild) |> is_nil
  end

  def no_channel?(guild) do
    voice_state = Nostrum.Voice.get_voice(guild)
    !is_nil(voice_state) && is_nil(voice_state.channel_id)
  end
end