diff --git a/electron/api.ts b/electron/api.ts index 5631da7c7..a1027e553 100644 --- a/electron/api.ts +++ b/electron/api.ts @@ -19,6 +19,7 @@ import { PLAYLIST_PARSE, PLAYLIST_PARSE_BY_URL, PLAYLIST_PARSE_RESPONSE, + PLAYLIST_PARSE_TEXT, PLAYLIST_REMOVE_BY_ID, PLAYLIST_REMOVE_BY_ID_RESPONSE, PLAYLIST_SAVE_DETAILS, @@ -91,6 +92,27 @@ export class Api { } }); + ipcMain.on(PLAYLIST_PARSE_TEXT, (event, args) => { + try { + const parsedPlaylist = this.parsePlaylist( + args.text.split('\n') + ); + const playlistObject = this.createPlaylistObject( + 'Imported as text', + parsedPlaylist + ); + this.insertToDb(playlistObject); + event.sender.send(PLAYLIST_PARSE_RESPONSE, { + payload: playlistObject, + }); + } catch (err) { + event.sender.send(ERROR, { + message: err.response.statusText, + status: err.response.status, + }); + } + }); + ipcMain.on(PLAYLIST_PARSE, (event, args) => { const parsedPlaylist = this.parsePlaylist(args.playlist); const playlistObject = this.createPlaylistObject( diff --git a/shared/ipc-commands.ts b/shared/ipc-commands.ts index ad3cc6b73..9fe484af1 100644 --- a/shared/ipc-commands.ts +++ b/shared/ipc-commands.ts @@ -14,6 +14,7 @@ export const PLAYLIST_GET_BY_ID = 'PLAYLIST:GET_BY_ID'; export const PLAYLIST_SAVE_DETAILS = 'PLAYLIST:SAVE_DETAILS'; export const PLAYLIST_PARSE = 'PLAYLIST:PARSE_PLAYLIST'; export const PLAYLIST_PARSE_BY_URL = 'PLAYLIST:PARSE_PLAYLIST_BY_URL'; +export const PLAYLIST_PARSE_TEXT = 'PLAYLIST:PLAYLIST_PARSE_TEXT'; export const PLAYLIST_PARSE_RESPONSE = 'PLAYLIST:PARSE_PLAYLIST_RESPONSE'; export const PLAYLIST_UPDATE = 'PLAYLIST:UPDATE'; export const PLAYLIST_UPDATE_RESPONSE = 'PLAYLIST:UPDATE_RESPONSE'; diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 2d942120e..f7832eba6 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -43,6 +43,17 @@ > + + + text_format + {{ 'HOME.TABS.TEXT_IMPORT' | translate }} + + + + + diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index fa5a7b2ca..70ac09613 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -7,6 +7,7 @@ import { PLAYLIST_PARSE, PLAYLIST_PARSE_BY_URL, PLAYLIST_PARSE_RESPONSE, + PLAYLIST_PARSE_TEXT, PLAYLIST_UPDATE_RESPONSE, } from '../../../shared/ipc-commands'; import { Playlist } from '../../../shared/playlist.interface'; @@ -154,6 +155,17 @@ export class HomeComponent { }); } + /** + * Sends IPC event to the renderer process to parse playlist + * @param text playlist as string + */ + uploadAsText(text: string): void { + this.isLoading = true; + this.electronService.sendIpcEvent(PLAYLIST_PARSE_TEXT, { + text, + }); + } + /** * Returns last segment (part after last slash "/") of the given URL * @param value URL as string diff --git a/src/app/home/home.module.ts b/src/app/home/home.module.ts index 77f74850d..98a95f54e 100644 --- a/src/app/home/home.module.ts +++ b/src/app/home/home.module.ts @@ -6,6 +6,7 @@ import { FileUploadComponent } from './file-upload/file-upload.component'; import { HomeComponent } from './home.component'; import { HomeRoutingModule } from './home.routing'; import { PlaylistInfoComponent } from './recent-playlists/playlist-info/playlist-info.component'; +import { TextImportComponent } from './text-import/text-import.component'; import { UrlUploadComponent } from './url-upload/url-upload.component'; @NgModule({ @@ -14,6 +15,7 @@ import { UrlUploadComponent } from './url-upload/url-upload.component'; HomeComponent, FileUploadComponent, PlaylistInfoComponent, + TextImportComponent, UrlUploadComponent, ], }) diff --git a/src/app/home/recent-playlists/recent-playlists.component.html b/src/app/home/recent-playlists/recent-playlists.component.html index e49d43545..b5f78ffa6 100644 --- a/src/app/home/recent-playlists/recent-playlists.component.html +++ b/src/app/home/recent-playlists/recent-playlists.component.html @@ -11,9 +11,11 @@ (click)="getPlaylist('GLOBAL_FAVORITES')" > star -
Global favorites
+
+ {{ 'HOME.PLAYLISTS.GLOBAL_FAVORITES_DESCRIPTION' | translate }} +
- Auto-generated playlist with aggregated favorites from all playlists + {{ 'HOME.PLAYLISTS.GLOBAL_FAVORITES' | translate }}
diff --git a/src/app/home/text-import/text-import.component.html b/src/app/home/text-import/text-import.component.html new file mode 100644 index 000000000..fc02b9ffe --- /dev/null +++ b/src/app/home/text-import/text-import.component.html @@ -0,0 +1,18 @@ +
+ + {{ 'HOME.TEXT_IMPORT.LABEL' | translate }} + + + +
diff --git a/src/app/home/text-import/text-import.component.scss b/src/app/home/text-import/text-import.component.scss new file mode 100644 index 000000000..3759c919b --- /dev/null +++ b/src/app/home/text-import/text-import.component.scss @@ -0,0 +1,8 @@ +button { + margin: 15px; + text-transform: uppercase; +} + +textarea { + height: calc(100vh - 300px); +} diff --git a/src/app/home/text-import/text-import.component.spec.ts b/src/app/home/text-import/text-import.component.spec.ts new file mode 100644 index 000000000..343386635 --- /dev/null +++ b/src/app/home/text-import/text-import.component.spec.ts @@ -0,0 +1,30 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { MatInputModule } from '@angular/material/input'; +import { TranslatePipe } from '@ngx-translate/core'; + +import { MockModule, MockPipe } from 'ng-mocks'; +import { TextImportComponent } from './text-import.component'; + +describe('TextImportComponent', () => { + let component: TextImportComponent; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [TextImportComponent, MockPipe(TranslatePipe)], + imports: [MockModule(MatInputModule)], + }).compileComponents(); + }) + ); + + beforeEach(() => { + fixture = TestBed.createComponent(TextImportComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/home/text-import/text-import.component.ts b/src/app/home/text-import/text-import.component.ts new file mode 100644 index 000000000..6fcbdb040 --- /dev/null +++ b/src/app/home/text-import/text-import.component.ts @@ -0,0 +1,15 @@ +import { Component, EventEmitter, Output } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; + +@Component({ + selector: 'app-text-import', + templateUrl: './text-import.component.html', + styleUrls: ['./text-import.component.scss'], +}) +export class TextImportComponent { + @Output() textAdded = new EventEmitter(); + + textForm = new FormGroup({ + text: new FormControl('', Validators.required), + }); +} diff --git a/src/app/player/components/video-player/video-player.component.html b/src/app/player/components/video-player/video-player.component.html index e84b4d2e1..1c2c5de7e 100644 --- a/src/app/player/components/video-player/video-player.component.html +++ b/src/app/player/components/video-player/video-player.component.html @@ -28,7 +28,7 @@ {{ playlistTitle$ | async }} - My Playlists + {{ 'HOME.PLAYLISTS.MY_PLAYLISTS' | translate }}
diff --git a/src/app/services/pwa.service.ts b/src/app/services/pwa.service.ts index 85e7d41e5..3aa53c2d6 100644 --- a/src/app/services/pwa.service.ts +++ b/src/app/services/pwa.service.ts @@ -13,6 +13,7 @@ import { PLAYLIST_PARSE, PLAYLIST_PARSE_BY_URL, PLAYLIST_PARSE_RESPONSE, + PLAYLIST_PARSE_TEXT, PLAYLIST_REMOVE_BY_ID, PLAYLIST_REMOVE_BY_ID_RESPONSE, PLAYLIST_SAVE_DETAILS, @@ -150,6 +151,34 @@ export class PwaService extends DataService { payload: playlist, }); }); + } else if (type === PLAYLIST_PARSE_TEXT) { + try { + const parsedPlaylist = this.parsePlaylist( + payload.text.split('\n') + ); + const playlistObject = this.createPlaylistObject( + 'Imported as text', + parsedPlaylist + ); + + // save to db + this.dbService + .add(DbStores.Playlists, playlistObject) + .subscribe(() => { + console.log('playlist was saved to db...'); + }); + + window.postMessage({ + type: PLAYLIST_PARSE_RESPONSE, + payload: playlistObject, + }); + } catch (error) { + window.postMessage({ + type: ERROR, + status: '', + message: 'Validation error - invalid playlist', + }); + } } else if (type === PLAYLIST_GET_ALL) { this.dbService .getAll(DbStores.Playlists)