mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 01:56:16 -08:00
feat: export playlist as m3u
This commit is contained in:
1 parent
ba41c8dae5
commit
7e4d6b171f
8 files changed
+204
-179
No files matched your search
@@ -67,6 +67,10 @@
|
||||
</ng-container>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-flat-button color="accent" (click)="exportPlaylist()">
|
||||
{{ 'HOME.PLAYLISTS.INFO_DIALOG.EXPORT_PLAYLIST' | translate }}
|
||||
</button>
|
||||
<div style="flex: 1 1 auto"></div>
|
||||
<button
|
||||
mat-flat-button
|
||||
mat-dialog-close
|
||||
|
||||
@@ -13,7 +13,8 @@ import { Actions } from '@ngrx/effects';
|
||||
import { provideMockActions } from '@ngrx/effects/testing';
|
||||
import { MockStore, provideMockStore } from '@ngrx/store/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MockModule, MockPipe } from 'ng-mocks';
|
||||
import { MockModule, MockPipe, MockProvider } from 'ng-mocks';
|
||||
import { NgxIndexedDBModule } from 'ngx-indexed-db';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DataService } from '../../../services/data.service';
|
||||
import { ElectronServiceStub } from '../../../services/electron.service.stub';
|
||||
@@ -23,7 +24,6 @@ import { PlaylistInfoComponent } from './playlist-info.component';
|
||||
describe('PlaylistInfoComponent', () => {
|
||||
let component: PlaylistInfoComponent;
|
||||
let fixture: ComponentFixture<PlaylistInfoComponent>;
|
||||
let electronService: DataService;
|
||||
let mockStore: MockStore;
|
||||
const actions$ = new Observable<Actions>();
|
||||
|
||||
@@ -45,6 +45,7 @@ describe('PlaylistInfoComponent', () => {
|
||||
UntypedFormBuilder,
|
||||
provideMockStore(),
|
||||
provideMockActions(actions$),
|
||||
MockProvider(NgxIndexedDBModule),
|
||||
],
|
||||
}).compileComponents();
|
||||
})
|
||||
|
||||
@@ -6,16 +6,19 @@ import {
|
||||
ReactiveFormsModule,
|
||||
UntypedFormBuilder,
|
||||
UntypedFormGroup,
|
||||
Validators,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatDialogModule, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { Playlist } from '../../../../../shared/playlist.interface';
|
||||
import { DataService } from '../../../services/data.service';
|
||||
import { PlaylistsService } from '../../../services/playlists.service';
|
||||
import { PlaylistMeta } from '../../../shared/playlist-meta.type';
|
||||
import * as PlaylistActions from '../../../state/actions';
|
||||
|
||||
@@ -26,6 +29,7 @@ import * as PlaylistActions from '../../../state/actions';
|
||||
imports: [
|
||||
TranslateModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatCheckboxModule,
|
||||
CommonModule,
|
||||
@@ -49,6 +53,7 @@ export class PlaylistInfoComponent {
|
||||
private formBuilder: UntypedFormBuilder,
|
||||
private dataService: DataService,
|
||||
@Inject(MAT_DIALOG_DATA) playlist: Playlist,
|
||||
private playlistService: PlaylistsService,
|
||||
private store: Store
|
||||
) {
|
||||
this.playlist = playlist;
|
||||
@@ -89,4 +94,21 @@ export class PlaylistInfoComponent {
|
||||
saveChanges(playlist: PlaylistMeta): void {
|
||||
this.store.dispatch(PlaylistActions.updatePlaylistMeta({ playlist }));
|
||||
}
|
||||
|
||||
async exportPlaylist() {
|
||||
const playlistAsString = await firstValueFrom(
|
||||
this.playlistService.getRawPlaylistById(this.playlist._id)
|
||||
);
|
||||
const element = document.createElement('a');
|
||||
element.setAttribute(
|
||||
'href',
|
||||
'data:text/plain;charset=utf-8,' +
|
||||
encodeURIComponent(playlistAsString)
|
||||
);
|
||||
element.setAttribute('download', this.playlist.title || 'exported.m3u');
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,12 @@ import { Channel } from '../../../shared/channel.interface';
|
||||
import { GLOBAL_FAVORITES_PLAYLIST_ID } from '../../../shared/constants';
|
||||
import {
|
||||
Playlist,
|
||||
PlaylistUpdateState,
|
||||
PlaylistUpdateState
|
||||
} from '../../../shared/playlist.interface';
|
||||
import {
|
||||
aggregateFavoriteChannels,
|
||||
createFavoritesPlaylist,
|
||||
createPlaylistObject,
|
||||
createPlaylistObject
|
||||
} from '../../../shared/playlist.utils';
|
||||
import { DbStores } from '../indexed-db.config';
|
||||
import { PlaylistMeta } from '../shared/playlist-meta.type';
|
||||
@@ -191,4 +191,11 @@ export class PlaylistsService {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
getRawPlaylistById(id: string) {
|
||||
return this.dbService.getByID<Playlist>(DbStores.Playlists, id).pipe(map(playlist => {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||
return playlist.playlist.header.raw + '\n' + playlist.playlist.items.map(item => item.raw).join('\n');
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,8 @@
|
||||
"UPDATE_FAILED": "Update fehlgeschlagen",
|
||||
"AUTO_UPDATE": "Auto-update",
|
||||
"AUTO_UPDATE_DESCRIPTION": "Wenn die Auto-Refresh-Funktion aktiviert ist, wird die Wiedergabeliste bei jedem Start der Anwendung automatisch aktualisiert.",
|
||||
"CUSTOM_USER_AGENT": "Einige IPTV-Anbieter benötigen einen bestimmten 'User-Agent', um ihre Playlist abspielen zu können."
|
||||
"CUSTOM_USER_AGENT": "Einige IPTV-Anbieter benötigen einen bestimmten 'User-Agent', um ihre Playlist abspielen zu können.",
|
||||
"EXPORT_PLAYLIST": "Als m3u exportieren"
|
||||
},
|
||||
"UPDATED": "Aktualisiert am",
|
||||
"REFRESH": "Aktualisieren",
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
"UPDATE_FAILED": "Last playlist update failed",
|
||||
"AUTO_UPDATE": "Auto-update",
|
||||
"AUTO_UPDATE_DESCRIPTION": "If the auto-refresh function is activated, the playlist will be updated automatically each time the app is started.",
|
||||
"CUSTOM_USER_AGENT": "Some IPTV providers need a specific user-agent in order to play their playlist."
|
||||
"CUSTOM_USER_AGENT": "Some IPTV providers need a specific user-agent in order to play their playlist.",
|
||||
"EXPORT_PLAYLIST": "Export playlist as m3u"
|
||||
},
|
||||
"REMOVE_DIALOG": {
|
||||
"TITLE": "Remove playlist",
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
"UPDATE_FAILED": "Не удалось обновить плейлист",
|
||||
"AUTO_UPDATE": "Автообновление",
|
||||
"AUTO_UPDATE_DESCRIPTION": "Если активирована функция автообновления, список воспроизведения будет обновляться автоматически при каждом запуске приложения.",
|
||||
"CUSTOM_USER_AGENT": "Некоторые IPTV провайдеры требуют указанние определенного пользовательского агента (User Agent) для воспроизведения своего плейлиста."
|
||||
"CUSTOM_USER_AGENT": "Некоторые IPTV провайдеры требуют указанние определенного пользовательского агента (User Agent) для воспроизведения своего плейлиста.",
|
||||
"EXPORT_PLAYLIST": "Экспортировать плейлист (m3u)"
|
||||
},
|
||||
"UPDATED": "Обновлен",
|
||||
"REFRESH": "Обновить плейлист",
|
||||
|
||||
Reference in new issue
Block a user