fix: channel id irregular
This commit is contained in:
parent
77b597e5d8
commit
c1a4025cbd
5 changed files with 1152 additions and 2026 deletions
1048
public/script.js
1048
public/script.js
File diff suppressed because it is too large
Load diff
|
@ -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();
|
||||||
|
|
115
public/video.js
115
public/video.js
|
@ -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
41
routes/channel.js
Normal 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;
|
|
@ -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");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue