diff options
Diffstat (limited to 'server/models/video')
-rw-r--r-- | server/models/video/video-caption.ts | 58 | ||||
-rw-r--r-- | server/models/video/video-playlist.ts | 2 |
2 files changed, 41 insertions, 19 deletions
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts index e8e883dd0..a1553ea15 100644 --- a/server/models/video/video-caption.ts +++ b/server/models/video/video-caption.ts | |||
@@ -16,7 +16,7 @@ import { | |||
16 | UpdatedAt | 16 | UpdatedAt |
17 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
18 | import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' | 18 | import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' |
19 | import { MVideoAccountLight, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/types/models' | 19 | import { MVideoAccountLight, MVideoCaption, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/types/models' |
20 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' | 20 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' |
21 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' | 21 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' |
22 | import { logger } from '../../helpers/logger' | 22 | import { logger } from '../../helpers/logger' |
@@ -24,6 +24,7 @@ import { CONFIG } from '../../initializers/config' | |||
24 | import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants' | 24 | import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants' |
25 | import { buildWhereIdOrUUID, throwIfNotValid } from '../utils' | 25 | import { buildWhereIdOrUUID, throwIfNotValid } from '../utils' |
26 | import { VideoModel } from './video' | 26 | import { VideoModel } from './video' |
27 | import { v4 as uuidv4 } from 'uuid' | ||
27 | 28 | ||
28 | export enum ScopeNames { | 29 | export enum ScopeNames { |
29 | WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE' | 30 | WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE' |
@@ -45,6 +46,10 @@ export enum ScopeNames { | |||
45 | tableName: 'videoCaption', | 46 | tableName: 'videoCaption', |
46 | indexes: [ | 47 | indexes: [ |
47 | { | 48 | { |
49 | fields: [ 'filename' ], | ||
50 | unique: true | ||
51 | }, | ||
52 | { | ||
48 | fields: [ 'videoId' ] | 53 | fields: [ 'videoId' ] |
49 | }, | 54 | }, |
50 | { | 55 | { |
@@ -65,6 +70,10 @@ export class VideoCaptionModel extends Model { | |||
65 | @Column | 70 | @Column |
66 | language: string | 71 | language: string |
67 | 72 | ||
73 | @AllowNull(false) | ||
74 | @Column | ||
75 | filename: string | ||
76 | |||
68 | @AllowNull(true) | 77 | @AllowNull(true) |
69 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.COMMONS.URL.max)) | 78 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.COMMONS.URL.max)) |
70 | fileUrl: string | 79 | fileUrl: string |
@@ -88,12 +97,12 @@ export class VideoCaptionModel extends Model { | |||
88 | } | 97 | } |
89 | 98 | ||
90 | if (instance.isOwned()) { | 99 | if (instance.isOwned()) { |
91 | logger.info('Removing captions %s of video %s.', instance.Video.uuid, instance.language) | 100 | logger.info('Removing caption %s.', instance.filename) |
92 | 101 | ||
93 | try { | 102 | try { |
94 | await instance.removeCaptionFile() | 103 | await instance.removeCaptionFile() |
95 | } catch (err) { | 104 | } catch (err) { |
96 | logger.error('Cannot remove caption file of video %s.', instance.Video.uuid) | 105 | logger.error('Cannot remove caption file %s.', instance.filename) |
97 | } | 106 | } |
98 | } | 107 | } |
99 | 108 | ||
@@ -119,15 +128,28 @@ export class VideoCaptionModel extends Model { | |||
119 | return VideoCaptionModel.findOne(query) | 128 | return VideoCaptionModel.findOne(query) |
120 | } | 129 | } |
121 | 130 | ||
122 | static insertOrReplaceLanguage (videoId: number, language: string, fileUrl: string, transaction: Transaction) { | 131 | static loadWithVideoByFilename (filename: string): Promise<MVideoCaptionVideo> { |
123 | const values = { | 132 | const query = { |
124 | videoId, | 133 | where: { |
125 | language, | 134 | filename |
126 | fileUrl | 135 | }, |
136 | include: [ | ||
137 | { | ||
138 | model: VideoModel.unscoped(), | ||
139 | attributes: [ 'id', 'remote', 'uuid' ] | ||
140 | } | ||
141 | ] | ||
127 | } | 142 | } |
128 | 143 | ||
129 | return VideoCaptionModel.upsert(values, { transaction, returning: true }) | 144 | return VideoCaptionModel.findOne(query) |
130 | .then(([ caption ]) => caption) | 145 | } |
146 | |||
147 | static async insertOrReplaceLanguage (caption: MVideoCaption, transaction: Transaction) { | ||
148 | const existing = await VideoCaptionModel.loadByVideoIdAndLanguage(caption.videoId, caption.language) | ||
149 | // Delete existing file | ||
150 | if (existing) await existing.destroy({ transaction }) | ||
151 | |||
152 | return caption.save({ transaction }) | ||
131 | } | 153 | } |
132 | 154 | ||
133 | static listVideoCaptions (videoId: number): Promise<MVideoCaptionVideo[]> { | 155 | static listVideoCaptions (videoId: number): Promise<MVideoCaptionVideo[]> { |
@@ -156,6 +178,10 @@ export class VideoCaptionModel extends Model { | |||
156 | return VideoCaptionModel.destroy(query) | 178 | return VideoCaptionModel.destroy(query) |
157 | } | 179 | } |
158 | 180 | ||
181 | static generateCaptionName (language: string) { | ||
182 | return `${uuidv4()}-${language}.vtt` | ||
183 | } | ||
184 | |||
159 | isOwned () { | 185 | isOwned () { |
160 | return this.Video.remote === false | 186 | return this.Video.remote === false |
161 | } | 187 | } |
@@ -170,16 +196,12 @@ export class VideoCaptionModel extends Model { | |||
170 | } | 196 | } |
171 | } | 197 | } |
172 | 198 | ||
173 | getCaptionStaticPath (this: MVideoCaptionFormattable) { | 199 | getCaptionStaticPath (this: MVideoCaption) { |
174 | return join(LAZY_STATIC_PATHS.VIDEO_CAPTIONS, this.getCaptionName()) | 200 | return join(LAZY_STATIC_PATHS.VIDEO_CAPTIONS, this.filename) |
175 | } | ||
176 | |||
177 | getCaptionName (this: MVideoCaptionFormattable) { | ||
178 | return `${this.Video.uuid}-${this.language}.vtt` | ||
179 | } | 201 | } |
180 | 202 | ||
181 | removeCaptionFile (this: MVideoCaptionFormattable) { | 203 | removeCaptionFile (this: MVideoCaption) { |
182 | return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.getCaptionName()) | 204 | return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.filename) |
183 | } | 205 | } |
184 | 206 | ||
185 | getFileUrl (video: MVideoAccountLight) { | 207 | getFileUrl (video: MVideoAccountLight) { |
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index 93ecf8cea..9e6ff1f81 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts | |||
@@ -471,7 +471,7 @@ export class VideoPlaylistModel extends Model { | |||
471 | generateThumbnailName () { | 471 | generateThumbnailName () { |
472 | const extension = '.jpg' | 472 | const extension = '.jpg' |
473 | 473 | ||
474 | return 'playlist-' + this.uuid + extension | 474 | return 'playlist-' + uuidv4() + extension |
475 | } | 475 | } |
476 | 476 | ||
477 | getThumbnailUrl () { | 477 | getThumbnailUrl () { |