fix: channel id irregular

This commit is contained in:
obvTiger 2025-06-13 23:20:44 +02:00
parent 77b597e5d8
commit c1a4025cbd
5 changed files with 1152 additions and 2026 deletions

File diff suppressed because it is too large Load diff

View file

@ -160,8 +160,8 @@ document.addEventListener("DOMContentLoaded", () => {
}; };
function openVideoPlayer(video) { function openVideoPlayer(video) {
sessionStorage.setItem('currentVideo', JSON.stringify(video)); sessionStorage.setItem("currentVideo", JSON.stringify(video));
sessionStorage.setItem('lastSearchQuery', lastSearchQuery); sessionStorage.setItem("lastSearchQuery", lastSearchQuery);
const videoId = video.url.replace("/watch?v=", ""); const videoId = video.url.replace("/watch?v=", "");
window.location.href = `video.html?v=${videoId}`; window.location.href = `video.html?v=${videoId}`;
@ -204,8 +204,7 @@ document.addEventListener("DOMContentLoaded", () => {
uploadTime.textContent = video.uploadedDate || "Unknown date"; uploadTime.textContent = video.uploadedDate || "Unknown date";
videoCard.style.animationDelay = `${index * 0.05}s`; videoCard.style.animationDelay = `${index * 0.05}s`;
videoCard.addEventListener("click", async (e) => {
videoCard.addEventListener("click", (e) => {
if ( if (
e.target === uploaderAvatar || e.target === uploaderAvatar ||
e.target === uploaderName || e.target === uploaderName ||
@ -213,17 +212,19 @@ document.addEventListener("DOMContentLoaded", () => {
) { ) {
e.stopPropagation(); e.stopPropagation();
if (video.uploaderUrl) { if (video.uploaderUrl) {
openChannelPage(video.uploaderUrl.replace("/channel/", "")); const username = video.uploaderUrl;
openChannelPage(username);
} }
} else { } else {
openVideoPlayer(video); openVideoPlayer(video);
} }
}); });
uploader.addEventListener("click", (e) => { uploader.addEventListener("click", async (e) => {
e.stopPropagation(); e.stopPropagation();
if (video.uploaderUrl) { if (video.uploaderUrl) {
openChannelPage(video.uploaderUrl.replace("/channel/", "")); const username = video.uploaderUrl;
openChannelPage(username);
} }
}); });
} catch (error) { } catch (error) {
@ -245,7 +246,7 @@ document.addEventListener("DOMContentLoaded", () => {
const videos = await response.json(); const videos = await response.json();
sessionStorage.setItem('trendingVideos', JSON.stringify(videos)); sessionStorage.setItem("trendingVideos", JSON.stringify(videos));
showSkeletons(trendingGrid); showSkeletons(trendingGrid);
@ -295,7 +296,9 @@ document.addEventListener("DOMContentLoaded", () => {
searchLoader.style.display = "flex"; searchLoader.style.display = "flex";
try { try {
const url = `${searchApiUrl}?q=${encodeURIComponent(lastSearchQuery)}&filter=all`; const url = `${searchApiUrl}?q=${encodeURIComponent(
lastSearchQuery
)}&filter=all`;
console.log(`Fetching search results from: ${url}`); console.log(`Fetching search results from: ${url}`);
const response = await fetch(url); const response = await fetch(url);
@ -310,9 +313,13 @@ document.addEventListener("DOMContentLoaded", () => {
? searchData.items.filter((item) => item.type === "stream") ? searchData.items.filter((item) => item.type === "stream")
: []; : [];
sessionStorage.setItem('searchResults', JSON.stringify(results)); sessionStorage.setItem("searchResults", JSON.stringify(results));
console.log(`Found ${results.length} video results out of ${searchData.items ? searchData.items.length : 0} total items`); console.log(
`Found ${results.length} video results out of ${
searchData.items ? searchData.items.length : 0
} total items`
);
searchCountText.textContent = `${results.length} videos`; searchCountText.textContent = `${results.length} videos`;
@ -365,14 +372,15 @@ document.addEventListener("DOMContentLoaded", () => {
fetchTrendingVideos(); fetchTrendingVideos();
} }
async function fetchChannelData(channelId) { async function fetchChannelData(channelId) {
try { try {
if (channelId === activeChannelId) { const resolvedChannelId = await resolveChannelId(channelId);
if (resolvedChannelId === activeChannelId) {
return; return;
} }
activeChannelId = channelId; activeChannelId = resolvedChannelId;
channelNextPageData = null; channelNextPageData = null;
updateHash({ channelId }); updateHash({ channelId });
@ -393,11 +401,23 @@ document.addEventListener("DOMContentLoaded", () => {
channelAvatar.src = ""; channelAvatar.src = "";
channelBanner.src = ""; channelBanner.src = "";
channelVerified.style.display = "none"; channelVerified.style.display = "none";
let finalChannelId = channelId;
const url = `https://pipedapi.wireway.ch/channel/${channelId}`; if (!channelId.startsWith("UC")) {
console.log(`Fetching channel data from: ${url}`); const url = `/api/channel/${channelId}`;
console.log(`Resolving channel ID from: ${url}`);
const response = await fetch(url); const idResponse = await fetch(url);
if (!idResponse.ok) {
throw new Error(`Network response was not ok: ${idResponse.status}`);
}
const idData = await idResponse.json();
finalChannelId = idData.channelId;
}
const pipedUrl = `https://pipedapi.wireway.ch/channel/${finalChannelId}`;
console.log(`Fetching channel data from: ${pipedUrl}`);
const response = await fetch(pipedUrl);
if (!response.ok) { if (!response.ok) {
throw new Error(`Network response was not ok: ${response.status}`); throw new Error(`Network response was not ok: ${response.status}`);
@ -413,10 +433,15 @@ document.addEventListener("DOMContentLoaded", () => {
channelNextPageData = channelData.nextpage || null; channelNextPageData = channelData.nextpage || null;
channelTitle.textContent = channelData.name || "Unknown Channel"; channelTitle.textContent = channelData.name || "Unknown Channel";
channelSubs.textContent = formatSubscribers(channelData.subscriberCount || 0); channelSubs.textContent = formatSubscribers(
channelData.subscriberCount || 0
);
if (channelData.description) { if (channelData.description) {
channelDescription.textContent = channelData.description.replace(/\\n/g, "\n"); channelDescription.textContent = channelData.description.replace(
/\\n/g,
"\n"
);
} else { } else {
channelDescription.textContent = "No description available"; channelDescription.textContent = "No description available";
} }
@ -435,9 +460,13 @@ document.addEventListener("DOMContentLoaded", () => {
channelBanner.style.display = "none"; channelBanner.style.display = "none";
} }
channelVerified.style.display = channelData.verified ? "inline-block" : "none"; channelVerified.style.display = channelData.verified
? "inline-block"
: "none";
const relatedStreams = Array.isArray(channelData.relatedStreams) ? channelData.relatedStreams : []; const relatedStreams = Array.isArray(channelData.relatedStreams)
? channelData.relatedStreams
: [];
const videoCount = relatedStreams.length; const videoCount = relatedStreams.length;
showSkeletons(channelVideosGrid, Math.min(12, videoCount || 6)); showSkeletons(channelVideosGrid, Math.min(12, videoCount || 6));
@ -465,7 +494,8 @@ document.addEventListener("DOMContentLoaded", () => {
observeElements(); observeElements();
const loadMoreContainer = document.getElementById("channel-load-more"); const loadMoreContainer =
document.getElementById("channel-load-more");
if (channelNextPageData) { if (channelNextPageData) {
loadMoreContainer.style.display = "flex"; loadMoreContainer.style.display = "flex";
} else { } else {
@ -506,12 +536,18 @@ document.addEventListener("DOMContentLoaded", () => {
try { try {
isLoadingMoreVideos = true; isLoadingMoreVideos = true;
const loadMoreButton = document.getElementById("channel-load-more-button"); const loadMoreButton = document.getElementById(
const loadMoreSpinner = document.getElementById("channel-load-more-spinner"); "channel-load-more-button"
);
const loadMoreSpinner = document.getElementById(
"channel-load-more-spinner"
);
loadMoreButton.style.display = "none"; loadMoreButton.style.display = "none";
loadMoreSpinner.style.display = "block"; loadMoreSpinner.style.display = "block";
const url = `https://pipedapi.wireway.ch/nextpage/channel/${activeChannelId}?nextpage=${encodeURIComponent(channelNextPageData)}`; const url = `https://pipedapi.wireway.ch/nextpage/channel/${activeChannelId}?nextpage=${encodeURIComponent(
channelNextPageData
)}`;
console.log(`Fetching next page data from: ${url}`); console.log(`Fetching next page data from: ${url}`);
const response = await fetch(url); const response = await fetch(url);
@ -530,7 +566,9 @@ document.addEventListener("DOMContentLoaded", () => {
channelNextPageData = nextPageData.nextpage || null; channelNextPageData = nextPageData.nextpage || null;
const relatedStreams = nextPageData.relatedStreams; const relatedStreams = nextPageData.relatedStreams;
const startIndex = document.querySelectorAll(".channel-videos-grid .video-card").length; const startIndex = document.querySelectorAll(
".channel-videos-grid .video-card"
).length;
if (relatedStreams.length > 0) { if (relatedStreams.length > 0) {
relatedStreams.forEach((video, index) => { relatedStreams.forEach((video, index) => {
@ -568,21 +606,31 @@ document.addEventListener("DOMContentLoaded", () => {
</div> </div>
`; `;
loadMoreContainer.addEventListener('click', () => { loadMoreContainer.addEventListener("click", () => {
loadMoreContainer.innerHTML = ` loadMoreContainer.innerHTML = `
<div class="loader" id="channel-load-more-spinner" style="display: none;"></div> <div class="loader" id="channel-load-more-spinner" style="display: none;"></div>
<button class="load-more-button" id="channel-load-more-button">Load More Videos</button> <button class="load-more-button" id="channel-load-more-button">Load More Videos</button>
`; `;
document.getElementById("channel-load-more-button").addEventListener("click", loadMoreChannelVideos); document
.getElementById("channel-load-more-button")
.addEventListener("click", loadMoreChannelVideos);
}); });
} finally { } finally {
document.getElementById("channel-load-more-spinner").style.display = "none"; document.getElementById("channel-load-more-spinner").style.display =
"none";
isLoadingMoreVideos = false; isLoadingMoreVideos = false;
} }
} }
function openChannelPage(channelId) { async function openChannelPage(channelIdOrUsername) {
try {
// Remove any existing hash params
const channelId = await resolveChannelId(channelIdOrUsername);
updateHash({ channelId });
fetchChannelData(channelId); fetchChannelData(channelId);
} catch (error) {
console.error("Error opening channel page:", error);
}
} }
function checkInitialHash() { function checkInitialHash() {
@ -597,7 +645,11 @@ document.addEventListener("DOMContentLoaded", () => {
function setupInfiniteScroll() { function setupInfiniteScroll() {
window.addEventListener("scroll", function () { window.addEventListener("scroll", function () {
if (!channelPage.classList.contains("active") || !channelNextPageData || isLoadingMoreVideos) { if (
!channelPage.classList.contains("active") ||
!channelNextPageData ||
isLoadingMoreVideos
) {
return; return;
} }
@ -610,7 +662,9 @@ document.addEventListener("DOMContentLoaded", () => {
} }
}); });
document.getElementById("channel-load-more-button").addEventListener("click", loadMoreChannelVideos); document
.getElementById("channel-load-more-button")
.addEventListener("click", loadMoreChannelVideos);
} }
logo.addEventListener("click", () => { logo.addEventListener("click", () => {
@ -638,6 +692,26 @@ document.addEventListener("DOMContentLoaded", () => {
} }
}); });
async function resolveChannelId(username) {
if (!username) return null;
if (!username.startsWith("@")) return username;
try {
const response = await fetch(
`/api/channel/${encodeURIComponent(username)}`
);
if (!response.ok) {
console.error("Failed to resolve channel ID for:", username);
return username;
}
const data = await response.json();
return data.channelId;
} catch (error) {
console.error("Error resolving channel ID:", error);
return username;
}
}
fetchTrendingVideos(); fetchTrendingVideos();
checkInitialHash(); checkInitialHash();
setupInfiniteScroll(); setupInfiniteScroll();

View file

@ -2,7 +2,9 @@ document.addEventListener("DOMContentLoaded", () => {
const playerWrapper = document.getElementById("player-wrapper"); const playerWrapper = document.getElementById("player-wrapper");
const preparationOverlay = document.getElementById("preparation-overlay"); const preparationOverlay = document.getElementById("preparation-overlay");
const preparationStatus = document.getElementById("preparation-status"); const preparationStatus = document.getElementById("preparation-status");
const preparationProgressBar = document.getElementById("preparation-progress-bar"); const preparationProgressBar = document.getElementById(
"preparation-progress-bar"
);
const reloadButton = document.getElementById("reload-button"); const reloadButton = document.getElementById("reload-button");
const relatedGrid = document.getElementById("related-grid"); const relatedGrid = document.getElementById("related-grid");
const logo = document.getElementById("logo"); const logo = document.getElementById("logo");
@ -46,7 +48,9 @@ document.addEventListener("DOMContentLoaded", () => {
const secs = seconds % 60; const secs = seconds % 60;
if (hours > 0) { if (hours > 0) {
return `${hours}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`; return `${hours}:${minutes.toString().padStart(2, "0")}:${secs
.toString()
.padStart(2, "0")}`;
} else { } else {
return `${minutes}:${secs.toString().padStart(2, "0")}`; return `${minutes}:${secs.toString().padStart(2, "0")}`;
} }
@ -54,7 +58,7 @@ document.addEventListener("DOMContentLoaded", () => {
function getVideoIdFromUrl() { function getVideoIdFromUrl() {
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('v'); return urlParams.get("v");
} }
function getVideoElement() { function getVideoElement() {
@ -109,13 +113,15 @@ document.addEventListener("DOMContentLoaded", () => {
} }
); );
document.querySelectorAll(".animated-item:not(.visible)").forEach((item) => { document
.querySelectorAll(".animated-item:not(.visible)")
.forEach((item) => {
observer.observe(item); observer.observe(item);
}); });
}; };
function openVideoPlayer(video) { function openVideoPlayer(video) {
sessionStorage.setItem('currentVideo', JSON.stringify(video)); sessionStorage.setItem("currentVideo", JSON.stringify(video));
const videoId = video.url.replace("/watch?v=", ""); const videoId = video.url.replace("/watch?v=", "");
window.location.href = `video.html?v=${videoId}`; window.location.href = `video.html?v=${videoId}`;
} }
@ -153,10 +159,22 @@ document.addEventListener("DOMContentLoaded", () => {
uploadTime.textContent = video.uploadedDate || "Unknown date"; uploadTime.textContent = video.uploadedDate || "Unknown date";
videoCard.style.animationDelay = `${index * 0.05}s`; videoCard.style.animationDelay = `${index * 0.05}s`;
videoCard.addEventListener("click", async (e) => {
videoCard.addEventListener("click", (e) => { const uploader = card.querySelector(".uploader");
e.preventDefault(); if (
e.target === uploaderAvatar ||
e.target === uploaderName ||
(e.target.parentElement && e.target.parentElement === uploader)
) {
e.stopPropagation();
if (video.uploaderUrl) {
const username = video.uploaderUrl;
const channelId = await getChannelId(username);
window.location.href = `index.html#channelId=${channelId}`;
}
} else {
openVideoPlayer(video); openVideoPlayer(video);
}
}); });
} catch (error) { } catch (error) {
console.error("Error creating video card:", error, video); console.error("Error creating video card:", error, video);
@ -166,7 +184,7 @@ document.addEventListener("DOMContentLoaded", () => {
} }
async function findVideoById(videoId) { async function findVideoById(videoId) {
const storedVideo = sessionStorage.getItem('currentVideo'); const storedVideo = sessionStorage.getItem("currentVideo");
if (storedVideo) { if (storedVideo) {
const video = JSON.parse(storedVideo); const video = JSON.parse(storedVideo);
if (video.url.includes(videoId)) { if (video.url.includes(videoId)) {
@ -174,16 +192,18 @@ document.addEventListener("DOMContentLoaded", () => {
} }
} }
const storedTrending = sessionStorage.getItem('trendingVideos'); const storedTrending = sessionStorage.getItem("trendingVideos");
if (storedTrending) { if (storedTrending) {
const trendingVideos = JSON.parse(storedTrending); const trendingVideos = JSON.parse(storedTrending);
const foundInTrending = trendingVideos.find((v) => v.url.includes(videoId)); const foundInTrending = trendingVideos.find((v) =>
v.url.includes(videoId)
);
if (foundInTrending) { if (foundInTrending) {
return foundInTrending; return foundInTrending;
} }
} }
const storedSearch = sessionStorage.getItem('searchResults'); const storedSearch = sessionStorage.getItem("searchResults");
if (storedSearch) { if (storedSearch) {
const searchResults = JSON.parse(storedSearch); const searchResults = JSON.parse(storedSearch);
const foundInSearch = searchResults.find((v) => v.url.includes(videoId)); const foundInSearch = searchResults.find((v) => v.url.includes(videoId));
@ -193,7 +213,7 @@ document.addEventListener("DOMContentLoaded", () => {
} }
try { try {
console.log('Video not found in cache, fetching from trending API...'); console.log("Video not found in cache, fetching from trending API...");
const response = await fetch(trendingApiUrl); const response = await fetch(trendingApiUrl);
if (response.ok) { if (response.ok) {
const videos = await response.json(); const videos = await response.json();
@ -203,15 +223,21 @@ document.addEventListener("DOMContentLoaded", () => {
} }
} }
const lastSearchQuery = sessionStorage.getItem('lastSearchQuery'); const lastSearchQuery = sessionStorage.getItem("lastSearchQuery");
if (lastSearchQuery) { if (lastSearchQuery) {
console.log('Trying search API with last query...'); console.log("Trying search API with last query...");
const searchUrl = `${searchApiUrl}?q=${encodeURIComponent(lastSearchQuery)}&filter=all`; const searchUrl = `${searchApiUrl}?q=${encodeURIComponent(
lastSearchQuery
)}&filter=all`;
const searchResponse = await fetch(searchUrl); const searchResponse = await fetch(searchUrl);
if (searchResponse.ok) { if (searchResponse.ok) {
const searchData = await searchResponse.json(); const searchData = await searchResponse.json();
const searchResults = searchData.items ? searchData.items.filter((item) => item.type === "stream") : []; const searchResults = searchData.items
const foundInSearch = searchResults.find((v) => v.url.includes(videoId)); ? searchData.items.filter((item) => item.type === "stream")
: [];
const foundInSearch = searchResults.find((v) =>
v.url.includes(videoId)
);
if (foundInSearch) { if (foundInSearch) {
return foundInSearch; return foundInSearch;
} }
@ -271,7 +297,8 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
} else { } else {
console.error("HLS is not supported in this browser"); console.error("HLS is not supported in this browser");
preparationStatus.textContent = "Your browser does not support HLS playback"; preparationStatus.textContent =
"Your browser does not support HLS playback";
} }
} }
@ -306,7 +333,9 @@ document.addEventListener("DOMContentLoaded", () => {
} else if (data.preparing !== undefined) { } else if (data.preparing !== undefined) {
const percentage = parseFloat(data.preparing); const percentage = parseFloat(data.preparing);
preparationProgressBar.style.width = `${percentage}%`; preparationProgressBar.style.width = `${percentage}%`;
preparationStatus.textContent = `Preparing video... ${percentage.toFixed(0)}%`; preparationStatus.textContent = `Preparing video... ${percentage.toFixed(
0
)}%`;
} else if (data.done && data.streamUrl) { } else if (data.done && data.streamUrl) {
preparationStatus.textContent = "Video ready! Starting playback..."; preparationStatus.textContent = "Video ready! Starting playback...";
preparationProgressBar.style.width = "100%"; preparationProgressBar.style.width = "100%";
@ -320,7 +349,8 @@ document.addEventListener("DOMContentLoaded", () => {
activeWs.close(); activeWs.close();
activeWs = null; activeWs = null;
} else { } else {
preparationStatus.textContent = "Video playback failed. Try reloading the page."; preparationStatus.textContent =
"Video playback failed. Try reloading the page.";
reloadButton.style.display = "block"; reloadButton.style.display = "block";
prepareInProgress = false; prepareInProgress = false;
} }
@ -328,7 +358,8 @@ document.addEventListener("DOMContentLoaded", () => {
activeWs.onerror = (error) => { activeWs.onerror = (error) => {
console.error("WebSocket error:", error); console.error("WebSocket error:", error);
preparationStatus.textContent = "Error preparing video. Please try again."; preparationStatus.textContent =
"Error preparing video. Please try again.";
reloadButton.style.display = "block"; reloadButton.style.display = "block";
prepareInProgress = false; prepareInProgress = false;
@ -346,6 +377,25 @@ document.addEventListener("DOMContentLoaded", () => {
} }
}; };
} }
async function getChannelId(username) {
try {
if (username.startsWith("UC")) {
return username;
}
const response = await fetch(
`/api/channel/${encodeURIComponent(username)}`
);
if (!response.ok) {
throw new Error(`Failed to fetch channel ID: ${response.status}`);
}
const data = await response.json();
return data.channelId;
} catch (error) {
console.error("Error fetching channel ID:", error);
return username;
}
}
function displayVideoDetails(video) { function displayVideoDetails(video) {
document.title = `${video.title} - Repiped`; document.title = `${video.title} - Repiped`;
@ -355,14 +405,18 @@ document.addEventListener("DOMContentLoaded", () => {
detailUploaded.textContent = video.uploadedDate; detailUploaded.textContent = video.uploadedDate;
detailViews.textContent = formatViews(video.views); detailViews.textContent = formatViews(video.views);
detailDuration.textContent = formatDuration(video.duration); detailDuration.textContent = formatDuration(video.duration);
detailDescription.textContent = video.shortDescription || "No description available"; detailDescription.textContent =
video.shortDescription || "No description available";
const videoDetailUploader = document.querySelector(".video-detail-uploader"); const videoDetailUploader = document.querySelector(
".video-detail-uploader"
);
if (videoDetailUploader) { if (videoDetailUploader) {
videoDetailUploader.style.cursor = "pointer"; videoDetailUploader.style.cursor = "pointer";
videoDetailUploader.addEventListener("click", () => { videoDetailUploader.addEventListener("click", async () => {
if (video.uploaderUrl) { if (video.uploaderUrl) {
const channelId = video.uploaderUrl.replace("/channel/", ""); const username = video.uploaderUrl;
const channelId = await getChannelId(username);
window.location.href = `index.html#channelId=${channelId}`; window.location.href = `index.html#channelId=${channelId}`;
} }
}); });
@ -372,7 +426,7 @@ document.addEventListener("DOMContentLoaded", () => {
async function fetchRelatedVideos(currentVideo) { async function fetchRelatedVideos(currentVideo) {
try { try {
let videos = []; let videos = [];
const storedTrending = sessionStorage.getItem('trendingVideos'); const storedTrending = sessionStorage.getItem("trendingVideos");
if (storedTrending) { if (storedTrending) {
videos = JSON.parse(storedTrending); videos = JSON.parse(storedTrending);
@ -413,7 +467,9 @@ document.addEventListener("DOMContentLoaded", () => {
async function performSearch(query) { async function performSearch(query) {
if (!query || query.trim() === "") return; if (!query || query.trim() === "") return;
window.location.href = `index.html#search=${encodeURIComponent(query.trim())}`; window.location.href = `index.html#search=${encodeURIComponent(
query.trim()
)}`;
} }
async function loadVideo() { async function loadVideo() {
@ -438,14 +494,13 @@ document.addEventListener("DOMContentLoaded", () => {
currentVideo = video; currentVideo = video;
sessionStorage.setItem('currentVideo', JSON.stringify(video)); sessionStorage.setItem("currentVideo", JSON.stringify(video));
displayVideoDetails(video); displayVideoDetails(video);
prepareVideo(video.url); prepareVideo(video.url);
fetchRelatedVideos(video); fetchRelatedVideos(video);
} catch (error) { } catch (error) {
console.error("Error loading video:", error); console.error("Error loading video:", error);
alert("Error loading video. Redirecting to home page."); alert("Error loading video. Redirecting to home page.");

41
routes/channel.js Normal file
View file

@ -0,0 +1,41 @@
const axios = require("axios");
const cheerio = require("cheerio");
function channelRouteHandler(app) {
app.get("/api/channel/:username", async (req, res) => {
try {
const username = req.params.username;
if (!username) {
return res.status(400).json({ error: "Username is required" });
}
const response = await axios.get(`https://www.youtube.com/${username}`);
const $ = cheerio.load(response.data);
const canonicalLink = $('link[rel="canonical"]').attr("href");
if (!canonicalLink) {
return res.status(404).json({ error: "Channel not found" });
}
const channelIdMatch = canonicalLink.match(/\/channel\/([\w-]+)/);
const channelId = channelIdMatch ? channelIdMatch[1] : null;
if (!channelId) {
return res.status(404).json({ error: "Could not extract channel ID" });
}
return res.json({
channelId: channelId,
username: username,
});
} catch (error) {
console.error("Error fetching channel ID:", error.message);
return res.status(500).json({
error: "Failed to fetch channel ID",
message: error.message,
});
}
});
}
module.exports = channelRouteHandler;

View file

@ -1,5 +1,5 @@
const https = require("https"); const https = require("https");
const yts = require('yt-search'); const yts = require("yt-search");
function searchRouteHandler(app) { function searchRouteHandler(app) {
app.get("/api/search", async (req, res) => { app.get("/api/search", async (req, res) => {
@ -10,32 +10,36 @@ function searchRouteHandler(app) {
} }
const results = await yts(query); const results = await yts(query);
console.log(results.videos[0]) console.log(results.videos[0]);
const formattedResults = { const formattedResults = {
items: results.videos.map(video => ({ items: results.videos.map((video) => ({
url: `/watch?v=${video.videoId}`, url: `/watch?v=${video.videoId}`,
type: "stream", type: "stream",
title: video.title, title: video.title,
thumbnail: `/api/thumbnail/${video.videoId}`, thumbnail: `/api/thumbnail/${video.videoId}`,
uploaderName: video.author.name, uploaderName: video.author.name,
uploaderUrl: `/channel/${video.author.url}`, uploaderUrl: `${video.author.url.replace(
uploaderAvatar: `/api/avatar/${video.author.url.replace("https://youtube.com/", "")}.png`, "https://youtube.com/",
""
)}`,
uploaderAvatar: `/api/avatar/${video.author.url.replace(
"https://youtube.com/",
""
)}.png`,
uploadedDate: video.ago, uploadedDate: video.ago,
shortDescription: video.description, shortDescription: video.description,
duration: video.seconds, duration: video.seconds,
views: video.views, views: video.views,
uploaded: new Date(video.timestamp * 1000).getTime(), uploaded: new Date(video.timestamp * 1000).getTime(),
uploaderVerified: false, isShort: video.duration.seconds < 60,
isShort: video.duration.seconds < 60
})), })),
nextpage: "", nextpage: "",
suggestion: "", suggestion: "",
corrected: false corrected: false,
}; };
res.json(formattedResults); res.json(formattedResults);
} catch (err) { } catch (err) {
console.error(`Error searching videos: ${err.message}`); console.error(`Error searching videos: ${err.message}`);
res.status(500).send("Error searching videos"); res.status(500).send("Error searching videos");