Fix Angular 21 runtime regressions in player and file lists

pull/1163/head
voc0der 2 months ago
parent d24a5b3cd0
commit 66a1fe5e59

@ -2,9 +2,9 @@
<div>
<div class="container">
<div class="row justify-content-center">
@for (playlist of playlists; track playlist; let i = $index) {
@for (playlist of playlists; track playlist.id; let i = $index) {
<div class="mb-2 mt-2" [ngClass]="[ postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
<app-unified-file-card [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" (goToFile)="goToPlaylist($event)" [file_obj]="playlist" [is_playlist]="true" (editPlaylist)="editPlaylistDialog($event)" (deleteFile)="deletePlaylist($event)" [baseStreamPath]="postsService.path" [jwtString]="postsService.isLoggedIn ? this.postsService.token : ''" [loading]="false"></app-unified-file-card>
<app-unified-file-card [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" (goToFile)="goToPlaylist($event)" [file_obj]="playlist" [is_playlist]="true" (editPlaylist)="editPlaylistDialog($event)" (deleteFile)="deletePlaylist($event)" [baseStreamPath]="postsService.path" [jwtString]="postsService.isLoggedIn ? this.postsService.token : ''" [apiKeyString]="!postsService.isLoggedIn ? postsService.auth_token : ''" [loading]="false"></app-unified-file-card>
</div>
}
</div>
@ -16,4 +16,4 @@
No playlists available. Create one from your downloading files by clicking the blue plus button.
</div>
}
<div class="add-playlist-button"><button (click)="openCreatePlaylistDialog()" mat-fab><mat-icon>add</mat-icon></button></div>
<div class="add-playlist-button"><button (click)="openCreatePlaylistDialog()" mat-fab><mat-icon>add</mat-icon></button></div>

@ -5,7 +5,7 @@
<div>
<div class="notifications-list-parent">
<mat-chip-listbox [value]="selectedFilters" [multiple]="true" (change)="selectedFiltersChanged($event)">
@for (filter of notificationFilters | keyvalue: originalOrder; track filter) {
@for (filter of notificationFilters | keyvalue: originalOrder; track filter.key) {
<mat-chip-option [value]="filter.key" [selected]="selectedFilters.includes(filter.key)" color="accent">{{filter.value.label}}</mat-chip-option>
}
</mat-chip-listbox>

@ -25,7 +25,7 @@
<!-- Filters -->
<div class="row justify-content-center">
<mat-chip-listbox class="filter-list" [value]="selectedFilters" [multiple]="true" (change)="selectedFiltersChanged($event)">
@for (filter of fileFilters | keyvalue: originalOrder; track filter) {
@for (filter of fileFilters | keyvalue: originalOrder; track filter.key) {
<mat-chip-option [value]="filter.key" [selected]="selectedFilters.includes(filter.key)" color="accent">{{filter.value.label}}</mat-chip-option>
}
</mat-chip-listbox>
@ -38,9 +38,9 @@
<div class="row justify-content-center">
<!-- Real cards -->
@if (normal_files_received && paged_data) {
@for (file of paged_data; track file; let i = $index) {
@for (file of paged_data; track file.uid; let i = $index) {
<div style="display: flex; align-items: center;" class="mb-2 mt-2 d-flex justify-content-center" [ngClass]="[ postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
<app-unified-file-card [ngClass]="downloading_content[file.uid] ? 'blurred' : ''" [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" (goToFile)="goToFile($event)" (goToSubscription)="goToSubscription($event)" (toggleFavorite)="toggleFavorite($event)" [file_obj]="file" [use_youtubedl_archive]="postsService.config['Downloader']['use_youtubedl_archive']" [availablePlaylists]="playlists" (addFileToPlaylist)="addFileToPlaylist($event)" [loading]="false" (deleteFile)="deleteFile($event)" [baseStreamPath]="postsService.path" [jwtString]="postsService.isLoggedIn ? this.postsService.token : ''"></app-unified-file-card>
<app-unified-file-card [ngClass]="downloading_content[file.uid] ? 'blurred' : ''" [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" (goToFile)="goToFile($event)" (goToSubscription)="goToSubscription($event)" (toggleFavorite)="toggleFavorite($event)" [file_obj]="file" [use_youtubedl_archive]="postsService.config['Downloader']['use_youtubedl_archive']" [availablePlaylists]="playlists" (addFileToPlaylist)="addFileToPlaylist($event)" [loading]="false" (deleteFile)="deleteFile($event)" [baseStreamPath]="postsService.path" [jwtString]="postsService.isLoggedIn ? this.postsService.token : ''" [apiKeyString]="!postsService.isLoggedIn ? postsService.auth_token : ''"></app-unified-file-card>
@if (downloading_content[file.uid]) {
<mat-spinner class="downloading-spinner" [diameter]="32"></mat-spinner>
}
@ -54,7 +54,7 @@
}
<!-- Fake cards -->
<ng-container>
@for (file of loading_files; track file; let i = $index) {
@for (file of loading_files; track $index; let i = $index) {
<div class="mb-2 mt-2 d-flex justify-content-center" [ngClass]="[normal_files_received ? 'hide' : '', postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
<app-unified-file-card [index]="i" [card_size]="postsService.card_size" [locale]="postsService.locale" [loading]="true" [theme]="postsService.theme"></app-unified-file-card>
</div>
@ -84,7 +84,7 @@
@if (selected_data.length) {
<mat-button-toggle-group class="media-list" cdkDropList (cdkDropListDropped)="drop($event)" style="width: 80%; left: 9%" vertical #group="matButtonToggleGroup">
<!-- The following for loop can be optimized but it requires a pipe https://stackoverflow.com/a/35703364/8088021 -->
@for (file of (reverse_order ? selected_data_objs.slice().reverse() : selected_data_objs); track file; let i = $index) {
@for (file of (reverse_order ? selected_data_objs.slice().reverse() : selected_data_objs); track file.uid; let i = $index) {
<mat-button-toggle class="media-box" cdkDrag [checked]="false"><div><div class="playlist-item-text">{{file.title}}</div> <button (click)="removeSelectedFile(i)" class="remove-item-button" mat-icon-button><mat-icon>cancel</mat-icon></button></div></mat-button-toggle>
}
</mat-button-toggle-group>
@ -98,7 +98,7 @@
<mat-tab label="Select files" i18n-label="Select files">
@if (normal_files_received) {
<mat-selection-list (selectionChange)="fileSelectionChanged($event)">
@for (file of paged_data; track file) {
@for (file of paged_data; track file.uid) {
<mat-list-option [selected]="selected_data.includes(file.uid)" [value]="file">
<div class="container">
<div class="row justify-content-center">
@ -116,7 +116,7 @@
@if (!normal_files_received && loading_files && loading_files.length > 0) {
@if (!normal_files_received) {
<mat-selection-list>
@for (file of paged_data; track file) {
@for (file of paged_data; track $index) {
<mat-list-option>
<content-loader class="list-ghosts" [backgroundColor]="postsService.theme.ghost_primary" [foregroundColor]="postsService.theme.ghost_secondary" viewBox="0 0 250 8"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="8" /></content-loader>
</mat-list-option>

@ -115,15 +115,16 @@ export class RecentVideosComponent implements OnInit {
if (this.postsService.initialized) {
this.getAllFiles();
this.getAllPlaylists();
} else {
const initSub = this.postsService.service_initialized.subscribe(init => {
if (init) {
this.getAllFiles();
this.getAllPlaylists();
initSub.unsubscribe();
}
});
}
this.postsService.service_initialized.subscribe(init => {
if (init) {
this.getAllFiles();
this.getAllPlaylists();
}
});
this.postsService.files_changed.subscribe(changed => {
if (changed) {
this.getAllFiles();

@ -46,7 +46,7 @@
}
<button [disabled]="!availablePlaylists || availablePlaylists.length === 0" [matMenuTriggerFor]="addtoplaylist" mat-menu-item><mat-icon>playlist_add</mat-icon>&nbsp;<ng-container i18n="Add to playlist menu item">Add to playlist</ng-container></button>
<mat-menu #addtoplaylist="matMenu">
@for (playlist of availablePlaylists; track playlist) {
@for (playlist of availablePlaylists; track playlist.id) {
@if ((playlist.type === 'audio') === file_obj.isAudio) {
<button [disabled]="playlist.uids?.includes(file_obj.uid)" (click)="emitAddFileToPlaylist(playlist.id)" mat-menu-item>{{playlist.name}}</button>
}

@ -50,6 +50,7 @@ export class UnifiedFileCardComponent implements OnInit {
@Input() locale = null;
@Input() baseStreamPath = null;
@Input() jwtString = null;
@Input() apiKeyString = null;
@Input() availablePlaylists = null;
@Output() goToFile = new EventEmitter<any>();
@Output() toggleFavorite = new EventEmitter<DatabaseFile>();
@ -77,7 +78,13 @@ export class UnifiedFileCardComponent implements OnInit {
}
if (this.file_obj && this.file_obj.thumbnailPath) {
this.thumbnailBlobURL = `${this.baseStreamPath}thumbnail/${encodeURIComponent(this.file_obj.thumbnailPath)}?jwt=${this.jwtString}`;
let authQuery = '';
if (this.jwtString) {
authQuery = `jwt=${this.jwtString}`;
} else if (this.apiKeyString) {
authQuery = `apiKey=${this.apiKeyString}`;
}
this.thumbnailBlobURL = `${this.baseStreamPath}thumbnail/${encodeURIComponent(this.file_obj.thumbnailPath)}${authQuery ? '?' + authQuery : ''}`;
}
if (this.file_obj) this.streamURL = this.generateStreamURL();
@ -140,6 +147,8 @@ export class UnifiedFileCardComponent implements OnInit {
let fullLocation = this.baseStreamPath + baseLocation + `?test=test&uid=${this.file_obj['uid']}`;
if (this.jwtString) {
fullLocation += `&jwt=${this.jwtString}`;
} else if (this.apiKeyString) {
fullLocation += `&apiKey=${this.apiKeyString}`;
}
fullLocation += '&t=,10';

@ -25,7 +25,7 @@
Best
</mat-option>
@if (url && cachedAvailableFormats && cachedAvailableFormats[url]?.formats && !cachedAvailableFormats[url]?.formats_failed) {
@for (option of cachedAvailableFormats[url]['formats'][audioOnly ? 'audio' : 'video']; track option) {
@for (option of cachedAvailableFormats[url]['formats'][audioOnly ? 'audio' : 'video']; track option.key) {
@if (option.key !== 'best_audio_format') {
<mat-option [matTooltip]="option.expected_filesize ? humanFileSize(option.expected_filesize) : null" [value]="option">
{{option.key}}
@ -34,7 +34,7 @@
}
}
@if (url && cachedAvailableFormats && cachedAvailableFormats[url]?.formats_failed) {
@for (option of qualityOptions[audioOnly ? 'audio' : 'video']; track option) {
@for (option of qualityOptions[audioOnly ? 'audio' : 'video']; track option.value) {
<mat-option [value]="option.value">
{{option.label}}
</mat-option>
@ -53,7 +53,7 @@
</div>
@if (results_showing) {
<div class="results-div">
@for (result of results; track result; let i = $index) {
@for (result of results; track result.videoUrl; let i = $index) {
<span>
<mat-card appearance="outlined" class="result-card mat-elevation-z7" [ngClass]="[(i === 0 && results.length > 1) ? 'first-result-card' : '', ((i === results.length-1) && results.length > 1) ? 'last-result-card' : '', (results.length === 1) ? 'only-result-card' : '']">
<div class="search-card-title">

@ -8,7 +8,7 @@
<video [ngClass]="(currentItem.type === 'audio/mp3') ? 'audio-styles' : 'video-styles'" #media class="video-player" [vgMedia]="$any(media)" [src]="currentItem.src" id="singleVideo" preload="auto" controls playsinline>
</video>
@if (postsService['config']['API']['use_sponsorblock_API'] && api && playlist?.length > 0 && playlist[currentIndex]['type'] === 'video/mp4') {
<app-skip-ad-button (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [current_video]="playlist[currentIndex]" [playback_timestamp]="api.currentTime" class="skip-ad-button"></app-skip-ad-button>
<app-skip-ad-button (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [current_video]="playlist[currentIndex]" [playback_timestamp]="api?.currentTime ?? 0" class="skip-ad-button"></app-skip-ad-button>
}
</vg-player>
</div>
@ -69,21 +69,21 @@
</div>
<div style="height: fit-content; width: 100%; margin-top: 10px;">
<mat-button-toggle-group cdkDropList [cdkDropListSortingDisabled]="true" (cdkDropListDropped)="drop($event)" style="width: 80%; left: 9%" vertical name="videoSelect" aria-label="Video Select" #group="matButtonToggleGroup">
@for (playlist_item of playlist; track playlist_item; let i = $index) {
@for (playlist_item of playlist; track (playlist_item.uid ?? playlist_item.url ?? $index); let i = $index) {
<mat-button-toggle cdkDrag [checked]="currentItem.title === playlist_item.title" (click)="onClickPlaylistItem(playlist_item, i)" class="toggle-button" [value]="playlist_item.title">{{playlist_item.label}}</mat-button-toggle>
}
</mat-button-toggle-group>
</div>
@if (db_file && api && postsService.config) {
<app-concurrent-stream (setPlaybackRate)="setPlaybackRate($event)" (togglePlayback)="togglePlayback($event)" (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [playing]="api.state === 'playing'" [uid]="uid" [playback_timestamp]="api.time.current/1000" [server_mode]="!postsService.config.Advanced.multi_user_mode || postsService.isLoggedIn"></app-concurrent-stream>
@if (db_file && api && api.time && postsService.config) {
<app-concurrent-stream (setPlaybackRate)="setPlaybackRate($event)" (togglePlayback)="togglePlayback($event)" (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [playing]="api?.state === 'playing'" [uid]="uid" [playback_timestamp]="(api?.time?.current ?? 0)/1000" [server_mode]="!postsService.config.Advanced.multi_user_mode || postsService.isLoggedIn"></app-concurrent-stream>
}
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists']">
@if (api_ready && db_file && db_file.url.includes('twitch.tv')) {
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime" [sub]="subscription"></app-twitch-chat>
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api?.currentTime ?? 0" [sub]="subscription"></app-twitch-chat>
}
</mat-drawer>
</mat-drawer-container>
</div>
</div>
</div>
}
}

@ -204,6 +204,8 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
if (this.postsService.isLoggedIn) {
fullLocation += `&jwt=${this.postsService.token}`;
} else if (this.postsService.auth_token) {
fullLocation += `&apiKey=${this.postsService.auth_token}`;
}
if (this.uuid) {

Loading…
Cancel
Save