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 @@
+
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)