-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbs_youtube.c
152 lines (127 loc) · 5.1 KB
/
bs_youtube.c
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
* Copyright (c) 2025 Mike "reverse" Chevronnet <HybridIRC Network>
* Rights to this code are as documented in doc/LICENSE.
*
*
* ./configure --enable-contrib LDFLAGS="-L/usr/lib -lcurl -ljansson" LIBS="-lcurl -ljansson"
*
* Configuration:
* loadmodule "contrib/bs_youtube";
*
*/
#include "atheme-compat.h"
#include <curl/curl.h>
#include <jansson.h>
#define YOUTUBE_API_KEY "YOURE YOUTUBE API" // Replace with your YouTube API key
struct memory {
char *response;
size_t size;
};
// Callback function to write response data into memory
static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct memory *mem = (struct memory *)userp;
char *ptr = realloc(mem->response, mem->size + realsize + 1);
if (ptr == NULL)
return 0; // Out of memory
mem->response = ptr;
memcpy(&(mem->response[mem->size]), contents, realsize);
mem->size += realsize;
mem->response[mem->size] = 0;
return realsize;
}
// Fetch YouTube metadata using libcurl
static void fetch_youtube_metadata(const char *video_id, mychan_t *mc, user_t *user)
{
CURL *curl;
CURLcode res;
struct memory chunk = {0};
char api_url[512];
snprintf(api_url, sizeof(api_url),
"https://www.googleapis.com/youtube/v3/videos?id=%s&key=%s&part=snippet,statistics",
video_id, YOUTUBE_API_KEY);
curl = curl_easy_init();
if (!curl) {
notice(chansvs.me->nick, user->nick, "Error: Could not initialize HTTP client.");
return;
}
curl_easy_setopt(curl, CURLOPT_URL, api_url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Atheme BotServ Module");
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
notice(chansvs.me->nick, user->nick, "Failed to fetch YouTube metadata: %s", curl_easy_strerror(res));
} else {
// Process JSON response
json_error_t error;
json_t *root = json_loads(chunk.response, 0, &error);
if (!root) {
notice(chansvs.me->nick, user->nick, "Error: Failed to parse YouTube API response: %s", error.text);
} else {
json_t *items = json_object_get(root, "items");
if (!items || !json_array_size(items)) {
notice(chansvs.me->nick, user->nick, "No metadata found for the video.");
} else {
json_t *snippet = json_object_get(json_array_get(items, 0), "snippet");
json_t *statistics = json_object_get(json_array_get(items, 0), "statistics");
json_t *title = json_object_get(snippet, "title");
json_t *channel_title = json_object_get(snippet, "channelTitle");
json_t *view_count = json_object_get(statistics, "viewCount");
if (title && channel_title && view_count) {
char *formatted_prefix = "\x02\x03""01,00You\x03""00,04Tube\x0F\x02";
char message[512];
snprintf(message, sizeof(message), "%s \"%s\" by %s with %s views.",
formatted_prefix,
json_string_value(title),
json_string_value(channel_title),
json_string_value(view_count));
msg(chansvs.me->nick, mc->name, "%s", message);
} else {
notice(chansvs.me->nick, user->nick, "Incomplete metadata found for the video.");
}
}
json_decref(root);
}
}
curl_easy_cleanup(curl);
if (chunk.response)
free(chunk.response);
}
// Handler for messages containing YouTube links
static void on_channel_message(hook_cmessage_data_t *data)
{
if (data == NULL || data->msg == NULL)
return;
const char *url = data->msg;
const char *youtube_prefix = "https://www.youtube.com/watch?v=";
const char *youtube_short_prefix = "https://youtu.be/";
const char *video_id = NULL;
if (strncmp(url, youtube_prefix, strlen(youtube_prefix)) == 0) {
video_id = url + strlen(youtube_prefix);
} else if (strncmp(url, youtube_short_prefix, strlen(youtube_short_prefix)) == 0) {
video_id = url + strlen(youtube_short_prefix);
}
if (video_id) {
// Extract the video ID (truncate any extra parameters, if present)
char video_id_clean[12] = {0};
strncpy(video_id_clean, video_id, sizeof(video_id_clean) - 1);
char *ampersand = strchr(video_id_clean, '&');
if (ampersand)
*ampersand = '\0';
mychan_t *mc = mychan_from(data->c);
if (mc)
fetch_youtube_metadata(video_id_clean, mc, data->u);
}
}
static void mod_init(module_t *const restrict m)
{
hook_add_event("channel_message");
hook_add_channel_message(on_channel_message);
}
static void mod_deinit(const module_unload_intent_t intent)
{
hook_del_channel_message(on_channel_message);
}
VENDOR_DECLARE_MODULE_V1("botserv/bs_youtube", MODULE_UNLOAD_CAPABILITY_OK)