mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -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_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<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 {
|
||||
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_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';
|
||||
@@ -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<Playlist, 'count' | 'title' | 'filename' | '_id' | 'url' | 'importDate'>;
|
||||
export type PlaylistMeta = Pick<
|
||||
Playlist,
|
||||
'count' | 'title' | 'filename' | '_id' | 'url' | 'importDate' | 'userAgent'
|
||||
>;
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
|
||||
@@ -14,4 +14,5 @@ export interface Playlist {
|
||||
favorites: string[];
|
||||
count: number;
|
||||
url?: string;
|
||||
userAgent?: string;
|
||||
}
|
||||
@@ -1,34 +1,60 @@
|
||||
<h2 mat-dialog-title>
|
||||
{{ 'HOME.PLAYLISTS.INFO_DIALOG.PLAYLIST_DETAILS' | translate }}
|
||||
</h2>
|
||||
<mat-dialog-content class="mat-typography">
|
||||
<mat-form-field class="full-width">
|
||||
<mat-label>{{
|
||||
'HOME.PLAYLISTS.INFO_DIALOG.TITLE' | translate
|
||||
}}</mat-label>
|
||||
<input matInput [value]="playlist.title" disabled="true" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="full-width" *ngIf="playlist.url">
|
||||
<mat-label>{{
|
||||
'HOME.PLAYLISTS.INFO_DIALOG.FROM_URL' | translate
|
||||
}}</mat-label>
|
||||
<input matInput [value]="playlist.url" disabled="true" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="full-width">
|
||||
<mat-label>{{
|
||||
'HOME.PLAYLISTS.INFO_DIALOG.IMPORT_DATE' | translate
|
||||
}}</mat-label>
|
||||
<input matInput [value]="playlist.importDate | date" disabled="true" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="full-width">
|
||||
<mat-label>{{
|
||||
'HOME.PLAYLISTS.INFO_DIALOG.CHANNELS' | translate
|
||||
}}</mat-label>
|
||||
<input matInput [value]="playlist.count" disabled="true" />
|
||||
</mat-form-field>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button mat-dialog-close cdkFocusInitial color="accent">
|
||||
{{ 'HOME.PLAYLISTS.INFO_DIALOG.CLOSE' | translate }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
<form
|
||||
[formGroup]="playlistDetails"
|
||||
(ngSubmit)="saveChanges(playlistDetails.value)"
|
||||
>
|
||||
<h2 mat-dialog-title>
|
||||
{{ 'HOME.PLAYLISTS.INFO_DIALOG.PLAYLIST_DETAILS' | translate }}
|
||||
</h2>
|
||||
<mat-dialog-content class="mat-typography">
|
||||
<mat-form-field class="full-width">
|
||||
<mat-label>{{
|
||||
'HOME.PLAYLISTS.INFO_DIALOG.TITLE' | translate
|
||||
}}</mat-label>
|
||||
<input formControlName="title" matInput />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="full-width" *ngIf="playlist.url">
|
||||
<mat-label>{{
|
||||
'HOME.PLAYLISTS.INFO_DIALOG.FROM_URL' | translate
|
||||
}}</mat-label>
|
||||
<input matInput formControlName="url" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="full-width">
|
||||
<mat-label>{{
|
||||
'HOME.PLAYLISTS.INFO_DIALOG.ORIGINAL_FILENAME' | translate
|
||||
}}</mat-label>
|
||||
<input matInput formControlName="filename" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="full-width">
|
||||
<mat-label>{{
|
||||
'HOME.PLAYLISTS.INFO_DIALOG.IMPORT_DATE' | translate
|
||||
}}</mat-label>
|
||||
<input matInput formControlName="importDate" />
|
||||
</mat-form-field>
|
||||
<mat-form-field class="full-width">
|
||||
<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 { 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();
|
||||
})
|
||||
);
|
||||
|
||||
@@ -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<Playlist, '_id' | 'title' | 'userAgent'>): void {
|
||||
this.electronService.ipcRenderer.send(PLAYLIST_SAVE_DETAILS, data);
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@
|
||||
(click)="$event.stopPropagation(); openInfoDialog(item)"
|
||||
[matTooltip]="'HOME.PLAYLISTS.SHOW_DETAILS' | translate"
|
||||
>
|
||||
<mat-icon>info</mat-icon>
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
|
||||
Reference in new issue
Block a user