Added description to player component and simplified the database by un-splitting videos and playlists by type

updated-player
Isaac Abadi 4 years ago
parent c6fc5352c5
commit 4f693d4eda

@ -13,7 +13,7 @@ var express = require("express");
var bodyParser = require("body-parser");
var archiver = require('archiver');
var unzipper = require('unzipper');
var db_api = require('./db')
var db_api = require('./db');
var utils = require('./utils')
var mergeFiles = require('merge-files');
const low = require('lowdb')
@ -87,14 +87,8 @@ categories_api.initialize(db, users_db, logger, db_api);
// Set some defaults
db.defaults(
{
playlists: {
audio: [],
video: []
},
files: {
audio: [],
video: []
},
playlists: [],
files: [],
configWriteFlag: false,
downloads: {},
subscriptions: [],
@ -218,10 +212,12 @@ async function checkMigrations() {
// 4.1->4.2 migration
const add_description_migration_complete = false; // db.get('add_description_migration_complete').value();
const add_description_migration_complete = db.get('add_description_migration_complete').value();
if (!add_description_migration_complete) {
logger.info('Beginning migration: 4.1->4.2+')
const success = await addMetadataPropertyToDB('description');
let success = await simplifyDBFileStructure();
success = success && await addMetadataPropertyToDB('view_count');
success = success && await addMetadataPropertyToDB('description');
if (success) { logger.info('4.1->4.2+ migration complete!'); }
else { logger.error('Migration failed: 4.1->4.2+'); }
}
@ -229,6 +225,7 @@ async function checkMigrations() {
return true;
}
/*
async function runFilesToDBMigration() {
try {
let mp3s = await getMp3s();
@ -260,6 +257,37 @@ async function runFilesToDBMigration() {
return false;
}
}
*/
async function simplifyDBFileStructure() {
let users = users_db.get('users').value();
for (let i = 0; i < users.length; i++) {
const user = users[i];
if (user['files']['video'] !== undefined && user['files']['audio'] !== undefined) {
const user_files = user['files']['video'].concat(user['files']['audio']);
const user_db_path = users_db.get('users').find({uid: user['uid']});
user_db_path.assign({files: user_files}).write();
}
if (user['playlists']['video'] !== undefined && user['playlists']['audio'] !== undefined) {
const user_playlists = user['playlists']['video'].concat(user['playlists']['audio']);
const user_db_path = users_db.get('users').find({uid: user['uid']});
user_db_path.assign({playlists: user_playlists}).write();
}
}
if (db.get('files.video').value() !== undefined && db.get('files.audio').value() !== undefined) {
const files = db.get('files.video').value().concat(db.get('files.audio'));
db.assign({files: files}).write();
}
if (db.get('playlists.video').value() !== undefined && db.get('playlists.audio').value() !== undefined) {
const playlists = db.get('playlists.video').value().concat(db.get('playlists.audio'));
db.assign({playlists: playlists}).write();
}
return true;
}
async function addMetadataPropertyToDB(property_key) {
try {
@ -592,6 +620,9 @@ async function loadConfig() {
// creates archive path if missing
await fs.ensureDir(archivePath);
// check migrations
await checkMigrations();
// now this is done here due to youtube-dl's repo takedown
await startYoutubeDL();
@ -606,9 +637,6 @@ async function loadConfig() {
db_api.importUnregisteredFiles();
// check migrations
await checkMigrations();
// load in previous downloads
downloads = db.get('downloads').value();
@ -1994,7 +2022,7 @@ async function addThumbnails(files) {
// gets all download mp3s
app.get('/api/getMp3s', optionalJwt, async function(req, res) {
var mp3s = db.get('files.audio').value(); // getMp3s();
var mp3s = db.get('files').chain().find({isAudio: true}).value(); // getMp3s();
var playlists = db.get('playlists.audio').value();
const is_authenticated = req.isAuthenticated();
if (is_authenticated) {
@ -2020,8 +2048,8 @@ app.get('/api/getMp3s', optionalJwt, async function(req, res) {
// gets all download mp4s
app.get('/api/getMp4s', optionalJwt, async function(req, res) {
var mp4s = db.get('files.video').value(); // getMp4s();
var playlists = db.get('playlists.video').value();
var mp4s = db.get('files').chain().find({isAudio: false}).value(); // getMp4s();
var playlists = db.get('playlists').value();
const is_authenticated = req.isAuthenticated();
if (is_authenticated) {
@ -2052,21 +2080,11 @@ app.post('/api/getFile', optionalJwt, function (req, res) {
var file = null;
if (req.isAuthenticated()) {
file = auth_api.getUserVideo(req.user.uid, uid, type);
file = auth_api.getUserVideo(req.user.uid, uid);
} else if (uuid) {
file = auth_api.getUserVideo(uuid, uid, type, true);
file = auth_api.getUserVideo(uuid, uid, true);
} else {
if (!type) {
file = db.get('files.audio').find({uid: uid}).value();
if (!file) {
file = db.get('files.video').find({uid: uid}).value();
if (file) type = 'video';
} else {
type = 'audio';
}
}
if (!file && type) file = db.get(`files.${type}`).find({uid: uid}).value();
file = db.get('files').find({uid: uid}).value();
}
// check if chat exists for twitch videos
@ -2086,32 +2104,20 @@ app.post('/api/getFile', optionalJwt, function (req, res) {
app.post('/api/getAllFiles', optionalJwt, async function (req, res) {
// these are returned
let files = [];
let playlists = [];
let subscription_files = [];
let videos = null;
let audios = null;
let audio_playlists = null;
let video_playlists = null;
let files = null;
let playlists = null;
let subscriptions = config_api.getConfigItem('ytdl_allow_subscriptions') ? (subscriptions_api.getAllSubscriptions(req.isAuthenticated() ? req.user.uid : null)) : [];
// get basic info depending on multi-user mode being enabled
if (req.isAuthenticated()) {
videos = auth_api.getUserVideos(req.user.uid, 'video');
audios = auth_api.getUserVideos(req.user.uid, 'audio');
audio_playlists = auth_api.getUserPlaylists(req.user.uid, 'audio');
video_playlists = auth_api.getUserPlaylists(req.user.uid, 'video');
files = auth_api.getUserVideos(req.user.uid);
playlists = auth_api.getUserPlaylists(req.user.uid);
} else {
videos = db.get('files.audio').value();
audios = db.get('files.video').value();
audio_playlists = db.get('playlists.audio').value();
video_playlists = db.get('playlists.video').value();
files = db.get('files').value();
playlists = db.get('playlists').value();
}
files = videos.concat(audios);
playlists = video_playlists.concat(audio_playlists);
// loop through subscriptions and add videos
for (let i = 0; i < subscriptions.length; i++) {
sub = subscriptions[i];
@ -2187,14 +2193,13 @@ app.post('/api/downloadTwitchChatByVODID', optionalJwt, async (req, res) => {
// video sharing
app.post('/api/enableSharing', optionalJwt, function(req, res) {
var type = req.body.type;
var uid = req.body.uid;
var is_playlist = req.body.is_playlist;
let success = false;
// multi-user mode
if (req.isAuthenticated()) {
// if multi user mode, use this method instead
success = auth_api.changeSharingMode(req.user.uid, uid, type, is_playlist, true);
success = auth_api.changeSharingMode(req.user.uid, uid, is_playlist, true);
res.send({success: success});
return;
}
@ -2203,12 +2208,12 @@ app.post('/api/enableSharing', optionalJwt, function(req, res) {
try {
success = true;
if (!is_playlist && type !== 'subscription') {
db.get(`files.${type}`)
db.get(`files`)
.find({uid: uid})
.assign({sharingEnabled: true})
.write();
} else if (is_playlist) {
db.get(`playlists.${type}`)
db.get(`playlists`)
.find({id: uid})
.assign({sharingEnabled: true})
.write();
@ -2237,7 +2242,7 @@ app.post('/api/disableSharing', optionalJwt, function(req, res) {
// multi-user mode
if (req.isAuthenticated()) {
// if multi user mode, use this method instead
success = auth_api.changeSharingMode(req.user.uid, uid, type, is_playlist, false);
success = auth_api.changeSharingMode(req.user.uid, uid, is_playlist, false);
res.send({success: success});
return;
}
@ -2246,12 +2251,12 @@ app.post('/api/disableSharing', optionalJwt, function(req, res) {
try {
success = true;
if (!is_playlist && type !== 'subscription') {
db.get(`files.${type}`)
db.get(`files`)
.find({uid: uid})
.assign({sharingEnabled: false})
.write();
} else if (is_playlist) {
db.get(`playlists.${type}`)
db.get(`playlists`)
.find({id: uid})
.assign({sharingEnabled: false})
.write();
@ -2544,7 +2549,7 @@ app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
if (req.isAuthenticated()) {
auth_api.addPlaylist(req.user.uid, new_playlist, type);
} else {
db.get(`playlists.${type}`)
db.get(`playlists`)
.push(new_playlist)
.write();
}
@ -2558,26 +2563,15 @@ app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
app.post('/api/getPlaylist', optionalJwt, async (req, res) => {
let playlistID = req.body.playlistID;
let type = req.body.type;
let uuid = req.body.uuid;
let playlist = null;
if (req.isAuthenticated()) {
playlist = auth_api.getUserPlaylist(uuid ? uuid : req.user.uid, playlistID, type);
playlist = auth_api.getUserPlaylist(uuid ? uuid : req.user.uid, playlistID);
type = playlist.type;
} else {
if (!type) {
playlist = db.get('playlists.audio').find({id: playlistID}).value();
if (!playlist) {
playlist = db.get('playlists.video').find({id: playlistID}).value();
if (playlist) type = 'video';
} else {
type = 'audio';
}
}
if (!playlist) playlist = db.get(`playlists.${type}`).find({id: playlistID}).value();
playlist = db.get(`playlists`).find({id: playlistID}).value();
}
res.send({
@ -2590,14 +2584,13 @@ app.post('/api/getPlaylist', optionalJwt, async (req, res) => {
app.post('/api/updatePlaylistFiles', optionalJwt, async (req, res) => {
let playlistID = req.body.playlistID;
let fileNames = req.body.fileNames;
let type = req.body.type;
let success = false;
try {
if (req.isAuthenticated()) {
auth_api.updatePlaylistFiles(req.user.uid, playlistID, fileNames, type);
auth_api.updatePlaylistFiles(req.user.uid, playlistID, fileNames);
} else {
db.get(`playlists.${type}`)
db.get(`playlists`)
.find({id: playlistID})
.assign({fileNames: fileNames})
.write();
@ -2623,15 +2616,14 @@ app.post('/api/updatePlaylist', optionalJwt, async (req, res) => {
app.post('/api/deletePlaylist', optionalJwt, async (req, res) => {
let playlistID = req.body.playlistID;
let type = req.body.type;
let success = null;
try {
if (req.isAuthenticated()) {
auth_api.removePlaylist(req.user.uid, playlistID, type);
auth_api.removePlaylist(req.user.uid, playlistID);
} else {
// removes playlist from playlists
db.get(`playlists.${type}`)
db.get(`playlists`)
.remove({id: playlistID})
.write();
}
@ -2653,23 +2645,23 @@ app.post('/api/deleteFile', optionalJwt, async (req, res) => {
var blacklistMode = req.body.blacklistMode;
if (req.isAuthenticated()) {
let success = auth_api.deleteUserFile(req.user.uid, uid, type, blacklistMode);
let success = auth_api.deleteUserFile(req.user.uid, uid, blacklistMode);
res.send(success);
return;
}
var file_obj = db.get(`files.${type}`).find({uid: uid}).value();
var file_obj = db.get(`files`).find({uid: uid}).value();
var name = file_obj.id;
var fullpath = file_obj ? file_obj.path : null;
var wasDeleted = false;
if (await fs.pathExists(fullpath))
{
wasDeleted = type === 'audio' ? await deleteAudioFile(name, path.basename(fullpath), blacklistMode) : await deleteVideoFile(name, path.basename(fullpath), blacklistMode);
db.get('files.video').remove({uid: uid}).write();
db.get('files').remove({uid: uid}).write();
// wasDeleted = true;
res.send(wasDeleted);
} else if (video_obj) {
db.get('files.video').remove({uid: uid}).write();
db.get('files').remove({uid: uid}).write();
wasDeleted = true;
res.send(wasDeleted);
} else {

@ -281,24 +281,13 @@ exports.adminExists = function() {
// video stuff
exports.getUserVideos = function(user_uid, type) {
exports.getUserVideos = function(user_uid) {
const user = users_db.get('users').find({uid: user_uid}).value();
return user['files'][type];
return user['files'];
}
exports.getUserVideo = function(user_uid, file_uid, type, requireSharing = false) {
let file = null;
if (!type) {
file = users_db.get('users').find({uid: user_uid}).get(`files.audio`).find({uid: file_uid}).value();
if (!file) {
file = users_db.get('users').find({uid: user_uid}).get(`files.video`).find({uid: file_uid}).value();
if (file) type = 'video';
} else {
type = 'audio';
}
}
if (!file && type) file = users_db.get('users').find({uid: user_uid}).get(`files.${type}`).find({uid: file_uid}).value();
exports.getUserVideo = function(user_uid, file_uid, requireSharing = false) {
let file = users_db.get('users').find({uid: user_uid}).get(`files`).find({uid: file_uid}).value();
// prevent unauthorized users from accessing the file info
if (file && !file['sharingEnabled'] && requireSharing) file = null;
@ -306,38 +295,28 @@ exports.getUserVideo = function(user_uid, file_uid, type, requireSharing = false
return file;
}
exports.addPlaylist = function(user_uid, new_playlist, type) {
users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).push(new_playlist).write();
exports.addPlaylist = function(user_uid, new_playlist) {
users_db.get('users').find({uid: user_uid}).get(`playlists`).push(new_playlist).write();
return true;
}
exports.updatePlaylistFiles = function(user_uid, playlistID, new_filenames, type) {
users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).find({id: playlistID}).assign({fileNames: new_filenames});
exports.updatePlaylistFiles = function(user_uid, playlistID, new_filenames) {
users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlistID}).assign({fileNames: new_filenames});
return true;
}
exports.removePlaylist = function(user_uid, playlistID, type) {
users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).remove({id: playlistID}).write();
exports.removePlaylist = function(user_uid, playlistID) {
users_db.get('users').find({uid: user_uid}).get(`playlists`).remove({id: playlistID}).write();
return true;
}
exports.getUserPlaylists = function(user_uid, type) {
exports.getUserPlaylists = function(user_uid) {
const user = users_db.get('users').find({uid: user_uid}).value();
return user['playlists'][type];
return user['playlists'];
}
exports.getUserPlaylist = function(user_uid, playlistID, type, requireSharing = false) {
let playlist = null;
if (!type) {
playlist = users_db.get('users').find({uid: user_uid}).get(`playlists.audio`).find({id: playlistID}).value();
if (!playlist) {
playlist = users_db.get('users').find({uid: user_uid}).get(`playlists.video`).find({id: playlistID}).value();
if (playlist) type = 'video';
} else {
type = 'audio';
}
}
if (!playlist) playlist = users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).find({id: playlistID}).value();
exports.getUserPlaylist = function(user_uid, playlistID, requireSharing = false) {
let playlist = users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlistID}).value();
// prevent unauthorized users from accessing the file info
if (requireSharing && !playlist['sharingEnabled']) playlist = null;
@ -345,21 +324,22 @@ exports.getUserPlaylist = function(user_uid, playlistID, type, requireSharing =
return playlist;
}
exports.registerUserFile = function(user_uid, file_object, type) {
users_db.get('users').find({uid: user_uid}).get(`files.${type}`)
exports.registerUserFile = function(user_uid, file_object) {
users_db.get('users').find({uid: user_uid}).get(`files`)
.remove({
path: file_object['path']
}).write();
users_db.get('users').find({uid: user_uid}).get(`files.${type}`)
users_db.get('users').find({uid: user_uid}).get(`files`)
.push(file_object)
.write();
}
exports.deleteUserFile = async function(user_uid, file_uid, type, blacklistMode = false) {
exports.deleteUserFile = async function(user_uid, file_uid, blacklistMode = false) {
let success = false;
const file_obj = users_db.get('users').find({uid: user_uid}).get(`files.${type}`).find({uid: file_uid}).value();
const file_obj = users_db.get('users').find({uid: user_uid}).get(`files`).find({uid: file_uid}).value();
if (file_obj) {
const type = file_obj.isAudio ? 'audio' : 'video';
const usersFileFolder = config_api.getConfigItem('ytdl_users_base_path');
const ext = type === 'audio' ? '.mp3' : '.mp4';
@ -375,7 +355,7 @@ exports.deleteUserFile = async function(user_uid, file_uid, type, blacklistMode
}
const full_path = path.join(usersFileFolder, user_uid, type, file_obj.id + ext);
users_db.get('users').find({uid: user_uid}).get(`files.${type}`)
users_db.get('users').find({uid: user_uid}).get(`files`)
.remove({
uid: file_uid
}).write();
@ -424,11 +404,11 @@ exports.deleteUserFile = async function(user_uid, file_uid, type, blacklistMode
return success;
}
exports.changeSharingMode = function(user_uid, file_uid, type, is_playlist, enabled) {
exports.changeSharingMode = function(user_uid, file_uid, is_playlist, enabled) {
let success = false;
const user_db_obj = users_db.get('users').find({uid: user_uid});
if (user_db_obj.value()) {
const file_db_obj = is_playlist ? user_db_obj.get(`playlists.${type}`).find({id: file_uid}) : user_db_obj.get(`files.${type}`).find({uid: file_uid});
const file_db_obj = is_playlist ? user_db_obj.get(`playlists`).find({id: file_uid}) : user_db_obj.get(`files`).find({uid: file_uid});
if (file_db_obj.value()) {
success = true;
file_db_obj.assign({sharingEnabled: enabled}).write();

@ -32,9 +32,9 @@ function registerFileDB(file_path, type, multiUserMode = null, sub = null, custo
if (!sub) {
if (multiUserMode) {
const user_uid = multiUserMode.user;
db_path = users_db.get('users').find({uid: user_uid}).get(`files.${type}`);
db_path = users_db.get('users').find({uid: user_uid}).get(`files`);
} else {
db_path = db.get(`files.${type}`)
db_path = db.get(`files`);
}
} else {
if (multiUserMode) {
@ -94,18 +94,18 @@ function generateFileObject(id, type, customPath = null, sub = null) {
var thumbnail = jsonobj.thumbnail;
var duration = jsonobj.duration;
var isaudio = type === 'audio';
var file_obj = new utils.File(id, title, thumbnail, isaudio, duration, url, uploader, size, file_path, upload_date);
var description = jsonobj.description;
var file_obj = new utils.File(id, title, thumbnail, isaudio, duration, url, uploader, size, file_path, upload_date, description);
return file_obj;
}
function updatePlaylist(playlist, user_uid) {
let playlistID = playlist.id;
let type = playlist.type;
let db_loc = null;
if (user_uid) {
db_loc = users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).find({id: playlistID});
db_loc = users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlistID});
} else {
db_loc = db.get(`playlists.${type}`).find({id: playlistID});
db_loc = db.get(`playlists`).find({id: playlistID});
}
db_loc.assign(playlist).write();
return true;
@ -132,14 +132,14 @@ function getFileDirectoriesAndDBs() {
// add user's audio dir to check list
dirs_to_check.push({
basePath: path.join(usersFileFolder, user.uid, 'audio'),
dbPath: users_db.get('users').find({uid: user.uid}).get('files.audio'),
dbPath: users_db.get('users').find({uid: user.uid}).get('files'),
type: 'audio'
});
// add user's video dir to check list
dirs_to_check.push({
basePath: path.join(usersFileFolder, user.uid, 'video'),
dbPath: users_db.get('users').find({uid: user.uid}).get('files.video'),
dbPath: users_db.get('users').find({uid: user.uid}).get('files'),
type: 'video'
});
}
@ -153,14 +153,14 @@ function getFileDirectoriesAndDBs() {
// add audio dir to check list
dirs_to_check.push({
basePath: audioFolderPath,
dbPath: db.get('files.audio'),
dbPath: db.get('files'),
type: 'audio'
});
// add video dir to check list
dirs_to_check.push({
basePath: videoFolderPath,
dbPath: db.get('files.video'),
dbPath: db.get('files'),
type: 'video'
});
}

@ -189,7 +189,7 @@ async function recFindByExt(base,ext,files,result)
// objects
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date) {
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date, description) {
this.id = id;
this.title = title;
this.thumbnailURL = thumbnailURL;
@ -200,6 +200,7 @@ function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, p
this.size = size;
this.path = path;
this.upload_date = upload_date;
this.description = description;
}
module.exports = {

@ -81,6 +81,7 @@ import { EditSubscriptionDialogComponent } from './dialogs/edit-subscription-dia
import { CustomPlaylistsComponent } from './components/custom-playlists/custom-playlists.component';
import { EditCategoryDialogComponent } from './dialogs/edit-category-dialog/edit-category-dialog.component';
import { TwitchChatComponent } from './components/twitch-chat/twitch-chat.component';
import { LinkifyPipe, SeeMoreComponent } from './components/see-more/see-more.component';
registerLocaleData(es, 'es');
@ -107,6 +108,7 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
VideoInfoDialogComponent,
ArgModifierDialogComponent,
HighlightPipe,
LinkifyPipe,
UpdaterComponent,
UpdateProgressDialogComponent,
ShareMediaDialogComponent,
@ -127,7 +129,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
EditSubscriptionDialogComponent,
CustomPlaylistsComponent,
EditCategoryDialogComponent,
TwitchChatComponent
TwitchChatComponent,
SeeMoreComponent
],
imports: [
CommonModule,
@ -188,7 +191,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
PostsService
],
exports: [
HighlightPipe
HighlightPipe,
LinkifyPipe
],
bootstrap: [AppComponent]
})

@ -0,0 +1,11 @@
<span class="text" [ngStyle]="{'-webkit-line-clamp': !see_more_active ? line_limit : null}" [innerHTML]="text | linkify"></span>
<span>
<a [routerLink]="" (click)="toggleSeeMore()">
<ng-container *ngIf="!see_more_active" i18n="See more">
See more.
</ng-container>
<ng-container *ngIf="see_more_active" i18n="See less">
See less.
</ng-container>
</a>
</span>

@ -0,0 +1,7 @@
.text {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
word-wrap: break-word;
}

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SeeMoreComponent } from './see-more.component';
describe('SeeMoreComponent', () => {
let component: SeeMoreComponent;
let fixture: ComponentFixture<SeeMoreComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SeeMoreComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SeeMoreComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,60 @@
import { Component, Input, OnInit, Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({ name: 'linkify' })
export class LinkifyPipe implements PipeTransform {
constructor(private _domSanitizer: DomSanitizer) {}
transform(value: any, args?: any): any {
return this._domSanitizer.bypassSecurityTrustHtml(this.stylize(value));
}
// Modify this method according to your custom logic
private stylize(text: string): string {
let stylizedText: string = '';
if (text && text.length > 0) {
for (let line of text.split("\n")) {
for (let t of line.split(" ")) {
if (t.startsWith("http") && t.length>7) {
stylizedText += `<a target="_blank" href="${t}">${t}</a> `;
}
else
stylizedText += t + " ";
}
stylizedText += '<br>';
}
return stylizedText;
}
else return text;
}
}
@Component({
selector: 'app-see-more',
templateUrl: './see-more.component.html',
providers: [LinkifyPipe],
styleUrls: ['./see-more.component.scss']
})
export class SeeMoreComponent implements OnInit {
see_more_active = false;
@Input() text = '';
@Input() line_limit = 2;
constructor() { }
ngOnInit(): void {
}
toggleSeeMore() {
this.see_more_active = !this.see_more_active;
}
parseText() {
return this.text.replace(/(http.*?\s)/, "<a href=\"$1\">$1</a>")
}
}

@ -8,14 +8,28 @@
</video>
</vg-player>
</div>
<div *ngIf="file_obj" style="height: fit-content; width: 100%; margin-top: 10px;">
<div *ngIf="db_file" style="height: fit-content; width: 100%; margin-top: 10px;">
<div class="container">
<div class="row">
<div class="col">
<ng-container *ngIf="file_obj">{{file_obj['local_play_count'] ? file_obj['local_play_count'] : 0}}&nbsp;<ng-container i18n="View count label">views</ng-container></ng-container>
<div class="col-2 col-lg-1">
<ng-container *ngIf="db_file">{{db_file['local_view_count'] ? db_file['local_view_count'] : 0}}&nbsp;<ng-container i18n="View count label">views</ng-container></ng-container>
</div>
<div class="col">
<div style="white-space: pre-line;" class="col-9 col-lg-10">
<ng-container *ngIf="db_file && db_file['description']">
<p>
<app-see-more [text]="db_file['description']"></app-see-more>
</p>
</ng-container>
<ng-container *ngIf="!db_file || !db_file['description']">
<p style="text-align: center;">
No description available.
</p>
</ng-container>
</div>
<div class="col-1">
<div *ngIf="db_file && db_file.url.includes('twitch.tv/videos/') && postsService['config']['API']['use_twitch_API']">
<button (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
</div>
</div>
</div>
</div>
@ -25,15 +39,11 @@
<mat-button-toggle cdkDrag *ngFor="let playlist_item of playlist; let i = index" [checked]="currentItem.title === playlist_item.title" (click)="onClickPlaylistItem(playlist_item, i)" class="toggle-button" [value]="playlist_item.title">{{playlist_item.label}}</mat-button-toggle>
</mat-button-toggle-group>
</div>
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists']">
<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/')">
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime"></app-twitch-chat>
</ng-container>
</mat-drawer>
<div *ngIf="db_file && db_file.url.includes('twitch.tv/videos/') && postsService['config']['API']['use_twitch_API']" style="position: absolute; right: 0px">
<button style="right: 0px; top: -46px;" (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
</div>
<div class="update-playlist-button-div" *ngIf="id && playlistChanged()">
<div class="spinner-div">

Loading…
Cancel
Save