unpiped :(

This commit is contained in:
Cynthia Foxwell 2024-12-22 18:30:35 -07:00
parent 9e061e2ff4
commit 1b72a87764
2 changed files with 85 additions and 53 deletions

View file

@ -14,23 +14,25 @@ yt.usage = "[search term]";
yt.callback = async function (msg, line) {
if (!line) return "Arguments are required.";
const req = await fetch(`${hf.config.piped_api}/search?q=${encodeURIComponent(line)}&filter=videos`).then((x) =>
x.json()
);
const req = await fetch(
`https://www.googleapis.com/youtube/v3/search?key=${
hf.apikeys.google
}&maxResults=5&part=snippet&type=video&q=${encodeURIComponent(line)}`
).then((res) => res.json());
const topVid = req.items[0];
let out = `**${safeString(parseHtmlEntities(topVid.title))}** | \`${safeString(
parseHtmlEntities(topVid.uploaderName)
)}\`\nhttps://youtube.com${topVid.url}\n\n**__See Also:__**\n`;
let out = `**${safeString(parseHtmlEntities(topVid.snippet.title))}** | \`${safeString(
parseHtmlEntities(topVid.snippet.channelTitle)
)}\`\nhttps://youtu.be/${topVid.id.videoId}\n\n**__See Also:__**\n`;
for (let i = 1; i < 5; i++) {
const vid = req.items[i];
if (!vid) continue;
out += `- **${safeString(parseHtmlEntities(vid.title))}** | By: \`${safeString(
parseHtmlEntities(vid.uploaderName)
)}\` | <https://youtube.com${vid.url}>\n`;
out += `- **${safeString(parseHtmlEntities(vid.snippet.title))}** | By: \`${safeString(
parseHtmlEntities(vid.snippet.channelTitle)
)}\` | <https://youtu.be/${vid.id.videoId}>\n`;
}
return out;
@ -60,15 +62,17 @@ fyt.usage = "[search term]";
fyt.callback = async function (msg, line) {
if (!line) return "Arguments are required.";
const req = await fetch(`${hf.config.piped_api}/search?q=${encodeURIComponent(line)}&filter=videos`).then((x) =>
x.json()
);
const req = await fetch(
`https://www.googleapis.com/youtube/v3/search?key=${
hf.apikeys.google
}&maxResults=2&part=snippet&type=video&q=${encodeURIComponent(line)}`
).then((res) => res.json());
const vid = req.items[0];
return `**${safeString(parseHtmlEntities(vid.title))}** | \`${safeString(
parseHtmlEntities(vid.uploaderName)
)}\`\nhttps://youtube.com${vid.url}`;
return `**${safeString(parseHtmlEntities(vid.snippet.title))}** | \`${safeString(
parseHtmlEntities(vid.snippet.channelTitle)
)}\`\nhttps://youtu.be/${vid.id.videoId}`;
};
hf.registerCommand(fyt);

View file

@ -1,6 +1,5 @@
const {Collection} = require("@projectdysnomia/dysnomia");
const {Readable} = require("node:stream");
const ffprobe = require("node-ffprobe");
const Command = require("#lib/command.js");
@ -55,20 +54,18 @@ async function processPlaylist(url, type, shuffle = false, limit = -1, offset =
const playlistId = url.match(REGEX_YOUTUBE_PLAYLIST)?.[4] ?? url.match(REGEX_YOUTUBE_PLAYLIST_SHORT)?.[0];
if (!playlistId) return null;
const baseUrl = "/playlists/" + playlistId;
const baseUrl = `https://www.googleapis.com/youtube/v3/playlistItems?key=${hf.apikeys.google}&part=snippet&playlistId=${playlistId}&maxResults=50`;
const data = await fetch(hf.config.piped_api + baseUrl).then((res) => res.json());
const data = await fetch(baseUrl).then((res) => res.json());
playlist = data.relatedStreams;
playlist = data.items;
let pageToken = data.nextpage;
while (pageToken?.startsWith("{")) {
const pageData = await fetch(
hf.config.piped_api + "/nextpage" + baseUrl + "&nextpage=" + encodeURIComponent(pageToken)
).then((res) => res.json());
if (pageData.nextpage) pageToken = pageData.nextpage;
let pageToken = data.nextPageToken;
while (pageToken != null) {
const pageData = await fetch(baseUrl + "&pageToken=" + encodeURIComponent(pageToken)).then((res) => res.json());
if (pageData.nextPageToken) pageToken = pageData.nextPageToken;
playlist = [...playlist, ...pageData.relatedStreams];
playlist = [...playlist, ...pageData.items];
}
} else if (type === "sc") {
const clientId = await getSoundcloudClientID();
@ -176,7 +173,6 @@ async function createVoiceConnection(guild_id, voice_id, text_id) {
return state;
}
const REGEX_HLS_AUDIO_TRACK = /#EXT-X-MEDIA:URI="(.+?)",TYPE=AUDIO,/;
async function enqueue({guild_id, voice_id, text_id, url, type, addedBy, suppress = false, queueNext = false}) {
if (!url) return;
@ -189,7 +185,8 @@ async function enqueue({guild_id, voice_id, text_id, url, type, addedBy, suppres
media,
stream = false;
if (type == "yt") {
// this is only whitelisted because residential ip being used
if (type == "yt" && hf.config.yt_whitelist.includes(guild_id)) {
let info;
let id = url;
try {
@ -201,27 +198,53 @@ async function enqueue({guild_id, voice_id, text_id, url, type, addedBy, suppres
id = uri.searchParams.get("v");
}
}
info = await fetch(`${hf.config.piped_api}/streams/${id}`).then((res) => res.json());
info = await fetch(
`https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id=${id}&fields=items%2Fsnippet&key=${hf.apikeys.google}`
)
.then((res) => res.json())
.then((data) => data?.items?.[0]);
} catch (err) {
await textChannel.createMessage({
content: `:warning: Failed to get metadata: \`\`\`\n${err}\n\`\`\``,
});
}
title = info?.title;
length = info?.duration * 1000;
thumbnail = info?.thumbnailUrl;
title = info?.snippet?.title;
const hlsUrl = new URL(info.hls);
const hlsBase = await fetch(info.hls)
.then((res) => res.text())
.then((data) => data.replaceAll("/api/manifest/", `https://${hlsUrl.hostname}/api/manifest/`));
const thumbnails = info?.snippet?.thumbnails;
thumbnail = thumbnails?.maxres?.url ?? thumbnails?.standard?.url;
media = Readable.from(
await fetch(hlsBase.match(REGEX_HLS_AUDIO_TRACK)[1])
.then((res) => res.text())
.then((data) => data.replaceAll("/videoplayback/", `https://${hlsUrl.hostname}/videoplayback/`))
);
const [, h, m, s] = info.contentDetails.duration.match(/P.*?T(\d+H)?(\d+M)?(\d+S)/);
length =
((h != null ? parseInt(h.replace("H", "")) * 60 * 60 : 0) +
(m != null ? parseInt(m.replace("M", "")) * 60 : 0) +
parseInt(s.replace("S", ""))) *
1000;
let stream;
if (!connection.connection.playing) {
try {
stream = await fetch(hf.config.cobalt_api, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Api-Key ${hf.apikeys.cobalt}`,
},
body: JSON.stringify({
url: `https://youtu.be/${id}`,
downloadMode: "audio",
filenameStyle: "basic",
}),
}).then((res) => res.json());
} catch (err) {
await textChannel.createMessage({
content: `:warning: Failed to get stream: \`\`\`\n${err}\n\`\`\``,
});
}
}
media = stream?.url;
} else if (type == "sc") {
if (url?.startsWith("sc:")) url = url.replace(/^sc:/, "https://soundcloud.com/");
const client_id = await getSoundcloudClientID();
@ -314,7 +337,7 @@ async function enqueue({guild_id, voice_id, text_id, url, type, addedBy, suppres
} else {
if (!media) {
textChannel.createMessage({
content: `:warning: No usable media was found for \`${url}\`. May possibly be due to region restrictions or paywalls.`,
content: type == "yt" ? "youtube :b:roke" : `:warning: No usable media was found for \`${url}\`.`,
});
return;
}
@ -367,18 +390,23 @@ async function enqueue({guild_id, voice_id, text_id, url, type, addedBy, suppres
}
async function youtubeSearch(msg, str) {
const {items} = await fetch(`${hf.config.piped_api}/search?q=${encodeURIComponent(str)}&filter=videos`).then((x) =>
x.json()
);
const {items} = await fetch(
`https://www.googleapis.com/youtube/v3/search?key=${
hf.apikeys.google
}&maxResults=5&part=snippet&type=video&q=${encodeURIComponent(str)}`
).then((res) => res.json());
const selection = items.map((item) => ({
value: "https://youtube.com" + item.url,
key: item.url.replace("/watch?v=", ""),
display: `${parseHtmlEntities(item.title).substring(0, 99)}${parseHtmlEntities(item.title).length > 99 ? "…" : ""}`,
description: `from ${parseHtmlEntities(item.uploaderName).substring(0, 95)}${
parseHtmlEntities(item.uploaderName).length > 95 ? "…" : ""
}`,
}));
const selection = items.map((item) => {
const title = parseHtmlEntities(item.snippet.title);
const channel = parseHtmlEntities(item.snippet.channelTitle);
return {
value: "https://youtu.be/" + item.id.videoId,
key: item.id.videoId,
display: `${title.substring(0, 99)}${title.length > 99 ? "…" : ""}`,
description: `from ${channel.substring(0, 95)}${channel.length > 95 ? "…" : ""}`,
};
});
try {
return await selectionMessage(msg, "Search results:", selection);