diff options
Diffstat (limited to 'server/models/video/video.ts')
-rw-r--r-- | server/models/video/video.ts | 204 |
1 files changed, 96 insertions, 108 deletions
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 0d1dbf106..f84a90992 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1,7 +1,5 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { maxBy } from 'lodash' | 2 | import { maxBy } from 'lodash' |
3 | import * as magnetUtil from 'magnet-uri' | ||
4 | import * as parseTorrent from 'parse-torrent' | ||
5 | import { join } from 'path' | 3 | import { join } from 'path' |
6 | import { | 4 | import { |
7 | CountOptions, | 5 | CountOptions, |
@@ -38,11 +36,11 @@ import { | |||
38 | } from 'sequelize-typescript' | 36 | } from 'sequelize-typescript' |
39 | import { UserRight, VideoPrivacy, VideoState } from '../../../shared' | 37 | import { UserRight, VideoPrivacy, VideoState } from '../../../shared' |
40 | import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' | 38 | import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' |
41 | import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' | 39 | import { Video, VideoDetails } from '../../../shared/models/videos' |
42 | import { VideoFilter } from '../../../shared/models/videos/video-query.type' | 40 | import { VideoFilter } from '../../../shared/models/videos/video-query.type' |
43 | import { peertubeTruncate } from '../../helpers/core-utils' | 41 | import { peertubeTruncate } from '../../helpers/core-utils' |
44 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 42 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
45 | import { isArray, isBooleanValid } from '../../helpers/custom-validators/misc' | 43 | import { isBooleanValid } from '../../helpers/custom-validators/misc' |
46 | import { | 44 | import { |
47 | isVideoCategoryValid, | 45 | isVideoCategoryValid, |
48 | isVideoDescriptionValid, | 46 | isVideoDescriptionValid, |
@@ -100,7 +98,7 @@ import { VideoTagModel } from './video-tag' | |||
100 | import { ScheduleVideoUpdateModel } from './schedule-video-update' | 98 | import { ScheduleVideoUpdateModel } from './schedule-video-update' |
101 | import { VideoCaptionModel } from './video-caption' | 99 | import { VideoCaptionModel } from './video-caption' |
102 | import { VideoBlacklistModel } from './video-blacklist' | 100 | import { VideoBlacklistModel } from './video-blacklist' |
103 | import { remove, writeFile } from 'fs-extra' | 101 | import { remove } from 'fs-extra' |
104 | import { VideoViewModel } from './video-views' | 102 | import { VideoViewModel } from './video-views' |
105 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' | 103 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' |
106 | import { | 104 | import { |
@@ -117,18 +115,20 @@ import { VideoPlaylistElementModel } from './video-playlist-element' | |||
117 | import { CONFIG } from '../../initializers/config' | 115 | import { CONFIG } from '../../initializers/config' |
118 | import { ThumbnailModel } from './thumbnail' | 116 | import { ThumbnailModel } from './thumbnail' |
119 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 117 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
120 | import { createTorrentPromise } from '../../helpers/webtorrent' | ||
121 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 118 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
122 | import { | 119 | import { |
123 | MChannel, | 120 | MChannel, |
124 | MChannelAccountDefault, | 121 | MChannelAccountDefault, |
125 | MChannelId, | 122 | MChannelId, |
123 | MStreamingPlaylist, | ||
124 | MStreamingPlaylistFilesVideo, | ||
126 | MUserAccountId, | 125 | MUserAccountId, |
127 | MUserId, | 126 | MUserId, |
128 | MVideoAccountLight, | 127 | MVideoAccountLight, |
129 | MVideoAccountLightBlacklistAllFiles, | 128 | MVideoAccountLightBlacklistAllFiles, |
130 | MVideoAP, | 129 | MVideoAP, |
131 | MVideoDetails, | 130 | MVideoDetails, |
131 | MVideoFileVideo, | ||
132 | MVideoFormattable, | 132 | MVideoFormattable, |
133 | MVideoFormattableDetails, | 133 | MVideoFormattableDetails, |
134 | MVideoForUser, | 134 | MVideoForUser, |
@@ -140,8 +140,10 @@ import { | |||
140 | MVideoWithFile, | 140 | MVideoWithFile, |
141 | MVideoWithRights | 141 | MVideoWithRights |
142 | } from '../../typings/models' | 142 | } from '../../typings/models' |
143 | import { MVideoFile, MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file' | 143 | import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file' |
144 | import { MThumbnail } from '../../typings/models/video/thumbnail' | 144 | import { MThumbnail } from '../../typings/models/video/thumbnail' |
145 | import { VideoFile } from '@shared/models/videos/video-file.model' | ||
146 | import { getTorrentFileName, getTorrentFilePath, getVideoFilename, getVideoFilePath } from '@server/lib/video-paths' | ||
145 | 147 | ||
146 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 148 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
147 | const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ | 149 | const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ |
@@ -211,7 +213,7 @@ export enum ScopeNames { | |||
211 | FOR_API = 'FOR_API', | 213 | FOR_API = 'FOR_API', |
212 | WITH_ACCOUNT_DETAILS = 'WITH_ACCOUNT_DETAILS', | 214 | WITH_ACCOUNT_DETAILS = 'WITH_ACCOUNT_DETAILS', |
213 | WITH_TAGS = 'WITH_TAGS', | 215 | WITH_TAGS = 'WITH_TAGS', |
214 | WITH_FILES = 'WITH_FILES', | 216 | WITH_WEBTORRENT_FILES = 'WITH_WEBTORRENT_FILES', |
215 | WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE', | 217 | WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE', |
216 | WITH_BLACKLISTED = 'WITH_BLACKLISTED', | 218 | WITH_BLACKLISTED = 'WITH_BLACKLISTED', |
217 | WITH_BLOCKLIST = 'WITH_BLOCKLIST', | 219 | WITH_BLOCKLIST = 'WITH_BLOCKLIST', |
@@ -666,7 +668,7 @@ export type AvailableForListIDsOptions = { | |||
666 | } | 668 | } |
667 | ] | 669 | ] |
668 | }, | 670 | }, |
669 | [ ScopeNames.WITH_FILES ]: (withRedundancies = false) => { | 671 | [ ScopeNames.WITH_WEBTORRENT_FILES ]: (withRedundancies = false) => { |
670 | let subInclude: any[] = [] | 672 | let subInclude: any[] = [] |
671 | 673 | ||
672 | if (withRedundancies === true) { | 674 | if (withRedundancies === true) { |
@@ -691,16 +693,19 @@ export type AvailableForListIDsOptions = { | |||
691 | } | 693 | } |
692 | }, | 694 | }, |
693 | [ ScopeNames.WITH_STREAMING_PLAYLISTS ]: (withRedundancies = false) => { | 695 | [ ScopeNames.WITH_STREAMING_PLAYLISTS ]: (withRedundancies = false) => { |
694 | let subInclude: any[] = [] | 696 | const subInclude: IncludeOptions[] = [ |
697 | { | ||
698 | model: VideoFileModel.unscoped(), | ||
699 | required: false | ||
700 | } | ||
701 | ] | ||
695 | 702 | ||
696 | if (withRedundancies === true) { | 703 | if (withRedundancies === true) { |
697 | subInclude = [ | 704 | subInclude.push({ |
698 | { | 705 | attributes: [ 'fileUrl' ], |
699 | attributes: [ 'fileUrl' ], | 706 | model: VideoRedundancyModel.unscoped(), |
700 | model: VideoRedundancyModel.unscoped(), | 707 | required: false |
701 | required: false | 708 | }) |
702 | } | ||
703 | ] | ||
704 | } | 709 | } |
705 | 710 | ||
706 | return { | 711 | return { |
@@ -913,7 +918,7 @@ export class VideoModel extends Model<VideoModel> { | |||
913 | @HasMany(() => VideoFileModel, { | 918 | @HasMany(() => VideoFileModel, { |
914 | foreignKey: { | 919 | foreignKey: { |
915 | name: 'videoId', | 920 | name: 'videoId', |
916 | allowNull: false | 921 | allowNull: true |
917 | }, | 922 | }, |
918 | hooks: true, | 923 | hooks: true, |
919 | onDelete: 'cascade' | 924 | onDelete: 'cascade' |
@@ -1071,7 +1076,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1071 | } | 1076 | } |
1072 | 1077 | ||
1073 | return VideoModel.scope([ | 1078 | return VideoModel.scope([ |
1074 | ScopeNames.WITH_FILES, | 1079 | ScopeNames.WITH_WEBTORRENT_FILES, |
1075 | ScopeNames.WITH_STREAMING_PLAYLISTS, | 1080 | ScopeNames.WITH_STREAMING_PLAYLISTS, |
1076 | ScopeNames.WITH_THUMBNAILS | 1081 | ScopeNames.WITH_THUMBNAILS |
1077 | ]).findAll(query) | 1082 | ]).findAll(query) |
@@ -1463,7 +1468,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1463 | } | 1468 | } |
1464 | 1469 | ||
1465 | return VideoModel.scope([ | 1470 | return VideoModel.scope([ |
1466 | ScopeNames.WITH_FILES, | 1471 | ScopeNames.WITH_WEBTORRENT_FILES, |
1467 | ScopeNames.WITH_STREAMING_PLAYLISTS, | 1472 | ScopeNames.WITH_STREAMING_PLAYLISTS, |
1468 | ScopeNames.WITH_THUMBNAILS | 1473 | ScopeNames.WITH_THUMBNAILS |
1469 | ]).findOne(query) | 1474 | ]).findOne(query) |
@@ -1500,7 +1505,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1500 | 1505 | ||
1501 | return VideoModel.scope([ | 1506 | return VideoModel.scope([ |
1502 | ScopeNames.WITH_ACCOUNT_DETAILS, | 1507 | ScopeNames.WITH_ACCOUNT_DETAILS, |
1503 | ScopeNames.WITH_FILES, | 1508 | ScopeNames.WITH_WEBTORRENT_FILES, |
1504 | ScopeNames.WITH_STREAMING_PLAYLISTS, | 1509 | ScopeNames.WITH_STREAMING_PLAYLISTS, |
1505 | ScopeNames.WITH_THUMBNAILS, | 1510 | ScopeNames.WITH_THUMBNAILS, |
1506 | ScopeNames.WITH_BLACKLISTED | 1511 | ScopeNames.WITH_BLACKLISTED |
@@ -1521,7 +1526,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1521 | ScopeNames.WITH_BLACKLISTED, | 1526 | ScopeNames.WITH_BLACKLISTED, |
1522 | ScopeNames.WITH_ACCOUNT_DETAILS, | 1527 | ScopeNames.WITH_ACCOUNT_DETAILS, |
1523 | ScopeNames.WITH_SCHEDULED_UPDATE, | 1528 | ScopeNames.WITH_SCHEDULED_UPDATE, |
1524 | ScopeNames.WITH_FILES, | 1529 | ScopeNames.WITH_WEBTORRENT_FILES, |
1525 | ScopeNames.WITH_STREAMING_PLAYLISTS, | 1530 | ScopeNames.WITH_STREAMING_PLAYLISTS, |
1526 | ScopeNames.WITH_THUMBNAILS | 1531 | ScopeNames.WITH_THUMBNAILS |
1527 | ] | 1532 | ] |
@@ -1555,7 +1560,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1555 | ScopeNames.WITH_ACCOUNT_DETAILS, | 1560 | ScopeNames.WITH_ACCOUNT_DETAILS, |
1556 | ScopeNames.WITH_SCHEDULED_UPDATE, | 1561 | ScopeNames.WITH_SCHEDULED_UPDATE, |
1557 | ScopeNames.WITH_THUMBNAILS, | 1562 | ScopeNames.WITH_THUMBNAILS, |
1558 | { method: [ ScopeNames.WITH_FILES, true ] }, | 1563 | { method: [ ScopeNames.WITH_WEBTORRENT_FILES, true ] }, |
1559 | { method: [ ScopeNames.WITH_STREAMING_PLAYLISTS, true ] } | 1564 | { method: [ ScopeNames.WITH_STREAMING_PLAYLISTS, true ] } |
1560 | ] | 1565 | ] |
1561 | 1566 | ||
@@ -1787,17 +1792,31 @@ export class VideoModel extends Model<VideoModel> { | |||
1787 | this.VideoChannel.Account.isBlocked() | 1792 | this.VideoChannel.Account.isBlocked() |
1788 | } | 1793 | } |
1789 | 1794 | ||
1790 | getOriginalFile <T extends MVideoWithFile> (this: T) { | 1795 | getMaxQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { |
1791 | if (Array.isArray(this.VideoFiles) === false) return undefined | 1796 | if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) { |
1797 | const file = maxBy(this.VideoFiles, file => file.resolution) | ||
1798 | |||
1799 | return Object.assign(file, { Video: this }) | ||
1800 | } | ||
1801 | |||
1802 | // No webtorrent files, try with streaming playlist files | ||
1803 | if (Array.isArray(this.VideoStreamingPlaylists) && this.VideoStreamingPlaylists.length !== 0) { | ||
1804 | const streamingPlaylistWithVideo = Object.assign(this.VideoStreamingPlaylists[0], { Video: this }) | ||
1805 | |||
1806 | const file = maxBy(streamingPlaylistWithVideo.VideoFiles, file => file.resolution) | ||
1807 | return Object.assign(file, { VideoStreamingPlaylist: streamingPlaylistWithVideo }) | ||
1808 | } | ||
1792 | 1809 | ||
1793 | // The original file is the file that have the higher resolution | 1810 | return undefined |
1794 | return maxBy(this.VideoFiles, file => file.resolution) | ||
1795 | } | 1811 | } |
1796 | 1812 | ||
1797 | getFile <T extends MVideoWithFile> (this: T, resolution: number) { | 1813 | getWebTorrentFile <T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo { |
1798 | if (Array.isArray(this.VideoFiles) === false) return undefined | 1814 | if (Array.isArray(this.VideoFiles) === false) return undefined |
1799 | 1815 | ||
1800 | return this.VideoFiles.find(f => f.resolution === resolution) | 1816 | const file = this.VideoFiles.find(f => f.resolution === resolution) |
1817 | if (!file) return undefined | ||
1818 | |||
1819 | return Object.assign(file, { Video: this }) | ||
1801 | } | 1820 | } |
1802 | 1821 | ||
1803 | async addAndSaveThumbnail (thumbnail: MThumbnail, transaction: Transaction) { | 1822 | async addAndSaveThumbnail (thumbnail: MThumbnail, transaction: Transaction) { |
@@ -1813,10 +1832,6 @@ export class VideoModel extends Model<VideoModel> { | |||
1813 | this.Thumbnails.push(savedThumbnail) | 1832 | this.Thumbnails.push(savedThumbnail) |
1814 | } | 1833 | } |
1815 | 1834 | ||
1816 | getVideoFilename (videoFile: MVideoFile) { | ||
1817 | return this.uuid + '-' + videoFile.resolution + videoFile.extname | ||
1818 | } | ||
1819 | |||
1820 | generateThumbnailName () { | 1835 | generateThumbnailName () { |
1821 | return this.uuid + '.jpg' | 1836 | return this.uuid + '.jpg' |
1822 | } | 1837 | } |
@@ -1837,46 +1852,10 @@ export class VideoModel extends Model<VideoModel> { | |||
1837 | return this.Thumbnails.find(t => t.type === ThumbnailType.PREVIEW) | 1852 | return this.Thumbnails.find(t => t.type === ThumbnailType.PREVIEW) |
1838 | } | 1853 | } |
1839 | 1854 | ||
1840 | getTorrentFileName (videoFile: MVideoFile) { | ||
1841 | const extension = '.torrent' | ||
1842 | return this.uuid + '-' + videoFile.resolution + extension | ||
1843 | } | ||
1844 | |||
1845 | isOwned () { | 1855 | isOwned () { |
1846 | return this.remote === false | 1856 | return this.remote === false |
1847 | } | 1857 | } |
1848 | 1858 | ||
1849 | getTorrentFilePath (videoFile: MVideoFile) { | ||
1850 | return join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) | ||
1851 | } | ||
1852 | |||
1853 | getVideoFilePath (videoFile: MVideoFile) { | ||
1854 | return join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile)) | ||
1855 | } | ||
1856 | |||
1857 | async createTorrentAndSetInfoHash (videoFile: MVideoFile) { | ||
1858 | const options = { | ||
1859 | // Keep the extname, it's used by the client to stream the file inside a web browser | ||
1860 | name: `${this.name} ${videoFile.resolution}p${videoFile.extname}`, | ||
1861 | createdBy: 'PeerTube', | ||
1862 | announceList: [ | ||
1863 | [ WEBSERVER.WS + '://' + WEBSERVER.HOSTNAME + ':' + WEBSERVER.PORT + '/tracker/socket' ], | ||
1864 | [ WEBSERVER.URL + '/tracker/announce' ] | ||
1865 | ], | ||
1866 | urlList: [ WEBSERVER.URL + STATIC_PATHS.WEBSEED + this.getVideoFilename(videoFile) ] | ||
1867 | } | ||
1868 | |||
1869 | const torrent = await createTorrentPromise(this.getVideoFilePath(videoFile), options) | ||
1870 | |||
1871 | const filePath = join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) | ||
1872 | logger.info('Creating torrent %s.', filePath) | ||
1873 | |||
1874 | await writeFile(filePath, torrent) | ||
1875 | |||
1876 | const parsedTorrent = parseTorrent(torrent) | ||
1877 | videoFile.infoHash = parsedTorrent.infoHash | ||
1878 | } | ||
1879 | |||
1880 | getWatchStaticPath () { | 1859 | getWatchStaticPath () { |
1881 | return '/videos/watch/' + this.uuid | 1860 | return '/videos/watch/' + this.uuid |
1882 | } | 1861 | } |
@@ -1909,7 +1888,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1909 | } | 1888 | } |
1910 | 1889 | ||
1911 | getFormattedVideoFilesJSON (): VideoFile[] { | 1890 | getFormattedVideoFilesJSON (): VideoFile[] { |
1912 | return videoFilesModelToFormattedJSON(this, this.VideoFiles) | 1891 | const { baseUrlHttp, baseUrlWs } = this.getBaseUrls() |
1892 | return videoFilesModelToFormattedJSON(this, baseUrlHttp, baseUrlWs, this.VideoFiles) | ||
1913 | } | 1893 | } |
1914 | 1894 | ||
1915 | toActivityPubObject (this: MVideoAP): VideoTorrentObject { | 1895 | toActivityPubObject (this: MVideoAP): VideoTorrentObject { |
@@ -1923,8 +1903,10 @@ export class VideoModel extends Model<VideoModel> { | |||
1923 | return peertubeTruncate(this.description, { length: maxLength }) | 1903 | return peertubeTruncate(this.description, { length: maxLength }) |
1924 | } | 1904 | } |
1925 | 1905 | ||
1926 | getOriginalFileResolution () { | 1906 | getMaxQualityResolution () { |
1927 | const originalFilePath = this.getVideoFilePath(this.getOriginalFile()) | 1907 | const file = this.getMaxQualityFile() |
1908 | const videoOrPlaylist = file.getVideoOrStreamingPlaylist() | ||
1909 | const originalFilePath = getVideoFilePath(videoOrPlaylist, file) | ||
1928 | 1910 | ||
1929 | return getVideoFileResolution(originalFilePath) | 1911 | return getVideoFileResolution(originalFilePath) |
1930 | } | 1912 | } |
@@ -1933,22 +1915,36 @@ export class VideoModel extends Model<VideoModel> { | |||
1933 | return `/api/${API_VERSION}/videos/${this.uuid}/description` | 1915 | return `/api/${API_VERSION}/videos/${this.uuid}/description` |
1934 | } | 1916 | } |
1935 | 1917 | ||
1936 | getHLSPlaylist () { | 1918 | getHLSPlaylist (): MStreamingPlaylistFilesVideo { |
1937 | if (!this.VideoStreamingPlaylists) return undefined | 1919 | if (!this.VideoStreamingPlaylists) return undefined |
1938 | 1920 | ||
1939 | return this.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) | 1921 | const playlist = this.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) |
1922 | playlist.Video = this | ||
1923 | |||
1924 | return playlist | ||
1940 | } | 1925 | } |
1941 | 1926 | ||
1942 | removeFile (videoFile: MVideoFile, isRedundancy = false) { | 1927 | setHLSPlaylist (playlist: MStreamingPlaylist) { |
1943 | const baseDir = isRedundancy ? CONFIG.STORAGE.REDUNDANCY_DIR : CONFIG.STORAGE.VIDEOS_DIR | 1928 | const toAdd = [ playlist ] as [ VideoStreamingPlaylistModel ] |
1944 | 1929 | ||
1945 | const filePath = join(baseDir, this.getVideoFilename(videoFile)) | 1930 | if (Array.isArray(this.VideoStreamingPlaylists) === false || this.VideoStreamingPlaylists.length === 0) { |
1931 | this.VideoStreamingPlaylists = toAdd | ||
1932 | return | ||
1933 | } | ||
1934 | |||
1935 | this.VideoStreamingPlaylists = this.VideoStreamingPlaylists | ||
1936 | .filter(s => s.type !== VideoStreamingPlaylistType.HLS) | ||
1937 | .concat(toAdd) | ||
1938 | } | ||
1939 | |||
1940 | removeFile (videoFile: MVideoFile, isRedundancy = false) { | ||
1941 | const filePath = getVideoFilePath(this, videoFile, isRedundancy) | ||
1946 | return remove(filePath) | 1942 | return remove(filePath) |
1947 | .catch(err => logger.warn('Cannot delete file %s.', filePath, { err })) | 1943 | .catch(err => logger.warn('Cannot delete file %s.', filePath, { err })) |
1948 | } | 1944 | } |
1949 | 1945 | ||
1950 | removeTorrent (videoFile: MVideoFile) { | 1946 | removeTorrent (videoFile: MVideoFile) { |
1951 | const torrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) | 1947 | const torrentPath = getTorrentFilePath(this, videoFile) |
1952 | return remove(torrentPath) | 1948 | return remove(torrentPath) |
1953 | .catch(err => logger.warn('Cannot delete torrent %s.', torrentPath, { err })) | 1949 | .catch(err => logger.warn('Cannot delete torrent %s.', torrentPath, { err })) |
1954 | } | 1950 | } |
@@ -1973,38 +1969,30 @@ export class VideoModel extends Model<VideoModel> { | |||
1973 | return this.save() | 1969 | return this.save() |
1974 | } | 1970 | } |
1975 | 1971 | ||
1976 | getBaseUrls () { | 1972 | async publishIfNeededAndSave (t: Transaction) { |
1977 | let baseUrlHttp | 1973 | if (this.state !== VideoState.PUBLISHED) { |
1978 | let baseUrlWs | 1974 | this.state = VideoState.PUBLISHED |
1975 | this.publishedAt = new Date() | ||
1976 | await this.save({ transaction: t }) | ||
1979 | 1977 | ||
1980 | if (this.isOwned()) { | 1978 | return true |
1981 | baseUrlHttp = WEBSERVER.URL | ||
1982 | baseUrlWs = WEBSERVER.WS + '://' + WEBSERVER.HOSTNAME + ':' + WEBSERVER.PORT | ||
1983 | } else { | ||
1984 | baseUrlHttp = REMOTE_SCHEME.HTTP + '://' + this.VideoChannel.Account.Actor.Server.host | ||
1985 | baseUrlWs = REMOTE_SCHEME.WS + '://' + this.VideoChannel.Account.Actor.Server.host | ||
1986 | } | 1979 | } |
1987 | 1980 | ||
1988 | return { baseUrlHttp, baseUrlWs } | 1981 | return false |
1989 | } | 1982 | } |
1990 | 1983 | ||
1991 | generateMagnetUri (videoFile: MVideoFileRedundanciesOpt, baseUrlHttp: string, baseUrlWs: string) { | 1984 | getBaseUrls () { |
1992 | const xs = this.getTorrentUrl(videoFile, baseUrlHttp) | 1985 | if (this.isOwned()) { |
1993 | const announce = this.getTrackerUrls(baseUrlHttp, baseUrlWs) | 1986 | return { |
1994 | let urlList = [ this.getVideoFileUrl(videoFile, baseUrlHttp) ] | 1987 | baseUrlHttp: WEBSERVER.URL, |
1995 | 1988 | baseUrlWs: WEBSERVER.WS + '://' + WEBSERVER.HOSTNAME + ':' + WEBSERVER.PORT | |
1996 | const redundancies = videoFile.RedundancyVideos | 1989 | } |
1997 | if (isArray(redundancies)) urlList = urlList.concat(redundancies.map(r => r.fileUrl)) | ||
1998 | |||
1999 | const magnetHash = { | ||
2000 | xs, | ||
2001 | announce, | ||
2002 | urlList, | ||
2003 | infoHash: videoFile.infoHash, | ||
2004 | name: this.name | ||
2005 | } | 1990 | } |
2006 | 1991 | ||
2007 | return magnetUtil.encode(magnetHash) | 1992 | return { |
1993 | baseUrlHttp: REMOTE_SCHEME.HTTP + '://' + this.VideoChannel.Account.Actor.Server.host, | ||
1994 | baseUrlWs: REMOTE_SCHEME.WS + '://' + this.VideoChannel.Account.Actor.Server.host | ||
1995 | } | ||
2008 | } | 1996 | } |
2009 | 1997 | ||
2010 | getTrackerUrls (baseUrlHttp: string, baseUrlWs: string) { | 1998 | getTrackerUrls (baseUrlHttp: string, baseUrlWs: string) { |
@@ -2012,23 +2000,23 @@ export class VideoModel extends Model<VideoModel> { | |||
2012 | } | 2000 | } |
2013 | 2001 | ||
2014 | getTorrentUrl (videoFile: MVideoFile, baseUrlHttp: string) { | 2002 | getTorrentUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
2015 | return baseUrlHttp + STATIC_PATHS.TORRENTS + this.getTorrentFileName(videoFile) | 2003 | return baseUrlHttp + STATIC_PATHS.TORRENTS + getTorrentFileName(this, videoFile) |
2016 | } | 2004 | } |
2017 | 2005 | ||
2018 | getTorrentDownloadUrl (videoFile: MVideoFile, baseUrlHttp: string) { | 2006 | getTorrentDownloadUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
2019 | return baseUrlHttp + STATIC_DOWNLOAD_PATHS.TORRENTS + this.getTorrentFileName(videoFile) | 2007 | return baseUrlHttp + STATIC_DOWNLOAD_PATHS.TORRENTS + getTorrentFileName(this, videoFile) |
2020 | } | 2008 | } |
2021 | 2009 | ||
2022 | getVideoFileUrl (videoFile: MVideoFile, baseUrlHttp: string) { | 2010 | getVideoFileUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
2023 | return baseUrlHttp + STATIC_PATHS.WEBSEED + this.getVideoFilename(videoFile) | 2011 | return baseUrlHttp + STATIC_PATHS.WEBSEED + getVideoFilename(this, videoFile) |
2024 | } | 2012 | } |
2025 | 2013 | ||
2026 | getVideoRedundancyUrl (videoFile: MVideoFile, baseUrlHttp: string) { | 2014 | getVideoRedundancyUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
2027 | return baseUrlHttp + STATIC_PATHS.REDUNDANCY + this.getVideoFilename(videoFile) | 2015 | return baseUrlHttp + STATIC_PATHS.REDUNDANCY + getVideoFilename(this, videoFile) |
2028 | } | 2016 | } |
2029 | 2017 | ||
2030 | getVideoFileDownloadUrl (videoFile: MVideoFile, baseUrlHttp: string) { | 2018 | getVideoFileDownloadUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
2031 | return baseUrlHttp + STATIC_DOWNLOAD_PATHS.VIDEOS + this.getVideoFilename(videoFile) | 2019 | return baseUrlHttp + STATIC_DOWNLOAD_PATHS.VIDEOS + getVideoFilename(this, videoFile) |
2032 | } | 2020 | } |
2033 | 2021 | ||
2034 | getBandwidthBits (videoFile: MVideoFile) { | 2022 | getBandwidthBits (videoFile: MVideoFile) { |