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
|
defmodule Nola.Plugins.YouTube do
require Logger
@moduledoc """
# youtube
* **!yt `<recherche>`**, !youtube `<recherche>`: retourne le premier résultat de la `<recherche>` YouTube
"""
defstruct client: nil
def irc_doc, do: @moduledoc
def start_link() do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init([]) do
for t <- ["trigger:yt", "trigger:youtube"],
do: {:ok, _} = Registry.register(Nola.PubSub, t, plugin: __MODULE__)
{:ok, %__MODULE__{}}
end
def handle_info(
{:irc, :trigger, _,
message = %Nola.Message{trigger: %Nola.Trigger{type: :bang, args: args}}},
state
) do
irc_search(Enum.join(args, " "), message)
{:noreply, state}
end
def handle_info(info, state) do
{:noreply, state}
end
defp irc_search(query, message) do
case search(query) do
{:ok, %{"items" => [item | _]}} ->
url = "https://youtube.com/watch?v=" <> item["id"]
snippet = item["snippet"]
duration =
item["contentDetails"]["duration"] |> String.replace("PT", "") |> String.downcase()
date =
snippet["publishedAt"]
|> DateTime.from_iso8601()
|> elem(1)
|> Timex.format("{relative}", :relative)
|> elem(1)
info_line =
"— #{duration} — uploaded by #{snippet["channelTitle"]} — #{date}" <>
" — #{item["statistics"]["viewCount"]} views, #{item["statistics"]["likeCount"]} likes," <>
" #{item["statistics"]["dislikeCount"]} dislikes"
message.replyfun.("#{snippet["title"]} — #{url}")
message.replyfun.(info_line)
{:error, error} ->
message.replyfun.("Erreur YouTube: " <> error)
_ ->
nil
end
end
defp search(query) do
query =
query
|> String.strip()
key = Application.get_env(:nola, :youtube)[:api_key]
params = %{
"key" => key,
"maxResults" => 1,
"part" => "id",
"safeSearch" => "none",
"type" => "video",
"q" => query
}
url = "https://www.googleapis.com/youtube/v3/search"
case HTTPoison.get(url, [], params: params) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
{:ok, json} = Jason.decode(body)
item = List.first(json["items"])
if item do
video_id = item["id"]["videoId"]
params = %{
"part" => "snippet,contentDetails,statistics",
"id" => video_id,
"key" => key
}
headers = []
options = [params: params]
case HTTPoison.get("https://www.googleapis.com/youtube/v3/videos", [], options) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
Jason.decode(body)
{:ok, %HTTPoison.Response{status_code: code, body: body}} ->
Logger.error("YouTube HTTP #{code}: #{inspect(body)}")
{:error, "http #{code}"}
error ->
Logger.error("YouTube http error: #{inspect(error)}")
:error
end
else
:error
end
{:ok, %HTTPoison.Response{status_code: code, body: body}} ->
Logger.error("YouTube HTTP #{code}: #{inspect(body)}")
{:error, "http #{code}"}
error ->
Logger.error("YouTube http error: #{inspect(error)}")
:error
end
end
end
|