Merge branch 'master' of https://github.com/Tzahi12345/YoutubeDL-Material into updated-player

This commit is contained in:
Isaac Abadi
2020-12-14 18:20:33 -05:00
55 changed files with 5891 additions and 7550 deletions

View File

@@ -6,7 +6,7 @@
[![GitHub issues badge](https://img.shields.io/github/issues/Tzahi12345/YoutubeDL-Material)](https://github.com/Tzahi12345/YoutubeDL-Material/issues) [![GitHub issues badge](https://img.shields.io/github/issues/Tzahi12345/YoutubeDL-Material)](https://github.com/Tzahi12345/YoutubeDL-Material/issues)
[![License badge](https://img.shields.io/github/license/Tzahi12345/YoutubeDL-Material)](https://github.com/Tzahi12345/YoutubeDL-Material/blob/master/LICENSE.md) [![License badge](https://img.shields.io/github/license/Tzahi12345/YoutubeDL-Material)](https://github.com/Tzahi12345/YoutubeDL-Material/blob/master/LICENSE.md)
YoutubeDL-Material is a Material Design frontend for [youtube-dl](https://rg3.github.io/youtube-dl/). It's coded using [Angular 9](https://angular.io/) for the frontend, and [Node.js](https://nodejs.org/) on the backend. YoutubeDL-Material is a Material Design frontend for [youtube-dl](https://rg3.github.io/youtube-dl/). It's coded using [Angular 11](https://angular.io/) for the frontend, and [Node.js](https://nodejs.org/) on the backend.
Now with [Docker](#Docker) support! Now with [Docker](#Docker) support!

View File

@@ -45,8 +45,6 @@
], ],
"optimization": true, "optimization": true,
"outputHashing": "all", "outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false, "namedChunks": false,
"aot": true, "aot": true,
"extractLicenses": true, "extractLicenses": true,

View File

@@ -1252,7 +1252,7 @@ async function downloadFileByURL_exec(url, type, options, sessionID = null) {
&& config.getConfigItem('ytdl_use_twitch_api') && config.getConfigItem('ytdl_twitch_auto_download_chat')) { && config.getConfigItem('ytdl_use_twitch_api') && config.getConfigItem('ytdl_twitch_auto_download_chat')) {
let vodId = url.split('twitch.tv/videos/')[1]; let vodId = url.split('twitch.tv/videos/')[1];
vodId = vodId.split('?')[0]; vodId = vodId.split('?')[0];
downloadTwitchChatByVODID(vodId, file_name, type, options.user); twitch_api.downloadTwitchChatByVODID(vodId, file_name, type, options.user);
} }
// renames file if necessary due to bug // renames file if necessary due to bug
@@ -1828,42 +1828,6 @@ function removeFileExtension(filename) {
return filename_parts.join('.'); return filename_parts.join('.');
} }
async function getTwitchChatByFileID(id, type, user_uid, uuid) {
let file_path = null;
if (user_uid) {
file_path = path.join('users', user_uid, type, id + '.twitch_chat.json');
} else {
file_path = path.join(type, id + '.twitch_chat.json');
}
var chat_file = null;
if (fs.existsSync(file_path)) {
chat_file = fs.readJSONSync(file_path);
}
return chat_file;
}
async function downloadTwitchChatByVODID(vodId, id, type, user_uid) {
const twitch_api_key = config_api.getConfigItem('ytdl_twitch_api_key');
const chat = await twitch_api.getCommentsForVOD(twitch_api_key, vodId);
// save file if needec params are included
if (id && type) {
let file_path = null;
if (user_uid) {
file_path = path.join('users', user_uid, type, id + '.twitch_chat.json');
} else {
file_path = path.join(type, id + '.twitch_chat.json');
}
if (chat) fs.writeJSONSync(file_path, chat);
}
return chat;
}
app.use(function(req, res, next) { app.use(function(req, res, next) {
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
res.header("Access-Control-Allow-Origin", getOrigin()); res.header("Access-Control-Allow-Origin", getOrigin());
@@ -2088,7 +2052,7 @@ app.post('/api/getFile', optionalJwt, function (req, res) {
} }
// check if chat exists for twitch videos // check if chat exists for twitch videos
if (file['url'].includes('twitch.tv')) file['chat_exists'] = fs.existsSync(file['path'].substring(0, file['path'].length - 4) + '.twitch_chat.json'); if (file && file['url'].includes('twitch.tv')) file['chat_exists'] = fs.existsSync(file['path'].substring(0, file['path'].length - 4) + '.twitch_chat.json');
if (file) { if (file) {
res.send({ res.send({
@@ -2147,11 +2111,12 @@ app.post('/api/getFullTwitchChat', optionalJwt, async (req, res) => {
var id = req.body.id; var id = req.body.id;
var type = req.body.type; var type = req.body.type;
var uuid = req.body.uuid; var uuid = req.body.uuid;
var sub = req.body.sub;
var user_uid = null; var user_uid = null;
if (req.isAuthenticated()) user_uid = req.user.uid; if (req.isAuthenticated()) user_uid = req.user.uid;
const chat_file = await getTwitchChatByFileID(id, type, user_uid, uuid); const chat_file = await twitch_api.getTwitchChatByFileID(id, type, user_uid, uuid, sub);
res.send({ res.send({
chat: chat_file chat: chat_file
@@ -2163,28 +2128,19 @@ app.post('/api/downloadTwitchChatByVODID', optionalJwt, async (req, res) => {
var type = req.body.type; var type = req.body.type;
var vodId = req.body.vodId; var vodId = req.body.vodId;
var uuid = req.body.uuid; var uuid = req.body.uuid;
var sub = req.body.sub;
var user_uid = null; var user_uid = null;
if (req.isAuthenticated()) user_uid = req.user.uid; if (req.isAuthenticated()) user_uid = req.user.uid;
// check if file already exists. if so, send that instead // check if file already exists. if so, send that instead
const file_exists_check = await getTwitchChatByFileID(id, type, user_uid, uuid); const file_exists_check = await twitch_api.getTwitchChatByFileID(id, type, user_uid, uuid, sub);
if (file_exists_check) { if (file_exists_check) {
res.send({chat: file_exists_check}); res.send({chat: file_exists_check});
return; return;
} }
const full_chat = await downloadTwitchChatByVODID(vodId); const full_chat = await twitch_api.downloadTwitchChatByVODID(vodId, id, type, user_uid, sub);
let file_path = null;
if (user_uid) {
file_path = path.join('users', req.user.uid, type, id + '.twitch_chat.json');
} else {
file_path = path.join(type, id + '.twitch_chat.json');
}
if (full_chat) fs.writeJSONSync(file_path, full_chat);
res.send({ res.send({
chat: full_chat chat: full_chat
@@ -2472,9 +2428,15 @@ app.post('/api/getSubscription', optionalJwt, async (req, res) => {
var file_obj = new utils.File(id, title, thumbnail, isaudio, duration, url, uploader, size, file, upload_date); var file_obj = new utils.File(id, title, thumbnail, isaudio, duration, url, uploader, size, file, upload_date);
parsed_files.push(file_obj); parsed_files.push(file_obj);
} }
} else {
// loop through files for extra processing
for (let i = 0; i < parsed_files.length; i++) {
const file = parsed_files[i];
// check if chat exists for twitch videos
if (file && file['url'].includes('twitch.tv')) file['chat_exists'] = fs.existsSync(file['path'].substring(0, file['path'].length - 4) + '.twitch_chat.json');
}
} }
res.send({ res.send({
subscription: subscription, subscription: subscription,
files: parsed_files files: parsed_files

View File

@@ -6,7 +6,8 @@ var path = require('path');
var youtubedl = require('youtube-dl'); var youtubedl = require('youtube-dl');
const config_api = require('./config'); const config_api = require('./config');
var utils = require('./utils') const twitch_api = require('./twitch');
var utils = require('./utils');
const debugMode = process.env.YTDL_MODE === 'debug'; const debugMode = process.env.YTDL_MODE === 'debug';
@@ -418,6 +419,15 @@ function handleOutputJSON(sub, sub_db, output_json, multiUserMode = null, reset_
sub_db.get('videos').push(output_json).write(); sub_db.get('videos').push(output_json).write();
} else { } else {
db_api.registerFileDB(path.basename(output_json['_filename']), sub.type, multiUserMode, sub); db_api.registerFileDB(path.basename(output_json['_filename']), sub.type, multiUserMode, sub);
const url = output_json['webpage_url'];
if (sub.type === 'video' && url.includes('twitch.tv/videos/') && url.split('twitch.tv/videos/').length > 1
&& config_api.getConfigItem('ytdl_use_twitch_api') && config_api.getConfigItem('ytdl_twitch_auto_download_chat')) {
const file_name = path.basename(output_json['_filename']);
const id = file_name.substring(0, file_name.length-4);
let vodId = url.split('twitch.tv/videos/')[1];
vodId = vodId.split('?')[0];
twitch_api.downloadTwitchChatByVODID(vodId, id, sub.type, multiUserMode.user, sub);
}
} }
} }

View File

@@ -1,5 +1,8 @@
var moment = require('moment'); var moment = require('moment');
var Axios = require('axios'); var Axios = require('axios');
var fs = require('fs-extra')
var path = require('path');
const config_api = require('./config');
async function getCommentsForVOD(clientID, vodId) { async function getCommentsForVOD(clientID, vodId) {
let url = `https://api.twitch.tv/v5/videos/${vodId}/comments?content_offset_seconds=0`, let url = `https://api.twitch.tv/v5/videos/${vodId}/comments?content_offset_seconds=0`,
@@ -68,6 +71,58 @@ async function getCommentsForVOD(clientID, vodId) {
return comments; return comments;
} }
async function getTwitchChatByFileID(id, type, user_uid, uuid, sub) {
let file_path = null;
if (user_uid) {
if (sub) {
file_path = path.join('users', user_uid, 'subscriptions', sub.isPlaylist ? 'playlists' : 'channels', sub.name, id + '.twitch_chat.json');
} else {
file_path = path.join('users', user_uid, type, id + '.twitch_chat.json');
}
} else {
if (sub) {
file_path = path.join('subscriptions', sub.isPlaylist ? 'playlists' : 'channels', sub.name, id + '.twitch_chat.json');
} else {
file_path = path.join(type, id + '.twitch_chat.json');
}
}
var chat_file = null;
if (fs.existsSync(file_path)) {
chat_file = fs.readJSONSync(file_path);
}
return chat_file;
}
async function downloadTwitchChatByVODID(vodId, id, type, user_uid, sub) {
const twitch_api_key = config_api.getConfigItem('ytdl_twitch_api_key');
const chat = await getCommentsForVOD(twitch_api_key, vodId);
// save file if needed params are included
let file_path = null;
if (user_uid) {
if (sub) {
file_path = path.join('users', user_uid, 'subscriptions', sub.isPlaylist ? 'playlists' : 'channels', sub.name, id + '.twitch_chat.json');
} else {
file_path = path.join('users', user_uid, type, id + '.twitch_chat.json');
}
} else {
if (sub) {
file_path = path.join('subscriptions', sub.isPlaylist ? 'playlists' : 'channels', sub.name, id + '.twitch_chat.json');
} else {
file_path = path.join(type, id + '.twitch_chat.json');
}
}
if (chat) fs.writeJSONSync(file_path, chat);
return chat;
}
module.exports = { module.exports = {
getCommentsForVOD: getCommentsForVOD getCommentsForVOD: getCommentsForVOD,
getTwitchChatByFileID: getTwitchChatByFileID,
downloadTwitchChatByVODID: downloadTwitchChatByVODID
} }

13012
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -18,19 +18,20 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular-devkit/core": "^9.0.6", "@angular-devkit/core": "^11.0.4",
"@angular/animations": "^9.1.0", "@angular/animations": "^11.0.4",
"@angular/cdk": "^9.2.0", "@angular/cdk": "^11.0.2",
"@angular/common": "^9.1.0", "@angular/common": "^11.0.4",
"@angular/compiler": "^9.1.0", "@angular/compiler": "^11.0.4",
"@angular/core": "^9.0.7", "@angular/core": "^11.0.4",
"@angular/forms": "^9.1.0", "@angular/forms": "^11.0.4",
"@angular/localize": "^9.1.0", "@angular/localize": "^11.0.4",
"@angular/material": "^9.2.0", "@angular/material": "^11.0.2",
"@angular/platform-browser": "^9.1.0", "@angular/platform-browser": "^11.0.4",
"@angular/platform-browser-dynamic": "^9.1.0", "@angular/platform-browser-dynamic": "^11.0.4",
"@angular/router": "^9.1.0", "@angular/router": "^11.0.4",
"@ngneat/content-loader": "^5.0.0", "@ngneat/content-loader": "^5.0.0",
"@videogular/ngx-videogular": "^2.1.0",
"core-js": "^2.4.1", "core-js": "^2.4.1",
"file-saver": "^2.0.2", "file-saver": "^2.0.2",
"filesize": "^6.1.0", "filesize": "^6.1.0",
@@ -39,35 +40,34 @@
"ng-lazyload-image": "^7.0.1", "ng-lazyload-image": "^7.0.1",
"ngx-avatar": "^4.0.0", "ngx-avatar": "^4.0.0",
"ngx-file-drop": "^9.0.1", "ngx-file-drop": "^9.0.1",
"ngx-videogular": "^9.0.1", "rxjs": "^6.6.3",
"rxjs": "^6.5.3",
"rxjs-compat": "^6.0.0-rc.0", "rxjs-compat": "^6.0.0-rc.0",
"tslib": "^1.10.0", "tslib": "^2.0.0",
"typescript": "~3.7.5", "typescript": "~4.0.5",
"web-animations-js": "^2.3.2", "web-animations-js": "^2.3.2",
"zone.js": "~0.10.2" "zone.js": "~0.10.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.901.0", "@angular-devkit/build-angular": "^0.1100.4",
"@angular/cli": "^9.0.7", "@angular/cli": "^11.0.4",
"@angular/compiler-cli": "^9.0.7", "@angular/compiler-cli": "^11.0.4",
"@angular/language-service": "^9.0.7", "@angular/language-service": "^11.0.4",
"@types/core-js": "^2.5.2", "@types/core-js": "^2.5.2",
"@types/file-saver": "^2.0.1", "@types/file-saver": "^2.0.1",
"@types/jasmine": "2.5.45", "@types/jasmine": "~3.6.0",
"@types/node": "^12.11.1", "@types/node": "^12.11.1",
"codelyzer": "^5.1.2", "codelyzer": "^6.0.0",
"electron": "^8.0.1", "electron": "^8.0.1",
"jasmine-core": "~2.6.2", "jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~4.1.0", "jasmine-spec-reporter": "~5.0.0",
"karma": "~1.7.0", "karma": "~5.0.0",
"karma-chrome-launcher": "~2.1.1", "karma-chrome-launcher": "~3.1.0",
"karma-cli": "~1.0.1", "karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1", "karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~1.1.0", "karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^0.2.2", "karma-jasmine-html-reporter": "^1.5.0",
"protractor": "~5.1.2", "protractor": "~7.0.0",
"ts-node": "~3.0.4", "ts-node": "~3.0.4",
"tslint": "~5.3.2" "tslint": "~6.1.0"
} }
} }

View File

@@ -19,7 +19,7 @@ const routes: Routes = [
]; ];
@NgModule({ @NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })], imports: [RouterModule.forRoot(routes, { useHash: true, relativeLinkResolution: 'legacy' })],
exports: [RouterModule] exports: [RouterModule]
}) })
export class AppRoutingModule { } export class AppRoutingModule { }

View File

@@ -1,9 +1,9 @@
import { TestBed, async } from '@angular/core/testing'; import { TestBed, waitForAsync } from '@angular/core/testing';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
describe('AppComponent', () => { describe('AppComponent', () => {
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ declarations: [
AppComponent AppComponent
@@ -11,19 +11,19 @@ describe('AppComponent', () => {
}).compileComponents(); }).compileComponents();
})); }));
it('should create the app', async(() => { it('should create the app', waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance; const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy(); expect(app).toBeTruthy();
})); }));
it(`should have as title 'app'`, async(() => { it(`should have as title 'app'`, waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance; const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app'); expect(app.title).toEqual('app');
})); }));
it('should render title in a h1 tag', async(() => { it('should render title in a h1 tag', waitForAsync(() => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges(); fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement; const compiled = fixture.debugElement.nativeElement;

View File

@@ -39,7 +39,10 @@ import { RouterModule } from '@angular/router';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { MainComponent } from './main/main.component'; import { MainComponent } from './main/main.component';
import { PlayerComponent } from './player/player.component'; import { PlayerComponent } from './player/player.component';
import { VgCoreModule, VgControlsModule, VgOverlayPlayModule, VgBufferingModule } from 'ngx-videogular'; import { VgControlsModule } from '@videogular/ngx-videogular/controls';
import { VgBufferingModule } from '@videogular/ngx-videogular/buffering';
import { VgOverlayPlayModule } from '@videogular/ngx-videogular/overlay-play';
import { VgCoreModule } from '@videogular/ngx-videogular/core';
import { InputDialogComponent } from './input-dialog/input-dialog.component'; import { InputDialogComponent } from './input-dialog/input-dialog.component';
import { LazyLoadImageModule, IsVisibleProps } from 'ng-lazyload-image'; import { LazyLoadImageModule, IsVisibleProps } from 'ng-lazyload-image';
import { audioFilesMouseHovering, videoFilesMouseHovering, audioFilesOpened, videoFilesOpened } from './main/main.component'; import { audioFilesMouseHovering, videoFilesMouseHovering, audioFilesOpened, videoFilesOpened } from './main/main.component';

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { CustomPlaylistsComponent } from './custom-playlists.component'; import { CustomPlaylistsComponent } from './custom-playlists.component';
@@ -6,7 +6,7 @@ describe('CustomPlaylistsComponent', () => {
let component: CustomPlaylistsComponent; let component: CustomPlaylistsComponent;
let fixture: ComponentFixture<CustomPlaylistsComponent>; let fixture: ComponentFixture<CustomPlaylistsComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ CustomPlaylistsComponent ] declarations: [ CustomPlaylistsComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { DownloadsComponent } from './downloads.component'; import { DownloadsComponent } from './downloads.component';
@@ -6,7 +6,7 @@ describe('DownloadsComponent', () => {
let component: DownloadsComponent; let component: DownloadsComponent;
let fixture: ComponentFixture<DownloadsComponent>; let fixture: ComponentFixture<DownloadsComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ DownloadsComponent ] declarations: [ DownloadsComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { LoginComponent } from './login.component'; import { LoginComponent } from './login.component';
@@ -6,7 +6,7 @@ describe('LoginComponent', () => {
let component: LoginComponent; let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>; let fixture: ComponentFixture<LoginComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ LoginComponent ] declarations: [ LoginComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { LogsViewerComponent } from './logs-viewer.component'; import { LogsViewerComponent } from './logs-viewer.component';
@@ -6,7 +6,7 @@ describe('LogsViewerComponent', () => {
let component: LogsViewerComponent; let component: LogsViewerComponent;
let fixture: ComponentFixture<LogsViewerComponent>; let fixture: ComponentFixture<LogsViewerComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ LogsViewerComponent ] declarations: [ LogsViewerComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ManageRoleComponent } from './manage-role.component'; import { ManageRoleComponent } from './manage-role.component';
@@ -6,7 +6,7 @@ describe('ManageRoleComponent', () => {
let component: ManageRoleComponent; let component: ManageRoleComponent;
let fixture: ComponentFixture<ManageRoleComponent>; let fixture: ComponentFixture<ManageRoleComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ManageRoleComponent ] declarations: [ ManageRoleComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ManageUserComponent } from './manage-user.component'; import { ManageUserComponent } from './manage-user.component';
@@ -6,7 +6,7 @@ describe('ManageUserComponent', () => {
let component: ManageUserComponent; let component: ManageUserComponent;
let fixture: ComponentFixture<ManageUserComponent>; let fixture: ComponentFixture<ManageUserComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ManageUserComponent ] declarations: [ ManageUserComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ModifyUsersComponent } from './modify-users.component'; import { ModifyUsersComponent } from './modify-users.component';
@@ -6,7 +6,7 @@ describe('ModifyUsersComponent', () => {
let component: ModifyUsersComponent; let component: ModifyUsersComponent;
let fixture: ComponentFixture<ModifyUsersComponent>; let fixture: ComponentFixture<ModifyUsersComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ModifyUsersComponent ] declarations: [ ModifyUsersComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RecentVideosComponent } from './recent-videos.component'; import { RecentVideosComponent } from './recent-videos.component';
@@ -6,7 +6,7 @@ describe('RecentVideosComponent', () => {
let component: RecentVideosComponent; let component: RecentVideosComponent;
let fixture: ComponentFixture<RecentVideosComponent>; let fixture: ComponentFixture<RecentVideosComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ RecentVideosComponent ] declarations: [ RecentVideosComponent ]
}) })

View File

@@ -59,7 +59,8 @@ export class RecentVideosComponent implements OnInit {
constructor(public postsService: PostsService, private router: Router) { constructor(public postsService: PostsService, private router: Router) {
// get cached file count // get cached file count
if (localStorage.getItem('cached_file_count')) { if (localStorage.getItem('cached_file_count')) {
this.cached_file_count = +localStorage.getItem('cached_file_count'); this.cached_file_count = +localStorage.getItem('cached_file_count') <= 10 ? +localStorage.getItem('cached_file_count') : 10;
this.loading_files = Array(this.cached_file_count).fill(0); this.loading_files = Array(this.cached_file_count).fill(0);
} }
} }

View File

@@ -1,7 +1,8 @@
<div class="chat-container" #scrollContainer *ngIf="visible_chat"> <div class="chat-container" #scrollContainer *ngIf="visible_chat">
<div style="width: 250px; text-align: center;"><strong>Twitch Chat</strong></div> <div style="width: 250px; text-align: center;"><strong>Twitch Chat</strong></div>
<div style="max-width: 250px" *ngFor="let chat of visible_chat"> <div #chat style="max-width: 250px" *ngFor="let chat of visible_chat; let last = last">
{{chat.timestamp_str}} - <strong [style.color]="chat.user_color ? chat.user_color : null">{{chat.name}}</strong>: {{chat.message}} {{chat.timestamp_str}} - <strong [style.color]="chat.user_color ? chat.user_color : null">{{chat.name}}</strong>: {{chat.message}}
{{last ? scrollToBottom() : ''}}
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TwitchChatComponent } from './twitch-chat.component'; import { TwitchChatComponent } from './twitch-chat.component';
@@ -6,7 +6,7 @@ describe('TwitchChatComponent', () => {
let component: TwitchChatComponent; let component: TwitchChatComponent;
let fixture: ComponentFixture<TwitchChatComponent>; let fixture: ComponentFixture<TwitchChatComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ TwitchChatComponent ] declarations: [ TwitchChatComponent ]
}) })

View File

@@ -21,9 +21,11 @@ export class TwitchChatComponent implements OnInit, AfterViewInit {
scrollContainer = null; scrollContainer = null;
@Input() db_file = null; @Input() db_file = null;
@Input() sub = null;
@Input() current_timestamp = null; @Input() current_timestamp = null;
@ViewChild('scrollContainer') scrollRef: ElementRef; @ViewChild('scrollContainer') scrollRef: ElementRef;
@ViewChildren('chat') chat: QueryList<any>;
constructor(private postsService: PostsService) { } constructor(private postsService: PostsService) { }
@@ -35,22 +37,31 @@ export class TwitchChatComponent implements OnInit, AfterViewInit {
} }
private isUserNearBottom(): boolean { private isUserNearBottom(): boolean {
const threshold = 300; const threshold = 150;
const position = this.scrollContainer.scrollTop + this.scrollContainer.offsetHeight; const position = this.scrollContainer.scrollTop + this.scrollContainer.offsetHeight;
const height = this.scrollContainer.scrollHeight; const height = this.scrollContainer.scrollHeight;
return position > height - threshold; return position > height - threshold;
} }
scrollToBottom = () => { scrollToBottom = (force_scroll) => {
this.scrollContainer.scrollTop = this.scrollContainer.scrollHeight; if (force_scroll || this.isUserNearBottom()) {
this.scrollContainer.scrollTop = this.scrollContainer.scrollHeight;
}
} }
addNewChatMessages() { addNewChatMessages() {
const next_chat_index = this.getIndexOfNextChat();
if (!this.scrollContainer) { if (!this.scrollContainer) {
this.scrollContainer = this.scrollRef.nativeElement; this.scrollContainer = this.scrollRef.nativeElement;
} }
if (this.current_chat_index === null) { if (this.current_chat_index === null) {
this.current_chat_index = this.getIndexOfNextChat(); this.current_chat_index = next_chat_index;
}
if (Math.abs(next_chat_index - this.current_chat_index) > 25) {
this.visible_chat = [];
this.current_chat_index = next_chat_index - 25;
setTimeout(() => this.scrollToBottom(true), 100);
} }
const latest_chat_timestamp = this.visible_chat.length ? this.visible_chat[this.visible_chat.length - 1]['timestamp'] : 0; const latest_chat_timestamp = this.visible_chat.length ? this.visible_chat[this.visible_chat.length - 1]['timestamp'] : 0;
@@ -59,9 +70,6 @@ export class TwitchChatComponent implements OnInit, AfterViewInit {
if (this.full_chat[i]['timestamp'] >= latest_chat_timestamp && this.full_chat[i]['timestamp'] <= this.current_timestamp) { if (this.full_chat[i]['timestamp'] >= latest_chat_timestamp && this.full_chat[i]['timestamp'] <= this.current_timestamp) {
this.visible_chat.push(this.full_chat[i]); this.visible_chat.push(this.full_chat[i]);
this.current_chat_index = i; this.current_chat_index = i;
if (this.isUserNearBottom()) {
this.scrollToBottom();
}
} else if (this.full_chat[i]['timestamp'] > this.current_timestamp) { } else if (this.full_chat[i]['timestamp'] > this.current_timestamp) {
break; break;
} }
@@ -74,7 +82,7 @@ export class TwitchChatComponent implements OnInit, AfterViewInit {
} }
getFullChat() { getFullChat() {
this.postsService.getFullTwitchChat(this.db_file.id, this.db_file.isAudio ? 'audio' : 'video', null).subscribe(res => { this.postsService.getFullTwitchChat(this.db_file.id, this.db_file.isAudio ? 'audio' : 'video', null, this.sub).subscribe(res => {
this.chat_response_received = true; this.chat_response_received = true;
if (res['chat']) { if (res['chat']) {
this.initializeChatCheck(res['chat']); this.initializeChatCheck(res['chat']);
@@ -82,11 +90,6 @@ export class TwitchChatComponent implements OnInit, AfterViewInit {
}); });
} }
renewChat() {
this.visible_chat = [];
this.current_chat_index = this.getIndexOfNextChat();
}
downloadTwitchChat() { downloadTwitchChat() {
this.downloading_chat = true; this.downloading_chat = true;
let vodId = this.db_file.url.split('videos/').length > 1 && this.db_file.url.split('videos/')[1]; let vodId = this.db_file.url.split('videos/').length > 1 && this.db_file.url.split('videos/')[1];
@@ -94,7 +97,7 @@ export class TwitchChatComponent implements OnInit, AfterViewInit {
if (!vodId) { if (!vodId) {
this.postsService.openSnackBar('VOD url for this video is not supported. VOD ID must be after "twitch.tv/videos/"'); this.postsService.openSnackBar('VOD url for this video is not supported. VOD ID must be after "twitch.tv/videos/"');
} }
this.postsService.downloadTwitchChat(this.db_file.id, this.db_file.isAudio ? 'audio' : 'video', vodId, null).subscribe(res => { this.postsService.downloadTwitchChat(this.db_file.id, this.db_file.isAudio ? 'audio' : 'video', vodId, null, this.sub).subscribe(res => {
if (res['chat']) { if (res['chat']) {
this.initializeChatCheck(res['chat']); this.initializeChatCheck(res['chat']);
} else { } else {

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { UnifiedFileCardComponent } from './unified-file-card.component'; import { UnifiedFileCardComponent } from './unified-file-card.component';
@@ -6,7 +6,7 @@ describe('UnifiedFileCardComponent', () => {
let component: UnifiedFileCardComponent; let component: UnifiedFileCardComponent;
let fixture: ComponentFixture<UnifiedFileCardComponent>; let fixture: ComponentFixture<UnifiedFileCardComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ UnifiedFileCardComponent ] declarations: [ UnifiedFileCardComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { CreatePlaylistComponent } from './create-playlist.component'; import { CreatePlaylistComponent } from './create-playlist.component';
@@ -6,7 +6,7 @@ describe('CreatePlaylistComponent', () => {
let component: CreatePlaylistComponent; let component: CreatePlaylistComponent;
let fixture: ComponentFixture<CreatePlaylistComponent>; let fixture: ComponentFixture<CreatePlaylistComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ CreatePlaylistComponent ] declarations: [ CreatePlaylistComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AboutDialogComponent } from './about-dialog.component'; import { AboutDialogComponent } from './about-dialog.component';
@@ -6,7 +6,7 @@ describe('AboutDialogComponent', () => {
let component: AboutDialogComponent; let component: AboutDialogComponent;
let fixture: ComponentFixture<AboutDialogComponent>; let fixture: ComponentFixture<AboutDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ AboutDialogComponent ] declarations: [ AboutDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AddUserDialogComponent } from './add-user-dialog.component'; import { AddUserDialogComponent } from './add-user-dialog.component';
@@ -6,7 +6,7 @@ describe('AddUserDialogComponent', () => {
let component: AddUserDialogComponent; let component: AddUserDialogComponent;
let fixture: ComponentFixture<AddUserDialogComponent>; let fixture: ComponentFixture<AddUserDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ AddUserDialogComponent ] declarations: [ AddUserDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ArgModifierDialogComponent } from './arg-modifier-dialog.component'; import { ArgModifierDialogComponent } from './arg-modifier-dialog.component';
@@ -6,7 +6,7 @@ describe('ArgModifierDialogComponent', () => {
let component: ArgModifierDialogComponent; let component: ArgModifierDialogComponent;
let fixture: ComponentFixture<ArgModifierDialogComponent>; let fixture: ComponentFixture<ArgModifierDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ArgModifierDialogComponent ] declarations: [ ArgModifierDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ConfirmDialogComponent } from './confirm-dialog.component'; import { ConfirmDialogComponent } from './confirm-dialog.component';
@@ -6,7 +6,7 @@ describe('ConfirmDialogComponent', () => {
let component: ConfirmDialogComponent; let component: ConfirmDialogComponent;
let fixture: ComponentFixture<ConfirmDialogComponent>; let fixture: ComponentFixture<ConfirmDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ConfirmDialogComponent ] declarations: [ ConfirmDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { CookiesUploaderDialogComponent } from './cookies-uploader-dialog.component'; import { CookiesUploaderDialogComponent } from './cookies-uploader-dialog.component';
@@ -6,7 +6,7 @@ describe('CookiesUploaderDialogComponent', () => {
let component: CookiesUploaderDialogComponent; let component: CookiesUploaderDialogComponent;
let fixture: ComponentFixture<CookiesUploaderDialogComponent>; let fixture: ComponentFixture<CookiesUploaderDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ CookiesUploaderDialogComponent ] declarations: [ CookiesUploaderDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { EditCategoryDialogComponent } from './edit-category-dialog.component'; import { EditCategoryDialogComponent } from './edit-category-dialog.component';
@@ -6,7 +6,7 @@ describe('EditCategoryDialogComponent', () => {
let component: EditCategoryDialogComponent; let component: EditCategoryDialogComponent;
let fixture: ComponentFixture<EditCategoryDialogComponent>; let fixture: ComponentFixture<EditCategoryDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ EditCategoryDialogComponent ] declarations: [ EditCategoryDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { EditSubscriptionDialogComponent } from './edit-subscription-dialog.component'; import { EditSubscriptionDialogComponent } from './edit-subscription-dialog.component';
@@ -6,7 +6,7 @@ describe('EditSubscriptionDialogComponent', () => {
let component: EditSubscriptionDialogComponent; let component: EditSubscriptionDialogComponent;
let fixture: ComponentFixture<EditSubscriptionDialogComponent>; let fixture: ComponentFixture<EditSubscriptionDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ EditSubscriptionDialogComponent ] declarations: [ EditSubscriptionDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ModifyPlaylistComponent } from './modify-playlist.component'; import { ModifyPlaylistComponent } from './modify-playlist.component';
@@ -6,7 +6,7 @@ describe('ModifyPlaylistComponent', () => {
let component: ModifyPlaylistComponent; let component: ModifyPlaylistComponent;
let fixture: ComponentFixture<ModifyPlaylistComponent>; let fixture: ComponentFixture<ModifyPlaylistComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ModifyPlaylistComponent ] declarations: [ ModifyPlaylistComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SetDefaultAdminDialogComponent } from './set-default-admin-dialog.component'; import { SetDefaultAdminDialogComponent } from './set-default-admin-dialog.component';
@@ -6,7 +6,7 @@ describe('SetDefaultAdminDialogComponent', () => {
let component: SetDefaultAdminDialogComponent; let component: SetDefaultAdminDialogComponent;
let fixture: ComponentFixture<SetDefaultAdminDialogComponent>; let fixture: ComponentFixture<SetDefaultAdminDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SetDefaultAdminDialogComponent ] declarations: [ SetDefaultAdminDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ShareMediaDialogComponent } from './share-media-dialog.component'; import { ShareMediaDialogComponent } from './share-media-dialog.component';
@@ -6,7 +6,7 @@ describe('ShareMediaDialogComponent', () => {
let component: ShareMediaDialogComponent; let component: ShareMediaDialogComponent;
let fixture: ComponentFixture<ShareMediaDialogComponent>; let fixture: ComponentFixture<ShareMediaDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ ShareMediaDialogComponent ] declarations: [ ShareMediaDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SubscribeDialogComponent } from './subscribe-dialog.component'; import { SubscribeDialogComponent } from './subscribe-dialog.component';
@@ -6,7 +6,7 @@ describe('SubscribeDialogComponent', () => {
let component: SubscribeDialogComponent; let component: SubscribeDialogComponent;
let fixture: ComponentFixture<SubscribeDialogComponent>; let fixture: ComponentFixture<SubscribeDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SubscribeDialogComponent ] declarations: [ SubscribeDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SubscriptionInfoDialogComponent } from './subscription-info-dialog.component'; import { SubscriptionInfoDialogComponent } from './subscription-info-dialog.component';
@@ -6,7 +6,7 @@ describe('SubscriptionInfoDialogComponent', () => {
let component: SubscriptionInfoDialogComponent; let component: SubscriptionInfoDialogComponent;
let fixture: ComponentFixture<SubscriptionInfoDialogComponent>; let fixture: ComponentFixture<SubscriptionInfoDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SubscriptionInfoDialogComponent ] declarations: [ SubscriptionInfoDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { UpdateProgressDialogComponent } from './update-progress-dialog.component'; import { UpdateProgressDialogComponent } from './update-progress-dialog.component';
@@ -6,7 +6,7 @@ describe('UpdateProgressDialogComponent', () => {
let component: UpdateProgressDialogComponent; let component: UpdateProgressDialogComponent;
let fixture: ComponentFixture<UpdateProgressDialogComponent>; let fixture: ComponentFixture<UpdateProgressDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ UpdateProgressDialogComponent ] declarations: [ UpdateProgressDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { UserProfileDialogComponent } from './user-profile-dialog.component'; import { UserProfileDialogComponent } from './user-profile-dialog.component';
@@ -6,7 +6,7 @@ describe('UserProfileDialogComponent', () => {
let component: UserProfileDialogComponent; let component: UserProfileDialogComponent;
let fixture: ComponentFixture<UserProfileDialogComponent>; let fixture: ComponentFixture<UserProfileDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ UserProfileDialogComponent ] declarations: [ UserProfileDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { VideoInfoDialogComponent } from './video-info-dialog.component'; import { VideoInfoDialogComponent } from './video-info-dialog.component';
@@ -6,7 +6,7 @@ describe('VideoInfoDialogComponent', () => {
let component: VideoInfoDialogComponent; let component: VideoInfoDialogComponent;
let fixture: ComponentFixture<VideoInfoDialogComponent>; let fixture: ComponentFixture<VideoInfoDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ VideoInfoDialogComponent ] declarations: [ VideoInfoDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { DownloadItemComponent } from './download-item.component'; import { DownloadItemComponent } from './download-item.component';
@@ -6,7 +6,7 @@ describe('DownloadItemComponent', () => {
let component: DownloadItemComponent; let component: DownloadItemComponent;
let fixture: ComponentFixture<DownloadItemComponent>; let fixture: ComponentFixture<DownloadItemComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ DownloadItemComponent ] declarations: [ DownloadItemComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FileCardComponent } from './file-card.component'; import { FileCardComponent } from './file-card.component';
@@ -6,7 +6,7 @@ describe('FileCardComponent', () => {
let component: FileCardComponent; let component: FileCardComponent;
let fixture: ComponentFixture<FileCardComponent>; let fixture: ComponentFixture<FileCardComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ FileCardComponent ] declarations: [ FileCardComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { InputDialogComponent } from './input-dialog.component'; import { InputDialogComponent } from './input-dialog.component';
@@ -6,7 +6,7 @@ describe('InputDialogComponent', () => {
let component: InputDialogComponent; let component: InputDialogComponent;
let fixture: ComponentFixture<InputDialogComponent>; let fixture: ComponentFixture<InputDialogComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ InputDialogComponent ] declarations: [ InputDialogComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { MainComponent } from './main.component'; import { MainComponent } from './main.component';
@@ -6,7 +6,7 @@ describe('MainComponent', () => {
let component: MainComponent; let component: MainComponent;
let fixture: ComponentFixture<MainComponent>; let fixture: ComponentFixture<MainComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ MainComponent ] declarations: [ MainComponent ]
}) })

View File

@@ -41,7 +41,7 @@
</div> </div>
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists'] && postsService['config']['API']['use_twitch_API']"> <mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists'] && postsService['config']['API']['use_twitch_API']">
<ng-container *ngIf="api_ready && db_file && db_file.url.includes('twitch.tv/videos/')"> <ng-container *ngIf="api_ready && db_file && db_file.url.includes('twitch.tv/videos/')">
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime"></app-twitch-chat> <app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime" [sub]="subscription"></app-twitch-chat>
</ng-container> </ng-container>
</mat-drawer> </mat-drawer>

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { PlayerComponent } from './player.component'; import { PlayerComponent } from './player.component';
@@ -6,7 +6,7 @@ describe('PlayerComponent', () => {
let component: PlayerComponent; let component: PlayerComponent;
let fixture: ComponentFixture<PlayerComponent>; let fixture: ComponentFixture<PlayerComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ PlayerComponent ] declarations: [ PlayerComponent ]
}) })

View File

@@ -1,5 +1,5 @@
import { Component, OnInit, HostListener, EventEmitter, OnDestroy, AfterViewInit, ViewChild } from '@angular/core'; import { Component, OnInit, HostListener, EventEmitter, OnDestroy, AfterViewInit, ViewChild } from '@angular/core';
import { VgAPI } from 'ngx-videogular'; import { VgApiService } from '@videogular/ngx-videogular/core';
import { PostsService } from 'app/posts.services'; import { PostsService } from 'app/posts.services';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
@@ -31,7 +31,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
currentIndex = 0; currentIndex = 0;
currentItem: IMedia = null; currentItem: IMedia = null;
api: VgAPI; api: VgApiService;
api_ready = false; api_ready = false;
// params // params
@@ -39,6 +39,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
type: string; type: string;
id = null; // used for playlists (not subscription) id = null; // used for playlists (not subscription)
uid = null; // used for non-subscription files (audio, video, playlist) uid = null; // used for non-subscription files (audio, video, playlist)
subscription = null;
subscriptionName = null; subscriptionName = null;
subPlaylist = null; subPlaylist = null;
uuid = null; // used for sharing in multi-user mode, uuid is the user that downloaded the video uuid = null; // used for sharing in multi-user mode, uuid is the user that downloaded the video
@@ -180,6 +181,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
getSubscription() { getSubscription() {
this.postsService.getSubscription(null, this.subscriptionName).subscribe(res => { this.postsService.getSubscription(null, this.subscriptionName).subscribe(res => {
const subscription = res['subscription']; const subscription = res['subscription'];
this.subscription = subscription;
if (this.fileNames) { if (this.fileNames) {
subscription.videos.forEach(video => { subscription.videos.forEach(video => {
if (video['id'] === this.fileNames[0]) { if (video['id'] === this.fileNames[0]) {
@@ -272,16 +274,10 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
this.original_playlist = JSON.stringify(this.playlist); this.original_playlist = JSON.stringify(this.playlist);
} }
onPlayerReady(api: VgAPI) { onPlayerReady(api: VgApiService) {
this.api = api; this.api = api;
this.api_ready = true; this.api_ready = true;
this.api.subscriptions.seeked.subscribe(data => {
if (this.twitchChat) {
this.twitchChat.renewChat();
}
});
// checks if volume has been previously set. if so, use that as default // checks if volume has been previously set. if so, use that as default
if (localStorage.getItem('player_volume')) { if (localStorage.getItem('player_volume')) {
this.api.volume = parseFloat(localStorage.getItem('player_volume')); this.api.volume = parseFloat(localStorage.getItem('player_volume'));

View File

@@ -234,12 +234,12 @@ export class PostsService implements CanActivate {
return this.http.post(this.path + 'getAllFiles', {}, this.httpOptions); return this.http.post(this.path + 'getAllFiles', {}, this.httpOptions);
} }
getFullTwitchChat(id, type, uuid = null) { getFullTwitchChat(id, type, uuid = null, sub = null) {
return this.http.post(this.path + 'getFullTwitchChat', {id: id, type: type, uuid: uuid}, this.httpOptions); return this.http.post(this.path + 'getFullTwitchChat', {id: id, type: type, uuid: uuid, sub: sub}, this.httpOptions);
} }
downloadTwitchChat(id, type, vodId, uuid = null) { downloadTwitchChat(id, type, vodId, uuid = null, sub = null) {
return this.http.post(this.path + 'downloadTwitchChatByVODID', {id: id, type: type, vodId: vodId, uuid: uuid}, this.httpOptions); return this.http.post(this.path + 'downloadTwitchChatByVODID', {id: id, type: type, vodId: vodId, uuid: uuid, sub: sub}, this.httpOptions);
} }
downloadFileFromServer(fileName, type, outputName = null, fullPathProvided = null, subscriptionName = null, subPlaylist = null, downloadFileFromServer(fileName, type, outputName = null, fullPathProvided = null, subscriptionName = null, subPlaylist = null,

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SettingsComponent } from './settings.component'; import { SettingsComponent } from './settings.component';
@@ -6,7 +6,7 @@ describe('SettingsComponent', () => {
let component: SettingsComponent; let component: SettingsComponent;
let fixture: ComponentFixture<SettingsComponent>; let fixture: ComponentFixture<SettingsComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SettingsComponent ] declarations: [ SettingsComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SubscriptionFileCardComponent } from './subscription-file-card.component'; import { SubscriptionFileCardComponent } from './subscription-file-card.component';
@@ -6,7 +6,7 @@ describe('SubscriptionFileCardComponent', () => {
let component: SubscriptionFileCardComponent; let component: SubscriptionFileCardComponent;
let fixture: ComponentFixture<SubscriptionFileCardComponent>; let fixture: ComponentFixture<SubscriptionFileCardComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SubscriptionFileCardComponent ] declarations: [ SubscriptionFileCardComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SubscriptionComponent } from './subscription.component'; import { SubscriptionComponent } from './subscription.component';
@@ -6,7 +6,7 @@ describe('SubscriptionComponent', () => {
let component: SubscriptionComponent; let component: SubscriptionComponent;
let fixture: ComponentFixture<SubscriptionComponent>; let fixture: ComponentFixture<SubscriptionComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SubscriptionComponent ] declarations: [ SubscriptionComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { SubscriptionsComponent } from './subscriptions.component'; import { SubscriptionsComponent } from './subscriptions.component';
@@ -6,7 +6,7 @@ describe('SubscriptionsComponent', () => {
let component: SubscriptionsComponent; let component: SubscriptionsComponent;
let fixture: ComponentFixture<SubscriptionsComponent>; let fixture: ComponentFixture<SubscriptionsComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ SubscriptionsComponent ] declarations: [ SubscriptionsComponent ]
}) })

View File

@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { UpdaterComponent } from './updater.component'; import { UpdaterComponent } from './updater.component';
@@ -6,7 +6,7 @@ describe('UpdaterComponent', () => {
let component: UpdaterComponent; let component: UpdaterComponent;
let fixture: ComponentFixture<UpdaterComponent>; let fixture: ComponentFixture<UpdaterComponent>;
beforeEach(async(() => { beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ UpdaterComponent ] declarations: [ UpdaterComponent ]
}) })

View File

@@ -20,6 +20,6 @@
"es2016", "es2016",
"dom" "dom"
], ],
"module": "esnext" "module": "es2020"
} }
} }

View File

@@ -13,6 +13,9 @@
"curly": true, "curly": true,
"eofline": true, "eofline": true,
"forin": true, "forin": true,
"deprecation": {
"severity": "warning"
},
"import-blacklist": [ "import-blacklist": [
true true
], ],
@@ -62,7 +65,6 @@
"no-trailing-whitespace": true, "no-trailing-whitespace": true,
"no-unnecessary-initializer": true, "no-unnecessary-initializer": true,
"no-unused-expression": true, "no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true, "no-var-keyword": true,
"object-literal-sort-keys": false, "object-literal-sort-keys": false,
"one-line": [ "one-line": [