mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-17 05:11:29 +03:00
Updated playlist file selection to use recent videos component
Playlists are now file type agnostic Updated translations
This commit is contained in:
@@ -1939,7 +1939,6 @@ components:
|
|||||||
- uids
|
- uids
|
||||||
- playlistName
|
- playlistName
|
||||||
- thumbnailURL
|
- thumbnailURL
|
||||||
- type
|
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
playlistName:
|
playlistName:
|
||||||
@@ -1948,8 +1947,6 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type:
|
|
||||||
$ref: '#/components/schemas/FileType'
|
|
||||||
thumbnailURL:
|
thumbnailURL:
|
||||||
type: string
|
type: string
|
||||||
CreatePlaylistResponse:
|
CreatePlaylistResponse:
|
||||||
@@ -1979,15 +1976,17 @@ components:
|
|||||||
required:
|
required:
|
||||||
- playlist
|
- playlist
|
||||||
- success
|
- success
|
||||||
- type
|
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
playlist:
|
playlist:
|
||||||
$ref: '#/components/schemas/Playlist'
|
$ref: '#/components/schemas/Playlist'
|
||||||
type:
|
|
||||||
$ref: '#/components/schemas/FileType'
|
|
||||||
success:
|
success:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
file_objs:
|
||||||
|
type: array
|
||||||
|
description: File objects for every uid in the playlist's uids property, in the same order
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/DatabaseFile'
|
||||||
GetPlaylistsRequest:
|
GetPlaylistsRequest:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -2012,13 +2011,10 @@ components:
|
|||||||
DeletePlaylistRequest:
|
DeletePlaylistRequest:
|
||||||
required:
|
required:
|
||||||
- playlist_id
|
- playlist_id
|
||||||
- type
|
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
playlist_id:
|
playlist_id:
|
||||||
type: string
|
type: string
|
||||||
type:
|
|
||||||
$ref: '#/components/schemas/FileType'
|
|
||||||
DownloadFileRequest:
|
DownloadFileRequest:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@@ -1339,9 +1339,8 @@ app.post('/api/getSubscriptions', optionalJwt, async (req, res) => {
|
|||||||
app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
|
app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
|
||||||
let playlistName = req.body.playlistName;
|
let playlistName = req.body.playlistName;
|
||||||
let uids = req.body.uids;
|
let uids = req.body.uids;
|
||||||
let type = req.body.type;
|
|
||||||
|
|
||||||
const new_playlist = await db_api.createPlaylist(playlistName, uids, type, req.isAuthenticated() ? req.user.uid : null);
|
const new_playlist = await db_api.createPlaylist(playlistName, uids, req.isAuthenticated() ? req.user.uid : null);
|
||||||
|
|
||||||
res.send({
|
res.send({
|
||||||
new_playlist: new_playlist,
|
new_playlist: new_playlist,
|
||||||
@@ -1369,7 +1368,6 @@ app.post('/api/getPlaylist', optionalJwt, async (req, res) => {
|
|||||||
res.send({
|
res.send({
|
||||||
playlist: playlist,
|
playlist: playlist,
|
||||||
file_objs: file_objs,
|
file_objs: file_objs,
|
||||||
type: playlist && playlist.type,
|
|
||||||
success: !!playlist
|
success: !!playlist
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ exports.addMetadataPropertyToDB = async (property_key) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.createPlaylist = async (playlist_name, uids, type, user_uid = null) => {
|
exports.createPlaylist = async (playlist_name, uids, user_uid = null) => {
|
||||||
const first_video = await exports.getVideo(uids[0]);
|
const first_video = await exports.getVideo(uids[0]);
|
||||||
const thumbnailToUse = first_video['thumbnailURL'];
|
const thumbnailToUse = first_video['thumbnailURL'];
|
||||||
|
|
||||||
@@ -366,7 +366,6 @@ exports.createPlaylist = async (playlist_name, uids, type, user_uid = null) => {
|
|||||||
uids: uids,
|
uids: uids,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
thumbnailURL: thumbnailToUse,
|
thumbnailURL: thumbnailToUse,
|
||||||
type: type,
|
|
||||||
registered: Date.now(),
|
registered: Date.now(),
|
||||||
randomize_order: false
|
randomize_order: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ async function deleteSubscriptionFile(sub, file, deleteForever, file_uid = null,
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (jsonExists) {
|
if (jsonExists) {
|
||||||
retrievedID = JSON.parse(await fs.readFile(jsonPath, 'utf8'))['id'];
|
retrievedID = fs.readJSONSync(jsonPath)['id'];
|
||||||
await fs.unlink(jsonPath);
|
await fs.unlink(jsonPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,8 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
import type { FileType } from './FileType';
|
|
||||||
|
|
||||||
export type CreatePlaylistRequest = {
|
export type CreatePlaylistRequest = {
|
||||||
playlistName: string;
|
playlistName: string;
|
||||||
uids: Array<string>;
|
uids: Array<string>;
|
||||||
type: FileType;
|
|
||||||
thumbnailURL: string;
|
thumbnailURL: string;
|
||||||
};
|
};
|
||||||
@@ -2,9 +2,6 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
import type { FileType } from './FileType';
|
|
||||||
|
|
||||||
export type DeletePlaylistRequest = {
|
export type DeletePlaylistRequest = {
|
||||||
playlist_id: string;
|
playlist_id: string;
|
||||||
type: FileType;
|
|
||||||
};
|
};
|
||||||
@@ -2,11 +2,14 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
import type { FileType } from './FileType';
|
import type { DatabaseFile } from './DatabaseFile';
|
||||||
import type { Playlist } from './Playlist';
|
import type { Playlist } from './Playlist';
|
||||||
|
|
||||||
export type GetPlaylistResponse = {
|
export type GetPlaylistResponse = {
|
||||||
playlist: Playlist;
|
playlist: Playlist;
|
||||||
type: FileType;
|
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
/**
|
||||||
|
* File objects for every uid in the playlist's uids property, in the same order
|
||||||
|
*/
|
||||||
|
file_objs?: Array<DatabaseFile>;
|
||||||
};
|
};
|
||||||
@@ -4,6 +4,7 @@ import { Router } from '@angular/router';
|
|||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { CreatePlaylistComponent } from 'app/create-playlist/create-playlist.component';
|
import { CreatePlaylistComponent } from 'app/create-playlist/create-playlist.component';
|
||||||
import { ModifyPlaylistComponent } from 'app/dialogs/modify-playlist/modify-playlist.component';
|
import { ModifyPlaylistComponent } from 'app/dialogs/modify-playlist/modify-playlist.component';
|
||||||
|
import { Playlist } from 'api-types';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-custom-playlists',
|
selector: 'app-custom-playlists',
|
||||||
@@ -32,7 +33,7 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllPlaylists() {
|
getAllPlaylists(): void {
|
||||||
this.playlists_received = false;
|
this.playlists_received = false;
|
||||||
// must call getAllFiles as we need to get category playlists as well
|
// must call getAllFiles as we need to get category playlists as well
|
||||||
this.postsService.getPlaylists(true).subscribe(res => {
|
this.postsService.getPlaylists(true).subscribe(res => {
|
||||||
@@ -42,10 +43,10 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// creating a playlist
|
// creating a playlist
|
||||||
openCreatePlaylistDialog() {
|
openCreatePlaylistDialog(): void {
|
||||||
const dialogRef = this.dialog.open(CreatePlaylistComponent, {
|
const dialogRef = this.dialog.open(CreatePlaylistComponent, {
|
||||||
data: {
|
minWidth: '90vw',
|
||||||
}
|
minHeight: '95vh'
|
||||||
});
|
});
|
||||||
dialogRef.afterClosed().subscribe(result => {
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
@@ -57,7 +58,7 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
goToPlaylist(info_obj) {
|
goToPlaylist(info_obj: { file: Playlist; }): void {
|
||||||
const playlist = info_obj.file;
|
const playlist = info_obj.file;
|
||||||
const playlistID = playlist.id;
|
const playlistID = playlist.id;
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadPlaylist(playlist_id, playlist_name) {
|
downloadPlaylist(playlist_id: string, playlist_name: string): void {
|
||||||
this.downloading_content[playlist_id] = true;
|
this.downloading_content[playlist_id] = true;
|
||||||
this.postsService.downloadPlaylistFromServer(playlist_id).subscribe(res => {
|
this.postsService.downloadPlaylistFromServer(playlist_id).subscribe(res => {
|
||||||
this.downloading_content[playlist_id] = false;
|
this.downloading_content[playlist_id] = false;
|
||||||
@@ -86,11 +87,11 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deletePlaylist(args) {
|
deletePlaylist(args: { file: Playlist; index: number; }): void {
|
||||||
const playlist = args.file;
|
const playlist = args.file;
|
||||||
const index = args.index;
|
const index = args.index;
|
||||||
const playlistID = playlist.id;
|
const playlistID = playlist.id;
|
||||||
this.postsService.removePlaylist(playlistID, playlist.type).subscribe(res => {
|
this.postsService.removePlaylist(playlistID).subscribe(res => {
|
||||||
if (res['success']) {
|
if (res['success']) {
|
||||||
this.playlists.splice(index, 1);
|
this.playlists.splice(index, 1);
|
||||||
this.postsService.openSnackBar('Playlist successfully removed.', '');
|
this.postsService.openSnackBar('Playlist successfully removed.', '');
|
||||||
@@ -99,7 +100,7 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
editPlaylistDialog(args) {
|
editPlaylistDialog(args: { playlist: Playlist; index: number; }): void {
|
||||||
const playlist = args.playlist;
|
const playlist = args.playlist;
|
||||||
const index = args.index;
|
const index = args.index;
|
||||||
const dialogRef = this.dialog.open(ModifyPlaylistComponent, {
|
const dialogRef = this.dialog.open(ModifyPlaylistComponent, {
|
||||||
@@ -109,7 +110,7 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(res => {
|
dialogRef.afterClosed().subscribe(() => {
|
||||||
// updates playlist in file manager if it changed
|
// updates playlist in file manager if it changed
|
||||||
if (dialogRef.componentInstance.playlist_updated) {
|
if (dialogRef.componentInstance.playlist_updated) {
|
||||||
this.playlists[index] = dialogRef.componentInstance.original_playlist;
|
this.playlists[index] = dialogRef.componentInstance.original_playlist;
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 order-1 col-sm-4 order-sm-2 d-flex justify-content-center">
|
<div class="col-12 order-1 col-sm-4 order-sm-2 d-flex justify-content-center">
|
||||||
<h4 class="my-videos-title" i18n="My files title">My files</h4>
|
<h4 *ngIf="!customHeader" class="my-videos-title" i18n="My files title">My files</h4>
|
||||||
|
<h4 *ngIf="customHeader" class="my-videos-title">{{customHeader}}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 order-3 col-sm-4 order-sm-3 d-flex justify-content-center">
|
<div class="col-12 order-3 col-sm-4 order-sm-3 d-flex justify-content-center">
|
||||||
<mat-form-field [ngClass]="searchIsFocused ? 'search-bar-focused' : 'search-bar-unfocused'" class="search-bar" color="accent">
|
<mat-form-field [ngClass]="searchIsFocused ? 'search-bar-focused' : 'search-bar-unfocused'" class="search-bar" color="accent">
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="container" style="margin-bottom: 16px">
|
<div *ngIf="!selectMode" class="container" style="margin-bottom: 16px">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<ng-container *ngIf="normal_files_received && paged_data">
|
<ng-container *ngIf="normal_files_received && paged_data">
|
||||||
<div *ngFor="let file of paged_data; let i = index" class="mb-2 mt-2 d-flex justify-content-center" [ngClass]="[ postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
|
<div *ngFor="let file of paged_data; let i = index" class="mb-2 mt-2 d-flex justify-content-center" [ngClass]="[ postsService.card_size === 'small' ? 'col-2 small-col' : '', postsService.card_size === 'medium' ? 'col-6 col-lg-4 medium-col' : '', postsService.card_size === 'large' ? 'col-12 large-col' : '' ]">
|
||||||
@@ -46,6 +47,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="selectMode">
|
||||||
|
<mat-selection-list *ngIf="normal_files_received" (selectionChange)="fileSelectionChanged($event)">
|
||||||
|
<mat-list-option [selected]="selected_data.includes(file.uid)" *ngFor="let file of paged_data" [value]="file.uid">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-10">
|
||||||
|
<mat-icon class="audio-video-icon">{{(file.type === 'audio' || file.isAudio) ? 'audiotrack' : 'movie'}}</mat-icon>
|
||||||
|
{{file.title}}
|
||||||
|
</div>
|
||||||
|
<div class="col-2">{{file.registered | date:'shortDate'}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</mat-list-option>
|
||||||
|
</mat-selection-list>
|
||||||
|
|
||||||
|
<ng-container *ngIf="!normal_files_received && loading_files && loading_files.length > 0">
|
||||||
|
<mat-selection-list *ngIf="!normal_files_received">
|
||||||
|
<mat-list-option *ngFor="let file of paged_data">
|
||||||
|
<content-loader class="list-ghosts" [primaryColor]="postsService.theme.ghost_primary" [secondaryColor]="postsService.theme.ghost_secondary" width="250" height="8"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="8" /></content-loader>
|
||||||
|
</mat-list-option>
|
||||||
|
</mat-selection-list>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div *ngIf="usePaginator">
|
<div *ngIf="usePaginator">
|
||||||
<div style="position: absolute; margin-left: 8px; margin-top: 5px; scale: 0.8">
|
<div style="position: absolute; margin-left: 8px; margin-top: 5px; scale: 0.8">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
|
|||||||
@@ -61,4 +61,14 @@
|
|||||||
.my-videos-title {
|
.my-videos-title {
|
||||||
top: 0px;
|
top: 0px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-ghosts {
|
||||||
|
position: relative;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.audio-video-icon {
|
||||||
|
position: relative;
|
||||||
|
top: 6px;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||||
import { PostsService } from 'app/posts.services';
|
import { PostsService } from 'app/posts.services';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { FileType, FileTypeFilter } from '../../../api-types';
|
import { DatabaseFile, FileType, FileTypeFilter } from '../../../api-types';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { distinctUntilChanged } from 'rxjs/operators';
|
import { distinctUntilChanged } from 'rxjs/operators';
|
||||||
@@ -14,7 +14,10 @@ import { distinctUntilChanged } from 'rxjs/operators';
|
|||||||
export class RecentVideosComponent implements OnInit {
|
export class RecentVideosComponent implements OnInit {
|
||||||
|
|
||||||
@Input() usePaginator = true;
|
@Input() usePaginator = true;
|
||||||
|
@Input() selectMode = false;
|
||||||
@Input() sub_id = null;
|
@Input() sub_id = null;
|
||||||
|
@Input() customHeader = null;
|
||||||
|
@Output() fileSelectionEmitter = new EventEmitter<{new_selection: string[], thumbnailURL: string}>();
|
||||||
|
|
||||||
cached_file_count = 0;
|
cached_file_count = 0;
|
||||||
loading_files = null;
|
loading_files = null;
|
||||||
@@ -61,7 +64,9 @@ export class RecentVideosComponent implements OnInit {
|
|||||||
playlists = null;
|
playlists = null;
|
||||||
|
|
||||||
pageSize = 10;
|
pageSize = 10;
|
||||||
paged_data = null;
|
paged_data: DatabaseFile[] = null;
|
||||||
|
|
||||||
|
selected_data: string[] = [];
|
||||||
|
|
||||||
@ViewChild('paginator') paginator: MatPaginator
|
@ViewChild('paginator') paginator: MatPaginator
|
||||||
|
|
||||||
@@ -358,4 +363,21 @@ export class RecentVideosComponent implements OnInit {
|
|||||||
this.loading_files = Array(this.pageSize).fill(0);
|
this.loading_files = Array(this.pageSize).fill(0);
|
||||||
this.getAllFiles();
|
this.getAllFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileSelectionChanged(event): void {
|
||||||
|
const adding = event.option._selected;
|
||||||
|
const value = event.option.value;
|
||||||
|
if (adding)
|
||||||
|
this.selected_data.push(value);
|
||||||
|
else
|
||||||
|
this.selected_data = this.selected_data.filter(e => e !== value);
|
||||||
|
|
||||||
|
let thumbnail_url = null;
|
||||||
|
if (this.selected_data.length) {
|
||||||
|
const file_obj = this.paged_data.find(file => file.uid === this.selected_data[0]);
|
||||||
|
if (file_obj) { thumbnail_url = file_obj['thumbnailURL'] }
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fileSelectionEmitter.emit({new_selection: this.selected_data, thumbnailURL: thumbnail_url});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<ng-container *ngIf="!is_playlist && !loading">
|
<ng-container *ngIf="!is_playlist && !loading">
|
||||||
<button (click)="openFileInfoDialog()" mat-menu-item><mat-icon>info</mat-icon><ng-container i18n="Video info button">Info</ng-container></button>
|
<button (click)="openFileInfoDialog()" mat-menu-item><mat-icon>info</mat-icon><ng-container i18n="Video info button">Info</ng-container></button>
|
||||||
<button (click)="navigateToSubscription()" mat-menu-item *ngIf="file_obj.sub_id"><mat-icon>{{file_obj.isAudio ? 'library_music' : 'video_library'}}</mat-icon> <ng-container i18n="Go to subscription menu item">Go to subscription</ng-container></button>
|
<button (click)="navigateToSubscription()" mat-menu-item *ngIf="file_obj.sub_id"><mat-icon>{{file_obj.isAudio ? 'library_music' : 'video_library'}}</mat-icon> <ng-container i18n="Go to subscription menu item">Go to subscription</ng-container></button>
|
||||||
<button *ngIf="availablePlaylists" [matMenuTriggerFor]="addtoplaylist" mat-menu-item><mat-icon>playlist_add</mat-icon> <ng-container i18n="Add to playlist menu item">Add to playlist</ng-container></button>
|
<button [disabled]="!availablePlaylists || availablePlaylists.length === 0" [matMenuTriggerFor]="addtoplaylist" mat-menu-item><mat-icon>playlist_add</mat-icon> <ng-container i18n="Add to playlist menu item">Add to playlist</ng-container></button>
|
||||||
<mat-menu #addtoplaylist="matMenu">
|
<mat-menu #addtoplaylist="matMenu">
|
||||||
<ng-container *ngFor="let playlist of availablePlaylists">
|
<ng-container *ngFor="let playlist of availablePlaylists">
|
||||||
<button *ngIf="(playlist.type === 'audio') === file_obj.isAudio" [disabled]="playlist.uids?.includes(file_obj.uid)" (click)="emitAddFileToPlaylist(playlist.id)" mat-menu-item>{{playlist.name}}</button>
|
<button *ngIf="(playlist.type === 'audio') === file_obj.isAudio" [disabled]="playlist.uids?.includes(file_obj.uid)" (click)="emitAddFileToPlaylist(playlist.id)" mat-menu-item>{{playlist.name}}</button>
|
||||||
|
|||||||
@@ -1,34 +1,12 @@
|
|||||||
<h4 mat-dialog-title i18n="Create a playlist dialog title">Create a playlist</h4>
|
<h4 mat-dialog-title i18n="Create a playlist dialog title">Create a playlist</h4>
|
||||||
<form>
|
<form>
|
||||||
<div *ngIf="filesToSelectFrom || (audiosToSelectFrom && videosToSelectFrom)">
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field color="accent">
|
<mat-form-field color="accent">
|
||||||
<input [(ngModel)]="name" matInput placeholder="Name" i18n-placeholder="Playlist name placeholder" type="text" required aria-required [ngModelOptions]="{standalone: true}">
|
<input [(ngModel)]="name" matInput placeholder="Name" i18n-placeholder="Playlist name placeholder" type="text" required aria-required [ngModelOptions]="{standalone: true}">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!filesToSelectFrom">
|
<app-recent-videos [selectMode]="true" [customHeader]="'Select files'" (fileSelectionEmitter)="fileSelectionChanged($event)"></app-recent-videos>
|
||||||
<mat-form-field color="accent">
|
|
||||||
<mat-select placeholder="Type" i18n-placeholder="Type select" [(ngModel)]="type" [ngModelOptions]="{standalone: true}">
|
|
||||||
<mat-option value="audio"><ng-container i18n="Audio">Audio</ng-container></mat-option>
|
|
||||||
<mat-option value="video"><ng-container i18n="Video">Video</ng-container></mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<mat-form-field *ngIf="type && ((filesToSelectFrom && filesToSelectFrom.length > 0) || (type === 'audio' && audiosToSelectFrom && audiosToSelectFrom.length > 0) || (type === 'video' && videosToSelectFrom && videosToSelectFrom.length > 0))" color="accent">
|
|
||||||
<mat-label *ngIf="type === 'audio'"><ng-container i18n="Audio files title">Audio files</ng-container></mat-label>
|
|
||||||
<mat-label *ngIf="type === 'video'"><ng-container i18n="Videos title">Videos</ng-container></mat-label>
|
|
||||||
<mat-select [formControl]="filesSelect" multiple required aria-required>
|
|
||||||
<ng-container *ngIf="filesToSelectFrom"><mat-option *ngFor="let file of filesToSelectFrom" [value]="file.uid">{{file.id}}</mat-option></ng-container>
|
|
||||||
<ng-container *ngIf="audiosToSelectFrom && type === 'audio'"><mat-option *ngFor="let file of audiosToSelectFrom" [value]="file.uid">{{file.id}}</mat-option></ng-container>
|
|
||||||
<ng-container *ngIf="videosToSelectFrom && type === 'video'"><mat-option *ngFor="let file of videosToSelectFrom" [value]="file.uid">{{file.id}}</mat-option></ng-container>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<!-- No videos available -->
|
|
||||||
<div style="margin-bottom: 15px;" *ngIf="type && ((filesToSelectFrom && filesToSelectFrom.length === 0) || (type === 'audio' && audiosToSelectFrom && audiosToSelectFrom.length === 0) || (type === 'video' && videosToSelectFrom && videosToSelectFrom.length === 0))">
|
|
||||||
No files available.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|||||||
@@ -17,42 +17,20 @@ export class CreatePlaylistComponent implements OnInit {
|
|||||||
audiosToSelectFrom = null;
|
audiosToSelectFrom = null;
|
||||||
videosToSelectFrom = null;
|
videosToSelectFrom = null;
|
||||||
name = '';
|
name = '';
|
||||||
|
cached_thumbnail_url = null;
|
||||||
|
|
||||||
create_in_progress = false;
|
create_in_progress = false;
|
||||||
|
|
||||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any,
|
constructor(private postsService: PostsService,
|
||||||
private postsService: PostsService,
|
|
||||||
public dialogRef: MatDialogRef<CreatePlaylistComponent>) { }
|
public dialogRef: MatDialogRef<CreatePlaylistComponent>) { }
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit(): void {}
|
||||||
if (this.data) {
|
|
||||||
this.filesToSelectFrom = this.data.filesToSelectFrom;
|
|
||||||
this.type = this.data.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.filesToSelectFrom) {
|
createPlaylist(): void {
|
||||||
this.getMp3s();
|
|
||||||
this.getMp4s();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getMp3s() {
|
|
||||||
this.postsService.getMp3s().subscribe(result => {
|
|
||||||
this.audiosToSelectFrom = result['mp3s'];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getMp4s() {
|
|
||||||
this.postsService.getMp4s().subscribe(result => {
|
|
||||||
this.videosToSelectFrom = result['mp4s'];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
createPlaylist() {
|
|
||||||
const thumbnailURL = this.getThumbnailURL();
|
const thumbnailURL = this.getThumbnailURL();
|
||||||
this.create_in_progress = true;
|
this.create_in_progress = true;
|
||||||
this.postsService.createPlaylist(this.name, this.filesSelect.value, this.type, thumbnailURL).subscribe(res => {
|
this.postsService.createPlaylist(this.name, this.filesSelect.value, thumbnailURL).subscribe(res => {
|
||||||
this.create_in_progress = false;
|
this.create_in_progress = false;
|
||||||
if (res['success']) {
|
if (res['success']) {
|
||||||
this.dialogRef.close(true);
|
this.dialogRef.close(true);
|
||||||
@@ -62,19 +40,13 @@ export class CreatePlaylistComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getThumbnailURL() {
|
getThumbnailURL(): string {
|
||||||
let properFilesToSelectFrom = this.filesToSelectFrom;
|
return this.cached_thumbnail_url;
|
||||||
if (!this.filesToSelectFrom) {
|
}
|
||||||
properFilesToSelectFrom = this.type === 'audio' ? this.audiosToSelectFrom : this.videosToSelectFrom;
|
|
||||||
}
|
fileSelectionChanged({new_selection, thumbnailURL}: {new_selection: string[], thumbnailURL: string}): void {
|
||||||
for (let i = 0; i < properFilesToSelectFrom.length; i++) {
|
this.filesSelect.setValue(new_selection);
|
||||||
const file = properFilesToSelectFrom[i];
|
if (new_selection.length) this.cached_thumbnail_url = thumbnailURL;
|
||||||
if (file.id === this.filesSelect.value[0]) {
|
else this.cached_thumbnail_url = null;
|
||||||
// different services store the thumbnail in different places
|
|
||||||
if (file.thumbnailURL) { return file.thumbnailURL };
|
|
||||||
if (file.thumbnail) { return file.thumbnail };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,15 +35,9 @@ export class ModifyPlaylistComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getFiles() {
|
getFiles() {
|
||||||
if (this.playlist.type === 'audio') {
|
this.postsService.getAllFiles().subscribe(res => {
|
||||||
this.postsService.getMp3s().subscribe(res => {
|
this.processFiles(res['files']);
|
||||||
this.processFiles(res['mp3s']);
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.postsService.getMp4s().subscribe(res => {
|
|
||||||
this.processFiles(res['mp4s']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
processFiles(new_files = null) {
|
processFiles(new_files = null) {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<br/>
|
<br/>
|
||||||
<mat-checkbox [disabled]="current_download" (change)="videoModeChanged($event)" [(ngModel)]="audioOnly" style="float: left; margin-top: -12px">
|
<mat-checkbox [disabled]="autoplay && current_download" (change)="videoModeChanged($event)" [(ngModel)]="audioOnly" style="float: left; margin-top: -12px">
|
||||||
<ng-container i18n="Only Audio checkbox">
|
<ng-container i18n="Only Audio checkbox">
|
||||||
Only Audio
|
Only Audio
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -10,12 +10,7 @@ import { Router, ActivatedRoute } from '@angular/router';
|
|||||||
import { Platform } from '@angular/cdk/platform';
|
import { Platform } from '@angular/cdk/platform';
|
||||||
import { ArgModifierDialogComponent } from 'app/dialogs/arg-modifier-dialog/arg-modifier-dialog.component';
|
import { ArgModifierDialogComponent } from 'app/dialogs/arg-modifier-dialog/arg-modifier-dialog.component';
|
||||||
import { RecentVideosComponent } from 'app/components/recent-videos/recent-videos.component';
|
import { RecentVideosComponent } from 'app/components/recent-videos/recent-videos.component';
|
||||||
import { Download, FileType } from 'api-types';
|
import { DatabaseFile, Download, FileType, Playlist } from 'api-types';
|
||||||
|
|
||||||
export let audioFilesMouseHovering = false;
|
|
||||||
export let videoFilesMouseHovering = false;
|
|
||||||
export let audioFilesOpened = false;
|
|
||||||
export let videoFilesOpened = false;
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@@ -78,7 +73,6 @@ export class MainComponent implements OnInit {
|
|||||||
mp4s: any[] = [];
|
mp4s: any[] = [];
|
||||||
playlists = {'audio': [], 'video': []};
|
playlists = {'audio': [], 'video': []};
|
||||||
playlist_thumbnails = {};
|
playlist_thumbnails = {};
|
||||||
downloading_content = {'audio': {}, 'video': {}};
|
|
||||||
downloads: Download[] = [];
|
downloads: Download[] = [];
|
||||||
download_uids: string[] = [];
|
download_uids: string[] = [];
|
||||||
current_download: Download = null;
|
current_download: Download = null;
|
||||||
@@ -466,11 +460,9 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadFileFromServer(file, type: string): void {
|
downloadFileFromServer(file: DatabaseFile, type: string): void {
|
||||||
const ext = type === 'audio' ? 'mp3' : 'mp4'
|
const ext = type === 'audio' ? 'mp3' : 'mp4'
|
||||||
this.downloading_content[type][file.id] = true;
|
|
||||||
this.postsService.downloadFileFromServer(file.uid).subscribe(res => {
|
this.postsService.downloadFileFromServer(file.uid).subscribe(res => {
|
||||||
this.downloading_content[type][file.id] = false;
|
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, decodeURIComponent(file.id) + `.${ext}`);
|
saveAs(blob, decodeURIComponent(file.id) + `.${ext}`);
|
||||||
|
|
||||||
@@ -481,9 +473,8 @@ export class MainComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadPlaylist(playlist): void {
|
downloadPlaylist(playlist: Playlist): void {
|
||||||
this.postsService.downloadPlaylistFromServer(playlist.id).subscribe(res => {
|
this.postsService.downloadPlaylistFromServer(playlist.id).subscribe(res => {
|
||||||
if (playlist.id) { this.downloading_content[playlist.type][playlist.id] = false };
|
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, playlist.name + '.zip');
|
saveAs(blob, playlist.name + '.zip');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.post<GetFileResponse>(this.path + 'getFile', body, this.httpOptions);
|
return this.http.post<GetFileResponse>(this.path + 'getFile', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllFiles(sort: Sort, range: number[], text_search: string, file_type_filter: FileTypeFilter, sub_id: string) {
|
getAllFiles(sort: Sort = null, range: number[] = null, text_search: string = null, file_type_filter: FileTypeFilter = FileTypeFilter.BOTH, sub_id: string = null) {
|
||||||
const body: GetAllFilesRequest = {sort: sort, range: range, text_search: text_search, file_type_filter: file_type_filter, sub_id: sub_id};
|
const body: GetAllFilesRequest = {sort: sort, range: range, text_search: text_search, file_type_filter: file_type_filter, sub_id: sub_id};
|
||||||
return this.http.post<GetAllFilesResponse>(this.path + 'getAllFiles', body, this.httpOptions);
|
return this.http.post<GetAllFilesResponse>(this.path + 'getAllFiles', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
@@ -447,10 +447,9 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.post<SuccessObject>(this.path + 'disableSharing', body, this.httpOptions);
|
return this.http.post<SuccessObject>(this.path + 'disableSharing', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
createPlaylist(playlistName: string, uids: string[], type: FileType, thumbnailURL: string) {
|
createPlaylist(playlistName: string, uids: string[], thumbnailURL: string) {
|
||||||
const body: CreatePlaylistRequest = {playlistName: playlistName,
|
const body: CreatePlaylistRequest = {playlistName: playlistName,
|
||||||
uids: uids,
|
uids: uids,
|
||||||
type: type,
|
|
||||||
thumbnailURL: thumbnailURL};
|
thumbnailURL: thumbnailURL};
|
||||||
return this.http.post<CreatePlaylistResponse>(this.path + 'createPlaylist', body, this.httpOptions);
|
return this.http.post<CreatePlaylistResponse>(this.path + 'createPlaylist', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
@@ -475,8 +474,8 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.post<SuccessObject>(this.path + 'updatePlaylist', body, this.httpOptions);
|
return this.http.post<SuccessObject>(this.path + 'updatePlaylist', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
removePlaylist(playlist_id: string, type: FileType) {
|
removePlaylist(playlist_id: string) {
|
||||||
const body: DeletePlaylistRequest = {playlist_id: playlist_id, type: type};
|
const body: DeletePlaylistRequest = {playlist_id: playlist_id};
|
||||||
return this.http.post<SuccessObject>(this.path + 'deletePlaylist', body, this.httpOptions);
|
return this.http.post<SuccessObject>(this.path + 'deletePlaylist', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -590,7 +590,7 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
||||||
<context context-type="linenumber">24</context>
|
<context context-type="linenumber">25</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">search field description</note>
|
<note priority="1" from="description">search field description</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -690,7 +690,7 @@
|
|||||||
<source>No files found.</source>
|
<source>No files found.</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
||||||
<context context-type="linenumber">38</context>
|
<context context-type="linenumber">39</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">No files found</note>
|
<note priority="1" from="description">No files found</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -698,7 +698,7 @@
|
|||||||
<source>File type</source>
|
<source>File type</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
||||||
<context context-type="linenumber">52</context>
|
<context context-type="linenumber">78</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">File type</note>
|
<note priority="1" from="description">File type</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -706,7 +706,7 @@
|
|||||||
<source>Both</source>
|
<source>Both</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
||||||
<context context-type="linenumber">54</context>
|
<context context-type="linenumber">80</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">Both</note>
|
<note priority="1" from="description">Both</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -714,7 +714,7 @@
|
|||||||
<source>Video only</source>
|
<source>Video only</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
||||||
<context context-type="linenumber">55</context>
|
<context context-type="linenumber">81</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">Video only</note>
|
<note priority="1" from="description">Video only</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -722,7 +722,7 @@
|
|||||||
<source>Audio only</source>
|
<source>Audio only</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
<context context-type="sourcefile">src/app/components/recent-videos/recent-videos.component.html</context>
|
||||||
<context context-type="linenumber">56</context>
|
<context context-type="linenumber">82</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">Audio only</note>
|
<note priority="1" from="description">Audio only</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -991,10 +991,6 @@
|
|||||||
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
||||||
<context context-type="linenumber">24</context>
|
<context context-type="linenumber">24</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/subscription/subscription-file-card/subscription-file-card.component.html</context>
|
|
||||||
<context context-type="linenumber">7</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Video info button</note>
|
<note priority="1" from="description">Video info button</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="a0720c36ee1057e5c54a86591b722485c62d7b1a" datatype="html">
|
<trans-unit id="a0720c36ee1057e5c54a86591b722485c62d7b1a" datatype="html">
|
||||||
@@ -1019,10 +1015,6 @@
|
|||||||
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
||||||
<context context-type="linenumber">34</context>
|
<context context-type="linenumber">34</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/subscription/subscription-file-card/subscription-file-card.component.html</context>
|
|
||||||
<context context-type="linenumber">8</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Delete and redownload subscription video button</note>
|
<note priority="1" from="description">Delete and redownload subscription video button</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2031adb51e07a41844e8ba7704b054e98345c9c1" datatype="html">
|
<trans-unit id="2031adb51e07a41844e8ba7704b054e98345c9c1" datatype="html">
|
||||||
@@ -1031,10 +1023,6 @@
|
|||||||
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
<context context-type="sourcefile">src/app/components/unified-file-card/unified-file-card.component.html</context>
|
||||||
<context context-type="linenumber">37</context>
|
<context context-type="linenumber">37</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/subscription/subscription-file-card/subscription-file-card.component.html</context>
|
|
||||||
<context context-type="linenumber">9</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Delete forever subscription video button</note>
|
<note priority="1" from="description">Delete forever subscription video button</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="826b25211922a1b46436589233cb6f1a163d89b7" datatype="html">
|
<trans-unit id="826b25211922a1b46436589233cb6f1a163d89b7" datatype="html">
|
||||||
@@ -1093,46 +1081,6 @@
|
|||||||
</context-group>
|
</context-group>
|
||||||
<note priority="1" from="description">Playlist name placeholder</note>
|
<note priority="1" from="description">Playlist name placeholder</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="f61c6867295f3b53d23557021f2f4e0aa1d0b8fc" datatype="html">
|
|
||||||
<source>Type</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/create-playlist/create-playlist.component.html</context>
|
|
||||||
<context context-type="linenumber">11</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Type select</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="f0baeb8b69d120073b6d60d34785889b0c3232c8" datatype="html">
|
|
||||||
<source>Audio</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/create-playlist/create-playlist.component.html</context>
|
|
||||||
<context context-type="linenumber">12</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Audio</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="2d1ea268a6a9f483dbc2cbfe19bf4256a57a6af4" datatype="html">
|
|
||||||
<source>Video</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/create-playlist/create-playlist.component.html</context>
|
|
||||||
<context context-type="linenumber">13</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Video</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="f47e2d56dd8a145b2e9599da9730c049d52962a2" datatype="html">
|
|
||||||
<source>Audio files</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/create-playlist/create-playlist.component.html</context>
|
|
||||||
<context context-type="linenumber">19</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Audio files title</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="a52dae09be10ca3a65da918533ced3d3f4992238" datatype="html">
|
|
||||||
<source>Videos</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/create-playlist/create-playlist.component.html</context>
|
|
||||||
<context context-type="linenumber">20</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Videos title</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="cec82c0a545f37420d55a9b6c45c20546e82f94e" datatype="html">
|
<trans-unit id="cec82c0a545f37420d55a9b6c45c20546e82f94e" datatype="html">
|
||||||
<source>About YoutubeDL-Material</source>
|
<source>About YoutubeDL-Material</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
@@ -2108,7 +2056,7 @@
|
|||||||
<source>Download for <x id="url" equiv-text="url"/> has been queued!</source>
|
<source>Download for <x id="url" equiv-text="url"/> has been queued!</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">src/app/main/main.component.ts</context>
|
<context context-type="sourcefile">src/app/main/main.component.ts</context>
|
||||||
<context context-type="linenumber">403</context>
|
<context context-type="linenumber">397</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="dad95154dcef3509b8cc705046061fd24994bbb7" datatype="html">
|
<trans-unit id="dad95154dcef3509b8cc705046061fd24994bbb7" datatype="html">
|
||||||
@@ -2906,14 +2854,6 @@
|
|||||||
<context context-type="linenumber">48</context>
|
<context context-type="linenumber">48</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2054791b822475aeaea95c0119113de3200f5e1c" datatype="html">
|
|
||||||
<source>Length:</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">src/app/subscription/subscription-file-card/subscription-file-card.component.html</context>
|
|
||||||
<context context-type="linenumber">3</context>
|
|
||||||
</context-group>
|
|
||||||
<note priority="1" from="description">Video duration label</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="e2319dec5b4ccfb6ed9f55ccabd63650a8fdf547" datatype="html">
|
<trans-unit id="e2319dec5b4ccfb6ed9f55ccabd63650a8fdf547" datatype="html">
|
||||||
<source>Your subscriptions</source>
|
<source>Your subscriptions</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
|
|||||||
Reference in New Issue
Block a user