aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/video.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-11-15 15:06:03 +0100
committerChocobozzz <me@florianbigard.com>2019-11-25 10:59:43 +0100
commitd7a25329f9e607894d29ab342b9cb66638b56dc0 (patch)
tree6cd6bc4f2689f78944238b313c93427423a932ac /server/models/video/video.ts
parent14981d7331da3f63fe6cfaf020ccb7c910006eaf (diff)
downloadPeerTube-d7a25329f9e607894d29ab342b9cb66638b56dc0.tar.gz
PeerTube-d7a25329f9e607894d29ab342b9cb66638b56dc0.tar.zst
PeerTube-d7a25329f9e607894d29ab342b9cb66638b56dc0.zip
Add ability to disable webtorrent
In favour of HLS
Diffstat (limited to 'server/models/video/video.ts')
-rw-r--r--server/models/video/video.ts204
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 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import { maxBy } from 'lodash' 2import { maxBy } from 'lodash'
3import * as magnetUtil from 'magnet-uri'
4import * as parseTorrent from 'parse-torrent'
5import { join } from 'path' 3import { join } from 'path'
6import { 4import {
7 CountOptions, 5 CountOptions,
@@ -38,11 +36,11 @@ import {
38} from 'sequelize-typescript' 36} from 'sequelize-typescript'
39import { UserRight, VideoPrivacy, VideoState } from '../../../shared' 37import { UserRight, VideoPrivacy, VideoState } from '../../../shared'
40import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' 38import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
41import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' 39import { Video, VideoDetails } from '../../../shared/models/videos'
42import { VideoFilter } from '../../../shared/models/videos/video-query.type' 40import { VideoFilter } from '../../../shared/models/videos/video-query.type'
43import { peertubeTruncate } from '../../helpers/core-utils' 41import { peertubeTruncate } from '../../helpers/core-utils'
44import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 42import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
45import { isArray, isBooleanValid } from '../../helpers/custom-validators/misc' 43import { isBooleanValid } from '../../helpers/custom-validators/misc'
46import { 44import {
47 isVideoCategoryValid, 45 isVideoCategoryValid,
48 isVideoDescriptionValid, 46 isVideoDescriptionValid,
@@ -100,7 +98,7 @@ import { VideoTagModel } from './video-tag'
100import { ScheduleVideoUpdateModel } from './schedule-video-update' 98import { ScheduleVideoUpdateModel } from './schedule-video-update'
101import { VideoCaptionModel } from './video-caption' 99import { VideoCaptionModel } from './video-caption'
102import { VideoBlacklistModel } from './video-blacklist' 100import { VideoBlacklistModel } from './video-blacklist'
103import { remove, writeFile } from 'fs-extra' 101import { remove } from 'fs-extra'
104import { VideoViewModel } from './video-views' 102import { VideoViewModel } from './video-views'
105import { VideoRedundancyModel } from '../redundancy/video-redundancy' 103import { VideoRedundancyModel } from '../redundancy/video-redundancy'
106import { 104import {
@@ -117,18 +115,20 @@ import { VideoPlaylistElementModel } from './video-playlist-element'
117import { CONFIG } from '../../initializers/config' 115import { CONFIG } from '../../initializers/config'
118import { ThumbnailModel } from './thumbnail' 116import { ThumbnailModel } from './thumbnail'
119import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' 117import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
120import { createTorrentPromise } from '../../helpers/webtorrent'
121import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' 118import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
122import { 119import {
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'
143import { MVideoFile, MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file' 143import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file'
144import { MThumbnail } from '../../typings/models/video/thumbnail' 144import { MThumbnail } from '../../typings/models/video/thumbnail'
145import { VideoFile } from '@shared/models/videos/video-file.model'
146import { 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
147const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ 149const 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) {