X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Fvideo%2Fvideo-file.ts;h=d48c9f5d4d9a0fccf5b0e2a8a16589ade1dc6cb8;hb=bb4ba6d94c5051fdd665ebe63fffcc105778b8be;hp=0294680046036274b437c96cb3eb94319374e82c;hpb=8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index 029468004..d48c9f5d4 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts @@ -27,21 +27,19 @@ import { VideoRedundancyModel } from '../redundancy/video-redundancy' import { VideoStreamingPlaylistModel } from './video-streaming-playlist' import { FindOptions, Op, QueryTypes, Transaction } from 'sequelize' import { MIMETYPES, MEMOIZE_LENGTH, MEMOIZE_TTL } from '../../initializers/constants' -import { MVideoFile, MVideoFileStreamingPlaylistVideo, MVideoFileVideo } from '../../typings/models/video/video-file' -import { MStreamingPlaylistVideo, MVideo } from '@server/typings/models' +import { MVideoFile, MVideoFileStreamingPlaylistVideo, MVideoFileVideo } from '../../types/models/video/video-file' +import { MStreamingPlaylistVideo, MVideo } from '@server/types/models' import * as memoizee from 'memoizee' +import validator from 'validator' export enum ScopeNames { WITH_VIDEO = 'WITH_VIDEO', - WITH_VIDEO_OR_PLAYLIST = 'WITH_VIDEO_OR_PLAYLIST', WITH_METADATA = 'WITH_METADATA' } -const METADATA_FIELDS = [ 'metadata', 'metadataUrl' ] - @DefaultScope(() => ({ attributes: { - exclude: [ METADATA_FIELDS[0] ] + exclude: [ 'metadata' ] } })) @Scopes(() => ({ @@ -53,35 +51,9 @@ const METADATA_FIELDS = [ 'metadata', 'metadataUrl' ] } ] }, - [ScopeNames.WITH_VIDEO_OR_PLAYLIST]: (videoIdOrUUID: string | number) => { - const where = (typeof videoIdOrUUID === 'number') - ? { id: videoIdOrUUID } - : { uuid: videoIdOrUUID } - - return { - include: [ - { - model: VideoModel.unscoped(), - required: false, - where - }, - { - model: VideoStreamingPlaylistModel.unscoped(), - required: false, - include: [ - { - model: VideoModel.unscoped(), - required: true, - where - } - ] - } - ] - } - }, [ScopeNames.WITH_METADATA]: { attributes: { - include: METADATA_FIELDS + include: [ 'metadata' ] } } })) @@ -151,8 +123,8 @@ export class VideoFileModel extends Model { @Column extname: string - @AllowNull(false) - @Is('VideoFileInfohash', value => throwIfNotValid(value, isVideoFileInfoHashValid, 'info hash')) + @AllowNull(true) + @Is('VideoFileInfohash', value => throwIfNotValid(value, isVideoFileInfoHashValid, 'info hash', true)) @Column infoHash: string @@ -223,10 +195,8 @@ export class VideoFileModel extends Model { static async doesVideoExistForVideoFile (id: number, videoIdOrUUID: number | string) { const videoFile = await VideoFileModel.loadWithVideoOrPlaylist(id, videoIdOrUUID) - return (videoFile?.Video.id === videoIdOrUUID) || - (videoFile?.Video.uuid === videoIdOrUUID) || - (videoFile?.VideoStreamingPlaylist?.Video?.id === videoIdOrUUID) || - (videoFile?.VideoStreamingPlaylist?.Video?.uuid === videoIdOrUUID) + + return !!videoFile } static loadWithMetadata (id: number) { @@ -238,12 +208,41 @@ export class VideoFileModel extends Model { } static loadWithVideoOrPlaylist (id: number, videoIdOrUUID: number | string) { - return VideoFileModel.scope({ - method: [ - ScopeNames.WITH_VIDEO_OR_PLAYLIST, - videoIdOrUUID + const whereVideo = validator.isUUID(videoIdOrUUID + '') + ? { uuid: videoIdOrUUID } + : { id: videoIdOrUUID } + + const options = { + where: { + id + }, + include: [ + { + model: VideoModel.unscoped(), + required: false, + where: whereVideo + }, + { + model: VideoStreamingPlaylistModel.unscoped(), + required: false, + include: [ + { + model: VideoModel.unscoped(), + required: true, + where: whereVideo + } + ] + } ] - }).findByPk(id) + } + + return VideoFileModel.findOne(options) + .then(file => { + // We used `required: false` so check we have at least a video or a streaming playlist + if (!file.Video && !file.VideoStreamingPlaylist) return null + + return file + }) } static listByStreamingPlaylist (streamingPlaylistId: number, transaction: Transaction) { @@ -270,10 +269,11 @@ export class VideoFileModel extends Model { } static getStats () { - const query: FindOptions = { + const webtorrentFilesQuery: FindOptions = { include: [ { attributes: [], + required: true, model: VideoModel.unscoped(), where: { remote: false @@ -282,10 +282,32 @@ export class VideoFileModel extends Model { ] } - return VideoFileModel.aggregate('size', 'SUM', query) - .then(result => ({ - totalLocalVideoFilesSize: parseAggregateResult(result) - })) + const hlsFilesQuery: FindOptions = { + include: [ + { + attributes: [], + required: true, + model: VideoStreamingPlaylistModel.unscoped(), + include: [ + { + attributes: [], + model: VideoModel.unscoped(), + required: true, + where: { + remote: false + } + } + ] + } + ] + } + + return Promise.all([ + VideoFileModel.aggregate('size', 'SUM', webtorrentFilesQuery), + VideoFileModel.aggregate('size', 'SUM', hlsFilesQuery) + ]).then(([ webtorrentResult, hlsResult ]) => ({ + totalLocalVideoFilesSize: parseAggregateResult(webtorrentResult) + parseAggregateResult(hlsResult) + })) } // Redefine upsert because sequelize does not use an appropriate where clause in the update query with 2 unique indexes @@ -312,6 +334,14 @@ export class VideoFileModel extends Model { return element.save({ transaction }) } + static removeHLSFilesOfVideoId (videoStreamingPlaylistId: number) { + const options = { + where: { videoStreamingPlaylistId } + } + + return VideoFileModel.destroy(options) + } + getVideoOrStreamingPlaylist (this: MVideoFileVideo | MVideoFileStreamingPlaylistVideo): MVideo | MStreamingPlaylistVideo { if (this.videoId) return (this as MVideoFileVideo).Video @@ -322,6 +352,14 @@ export class VideoFileModel extends Model { return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname] } + isLive () { + return this.size === -1 + } + + isHLS () { + return !!this.videoStreamingPlaylistId + } + hasSameUniqueKeysThan (other: MVideoFile) { return this.fps === other.fps && this.resolution === other.resolution &&