update
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
|
networks:
|
||||||
|
iptv:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
services:
|
services:
|
||||||
chzzk-proxy:
|
chzzk-proxy:
|
||||||
build: .
|
build: .
|
||||||
@@ -9,3 +13,21 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- iptv
|
||||||
|
|
||||||
|
threadfin:
|
||||||
|
image: fyb3roptik/threadfin:latest
|
||||||
|
container_name: threadfin
|
||||||
|
ports:
|
||||||
|
- "34400:34400"
|
||||||
|
environment:
|
||||||
|
- THREADFIN_PORT=34400
|
||||||
|
- THREADFIN_BRANCH=main
|
||||||
|
volumes:
|
||||||
|
- ./threadfin-config:/home/threadfin/conf
|
||||||
|
depends_on:
|
||||||
|
- chzzk-proxy
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- iptv
|
||||||
|
|||||||
@@ -33,6 +33,43 @@ app.get('/playlist.m3u', (req, res) => {
|
|||||||
res.send(m3u);
|
res.send(m3u);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Dynamic live-only playlist — only includes channels currently broadcasting
|
||||||
|
// This is the URL you point Threadfin at
|
||||||
|
app.get('/playlist-live.m3u', async (req, res) => {
|
||||||
|
const channels = parseChannels();
|
||||||
|
const host = req.get('host');
|
||||||
|
const protocol = req.protocol;
|
||||||
|
|
||||||
|
const results = await Promise.allSettled(
|
||||||
|
channels.map(async (ch) => {
|
||||||
|
try {
|
||||||
|
const content = await fetchLiveDetail(ch.id);
|
||||||
|
return { ch, content };
|
||||||
|
} catch {
|
||||||
|
return { ch, content: null };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
let m3u = "#EXTM3U\n";
|
||||||
|
|
||||||
|
results.forEach(r => {
|
||||||
|
if (r.status !== 'fulfilled') return;
|
||||||
|
const { ch, content } = r.value;
|
||||||
|
// Only include the channel if it is actively live
|
||||||
|
if (!content || content.status !== 'OPEN') return;
|
||||||
|
|
||||||
|
const title = content.liveTitle ? `${ch.name} — ${content.liveTitle}` : ch.name;
|
||||||
|
const logo = (content.channel && content.channel.channelImageUrl) || '';
|
||||||
|
|
||||||
|
m3u += `#EXTINF:-1 tvg-id="${ch.id}" tvg-name="${ch.name}" tvg-logo="${logo}" group-title="Chzzk Live",${title}\n`;
|
||||||
|
m3u += `${protocol}://${host}/stream/${ch.id}\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.header('Content-Type', 'application/vnd.apple.mpegurl');
|
||||||
|
res.send(m3u);
|
||||||
|
});
|
||||||
|
|
||||||
// Helper: build request headers with optional Naver auth cookies
|
// Helper: build request headers with optional Naver auth cookies
|
||||||
const buildHeaders = () => {
|
const buildHeaders = () => {
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -270,6 +307,7 @@ app.get('/key', async (req, res) => {
|
|||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Chzzk IPTV Proxy running on port ${port}`);
|
console.log(`Chzzk IPTV Proxy running on port ${port}`);
|
||||||
console.log(`Playlist URL: http://localhost:${port}/playlist.m3u`);
|
console.log(`Playlist URL: http://localhost:${port}/playlist.m3u`);
|
||||||
|
console.log(`Live Playlist URL: http://localhost:${port}/playlist-live.m3u`);
|
||||||
console.log(`Schedule URL: http://localhost:${port}/schedule`);
|
console.log(`Schedule URL: http://localhost:${port}/schedule`);
|
||||||
console.log(`EPG URL: http://localhost:${port}/epg.xml`);
|
console.log(`EPG URL: http://localhost:${port}/epg.xml`);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user