Skip to content

Instantly share code, notes, and snippets.

@RealEthanPlayzDev
Last active November 26, 2022 09:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RealEthanPlayzDev/b95ecfca4fa4d651152ee4975a52a5a2 to your computer and use it in GitHub Desktop.
Save RealEthanPlayzDev/b95ecfca4fa4d651152ee4975a52a5a2 to your computer and use it in GitHub Desktop.
RbxHolodexAPI - A Holodex API wrapper for usage in Roblox
--// This is the v1 version of the RbxHolodexAPI, I suggest you to use the v2 instead.
--[[
File name: HoloDexLuaAPI.lua
Author: RadiatedExodus (RealEthanPlayzDev)
API wrapper for Holodex (https://holodex.net)
--]]
local serv = { HttpService = game:GetService("HttpService") }
--// CLASS DEFINITION: HoloDexLuaAPI
local HoloDexLuaAPI = {}
HoloDexLuaAPI.__index = HoloDexLuaAPI
HoloDexLuaAPI.ClassName = "HoloDexLuaAPI"
--// [Internal] [NotExposed] function HttpReqHoloAPI(url: string, method: string, apikey: string)
local function HttpReqHoloAPI(url: string, method: string, apikey: string)
assert(typeof(url) == "string" or not tostring(url), "HttpReqHoloAPI: url is not a string.")
assert(typeof(method) == "string" or not tostring(method), "HttpReqHoloAPI: method is not a string.")
assert(typeof(apikey) == "string" or not tostring(apikey), "HttpReqHoloAPI: apikey is not a string.")
local success, ret = false, nil
local tries, maxtries = 0, 3
repeat
tries += 1
success, ret = pcall(serv.HttpService.RequestAsync, serv.HttpService, {
Url = tostring(url);
Method = string.upper(tostring(method));
Headers = {
["Content-Type"] = "application/json";
["X-APIKEY"] = tostring(apikey) or ""; --// X-APIKEY, see https://holodex.stoplight.io/
};
})
until success or tries >= maxtries
return success, ret
end
--// [Yields/Async] function HoloDexLuaAPI:GetChannelInformation(channelId: string)
function HoloDexLuaAPI:GetChannelInformation(channelId: string)
assert(typeof(channelId) == "string", "HoloDexLuaAPI: GetChannelInformation: invalid argument #1 to 'GetChannelInformation' (string expected, got "..typeof(channelId)..")")
local success, ret = HttpReqHoloAPI(string.format("https://holodex.net/api/v2/channels/%s", tostring(channelId)), "GET", self.__apikey)
if not success then return error("HoloDexLuaAPI: GetChannelInformation: attempt to fetch information failure, possible error code:\n"..tostring(ret), 2) end
return serv.HttpService:JSONDecode(ret.Body)
end
--// [Yields/Async] function HoloDexLuaAPI:GetVideoMetadata(videoId: string, commentsAllowed: boolean)
function HoloDexLuaAPI:GetVideoMetadata(videoId: string, commentsAllowed: boolean)
assert(typeof(videoId) == "string", "HoloDexLuaAPI: GetChannelInformation: invalid argument #1 to 'GetVideoMetadata' (string expected, got "..typeof(videoId)..")")
local success, ret = HttpReqHoloAPI(string.format("https://holodex.net/api/v2/videos/%s?c=%s", tostring(videoId), (commentsAllowed and "1") or (not commentsAllowed and "0")), "GET", self.__apikey)
if not success then return error("HoloDexLuaAPI: GetVideoMetadata: attempt to fetch information failure, possible error code:\n"..tostring(ret), 2) end
return serv.HttpService:JSONDecode(ret.Body)
end
--// [Yields/Async] function HoloDexLuaAPI:GetUpcomingsForChannels(channels: table)
function HoloDexLuaAPI:GetUpcomingsForChannels(channels)
assert(typeof(channels) == "table", "HoloDexLuaAPI: GetUpcomingsForChannels: invalid argument #1 to 'GetUpcomingsForChannels' (table expected, got "..typeof(channels)..")")
channels = table.concat(channels, ",")
local success, ret = HttpReqHoloAPI(string.format("https://holodex.net/api/v2/users/live?channels=%s", channels), "GET", self.__apikey)
if not success then return error("HoloDexLuaAPI: GetUpcomingsForChannels: attempt to fetch information failure, possible error code:\n"..tostring(ret), 2) end
return serv.HttpService:JSONDecode(ret.Body)
end
--// [Yields/Async] function HoloDexLuaAPI:GetChannelList(lang: string?, limit: number|string?, order: string, org: string, type: string)
function HoloDexLuaAPI:GetChannelList(lang: string?, limit: number?, order: string, org: string, type: string)
local targeturl = "https://holodex.net/api/v2/channels"
local argcount = 1
local prefix = "?"
--// lang
if lang and tostring(lang) then
if argcount ~= 1 then prefix = "&" end
argcount += 1
targeturl ..= prefix.."lang="..tostring(lang)
end
--// limit
if limit and tonumber(limit) then
limit = tonumber(limit)
if argcount ~= 1 then prefix = "&" end
argcount += 1
if limit >= 50 then warn("HoloDexLuaAPI: GetChannelList: limit cannot be above 50, will be set to 50 (previous value was ", limit, ")") limit = 50 end
targeturl ..= prefix.."limit="..tostring(limit)
end
--// order
if order and tostring(order) then
if argcount ~= 1 then prefix = "&" end
argcount += 1
targeturl ..= prefix.."order="..tostring(order)
end
--// org
if org and tostring(org) then
if argcount ~= 1 then prefix = "&" end
argcount += 1
targeturl ..= prefix.."org="..tostring(org)
end
--// type
if type and tostring(type) then
if argcount ~= 1 then prefix = "&" end
argcount += 1
targeturl ..= prefix.."type="..tostring(type)
end
--//print(targeturl)
local success, ret = HttpReqHoloAPI(targeturl, "GET", self.__apikey)
if not success then return error("HoloDexLuaAPI: GetChannelList: attempt to fetch channel list failure, possible error code:\n"..tostring(ret), 2) end
return serv.HttpService:JSONDecode(ret.Body)
end
return {
--// CONSTRUCTOR new(apikey: string): HoloDexLuaAPI
new = function(apikey: string?)
return setmetatable({
__apikey = tostring(apikey) or "";
}, HoloDexLuaAPI)
end,
}
--[[
File name: RbxHoloDexAPI.luau
Author: RadiatedExodus (RealEthanPlayzDev)
Version: 2.0.0
API wrapper for Holodex, written in Luau for usage in Roblox
--]]
--// Static configuration
local BASE_HOLODEXAPI_URL = "https://holodex.net/api/v2" --// The base url of the Holodex api, must NOT end with a slash
--// Services
local serv = {
HttpService = game:GetService("HttpService");
}
--// Functions
local function CheckHttpEnabled(customurl: string?)
return ({pcall(serv.HttpService.GetAsync, serv.HttpService, customurl or "https://google.com")})[1]
end
local function RequestHolodexAPI(method: string, path: string, query: any, body: string?, token: string?)
local Query do
if query then
Query = ""
for name, value in pairs(query) do
if (typeof(value) == "table") then
value = table.concat(value, ",")
end
if (typeof(value) == "boolean") then
value = if value then "1" else "0"
end
Query ..= if (Query == "") then serv.HttpService:UrlEncode(name).."="..serv.HttpService:UrlEncode(value) else "&"..serv.HttpService:UrlEncode(name).."="..serv.HttpService:UrlEncode(value)
end
end
end
local Url = BASE_HOLODEXAPI_URL..(if (string.sub(path, 1, 1) == "/") then path else "/"..path)..(if Query then "?"..Query else "")
print(Url)
return serv.HttpService:RequestAsync({
Url = Url;
Method = method;
Headers = {
["X-APIKEY"] = token;
["Content-Type"] = "application/x-www-form-urlencoded";
};
Body = body;
})
end
--// Enums
local VideoExtraInfos = {
Clips = "clips";
Refers = "refers";
Sources = "sources";
Simulcasts = "simulcasts";
Mentions = "mentions";
Description = "description";
LiveInfo = "live_info";
ChannelStats = "channel_stats";
Songs = "songs";
}
local Ordering = {
Ascending = "asc";
Descending = "desc";
}
local VideoStatus = {
New = "new";
Upcoming = "upcoming";
Live = "live";
Past = "past";
Missing = "missing";
}
local VideoType = {
Stream = "stream";
Clip = "clip";
}
local ChannelType = {
Subber = "subber";
Vtuber = "vtuber";
}
local VideoSearchSort = {
Newest = "newest";
Oldest = "oldest";
}
local HolodexAPI = {}
HolodexAPI.__index = HolodexAPI
HolodexAPI.__tostring = function(_) return "HolodexAPI" end
HolodexAPI.__metatable = "This metatable is locked"
--// Export enums
HolodexAPI.VideoExtraInfos = VideoExtraInfos
HolodexAPI.Ordering = Ordering
HolodexAPI.VideoStatus = VideoStatus
HolodexAPI.VideoType = VideoType
HolodexAPI.ChannelType = ChannelType
HolodexAPI.VideoSearchSort = VideoSearchSort
--// Argument types
export type QueryLiveAndUpcomingVideosQuery = {
channel_id: string?;
id: string?;
include: {string}?;
lang: string?;
limit: number?;
max_upcoming_hours: number?;
mentioned_channel_id: string?;
offset: number?;
order: ("asc" | "desc")?;
org: string?;
sort: string?;
status: ("new" | "upcoming" | "live" | "past" | "missing")?;
topic: string?;
type: ("stream" | "clip")?;
paginated: boolean?;
}
export type QueryVideosQuery = {
channel_id: string?;
id: string?;
include: {string}?;
lang: string?;
limit: number?;
max_upcoming_hours: number?;
mentioned_channel_id: string?;
offset: number?;
order: ("asc" | "desc")?;
org: string?;
sort: string?;
status: string?;
topic: string?;
from: string?;
paginated: boolean?;
to: string?;
}
export type QueryVideosRelatedToChannelQuery = {
include: {string}?;
lang: string?;
limit: number?;
offset: number?;
paginated: boolean?;
}
export type ListChannelsQuery = {
limit: number?;
offset: number?;
type: ("subber" | "vtuber")?;
lang: string?;
order: ("asc" | "desc")?;
org: string?;
sort: string?;
}
export type VideoSearchBody = {
sort: "oldest" | "newest";
lang: {string}?;
target: {"clip" | "stream"}?;
conditions: {string}?;
topic: {string}?;
vch: {string}?;
org: {string}?;
paginated: boolean?;
offset: number?;
limit: number?;
}
export type CommentSearchBody = {
sort: "oldest" | "newest";
lang: {string}?;
target: {"clip" | "stream"}?;
comment: string;
topic: {string}?;
vch: {string}?;
org: {string}?;
paginated: boolean?;
offset: number;
limit: number;
}
--// Query Live and Upcoming Videos
--// https://holodex.stoplight.io/docs/holodex/b675902a04ca9-query-live-and-upcoming-videos
function HolodexAPI:QueryLiveAndUpcomingVideos(query: QueryLiveAndUpcomingVideosQuery)
return RequestHolodexAPI("GET", "/live", query, nil, self.Token)
end
--// Query Videos
--// https://holodex.stoplight.io/docs/holodex/ba328f7332280-query-videos
function HolodexAPI:QueryVideos(query: QueryVideosQuery)
return RequestHolodexAPI("GET", "/videos", query, nil, self.Token)
end
--// Get Channel Information
--// https://holodex.stoplight.io/docs/holodex/5dfaf299ea9fd-get-channel-information
function HolodexAPI:GetChannelInformation(channelid: string)
return RequestHolodexAPI("GET", "/channels/"..channelid, nil, nil, self.Token)
end
--// Query Videos Related to Channel
--// https://holodex.stoplight.io/docs/holodex/643f06b1f7e4d-query-videos-related-to-channel
function HolodexAPI:QueryVideosRelatedToChannel(channelid: string, type: string, query: QueryVideosRelatedToChannelQuery)
return RequestHolodexAPI("GET", string.format("/channels/%s/%s", channelid, type), query, nil, self.Token)
end
--// Quickly Access Live / Upcoming for a set of Channels
--// https://holodex.stoplight.io/docs/holodex/f1e355dc4cb79-quickly-access-live-upcoming-for-a-set-of-channels
function HolodexAPI:QuickAccessLiveOrUpcomingWithSetOfChannels(channels: {string})
return RequestHolodexAPI("GET", "/users/live", { channels = channels }, nil, self.Token)
end
--// Get a single Video's metadata
--// https://holodex.stoplight.io/docs/holodex/d18465c977416-get-a-single-video-s-metadata
function HolodexAPI:GetVideoMetadata(videoid: string, lang: string, commenttimestamp: boolean?)
return RequestHolodexAPI("GET", "/videos/"..videoid, { lang = lang, c = commenttimestamp }, nil, self.Token)
end
--// List Channels
--// https://holodex.stoplight.io/docs/holodex/4fd0f20623a29-list-channels
function HolodexAPI:ListChannels(query)
return RequestHolodexAPI("GET", "/channels", query, nil, self.Token)
end
--// Create a Search Video Search
--// https://holodex.stoplight.io/docs/holodex/7ef9a63c3d44a-create-a-search-video-search
function HolodexAPI:SearchVideo(body: VideoSearchBody)
return RequestHolodexAPI("POST", "/search/videoSearch", nil, serv.HttpService:JSONEncode(body), self.Token)
end
--// Create a Search Comment Search
--// https://holodex.stoplight.io/docs/holodex/1485e15cbe9e2-create-a-search-comment-search
function HolodexAPI:SearchComment(body: CommentSearchBody)
return RequestHolodexAPI("POST", "/search/commentSearch", nil, serv.HttpService:JSONEncode(body), self.Token)
end
local function constructor_HolodexAPI(token: string?, bypasshttpenabledcheck: boolean?)
assert(if bypasshttpenabledcheck then true else CheckHttpEnabled(), "This experience does not have allow http requests enabled, turn it on via game settings to use this module.")
return setmetatable({
Token = token;
}, HolodexAPI)
end
return setmetatable({
--// Constructor
new = constructor_HolodexAPI;
--// Enums (also exported in HolodexAPI)
VideoExtraInfos = VideoExtraInfos;
Ordering = Ordering;
VideoStatus = VideoStatus;
VideoType = VideoType;
ChannelType = ChannelType;
VideoSearchSort = VideoSearchSort;
}, { __call = function(_, ...) return constructor_HolodexAPI(...) end })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment