]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/videos.js
Try to make a better communication (between pods) module
[github/Chocobozzz/PeerTube.git] / server / lib / videos.js
1 'use strict'
2
3 const async = require('async')
4 const config = require('config')
5 const ffmpeg = require('fluent-ffmpeg')
6 const fs = require('fs')
7 const map = require('lodash/map')
8 const pathUtils = require('path')
9
10 const constants = require('../initializers/constants')
11 const logger = require('../helpers/logger')
12 const utils = require('../helpers/utils')
13 const Videos = require('../models/videos')
14 const webtorrent = require('../lib/webtorrent')
15
16 const uploadDir = pathUtils.join(__dirname, '..', '..', config.get('storage.uploads'))
17 const thumbnailsDir = pathUtils.join(__dirname, '..', '..', config.get('storage.thumbnails'))
18
19 const videos = {
20 convertVideoToRemote: convertVideoToRemote,
21 createRemoteVideos: createRemoteVideos,
22 getVideoDuration: getVideoDuration,
23 getVideoState: getVideoState,
24 createVideoThumbnail: createVideoThumbnail,
25 removeVideosDataFromDisk: removeVideosDataFromDisk,
26 removeRemoteVideos: removeRemoteVideos,
27 seed: seed,
28 seedAllExisting: seedAllExisting
29 }
30
31 function convertVideoToRemote (video, callback) {
32 fs.readFile(thumbnailsDir + video.thumbnail, function (err, thumbnailData) {
33 if (err) {
34 logger.error('Cannot read the thumbnail of the video')
35 return callback(err)
36 }
37
38 const remoteVideo = {
39 name: video.name,
40 description: video.description,
41 magnetUri: video.magnetUri,
42 author: video.author,
43 duration: video.duration,
44 thumbnailBase64: new Buffer(thumbnailData).toString('base64'),
45 tags: video.tags,
46 createdDate: video.createdDate,
47 podUrl: video.podUrl
48 }
49
50 return callback(null, remoteVideo)
51 })
52 }
53
54 function createRemoteVideos (videos, callback) {
55 // Create the remote videos from the new pod
56 createRemoteVideoObjects(videos, function (err, remoteVideos) {
57 if (err) return callback(err)
58
59 Videos.addRemotes(remoteVideos, callback)
60 })
61 }
62
63 function getVideoDuration (videoPath, callback) {
64 ffmpeg.ffprobe(videoPath, function (err, metadata) {
65 if (err) return callback(err)
66
67 return callback(null, Math.floor(metadata.format.duration))
68 })
69 }
70
71 function getVideoState (video) {
72 const exist = (video !== null)
73 let owned = false
74 if (exist === true) {
75 owned = (video.namePath !== null)
76 }
77
78 return { exist: exist, owned: owned }
79 }
80
81 function createVideoThumbnail (videoPath, callback) {
82 const filename = pathUtils.basename(videoPath) + '.jpg'
83 ffmpeg(videoPath)
84 .on('error', callback)
85 .on('end', function () {
86 callback(null, filename)
87 })
88 .thumbnail({
89 count: 1,
90 folder: thumbnailsDir,
91 size: constants.THUMBNAILS_SIZE,
92 filename: filename
93 })
94 }
95
96 // Remove video datas from disk (video file, thumbnail...)
97 function removeVideosDataFromDisk (videos, callback) {
98 async.each(videos, function (video, callbackEach) {
99 fs.unlink(thumbnailsDir + video.thumbnail, function (err) {
100 if (err) logger.error('Cannot remove the video thumbnail')
101
102 if (getVideoState(video).owned === true) {
103 fs.unlink(uploadDir + video.namePath, function (err) {
104 if (err) {
105 logger.error('Cannot remove this video file.')
106 return callbackEach(err)
107 }
108
109 callbackEach(null)
110 })
111 } else {
112 callbackEach(null)
113 }
114 })
115 }, callback)
116 }
117
118 function removeRemoteVideos (videos, callback) {
119 Videos.removeByIds(map(videos, '_id'), function (err) {
120 if (err) return callback(err)
121
122 removeVideosDataFromDisk(videos, callback)
123 })
124 }
125
126 function seed (path, callback) {
127 logger.info('Seeding %s...', path)
128
129 webtorrent.seed(path, function (torrent) {
130 logger.info('%s seeded (%s).', path, torrent.magnetURI)
131
132 return callback(null, torrent)
133 })
134 }
135
136 function seedAllExisting (callback) {
137 Videos.listOwned(function (err, videosList) {
138 if (err) {
139 logger.error('Cannot get list of the videos to seed.')
140 return callback(err)
141 }
142
143 async.each(videosList, function (video, callbackEach) {
144 seed(uploadDir + video.namePath, function (err) {
145 if (err) {
146 logger.error('Cannot seed this video.')
147 return callback(err)
148 }
149
150 callbackEach(null)
151 })
152 }, callback)
153 })
154 }
155
156 // ---------------------------------------------------------------------------
157
158 module.exports = videos
159
160 // ---------------------------------------------------------------------------
161
162 function createRemoteVideoObjects (videos, callback) {
163 const remoteVideos = []
164
165 async.each(videos, function (video, callbackEach) {
166 // Creating the thumbnail for this remote video
167 utils.generateRandomString(16, function (err, randomString) {
168 if (err) return callbackEach(err)
169
170 const thumbnailName = randomString + '.jpg'
171 createThumbnailFromBase64(thumbnailName, video.thumbnailBase64, function (err) {
172 if (err) return callbackEach(err)
173
174 const params = {
175 name: video.name,
176 description: video.description,
177 magnetUri: video.magnetUri,
178 podUrl: video.podUrl,
179 duration: video.duration,
180 thumbnail: thumbnailName,
181 tags: video.tags,
182 author: video.author
183 }
184 remoteVideos.push(params)
185
186 callbackEach(null)
187 })
188 })
189 },
190 function (err) {
191 if (err) return callback(err)
192
193 callback(null, remoteVideos)
194 })
195 }
196
197 function createThumbnailFromBase64 (thumbnailName, data, callback) {
198 fs.writeFile(thumbnailsDir + thumbnailName, data, { encoding: 'base64' }, callback)
199 }