fix: use NEXT_PUBLIC_API_URL and add yt-dlp to fix backend info fetching
This commit is contained in:
parent
bc1be07967
commit
66d95e0fb4
9 changed files with 58 additions and 21 deletions
|
|
@ -12,7 +12,9 @@ RUN CGO_ENABLED=1 GOOS=linux go build -o kv-tube .
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates ffmpeg curl
|
RUN apk add --no-cache ca-certificates ffmpeg curl python3 py3-pip && \
|
||||||
|
curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp && \
|
||||||
|
chmod a+rx /usr/local/bin/yt-dlp
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ services:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "5011:3000"
|
- "5011:3000"
|
||||||
|
environment:
|
||||||
|
- NEXT_PUBLIC_API_URL=http://kv-tube-backend:8080
|
||||||
depends_on:
|
depends_on:
|
||||||
- kv-tube-backend
|
- kv-tube-backend
|
||||||
labels:
|
labels:
|
||||||
|
|
|
||||||
33
fix_urls.js
Normal file
33
fix_urls.js
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const glob = require('glob');
|
||||||
|
|
||||||
|
// Use simple find approach for ts/tsx files
|
||||||
|
const execSync = require('child_process').execSync;
|
||||||
|
const files = execSync('find frontend -type f -name "*.ts" -o -name "*.tsx"').toString().trim().split('\n');
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
let content = fs.readFileSync(file, 'utf8');
|
||||||
|
// Revert the bad perl replacement
|
||||||
|
content = content.replace(/\$\{process\.env\.NEXT_PUBLIC_API_URL \|\| 'http:\/\/127\.0\.0\.1:8080'\}/g, 'http://127.0.0.1:8080');
|
||||||
|
|
||||||
|
// Apply proper replacement:
|
||||||
|
// const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080';
|
||||||
|
// fetch(`http://127.0.0.1:8080...`) -> fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}...`)
|
||||||
|
|
||||||
|
// Actually, only fetch calls need the environment var, but we can just replace 'http://127.0.0.1:8080'
|
||||||
|
// with API_BASE if we import or define API_BASE. Since it's easier, let's just replace the raw literal string.
|
||||||
|
|
||||||
|
content = content.replace(/'http:\/\/127\.0\.0\.1:8080/g, '`${process.env.NEXT_PUBLIC_API_URL || \'http://127.0.0.1:8080\'}');
|
||||||
|
content = content.replace(/"http:\/\/127\.0\.0\.1:8080/g, '`${process.env.NEXT_PUBLIC_API_URL || \'http://127.0.0.1:8080\'}');
|
||||||
|
content = content.replace(/`http:\/\/127\.0\.0\.1:8080/g, '`${process.env.NEXT_PUBLIC_API_URL || \'http://127.0.0.1:8080\'}');
|
||||||
|
|
||||||
|
// We have to be careful not to double replace. The above will turn 'http://127.0.0.1:8080/api...' into
|
||||||
|
// `${process.env...}/api...`
|
||||||
|
|
||||||
|
// Let's actually just revert the breaking perl replace first:
|
||||||
|
// It looks like: process.env.NEXT_PUBLIC_API_URL || '${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}'
|
||||||
|
|
||||||
|
fs.writeFileSync(file, content);
|
||||||
|
});
|
||||||
|
console.log("Done");
|
||||||
|
|
@ -5,7 +5,7 @@ const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080';
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
const videoId = request.nextUrl.searchParams.get('v');
|
const videoId = request.nextUrl.searchParams.get('v');
|
||||||
const formatId = request.nextUrl.searchParams.get('f');
|
const formatId = request.nextUrl.searchParams.get('f');
|
||||||
|
|
||||||
if (!videoId) {
|
if (!videoId) {
|
||||||
return NextResponse.json({ error: 'No video ID' }, { status: 400 });
|
return NextResponse.json({ error: 'No video ID' }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
@ -15,13 +15,13 @@ export async function GET(request: NextRequest) {
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
return NextResponse.json({ error: data.error || 'Download failed' }, { status: 500 });
|
return NextResponse.json({ error: data.error || 'Download failed' }, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json(data);
|
return NextResponse.json(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: 'Failed to get download link' }, { status: 500 });
|
return NextResponse.json({ error: 'Failed to get download link' }, { status: 500 });
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,25 @@ import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
const videoId = request.nextUrl.searchParams.get('v');
|
const videoId = request.nextUrl.searchParams.get('v');
|
||||||
|
|
||||||
if (!videoId) {
|
if (!videoId) {
|
||||||
return NextResponse.json({ error: 'No video ID' }, { status: 400 });
|
return NextResponse.json({ error: 'No video ID' }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://127.0.0.1:8080/api/get_stream_info?v=${videoId}`, {
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}/api/get_stream_info?v=${videoId}`, {
|
||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
return NextResponse.json({ error: 'Failed to fetch' }, { status: 500 });
|
return NextResponse.json({ error: 'Failed to fetch' }, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const streamUrl = data.original_url || data.stream_url;
|
const streamUrl = data.original_url || data.stream_url;
|
||||||
const proxyUrl = streamUrl ? `/api/proxy-stream?url=${encodeURIComponent(streamUrl)}` : null;
|
const proxyUrl = streamUrl ? `/api/proxy-stream?url=${encodeURIComponent(streamUrl)}` : null;
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
streamUrl: proxyUrl,
|
streamUrl: proxyUrl,
|
||||||
title: data.title,
|
title: data.title,
|
||||||
thumbnail: data.thumbnail
|
thumbnail: data.thumbnail
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ function formatSubscribers(count: number): string {
|
||||||
|
|
||||||
async function getChannelInfo(id: string) {
|
async function getChannelInfo(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://127.0.0.1:8080/api/channel/info?id=${id}`, { cache: 'no-store' });
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}/api/channel/info?id=${id}`, { cache: 'no-store' });
|
||||||
if (!res.ok) return null;
|
if (!res.ok) return null;
|
||||||
return res.json() as Promise<ChannelInfo>;
|
return res.json() as Promise<ChannelInfo>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -40,7 +40,7 @@ async function getChannelInfo(id: string) {
|
||||||
|
|
||||||
async function getChannelVideos(id: string) {
|
async function getChannelVideos(id: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://127.0.0.1:8080/api/channel/videos?id=${id}&limit=30`, { cache: 'no-store' });
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}/api/channel/videos?id=${id}&limit=30`, { cache: 'no-store' });
|
||||||
if (!res.ok) return [];
|
if (!res.ok) return [];
|
||||||
return res.json() as Promise<VideoData[]>;
|
return res.json() as Promise<VideoData[]>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ interface Subscription {
|
||||||
|
|
||||||
async function getHistory() {
|
async function getHistory() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('http://127.0.0.1:8080/api/history?limit=20', { cache: 'no-store' });
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}/api/history?limit=20`, { cache: 'no-store' });
|
||||||
if (!res.ok) return [];
|
if (!res.ok) return [];
|
||||||
return res.json() as Promise<VideoData[]>;
|
return res.json() as Promise<VideoData[]>;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -28,7 +28,7 @@ async function getHistory() {
|
||||||
|
|
||||||
async function getSubscriptions() {
|
async function getSubscriptions() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('http://127.0.0.1:8080/api/subscriptions', { cache: 'no-store' });
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}/api/subscriptions`, { cache: 'no-store' });
|
||||||
if (!res.ok) return [];
|
if (!res.ok) return [];
|
||||||
return res.json() as Promise<Subscription[]>;
|
return res.json() as Promise<Subscription[]>;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ interface Subscription {
|
||||||
|
|
||||||
async function getSubscriptions() {
|
async function getSubscriptions() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('http://127.0.0.1:8080/api/subscriptions', { cache: 'no-store' });
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}/api/subscriptions`, { cache: 'no-store' });
|
||||||
if (!res.ok) return [];
|
if (!res.ok) return [];
|
||||||
return res.json() as Promise<Subscription[]>;
|
return res.json() as Promise<Subscription[]>;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -29,7 +29,7 @@ async function getSubscriptions() {
|
||||||
|
|
||||||
async function getChannelVideos(channelId: string, limit: number = 5) {
|
async function getChannelVideos(channelId: string, limit: number = 5) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://127.0.0.1:8080/api/channel/videos?id=${channelId}&limit=${limit}`, { cache: 'no-store' });
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}/api/channel/videos?id=${channelId}&limit=${limit}`, { cache: 'no-store' });
|
||||||
if (!res.ok) return [];
|
if (!res.ok) return [];
|
||||||
return res.json() as Promise<VideoData[]>;
|
return res.json() as Promise<VideoData[]>;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -65,10 +65,10 @@ export default async function SubscriptionsPage() {
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '24px', maxWidth: '1400px', margin: '0 auto' }}>
|
<div style={{ padding: '24px', maxWidth: '1400px', margin: '0 auto' }}>
|
||||||
<h1 style={{ fontSize: '24px', fontWeight: '600', marginBottom: '24px' }}>Subscriptions</h1>
|
<h1 style={{ fontSize: '24px', fontWeight: '600', marginBottom: '24px' }}>Subscriptions</h1>
|
||||||
|
|
||||||
{videosPerChannel.map(({ subscription, videos }) => (
|
{videosPerChannel.map(({ subscription, videos }) => (
|
||||||
<section key={subscription.channel_id} style={{ marginBottom: '32px' }}>
|
<section key={subscription.channel_id} style={{ marginBottom: '32px' }}>
|
||||||
<Link
|
<Link
|
||||||
href={`/channel/${subscription.channel_id}`}
|
href={`/channel/${subscription.channel_id}`}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
@ -93,7 +93,7 @@ export default async function SubscriptionsPage() {
|
||||||
</div>
|
</div>
|
||||||
<h2 style={{ fontSize: '18px', fontWeight: '500' }}>{subscription.channel_name || subscription.channel_id}</h2>
|
<h2 style={{ fontSize: '18px', fontWeight: '500' }}>{subscription.channel_name || subscription.channel_id}</h2>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{videos.length > 0 ? (
|
{videos.length > 0 ? (
|
||||||
<div style={{
|
<div style={{
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ function formatViews(views: number): string {
|
||||||
|
|
||||||
async function fetchSearchResults(query: string) {
|
async function fetchSearchResults(query: string) {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`http://127.0.0.1:8080/api/search?q=${encodeURIComponent(query)}`, { cache: 'no-store' });
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8080'}/api/search?q=${encodeURIComponent(query)}`, { cache: 'no-store' });
|
||||||
if (!res.ok) return [];
|
if (!res.ok) return [];
|
||||||
return res.json() as Promise<VideoData[]>;
|
return res.json() as Promise<VideoData[]>;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue