diff options
Diffstat (limited to 'server/helpers')
-rw-r--r-- | server/helpers/actor.ts | 13 | ||||
-rw-r--r-- | server/helpers/audit-logger.ts | 8 | ||||
-rw-r--r-- | server/helpers/custom-validators/activitypub/videos.ts | 2 | ||||
-rw-r--r-- | server/helpers/custom-validators/video-ownership.ts | 2 | ||||
-rw-r--r-- | server/helpers/custom-validators/videos.ts | 13 | ||||
-rw-r--r-- | server/helpers/utils.ts | 24 | ||||
-rw-r--r-- | server/helpers/video.ts | 25 | ||||
-rw-r--r-- | server/helpers/webfinger.ts | 5 | ||||
-rw-r--r-- | server/helpers/webtorrent.ts | 2 | ||||
-rw-r--r-- | server/helpers/youtube-dl.ts | 69 |
10 files changed, 128 insertions, 35 deletions
diff --git a/server/helpers/actor.ts b/server/helpers/actor.ts new file mode 100644 index 000000000..12a7ace9f --- /dev/null +++ b/server/helpers/actor.ts | |||
@@ -0,0 +1,13 @@ | |||
1 | import { ActorModel } from '../models/activitypub/actor' | ||
2 | |||
3 | type ActorFetchByUrlType = 'all' | 'actor-and-association-ids' | ||
4 | function fetchActorByUrl (url: string, fetchType: ActorFetchByUrlType) { | ||
5 | if (fetchType === 'all') return ActorModel.loadByUrlAndPopulateAccountAndChannel(url) | ||
6 | |||
7 | if (fetchType === 'actor-and-association-ids') return ActorModel.loadByUrl(url) | ||
8 | } | ||
9 | |||
10 | export { | ||
11 | ActorFetchByUrlType, | ||
12 | fetchActorByUrl | ||
13 | } | ||
diff --git a/server/helpers/audit-logger.ts b/server/helpers/audit-logger.ts index 7db72b69c..00311fce1 100644 --- a/server/helpers/audit-logger.ts +++ b/server/helpers/audit-logger.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import * as path from 'path' | 1 | import * as path from 'path' |
2 | import * as express from 'express' | ||
2 | import { diff } from 'deep-object-diff' | 3 | import { diff } from 'deep-object-diff' |
3 | import { chain } from 'lodash' | 4 | import { chain } from 'lodash' |
4 | import * as flatten from 'flat' | 5 | import * as flatten from 'flat' |
@@ -8,6 +9,11 @@ import { jsonLoggerFormat, labelFormatter } from './logger' | |||
8 | import { VideoDetails, User, VideoChannel, VideoAbuse, VideoImport } from '../../shared' | 9 | import { VideoDetails, User, VideoChannel, VideoAbuse, VideoImport } from '../../shared' |
9 | import { VideoComment } from '../../shared/models/videos/video-comment.model' | 10 | import { VideoComment } from '../../shared/models/videos/video-comment.model' |
10 | import { CustomConfig } from '../../shared/models/server/custom-config.model' | 11 | import { CustomConfig } from '../../shared/models/server/custom-config.model' |
12 | import { UserModel } from '../models/account/user' | ||
13 | |||
14 | function getAuditIdFromRes (res: express.Response) { | ||
15 | return (res.locals.oauth.token.User as UserModel).username | ||
16 | } | ||
11 | 17 | ||
12 | enum AUDIT_TYPE { | 18 | enum AUDIT_TYPE { |
13 | CREATE = 'create', | 19 | CREATE = 'create', |
@@ -255,6 +261,8 @@ class CustomConfigAuditView extends EntityAuditView { | |||
255 | } | 261 | } |
256 | 262 | ||
257 | export { | 263 | export { |
264 | getAuditIdFromRes, | ||
265 | |||
258 | auditLoggerFactory, | 266 | auditLoggerFactory, |
259 | VideoImportAuditView, | 267 | VideoImportAuditView, |
260 | VideoChannelAuditView, | 268 | VideoChannelAuditView, |
diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts index f76eba474..8772e74cf 100644 --- a/server/helpers/custom-validators/activitypub/videos.ts +++ b/server/helpers/custom-validators/activitypub/videos.ts | |||
@@ -171,5 +171,3 @@ function setRemoteVideoTruncatedContent (video: any) { | |||
171 | 171 | ||
172 | return true | 172 | return true |
173 | } | 173 | } |
174 | |||
175 | |||
diff --git a/server/helpers/custom-validators/video-ownership.ts b/server/helpers/custom-validators/video-ownership.ts index aaa0c736b..a7771e07b 100644 --- a/server/helpers/custom-validators/video-ownership.ts +++ b/server/helpers/custom-validators/video-ownership.ts | |||
@@ -31,7 +31,7 @@ export function checkUserCanTerminateOwnershipChange ( | |||
31 | videoChangeOwnership: VideoChangeOwnershipModel, | 31 | videoChangeOwnership: VideoChangeOwnershipModel, |
32 | res: Response | 32 | res: Response |
33 | ): boolean { | 33 | ): boolean { |
34 | if (videoChangeOwnership.NextOwner.userId === user.Account.userId) { | 34 | if (videoChangeOwnership.NextOwner.userId === user.id) { |
35 | return true | 35 | return true |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index edafba6e2..9875c68bd 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts | |||
@@ -18,6 +18,7 @@ import { exists, isArray, isFileValid } from './misc' | |||
18 | import { VideoChannelModel } from '../../models/video/video-channel' | 18 | import { VideoChannelModel } from '../../models/video/video-channel' |
19 | import { UserModel } from '../../models/account/user' | 19 | import { UserModel } from '../../models/account/user' |
20 | import * as magnetUtil from 'magnet-uri' | 20 | import * as magnetUtil from 'magnet-uri' |
21 | import { fetchVideo, VideoFetchType } from '../video' | ||
21 | 22 | ||
22 | const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS | 23 | const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS |
23 | 24 | ||
@@ -152,14 +153,8 @@ function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: Use | |||
152 | return true | 153 | return true |
153 | } | 154 | } |
154 | 155 | ||
155 | async function isVideoExist (id: string, res: Response) { | 156 | async function isVideoExist (id: string, res: Response, fetchType: VideoFetchType = 'all') { |
156 | let video: VideoModel | null | 157 | const video = await fetchVideo(id, fetchType) |
157 | |||
158 | if (validator.isInt(id)) { | ||
159 | video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id) | ||
160 | } else { // UUID | ||
161 | video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id) | ||
162 | } | ||
163 | 158 | ||
164 | if (video === null) { | 159 | if (video === null) { |
165 | res.status(404) | 160 | res.status(404) |
@@ -169,7 +164,7 @@ async function isVideoExist (id: string, res: Response) { | |||
169 | return false | 164 | return false |
170 | } | 165 | } |
171 | 166 | ||
172 | res.locals.video = video | 167 | if (fetchType !== 'none') res.locals.video = video |
173 | return true | 168 | return true |
174 | } | 169 | } |
175 | 170 | ||
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index a1ed8e72d..a42474417 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import { ResultList } from '../../shared' | 1 | import { ResultList } from '../../shared' |
2 | import { CONFIG } from '../initializers' | 2 | import { CONFIG } from '../initializers' |
3 | import { ActorModel } from '../models/activitypub/actor' | ||
4 | import { ApplicationModel } from '../models/application/application' | 3 | import { ApplicationModel } from '../models/application/application' |
5 | import { pseudoRandomBytesPromise, sha256 } from './core-utils' | 4 | import { pseudoRandomBytesPromise, sha256 } from './core-utils' |
6 | import { logger } from './logger' | 5 | import { logger } from './logger' |
7 | import { join } from 'path' | 6 | import { join } from 'path' |
8 | import { Instance as ParseTorrent } from 'parse-torrent' | 7 | import { Instance as ParseTorrent } from 'parse-torrent' |
9 | import { remove } from 'fs-extra' | 8 | import { remove } from 'fs-extra' |
9 | import * as memoizee from 'memoizee' | ||
10 | 10 | ||
11 | function deleteFileAsync (path: string) { | 11 | function deleteFileAsync (path: string) { |
12 | remove(path) | 12 | remove(path) |
@@ -36,24 +36,12 @@ function getFormattedObjects<U, T extends FormattableToJSON> (objects: T[], obje | |||
36 | } as ResultList<U> | 36 | } as ResultList<U> |
37 | } | 37 | } |
38 | 38 | ||
39 | async function getServerActor () { | 39 | const getServerActor = memoizee(async function () { |
40 | if (getServerActor.serverActor === undefined) { | 40 | const application = await ApplicationModel.load() |
41 | const application = await ApplicationModel.load() | 41 | if (!application) throw Error('Could not load Application from database.') |
42 | if (!application) throw Error('Could not load Application from database.') | ||
43 | 42 | ||
44 | getServerActor.serverActor = application.Account.Actor | 43 | return application.Account.Actor |
45 | } | 44 | }) |
46 | |||
47 | if (!getServerActor.serverActor) { | ||
48 | logger.error('Cannot load server actor.') | ||
49 | process.exit(0) | ||
50 | } | ||
51 | |||
52 | return Promise.resolve(getServerActor.serverActor) | ||
53 | } | ||
54 | namespace getServerActor { | ||
55 | export let serverActor: ActorModel | ||
56 | } | ||
57 | 45 | ||
58 | function generateVideoTmpPath (target: string | ParseTorrent) { | 46 | function generateVideoTmpPath (target: string | ParseTorrent) { |
59 | const id = typeof target === 'string' ? target : target.infoHash | 47 | const id = typeof target === 'string' ? target : target.infoHash |
diff --git a/server/helpers/video.ts b/server/helpers/video.ts new file mode 100644 index 000000000..b1577a6b0 --- /dev/null +++ b/server/helpers/video.ts | |||
@@ -0,0 +1,25 @@ | |||
1 | import { VideoModel } from '../models/video/video' | ||
2 | |||
3 | type VideoFetchType = 'all' | 'only-video' | 'id' | 'none' | ||
4 | |||
5 | function fetchVideo (id: number | string, fetchType: VideoFetchType) { | ||
6 | if (fetchType === 'all') return VideoModel.loadAndPopulateAccountAndServerAndTags(id) | ||
7 | |||
8 | if (fetchType === 'only-video') return VideoModel.load(id) | ||
9 | |||
10 | if (fetchType === 'id' || fetchType === 'none') return VideoModel.loadOnlyId(id) | ||
11 | } | ||
12 | |||
13 | type VideoFetchByUrlType = 'all' | 'only-video' | ||
14 | function fetchVideoByUrl (url: string, fetchType: VideoFetchByUrlType) { | ||
15 | if (fetchType === 'all') return VideoModel.loadByUrlAndPopulateAccount(url) | ||
16 | |||
17 | if (fetchType === 'only-video') return VideoModel.loadByUrl(url) | ||
18 | } | ||
19 | |||
20 | export { | ||
21 | VideoFetchType, | ||
22 | VideoFetchByUrlType, | ||
23 | fetchVideo, | ||
24 | fetchVideoByUrl | ||
25 | } | ||
diff --git a/server/helpers/webfinger.ts b/server/helpers/webfinger.ts index 10fcec462..156376943 100644 --- a/server/helpers/webfinger.ts +++ b/server/helpers/webfinger.ts | |||
@@ -12,7 +12,10 @@ const webfinger = new WebFinger({ | |||
12 | request_timeout: 3000 | 12 | request_timeout: 3000 |
13 | }) | 13 | }) |
14 | 14 | ||
15 | async function loadActorUrlOrGetFromWebfinger (uri: string) { | 15 | async function loadActorUrlOrGetFromWebfinger (uriArg: string) { |
16 | // Handle strings like @toto@example.com | ||
17 | const uri = uriArg.startsWith('@') ? uriArg.slice(1) : uriArg | ||
18 | |||
16 | const [ name, host ] = uri.split('@') | 19 | const [ name, host ] = uri.split('@') |
17 | let actor: ActorModel | 20 | let actor: ActorModel |
18 | 21 | ||
diff --git a/server/helpers/webtorrent.ts b/server/helpers/webtorrent.ts index 2fdfd1876..f4b44bc4f 100644 --- a/server/helpers/webtorrent.ts +++ b/server/helpers/webtorrent.ts | |||
@@ -24,7 +24,7 @@ function downloadWebTorrentVideo (target: { magnetUri: string, torrentName?: str | |||
24 | if (timer) clearTimeout(timer) | 24 | if (timer) clearTimeout(timer) |
25 | 25 | ||
26 | return safeWebtorrentDestroy(webtorrent, torrentId, file.name, target.torrentName) | 26 | return safeWebtorrentDestroy(webtorrent, torrentId, file.name, target.torrentName) |
27 | .then(() => rej(new Error('The number of files is not equal to 1 for ' + torrentId))) | 27 | .then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it'))) |
28 | } | 28 | } |
29 | 29 | ||
30 | file = torrent.files[ 0 ] | 30 | file = torrent.files[ 0 ] |
diff --git a/server/helpers/youtube-dl.ts b/server/helpers/youtube-dl.ts index 8b2bc1782..25e719cc3 100644 --- a/server/helpers/youtube-dl.ts +++ b/server/helpers/youtube-dl.ts | |||
@@ -2,7 +2,11 @@ import { truncate } from 'lodash' | |||
2 | import { CONSTRAINTS_FIELDS, VIDEO_CATEGORIES } from '../initializers' | 2 | import { CONSTRAINTS_FIELDS, VIDEO_CATEGORIES } from '../initializers' |
3 | import { logger } from './logger' | 3 | import { logger } from './logger' |
4 | import { generateVideoTmpPath } from './utils' | 4 | import { generateVideoTmpPath } from './utils' |
5 | import { YoutubeDlUpdateScheduler } from '../lib/schedulers/youtube-dl-update-scheduler' | 5 | import { join } from 'path' |
6 | import { root } from './core-utils' | ||
7 | import { ensureDir, writeFile } from 'fs-extra' | ||
8 | import * as request from 'request' | ||
9 | import { createWriteStream } from 'fs' | ||
6 | 10 | ||
7 | export type YoutubeDLInfo = { | 11 | export type YoutubeDLInfo = { |
8 | name?: string | 12 | name?: string |
@@ -40,7 +44,7 @@ function downloadYoutubeDLVideo (url: string) { | |||
40 | 44 | ||
41 | return new Promise<string>(async (res, rej) => { | 45 | return new Promise<string>(async (res, rej) => { |
42 | const youtubeDL = await safeGetYoutubeDL() | 46 | const youtubeDL = await safeGetYoutubeDL() |
43 | youtubeDL.exec(url, options, async (err, output) => { | 47 | youtubeDL.exec(url, options, err => { |
44 | if (err) return rej(err) | 48 | if (err) return rej(err) |
45 | 49 | ||
46 | return res(path) | 50 | return res(path) |
@@ -48,6 +52,64 @@ function downloadYoutubeDLVideo (url: string) { | |||
48 | }) | 52 | }) |
49 | } | 53 | } |
50 | 54 | ||
55 | // Thanks: https://github.com/przemyslawpluta/node-youtube-dl/blob/master/lib/downloader.js | ||
56 | // We rewrote it to avoid sync calls | ||
57 | async function updateYoutubeDLBinary () { | ||
58 | logger.info('Updating youtubeDL binary.') | ||
59 | |||
60 | const binDirectory = join(root(), 'node_modules', 'youtube-dl', 'bin') | ||
61 | const bin = join(binDirectory, 'youtube-dl') | ||
62 | const detailsPath = join(binDirectory, 'details') | ||
63 | const url = 'https://yt-dl.org/downloads/latest/youtube-dl' | ||
64 | |||
65 | await ensureDir(binDirectory) | ||
66 | |||
67 | return new Promise(res => { | ||
68 | request.get(url, { followRedirect: false }, (err, result) => { | ||
69 | if (err) { | ||
70 | logger.error('Cannot update youtube-dl.', { err }) | ||
71 | return res() | ||
72 | } | ||
73 | |||
74 | if (result.statusCode !== 302) { | ||
75 | logger.error('youtube-dl update error: did not get redirect for the latest version link. Status %d', result.statusCode) | ||
76 | return res() | ||
77 | } | ||
78 | |||
79 | const url = result.headers.location | ||
80 | const downloadFile = request.get(url) | ||
81 | const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[ 1 ] | ||
82 | |||
83 | downloadFile.on('response', result => { | ||
84 | if (result.statusCode !== 200) { | ||
85 | logger.error('Cannot update youtube-dl: new version response is not 200, it\'s %d.', result.statusCode) | ||
86 | return res() | ||
87 | } | ||
88 | |||
89 | downloadFile.pipe(createWriteStream(bin, { mode: 493 })) | ||
90 | }) | ||
91 | |||
92 | downloadFile.on('error', err => { | ||
93 | logger.error('youtube-dl update error.', { err }) | ||
94 | return res() | ||
95 | }) | ||
96 | |||
97 | downloadFile.on('end', () => { | ||
98 | const details = JSON.stringify({ version: newVersion, path: bin, exec: 'youtube-dl' }) | ||
99 | writeFile(detailsPath, details, { encoding: 'utf8' }, err => { | ||
100 | if (err) { | ||
101 | logger.error('youtube-dl update error: cannot write details.', { err }) | ||
102 | return res() | ||
103 | } | ||
104 | |||
105 | logger.info('youtube-dl updated to version %s.', newVersion) | ||
106 | return res() | ||
107 | }) | ||
108 | }) | ||
109 | }) | ||
110 | }) | ||
111 | } | ||
112 | |||
51 | async function safeGetYoutubeDL () { | 113 | async function safeGetYoutubeDL () { |
52 | let youtubeDL | 114 | let youtubeDL |
53 | 115 | ||
@@ -55,7 +117,7 @@ async function safeGetYoutubeDL () { | |||
55 | youtubeDL = require('youtube-dl') | 117 | youtubeDL = require('youtube-dl') |
56 | } catch (e) { | 118 | } catch (e) { |
57 | // Download binary | 119 | // Download binary |
58 | await YoutubeDlUpdateScheduler.Instance.execute() | 120 | await updateYoutubeDLBinary() |
59 | youtubeDL = require('youtube-dl') | 121 | youtubeDL = require('youtube-dl') |
60 | } | 122 | } |
61 | 123 | ||
@@ -65,6 +127,7 @@ async function safeGetYoutubeDL () { | |||
65 | // --------------------------------------------------------------------------- | 127 | // --------------------------------------------------------------------------- |
66 | 128 | ||
67 | export { | 129 | export { |
130 | updateYoutubeDLBinary, | ||
68 | downloadYoutubeDLVideo, | 131 | downloadYoutubeDLVideo, |
69 | getYoutubeDLInfo, | 132 | getYoutubeDLInfo, |
70 | safeGetYoutubeDL | 133 | safeGetYoutubeDL |