live stream support
This commit is contained in:
@@ -110,7 +110,7 @@ App.videos = App.videos || {};
|
||||
App.videos.buildImageProxyUrl = function(imageUrl) {
|
||||
if (!imageUrl) return '';
|
||||
try {
|
||||
return `/api/image?url=${encodeURIComponent(imageUrl)}&ts=${Date.now()}`;
|
||||
return `/api/image?url=${encodeURIComponent(imageUrl)}`;
|
||||
} catch (err) {
|
||||
return '';
|
||||
}
|
||||
@@ -290,14 +290,16 @@ App.videos = App.videos || {};
|
||||
const tagsMarkup = tags.length
|
||||
? `<div class="video-tags">${tags.map(tag => `<button class="video-tag" type="button" data-tag="${tag}">${tag}</button>`).join('')}</div>`
|
||||
: '';
|
||||
const liveBadge = v.isLive ? '<span class="live-badge">● LIVE</span>' : '';
|
||||
card.innerHTML = `
|
||||
${liveBadge}
|
||||
<button class="favorite-btn" type="button" aria-pressed="false" aria-label="Add to favorites" data-fav-key="${favoriteKey || ''}">♡</button>
|
||||
<button class="video-menu-btn" type="button" aria-haspopup="true" aria-expanded="false" aria-label="More options">⋯</button>
|
||||
<div class="video-menu" role="menu">
|
||||
<button class="video-menu-item" type="button" data-action="info" role="menuitem">Show info</button>
|
||||
<button class="video-menu-item" type="button" data-action="download" role="menuitem">Download</button>
|
||||
</div>
|
||||
<img src="${v.thumb}" alt="${v.title}">
|
||||
<img src="${v.thumb}" alt="${v.title}" loading="lazy" decoding="async">
|
||||
<div class="video-loading" aria-hidden="true">
|
||||
<div class="video-loading-spinner"></div>
|
||||
</div>
|
||||
@@ -432,11 +434,16 @@ App.videos = App.videos || {};
|
||||
App.videos.handleSearch = function(value) {
|
||||
if (typeof value === 'string') {
|
||||
const searchInput = document.getElementById('search-input');
|
||||
if (searchInput) {
|
||||
if (searchInput.value !== value) {
|
||||
searchInput.value = value;
|
||||
}
|
||||
searchInput.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
if (searchInput && searchInput.value !== value) {
|
||||
searchInput.value = value;
|
||||
}
|
||||
// Keep the clear button in sync without re-dispatching an `input`
|
||||
// event (which would re-trigger the debounced reload listener).
|
||||
const clearBtn = document.getElementById('search-clear-btn');
|
||||
if (searchInput && clearBtn) {
|
||||
const hasValue = searchInput.value.trim().length > 0;
|
||||
clearBtn.classList.toggle('is-visible', hasValue);
|
||||
clearBtn.disabled = !hasValue;
|
||||
}
|
||||
}
|
||||
state.currentPage = 1;
|
||||
@@ -600,6 +607,8 @@ App.videos = App.videos || {};
|
||||
let sourceUrl = '';
|
||||
let referer = '';
|
||||
let userAgent = '';
|
||||
const isLive = !!(videoOrUrl && typeof videoOrUrl === 'object' &&
|
||||
(videoOrUrl.isLive || (videoOrUrl.meta && videoOrUrl.meta.isLive)));
|
||||
if (typeof videoOrUrl === 'string') {
|
||||
sourceUrl = videoOrUrl;
|
||||
} else if (videoOrUrl && typeof videoOrUrl === 'object') {
|
||||
@@ -634,7 +643,7 @@ App.videos = App.videos || {};
|
||||
referer = '';
|
||||
}
|
||||
}
|
||||
return { url: sourceUrl, referer, userAgent };
|
||||
return { url: sourceUrl, referer, userAgent, isLive };
|
||||
};
|
||||
|
||||
// Builds a proxied stream URL. Extra params other than `url` are forwarded
|
||||
@@ -644,7 +653,8 @@ App.videos = App.videos || {};
|
||||
if (!resolved.url) return '';
|
||||
const refererParam = resolved.referer ? `&referer=${encodeURIComponent(resolved.referer)}` : '';
|
||||
const userAgentParam = resolved.userAgent ? `&User-Agent=${encodeURIComponent(resolved.userAgent)}` : '';
|
||||
return `/api/stream?url=${encodeURIComponent(resolved.url)}${refererParam}${userAgentParam}`;
|
||||
const liveParam = resolved.isLive ? '&live=1' : '';
|
||||
return `/api/stream?url=${encodeURIComponent(resolved.url)}${refererParam}${userAgentParam}${liveParam}`;
|
||||
};
|
||||
|
||||
App.videos.downloadVideo = function(video) {
|
||||
|
||||
Reference in New Issue
Block a user