From a8167c4b2ae625f9714c8bbe5cd6ffa3fcfa0140 Mon Sep 17 00:00:00 2001 From: 4gray Date: Sat, 27 Mar 2021 14:13:54 +0100 Subject: [PATCH] feat: set custom user agent for a playlist This commit closes the feature request from #26 --- api.ts | 63 +++++++++++-- ipc-commands.ts | 4 + src/app/home/home.component.ts | 5 +- src/app/home/playlist.interface.ts | 1 + .../playlist-info.component.html | 94 ++++++++++++------- .../playlist-info.component.spec.ts | 10 +- .../playlist-info/playlist-info.component.ts | 45 ++++++++- .../recent-playlists.component.html | 2 +- 8 files changed, 176 insertions(+), 48 deletions(-) diff --git a/api.ts b/api.ts index cc126203..0e5821da 100644 --- a/api.ts +++ b/api.ts @@ -11,6 +11,7 @@ import { EPG_FETCH_DONE, EPG_GET_PROGRAM, EPG_GET_PROGRAM_DONE, + PLAYLIST_SAVE_DETAILS, } from './ipc-commands'; const fs = require('fs'); @@ -24,6 +25,9 @@ export class Api { /** Instance of the main application window */ mainWindow: BrowserWindow; + /** Default user agent stored as a fallback value */ + defaultUserAgent: string; + /** Instance of the epg browser window */ workerWindow: BrowserWindow; @@ -61,18 +65,11 @@ export class Api { event.sender.send('parse-response', { payload: playlistObject }); }); - ipcMain.on('playlists-all', async (event) => { - const playlists = await db.find( - { type: { $exists: false } }, - { count: 1, title: 1, _id: 1, url: 1, importDate: 1 } - ); - event.sender.send('playlist-all-result', { - payload: playlists, - }); - }); + ipcMain.on('playlists-all', (event) => this.sendAllPlaylists(event)); ipcMain.on('playlist-by-id', async (event, args) => { const playlist = await db.findOne({ _id: args.id }); + this.setUserAgent(playlist.userAgent); event.sender.send('parse-response', { payload: playlist, }); @@ -137,6 +134,51 @@ export class Api { .on(EPG_ERROR, (event, arg) => this.mainWindow.webContents.send(EPG_ERROR, arg) ); + + ipcMain.on(PLAYLIST_SAVE_DETAILS, async (event, args) => { + const updated = await db.update( + { _id: args._id }, + { $set: { title: args.title, userAgent: args.userAgent } } + ); + if (!updated.numAffected || updated.numAffected === 0) { + console.error('Error: Playlist details were not updated'); + } + this.sendAllPlaylists(event); + }); + } + + /** + * Sends list with all playlists which are stored in the database + * @param event main event + */ + async sendAllPlaylists(event: Electron.IpcMainEvent): Promise { + const playlists = await db.find( + { type: { $exists: false } }, + { + count: 1, + title: 1, + _id: 1, + url: 1, + importDate: 1, + userAgent: 1, + filename: 1, + } + ); + event.sender.send('playlist-all-result', { + payload: playlists, + }); + } + + /** + * Sets the user agent header for all http requests + * @param userAgent user agent to use + */ + setUserAgent(userAgent: string): void { + if (userAgent === undefined || userAgent === null || userAgent === '') { + userAgent = this.defaultUserAgent; + } + this.mainWindow.webContents.setUserAgent(userAgent); + console.log(`Success: Set "${userAgent}" as user agent header`); } /** @@ -145,6 +187,9 @@ export class Api { */ setEpgWorkerWindow(workerWindow: BrowserWindow): void { this.workerWindow = workerWindow; + + // store default user agent as fallback + this.defaultUserAgent = this.workerWindow.webContents.getUserAgent(); } /** diff --git a/ipc-commands.ts b/ipc-commands.ts index 69d15000..4a235272 100644 --- a/ipc-commands.ts +++ b/ipc-commands.ts @@ -1,5 +1,9 @@ +// EPG related commands export const EPG_FETCH = 'EPG:FETCH'; export const EPG_FETCH_DONE = 'EPG:FETCH_DONE'; export const EPG_ERROR = 'EPG:ERROR'; export const EPG_GET_PROGRAM = 'EPG:GET_PROGRAM'; export const EPG_GET_PROGRAM_DONE = 'EPG:GET_PROGRAM_DONE'; + +// Playlist related commands +export const PLAYLIST_SAVE_DETAILS = 'PLAYLIST:SAVE_DETAILS'; diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 54843227..1ac109da 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -8,7 +8,10 @@ import { Playlist } from './playlist.interface'; import { ElectronService } from '../services/electron.service'; /** Type to describe meta data of a playlist */ -export type PlaylistMeta = Pick; +export type PlaylistMeta = Pick< + Playlist, + 'count' | 'title' | 'filename' | '_id' | 'url' | 'importDate' | 'userAgent' +>; @Component({ selector: 'app-home', diff --git a/src/app/home/playlist.interface.ts b/src/app/home/playlist.interface.ts index d7bfca45..2c685de5 100644 --- a/src/app/home/playlist.interface.ts +++ b/src/app/home/playlist.interface.ts @@ -14,4 +14,5 @@ export interface Playlist { favorites: string[]; count: number; url?: string; + userAgent?: string; } diff --git a/src/app/home/recent-playlists/playlist-info/playlist-info.component.html b/src/app/home/recent-playlists/playlist-info/playlist-info.component.html index 67cb6686..d56c52b7 100644 --- a/src/app/home/recent-playlists/playlist-info/playlist-info.component.html +++ b/src/app/home/recent-playlists/playlist-info/playlist-info.component.html @@ -1,34 +1,60 @@ -

- {{ 'HOME.PLAYLISTS.INFO_DIALOG.PLAYLIST_DETAILS' | translate }} -

- - - {{ - 'HOME.PLAYLISTS.INFO_DIALOG.TITLE' | translate - }} - - - - {{ - 'HOME.PLAYLISTS.INFO_DIALOG.FROM_URL' | translate - }} - - - - {{ - 'HOME.PLAYLISTS.INFO_DIALOG.IMPORT_DATE' | translate - }} - - - - {{ - 'HOME.PLAYLISTS.INFO_DIALOG.CHANNELS' | translate - }} - - - - - - +
+

+ {{ 'HOME.PLAYLISTS.INFO_DIALOG.PLAYLIST_DETAILS' | translate }} +

+ + + {{ + 'HOME.PLAYLISTS.INFO_DIALOG.TITLE' | translate + }} + + + + {{ + 'HOME.PLAYLISTS.INFO_DIALOG.FROM_URL' | translate + }} + + + + {{ + 'HOME.PLAYLISTS.INFO_DIALOG.ORIGINAL_FILENAME' | translate + }} + + + + {{ + 'HOME.PLAYLISTS.INFO_DIALOG.IMPORT_DATE' | translate + }} + + + + {{ + 'HOME.PLAYLISTS.INFO_DIALOG.CHANNELS' | translate + }} + + + + {{ + 'HOME.PLAYLISTS.INFO_DIALOG.USER_AGENT' | translate + }} + + + + + + + +
diff --git a/src/app/home/recent-playlists/playlist-info/playlist-info.component.spec.ts b/src/app/home/recent-playlists/playlist-info/playlist-info.component.spec.ts index 84b84966..9332cf71 100644 --- a/src/app/home/recent-playlists/playlist-info/playlist-info.component.spec.ts +++ b/src/app/home/recent-playlists/playlist-info/playlist-info.component.spec.ts @@ -1,3 +1,5 @@ +import { ElectronServiceStub } from './../../home.component.spec'; +import { ElectronService } from './../../../services/electron.service'; import { TranslatePipe } from '@ngx-translate/core'; import { MockModule, MockPipe } from 'ng-mocks'; import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; @@ -5,6 +7,7 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { PlaylistInfoComponent } from './playlist-info.component'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; describe('PlaylistInfoComponent', () => { let component: PlaylistInfoComponent; @@ -14,11 +17,16 @@ describe('PlaylistInfoComponent', () => { waitForAsync(() => { TestBed.configureTestingModule({ imports: [ + MockModule(FormsModule), MockModule(MatDialogModule), MockModule(MatFormFieldModule), + ReactiveFormsModule, ], declarations: [PlaylistInfoComponent, MockPipe(TranslatePipe)], - providers: [{ provide: MAT_DIALOG_DATA, useValue: {} }], + providers: [ + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: ElectronService, useClass: ElectronServiceStub }, + ], }).compileComponents(); }) ); diff --git a/src/app/home/recent-playlists/playlist-info/playlist-info.component.ts b/src/app/home/recent-playlists/playlist-info/playlist-info.component.ts index 42ec4f23..ced2e84a 100644 --- a/src/app/home/recent-playlists/playlist-info/playlist-info.component.ts +++ b/src/app/home/recent-playlists/playlist-info/playlist-info.component.ts @@ -1,21 +1,62 @@ +/* eslint-disable @typescript-eslint/unbound-method */ +import { DatePipe } from '@angular/common'; import { Component, Inject } from '@angular/core'; +import { + FormBuilder, + FormControl, + FormGroup, + Validators, +} from '@angular/forms'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { PLAYLIST_SAVE_DETAILS } from '../../../../../ipc-commands'; +import { ElectronService } from '../../../services/electron.service'; import { Playlist } from '../../playlist.interface'; @Component({ selector: 'app-playlist-info', templateUrl: './playlist-info.component.html', styleUrls: ['./playlist-info.component.scss'], + providers: [DatePipe], }) export class PlaylistInfoComponent { /** Playlist object */ playlist: Playlist; + playlistDetails: FormGroup; + /** * Creates an instance of the component and injects the selected playlist from the parent component - * @param data playlist object to show + * @param playlist playlist object to show */ - constructor(@Inject(MAT_DIALOG_DATA) playlist: Playlist) { + constructor( + @Inject(MAT_DIALOG_DATA) playlist: Playlist, + datePipe: DatePipe, + formBuilder: FormBuilder, + private electronService: ElectronService + ) { this.playlist = playlist; + this.playlistDetails = formBuilder.group({ + _id: playlist._id, + title: new FormControl(playlist.title, Validators.required), + userAgent: playlist.userAgent || '', + filename: new FormControl({ + value: playlist.filename || '', + disabled: true, + }), + count: new FormControl({ value: playlist.count, disabled: true }), + importDate: new FormControl({ + value: datePipe.transform(playlist.importDate), + disabled: true, + }), + url: new FormControl({ value: playlist.url, disabled: true }), + }); + } + + /** + * Saves updated playlist information + * @param data updated form data + */ + saveChanges(data: Pick): void { + this.electronService.ipcRenderer.send(PLAYLIST_SAVE_DETAILS, data); } } diff --git a/src/app/home/recent-playlists/recent-playlists.component.html b/src/app/home/recent-playlists/recent-playlists.component.html index 35a459f1..2c66ee2e 100644 --- a/src/app/home/recent-playlists/recent-playlists.component.html +++ b/src/app/home/recent-playlists/recent-playlists.component.html @@ -39,7 +39,7 @@ (click)="$event.stopPropagation(); openInfoDialog(item)" [matTooltip]="'HOME.PLAYLISTS.SHOW_DETAILS' | translate" > - info + edit