chore: update Angular cache and TypeScript build info files

This commit is contained in:
Bruno Charest 2025-09-19 09:10:29 -04:00
parent 41255a8126
commit 709b2e55c2
4 changed files with 62 additions and 11 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -60,7 +60,27 @@ async function scrapeRumbleVideo(videoId) {
const duration = durationText ? parseInt(durationText) : 0; const duration = durationText ? parseInt(durationText) : 0;
const uploadedDate = $('meta[property="article:published_time"]').attr('content') || ''; const uploadedDate = $('meta[property="article:published_time"]').attr('content') || '';
const description = $('meta[property="og:description"]').attr('content') || ''; const description = $('meta[property="og:description"]').attr('content') || '';
return { videoId, title: title || 'Untitled Video', thumbnail, uploaderName: uploaderName || 'Unknown Uploader', views, duration, uploadedDate, description, url: `https://rumble.com/${videoId}`, type: 'video' }; // Try to extract the official embed URL
let embedUrl = $('meta[property="og:video"], meta[name="twitter:player"]').attr('content') || '';
if (!embedUrl) {
const iframeSrc = $('iframe[src*="/embed/"]').attr('src') || '';
embedUrl = iframeSrc || '';
}
// Normalize protocol-less URLs
if (embedUrl && embedUrl.startsWith('//')) embedUrl = 'https:' + embedUrl;
// Detect canonical URL to extract stable ID
const canonicalUrl = $('link[rel="canonical"]').attr('href') || $('meta[property="og:url"]').attr('content') || '';
// Normalize/derive the stable Rumble ID (e.g., v464efu)
let stableId = videoId;
const mEmbed = /\/embed\/(v[0-9A-Za-z]+)/.exec(embedUrl || '');
const mCanon = /\/(v[0-9A-Za-z]+)(?:[\-./]|$)/.exec(canonicalUrl || '');
if (mEmbed && mEmbed[1]) stableId = mEmbed[1];
else if (mCanon && mCanon[1]) stableId = mCanon[1];
// If embedUrl is a page URL, convert to embed path as a fallback
if (!/\/embed\//.test(embedUrl)) {
embedUrl = `https://rumble.com/embed/${stableId}/?autoplay=2&muted=1`;
}
return { videoId: stableId, title: title || 'Untitled Video', thumbnail, uploaderName: uploaderName || 'Unknown Uploader', views, duration, uploadedDate, description, url: `https://rumble.com/${stableId}`, embedUrl, type: 'video' };
} catch (e) { } catch (e) {
console.error('scrapeRumbleVideo error:', e.message); console.error('scrapeRumbleVideo error:', e.message);
return { videoId, error: 'Scraping failed' }; return { videoId, error: 'Scraping failed' };

View File

@ -208,6 +208,9 @@ export class WatchComponent implements OnDestroy, AfterViewInit {
private providerSel = signal<string>(''); private providerSel = signal<string>('');
provider = computed(() => this.providerSel() || this.instances.selectedProvider()); provider = computed(() => this.providerSel() || this.instances.selectedProvider());
private twitchChannel = signal<string | null>(null); private twitchChannel = signal<string | null>(null);
// Backend-provided embed URL for providers that need it (e.g., Rumble)
private rumbleEmbed = signal<string | null>(null);
embedUrl = computed<SafeResourceUrl | null>(() => { embedUrl = computed<SafeResourceUrl | null>(() => {
const id = this.videoId(); const id = this.videoId();
const p = this.provider(); const p = this.provider();
@ -261,8 +264,11 @@ export class WatchComponent implements OnDestroy, AfterViewInit {
return this.sanitizer.bypassSecurityTrustResourceUrl(u); return this.sanitizer.bypassSecurityTrustResourceUrl(u);
} }
if (p === 'rumble') { if (p === 'rumble') {
// Best-effort: Rumble embed path may vary depending on the id format // Prefer backend-provided embed URL (includes required pub/query params)
const u = `https://rumble.com/embed/${encodeURIComponent(id)}/?autoplay=2&muted=1`; const fromBackend = this.rumbleEmbed();
const u = fromBackend && /^https?:\/\//i.test(fromBackend)
? fromBackend
: `https://rumble.com/embed/${encodeURIComponent(id)}/?autoplay=2&muted=1`;
return this.sanitizer.bypassSecurityTrustResourceUrl(u); return this.sanitizer.bypassSecurityTrustResourceUrl(u);
} }
} catch {} } catch {}
@ -348,6 +354,8 @@ export class WatchComponent implements OnDestroy, AfterViewInit {
loadVideo(id: string) { loadVideo(id: string) {
console.log('[Watch] Loading video', { id }); console.log('[Watch] Loading video', { id });
this.loading.set(true); this.loading.set(true);
// Clear any previous Rumble embed URL to avoid stale iframes during fast navigation
this.rumbleEmbed.set(null);
// Prepare placeholder from router state if available for richer UI // Prepare placeholder from router state if available for richer UI
const stateVideo = (history.state && (history.state as any).video) as Video | undefined; const stateVideo = (history.state && (history.state as any).video) as Video | undefined;
this.video.set({ this.video.set({
@ -385,13 +393,28 @@ export class WatchComponent implements OnDestroy, AfterViewInit {
const provider = this.provider(); const provider = this.provider();
if (provider === 'rumble') { if (provider === 'rumble') {
// Validate and enrich Rumble video via backend scraping (may also normalize id) // Validate and enrich Rumble video via backend scraping (may also normalize id)
this.http.get<any>(`/api/rumble/video/${encodeURIComponent(id)}`).subscribe({ const handle = (data: any) => {
next: (data) => {
const newId = (data && (data.videoId || data.id)) ? String(data.videoId || data.id) : id; const newId = (data && (data.videoId || data.id)) ? String(data.videoId || data.id) : id;
// If route changed while request was in-flight, ignore this response
const current = this.videoId();
if (current && current !== id && current !== newId) {
console.warn('[Watch] Ignoring out-of-date Rumble response', { requested: id, newId, current });
return;
}
// Update id if backend provided a more accurate one // Update id if backend provided a more accurate one
if (newId && newId !== id) { if (newId && newId !== current) {
this.videoId.set(newId); this.videoId.set(newId);
} }
// Store backend-provided embed url if present, but only if it matches the expected id
try {
const eurl = (data && data.embedUrl) ? String(data.embedUrl) : '';
const match = /\/embed\/([A-Za-z0-9]+)/.exec(eurl || '');
if (eurl && match && match[1] && (match[1] === newId.replace(/^v/, 'v'))) {
this.rumbleEmbed.set(eurl);
} else {
this.rumbleEmbed.set(null);
}
} catch { this.rumbleEmbed.set(null); }
// Merge enriched fields // Merge enriched fields
this.video.update(v => v ? { this.video.update(v => v ? {
...v, ...v,
@ -434,11 +457,19 @@ export class WatchComponent implements OnDestroy, AfterViewInit {
error: () => {} error: () => {}
}); });
} catch {} } catch {}
}, };
this.http.get<any>(`/api/rumble/video/${encodeURIComponent(id)}`).subscribe({
next: handle,
error: () => { error: () => {
// Even if details fail, try to display embed with the original id // Fallback to dev proxy alias if /api is not available in dev
this.loading.set(false); this.http.get<any>(`/proxy/api/rumble/video/${encodeURIComponent(id)}`).subscribe({
this.loadRelatedSuggestions(); next: handle,
error: () => {
// Even if details fail, try to display embed with the original id
this.loading.set(false);
this.loadRelatedSuggestions();
}
});
} }
}); });
} else { } else {