diff --git a/libs/playlist/import/feature/src/lib/add-playlist-dialog/add-playlist-dialog.component.html b/libs/playlist/import/feature/src/lib/add-playlist-dialog/add-playlist-dialog.component.html
index 4df139864..a6e08f317 100644
--- a/libs/playlist/import/feature/src/lib/add-playlist-dialog/add-playlist-dialog.component.html
+++ b/libs/playlist/import/feature/src/lib/add-playlist-dialog/add-playlist-dialog.component.html
@@ -45,7 +45,7 @@
@case ('file') {
}
diff --git a/libs/playlist/import/feature/src/lib/add-playlist-dialog/add-playlist-dialog.component.ts b/libs/playlist/import/feature/src/lib/add-playlist-dialog/add-playlist-dialog.component.ts
index 7c09dc0f1..318b9736a 100644
--- a/libs/playlist/import/feature/src/lib/add-playlist-dialog/add-playlist-dialog.component.ts
+++ b/libs/playlist/import/feature/src/lib/add-playlist-dialog/add-playlist-dialog.component.ts
@@ -111,21 +111,11 @@ export class AddPlaylistDialogComponent {
}
/**
- * Parse and store uploaded playlist
- * @param payload
+ * Closes the dialog after a successful file import. The actual parse and
+ * dispatch happens inside `PlaylistFileImportService` (called from the
+ * `FileUploadComponent`).
*/
- handlePlaylist(payload: { uploadEvent: Event; file: File }): void {
- const playlist = (payload.uploadEvent.target as FileReader)
- .result as string;
-
- this.store.dispatch(
- PlaylistActions.parsePlaylist({
- uploadType: 'FILE',
- playlist,
- title: this.normalizeImportedFileTitle(payload.file.name),
- path: (payload.file as File & { path?: string }).path,
- })
- );
+ onFileImported(): void {
this.closeDialog();
}
@@ -181,16 +171,4 @@ export class AddPlaylistDialogComponent {
const normalizedValue = value?.trim();
return normalizedValue ? normalizedValue : undefined;
}
-
- private normalizeImportedFileTitle(filename: string): string {
- const normalizedFilename = filename.trim();
- if (!normalizedFilename) {
- return filename;
- }
-
- return (
- normalizedFilename.replace(/\.(m3u8?|pls|txt)$/i, '') ||
- normalizedFilename
- );
- }
}
diff --git a/libs/playlist/import/feature/src/lib/file-upload/file-upload.component.ts b/libs/playlist/import/feature/src/lib/file-upload/file-upload.component.ts
index 8607ce291..bcb887d81 100644
--- a/libs/playlist/import/feature/src/lib/file-upload/file-upload.component.ts
+++ b/libs/playlist/import/feature/src/lib/file-upload/file-upload.component.ts
@@ -1,9 +1,9 @@
-import { Component, EventEmitter, Output, signal } from '@angular/core';
+import { Component, EventEmitter, Output, inject, signal } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { TranslatePipe } from '@ngx-translate/core';
+import { PlaylistFileImportService } from '@iptvnator/playlist/shared/util';
import { DragDropFileUploadDirective } from './drag-drop-file-upload.directive';
-const M3U_EXTENSIONS = ['.m3u', '.m3u8'];
const MB = 1024 * 1024;
const KB = 1024;
@@ -14,15 +14,15 @@ const KB = 1024;
styleUrls: ['./file-upload.component.scss'],
})
export class FileUploadComponent {
- @Output() fileSelected = new EventEmitter<{
- uploadEvent: Event;
- file: File;
- }>();
+ private readonly importService = inject(PlaylistFileImportService);
+
+ @Output() imported = new EventEmitter<{ title: string }>();
@Output() fileRejected = new EventEmitter();
@Output() closeDialog = new EventEmitter();
readonly selectedFile = signal(null);
readonly isDragging = signal(false);
+ readonly isImporting = signal(false);
openPicker(input: HTMLInputElement): void {
input.value = '';
@@ -60,14 +60,21 @@ export class FileUploadComponent {
this.selectedFile.set(null);
}
- confirm(): void {
+ async confirm(): Promise {
const file = this.selectedFile();
- if (!file) return;
+ if (!file || this.isImporting()) return;
- const reader = new FileReader();
- reader.onload = (uploadEvent) =>
- this.fileSelected.emit({ uploadEvent, file });
- reader.readAsText(file);
+ this.isImporting.set(true);
+ const result = await this.importService.importFile(file);
+ this.isImporting.set(false);
+
+ if (result.ok === true) {
+ this.imported.emit({ title: result.title });
+ return;
+ }
+
+ this.selectedFile.set(null);
+ this.fileRejected.emit(file.name);
}
formatSize(bytes: number): string {
@@ -78,15 +85,10 @@ export class FileUploadComponent {
private setFile(file: File | undefined): void {
if (!file) return;
- if (!this.hasAllowedExtension(file.name)) {
+ if (!this.importService.isSupportedFile(file)) {
this.fileRejected.emit(file.name);
return;
}
this.selectedFile.set(file);
}
-
- private hasAllowedExtension(name: string): boolean {
- const lower = name.toLowerCase();
- return M3U_EXTENSIONS.some((ext) => lower.endsWith(ext));
- }
}