diff options
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/server/tracker.ts | 73 | ||||
-rw-r--r-- | server/models/server/video-tracker.ts | 30 | ||||
-rw-r--r-- | server/models/video/thumbnail.ts | 5 | ||||
-rw-r--r-- | server/models/video/video-caption.ts | 5 | ||||
-rw-r--r-- | server/models/video/video-file.ts | 9 | ||||
-rw-r--r-- | server/models/video/video-format-utils.ts | 49 | ||||
-rw-r--r-- | server/models/video/video.ts | 54 |
7 files changed, 162 insertions, 63 deletions
diff --git a/server/models/server/tracker.ts b/server/models/server/tracker.ts new file mode 100644 index 000000000..d7c91faad --- /dev/null +++ b/server/models/server/tracker.ts | |||
@@ -0,0 +1,73 @@ | |||
1 | import { AllowNull, BelongsToMany, Column, CreatedAt, Model, Table, UpdatedAt } from 'sequelize-typescript' | ||
2 | import { Transaction } from 'sequelize/types' | ||
3 | import { MTracker } from '@server/types/models/server/tracker' | ||
4 | import { VideoModel } from '../video/video' | ||
5 | import { VideoTrackerModel } from './video-tracker' | ||
6 | |||
7 | @Table({ | ||
8 | tableName: 'tracker', | ||
9 | indexes: [ | ||
10 | { | ||
11 | fields: [ 'url' ], | ||
12 | unique: true | ||
13 | } | ||
14 | ] | ||
15 | }) | ||
16 | export class TrackerModel extends Model { | ||
17 | |||
18 | @AllowNull(false) | ||
19 | @Column | ||
20 | url: string | ||
21 | |||
22 | @CreatedAt | ||
23 | createdAt: Date | ||
24 | |||
25 | @UpdatedAt | ||
26 | updatedAt: Date | ||
27 | |||
28 | @BelongsToMany(() => VideoModel, { | ||
29 | foreignKey: 'trackerId', | ||
30 | through: () => VideoTrackerModel, | ||
31 | onDelete: 'CASCADE' | ||
32 | }) | ||
33 | Videos: VideoModel[] | ||
34 | |||
35 | static listUrlsByVideoId (videoId: number) { | ||
36 | const query = { | ||
37 | include: [ | ||
38 | { | ||
39 | attributes: [ 'id', 'trackerId' ], | ||
40 | model: VideoModel.unscoped(), | ||
41 | required: true, | ||
42 | where: { id: videoId } | ||
43 | } | ||
44 | ] | ||
45 | } | ||
46 | |||
47 | return TrackerModel.findAll(query) | ||
48 | .then(rows => rows.map(rows => rows.url)) | ||
49 | } | ||
50 | |||
51 | static findOrCreateTrackers (trackers: string[], transaction: Transaction): Promise<MTracker[]> { | ||
52 | if (trackers === null) return Promise.resolve([]) | ||
53 | |||
54 | const tasks: Promise<MTracker>[] = [] | ||
55 | trackers.forEach(tracker => { | ||
56 | const query = { | ||
57 | where: { | ||
58 | url: tracker | ||
59 | }, | ||
60 | defaults: { | ||
61 | url: tracker | ||
62 | }, | ||
63 | transaction | ||
64 | } | ||
65 | |||
66 | const promise = TrackerModel.findOrCreate<MTracker>(query) | ||
67 | .then(([ trackerInstance ]) => trackerInstance) | ||
68 | tasks.push(promise) | ||
69 | }) | ||
70 | |||
71 | return Promise.all(tasks) | ||
72 | } | ||
73 | } | ||
diff --git a/server/models/server/video-tracker.ts b/server/models/server/video-tracker.ts new file mode 100644 index 000000000..367bf0117 --- /dev/null +++ b/server/models/server/video-tracker.ts | |||
@@ -0,0 +1,30 @@ | |||
1 | import { Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | ||
2 | import { VideoModel } from '../video/video' | ||
3 | import { TrackerModel } from './tracker' | ||
4 | |||
5 | @Table({ | ||
6 | tableName: 'videoTracker', | ||
7 | indexes: [ | ||
8 | { | ||
9 | fields: [ 'videoId' ] | ||
10 | }, | ||
11 | { | ||
12 | fields: [ 'trackerId' ] | ||
13 | } | ||
14 | ] | ||
15 | }) | ||
16 | export class VideoTrackerModel extends Model { | ||
17 | @CreatedAt | ||
18 | createdAt: Date | ||
19 | |||
20 | @UpdatedAt | ||
21 | updatedAt: Date | ||
22 | |||
23 | @ForeignKey(() => VideoModel) | ||
24 | @Column | ||
25 | videoId: number | ||
26 | |||
27 | @ForeignKey(() => TrackerModel) | ||
28 | @Column | ||
29 | trackerId: number | ||
30 | } | ||
diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts index 9533c8d19..319e1175a 100644 --- a/server/models/video/thumbnail.ts +++ b/server/models/video/thumbnail.ts | |||
@@ -15,7 +15,6 @@ import { | |||
15 | Table, | 15 | Table, |
16 | UpdatedAt | 16 | UpdatedAt |
17 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
18 | import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' | ||
19 | import { afterCommitIfTransaction } from '@server/helpers/database-utils' | 18 | import { afterCommitIfTransaction } from '@server/helpers/database-utils' |
20 | import { MThumbnail, MThumbnailVideo, MVideoWithHost } from '@server/types/models' | 19 | import { MThumbnail, MThumbnailVideo, MVideoWithHost } from '@server/types/models' |
21 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 20 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
@@ -168,10 +167,8 @@ export class ThumbnailModel extends Model { | |||
168 | const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename | 167 | const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename |
169 | 168 | ||
170 | if (video.isOwned()) return WEBSERVER.URL + staticPath | 169 | if (video.isOwned()) return WEBSERVER.URL + staticPath |
171 | if (this.fileUrl) return this.fileUrl | ||
172 | 170 | ||
173 | // Fallback if we don't have a file URL | 171 | return this.fileUrl |
174 | return buildRemoteVideoBaseUrl(video, staticPath) | ||
175 | } | 172 | } |
176 | 173 | ||
177 | getPath () { | 174 | getPath () { |
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts index 71b067335..0bbe9b752 100644 --- a/server/models/video/video-caption.ts +++ b/server/models/video/video-caption.ts | |||
@@ -16,7 +16,6 @@ import { | |||
16 | UpdatedAt | 16 | UpdatedAt |
17 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
18 | import { v4 as uuidv4 } from 'uuid' | 18 | import { v4 as uuidv4 } from 'uuid' |
19 | import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' | ||
20 | import { MVideoCaption, MVideoCaptionFormattable, MVideoCaptionVideo, MVideoWithHost } from '@server/types/models' | 19 | import { MVideoCaption, MVideoCaptionFormattable, MVideoCaptionVideo, MVideoWithHost } from '@server/types/models' |
21 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' | 20 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' |
22 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' | 21 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' |
@@ -208,9 +207,7 @@ export class VideoCaptionModel extends Model { | |||
208 | if (!this.Video) this.Video = video as VideoModel | 207 | if (!this.Video) this.Video = video as VideoModel |
209 | 208 | ||
210 | if (video.isOwned()) return WEBSERVER.URL + this.getCaptionStaticPath() | 209 | if (video.isOwned()) return WEBSERVER.URL + this.getCaptionStaticPath() |
211 | if (this.fileUrl) return this.fileUrl | ||
212 | 210 | ||
213 | // Fallback if we don't have a file URL | 211 | return this.fileUrl |
214 | return buildRemoteVideoBaseUrl(video, this.getCaptionStaticPath()) | ||
215 | } | 212 | } |
216 | } | 213 | } |
diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index 57807cbfd..5a3706259 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts | |||
@@ -427,10 +427,8 @@ export class VideoFileModel extends Model { | |||
427 | if (!this.Video) this.Video = video as VideoModel | 427 | if (!this.Video) this.Video = video as VideoModel |
428 | 428 | ||
429 | if (video.isOwned()) return WEBSERVER.URL + this.getFileStaticPath(video) | 429 | if (video.isOwned()) return WEBSERVER.URL + this.getFileStaticPath(video) |
430 | if (this.fileUrl) return this.fileUrl | ||
431 | 430 | ||
432 | // Fallback if we don't have a file URL | 431 | return this.fileUrl |
433 | return buildRemoteVideoBaseUrl(video, this.getFileStaticPath(video)) | ||
434 | } | 432 | } |
435 | 433 | ||
436 | getFileStaticPath (video: MVideo) { | 434 | getFileStaticPath (video: MVideo) { |
@@ -454,10 +452,7 @@ export class VideoFileModel extends Model { | |||
454 | getRemoteTorrentUrl (video: MVideoWithHost) { | 452 | getRemoteTorrentUrl (video: MVideoWithHost) { |
455 | if (video.isOwned()) throw new Error(`Video ${video.url} is not a remote video`) | 453 | if (video.isOwned()) throw new Error(`Video ${video.url} is not a remote video`) |
456 | 454 | ||
457 | if (this.torrentUrl) return this.torrentUrl | 455 | return this.torrentUrl |
458 | |||
459 | // Fallback if we don't have a torrent URL | ||
460 | return buildRemoteVideoBaseUrl(video, this.getTorrentStaticPath()) | ||
461 | } | 456 | } |
462 | 457 | ||
463 | // We proxify torrent requests so use a local URL | 458 | // We proxify torrent requests so use a local URL |
diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts index adf460734..9dc3e7722 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts | |||
@@ -14,8 +14,6 @@ import { | |||
14 | } from '../../lib/activitypub/url' | 14 | } from '../../lib/activitypub/url' |
15 | import { | 15 | import { |
16 | MStreamingPlaylistRedundanciesOpt, | 16 | MStreamingPlaylistRedundanciesOpt, |
17 | MStreamingPlaylistVideo, | ||
18 | MVideo, | ||
19 | MVideoAP, | 17 | MVideoAP, |
20 | MVideoFile, | 18 | MVideoFile, |
21 | MVideoFormattable, | 19 | MVideoFormattable, |
@@ -127,8 +125,6 @@ function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): Vid | |||
127 | } | 125 | } |
128 | }) | 126 | }) |
129 | 127 | ||
130 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() | ||
131 | |||
132 | const tags = video.Tags ? video.Tags.map(t => t.name) : [] | 128 | const tags = video.Tags ? video.Tags.map(t => t.name) : [] |
133 | 129 | ||
134 | const streamingPlaylists = streamingPlaylistsModelToFormattedJSON(video, video.VideoStreamingPlaylists) | 130 | const streamingPlaylists = streamingPlaylistsModelToFormattedJSON(video, video.VideoStreamingPlaylists) |
@@ -147,14 +143,14 @@ function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): Vid | |||
147 | label: VideoModel.getStateLabel(video.state) | 143 | label: VideoModel.getStateLabel(video.state) |
148 | }, | 144 | }, |
149 | 145 | ||
150 | trackerUrls: video.getTrackerUrls(baseUrlHttp, baseUrlWs), | 146 | trackerUrls: video.getTrackerUrls(), |
151 | 147 | ||
152 | files: [], | 148 | files: [], |
153 | streamingPlaylists | 149 | streamingPlaylists |
154 | } | 150 | } |
155 | 151 | ||
156 | // Format and sort video files | 152 | // Format and sort video files |
157 | detailsJson.files = videoFilesModelToFormattedJSON(video, video, baseUrlHttp, baseUrlWs, video.VideoFiles) | 153 | detailsJson.files = videoFilesModelToFormattedJSON(video, video.VideoFiles) |
158 | 154 | ||
159 | return Object.assign(formattedJson, detailsJson) | 155 | return Object.assign(formattedJson, detailsJson) |
160 | } | 156 | } |
@@ -165,17 +161,13 @@ function streamingPlaylistsModelToFormattedJSON ( | |||
165 | ): VideoStreamingPlaylist[] { | 161 | ): VideoStreamingPlaylist[] { |
166 | if (isArray(playlists) === false) return [] | 162 | if (isArray(playlists) === false) return [] |
167 | 163 | ||
168 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() | ||
169 | |||
170 | return playlists | 164 | return playlists |
171 | .map(playlist => { | 165 | .map(playlist => { |
172 | const playlistWithVideo = Object.assign(playlist, { Video: video }) | ||
173 | |||
174 | const redundancies = isArray(playlist.RedundancyVideos) | 166 | const redundancies = isArray(playlist.RedundancyVideos) |
175 | ? playlist.RedundancyVideos.map(r => ({ baseUrl: r.fileUrl })) | 167 | ? playlist.RedundancyVideos.map(r => ({ baseUrl: r.fileUrl })) |
176 | : [] | 168 | : [] |
177 | 169 | ||
178 | const files = videoFilesModelToFormattedJSON(playlistWithVideo, video, baseUrlHttp, baseUrlWs, playlist.VideoFiles) | 170 | const files = videoFilesModelToFormattedJSON(video, playlist.VideoFiles) |
179 | 171 | ||
180 | return { | 172 | return { |
181 | id: playlist.id, | 173 | id: playlist.id, |
@@ -194,14 +186,12 @@ function sortByResolutionDesc (fileA: MVideoFile, fileB: MVideoFile) { | |||
194 | return -1 | 186 | return -1 |
195 | } | 187 | } |
196 | 188 | ||
197 | // FIXME: refactor/merge model and video arguments | ||
198 | function videoFilesModelToFormattedJSON ( | 189 | function videoFilesModelToFormattedJSON ( |
199 | model: MVideo | MStreamingPlaylistVideo, | ||
200 | video: MVideoFormattableDetails, | 190 | video: MVideoFormattableDetails, |
201 | baseUrlHttp: string, | ||
202 | baseUrlWs: string, | ||
203 | videoFiles: MVideoFileRedundanciesOpt[] | 191 | videoFiles: MVideoFileRedundanciesOpt[] |
204 | ): VideoFile[] { | 192 | ): VideoFile[] { |
193 | const trackerUrls = video.getTrackerUrls() | ||
194 | |||
205 | return [ ...videoFiles ] | 195 | return [ ...videoFiles ] |
206 | .filter(f => !f.isLive()) | 196 | .filter(f => !f.isLive()) |
207 | .sort(sortByResolutionDesc) | 197 | .sort(sortByResolutionDesc) |
@@ -213,7 +203,7 @@ function videoFilesModelToFormattedJSON ( | |||
213 | }, | 203 | }, |
214 | 204 | ||
215 | // FIXME: deprecated in 3.2 | 205 | // FIXME: deprecated in 3.2 |
216 | magnetUri: generateMagnetUri(model, video, videoFile, baseUrlHttp, baseUrlWs), | 206 | magnetUri: generateMagnetUri(video, videoFile, trackerUrls), |
217 | 207 | ||
218 | size: videoFile.size, | 208 | size: videoFile.size, |
219 | fps: videoFile.fps, | 209 | fps: videoFile.fps, |
@@ -229,15 +219,13 @@ function videoFilesModelToFormattedJSON ( | |||
229 | }) | 219 | }) |
230 | } | 220 | } |
231 | 221 | ||
232 | // FIXME: refactor/merge model and video arguments | ||
233 | function addVideoFilesInAPAcc ( | 222 | function addVideoFilesInAPAcc ( |
234 | acc: ActivityUrlObject[] | ActivityTagObject[], | 223 | acc: ActivityUrlObject[] | ActivityTagObject[], |
235 | model: MVideoAP | MStreamingPlaylistVideo, | ||
236 | video: MVideoWithHost, | 224 | video: MVideoWithHost, |
237 | baseUrlHttp: string, | ||
238 | baseUrlWs: string, | ||
239 | files: MVideoFile[] | 225 | files: MVideoFile[] |
240 | ) { | 226 | ) { |
227 | const trackerUrls = video.getTrackerUrls() | ||
228 | |||
241 | const sortedFiles = [ ...files ] | 229 | const sortedFiles = [ ...files ] |
242 | .filter(f => !f.isLive()) | 230 | .filter(f => !f.isLive()) |
243 | .sort(sortByResolutionDesc) | 231 | .sort(sortByResolutionDesc) |
@@ -271,14 +259,13 @@ function addVideoFilesInAPAcc ( | |||
271 | acc.push({ | 259 | acc.push({ |
272 | type: 'Link', | 260 | type: 'Link', |
273 | mediaType: 'application/x-bittorrent;x-scheme-handler/magnet' as 'application/x-bittorrent;x-scheme-handler/magnet', | 261 | mediaType: 'application/x-bittorrent;x-scheme-handler/magnet' as 'application/x-bittorrent;x-scheme-handler/magnet', |
274 | href: generateMagnetUri(model, video, file, baseUrlHttp, baseUrlWs), | 262 | href: generateMagnetUri(video, file, trackerUrls), |
275 | height: file.resolution | 263 | height: file.resolution |
276 | }) | 264 | }) |
277 | } | 265 | } |
278 | } | 266 | } |
279 | 267 | ||
280 | function videoModelToActivityPubObject (video: MVideoAP): VideoObject { | 268 | function videoModelToActivityPubObject (video: MVideoAP): VideoObject { |
281 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() | ||
282 | if (!video.Tags) video.Tags = [] | 269 | if (!video.Tags) video.Tags = [] |
283 | 270 | ||
284 | const tag = video.Tags.map(t => ({ | 271 | const tag = video.Tags.map(t => ({ |
@@ -319,7 +306,7 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject { | |||
319 | } | 306 | } |
320 | ] | 307 | ] |
321 | 308 | ||
322 | addVideoFilesInAPAcc(url, video, video, baseUrlHttp, baseUrlWs, video.VideoFiles || []) | 309 | addVideoFilesInAPAcc(url, video, video.VideoFiles || []) |
323 | 310 | ||
324 | for (const playlist of (video.VideoStreamingPlaylists || [])) { | 311 | for (const playlist of (video.VideoStreamingPlaylists || [])) { |
325 | const tag = playlist.p2pMediaLoaderInfohashes | 312 | const tag = playlist.p2pMediaLoaderInfohashes |
@@ -331,8 +318,7 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject { | |||
331 | href: playlist.segmentsSha256Url | 318 | href: playlist.segmentsSha256Url |
332 | }) | 319 | }) |
333 | 320 | ||
334 | const playlistWithVideo = Object.assign(playlist, { Video: video }) | 321 | addVideoFilesInAPAcc(tag, video, playlist.VideoFiles || []) |
335 | addVideoFilesInAPAcc(tag, playlistWithVideo, video, baseUrlHttp, baseUrlWs, playlist.VideoFiles || []) | ||
336 | 322 | ||
337 | url.push({ | 323 | url.push({ |
338 | type: 'Link', | 324 | type: 'Link', |
@@ -342,6 +328,19 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoObject { | |||
342 | }) | 328 | }) |
343 | } | 329 | } |
344 | 330 | ||
331 | for (const trackerUrl of video.getTrackerUrls()) { | ||
332 | const rel2 = trackerUrl.startsWith('http') | ||
333 | ? 'http' | ||
334 | : 'websocket' | ||
335 | |||
336 | url.push({ | ||
337 | type: 'Link', | ||
338 | name: `tracker-${rel2}`, | ||
339 | rel: [ 'tracker', rel2 ], | ||
340 | href: trackerUrl | ||
341 | }) | ||
342 | } | ||
343 | |||
345 | const subtitleLanguage = [] | 344 | const subtitleLanguage = [] |
346 | for (const caption of video.VideoCaptions) { | 345 | for (const caption of video.VideoCaptions) { |
347 | subtitleLanguage.push({ | 346 | subtitleLanguage.push({ |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 2e6b6aeec..9e67ca0f4 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -60,7 +60,6 @@ import { | |||
60 | API_VERSION, | 60 | API_VERSION, |
61 | CONSTRAINTS_FIELDS, | 61 | CONSTRAINTS_FIELDS, |
62 | LAZY_STATIC_PATHS, | 62 | LAZY_STATIC_PATHS, |
63 | REMOTE_SCHEME, | ||
64 | STATIC_PATHS, | 63 | STATIC_PATHS, |
65 | VIDEO_CATEGORIES, | 64 | VIDEO_CATEGORIES, |
66 | VIDEO_LANGUAGES, | 65 | VIDEO_LANGUAGES, |
@@ -107,6 +106,8 @@ import { ActorModel } from '../activitypub/actor' | |||
107 | import { AvatarModel } from '../avatar/avatar' | 106 | import { AvatarModel } from '../avatar/avatar' |
108 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' | 107 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' |
109 | import { ServerModel } from '../server/server' | 108 | import { ServerModel } from '../server/server' |
109 | import { TrackerModel } from '../server/tracker' | ||
110 | import { VideoTrackerModel } from '../server/video-tracker' | ||
110 | import { buildTrigramSearchIndex, buildWhereIdOrUUID, getVideoSort, isOutdated, throwIfNotValid } from '../utils' | 111 | import { buildTrigramSearchIndex, buildWhereIdOrUUID, getVideoSort, isOutdated, throwIfNotValid } from '../utils' |
111 | import { ScheduleVideoUpdateModel } from './schedule-video-update' | 112 | import { ScheduleVideoUpdateModel } from './schedule-video-update' |
112 | import { TagModel } from './tag' | 113 | import { TagModel } from './tag' |
@@ -137,6 +138,7 @@ export enum ScopeNames { | |||
137 | FOR_API = 'FOR_API', | 138 | FOR_API = 'FOR_API', |
138 | WITH_ACCOUNT_DETAILS = 'WITH_ACCOUNT_DETAILS', | 139 | WITH_ACCOUNT_DETAILS = 'WITH_ACCOUNT_DETAILS', |
139 | WITH_TAGS = 'WITH_TAGS', | 140 | WITH_TAGS = 'WITH_TAGS', |
141 | WITH_TRACKERS = 'WITH_TRACKERS', | ||
140 | WITH_WEBTORRENT_FILES = 'WITH_WEBTORRENT_FILES', | 142 | WITH_WEBTORRENT_FILES = 'WITH_WEBTORRENT_FILES', |
141 | WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE', | 143 | WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE', |
142 | WITH_BLACKLISTED = 'WITH_BLACKLISTED', | 144 | WITH_BLACKLISTED = 'WITH_BLACKLISTED', |
@@ -320,6 +322,14 @@ export type AvailableForListIDsOptions = { | |||
320 | [ScopeNames.WITH_TAGS]: { | 322 | [ScopeNames.WITH_TAGS]: { |
321 | include: [ TagModel ] | 323 | include: [ TagModel ] |
322 | }, | 324 | }, |
325 | [ScopeNames.WITH_TRACKERS]: { | ||
326 | include: [ | ||
327 | { | ||
328 | attributes: [ 'id', 'url' ], | ||
329 | model: TrackerModel | ||
330 | } | ||
331 | ] | ||
332 | }, | ||
323 | [ScopeNames.WITH_BLACKLISTED]: { | 333 | [ScopeNames.WITH_BLACKLISTED]: { |
324 | include: [ | 334 | include: [ |
325 | { | 335 | { |
@@ -616,6 +626,13 @@ export class VideoModel extends Model { | |||
616 | }) | 626 | }) |
617 | Tags: TagModel[] | 627 | Tags: TagModel[] |
618 | 628 | ||
629 | @BelongsToMany(() => TrackerModel, { | ||
630 | foreignKey: 'videoId', | ||
631 | through: () => VideoTrackerModel, | ||
632 | onDelete: 'CASCADE' | ||
633 | }) | ||
634 | Trackers: TrackerModel[] | ||
635 | |||
619 | @HasMany(() => ThumbnailModel, { | 636 | @HasMany(() => ThumbnailModel, { |
620 | foreignKey: { | 637 | foreignKey: { |
621 | name: 'videoId', | 638 | name: 'videoId', |
@@ -1436,6 +1453,7 @@ export class VideoModel extends Model { | |||
1436 | ScopeNames.WITH_SCHEDULED_UPDATE, | 1453 | ScopeNames.WITH_SCHEDULED_UPDATE, |
1437 | ScopeNames.WITH_THUMBNAILS, | 1454 | ScopeNames.WITH_THUMBNAILS, |
1438 | ScopeNames.WITH_LIVE, | 1455 | ScopeNames.WITH_LIVE, |
1456 | ScopeNames.WITH_TRACKERS, | ||
1439 | { method: [ ScopeNames.WITH_WEBTORRENT_FILES, true ] }, | 1457 | { method: [ ScopeNames.WITH_WEBTORRENT_FILES, true ] }, |
1440 | { method: [ ScopeNames.WITH_STREAMING_PLAYLISTS, true ] } | 1458 | { method: [ ScopeNames.WITH_STREAMING_PLAYLISTS, true ] } |
1441 | ] | 1459 | ] |
@@ -1887,18 +1905,15 @@ export class VideoModel extends Model { | |||
1887 | } | 1905 | } |
1888 | 1906 | ||
1889 | getFormattedVideoFilesJSON (): VideoFile[] { | 1907 | getFormattedVideoFilesJSON (): VideoFile[] { |
1890 | const { baseUrlHttp, baseUrlWs } = this.getBaseUrls() | ||
1891 | let files: VideoFile[] = [] | 1908 | let files: VideoFile[] = [] |
1892 | 1909 | ||
1893 | if (Array.isArray(this.VideoFiles)) { | 1910 | if (Array.isArray(this.VideoFiles)) { |
1894 | const result = videoFilesModelToFormattedJSON(this, this, baseUrlHttp, baseUrlWs, this.VideoFiles) | 1911 | const result = videoFilesModelToFormattedJSON(this, this.VideoFiles) |
1895 | files = files.concat(result) | 1912 | files = files.concat(result) |
1896 | } | 1913 | } |
1897 | 1914 | ||
1898 | for (const p of (this.VideoStreamingPlaylists || [])) { | 1915 | for (const p of (this.VideoStreamingPlaylists || [])) { |
1899 | p.Video = this | 1916 | const result = videoFilesModelToFormattedJSON(this, p.VideoFiles) |
1900 | |||
1901 | const result = videoFilesModelToFormattedJSON(p, this, baseUrlHttp, baseUrlWs, p.VideoFiles) | ||
1902 | files = files.concat(result) | 1917 | files = files.concat(result) |
1903 | } | 1918 | } |
1904 | 1919 | ||
@@ -2030,25 +2045,18 @@ export class VideoModel extends Model { | |||
2030 | return false | 2045 | return false |
2031 | } | 2046 | } |
2032 | 2047 | ||
2033 | getBaseUrls () { | 2048 | getBandwidthBits (videoFile: MVideoFile) { |
2034 | if (this.isOwned()) { | 2049 | return Math.ceil((videoFile.size * 8) / this.duration) |
2035 | return { | ||
2036 | baseUrlHttp: WEBSERVER.URL, | ||
2037 | baseUrlWs: WEBSERVER.WS + '://' + WEBSERVER.HOSTNAME + ':' + WEBSERVER.PORT | ||
2038 | } | ||
2039 | } | ||
2040 | |||
2041 | return { | ||
2042 | baseUrlHttp: REMOTE_SCHEME.HTTP + '://' + this.VideoChannel.Account.Actor.Server.host, | ||
2043 | baseUrlWs: REMOTE_SCHEME.WS + '://' + this.VideoChannel.Account.Actor.Server.host | ||
2044 | } | ||
2045 | } | 2050 | } |
2046 | 2051 | ||
2047 | getTrackerUrls (baseUrlHttp: string, baseUrlWs: string) { | 2052 | getTrackerUrls () { |
2048 | return [ baseUrlWs + '/tracker/socket', baseUrlHttp + '/tracker/announce' ] | 2053 | if (this.isOwned()) { |
2049 | } | 2054 | return [ |
2055 | WEBSERVER.URL + '/tracker/announce', | ||
2056 | WEBSERVER.WS + '://' + WEBSERVER.HOSTNAME + ':' + WEBSERVER.PORT + '/tracker/socket' | ||
2057 | ] | ||
2058 | } | ||
2050 | 2059 | ||
2051 | getBandwidthBits (videoFile: MVideoFile) { | 2060 | return this.Trackers.map(t => t.url) |
2052 | return Math.ceil((videoFile.size * 8) / this.duration) | ||
2053 | } | 2061 | } |
2054 | } | 2062 | } |