diff options
-rw-r--r-- | server/helpers/webtorrent.ts | 4 | ||||
-rw-r--r-- | server/initializers/migrations/0450-streaming-playlist-files.ts | 75 |
2 files changed, 78 insertions, 1 deletions
diff --git a/server/helpers/webtorrent.ts b/server/helpers/webtorrent.ts index f3e41f8d6..3a99518c6 100644 --- a/server/helpers/webtorrent.ts +++ b/server/helpers/webtorrent.ts | |||
@@ -72,6 +72,7 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName | |||
72 | 72 | ||
73 | async function createTorrentAndSetInfoHash (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) { | 73 | async function createTorrentAndSetInfoHash (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) { |
74 | const video = extractVideo(videoOrPlaylist) | 74 | const video = extractVideo(videoOrPlaylist) |
75 | const { baseUrlHttp } = video.getBaseUrls() | ||
75 | 76 | ||
76 | const options = { | 77 | const options = { |
77 | // Keep the extname, it's used by the client to stream the file inside a web browser | 78 | // Keep the extname, it's used by the client to stream the file inside a web browser |
@@ -81,7 +82,7 @@ async function createTorrentAndSetInfoHash (videoOrPlaylist: MVideo | MStreaming | |||
81 | [ WEBSERVER.WS + '://' + WEBSERVER.HOSTNAME + ':' + WEBSERVER.PORT + '/tracker/socket' ], | 82 | [ WEBSERVER.WS + '://' + WEBSERVER.HOSTNAME + ':' + WEBSERVER.PORT + '/tracker/socket' ], |
82 | [ WEBSERVER.URL + '/tracker/announce' ] | 83 | [ WEBSERVER.URL + '/tracker/announce' ] |
83 | ], | 84 | ], |
84 | urlList: [ WEBSERVER.URL + STATIC_PATHS.WEBSEED + getVideoFilename(videoOrPlaylist, videoFile) ] | 85 | urlList: [ videoOrPlaylist.getVideoFileUrl(videoFile, baseUrlHttp) ] |
85 | } | 86 | } |
86 | 87 | ||
87 | const torrent = await createTorrentPromise(getVideoFilePath(videoOrPlaylist, videoFile), options) | 88 | const torrent = await createTorrentPromise(getVideoFilePath(videoOrPlaylist, videoFile), options) |
@@ -126,6 +127,7 @@ function generateMagnetUri ( | |||
126 | // --------------------------------------------------------------------------- | 127 | // --------------------------------------------------------------------------- |
127 | 128 | ||
128 | export { | 129 | export { |
130 | createTorrentPromise, | ||
129 | createTorrentAndSetInfoHash, | 131 | createTorrentAndSetInfoHash, |
130 | generateMagnetUri, | 132 | generateMagnetUri, |
131 | downloadWebTorrentVideo | 133 | downloadWebTorrentVideo |
diff --git a/server/initializers/migrations/0450-streaming-playlist-files.ts b/server/initializers/migrations/0450-streaming-playlist-files.ts index 536ef00f9..4e177bef8 100644 --- a/server/initializers/migrations/0450-streaming-playlist-files.ts +++ b/server/initializers/migrations/0450-streaming-playlist-files.ts | |||
@@ -1,4 +1,10 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { join } from 'path' | ||
3 | import { HLS_STREAMING_PLAYLIST_DIRECTORY, WEBSERVER } from '@server/initializers/constants' | ||
4 | import { CONFIG } from '@server/initializers/config' | ||
5 | import { pathExists, stat, writeFile } from 'fs-extra' | ||
6 | import * as parseTorrent from 'parse-torrent' | ||
7 | import { createTorrentPromise } from '@server/helpers/webtorrent' | ||
2 | 8 | ||
3 | async function up (utils: { | 9 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 10 | transaction: Sequelize.Transaction, |
@@ -28,6 +34,75 @@ async function up (utils: { | |||
28 | 34 | ||
29 | await utils.queryInterface.changeColumn('videoFile', 'videoId', data) | 35 | await utils.queryInterface.changeColumn('videoFile', 'videoId', data) |
30 | } | 36 | } |
37 | |||
38 | { | ||
39 | await utils.queryInterface.removeIndex('videoFile', 'video_file_video_id_resolution_fps') | ||
40 | } | ||
41 | |||
42 | { | ||
43 | const query = 'insert into "videoFile" ' + | ||
44 | '(resolution, size, "infoHash", "videoId", "createdAt", "updatedAt", fps, extname, "videoStreamingPlaylistId")' + | ||
45 | '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", "videoFile"."fps", ' + | ||
46 | '"videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' + | ||
47 | 'inner join video ON video.id = "videoStreamingPlaylist"."videoId" inner join "videoFile" ON "videoFile"."videoId" = video.id)' | ||
48 | |||
49 | await utils.sequelize.query(query, { transaction: utils.transaction }) | ||
50 | } | ||
51 | |||
52 | { | ||
53 | const query = 'select "videoFile".id as id, "videoFile".resolution as resolution, "video".uuid as uuid from "videoFile" ' + | ||
54 | 'inner join "videoStreamingPlaylist" ON "videoStreamingPlaylist".id = "videoFile"."videoStreamingPlaylistId" ' + | ||
55 | 'inner join video ON video.id = "videoStreamingPlaylist"."videoId" ' + | ||
56 | 'WHERE video.remote IS FALSE' | ||
57 | const options = { | ||
58 | type: Sequelize.QueryTypes.SELECT, | ||
59 | transaction: utils.transaction | ||
60 | } | ||
61 | const res = await utils.sequelize.query(query, options) | ||
62 | |||
63 | for (const row of res) { | ||
64 | const videoFilename = `${row['uuid']}-${row['resolution']}-fragmented.mp4` | ||
65 | const videoFilePath = join(HLS_STREAMING_PLAYLIST_DIRECTORY, row['uuid'], videoFilename) | ||
66 | |||
67 | if (!await pathExists(videoFilePath)) { | ||
68 | console.warn('Cannot generate torrent of %s: file does not exist.', videoFilePath) | ||
69 | continue | ||
70 | } | ||
71 | |||
72 | const createTorrentOptions = { | ||
73 | // Keep the extname, it's used by the client to stream the file inside a web browser | ||
74 | name: `video ${row['uuid']}`, | ||
75 | createdBy: 'PeerTube', | ||
76 | announceList: [ | ||
77 | [ WEBSERVER.WS + '://' + WEBSERVER.HOSTNAME + ':' + WEBSERVER.PORT + '/tracker/socket' ], | ||
78 | [ WEBSERVER.URL + '/tracker/announce' ] | ||
79 | ], | ||
80 | urlList: [ WEBSERVER.URL + join(HLS_STREAMING_PLAYLIST_DIRECTORY, row['uuid'], videoFilename) ] | ||
81 | } | ||
82 | const torrent = await createTorrentPromise(videoFilePath, createTorrentOptions) | ||
83 | |||
84 | const torrentName = `${row['uuid']}-${row['resolution']}-hls.torrent` | ||
85 | const filePath = join(CONFIG.STORAGE.TORRENTS_DIR, torrentName) | ||
86 | |||
87 | await writeFile(filePath, torrent) | ||
88 | |||
89 | const parsedTorrent = parseTorrent(torrent) | ||
90 | const infoHash = parsedTorrent.infoHash | ||
91 | |||
92 | const stats = await stat(videoFilePath) | ||
93 | const size = stats.size | ||
94 | |||
95 | const queryUpdate = 'UPDATE "videoFile" SET "infoHash" = ?, "size" = ? WHERE id = ?' | ||
96 | |||
97 | const options = { | ||
98 | type: Sequelize.QueryTypes.UPDATE, | ||
99 | replacements: [ infoHash, size, row['id'] ], | ||
100 | transaction: utils.transaction | ||
101 | } | ||
102 | await utils.sequelize.query(queryUpdate, options) | ||
103 | |||
104 | } | ||
105 | } | ||
31 | } | 106 | } |
32 | 107 | ||
33 | function down (options) { | 108 | function down (options) { |