mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-23 00:53:20 +03:00
Created unified file card component, recent videos component (not done) and started scaffolding work on the backend
This commit is contained in:
@@ -2046,6 +2046,24 @@ app.post('/api/getFile', optionalJwt, function (req, res) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post('/api/getAllFiles', optionalJwt, function (req, res) {
|
||||||
|
files = null;
|
||||||
|
playlists = null;
|
||||||
|
if (req.isAuthenticated()) {
|
||||||
|
const videos = auth_api.getUserVideos(req.user.uid, 'video');
|
||||||
|
const audios = auth_api.getUserVideos(req.user.uid, 'audio');
|
||||||
|
const audio_playlists = null;
|
||||||
|
const video_playlists = null;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send({
|
||||||
|
files: files,
|
||||||
|
playlists: playlists
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
// video sharing
|
// video sharing
|
||||||
app.post('/api/enableSharing', optionalJwt, function(req, res) {
|
app.post('/api/enableSharing', optionalJwt, function(req, res) {
|
||||||
var type = req.body.type;
|
var type = req.body.type;
|
||||||
|
|||||||
@@ -44,6 +44,10 @@
|
|||||||
<a *ngIf="postsService.config && postsService.config.Advanced.multi_user_mode && !postsService.isLoggedIn" mat-list-item (click)="sidenav.close()" routerLink='/login'><ng-container i18n="Navigation menu Login Page title">Login</ng-container></a>
|
<a *ngIf="postsService.config && postsService.config.Advanced.multi_user_mode && !postsService.isLoggedIn" mat-list-item (click)="sidenav.close()" routerLink='/login'><ng-container i18n="Navigation menu Login Page title">Login</ng-container></a>
|
||||||
<a *ngIf="postsService.config && allowSubscriptions && (!postsService.config.Advanced.multi_user_mode || (postsService.isLoggedIn && postsService.permissions.includes('subscriptions')))" mat-list-item (click)="sidenav.close()" routerLink='/subscriptions'><ng-container i18n="Navigation menu Subscriptions Page title">Subscriptions</ng-container></a>
|
<a *ngIf="postsService.config && allowSubscriptions && (!postsService.config.Advanced.multi_user_mode || (postsService.isLoggedIn && postsService.permissions.includes('subscriptions')))" mat-list-item (click)="sidenav.close()" routerLink='/subscriptions'><ng-container i18n="Navigation menu Subscriptions Page title">Subscriptions</ng-container></a>
|
||||||
<a *ngIf="postsService.config && enableDownloadsManager && (!postsService.config.Advanced.multi_user_mode || (postsService.isLoggedIn && postsService.permissions.includes('downloads_manager')))" mat-list-item (click)="sidenav.close()" routerLink='/downloads'><ng-container i18n="Navigation menu Downloads Page title">Downloads</ng-container></a>
|
<a *ngIf="postsService.config && enableDownloadsManager && (!postsService.config.Advanced.multi_user_mode || (postsService.isLoggedIn && postsService.permissions.includes('downloads_manager')))" mat-list-item (click)="sidenav.close()" routerLink='/downloads'><ng-container i18n="Navigation menu Downloads Page title">Downloads</ng-container></a>
|
||||||
|
<ng-container *ngIf="postsService.config && allowSubscriptions && subscriptions && (!postsService.config.Advanced.multi_user_mode || (postsService.isLoggedIn && postsService.permissions.includes('subscriptions')))">
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<a *ngFor="let subscription of subscriptions" mat-list-item (click)="sidenav.close()" [routerLink]="['/subscription', { id: subscription.id }]"><ngx-avatar [style.margin-right]="'10px'" size="32" [name]="subscription.name"></ngx-avatar><ng-container i18n="Navigation menu Downloads Page title">{{subscription.name}}</ng-container></a>
|
||||||
|
</ng-container>
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</mat-sidenav>
|
</mat-sidenav>
|
||||||
<mat-sidenav-content [style.background]="postsService.theme ? postsService.theme.background_color : null">
|
<mat-sidenav-content [style.background]="postsService.theme ? postsService.theme.background_color : null">
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ export class AppComponent implements OnInit {
|
|||||||
@ViewChild('hamburgerMenu', { read: ElementRef }) hamburgerMenuButton: ElementRef;
|
@ViewChild('hamburgerMenu', { read: ElementRef }) hamburgerMenuButton: ElementRef;
|
||||||
navigator: string = null;
|
navigator: string = null;
|
||||||
|
|
||||||
|
subscriptions = null;
|
||||||
|
|
||||||
constructor(public postsService: PostsService, public snackBar: MatSnackBar, private dialog: MatDialog,
|
constructor(public postsService: PostsService, public snackBar: MatSnackBar, private dialog: MatDialog,
|
||||||
public router: Router, public overlayContainer: OverlayContainer, private elementRef: ElementRef) {
|
public router: Router, public overlayContainer: OverlayContainer, private elementRef: ElementRef) {
|
||||||
|
|
||||||
@@ -86,6 +88,13 @@ export class AppComponent implements OnInit {
|
|||||||
if (!localStorage.getItem('theme')) {
|
if (!localStorage.getItem('theme')) {
|
||||||
this.setTheme(themingExists ? this.defaultTheme : 'default');
|
this.setTheme(themingExists ? this.defaultTheme : 'default');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gets the subscriptions
|
||||||
|
if (this.allowSubscriptions) {
|
||||||
|
this.postsService.getAllSubscriptions().subscribe(res => {
|
||||||
|
this.subscriptions = res['subscriptions'];
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// theme stuff
|
// theme stuff
|
||||||
@@ -162,6 +171,11 @@ onSetTheme(theme, old_theme) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getSubscriptions() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
goBack() {
|
goBack() {
|
||||||
if (!this.navigator) {
|
if (!this.navigator) {
|
||||||
this.router.navigate(['/home']);
|
this.router.navigate(['/home']);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import { SubscriptionInfoDialogComponent } from './dialogs/subscription-info-dia
|
|||||||
import { SettingsComponent } from './settings/settings.component';
|
import { SettingsComponent } from './settings/settings.component';
|
||||||
import { MatChipsModule } from '@angular/material/chips';
|
import { MatChipsModule } from '@angular/material/chips';
|
||||||
import { NgxFileDropModule } from 'ngx-file-drop';
|
import { NgxFileDropModule } from 'ngx-file-drop';
|
||||||
|
import { AvatarModule } from 'ngx-avatar';
|
||||||
|
|
||||||
import es from '@angular/common/locales/es';
|
import es from '@angular/common/locales/es';
|
||||||
import { AboutDialogComponent } from './dialogs/about-dialog/about-dialog.component';
|
import { AboutDialogComponent } from './dialogs/about-dialog/about-dialog.component';
|
||||||
@@ -73,6 +74,8 @@ import { CookiesUploaderDialogComponent } from './dialogs/cookies-uploader-dialo
|
|||||||
import { LogsViewerComponent } from './components/logs-viewer/logs-viewer.component';
|
import { LogsViewerComponent } from './components/logs-viewer/logs-viewer.component';
|
||||||
import { ModifyPlaylistComponent } from './dialogs/modify-playlist/modify-playlist.component';
|
import { ModifyPlaylistComponent } from './dialogs/modify-playlist/modify-playlist.component';
|
||||||
import { ConfirmDialogComponent } from './dialogs/confirm-dialog/confirm-dialog.component';
|
import { ConfirmDialogComponent } from './dialogs/confirm-dialog/confirm-dialog.component';
|
||||||
|
import { UnifiedFileCardComponent } from './components/unified-file-card/unified-file-card.component';
|
||||||
|
import { RecentVideosComponent } from './components/recent-videos/recent-videos.component';
|
||||||
|
|
||||||
registerLocaleData(es, 'es');
|
registerLocaleData(es, 'es');
|
||||||
|
|
||||||
@@ -113,7 +116,9 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
|||||||
CookiesUploaderDialogComponent,
|
CookiesUploaderDialogComponent,
|
||||||
LogsViewerComponent,
|
LogsViewerComponent,
|
||||||
ModifyPlaylistComponent,
|
ModifyPlaylistComponent,
|
||||||
ConfirmDialogComponent
|
ConfirmDialogComponent,
|
||||||
|
UnifiedFileCardComponent,
|
||||||
|
RecentVideosComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -154,6 +159,7 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
|||||||
DragDropModule,
|
DragDropModule,
|
||||||
ClipboardModule,
|
ClipboardModule,
|
||||||
NgxFileDropModule,
|
NgxFileDropModule,
|
||||||
|
AvatarModule,
|
||||||
VgCoreModule,
|
VgCoreModule,
|
||||||
VgControlsModule,
|
VgControlsModule,
|
||||||
VgOverlayPlayModule,
|
VgOverlayPlayModule,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div *ngFor="let file of files" class="col-6 col-lg-4 mb-2 mt-2 file-col">
|
||||||
|
<app-unified-file-card [file_obj]="file"></app-unified-file-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.file-col {
|
||||||
|
max-width: 240px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RecentVideosComponent } from './recent-videos.component';
|
||||||
|
|
||||||
|
describe('RecentVideosComponent', () => {
|
||||||
|
let component: RecentVideosComponent;
|
||||||
|
let fixture: ComponentFixture<RecentVideosComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ RecentVideosComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(RecentVideosComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
29
src/app/components/recent-videos/recent-videos.component.ts
Normal file
29
src/app/components/recent-videos/recent-videos.component.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { PostsService } from 'app/posts.services';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-recent-videos',
|
||||||
|
templateUrl: './recent-videos.component.html',
|
||||||
|
styleUrls: ['./recent-videos.component.scss']
|
||||||
|
})
|
||||||
|
export class RecentVideosComponent implements OnInit {
|
||||||
|
|
||||||
|
normal_files_received = false;
|
||||||
|
subscription_files_received = false;
|
||||||
|
files: any[] = null;
|
||||||
|
|
||||||
|
constructor(private postsService: PostsService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllFiles() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sortFiles(a, b) {
|
||||||
|
// uses the 'registered' flag as the timestamp
|
||||||
|
const result = b.registered - a.registered;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<div style="position: relative; width: fit-content;">
|
||||||
|
<div class="duration-time">
|
||||||
|
<ng-container i18n="Video duration label">Length:</ng-container> {{file_length}}
|
||||||
|
</div>
|
||||||
|
<button [matMenuTriggerFor]="action_menu" class="menuButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
||||||
|
<mat-menu #action_menu="matMenu">
|
||||||
|
<button (click)="openFileInfoDialog()" mat-menu-item><mat-icon>info</mat-icon><ng-container i18n="Video info button">Info</ng-container></button>
|
||||||
|
<button (click)="deleteFile()" mat-menu-item>
|
||||||
|
<mat-icon>restore</mat-icon><ng-container i18n="Delete and redownload subscription video button">Delete and redownload</ng-container>
|
||||||
|
</button>
|
||||||
|
<button (click)="deleteFile(true)" mat-menu-item *ngIf="use_youtubedl_archive">
|
||||||
|
<mat-icon>delete_forever</mat-icon><ng-container i18n="Delete forever subscription video button">Delete forever</ng-container>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
<mat-card (click)="navigateToFile()" matRipple class="example-card mat-elevation-z6">
|
||||||
|
<div style="padding:5px">
|
||||||
|
<div *ngIf="fileThumbnail" class="img-div">
|
||||||
|
<img class="image" [src]="file_thumbnail" alt="Thumbnail">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="max-two-lines"><strong>{{file_title}}</strong></span>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
.example-card {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
padding: 0px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuButton {
|
||||||
|
right: 0px;
|
||||||
|
top: -1px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Coerce the <span> icon container away from display:inline */
|
||||||
|
.mat-icon-button .mat-button-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: 200px;
|
||||||
|
height: 112.5px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-full-width-height {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered {
|
||||||
|
margin: 0 auto;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-div {
|
||||||
|
max-height: 80px;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 32px 0px 0px -5px;
|
||||||
|
width: calc(100% + 5px + 5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-two-lines {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -moz-box;
|
||||||
|
max-height: 2.4em;
|
||||||
|
line-height: 1.2em;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
bottom: 5px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.duration-time {
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
top: 5px;
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 576px){
|
||||||
|
|
||||||
|
.example-card {
|
||||||
|
width: 175px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: 175px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UnifiedFileCardComponent } from './unified-file-card.component';
|
||||||
|
|
||||||
|
describe('UnifiedFileCardComponent', () => {
|
||||||
|
let component: UnifiedFileCardComponent;
|
||||||
|
let fixture: ComponentFixture<UnifiedFileCardComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ UnifiedFileCardComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(UnifiedFileCardComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-unified-file-card',
|
||||||
|
templateUrl: './unified-file-card.component.html',
|
||||||
|
styleUrls: ['./unified-file-card.component.scss']
|
||||||
|
})
|
||||||
|
export class UnifiedFileCardComponent implements OnInit {
|
||||||
|
|
||||||
|
// required info
|
||||||
|
file_title = '';
|
||||||
|
file_length = '';
|
||||||
|
file_thumbnail = '';
|
||||||
|
type = null;
|
||||||
|
use_youtubedl_archive = false;
|
||||||
|
|
||||||
|
isSubscriptionFile: boolean = null;
|
||||||
|
|
||||||
|
@Input() file_obj = null;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.file_length = fancyTimeFormat(this.file_obj.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteFile(blacklistMode = false) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToFile() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
openFileInfoDialog() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function fancyTimeFormat(time) {
|
||||||
|
// Hours, minutes and seconds
|
||||||
|
const hrs = ~~(time / 3600);
|
||||||
|
const mins = ~~((time % 3600) / 60);
|
||||||
|
const secs = ~~time % 60;
|
||||||
|
|
||||||
|
// Output like "1:01" or "4:03:59" or "123:03:59"
|
||||||
|
let ret = '';
|
||||||
|
|
||||||
|
if (hrs > 0) {
|
||||||
|
ret += '' + hrs + ':' + (mins < 10 ? '0' : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += '' + mins + ':' + (secs < 10 ? '0' : '');
|
||||||
|
ret += '' + secs;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { PostsService } from 'app/posts.services';
|
import { PostsService } from 'app/posts.services';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router, ParamMap } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-subscription',
|
selector: 'app-subscription',
|
||||||
@@ -43,9 +43,26 @@ export class SubscriptionComponent implements OnInit {
|
|||||||
filterProperty = this.filterProperties['upload_date'];
|
filterProperty = this.filterProperties['upload_date'];
|
||||||
downloading = false;
|
downloading = false;
|
||||||
|
|
||||||
|
initialized = false;
|
||||||
|
|
||||||
constructor(private postsService: PostsService, private route: ActivatedRoute, private router: Router) { }
|
constructor(private postsService: PostsService, private route: ActivatedRoute, private router: Router) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.route.paramMap.subscribe((params: ParamMap) => {
|
||||||
|
this.id = params.get('id');
|
||||||
|
this.postsService.service_initialized.subscribe(init => {
|
||||||
|
if (init) {
|
||||||
|
this.initialized = true;
|
||||||
|
this.getConfig();
|
||||||
|
this.getSubscription();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.initialized) {
|
||||||
|
this.getConfig();
|
||||||
|
this.getSubscription();
|
||||||
|
}
|
||||||
|
});
|
||||||
if (this.route.snapshot.paramMap.get('id')) {
|
if (this.route.snapshot.paramMap.get('id')) {
|
||||||
this.id = this.route.snapshot.paramMap.get('id');
|
this.id = this.route.snapshot.paramMap.get('id');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user