mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 01:56:16 -08:00
feat: set custom user agent for a playlist
This commit closes the feature request from #26
This commit is contained in:
8 files changed
+176
-48
No files matched your search
@@ -11,6 +11,7 @@ import {
|
|||||||
EPG_FETCH_DONE,
|
EPG_FETCH_DONE,
|
||||||
EPG_GET_PROGRAM,
|
EPG_GET_PROGRAM,
|
||||||
EPG_GET_PROGRAM_DONE,
|
EPG_GET_PROGRAM_DONE,
|
||||||
|
PLAYLIST_SAVE_DETAILS,
|
||||||
} from './ipc-commands';
|
} from './ipc-commands';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -24,6 +25,9 @@ export class Api {
|
|||||||
/** Instance of the main application window */
|
/** Instance of the main application window */
|
||||||
mainWindow: BrowserWindow;
|
mainWindow: BrowserWindow;
|
||||||
|
|
||||||
|
/** Default user agent stored as a fallback value */
|
||||||
|
defaultUserAgent: string;
|
||||||
|
|
||||||
/** Instance of the epg browser window */
|
/** Instance of the epg browser window */
|
||||||
workerWindow: BrowserWindow;
|
workerWindow: BrowserWindow;
|
||||||
|
|
||||||
@@ -61,18 +65,11 @@ export class Api {
|
|||||||
event.sender.send('parse-response', { payload: playlistObject });
|
event.sender.send('parse-response', { payload: playlistObject });
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('playlists-all', async (event) => {
|
ipcMain.on('playlists-all', (event) => this.sendAllPlaylists(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('playlist-by-id', async (event, args) => {
|
ipcMain.on('playlist-by-id', async (event, args) => {
|
||||||
const playlist = await db.findOne({ _id: args.id });
|
const playlist = await db.findOne({ _id: args.id });
|
||||||
|
this.setUserAgent(playlist.userAgent);
|
||||||
event.sender.send('parse-response', {
|
event.sender.send('parse-response', {
|
||||||
payload: playlist,
|
payload: playlist,
|
||||||
});
|
});
|
||||||
@@ -137,6 +134,51 @@ export class Api {
|
|||||||
.on(EPG_ERROR, (event, arg) =>
|
.on(EPG_ERROR, (event, arg) =>
|
||||||
this.mainWindow.webContents.send(EPG_ERROR, 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<void> {
|
||||||
|
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 {
|
setEpgWorkerWindow(workerWindow: BrowserWindow): void {
|
||||||
this.workerWindow = workerWindow;
|
this.workerWindow = workerWindow;
|
||||||
|
|
||||||
|
// store default user agent as fallback
|
||||||
|
this.defaultUserAgent = this.workerWindow.webContents.getUserAgent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
// EPG related commands
|
||||||
export const EPG_FETCH = 'EPG:FETCH';
|
export const EPG_FETCH = 'EPG:FETCH';
|
||||||
export const EPG_FETCH_DONE = 'EPG:FETCH_DONE';
|
export const EPG_FETCH_DONE = 'EPG:FETCH_DONE';
|
||||||
export const EPG_ERROR = 'EPG:ERROR';
|
export const EPG_ERROR = 'EPG:ERROR';
|
||||||
export const EPG_GET_PROGRAM = 'EPG:GET_PROGRAM';
|
export const EPG_GET_PROGRAM = 'EPG:GET_PROGRAM';
|
||||||
export const EPG_GET_PROGRAM_DONE = 'EPG:GET_PROGRAM_DONE';
|
export const EPG_GET_PROGRAM_DONE = 'EPG:GET_PROGRAM_DONE';
|
||||||
|
|
||||||
|
// Playlist related commands
|
||||||
|
export const PLAYLIST_SAVE_DETAILS = 'PLAYLIST:SAVE_DETAILS';
|
||||||
@@ -8,7 +8,10 @@ import { Playlist } from './playlist.interface';
|
|||||||
import { ElectronService } from '../services/electron.service';
|
import { ElectronService } from '../services/electron.service';
|
||||||
|
|
||||||
/** Type to describe meta data of a playlist */
|
/** Type to describe meta data of a playlist */
|
||||||
export type PlaylistMeta = Pick<Playlist, 'count' | 'title' | 'filename' | '_id' | 'url' | 'importDate'>;
|
export type PlaylistMeta = Pick<
|
||||||
|
Playlist,
|
||||||
|
'count' | 'title' | 'filename' | '_id' | 'url' | 'importDate' | 'userAgent'
|
||||||
|
>;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ export interface Playlist {
|
|||||||
favorites: string[];
|
favorites: string[];
|
||||||
count: number;
|
count: number;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
userAgent?: string;
|
||||||
}
|
}
|
||||||
@@ -1,34 +1,60 @@
|
|||||||
<h2 mat-dialog-title>
|
<form
|
||||||
{{ 'HOME.PLAYLISTS.INFO_DIALOG.PLAYLIST_DETAILS' | translate }}
|
[formGroup]="playlistDetails"
|
||||||
</h2>
|
(ngSubmit)="saveChanges(playlistDetails.value)"
|
||||||
<mat-dialog-content class="mat-typography">
|
>
|
||||||
<mat-form-field class="full-width">
|
<h2 mat-dialog-title>
|
||||||
<mat-label>{{
|
{{ 'HOME.PLAYLISTS.INFO_DIALOG.PLAYLIST_DETAILS' | translate }}
|
||||||
'HOME.PLAYLISTS.INFO_DIALOG.TITLE' | translate
|
</h2>
|
||||||
}}</mat-label>
|
<mat-dialog-content class="mat-typography">
|
||||||
<input matInput [value]="playlist.title" disabled="true" />
|
<mat-form-field class="full-width">
|
||||||
</mat-form-field>
|
<mat-label>{{
|
||||||
<mat-form-field class="full-width" *ngIf="playlist.url">
|
'HOME.PLAYLISTS.INFO_DIALOG.TITLE' | translate
|
||||||
<mat-label>{{
|
}}</mat-label>
|
||||||
'HOME.PLAYLISTS.INFO_DIALOG.FROM_URL' | translate
|
<input formControlName="title" matInput />
|
||||||
}}</mat-label>
|
</mat-form-field>
|
||||||
<input matInput [value]="playlist.url" disabled="true" />
|
<mat-form-field class="full-width" *ngIf="playlist.url">
|
||||||
</mat-form-field>
|
<mat-label>{{
|
||||||
<mat-form-field class="full-width">
|
'HOME.PLAYLISTS.INFO_DIALOG.FROM_URL' | translate
|
||||||
<mat-label>{{
|
}}</mat-label>
|
||||||
'HOME.PLAYLISTS.INFO_DIALOG.IMPORT_DATE' | translate
|
<input matInput formControlName="url" />
|
||||||
}}</mat-label>
|
</mat-form-field>
|
||||||
<input matInput [value]="playlist.importDate | date" disabled="true" />
|
<mat-form-field class="full-width">
|
||||||
</mat-form-field>
|
<mat-label>{{
|
||||||
<mat-form-field class="full-width">
|
'HOME.PLAYLISTS.INFO_DIALOG.ORIGINAL_FILENAME' | translate
|
||||||
<mat-label>{{
|
}}</mat-label>
|
||||||
'HOME.PLAYLISTS.INFO_DIALOG.CHANNELS' | translate
|
<input matInput formControlName="filename" />
|
||||||
}}</mat-label>
|
</mat-form-field>
|
||||||
<input matInput [value]="playlist.count" disabled="true" />
|
<mat-form-field class="full-width">
|
||||||
</mat-form-field>
|
<mat-label>{{
|
||||||
</mat-dialog-content>
|
'HOME.PLAYLISTS.INFO_DIALOG.IMPORT_DATE' | translate
|
||||||
<mat-dialog-actions align="end">
|
}}</mat-label>
|
||||||
<button mat-button mat-dialog-close cdkFocusInitial color="accent">
|
<input matInput formControlName="importDate" />
|
||||||
{{ 'HOME.PLAYLISTS.INFO_DIALOG.CLOSE' | translate }}
|
</mat-form-field>
|
||||||
</button>
|
<mat-form-field class="full-width">
|
||||||
</mat-dialog-actions>
|
<mat-label>{{
|
||||||
|
'HOME.PLAYLISTS.INFO_DIALOG.CHANNELS' | translate
|
||||||
|
}}</mat-label>
|
||||||
|
<input matInput formControlName="count" />
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="full-width">
|
||||||
|
<mat-label>{{
|
||||||
|
'HOME.PLAYLISTS.INFO_DIALOG.USER_AGENT' | translate
|
||||||
|
}}</mat-label>
|
||||||
|
<input formControlName="userAgent" matInput />
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-dialog-content>
|
||||||
|
<mat-dialog-actions align="end">
|
||||||
|
<button
|
||||||
|
mat-flat-button
|
||||||
|
mat-dialog-close
|
||||||
|
color="accent"
|
||||||
|
type="submit"
|
||||||
|
[disabled]="!playlistDetails.valid || playlistDetails.pristine"
|
||||||
|
>
|
||||||
|
{{ 'HOME.PLAYLISTS.INFO_DIALOG.SAVE' | translate }}
|
||||||
|
</button>
|
||||||
|
<button mat-button mat-dialog-close cdkFocusInitial color="accent">
|
||||||
|
{{ 'HOME.PLAYLISTS.INFO_DIALOG.CLOSE' | translate }}
|
||||||
|
</button>
|
||||||
|
</mat-dialog-actions>
|
||||||
|
</form>
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ElectronServiceStub } from './../../home.component.spec';
|
||||||
|
import { ElectronService } from './../../../services/electron.service';
|
||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
import { MockModule, MockPipe } from 'ng-mocks';
|
import { MockModule, MockPipe } from 'ng-mocks';
|
||||||
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
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 { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
|
|
||||||
import { PlaylistInfoComponent } from './playlist-info.component';
|
import { PlaylistInfoComponent } from './playlist-info.component';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
describe('PlaylistInfoComponent', () => {
|
describe('PlaylistInfoComponent', () => {
|
||||||
let component: PlaylistInfoComponent;
|
let component: PlaylistInfoComponent;
|
||||||
@@ -14,11 +17,16 @@ describe('PlaylistInfoComponent', () => {
|
|||||||
waitForAsync(() => {
|
waitForAsync(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
MockModule(FormsModule),
|
||||||
MockModule(MatDialogModule),
|
MockModule(MatDialogModule),
|
||||||
MockModule(MatFormFieldModule),
|
MockModule(MatFormFieldModule),
|
||||||
|
ReactiveFormsModule,
|
||||||
],
|
],
|
||||||
declarations: [PlaylistInfoComponent, MockPipe(TranslatePipe)],
|
declarations: [PlaylistInfoComponent, MockPipe(TranslatePipe)],
|
||||||
providers: [{ provide: MAT_DIALOG_DATA, useValue: {} }],
|
providers: [
|
||||||
|
{ provide: MAT_DIALOG_DATA, useValue: {} },
|
||||||
|
{ provide: ElectronService, useClass: ElectronServiceStub },
|
||||||
|
],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,21 +1,62 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
|
import { DatePipe } from '@angular/common';
|
||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import {
|
||||||
|
FormBuilder,
|
||||||
|
FormControl,
|
||||||
|
FormGroup,
|
||||||
|
Validators,
|
||||||
|
} from '@angular/forms';
|
||||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
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';
|
import { Playlist } from '../../playlist.interface';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-playlist-info',
|
selector: 'app-playlist-info',
|
||||||
templateUrl: './playlist-info.component.html',
|
templateUrl: './playlist-info.component.html',
|
||||||
styleUrls: ['./playlist-info.component.scss'],
|
styleUrls: ['./playlist-info.component.scss'],
|
||||||
|
providers: [DatePipe],
|
||||||
})
|
})
|
||||||
export class PlaylistInfoComponent {
|
export class PlaylistInfoComponent {
|
||||||
/** Playlist object */
|
/** Playlist object */
|
||||||
playlist: Playlist;
|
playlist: Playlist;
|
||||||
|
|
||||||
|
playlistDetails: FormGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of the component and injects the selected playlist from the parent component
|
* 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.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<Playlist, '_id' | 'title' | 'userAgent'>): void {
|
||||||
|
this.electronService.ipcRenderer.send(PLAYLIST_SAVE_DETAILS, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
(click)="$event.stopPropagation(); openInfoDialog(item)"
|
(click)="$event.stopPropagation(); openInfoDialog(item)"
|
||||||
[matTooltip]="'HOME.PLAYLISTS.SHOW_DETAILS' | translate"
|
[matTooltip]="'HOME.PLAYLISTS.SHOW_DETAILS' | translate"
|
||||||
>
|
>
|
||||||
<mat-icon>info</mat-icon>
|
<mat-icon>edit</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
|
|||||||
Reference in new issue
Block a user