chore: update Angular TypeScript build info cache
This commit is contained in:
parent
2866d74b32
commit
23c9ec539e
2
.angular/cache/20.2.2/app/.tsbuildinfo
vendored
2
.angular/cache/20.2.2/app/.tsbuildinfo
vendored
File diff suppressed because one or more lines are too long
@ -100,8 +100,8 @@ import {
|
||||
DOCUMENT,
|
||||
IMAGE_CONFIG
|
||||
} from "./chunk-FVA7C6JK.js";
|
||||
import "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-JRFR6BLO.js";
|
||||
import "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-MARUHEWW.js";
|
||||
import "./chunk-GOMI4DH3.js";
|
||||
export {
|
||||
|
@ -41,8 +41,8 @@ import {
|
||||
} from "./chunk-5DRVFSXL.js";
|
||||
import "./chunk-OUSM42MY.js";
|
||||
import "./chunk-FVA7C6JK.js";
|
||||
import "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-JRFR6BLO.js";
|
||||
import "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-MARUHEWW.js";
|
||||
import "./chunk-GOMI4DH3.js";
|
||||
export {
|
||||
|
@ -498,8 +498,8 @@ import {
|
||||
ɵɵviewQuery,
|
||||
ɵɵviewQuerySignal
|
||||
} from "./chunk-FVA7C6JK.js";
|
||||
import "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-JRFR6BLO.js";
|
||||
import "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-MARUHEWW.js";
|
||||
import "./chunk-GOMI4DH3.js";
|
||||
export {
|
||||
|
@ -46,10 +46,10 @@ import {
|
||||
ɵɵgetInheritedFactory,
|
||||
ɵɵlistener
|
||||
} from "./chunk-FVA7C6JK.js";
|
||||
import "./chunk-JRFR6BLO.js";
|
||||
import {
|
||||
forkJoin
|
||||
} from "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-JRFR6BLO.js";
|
||||
import {
|
||||
Subject,
|
||||
from,
|
||||
|
@ -41,8 +41,8 @@ import {
|
||||
} from "./chunk-H4LQPAO2.js";
|
||||
import "./chunk-OUSM42MY.js";
|
||||
import "./chunk-FVA7C6JK.js";
|
||||
import "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-JRFR6BLO.js";
|
||||
import "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-MARUHEWW.js";
|
||||
import "./chunk-GOMI4DH3.js";
|
||||
export {
|
||||
|
@ -83,11 +83,11 @@ import {
|
||||
ɵɵqueryRefresh,
|
||||
ɵɵsanitizeUrlOrResourceUrl
|
||||
} from "./chunk-FVA7C6JK.js";
|
||||
import "./chunk-JRFR6BLO.js";
|
||||
import {
|
||||
defer,
|
||||
isObservable
|
||||
} from "./chunk-HWYXSU2G.js";
|
||||
import "./chunk-JRFR6BLO.js";
|
||||
import {
|
||||
BehaviorSubject,
|
||||
ConnectableObservable,
|
||||
|
@ -1,61 +1,61 @@
|
||||
{
|
||||
"hash": "23edc511",
|
||||
"configHash": "2277c002",
|
||||
"hash": "4a15fadf",
|
||||
"configHash": "d859ec53",
|
||||
"lockfileHash": "c86d7ad1",
|
||||
"browserHash": "0d41a6ee",
|
||||
"browserHash": "3b79ea76",
|
||||
"optimized": {
|
||||
"@angular/common": {
|
||||
"src": "../../../../../../node_modules/@angular/common/fesm2022/common.mjs",
|
||||
"file": "@angular_common.js",
|
||||
"fileHash": "ed7bea66",
|
||||
"fileHash": "3cdf8c58",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@angular/common/http": {
|
||||
"src": "../../../../../../node_modules/@angular/common/fesm2022/http.mjs",
|
||||
"file": "@angular_common_http.js",
|
||||
"fileHash": "d8740647",
|
||||
"fileHash": "c729a905",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@angular/core": {
|
||||
"src": "../../../../../../node_modules/@angular/core/fesm2022/core.mjs",
|
||||
"file": "@angular_core.js",
|
||||
"fileHash": "fc2503ca",
|
||||
"fileHash": "262b482a",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@angular/forms": {
|
||||
"src": "../../../../../../node_modules/@angular/forms/fesm2022/forms.mjs",
|
||||
"file": "@angular_forms.js",
|
||||
"fileHash": "36d0134e",
|
||||
"fileHash": "08308e50",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@angular/platform-browser": {
|
||||
"src": "../../../../../../node_modules/@angular/platform-browser/fesm2022/platform-browser.mjs",
|
||||
"file": "@angular_platform-browser.js",
|
||||
"fileHash": "c0c2a1fa",
|
||||
"fileHash": "f61025b6",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@angular/router": {
|
||||
"src": "../../../../../../node_modules/@angular/router/fesm2022/router.mjs",
|
||||
"file": "@angular_router.js",
|
||||
"fileHash": "381708ba",
|
||||
"fileHash": "f2b90ce6",
|
||||
"needsInterop": false
|
||||
},
|
||||
"@google/genai": {
|
||||
"src": "../../../../../../node_modules/@google/genai/dist/web/index.mjs",
|
||||
"file": "@google_genai.js",
|
||||
"fileHash": "a56c743a",
|
||||
"fileHash": "3476d74f",
|
||||
"needsInterop": false
|
||||
},
|
||||
"rxjs": {
|
||||
"src": "../../../../../../node_modules/rxjs/dist/esm5/index.js",
|
||||
"file": "rxjs.js",
|
||||
"fileHash": "c69b23b3",
|
||||
"fileHash": "df88f612",
|
||||
"needsInterop": false
|
||||
},
|
||||
"rxjs/operators": {
|
||||
"src": "../../../../../../node_modules/rxjs/dist/esm5/operators/index.js",
|
||||
"file": "rxjs_operators.js",
|
||||
"fileHash": "56086c3c",
|
||||
"fileHash": "8d5942d8",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
@ -75,12 +75,12 @@
|
||||
"chunk-FVA7C6JK": {
|
||||
"file": "chunk-FVA7C6JK.js"
|
||||
},
|
||||
"chunk-HWYXSU2G": {
|
||||
"file": "chunk-HWYXSU2G.js"
|
||||
},
|
||||
"chunk-JRFR6BLO": {
|
||||
"file": "chunk-JRFR6BLO.js"
|
||||
},
|
||||
"chunk-HWYXSU2G": {
|
||||
"file": "chunk-HWYXSU2G.js"
|
||||
},
|
||||
"chunk-MARUHEWW": {
|
||||
"file": "chunk-MARUHEWW.js"
|
||||
},
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"hash": "bd8fc5b3",
|
||||
"configHash": "d5bc65c8",
|
||||
"hash": "65ebd7bc",
|
||||
"configHash": "3d00a7fd",
|
||||
"lockfileHash": "c86d7ad1",
|
||||
"browserHash": "5244fe32",
|
||||
"browserHash": "acdb5c3c",
|
||||
"optimized": {},
|
||||
"chunks": {}
|
||||
}
|
BIN
db/newtube.db
BIN
db/newtube.db
Binary file not shown.
@ -561,6 +561,37 @@ r.get('/peertube/:instance/*', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// -------------------- Generic video details (GET) --------------------
|
||||
// Returns metadata such as title, description, uploader, thumbnail, duration and views for a provider/videoId
|
||||
// Supports query params similar to download endpoints: instance (PeerTube), slug (Odysee), sourceUrl (direct)
|
||||
r.get('/details/:provider/:videoId', async (req, res) => {
|
||||
try {
|
||||
const { provider, videoId } = req.params;
|
||||
const instance = req.query.instance || undefined;
|
||||
const slug = req.query.slug || undefined;
|
||||
const sourceUrl = req.query.sourceUrl || undefined;
|
||||
const url = providerUrlFrom(provider, videoId, { instance, slug, sourceUrl });
|
||||
const raw = await youtubedl(url, { dumpSingleJson: true, noWarnings: true, noCheckCertificates: true, skipDownload: true });
|
||||
const meta = (typeof raw === 'string') ? JSON.parse(raw || '{}') : (raw || {});
|
||||
const out = {
|
||||
videoId,
|
||||
title: meta.title || '',
|
||||
thumbnail: meta.thumbnail || (Array.isArray(meta.thumbnails) && meta.thumbnails.length ? meta.thumbnails[0].url : ''),
|
||||
uploaderName: meta.uploader || meta.channel || '',
|
||||
uploaderAvatar: '',
|
||||
views: typeof meta.view_count === 'number' ? meta.view_count : (typeof meta.viewCount === 'number' ? meta.viewCount : 0),
|
||||
duration: typeof meta.duration === 'number' ? meta.duration : 0,
|
||||
uploadedDate: meta.upload_date ? new Date(meta.upload_date.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3')).toISOString() : (meta.release_timestamp ? new Date(meta.release_timestamp * 1000).toISOString() : ''),
|
||||
description: meta.description || meta.summary || '',
|
||||
url,
|
||||
type: 'video',
|
||||
};
|
||||
return res.json(out);
|
||||
} catch (e) {
|
||||
return res.status(500).json({ error: 'details_failed', details: String(e?.message || e) });
|
||||
}
|
||||
});
|
||||
|
||||
// Download routes middleware (auth supports both Authorization header and cookies)
|
||||
r.use('/download', authMiddlewareCookieAware, downloadLimiter);
|
||||
|
||||
|
@ -21,39 +21,41 @@
|
||||
<span [class.hidden]="collapsed">{{ 'nav.shorts' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/library/subscriptions" routerLinkActive="bg-slate-800" class="flex items-center px-3 py-2 rounded hover:bg-slate-800 transition" [ngClass]="{ 'gap-0 justify-center': collapsed, 'gap-3': !collapsed }" [attr.title]="collapsed ? ('nav.subscriptions' | t) : null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zm0 2v12h16V6H4zm3 3h10v2H7V9zm0 4h7v2H7v-2z"/></svg>
|
||||
<span [class.hidden]="collapsed">{{ 'nav.subscriptions' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Vous -->
|
||||
<div>
|
||||
<div class="px-3 py-2 text-xs uppercase tracking-wide text-slate-400" [class.hidden]="collapsed">{{ 'nav.you' | t }}</div>
|
||||
<ul class="space-y-1">
|
||||
<li>
|
||||
<a routerLink="/account/history" routerLinkActive="bg-slate-800" class="flex items-center px-3 py-2 rounded hover:bg-slate-800 transition" [ngClass]="{ 'gap-0 justify-center': collapsed, 'gap-3': !collapsed }" [attr.title]="collapsed ? ('nav.history' | t) : null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M12 8a1 1 0 0 1 1 1v3.38l2.32 1.34a1 1 0 1 1-1 1.74l-2.82-1.63A1 1 0 0 1 11 13V9a1 1 0 0 1 1-1zm0-6a10 10 0 1 0 10 10 10.011 10.011 0 0 0-10-10z"/></svg>
|
||||
<span [class.hidden]="collapsed">{{ 'nav.history' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/library/playlists" routerLinkActive="bg-slate-800" class="flex items-center px-3 py-2 rounded hover:bg-slate-800 transition" [ngClass]="{ 'gap-0 justify-center': collapsed, 'gap-3': !collapsed }" [attr.title]="collapsed ? ('nav.playlists' | t) : null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6h12v2H4V6zm0 4h12v2H4v-2zm0 4h8v2H4v-2zm14-6h2v8h-2v-8z"/></svg>
|
||||
<span [class.hidden]="collapsed">{{ 'nav.playlists' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/library/liked" routerLinkActive="bg-slate-800" class="flex items-center px-3 py-2 rounded hover:bg-slate-800 transition" [ngClass]="{ 'gap-0 justify-center': collapsed, 'gap-3': !collapsed }" [attr.title]="collapsed ? ('nav.liked' | t) : null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M12 21s-6.716-4.248-9.193-6.725A6 6 0 0 1 12 5.414 6 6 0 0 1 21.193 14.275C18.716 16.752 12 21 12 21z"/></svg>
|
||||
<span [class.hidden]="collapsed">{{ 'nav.liked' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@if (isLoggedIn()) {
|
||||
<div>
|
||||
<div class="px-3 py-2 text-xs uppercase tracking-wide text-slate-400" [class.hidden]="collapsed">{{ 'nav.you' | t }}</div>
|
||||
<ul class="space-y-1">
|
||||
<li>
|
||||
<a routerLink="/library/subscriptions" routerLinkActive="bg-slate-800" class="flex items-center px-3 py-2 rounded hover:bg-slate-800 transition" [ngClass]="{ 'gap-0 justify-center': collapsed, 'gap-3': !collapsed }" [attr.title]="collapsed ? ('nav.subscriptions' | t) : null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zm0 2v12h16V6H4zm3 3h10v2H7V9zm0 4h7v2H7v-2z"/></svg>
|
||||
<span [class.hidden]="collapsed">{{ 'nav.subscriptions' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/account/history" routerLinkActive="bg-slate-800" class="flex items-center px-3 py-2 rounded hover:bg-slate-800 transition" [ngClass]="{ 'gap-0 justify-center': collapsed, 'gap-3': !collapsed }" [attr.title]="collapsed ? ('nav.history' | t) : null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M12 8a1 1 0 0 1 1 1v3.38l2.32 1.34a1 1 0 1 1-1 1.74l-2.82-1.63A1 1 0 0 1 11 13V9a1 1 0 0 1 1-1zm0-6a10 10 0 1 0 10 10 10.011 10.011 0 0 0-10-10z"/></svg>
|
||||
<span [class.hidden]="collapsed">{{ 'nav.history' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/library/playlists" routerLinkActive="bg-slate-800" class="flex items-center px-3 py-2 rounded hover:bg-slate-800 transition" [ngClass]="{ 'gap-0 justify-center': collapsed, 'gap-3': !collapsed }" [attr.title]="collapsed ? ('nav.playlists' | t) : null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6h12v2H4V6zm0 4h12v2H4v-2zm0 4h8v2H4v-2zm14-6h2v8h-2v-8z"/></svg>
|
||||
<span [class.hidden]="collapsed">{{ 'nav.playlists' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="/library/liked" routerLinkActive="bg-slate-800" class="flex items-center px-3 py-2 rounded hover:bg-slate-800 transition" [ngClass]="{ 'gap-0 justify-center': collapsed, 'gap-3': !collapsed }" [attr.title]="collapsed ? ('nav.liked' | t) : null">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor"><path d="M12 21s-6.716-4.248-9.193-6.725A6 6 0 0 1 12 5.414 6 6 0 0 1 21.193 14.275C18.716 16.752 12 21 12 21z"/></svg>
|
||||
<span [class.hidden]="collapsed">{{ 'nav.liked' | t }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Fournisseurs -->
|
||||
<div>
|
||||
|
@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { RouterLink, RouterLinkActive } from '@angular/router';
|
||||
import { InstanceService } from '../../services/instance.service';
|
||||
import { ThemesService } from '../../services/themes.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { TranslatePipe } from '../../pipes/translate.pipe';
|
||||
|
||||
@Component({
|
||||
@ -14,7 +15,11 @@ import { TranslatePipe } from '../../pipes/translate.pipe';
|
||||
})
|
||||
export class SidebarComponent {
|
||||
private instances = inject(InstanceService);
|
||||
private auth = inject(AuthService);
|
||||
themes = inject(ThemesService);
|
||||
|
||||
// Check if user is logged in
|
||||
isLoggedIn = computed(() => !!this.auth.currentUser());
|
||||
|
||||
provider = computed(() => this.instances.selectedProvider());
|
||||
providerLabel = computed(() => this.instances.selectedProviderLabel());
|
||||
|
@ -100,10 +100,14 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-4 bg-slate-800/70 p-4 rounded-lg">
|
||||
<p [class.line-clamp-3]="!showFullDescription()">{{ v.description }}</p>
|
||||
<button (click)="toggleDescription()" class="text-red-400 hover:text-red-300 font-semibold mt-2">
|
||||
{{ showFullDescription() ? 'Show less' : 'Show more' }}
|
||||
</button>
|
||||
<p class="whitespace-pre-wrap text-slate-300" [class.line-clamp-3]="!showFullDescription()">
|
||||
{{ hasDescription() ? descriptionText() : 'Aucune description disponible.' }}
|
||||
</p>
|
||||
@if (showMoreAvailable()) {
|
||||
<button (click)="toggleDescription()" class="text-red-400 hover:text-red-300 font-semibold mt-2">
|
||||
{{ showFullDescription() ? 'Show less' : 'Show more' }}
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Download Panel (shown only when logged in) -->
|
||||
|
@ -33,9 +33,30 @@ export class WatchComponent implements OnDestroy {
|
||||
private http = inject(HttpClient);
|
||||
private routeSubscription: Subscription;
|
||||
|
||||
// Choose correct API base: use dev proxy when UI runs on a different port than the backend
|
||||
private apiBase(): string {
|
||||
try {
|
||||
const port = window?.location?.port || '';
|
||||
// If not running on backend port, route through Angular proxy
|
||||
return port && port !== '4000' ? '/proxy/api' : '/api';
|
||||
} catch {
|
||||
return '/api';
|
||||
}
|
||||
}
|
||||
|
||||
video = signal<VideoDetail | null>(null);
|
||||
loading = signal(true);
|
||||
showFullDescription = signal(false);
|
||||
// Prefer full description if available; otherwise fallback to shortDescription
|
||||
descriptionText = computed(() => {
|
||||
const v = this.video();
|
||||
const full = (v?.description || '').trim();
|
||||
if (full) return full;
|
||||
const short = (v?.shortDescription || '').trim();
|
||||
return short || '';
|
||||
});
|
||||
hasDescription = computed(() => this.descriptionText().length > 0);
|
||||
showMoreAvailable = computed(() => this.descriptionText().length > 240);
|
||||
|
||||
summary = signal<string | null>(null);
|
||||
isSummarizing = signal(false);
|
||||
@ -268,9 +289,30 @@ export class WatchComponent implements OnDestroy {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// For other providers rely on embed/placeholder
|
||||
this.loading.set(false);
|
||||
this.loadRelatedSuggestions();
|
||||
// For other providers, enrich details via backend using yt-dlp metadata when possible
|
||||
const opts = this.buildProviderOpts();
|
||||
this.http.get<any>(`${this.apiBase()}/details/${encodeURIComponent(provider)}/${encodeURIComponent(id)}`, { params: opts as any }).subscribe({
|
||||
next: (data) => {
|
||||
this.video.update(v => v ? {
|
||||
...v,
|
||||
title: data?.title || v.title,
|
||||
thumbnail: data?.thumbnail || v.thumbnail,
|
||||
uploaderName: data?.uploaderName || v.uploaderName,
|
||||
uploadedDate: data?.uploadedDate || v.uploadedDate,
|
||||
views: typeof data?.views === 'number' ? data.views : v.views,
|
||||
duration: typeof data?.duration === 'number' ? data.duration : v.duration,
|
||||
description: (data?.description || v.description || v.shortDescription || ''),
|
||||
url: data?.url || v.url,
|
||||
} : v);
|
||||
this.loading.set(false);
|
||||
this.loadRelatedSuggestions();
|
||||
},
|
||||
error: () => {
|
||||
// Fallback to existing placeholder
|
||||
this.loading.set(false);
|
||||
this.loadRelatedSuggestions();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Record watch start
|
||||
|
Loading…
x
Reference in New Issue
Block a user