diff --git a/docker-compose.yml b/docker-compose.yml index 47e6a64..8062c4c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,9 +4,9 @@ version: '3.8' services: - kv-tube-app: + kv-tube: image: git.khoavo.myds.me/vndangkhoa/kv-tube:v4.0.8 - container_name: kv-tube-app + container_name: kv-tube platform: linux/amd64 restart: unless-stopped ports: diff --git a/frontend/app/components/VideoCard.tsx b/frontend/app/components/VideoCard.tsx index 9c74b60..af27507 100644 --- a/frontend/app/components/VideoCard.tsx +++ b/frontend/app/components/VideoCard.tsx @@ -51,6 +51,10 @@ function VideoCard({ video, hideChannelAvatar }: { video: VideoData; hideChannel style={{ objectFit: 'cover', backgroundColor: 'var(--yt-hover)' }} className="videocard-thumb" priority={false} + onError={(e) => { + e.target.onError = null; // Prevent infinite loop + e.target.src = 'https://i.ytimg.com/vi/default/hqdefault.jpg'; // Fallback to YouTube's default thumbnail + }} /> {video.duration && !video.is_mix && (
diff --git a/frontend/app/feed/library/page.tsx b/frontend/app/feed/library/page.tsx index df622f8..5e271b2 100644 --- a/frontend/app/feed/library/page.tsx +++ b/frontend/app/feed/library/page.tsx @@ -144,12 +144,16 @@ export default async function LibraryPage() { }} >
- {video.title} + {video.title} { + e.target.onError = null; // Prevent infinite loop + e.target.src = 'https://i.ytimg.com/vi/default/hqdefault.jpg'; // Fallback to YouTube's default thumbnail + }} + /> {video.duration && (
{video.duration}
)} diff --git a/frontend/app/feed/subscriptions/page.tsx b/frontend/app/feed/subscriptions/page.tsx index 272173c..9d114c9 100644 --- a/frontend/app/feed/subscriptions/page.tsx +++ b/frontend/app/feed/subscriptions/page.tsx @@ -119,11 +119,15 @@ export default async function SubscriptionsPage() { className="card-hover-lift" >
- {video.title} + {video.title} { + e.target.onError = null; // Prevent infinite loop + e.target.src = 'https://i.ytimg.com/vi/default/hqdefault.jpg'; // Fallback to YouTube's default thumbnail + }} + /> {video.duration && (
{video.duration}
)} diff --git a/frontend/app/search/page.tsx b/frontend/app/search/page.tsx index e196d27..15be355 100644 --- a/frontend/app/search/page.tsx +++ b/frontend/app/search/page.tsx @@ -82,12 +82,16 @@ async function SearchResults({ query }: { query: string }) { {/* Thumbnail */}
{/* eslint-disable-next-line @next/next/no-img-element */} - {v.title} + {v.title} { + e.target.onError = null; // Prevent infinite loop + e.target.src = 'https://i.ytimg.com/vi/default/hqdefault.jpg'; // Fallback to YouTube's default thumbnail + }} + /> {v.duration && ( {v.duration} @@ -108,10 +112,18 @@ async function SearchResults({ query }: { query: string }) {
- {v.avatar_url ? ( - // eslint-disable-next-line @next/next/no-img-element - - ) : firstLetter} + {v.avatar_url ? ( + // eslint-disable-next-line @next/next/no-img-element + { + e.target.onError = null; // Prevent infinite loop + e.target.src = 'https://i.ytimg.com/img/channels/c_ip_m_default.jpg'; // Fallback to YouTube's default channel avatar + }} + /> + ) : firstLetter}
{v.uploader}
diff --git a/frontend/app/watch/Comments.tsx b/frontend/app/watch/Comments.tsx index df329d1..b0aebcb 100644 --- a/frontend/app/watch/Comments.tsx +++ b/frontend/app/watch/Comments.tsx @@ -115,13 +115,17 @@ export default function Comments({ videoId }: CommentsProps) { {comments.map((c) => (
- {c.author} + {c.author} { + e.target.onError = null; // Prevent infinite loop + e.target.src = 'https://i.ytimg.com/img/channels/c_ip_m_default.jpg'; // Fallback to YouTube's default channel avatar + }} + />
diff --git a/frontend/app/watch/PlaylistPanel.tsx b/frontend/app/watch/PlaylistPanel.tsx index dfcad3f..a02bb5e 100644 --- a/frontend/app/watch/PlaylistPanel.tsx +++ b/frontend/app/watch/PlaylistPanel.tsx @@ -93,13 +93,17 @@ export default function PlaylistPanel({ videos, currentVideoId, listId, title }: borderRadius: '8px', overflow: 'hidden' }}> - {video.title} + {video.title} { + e.target.onError = null; // Prevent infinite loop + e.target.src = 'https://i.ytimg.com/vi/default/hqdefault.jpg'; // Fallback to YouTube's default thumbnail + }} + /> {video.duration && (
- {video.title} + {video.title} { + e.target.onError = null; // Prevent infinite loop + e.target.src = 'https://i.ytimg.com/vi/default/hqdefault.jpg'; // Fallback to YouTube's default thumbnail + }} + /> {video.duration && (
{video.duration} diff --git a/frontend/app/watch/VideoPlayer.tsx b/frontend/app/watch/VideoPlayer.tsx index bd4f389..de55024 100644 --- a/frontend/app/watch/VideoPlayer.tsx +++ b/frontend/app/watch/VideoPlayer.tsx @@ -557,18 +557,22 @@ export default function VideoPlayer({ videoId, title }: VideoPlayerProps) {
)} -