aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json88
-rw-r--r--package.json15
-rwxr-xr-xscripts/ci.sh2
-rw-r--r--scripts/create-import-video-file-job.ts2
-rwxr-xr-xscripts/create-transcoding-job.ts2
-rw-r--r--server/controllers/activitypub/client.ts8
-rw-r--r--server/controllers/activitypub/inbox.ts4
-rw-r--r--server/controllers/api/accounts.ts13
-rw-r--r--server/controllers/api/config.ts22
-rw-r--r--server/controllers/api/jobs.ts2
-rw-r--r--server/controllers/api/overviews.ts2
-rw-r--r--server/controllers/api/server/debug.ts6
-rw-r--r--server/controllers/api/server/follows.ts1
-rw-r--r--server/controllers/api/server/logs.ts10
-rw-r--r--server/controllers/api/server/redundancy.ts2
-rw-r--r--server/controllers/api/users/me.ts4
-rw-r--r--server/controllers/api/users/my-subscriptions.ts6
-rw-r--r--server/controllers/api/video-channel.ts3
-rw-r--r--server/controllers/api/video-playlist.ts1
-rw-r--r--server/controllers/api/videos/import.ts22
-rw-r--r--server/controllers/api/videos/index.ts6
-rw-r--r--server/controllers/client.ts2
-rw-r--r--server/controllers/static.ts16
-rw-r--r--server/controllers/tracker.ts15
-rw-r--r--server/helpers/activitypub.ts6
-rw-r--r--server/helpers/audit-logger.ts24
-rw-r--r--server/helpers/core-utils.ts66
-rw-r--r--server/helpers/custom-jsonld-signature.ts90
-rw-r--r--server/helpers/custom-validators/activitypub/actor.ts4
-rw-r--r--server/helpers/custom-validators/activitypub/video-comments.ts2
-rw-r--r--server/helpers/custom-validators/misc.ts4
-rw-r--r--server/helpers/custom-validators/plugins.ts6
-rw-r--r--server/helpers/custom-validators/user-notifications.ts3
-rw-r--r--server/helpers/custom-validators/video-abuses.ts4
-rw-r--r--server/helpers/custom-validators/video-captions.ts2
-rw-r--r--server/helpers/custom-validators/video-imports.ts2
-rw-r--r--server/helpers/custom-validators/video-playlists.ts6
-rw-r--r--server/helpers/custom-validators/videos.ts8
-rw-r--r--server/helpers/express-utils.ts16
-rw-r--r--server/helpers/ffmpeg-utils.ts179
-rw-r--r--server/helpers/logger.ts13
-rw-r--r--server/helpers/regexp.ts2
-rw-r--r--server/helpers/register-ts-paths.ts2
-rw-r--r--server/helpers/signup.ts2
-rw-r--r--server/helpers/utils.ts4
-rw-r--r--server/helpers/webtorrent.ts20
-rw-r--r--server/helpers/youtube-dl.ts61
-rw-r--r--server/initializers/checker-after-init.ts4
-rw-r--r--server/initializers/checker-before-init.ts4
-rw-r--r--server/initializers/config.ts4
-rw-r--r--server/initializers/constants.ts100
-rw-r--r--server/initializers/database.ts2
-rw-r--r--server/initializers/migrations/0005-email-pod.ts4
-rw-r--r--server/initializers/migrations/0010-email-user.ts4
-rw-r--r--server/initializers/migrations/0015-video-views.ts4
-rw-r--r--server/initializers/migrations/0020-video-likes.ts4
-rw-r--r--server/initializers/migrations/0025-video-dislikes.ts4
-rw-r--r--server/initializers/migrations/0030-video-category.ts4
-rw-r--r--server/initializers/migrations/0035-video-licence.ts4
-rw-r--r--server/initializers/migrations/0040-video-nsfw.ts4
-rw-r--r--server/initializers/migrations/0045-user-display-nsfw.ts4
-rw-r--r--server/initializers/migrations/0050-video-language.ts4
-rw-r--r--server/initializers/migrations/0055-video-uuid.ts4
-rw-r--r--server/initializers/migrations/0060-video-file.ts6
-rw-r--r--server/initializers/migrations/0065-video-file-size.ts6
-rw-r--r--server/initializers/migrations/0070-user-video-quota.ts6
-rw-r--r--server/initializers/migrations/0075-video-resolutions.ts6
-rw-r--r--server/initializers/migrations/0080-video-channels.ts6
-rw-r--r--server/initializers/migrations/0085-user-role.ts6
-rw-r--r--server/initializers/migrations/0090-videos-description.ts6
-rw-r--r--server/initializers/migrations/0095-videos-privacy.ts6
-rw-r--r--server/initializers/migrations/0100-activitypub.ts6
-rw-r--r--server/initializers/migrations/0105-server-mail.ts6
-rw-r--r--server/initializers/migrations/0110-server-key.ts6
-rw-r--r--server/initializers/migrations/0115-account-avatar.ts6
-rw-r--r--server/initializers/migrations/0120-video-null.ts6
-rw-r--r--server/initializers/migrations/0125-table-lowercase.ts4
-rw-r--r--server/initializers/migrations/0130-user-autoplay-video.ts4
-rw-r--r--server/initializers/migrations/0135-video-channel-actor.ts42
-rw-r--r--server/initializers/migrations/0140-actor-url.ts4
-rw-r--r--server/initializers/migrations/0145-delete-author.ts4
-rw-r--r--server/initializers/migrations/0150-avatar-cascade.ts4
-rw-r--r--server/initializers/migrations/0155-video-comments-enabled.ts4
-rw-r--r--server/initializers/migrations/0160-account-route.ts4
-rw-r--r--server/initializers/migrations/0165-video-route.ts4
-rw-r--r--server/initializers/migrations/0170-actor-follow-score.ts4
-rw-r--r--server/initializers/migrations/0175-actor-follow-counts.ts4
-rw-r--r--server/initializers/migrations/0180-job-table-delete.ts4
-rw-r--r--server/initializers/migrations/0185-video-share-url.ts4
-rw-r--r--server/initializers/migrations/0190-video-comment-unique-url.ts4
-rw-r--r--server/initializers/migrations/0195-support.ts4
-rw-r--r--server/initializers/migrations/0200-video-published-at.ts4
-rw-r--r--server/initializers/migrations/0205-user-nsfw-policy.ts4
-rw-r--r--server/initializers/migrations/0210-video-language.ts4
-rw-r--r--server/initializers/migrations/0215-video-support-length.ts4
-rw-r--r--server/initializers/migrations/0255-video-blacklist-reason.ts1
-rw-r--r--server/initializers/migrations/0285-description-support.ts6
-rw-r--r--server/initializers/migrations/0290-account-video-rate-url.ts6
-rw-r--r--server/initializers/migrations/0295-video-file-extname.ts6
-rw-r--r--server/initializers/migrations/0300-user-videos-history-enabled.ts6
-rw-r--r--server/initializers/migrations/0305-fix-unfederated-videos.ts6
-rw-r--r--server/initializers/migrations/0310-drop-unused-video-indexes.ts6
-rw-r--r--server/initializers/migrations/0315-user-notifications.ts4
-rw-r--r--server/initializers/migrations/0320-blacklist-unfederate.ts4
-rw-r--r--server/initializers/migrations/0325-video-abuse-fields.ts4
-rw-r--r--server/initializers/migrations/0330-video-streaming-playlist.ts4
-rw-r--r--server/initializers/migrations/0335-video-downloading-enabled.ts4
-rw-r--r--server/initializers/migrations/0340-add-originally-published-at.ts4
-rw-r--r--server/initializers/migrations/0345-video-playlists.ts4
-rw-r--r--server/initializers/migrations/0350-video-blacklist-type.ts6
-rw-r--r--server/initializers/migrations/0355-p2p-peer-version.ts6
-rw-r--r--server/initializers/migrations/0360-notification-instance-follower.ts6
-rw-r--r--server/initializers/migrations/0365-user-admin-flags.ts6
-rw-r--r--server/initializers/migrations/0370-thumbnail.ts6
-rw-r--r--server/initializers/migrations/0375-account-description.ts6
-rw-r--r--server/initializers/migrations/0380-cleanup-timestamps.ts6
-rw-r--r--server/initializers/migrations/0385-remove-actor-uuid.ts6
-rw-r--r--server/initializers/migrations/0390-user-pending-email.ts6
-rw-r--r--server/initializers/migrations/0395-user-video-languages.ts6
-rw-r--r--server/initializers/migrations/0400-user-theme.ts6
-rw-r--r--server/initializers/migrations/0405-plugin.ts6
-rw-r--r--server/initializers/migrations/0410-video-playlist-element.ts6
-rw-r--r--server/initializers/migrations/0415-thumbnail-auto-generated.ts6
-rw-r--r--server/initializers/migrations/0420-avatar-lazy.ts6
-rw-r--r--server/initializers/migrations/0425-nullable-actor-fields.ts6
-rw-r--r--server/initializers/migrations/0430-auto-follow-notification-setting.ts6
-rw-r--r--server/initializers/migrations/0435-user-modals.ts6
-rw-r--r--server/initializers/migrations/0440-user-auto-play-next-video.ts6
-rw-r--r--server/initializers/migrations/0445-shared-inbox-optional.ts6
-rw-r--r--server/initializers/migrations/0450-streaming-playlist-files.ts16
-rw-r--r--server/initializers/migrations/0455-soft-delete-video-comments.ts6
-rw-r--r--server/initializers/migrations/0460-user-playlist-autoplay.ts6
-rw-r--r--server/initializers/migrations/0465-thumbnail-file-url-length.ts6
-rw-r--r--server/initializers/migrations/0470-cleaup-indexes.ts6
-rw-r--r--server/initializers/migrations/0475-redundancy-expires-on.ts6
-rw-r--r--server/initializers/migrations/0480-caption-file-url.ts6
-rw-r--r--server/initializers/migrator.ts4
-rw-r--r--server/lib/activitypub/actor.ts22
-rw-r--r--server/lib/activitypub/crawl.ts6
-rw-r--r--server/lib/activitypub/follow.ts1
-rw-r--r--server/lib/activitypub/send/send-accept.ts2
-rw-r--r--server/lib/activitypub/send/send-create.ts8
-rw-r--r--server/lib/activitypub/send/send-dislike.ts2
-rw-r--r--server/lib/activitypub/send/send-flag.ts2
-rw-r--r--server/lib/activitypub/send/send-like.ts2
-rw-r--r--server/lib/activitypub/send/send-reject.ts2
-rw-r--r--server/lib/activitypub/send/send-undo.ts10
-rw-r--r--server/lib/activitypub/send/send-update.ts3
-rw-r--r--server/lib/activitypub/send/utils.ts4
-rw-r--r--server/lib/activitypub/video-comments.ts14
-rw-r--r--server/lib/activitypub/video-rates.ts2
-rw-r--r--server/lib/activitypub/videos.ts50
-rw-r--r--server/lib/client-html.ts24
-rw-r--r--server/lib/emailer.ts101
-rw-r--r--server/lib/files-cache/videos-preview-cache.ts3
-rw-r--r--server/lib/job-queue/handlers/utils/activitypub-http-utils.ts2
-rw-r--r--server/lib/job-queue/handlers/video-file-import.ts2
-rw-r--r--server/lib/job-queue/handlers/video-import.ts2
-rw-r--r--server/lib/job-queue/handlers/video-transcoding.ts17
-rw-r--r--server/lib/job-queue/job-queue.ts34
-rw-r--r--server/lib/moderation.ts22
-rw-r--r--server/lib/notifier.ts47
-rw-r--r--server/lib/plugins/plugin-index.ts4
-rw-r--r--server/lib/plugins/plugin-manager.ts44
-rw-r--r--server/lib/redis.ts41
-rw-r--r--server/lib/schedulers/auto-follow-index-instances.ts3
-rw-r--r--server/lib/schedulers/plugins-check-scheduler.ts2
-rw-r--r--server/lib/schedulers/remove-old-views-scheduler.ts2
-rw-r--r--server/lib/schedulers/videos-redundancy-scheduler.ts6
-rw-r--r--server/lib/thumbnail.ts18
-rw-r--r--server/lib/user.ts16
-rw-r--r--server/lib/video-blacklist.ts20
-rw-r--r--server/lib/video-channel.ts3
-rw-r--r--server/lib/video-comment.ts6
-rw-r--r--server/middlewares/activitypub.ts3
-rw-r--r--server/middlewares/csp.ts30
-rw-r--r--server/middlewares/dnt.ts3
-rw-r--r--server/middlewares/oauth.ts1
-rw-r--r--server/middlewares/sort.ts2
-rw-r--r--server/middlewares/validators/avatar.ts4
-rw-r--r--server/middlewares/validators/config.ts2
-rw-r--r--server/middlewares/validators/feeds.ts8
-rw-r--r--server/middlewares/validators/redundancy.ts2
-rw-r--r--server/middlewares/validators/users.ts7
-rw-r--r--server/middlewares/validators/videos/video-captions.ts10
-rw-r--r--server/middlewares/validators/videos/video-comments.ts2
-rw-r--r--server/middlewares/validators/videos/video-imports.ts9
-rw-r--r--server/middlewares/validators/videos/video-playlists.ts9
-rw-r--r--server/middlewares/validators/videos/video-rates.ts2
-rw-r--r--server/middlewares/validators/videos/videos.ts28
-rw-r--r--server/models/account/account-video-rate.ts12
-rw-r--r--server/models/account/account.ts8
-rw-r--r--server/models/account/user-notification.ts2
-rw-r--r--server/models/account/user.ts86
-rw-r--r--server/models/activitypub/actor-follow.ts53
-rw-r--r--server/models/activitypub/actor.ts12
-rw-r--r--server/models/oauth/oauth-token.ts4
-rw-r--r--server/models/redundancy/video-redundancy.ts58
-rw-r--r--server/models/server/plugin.ts8
-rw-r--r--server/models/utils.ts4
-rw-r--r--server/models/video/thumbnail.ts2
-rw-r--r--server/models/video/video-abuse.ts6
-rw-r--r--server/models/video/video-caption.ts7
-rw-r--r--server/models/video/video-channel.ts10
-rw-r--r--server/models/video/video-comment.ts20
-rw-r--r--server/models/video/video-format-utils.ts19
-rw-r--r--server/models/video/video-playlist-element.ts8
-rw-r--r--server/models/video/video-playlist.ts34
-rw-r--r--server/models/video/video.ts165
-rw-r--r--server/tests/api/activitypub/client.ts4
-rw-r--r--server/tests/api/activitypub/fetch.ts4
-rw-r--r--server/tests/api/activitypub/helpers.ts2
-rw-r--r--server/tests/api/activitypub/refresher.ts70
-rw-r--r--server/tests/api/activitypub/security.ts13
-rw-r--r--server/tests/api/check-params/accounts.ts2
-rw-r--r--server/tests/api/check-params/blocklist.ts2
-rw-r--r--server/tests/api/check-params/config.ts2
-rw-r--r--server/tests/api/check-params/contact-form.ts18
-rw-r--r--server/tests/api/check-params/debug.ts7
-rw-r--r--server/tests/api/check-params/follows.ts2
-rw-r--r--server/tests/api/check-params/jobs.ts8
-rw-r--r--server/tests/api/check-params/logs.ts8
-rw-r--r--server/tests/api/check-params/plugins.ts2
-rw-r--r--server/tests/api/check-params/redundancy.ts4
-rw-r--r--server/tests/api/check-params/search.ts2
-rw-r--r--server/tests/api/check-params/services.ts2
-rw-r--r--server/tests/api/check-params/user-notifications.ts2
-rw-r--r--server/tests/api/check-params/user-subscriptions.ts2
-rw-r--r--server/tests/api/check-params/users.ts13
-rw-r--r--server/tests/api/check-params/video-abuses.ts4
-rw-r--r--server/tests/api/check-params/video-blacklist.ts15
-rw-r--r--server/tests/api/check-params/video-captions.ts4
-rw-r--r--server/tests/api/check-params/video-channels.ts12
-rw-r--r--server/tests/api/check-params/video-comments.ts2
-rw-r--r--server/tests/api/check-params/video-imports.ts17
-rw-r--r--server/tests/api/check-params/video-playlists.ts7
-rw-r--r--server/tests/api/check-params/videos-filter.ts6
-rw-r--r--server/tests/api/check-params/videos-history.ts9
-rw-r--r--server/tests/api/check-params/videos.ts38
-rw-r--r--server/tests/api/notifications/user-notifications.ts88
-rw-r--r--server/tests/api/redundancy/manage-redundancy.ts44
-rw-r--r--server/tests/api/redundancy/redundancy.ts44
-rw-r--r--server/tests/api/search/search-activitypub-video-channels.ts44
-rw-r--r--server/tests/api/search/search-activitypub-videos.ts8
-rw-r--r--server/tests/api/search/search-videos.ts14
-rw-r--r--server/tests/api/server/auto-follows.ts19
-rw-r--r--server/tests/api/server/config.ts11
-rw-r--r--server/tests/api/server/contact-form.ts12
-rw-r--r--server/tests/api/server/email.ts2
-rw-r--r--server/tests/api/server/follow-constraints.ts8
-rw-r--r--server/tests/api/server/follows-moderation.ts18
-rw-r--r--server/tests/api/server/follows.ts88
-rw-r--r--server/tests/api/server/handle-down.ts36
-rw-r--r--server/tests/api/server/jobs.ts16
-rw-r--r--server/tests/api/server/logs.ts2
-rw-r--r--server/tests/api/server/no-client.ts2
-rw-r--r--server/tests/api/server/plugins.ts25
-rw-r--r--server/tests/api/server/reverse-proxy.ts2
-rw-r--r--server/tests/api/server/stats.ts7
-rw-r--r--server/tests/api/server/tracker.ts2
-rw-r--r--server/tests/api/users/blocklist.ts259
-rw-r--r--server/tests/api/users/user-subscriptions.ts15
-rw-r--r--server/tests/api/users/users-multiple-servers.ts11
-rw-r--r--server/tests/api/users/users-verification.ts2
-rw-r--r--server/tests/api/users/users.ts55
-rw-r--r--server/tests/api/videos/audio-only.ts27
-rw-r--r--server/tests/api/videos/multiple-servers.ts32
-rw-r--r--server/tests/api/videos/services.ts10
-rw-r--r--server/tests/api/videos/single-server.ts2
-rw-r--r--server/tests/api/videos/video-abuse.ts18
-rw-r--r--server/tests/api/videos/video-blacklist.ts86
-rw-r--r--server/tests/api/videos/video-captions.ts9
-rw-r--r--server/tests/api/videos/video-change-ownership.ts18
-rw-r--r--server/tests/api/videos/video-channels.ts35
-rw-r--r--server/tests/api/videos/video-comments.ts6
-rw-r--r--server/tests/api/videos/video-description.ts7
-rw-r--r--server/tests/api/videos/video-hls.ts29
-rw-r--r--server/tests/api/videos/video-imports.ts11
-rw-r--r--server/tests/api/videos/video-nsfw.ts34
-rw-r--r--server/tests/api/videos/video-playlist-thumbnails.ts53
-rw-r--r--server/tests/api/videos/video-playlists.ts392
-rw-r--r--server/tests/api/videos/video-privacy.ts11
-rw-r--r--server/tests/api/videos/video-schedule-update.ts3
-rw-r--r--server/tests/api/videos/video-transcoder.ts46
-rw-r--r--server/tests/api/videos/videos-filter.ts12
-rw-r--r--server/tests/api/videos/videos-history.ts2
-rw-r--r--server/tests/api/videos/videos-overview.ts2
-rw-r--r--server/tests/api/videos/videos-views-cleaner.ts16
-rw-r--r--server/tests/cli/create-import-video-file-job.ts6
-rw-r--r--server/tests/cli/create-transcoding-job.ts15
-rw-r--r--server/tests/cli/optimize-old-videos.ts4
-rw-r--r--server/tests/cli/peertube.ts19
-rw-r--r--server/tests/cli/plugins.ts2
-rw-r--r--server/tests/cli/prune-storage.ts19
-rw-r--r--server/tests/cli/update-host.ts2
-rw-r--r--server/tests/client.ts2
-rw-r--r--server/tests/feeds/feeds.ts58
-rw-r--r--server/tests/helpers/comment-model.ts4
-rw-r--r--server/tests/helpers/core-utils.ts2
-rw-r--r--server/tests/helpers/request.ts2
-rw-r--r--server/tests/misc-endpoints.ts2
-rw-r--r--server/tests/plugins/action-hooks.ts17
-rw-r--r--server/tests/plugins/filter-hooks.ts41
-rw-r--r--server/tests/plugins/translations.ts35
-rw-r--r--server/tests/plugins/video-constants.ts58
-rw-r--r--server/tests/real-world/populate-database.ts122
-rw-r--r--server/tests/real-world/real-world.ts375
-rw-r--r--server/tools/cli.ts42
-rw-r--r--server/tools/peertube-auth.ts10
-rw-r--r--server/tools/peertube-import-videos.ts83
-rw-r--r--server/tools/peertube-plugins.ts11
-rw-r--r--server/tools/peertube-redundancy.ts19
-rw-r--r--server/tools/peertube-repl.ts41
-rw-r--r--server/tools/peertube-upload.ts21
-rw-r--r--server/tools/peertube-watch.ts10
-rw-r--r--server/tools/peertube.ts23
-rw-r--r--server/typings/models/account/account-blocklist.ts6
-rw-r--r--server/typings/models/account/account.ts42
-rw-r--r--server/typings/models/account/actor-follow.ts24
-rw-r--r--server/typings/models/account/actor.ts54
-rw-r--r--server/typings/models/account/avatar.ts3
-rw-r--r--server/typings/models/oauth/oauth-token.ts3
-rw-r--r--server/typings/models/server/plugin.ts3
-rw-r--r--server/typings/models/server/server-blocklist.ts6
-rw-r--r--server/typings/models/server/server.ts6
-rw-r--r--server/typings/models/user/user-notification.ts42
-rw-r--r--server/typings/models/user/user.ts33
-rw-r--r--server/typings/models/video/schedule-video-update.ts3
-rw-r--r--server/typings/models/video/video-abuse.ts9
-rw-r--r--server/typings/models/video/video-blacklist.ts9
-rw-r--r--server/typings/models/video/video-caption.ts6
-rw-r--r--server/typings/models/video/video-change-ownership.ts6
-rw-r--r--server/typings/models/video/video-channels.ts57
-rw-r--r--server/typings/models/video/video-comment.ts27
-rw-r--r--server/typings/models/video/video-file.ts18
-rw-r--r--server/typings/models/video/video-import.ts12
-rw-r--r--server/typings/models/video/video-playlist-element.ts12
-rw-r--r--server/typings/models/video/video-playlist.ts36
-rw-r--r--server/typings/models/video/video-rate.ts9
-rw-r--r--server/typings/models/video/video-redundancy.ts15
-rw-r--r--server/typings/models/video/video-share.ts6
-rw-r--r--server/typings/models/video/video-streaming-playlist.ts18
-rw-r--r--server/typings/models/video/video.ts78
-rw-r--r--server/typings/utils.ts2
-rw-r--r--shared/core-utils/miscs/miscs.ts2
-rw-r--r--shared/extra-utils/instances-index/mock-instances-index.ts2
-rw-r--r--shared/extra-utils/miscs/miscs.ts10
-rw-r--r--shared/extra-utils/miscs/sql.ts12
-rw-r--r--shared/extra-utils/requests/requests.ts58
-rw-r--r--shared/extra-utils/search/videos.ts2
-rw-r--r--shared/extra-utils/server/clients.ts4
-rw-r--r--shared/extra-utils/server/contact-form.ts10
-rw-r--r--shared/extra-utils/server/follows.ts26
-rw-r--r--shared/extra-utils/server/jobs.ts22
-rw-r--r--shared/extra-utils/server/plugins.ts72
-rw-r--r--shared/extra-utils/server/redundancy.ts18
-rw-r--r--shared/extra-utils/server/servers.ts27
-rw-r--r--shared/extra-utils/users/accounts.ts2
-rw-r--r--shared/extra-utils/users/blocklist.ts2
-rw-r--r--shared/extra-utils/users/login.ts2
-rw-r--r--shared/extra-utils/users/user-notifications.ts33
-rw-r--r--shared/extra-utils/users/users.ts40
-rw-r--r--shared/extra-utils/videos/video-blacklist.ts28
-rw-r--r--shared/extra-utils/videos/video-captions.ts6
-rw-r--r--shared/extra-utils/videos/video-channels.ts20
-rw-r--r--shared/extra-utils/videos/video-comments.ts2
-rw-r--r--shared/extra-utils/videos/video-imports.ts2
-rw-r--r--shared/extra-utils/videos/video-playlists.ts50
-rw-r--r--shared/extra-utils/videos/video-streaming-playlists.ts2
-rw-r--r--shared/extra-utils/videos/videos.ts21
-rw-r--r--shared/models/activitypub/activity.ts43
-rw-r--r--shared/models/activitypub/activitypub-actor.ts8
-rw-r--r--shared/models/activitypub/activitypub-signature.ts4
-rw-r--r--shared/models/activitypub/objects/cache-file-object.ts2
-rw-r--r--shared/models/activitypub/objects/common-objects.ts32
-rw-r--r--shared/models/activitypub/objects/video-abuse-object.ts2
-rw-r--r--shared/models/activitypub/objects/video-torrent-object.ts4
-rw-r--r--shared/models/activitypub/objects/view-object.ts2
-rw-r--r--shared/models/i18n/i18n.ts2
-rw-r--r--shared/models/nodeinfo/index.d.ts2
-rw-r--r--shared/models/plugins/peertube-plugin-latest-version.model.ts2
-rw-r--r--shared/models/plugins/plugin-package-json.model.ts12
-rw-r--r--shared/models/plugins/server-hook.model.ts2
-rw-r--r--shared/models/redundancy/video-redundancy.model.ts2
-rw-r--r--shared/models/server/custom-config.model.ts4
-rw-r--r--shared/models/server/job.model.ts27
-rw-r--r--shared/models/server/server-config.model.ts6
-rw-r--r--shared/models/users/user.model.ts1
-rw-r--r--tslint.json19
-rw-r--r--yarn.lock788
390 files changed, 3951 insertions, 3616 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 000000000..a86c5bbba
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,88 @@
1{
2 "extends": "standard-with-typescript",
3 "rules": {
4 "eol-last": [
5 "error",
6 "always"
7 ],
8 "indent": "off",
9 "no-lone-blocks": "off",
10 "no-mixed-operators": "off",
11 "max-len": [
12 "error",
13 {
14 "code": 140
15 }
16 ],
17 "array-bracket-spacing": [
18 "error",
19 "always"
20 ],
21 "quote-props": [
22 "error",
23 "consistent-as-needed"
24 ],
25 "padded-blocks": "off",
26 "no-async-promise-executor": "off",
27 "dot-notation": "off",
28 "promise/param-names": "off",
29 "import/first": "off",
30 "operator-linebreak": [
31 "error",
32 "after",
33 {
34 "overrides": {
35 "?": "before",
36 ":": "before"
37 }
38 }
39 ],
40 "@typescript-eslint/indent": [
41 "error",
42 2,
43 {
44 "SwitchCase": 1,
45 "MemberExpression": "off"
46 }
47 ],
48 "@typescript-eslint/consistent-type-assertions": [
49 "error",
50 {
51 "assertionStyle": "as"
52 }
53 ],
54 "@typescript-eslint/array-type": [
55 "error",
56 {
57 "default": "array"
58 }
59 ],
60 "@typescript-eslint/restrict-template-expressions": [
61 "off",
62 {
63 "allowNumber": "true"
64 }
65 ],
66 "@typescript-eslint/quotes": "off",
67 "@typescript-eslint/no-var-requires": "off",
68 "@typescript-eslint/explicit-function-return-type": "off",
69 "@typescript-eslint/promise-function-async": "off",
70 "@typescript-eslint/no-dynamic-delete": "off",
71 "@typescript-eslint/strict-boolean-expressions": "off",
72 "@typescript-eslint/consistent-type-definitions": "off",
73 "@typescript-eslint/no-misused-promises": "off",
74 "@typescript-eslint/no-namespace": "off",
75 "@typescript-eslint/no-extraneous-class": "off",
76 // bugged but useful
77 "@typescript-eslint/restrict-plus-operands": "off"
78 },
79 "ignorePatterns": [
80 "node_modules/"
81 ],
82 "parserOptions": {
83 "project": [
84 "./tsconfig.json",
85 "./server/tools/tsconfig.json"
86 ]
87 }
88}
diff --git a/package.json b/package.json
index a766f8d81..0a5484d2a 100644
--- a/package.json
+++ b/package.json
@@ -63,7 +63,7 @@
63 "ng": "ng", 63 "ng": "ng",
64 "nodemon": "nodemon", 64 "nodemon": "nodemon",
65 "ts-node": "ts-node", 65 "ts-node": "ts-node",
66 "tslint": "tslint", 66 "eslint": "eslint",
67 "concurrently": "concurrently", 67 "concurrently": "concurrently",
68 "mocha-parallel-tests": "mocha-parallel-tests", 68 "mocha-parallel-tests": "mocha-parallel-tests",
69 "sasslint": "sass-lint --verbose --no-exit", 69 "sasslint": "sass-lint --verbose --no-exit",
@@ -96,7 +96,7 @@
96 "express": "^4.12.4", 96 "express": "^4.12.4",
97 "express-oauth-server": "^2.0.0", 97 "express-oauth-server": "^2.0.0",
98 "express-rate-limit": "^4.0.4", 98 "express-rate-limit": "^4.0.4",
99 "express-validator": "^6.1.1", 99 "express-validator": "^6.4.0",
100 "flat": "^5.0.0", 100 "flat": "^5.0.0",
101 "fluent-ffmpeg": "^2.1.0", 101 "fluent-ffmpeg": "^2.1.0",
102 "fs-extra": "^8.0.1", 102 "fs-extra": "^8.0.1",
@@ -139,7 +139,7 @@
139 "webtorrent": "^0.107.16", 139 "webtorrent": "^0.107.16",
140 "winston": "3.2.1", 140 "winston": "3.2.1",
141 "ws": "^7.0.0", 141 "ws": "^7.0.0",
142 "youtube-dl": "^3.0.1" 142 "youtube-dl": "^3.0.2"
143 }, 143 },
144 "devDependencies": { 144 "devDependencies": {
145 "@types/apicache": "^1.2.0", 145 "@types/apicache": "^1.2.0",
@@ -180,10 +180,17 @@
180 "@types/validator": "^12.0.1", 180 "@types/validator": "^12.0.1",
181 "@types/webtorrent": "^0.107.0", 181 "@types/webtorrent": "^0.107.0",
182 "@types/ws": "^7.2.1", 182 "@types/ws": "^7.2.1",
183 "@typescript-eslint/eslint-plugin": "^2.18.0",
183 "chai": "^4.1.1", 184 "chai": "^4.1.1",
184 "chai-json-schema": "^1.5.0", 185 "chai-json-schema": "^1.5.0",
185 "chai-xml": "^0.3.2", 186 "chai-xml": "^0.3.2",
186 "concurrently": "^5.0.0", 187 "concurrently": "^5.0.0",
188 "eslint": "^6.8.0",
189 "eslint-config-standard-with-typescript": "^12.0.1",
190 "eslint-plugin-import": "^2.20.1",
191 "eslint-plugin-node": "^11.0.0",
192 "eslint-plugin-promise": "^4.2.1",
193 "eslint-plugin-standard": "^4.0.1",
187 "libxmljs": "0.19.7", 194 "libxmljs": "0.19.7",
188 "maildev": "^1.0.0-rc3", 195 "maildev": "^1.0.0-rc3",
189 "marked": "^0.8.0", 196 "marked": "^0.8.0",
@@ -195,8 +202,6 @@
195 "supertest": "^4.0.2", 202 "supertest": "^4.0.2",
196 "swagger-cli": "^3.0.1", 203 "swagger-cli": "^3.0.1",
197 "ts-node": "8.6.2", 204 "ts-node": "8.6.2",
198 "tslint": "^6.0.0",
199 "tslint-config-standard": "^9.0.0",
200 "typescript": "^3.7.2" 205 "typescript": "^3.7.2"
201 }, 206 },
202 "scripty": { 207 "scripty": {
diff --git a/scripts/ci.sh b/scripts/ci.sh
index 4063a6241..aea009d9f 100755
--- a/scripts/ci.sh
+++ b/scripts/ci.sh
@@ -35,7 +35,7 @@ elif [ "$1" = "api-4" ]; then
35 npm run build:server 35 npm run build:server
36 sh ./server/tests/api/ci-4.sh 2 36 sh ./server/tests/api/ci-4.sh 2
37elif [ "$1" = "lint" ]; then 37elif [ "$1" = "lint" ]; then
38 npm run tslint -- --project ./tsconfig.json -c ./tslint.json server.ts "server/**/*.ts" "shared/**/*.ts" 38 npm run eslint -- --ext .ts "server/**/*.ts" "shared/**/*.ts"
39 npm run swagger-cli -- validate support/doc/api/openapi.yaml 39 npm run swagger-cli -- validate support/doc/api/openapi.yaml
40 40
41 ( cd client 41 ( cd client
diff --git a/scripts/create-import-video-file-job.ts b/scripts/create-import-video-file-job.ts
index 204337d55..37738ca40 100644
--- a/scripts/create-import-video-file-job.ts
+++ b/scripts/create-import-video-file-job.ts
@@ -38,6 +38,6 @@ async function run () {
38 } 38 }
39 39
40 await JobQueue.Instance.init() 40 await JobQueue.Instance.init()
41 await JobQueue.Instance.createJob({ type: 'video-file-import', payload: dataInput }) 41 await JobQueue.Instance.createJobWithPromise({ type: 'video-file-import', payload: dataInput })
42 console.log('Import job for video %s created.', video.uuid) 42 console.log('Import job for video %s created.', video.uuid)
43} 43}
diff --git a/scripts/create-transcoding-job.ts b/scripts/create-transcoding-job.ts
index 27170299d..fec58da2e 100755
--- a/scripts/create-transcoding-job.ts
+++ b/scripts/create-transcoding-job.ts
@@ -72,7 +72,7 @@ async function run () {
72 await JobQueue.Instance.init() 72 await JobQueue.Instance.init()
73 73
74 for (const d of dataInput) { 74 for (const d of dataInput) {
75 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: d }) 75 await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: d })
76 console.log('Transcoding job for video %s created.', video.uuid) 76 console.log('Transcoding job for video %s created.', video.uuid)
77 } 77 }
78} 78}
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts
index 95c2a26a6..39f6d7231 100644
--- a/server/controllers/activitypub/client.ts
+++ b/server/controllers/activitypub/client.ts
@@ -122,7 +122,7 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity
122activityPubClientRouter.get('/video-channels/:name', 122activityPubClientRouter.get('/video-channels/:name',
123 executeIfActivityPub, 123 executeIfActivityPub,
124 asyncMiddleware(localVideoChannelValidator), 124 asyncMiddleware(localVideoChannelValidator),
125 asyncMiddleware(videoChannelController) 125 videoChannelController
126) 126)
127activityPubClientRouter.get('/video-channels/:name/followers', 127activityPubClientRouter.get('/video-channels/:name/followers',
128 executeIfActivityPub, 128 executeIfActivityPub,
@@ -154,7 +154,7 @@ activityPubClientRouter.get('/video-playlists/:playlistId',
154activityPubClientRouter.get('/video-playlists/:playlistId/:videoId', 154activityPubClientRouter.get('/video-playlists/:playlistId/:videoId',
155 executeIfActivityPub, 155 executeIfActivityPub,
156 asyncMiddleware(videoPlaylistElementAPGetValidator), 156 asyncMiddleware(videoPlaylistElementAPGetValidator),
157 asyncMiddleware(videoPlaylistElementController) 157 videoPlaylistElementController
158) 158)
159 159
160// --------------------------------------------------------------------------- 160// ---------------------------------------------------------------------------
@@ -281,7 +281,7 @@ async function videoCommentsController (req: express.Request, res: express.Respo
281 return activityPubResponse(activityPubContextify(json), res) 281 return activityPubResponse(activityPubContextify(json), res)
282} 282}
283 283
284async function videoChannelController (req: express.Request, res: express.Response) { 284function videoChannelController (req: express.Request, res: express.Response) {
285 const videoChannel = res.locals.videoChannel 285 const videoChannel = res.locals.videoChannel
286 286
287 return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res) 287 return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res)
@@ -353,7 +353,7 @@ async function videoPlaylistController (req: express.Request, res: express.Respo
353 return activityPubResponse(activityPubContextify(object), res) 353 return activityPubResponse(activityPubContextify(object), res)
354} 354}
355 355
356async function videoPlaylistElementController (req: express.Request, res: express.Response) { 356function videoPlaylistElementController (req: express.Request, res: express.Response) {
357 const videoPlaylistElement = res.locals.videoPlaylistElementAP 357 const videoPlaylistElement = res.locals.videoPlaylistElementAP
358 358
359 const json = videoPlaylistElement.toActivityPubObject() 359 const json = videoPlaylistElement.toActivityPubObject()
diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts
index 4fb180003..3b8fb34a8 100644
--- a/server/controllers/activitypub/inbox.ts
+++ b/server/controllers/activitypub/inbox.ts
@@ -46,6 +46,10 @@ const inboxQueue = queue<QueueParam, Error>((task, cb) => {
46 46
47 processActivities(task.activities, options) 47 processActivities(task.activities, options)
48 .then(() => cb()) 48 .then(() => cb())
49 .catch(err => {
50 logger.error('Error in process activities.', { err })
51 cb()
52 })
49}) 53})
50 54
51function inboxController (req: express.Request, res: express.Response) { 55function inboxController (req: express.Request, res: express.Response) {
diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts
index 05740318e..f354ccf24 100644
--- a/server/controllers/api/accounts.ts
+++ b/server/controllers/api/accounts.ts
@@ -16,21 +16,17 @@ import {
16 accountNameWithHostGetValidator, 16 accountNameWithHostGetValidator,
17 accountsSortValidator, 17 accountsSortValidator,
18 ensureAuthUserOwnsAccountValidator, 18 ensureAuthUserOwnsAccountValidator,
19 videosSortValidator, 19 videoChannelsSortValidator,
20 videoChannelsSortValidator 20 videosSortValidator
21} from '../../middlewares/validators' 21} from '../../middlewares/validators'
22import { AccountModel } from '../../models/account/account' 22import { AccountModel } from '../../models/account/account'
23import { AccountVideoRateModel } from '../../models/account/account-video-rate' 23import { AccountVideoRateModel } from '../../models/account/account-video-rate'
24import { VideoModel } from '../../models/video/video' 24import { VideoModel } from '../../models/video/video'
25import { buildNSFWFilter, isUserAbleToSearchRemoteURI, getCountVideos } from '../../helpers/express-utils' 25import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
26import { VideoChannelModel } from '../../models/video/video-channel' 26import { VideoChannelModel } from '../../models/video/video-channel'
27import { JobQueue } from '../../lib/job-queue' 27import { JobQueue } from '../../lib/job-queue'
28import { logger } from '../../helpers/logger'
29import { VideoPlaylistModel } from '../../models/video/video-playlist' 28import { VideoPlaylistModel } from '../../models/video/video-playlist'
30import { 29import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists'
31 commonVideoPlaylistFiltersValidator,
32 videoPlaylistsSearchValidator
33} from '../../middlewares/validators/videos/video-playlists'
34 30
35const accountsRouter = express.Router() 31const accountsRouter = express.Router()
36 32
@@ -104,7 +100,6 @@ function getAccount (req: express.Request, res: express.Response) {
104 100
105 if (account.isOutdated()) { 101 if (account.isOutdated()) {
106 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) 102 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } })
107 .catch(err => logger.error('Cannot create AP refresher job for actor %s.', account.Actor.url, { err }))
108 } 103 }
109 104
110 return res.json(account.toFormattedJSON()) 105 return res.json(account.toFormattedJSON())
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index ae4e00248..69940f395 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -31,12 +31,12 @@ configRouter.get('/',
31configRouter.get('/custom', 31configRouter.get('/custom',
32 authenticate, 32 authenticate,
33 ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), 33 ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
34 asyncMiddleware(getCustomConfig) 34 getCustomConfig
35) 35)
36configRouter.put('/custom', 36configRouter.put('/custom',
37 authenticate, 37 authenticate,
38 ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), 38 ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
39 asyncMiddleware(customConfigUpdateValidator), 39 customConfigUpdateValidator,
40 asyncMiddleware(updateCustomConfig) 40 asyncMiddleware(updateCustomConfig)
41) 41)
42configRouter.delete('/custom', 42configRouter.delete('/custom',
@@ -196,7 +196,7 @@ function getAbout (req: express.Request, res: express.Response) {
196 return res.json(about).end() 196 return res.json(about).end()
197} 197}
198 198
199async function getCustomConfig (req: express.Request, res: express.Response) { 199function getCustomConfig (req: express.Request, res: express.Response) {
200 const data = customConfig() 200 const data = customConfig()
201 201
202 return res.json(data).end() 202 return res.json(data).end()
@@ -250,7 +250,7 @@ function getRegisteredThemes () {
250 250
251function getEnabledResolutions () { 251function getEnabledResolutions () {
252 return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) 252 return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
253 .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[ key ] === true) 253 .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
254 .map(r => parseInt(r, 10)) 254 .map(r => parseInt(r, 10))
255} 255}
256 256
@@ -340,13 +340,13 @@ function customConfig (): CustomConfig {
340 allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, 340 allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES,
341 threads: CONFIG.TRANSCODING.THREADS, 341 threads: CONFIG.TRANSCODING.THREADS,
342 resolutions: { 342 resolutions: {
343 '0p': CONFIG.TRANSCODING.RESOLUTIONS[ '0p' ], 343 '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'],
344 '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], 344 '240p': CONFIG.TRANSCODING.RESOLUTIONS['240p'],
345 '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ], 345 '360p': CONFIG.TRANSCODING.RESOLUTIONS['360p'],
346 '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], 346 '480p': CONFIG.TRANSCODING.RESOLUTIONS['480p'],
347 '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], 347 '720p': CONFIG.TRANSCODING.RESOLUTIONS['720p'],
348 '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ], 348 '1080p': CONFIG.TRANSCODING.RESOLUTIONS['1080p'],
349 '2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ] 349 '2160p': CONFIG.TRANSCODING.RESOLUTIONS['2160p']
350 }, 350 },
351 webtorrent: { 351 webtorrent: {
352 enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED 352 enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED
diff --git a/server/controllers/api/jobs.ts b/server/controllers/api/jobs.ts
index 05320311e..13fc04d18 100644
--- a/server/controllers/api/jobs.ts
+++ b/server/controllers/api/jobs.ts
@@ -50,7 +50,7 @@ async function listJobs (req: express.Request, res: express.Response) {
50 }) 50 })
51 const total = await JobQueue.Instance.count(state) 51 const total = await JobQueue.Instance.count(state)
52 52
53 const result: ResultList<any> = { 53 const result: ResultList<Job> = {
54 total, 54 total,
55 data: jobs.map(j => formatJob(j, state)) 55 data: jobs.map(j => formatJob(j, state))
56 } 56 }
diff --git a/server/controllers/api/overviews.ts b/server/controllers/api/overviews.ts
index 46e76ac6b..75f3baedb 100644
--- a/server/controllers/api/overviews.ts
+++ b/server/controllers/api/overviews.ts
@@ -24,7 +24,7 @@ export { overviewsRouter }
24const buildSamples = memoizee(async function () { 24const buildSamples = memoizee(async function () {
25 const [ categories, channels, tags ] = await Promise.all([ 25 const [ categories, channels, tags ] = await Promise.all([
26 VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), 26 VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
27 VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), 27 VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
28 TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) 28 TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT)
29 ]) 29 ])
30 30
diff --git a/server/controllers/api/server/debug.ts b/server/controllers/api/server/debug.ts
index 4450038f6..e12fc1dd4 100644
--- a/server/controllers/api/server/debug.ts
+++ b/server/controllers/api/server/debug.ts
@@ -1,13 +1,13 @@
1import * as express from 'express' 1import * as express from 'express'
2import { UserRight } from '../../../../shared/models/users' 2import { UserRight } from '../../../../shared/models/users'
3import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' 3import { authenticate, ensureUserHasRight } from '../../../middlewares'
4 4
5const debugRouter = express.Router() 5const debugRouter = express.Router()
6 6
7debugRouter.get('/debug', 7debugRouter.get('/debug',
8 authenticate, 8 authenticate,
9 ensureUserHasRight(UserRight.MANAGE_DEBUG), 9 ensureUserHasRight(UserRight.MANAGE_DEBUG),
10 asyncMiddleware(getDebug) 10 getDebug
11) 11)
12 12
13// --------------------------------------------------------------------------- 13// ---------------------------------------------------------------------------
@@ -18,7 +18,7 @@ export {
18 18
19// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
20 20
21async function getDebug (req: express.Request, res: express.Response) { 21function getDebug (req: express.Request, res: express.Response) {
22 return res.json({ 22 return res.json({
23 ip: req.ip 23 ip: req.ip
24 }).end() 24 }).end()
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts
index c69de21fb..0bc20bd60 100644
--- a/server/controllers/api/server/follows.ts
+++ b/server/controllers/api/server/follows.ts
@@ -135,7 +135,6 @@ async function followInstance (req: express.Request, res: express.Response) {
135 } 135 }
136 136
137 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) 137 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
138 .catch(err => logger.error('Cannot create follow job for %s.', host, err))
139 } 138 }
140 139
141 return res.status(204).end() 140 return res.status(204).end()
diff --git a/server/controllers/api/server/logs.ts b/server/controllers/api/server/logs.ts
index cd1e0f5bf..4b543d686 100644
--- a/server/controllers/api/server/logs.ts
+++ b/server/controllers/api/server/logs.ts
@@ -59,9 +59,9 @@ async function getLogs (req: express.Request, res: express.Response) {
59} 59}
60 60
61async function generateOutput (options: { 61async function generateOutput (options: {
62 startDateQuery: string, 62 startDateQuery: string
63 endDateQuery?: string, 63 endDateQuery?: string
64 level: LogLevel, 64 level: LogLevel
65 nameFilter: RegExp 65 nameFilter: RegExp
66}) { 66}) {
67 const { startDateQuery, level, nameFilter } = options 67 const { startDateQuery, level, nameFilter } = options
@@ -111,7 +111,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date,
111 const output: any[] = [] 111 const output: any[] = []
112 112
113 for (let i = lines.length - 1; i >= 0; i--) { 113 for (let i = lines.length - 1; i >= 0; i--) {
114 const line = lines[ i ] 114 const line = lines[i]
115 let log: any 115 let log: any
116 116
117 try { 117 try {
@@ -122,7 +122,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date,
122 } 122 }
123 123
124 logTime = new Date(log.timestamp).getTime() 124 logTime = new Date(log.timestamp).getTime()
125 if (logTime >= startTime && logTime <= endTime && logsLevel[ log.level ] >= logsLevel[ level ]) { 125 if (logTime >= startTime && logTime <= endTime && logsLevel[log.level] >= logsLevel[level]) {
126 output.push(log) 126 output.push(log)
127 127
128 currentSize += line.length 128 currentSize += line.length
diff --git a/server/controllers/api/server/redundancy.ts b/server/controllers/api/server/redundancy.ts
index a11c1a74f..1ced0759e 100644
--- a/server/controllers/api/server/redundancy.ts
+++ b/server/controllers/api/server/redundancy.ts
@@ -84,7 +84,7 @@ async function addVideoRedundancy (req: express.Request, res: express.Response)
84 videoId: res.locals.onlyVideo.id 84 videoId: res.locals.onlyVideo.id
85 } 85 }
86 86
87 await JobQueue.Instance.createJob({ 87 await JobQueue.Instance.createJobWithPromise({
88 type: 'video-redundancy', 88 type: 'video-redundancy',
89 payload 89 payload
90 }) 90 })
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts
index ac7c62aab..23890e20c 100644
--- a/server/controllers/api/users/me.ts
+++ b/server/controllers/api/users/me.ts
@@ -39,7 +39,7 @@ meRouter.get('/me',
39) 39)
40meRouter.delete('/me', 40meRouter.delete('/me',
41 authenticate, 41 authenticate,
42 asyncMiddleware(deleteMeValidator), 42 deleteMeValidator,
43 asyncMiddleware(deleteMe) 43 asyncMiddleware(deleteMe)
44) 44)
45 45
@@ -214,7 +214,7 @@ async function updateMe (req: express.Request, res: express.Response) {
214} 214}
215 215
216async function updateMyAvatar (req: express.Request, res: express.Response) { 216async function updateMyAvatar (req: express.Request, res: express.Response) {
217 const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] 217 const avatarPhysicalFile = req.files['avatarfile'][0]
218 const user = res.locals.oauth.token.user 218 const user = res.locals.oauth.token.user
219 219
220 const userAccount = await AccountModel.load(user.Account.id) 220 const userAccount = await AccountModel.load(user.Account.id)
diff --git a/server/controllers/api/users/my-subscriptions.ts b/server/controllers/api/users/my-subscriptions.ts
index 43c4c37d8..888392b8b 100644
--- a/server/controllers/api/users/my-subscriptions.ts
+++ b/server/controllers/api/users/my-subscriptions.ts
@@ -19,7 +19,6 @@ import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils'
19import { VideoFilter } from '../../../../shared/models/videos/video-query.type' 19import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
20import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 20import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
21import { JobQueue } from '../../../lib/job-queue' 21import { JobQueue } from '../../../lib/job-queue'
22import { logger } from '../../../helpers/logger'
23import { sequelizeTypescript } from '../../../initializers/database' 22import { sequelizeTypescript } from '../../../initializers/database'
24 23
25const mySubscriptionsRouter = express.Router() 24const mySubscriptionsRouter = express.Router()
@@ -52,7 +51,7 @@ mySubscriptionsRouter.get('/me/subscriptions',
52mySubscriptionsRouter.post('/me/subscriptions', 51mySubscriptionsRouter.post('/me/subscriptions',
53 authenticate, 52 authenticate,
54 userSubscriptionAddValidator, 53 userSubscriptionAddValidator,
55 asyncMiddleware(addUserSubscription) 54 addUserSubscription
56) 55)
57 56
58mySubscriptionsRouter.get('/me/subscriptions/:uri', 57mySubscriptionsRouter.get('/me/subscriptions/:uri',
@@ -106,7 +105,7 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons
106 return res.json(existObject) 105 return res.json(existObject)
107} 106}
108 107
109async function addUserSubscription (req: express.Request, res: express.Response) { 108function addUserSubscription (req: express.Request, res: express.Response) {
110 const user = res.locals.oauth.token.User 109 const user = res.locals.oauth.token.User
111 const [ name, host ] = req.body.uri.split('@') 110 const [ name, host ] = req.body.uri.split('@')
112 111
@@ -117,7 +116,6 @@ async function addUserSubscription (req: express.Request, res: express.Response)
117 } 116 }
118 117
119 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) 118 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
120 .catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err))
121 119
122 return res.status(204).end() 120 return res.status(204).end()
123} 121}
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts
index e1f37a8fb..a808896ff 100644
--- a/server/controllers/api/video-channel.ts
+++ b/server/controllers/api/video-channel.ts
@@ -119,7 +119,7 @@ async function listVideoChannels (req: express.Request, res: express.Response) {
119} 119}
120 120
121async function updateVideoChannelAvatar (req: express.Request, res: express.Response) { 121async function updateVideoChannelAvatar (req: express.Request, res: express.Response) {
122 const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] 122 const avatarPhysicalFile = req.files['avatarfile'][0]
123 const videoChannel = res.locals.videoChannel 123 const videoChannel = res.locals.videoChannel
124 const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) 124 const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON())
125 125
@@ -232,7 +232,6 @@ async function getVideoChannel (req: express.Request, res: express.Response) {
232 232
233 if (videoChannelWithVideos.isOutdated()) { 233 if (videoChannelWithVideos.isOutdated()) {
234 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } }) 234 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } })
235 .catch(err => logger.error('Cannot create AP refresher job for actor %s.', videoChannelWithVideos.Actor.url, { err }))
236 } 235 }
237 236
238 return res.json(videoChannelWithVideos.toFormattedJSON()) 237 return res.json(videoChannelWithVideos.toFormattedJSON())
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts
index d9f0ff925..b51490bf9 100644
--- a/server/controllers/api/video-playlist.ts
+++ b/server/controllers/api/video-playlist.ts
@@ -144,7 +144,6 @@ function getVideoPlaylist (req: express.Request, res: express.Response) {
144 144
145 if (videoPlaylist.isOutdated()) { 145 if (videoPlaylist.isOutdated()) {
146 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } }) 146 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } })
147 .catch(err => logger.error('Cannot create AP refresher job for playlist %s.', videoPlaylist.url, { err }))
148 } 147 }
149 148
150 return res.json(videoPlaylist.toFormattedJSON()) 149 return res.json(videoPlaylist.toFormattedJSON())
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts
index 28ced5836..ed223cbc9 100644
--- a/server/controllers/api/videos/import.ts
+++ b/server/controllers/api/videos/import.ts
@@ -88,12 +88,12 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
88 const buf = await readFile(torrentfile.path) 88 const buf = await readFile(torrentfile.path)
89 const parsedTorrent = parseTorrent(buf) 89 const parsedTorrent = parseTorrent(buf)
90 90
91 videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[ 0 ] : parsedTorrent.name as string 91 videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[0] : parsedTorrent.name as string
92 } else { 92 } else {
93 magnetUri = body.magnetUri 93 magnetUri = body.magnetUri
94 94
95 const parsed = magnetUtil.decode(magnetUri) 95 const parsed = magnetUtil.decode(magnetUri)
96 videoName = isArray(parsed.name) ? parsed.name[ 0 ] : parsed.name as string 96 videoName = isArray(parsed.name) ? parsed.name[0] : parsed.name as string
97 } 97 }
98 98
99 const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) 99 const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName })
@@ -124,7 +124,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
124 videoImportId: videoImport.id, 124 videoImportId: videoImport.id,
125 magnetUri 125 magnetUri
126 } 126 }
127 await JobQueue.Instance.createJob({ type: 'video-import', payload }) 127 await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload })
128 128
129 auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) 129 auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
130 130
@@ -176,7 +176,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response)
176 downloadThumbnail: !thumbnailModel, 176 downloadThumbnail: !thumbnailModel,
177 downloadPreview: !previewModel 177 downloadPreview: !previewModel
178 } 178 }
179 await JobQueue.Instance.createJob({ type: 'video-import', payload }) 179 await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload })
180 180
181 auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) 181 auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
182 182
@@ -211,7 +211,7 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You
211async function processThumbnail (req: express.Request, video: VideoModel) { 211async function processThumbnail (req: express.Request, video: VideoModel) {
212 const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined 212 const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined
213 if (thumbnailField) { 213 if (thumbnailField) {
214 const thumbnailPhysicalFile = thumbnailField[ 0 ] 214 const thumbnailPhysicalFile = thumbnailField[0]
215 215
216 return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false) 216 return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false)
217 } 217 }
@@ -231,12 +231,12 @@ async function processPreview (req: express.Request, video: VideoModel) {
231} 231}
232 232
233function insertIntoDB (parameters: { 233function insertIntoDB (parameters: {
234 video: MVideoThumbnailAccountDefault, 234 video: MVideoThumbnailAccountDefault
235 thumbnailModel: MThumbnail, 235 thumbnailModel: MThumbnail
236 previewModel: MThumbnail, 236 previewModel: MThumbnail
237 videoChannel: MChannelAccountDefault, 237 videoChannel: MChannelAccountDefault
238 tags: string[], 238 tags: string[]
239 videoImportAttributes: Partial<MVideoImport>, 239 videoImportAttributes: Partial<MVideoImport>
240 user: MUser 240 user: MUser
241}): Bluebird<MVideoImportFormattable> { 241}): Bluebird<MVideoImportFormattable> {
242 const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters 242 const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index a593f7076..1d61f8427 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -12,8 +12,7 @@ import {
12 VIDEO_CATEGORIES, 12 VIDEO_CATEGORIES,
13 VIDEO_LANGUAGES, 13 VIDEO_LANGUAGES,
14 VIDEO_LICENCES, 14 VIDEO_LICENCES,
15 VIDEO_PRIVACIES, 15 VIDEO_PRIVACIES
16 VIDEO_TRANSCODING_FPS
17} from '../../../initializers/constants' 16} from '../../../initializers/constants'
18import { 17import {
19 changeVideoChannelShare, 18 changeVideoChannelShare,
@@ -308,7 +307,7 @@ async function addVideo (req: express.Request, res: express.Response) {
308 } 307 }
309 } 308 }
310 309
311 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) 310 await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput })
312 } 311 }
313 312
314 Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) 313 Hooks.runAction('action:api.video.uploaded', { video: videoCreated })
@@ -453,7 +452,6 @@ async function getVideo (req: express.Request, res: express.Response) {
453 452
454 if (video.isOutdated()) { 453 if (video.isOutdated()) {
455 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) 454 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } })
456 .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err }))
457 } 455 }
458 456
459 return res.json(video.toFormattedDetailsJSON()) 457 return res.json(video.toFormattedDetailsJSON())
diff --git a/server/controllers/client.ts b/server/controllers/client.ts
index dc3ff18fc..e4643e171 100644
--- a/server/controllers/client.ts
+++ b/server/controllers/client.ts
@@ -66,7 +66,7 @@ export {
66 66
67// --------------------------------------------------------------------------- 67// ---------------------------------------------------------------------------
68 68
69async function serveServerTranslations (req: express.Request, res: express.Response) { 69function serveServerTranslations (req: express.Request, res: express.Response) {
70 const locale = req.params.locale 70 const locale = req.params.locale
71 const file = req.params.file 71 const file = req.params.file
72 72
diff --git a/server/controllers/static.ts b/server/controllers/static.ts
index a4bb3a4d9..4c6cf9597 100644
--- a/server/controllers/static.ts
+++ b/server/controllers/static.ts
@@ -45,12 +45,12 @@ staticRouter.use(
45staticRouter.use( 45staticRouter.use(
46 STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent', 46 STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent',
47 asyncMiddleware(videosDownloadValidator), 47 asyncMiddleware(videosDownloadValidator),
48 asyncMiddleware(downloadTorrent) 48 downloadTorrent
49) 49)
50staticRouter.use( 50staticRouter.use(
51 STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent', 51 STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent',
52 asyncMiddleware(videosDownloadValidator), 52 asyncMiddleware(videosDownloadValidator),
53 asyncMiddleware(downloadHLSVideoFileTorrent) 53 downloadHLSVideoFileTorrent
54) 54)
55 55
56// Videos path for webseeding 56// Videos path for webseeding
@@ -68,13 +68,13 @@ staticRouter.use(
68staticRouter.use( 68staticRouter.use(
69 STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', 69 STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension',
70 asyncMiddleware(videosDownloadValidator), 70 asyncMiddleware(videosDownloadValidator),
71 asyncMiddleware(downloadVideoFile) 71 downloadVideoFile
72) 72)
73 73
74staticRouter.use( 74staticRouter.use(
75 STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', 75 STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension',
76 asyncMiddleware(videosDownloadValidator), 76 asyncMiddleware(videosDownloadValidator),
77 asyncMiddleware(downloadHLSVideoFile) 77 downloadHLSVideoFile
78) 78)
79 79
80// HLS 80// HLS
@@ -325,7 +325,7 @@ async function generateNodeinfo (req: express.Request, res: express.Response) {
325 return res.send(json).end() 325 return res.send(json).end()
326} 326}
327 327
328async function downloadTorrent (req: express.Request, res: express.Response) { 328function downloadTorrent (req: express.Request, res: express.Response) {
329 const video = res.locals.videoAll 329 const video = res.locals.videoAll
330 330
331 const videoFile = getVideoFile(req, video.VideoFiles) 331 const videoFile = getVideoFile(req, video.VideoFiles)
@@ -334,7 +334,7 @@ async function downloadTorrent (req: express.Request, res: express.Response) {
334 return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`) 334 return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`)
335} 335}
336 336
337async function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) { 337function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) {
338 const video = res.locals.videoAll 338 const video = res.locals.videoAll
339 339
340 const playlist = getHLSPlaylist(video) 340 const playlist = getHLSPlaylist(video)
@@ -346,7 +346,7 @@ async function downloadHLSVideoFileTorrent (req: express.Request, res: express.R
346 return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`) 346 return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`)
347} 347}
348 348
349async function downloadVideoFile (req: express.Request, res: express.Response) { 349function downloadVideoFile (req: express.Request, res: express.Response) {
350 const video = res.locals.videoAll 350 const video = res.locals.videoAll
351 351
352 const videoFile = getVideoFile(req, video.VideoFiles) 352 const videoFile = getVideoFile(req, video.VideoFiles)
@@ -355,7 +355,7 @@ async function downloadVideoFile (req: express.Request, res: express.Response) {
355 return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) 355 return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`)
356} 356}
357 357
358async function downloadHLSVideoFile (req: express.Request, res: express.Response) { 358function downloadHLSVideoFile (req: express.Request, res: express.Response) {
359 const video = res.locals.videoAll 359 const video = res.locals.videoAll
360 const playlist = getHLSPlaylist(video) 360 const playlist = getHLSPlaylist(video)
361 if (!playlist) return res.status(404).end 361 if (!playlist) return res.status(404).end
diff --git a/server/controllers/tracker.ts b/server/controllers/tracker.ts
index 2ae1cf86c..e9c8a13da 100644
--- a/server/controllers/tracker.ts
+++ b/server/controllers/tracker.ts
@@ -6,7 +6,6 @@ import * as proxyAddr from 'proxy-addr'
6import { Server as WebSocketServer } from 'ws' 6import { Server as WebSocketServer } from 'ws'
7import { TRACKER_RATE_LIMITS } from '../initializers/constants' 7import { TRACKER_RATE_LIMITS } from '../initializers/constants'
8import { VideoFileModel } from '../models/video/video-file' 8import { VideoFileModel } from '../models/video/video-file'
9import { parse } from 'url'
10import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' 9import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
11import { CONFIG } from '../initializers/config' 10import { CONFIG } from '../initializers/config'
12 11
@@ -38,11 +37,11 @@ const trackerServer = new TrackerServer({
38 37
39 const key = ip + '-' + infoHash 38 const key = ip + '-' + infoHash
40 39
41 peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1 40 peersIps[ip] = peersIps[ip] ? peersIps[ip] + 1 : 1
42 peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 1 : 1 41 peersIpInfoHash[key] = peersIpInfoHash[key] ? peersIpInfoHash[key] + 1 : 1
43 42
44 if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) { 43 if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[key] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
45 return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`)) 44 return cb(new Error(`Too many requests (${peersIpInfoHash[key]} of ip ${ip} for torrent ${infoHash}`))
46 } 45 }
47 46
48 try { 47 try {
@@ -87,10 +86,8 @@ function createWebsocketTrackerServer (app: express.Application) {
87 trackerServer.onWebSocketConnection(ws) 86 trackerServer.onWebSocketConnection(ws)
88 }) 87 })
89 88
90 server.on('upgrade', (request, socket, head) => { 89 server.on('upgrade', (request: express.Request, socket, head) => {
91 const pathname = parse(request.url).pathname 90 if (request.path === '/tracker/socket') {
92
93 if (pathname === '/tracker/socket') {
94 wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request)) 91 wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request))
95 } 92 }
96 93
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts
index 9f9e8fba7..22f8550ca 100644
--- a/server/helpers/activitypub.ts
+++ b/server/helpers/activitypub.ts
@@ -5,7 +5,7 @@ import { Activity } from '../../shared/models/activitypub'
5import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants' 5import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants'
6import { signJsonLDObject } from './peertube-crypto' 6import { signJsonLDObject } from './peertube-crypto'
7import { pageToStartAndCount } from './core-utils' 7import { pageToStartAndCount } from './core-utils'
8import { parse } from 'url' 8import { URL } from 'url'
9import { MActor, MVideoAccountLight } from '../typings/models' 9import { MActor, MVideoAccountLight } from '../typings/models'
10 10
11function activityPubContextify <T> (data: T) { 11function activityPubContextify <T> (data: T) {
@@ -161,8 +161,8 @@ function getAPId (activity: string | { id: string }) {
161} 161}
162 162
163function checkUrlsSameHost (url1: string, url2: string) { 163function checkUrlsSameHost (url1: string, url2: string) {
164 const idHost = parse(url1).host 164 const idHost = new URL(url1).host
165 const actorHost = parse(url2).host 165 const actorHost = new URL(url2).host
166 166
167 return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase() 167 return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase()
168} 168}
diff --git a/server/helpers/audit-logger.ts b/server/helpers/audit-logger.ts
index 9b258dc3a..a4cfeef76 100644
--- a/server/helpers/audit-logger.ts
+++ b/server/helpers/audit-logger.ts
@@ -81,7 +81,8 @@ function auditLoggerFactory (domain: string) {
81} 81}
82 82
83abstract class EntityAuditView { 83abstract class EntityAuditView {
84 constructor (private keysToKeep: Array<string>, private prefix: string, private entityInfos: object) { } 84 constructor (private readonly keysToKeep: string[], private readonly prefix: string, private readonly entityInfos: object) { }
85
85 toLogKeys (): object { 86 toLogKeys (): object {
86 return chain(flatten(this.entityInfos, { delimiter: '-', safe: true })) 87 return chain(flatten(this.entityInfos, { delimiter: '-', safe: true }))
87 .pick(this.keysToKeep) 88 .pick(this.keysToKeep)
@@ -121,7 +122,7 @@ const videoKeysToKeep = [
121 'downloadEnabled' 122 'downloadEnabled'
122] 123]
123class VideoAuditView extends EntityAuditView { 124class VideoAuditView extends EntityAuditView {
124 constructor (private video: VideoDetails) { 125 constructor (private readonly video: VideoDetails) {
125 super(videoKeysToKeep, 'video', video) 126 super(videoKeysToKeep, 'video', video)
126 } 127 }
127} 128}
@@ -132,7 +133,7 @@ const videoImportKeysToKeep = [
132 'video-name' 133 'video-name'
133] 134]
134class VideoImportAuditView extends EntityAuditView { 135class VideoImportAuditView extends EntityAuditView {
135 constructor (private videoImport: VideoImport) { 136 constructor (private readonly videoImport: VideoImport) {
136 super(videoImportKeysToKeep, 'video-import', videoImport) 137 super(videoImportKeysToKeep, 'video-import', videoImport)
137 } 138 }
138} 139}
@@ -151,7 +152,7 @@ const commentKeysToKeep = [
151 'account-name' 152 'account-name'
152] 153]
153class CommentAuditView extends EntityAuditView { 154class CommentAuditView extends EntityAuditView {
154 constructor (private comment: VideoComment) { 155 constructor (private readonly comment: VideoComment) {
155 super(commentKeysToKeep, 'comment', comment) 156 super(commentKeysToKeep, 'comment', comment)
156 } 157 }
157} 158}
@@ -180,7 +181,7 @@ const userKeysToKeep = [
180 'videoChannels' 181 'videoChannels'
181] 182]
182class UserAuditView extends EntityAuditView { 183class UserAuditView extends EntityAuditView {
183 constructor (private user: User) { 184 constructor (private readonly user: User) {
184 super(userKeysToKeep, 'user', user) 185 super(userKeysToKeep, 'user', user)
185 } 186 }
186} 187}
@@ -206,7 +207,7 @@ const channelKeysToKeep = [
206 'ownerAccount-displayedName' 207 'ownerAccount-displayedName'
207] 208]
208class VideoChannelAuditView extends EntityAuditView { 209class VideoChannelAuditView extends EntityAuditView {
209 constructor (private channel: VideoChannel) { 210 constructor (private readonly channel: VideoChannel) {
210 super(channelKeysToKeep, 'channel', channel) 211 super(channelKeysToKeep, 'channel', channel)
211 } 212 }
212} 213}
@@ -221,7 +222,7 @@ const videoAbuseKeysToKeep = [
221 'createdAt' 222 'createdAt'
222] 223]
223class VideoAbuseAuditView extends EntityAuditView { 224class VideoAbuseAuditView extends EntityAuditView {
224 constructor (private videoAbuse: VideoAbuse) { 225 constructor (private readonly videoAbuse: VideoAbuse) {
225 super(videoAbuseKeysToKeep, 'abuse', videoAbuse) 226 super(videoAbuseKeysToKeep, 'abuse', videoAbuse)
226 } 227 }
227} 228}
@@ -253,9 +254,12 @@ class CustomConfigAuditView extends EntityAuditView {
253 const infos: any = customConfig 254 const infos: any = customConfig
254 const resolutionsDict = infos.transcoding.resolutions 255 const resolutionsDict = infos.transcoding.resolutions
255 const resolutionsArray = [] 256 const resolutionsArray = []
256 Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => { 257
257 if (isEnabled) resolutionsArray.push(resolution) 258 Object.entries(resolutionsDict)
258 }) 259 .forEach(([ resolution, isEnabled ]) => {
260 if (isEnabled) resolutionsArray.push(resolution)
261 })
262
259 Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } }) 263 Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } })
260 super(customConfigKeysToKeep, 'config', infos) 264 super(customConfigKeysToKeep, 'config', infos)
261 } 265 }
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts
index 7e8252aa4..2cecea450 100644
--- a/server/helpers/core-utils.ts
+++ b/server/helpers/core-utils.ts
@@ -1,9 +1,11 @@
1/* eslint-disable no-useless-call */
2
1/* 3/*
2 Different from 'utils' because we don't not import other PeerTube modules. 4 Different from 'utils' because we don't not import other PeerTube modules.
3 Useful to avoid circular dependencies. 5 Useful to avoid circular dependencies.
4*/ 6*/
5 7
6import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto' 8import { createHash, HexBase64Latin1Encoding, randomBytes } from 'crypto'
7import { basename, isAbsolute, join, resolve } from 'path' 9import { basename, isAbsolute, join, resolve } from 'path'
8import * as pem from 'pem' 10import * as pem from 'pem'
9import { URL } from 'url' 11import { URL } from 'url'
@@ -22,31 +24,31 @@ const objectConverter = (oldObject: any, keyConverter: (e: string) => string, va
22 const newObject = {} 24 const newObject = {}
23 Object.keys(oldObject).forEach(oldKey => { 25 Object.keys(oldObject).forEach(oldKey => {
24 const newKey = keyConverter(oldKey) 26 const newKey = keyConverter(oldKey)
25 newObject[ newKey ] = objectConverter(oldObject[ oldKey ], keyConverter, valueConverter) 27 newObject[newKey] = objectConverter(oldObject[oldKey], keyConverter, valueConverter)
26 }) 28 })
27 29
28 return newObject 30 return newObject
29} 31}
30 32
31const timeTable = { 33const timeTable = {
32 ms: 1, 34 ms: 1,
33 second: 1000, 35 second: 1000,
34 minute: 60000, 36 minute: 60000,
35 hour: 3600000, 37 hour: 3600000,
36 day: 3600000 * 24, 38 day: 3600000 * 24,
37 week: 3600000 * 24 * 7, 39 week: 3600000 * 24 * 7,
38 month: 3600000 * 24 * 30 40 month: 3600000 * 24 * 30
39} 41}
40 42
41export function parseDurationToMs (duration: number | string): number { 43export function parseDurationToMs (duration: number | string): number {
42 if (typeof duration === 'number') return duration 44 if (typeof duration === 'number') return duration
43 45
44 if (typeof duration === 'string') { 46 if (typeof duration === 'string') {
45 const split = duration.match(/^([\d\.,]+)\s?(\w+)$/) 47 const split = duration.match(/^([\d.,]+)\s?(\w+)$/)
46 48
47 if (split.length === 3) { 49 if (split.length === 3) {
48 const len = parseFloat(split[1]) 50 const len = parseFloat(split[1])
49 let unit = split[2].replace(/s$/i,'').toLowerCase() 51 let unit = split[2].replace(/s$/i, '').toLowerCase()
50 if (unit === 'm') { 52 if (unit === 'm') {
51 unit = 'ms' 53 unit = 'ms'
52 } 54 }
@@ -73,21 +75,21 @@ export function parseBytes (value: string | number): number {
73 75
74 if (value.match(tgm)) { 76 if (value.match(tgm)) {
75 match = value.match(tgm) 77 match = value.match(tgm)
76 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 78 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
77 + parseInt(match[2], 10) * 1024 * 1024 * 1024 79 parseInt(match[2], 10) * 1024 * 1024 * 1024 +
78 + parseInt(match[3], 10) * 1024 * 1024 80 parseInt(match[3], 10) * 1024 * 1024
79 } else if (value.match(tg)) { 81 } else if (value.match(tg)) {
80 match = value.match(tg) 82 match = value.match(tg)
81 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 83 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
82 + parseInt(match[2], 10) * 1024 * 1024 * 1024 84 parseInt(match[2], 10) * 1024 * 1024 * 1024
83 } else if (value.match(tm)) { 85 } else if (value.match(tm)) {
84 match = value.match(tm) 86 match = value.match(tm)
85 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 87 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
86 + parseInt(match[2], 10) * 1024 * 1024 88 parseInt(match[2], 10) * 1024 * 1024
87 } else if (value.match(gm)) { 89 } else if (value.match(gm)) {
88 match = value.match(gm) 90 match = value.match(gm)
89 return parseInt(match[1], 10) * 1024 * 1024 * 1024 91 return parseInt(match[1], 10) * 1024 * 1024 * 1024 +
90 + parseInt(match[2], 10) * 1024 * 1024 92 parseInt(match[2], 10) * 1024 * 1024
91 } else if (value.match(t)) { 93 } else if (value.match(t)) {
92 match = value.match(t) 94 match = value.match(t)
93 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 95 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
@@ -137,6 +139,7 @@ function getAppNumber () {
137} 139}
138 140
139let rootPath: string 141let rootPath: string
142
140function root () { 143function root () {
141 if (rootPath) return rootPath 144 if (rootPath) return rootPath
142 145
@@ -163,7 +166,7 @@ function escapeHTML (stringParam) {
163 '=': '&#x3D;' 166 '=': '&#x3D;'
164 } 167 }
165 168
166 return String(stringParam).replace(/[&<>"'`=\/]/g, s => entityMap[s]) 169 return String(stringParam).replace(/[&<>"'`=/]/g, s => entityMap[s])
167} 170}
168 171
169function pageToStartAndCount (page: number, itemsPerPage: number) { 172function pageToStartAndCount (page: number, itemsPerPage: number) {
@@ -202,6 +205,7 @@ function sha1 (str: string | Buffer, encoding: HexBase64Latin1Encoding = 'hex')
202function execShell (command: string, options?: ExecOptions) { 205function execShell (command: string, options?: ExecOptions) {
203 return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { 206 return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => {
204 exec(command, options, (err, stdout, stderr) => { 207 exec(command, options, (err, stdout, stderr) => {
208 // eslint-disable-next-line prefer-promise-reject-errors
205 if (err) return rej({ err, stdout, stderr }) 209 if (err) return rej({ err, stdout, stderr })
206 210
207 return res({ stdout, stderr }) 211 return res({ stdout, stderr })
@@ -226,14 +230,6 @@ function promisify1<T, A> (func: (arg: T, cb: (err: any, result: A) => void) =>
226 } 230 }
227} 231}
228 232
229function promisify1WithVoid<T> (func: (arg: T, cb: (err: any) => void) => void): (arg: T) => Promise<void> {
230 return function promisified (arg: T): Promise<void> {
231 return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
232 func.apply(null, [ arg, (err: any) => err ? reject(err) : resolve() ])
233 })
234 }
235}
236
237function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> { 233function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> {
238 return function promisified (arg1: T, arg2: U): Promise<A> { 234 return function promisified (arg1: T, arg2: U): Promise<A> {
239 return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { 235 return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
@@ -242,15 +238,7 @@ function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A)
242 } 238 }
243} 239}
244 240
245function promisify2WithVoid<T, U> (func: (arg1: T, arg2: U, cb: (err: any) => void) => void): (arg1: T, arg2: U) => Promise<void> { 241const randomBytesPromise = promisify1<number, Buffer>(randomBytes)
246 return function promisified (arg1: T, arg2: U): Promise<void> {
247 return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
248 func.apply(null, [ arg1, arg2, (err: any) => err ? reject(err) : resolve() ])
249 })
250 }
251}
252
253const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
254const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) 242const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
255const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) 243const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
256const execPromise2 = promisify2<string, any, string>(exec) 244const execPromise2 = promisify2<string, any, string>(exec)
@@ -280,7 +268,7 @@ export {
280 promisify1, 268 promisify1,
281 promisify2, 269 promisify2,
282 270
283 pseudoRandomBytesPromise, 271 randomBytesPromise,
284 createPrivateKey, 272 createPrivateKey,
285 getPublicKey, 273 getPublicKey,
286 execPromise2, 274 execPromise2,
diff --git a/server/helpers/custom-jsonld-signature.ts b/server/helpers/custom-jsonld-signature.ts
index a407a9fec..749c50cb3 100644
--- a/server/helpers/custom-jsonld-signature.ts
+++ b/server/helpers/custom-jsonld-signature.ts
@@ -5,52 +5,52 @@ import { logger } from './logger'
5const CACHE = { 5const CACHE = {
6 'https://w3id.org/security/v1': { 6 'https://w3id.org/security/v1': {
7 '@context': { 7 '@context': {
8 'id': '@id', 8 id: '@id',
9 'type': '@type', 9 type: '@type',
10 10
11 'dc': 'http://purl.org/dc/terms/', 11 dc: 'http://purl.org/dc/terms/',
12 'sec': 'https://w3id.org/security#', 12 sec: 'https://w3id.org/security#',
13 'xsd': 'http://www.w3.org/2001/XMLSchema#', 13 xsd: 'http://www.w3.org/2001/XMLSchema#',
14 14
15 'EcdsaKoblitzSignature2016': 'sec:EcdsaKoblitzSignature2016', 15 EcdsaKoblitzSignature2016: 'sec:EcdsaKoblitzSignature2016',
16 'Ed25519Signature2018': 'sec:Ed25519Signature2018', 16 Ed25519Signature2018: 'sec:Ed25519Signature2018',
17 'EncryptedMessage': 'sec:EncryptedMessage', 17 EncryptedMessage: 'sec:EncryptedMessage',
18 'GraphSignature2012': 'sec:GraphSignature2012', 18 GraphSignature2012: 'sec:GraphSignature2012',
19 'LinkedDataSignature2015': 'sec:LinkedDataSignature2015', 19 LinkedDataSignature2015: 'sec:LinkedDataSignature2015',
20 'LinkedDataSignature2016': 'sec:LinkedDataSignature2016', 20 LinkedDataSignature2016: 'sec:LinkedDataSignature2016',
21 'CryptographicKey': 'sec:Key', 21 CryptographicKey: 'sec:Key',
22 22
23 'authenticationTag': 'sec:authenticationTag', 23 authenticationTag: 'sec:authenticationTag',
24 'canonicalizationAlgorithm': 'sec:canonicalizationAlgorithm', 24 canonicalizationAlgorithm: 'sec:canonicalizationAlgorithm',
25 'cipherAlgorithm': 'sec:cipherAlgorithm', 25 cipherAlgorithm: 'sec:cipherAlgorithm',
26 'cipherData': 'sec:cipherData', 26 cipherData: 'sec:cipherData',
27 'cipherKey': 'sec:cipherKey', 27 cipherKey: 'sec:cipherKey',
28 'created': { '@id': 'dc:created', '@type': 'xsd:dateTime' }, 28 created: { '@id': 'dc:created', '@type': 'xsd:dateTime' },
29 'creator': { '@id': 'dc:creator', '@type': '@id' }, 29 creator: { '@id': 'dc:creator', '@type': '@id' },
30 'digestAlgorithm': 'sec:digestAlgorithm', 30 digestAlgorithm: 'sec:digestAlgorithm',
31 'digestValue': 'sec:digestValue', 31 digestValue: 'sec:digestValue',
32 'domain': 'sec:domain', 32 domain: 'sec:domain',
33 'encryptionKey': 'sec:encryptionKey', 33 encryptionKey: 'sec:encryptionKey',
34 'expiration': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, 34 expiration: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
35 'expires': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, 35 expires: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
36 'initializationVector': 'sec:initializationVector', 36 initializationVector: 'sec:initializationVector',
37 'iterationCount': 'sec:iterationCount', 37 iterationCount: 'sec:iterationCount',
38 'nonce': 'sec:nonce', 38 nonce: 'sec:nonce',
39 'normalizationAlgorithm': 'sec:normalizationAlgorithm', 39 normalizationAlgorithm: 'sec:normalizationAlgorithm',
40 'owner': { '@id': 'sec:owner', '@type': '@id' }, 40 owner: { '@id': 'sec:owner', '@type': '@id' },
41 'password': 'sec:password', 41 password: 'sec:password',
42 'privateKey': { '@id': 'sec:privateKey', '@type': '@id' }, 42 privateKey: { '@id': 'sec:privateKey', '@type': '@id' },
43 'privateKeyPem': 'sec:privateKeyPem', 43 privateKeyPem: 'sec:privateKeyPem',
44 'publicKey': { '@id': 'sec:publicKey', '@type': '@id' }, 44 publicKey: { '@id': 'sec:publicKey', '@type': '@id' },
45 'publicKeyBase58': 'sec:publicKeyBase58', 45 publicKeyBase58: 'sec:publicKeyBase58',
46 'publicKeyPem': 'sec:publicKeyPem', 46 publicKeyPem: 'sec:publicKeyPem',
47 'publicKeyWif': 'sec:publicKeyWif', 47 publicKeyWif: 'sec:publicKeyWif',
48 'publicKeyService': { '@id': 'sec:publicKeyService', '@type': '@id' }, 48 publicKeyService: { '@id': 'sec:publicKeyService', '@type': '@id' },
49 'revoked': { '@id': 'sec:revoked', '@type': 'xsd:dateTime' }, 49 revoked: { '@id': 'sec:revoked', '@type': 'xsd:dateTime' },
50 'salt': 'sec:salt', 50 salt: 'sec:salt',
51 'signature': 'sec:signature', 51 signature: 'sec:signature',
52 'signatureAlgorithm': 'sec:signingAlgorithm', 52 signatureAlgorithm: 'sec:signingAlgorithm',
53 'signatureValue': 'sec:signatureValue' 53 signatureValue: 'sec:signatureValue'
54 } 54 }
55 } 55 }
56} 56}
@@ -60,12 +60,12 @@ const nodeDocumentLoader = jsonld.documentLoaders.node()
60const lru = new AsyncLRU({ 60const lru = new AsyncLRU({
61 max: 10, 61 max: 10,
62 load: (url, cb) => { 62 load: (url, cb) => {
63 if (CACHE[ url ] !== undefined) { 63 if (CACHE[url] !== undefined) {
64 logger.debug('Using cache for JSON-LD %s.', url) 64 logger.debug('Using cache for JSON-LD %s.', url)
65 65
66 return cb(null, { 66 return cb(null, {
67 contextUrl: null, 67 contextUrl: null,
68 document: CACHE[ url ], 68 document: CACHE[url],
69 documentUrl: url 69 documentUrl: url
70 }) 70 })
71 } 71 }
diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts
index fa58e163f..fec67823d 100644
--- a/server/helpers/custom-validators/activitypub/actor.ts
+++ b/server/helpers/custom-validators/activitypub/actor.ts
@@ -6,7 +6,7 @@ import { isHostValid } from '../servers'
6import { peertubeTruncate } from '@server/helpers/core-utils' 6import { peertubeTruncate } from '@server/helpers/core-utils'
7 7
8function isActorEndpointsObjectValid (endpointObject: any) { 8function isActorEndpointsObjectValid (endpointObject: any) {
9 if (endpointObject && endpointObject.sharedInbox) { 9 if (endpointObject?.sharedInbox) {
10 return isActivityPubUrlValid(endpointObject.sharedInbox) 10 return isActivityPubUrlValid(endpointObject.sharedInbox)
11 } 11 }
12 12
@@ -101,8 +101,6 @@ function normalizeActor (actor: any) {
101 actor.summary = null 101 actor.summary = null
102 } 102 }
103 } 103 }
104
105 return
106} 104}
107 105
108function isValidActorHandle (handle: string) { 106function isValidActorHandle (handle: string) {
diff --git a/server/helpers/custom-validators/activitypub/video-comments.ts b/server/helpers/custom-validators/activitypub/video-comments.ts
index aa3c246b5..ea852c491 100644
--- a/server/helpers/custom-validators/activitypub/video-comments.ts
+++ b/server/helpers/custom-validators/activitypub/video-comments.ts
@@ -48,8 +48,6 @@ function normalizeComment (comment: any) {
48 if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url 48 if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url
49 else comment.url = comment.id 49 else comment.url = comment.id
50 } 50 }
51
52 return
53} 51}
54 52
55function isCommentTypeValid (comment: any): boolean { 53function isCommentTypeValid (comment: any): boolean {
diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts
index 89149b3e0..cf32201c4 100644
--- a/server/helpers/custom-validators/misc.ts
+++ b/server/helpers/custom-validators/misc.ts
@@ -94,13 +94,13 @@ function isFileValid (
94 if (isArray(files)) return optional 94 if (isArray(files)) return optional
95 95
96 // Should have a file 96 // Should have a file
97 const fileArray = files[ field ] 97 const fileArray = files[field]
98 if (!fileArray || fileArray.length === 0) { 98 if (!fileArray || fileArray.length === 0) {
99 return optional 99 return optional
100 } 100 }
101 101
102 // The file should exist 102 // The file should exist
103 const file = fileArray[ 0 ] 103 const file = fileArray[0]
104 if (!file || !file.originalname) return false 104 if (!file || !file.originalname) return false
105 105
106 // Check size 106 // Check size
diff --git a/server/helpers/custom-validators/plugins.ts b/server/helpers/custom-validators/plugins.ts
index 3af72547b..5a4531f72 100644
--- a/server/helpers/custom-validators/plugins.ts
+++ b/server/helpers/custom-validators/plugins.ts
@@ -14,7 +14,7 @@ function isPluginTypeValid (value: any) {
14function isPluginNameValid (value: string) { 14function isPluginNameValid (value: string) {
15 return exists(value) && 15 return exists(value) &&
16 validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && 16 validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) &&
17 validator.matches(value, /^[a-z\-]+$/) 17 validator.matches(value, /^[a-z-]+$/)
18} 18}
19 19
20function isNpmPluginNameValid (value: string) { 20function isNpmPluginNameValid (value: string) {
@@ -146,8 +146,8 @@ function isPackageJSONValid (packageJSON: PluginPackageJson, pluginType: PluginT
146} 146}
147 147
148function isLibraryCodeValid (library: any) { 148function isLibraryCodeValid (library: any) {
149 return typeof library.register === 'function' 149 return typeof library.register === 'function' &&
150 && typeof library.unregister === 'function' 150 typeof library.unregister === 'function'
151} 151}
152 152
153export { 153export {
diff --git a/server/helpers/custom-validators/user-notifications.ts b/server/helpers/custom-validators/user-notifications.ts
index 5a4d10504..8a33b895b 100644
--- a/server/helpers/custom-validators/user-notifications.ts
+++ b/server/helpers/custom-validators/user-notifications.ts
@@ -9,7 +9,8 @@ function isUserNotificationTypeValid (value: any) {
9 9
10function isUserNotificationSettingValid (value: any) { 10function isUserNotificationSettingValid (value: any) {
11 return exists(value) && 11 return exists(value) &&
12 validator.isInt('' + value) && ( 12 validator.isInt('' + value) &&
13 (
13 value === UserNotificationSettingValue.NONE || 14 value === UserNotificationSettingValue.NONE ||
14 value === UserNotificationSettingValue.WEB || 15 value === UserNotificationSettingValue.WEB ||
15 value === UserNotificationSettingValue.EMAIL || 16 value === UserNotificationSettingValue.EMAIL ||
diff --git a/server/helpers/custom-validators/video-abuses.ts b/server/helpers/custom-validators/video-abuses.ts
index a9478c76a..5c7bc6fd9 100644
--- a/server/helpers/custom-validators/video-abuses.ts
+++ b/server/helpers/custom-validators/video-abuses.ts
@@ -1,8 +1,6 @@
1import { Response } from 'express'
2import validator from 'validator' 1import validator from 'validator'
3import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' 2import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants'
4import { exists } from './misc' 3import { exists } from './misc'
5import { VideoAbuseModel } from '../../models/video/video-abuse'
6 4
7const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES 5const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
8 6
@@ -15,7 +13,7 @@ function isVideoAbuseModerationCommentValid (value: string) {
15} 13}
16 14
17function isVideoAbuseStateValid (value: string) { 15function isVideoAbuseStateValid (value: string) {
18 return exists(value) && VIDEO_ABUSE_STATES[ value ] !== undefined 16 return exists(value) && VIDEO_ABUSE_STATES[value] !== undefined
19} 17}
20 18
21// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
diff --git a/server/helpers/custom-validators/video-captions.ts b/server/helpers/custom-validators/video-captions.ts
index d06eb3695..9abbce04a 100644
--- a/server/helpers/custom-validators/video-captions.ts
+++ b/server/helpers/custom-validators/video-captions.ts
@@ -2,7 +2,7 @@ import { CONSTRAINTS_FIELDS, MIMETYPES, VIDEO_LANGUAGES } from '../../initialize
2import { exists, isFileValid } from './misc' 2import { exists, isFileValid } from './misc'
3 3
4function isVideoCaptionLanguageValid (value: any) { 4function isVideoCaptionLanguageValid (value: any) {
5 return exists(value) && VIDEO_LANGUAGES[ value ] !== undefined 5 return exists(value) && VIDEO_LANGUAGES[value] !== undefined
6} 6}
7 7
8const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT) 8const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT)
diff --git a/server/helpers/custom-validators/video-imports.ts b/server/helpers/custom-validators/video-imports.ts
index ffad482b4..c571f5ddd 100644
--- a/server/helpers/custom-validators/video-imports.ts
+++ b/server/helpers/custom-validators/video-imports.ts
@@ -20,7 +20,7 @@ function isVideoImportTargetUrlValid (url: string) {
20} 20}
21 21
22function isVideoImportStateValid (value: any) { 22function isVideoImportStateValid (value: any) {
23 return exists(value) && VIDEO_IMPORT_STATES[ value ] !== undefined 23 return exists(value) && VIDEO_IMPORT_STATES[value] !== undefined
24} 24}
25 25
26const videoTorrentImportTypes = Object.keys(MIMETYPES.TORRENT.MIMETYPE_EXT).map(m => `(${m})`) 26const videoTorrentImportTypes = Object.keys(MIMETYPES.TORRENT.MIMETYPE_EXT).map(m => `(${m})`)
diff --git a/server/helpers/custom-validators/video-playlists.ts b/server/helpers/custom-validators/video-playlists.ts
index 4bb8384ab..180018fc5 100644
--- a/server/helpers/custom-validators/video-playlists.ts
+++ b/server/helpers/custom-validators/video-playlists.ts
@@ -1,8 +1,6 @@
1import { exists } from './misc' 1import { exists } from './misc'
2import validator from 'validator' 2import validator from 'validator'
3import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants' 3import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants'
4import * as express from 'express'
5import { VideoPlaylistModel } from '../../models/video/video-playlist'
6 4
7const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS 5const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS
8 6
@@ -15,7 +13,7 @@ function isVideoPlaylistDescriptionValid (value: any) {
15} 13}
16 14
17function isVideoPlaylistPrivacyValid (value: number) { 15function isVideoPlaylistPrivacyValid (value: number) {
18 return validator.isInt(value + '') && VIDEO_PLAYLIST_PRIVACIES[ value ] !== undefined 16 return validator.isInt(value + '') && VIDEO_PLAYLIST_PRIVACIES[value] !== undefined
19} 17}
20 18
21function isVideoPlaylistTimestampValid (value: any) { 19function isVideoPlaylistTimestampValid (value: any) {
@@ -23,7 +21,7 @@ function isVideoPlaylistTimestampValid (value: any) {
23} 21}
24 22
25function isVideoPlaylistTypeValid (value: any) { 23function isVideoPlaylistTypeValid (value: any) {
26 return exists(value) && VIDEO_PLAYLIST_TYPES[ value ] !== undefined 24 return exists(value) && VIDEO_PLAYLIST_TYPES[value] !== undefined
27} 25}
28 26
29// --------------------------------------------------------------------------- 27// ---------------------------------------------------------------------------
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts
index a9e859e54..cfb430c63 100644
--- a/server/helpers/custom-validators/videos.ts
+++ b/server/helpers/custom-validators/videos.ts
@@ -20,15 +20,15 @@ function isVideoFilterValid (filter: VideoFilter) {
20} 20}
21 21
22function isVideoCategoryValid (value: any) { 22function isVideoCategoryValid (value: any) {
23 return value === null || VIDEO_CATEGORIES[ value ] !== undefined 23 return value === null || VIDEO_CATEGORIES[value] !== undefined
24} 24}
25 25
26function isVideoStateValid (value: any) { 26function isVideoStateValid (value: any) {
27 return exists(value) && VIDEO_STATES[ value ] !== undefined 27 return exists(value) && VIDEO_STATES[value] !== undefined
28} 28}
29 29
30function isVideoLicenceValid (value: any) { 30function isVideoLicenceValid (value: any) {
31 return value === null || VIDEO_LICENCES[ value ] !== undefined 31 return value === null || VIDEO_LICENCES[value] !== undefined
32} 32}
33 33
34function isVideoLanguageValid (value: any) { 34function isVideoLanguageValid (value: any) {
@@ -98,7 +98,7 @@ function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } |
98} 98}
99 99
100function isVideoPrivacyValid (value: number) { 100function isVideoPrivacyValid (value: number) {
101 return VIDEO_PRIVACIES[ value ] !== undefined 101 return VIDEO_PRIVACIES[value] !== undefined
102} 102}
103 103
104function isScheduleVideoUpdatePrivacyValid (value: number) { 104function isScheduleVideoUpdatePrivacyValid (value: number) {
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts
index 9bf6d85a8..f46812977 100644
--- a/server/helpers/express-utils.ts
+++ b/server/helpers/express-utils.ts
@@ -12,7 +12,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) {
12 if (paramNSFW === 'false') return false 12 if (paramNSFW === 'false') return false
13 if (paramNSFW === 'both') return undefined 13 if (paramNSFW === 'both') return undefined
14 14
15 if (res && res.locals.oauth) { 15 if (res?.locals.oauth) {
16 const user = res.locals.oauth.token.User 16 const user = res.locals.oauth.token.User
17 17
18 // User does not want NSFW videos 18 // User does not want NSFW videos
@@ -28,7 +28,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) {
28 return null 28 return null
29} 29}
30 30
31function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[] }) { 31function cleanUpReqFiles (req: { files: { [fieldname: string]: Express.Multer.File[] } | Express.Multer.File[] }) {
32 const files = req.files 32 const files = req.files
33 33
34 if (!files) return 34 if (!files) return
@@ -39,7 +39,7 @@ function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.
39 } 39 }
40 40
41 for (const key of Object.keys(files)) { 41 for (const key of Object.keys(files)) {
42 const file = files[ key ] 42 const file = files[key]
43 43
44 if (isArray(file)) file.forEach(f => deleteFileAsync(f.path)) 44 if (isArray(file)) file.forEach(f => deleteFileAsync(f.path))
45 else deleteFileAsync(file.path) 45 else deleteFileAsync(file.path)
@@ -65,18 +65,18 @@ function badRequest (req: express.Request, res: express.Response) {
65 65
66function createReqFiles ( 66function createReqFiles (
67 fieldNames: string[], 67 fieldNames: string[],
68 mimeTypes: { [ id: string ]: string }, 68 mimeTypes: { [id: string]: string },
69 destinations: { [ fieldName: string ]: string } 69 destinations: { [fieldName: string]: string }
70) { 70) {
71 const storage = multer.diskStorage({ 71 const storage = multer.diskStorage({
72 destination: (req, file, cb) => { 72 destination: (req, file, cb) => {
73 cb(null, destinations[ file.fieldname ]) 73 cb(null, destinations[file.fieldname])
74 }, 74 },
75 75
76 filename: async (req, file, cb) => { 76 filename: async (req, file, cb) => {
77 let extension: string 77 let extension: string
78 const fileExtension = extname(file.originalname) 78 const fileExtension = extname(file.originalname)
79 const extensionFromMimetype = mimeTypes[ file.mimetype ] 79 const extensionFromMimetype = mimeTypes[file.mimetype]
80 80
81 // Take the file extension if we don't understand the mime type 81 // Take the file extension if we don't understand the mime type
82 // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file 82 // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file
@@ -99,7 +99,7 @@ function createReqFiles (
99 } 99 }
100 }) 100 })
101 101
102 let fields: { name: string, maxCount: number }[] = [] 102 const fields: { name: string, maxCount: number }[] = []
103 for (const fieldName of fieldNames) { 103 for (const fieldName of fieldNames) {
104 fields.push({ 104 fields.push({
105 name: fieldName, 105 name: fieldName,
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index 7022d3e03..084516e55 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -1,6 +1,6 @@
1import * as ffmpeg from 'fluent-ffmpeg' 1import * as ffmpeg from 'fluent-ffmpeg'
2import { dirname, join } from 'path' 2import { dirname, join } from 'path'
3import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos' 3import { getMaxBitrate, getTargetBitrate, VideoResolution } from '../../shared/models/videos'
4import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' 4import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants'
5import { processImage } from './image-utils' 5import { processImage } from './image-utils'
6import { logger } from './logger' 6import { logger } from './logger'
@@ -8,6 +8,71 @@ import { checkFFmpegEncoders } from '../initializers/checker-before-init'
8import { readFile, remove, writeFile } from 'fs-extra' 8import { readFile, remove, writeFile } from 'fs-extra'
9import { CONFIG } from '../initializers/config' 9import { CONFIG } from '../initializers/config'
10 10
11/**
12 * A toolbox to play with audio
13 */
14namespace audio {
15 export const get = (videoPath: string) => {
16 // without position, ffprobe considers the last input only
17 // we make it consider the first input only
18 // if you pass a file path to pos, then ffprobe acts on that file directly
19 return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => {
20
21 function parseFfprobe (err: any, data: ffmpeg.FfprobeData) {
22 if (err) return rej(err)
23
24 if ('streams' in data) {
25 const audioStream = data.streams.find(stream => stream['codec_type'] === 'audio')
26 if (audioStream) {
27 return res({
28 absolutePath: data.format.filename,
29 audioStream
30 })
31 }
32 }
33
34 return res({ absolutePath: data.format.filename })
35 }
36
37 return ffmpeg.ffprobe(videoPath, parseFfprobe)
38 })
39 }
40
41 export namespace bitrate {
42 const baseKbitrate = 384
43
44 const toBits = (kbits: number) => kbits * 8000
45
46 export const aac = (bitrate: number): number => {
47 switch (true) {
48 case bitrate > toBits(baseKbitrate):
49 return baseKbitrate
50
51 default:
52 return -1 // we interpret it as a signal to copy the audio stream as is
53 }
54 }
55
56 export const mp3 = (bitrate: number): number => {
57 /*
58 a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac.
59 That's why, when using aac, we can go to lower kbit/sec. The equivalences
60 made here are not made to be accurate, especially with good mp3 encoders.
61 */
62 switch (true) {
63 case bitrate <= toBits(192):
64 return 128
65
66 case bitrate <= toBits(384):
67 return 256
68
69 default:
70 return baseKbitrate
71 }
72 }
73 }
74}
75
11function computeResolutionsToTranscode (videoFileHeight: number) { 76function computeResolutionsToTranscode (videoFileHeight: number) {
12 const resolutionsEnabled: number[] = [] 77 const resolutionsEnabled: number[] = []
13 const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS 78 const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS
@@ -24,7 +89,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
24 ] 89 ]
25 90
26 for (const resolution of resolutions) { 91 for (const resolution of resolutions) {
27 if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) { 92 if (configResolutions[resolution + 'p'] === true && videoFileHeight > resolution) {
28 resolutionsEnabled.push(resolution) 93 resolutionsEnabled.push(resolution)
29 } 94 }
30 } 95 }
@@ -48,9 +113,9 @@ async function getVideoStreamCodec (path: string) {
48 const videoCodec = videoStream.codec_tag_string 113 const videoCodec = videoStream.codec_tag_string
49 114
50 const baseProfileMatrix = { 115 const baseProfileMatrix = {
51 'High': '6400', 116 High: '6400',
52 'Main': '4D40', 117 Main: '4D40',
53 'Baseline': '42E0' 118 Baseline: '42E0'
54 } 119 }
55 120
56 let baseProfile = baseProfileMatrix[videoStream.profile] 121 let baseProfile = baseProfileMatrix[videoStream.profile]
@@ -91,7 +156,7 @@ async function getVideoFileFPS (path: string) {
91 if (videoStream === null) return 0 156 if (videoStream === null) return 0
92 157
93 for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { 158 for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) {
94 const valuesText: string = videoStream[ key ] 159 const valuesText: string = videoStream[key]
95 if (!valuesText) continue 160 if (!valuesText) continue
96 161
97 const [ frames, seconds ] = valuesText.split('/') 162 const [ frames, seconds ] = valuesText.split('/')
@@ -191,7 +256,8 @@ interface OnlyAudioTranscodeOptions extends BaseTranscodeOptions {
191 type: 'only-audio' 256 type: 'only-audio'
192} 257}
193 258
194type TranscodeOptions = HLSTranscodeOptions 259type TranscodeOptions =
260 HLSTranscodeOptions
195 | VideoTranscodeOptions 261 | VideoTranscodeOptions
196 | MergeAudioTranscodeOptions 262 | MergeAudioTranscodeOptions
197 | OnlyAudioTranscodeOptions 263 | OnlyAudioTranscodeOptions
@@ -204,13 +270,13 @@ function transcode (options: TranscodeOptions) {
204 .output(options.outputPath) 270 .output(options.outputPath)
205 271
206 if (options.type === 'quick-transcode') { 272 if (options.type === 'quick-transcode') {
207 command = await buildQuickTranscodeCommand(command) 273 command = buildQuickTranscodeCommand(command)
208 } else if (options.type === 'hls') { 274 } else if (options.type === 'hls') {
209 command = await buildHLSCommand(command, options) 275 command = await buildHLSCommand(command, options)
210 } else if (options.type === 'merge-audio') { 276 } else if (options.type === 'merge-audio') {
211 command = await buildAudioMergeCommand(command, options) 277 command = await buildAudioMergeCommand(command, options)
212 } else if (options.type === 'only-audio') { 278 } else if (options.type === 'only-audio') {
213 command = await buildOnlyAudioCommand(command, options) 279 command = buildOnlyAudioCommand(command, options)
214 } else { 280 } else {
215 command = await buildx264Command(command, options) 281 command = await buildx264Command(command, options)
216 } 282 }
@@ -247,17 +313,17 @@ async function canDoQuickTranscode (path: string): Promise<boolean> {
247 313
248 // check video params 314 // check video params
249 if (videoStream == null) return false 315 if (videoStream == null) return false
250 if (videoStream[ 'codec_name' ] !== 'h264') return false 316 if (videoStream['codec_name'] !== 'h264') return false
251 if (videoStream[ 'pix_fmt' ] !== 'yuv420p') return false 317 if (videoStream['pix_fmt'] !== 'yuv420p') return false
252 if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false 318 if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false
253 if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false 319 if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false
254 320
255 // check audio params (if audio stream exists) 321 // check audio params (if audio stream exists)
256 if (parsedAudio.audioStream) { 322 if (parsedAudio.audioStream) {
257 if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false 323 if (parsedAudio.audioStream['codec_name'] !== 'aac') return false
258 324
259 const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ]) 325 const maxAudioBitrate = audio.bitrate['aac'](parsedAudio.audioStream['bit_rate'])
260 if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false 326 if (maxAudioBitrate !== -1 && parsedAudio.audioStream['bit_rate'] > maxAudioBitrate) return false
261 } 327 }
262 328
263 return true 329 return true
@@ -333,14 +399,14 @@ async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: M
333 return command 399 return command
334} 400}
335 401
336async function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) { 402function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) {
337 command = await presetOnlyAudio(command) 403 command = presetOnlyAudio(command)
338 404
339 return command 405 return command
340} 406}
341 407
342async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { 408function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
343 command = await presetCopy(command) 409 command = presetCopy(command)
344 410
345 command = command.outputOption('-map_metadata -1') // strip all metadata 411 command = command.outputOption('-map_metadata -1') // strip all metadata
346 .outputOption('-movflags faststart') 412 .outputOption('-movflags faststart')
@@ -351,7 +417,7 @@ async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
351async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) { 417async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) {
352 const videoPath = getHLSVideoPath(options) 418 const videoPath = getHLSVideoPath(options)
353 419
354 if (options.copyCodecs) command = await presetCopy(command) 420 if (options.copyCodecs) command = presetCopy(command)
355 else command = await buildx264Command(command, options) 421 else command = await buildx264Command(command, options)
356 422
357 command = command.outputOption('-hls_time 4') 423 command = command.outputOption('-hls_time 4')
@@ -419,71 +485,6 @@ async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string,
419} 485}
420 486
421/** 487/**
422 * A toolbox to play with audio
423 */
424namespace audio {
425 export const get = (videoPath: string) => {
426 // without position, ffprobe considers the last input only
427 // we make it consider the first input only
428 // if you pass a file path to pos, then ffprobe acts on that file directly
429 return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => {
430
431 function parseFfprobe (err: any, data: ffmpeg.FfprobeData) {
432 if (err) return rej(err)
433
434 if ('streams' in data) {
435 const audioStream = data.streams.find(stream => stream[ 'codec_type' ] === 'audio')
436 if (audioStream) {
437 return res({
438 absolutePath: data.format.filename,
439 audioStream
440 })
441 }
442 }
443
444 return res({ absolutePath: data.format.filename })
445 }
446
447 return ffmpeg.ffprobe(videoPath, parseFfprobe)
448 })
449 }
450
451 export namespace bitrate {
452 const baseKbitrate = 384
453
454 const toBits = (kbits: number) => kbits * 8000
455
456 export const aac = (bitrate: number): number => {
457 switch (true) {
458 case bitrate > toBits(baseKbitrate):
459 return baseKbitrate
460
461 default:
462 return -1 // we interpret it as a signal to copy the audio stream as is
463 }
464 }
465
466 export const mp3 = (bitrate: number): number => {
467 /*
468 a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac.
469 That's why, when using aac, we can go to lower kbit/sec. The equivalences
470 made here are not made to be accurate, especially with good mp3 encoders.
471 */
472 switch (true) {
473 case bitrate <= toBits(192):
474 return 128
475
476 case bitrate <= toBits(384):
477 return 256
478
479 default:
480 return baseKbitrate
481 }
482 }
483 }
484}
485
486/**
487 * Standard profile, with variable bitrate audio and faststart. 488 * Standard profile, with variable bitrate audio and faststart.
488 * 489 *
489 * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel 490 * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel
@@ -513,10 +514,10 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut
513 // of course this is far from perfect, but it might save some space in the end 514 // of course this is far from perfect, but it might save some space in the end
514 localCommand = localCommand.audioCodec('aac') 515 localCommand = localCommand.audioCodec('aac')
515 516
516 const audioCodecName = parsedAudio.audioStream[ 'codec_name' ] 517 const audioCodecName = parsedAudio.audioStream['codec_name']
517 518
518 if (audio.bitrate[ audioCodecName ]) { 519 if (audio.bitrate[audioCodecName]) {
519 const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) 520 const bitrate = audio.bitrate[audioCodecName](parsedAudio.audioStream['bit_rate'])
520 if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) 521 if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate)
521 } 522 }
522 } 523 }
@@ -537,14 +538,14 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut
537 return localCommand 538 return localCommand
538} 539}
539 540
540async function presetCopy (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { 541function presetCopy (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand {
541 return command 542 return command
542 .format('mp4') 543 .format('mp4')
543 .videoCodec('copy') 544 .videoCodec('copy')
544 .audioCodec('copy') 545 .audioCodec('copy')
545} 546}
546 547
547async function presetOnlyAudio (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { 548function presetOnlyAudio (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand {
548 return command 549 return command
549 .format('mp4') 550 .format('mp4')
550 .audioCodec('copy') 551 .audioCodec('copy')
diff --git a/server/helpers/logger.ts b/server/helpers/logger.ts
index fd2988ad0..b8ae28b3f 100644
--- a/server/helpers/logger.ts
+++ b/server/helpers/logger.ts
@@ -27,7 +27,7 @@ function getLoggerReplacer () {
27 if (value instanceof Error) { 27 if (value instanceof Error) {
28 const error = {} 28 const error = {}
29 29
30 Object.getOwnPropertyNames(value).forEach(key => error[ key ] = value[ key ]) 30 Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] })
31 31
32 return error 32 return error
33 } 33 }
@@ -98,19 +98,20 @@ function bunyanLogFactory (level: string) {
98 let args: any[] = [] 98 let args: any[] = []
99 args.concat(arguments) 99 args.concat(arguments)
100 100
101 if (arguments[ 0 ] instanceof Error) { 101 if (arguments[0] instanceof Error) {
102 meta = arguments[ 0 ].toString() 102 meta = arguments[0].toString()
103 args = Array.prototype.slice.call(arguments, 1) 103 args = Array.prototype.slice.call(arguments, 1)
104 args.push(meta) 104 args.push(meta)
105 } else if (typeof (args[ 0 ]) !== 'string') { 105 } else if (typeof (args[0]) !== 'string') {
106 meta = arguments[ 0 ] 106 meta = arguments[0]
107 args = Array.prototype.slice.call(arguments, 1) 107 args = Array.prototype.slice.call(arguments, 1)
108 args.push(meta) 108 args.push(meta)
109 } 109 }
110 110
111 logger[ level ].apply(logger, args) 111 logger[level].apply(logger, args)
112 } 112 }
113} 113}
114
114const bunyanLogger = { 115const bunyanLogger = {
115 trace: bunyanLogFactory('debug'), 116 trace: bunyanLogFactory('debug'),
116 debug: bunyanLogFactory('debug'), 117 debug: bunyanLogFactory('debug'),
diff --git a/server/helpers/regexp.ts b/server/helpers/regexp.ts
index 2336654b0..cfc2be488 100644
--- a/server/helpers/regexp.ts
+++ b/server/helpers/regexp.ts
@@ -1,8 +1,8 @@
1// Thanks to https://regex101.com 1// Thanks to https://regex101.com
2function regexpCapture (str: string, regex: RegExp, maxIterations = 100) { 2function regexpCapture (str: string, regex: RegExp, maxIterations = 100) {
3 const result: RegExpExecArray[] = []
3 let m: RegExpExecArray 4 let m: RegExpExecArray
4 let i = 0 5 let i = 0
5 let result: RegExpExecArray[] = []
6 6
7 // tslint:disable:no-conditional-assignment 7 // tslint:disable:no-conditional-assignment
8 while ((m = regex.exec(str)) !== null && i < maxIterations) { 8 while ((m = regex.exec(str)) !== null && i < maxIterations) {
diff --git a/server/helpers/register-ts-paths.ts b/server/helpers/register-ts-paths.ts
index e8db369e3..eec7fed3e 100644
--- a/server/helpers/register-ts-paths.ts
+++ b/server/helpers/register-ts-paths.ts
@@ -1,5 +1,5 @@
1import { resolve } from 'path' 1import { resolve } from 'path'
2const tsConfigPaths = require('tsconfig-paths') 2import tsConfigPaths = require('tsconfig-paths')
3 3
4const tsConfig = require('../../tsconfig.json') 4const tsConfig = require('../../tsconfig.json')
5 5
diff --git a/server/helpers/signup.ts b/server/helpers/signup.ts
index 7c73f7c5c..d34ff2db5 100644
--- a/server/helpers/signup.ts
+++ b/server/helpers/signup.ts
@@ -21,7 +21,7 @@ async function isSignupAllowed (): Promise<{ allowed: boolean, errorMessage?: st
21 21
22function isSignupAllowedForCurrentIP (ip: string) { 22function isSignupAllowedForCurrentIP (ip: string) {
23 const addr = ipaddr.parse(ip) 23 const addr = ipaddr.parse(ip)
24 let excludeList = [ 'blacklist' ] 24 const excludeList = [ 'blacklist' ]
25 let matched = '' 25 let matched = ''
26 26
27 // if there is a valid, non-empty whitelist, we exclude all unknown adresses too 27 // if there is a valid, non-empty whitelist, we exclude all unknown adresses too
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts
index 4c6f200f8..7a4c781cc 100644
--- a/server/helpers/utils.ts
+++ b/server/helpers/utils.ts
@@ -1,6 +1,6 @@
1import { ResultList } from '../../shared' 1import { ResultList } from '../../shared'
2import { ApplicationModel } from '../models/application/application' 2import { ApplicationModel } from '../models/application/application'
3import { execPromise, execPromise2, pseudoRandomBytesPromise, sha256 } from './core-utils' 3import { execPromise, execPromise2, randomBytesPromise, sha256 } from './core-utils'
4import { logger } from './logger' 4import { logger } from './logger'
5import { join } from 'path' 5import { join } from 'path'
6import { Instance as ParseTorrent } from 'parse-torrent' 6import { Instance as ParseTorrent } from 'parse-torrent'
@@ -14,7 +14,7 @@ function deleteFileAsync (path: string) {
14} 14}
15 15
16async function generateRandomString (size: number) { 16async function generateRandomString (size: number) {
17 const raw = await pseudoRandomBytesPromise(size) 17 const raw = await randomBytesPromise(size)
18 18
19 return raw.toString('hex') 19 return raw.toString('hex')
20} 20}
diff --git a/server/helpers/webtorrent.ts b/server/helpers/webtorrent.ts
index 8a5d030df..b25e44fcd 100644
--- a/server/helpers/webtorrent.ts
+++ b/server/helpers/webtorrent.ts
@@ -39,7 +39,7 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName
39 if (torrent.files.length !== 1) { 39 if (torrent.files.length !== 1) {
40 if (timer) clearTimeout(timer) 40 if (timer) clearTimeout(timer)
41 41
42 for (let file of torrent.files) { 42 for (const file of torrent.files) {
43 deleteDownloadedFile({ directoryPath, filepath: file.path }) 43 deleteDownloadedFile({ directoryPath, filepath: file.path })
44 } 44 }
45 45
@@ -47,15 +47,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName
47 .then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it'))) 47 .then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it')))
48 } 48 }
49 49
50 file = torrent.files[ 0 ] 50 file = torrent.files[0]
51 51
52 // FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed 52 // FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed
53 const writeStream = createWriteStream(path) 53 const writeStream = createWriteStream(path)
54 writeStream.on('finish', () => { 54 writeStream.on('finish', () => {
55 if (timer) clearTimeout(timer) 55 if (timer) clearTimeout(timer)
56 56
57 return safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName) 57 safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName)
58 .then(() => res(path)) 58 .then(() => res(path))
59 .catch(err => logger.error('Cannot destroy webtorrent.', { err }))
59 }) 60 })
60 61
61 file.createReadStream().pipe(writeStream) 62 file.createReadStream().pipe(writeStream)
@@ -63,9 +64,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName
63 64
64 torrent.on('error', err => rej(err)) 65 torrent.on('error', err => rej(err))
65 66
66 timer = setTimeout(async () => { 67 timer = setTimeout(() => {
67 return safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName) 68 const err = new Error('Webtorrent download timeout.')
68 .then(() => rej(new Error('Webtorrent download timeout.'))) 69
70 safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName)
71 .then(() => rej(err))
72 .catch(destroyErr => {
73 logger.error('Cannot destroy webtorrent.', { err: destroyErr })
74 rej(err)
75 })
76
69 }, timeout) 77 }, timeout)
70 }) 78 })
71} 79}
diff --git a/server/helpers/youtube-dl.ts b/server/helpers/youtube-dl.ts
index 577a59dbf..fc9d416a1 100644
--- a/server/helpers/youtube-dl.ts
+++ b/server/helpers/youtube-dl.ts
@@ -24,20 +24,23 @@ const processOptions = {
24} 24}
25 25
26function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> { 26function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> {
27 return new Promise<YoutubeDLInfo>(async (res, rej) => { 27 return new Promise<YoutubeDLInfo>((res, rej) => {
28 let args = opts || [ '-j', '--flat-playlist' ] 28 let args = opts || [ '-j', '--flat-playlist' ]
29 args = wrapWithProxyOptions(args) 29 args = wrapWithProxyOptions(args)
30 30
31 const youtubeDL = await safeGetYoutubeDL() 31 safeGetYoutubeDL()
32 youtubeDL.getInfo(url, args, processOptions, (err, info) => { 32 .then(youtubeDL => {
33 if (err) return rej(err) 33 youtubeDL.getInfo(url, args, processOptions, (err, info) => {
34 if (info.is_live === true) return rej(new Error('Cannot download a live streaming.')) 34 if (err) return rej(err)
35 if (info.is_live === true) return rej(new Error('Cannot download a live streaming.'))
35 36
36 const obj = buildVideoInfo(normalizeObject(info)) 37 const obj = buildVideoInfo(normalizeObject(info))
37 if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video' 38 if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video'
38 39
39 return res(obj) 40 return res(obj)
40 }) 41 })
42 })
43 .catch(err => rej(err))
41 }) 44 })
42} 45}
43 46
@@ -54,26 +57,34 @@ function downloadYoutubeDLVideo (url: string, timeout: number) {
54 options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ]) 57 options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ])
55 } 58 }
56 59
57 return new Promise<string>(async (res, rej) => { 60 return new Promise<string>((res, rej) => {
58 const youtubeDL = await safeGetYoutubeDL() 61 safeGetYoutubeDL()
59 youtubeDL.exec(url, options, processOptions, err => { 62 .then(youtubeDL => {
60 clearTimeout(timer) 63 youtubeDL.exec(url, options, processOptions, err => {
64 clearTimeout(timer)
61 65
62 if (err) { 66 if (err) {
63 remove(path) 67 remove(path)
64 .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err })) 68 .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err }))
65 69
66 return rej(err) 70 return rej(err)
67 } 71 }
68 72
69 return res(path) 73 return res(path)
70 }) 74 })
71 75
72 timer = setTimeout(async () => { 76 timer = setTimeout(() => {
73 await remove(path) 77 const err = new Error('YoutubeDL download timeout.')
74 78
75 return rej(new Error('YoutubeDL download timeout.')) 79 remove(path)
76 }, timeout) 80 .finally(() => rej(err))
81 .catch(err => {
82 logger.error('Cannot remove %s in youtubeDL timeout.', path, { err })
83 return rej(err)
84 })
85 }, timeout)
86 })
87 .catch(err => rej(err))
77 }) 88 })
78} 89}
79 90
@@ -103,7 +114,7 @@ async function updateYoutubeDLBinary () {
103 114
104 const url = result.headers.location 115 const url = result.headers.location
105 const downloadFile = request.get(url) 116 const downloadFile = request.get(url)
106 const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[ 1 ] 117 const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[1]
107 118
108 downloadFile.on('response', result => { 119 downloadFile.on('response', result => {
109 if (result.statusCode !== 200) { 120 if (result.statusCode !== 200) {
diff --git a/server/initializers/checker-after-init.ts b/server/initializers/checker-after-init.ts
index 44efd346c..978023129 100644
--- a/server/initializers/checker-after-init.ts
+++ b/server/initializers/checker-after-init.ts
@@ -3,7 +3,7 @@ import { isProdInstance, isTestInstance } from '../helpers/core-utils'
3import { UserModel } from '../models/account/user' 3import { UserModel } from '../models/account/user'
4import { ApplicationModel } from '../models/application/application' 4import { ApplicationModel } from '../models/application/application'
5import { OAuthClientModel } from '../models/oauth/oauth-client' 5import { OAuthClientModel } from '../models/oauth/oauth-client'
6import { parse } from 'url' 6import { URL } from 'url'
7import { CONFIG } from './config' 7import { CONFIG } from './config'
8import { logger } from '../helpers/logger' 8import { logger } from '../helpers/logger'
9import { getServerActor } from '../helpers/utils' 9import { getServerActor } from '../helpers/utils'
@@ -16,7 +16,7 @@ import { WEBSERVER } from './constants'
16async function checkActivityPubUrls () { 16async function checkActivityPubUrls () {
17 const actor = await getServerActor() 17 const actor = await getServerActor()
18 18
19 const parsed = parse(actor.url) 19 const parsed = new URL(actor.url)
20 if (WEBSERVER.HOST !== parsed.host) { 20 if (WEBSERVER.HOST !== parsed.host) {
21 const NODE_ENV = config.util.getEnv('NODE_ENV') 21 const NODE_ENV = config.util.getEnv('NODE_ENV')
22 const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR') 22 const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR')
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts
index 9731a0af9..a75f2cec2 100644
--- a/server/initializers/checker-before-init.ts
+++ b/server/initializers/checker-before-init.ts
@@ -35,8 +35,8 @@ function checkMissedConfig () {
35 ] 35 ]
36 const requiredAlternatives = [ 36 const requiredAlternatives = [
37 [ // set 37 [ // set
38 ['redis.hostname', 'redis.port'], // alternative 38 [ 'redis.hostname', 'redis.port' ], // alternative
39 ['redis.socket'] 39 [ 'redis.socket' ]
40 ] 40 ]
41 ] 41 ]
42 const miss: string[] = [] 42 const miss: string[] = []
diff --git a/server/initializers/config.ts b/server/initializers/config.ts
index fd8bf09fc..75372fa4e 100644
--- a/server/initializers/config.ts
+++ b/server/initializers/config.ts
@@ -301,7 +301,7 @@ function getLocalConfigFilePath () {
301 if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}` 301 if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}`
302 if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}` 302 if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}`
303 303
304 return join(dirname(configSources[ 0 ].name), filename + '.json') 304 return join(dirname(configSources[0].name), filename + '.json')
305} 305}
306 306
307function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] { 307function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] {
@@ -330,7 +330,7 @@ export function reloadConfig () {
330 330
331 function purge () { 331 function purge () {
332 for (const fileName in require.cache) { 332 for (const fileName in require.cache) {
333 if (-1 === fileName.indexOf(directory())) { 333 if (fileName.indexOf(directory()) === -1) {
334 continue 334 continue
335 } 335 }
336 336
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 3a9946bba..fb8ae7cd6 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -4,7 +4,7 @@ import { ActivityPubActorType } from '../../shared/models/activitypub'
4import { FollowState } from '../../shared/models/actors' 4import { FollowState } from '../../shared/models/actors'
5import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos' 5import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos'
6// Do not use barrels, remain constants as independent as possible 6// Do not use barrels, remain constants as independent as possible
7import { isTestInstance, sanitizeHost, sanitizeUrl, root, parseDurationToMs } from '../helpers/core-utils' 7import { isTestInstance, sanitizeHost, sanitizeUrl, root } from '../helpers/core-utils'
8import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' 8import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
9import { invert } from 'lodash' 9import { invert } from 'lodash'
10import { CronRepeatOptions, EveryRepeatOptions } from 'bull' 10import { CronRepeatOptions, EveryRepeatOptions } from 'bull'
@@ -310,8 +310,8 @@ let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour
310 310
311const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { 311const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = {
312 MIN: 10, 312 MIN: 10,
313 STANDARD: [24, 25, 30], 313 STANDARD: [ 24, 25, 30 ],
314 HD_STANDARD: [50, 60], 314 HD_STANDARD: [ 50, 60 ],
315 AVERAGE: 30, 315 AVERAGE: 30,
316 MAX: 60, 316 MAX: 60,
317 KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) 317 KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum)
@@ -361,42 +361,42 @@ const VIDEO_LICENCES = {
361 7: 'Public Domain Dedication' 361 7: 'Public Domain Dedication'
362} 362}
363 363
364let VIDEO_LANGUAGES: { [id: string]: string } = {} 364const VIDEO_LANGUAGES: { [id: string]: string } = {}
365 365
366const VIDEO_PRIVACIES = { 366const VIDEO_PRIVACIES = {
367 [ VideoPrivacy.PUBLIC ]: 'Public', 367 [VideoPrivacy.PUBLIC]: 'Public',
368 [ VideoPrivacy.UNLISTED ]: 'Unlisted', 368 [VideoPrivacy.UNLISTED]: 'Unlisted',
369 [ VideoPrivacy.PRIVATE ]: 'Private', 369 [VideoPrivacy.PRIVATE]: 'Private',
370 [ VideoPrivacy.INTERNAL ]: 'Internal' 370 [VideoPrivacy.INTERNAL]: 'Internal'
371} 371}
372 372
373const VIDEO_STATES = { 373const VIDEO_STATES = {
374 [ VideoState.PUBLISHED ]: 'Published', 374 [VideoState.PUBLISHED]: 'Published',
375 [ VideoState.TO_TRANSCODE ]: 'To transcode', 375 [VideoState.TO_TRANSCODE]: 'To transcode',
376 [ VideoState.TO_IMPORT ]: 'To import' 376 [VideoState.TO_IMPORT]: 'To import'
377} 377}
378 378
379const VIDEO_IMPORT_STATES = { 379const VIDEO_IMPORT_STATES = {
380 [ VideoImportState.FAILED ]: 'Failed', 380 [VideoImportState.FAILED]: 'Failed',
381 [ VideoImportState.PENDING ]: 'Pending', 381 [VideoImportState.PENDING]: 'Pending',
382 [ VideoImportState.SUCCESS ]: 'Success' 382 [VideoImportState.SUCCESS]: 'Success'
383} 383}
384 384
385const VIDEO_ABUSE_STATES = { 385const VIDEO_ABUSE_STATES = {
386 [ VideoAbuseState.PENDING ]: 'Pending', 386 [VideoAbuseState.PENDING]: 'Pending',
387 [ VideoAbuseState.REJECTED ]: 'Rejected', 387 [VideoAbuseState.REJECTED]: 'Rejected',
388 [ VideoAbuseState.ACCEPTED ]: 'Accepted' 388 [VideoAbuseState.ACCEPTED]: 'Accepted'
389} 389}
390 390
391const VIDEO_PLAYLIST_PRIVACIES = { 391const VIDEO_PLAYLIST_PRIVACIES = {
392 [ VideoPlaylistPrivacy.PUBLIC ]: 'Public', 392 [VideoPlaylistPrivacy.PUBLIC]: 'Public',
393 [ VideoPlaylistPrivacy.UNLISTED ]: 'Unlisted', 393 [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted',
394 [ VideoPlaylistPrivacy.PRIVATE ]: 'Private' 394 [VideoPlaylistPrivacy.PRIVATE]: 'Private'
395} 395}
396 396
397const VIDEO_PLAYLIST_TYPES = { 397const VIDEO_PLAYLIST_TYPES = {
398 [ VideoPlaylistType.REGULAR ]: 'Regular', 398 [VideoPlaylistType.REGULAR]: 'Regular',
399 [ VideoPlaylistType.WATCH_LATER ]: 'Watch later' 399 [VideoPlaylistType.WATCH_LATER]: 'Watch later'
400} 400}
401 401
402const MIMETYPES = { 402const MIMETYPES = {
@@ -533,7 +533,7 @@ const LAZY_STATIC_PATHS = {
533} 533}
534 534
535// Cache control 535// Cache control
536let STATIC_MAX_AGE = { 536const STATIC_MAX_AGE = {
537 SERVER: '2h', 537 SERVER: '2h',
538 CLIENT: '30d' 538 CLIENT: '30d'
539} 539}
@@ -671,14 +671,14 @@ if (isTestInstance() === true) {
671 SCHEDULER_INTERVALS_MS.removeOldViews = 5000 671 SCHEDULER_INTERVALS_MS.removeOldViews = 5000
672 SCHEDULER_INTERVALS_MS.updateVideos = 5000 672 SCHEDULER_INTERVALS_MS.updateVideos = 5000
673 SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000 673 SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000
674 REPEAT_JOBS[ 'videos-views' ] = { every: 5000 } 674 REPEAT_JOBS['videos-views'] = { every: 5000 }
675 675
676 REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 676 REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1
677 677
678 VIDEO_VIEW_LIFETIME = 1000 // 1 second 678 VIDEO_VIEW_LIFETIME = 1000 // 1 second
679 CONTACT_FORM_LIFETIME = 1000 // 1 second 679 CONTACT_FORM_LIFETIME = 1000 // 1 second
680 680
681 JOB_ATTEMPTS[ 'email' ] = 1 681 JOB_ATTEMPTS['email'] = 1
682 682
683 FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000 683 FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000
684 MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1 684 MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1
@@ -838,42 +838,42 @@ function loadLanguages () {
838function buildLanguages () { 838function buildLanguages () {
839 const iso639 = require('iso-639-3') 839 const iso639 = require('iso-639-3')
840 840
841 const languages: { [ id: string ]: string } = {} 841 const languages: { [id: string]: string } = {}
842 842
843 const additionalLanguages = { 843 const additionalLanguages = {
844 'sgn': true, // Sign languages (macro language) 844 sgn: true, // Sign languages (macro language)
845 'ase': true, // American sign language 845 ase: true, // American sign language
846 'sdl': true, // Arabian sign language 846 sdl: true, // Arabian sign language
847 'bfi': true, // British sign language 847 bfi: true, // British sign language
848 'bzs': true, // Brazilian sign language 848 bzs: true, // Brazilian sign language
849 'csl': true, // Chinese sign language 849 csl: true, // Chinese sign language
850 'cse': true, // Czech sign language 850 cse: true, // Czech sign language
851 'dsl': true, // Danish sign language 851 dsl: true, // Danish sign language
852 'fsl': true, // French sign language 852 fsl: true, // French sign language
853 'gsg': true, // German sign language 853 gsg: true, // German sign language
854 'pks': true, // Pakistan sign language 854 pks: true, // Pakistan sign language
855 'jsl': true, // Japanese sign language 855 jsl: true, // Japanese sign language
856 'sfs': true, // South African sign language 856 sfs: true, // South African sign language
857 'swl': true, // Swedish sign language 857 swl: true, // Swedish sign language
858 'rsl': true, // Russian sign language: true 858 rsl: true, // Russian sign language: true
859 859
860 'epo': true, // Esperanto 860 epo: true, // Esperanto
861 'tlh': true, // Klingon 861 tlh: true, // Klingon
862 'jbo': true, // Lojban 862 jbo: true, // Lojban
863 'avk': true // Kotava 863 avk: true // Kotava
864 } 864 }
865 865
866 // Only add ISO639-1 languages and some sign languages (ISO639-3) 866 // Only add ISO639-1 languages and some sign languages (ISO639-3)
867 iso639 867 iso639
868 .filter(l => { 868 .filter(l => {
869 return (l.iso6391 !== null && l.type === 'living') || 869 return (l.iso6391 !== null && l.type === 'living') ||
870 additionalLanguages[ l.iso6393 ] === true 870 additionalLanguages[l.iso6393] === true
871 }) 871 })
872 .forEach(l => languages[ l.iso6391 || l.iso6393 ] = l.name) 872 .forEach(l => { languages[l.iso6391 || l.iso6393] = l.name })
873 873
874 // Override Occitan label 874 // Override Occitan label
875 languages[ 'oc' ] = 'Occitan' 875 languages['oc'] = 'Occitan'
876 languages[ 'el' ] = 'Greek' 876 languages['el'] = 'Greek'
877 877
878 return languages 878 return languages
879} 879}
diff --git a/server/initializers/database.ts b/server/initializers/database.ts
index 9ec146ab1..eedaf3c4e 100644
--- a/server/initializers/database.ts
+++ b/server/initializers/database.ts
@@ -119,8 +119,6 @@ async function initDatabaseModels (silent: boolean) {
119 await createFunctions() 119 await createFunctions()
120 120
121 if (!silent) logger.info('Database %s is ready.', dbname) 121 if (!silent) logger.info('Database %s is ready.', dbname)
122
123 return
124} 122}
125 123
126// --------------------------------------------------------------------------- 124// ---------------------------------------------------------------------------
diff --git a/server/initializers/migrations/0005-email-pod.ts b/server/initializers/migrations/0005-email-pod.ts
index c34a12255..417c33b1f 100644
--- a/server/initializers/migrations/0005-email-pod.ts
+++ b/server/initializers/migrations/0005-email-pod.ts
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations' 3import { Migration } from '../../models/migrations'
4 4
5function up (utils: { 5function up (utils: {
6 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface, 7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize 8 sequelize: Sequelize.Sequelize
9}): Promise<void> { 9}): Promise<void> {
10 const q = utils.queryInterface 10 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0010-email-user.ts b/server/initializers/migrations/0010-email-user.ts
index 37a7b0bb3..f7d01f6d6 100644
--- a/server/initializers/migrations/0010-email-user.ts
+++ b/server/initializers/migrations/0010-email-user.ts
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations' 3import { Migration } from '../../models/migrations'
4 4
5function up (utils: { 5function up (utils: {
6 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface, 7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize 8 sequelize: Sequelize.Sequelize
9}): Promise<void> { 9}): Promise<void> {
10 const q = utils.queryInterface 10 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0015-video-views.ts b/server/initializers/migrations/0015-video-views.ts
index 25164ff4d..47dd4069b 100644
--- a/server/initializers/migrations/0015-video-views.ts
+++ b/server/initializers/migrations/0015-video-views.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3 3
4function up (utils: { 4function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0020-video-likes.ts b/server/initializers/migrations/0020-video-likes.ts
index 945be5a98..44333f3b0 100644
--- a/server/initializers/migrations/0020-video-likes.ts
+++ b/server/initializers/migrations/0020-video-likes.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3 3
4function up (utils: { 4function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0025-video-dislikes.ts b/server/initializers/migrations/0025-video-dislikes.ts
index 27144c437..2aa22e2d7 100644
--- a/server/initializers/migrations/0025-video-dislikes.ts
+++ b/server/initializers/migrations/0025-video-dislikes.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3 3
4function up (utils: { 4function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0030-video-category.ts b/server/initializers/migrations/0030-video-category.ts
index f784f820d..00cd2d8cf 100644
--- a/server/initializers/migrations/0030-video-category.ts
+++ b/server/initializers/migrations/0030-video-category.ts
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations' 3import { Migration } from '../../models/migrations'
4 4
5function up (utils: { 5function up (utils: {
6 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface, 7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize 8 sequelize: Sequelize.Sequelize
9}): Promise<void> { 9}): Promise<void> {
10 const q = utils.queryInterface 10 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0035-video-licence.ts b/server/initializers/migrations/0035-video-licence.ts
index 3d0b0bac9..61d666c5e 100644
--- a/server/initializers/migrations/0035-video-licence.ts
+++ b/server/initializers/migrations/0035-video-licence.ts
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations' 3import { Migration } from '../../models/migrations'
4 4
5function up (utils: { 5function up (utils: {
6 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface, 7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize 8 sequelize: Sequelize.Sequelize
9}): Promise<void> { 9}): Promise<void> {
10 const q = utils.queryInterface 10 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0040-video-nsfw.ts b/server/initializers/migrations/0040-video-nsfw.ts
index f7f70d3c4..44aec8a6c 100644
--- a/server/initializers/migrations/0040-video-nsfw.ts
+++ b/server/initializers/migrations/0040-video-nsfw.ts
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations' 3import { Migration } from '../../models/migrations'
4 4
5function up (utils: { 5function up (utils: {
6 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface, 7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize 8 sequelize: Sequelize.Sequelize
9}): Promise<void> { 9}): Promise<void> {
10 const q = utils.queryInterface 10 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0045-user-display-nsfw.ts b/server/initializers/migrations/0045-user-display-nsfw.ts
index aef420f0e..07795bd75 100644
--- a/server/initializers/migrations/0045-user-display-nsfw.ts
+++ b/server/initializers/migrations/0045-user-display-nsfw.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3 3
4function up (utils: { 4function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0050-video-language.ts b/server/initializers/migrations/0050-video-language.ts
index 796fa5f95..6f90abb44 100644
--- a/server/initializers/migrations/0050-video-language.ts
+++ b/server/initializers/migrations/0050-video-language.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3 3
4function up (utils: { 4function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0055-video-uuid.ts b/server/initializers/migrations/0055-video-uuid.ts
index e0f904080..8a58aebb8 100644
--- a/server/initializers/migrations/0055-video-uuid.ts
+++ b/server/initializers/migrations/0055-video-uuid.ts
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations' 3import { Migration } from '../../models/migrations'
4 4
5function up (utils: { 5function up (utils: {
6 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface, 7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize 8 sequelize: Sequelize.Sequelize
9}): Promise<void> { 9}): Promise<void> {
10 const q = utils.queryInterface 10 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0060-video-file.ts b/server/initializers/migrations/0060-video-file.ts
index c362cf71a..00647e60e 100644
--- a/server/initializers/migrations/0060-video-file.ts
+++ b/server/initializers/migrations/0060-video-file.ts
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3 3
4function up (utils: { 4function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize, 7 sequelize: Sequelize.Sequelize
8 db: any 8 db: any
9}): Promise<void> { 9}): Promise<void> {
10 const q = utils.queryInterface 10 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0065-video-file-size.ts b/server/initializers/migrations/0065-video-file-size.ts
index e9ce77e50..0bdc675c2 100644
--- a/server/initializers/migrations/0065-video-file-size.ts
+++ b/server/initializers/migrations/0065-video-file-size.ts
@@ -5,9 +5,9 @@ import { VideoModel } from '../../models/video/video'
5import { getVideoFilePath } from '@server/lib/video-paths' 5import { getVideoFilePath } from '@server/lib/video-paths'
6 6
7function up (utils: { 7function up (utils: {
8 transaction: Sequelize.Transaction, 8 transaction: Sequelize.Transaction
9 queryInterface: Sequelize.QueryInterface, 9 queryInterface: Sequelize.QueryInterface
10 sequelize: Sequelize.Sequelize, 10 sequelize: Sequelize.Sequelize
11 db: any 11 db: any
12}): Promise<void> { 12}): Promise<void> {
13 return utils.db.Video.listOwnedAndPopulateAuthorAndTags() 13 return utils.db.Video.listOwnedAndPopulateAuthorAndTags()
diff --git a/server/initializers/migrations/0070-user-video-quota.ts b/server/initializers/migrations/0070-user-video-quota.ts
index 37683432f..1d073f244 100644
--- a/server/initializers/migrations/0070-user-video-quota.ts
+++ b/server/initializers/migrations/0070-user-video-quota.ts
@@ -3,9 +3,9 @@ import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations' 3import { Migration } from '../../models/migrations'
4 4
5function up (utils: { 5function up (utils: {
6 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface, 7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize, 8 sequelize: Sequelize.Sequelize
9 db: any 9 db: any
10}): Promise<void> { 10}): Promise<void> {
11 const q = utils.queryInterface 11 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0075-video-resolutions.ts b/server/initializers/migrations/0075-video-resolutions.ts
index e4f26cb77..f56c1b2c3 100644
--- a/server/initializers/migrations/0075-video-resolutions.ts
+++ b/server/initializers/migrations/0075-video-resolutions.ts
@@ -5,9 +5,9 @@ import { getVideoFileResolution } from '../../helpers/ffmpeg-utils'
5import { readdir, rename } from 'fs-extra' 5import { readdir, rename } from 'fs-extra'
6 6
7function up (utils: { 7function up (utils: {
8 transaction: Sequelize.Transaction, 8 transaction: Sequelize.Transaction
9 queryInterface: Sequelize.QueryInterface, 9 queryInterface: Sequelize.QueryInterface
10 sequelize: Sequelize.Sequelize, 10 sequelize: Sequelize.Sequelize
11 db: any 11 db: any
12}): Promise<void> { 12}): Promise<void> {
13 const torrentDir = CONFIG.STORAGE.TORRENTS_DIR 13 const torrentDir = CONFIG.STORAGE.TORRENTS_DIR
diff --git a/server/initializers/migrations/0080-video-channels.ts b/server/initializers/migrations/0080-video-channels.ts
index 5512bdcf1..b8e9bd6d0 100644
--- a/server/initializers/migrations/0080-video-channels.ts
+++ b/server/initializers/migrations/0080-video-channels.ts
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize'
2import * as uuidv4 from 'uuid/v4' 2import * as uuidv4 from 'uuid/v4'
3 3
4async function up (utils: { 4async function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize, 7 sequelize: Sequelize.Sequelize
8 db: any 8 db: any
9}): Promise<void> { 9}): Promise<void> {
10 const q = utils.queryInterface 10 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0085-user-role.ts b/server/initializers/migrations/0085-user-role.ts
index de75faec2..ec7428fd5 100644
--- a/server/initializers/migrations/0085-user-role.ts
+++ b/server/initializers/migrations/0085-user-role.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0090-videos-description.ts b/server/initializers/migrations/0090-videos-description.ts
index 6f98dcade..32e518d75 100644
--- a/server/initializers/migrations/0090-videos-description.ts
+++ b/server/initializers/migrations/0090-videos-description.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0095-videos-privacy.ts b/server/initializers/migrations/0095-videos-privacy.ts
index 4c2bf91d0..c732d6f6a 100644
--- a/server/initializers/migrations/0095-videos-privacy.ts
+++ b/server/initializers/migrations/0095-videos-privacy.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0100-activitypub.ts b/server/initializers/migrations/0100-activitypub.ts
index 96d44a7ce..05fd37406 100644
--- a/server/initializers/migrations/0100-activitypub.ts
+++ b/server/initializers/migrations/0100-activitypub.ts
@@ -7,9 +7,9 @@ import { ApplicationModel } from '../../models/application/application'
7import { SERVER_ACTOR_NAME } from '../constants' 7import { SERVER_ACTOR_NAME } from '../constants'
8 8
9async function up (utils: { 9async function up (utils: {
10 transaction: Sequelize.Transaction, 10 transaction: Sequelize.Transaction
11 queryInterface: Sequelize.QueryInterface, 11 queryInterface: Sequelize.QueryInterface
12 sequelize: Sequelize.Sequelize, 12 sequelize: Sequelize.Sequelize
13 db: any 13 db: any
14}): Promise<void> { 14}): Promise<void> {
15 const q = utils.queryInterface 15 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0105-server-mail.ts b/server/initializers/migrations/0105-server-mail.ts
index 4b9600e91..5ee37c418 100644
--- a/server/initializers/migrations/0105-server-mail.ts
+++ b/server/initializers/migrations/0105-server-mail.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 await utils.queryInterface.removeColumn('Servers', 'email') 9 await utils.queryInterface.removeColumn('Servers', 'email')
diff --git a/server/initializers/migrations/0110-server-key.ts b/server/initializers/migrations/0110-server-key.ts
index 5ff6daf69..354cd7e76 100644
--- a/server/initializers/migrations/0110-server-key.ts
+++ b/server/initializers/migrations/0110-server-key.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 await utils.queryInterface.removeColumn('Servers', 'publicKey') 9 await utils.queryInterface.removeColumn('Servers', 'publicKey')
diff --git a/server/initializers/migrations/0115-account-avatar.ts b/server/initializers/migrations/0115-account-avatar.ts
index b318e8163..604b6394a 100644
--- a/server/initializers/migrations/0115-account-avatar.ts
+++ b/server/initializers/migrations/0115-account-avatar.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 await utils.db.Avatar.sync() 9 await utils.db.Avatar.sync()
diff --git a/server/initializers/migrations/0120-video-null.ts b/server/initializers/migrations/0120-video-null.ts
index 6d253f04f..1b407b270 100644
--- a/server/initializers/migrations/0120-video-null.ts
+++ b/server/initializers/migrations/0120-video-null.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 9
diff --git a/server/initializers/migrations/0125-table-lowercase.ts b/server/initializers/migrations/0125-table-lowercase.ts
index 78041ccb0..f75a56791 100644
--- a/server/initializers/migrations/0125-table-lowercase.ts
+++ b/server/initializers/migrations/0125-table-lowercase.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 await utils.queryInterface.renameTable('Applications', 'application') 8 await utils.queryInterface.renameTable('Applications', 'application')
diff --git a/server/initializers/migrations/0130-user-autoplay-video.ts b/server/initializers/migrations/0130-user-autoplay-video.ts
index 9f6878e39..d57934588 100644
--- a/server/initializers/migrations/0130-user-autoplay-video.ts
+++ b/server/initializers/migrations/0130-user-autoplay-video.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3 3
4function up (utils: { 4function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const q = utils.queryInterface 9 const q = utils.queryInterface
diff --git a/server/initializers/migrations/0135-video-channel-actor.ts b/server/initializers/migrations/0135-video-channel-actor.ts
index 5ace0f4d2..c0c343384 100644
--- a/server/initializers/migrations/0135-video-channel-actor.ts
+++ b/server/initializers/migrations/0135-video-channel-actor.ts
@@ -3,8 +3,8 @@ import { DataType } from 'sequelize-typescript'
3import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' 3import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
4 4
5async function up (utils: { 5async function up (utils: {
6 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction
7 queryInterface: Sequelize.QueryInterface, 7 queryInterface: Sequelize.QueryInterface
8 sequelize: Sequelize.Sequelize 8 sequelize: Sequelize.Sequelize
9}): Promise<void> { 9}): Promise<void> {
10 // Create actor table 10 // Create actor table
@@ -64,10 +64,10 @@ async function up (utils: {
64 type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", 64 type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
65 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" 65 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
66 ) 66 )
67 SELECT 67 SELECT
68 'Application', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", 68 'Application', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
69 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" 69 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
70 FROM account 70 FROM account
71 WHERE "applicationId" IS NOT NULL 71 WHERE "applicationId" IS NOT NULL
72 ` 72 `
73 await utils.sequelize.query(query1) 73 await utils.sequelize.query(query1)
@@ -79,10 +79,10 @@ async function up (utils: {
79 type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", 79 type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
80 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" 80 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
81 ) 81 )
82 SELECT 82 SELECT
83 'Person', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", 83 'Person', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
84 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" 84 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
85 FROM account 85 FROM account
86 WHERE "applicationId" IS NULL 86 WHERE "applicationId" IS NULL
87 ` 87 `
88 await utils.sequelize.query(query2) 88 await utils.sequelize.query(query2)
@@ -108,17 +108,17 @@ async function up (utils: {
108 } 108 }
109 109
110 { 110 {
111 const query = ` 111 const query = `
112 INSERT INTO actor 112 INSERT INTO actor
113 ( 113 (
114 type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", 114 type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
115 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" 115 "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
116 ) 116 )
117 SELECT 117 SELECT
118 'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox', 118 'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox',
119 "videoChannel".url || '/outbox', "videoChannel".url || '/inbox', "videoChannel".url || '/followers', "videoChannel".url || '/following', 119 "videoChannel".url || '/outbox', "videoChannel".url || '/inbox', "videoChannel".url || '/followers', "videoChannel".url || '/following',
120 null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt" 120 null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt"
121 FROM "videoChannel" 121 FROM "videoChannel"
122 INNER JOIN "account" on "videoChannel"."accountId" = "account".id 122 INNER JOIN "account" on "videoChannel"."accountId" = "account".id
123 ` 123 `
124 await utils.sequelize.query(query) 124 await utils.sequelize.query(query)
@@ -157,13 +157,13 @@ async function up (utils: {
157 } 157 }
158 158
159 { 159 {
160 const query1 = `UPDATE "actorFollow" 160 const query1 = `UPDATE "actorFollow"
161 SET "actorId" = 161 SET "actorId" =
162 (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."actorId")` 162 (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."actorId")`
163 await utils.sequelize.query(query1) 163 await utils.sequelize.query(query1)
164 164
165 const query2 = `UPDATE "actorFollow" 165 const query2 = `UPDATE "actorFollow"
166 SET "targetActorId" = 166 SET "targetActorId" =
167 (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."targetActorId")` 167 (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."targetActorId")`
168 168
169 await utils.sequelize.query(query2) 169 await utils.sequelize.query(query2)
@@ -189,8 +189,8 @@ async function up (utils: {
189 await utils.queryInterface.removeConstraint('videoShare', 'videoShare_accountId_fkey') 189 await utils.queryInterface.removeConstraint('videoShare', 'videoShare_accountId_fkey')
190 } 190 }
191 191
192 const query = `UPDATE "videoShare" 192 const query = `UPDATE "videoShare"
193 SET "actorId" = 193 SET "actorId" =
194 (SELECT "actorId" FROM account WHERE id = "videoShare"."actorId")` 194 (SELECT "actorId" FROM account WHERE id = "videoShare"."actorId")`
195 await utils.sequelize.query(query) 195 await utils.sequelize.query(query)
196 196
diff --git a/server/initializers/migrations/0140-actor-url.ts b/server/initializers/migrations/0140-actor-url.ts
index 020499391..d790988ad 100644
--- a/server/initializers/migrations/0140-actor-url.ts
+++ b/server/initializers/migrations/0140-actor-url.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import { WEBSERVER } from '../constants' 2import { WEBSERVER } from '../constants'
3 3
4async function up (utils: { 4async function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const toReplace = WEBSERVER.HOSTNAME + ':443' 9 const toReplace = WEBSERVER.HOSTNAME + ':443'
diff --git a/server/initializers/migrations/0145-delete-author.ts b/server/initializers/migrations/0145-delete-author.ts
index cb23d1cc2..6c9427997 100644
--- a/server/initializers/migrations/0145-delete-author.ts
+++ b/server/initializers/migrations/0145-delete-author.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 await utils.queryInterface.dropTable('Authors') 8 await utils.queryInterface.dropTable('Authors')
diff --git a/server/initializers/migrations/0150-avatar-cascade.ts b/server/initializers/migrations/0150-avatar-cascade.ts
index 821696717..fb3b25773 100644
--- a/server/initializers/migrations/0150-avatar-cascade.ts
+++ b/server/initializers/migrations/0150-avatar-cascade.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey') 8 await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey')
diff --git a/server/initializers/migrations/0155-video-comments-enabled.ts b/server/initializers/migrations/0155-video-comments-enabled.ts
index 6949d3a0c..691640b35 100644
--- a/server/initializers/migrations/0155-video-comments-enabled.ts
+++ b/server/initializers/migrations/0155-video-comments-enabled.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import { Migration } from '../../models/migrations' 2import { Migration } from '../../models/migrations'
3 3
4async function up (utils: { 4async function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const data = { 9 const data = {
diff --git a/server/initializers/migrations/0160-account-route.ts b/server/initializers/migrations/0160-account-route.ts
index cab4c72f1..97469948b 100644
--- a/server/initializers/migrations/0160-account-route.ts
+++ b/server/initializers/migrations/0160-account-route.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 { 8 {
diff --git a/server/initializers/migrations/0165-video-route.ts b/server/initializers/migrations/0165-video-route.ts
index 56d98bc69..aa7c75128 100644
--- a/server/initializers/migrations/0165-video-route.ts
+++ b/server/initializers/migrations/0165-video-route.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 { 8 {
diff --git a/server/initializers/migrations/0170-actor-follow-score.ts b/server/initializers/migrations/0170-actor-follow-score.ts
index a12b35da9..901a3c799 100644
--- a/server/initializers/migrations/0170-actor-follow-score.ts
+++ b/server/initializers/migrations/0170-actor-follow-score.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import { ACTOR_FOLLOW_SCORE } from '../constants' 2import { ACTOR_FOLLOW_SCORE } from '../constants'
3 3
4async function up (utils: { 4async function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 await utils.queryInterface.removeColumn('server', 'score') 9 await utils.queryInterface.removeColumn('server', 'score')
diff --git a/server/initializers/migrations/0175-actor-follow-counts.ts b/server/initializers/migrations/0175-actor-follow-counts.ts
index 4fb524181..d7853f8dc 100644
--- a/server/initializers/migrations/0175-actor-follow-counts.ts
+++ b/server/initializers/migrations/0175-actor-follow-counts.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 const query = 'UPDATE "actor" SET ' + 8 const query = 'UPDATE "actor" SET ' +
diff --git a/server/initializers/migrations/0180-job-table-delete.ts b/server/initializers/migrations/0180-job-table-delete.ts
index df29145d0..fb48a0c9d 100644
--- a/server/initializers/migrations/0180-job-table-delete.ts
+++ b/server/initializers/migrations/0180-job-table-delete.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 await utils.queryInterface.dropTable('job') 8 await utils.queryInterface.dropTable('job')
diff --git a/server/initializers/migrations/0185-video-share-url.ts b/server/initializers/migrations/0185-video-share-url.ts
index f7eeb0878..f59931e0f 100644
--- a/server/initializers/migrations/0185-video-share-url.ts
+++ b/server/initializers/migrations/0185-video-share-url.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 { 8 {
diff --git a/server/initializers/migrations/0190-video-comment-unique-url.ts b/server/initializers/migrations/0190-video-comment-unique-url.ts
index b196c9352..a8769ed41 100644
--- a/server/initializers/migrations/0190-video-comment-unique-url.ts
+++ b/server/initializers/migrations/0190-video-comment-unique-url.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 { 8 {
diff --git a/server/initializers/migrations/0195-support.ts b/server/initializers/migrations/0195-support.ts
index 3b9eabe79..3f7c75dce 100644
--- a/server/initializers/migrations/0195-support.ts
+++ b/server/initializers/migrations/0195-support.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 { 8 {
diff --git a/server/initializers/migrations/0200-video-published-at.ts b/server/initializers/migrations/0200-video-published-at.ts
index 1701ea07a..d8c7b42a7 100644
--- a/server/initializers/migrations/0200-video-published-at.ts
+++ b/server/initializers/migrations/0200-video-published-at.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 8
diff --git a/server/initializers/migrations/0205-user-nsfw-policy.ts b/server/initializers/migrations/0205-user-nsfw-policy.ts
index d0f6e8962..9c2786f12 100644
--- a/server/initializers/migrations/0205-user-nsfw-policy.ts
+++ b/server/initializers/migrations/0205-user-nsfw-policy.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 8
diff --git a/server/initializers/migrations/0210-video-language.ts b/server/initializers/migrations/0210-video-language.ts
index ca95c7527..ee4ce9266 100644
--- a/server/initializers/migrations/0210-video-language.ts
+++ b/server/initializers/migrations/0210-video-language.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import { CONSTRAINTS_FIELDS } from '../constants' 2import { CONSTRAINTS_FIELDS } from '../constants'
3 3
4async function up (utils: { 4async function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 9
diff --git a/server/initializers/migrations/0215-video-support-length.ts b/server/initializers/migrations/0215-video-support-length.ts
index ba395050f..26c0ca700 100644
--- a/server/initializers/migrations/0215-video-support-length.ts
+++ b/server/initializers/migrations/0215-video-support-length.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 { 8 {
diff --git a/server/initializers/migrations/0255-video-blacklist-reason.ts b/server/initializers/migrations/0255-video-blacklist-reason.ts
index 69d6efb9e..7de982f93 100644
--- a/server/initializers/migrations/0255-video-blacklist-reason.ts
+++ b/server/initializers/migrations/0255-video-blacklist-reason.ts
@@ -1,5 +1,4 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { VideoAbuseState } from '../../../shared/models/videos'
3 2
4async function up (utils: { 3async function up (utils: {
5 transaction: Sequelize.Transaction 4 transaction: Sequelize.Transaction
diff --git a/server/initializers/migrations/0285-description-support.ts b/server/initializers/migrations/0285-description-support.ts
index 85ef4ef39..aab3a938f 100644
--- a/server/initializers/migrations/0285-description-support.ts
+++ b/server/initializers/migrations/0285-description-support.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0290-account-video-rate-url.ts b/server/initializers/migrations/0290-account-video-rate-url.ts
index bdabf2929..b974b1a81 100644
--- a/server/initializers/migrations/0290-account-video-rate-url.ts
+++ b/server/initializers/migrations/0290-account-video-rate-url.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0295-video-file-extname.ts b/server/initializers/migrations/0295-video-file-extname.ts
index dbf249f66..e1999b072 100644
--- a/server/initializers/migrations/0295-video-file-extname.ts
+++ b/server/initializers/migrations/0295-video-file-extname.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0300-user-videos-history-enabled.ts b/server/initializers/migrations/0300-user-videos-history-enabled.ts
index aa5fc21fb..5e35e14ba 100644
--- a/server/initializers/migrations/0300-user-videos-history-enabled.ts
+++ b/server/initializers/migrations/0300-user-videos-history-enabled.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0305-fix-unfederated-videos.ts b/server/initializers/migrations/0305-fix-unfederated-videos.ts
index be206601f..9c5d56b7b 100644
--- a/server/initializers/migrations/0305-fix-unfederated-videos.ts
+++ b/server/initializers/migrations/0305-fix-unfederated-videos.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0310-drop-unused-video-indexes.ts b/server/initializers/migrations/0310-drop-unused-video-indexes.ts
index d51f430c0..181858d3d 100644
--- a/server/initializers/migrations/0310-drop-unused-video-indexes.ts
+++ b/server/initializers/migrations/0310-drop-unused-video-indexes.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const indexNames = [ 9 const indexNames = [
diff --git a/server/initializers/migrations/0315-user-notifications.ts b/server/initializers/migrations/0315-user-notifications.ts
index 8284c58a0..0e3f4fbef 100644
--- a/server/initializers/migrations/0315-user-notifications.ts
+++ b/server/initializers/migrations/0315-user-notifications.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 8
diff --git a/server/initializers/migrations/0320-blacklist-unfederate.ts b/server/initializers/migrations/0320-blacklist-unfederate.ts
index 6fb7bbb90..41de41c55 100644
--- a/server/initializers/migrations/0320-blacklist-unfederate.ts
+++ b/server/initializers/migrations/0320-blacklist-unfederate.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 8
diff --git a/server/initializers/migrations/0325-video-abuse-fields.ts b/server/initializers/migrations/0325-video-abuse-fields.ts
index fca6d666f..d88724a20 100644
--- a/server/initializers/migrations/0325-video-abuse-fields.ts
+++ b/server/initializers/migrations/0325-video-abuse-fields.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 8
diff --git a/server/initializers/migrations/0330-video-streaming-playlist.ts b/server/initializers/migrations/0330-video-streaming-playlist.ts
index c85a762ab..f75541a7f 100644
--- a/server/initializers/migrations/0330-video-streaming-playlist.ts
+++ b/server/initializers/migrations/0330-video-streaming-playlist.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 8
diff --git a/server/initializers/migrations/0335-video-downloading-enabled.ts b/server/initializers/migrations/0335-video-downloading-enabled.ts
index e79466447..c745f1f02 100644
--- a/server/initializers/migrations/0335-video-downloading-enabled.ts
+++ b/server/initializers/migrations/0335-video-downloading-enabled.ts
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
2import { Migration } from '../../models/migrations' 2import { Migration } from '../../models/migrations'
3 3
4async function up (utils: { 4async function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize 7 sequelize: Sequelize.Sequelize
8}): Promise<void> { 8}): Promise<void> {
9 const data = { 9 const data = {
diff --git a/server/initializers/migrations/0340-add-originally-published-at.ts b/server/initializers/migrations/0340-add-originally-published-at.ts
index fe4f4a5f9..7cbc14ab5 100644
--- a/server/initializers/migrations/0340-add-originally-published-at.ts
+++ b/server/initializers/migrations/0340-add-originally-published-at.ts
@@ -1,8 +1,8 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize 6 sequelize: Sequelize.Sequelize
7}): Promise<void> { 7}): Promise<void> {
8 8
diff --git a/server/initializers/migrations/0345-video-playlists.ts b/server/initializers/migrations/0345-video-playlists.ts
index de69f5b9e..76813f93f 100644
--- a/server/initializers/migrations/0345-video-playlists.ts
+++ b/server/initializers/migrations/0345-video-playlists.ts
@@ -4,8 +4,8 @@ import * as uuidv4 from 'uuid/v4'
4import { WEBSERVER } from '../constants' 4import { WEBSERVER } from '../constants'
5 5
6async function up (utils: { 6async function up (utils: {
7 transaction: Sequelize.Transaction, 7 transaction: Sequelize.Transaction
8 queryInterface: Sequelize.QueryInterface, 8 queryInterface: Sequelize.QueryInterface
9 sequelize: Sequelize.Sequelize 9 sequelize: Sequelize.Sequelize
10}): Promise<void> { 10}): Promise<void> {
11 const transaction = utils.transaction 11 const transaction = utils.transaction
diff --git a/server/initializers/migrations/0350-video-blacklist-type.ts b/server/initializers/migrations/0350-video-blacklist-type.ts
index 4849020ef..f79ae5ec7 100644
--- a/server/initializers/migrations/0350-video-blacklist-type.ts
+++ b/server/initializers/migrations/0350-video-blacklist-type.ts
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize'
2import { VideoBlacklistType } from '../../../shared/models/videos' 2import { VideoBlacklistType } from '../../../shared/models/videos'
3 3
4async function up (utils: { 4async function up (utils: {
5 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface, 6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize, 7 sequelize: Sequelize.Sequelize
8 db: any 8 db: any
9}): Promise<void> { 9}): Promise<void> {
10 { 10 {
diff --git a/server/initializers/migrations/0355-p2p-peer-version.ts b/server/initializers/migrations/0355-p2p-peer-version.ts
index 18f23d9b7..89af28d07 100644
--- a/server/initializers/migrations/0355-p2p-peer-version.ts
+++ b/server/initializers/migrations/0355-p2p-peer-version.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 9
diff --git a/server/initializers/migrations/0360-notification-instance-follower.ts b/server/initializers/migrations/0360-notification-instance-follower.ts
index 05caf8e1d..6f9a01a9c 100644
--- a/server/initializers/migrations/0360-notification-instance-follower.ts
+++ b/server/initializers/migrations/0360-notification-instance-follower.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0365-user-admin-flags.ts b/server/initializers/migrations/0365-user-admin-flags.ts
index 20553100a..b705387da 100644
--- a/server/initializers/migrations/0365-user-admin-flags.ts
+++ b/server/initializers/migrations/0365-user-admin-flags.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0370-thumbnail.ts b/server/initializers/migrations/0370-thumbnail.ts
index 384ca1a15..07c25436a 100644
--- a/server/initializers/migrations/0370-thumbnail.ts
+++ b/server/initializers/migrations/0370-thumbnail.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0375-account-description.ts b/server/initializers/migrations/0375-account-description.ts
index 1258563fd..f9af942e0 100644
--- a/server/initializers/migrations/0375-account-description.ts
+++ b/server/initializers/migrations/0375-account-description.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const data = { 9 const data = {
diff --git a/server/initializers/migrations/0380-cleanup-timestamps.ts b/server/initializers/migrations/0380-cleanup-timestamps.ts
index 2a9fd6f02..18ecfb997 100644
--- a/server/initializers/migrations/0380-cleanup-timestamps.ts
+++ b/server/initializers/migrations/0380-cleanup-timestamps.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 try { 9 try {
diff --git a/server/initializers/migrations/0385-remove-actor-uuid.ts b/server/initializers/migrations/0385-remove-actor-uuid.ts
index 032c0562b..eefbc386b 100644
--- a/server/initializers/migrations/0385-remove-actor-uuid.ts
+++ b/server/initializers/migrations/0385-remove-actor-uuid.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 await utils.queryInterface.removeColumn('actor', 'uuid') 9 await utils.queryInterface.removeColumn('actor', 'uuid')
diff --git a/server/initializers/migrations/0390-user-pending-email.ts b/server/initializers/migrations/0390-user-pending-email.ts
index 5ca871746..9cf0affa5 100644
--- a/server/initializers/migrations/0390-user-pending-email.ts
+++ b/server/initializers/migrations/0390-user-pending-email.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const data = { 9 const data = {
diff --git a/server/initializers/migrations/0395-user-video-languages.ts b/server/initializers/migrations/0395-user-video-languages.ts
index 278698bf4..9c24fbc9a 100644
--- a/server/initializers/migrations/0395-user-video-languages.ts
+++ b/server/initializers/migrations/0395-user-video-languages.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const data = { 9 const data = {
diff --git a/server/initializers/migrations/0400-user-theme.ts b/server/initializers/migrations/0400-user-theme.ts
index f74d76115..7addb1bb3 100644
--- a/server/initializers/migrations/0400-user-theme.ts
+++ b/server/initializers/migrations/0400-user-theme.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const data = { 9 const data = {
diff --git a/server/initializers/migrations/0405-plugin.ts b/server/initializers/migrations/0405-plugin.ts
index c55b81960..5c290b986 100644
--- a/server/initializers/migrations/0405-plugin.ts
+++ b/server/initializers/migrations/0405-plugin.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0410-video-playlist-element.ts b/server/initializers/migrations/0410-video-playlist-element.ts
index f536632a2..1b4692357 100644
--- a/server/initializers/migrations/0410-video-playlist-element.ts
+++ b/server/initializers/migrations/0410-video-playlist-element.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0415-thumbnail-auto-generated.ts b/server/initializers/migrations/0415-thumbnail-auto-generated.ts
index f822a4c05..98d563c88 100644
--- a/server/initializers/migrations/0415-thumbnail-auto-generated.ts
+++ b/server/initializers/migrations/0415-thumbnail-auto-generated.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0420-avatar-lazy.ts b/server/initializers/migrations/0420-avatar-lazy.ts
index 5fc57aac2..5c74819d2 100644
--- a/server/initializers/migrations/0420-avatar-lazy.ts
+++ b/server/initializers/migrations/0420-avatar-lazy.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0425-nullable-actor-fields.ts b/server/initializers/migrations/0425-nullable-actor-fields.ts
index 4e5f9e6ab..720b99ccc 100644
--- a/server/initializers/migrations/0425-nullable-actor-fields.ts
+++ b/server/initializers/migrations/0425-nullable-actor-fields.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 const data = { 9 const data = {
diff --git a/server/initializers/migrations/0430-auto-follow-notification-setting.ts b/server/initializers/migrations/0430-auto-follow-notification-setting.ts
index 034bdd46d..1734828a4 100644
--- a/server/initializers/migrations/0430-auto-follow-notification-setting.ts
+++ b/server/initializers/migrations/0430-auto-follow-notification-setting.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0435-user-modals.ts b/server/initializers/migrations/0435-user-modals.ts
index 5c2aa85b5..737440e9b 100644
--- a/server/initializers/migrations/0435-user-modals.ts
+++ b/server/initializers/migrations/0435-user-modals.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0440-user-auto-play-next-video.ts b/server/initializers/migrations/0440-user-auto-play-next-video.ts
index f0baafe7b..f3f663f59 100644
--- a/server/initializers/migrations/0440-user-auto-play-next-video.ts
+++ b/server/initializers/migrations/0440-user-auto-play-next-video.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0445-shared-inbox-optional.ts b/server/initializers/migrations/0445-shared-inbox-optional.ts
index dad2d6569..ade1a2a57 100644
--- a/server/initializers/migrations/0445-shared-inbox-optional.ts
+++ b/server/initializers/migrations/0445-shared-inbox-optional.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0450-streaming-playlist-files.ts b/server/initializers/migrations/0450-streaming-playlist-files.ts
index 460dac8be..08e2e3989 100644
--- a/server/initializers/migrations/0450-streaming-playlist-files.ts
+++ b/server/initializers/migrations/0450-streaming-playlist-files.ts
@@ -1,15 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { join } from 'path'
3import { HLS_STREAMING_PLAYLIST_DIRECTORY, WEBSERVER } from '@server/initializers/constants'
4import { CONFIG } from '@server/initializers/config'
5import { pathExists, stat, writeFile } from 'fs-extra'
6import * as parseTorrent from 'parse-torrent'
7import { createTorrentPromise } from '@server/helpers/webtorrent'
8 2
9async function up (utils: { 3async function up (utils: {
10 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
11 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
12 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
13 db: any 7 db: any
14}): Promise<void> { 8}): Promise<void> {
15 { 9 {
@@ -42,8 +36,8 @@ async function up (utils: {
42 { 36 {
43 const query = 'insert into "videoFile" ' + 37 const query = 'insert into "videoFile" ' +
44 '(resolution, size, "infoHash", "videoId", "createdAt", "updatedAt", fps, extname, "videoStreamingPlaylistId")' + 38 '(resolution, size, "infoHash", "videoId", "createdAt", "updatedAt", fps, extname, "videoStreamingPlaylistId")' +
45 '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", "videoFile"."fps", ' + 39 '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", ' +
46 '"videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' + 40 '"videoFile"."fps", "videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' +
47 'inner join video ON video.id = "videoStreamingPlaylist"."videoId" inner join "videoFile" ON "videoFile"."videoId" = video.id)' 41 'inner join video ON video.id = "videoStreamingPlaylist"."videoId" inner join "videoFile" ON "videoFile"."videoId" = video.id)'
48 42
49 await utils.sequelize.query(query, { transaction: utils.transaction }) 43 await utils.sequelize.query(query, { transaction: utils.transaction })
diff --git a/server/initializers/migrations/0455-soft-delete-video-comments.ts b/server/initializers/migrations/0455-soft-delete-video-comments.ts
index bcfb97b56..00e56015f 100644
--- a/server/initializers/migrations/0455-soft-delete-video-comments.ts
+++ b/server/initializers/migrations/0455-soft-delete-video-comments.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0460-user-playlist-autoplay.ts b/server/initializers/migrations/0460-user-playlist-autoplay.ts
index 3067ac1a4..d6f5081ab 100644
--- a/server/initializers/migrations/0460-user-playlist-autoplay.ts
+++ b/server/initializers/migrations/0460-user-playlist-autoplay.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0465-thumbnail-file-url-length.ts b/server/initializers/migrations/0465-thumbnail-file-url-length.ts
index db8c85c29..84a4fa0ba 100644
--- a/server/initializers/migrations/0465-thumbnail-file-url-length.ts
+++ b/server/initializers/migrations/0465-thumbnail-file-url-length.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0470-cleaup-indexes.ts b/server/initializers/migrations/0470-cleaup-indexes.ts
index 53e401c2b..7365c30f8 100644
--- a/server/initializers/migrations/0470-cleaup-indexes.ts
+++ b/server/initializers/migrations/0470-cleaup-indexes.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 await utils.sequelize.query('DROP INDEX IF EXISTS video_share_account_id;') 9 await utils.sequelize.query('DROP INDEX IF EXISTS video_share_account_id;')
diff --git a/server/initializers/migrations/0475-redundancy-expires-on.ts b/server/initializers/migrations/0475-redundancy-expires-on.ts
index 7e392c8c0..edbddba37 100644
--- a/server/initializers/migrations/0475-redundancy-expires-on.ts
+++ b/server/initializers/migrations/0475-redundancy-expires-on.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrations/0480-caption-file-url.ts b/server/initializers/migrations/0480-caption-file-url.ts
index 7d8a3d4b9..1f88206d3 100644
--- a/server/initializers/migrations/0480-caption-file-url.ts
+++ b/server/initializers/migrations/0480-caption-file-url.ts
@@ -1,9 +1,9 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2 2
3async function up (utils: { 3async function up (utils: {
4 transaction: Sequelize.Transaction, 4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface, 5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize, 6 sequelize: Sequelize.Sequelize
7 db: any 7 db: any
8}): Promise<void> { 8}): Promise<void> {
9 { 9 {
diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts
index 1cb0116b7..77203ae24 100644
--- a/server/initializers/migrator.ts
+++ b/server/initializers/migrator.ts
@@ -20,7 +20,7 @@ async function migrate () {
20 } 20 }
21 21
22 const rows = await sequelizeTypescript.query<{ migrationVersion: number }>(query, options) 22 const rows = await sequelizeTypescript.query<{ migrationVersion: number }>(query, options)
23 if (rows && rows[0] && rows[0].migrationVersion) { 23 if (rows?.[0]?.migrationVersion) {
24 actualVersion = rows[0].migrationVersion 24 actualVersion = rows[0].migrationVersion
25 } 25 }
26 26
@@ -60,7 +60,7 @@ export {
60async function getMigrationScripts () { 60async function getMigrationScripts () {
61 const files = await readdir(path.join(__dirname, 'migrations')) 61 const files = await readdir(path.join(__dirname, 'migrations'))
62 const filesToMigrate: { 62 const filesToMigrate: {
63 version: string, 63 version: string
64 script: string 64 script: string
65 }[] = [] 65 }[] = []
66 66
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index f802658cf..3f6edc070 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -1,6 +1,6 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import { Transaction } from 'sequelize' 2import { Transaction } from 'sequelize'
3import * as url from 'url' 3import { URL } from 'url'
4import * as uuidv4 from 'uuid/v4' 4import * as uuidv4 from 'uuid/v4'
5import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' 5import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub'
6import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' 6import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects'
@@ -33,8 +33,7 @@ import {
33 MActorFull, 33 MActorFull,
34 MActorFullActor, 34 MActorFullActor,
35 MActorId, 35 MActorId,
36 MChannel, 36 MChannel
37 MChannelAccountDefault
38} from '../../typings/models' 37} from '../../typings/models'
39 38
40// Set account keys, this could be long so process after the account creation and do not block the client 39// Set account keys, this could be long so process after the account creation and do not block the client
@@ -121,13 +120,13 @@ async function getOrCreateActorAndServerAndModel (
121 120
122 if ((created === true || refreshed === true) && updateCollections === true) { 121 if ((created === true || refreshed === true) && updateCollections === true) {
123 const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } 122 const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' }
124 await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) 123 await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload })
125 } 124 }
126 125
127 // We created a new account: fetch the playlists 126 // We created a new account: fetch the playlists
128 if (created === true && actor.Account && accountPlaylistsUrl) { 127 if (created === true && actor.Account && accountPlaylistsUrl) {
129 const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' } 128 const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' }
130 await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) 129 await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload })
131 } 130 }
132 131
133 return actorRefreshed 132 return actorRefreshed
@@ -215,7 +214,7 @@ async function fetchActorTotalItems (url: string) {
215 } 214 }
216} 215}
217 216
218async function getAvatarInfoIfExists (actorJSON: ActivityPubActor) { 217function getAvatarInfoIfExists (actorJSON: ActivityPubActor) {
219 if ( 218 if (
220 actorJSON.icon && actorJSON.icon.type === 'Image' && MIMETYPES.IMAGE.MIMETYPE_EXT[actorJSON.icon.mediaType] !== undefined && 219 actorJSON.icon && actorJSON.icon.type === 'Image' && MIMETYPES.IMAGE.MIMETYPE_EXT[actorJSON.icon.mediaType] !== undefined &&
221 isActivityPubUrlValid(actorJSON.icon.url) 220 isActivityPubUrlValid(actorJSON.icon.url)
@@ -271,7 +270,10 @@ async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannel
271 270
272 if (statusCode === 404) { 271 if (statusCode === 404) {
273 logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) 272 logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url)
274 actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy() 273 actor.Account
274 ? await actor.Account.destroy()
275 : await actor.VideoChannel.destroy()
276
275 return { actor: undefined, refreshed: false } 277 return { actor: undefined, refreshed: false }
276 } 278 }
277 279
@@ -337,14 +339,14 @@ function saveActorAndServerAndModelIfNotExist (
337 ownerActor?: MActorFullActor, 339 ownerActor?: MActorFullActor,
338 t?: Transaction 340 t?: Transaction
339): Bluebird<MActorFullActor> | Promise<MActorFullActor> { 341): Bluebird<MActorFullActor> | Promise<MActorFullActor> {
340 let actor = result.actor 342 const actor = result.actor
341 343
342 if (t !== undefined) return save(t) 344 if (t !== undefined) return save(t)
343 345
344 return sequelizeTypescript.transaction(t => save(t)) 346 return sequelizeTypescript.transaction(t => save(t))
345 347
346 async function save (t: Transaction) { 348 async function save (t: Transaction) {
347 const actorHost = url.parse(actor.url).host 349 const actorHost = new URL(actor.url).host
348 350
349 const serverOptions = { 351 const serverOptions = {
350 where: { 352 where: {
@@ -402,7 +404,7 @@ type FetchRemoteActorResult = {
402 support?: string 404 support?: string
403 playlists?: string 405 playlists?: string
404 avatar?: { 406 avatar?: {
405 name: string, 407 name: string
406 fileUrl: string 408 fileUrl: string
407 } 409 }
408 attributedTo: ActivityPubAttributedTo[] 410 attributedTo: ActivityPubAttributedTo[]
diff --git a/server/lib/activitypub/crawl.ts b/server/lib/activitypub/crawl.ts
index 9e469e3e6..eeafdf4ba 100644
--- a/server/lib/activitypub/crawl.ts
+++ b/server/lib/activitypub/crawl.ts
@@ -3,7 +3,7 @@ import { doRequest } from '../../helpers/requests'
3import { logger } from '../../helpers/logger' 3import { logger } from '../../helpers/logger'
4import * as Bluebird from 'bluebird' 4import * as Bluebird from 'bluebird'
5import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub' 5import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub'
6import { parse } from 'url' 6import { URL } from 'url'
7 7
8type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>) 8type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>)
9type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>) 9type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>)
@@ -24,7 +24,7 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T>
24 const response = await doRequest<ActivityPubOrderedCollection<T>>(options) 24 const response = await doRequest<ActivityPubOrderedCollection<T>>(options)
25 const firstBody = response.body 25 const firstBody = response.body
26 26
27 let limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT 27 const limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT
28 let i = 0 28 let i = 0
29 let nextLink = firstBody.first 29 let nextLink = firstBody.first
30 while (nextLink && i < limit) { 30 while (nextLink && i < limit) {
@@ -32,7 +32,7 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T>
32 32
33 if (typeof nextLink === 'string') { 33 if (typeof nextLink === 'string') {
34 // Don't crawl ourselves 34 // Don't crawl ourselves
35 const remoteHost = parse(nextLink).host 35 const remoteHost = new URL(nextLink).host
36 if (remoteHost === WEBSERVER.HOST) continue 36 if (remoteHost === WEBSERVER.HOST) continue
37 37
38 options.uri = nextLink 38 options.uri = nextLink
diff --git a/server/lib/activitypub/follow.ts b/server/lib/activitypub/follow.ts
index 1abf43cd4..a1c95504e 100644
--- a/server/lib/activitypub/follow.ts
+++ b/server/lib/activitypub/follow.ts
@@ -27,7 +27,6 @@ async function autoFollowBackIfNeeded (actorFollow: MActorFollowActors) {
27 } 27 }
28 28
29 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) 29 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
30 .catch(err => logger.error('Cannot create auto follow back job for %s.', host, err))
31 } 30 }
32} 31}
33 32
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts
index 9f0225b64..c4c6b849b 100644
--- a/server/lib/activitypub/send/send-accept.ts
+++ b/server/lib/activitypub/send/send-accept.ts
@@ -5,7 +5,7 @@ import { buildFollowActivity } from './send-follow'
5import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
6import { MActor, MActorFollowActors } from '../../../typings/models' 6import { MActor, MActorFollowActors } from '../../../typings/models'
7 7
8async function sendAccept (actorFollow: MActorFollowActors) { 8function sendAccept (actorFollow: MActorFollowActors) {
9 const follower = actorFollow.ActorFollower 9 const follower = actorFollow.ActorFollower
10 const me = actorFollow.ActorFollowing 10 const me = actorFollow.ActorFollowing
11 11
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts
index 1709d8348..3585d704a 100644
--- a/server/lib/activitypub/send/send-create.ts
+++ b/server/lib/activitypub/send/send-create.ts
@@ -130,10 +130,10 @@ export {
130// --------------------------------------------------------------------------- 130// ---------------------------------------------------------------------------
131 131
132async function sendVideoRelatedCreateActivity (options: { 132async function sendVideoRelatedCreateActivity (options: {
133 byActor: MActorLight, 133 byActor: MActorLight
134 video: MVideoAccountLight, 134 video: MVideoAccountLight
135 url: string, 135 url: string
136 object: any, 136 object: any
137 transaction?: Transaction 137 transaction?: Transaction
138}) { 138}) {
139 const activityBuilder = (audience: ActivityAudience) => { 139 const activityBuilder = (audience: ActivityAudience) => {
diff --git a/server/lib/activitypub/send/send-dislike.ts b/server/lib/activitypub/send/send-dislike.ts
index 6e41f241f..600469c71 100644
--- a/server/lib/activitypub/send/send-dislike.ts
+++ b/server/lib/activitypub/send/send-dislike.ts
@@ -6,7 +6,7 @@ import { sendVideoRelatedActivity } from './utils'
6import { audiencify, getAudience } from '../audience' 6import { audiencify, getAudience } from '../audience'
7import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' 7import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models'
8 8
9async function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { 9function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
10 logger.info('Creating job to dislike %s.', video.url) 10 logger.info('Creating job to dislike %s.', video.url)
11 11
12 const activityBuilder = (audience: ActivityAudience) => { 12 const activityBuilder = (audience: ActivityAudience) => {
diff --git a/server/lib/activitypub/send/send-flag.ts b/server/lib/activitypub/send/send-flag.ts
index da7638a7b..e4e523631 100644
--- a/server/lib/activitypub/send/send-flag.ts
+++ b/server/lib/activitypub/send/send-flag.ts
@@ -7,7 +7,7 @@ import { Transaction } from 'sequelize'
7import { MActor, MVideoFullLight } from '../../../typings/models' 7import { MActor, MVideoFullLight } from '../../../typings/models'
8import { MVideoAbuseVideo } from '../../../typings/models/video' 8import { MVideoAbuseVideo } from '../../../typings/models/video'
9 9
10async function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) { 10function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) {
11 if (!video.VideoChannel.Account.Actor.serverId) return // Local user 11 if (!video.VideoChannel.Account.Actor.serverId) return // Local user
12 12
13 const url = getVideoAbuseActivityPubUrl(videoAbuse) 13 const url = getVideoAbuseActivityPubUrl(videoAbuse)
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts
index e84a6f98b..5db252325 100644
--- a/server/lib/activitypub/send/send-like.ts
+++ b/server/lib/activitypub/send/send-like.ts
@@ -6,7 +6,7 @@ import { audiencify, getAudience } from '../audience'
6import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
7import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' 7import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models'
8 8
9async function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { 9function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
10 logger.info('Creating job to like %s.', video.url) 10 logger.info('Creating job to like %s.', video.url)
11 11
12 const activityBuilder = (audience: ActivityAudience) => { 12 const activityBuilder = (audience: ActivityAudience) => {
diff --git a/server/lib/activitypub/send/send-reject.ts b/server/lib/activitypub/send/send-reject.ts
index 4258a3c36..643c468a9 100644
--- a/server/lib/activitypub/send/send-reject.ts
+++ b/server/lib/activitypub/send/send-reject.ts
@@ -5,7 +5,7 @@ import { buildFollowActivity } from './send-follow'
5import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
6import { MActor } from '../../../typings/models' 6import { MActor } from '../../../typings/models'
7 7
8async function sendReject (follower: MActor, following: MActor) { 8function sendReject (follower: MActor, following: MActor) {
9 if (!follower.serverId) { // This should never happen 9 if (!follower.serverId) { // This should never happen
10 logger.warn('Do not sending reject to local follower.') 10 logger.warn('Do not sending reject to local follower.')
11 return 11 return
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts
index e9ab5b3c5..33f1d4921 100644
--- a/server/lib/activitypub/send/send-undo.ts
+++ b/server/lib/activitypub/send/send-undo.ts
@@ -28,7 +28,7 @@ import {
28 MVideoShare 28 MVideoShare
29} from '../../../typings/models' 29} from '../../../typings/models'
30 30
31async function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) { 31function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) {
32 const me = actorFollow.ActorFollower 32 const me = actorFollow.ActorFollower
33 const following = actorFollow.ActorFollowing 33 const following = actorFollow.ActorFollowing
34 34
@@ -118,10 +118,10 @@ function undoActivityData (
118} 118}
119 119
120async function sendUndoVideoRelatedActivity (options: { 120async function sendUndoVideoRelatedActivity (options: {
121 byActor: MActor, 121 byActor: MActor
122 video: MVideoAccountLight, 122 video: MVideoAccountLight
123 url: string, 123 url: string
124 activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce, 124 activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce
125 transaction: Transaction 125 transaction: Transaction
126}) { 126}) {
127 const activityBuilder = (audience: ActivityAudience) => { 127 const activityBuilder = (audience: ActivityAudience) => {
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts
index 9c76671b5..cb500bd34 100644
--- a/server/lib/activitypub/send/send-update.ts
+++ b/server/lib/activitypub/send/send-update.ts
@@ -8,7 +8,6 @@ import { getUpdateActivityPubUrl } from '../url'
8import { broadcastToFollowers, sendVideoRelatedActivity } from './utils' 8import { broadcastToFollowers, sendVideoRelatedActivity } from './utils'
9import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience' 9import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience'
10import { logger } from '../../../helpers/logger' 10import { logger } from '../../../helpers/logger'
11import { VideoCaptionModel } from '../../../models/video/video-caption'
12import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' 11import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
13import { getServerActor } from '../../../helpers/utils' 12import { getServerActor } from '../../../helpers/utils'
14import { 13import {
@@ -29,7 +28,7 @@ async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction
29 28
30 logger.info('Creating job to update video %s.', video.url) 29 logger.info('Creating job to update video %s.', video.url)
31 30
32 const byActor = overrodeByActor ? overrodeByActor : video.VideoChannel.Account.Actor 31 const byActor = overrodeByActor || video.VideoChannel.Account.Actor
33 32
34 const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) 33 const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString())
35 34
diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts
index 77b723479..6fb4efd60 100644
--- a/server/lib/activitypub/send/utils.ts
+++ b/server/lib/activitypub/send/utils.ts
@@ -10,8 +10,8 @@ import { afterCommitIfTransaction } from '../../../helpers/database-utils'
10import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models' 10import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models'
11 11
12async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { 12async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
13 byActor: MActorLight, 13 byActor: MActorLight
14 video: MVideoAccountLight, 14 video: MVideoAccountLight
15 transaction?: Transaction 15 transaction?: Transaction
16}) { 16}) {
17 const { byActor, video, transaction } = options 17 const { byActor, video, transaction } = options
diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts
index d5c078a29..8642d2432 100644
--- a/server/lib/activitypub/video-comments.ts
+++ b/server/lib/activitypub/video-comments.ts
@@ -10,9 +10,9 @@ import { checkUrlsSameHost } from '../../helpers/activitypub'
10import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../typings/models/video' 10import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../typings/models/video'
11 11
12type ResolveThreadParams = { 12type ResolveThreadParams = {
13 url: string, 13 url: string
14 comments?: MCommentOwner[], 14 comments?: MCommentOwner[]
15 isVideo?: boolean, 15 isVideo?: boolean
16 commentCreated?: boolean 16 commentCreated?: boolean
17} 17}
18type ResolveThreadResult = Promise<{ video: MVideoAccountLightBlacklistAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }> 18type ResolveThreadResult = Promise<{ video: MVideoAccountLightBlacklistAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }>
@@ -28,7 +28,7 @@ async function resolveThread (params: ResolveThreadParams): ResolveThreadResult
28 if (params.commentCreated === undefined) params.commentCreated = false 28 if (params.commentCreated === undefined) params.commentCreated = false
29 if (params.comments === undefined) params.comments = [] 29 if (params.comments === undefined) params.comments = []
30 30
31 // Already have this comment? 31 // Already have this comment?
32 if (isVideo !== true) { 32 if (isVideo !== true) {
33 const result = await resolveCommentFromDB(params) 33 const result = await resolveCommentFromDB(params)
34 if (result) return result 34 if (result) return result
@@ -87,7 +87,7 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) {
87 87
88 let resultComment: MCommentOwnerVideo 88 let resultComment: MCommentOwnerVideo
89 if (comments.length !== 0) { 89 if (comments.length !== 0) {
90 const firstReply = comments[ comments.length - 1 ] as MCommentOwnerVideo 90 const firstReply = comments[comments.length - 1] as MCommentOwnerVideo
91 firstReply.inReplyToCommentId = null 91 firstReply.inReplyToCommentId = null
92 firstReply.originCommentId = null 92 firstReply.originCommentId = null
93 firstReply.videoId = video.id 93 firstReply.videoId = video.id
@@ -97,9 +97,9 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) {
97 comments[comments.length - 1] = await firstReply.save() 97 comments[comments.length - 1] = await firstReply.save()
98 98
99 for (let i = comments.length - 2; i >= 0; i--) { 99 for (let i = comments.length - 2; i >= 0; i--) {
100 const comment = comments[ i ] as MCommentOwnerVideo 100 const comment = comments[i] as MCommentOwnerVideo
101 comment.originCommentId = firstReply.id 101 comment.originCommentId = firstReply.id
102 comment.inReplyToCommentId = comments[ i + 1 ].id 102 comment.inReplyToCommentId = comments[i + 1].id
103 comment.videoId = video.id 103 comment.videoId = video.id
104 comment.changed('updatedAt', true) 104 comment.changed('updatedAt', true)
105 comment.Video = video 105 comment.Video = video
diff --git a/server/lib/activitypub/video-rates.ts b/server/lib/activitypub/video-rates.ts
index 6bd46bb58..79ccfbc7e 100644
--- a/server/lib/activitypub/video-rates.ts
+++ b/server/lib/activitypub/video-rates.ts
@@ -58,8 +58,6 @@ async function createRates (ratesUrl: string[], video: MVideo, rate: VideoRateTy
58 const field = rate === 'like' ? 'likes' : 'dislikes' 58 const field = rate === 'like' ? 'likes' : 'dislikes'
59 await video.increment(field, { by: rateCounts }) 59 await video.increment(field, { by: rateCounts })
60 } 60 }
61
62 return
63} 61}
64 62
65async function sendVideoRateChange ( 63async function sendVideoRateChange (
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index 6bc2258cc..9e43caa20 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -197,25 +197,25 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo
197 jobPayloads.push({ uri: fetchedVideo.comments, videoId: video.id, type: 'video-comments' as 'video-comments' }) 197 jobPayloads.push({ uri: fetchedVideo.comments, videoId: video.id, type: 'video-comments' as 'video-comments' })
198 } 198 }
199 199
200 await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })) 200 await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }))
201} 201}
202 202
203function getOrCreateVideoAndAccountAndChannel (options: { 203function getOrCreateVideoAndAccountAndChannel (options: {
204 videoObject: { id: string } | string, 204 videoObject: { id: string } | string
205 syncParam?: SyncParam, 205 syncParam?: SyncParam
206 fetchType?: 'all', 206 fetchType?: 'all'
207 allowRefresh?: boolean 207 allowRefresh?: boolean
208}): Promise<{ video: MVideoAccountLightBlacklistAllFiles, created: boolean, autoBlacklisted?: boolean }> 208}): Promise<{ video: MVideoAccountLightBlacklistAllFiles, created: boolean, autoBlacklisted?: boolean }>
209function getOrCreateVideoAndAccountAndChannel (options: { 209function getOrCreateVideoAndAccountAndChannel (options: {
210 videoObject: { id: string } | string, 210 videoObject: { id: string } | string
211 syncParam?: SyncParam, 211 syncParam?: SyncParam
212 fetchType?: VideoFetchByUrlType, 212 fetchType?: VideoFetchByUrlType
213 allowRefresh?: boolean 213 allowRefresh?: boolean
214}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> 214}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }>
215async function getOrCreateVideoAndAccountAndChannel (options: { 215async function getOrCreateVideoAndAccountAndChannel (options: {
216 videoObject: { id: string } | string, 216 videoObject: { id: string } | string
217 syncParam?: SyncParam, 217 syncParam?: SyncParam
218 fetchType?: VideoFetchByUrlType, 218 fetchType?: VideoFetchByUrlType
219 allowRefresh?: boolean // true by default 219 allowRefresh?: boolean // true by default
220}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> { 220}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> {
221 // Default params 221 // Default params
@@ -235,8 +235,14 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
235 syncParam 235 syncParam
236 } 236 }
237 237
238 if (syncParam.refreshVideo === true) videoFromDatabase = await refreshVideoIfNeeded(refreshOptions) 238 if (syncParam.refreshVideo === true) {
239 else await JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: videoFromDatabase.url } }) 239 videoFromDatabase = await refreshVideoIfNeeded(refreshOptions)
240 } else {
241 await JobQueue.Instance.createJobWithPromise({
242 type: 'activitypub-refresher',
243 payload: { type: 'video', url: videoFromDatabase.url }
244 })
245 }
240 } 246 }
241 247
242 return { video: videoFromDatabase, created: false } 248 return { video: videoFromDatabase, created: false }
@@ -255,10 +261,10 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
255} 261}
256 262
257async function updateVideoFromAP (options: { 263async function updateVideoFromAP (options: {
258 video: MVideoAccountLightBlacklistAllFiles, 264 video: MVideoAccountLightBlacklistAllFiles
259 videoObject: VideoTorrentObject, 265 videoObject: VideoTorrentObject
260 account: MAccountIdActor, 266 account: MAccountIdActor
261 channel: MChannelDefault, 267 channel: MChannelDefault
262 overrideTo?: string[] 268 overrideTo?: string[]
263}) { 269}) {
264 const { video, videoObject, account, channel, overrideTo } = options 270 const { video, videoObject, account, channel, overrideTo } = options
@@ -289,7 +295,7 @@ async function updateVideoFromAP (options: {
289 throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url) 295 throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url)
290 } 296 }
291 297
292 const to = overrideTo ? overrideTo : videoObject.to 298 const to = overrideTo || videoObject.to
293 const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to) 299 const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to)
294 video.name = videoData.name 300 video.name = videoData.name
295 video.uuid = videoData.uuid 301 video.uuid = videoData.uuid
@@ -412,8 +418,8 @@ async function updateVideoFromAP (options: {
412} 418}
413 419
414async function refreshVideoIfNeeded (options: { 420async function refreshVideoIfNeeded (options: {
415 video: MVideoThumbnail, 421 video: MVideoThumbnail
416 fetchedType: VideoFetchByUrlType, 422 fetchedType: VideoFetchByUrlType
417 syncParam: SyncParam 423 syncParam: SyncParam
418}): Promise<MVideoThumbnail> { 424}): Promise<MVideoThumbnail> {
419 if (!options.video.isOutdated()) return options.video 425 if (!options.video.isOutdated()) return options.video
@@ -582,13 +588,13 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc
582 thumbnailModel = videoCreated.id 588 thumbnailModel = videoCreated.id
583 589
584 return thumbnailModel.save() 590 return thumbnailModel.save()
585 }) 591 }).catch(err => logger.error('Cannot create miniature from url.', { err }))
586 } 592 }
587 593
588 return { autoBlacklisted, videoCreated } 594 return { autoBlacklisted, videoCreated }
589} 595}
590 596
591async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) { 597function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) {
592 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED 598 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED
593 const duration = videoObject.duration.replace(/[^\d]+/, '') 599 const duration = videoObject.duration.replace(/[^\d]+/, '')
594 600
@@ -661,7 +667,7 @@ function videoFileActivityUrlToDBAttributes (
661 667
662 const mediaType = fileUrl.mediaType 668 const mediaType = fileUrl.mediaType
663 const attribute = { 669 const attribute = {
664 extname: MIMETYPES.VIDEO.MIMETYPE_EXT[ mediaType ], 670 extname: MIMETYPES.VIDEO.MIMETYPE_EXT[mediaType],
665 infoHash: parsed.infoHash, 671 infoHash: parsed.infoHash,
666 resolution: fileUrl.height, 672 resolution: fileUrl.height,
667 size: fileUrl.size, 673 size: fileUrl.size,
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts
index 1d8a08ed0..572bd03bd 100644
--- a/server/lib/client-html.ts
+++ b/server/lib/client-html.ts
@@ -17,7 +17,7 @@ import { MAccountActor, MChannelActor, MVideo } from '../typings/models'
17 17
18export class ClientHtml { 18export class ClientHtml {
19 19
20 private static htmlCache: { [ path: string ]: string } = {} 20 private static htmlCache: { [path: string]: string } = {}
21 21
22 static invalidCache () { 22 static invalidCache () {
23 logger.info('Cleaning HTML cache.') 23 logger.info('Cleaning HTML cache.')
@@ -94,7 +94,7 @@ export class ClientHtml {
94 94
95 private static async getIndexHTML (req: express.Request, res: express.Response, paramLang?: string) { 95 private static async getIndexHTML (req: express.Request, res: express.Response, paramLang?: string) {
96 const path = ClientHtml.getIndexPath(req, res, paramLang) 96 const path = ClientHtml.getIndexPath(req, res, paramLang)
97 if (ClientHtml.htmlCache[ path ]) return ClientHtml.htmlCache[ path ] 97 if (ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path]
98 98
99 const buffer = await readFile(path) 99 const buffer = await readFile(path)
100 100
@@ -104,7 +104,7 @@ export class ClientHtml {
104 html = ClientHtml.addCustomCSS(html) 104 html = ClientHtml.addCustomCSS(html)
105 html = await ClientHtml.addAsyncPluginCSS(html) 105 html = await ClientHtml.addAsyncPluginCSS(html)
106 106
107 ClientHtml.htmlCache[ path ] = html 107 ClientHtml.htmlCache[path] = html
108 108
109 return html 109 return html
110 } 110 }
@@ -214,21 +214,21 @@ export class ClientHtml {
214 const schemaTags = { 214 const schemaTags = {
215 '@context': 'http://schema.org', 215 '@context': 'http://schema.org',
216 '@type': 'VideoObject', 216 '@type': 'VideoObject',
217 name: videoNameEscaped, 217 'name': videoNameEscaped,
218 description: videoDescriptionEscaped, 218 'description': videoDescriptionEscaped,
219 thumbnailUrl: previewUrl, 219 'thumbnailUrl': previewUrl,
220 uploadDate: video.createdAt.toISOString(), 220 'uploadDate': video.createdAt.toISOString(),
221 duration: getActivityStreamDuration(video.duration), 221 'duration': getActivityStreamDuration(video.duration),
222 contentUrl: videoUrl, 222 'contentUrl': videoUrl,
223 embedUrl: embedUrl, 223 'embedUrl': embedUrl,
224 interactionCount: video.views 224 'interactionCount': video.views
225 } 225 }
226 226
227 let tagsString = '' 227 let tagsString = ''
228 228
229 // Opengraph 229 // Opengraph
230 Object.keys(openGraphMetaTags).forEach(tagName => { 230 Object.keys(openGraphMetaTags).forEach(tagName => {
231 const tagValue = openGraphMetaTags[ tagName ] 231 const tagValue = openGraphMetaTags[tagName]
232 232
233 tagsString += `<meta property="${tagName}" content="${tagValue}" />` 233 tagsString += `<meta property="${tagName}" content="${tagValue}" />`
234 }) 234 })
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts
index 7484524a4..9ce6186b1 100644
--- a/server/lib/emailer.ts
+++ b/server/lib/emailer.ts
@@ -32,7 +32,8 @@ class Emailer {
32 private initialized = false 32 private initialized = false
33 private transporter: Transporter 33 private transporter: Transporter
34 34
35 private constructor () {} 35 private constructor () {
36 }
36 37
37 init () { 38 init () {
38 // Already initialized 39 // Already initialized
@@ -97,12 +98,12 @@ class Emailer {
97 const channelName = video.VideoChannel.getDisplayName() 98 const channelName = video.VideoChannel.getDisplayName()
98 const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() 99 const videoUrl = WEBSERVER.URL + video.getWatchStaticPath()
99 100
100 const text = `Hi dear user,\n\n` + 101 const text = 'Hi dear user,\n\n' +
101 `Your subscription ${channelName} just published a new video: ${video.name}` + 102 `Your subscription ${channelName} just published a new video: ${video.name}` +
102 `\n\n` + 103 '\n\n' +
103 `You can view it on ${videoUrl} ` + 104 `You can view it on ${videoUrl} ` +
104 `\n\n` + 105 '\n\n' +
105 `Cheers,\n` + 106 'Cheers,\n' +
106 `${CONFIG.EMAIL.BODY.SIGNATURE}` 107 `${CONFIG.EMAIL.BODY.SIGNATURE}`
107 108
108 const emailPayload: EmailPayload = { 109 const emailPayload: EmailPayload = {
@@ -118,10 +119,10 @@ class Emailer {
118 const followerName = actorFollow.ActorFollower.Account.getDisplayName() 119 const followerName = actorFollow.ActorFollower.Account.getDisplayName()
119 const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() 120 const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName()
120 121
121 const text = `Hi dear user,\n\n` + 122 const text = 'Hi dear user,\n\n' +
122 `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + 123 `Your ${followType} ${followingName} has a new subscriber: ${followerName}` +
123 `\n\n` + 124 '\n\n' +
124 `Cheers,\n` + 125 'Cheers,\n' +
125 `${CONFIG.EMAIL.BODY.SIGNATURE}` 126 `${CONFIG.EMAIL.BODY.SIGNATURE}`
126 127
127 const emailPayload: EmailPayload = { 128 const emailPayload: EmailPayload = {
@@ -136,10 +137,10 @@ class Emailer {
136 addNewInstanceFollowerNotification (to: string[], actorFollow: MActorFollowActors) { 137 addNewInstanceFollowerNotification (to: string[], actorFollow: MActorFollowActors) {
137 const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : '' 138 const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : ''
138 139
139 const text = `Hi dear admin,\n\n` + 140 const text = 'Hi dear admin,\n\n' +
140 `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + 141 `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` +
141 `\n\n` + 142 '\n\n' +
142 `Cheers,\n` + 143 'Cheers,\n' +
143 `${CONFIG.EMAIL.BODY.SIGNATURE}` 144 `${CONFIG.EMAIL.BODY.SIGNATURE}`
144 145
145 const emailPayload: EmailPayload = { 146 const emailPayload: EmailPayload = {
@@ -152,10 +153,10 @@ class Emailer {
152 } 153 }
153 154
154 addAutoInstanceFollowingNotification (to: string[], actorFollow: MActorFollowActors) { 155 addAutoInstanceFollowingNotification (to: string[], actorFollow: MActorFollowActors) {
155 const text = `Hi dear admin,\n\n` + 156 const text = 'Hi dear admin,\n\n' +
156 `Your instance automatically followed a new instance: ${actorFollow.ActorFollowing.url}` + 157 `Your instance automatically followed a new instance: ${actorFollow.ActorFollowing.url}` +
157 `\n\n` + 158 '\n\n' +
158 `Cheers,\n` + 159 'Cheers,\n' +
159 `${CONFIG.EMAIL.BODY.SIGNATURE}` 160 `${CONFIG.EMAIL.BODY.SIGNATURE}`
160 161
161 const emailPayload: EmailPayload = { 162 const emailPayload: EmailPayload = {
@@ -170,12 +171,12 @@ class Emailer {
170 myVideoPublishedNotification (to: string[], video: MVideo) { 171 myVideoPublishedNotification (to: string[], video: MVideo) {
171 const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() 172 const videoUrl = WEBSERVER.URL + video.getWatchStaticPath()
172 173
173 const text = `Hi dear user,\n\n` + 174 const text = 'Hi dear user,\n\n' +
174 `Your video ${video.name} has been published.` + 175 `Your video ${video.name} has been published.` +
175 `\n\n` + 176 '\n\n' +
176 `You can view it on ${videoUrl} ` + 177 `You can view it on ${videoUrl} ` +
177 `\n\n` + 178 '\n\n' +
178 `Cheers,\n` + 179 'Cheers,\n' +
179 `${CONFIG.EMAIL.BODY.SIGNATURE}` 180 `${CONFIG.EMAIL.BODY.SIGNATURE}`
180 181
181 const emailPayload: EmailPayload = { 182 const emailPayload: EmailPayload = {
@@ -190,12 +191,12 @@ class Emailer {
190 myVideoImportSuccessNotification (to: string[], videoImport: MVideoImportVideo) { 191 myVideoImportSuccessNotification (to: string[], videoImport: MVideoImportVideo) {
191 const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath() 192 const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath()
192 193
193 const text = `Hi dear user,\n\n` + 194 const text = 'Hi dear user,\n\n' +
194 `Your video import ${videoImport.getTargetIdentifier()} is finished.` + 195 `Your video import ${videoImport.getTargetIdentifier()} is finished.` +
195 `\n\n` + 196 '\n\n' +
196 `You can view the imported video on ${videoUrl} ` + 197 `You can view the imported video on ${videoUrl} ` +
197 `\n\n` + 198 '\n\n' +
198 `Cheers,\n` + 199 'Cheers,\n' +
199 `${CONFIG.EMAIL.BODY.SIGNATURE}` 200 `${CONFIG.EMAIL.BODY.SIGNATURE}`
200 201
201 const emailPayload: EmailPayload = { 202 const emailPayload: EmailPayload = {
@@ -210,12 +211,12 @@ class Emailer {
210 myVideoImportErrorNotification (to: string[], videoImport: MVideoImport) { 211 myVideoImportErrorNotification (to: string[], videoImport: MVideoImport) {
211 const importUrl = WEBSERVER.URL + '/my-account/video-imports' 212 const importUrl = WEBSERVER.URL + '/my-account/video-imports'
212 213
213 const text = `Hi dear user,\n\n` + 214 const text = 'Hi dear user,\n\n' +
214 `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + 215 `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` +
215 `\n\n` + 216 '\n\n' +
216 `See your videos import dashboard for more information: ${importUrl}` + 217 `See your videos import dashboard for more information: ${importUrl}` +
217 `\n\n` + 218 '\n\n' +
218 `Cheers,\n` + 219 'Cheers,\n' +
219 `${CONFIG.EMAIL.BODY.SIGNATURE}` 220 `${CONFIG.EMAIL.BODY.SIGNATURE}`
220 221
221 const emailPayload: EmailPayload = { 222 const emailPayload: EmailPayload = {
@@ -232,12 +233,12 @@ class Emailer {
232 const video = comment.Video 233 const video = comment.Video
233 const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() 234 const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath()
234 235
235 const text = `Hi dear user,\n\n` + 236 const text = 'Hi dear user,\n\n' +
236 `A new comment has been posted by ${accountName} on your video ${video.name}` + 237 `A new comment has been posted by ${accountName} on your video ${video.name}` +
237 `\n\n` + 238 '\n\n' +
238 `You can view it on ${commentUrl} ` + 239 `You can view it on ${commentUrl} ` +
239 `\n\n` + 240 '\n\n' +
240 `Cheers,\n` + 241 'Cheers,\n' +
241 `${CONFIG.EMAIL.BODY.SIGNATURE}` 242 `${CONFIG.EMAIL.BODY.SIGNATURE}`
242 243
243 const emailPayload: EmailPayload = { 244 const emailPayload: EmailPayload = {
@@ -254,12 +255,12 @@ class Emailer {
254 const video = comment.Video 255 const video = comment.Video
255 const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() 256 const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath()
256 257
257 const text = `Hi dear user,\n\n` + 258 const text = 'Hi dear user,\n\n' +
258 `${accountName} mentioned you on video ${video.name}` + 259 `${accountName} mentioned you on video ${video.name}` +
259 `\n\n` + 260 '\n\n' +
260 `You can view the comment on ${commentUrl} ` + 261 `You can view the comment on ${commentUrl} ` +
261 `\n\n` + 262 '\n\n' +
262 `Cheers,\n` + 263 'Cheers,\n' +
263 `${CONFIG.EMAIL.BODY.SIGNATURE}` 264 `${CONFIG.EMAIL.BODY.SIGNATURE}`
264 265
265 const emailPayload: EmailPayload = { 266 const emailPayload: EmailPayload = {
@@ -274,9 +275,9 @@ class Emailer {
274 addVideoAbuseModeratorsNotification (to: string[], videoAbuse: MVideoAbuseVideo) { 275 addVideoAbuseModeratorsNotification (to: string[], videoAbuse: MVideoAbuseVideo) {
275 const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() 276 const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath()
276 277
277 const text = `Hi,\n\n` + 278 const text = 'Hi,\n\n' +
278 `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + 279 `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` +
279 `Cheers,\n` + 280 'Cheers,\n' +
280 `${CONFIG.EMAIL.BODY.SIGNATURE}` 281 `${CONFIG.EMAIL.BODY.SIGNATURE}`
281 282
282 const emailPayload: EmailPayload = { 283 const emailPayload: EmailPayload = {
@@ -292,14 +293,14 @@ class Emailer {
292 const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list' 293 const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list'
293 const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() 294 const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath()
294 295
295 const text = `Hi,\n\n` + 296 const text = 'Hi,\n\n' +
296 `A recently added video was auto-blacklisted and requires moderator review before publishing.` + 297 'A recently added video was auto-blacklisted and requires moderator review before publishing.' +
297 `\n\n` + 298 '\n\n' +
298 `You can view it and take appropriate action on ${videoUrl}` + 299 `You can view it and take appropriate action on ${videoUrl}` +
299 `\n\n` + 300 '\n\n' +
300 `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + 301 `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` +
301 `\n\n` + 302 '\n\n' +
302 `Cheers,\n` + 303 'Cheers,\n' +
303 `${CONFIG.EMAIL.BODY.SIGNATURE}` 304 `${CONFIG.EMAIL.BODY.SIGNATURE}`
304 305
305 const emailPayload: EmailPayload = { 306 const emailPayload: EmailPayload = {
@@ -312,9 +313,9 @@ class Emailer {
312 } 313 }
313 314
314 addNewUserRegistrationNotification (to: string[], user: MUser) { 315 addNewUserRegistrationNotification (to: string[], user: MUser) {
315 const text = `Hi,\n\n` + 316 const text = 'Hi,\n\n' +
316 `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + 317 `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` +
317 `Cheers,\n` + 318 'Cheers,\n' +
318 `${CONFIG.EMAIL.BODY.SIGNATURE}` 319 `${CONFIG.EMAIL.BODY.SIGNATURE}`
319 320
320 const emailPayload: EmailPayload = { 321 const emailPayload: EmailPayload = {
@@ -367,11 +368,11 @@ class Emailer {
367 } 368 }
368 369
369 addPasswordResetEmailJob (to: string, resetPasswordUrl: string) { 370 addPasswordResetEmailJob (to: string, resetPasswordUrl: string) {
370 const text = `Hi dear user,\n\n` + 371 const text = 'Hi dear user,\n\n' +
371 `A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` + 372 `A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` +
372 `Please follow this link to reset it: ${resetPasswordUrl} (the link will expire within 1 hour)\n\n` + 373 `Please follow this link to reset it: ${resetPasswordUrl} (the link will expire within 1 hour)\n\n` +
373 `If you are not the person who initiated this request, please ignore this email.\n\n` + 374 'If you are not the person who initiated this request, please ignore this email.\n\n' +
374 `Cheers,\n` + 375 'Cheers,\n' +
375 `${CONFIG.EMAIL.BODY.SIGNATURE}` 376 `${CONFIG.EMAIL.BODY.SIGNATURE}`
376 377
377 const emailPayload: EmailPayload = { 378 const emailPayload: EmailPayload = {
@@ -384,11 +385,11 @@ class Emailer {
384 } 385 }
385 386
386 addVerifyEmailJob (to: string, verifyEmailUrl: string) { 387 addVerifyEmailJob (to: string, verifyEmailUrl: string) {
387 const text = `Welcome to PeerTube,\n\n` + 388 const text = 'Welcome to PeerTube,\n\n' +
388 `To start using PeerTube on ${WEBSERVER.HOST} you must verify your email! ` + 389 `To start using PeerTube on ${WEBSERVER.HOST} you must verify your email! ` +
389 `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + 390 `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` +
390 `If you are not the person who initiated this request, please ignore this email.\n\n` + 391 'If you are not the person who initiated this request, please ignore this email.\n\n' +
391 `Cheers,\n` + 392 'Cheers,\n' +
392 `${CONFIG.EMAIL.BODY.SIGNATURE}` 393 `${CONFIG.EMAIL.BODY.SIGNATURE}`
393 394
394 const emailPayload: EmailPayload = { 395 const emailPayload: EmailPayload = {
diff --git a/server/lib/files-cache/videos-preview-cache.ts b/server/lib/files-cache/videos-preview-cache.ts
index 7bfeb5783..d0d4fc5b5 100644
--- a/server/lib/files-cache/videos-preview-cache.ts
+++ b/server/lib/files-cache/videos-preview-cache.ts
@@ -1,9 +1,8 @@
1import { join } from 'path' 1import { join } from 'path'
2import { FILES_CACHE, STATIC_PATHS } from '../../initializers/constants' 2import { FILES_CACHE } from '../../initializers/constants'
3import { VideoModel } from '../../models/video/video' 3import { VideoModel } from '../../models/video/video'
4import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' 4import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache'
5import { doRequestAndSaveToFile } from '@server/helpers/requests' 5import { doRequestAndSaveToFile } from '@server/helpers/requests'
6import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
7 6
8class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { 7class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
9 8
diff --git a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts
index d3bde6e6a..a28f3596f 100644
--- a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts
+++ b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts
@@ -42,7 +42,7 @@ async function buildSignedRequestOptions (payload: Payload) {
42 42
43function buildGlobalHeaders (body: any) { 43function buildGlobalHeaders (body: any) {
44 return { 44 return {
45 'Digest': buildDigest(body) 45 Digest: buildDigest(body)
46 } 46 }
47} 47}
48 48
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts
index 99c991e72..be9e7d181 100644
--- a/server/lib/job-queue/handlers/video-file-import.ts
+++ b/server/lib/job-queue/handlers/video-file-import.ts
@@ -11,7 +11,7 @@ import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent'
11import { getVideoFilePath } from '@server/lib/video-paths' 11import { getVideoFilePath } from '@server/lib/video-paths'
12 12
13export type VideoFileImportPayload = { 13export type VideoFileImportPayload = {
14 videoUUID: string, 14 videoUUID: string
15 filePath: string 15 filePath: string
16} 16}
17 17
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts
index 1fca17584..09f225cec 100644
--- a/server/lib/job-queue/handlers/video-import.ts
+++ b/server/lib/job-queue/handlers/video-import.ts
@@ -221,7 +221,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid
221 isNewVideo: true 221 isNewVideo: true
222 } 222 }
223 223
224 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) 224 await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput })
225 } 225 }
226 226
227 } catch (err) { 227 } catch (err) {
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts
index 39b9fac98..c020057c9 100644
--- a/server/lib/job-queue/handlers/video-transcoding.ts
+++ b/server/lib/job-queue/handlers/video-transcoding.ts
@@ -6,7 +6,6 @@ import { JobQueue } from '../job-queue'
6import { federateVideoIfNeeded } from '../../activitypub' 6import { federateVideoIfNeeded } from '../../activitypub'
7import { retryTransactionWrapper } from '../../../helpers/database-utils' 7import { retryTransactionWrapper } from '../../../helpers/database-utils'
8import { sequelizeTypescript } from '../../../initializers' 8import { sequelizeTypescript } from '../../../initializers'
9import * as Bluebird from 'bluebird'
10import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' 9import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils'
11import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding' 10import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding'
12import { Notifier } from '../../notifier' 11import { Notifier } from '../../notifier'
@@ -40,8 +39,11 @@ interface OptimizeTranscodingPayload extends BaseTranscodingPayload {
40 type: 'optimize' 39 type: 'optimize'
41} 40}
42 41
43export type VideoTranscodingPayload = HLSTranscodingPayload | NewResolutionTranscodingPayload 42export type VideoTranscodingPayload =
44 | OptimizeTranscodingPayload | MergeAudioTranscodingPayload 43 HLSTranscodingPayload
44 | NewResolutionTranscodingPayload
45 | OptimizeTranscodingPayload
46 | MergeAudioTranscodingPayload
45 47
46async function processVideoTranscoding (job: Bull.Job) { 48async function processVideoTranscoding (job: Bull.Job) {
47 const payload = job.data as VideoTranscodingPayload 49 const payload = job.data as VideoTranscodingPayload
@@ -105,7 +107,7 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O
105 107
106 const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { 108 const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => {
107 // Maybe the video changed in database, refresh it 109 // Maybe the video changed in database, refresh it
108 let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t) 110 const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t)
109 // Video does not exist anymore 111 // Video does not exist anymore
110 if (!videoDatabase) return undefined 112 if (!videoDatabase) return undefined
111 113
@@ -122,8 +124,6 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O
122 await createHlsJobIfEnabled(hlsPayload) 124 await createHlsJobIfEnabled(hlsPayload)
123 125
124 if (resolutionsEnabled.length !== 0) { 126 if (resolutionsEnabled.length !== 0) {
125 const tasks: (Bluebird<Bull.Job<any>> | Promise<Bull.Job<any>>)[] = []
126
127 for (const resolution of resolutionsEnabled) { 127 for (const resolution of resolutionsEnabled) {
128 let dataInput: VideoTranscodingPayload 128 let dataInput: VideoTranscodingPayload
129 129
@@ -143,12 +143,9 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O
143 } 143 }
144 } 144 }
145 145
146 const p = JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) 146 JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
147 tasks.push(p)
148 } 147 }
149 148
150 await Promise.all(tasks)
151
152 logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) 149 logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled })
153 } else { 150 } else {
154 // No transcoding to do, it's now published 151 // No transcoding to do, it's now published
diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts
index 61f07c487..14acace7d 100644
--- a/server/lib/job-queue/job-queue.ts
+++ b/server/lib/job-queue/job-queue.ts
@@ -28,7 +28,7 @@ type CreateJobArgument =
28 { type: 'videos-views', payload: {} } | 28 { type: 'videos-views', payload: {} } |
29 { type: 'video-redundancy', payload: VideoRedundancyPayload } 29 { type: 'video-redundancy', payload: VideoRedundancyPayload }
30 30
31const handlers: { [ id in JobType ]: (job: Bull.Job) => Promise<any>} = { 31const handlers: { [id in JobType]: (job: Bull.Job) => Promise<any> } = {
32 'activitypub-http-broadcast': processActivityPubHttpBroadcast, 32 'activitypub-http-broadcast': processActivityPubHttpBroadcast,
33 'activitypub-http-unicast': processActivityPubHttpUnicast, 33 'activitypub-http-unicast': processActivityPubHttpUnicast,
34 'activitypub-http-fetcher': processActivityPubHttpFetcher, 34 'activitypub-http-fetcher': processActivityPubHttpFetcher,
@@ -60,13 +60,14 @@ class JobQueue {
60 60
61 private static instance: JobQueue 61 private static instance: JobQueue
62 62
63 private queues: { [ id in JobType ]?: Bull.Queue } = {} 63 private queues: { [id in JobType]?: Bull.Queue } = {}
64 private initialized = false 64 private initialized = false
65 private jobRedisPrefix: string 65 private jobRedisPrefix: string
66 66
67 private constructor () {} 67 private constructor () {
68 }
68 69
69 async init () { 70 init () {
70 // Already initialized 71 // Already initialized
71 if (this.initialized === true) return 72 if (this.initialized === true) return
72 this.initialized = true 73 this.initialized = true
@@ -108,11 +109,16 @@ class JobQueue {
108 } 109 }
109 } 110 }
110 111
111 createJob (obj: CreateJobArgument) { 112 createJob (obj: CreateJobArgument): void {
113 this.createJobWithPromise(obj)
114 .catch(err => logger.error('Cannot create job.', { err, obj }))
115 }
116
117 createJobWithPromise (obj: CreateJobArgument) {
112 const queue = this.queues[obj.type] 118 const queue = this.queues[obj.type]
113 if (queue === undefined) { 119 if (queue === undefined) {
114 logger.error('Unknown queue %s: cannot create job.', obj.type) 120 logger.error('Unknown queue %s: cannot create job.', obj.type)
115 throw Error('Unknown queue, cannot create job') 121 return
116 } 122 }
117 123
118 const jobArgs: Bull.JobOptions = { 124 const jobArgs: Bull.JobOptions = {
@@ -125,10 +131,10 @@ class JobQueue {
125 } 131 }
126 132
127 async listForApi (options: { 133 async listForApi (options: {
128 state: JobState, 134 state: JobState
129 start: number, 135 start: number
130 count: number, 136 count: number
131 asc?: boolean, 137 asc?: boolean
132 jobType: JobType 138 jobType: JobType
133 }): Promise<Bull.Job[]> { 139 }): Promise<Bull.Job[]> {
134 const { state, start, count, asc, jobType } = options 140 const { state, start, count, asc, jobType } = options
@@ -137,7 +143,7 @@ class JobQueue {
137 const filteredJobTypes = this.filterJobTypes(jobType) 143 const filteredJobTypes = this.filterJobTypes(jobType)
138 144
139 for (const jobType of filteredJobTypes) { 145 for (const jobType of filteredJobTypes) {
140 const queue = this.queues[ jobType ] 146 const queue = this.queues[jobType]
141 if (queue === undefined) { 147 if (queue === undefined) {
142 logger.error('Unknown queue %s to list jobs.', jobType) 148 logger.error('Unknown queue %s to list jobs.', jobType)
143 continue 149 continue
@@ -165,7 +171,7 @@ class JobQueue {
165 const filteredJobTypes = this.filterJobTypes(jobType) 171 const filteredJobTypes = this.filterJobTypes(jobType)
166 172
167 for (const type of filteredJobTypes) { 173 for (const type of filteredJobTypes) {
168 const queue = this.queues[ type ] 174 const queue = this.queues[type]
169 if (queue === undefined) { 175 if (queue === undefined) {
170 logger.error('Unknown queue %s to count jobs.', type) 176 logger.error('Unknown queue %s to count jobs.', type)
171 continue 177 continue
@@ -173,7 +179,7 @@ class JobQueue {
173 179
174 const counts = await queue.getJobCounts() 180 const counts = await queue.getJobCounts()
175 181
176 total += counts[ state ] 182 total += counts[state]
177 } 183 }
178 184
179 return total 185 return total
@@ -189,7 +195,7 @@ class JobQueue {
189 private addRepeatableJobs () { 195 private addRepeatableJobs () {
190 this.queues['videos-views'].add({}, { 196 this.queues['videos-views'].add({}, {
191 repeat: REPEAT_JOBS['videos-views'] 197 repeat: REPEAT_JOBS['videos-views']
192 }) 198 }).catch(err => logger.error('Cannot add repeatable job.', { err }))
193 } 199 }
194 200
195 private filterJobTypes (jobType?: JobType) { 201 private filterJobTypes (jobType?: JobType) {
diff --git a/server/lib/moderation.ts b/server/lib/moderation.ts
index b609f4585..55f7a985d 100644
--- a/server/lib/moderation.ts
+++ b/server/lib/moderation.ts
@@ -15,41 +15,41 @@ export type AcceptResult = {
15 15
16// Can be filtered by plugins 16// Can be filtered by plugins
17function isLocalVideoAccepted (object: { 17function isLocalVideoAccepted (object: {
18 videoBody: VideoCreate, 18 videoBody: VideoCreate
19 videoFile: Express.Multer.File & { duration?: number }, 19 videoFile: Express.Multer.File & { duration?: number }
20 user: UserModel 20 user: UserModel
21}): AcceptResult { 21}): AcceptResult {
22 return { accepted: true } 22 return { accepted: true }
23} 23}
24 24
25function isLocalVideoThreadAccepted (_object: { 25function isLocalVideoThreadAccepted (_object: {
26 commentBody: VideoCommentCreate, 26 commentBody: VideoCommentCreate
27 video: VideoModel, 27 video: VideoModel
28 user: UserModel 28 user: UserModel
29}): AcceptResult { 29}): AcceptResult {
30 return { accepted: true } 30 return { accepted: true }
31} 31}
32 32
33function isLocalVideoCommentReplyAccepted (_object: { 33function isLocalVideoCommentReplyAccepted (_object: {
34 commentBody: VideoCommentCreate, 34 commentBody: VideoCommentCreate
35 parentComment: VideoCommentModel, 35 parentComment: VideoCommentModel
36 video: VideoModel, 36 video: VideoModel
37 user: UserModel 37 user: UserModel
38}): AcceptResult { 38}): AcceptResult {
39 return { accepted: true } 39 return { accepted: true }
40} 40}
41 41
42function isRemoteVideoAccepted (_object: { 42function isRemoteVideoAccepted (_object: {
43 activity: ActivityCreate, 43 activity: ActivityCreate
44 videoAP: VideoTorrentObject, 44 videoAP: VideoTorrentObject
45 byActor: ActorModel 45 byActor: ActorModel
46}): AcceptResult { 46}): AcceptResult {
47 return { accepted: true } 47 return { accepted: true }
48} 48}
49 49
50function isRemoteVideoCommentAccepted (_object: { 50function isRemoteVideoCommentAccepted (_object: {
51 activity: ActivityCreate, 51 activity: ActivityCreate
52 commentAP: VideoCommentObject, 52 commentAP: VideoCommentObject
53 byActor: ActorModel 53 byActor: ActorModel
54}): AcceptResult { 54}): AcceptResult {
55 return { accepted: true } 55 return { accepted: true }
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts
index 679b9bcf6..63197eee1 100644
--- a/server/lib/notifier.ts
+++ b/server/lib/notifier.ts
@@ -6,7 +6,6 @@ import { UserModel } from '../models/account/user'
6import { PeerTubeSocket } from './peertube-socket' 6import { PeerTubeSocket } from './peertube-socket'
7import { CONFIG } from '../initializers/config' 7import { CONFIG } from '../initializers/config'
8import { VideoPrivacy, VideoState } from '../../shared/models/videos' 8import { VideoPrivacy, VideoState } from '../../shared/models/videos'
9import * as Bluebird from 'bluebird'
10import { AccountBlocklistModel } from '../models/account/account-blocklist' 9import { AccountBlocklistModel } from '../models/account/account-blocklist'
11import { 10import {
12 MCommentOwnerVideo, 11 MCommentOwnerVideo,
@@ -17,7 +16,8 @@ import {
17 MVideoFullLight 16 MVideoFullLight
18} from '../typings/models/video' 17} from '../typings/models/video'
19import { 18import {
20 MUser, MUserAccount, 19 MUser,
20 MUserAccount,
21 MUserDefault, 21 MUserDefault,
22 MUserNotifSettingAccount, 22 MUserNotifSettingAccount,
23 MUserWithNotificationSetting, 23 MUserWithNotificationSetting,
@@ -32,14 +32,15 @@ class Notifier {
32 32
33 private static instance: Notifier 33 private static instance: Notifier
34 34
35 private constructor () {} 35 private constructor () {
36 }
36 37
37 notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void { 38 notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void {
38 // Only notify on public and published videos which are not blacklisted 39 // Only notify on public and published videos which are not blacklisted
39 if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return 40 if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return
40 41
41 this.notifySubscribersOfNewVideo(video) 42 this.notifySubscribersOfNewVideo(video)
42 .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) 43 .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err }))
43 } 44 }
44 45
45 notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void { 46 notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void {
@@ -63,7 +64,9 @@ class Notifier {
63 if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return 64 if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return
64 65
65 this.notifyOwnedVideoHasBeenPublished(video) 66 this.notifyOwnedVideoHasBeenPublished(video)
66 .catch(err => logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })) // tslint:disable-line:max-line-length 67 .catch(err => {
68 logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })
69 })
67 } 70 }
68 71
69 notifyOnNewComment (comment: MCommentOwnerVideo): void { 72 notifyOnNewComment (comment: MCommentOwnerVideo): void {
@@ -76,17 +79,17 @@ class Notifier {
76 79
77 notifyOnNewVideoAbuse (videoAbuse: MVideoAbuseVideo): void { 80 notifyOnNewVideoAbuse (videoAbuse: MVideoAbuseVideo): void {
78 this.notifyModeratorsOfNewVideoAbuse(videoAbuse) 81 this.notifyModeratorsOfNewVideoAbuse(videoAbuse)
79 .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err })) 82 .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err }))
80 } 83 }
81 84
82 notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void { 85 notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void {
83 this.notifyModeratorsOfVideoAutoBlacklist(videoBlacklist) 86 this.notifyModeratorsOfVideoAutoBlacklist(videoBlacklist)
84 .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err })) 87 .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err }))
85 } 88 }
86 89
87 notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void { 90 notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void {
88 this.notifyVideoOwnerOfBlacklist(videoBlacklist) 91 this.notifyVideoOwnerOfBlacklist(videoBlacklist)
89 .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err })) 92 .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err }))
90 } 93 }
91 94
92 notifyOnVideoUnblacklist (video: MVideoFullLight): void { 95 notifyOnVideoUnblacklist (video: MVideoFullLight): void {
@@ -96,7 +99,7 @@ class Notifier {
96 99
97 notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void { 100 notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void {
98 this.notifyOwnerVideoImportIsFinished(videoImport, success) 101 this.notifyOwnerVideoImportIsFinished(videoImport, success)
99 .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) 102 .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err }))
100 } 103 }
101 104
102 notifyOnNewUserRegistration (user: MUserDefault): void { 105 notifyOnNewUserRegistration (user: MUserDefault): void {
@@ -106,14 +109,14 @@ class Notifier {
106 109
107 notifyOfNewUserFollow (actorFollow: MActorFollowFull): void { 110 notifyOfNewUserFollow (actorFollow: MActorFollowFull): void {
108 this.notifyUserOfNewActorFollow(actorFollow) 111 this.notifyUserOfNewActorFollow(actorFollow)
109 .catch(err => { 112 .catch(err => {
110 logger.error( 113 logger.error(
111 'Cannot notify owner of channel %s of a new follow by %s.', 114 'Cannot notify owner of channel %s of a new follow by %s.',
112 actorFollow.ActorFollowing.VideoChannel.getDisplayName(), 115 actorFollow.ActorFollowing.VideoChannel.getDisplayName(),
113 actorFollow.ActorFollower.Account.getDisplayName(), 116 actorFollow.ActorFollower.Account.getDisplayName(),
114 { err } 117 { err }
115 ) 118 )
116 }) 119 })
117 } 120 }
118 121
119 notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void { 122 notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void {
@@ -548,10 +551,10 @@ class Notifier {
548 return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) 551 return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender })
549 } 552 }
550 553
551 private async notify <T extends MUserWithNotificationSetting> (options: { 554 private async notify<T extends MUserWithNotificationSetting> (options: {
552 users: T[], 555 users: T[]
553 notificationCreator: (user: T) => Promise<UserNotificationModelForApi>, 556 notificationCreator: (user: T) => Promise<UserNotificationModelForApi>
554 emailSender: (emails: string[]) => Promise<any> | Bluebird<any>, 557 emailSender: (emails: string[]) => void
555 settingGetter: (user: T) => UserNotificationSettingValue 558 settingGetter: (user: T) => UserNotificationSettingValue
556 }) { 559 }) {
557 const emails: string[] = [] 560 const emails: string[] = []
@@ -569,7 +572,7 @@ class Notifier {
569 } 572 }
570 573
571 if (emails.length !== 0) { 574 if (emails.length !== 0) {
572 await options.emailSender(emails) 575 options.emailSender(emails)
573 } 576 }
574 } 577 }
575 578
diff --git a/server/lib/plugins/plugin-index.ts b/server/lib/plugins/plugin-index.ts
index 25b4f3c61..dcdfba28c 100644
--- a/server/lib/plugins/plugin-index.ts
+++ b/server/lib/plugins/plugin-index.ts
@@ -31,7 +31,7 @@ async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList)
31 31
32 logger.debug('Got result from PeerTube index.', { body }) 32 logger.debug('Got result from PeerTube index.', { body })
33 33
34 await addInstanceInformation(body) 34 addInstanceInformation(body)
35 35
36 return body as ResultList<PeerTubePluginIndex> 36 return body as ResultList<PeerTubePluginIndex>
37 } catch (err) { 37 } catch (err) {
@@ -40,7 +40,7 @@ async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList)
40 } 40 }
41} 41}
42 42
43async function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) { 43function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) {
44 for (const d of result.data) { 44 for (const d of result.data) {
45 d.installed = PluginManager.Instance.isRegistered(d.npmName) 45 d.installed = PluginManager.Instance.isRegistered(d.npmName)
46 d.name = PluginModel.normalizePluginName(d.npmName) 46 d.name = PluginModel.normalizePluginName(d.npmName)
diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts
index 7ebdabd34..73f7a71ce 100644
--- a/server/lib/plugins/plugin-manager.ts
+++ b/server/lib/plugins/plugin-manager.ts
@@ -55,30 +55,30 @@ export interface HookInformationValue {
55} 55}
56 56
57type AlterableVideoConstant = 'language' | 'licence' | 'category' 57type AlterableVideoConstant = 'language' | 'licence' | 'category'
58type VideoConstant = { [ key in number | string ]: string } 58type VideoConstant = { [key in number | string]: string }
59type UpdatedVideoConstant = { 59type UpdatedVideoConstant = {
60 [ name in AlterableVideoConstant ]: { 60 [name in AlterableVideoConstant]: {
61 [ npmName: string ]: { 61 [npmName: string]: {
62 added: { key: number | string, label: string }[], 62 added: { key: number | string, label: string }[]
63 deleted: { key: number | string, label: string }[] 63 deleted: { key: number | string, label: string }[]
64 } 64 }
65 } 65 }
66} 66}
67 67
68type PluginLocalesTranslations = { 68type PluginLocalesTranslations = {
69 [ locale: string ]: PluginTranslation 69 [locale: string]: PluginTranslation
70} 70}
71 71
72export class PluginManager implements ServerHook { 72export class PluginManager implements ServerHook {
73 73
74 private static instance: PluginManager 74 private static instance: PluginManager
75 75
76 private registeredPlugins: { [ name: string ]: RegisteredPlugin } = {} 76 private registeredPlugins: { [name: string]: RegisteredPlugin } = {}
77 private settings: { [ name: string ]: RegisterServerSettingOptions[] } = {} 77 private settings: { [name: string]: RegisterServerSettingOptions[] } = {}
78 private hooks: { [ name: string ]: HookInformationValue[] } = {} 78 private hooks: { [name: string]: HookInformationValue[] } = {}
79 private translations: PluginLocalesTranslations = {} 79 private translations: PluginLocalesTranslations = {}
80 80
81 private updatedVideoConstants: UpdatedVideoConstant = { 81 private readonly updatedVideoConstants: UpdatedVideoConstant = {
82 language: {}, 82 language: {},
83 licence: {}, 83 licence: {},
84 category: {} 84 category: {}
@@ -133,7 +133,7 @@ export class PluginManager implements ServerHook {
133 133
134 // ###################### Hooks ###################### 134 // ###################### Hooks ######################
135 135
136 async runHook <T> (hookName: ServerHookName, result?: T, params?: any): Promise<T> { 136 async runHook<T> (hookName: ServerHookName, result?: T, params?: any): Promise<T> {
137 if (!this.hooks[hookName]) return Promise.resolve(result) 137 if (!this.hooks[hookName]) return Promise.resolve(result)
138 138
139 const hookType = getHookType(hookName) 139 const hookType = getHookType(hookName)
@@ -312,7 +312,7 @@ export class PluginManager implements ServerHook {
312 clientScripts[c.script] = c 312 clientScripts[c.script] = c
313 } 313 }
314 314
315 this.registeredPlugins[ npmName ] = { 315 this.registeredPlugins[npmName] = {
316 npmName, 316 npmName,
317 name: plugin.name, 317 name: plugin.name,
318 type: plugin.type, 318 type: plugin.type,
@@ -438,7 +438,7 @@ export class PluginManager implements ServerHook {
438 const plugins: RegisteredPlugin[] = [] 438 const plugins: RegisteredPlugin[] = []
439 439
440 for (const npmName of Object.keys(this.registeredPlugins)) { 440 for (const npmName of Object.keys(this.registeredPlugins)) {
441 const plugin = this.registeredPlugins[ npmName ] 441 const plugin = this.registeredPlugins[npmName]
442 if (plugin.type !== type) continue 442 if (plugin.type !== type) continue
443 443
444 plugins.push(plugin) 444 plugins.push(plugin)
@@ -518,11 +518,11 @@ export class PluginManager implements ServerHook {
518 } 518 }
519 } 519 }
520 520
521 private addConstant <T extends string | number> (parameters: { 521 private addConstant<T extends string | number> (parameters: {
522 npmName: string, 522 npmName: string
523 type: AlterableVideoConstant, 523 type: AlterableVideoConstant
524 obj: VideoConstant, 524 obj: VideoConstant
525 key: T, 525 key: T
526 label: string 526 label: string
527 }) { 527 }) {
528 const { npmName, type, obj, key, label } = parameters 528 const { npmName, type, obj, key, label } = parameters
@@ -545,10 +545,10 @@ export class PluginManager implements ServerHook {
545 return true 545 return true
546 } 546 }
547 547
548 private deleteConstant <T extends string | number> (parameters: { 548 private deleteConstant<T extends string | number> (parameters: {
549 npmName: string, 549 npmName: string
550 type: AlterableVideoConstant, 550 type: AlterableVideoConstant
551 obj: VideoConstant, 551 obj: VideoConstant
552 key: T 552 key: T
553 }) { 553 }) {
554 const { npmName, type, obj, key } = parameters 554 const { npmName, type, obj, key } = parameters
@@ -604,7 +604,7 @@ export class PluginManager implements ServerHook {
604 const { result: packageJSONValid, badFields } = isPackageJSONValid(packageJSON, pluginType) 604 const { result: packageJSONValid, badFields } = isPackageJSONValid(packageJSON, pluginType)
605 if (!packageJSONValid) { 605 if (!packageJSONValid) {
606 const formattedFields = badFields.map(f => `"${f}"`) 606 const formattedFields = badFields.map(f => `"${f}"`)
607 .join(', ') 607 .join(', ')
608 608
609 throw new Error(`PackageJSON is invalid (invalid fields: ${formattedFields}).`) 609 throw new Error(`PackageJSON is invalid (invalid fields: ${formattedFields}).`)
610 } 610 }
diff --git a/server/lib/redis.ts b/server/lib/redis.ts
index f77d0b62c..0c5dbdd3e 100644
--- a/server/lib/redis.ts
+++ b/server/lib/redis.ts
@@ -12,7 +12,7 @@ import {
12import { CONFIG } from '../initializers/config' 12import { CONFIG } from '../initializers/config'
13 13
14type CachedRoute = { 14type CachedRoute = {
15 body: string, 15 body: string
16 contentType?: string 16 contentType?: string
17 statusCode?: string 17 statusCode?: string
18} 18}
@@ -24,7 +24,8 @@ class Redis {
24 private client: RedisClient 24 private client: RedisClient
25 private prefix: string 25 private prefix: string
26 26
27 private constructor () {} 27 private constructor () {
28 }
28 29
29 init () { 30 init () {
30 // Already initialized 31 // Already initialized
@@ -49,9 +50,9 @@ class Redis {
49 return Object.assign({}, 50 return Object.assign({},
50 (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {}, 51 (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {},
51 (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {}, 52 (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {},
52 (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT) ? 53 (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT)
53 { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT } : 54 ? { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT }
54 { path: CONFIG.REDIS.SOCKET } 55 : { path: CONFIG.REDIS.SOCKET }
55 ) 56 )
56 } 57 }
57 58
@@ -63,7 +64,7 @@ class Redis {
63 return this.prefix 64 return this.prefix
64 } 65 }
65 66
66 /************* Forgot password *************/ 67 /* ************ Forgot password ************ */
67 68
68 async setResetPasswordVerificationString (userId: number) { 69 async setResetPasswordVerificationString (userId: number) {
69 const generatedString = await generateRandomString(32) 70 const generatedString = await generateRandomString(32)
@@ -77,7 +78,7 @@ class Redis {
77 return this.getValue(this.generateResetPasswordKey(userId)) 78 return this.getValue(this.generateResetPasswordKey(userId))
78 } 79 }
79 80
80 /************* Email verification *************/ 81 /* ************ Email verification ************ */
81 82
82 async setVerifyEmailVerificationString (userId: number) { 83 async setVerifyEmailVerificationString (userId: number) {
83 const generatedString = await generateRandomString(32) 84 const generatedString = await generateRandomString(32)
@@ -91,7 +92,7 @@ class Redis {
91 return this.getValue(this.generateVerifyEmailKey(userId)) 92 return this.getValue(this.generateVerifyEmailKey(userId))
92 } 93 }
93 94
94 /************* Contact form per IP *************/ 95 /* ************ Contact form per IP ************ */
95 96
96 async setContactFormIp (ip: string) { 97 async setContactFormIp (ip: string) {
97 return this.setValue(this.generateContactFormKey(ip), '1', CONTACT_FORM_LIFETIME) 98 return this.setValue(this.generateContactFormKey(ip), '1', CONTACT_FORM_LIFETIME)
@@ -101,7 +102,7 @@ class Redis {
101 return this.exists(this.generateContactFormKey(ip)) 102 return this.exists(this.generateContactFormKey(ip))
102 } 103 }
103 104
104 /************* Views per IP *************/ 105 /* ************ Views per IP ************ */
105 106
106 setIPVideoView (ip: string, videoUUID: string) { 107 setIPVideoView (ip: string, videoUUID: string) {
107 return this.setValue(this.generateViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME) 108 return this.setValue(this.generateViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME)
@@ -111,7 +112,7 @@ class Redis {
111 return this.exists(this.generateViewKey(ip, videoUUID)) 112 return this.exists(this.generateViewKey(ip, videoUUID))
112 } 113 }
113 114
114 /************* API cache *************/ 115 /* ************ API cache ************ */
115 116
116 async getCachedRoute (req: express.Request) { 117 async getCachedRoute (req: express.Request) {
117 const cached = await this.getObject(this.generateCachedRouteKey(req)) 118 const cached = await this.getObject(this.generateCachedRouteKey(req))
@@ -120,17 +121,17 @@ class Redis {
120 } 121 }
121 122
122 setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) { 123 setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) {
123 const cached: CachedRoute = Object.assign({}, { 124 const cached: CachedRoute = Object.assign(
124 body: body.toString() 125 {},
125 }, 126 { body: body.toString() },
126 (contentType) ? { contentType } : null, 127 (contentType) ? { contentType } : null,
127 (statusCode) ? { statusCode: statusCode.toString() } : null 128 (statusCode) ? { statusCode: statusCode.toString() } : null
128 ) 129 )
129 130
130 return this.setObject(this.generateCachedRouteKey(req), cached, lifetime) 131 return this.setObject(this.generateCachedRouteKey(req), cached, lifetime)
131 } 132 }
132 133
133 /************* Video views *************/ 134 /* ************ Video views ************ */
134 135
135 addVideoView (videoId: number) { 136 addVideoView (videoId: number) {
136 const keyIncr = this.generateVideoViewKey(videoId) 137 const keyIncr = this.generateVideoViewKey(videoId)
@@ -173,7 +174,7 @@ class Redis {
173 ]) 174 ])
174 } 175 }
175 176
176 /************* Keys generation *************/ 177 /* ************ Keys generation ************ */
177 178
178 generateCachedRouteKey (req: express.Request) { 179 generateCachedRouteKey (req: express.Request) {
179 return req.method + '-' + req.originalUrl 180 return req.method + '-' + req.originalUrl
@@ -207,7 +208,7 @@ class Redis {
207 return 'contact-form-' + ip 208 return 'contact-form-' + ip
208 } 209 }
209 210
210 /************* Redis helpers *************/ 211 /* ************ Redis helpers ************ */
211 212
212 private getValue (key: string) { 213 private getValue (key: string) {
213 return new Promise<string>((res, rej) => { 214 return new Promise<string>((res, rej) => {
@@ -265,7 +266,7 @@ class Redis {
265 }) 266 })
266 } 267 }
267 268
268 private setObject (key: string, obj: { [ id: string ]: string }, expirationMilliseconds: number) { 269 private setObject (key: string, obj: { [id: string]: string }, expirationMilliseconds: number) {
269 return new Promise<void>((res, rej) => { 270 return new Promise<void>((res, rej) => {
270 this.client.hmset(this.prefix + key, obj, (err, ok) => { 271 this.client.hmset(this.prefix + key, obj, (err, ok) => {
271 if (err) return rej(err) 272 if (err) return rej(err)
@@ -282,7 +283,7 @@ class Redis {
282 } 283 }
283 284
284 private getObject (key: string) { 285 private getObject (key: string) {
285 return new Promise<{ [ id: string ]: string }>((res, rej) => { 286 return new Promise<{ [id: string]: string }>((res, rej) => {
286 this.client.hgetall(this.prefix + key, (err, value) => { 287 this.client.hgetall(this.prefix + key, (err, value) => {
287 if (err) return rej(err) 288 if (err) return rej(err)
288 289
diff --git a/server/lib/schedulers/auto-follow-index-instances.ts b/server/lib/schedulers/auto-follow-index-instances.ts
index dd326bc1e..d700a99f0 100644
--- a/server/lib/schedulers/auto-follow-index-instances.ts
+++ b/server/lib/schedulers/auto-follow-index-instances.ts
@@ -57,8 +57,7 @@ export class AutoFollowIndexInstances extends AbstractScheduler {
57 isAutoFollow: true 57 isAutoFollow: true
58 } 58 }
59 59
60 await JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) 60 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
61 .catch(err => logger.error('Cannot create follow job for %s.', unfollowedHost, err))
62 } 61 }
63 } 62 }
64 63
diff --git a/server/lib/schedulers/plugins-check-scheduler.ts b/server/lib/schedulers/plugins-check-scheduler.ts
index 7ff41e639..014993e94 100644
--- a/server/lib/schedulers/plugins-check-scheduler.ts
+++ b/server/lib/schedulers/plugins-check-scheduler.ts
@@ -43,7 +43,7 @@ export class PluginsCheckScheduler extends AbstractScheduler {
43 const results = await getLatestPluginsVersion(npmNames) 43 const results = await getLatestPluginsVersion(npmNames)
44 44
45 for (const result of results) { 45 for (const result of results) {
46 const plugin = pluginIndex[ result.npmName ] 46 const plugin = pluginIndex[result.npmName]
47 if (!result.latestVersion) continue 47 if (!result.latestVersion) continue
48 48
49 if ( 49 if (
diff --git a/server/lib/schedulers/remove-old-views-scheduler.ts b/server/lib/schedulers/remove-old-views-scheduler.ts
index 39fbb9163..5ae87fe50 100644
--- a/server/lib/schedulers/remove-old-views-scheduler.ts
+++ b/server/lib/schedulers/remove-old-views-scheduler.ts
@@ -1,9 +1,7 @@
1import { logger } from '../../helpers/logger' 1import { logger } from '../../helpers/logger'
2import { AbstractScheduler } from './abstract-scheduler' 2import { AbstractScheduler } from './abstract-scheduler'
3import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' 3import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants'
4import { UserVideoHistoryModel } from '../../models/account/user-video-history'
5import { CONFIG } from '../../initializers/config' 4import { CONFIG } from '../../initializers/config'
6import { isTestInstance } from '../../helpers/core-utils'
7import { VideoViewModel } from '../../models/video/video-views' 5import { VideoViewModel } from '../../models/video/video-views'
8 6
9export class RemoveOldViewsScheduler extends AbstractScheduler { 7export class RemoveOldViewsScheduler extends AbstractScheduler {
diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts
index 6e61cbe7d..e33a4133a 100644
--- a/server/lib/schedulers/videos-redundancy-scheduler.ts
+++ b/server/lib/schedulers/videos-redundancy-scheduler.ts
@@ -28,9 +28,9 @@ import { getVideoFilename } from '../video-paths'
28import { VideoModel } from '@server/models/video/video' 28import { VideoModel } from '@server/models/video/video'
29 29
30type CandidateToDuplicate = { 30type CandidateToDuplicate = {
31 redundancy: VideosRedundancyStrategy, 31 redundancy: VideosRedundancyStrategy
32 video: MVideoWithAllFiles, 32 video: MVideoWithAllFiles
33 files: MVideoFile[], 33 files: MVideoFile[]
34 streamingPlaylists: MStreamingPlaylistFiles[] 34 streamingPlaylists: MStreamingPlaylistFiles[]
35} 35}
36 36
diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts
index a99f71629..8dbd41771 100644
--- a/server/lib/thumbnail.ts
+++ b/server/lib/thumbnail.ts
@@ -69,7 +69,7 @@ function generateVideoMiniature (video: MVideoThumbnail, videoFile: MVideoFile,
69function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) { 69function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) {
70 const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) 70 const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
71 71
72 const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() 72 const thumbnail = existingThumbnail || new ThumbnailModel()
73 73
74 thumbnail.filename = filename 74 thumbnail.filename = filename
75 thumbnail.height = height 75 thumbnail.height = height
@@ -142,18 +142,18 @@ function buildMetadataFromVideo (video: MVideoThumbnail, type: ThumbnailType, si
142} 142}
143 143
144async function createThumbnailFromFunction (parameters: { 144async function createThumbnailFromFunction (parameters: {
145 thumbnailCreator: () => Promise<any>, 145 thumbnailCreator: () => Promise<any>
146 filename: string, 146 filename: string
147 height: number, 147 height: number
148 width: number, 148 width: number
149 type: ThumbnailType, 149 type: ThumbnailType
150 automaticallyGenerated?: boolean, 150 automaticallyGenerated?: boolean
151 fileUrl?: string, 151 fileUrl?: string
152 existingThumbnail?: MThumbnail 152 existingThumbnail?: MThumbnail
153}) { 153}) {
154 const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters 154 const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters
155 155
156 const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() 156 const thumbnail = existingThumbnail || new ThumbnailModel()
157 157
158 thumbnail.filename = filename 158 thumbnail.filename = filename
159 thumbnail.height = height 159 thumbnail.height = height
diff --git a/server/lib/user.ts b/server/lib/user.ts
index c45438d95..88e60a7df 100644
--- a/server/lib/user.ts
+++ b/server/lib/user.ts
@@ -18,9 +18,9 @@ import { MUser, MUserDefault, MUserId } from '../typings/models/user'
18type ChannelNames = { name: string, displayName: string } 18type ChannelNames = { name: string, displayName: string }
19 19
20async function createUserAccountAndChannelAndPlaylist (parameters: { 20async function createUserAccountAndChannelAndPlaylist (parameters: {
21 userToCreate: MUser, 21 userToCreate: MUser
22 userDisplayName?: string, 22 userDisplayName?: string
23 channelNames?: ChannelNames, 23 channelNames?: ChannelNames
24 validateUser?: boolean 24 validateUser?: boolean
25}): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> { 25}): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> {
26 const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters 26 const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters
@@ -63,11 +63,11 @@ async function createUserAccountAndChannelAndPlaylist (parameters: {
63} 63}
64 64
65async function createLocalAccountWithoutKeys (parameters: { 65async function createLocalAccountWithoutKeys (parameters: {
66 name: string, 66 name: string
67 displayName?: string, 67 displayName?: string
68 userId: number | null, 68 userId: number | null
69 applicationId: number | null, 69 applicationId: number | null
70 t: Transaction | undefined, 70 t: Transaction | undefined
71 type?: ActivityPubActorType 71 type?: ActivityPubActorType
72}) { 72}) {
73 const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters 73 const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters
diff --git a/server/lib/video-blacklist.ts b/server/lib/video-blacklist.ts
index 1dd45b76d..3b90b1b94 100644
--- a/server/lib/video-blacklist.ts
+++ b/server/lib/video-blacklist.ts
@@ -9,15 +9,15 @@ import { Notifier } from './notifier'
9import { MUser, MVideoBlacklistVideo, MVideoWithBlacklistLight } from '@server/typings/models' 9import { MUser, MVideoBlacklistVideo, MVideoWithBlacklistLight } from '@server/typings/models'
10 10
11async function autoBlacklistVideoIfNeeded (parameters: { 11async function autoBlacklistVideoIfNeeded (parameters: {
12 video: MVideoWithBlacklistLight, 12 video: MVideoWithBlacklistLight
13 user?: MUser, 13 user?: MUser
14 isRemote: boolean, 14 isRemote: boolean
15 isNew: boolean, 15 isNew: boolean
16 notify?: boolean, 16 notify?: boolean
17 transaction?: Transaction 17 transaction?: Transaction
18}) { 18}) {
19 const { video, user, isRemote, isNew, notify = true, transaction } = parameters 19 const { video, user, isRemote, isNew, notify = true, transaction } = parameters
20 const doAutoBlacklist = await Hooks.wrapPromiseFun( 20 const doAutoBlacklist = await Hooks.wrapFun(
21 autoBlacklistNeeded, 21 autoBlacklistNeeded,
22 { video, user, isRemote, isNew }, 22 { video, user, isRemote, isNew },
23 'filter:video.auto-blacklist.result' 23 'filter:video.auto-blacklist.result'
@@ -49,10 +49,10 @@ async function autoBlacklistVideoIfNeeded (parameters: {
49 return true 49 return true
50} 50}
51 51
52async function autoBlacklistNeeded (parameters: { 52function autoBlacklistNeeded (parameters: {
53 video: MVideoWithBlacklistLight, 53 video: MVideoWithBlacklistLight
54 isRemote: boolean, 54 isRemote: boolean
55 isNew: boolean, 55 isNew: boolean
56 user?: MUser 56 user?: MUser
57}) { 57}) {
58 const { user, video, isRemote, isNew } = parameters 58 const { user, video, isRemote, isNew } = parameters
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts
index 41eab456b..14829c9d6 100644
--- a/server/lib/video-channel.ts
+++ b/server/lib/video-channel.ts
@@ -6,8 +6,7 @@ import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUr
6import { VideoModel } from '../models/video/video' 6import { VideoModel } from '../models/video/video'
7import { MAccountId, MChannelDefault, MChannelId } from '../typings/models' 7import { MAccountId, MChannelDefault, MChannelId } from '../typings/models'
8 8
9type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & 9type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & { Account?: T }
10 { Account?: T }
11 10
12async function createLocalVideoChannel <T extends MAccountId> ( 11async function createLocalVideoChannel <T extends MAccountId> (
13 videoChannelInfo: VideoChannelCreate, 12 videoChannelInfo: VideoChannelCreate,
diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts
index b8074e6d2..fe83d23e7 100644
--- a/server/lib/video-comment.ts
+++ b/server/lib/video-comment.ts
@@ -7,9 +7,9 @@ import { sendCreateVideoComment } from './activitypub/send'
7import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight } from '../typings/models' 7import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight } from '../typings/models'
8 8
9async function createVideoComment (obj: { 9async function createVideoComment (obj: {
10 text: string, 10 text: string
11 inReplyToComment: MComment | null, 11 inReplyToComment: MComment | null
12 video: MVideoFullLight, 12 video: MVideoFullLight
13 account: MAccountDefault 13 account: MAccountDefault
14}, t: Sequelize.Transaction) { 14}, t: Sequelize.Transaction) {
15 let originCommentId: number | null = null 15 let originCommentId: number | null = null
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts
index f3feae41e..ab7d04d25 100644
--- a/server/middlewares/activitypub.ts
+++ b/server/middlewares/activitypub.ts
@@ -6,6 +6,7 @@ import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/co
6import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' 6import { getOrCreateActorAndServerAndModel } from '../lib/activitypub'
7import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' 7import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger'
8import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor' 8import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor'
9import { getAPId } from '@server/helpers/activitypub'
9 10
10async function checkSignature (req: Request, res: Response, next: NextFunction) { 11async function checkSignature (req: Request, res: Response, next: NextFunction) {
11 try { 12 try {
@@ -16,7 +17,7 @@ async function checkSignature (req: Request, res: Response, next: NextFunction)
16 17
17 // Forwarded activity 18 // Forwarded activity
18 const bodyActor = req.body.actor 19 const bodyActor = req.body.actor
19 const bodyActorId = bodyActor && bodyActor.id ? bodyActor.id : bodyActor 20 const bodyActorId = getAPId(bodyActor)
20 if (bodyActorId && bodyActorId !== actor.url) { 21 if (bodyActorId && bodyActorId !== actor.url) {
21 const jsonLDSignatureChecked = await checkJsonLDSignature(req, res) 22 const jsonLDSignatureChecked = await checkJsonLDSignature(req, res)
22 if (jsonLDSignatureChecked !== true) return 23 if (jsonLDSignatureChecked !== true) return
diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts
index d11d70790..f5de69603 100644
--- a/server/middlewares/csp.ts
+++ b/server/middlewares/csp.ts
@@ -3,20 +3,20 @@ import { CONFIG } from '../initializers/config'
3 3
4const baseDirectives = Object.assign({}, 4const baseDirectives = Object.assign({},
5 { 5 {
6 defaultSrc: ["'none'"], // by default, not specifying default-src = '*' 6 defaultSrc: [ '\'none\'' ], // by default, not specifying default-src = '*'
7 connectSrc: ['*', 'data:'], 7 connectSrc: [ '*', 'data:' ],
8 mediaSrc: ["'self'", 'https:', 'blob:'], 8 mediaSrc: [ '\'self\'', 'https:', 'blob:' ],
9 fontSrc: ["'self'", 'data:'], 9 fontSrc: [ '\'self\'', 'data:' ],
10 imgSrc: ["'self'", 'data:', 'blob:'], 10 imgSrc: [ '\'self\'', 'data:', 'blob:' ],
11 scriptSrc: ["'self' 'unsafe-inline' 'unsafe-eval'", 'blob:'], 11 scriptSrc: [ '\'self\' \'unsafe-inline\' \'unsafe-eval\'', 'blob:' ],
12 styleSrc: ["'self' 'unsafe-inline'"], 12 styleSrc: [ '\'self\' \'unsafe-inline\'' ],
13 objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it 13 objectSrc: [ '\'none\'' ], // only define to allow plugins, else let defaultSrc 'none' block it
14 formAction: ["'self'"], 14 formAction: [ '\'self\'' ],
15 frameAncestors: ["'none'"], 15 frameAncestors: [ '\'none\'' ],
16 baseUri: ["'self'"], 16 baseUri: [ '\'self\'' ],
17 manifestSrc: ["'self'"], 17 manifestSrc: [ '\'self\'' ],
18 frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed 18 frameSrc: [ '\'self\'' ], // instead of deprecated child-src / self because of test-embed
19 workerSrc: ["'self'", 'blob:'] // instead of deprecated child-src 19 workerSrc: [ '\'self\'', 'blob:' ] // instead of deprecated child-src
20 }, 20 },
21 CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {}, 21 CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {},
22 CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} 22 CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {}
@@ -29,7 +29,7 @@ const baseCSP = helmet.contentSecurityPolicy({
29}) 29})
30 30
31const embedCSP = helmet.contentSecurityPolicy({ 31const embedCSP = helmet.contentSecurityPolicy({
32 directives: Object.assign({}, baseDirectives, { frameAncestors: ['*'] }), 32 directives: Object.assign({}, baseDirectives, { frameAncestors: [ '*' ] }),
33 browserSniff: false, // assumes a modern browser, but allows CDN in front 33 browserSniff: false, // assumes a modern browser, but allows CDN in front
34 reportOnly: CONFIG.CSP.REPORT_ONLY 34 reportOnly: CONFIG.CSP.REPORT_ONLY
35}) 35})
diff --git a/server/middlewares/dnt.ts b/server/middlewares/dnt.ts
index 607def855..dd88005dd 100644
--- a/server/middlewares/dnt.ts
+++ b/server/middlewares/dnt.ts
@@ -1,6 +1,3 @@
1import * as ipaddr from 'ipaddr.js'
2import { format } from 'util'
3
4const advertiseDoNotTrack = (_, res, next) => { 1const advertiseDoNotTrack = (_, res, next) => {
5 res.setHeader('Tk', 'N') 2 res.setHeader('Tk', 'N')
6 return next() 3 return next()
diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts
index 749f5cccd..9eef03bb4 100644
--- a/server/middlewares/oauth.ts
+++ b/server/middlewares/oauth.ts
@@ -51,6 +51,7 @@ function authenticateSocket (socket: Socket, next: (err?: any) => void) {
51 51
52 return next() 52 return next()
53 }) 53 })
54 .catch(err => logger.error('Cannot get access token.', { err }))
54} 55}
55 56
56function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) { 57function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) {
diff --git a/server/middlewares/sort.ts b/server/middlewares/sort.ts
index 75238228f..fcbb2902c 100644
--- a/server/middlewares/sort.ts
+++ b/server/middlewares/sort.ts
@@ -8,7 +8,7 @@ const setDefaultVideoRedundanciesSort = setDefaultSortFactory('name')
8const setDefaultSearchSort = setDefaultSortFactory('-match') 8const setDefaultSearchSort = setDefaultSortFactory('-match')
9 9
10function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) { 10function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
11 let newSort: SortType = { sortModel: undefined, sortValue: '' } 11 const newSort: SortType = { sortModel: undefined, sortValue: '' }
12 12
13 if (!req.query.sort) req.query.sort = '-createdAt' 13 if (!req.query.sort) req.query.sort = '-createdAt'
14 14
diff --git a/server/middlewares/validators/avatar.ts b/server/middlewares/validators/avatar.ts
index 8623d07e8..2acb97483 100644
--- a/server/middlewares/validators/avatar.ts
+++ b/server/middlewares/validators/avatar.ts
@@ -8,8 +8,8 @@ import { cleanUpReqFiles } from '../../helpers/express-utils'
8 8
9const updateAvatarValidator = [ 9const updateAvatarValidator = [
10 body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( 10 body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage(
11 'This file is not supported or too large. Please, make sure it is of the following type : ' 11 'This file is not supported or too large. Please, make sure it is of the following type : ' +
12 + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') 12 CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ')
13 ), 13 ),
14 14
15 (req: express.Request, res: express.Response, next: express.NextFunction) => { 15 (req: express.Request, res: express.Response, next: express.NextFunction) => {
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts
index 2d1f61947..ceab646c0 100644
--- a/server/middlewares/validators/config.ts
+++ b/server/middlewares/validators/config.ts
@@ -55,7 +55,7 @@ const customConfigUpdateValidator = [
55 55
56 body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'), 56 body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'),
57 57
58 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 58 (req: express.Request, res: express.Response, next: express.NextFunction) => {
59 logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) 59 logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body })
60 60
61 if (areValidationErrors(req, res)) return 61 if (areValidationErrors(req, res)) return
diff --git a/server/middlewares/validators/feeds.ts b/server/middlewares/validators/feeds.ts
index 29f6c87be..f34c2b174 100644
--- a/server/middlewares/validators/feeds.ts
+++ b/server/middlewares/validators/feeds.ts
@@ -22,13 +22,13 @@ function setFeedFormatContentType (req: express.Request, res: express.Response,
22 22
23 let acceptableContentTypes: string[] 23 let acceptableContentTypes: string[]
24 if (format === 'atom' || format === 'atom1') { 24 if (format === 'atom' || format === 'atom1') {
25 acceptableContentTypes = ['application/atom+xml', 'application/xml', 'text/xml'] 25 acceptableContentTypes = [ 'application/atom+xml', 'application/xml', 'text/xml' ]
26 } else if (format === 'json' || format === 'json1') { 26 } else if (format === 'json' || format === 'json1') {
27 acceptableContentTypes = ['application/json'] 27 acceptableContentTypes = [ 'application/json' ]
28 } else if (format === 'rss' || format === 'rss2') { 28 } else if (format === 'rss' || format === 'rss2') {
29 acceptableContentTypes = ['application/rss+xml', 'application/xml', 'text/xml'] 29 acceptableContentTypes = [ 'application/rss+xml', 'application/xml', 'text/xml' ]
30 } else { 30 } else {
31 acceptableContentTypes = ['application/xml', 'text/xml'] 31 acceptableContentTypes = [ 'application/xml', 'text/xml' ]
32 } 32 }
33 33
34 if (req.accepts(acceptableContentTypes)) { 34 if (req.accepts(acceptableContentTypes)) {
diff --git a/server/middlewares/validators/redundancy.ts b/server/middlewares/validators/redundancy.ts
index 16b42fc0d..8cd3bc33d 100644
--- a/server/middlewares/validators/redundancy.ts
+++ b/server/middlewares/validators/redundancy.ts
@@ -106,7 +106,7 @@ const listVideoRedundanciesValidator = [
106 query('target') 106 query('target')
107 .custom(isVideoRedundancyTarget).withMessage('Should have a valid video redundancies target'), 107 .custom(isVideoRedundancyTarget).withMessage('Should have a valid video redundancies target'),
108 108
109 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 109 (req: express.Request, res: express.Response, next: express.NextFunction) => {
110 logger.debug('Checking listVideoRedundanciesValidator parameters', { parameters: req.query }) 110 logger.debug('Checking listVideoRedundanciesValidator parameters', { parameters: req.query })
111 111
112 if (areValidationErrors(req, res)) return 112 if (areValidationErrors(req, res)) return
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index c78c67a8c..5d52b5804 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -36,7 +36,6 @@ import { doesVideoExist } from '../../helpers/middlewares'
36import { UserRole } from '../../../shared/models/users' 36import { UserRole } from '../../../shared/models/users'
37import { MUserDefault } from '@server/typings/models' 37import { MUserDefault } from '@server/typings/models'
38import { Hooks } from '@server/lib/plugins/hooks' 38import { Hooks } from '@server/lib/plugins/hooks'
39import { isLocalVideoAccepted } from '@server/lib/moderation'
40 39
41const usersAddValidator = [ 40const usersAddValidator = [
42 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), 41 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'),
@@ -149,7 +148,7 @@ const usersBlockingValidator = [
149] 148]
150 149
151const deleteMeValidator = [ 150const deleteMeValidator = [
152 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 151 (req: express.Request, res: express.Response, next: express.NextFunction) => {
153 const user = res.locals.oauth.token.User 152 const user = res.locals.oauth.token.User
154 if (user.username === 'root') { 153 if (user.username === 'root') {
155 return res.status(400) 154 return res.status(400)
@@ -303,7 +302,7 @@ const ensureUserRegistrationAllowed = [
303] 302]
304 303
305const ensureUserRegistrationAllowedForIP = [ 304const ensureUserRegistrationAllowedForIP = [
306 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 305 (req: express.Request, res: express.Response, next: express.NextFunction) => {
307 const allowed = isSignupAllowedForCurrentIP(req.ip) 306 const allowed = isSignupAllowedForCurrentIP(req.ip)
308 307
309 if (allowed === false) { 308 if (allowed === false) {
@@ -410,7 +409,7 @@ const userAutocompleteValidator = [
410] 409]
411 410
412const ensureAuthUserOwnsAccountValidator = [ 411const ensureAuthUserOwnsAccountValidator = [
413 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 412 (req: express.Request, res: express.Response, next: express.NextFunction) => {
414 const user = res.locals.oauth.token.User 413 const user = res.locals.oauth.token.User
415 414
416 if (res.locals.account.id !== user.Account.id) { 415 if (res.locals.account.id !== user.Account.id) {
diff --git a/server/middlewares/validators/videos/video-captions.ts b/server/middlewares/validators/videos/video-captions.ts
index 7b0cd6f66..872d9c2ab 100644
--- a/server/middlewares/validators/videos/video-captions.ts
+++ b/server/middlewares/validators/videos/video-captions.ts
@@ -13,10 +13,12 @@ const addVideoCaptionValidator = [
13 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), 13 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'),
14 param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'), 14 param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
15 body('captionfile') 15 body('captionfile')
16 .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile')).withMessage( 16 .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile'))
17 `This caption file is not supported or too large. Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` 17 .withMessage(
18 + Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ') 18 'This caption file is not supported or too large. ' +
19 ), 19 `Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` +
20 Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ')
21 ),
20 22
21 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 23 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
22 logger.debug('Checking addVideoCaption parameters', { parameters: req.body }) 24 logger.debug('Checking addVideoCaption parameters', { parameters: req.body })
diff --git a/server/middlewares/validators/videos/video-comments.ts b/server/middlewares/validators/videos/video-comments.ts
index 77c5f940d..da2fafb10 100644
--- a/server/middlewares/validators/videos/video-comments.ts
+++ b/server/middlewares/validators/videos/video-comments.ts
@@ -50,7 +50,7 @@ const addVideoCommentThreadValidator = [
50 if (areValidationErrors(req, res)) return 50 if (areValidationErrors(req, res)) return
51 if (!await doesVideoExist(req.params.videoId, res)) return 51 if (!await doesVideoExist(req.params.videoId, res)) return
52 if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return 52 if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
53 if (!await isVideoCommentAccepted(req, res, res.locals.videoAll,false)) return 53 if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return
54 54
55 return next() 55 return next()
56 } 56 }
diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts
index 318dad100..5dc5db533 100644
--- a/server/middlewares/validators/videos/video-imports.ts
+++ b/server/middlewares/validators/videos/video-imports.ts
@@ -22,10 +22,11 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([
22 .optional() 22 .optional()
23 .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'), 23 .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'),
24 body('torrentfile') 24 body('torrentfile')
25 .custom((value, { req }) => isVideoImportTorrentFile(req.files)).withMessage( 25 .custom((value, { req }) => isVideoImportTorrentFile(req.files))
26 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' 26 .withMessage(
27 + CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ') 27 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' +
28 ), 28 CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ')
29 ),
29 body('name') 30 body('name')
30 .optional() 31 .optional()
31 .custom(isVideoNameValid).withMessage('Should have a valid name'), 32 .custom(isVideoNameValid).withMessage('Should have a valid name'),
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts
index 1d67e8666..6b15c5464 100644
--- a/server/middlewares/validators/videos/video-playlists.ts
+++ b/server/middlewares/validators/videos/video-playlists.ts
@@ -384,10 +384,11 @@ export {
384function getCommonPlaylistEditAttributes () { 384function getCommonPlaylistEditAttributes () {
385 return [ 385 return [
386 body('thumbnailfile') 386 body('thumbnailfile')
387 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( 387 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile'))
388 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' 388 .withMessage(
389 + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') 389 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' +
390 ), 390 CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ')
391 ),
391 392
392 body('description') 393 body('description')
393 .optional() 394 .optional()
diff --git a/server/middlewares/validators/videos/video-rates.ts b/server/middlewares/validators/videos/video-rates.ts
index 5d5fae8aa..cbc144f69 100644
--- a/server/middlewares/validators/videos/video-rates.ts
+++ b/server/middlewares/validators/videos/video-rates.ts
@@ -51,7 +51,7 @@ const getAccountVideoRateValidatorFactory = function (rateType: VideoRateType) {
51const videoRatingValidator = [ 51const videoRatingValidator = [
52 query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'), 52 query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'),
53 53
54 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 54 (req: express.Request, res: express.Response, next: express.NextFunction) => {
55 logger.debug('Checking rating parameter', { parameters: req.params }) 55 logger.debug('Checking rating parameter', { parameters: req.params })
56 56
57 if (areValidationErrors(req, res)) return 57 if (areValidationErrors(req, res)) return
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts
index 6733d9dec..11dd02706 100644
--- a/server/middlewares/validators/videos/videos.ts
+++ b/server/middlewares/validators/videos/videos.ts
@@ -49,8 +49,8 @@ import { getVideoWithAttributes } from '../../../helpers/video'
49const videosAddValidator = getCommonVideoEditAttributes().concat([ 49const videosAddValidator = getCommonVideoEditAttributes().concat([
50 body('videofile') 50 body('videofile')
51 .custom((value, { req }) => isVideoFile(req.files)).withMessage( 51 .custom((value, { req }) => isVideoFile(req.files)).withMessage(
52 'This file is not supported or too large. Please, make sure it is of the following type: ' 52 'This file is not supported or too large. Please, make sure it is of the following type: ' +
53 + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') 53 CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ')
54 ), 54 ),
55 body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), 55 body('name').custom(isVideoNameValid).withMessage('Should have a valid name'),
56 body('channelId') 56 body('channelId')
@@ -245,19 +245,15 @@ const videosTerminateChangeOwnershipValidator = [
245 // Check if the user who did the request is able to change the ownership of the video 245 // Check if the user who did the request is able to change the ownership of the video
246 if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return 246 if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return
247 247
248 return next()
249 },
250 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
251 const videoChangeOwnership = res.locals.videoChangeOwnership 248 const videoChangeOwnership = res.locals.videoChangeOwnership
252 249
253 if (videoChangeOwnership.status === VideoChangeOwnershipStatus.WAITING) { 250 if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) {
254 return next()
255 } else {
256 res.status(403) 251 res.status(403)
257 .json({ error: 'Ownership already accepted or refused' }) 252 .json({ error: 'Ownership already accepted or refused' })
258
259 return 253 return
260 } 254 }
255
256 return next()
261 } 257 }
262] 258]
263 259
@@ -284,14 +280,14 @@ function getCommonVideoEditAttributes () {
284 return [ 280 return [
285 body('thumbnailfile') 281 body('thumbnailfile')
286 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( 282 .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage(
287 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' 283 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' +
288 + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') 284 CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
289 ), 285 ),
290 body('previewfile') 286 body('previewfile')
291 .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( 287 .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage(
292 'This preview file is not supported or too large. Please, make sure it is of the following type: ' 288 'This preview file is not supported or too large. Please, make sure it is of the following type: ' +
293 + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') 289 CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
294 ), 290 ),
295 291
296 body('category') 292 body('category')
297 .optional() 293 .optional()
diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts
index c593595b2..8aeb486d1 100644
--- a/server/models/account/account-video-rate.ts
+++ b/server/models/account/account-video-rate.ts
@@ -99,7 +99,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
99 static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> { 99 static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> {
100 const options: FindOptions = { 100 const options: FindOptions = {
101 where: { 101 where: {
102 [ Op.or]: [ 102 [Op.or]: [
103 { 103 {
104 accountId, 104 accountId,
105 videoId 105 videoId
@@ -116,10 +116,10 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
116 } 116 }
117 117
118 static listByAccountForApi (options: { 118 static listByAccountForApi (options: {
119 start: number, 119 start: number
120 count: number, 120 count: number
121 sort: string, 121 sort: string
122 type?: string, 122 type?: string
123 accountId: number 123 accountId: number
124 }) { 124 }) {
125 const query: FindOptions = { 125 const query: FindOptions = {
@@ -135,7 +135,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
135 required: true, 135 required: true,
136 include: [ 136 include: [
137 { 137 {
138 model: VideoChannelModel.scope({ method: [VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }), 138 model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }),
139 required: true 139 required: true
140 } 140 }
141 ] 141 ]
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index 8a0ffeb63..0905a0fb2 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -53,7 +53,7 @@ export type SummaryOptions = {
53 ] 53 ]
54})) 54}))
55@Scopes(() => ({ 55@Scopes(() => ({
56 [ ScopeNames.SUMMARY ]: (options: SummaryOptions = {}) => { 56 [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => {
57 const whereActor = options.whereActor || undefined 57 const whereActor = options.whereActor || undefined
58 58
59 const serverInclude: IncludeOptions = { 59 const serverInclude: IncludeOptions = {
@@ -254,15 +254,15 @@ export class AccountModel extends Model<AccountModel> {
254 254
255 const query = { 255 const query = {
256 where: { 256 where: {
257 [ Op.or ]: [ 257 [Op.or]: [
258 { 258 {
259 userId: { 259 userId: {
260 [ Op.ne ]: null 260 [Op.ne]: null
261 } 261 }
262 }, 262 },
263 { 263 {
264 applicationId: { 264 applicationId: {
265 [ Op.ne ]: null 265 [Op.ne]: null
266 } 266 }
267 } 267 }
268 ] 268 ]
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts
index f649b8f95..5a725187a 100644
--- a/server/models/account/user-notification.ts
+++ b/server/models/account/user-notification.ts
@@ -379,7 +379,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
379 379
380 toFormattedJSON (this: UserNotificationModelForApi): UserNotification { 380 toFormattedJSON (this: UserNotificationModelForApi): UserNotification {
381 const video = this.Video 381 const video = this.Video
382 ? Object.assign(this.formatVideo(this.Video),{ channel: this.formatActor(this.Video.VideoChannel) }) 382 ? Object.assign(this.formatVideo(this.Video), { channel: this.formatActor(this.Video.VideoChannel) })
383 : undefined 383 : undefined
384 384
385 const videoImport = this.VideoImport ? { 385 const videoImport = this.VideoImport ? {
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 4c2c5e278..fb4c15aef 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -1,4 +1,4 @@
1import { FindOptions, literal, Op, QueryTypes, where, fn, col } from 'sequelize' 1import { FindOptions, literal, Op, QueryTypes, where, fn, col, WhereOptions } from 'sequelize'
2import { 2import {
3 AfterDestroy, 3 AfterDestroy,
4 AfterUpdate, 4 AfterUpdate,
@@ -101,7 +101,7 @@ enum ScopeNames {
101 required: true, 101 required: true,
102 where: { 102 where: {
103 type: { 103 type: {
104 [ Op.ne ]: VideoPlaylistType.REGULAR 104 [Op.ne]: VideoPlaylistType.REGULAR
105 } 105 }
106 } 106 }
107 } 107 }
@@ -186,7 +186,10 @@ export class UserModel extends Model<UserModel> {
186 186
187 @AllowNull(false) 187 @AllowNull(false)
188 @Default(true) 188 @Default(true)
189 @Is('UserAutoPlayNextVideoPlaylist', value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean')) 189 @Is(
190 'UserAutoPlayNextVideoPlaylist',
191 value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean')
192 )
190 @Column 193 @Column
191 autoPlayNextVideoPlaylist: boolean 194 autoPlayNextVideoPlaylist: boolean
192 195
@@ -308,7 +311,8 @@ export class UserModel extends Model<UserModel> {
308 } 311 }
309 312
310 static listForApi (start: number, count: number, sort: string, search?: string) { 313 static listForApi (start: number, count: number, sort: string, search?: string) {
311 let where = undefined 314 let where: WhereOptions
315
312 if (search) { 316 if (search) {
313 where = { 317 where = {
314 [Op.or]: [ 318 [Op.or]: [
@@ -319,7 +323,7 @@ export class UserModel extends Model<UserModel> {
319 }, 323 },
320 { 324 {
321 username: { 325 username: {
322 [ Op.iLike ]: '%' + search + '%' 326 [Op.iLike]: '%' + search + '%'
323 } 327 }
324 } 328 }
325 ] 329 ]
@@ -332,14 +336,14 @@ export class UserModel extends Model<UserModel> {
332 [ 336 [
333 literal( 337 literal(
334 '(' + 338 '(' +
335 'SELECT COALESCE(SUM("size"), 0) ' + 339 'SELECT COALESCE(SUM("size"), 0) ' +
336 'FROM (' + 340 'FROM (' +
337 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + 341 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
338 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + 342 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
339 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + 343 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
340 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + 344 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
341 'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' + 345 'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' +
342 ') t' + 346 ') t' +
343 ')' 347 ')'
344 ), 348 ),
345 'videoQuotaUsed' 349 'videoQuotaUsed'
@@ -353,18 +357,18 @@ export class UserModel extends Model<UserModel> {
353 } 357 }
354 358
355 return UserModel.findAndCountAll(query) 359 return UserModel.findAndCountAll(query)
356 .then(({ rows, count }) => { 360 .then(({ rows, count }) => {
357 return { 361 return {
358 data: rows, 362 data: rows,
359 total: count 363 total: count
360 } 364 }
361 }) 365 })
362 } 366 }
363 367
364 static listWithRight (right: UserRight): Bluebird<MUserDefault[]> { 368 static listWithRight (right: UserRight): Bluebird<MUserDefault[]> {
365 const roles = Object.keys(USER_ROLE_LABELS) 369 const roles = Object.keys(USER_ROLE_LABELS)
366 .map(k => parseInt(k, 10) as UserRole) 370 .map(k => parseInt(k, 10) as UserRole)
367 .filter(role => hasUserRight(role, right)) 371 .filter(role => hasUserRight(role, right))
368 372
369 const query = { 373 const query = {
370 where: { 374 where: {
@@ -390,7 +394,7 @@ export class UserModel extends Model<UserModel> {
390 required: true, 394 required: true,
391 include: [ 395 include: [
392 { 396 {
393 attributes: [ ], 397 attributes: [],
394 model: ActorModel.unscoped(), 398 model: ActorModel.unscoped(),
395 required: true, 399 required: true,
396 where: { 400 where: {
@@ -398,7 +402,7 @@ export class UserModel extends Model<UserModel> {
398 }, 402 },
399 include: [ 403 include: [
400 { 404 {
401 attributes: [ ], 405 attributes: [],
402 as: 'ActorFollowings', 406 as: 'ActorFollowings',
403 model: ActorFollowModel.unscoped(), 407 model: ActorFollowModel.unscoped(),
404 required: true, 408 required: true,
@@ -433,7 +437,7 @@ export class UserModel extends Model<UserModel> {
433 static loadByUsername (username: string): Bluebird<MUserDefault> { 437 static loadByUsername (username: string): Bluebird<MUserDefault> {
434 const query = { 438 const query = {
435 where: { 439 where: {
436 username: { [ Op.iLike ]: username } 440 username: { [Op.iLike]: username }
437 } 441 }
438 } 442 }
439 443
@@ -443,7 +447,7 @@ export class UserModel extends Model<UserModel> {
443 static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> { 447 static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> {
444 const query = { 448 const query = {
445 where: { 449 where: {
446 username: { [ Op.iLike ]: username } 450 username: { [Op.iLike]: username }
447 } 451 }
448 } 452 }
449 453
@@ -465,7 +469,7 @@ export class UserModel extends Model<UserModel> {
465 469
466 const query = { 470 const query = {
467 where: { 471 where: {
468 [ Op.or ]: [ 472 [Op.or]: [
469 where(fn('lower', col('username')), fn('lower', username)), 473 where(fn('lower', col('username')), fn('lower', username)),
470 474
471 { email } 475 { email }
@@ -592,7 +596,7 @@ export class UserModel extends Model<UserModel> {
592 const query = { 596 const query = {
593 where: { 597 where: {
594 username: { 598 username: {
595 [ Op.like ]: `%${search}%` 599 [Op.like]: `%${search}%`
596 } 600 }
597 }, 601 },
598 limit: 10 602 limit: 10
@@ -652,7 +656,7 @@ export class UserModel extends Model<UserModel> {
652 videoLanguages: this.videoLanguages, 656 videoLanguages: this.videoLanguages,
653 657
654 role: this.role, 658 role: this.role,
655 roleLabel: USER_ROLE_LABELS[ this.role ], 659 roleLabel: USER_ROLE_LABELS[this.role],
656 660
657 videoQuota: this.videoQuota, 661 videoQuota: this.videoQuota,
658 videoQuotaDaily: this.videoQuotaDaily, 662 videoQuotaDaily: this.videoQuotaDaily,
@@ -686,13 +690,13 @@ export class UserModel extends Model<UserModel> {
686 690
687 if (Array.isArray(this.Account.VideoChannels) === true) { 691 if (Array.isArray(this.Account.VideoChannels) === true) {
688 json.videoChannels = this.Account.VideoChannels 692 json.videoChannels = this.Account.VideoChannels
689 .map(c => c.toFormattedJSON()) 693 .map(c => c.toFormattedJSON())
690 .sort((v1, v2) => { 694 .sort((v1, v2) => {
691 if (v1.createdAt < v2.createdAt) return -1 695 if (v1.createdAt < v2.createdAt) return -1
692 if (v1.createdAt === v2.createdAt) return 0 696 if (v1.createdAt === v2.createdAt) return 0
693 697
694 return 1 698 return 1
695 }) 699 })
696 } 700 }
697 701
698 return json 702 return json
@@ -702,7 +706,7 @@ export class UserModel extends Model<UserModel> {
702 const formatted = this.toFormattedJSON() 706 const formatted = this.toFormattedJSON()
703 707
704 const specialPlaylists = this.Account.VideoPlaylists 708 const specialPlaylists = this.Account.VideoPlaylists
705 .map(p => ({ id: p.id, name: p.name, type: p.type })) 709 .map(p => ({ id: p.id, name: p.name, type: p.type }))
706 710
707 return Object.assign(formatted, { specialPlaylists }) 711 return Object.assign(formatted, { specialPlaylists })
708 } 712 }
@@ -729,12 +733,12 @@ export class UserModel extends Model<UserModel> {
729 733
730 return 'SELECT SUM("size") AS "total" ' + 734 return 'SELECT SUM("size") AS "total" ' +
731 'FROM (' + 735 'FROM (' +
732 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + 736 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
733 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + 737 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
734 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + 738 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
735 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + 739 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
736 'WHERE "account"."userId" = $userId ' + andWhere + 740 'WHERE "account"."userId" = $userId ' + andWhere +
737 'GROUP BY "video"."id"' + 741 'GROUP BY "video"."id"' +
738 ') t' 742 ') t'
739 } 743 }
740 744
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index f21d2b8a2..27643704e 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -1,5 +1,5 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import { values, difference } from 'lodash' 2import { difference, values } from 'lodash'
3import { 3import {
4 AfterCreate, 4 AfterCreate,
5 AfterDestroy, 5 AfterDestroy,
@@ -23,7 +23,7 @@ import { logger } from '../../helpers/logger'
23import { getServerActor } from '../../helpers/utils' 23import { getServerActor } from '../../helpers/utils'
24import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants' 24import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants'
25import { ServerModel } from '../server/server' 25import { ServerModel } from '../server/server'
26import { createSafeIn, getSort, getFollowsSort } from '../utils' 26import { createSafeIn, getFollowsSort, getSort } from '../utils'
27import { ActorModel, unusedActorAttributesForAPI } from './actor' 27import { ActorModel, unusedActorAttributesForAPI } from './actor'
28import { VideoChannelModel } from '../video/video-channel' 28import { VideoChannelModel } from '../video/video-channel'
29import { AccountModel } from '../account/account' 29import { AccountModel } from '../account/account'
@@ -36,7 +36,6 @@ import {
36 MActorFollowSubscriptions 36 MActorFollowSubscriptions
37} from '@server/typings/models' 37} from '@server/typings/models'
38import { ActivityPubActorType } from '@shared/models' 38import { ActivityPubActorType } from '@shared/models'
39import { afterCommitIfTransaction } from '@server/helpers/database-utils'
40 39
41@Table({ 40@Table({
42 tableName: 'actorFollow', 41 tableName: 'actorFollow',
@@ -226,7 +225,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
226 225
227 return ActorFollowModel.findOne(query) 226 return ActorFollowModel.findOne(query)
228 .then(result => { 227 .then(result => {
229 if (result && result.ActorFollowing.VideoChannel) { 228 if (result?.ActorFollowing.VideoChannel) {
230 result.ActorFollowing.VideoChannel.Actor = result.ActorFollowing 229 result.ActorFollowing.VideoChannel.Actor = result.ActorFollowing
231 } 230 }
232 231
@@ -239,24 +238,24 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
239 .map(t => { 238 .map(t => {
240 if (t.host) { 239 if (t.host) {
241 return { 240 return {
242 [ Op.and ]: [ 241 [Op.and]: [
243 { 242 {
244 '$preferredUsername$': t.name 243 $preferredUsername$: t.name
245 }, 244 },
246 { 245 {
247 '$host$': t.host 246 $host$: t.host
248 } 247 }
249 ] 248 ]
250 } 249 }
251 } 250 }
252 251
253 return { 252 return {
254 [ Op.and ]: [ 253 [Op.and]: [
255 { 254 {
256 '$preferredUsername$': t.name 255 $preferredUsername$: t.name
257 }, 256 },
258 { 257 {
259 '$serverId$': null 258 $serverId$: null
260 } 259 }
261 ] 260 ]
262 } 261 }
@@ -265,9 +264,9 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
265 const query = { 264 const query = {
266 attributes: [], 265 attributes: [],
267 where: { 266 where: {
268 [ Op.and ]: [ 267 [Op.and]: [
269 { 268 {
270 [ Op.or ]: whereTab 269 [Op.or]: whereTab
271 }, 270 },
272 { 271 {
273 actorId 272 actorId
@@ -295,12 +294,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
295 } 294 }
296 295
297 static listFollowingForApi (options: { 296 static listFollowingForApi (options: {
298 id: number, 297 id: number
299 start: number, 298 start: number
300 count: number, 299 count: number
301 sort: string, 300 sort: string
302 state?: FollowState, 301 state?: FollowState
303 actorType?: ActivityPubActorType, 302 actorType?: ActivityPubActorType
304 search?: string 303 search?: string
305 }) { 304 }) {
306 const { id, start, count, sort, search, state, actorType } = options 305 const { id, start, count, sort, search, state, actorType } = options
@@ -312,7 +311,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
312 if (search) { 311 if (search) {
313 Object.assign(followingServerWhere, { 312 Object.assign(followingServerWhere, {
314 host: { 313 host: {
315 [ Op.iLike ]: '%' + search + '%' 314 [Op.iLike]: '%' + search + '%'
316 } 315 }
317 }) 316 })
318 } 317 }
@@ -362,12 +361,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
362 } 361 }
363 362
364 static listFollowersForApi (options: { 363 static listFollowersForApi (options: {
365 actorId: number, 364 actorId: number
366 start: number, 365 start: number
367 count: number, 366 count: number
368 sort: string, 367 sort: string
369 state?: FollowState, 368 state?: FollowState
370 actorType?: ActivityPubActorType, 369 actorType?: ActivityPubActorType
371 search?: string 370 search?: string
372 }) { 371 }) {
373 const { actorId, start, count, sort, search, state, actorType } = options 372 const { actorId, start, count, sort, search, state, actorType } = options
@@ -379,7 +378,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
379 if (search) { 378 if (search) {
380 Object.assign(followerServerWhere, { 379 Object.assign(followerServerWhere, {
381 host: { 380 host: {
382 [ Op.iLike ]: '%' + search + '%' 381 [Op.iLike]: '%' + search + '%'
383 } 382 }
384 }) 383 })
385 } 384 }
@@ -631,7 +630,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
631 630
632 const tasks: Bluebird<any>[] = [] 631 const tasks: Bluebird<any>[] = []
633 632
634 for (let selection of selections) { 633 for (const selection of selections) {
635 let query = 'SELECT ' + selection + ' FROM "actor" ' + 634 let query = 'SELECT ' + selection + ' FROM "actor" ' +
636 'INNER JOIN "actorFollow" ON "actorFollow"."' + firstJoin + '" = "actor"."id" ' + 635 'INNER JOIN "actorFollow" ON "actorFollow"."' + firstJoin + '" = "actor"."id" ' +
637 'INNER JOIN "actor" AS "Follows" ON "actorFollow"."' + secondJoin + '" = "Follows"."id" ' + 636 'INNER JOIN "actor" AS "Follows" ON "actorFollow"."' + secondJoin + '" = "Follows"."id" ' +
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index d651a281a..00e8dc954 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -16,7 +16,7 @@ import {
16 Table, 16 Table,
17 UpdatedAt 17 UpdatedAt
18} from 'sequelize-typescript' 18} from 'sequelize-typescript'
19import { ActivityPubActorType } from '../../../shared/models/activitypub' 19import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub'
20import { Avatar } from '../../../shared/models/avatars/avatar.model' 20import { Avatar } from '../../../shared/models/avatars/avatar.model'
21import { activityPubContextify } from '../../helpers/activitypub' 21import { activityPubContextify } from '../../helpers/activitypub'
22import { 22import {
@@ -335,7 +335,7 @@ export class ActorModel extends Model<ActorModel> {
335 const query = { 335 const query = {
336 where: { 336 where: {
337 followersUrl: { 337 followersUrl: {
338 [ Op.in ]: followersUrls 338 [Op.in]: followersUrls
339 } 339 }
340 }, 340 },
341 transaction 341 transaction
@@ -362,7 +362,7 @@ export class ActorModel extends Model<ActorModel> {
362 .findOne(query) 362 .findOne(query)
363 .then(actor => { 363 .then(actor => {
364 if (preferredUsername === SERVER_ACTOR_NAME) { 364 if (preferredUsername === SERVER_ACTOR_NAME) {
365 ActorModel.localNameCache[ preferredUsername ] = actor 365 ActorModel.localNameCache[preferredUsername] = actor
366 } 366 }
367 367
368 return actor 368 return actor
@@ -388,7 +388,7 @@ export class ActorModel extends Model<ActorModel> {
388 .findOne(query) 388 .findOne(query)
389 .then(actor => { 389 .then(actor => {
390 if (preferredUsername === SERVER_ACTOR_NAME) { 390 if (preferredUsername === SERVER_ACTOR_NAME) {
391 ActorModel.localUrlCache[ preferredUsername ] = actor 391 ActorModel.localUrlCache[preferredUsername] = actor
392 } 392 }
393 393
394 return actor 394 return actor
@@ -500,9 +500,11 @@ export class ActorModel extends Model<ActorModel> {
500 } 500 }
501 501
502 toActivityPubObject (this: MActorAP, name: string) { 502 toActivityPubObject (this: MActorAP, name: string) {
503 let icon = undefined 503 let icon: ActivityIconObject
504
504 if (this.avatarId) { 505 if (this.avatarId) {
505 const extension = extname(this.Avatar.filename) 506 const extension = extname(this.Avatar.filename)
507
506 icon = { 508 icon = {
507 type: 'Image', 509 type: 'Image',
508 mediaType: extension === '.png' ? 'image/png' : 'image/jpeg', 510 mediaType: extension === '.png' ? 'image/png' : 'image/jpeg',
diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts
index b680be237..d2101ce86 100644
--- a/server/models/oauth/oauth-token.ts
+++ b/server/models/oauth/oauth-token.ts
@@ -23,10 +23,10 @@ import { MOAuthTokenUser } from '@server/typings/models/oauth/oauth-token'
23 23
24export type OAuthTokenInfo = { 24export type OAuthTokenInfo = {
25 refreshToken: string 25 refreshToken: string
26 refreshTokenExpiresAt: Date, 26 refreshTokenExpiresAt: Date
27 client: { 27 client: {
28 id: number 28 id: number
29 }, 29 }
30 user: { 30 user: {
31 id: number 31 id: number
32 } 32 }
diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts
index 4e66d72e3..1b63d3818 100644
--- a/server/models/redundancy/video-redundancy.ts
+++ b/server/models/redundancy/video-redundancy.ts
@@ -43,7 +43,7 @@ export enum ScopeNames {
43} 43}
44 44
45@Scopes(() => ({ 45@Scopes(() => ({
46 [ ScopeNames.WITH_VIDEO ]: { 46 [ScopeNames.WITH_VIDEO]: {
47 include: [ 47 include: [
48 { 48 {
49 model: VideoFileModel, 49 model: VideoFileModel,
@@ -167,7 +167,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
167 logger.info('Removing duplicated video streaming playlist %s.', videoUUID) 167 logger.info('Removing duplicated video streaming playlist %s.', videoUUID)
168 168
169 videoStreamingPlaylist.Video.removeStreamingPlaylistFiles(videoStreamingPlaylist, true) 169 videoStreamingPlaylist.Video.removeStreamingPlaylistFiles(videoStreamingPlaylist, true)
170 .catch(err => logger.error('Cannot delete video streaming playlist files of %s.', videoUUID, { err })) 170 .catch(err => logger.error('Cannot delete video streaming playlist files of %s.', videoUUID, { err }))
171 } 171 }
172 172
173 return undefined 173 return undefined
@@ -230,12 +230,12 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
230 }, 230 },
231 include: [ 231 include: [
232 { 232 {
233 attributes: [ ], 233 attributes: [],
234 model: VideoFileModel, 234 model: VideoFileModel,
235 required: true, 235 required: true,
236 include: [ 236 include: [
237 { 237 {
238 attributes: [ ], 238 attributes: [],
239 model: VideoModel, 239 model: VideoModel,
240 required: true, 240 required: true,
241 where: { 241 where: {
@@ -248,7 +248,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
248 } 248 }
249 249
250 return VideoRedundancyModel.findOne(query) 250 return VideoRedundancyModel.findOne(query)
251 .then(r => !!r) 251 .then(r => !!r)
252 } 252 }
253 253
254 static async getVideoSample (p: Bluebird<VideoModel[]>) { 254 static async getVideoSample (p: Bluebird<VideoModel[]>) {
@@ -310,7 +310,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
310 where: { 310 where: {
311 privacy: VideoPrivacy.PUBLIC, 311 privacy: VideoPrivacy.PUBLIC,
312 views: { 312 views: {
313 [ Op.gte ]: minViews 313 [Op.gte]: minViews
314 } 314 }
315 }, 315 },
316 include: [ 316 include: [
@@ -333,7 +333,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
333 actorId: actor.id, 333 actorId: actor.id,
334 strategy, 334 strategy,
335 createdAt: { 335 createdAt: {
336 [ Op.lt ]: expiredDate 336 [Op.lt]: expiredDate
337 } 337 }
338 } 338 }
339 } 339 }
@@ -392,7 +392,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
392 where: { 392 where: {
393 actorId: actor.id, 393 actorId: actor.id,
394 expiresOn: { 394 expiresOn: {
395 [ Op.lt ]: new Date() 395 [Op.lt]: new Date()
396 } 396 }
397 } 397 }
398 } 398 }
@@ -409,8 +409,8 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
409 [Op.ne]: actor.id 409 [Op.ne]: actor.id
410 }, 410 },
411 expiresOn: { 411 expiresOn: {
412 [ Op.lt ]: new Date(), 412 [Op.lt]: new Date(),
413 [ Op.ne ]: null 413 [Op.ne]: null
414 } 414 }
415 } 415 }
416 } 416 }
@@ -464,15 +464,15 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
464 } 464 }
465 465
466 static listForApi (options: { 466 static listForApi (options: {
467 start: number, 467 start: number
468 count: number, 468 count: number
469 sort: string, 469 sort: string
470 target: VideoRedundanciesTarget, 470 target: VideoRedundanciesTarget
471 strategy?: string 471 strategy?: string
472 }) { 472 }) {
473 const { start, count, sort, target, strategy } = options 473 const { start, count, sort, target, strategy } = options
474 let redundancyWhere: WhereOptions = {} 474 const redundancyWhere: WhereOptions = {}
475 let videosWhere: WhereOptions = {} 475 const videosWhere: WhereOptions = {}
476 let redundancySqlSuffix = '' 476 let redundancySqlSuffix = ''
477 477
478 if (target === 'my-videos') { 478 if (target === 'my-videos') {
@@ -490,10 +490,10 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
490 const videoFilterWhere = { 490 const videoFilterWhere = {
491 [Op.and]: [ 491 [Op.and]: [
492 { 492 {
493 [ Op.or ]: [ 493 [Op.or]: [
494 { 494 {
495 id: { 495 id: {
496 [ Op.in ]: literal( 496 [Op.in]: literal(
497 '(' + 497 '(' +
498 'SELECT "videoId" FROM "videoFile" ' + 498 'SELECT "videoId" FROM "videoFile" ' +
499 'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoFileId" = "videoFile".id' + 499 'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoFileId" = "videoFile".id' +
@@ -504,7 +504,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
504 }, 504 },
505 { 505 {
506 id: { 506 id: {
507 [ Op.in ]: literal( 507 [Op.in]: literal(
508 '(' + 508 '(' +
509 'select "videoId" FROM "videoStreamingPlaylist" ' + 509 'select "videoId" FROM "videoStreamingPlaylist" ' +
510 'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoStreamingPlaylistId" = "videoStreamingPlaylist".id' + 510 'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoStreamingPlaylistId" = "videoStreamingPlaylist".id' +
@@ -592,16 +592,16 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
592 } 592 }
593 593
594 return VideoRedundancyModel.findOne(query) 594 return VideoRedundancyModel.findOne(query)
595 .then((r: any) => ({ 595 .then((r: any) => ({
596 totalUsed: parseAggregateResult(r.totalUsed), 596 totalUsed: parseAggregateResult(r.totalUsed),
597 totalVideos: r.totalVideos, 597 totalVideos: r.totalVideos,
598 totalVideoFiles: r.totalVideoFiles 598 totalVideoFiles: r.totalVideoFiles
599 })) 599 }))
600 } 600 }
601 601
602 static toFormattedJSONStatic (video: MVideoForRedundancyAPI): VideoRedundancy { 602 static toFormattedJSONStatic (video: MVideoForRedundancyAPI): VideoRedundancy {
603 let filesRedundancies: FileRedundancyInformation[] = [] 603 const filesRedundancies: FileRedundancyInformation[] = []
604 let streamingPlaylistsRedundancies: StreamingPlaylistRedundancyInformation[] = [] 604 const streamingPlaylistsRedundancies: StreamingPlaylistRedundancyInformation[] = []
605 605
606 for (const file of video.VideoFiles) { 606 for (const file of video.VideoFiles) {
607 for (const redundancy of file.RedundancyVideos) { 607 for (const redundancy of file.RedundancyVideos) {
@@ -678,7 +678,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
678 expires: this.expiresOn ? this.expiresOn.toISOString() : null, 678 expires: this.expiresOn ? this.expiresOn.toISOString() : null,
679 url: { 679 url: {
680 type: 'Link', 680 type: 'Link',
681 mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ this.VideoFile.extname ] as any, 681 mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[this.VideoFile.extname] as any,
682 href: this.fileUrl, 682 href: this.fileUrl,
683 height: this.VideoFile.resolution, 683 height: this.VideoFile.resolution,
684 size: this.VideoFile.size, 684 size: this.VideoFile.size,
@@ -693,7 +693,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
693 693
694 const notIn = literal( 694 const notIn = literal(
695 '(' + 695 '(' +
696 `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "videoFileId" IS NOT NULL` + 696 `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "videoFileId" IS NOT NULL` +
697 ')' 697 ')'
698 ) 698 )
699 699
@@ -703,7 +703,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
703 required: true, 703 required: true,
704 where: { 704 where: {
705 id: { 705 id: {
706 [ Op.notIn ]: notIn 706 [Op.notIn]: notIn
707 } 707 }
708 } 708 }
709 } 709 }
diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts
index d094da1f5..95774a467 100644
--- a/server/models/server/plugin.ts
+++ b/server/models/server/plugin.ts
@@ -189,10 +189,10 @@ export class PluginModel extends Model<PluginModel> {
189 } 189 }
190 190
191 static listForApi (options: { 191 static listForApi (options: {
192 pluginType?: PluginType, 192 pluginType?: PluginType
193 uninstalled?: boolean, 193 uninstalled?: boolean
194 start: number, 194 start: number
195 count: number, 195 count: number
196 sort: string 196 sort: string
197 }) { 197 }) {
198 const { uninstalled = false } = options 198 const { uninstalled = false } = options
diff --git a/server/models/utils.ts b/server/models/utils.ts
index f89b80011..f7afb8d4b 100644
--- a/server/models/utils.ts
+++ b/server/models/utils.ts
@@ -67,7 +67,7 @@ function getVideoSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): Or
67function getBlacklistSort (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { 67function getBlacklistSort (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] {
68 const [ firstSort ] = getSort(value) 68 const [ firstSort ] = getSort(value)
69 69
70 if (model) return [ [ literal(`"${model}.${firstSort[ 0 ]}" ${firstSort[ 1 ]}`) ], lastSort ] as any[] // FIXME: typings 70 if (model) return [ [ literal(`"${model}.${firstSort[0]}" ${firstSort[1]}`) ], lastSort ] as any[] // FIXME: typings
71 return [ firstSort, lastSort ] 71 return [ firstSort, lastSort ]
72} 72}
73 73
@@ -139,7 +139,7 @@ function buildServerIdsFollowedBy (actorId: any) {
139 'SELECT "actor"."serverId" FROM "actorFollow" ' + 139 'SELECT "actor"."serverId" FROM "actorFollow" ' +
140 'INNER JOIN "actor" ON actor.id = "actorFollow"."targetActorId" ' + 140 'INNER JOIN "actor" ON actor.id = "actorFollow"."targetActorId" ' +
141 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + 141 'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
142 ')' 142 ')'
143} 143}
144 144
145function buildWhereIdOrUUID (id: number | string) { 145function buildWhereIdOrUUID (id: number | string) {
diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts
index b69bc0872..e396784d2 100644
--- a/server/models/video/thumbnail.ts
+++ b/server/models/video/thumbnail.ts
@@ -92,7 +92,7 @@ export class ThumbnailModel extends Model<ThumbnailModel> {
92 @UpdatedAt 92 @UpdatedAt
93 updatedAt: Date 93 updatedAt: Date
94 94
95 private static types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = { 95 private static readonly types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = {
96 [ThumbnailType.MINIATURE]: { 96 [ThumbnailType.MINIATURE]: {
97 label: 'miniature', 97 label: 'miniature',
98 directory: CONFIG.STORAGE.THUMBNAILS_DIR, 98 directory: CONFIG.STORAGE.THUMBNAILS_DIR,
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts
index 3636db18d..da8c1577c 100644
--- a/server/models/video/video-abuse.ts
+++ b/server/models/video/video-abuse.ts
@@ -87,9 +87,9 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
87 } 87 }
88 88
89 static listForApi (parameters: { 89 static listForApi (parameters: {
90 start: number, 90 start: number
91 count: number, 91 count: number
92 sort: string, 92 sort: string
93 serverAccountId: number 93 serverAccountId: number
94 user?: MUserAccountId 94 user?: MUserAccountId
95 }) { 95 }) {
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts
index 1307c27f1..59d3e1050 100644
--- a/server/models/video/video-caption.ts
+++ b/server/models/video/video-caption.ts
@@ -4,7 +4,8 @@ import {
4 BeforeDestroy, 4 BeforeDestroy,
5 BelongsTo, 5 BelongsTo,
6 Column, 6 Column,
7 CreatedAt, DataType, 7 CreatedAt,
8 DataType,
8 ForeignKey, 9 ForeignKey,
9 Is, 10 Is,
10 Model, 11 Model,
@@ -16,13 +17,13 @@ import { buildWhereIdOrUUID, throwIfNotValid } from '../utils'
16import { VideoModel } from './video' 17import { VideoModel } from './video'
17import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' 18import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions'
18import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' 19import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model'
19import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants' 20import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants'
20import { join } from 'path' 21import { join } from 'path'
21import { logger } from '../../helpers/logger' 22import { logger } from '../../helpers/logger'
22import { remove } from 'fs-extra' 23import { remove } from 'fs-extra'
23import { CONFIG } from '../../initializers/config' 24import { CONFIG } from '../../initializers/config'
24import * as Bluebird from 'bluebird' 25import * as Bluebird from 'bluebird'
25import { MVideo, MVideoAccountLight, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models' 26import { MVideoAccountLight, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models'
26import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' 27import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
27 28
28export enum ScopeNames { 29export enum ScopeNames {
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index 4e98e7ba3..835216671 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -30,7 +30,7 @@ import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttr
30import { VideoModel } from './video' 30import { VideoModel } from './video'
31import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' 31import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants'
32import { ServerModel } from '../server/server' 32import { ServerModel } from '../server/server'
33import { FindOptions, ModelIndexesOptions, Op } from 'sequelize' 33import { FindOptions, Op } from 'sequelize'
34import { AvatarModel } from '../avatar/avatar' 34import { AvatarModel } from '../avatar/avatar'
35import { VideoPlaylistModel } from './video-playlist' 35import { VideoPlaylistModel } from './video-playlist'
36import * as Bluebird from 'bluebird' 36import * as Bluebird from 'bluebird'
@@ -121,7 +121,7 @@ export type SummaryOptions = {
121 }, 121 },
122 { 122 {
123 serverId: { 123 serverId: {
124 [ Op.in ]: Sequelize.literal(inQueryInstanceFollow) 124 [Op.in]: Sequelize.literal(inQueryInstanceFollow)
125 } 125 }
126 } 126 }
127 ] 127 ]
@@ -348,9 +348,9 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
348 } 348 }
349 349
350 static listByAccount (options: { 350 static listByAccount (options: {
351 accountId: number, 351 accountId: number
352 start: number, 352 start: number
353 count: number, 353 count: number
354 sort: string 354 sort: string
355 }) { 355 }) {
356 const query = { 356 const query = {
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts
index fb4d16b4d..b33c33d5e 100644
--- a/server/models/video/video-comment.ts
+++ b/server/models/video/video-comment.ts
@@ -257,10 +257,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
257 } 257 }
258 258
259 static async listThreadsForApi (parameters: { 259 static async listThreadsForApi (parameters: {
260 videoId: number, 260 videoId: number
261 start: number, 261 start: number
262 count: number, 262 count: number
263 sort: string, 263 sort: string
264 user?: MUserAccountId 264 user?: MUserAccountId
265 }) { 265 }) {
266 const { videoId, start, count, sort, user } = parameters 266 const { videoId, start, count, sort, user } = parameters
@@ -300,8 +300,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
300 } 300 }
301 301
302 static async listThreadCommentsForApi (parameters: { 302 static async listThreadCommentsForApi (parameters: {
303 videoId: number, 303 videoId: number
304 threadId: number, 304 threadId: number
305 user?: MUserAccountId 305 user?: MUserAccountId
306 }) { 306 }) {
307 const { videoId, threadId, user } = parameters 307 const { videoId, threadId, user } = parameters
@@ -314,7 +314,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
314 order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order, 314 order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order,
315 where: { 315 where: {
316 videoId, 316 videoId,
317 [ Op.or ]: [ 317 [Op.or]: [
318 { id: threadId }, 318 { id: threadId },
319 { originCommentId: threadId } 319 { originCommentId: threadId }
320 ], 320 ],
@@ -346,7 +346,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
346 order: [ [ 'createdAt', order ] ] as Order, 346 order: [ [ 'createdAt', order ] ] as Order,
347 where: { 347 where: {
348 id: { 348 id: {
349 [ Op.in ]: Sequelize.literal('(' + 349 [Op.in]: Sequelize.literal('(' +
350 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' + 350 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' +
351 `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` + 351 `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` +
352 'UNION ' + 352 'UNION ' +
@@ -355,7 +355,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
355 ') ' + 355 ') ' +
356 'SELECT id FROM children' + 356 'SELECT id FROM children' +
357 ')'), 357 ')'),
358 [ Op.ne ]: comment.id 358 [Op.ne]: comment.id
359 } 359 }
360 }, 360 },
361 transaction: t 361 transaction: t
@@ -461,7 +461,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
461 } 461 }
462 462
463 isDeleted () { 463 isDeleted () {
464 return null !== this.deletedAt 464 return this.deletedAt !== null
465 } 465 }
466 466
467 extractMentions () { 467 extractMentions () {
diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts
index bb50edcaa..55b0ed062 100644
--- a/server/models/video/video-format-utils.ts
+++ b/server/models/video/video-format-utils.ts
@@ -27,12 +27,13 @@ import { generateMagnetUri } from '@server/helpers/webtorrent'
27export type VideoFormattingJSONOptions = { 27export type VideoFormattingJSONOptions = {
28 completeDescription?: boolean 28 completeDescription?: boolean
29 additionalAttributes: { 29 additionalAttributes: {
30 state?: boolean, 30 state?: boolean
31 waitTranscoding?: boolean, 31 waitTranscoding?: boolean
32 scheduledUpdate?: boolean, 32 scheduledUpdate?: boolean
33 blacklistInfo?: boolean 33 blacklistInfo?: boolean
34 } 34 }
35} 35}
36
36function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { 37function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video {
37 const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined 38 const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined
38 39
@@ -181,12 +182,10 @@ function videoFilesModelToFormattedJSON (
181): VideoFile[] { 182): VideoFile[] {
182 return videoFiles 183 return videoFiles
183 .map(videoFile => { 184 .map(videoFile => {
184 let resolutionLabel = videoFile.resolution + 'p'
185
186 return { 185 return {
187 resolution: { 186 resolution: {
188 id: videoFile.resolution, 187 id: videoFile.resolution,
189 label: resolutionLabel 188 label: videoFile.resolution + 'p'
190 }, 189 },
191 magnetUri: generateMagnetUri(model, videoFile, baseUrlHttp, baseUrlWs), 190 magnetUri: generateMagnetUri(model, videoFile, baseUrlHttp, baseUrlWs),
192 size: videoFile.size, 191 size: videoFile.size,
@@ -214,7 +213,7 @@ function addVideoFilesInAPAcc (
214 for (const file of files) { 213 for (const file of files) {
215 acc.push({ 214 acc.push({
216 type: 'Link', 215 type: 'Link',
217 mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ file.extname ] as any, 216 mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[file.extname] as any,
218 href: model.getVideoFileUrl(file, baseUrlHttp), 217 href: model.getVideoFileUrl(file, baseUrlHttp),
219 height: file.resolution, 218 height: file.resolution,
220 size: file.size, 219 size: file.size,
@@ -274,10 +273,8 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject {
274 addVideoFilesInAPAcc(url, video, baseUrlHttp, baseUrlWs, video.VideoFiles || []) 273 addVideoFilesInAPAcc(url, video, baseUrlHttp, baseUrlWs, video.VideoFiles || [])
275 274
276 for (const playlist of (video.VideoStreamingPlaylists || [])) { 275 for (const playlist of (video.VideoStreamingPlaylists || [])) {
277 let tag: ActivityTagObject[] 276 const tag = playlist.p2pMediaLoaderInfohashes
278 277 .map(i => ({ type: 'Infohash' as 'Infohash', name: i })) as ActivityTagObject[]
279 tag = playlist.p2pMediaLoaderInfohashes
280 .map(i => ({ type: 'Infohash' as 'Infohash', name: i }))
281 tag.push({ 278 tag.push({
282 type: 'Link', 279 type: 'Link',
283 name: 'sha256', 280 name: 'sha256',
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts
index f2d71357f..4ba16f5fd 100644
--- a/server/models/video/video-playlist-element.ts
+++ b/server/models/video/video-playlist-element.ts
@@ -120,10 +120,10 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
120 } 120 }
121 121
122 static listForApi (options: { 122 static listForApi (options: {
123 start: number, 123 start: number
124 count: number, 124 count: number
125 videoPlaylistId: number, 125 videoPlaylistId: number
126 serverAccount: AccountModel, 126 serverAccount: AccountModel
127 user?: MUserAccountId 127 user?: MUserAccountId
128 }) { 128 }) {
129 const accountIds = [ options.serverAccount.id ] 129 const accountIds = [ options.serverAccount.id ]
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts
index ba1fc23ea..4ca17ebec 100644
--- a/server/models/video/video-playlist.ts
+++ b/server/models/video/video-playlist.ts
@@ -68,12 +68,12 @@ type AvailableForListOptions = {
68 type?: VideoPlaylistType 68 type?: VideoPlaylistType
69 accountId?: number 69 accountId?: number
70 videoChannelId?: number 70 videoChannelId?: number
71 listMyPlaylists?: boolean, 71 listMyPlaylists?: boolean
72 search?: string 72 search?: string
73} 73}
74 74
75@Scopes(() => ({ 75@Scopes(() => ({
76 [ ScopeNames.WITH_THUMBNAIL ]: { 76 [ScopeNames.WITH_THUMBNAIL]: {
77 include: [ 77 include: [
78 { 78 {
79 model: ThumbnailModel, 79 model: ThumbnailModel,
@@ -81,7 +81,7 @@ type AvailableForListOptions = {
81 } 81 }
82 ] 82 ]
83 }, 83 },
84 [ ScopeNames.WITH_VIDEOS_LENGTH ]: { 84 [ScopeNames.WITH_VIDEOS_LENGTH]: {
85 attributes: { 85 attributes: {
86 include: [ 86 include: [
87 [ 87 [
@@ -91,7 +91,7 @@ type AvailableForListOptions = {
91 ] 91 ]
92 } 92 }
93 } as FindOptions, 93 } as FindOptions,
94 [ ScopeNames.WITH_ACCOUNT ]: { 94 [ScopeNames.WITH_ACCOUNT]: {
95 include: [ 95 include: [
96 { 96 {
97 model: AccountModel, 97 model: AccountModel,
@@ -99,7 +99,7 @@ type AvailableForListOptions = {
99 } 99 }
100 ] 100 ]
101 }, 101 },
102 [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY ]: { 102 [ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY]: {
103 include: [ 103 include: [
104 { 104 {
105 model: AccountModel.scope(AccountScopeNames.SUMMARY), 105 model: AccountModel.scope(AccountScopeNames.SUMMARY),
@@ -111,7 +111,7 @@ type AvailableForListOptions = {
111 } 111 }
112 ] 112 ]
113 }, 113 },
114 [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL ]: { 114 [ScopeNames.WITH_ACCOUNT_AND_CHANNEL]: {
115 include: [ 115 include: [
116 { 116 {
117 model: AccountModel, 117 model: AccountModel,
@@ -123,7 +123,7 @@ type AvailableForListOptions = {
123 } 123 }
124 ] 124 ]
125 }, 125 },
126 [ ScopeNames.AVAILABLE_FOR_LIST ]: (options: AvailableForListOptions) => { 126 [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => {
127 127
128 let whereActor: WhereOptions = {} 128 let whereActor: WhereOptions = {}
129 129
@@ -138,13 +138,13 @@ type AvailableForListOptions = {
138 const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) 138 const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId)
139 139
140 whereActor = { 140 whereActor = {
141 [ Op.or ]: [ 141 [Op.or]: [
142 { 142 {
143 serverId: null 143 serverId: null
144 }, 144 },
145 { 145 {
146 serverId: { 146 serverId: {
147 [ Op.in ]: literal(inQueryInstanceFollow) 147 [Op.in]: literal(inQueryInstanceFollow)
148 } 148 }
149 } 149 }
150 ] 150 ]
@@ -172,7 +172,7 @@ type AvailableForListOptions = {
172 if (options.search) { 172 if (options.search) {
173 whereAnd.push({ 173 whereAnd.push({
174 name: { 174 name: {
175 [ Op.iLike ]: '%' + options.search + '%' 175 [Op.iLike]: '%' + options.search + '%'
176 } 176 }
177 }) 177 })
178 } 178 }
@@ -299,13 +299,13 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
299 299
300 static listForApi (options: { 300 static listForApi (options: {
301 followerActorId: number 301 followerActorId: number
302 start: number, 302 start: number
303 count: number, 303 count: number
304 sort: string, 304 sort: string
305 type?: VideoPlaylistType, 305 type?: VideoPlaylistType
306 accountId?: number, 306 accountId?: number
307 videoChannelId?: number, 307 videoChannelId?: number
308 listMyPlaylists?: boolean, 308 listMyPlaylists?: boolean
309 search?: string 309 search?: string
310 }) { 310 }) {
311 const query = { 311 const query = {
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index 1a924e6c9..1ec8d717e 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -187,7 +187,7 @@ export type AvailableForListIDsOptions = {
187} 187}
188 188
189@Scopes(() => ({ 189@Scopes(() => ({
190 [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => { 190 [ScopeNames.FOR_API]: (options: ForAPIOptions) => {
191 const query: FindOptions = { 191 const query: FindOptions = {
192 include: [ 192 include: [
193 { 193 {
@@ -212,7 +212,7 @@ export type AvailableForListIDsOptions = {
212 if (options.ids) { 212 if (options.ids) {
213 query.where = { 213 query.where = {
214 id: { 214 id: {
215 [ Op.in ]: options.ids 215 [Op.in]: options.ids
216 } 216 }
217 } 217 }
218 } 218 }
@@ -236,7 +236,7 @@ export type AvailableForListIDsOptions = {
236 236
237 return query 237 return query
238 }, 238 },
239 [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => { 239 [ScopeNames.AVAILABLE_FOR_LIST_IDS]: (options: AvailableForListIDsOptions) => {
240 const whereAnd = options.baseWhere ? [].concat(options.baseWhere) : [] 240 const whereAnd = options.baseWhere ? [].concat(options.baseWhere) : []
241 241
242 const query: FindOptions = { 242 const query: FindOptions = {
@@ -247,11 +247,11 @@ export type AvailableForListIDsOptions = {
247 const attributesType = options.attributesType || 'id' 247 const attributesType = options.attributesType || 'id'
248 248
249 if (attributesType === 'id') query.attributes = [ 'id' ] 249 if (attributesType === 'id') query.attributes = [ 'id' ]
250 else if (attributesType === 'none') query.attributes = [ ] 250 else if (attributesType === 'none') query.attributes = []
251 251
252 whereAnd.push({ 252 whereAnd.push({
253 id: { 253 id: {
254 [ Op.notIn ]: Sequelize.literal( 254 [Op.notIn]: Sequelize.literal(
255 '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' 255 '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")'
256 ) 256 )
257 } 257 }
@@ -260,7 +260,7 @@ export type AvailableForListIDsOptions = {
260 if (options.serverAccountId) { 260 if (options.serverAccountId) {
261 whereAnd.push({ 261 whereAnd.push({
262 channelId: { 262 channelId: {
263 [ Op.notIn ]: Sequelize.literal( 263 [Op.notIn]: Sequelize.literal(
264 '(' + 264 '(' +
265 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' + 265 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' +
266 buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) + 266 buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) +
@@ -273,15 +273,14 @@ export type AvailableForListIDsOptions = {
273 273
274 // Only list public/published videos 274 // Only list public/published videos
275 if (!options.filter || options.filter !== 'all-local') { 275 if (!options.filter || options.filter !== 'all-local') {
276
277 const publishWhere = { 276 const publishWhere = {
278 // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding 277 // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding
279 [ Op.or ]: [ 278 [Op.or]: [
280 { 279 {
281 state: VideoState.PUBLISHED 280 state: VideoState.PUBLISHED
282 }, 281 },
283 { 282 {
284 [ Op.and ]: { 283 [Op.and]: {
285 state: VideoState.TO_TRANSCODE, 284 state: VideoState.TO_TRANSCODE,
286 waitTranscoding: false 285 waitTranscoding: false
287 } 286 }
@@ -368,7 +367,7 @@ export type AvailableForListIDsOptions = {
368 [Op.or]: [ 367 [Op.or]: [
369 { 368 {
370 id: { 369 id: {
371 [ Op.in ]: Sequelize.literal( 370 [Op.in]: Sequelize.literal(
372 '(' + 371 '(' +
373 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + 372 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
374 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + 373 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
@@ -379,7 +378,7 @@ export type AvailableForListIDsOptions = {
379 }, 378 },
380 { 379 {
381 id: { 380 id: {
382 [ Op.in ]: Sequelize.literal( 381 [Op.in]: Sequelize.literal(
383 '(' + 382 '(' +
384 'SELECT "video"."id" AS "id" FROM "video" ' + 383 'SELECT "video"."id" AS "id" FROM "video" ' +
385 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + 384 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
@@ -399,7 +398,7 @@ export type AvailableForListIDsOptions = {
399 if (options.withFiles === true) { 398 if (options.withFiles === true) {
400 whereAnd.push({ 399 whereAnd.push({
401 id: { 400 id: {
402 [ Op.in ]: Sequelize.literal( 401 [Op.in]: Sequelize.literal(
403 '(SELECT "videoId" FROM "videoFile")' 402 '(SELECT "videoId" FROM "videoFile")'
404 ) 403 )
405 } 404 }
@@ -413,7 +412,7 @@ export type AvailableForListIDsOptions = {
413 412
414 whereAnd.push({ 413 whereAnd.push({
415 id: { 414 id: {
416 [ Op.in ]: Sequelize.literal( 415 [Op.in]: Sequelize.literal(
417 '(' + 416 '(' +
418 'SELECT "videoId" FROM "videoTag" ' + 417 'SELECT "videoId" FROM "videoTag" ' +
419 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + 418 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
@@ -429,7 +428,7 @@ export type AvailableForListIDsOptions = {
429 428
430 whereAnd.push({ 429 whereAnd.push({
431 id: { 430 id: {
432 [ Op.in ]: Sequelize.literal( 431 [Op.in]: Sequelize.literal(
433 '(' + 432 '(' +
434 'SELECT "videoId" FROM "videoTag" ' + 433 'SELECT "videoId" FROM "videoTag" ' +
435 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + 434 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
@@ -449,7 +448,7 @@ export type AvailableForListIDsOptions = {
449 if (options.categoryOneOf) { 448 if (options.categoryOneOf) {
450 whereAnd.push({ 449 whereAnd.push({
451 category: { 450 category: {
452 [ Op.or ]: options.categoryOneOf 451 [Op.or]: options.categoryOneOf
453 } 452 }
454 }) 453 })
455 } 454 }
@@ -457,7 +456,7 @@ export type AvailableForListIDsOptions = {
457 if (options.licenceOneOf) { 456 if (options.licenceOneOf) {
458 whereAnd.push({ 457 whereAnd.push({
459 licence: { 458 licence: {
460 [ Op.or ]: options.licenceOneOf 459 [Op.or]: options.licenceOneOf
461 } 460 }
462 }) 461 })
463 } 462 }
@@ -472,12 +471,12 @@ export type AvailableForListIDsOptions = {
472 [Op.or]: [ 471 [Op.or]: [
473 { 472 {
474 language: { 473 language: {
475 [ Op.or ]: videoLanguages 474 [Op.or]: videoLanguages
476 } 475 }
477 }, 476 },
478 { 477 {
479 id: { 478 id: {
480 [ Op.in ]: Sequelize.literal( 479 [Op.in]: Sequelize.literal(
481 '(' + 480 '(' +
482 'SELECT "videoId" FROM "videoCaption" ' + 481 'SELECT "videoId" FROM "videoCaption" ' +
483 'WHERE "language" IN (' + createSafeIn(VideoModel, options.languageOneOf) + ') ' + 482 'WHERE "language" IN (' + createSafeIn(VideoModel, options.languageOneOf) + ') ' +
@@ -511,12 +510,12 @@ export type AvailableForListIDsOptions = {
511 } 510 }
512 511
513 query.where = { 512 query.where = {
514 [ Op.and ]: whereAnd 513 [Op.and]: whereAnd
515 } 514 }
516 515
517 return query 516 return query
518 }, 517 },
519 [ ScopeNames.WITH_THUMBNAILS ]: { 518 [ScopeNames.WITH_THUMBNAILS]: {
520 include: [ 519 include: [
521 { 520 {
522 model: ThumbnailModel, 521 model: ThumbnailModel,
@@ -524,7 +523,7 @@ export type AvailableForListIDsOptions = {
524 } 523 }
525 ] 524 ]
526 }, 525 },
527 [ ScopeNames.WITH_USER_ID ]: { 526 [ScopeNames.WITH_USER_ID]: {
528 include: [ 527 include: [
529 { 528 {
530 attributes: [ 'accountId' ], 529 attributes: [ 'accountId' ],
@@ -540,7 +539,7 @@ export type AvailableForListIDsOptions = {
540 } 539 }
541 ] 540 ]
542 }, 541 },
543 [ ScopeNames.WITH_ACCOUNT_DETAILS ]: { 542 [ScopeNames.WITH_ACCOUNT_DETAILS]: {
544 include: [ 543 include: [
545 { 544 {
546 model: VideoChannelModel.unscoped(), 545 model: VideoChannelModel.unscoped(),
@@ -592,10 +591,10 @@ export type AvailableForListIDsOptions = {
592 } 591 }
593 ] 592 ]
594 }, 593 },
595 [ ScopeNames.WITH_TAGS ]: { 594 [ScopeNames.WITH_TAGS]: {
596 include: [ TagModel ] 595 include: [ TagModel ]
597 }, 596 },
598 [ ScopeNames.WITH_BLACKLISTED ]: { 597 [ScopeNames.WITH_BLACKLISTED]: {
599 include: [ 598 include: [
600 { 599 {
601 attributes: [ 'id', 'reason', 'unfederated' ], 600 attributes: [ 'id', 'reason', 'unfederated' ],
@@ -604,7 +603,7 @@ export type AvailableForListIDsOptions = {
604 } 603 }
605 ] 604 ]
606 }, 605 },
607 [ ScopeNames.WITH_WEBTORRENT_FILES ]: (withRedundancies = false) => { 606 [ScopeNames.WITH_WEBTORRENT_FILES]: (withRedundancies = false) => {
608 let subInclude: any[] = [] 607 let subInclude: any[] = []
609 608
610 if (withRedundancies === true) { 609 if (withRedundancies === true) {
@@ -628,7 +627,7 @@ export type AvailableForListIDsOptions = {
628 ] 627 ]
629 } 628 }
630 }, 629 },
631 [ ScopeNames.WITH_STREAMING_PLAYLISTS ]: (withRedundancies = false) => { 630 [ScopeNames.WITH_STREAMING_PLAYLISTS]: (withRedundancies = false) => {
632 const subInclude: IncludeOptions[] = [ 631 const subInclude: IncludeOptions[] = [
633 { 632 {
634 model: VideoFileModel.unscoped(), 633 model: VideoFileModel.unscoped(),
@@ -655,7 +654,7 @@ export type AvailableForListIDsOptions = {
655 ] 654 ]
656 } 655 }
657 }, 656 },
658 [ ScopeNames.WITH_SCHEDULED_UPDATE ]: { 657 [ScopeNames.WITH_SCHEDULED_UPDATE]: {
659 include: [ 658 include: [
660 { 659 {
661 model: ScheduleVideoUpdateModel.unscoped(), 660 model: ScheduleVideoUpdateModel.unscoped(),
@@ -663,7 +662,7 @@ export type AvailableForListIDsOptions = {
663 } 662 }
664 ] 663 ]
665 }, 664 },
666 [ ScopeNames.WITH_USER_HISTORY ]: (userId: number) => { 665 [ScopeNames.WITH_USER_HISTORY]: (userId: number) => {
667 return { 666 return {
668 include: [ 667 include: [
669 { 668 {
@@ -1016,7 +1015,7 @@ export class VideoModel extends Model<VideoModel> {
1016 }, 1015 },
1017 onDelete: 'cascade', 1016 onDelete: 'cascade',
1018 hooks: true, 1017 hooks: true,
1019 [ 'separate' as any ]: true 1018 ['separate' as any]: true
1020 }) 1019 })
1021 VideoCaptions: VideoCaptionModel[] 1020 VideoCaptions: VideoCaptionModel[]
1022 1021
@@ -1112,9 +1111,9 @@ export class VideoModel extends Model<VideoModel> {
1112 order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings 1111 order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings
1113 where: { 1112 where: {
1114 id: { 1113 id: {
1115 [ Op.in ]: Sequelize.literal('(' + rawQuery + ')') 1114 [Op.in]: Sequelize.literal('(' + rawQuery + ')')
1116 }, 1115 },
1117 [ Op.or ]: [ 1116 [Op.or]: [
1118 { privacy: VideoPrivacy.PUBLIC }, 1117 { privacy: VideoPrivacy.PUBLIC },
1119 { privacy: VideoPrivacy.UNLISTED } 1118 { privacy: VideoPrivacy.UNLISTED }
1120 ] 1119 ]
@@ -1131,10 +1130,10 @@ export class VideoModel extends Model<VideoModel> {
1131 required: false, 1130 required: false,
1132 // We only want videos shared by this actor 1131 // We only want videos shared by this actor
1133 where: { 1132 where: {
1134 [ Op.and ]: [ 1133 [Op.and]: [
1135 { 1134 {
1136 id: { 1135 id: {
1137 [ Op.not ]: null 1136 [Op.not]: null
1138 } 1137 }
1139 }, 1138 },
1140 { 1139 {
@@ -1184,8 +1183,8 @@ export class VideoModel extends Model<VideoModel> {
1184 // totals: totalVideos + totalVideoShares 1183 // totals: totalVideos + totalVideoShares
1185 let totalVideos = 0 1184 let totalVideos = 0
1186 let totalVideoShares = 0 1185 let totalVideoShares = 0
1187 if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total, 10) 1186 if (totals[0]) totalVideos = parseInt(totals[0].total, 10)
1188 if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total, 10) 1187 if (totals[1]) totalVideoShares = parseInt(totals[1].total, 10)
1189 1188
1190 const total = totalVideos + totalVideoShares 1189 const total = totalVideos + totalVideoShares
1191 return { 1190 return {
@@ -1228,7 +1227,7 @@ export class VideoModel extends Model<VideoModel> {
1228 baseQuery = Object.assign(baseQuery, { 1227 baseQuery = Object.assign(baseQuery, {
1229 where: { 1228 where: {
1230 name: { 1229 name: {
1231 [ Op.iLike ]: '%' + search + '%' 1230 [Op.iLike]: '%' + search + '%'
1232 } 1231 }
1233 } 1232 }
1234 }) 1233 })
@@ -1258,25 +1257,25 @@ export class VideoModel extends Model<VideoModel> {
1258 } 1257 }
1259 1258
1260 static async listForApi (options: { 1259 static async listForApi (options: {
1261 start: number, 1260 start: number
1262 count: number, 1261 count: number
1263 sort: string, 1262 sort: string
1264 nsfw: boolean, 1263 nsfw: boolean
1265 includeLocalVideos: boolean, 1264 includeLocalVideos: boolean
1266 withFiles: boolean, 1265 withFiles: boolean
1267 categoryOneOf?: number[], 1266 categoryOneOf?: number[]
1268 licenceOneOf?: number[], 1267 licenceOneOf?: number[]
1269 languageOneOf?: string[], 1268 languageOneOf?: string[]
1270 tagsOneOf?: string[], 1269 tagsOneOf?: string[]
1271 tagsAllOf?: string[], 1270 tagsAllOf?: string[]
1272 filter?: VideoFilter, 1271 filter?: VideoFilter
1273 accountId?: number, 1272 accountId?: number
1274 videoChannelId?: number, 1273 videoChannelId?: number
1275 followerActorId?: number 1274 followerActorId?: number
1276 videoPlaylistId?: number, 1275 videoPlaylistId?: number
1277 trendingDays?: number, 1276 trendingDays?: number
1278 user?: MUserAccountId, 1277 user?: MUserAccountId
1279 historyOfUser?: MUserId, 1278 historyOfUser?: MUserId
1280 countVideos?: boolean 1279 countVideos?: boolean
1281 }) { 1280 }) {
1282 if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { 1281 if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
@@ -1342,7 +1341,7 @@ export class VideoModel extends Model<VideoModel> {
1342 tagsAllOf?: string[] 1341 tagsAllOf?: string[]
1343 durationMin?: number // seconds 1342 durationMin?: number // seconds
1344 durationMax?: number // seconds 1343 durationMax?: number // seconds
1345 user?: MUserAccountId, 1344 user?: MUserAccountId
1346 filter?: VideoFilter 1345 filter?: VideoFilter
1347 }) { 1346 }) {
1348 const whereAnd = [] 1347 const whereAnd = []
@@ -1350,8 +1349,8 @@ export class VideoModel extends Model<VideoModel> {
1350 if (options.startDate || options.endDate) { 1349 if (options.startDate || options.endDate) {
1351 const publishedAtRange = {} 1350 const publishedAtRange = {}
1352 1351
1353 if (options.startDate) publishedAtRange[ Op.gte ] = options.startDate 1352 if (options.startDate) publishedAtRange[Op.gte] = options.startDate
1354 if (options.endDate) publishedAtRange[ Op.lte ] = options.endDate 1353 if (options.endDate) publishedAtRange[Op.lte] = options.endDate
1355 1354
1356 whereAnd.push({ publishedAt: publishedAtRange }) 1355 whereAnd.push({ publishedAt: publishedAtRange })
1357 } 1356 }
@@ -1359,8 +1358,8 @@ export class VideoModel extends Model<VideoModel> {
1359 if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { 1358 if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) {
1360 const originallyPublishedAtRange = {} 1359 const originallyPublishedAtRange = {}
1361 1360
1362 if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Op.gte ] = options.originallyPublishedStartDate 1361 if (options.originallyPublishedStartDate) originallyPublishedAtRange[Op.gte] = options.originallyPublishedStartDate
1363 if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Op.lte ] = options.originallyPublishedEndDate 1362 if (options.originallyPublishedEndDate) originallyPublishedAtRange[Op.lte] = options.originallyPublishedEndDate
1364 1363
1365 whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) 1364 whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange })
1366 } 1365 }
@@ -1368,8 +1367,8 @@ export class VideoModel extends Model<VideoModel> {
1368 if (options.durationMin || options.durationMax) { 1367 if (options.durationMin || options.durationMax) {
1369 const durationRange = {} 1368 const durationRange = {}
1370 1369
1371 if (options.durationMin) durationRange[ Op.gte ] = options.durationMin 1370 if (options.durationMin) durationRange[Op.gte] = options.durationMin
1372 if (options.durationMax) durationRange[ Op.lte ] = options.durationMax 1371 if (options.durationMax) durationRange[Op.lte] = options.durationMax
1373 1372
1374 whereAnd.push({ duration: durationRange }) 1373 whereAnd.push({ duration: durationRange })
1375 } 1374 }
@@ -1380,7 +1379,7 @@ export class VideoModel extends Model<VideoModel> {
1380 if (options.search) { 1379 if (options.search) {
1381 const trigramSearch = { 1380 const trigramSearch = {
1382 id: { 1381 id: {
1383 [ Op.in ]: Sequelize.literal( 1382 [Op.in]: Sequelize.literal(
1384 '(' + 1383 '(' +
1385 'SELECT "video"."id" FROM "video" ' + 1384 'SELECT "video"."id" FROM "video" ' +
1386 'WHERE ' + 1385 'WHERE ' +
@@ -1578,8 +1577,8 @@ export class VideoModel extends Model<VideoModel> {
1578 } 1577 }
1579 1578
1580 static loadForGetAPI (parameters: { 1579 static loadForGetAPI (parameters: {
1581 id: number | string, 1580 id: number | string
1582 t?: Transaction, 1581 t?: Transaction
1583 userId?: number 1582 userId?: number
1584 }): Bluebird<MVideoDetails> { 1583 }): Bluebird<MVideoDetails> {
1585 const { id, t, userId } = parameters 1584 const { id, t, userId } = parameters
@@ -1645,9 +1644,9 @@ export class VideoModel extends Model<VideoModel> {
1645 static checkVideoHasInstanceFollow (videoId: number, followerActorId: number) { 1644 static checkVideoHasInstanceFollow (videoId: number, followerActorId: number) {
1646 // Instances only share videos 1645 // Instances only share videos
1647 const query = 'SELECT 1 FROM "videoShare" ' + 1646 const query = 'SELECT 1 FROM "videoShare" ' +
1648 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + 1647 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
1649 'WHERE "actorFollow"."actorId" = $followerActorId AND "videoShare"."videoId" = $videoId ' + 1648 'WHERE "actorFollow"."actorId" = $followerActorId AND "videoShare"."videoId" = $videoId ' +
1650 'LIMIT 1' 1649 'LIMIT 1'
1651 1650
1652 const options = { 1651 const options = {
1653 type: QueryTypes.SELECT as QueryTypes.SELECT, 1652 type: QueryTypes.SELECT as QueryTypes.SELECT,
@@ -1679,7 +1678,7 @@ export class VideoModel extends Model<VideoModel> {
1679 } 1678 }
1680 1679
1681 return VideoModel.findAll(query) 1680 return VideoModel.findAll(query)
1682 .then(videos => videos.map(v => v.id)) 1681 .then(videos => videos.map(v => v.id))
1683 } 1682 }
1684 1683
1685 // threshold corresponds to how many video the field should have to be returned 1684 // threshold corresponds to how many video the field should have to be returned
@@ -1699,14 +1698,14 @@ export class VideoModel extends Model<VideoModel> {
1699 limit: count, 1698 limit: count,
1700 group: field, 1699 group: field,
1701 having: Sequelize.where( 1700 having: Sequelize.where(
1702 Sequelize.fn('COUNT', Sequelize.col(field)), { [ Op.gte ]: threshold } 1701 Sequelize.fn('COUNT', Sequelize.col(field)), { [Op.gte]: threshold }
1703 ), 1702 ),
1704 order: [ (this.sequelize as any).random() ] 1703 order: [ (this.sequelize as any).random() ]
1705 } 1704 }
1706 1705
1707 return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) 1706 return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] })
1708 .findAll(query) 1707 .findAll(query)
1709 .then(rows => rows.map(r => r[ field ])) 1708 .then(rows => rows.map(r => r[field]))
1710 } 1709 }
1711 1710
1712 static buildTrendingQuery (trendingDays: number) { 1711 static buildTrendingQuery (trendingDays: number) {
@@ -1717,7 +1716,7 @@ export class VideoModel extends Model<VideoModel> {
1717 required: false, 1716 required: false,
1718 where: { 1717 where: {
1719 startDate: { 1718 startDate: {
1720 [ Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) 1719 [Op.gte]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays)
1721 } 1720 }
1722 } 1721 }
1723 } 1722 }
@@ -1800,23 +1799,23 @@ export class VideoModel extends Model<VideoModel> {
1800 } 1799 }
1801 1800
1802 static getCategoryLabel (id: number) { 1801 static getCategoryLabel (id: number) {
1803 return VIDEO_CATEGORIES[ id ] || 'Misc' 1802 return VIDEO_CATEGORIES[id] || 'Misc'
1804 } 1803 }
1805 1804
1806 static getLicenceLabel (id: number) { 1805 static getLicenceLabel (id: number) {
1807 return VIDEO_LICENCES[ id ] || 'Unknown' 1806 return VIDEO_LICENCES[id] || 'Unknown'
1808 } 1807 }
1809 1808
1810 static getLanguageLabel (id: string) { 1809 static getLanguageLabel (id: string) {
1811 return VIDEO_LANGUAGES[ id ] || 'Unknown' 1810 return VIDEO_LANGUAGES[id] || 'Unknown'
1812 } 1811 }
1813 1812
1814 static getPrivacyLabel (id: number) { 1813 static getPrivacyLabel (id: number) {
1815 return VIDEO_PRIVACIES[ id ] || 'Unknown' 1814 return VIDEO_PRIVACIES[id] || 'Unknown'
1816 } 1815 }
1817 1816
1818 static getStateLabel (id: number) { 1817 static getStateLabel (id: number) {
1819 return VIDEO_STATES[ id ] || 'Unknown' 1818 return VIDEO_STATES[id] || 'Unknown'
1820 } 1819 }
1821 1820
1822 isBlacklisted () { 1821 isBlacklisted () {
@@ -1828,7 +1827,7 @@ export class VideoModel extends Model<VideoModel> {
1828 this.VideoChannel.Account.isBlocked() 1827 this.VideoChannel.Account.isBlocked()
1829 } 1828 }
1830 1829
1831 getQualityFileBy <T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) { 1830 getQualityFileBy<T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) {
1832 if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) { 1831 if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) {
1833 const file = fun(this.VideoFiles, file => file.resolution) 1832 const file = fun(this.VideoFiles, file => file.resolution)
1834 1833
@@ -1846,15 +1845,15 @@ export class VideoModel extends Model<VideoModel> {
1846 return undefined 1845 return undefined
1847 } 1846 }
1848 1847
1849 getMaxQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { 1848 getMaxQualityFile<T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo {
1850 return this.getQualityFileBy(maxBy) 1849 return this.getQualityFileBy(maxBy)
1851 } 1850 }
1852 1851
1853 getMinQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { 1852 getMinQualityFile<T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo {
1854 return this.getQualityFileBy(minBy) 1853 return this.getQualityFileBy(minBy)
1855 } 1854 }
1856 1855
1857 getWebTorrentFile <T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo { 1856 getWebTorrentFile<T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo {
1858 if (Array.isArray(this.VideoFiles) === false) return undefined 1857 if (Array.isArray(this.VideoFiles) === false) return undefined
1859 1858
1860 const file = this.VideoFiles.find(f => f.resolution === resolution) 1859 const file = this.VideoFiles.find(f => f.resolution === resolution)
@@ -1977,8 +1976,8 @@ export class VideoModel extends Model<VideoModel> {
1977 } 1976 }
1978 1977
1979 this.VideoStreamingPlaylists = this.VideoStreamingPlaylists 1978 this.VideoStreamingPlaylists = this.VideoStreamingPlaylists
1980 .filter(s => s.type !== VideoStreamingPlaylistType.HLS) 1979 .filter(s => s.type !== VideoStreamingPlaylistType.HLS)
1981 .concat(toAdd) 1980 .concat(toAdd)
1982 } 1981 }
1983 1982
1984 removeFile (videoFile: MVideoFile, isRedundancy = false) { 1983 removeFile (videoFile: MVideoFile, isRedundancy = false) {
@@ -1999,7 +1998,7 @@ export class VideoModel extends Model<VideoModel> {
1999 await remove(directoryPath) 1998 await remove(directoryPath)
2000 1999
2001 if (isRedundancy !== true) { 2000 if (isRedundancy !== true) {
2002 let streamingPlaylistWithFiles = streamingPlaylist as MStreamingPlaylistFilesVideo 2001 const streamingPlaylistWithFiles = streamingPlaylist as MStreamingPlaylistFilesVideo
2003 streamingPlaylistWithFiles.Video = this 2002 streamingPlaylistWithFiles.Video = this
2004 2003
2005 if (!Array.isArray(streamingPlaylistWithFiles.VideoFiles)) { 2004 if (!Array.isArray(streamingPlaylistWithFiles.VideoFiles)) {
diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts
index 34c6be49b..d16f05108 100644
--- a/server/tests/api/activitypub/client.ts
+++ b/server/tests/api/activitypub/client.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -6,8 +6,6 @@ import {
6 cleanupTests, 6 cleanupTests,
7 doubleFollow, 7 doubleFollow,
8 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
9 flushTests,
10 killallServers,
11 makeActivityPubGetRequest, 9 makeActivityPubGetRequest,
12 ServerInfo, 10 ServerInfo,
13 setAccessTokensToServers, 11 setAccessTokensToServers,
diff --git a/server/tests/api/activitypub/fetch.ts b/server/tests/api/activitypub/fetch.ts
index 3d54c2042..35fd94eed 100644
--- a/server/tests/api/activitypub/fetch.ts
+++ b/server/tests/api/activitypub/fetch.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
@@ -8,9 +8,7 @@ import {
8 createUser, 8 createUser,
9 doubleFollow, 9 doubleFollow,
10 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
11 flushTests,
12 getVideosListSort, 11 getVideosListSort,
13 killallServers,
14 ServerInfo, 12 ServerInfo,
15 setAccessTokensToServers, 13 setAccessTokensToServers,
16 setActorField, 14 setActorField,
diff --git a/server/tests/api/activitypub/helpers.ts b/server/tests/api/activitypub/helpers.ts
index 8c00ba3d6..60d95b823 100644
--- a/server/tests/api/activitypub/helpers.ts
+++ b/server/tests/api/activitypub/helpers.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { expect } from 'chai' 4import { expect } from 'chai'
diff --git a/server/tests/api/activitypub/refresher.ts b/server/tests/api/activitypub/refresher.ts
index aa4bc6c0f..232c5d823 100644
--- a/server/tests/api/activitypub/refresher.ts
+++ b/server/tests/api/activitypub/refresher.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { 4import {
@@ -43,32 +43,32 @@ describe('Test AP refresher', function () {
43 await setDefaultVideoChannel(servers) 43 await setDefaultVideoChannel(servers)
44 44
45 { 45 {
46 videoUUID1 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video1' })).uuid 46 videoUUID1 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video1' })).uuid
47 videoUUID2 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video2' })).uuid 47 videoUUID2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video2' })).uuid
48 videoUUID3 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video3' })).uuid 48 videoUUID3 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video3' })).uuid
49 } 49 }
50 50
51 { 51 {
52 const a1 = await generateUserAccessToken(servers[ 1 ], 'user1') 52 const a1 = await generateUserAccessToken(servers[1], 'user1')
53 await uploadVideo(servers[ 1 ].url, a1, { name: 'video4' }) 53 await uploadVideo(servers[1].url, a1, { name: 'video4' })
54 54
55 const a2 = await generateUserAccessToken(servers[ 1 ], 'user2') 55 const a2 = await generateUserAccessToken(servers[1], 'user2')
56 await uploadVideo(servers[ 1 ].url, a2, { name: 'video5' }) 56 await uploadVideo(servers[1].url, a2, { name: 'video5' })
57 } 57 }
58 58
59 { 59 {
60 const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id } 60 const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id }
61 const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs }) 61 const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs })
62 playlistUUID1 = res.body.videoPlaylist.uuid 62 playlistUUID1 = res.body.videoPlaylist.uuid
63 } 63 }
64 64
65 { 65 {
66 const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id } 66 const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id }
67 const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs }) 67 const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs })
68 playlistUUID2 = res.body.videoPlaylist.uuid 68 playlistUUID2 = res.body.videoPlaylist.uuid
69 } 69 }
70 70
71 await doubleFollow(servers[ 0 ], servers[ 1 ]) 71 await doubleFollow(servers[0], servers[1])
72 }) 72 })
73 73
74 describe('Videos refresher', function () { 74 describe('Videos refresher', function () {
@@ -79,34 +79,34 @@ describe('Test AP refresher', function () {
79 await wait(10000) 79 await wait(10000)
80 80
81 // Change UUID so the remote server returns a 404 81 // Change UUID so the remote server returns a 404
82 await setVideoField(servers[ 1 ].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') 82 await setVideoField(servers[1].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f')
83 83
84 await getVideo(servers[ 0 ].url, videoUUID1) 84 await getVideo(servers[0].url, videoUUID1)
85 await getVideo(servers[ 0 ].url, videoUUID2) 85 await getVideo(servers[0].url, videoUUID2)
86 86
87 await waitJobs(servers) 87 await waitJobs(servers)
88 88
89 await getVideo(servers[ 0 ].url, videoUUID1, 404) 89 await getVideo(servers[0].url, videoUUID1, 404)
90 await getVideo(servers[ 0 ].url, videoUUID2, 200) 90 await getVideo(servers[0].url, videoUUID2, 200)
91 }) 91 })
92 92
93 it('Should not update a remote video if the remote instance is down', async function () { 93 it('Should not update a remote video if the remote instance is down', async function () {
94 this.timeout(70000) 94 this.timeout(70000)
95 95
96 killallServers([ servers[ 1 ] ]) 96 killallServers([ servers[1] ])
97 97
98 await setVideoField(servers[ 1 ].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') 98 await setVideoField(servers[1].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e')
99 99
100 // Video will need a refresh 100 // Video will need a refresh
101 await wait(10000) 101 await wait(10000)
102 102
103 await getVideo(servers[ 0 ].url, videoUUID3) 103 await getVideo(servers[0].url, videoUUID3)
104 // The refresh should fail 104 // The refresh should fail
105 await waitJobs([ servers[ 0 ] ]) 105 await waitJobs([ servers[0] ])
106 106
107 await reRunServer(servers[ 1 ]) 107 await reRunServer(servers[1])
108 108
109 await getVideo(servers[ 0 ].url, videoUUID3, 200) 109 await getVideo(servers[0].url, videoUUID3, 200)
110 }) 110 })
111 }) 111 })
112 112
@@ -118,16 +118,16 @@ describe('Test AP refresher', function () {
118 await wait(10000) 118 await wait(10000)
119 119
120 // Change actor name so the remote server returns a 404 120 // Change actor name so the remote server returns a 404
121 const to = 'http://localhost:' + servers[ 1 ].port + '/accounts/user2' 121 const to = 'http://localhost:' + servers[1].port + '/accounts/user2'
122 await setActorField(servers[ 1 ].internalServerNumber, to, 'preferredUsername', 'toto') 122 await setActorField(servers[1].internalServerNumber, to, 'preferredUsername', 'toto')
123 123
124 await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port) 124 await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port)
125 await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port) 125 await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port)
126 126
127 await waitJobs(servers) 127 await waitJobs(servers)
128 128
129 await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port, 200) 129 await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port, 200)
130 await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port, 404) 130 await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port, 404)
131 }) 131 })
132 }) 132 })
133 133
@@ -139,15 +139,15 @@ describe('Test AP refresher', function () {
139 await wait(10000) 139 await wait(10000)
140 140
141 // Change UUID so the remote server returns a 404 141 // Change UUID so the remote server returns a 404
142 await setPlaylistField(servers[ 1 ].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') 142 await setPlaylistField(servers[1].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e')
143 143
144 await getVideoPlaylist(servers[ 0 ].url, playlistUUID1) 144 await getVideoPlaylist(servers[0].url, playlistUUID1)
145 await getVideoPlaylist(servers[ 0 ].url, playlistUUID2) 145 await getVideoPlaylist(servers[0].url, playlistUUID2)
146 146
147 await waitJobs(servers) 147 await waitJobs(servers)
148 148
149 await getVideoPlaylist(servers[ 0 ].url, playlistUUID1, 200) 149 await getVideoPlaylist(servers[0].url, playlistUUID1, 200)
150 await getVideoPlaylist(servers[ 0 ].url, playlistUUID2, 404) 150 await getVideoPlaylist(servers[0].url, playlistUUID2, 404)
151 }) 151 })
152 }) 152 })
153 153
diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts
index dc960c5c3..7e58bf065 100644
--- a/server/tests/api/activitypub/security.ts
+++ b/server/tests/api/activitypub/security.ts
@@ -1,15 +1,8 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
5import { 5import { cleanupTests, closeAllSequelize, flushAndRunMultipleServers, ServerInfo, setActorField } from '../../../../shared/extra-utils'
6 cleanupTests,
7 closeAllSequelize,
8 flushAndRunMultipleServers,
9 killallServers,
10 ServerInfo,
11 setActorField
12} from '../../../../shared/extra-utils'
13import { HTTP_SIGNATURE } from '../../../initializers/constants' 6import { HTTP_SIGNATURE } from '../../../initializers/constants'
14import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' 7import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils'
15import * as chai from 'chai' 8import * as chai from 'chai'
@@ -33,7 +26,7 @@ function getAnnounceWithoutContext (server2: ServerInfo) {
33 if (Array.isArray(json[key])) { 26 if (Array.isArray(json[key])) {
34 result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`)) 27 result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`))
35 } else { 28 } else {
36 result[ key ] = json[ key ].replace(':9002', `:${server2.port}`) 29 result[key] = json[key].replace(':9002', `:${server2.port}`)
37 } 30 }
38 } 31 }
39 32
diff --git a/server/tests/api/check-params/accounts.ts b/server/tests/api/check-params/accounts.ts
index 4f79685bd..c29af7cd7 100644
--- a/server/tests/api/check-params/accounts.ts
+++ b/server/tests/api/check-params/accounts.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
diff --git a/server/tests/api/check-params/blocklist.ts b/server/tests/api/check-params/blocklist.ts
index 0661676ce..fb459f756 100644
--- a/server/tests/api/check-params/blocklist.ts
+++ b/server/tests/api/check-params/blocklist.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts
index 443fbcb60..f1a79806b 100644
--- a/server/tests/api/check-params/config.ts
+++ b/server/tests/api/check-params/config.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { omit } from 'lodash' 3import { omit } from 'lodash'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/api/check-params/contact-form.ts b/server/tests/api/check-params/contact-form.ts
index b3051945e..b2126b9b0 100644
--- a/server/tests/api/check-params/contact-form.ts
+++ b/server/tests/api/check-params/contact-form.ts
@@ -1,22 +1,8 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
5import { 5import { cleanupTests, flushAndRunServer, immutableAssign, killallServers, reRunServer, ServerInfo } from '../../../../shared/extra-utils'
6 flushTests,
7 immutableAssign,
8 killallServers,
9 reRunServer,
10 flushAndRunServer,
11 ServerInfo,
12 setAccessTokensToServers, cleanupTests
13} from '../../../../shared/extra-utils'
14import {
15 checkBadCountPagination,
16 checkBadSortPagination,
17 checkBadStartPagination
18} from '../../../../shared/extra-utils/requests/check-api-params'
19import { getAccount } from '../../../../shared/extra-utils/users/accounts'
20import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' 6import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form'
21import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' 7import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
22 8
diff --git a/server/tests/api/check-params/debug.ts b/server/tests/api/check-params/debug.ts
index 8dad26723..5fac73485 100644
--- a/server/tests/api/check-params/debug.ts
+++ b/server/tests/api/check-params/debug.ts
@@ -1,15 +1,14 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
5import { 5import {
6 cleanupTests,
6 createUser, 7 createUser,
7 flushTests,
8 killallServers,
9 flushAndRunServer, 8 flushAndRunServer,
10 ServerInfo, 9 ServerInfo,
11 setAccessTokensToServers, 10 setAccessTokensToServers,
12 userLogin, cleanupTests 11 userLogin
13} from '../../../../shared/extra-utils' 12} from '../../../../shared/extra-utils'
14import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' 13import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests'
15 14
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts
index be2a603a3..2c2224a45 100644
--- a/server/tests/api/check-params/follows.ts
+++ b/server/tests/api/check-params/follows.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
diff --git a/server/tests/api/check-params/jobs.ts b/server/tests/api/check-params/jobs.ts
index 22e237964..8f4af8d16 100644
--- a/server/tests/api/check-params/jobs.ts
+++ b/server/tests/api/check-params/jobs.ts
@@ -1,16 +1,14 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
5import { 5import {
6 cleanupTests,
6 createUser, 7 createUser,
7 flushTests,
8 killallServers,
9 flushAndRunServer, 8 flushAndRunServer,
10 ServerInfo, 9 ServerInfo,
11 setAccessTokensToServers, 10 setAccessTokensToServers,
12 userLogin, 11 userLogin
13 cleanupTests
14} from '../../../../shared/extra-utils' 12} from '../../../../shared/extra-utils'
15import { 13import {
16 checkBadCountPagination, 14 checkBadCountPagination,
diff --git a/server/tests/api/check-params/logs.ts b/server/tests/api/check-params/logs.ts
index f9d96bcc0..719da54e6 100644
--- a/server/tests/api/check-params/logs.ts
+++ b/server/tests/api/check-params/logs.ts
@@ -1,16 +1,14 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
5import { 5import {
6 cleanupTests,
6 createUser, 7 createUser,
7 flushTests,
8 killallServers,
9 flushAndRunServer, 8 flushAndRunServer,
10 ServerInfo, 9 ServerInfo,
11 setAccessTokensToServers, 10 setAccessTokensToServers,
12 userLogin, 11 userLogin
13 cleanupTests
14} from '../../../../shared/extra-utils' 12} from '../../../../shared/extra-utils'
15import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' 13import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests'
16 14
diff --git a/server/tests/api/check-params/plugins.ts b/server/tests/api/check-params/plugins.ts
index 9553bce17..cf80b35c2 100644
--- a/server/tests/api/check-params/plugins.ts
+++ b/server/tests/api/check-params/plugins.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
diff --git a/server/tests/api/check-params/redundancy.ts b/server/tests/api/check-params/redundancy.ts
index 7012a39ee..b2370a094 100644
--- a/server/tests/api/check-params/redundancy.ts
+++ b/server/tests/api/check-params/redundancy.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
@@ -38,7 +38,7 @@ describe('Test server redundancy API validators', function () {
38 password: 'password' 38 password: 'password'
39 } 39 }
40 40
41 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) 41 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
42 userAccessToken = await userLogin(servers[0], user) 42 userAccessToken = await userLogin(servers[0], user)
43 43
44 videoIdLocal = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video' })).id 44 videoIdLocal = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video' })).id
diff --git a/server/tests/api/check-params/search.ts b/server/tests/api/check-params/search.ts
index 8ad9d98bf..f8d0cd4ec 100644
--- a/server/tests/api/check-params/search.ts
+++ b/server/tests/api/check-params/search.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
diff --git a/server/tests/api/check-params/services.ts b/server/tests/api/check-params/services.ts
index d15753aed..457adfaab 100644
--- a/server/tests/api/check-params/services.ts
+++ b/server/tests/api/check-params/services.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
diff --git a/server/tests/api/check-params/user-notifications.ts b/server/tests/api/check-params/user-notifications.ts
index 3b06be7ef..2048fa667 100644
--- a/server/tests/api/check-params/user-notifications.ts
+++ b/server/tests/api/check-params/user-notifications.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as io from 'socket.io-client' 4import * as io from 'socket.io-client'
diff --git a/server/tests/api/check-params/user-subscriptions.ts b/server/tests/api/check-params/user-subscriptions.ts
index fa36c4078..1edba4d64 100644
--- a/server/tests/api/check-params/user-subscriptions.ts
+++ b/server/tests/api/check-params/user-subscriptions.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts
index 5d5af284c..f448bb2a6 100644
--- a/server/tests/api/check-params/users.ts
+++ b/server/tests/api/check-params/users.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { omit } from 'lodash' 3import { omit } from 'lodash'
4import 'mocha' 4import 'mocha'
@@ -50,6 +50,7 @@ describe('Test users API validators', function () {
50 let serverWithRegistrationDisabled: ServerInfo 50 let serverWithRegistrationDisabled: ServerInfo
51 let userAccessToken = '' 51 let userAccessToken = ''
52 let moderatorAccessToken = '' 52 let moderatorAccessToken = ''
53 // eslint-disable-next-line @typescript-eslint/no-unused-vars
53 let channelId: number 54 let channelId: number
54 55
55 // --------------------------------------------------------------- 56 // ---------------------------------------------------------------
@@ -120,7 +121,7 @@ describe('Test users API validators', function () {
120 121
121 { 122 {
122 const res = await getMyUserInformation(server.url, server.accessToken) 123 const res = await getMyUserInformation(server.url, server.accessToken)
123 channelId = res.body.videoChannels[ 0 ].id 124 channelId = res.body.videoChannels[0].id
124 } 125 }
125 126
126 { 127 {
@@ -529,7 +530,7 @@ describe('Test users API validators', function () {
529 it('Should fail without an incorrect input file', async function () { 530 it('Should fail without an incorrect input file', async function () {
530 const fields = {} 531 const fields = {}
531 const attaches = { 532 const attaches = {
532 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') 533 avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
533 } 534 }
534 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) 535 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
535 }) 536 })
@@ -537,7 +538,7 @@ describe('Test users API validators', function () {
537 it('Should fail with a big file', async function () { 538 it('Should fail with a big file', async function () {
538 const fields = {} 539 const fields = {}
539 const attaches = { 540 const attaches = {
540 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') 541 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
541 } 542 }
542 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) 543 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
543 }) 544 })
@@ -545,7 +546,7 @@ describe('Test users API validators', function () {
545 it('Should fail with an unauthenticated user', async function () { 546 it('Should fail with an unauthenticated user', async function () {
546 const fields = {} 547 const fields = {}
547 const attaches = { 548 const attaches = {
548 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') 549 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
549 } 550 }
550 await makeUploadRequest({ 551 await makeUploadRequest({
551 url: server.url, 552 url: server.url,
@@ -559,7 +560,7 @@ describe('Test users API validators', function () {
559 it('Should succeed with the correct params', async function () { 560 it('Should succeed with the correct params', async function () {
560 const fields = {} 561 const fields = {}
561 const attaches = { 562 const attaches = {
562 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') 563 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
563 } 564 }
564 await makeUploadRequest({ 565 await makeUploadRequest({
565 url: server.url, 566 url: server.url,
diff --git a/server/tests/api/check-params/video-abuses.ts b/server/tests/api/check-params/video-abuses.ts
index bf29f8d4d..bea2177f3 100644
--- a/server/tests/api/check-params/video-abuses.ts
+++ b/server/tests/api/check-params/video-abuses.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
@@ -126,6 +126,7 @@ describe('Test video abuses API validators', function () {
126 126
127 describe('When updating a video abuse', function () { 127 describe('When updating a video abuse', function () {
128 const basePath = '/api/v1/videos/' 128 const basePath = '/api/v1/videos/'
129 // eslint-disable-next-line @typescript-eslint/no-unused-vars
129 let path: string 130 let path: string
130 131
131 before(() => { 132 before(() => {
@@ -163,6 +164,7 @@ describe('Test video abuses API validators', function () {
163 164
164 describe('When deleting a video abuse', function () { 165 describe('When deleting a video abuse', function () {
165 const basePath = '/api/v1/videos/' 166 const basePath = '/api/v1/videos/'
167 // eslint-disable-next-line @typescript-eslint/no-unused-vars
166 let path: string 168 let path: string
167 169
168 before(() => { 170 before(() => {
diff --git a/server/tests/api/check-params/video-blacklist.ts b/server/tests/api/check-params/video-blacklist.ts
index 6466888fb..145f43980 100644
--- a/server/tests/api/check-params/video-blacklist.ts
+++ b/server/tests/api/check-params/video-blacklist.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4
@@ -7,25 +7,24 @@ import {
7 createUser, 7 createUser,
8 doubleFollow, 8 doubleFollow,
9 flushAndRunMultipleServers, 9 flushAndRunMultipleServers,
10 flushTests,
11 getBlacklistedVideosList, 10 getBlacklistedVideosList,
12 getVideo, 11 getVideo,
13 getVideoWithToken, 12 getVideoWithToken,
14 killallServers,
15 makePostBodyRequest, 13 makePostBodyRequest,
16 makePutBodyRequest, 14 makePutBodyRequest,
17 removeVideoFromBlacklist, 15 removeVideoFromBlacklist,
18 ServerInfo, 16 ServerInfo,
19 setAccessTokensToServers, 17 setAccessTokensToServers,
20 uploadVideo, 18 uploadVideo,
21 userLogin, waitJobs 19 userLogin,
20 waitJobs
22} from '../../../../shared/extra-utils' 21} from '../../../../shared/extra-utils'
23import { 22import {
24 checkBadCountPagination, 23 checkBadCountPagination,
25 checkBadSortPagination, 24 checkBadSortPagination,
26 checkBadStartPagination 25 checkBadStartPagination
27} from '../../../../shared/extra-utils/requests/check-api-params' 26} from '../../../../shared/extra-utils/requests/check-api-params'
28import { VideoDetails, VideoBlacklistType } from '../../../../shared/models/videos' 27import { VideoBlacklistType, VideoDetails } from '../../../../shared/models/videos'
29import { expect } from 'chai' 28import { expect } from 'chai'
30 29
31describe('Test video blacklist API validators', function () { 30describe('Test video blacklist API validators', function () {
@@ -48,14 +47,14 @@ describe('Test video blacklist API validators', function () {
48 { 47 {
49 const username = 'user1' 48 const username = 'user1'
50 const password = 'my super password' 49 const password = 'my super password'
51 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: username, password: password }) 50 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: username, password: password })
52 userAccessToken1 = await userLogin(servers[0], { username, password }) 51 userAccessToken1 = await userLogin(servers[0], { username, password })
53 } 52 }
54 53
55 { 54 {
56 const username = 'user2' 55 const username = 'user2'
57 const password = 'my super password' 56 const password = 'my super password'
58 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: username, password: password }) 57 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: username, password: password })
59 userAccessToken2 = await userLogin(servers[0], { username, password }) 58 userAccessToken2 = await userLogin(servers[0], { username, password })
60 } 59 }
61 60
@@ -120,7 +119,7 @@ describe('Test video blacklist API validators', function () {
120 119
121 it('Should succeed with the correct params', async function () { 120 it('Should succeed with the correct params', async function () {
122 const path = basePath + servers[0].video.uuid + '/blacklist' 121 const path = basePath + servers[0].video.uuid + '/blacklist'
123 const fields = { } 122 const fields = {}
124 123
125 await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields, statusCodeExpected: 204 }) 124 await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields, statusCodeExpected: 204 })
126 }) 125 })
diff --git a/server/tests/api/check-params/video-captions.ts b/server/tests/api/check-params/video-captions.ts
index 6ddc20d69..a5f5c3322 100644
--- a/server/tests/api/check-params/video-captions.ts
+++ b/server/tests/api/check-params/video-captions.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { 4import {
@@ -50,7 +50,7 @@ describe('Test video captions API validator', function () {
50 describe('When adding video caption', function () { 50 describe('When adding video caption', function () {
51 const fields = { } 51 const fields = { }
52 const attaches = { 52 const attaches = {
53 'captionfile': join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt') 53 captionfile: join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt')
54 } 54 }
55 55
56 it('Should fail without a valid uuid', async function () { 56 it('Should fail without a valid uuid', async function () {
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts
index de88298d1..2795ad7d5 100644
--- a/server/tests/api/check-params/video-channels.ts
+++ b/server/tests/api/check-params/video-channels.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import { omit } from 'lodash' 4import { omit } from 'lodash'
@@ -243,7 +243,7 @@ describe('Test video channels API validator', function () {
243 it('Should fail with an incorrect input file', async function () { 243 it('Should fail with an incorrect input file', async function () {
244 const fields = {} 244 const fields = {}
245 const attaches = { 245 const attaches = {
246 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') 246 avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
247 } 247 }
248 await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) 248 await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches })
249 }) 249 })
@@ -251,7 +251,7 @@ describe('Test video channels API validator', function () {
251 it('Should fail with a big file', async function () { 251 it('Should fail with a big file', async function () {
252 const fields = {} 252 const fields = {}
253 const attaches = { 253 const attaches = {
254 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') 254 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
255 } 255 }
256 await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) 256 await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches })
257 }) 257 })
@@ -259,7 +259,7 @@ describe('Test video channels API validator', function () {
259 it('Should fail with an unauthenticated user', async function () { 259 it('Should fail with an unauthenticated user', async function () {
260 const fields = {} 260 const fields = {}
261 const attaches = { 261 const attaches = {
262 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') 262 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
263 } 263 }
264 await makeUploadRequest({ 264 await makeUploadRequest({
265 url: server.url, 265 url: server.url,
@@ -273,7 +273,7 @@ describe('Test video channels API validator', function () {
273 it('Should succeed with the correct params', async function () { 273 it('Should succeed with the correct params', async function () {
274 const fields = {} 274 const fields = {}
275 const attaches = { 275 const attaches = {
276 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') 276 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
277 } 277 }
278 await makeUploadRequest({ 278 await makeUploadRequest({
279 url: server.url, 279 url: server.url,
@@ -324,7 +324,7 @@ describe('Test video channels API validator', function () {
324 }) 324 })
325 325
326 it('Should fail with an unknown video channel id', async function () { 326 it('Should fail with an unknown video channel id', async function () {
327 await deleteVideoChannel(server.url, server.accessToken,'super_channel2', 404) 327 await deleteVideoChannel(server.url, server.accessToken, 'super_channel2', 404)
328 }) 328 })
329 329
330 it('Should succeed with the correct parameters', async function () { 330 it('Should succeed with the correct parameters', async function () {
diff --git a/server/tests/api/check-params/video-comments.ts b/server/tests/api/check-params/video-comments.ts
index 5cf90bacc..e67cc01fa 100644
--- a/server/tests/api/check-params/video-comments.ts
+++ b/server/tests/api/check-params/video-comments.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts
index 231d5cc85..dbea39c48 100644
--- a/server/tests/api/check-params/video-imports.ts
+++ b/server/tests/api/check-params/video-imports.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { omit } from 'lodash' 3import { omit } from 'lodash'
4import 'mocha' 4import 'mocha'
@@ -29,6 +29,7 @@ describe('Test video imports API validator', function () {
29 const path = '/api/v1/videos/imports' 29 const path = '/api/v1/videos/imports'
30 let server: ServerInfo 30 let server: ServerInfo
31 let userAccessToken = '' 31 let userAccessToken = ''
32 // eslint-disable-next-line @typescript-eslint/no-unused-vars
32 let accountName: string 33 let accountName: string
33 let channelId: number 34 let channelId: number
34 35
@@ -48,7 +49,7 @@ describe('Test video imports API validator', function () {
48 49
49 { 50 {
50 const res = await getMyUserInformation(server.url, server.accessToken) 51 const res = await getMyUserInformation(server.url, server.accessToken)
51 channelId = res.body.videoChannels[ 0 ].id 52 channelId = res.body.videoChannels[0].id
52 accountName = res.body.account.name + '@' + res.body.account.host 53 accountName = res.body.account.name + '@' + res.body.account.host
53 } 54 }
54 }) 55 })
@@ -196,7 +197,7 @@ describe('Test video imports API validator', function () {
196 it('Should fail with an incorrect thumbnail file', async function () { 197 it('Should fail with an incorrect thumbnail file', async function () {
197 const fields = baseCorrectParams 198 const fields = baseCorrectParams
198 const attaches = { 199 const attaches = {
199 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') 200 thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
200 } 201 }
201 202
202 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 203 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -205,7 +206,7 @@ describe('Test video imports API validator', function () {
205 it('Should fail with a big thumbnail file', async function () { 206 it('Should fail with a big thumbnail file', async function () {
206 const fields = baseCorrectParams 207 const fields = baseCorrectParams
207 const attaches = { 208 const attaches = {
208 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') 209 thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
209 } 210 }
210 211
211 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 212 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -214,7 +215,7 @@ describe('Test video imports API validator', function () {
214 it('Should fail with an incorrect preview file', async function () { 215 it('Should fail with an incorrect preview file', async function () {
215 const fields = baseCorrectParams 216 const fields = baseCorrectParams
216 const attaches = { 217 const attaches = {
217 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') 218 previewfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
218 } 219 }
219 220
220 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 221 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -223,7 +224,7 @@ describe('Test video imports API validator', function () {
223 it('Should fail with a big preview file', async function () { 224 it('Should fail with a big preview file', async function () {
224 const fields = baseCorrectParams 225 const fields = baseCorrectParams
225 const attaches = { 226 const attaches = {
226 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') 227 previewfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
227 } 228 }
228 229
229 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 230 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -232,7 +233,7 @@ describe('Test video imports API validator', function () {
232 it('Should fail with an invalid torrent file', async function () { 233 it('Should fail with an invalid torrent file', async function () {
233 const fields = omit(baseCorrectParams, 'targetUrl') 234 const fields = omit(baseCorrectParams, 'targetUrl')
234 const attaches = { 235 const attaches = {
235 'torrentfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') 236 torrentfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
236 } 237 }
237 238
238 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 239 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -303,7 +304,7 @@ describe('Test video imports API validator', function () {
303 304
304 fields = omit(fields, 'magnetUri') 305 fields = omit(fields, 'magnetUri')
305 const attaches = { 306 const attaches = {
306 'torrentfile': join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent') 307 torrentfile: join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent')
307 } 308 }
308 309
309 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches, statusCodeExpected: 409 }) 310 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches, statusCodeExpected: 409 })
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts
index df158f3b1..0410e737a 100644
--- a/server/tests/api/check-params/video-playlists.ts
+++ b/server/tests/api/check-params/video-playlists.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { 4import {
@@ -36,6 +36,7 @@ describe('Test video playlists API validator', function () {
36 let privatePlaylistUUID: string 36 let privatePlaylistUUID: string
37 let watchLaterPlaylistId: number 37 let watchLaterPlaylistId: number
38 let videoId: number 38 let videoId: number
39 // eslint-disable-next-line @typescript-eslint/no-unused-vars
39 let videoId2: number 40 let videoId2: number
40 let playlistElementId: number 41 let playlistElementId: number
41 42
@@ -449,7 +450,7 @@ describe('Test video playlists API validator', function () {
449 videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id 450 videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id
450 videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id 451 videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id
451 452
452 for (let id of [ videoId3, videoId4 ]) { 453 for (const id of [ videoId3, videoId4 ]) {
453 await addVideoInPlaylist({ 454 await addVideoInPlaylist({
454 url: server.url, 455 url: server.url,
455 token: server.accessToken, 456 token: server.accessToken,
@@ -476,7 +477,7 @@ describe('Test video playlists API validator', function () {
476 } 477 }
477 478
478 { 479 {
479 const params = getBase({}, { playlistId: 42, expectedStatus: 404 }) 480 const params = getBase({}, { playlistId: 42, expectedStatus: 404 })
480 await reorderVideosPlaylist(params) 481 await reorderVideosPlaylist(params)
481 } 482 }
482 }) 483 })
diff --git a/server/tests/api/check-params/videos-filter.ts b/server/tests/api/check-params/videos-filter.ts
index 811756745..ec8654db2 100644
--- a/server/tests/api/check-params/videos-filter.ts
+++ b/server/tests/api/check-params/videos-filter.ts
@@ -1,10 +1,9 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { 4import {
5 cleanupTests, 5 cleanupTests,
6 createUser, 6 createUser,
7 createVideoPlaylist,
8 flushAndRunServer, 7 flushAndRunServer,
9 makeGetRequest, 8 makeGetRequest,
10 ServerInfo, 9 ServerInfo,
@@ -13,7 +12,6 @@ import {
13 userLogin 12 userLogin
14} from '../../../../shared/extra-utils' 13} from '../../../../shared/extra-utils'
15import { UserRole } from '../../../../shared/models/users' 14import { UserRole } from '../../../../shared/models/users'
16import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
17 15
18async function testEndpoints (server: ServerInfo, token: string, filter: string, statusCodeExpected: number) { 16async function testEndpoints (server: ServerInfo, token: string, filter: string, statusCodeExpected: number) {
19 const paths = [ 17 const paths = [
@@ -77,7 +75,7 @@ describe('Test videos filters', function () {
77 }) 75 })
78 76
79 it('Should succeed with a good filter', async function () { 77 it('Should succeed with a good filter', async function () {
80 await testEndpoints(server, server.accessToken,'local', 200) 78 await testEndpoints(server, server.accessToken, 'local', 200)
81 }) 79 })
82 80
83 it('Should fail to list all-local with a simple user', async function () { 81 it('Should fail to list all-local with a simple user', async function () {
diff --git a/server/tests/api/check-params/videos-history.ts b/server/tests/api/check-params/videos-history.ts
index 3739e3fad..941f62654 100644
--- a/server/tests/api/check-params/videos-history.ts
+++ b/server/tests/api/check-params/videos-history.ts
@@ -1,6 +1,5 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { 4import {
6 checkBadCountPagination, 5 checkBadCountPagination,
@@ -15,12 +14,10 @@ import {
15 uploadVideo 14 uploadVideo
16} from '../../../../shared/extra-utils' 15} from '../../../../shared/extra-utils'
17 16
18const expect = chai.expect
19
20describe('Test videos history API validator', function () { 17describe('Test videos history API validator', function () {
18 const myHistoryPath = '/api/v1/users/me/history/videos'
19 const myHistoryRemove = myHistoryPath + '/remove'
21 let watchingPath: string 20 let watchingPath: string
22 let myHistoryPath = '/api/v1/users/me/history/videos'
23 let myHistoryRemove = myHistoryPath + '/remove'
24 let server: ServerInfo 21 let server: ServerInfo
25 22
26 // --------------------------------------------------------------- 23 // ---------------------------------------------------------------
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts
index 16ef1c505..0d4665954 100644
--- a/server/tests/api/check-params/videos.ts
+++ b/server/tests/api/check-params/videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import { omit } from 'lodash' 4import { omit } from 'lodash'
@@ -56,8 +56,8 @@ describe('Test videos API validator', function () {
56 56
57 { 57 {
58 const res = await getMyUserInformation(server.url, server.accessToken) 58 const res = await getMyUserInformation(server.url, server.accessToken)
59 channelId = res.body.videoChannels[ 0 ].id 59 channelId = res.body.videoChannels[0].id
60 channelName = res.body.videoChannels[ 0 ].name 60 channelName = res.body.videoChannels[0].name
61 accountName = res.body.account.name + '@' + res.body.account.host 61 accountName = res.body.account.name + '@' + res.body.account.host
62 } 62 }
63 }) 63 })
@@ -182,7 +182,7 @@ describe('Test videos API validator', function () {
182 describe('When adding a video', function () { 182 describe('When adding a video', function () {
183 let baseCorrectParams 183 let baseCorrectParams
184 const baseCorrectAttaches = { 184 const baseCorrectAttaches = {
185 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') 185 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm')
186 } 186 }
187 187
188 before(function () { 188 before(function () {
@@ -330,7 +330,7 @@ describe('Test videos API validator', function () {
330 }) 330 })
331 331
332 it('Should fail with a bad originally published at attribute', async function () { 332 it('Should fail with a bad originally published at attribute', async function () {
333 const fields = immutableAssign(baseCorrectParams, { 'originallyPublishedAt': 'toto' }) 333 const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' })
334 const attaches = baseCorrectAttaches 334 const attaches = baseCorrectAttaches
335 335
336 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 336 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
@@ -345,12 +345,12 @@ describe('Test videos API validator', function () {
345 it('Should fail with an incorrect input file', async function () { 345 it('Should fail with an incorrect input file', async function () {
346 const fields = baseCorrectParams 346 const fields = baseCorrectParams
347 let attaches = { 347 let attaches = {
348 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') 348 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm')
349 } 349 }
350 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 350 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
351 351
352 attaches = { 352 attaches = {
353 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') 353 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv')
354 } 354 }
355 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 355 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
356 }) 356 })
@@ -358,8 +358,8 @@ describe('Test videos API validator', function () {
358 it('Should fail with an incorrect thumbnail file', async function () { 358 it('Should fail with an incorrect thumbnail file', async function () {
359 const fields = baseCorrectParams 359 const fields = baseCorrectParams
360 const attaches = { 360 const attaches = {
361 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), 361 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png'),
362 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 362 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
363 } 363 }
364 364
365 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 365 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
@@ -368,8 +368,8 @@ describe('Test videos API validator', function () {
368 it('Should fail with a big thumbnail file', async function () { 368 it('Should fail with a big thumbnail file', async function () {
369 const fields = baseCorrectParams 369 const fields = baseCorrectParams
370 const attaches = { 370 const attaches = {
371 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), 371 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'),
372 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 372 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
373 } 373 }
374 374
375 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 375 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
@@ -378,8 +378,8 @@ describe('Test videos API validator', function () {
378 it('Should fail with an incorrect preview file', async function () { 378 it('Should fail with an incorrect preview file', async function () {
379 const fields = baseCorrectParams 379 const fields = baseCorrectParams
380 const attaches = { 380 const attaches = {
381 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), 381 previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png'),
382 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 382 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
383 } 383 }
384 384
385 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 385 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
@@ -388,8 +388,8 @@ describe('Test videos API validator', function () {
388 it('Should fail with a big preview file', async function () { 388 it('Should fail with a big preview file', async function () {
389 const fields = baseCorrectParams 389 const fields = baseCorrectParams
390 const attaches = { 390 const attaches = {
391 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), 391 previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'),
392 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 392 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
393 } 393 }
394 394
395 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 395 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
@@ -566,7 +566,7 @@ describe('Test videos API validator', function () {
566 it('Should fail with an incorrect thumbnail file', async function () { 566 it('Should fail with an incorrect thumbnail file', async function () {
567 const fields = baseCorrectParams 567 const fields = baseCorrectParams
568 const attaches = { 568 const attaches = {
569 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png') 569 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png')
570 } 570 }
571 571
572 await makeUploadRequest({ 572 await makeUploadRequest({
@@ -582,7 +582,7 @@ describe('Test videos API validator', function () {
582 it('Should fail with a big thumbnail file', async function () { 582 it('Should fail with a big thumbnail file', async function () {
583 const fields = baseCorrectParams 583 const fields = baseCorrectParams
584 const attaches = { 584 const attaches = {
585 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') 585 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png')
586 } 586 }
587 587
588 await makeUploadRequest({ 588 await makeUploadRequest({
@@ -598,7 +598,7 @@ describe('Test videos API validator', function () {
598 it('Should fail with an incorrect preview file', async function () { 598 it('Should fail with an incorrect preview file', async function () {
599 const fields = baseCorrectParams 599 const fields = baseCorrectParams
600 const attaches = { 600 const attaches = {
601 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png') 601 previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png')
602 } 602 }
603 603
604 await makeUploadRequest({ 604 await makeUploadRequest({
@@ -614,7 +614,7 @@ describe('Test videos API validator', function () {
614 it('Should fail with a big preview file', async function () { 614 it('Should fail with a big preview file', async function () {
615 const fields = baseCorrectParams 615 const fields = baseCorrectParams
616 const attaches = { 616 const attaches = {
617 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') 617 previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png')
618 } 618 }
619 619
620 await makeUploadRequest({ 620 await makeUploadRequest({
diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts
index 15a34f5aa..2a632e16f 100644
--- a/server/tests/api/notifications/user-notifications.ts
+++ b/server/tests/api/notifications/user-notifications.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -74,7 +74,7 @@ async function uploadVideoByRemoteAccount (servers: ServerInfo[], additionalPara
74 const name = 'remote video ' + uuidv4() 74 const name = 'remote video ' + uuidv4()
75 75
76 const data = Object.assign({ name }, additionalParams) 76 const data = Object.assign({ name }, additionalParams)
77 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, data) 77 const res = await uploadVideo(servers[1].url, servers[1].accessToken, data)
78 78
79 await waitJobs(servers) 79 await waitJobs(servers)
80 80
@@ -85,7 +85,7 @@ async function uploadVideoByLocalAccount (servers: ServerInfo[], additionalParam
85 const name = 'local video ' + uuidv4() 85 const name = 'local video ' + uuidv4()
86 86
87 const data = Object.assign({ name }, additionalParams) 87 const data = Object.assign({ name }, additionalParams)
88 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, data) 88 const res = await uploadVideo(servers[0].url, servers[0].accessToken, data)
89 89
90 await waitJobs(servers) 90 await waitJobs(servers)
91 91
@@ -95,9 +95,9 @@ async function uploadVideoByLocalAccount (servers: ServerInfo[], additionalParam
95describe('Test users notifications', function () { 95describe('Test users notifications', function () {
96 let servers: ServerInfo[] = [] 96 let servers: ServerInfo[] = []
97 let userAccessToken: string 97 let userAccessToken: string
98 let userNotifications: UserNotification[] = [] 98 const userNotifications: UserNotification[] = []
99 let adminNotifications: UserNotification[] = [] 99 const adminNotifications: UserNotification[] = []
100 let adminNotificationsServer2: UserNotification[] = [] 100 const adminNotificationsServer2: UserNotification[] = []
101 const emails: object[] = [] 101 const emails: object[] = []
102 let channelId: number 102 let channelId: number
103 103
@@ -142,8 +142,8 @@ describe('Test users notifications', function () {
142 password: 'super password' 142 password: 'super password'
143 } 143 }
144 await createUser({ 144 await createUser({
145 url: servers[ 0 ].url, 145 url: servers[0].url,
146 accessToken: servers[ 0 ].accessToken, 146 accessToken: servers[0].accessToken,
147 username: user.username, 147 username: user.username,
148 password: user.password, 148 password: user.password,
149 videoQuota: 10 * 1000 * 1000 149 videoQuota: 10 * 1000 * 1000
@@ -155,15 +155,15 @@ describe('Test users notifications', function () {
155 await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, allNotificationSettings) 155 await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, allNotificationSettings)
156 156
157 { 157 {
158 const socket = getUserNotificationSocket(servers[ 0 ].url, userAccessToken) 158 const socket = getUserNotificationSocket(servers[0].url, userAccessToken)
159 socket.on('new-notification', n => userNotifications.push(n)) 159 socket.on('new-notification', n => userNotifications.push(n))
160 } 160 }
161 { 161 {
162 const socket = getUserNotificationSocket(servers[ 0 ].url, servers[0].accessToken) 162 const socket = getUserNotificationSocket(servers[0].url, servers[0].accessToken)
163 socket.on('new-notification', n => adminNotifications.push(n)) 163 socket.on('new-notification', n => adminNotifications.push(n))
164 } 164 }
165 { 165 {
166 const socket = getUserNotificationSocket(servers[ 1 ].url, servers[1].accessToken) 166 const socket = getUserNotificationSocket(servers[1].url, servers[1].accessToken)
167 socket.on('new-notification', n => adminNotificationsServer2.push(n)) 167 socket.on('new-notification', n => adminNotificationsServer2.push(n))
168 } 168 }
169 169
@@ -190,7 +190,7 @@ describe('Test users notifications', function () {
190 190
191 await uploadVideoByLocalAccount(servers) 191 await uploadVideoByLocalAccount(servers)
192 192
193 const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) 193 const notification = await getLastNotification(servers[0].url, userAccessToken)
194 expect(notification).to.be.undefined 194 expect(notification).to.be.undefined
195 195
196 expect(emails).to.have.lengthOf(0) 196 expect(emails).to.have.lengthOf(0)
@@ -221,7 +221,7 @@ describe('Test users notifications', function () {
221 this.timeout(20000) 221 this.timeout(20000)
222 222
223 // In 2 seconds 223 // In 2 seconds
224 let updateAt = new Date(new Date().getTime() + 2000) 224 const updateAt = new Date(new Date().getTime() + 2000)
225 225
226 const data = { 226 const data = {
227 privacy: VideoPrivacy.PRIVATE, 227 privacy: VideoPrivacy.PRIVATE,
@@ -240,7 +240,7 @@ describe('Test users notifications', function () {
240 this.timeout(50000) 240 this.timeout(50000)
241 241
242 // In 2 seconds 242 // In 2 seconds
243 let updateAt = new Date(new Date().getTime() + 2000) 243 const updateAt = new Date(new Date().getTime() + 2000)
244 244
245 const data = { 245 const data = {
246 privacy: VideoPrivacy.PRIVATE, 246 privacy: VideoPrivacy.PRIVATE,
@@ -259,7 +259,7 @@ describe('Test users notifications', function () {
259 it('Should not send a notification before the video is published', async function () { 259 it('Should not send a notification before the video is published', async function () {
260 this.timeout(20000) 260 this.timeout(20000)
261 261
262 let updateAt = new Date(new Date().getTime() + 1000000) 262 const updateAt = new Date(new Date().getTime() + 1000000)
263 263
264 const data = { 264 const data = {
265 privacy: VideoPrivacy.PRIVATE, 265 privacy: VideoPrivacy.PRIVATE,
@@ -386,7 +386,7 @@ describe('Test users notifications', function () {
386 it('Should not send a new comment notification if the account is muted', async function () { 386 it('Should not send a new comment notification if the account is muted', async function () {
387 this.timeout(10000) 387 this.timeout(10000)
388 388
389 await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') 389 await addAccountToAccountBlocklist(servers[0].url, userAccessToken, 'root')
390 390
391 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'super video' }) 391 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'super video' })
392 const uuid = resVideo.body.video.uuid 392 const uuid = resVideo.body.video.uuid
@@ -397,7 +397,7 @@ describe('Test users notifications', function () {
397 await wait(500) 397 await wait(500)
398 await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence') 398 await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence')
399 399
400 await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') 400 await removeAccountFromAccountBlocklist(servers[0].url, userAccessToken, 'root')
401 }) 401 })
402 402
403 it('Should send a new comment notification after a local comment on my video', async function () { 403 it('Should send a new comment notification after a local comment on my video', async function () {
@@ -456,9 +456,9 @@ describe('Test users notifications', function () {
456 await waitJobs(servers) 456 await waitJobs(servers)
457 457
458 { 458 {
459 const resThread = await addVideoCommentThread(servers[ 1 ].url, servers[ 1 ].accessToken, uuid, 'comment') 459 const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, 'comment')
460 const threadId = resThread.body.comment.id 460 const threadId = resThread.body.comment.id
461 await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, uuid, threadId, 'reply') 461 await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, threadId, 'reply')
462 } 462 }
463 463
464 await waitJobs(servers) 464 await waitJobs(servers)
@@ -530,7 +530,7 @@ describe('Test users notifications', function () {
530 it('Should not send a new mention notification if the account is muted', async function () { 530 it('Should not send a new mention notification if the account is muted', async function () {
531 this.timeout(10000) 531 this.timeout(10000)
532 532
533 await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') 533 await addAccountToAccountBlocklist(servers[0].url, userAccessToken, 'root')
534 534
535 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' }) 535 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' })
536 const uuid = resVideo.body.video.uuid 536 const uuid = resVideo.body.video.uuid
@@ -541,7 +541,7 @@ describe('Test users notifications', function () {
541 await wait(500) 541 await wait(500)
542 await checkCommentMention(baseParams, uuid, commentId, commentId, 'super root name', 'absence') 542 await checkCommentMention(baseParams, uuid, commentId, commentId, 'super root name', 'absence')
543 543
544 await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') 544 await removeAccountFromAccountBlocklist(servers[0].url, userAccessToken, 'root')
545 }) 545 })
546 546
547 it('Should not send a new mention notification if the remote account mention a local account', async function () { 547 it('Should not send a new mention notification if the remote account mention a local account', async function () {
@@ -585,7 +585,7 @@ describe('Test users notifications', function () {
585 585
586 await waitJobs(servers) 586 await waitJobs(servers)
587 587
588 const text1 = `hello @user_1@localhost:${servers[ 0 ].port} 1` 588 const text1 = `hello @user_1@localhost:${servers[0].port} 1`
589 const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1) 589 const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1)
590 const server2ThreadId = resThread.body.comment.id 590 const server2ThreadId = resThread.body.comment.id
591 591
@@ -596,7 +596,7 @@ describe('Test users notifications', function () {
596 const server1ThreadId = resThread2.body.data[0].id 596 const server1ThreadId = resThread2.body.data[0].id
597 await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence') 597 await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence')
598 598
599 const text2 = `@user_1@localhost:${servers[ 0 ].port} hello 2 @root@localhost:${servers[ 0 ].port}` 599 const text2 = `@user_1@localhost:${servers[0].port} hello 2 @root@localhost:${servers[0].port}`
600 await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2) 600 await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2)
601 601
602 await waitJobs(servers) 602 await waitJobs(servers)
@@ -611,7 +611,7 @@ describe('Test users notifications', function () {
611 }) 611 })
612 }) 612 })
613 613
614 describe('Video abuse for moderators notification' , function () { 614 describe('Video abuse for moderators notification', function () {
615 let baseParams: CheckerBaseParams 615 let baseParams: CheckerBaseParams
616 616
617 before(() => { 617 before(() => {
@@ -722,7 +722,7 @@ describe('Test users notifications', function () {
722 await uploadVideoByRemoteAccount(servers, { waitTranscoding: false }) 722 await uploadVideoByRemoteAccount(servers, { waitTranscoding: false })
723 await waitJobs(servers) 723 await waitJobs(servers)
724 724
725 const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) 725 const notification = await getLastNotification(servers[0].url, userAccessToken)
726 if (notification) { 726 if (notification) {
727 expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED) 727 expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED)
728 } 728 }
@@ -769,7 +769,7 @@ describe('Test users notifications', function () {
769 this.timeout(70000) 769 this.timeout(70000)
770 770
771 // In 2 seconds 771 // In 2 seconds
772 let updateAt = new Date(new Date().getTime() + 2000) 772 const updateAt = new Date(new Date().getTime() + 2000)
773 773
774 const data = { 774 const data = {
775 privacy: VideoPrivacy.PRIVATE, 775 privacy: VideoPrivacy.PRIVATE,
@@ -787,7 +787,7 @@ describe('Test users notifications', function () {
787 it('Should not send a notification before the video is published', async function () { 787 it('Should not send a notification before the video is published', async function () {
788 this.timeout(20000) 788 this.timeout(20000)
789 789
790 let updateAt = new Date(new Date().getTime() + 1000000) 790 const updateAt = new Date(new Date().getTime() + 1000000)
791 791
792 const data = { 792 const data = {
793 privacy: VideoPrivacy.PRIVATE, 793 privacy: VideoPrivacy.PRIVATE,
@@ -970,8 +970,8 @@ describe('Test users notifications', function () {
970 970
971 describe('New actor follow', function () { 971 describe('New actor follow', function () {
972 let baseParams: CheckerBaseParams 972 let baseParams: CheckerBaseParams
973 let myChannelName = 'super channel name' 973 const myChannelName = 'super channel name'
974 let myUserName = 'super user name' 974 const myUserName = 'super user name'
975 975
976 before(async () => { 976 before(async () => {
977 baseParams = { 977 baseParams = {
@@ -1143,7 +1143,7 @@ describe('Test users notifications', function () {
1143 it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () { 1143 it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () {
1144 this.timeout(20000) 1144 this.timeout(20000)
1145 1145
1146 let updateAt = new Date(new Date().getTime() + 1000000) 1146 const updateAt = new Date(new Date().getTime() + 1000000)
1147 1147
1148 const name = 'video with auto-blacklist and future schedule ' + uuidv4() 1148 const name = 'video with auto-blacklist and future schedule ' + uuidv4()
1149 1149
@@ -1176,7 +1176,7 @@ describe('Test users notifications', function () {
1176 this.timeout(20000) 1176 this.timeout(20000)
1177 1177
1178 // In 2 seconds 1178 // In 2 seconds
1179 let updateAt = new Date(new Date().getTime() + 2000) 1179 const updateAt = new Date(new Date().getTime() + 2000)
1180 1180
1181 const name = 'video with schedule done and still auto-blacklisted ' + uuidv4() 1181 const name = 'video with schedule done and still auto-blacklisted ' + uuidv4()
1182 1182
@@ -1221,26 +1221,26 @@ describe('Test users notifications', function () {
1221 1221
1222 describe('Mark as read', function () { 1222 describe('Mark as read', function () {
1223 it('Should mark as read some notifications', async function () { 1223 it('Should mark as read some notifications', async function () {
1224 const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 2, 3) 1224 const res = await getUserNotifications(servers[0].url, userAccessToken, 2, 3)
1225 const ids = res.body.data.map(n => n.id) 1225 const ids = res.body.data.map(n => n.id)
1226 1226
1227 await markAsReadNotifications(servers[ 0 ].url, userAccessToken, ids) 1227 await markAsReadNotifications(servers[0].url, userAccessToken, ids)
1228 }) 1228 })
1229 1229
1230 it('Should have the notifications marked as read', async function () { 1230 it('Should have the notifications marked as read', async function () {
1231 const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10) 1231 const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10)
1232 1232
1233 const notifications = res.body.data as UserNotification[] 1233 const notifications = res.body.data as UserNotification[]
1234 expect(notifications[ 0 ].read).to.be.false 1234 expect(notifications[0].read).to.be.false
1235 expect(notifications[ 1 ].read).to.be.false 1235 expect(notifications[1].read).to.be.false
1236 expect(notifications[ 2 ].read).to.be.true 1236 expect(notifications[2].read).to.be.true
1237 expect(notifications[ 3 ].read).to.be.true 1237 expect(notifications[3].read).to.be.true
1238 expect(notifications[ 4 ].read).to.be.true 1238 expect(notifications[4].read).to.be.true
1239 expect(notifications[ 5 ].read).to.be.false 1239 expect(notifications[5].read).to.be.false
1240 }) 1240 })
1241 1241
1242 it('Should only list read notifications', async function () { 1242 it('Should only list read notifications', async function () {
1243 const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, false) 1243 const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, false)
1244 1244
1245 const notifications = res.body.data as UserNotification[] 1245 const notifications = res.body.data as UserNotification[]
1246 for (const notification of notifications) { 1246 for (const notification of notifications) {
@@ -1249,7 +1249,7 @@ describe('Test users notifications', function () {
1249 }) 1249 })
1250 1250
1251 it('Should only list unread notifications', async function () { 1251 it('Should only list unread notifications', async function () {
1252 const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true) 1252 const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, true)
1253 1253
1254 const notifications = res.body.data as UserNotification[] 1254 const notifications = res.body.data as UserNotification[]
1255 for (const notification of notifications) { 1255 for (const notification of notifications) {
@@ -1258,9 +1258,9 @@ describe('Test users notifications', function () {
1258 }) 1258 })
1259 1259
1260 it('Should mark as read all notifications', async function () { 1260 it('Should mark as read all notifications', async function () {
1261 await markAsReadAllNotifications(servers[ 0 ].url, userAccessToken) 1261 await markAsReadAllNotifications(servers[0].url, userAccessToken)
1262 1262
1263 const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true) 1263 const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, true)
1264 1264
1265 expect(res.body.total).to.equal(0) 1265 expect(res.body.total).to.equal(0)
1266 expect(res.body.data).to.have.lengthOf(0) 1266 expect(res.body.data).to.have.lengthOf(0)
diff --git a/server/tests/api/redundancy/manage-redundancy.ts b/server/tests/api/redundancy/manage-redundancy.ts
index 6a8937f24..4253124c8 100644
--- a/server/tests/api/redundancy/manage-redundancy.ts
+++ b/server/tests/api/redundancy/manage-redundancy.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -56,20 +56,20 @@ describe('Test manage videos redundancy', function () {
56 await setAccessTokensToServers(servers) 56 await setAccessTokensToServers(servers)
57 57
58 { 58 {
59 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 server 2' }) 59 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' })
60 video1Server2UUID = res.body.video.uuid 60 video1Server2UUID = res.body.video.uuid
61 } 61 }
62 62
63 { 63 {
64 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 2 server 2' }) 64 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 2 server 2' })
65 video2Server2UUID = res.body.video.uuid 65 video2Server2UUID = res.body.video.uuid
66 } 66 }
67 67
68 await waitJobs(servers) 68 await waitJobs(servers)
69 69
70 // Server 1 and server 2 follow each other 70 // Server 1 and server 2 follow each other
71 await doubleFollow(servers[ 0 ], servers[ 1 ]) 71 await doubleFollow(servers[0], servers[1])
72 await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true) 72 await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true)
73 73
74 await waitJobs(servers) 74 await waitJobs(servers)
75 }) 75 })
@@ -195,8 +195,8 @@ describe('Test manage videos redundancy', function () {
195 }) 195 })
196 196
197 const videos = res.body.data 197 const videos = res.body.data
198 expect(videos[ 0 ].name).to.equal('video 1 server 2') 198 expect(videos[0].name).to.equal('video 1 server 2')
199 expect(videos[ 1 ].name).to.equal('video 2 server 2') 199 expect(videos[1].name).to.equal('video 2 server 2')
200 } 200 }
201 201
202 { 202 {
@@ -210,8 +210,8 @@ describe('Test manage videos redundancy', function () {
210 }) 210 })
211 211
212 const videos = res.body.data 212 const videos = res.body.data
213 expect(videos[ 0 ].name).to.equal('video 2 server 2') 213 expect(videos[0].name).to.equal('video 2 server 2')
214 expect(videos[ 1 ].name).to.equal('video 1 server 2') 214 expect(videos[1].name).to.equal('video 1 server 2')
215 } 215 }
216 216
217 { 217 {
@@ -225,14 +225,14 @@ describe('Test manage videos redundancy', function () {
225 }) 225 })
226 226
227 const videos = res.body.data 227 const videos = res.body.data
228 expect(videos[ 0 ].name).to.equal('video 1 server 2') 228 expect(videos[0].name).to.equal('video 1 server 2')
229 } 229 }
230 }) 230 })
231 231
232 it('Should manually add a redundancy and list it', async function () { 232 it('Should manually add a redundancy and list it', async function () {
233 this.timeout(120000) 233 this.timeout(120000)
234 234
235 const uuid = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video 3 server 2', privacy: VideoPrivacy.UNLISTED })).uuid 235 const uuid = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 3 server 2', privacy: VideoPrivacy.UNLISTED })).uuid
236 await waitJobs(servers) 236 await waitJobs(servers)
237 const videoId = await getLocalIdByUUID(servers[0].url, uuid) 237 const videoId = await getLocalIdByUUID(servers[0].url, uuid)
238 238
@@ -257,9 +257,9 @@ describe('Test manage videos redundancy', function () {
257 }) 257 })
258 258
259 const videos = res.body.data 259 const videos = res.body.data
260 expect(videos[ 0 ].name).to.equal('video 3 server 2') 260 expect(videos[0].name).to.equal('video 3 server 2')
261 261
262 const video = videos[ 0 ] 262 const video = videos[0]
263 expect(video.redundancies.files).to.have.lengthOf(4) 263 expect(video.redundancies.files).to.have.lengthOf(4)
264 expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) 264 expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1)
265 265
@@ -286,9 +286,9 @@ describe('Test manage videos redundancy', function () {
286 }) 286 })
287 287
288 const videos = res.body.data 288 const videos = res.body.data
289 expect(videos[ 0 ].name).to.equal('video 3 server 2') 289 expect(videos[0].name).to.equal('video 3 server 2')
290 290
291 const video = videos[ 0 ] 291 const video = videos[0]
292 expect(video.redundancies.files).to.have.lengthOf(4) 292 expect(video.redundancies.files).to.have.lengthOf(4)
293 expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) 293 expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1)
294 294
@@ -308,8 +308,8 @@ describe('Test manage videos redundancy', function () {
308 308
309 for (const redundancyId of redundanciesToRemove) { 309 for (const redundancyId of redundanciesToRemove) {
310 await removeVideoRedundancy({ 310 await removeVideoRedundancy({
311 url: servers[ 0 ].url, 311 url: servers[0].url,
312 accessToken: servers[ 0 ].accessToken, 312 accessToken: servers[0].accessToken,
313 redundancyId 313 redundancyId
314 }) 314 })
315 } 315 }
@@ -327,10 +327,10 @@ describe('Test manage videos redundancy', function () {
327 const videos = res.body.data 327 const videos = res.body.data
328 expect(videos).to.have.lengthOf(2) 328 expect(videos).to.have.lengthOf(2)
329 329
330 expect(videos[ 0 ].name).to.equal('video 2 server 2') 330 expect(videos[0].name).to.equal('video 2 server 2')
331 331
332 redundanciesToRemove = [] 332 redundanciesToRemove = []
333 const video = videos[ 0 ] 333 const video = videos[0]
334 expect(video.redundancies.files).to.have.lengthOf(4) 334 expect(video.redundancies.files).to.have.lengthOf(4)
335 expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) 335 expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1)
336 336
@@ -346,8 +346,8 @@ describe('Test manage videos redundancy', function () {
346 { 346 {
347 for (const redundancyId of redundanciesToRemove) { 347 for (const redundancyId of redundanciesToRemove) {
348 await removeVideoRedundancy({ 348 await removeVideoRedundancy({
349 url: servers[ 0 ].url, 349 url: servers[0].url,
350 accessToken: servers[ 0 ].accessToken, 350 accessToken: servers[0].accessToken,
351 redundancyId 351 redundancyId
352 }) 352 })
353 } 353 }
@@ -362,7 +362,7 @@ describe('Test manage videos redundancy', function () {
362 }) 362 })
363 363
364 const videos = res.body.data 364 const videos = res.body.data
365 expect(videos[ 0 ].name).to.equal('video 1 server 2') 365 expect(videos[0].name).to.equal('video 1 server 2')
366 expect(videos).to.have.lengthOf(1) 366 expect(videos).to.have.lengthOf(1)
367 } 367 }
368 }) 368 })
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts
index f5bf130d5..c5037a541 100644
--- a/server/tests/api/redundancy/redundancy.ts
+++ b/server/tests/api/redundancy/redundancy.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -92,21 +92,21 @@ async function flushAndRunServers (strategy: VideoRedundancyStrategy | null, add
92 await setAccessTokensToServers(servers) 92 await setAccessTokensToServers(servers)
93 93
94 { 94 {
95 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 server 2' }) 95 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' })
96 video1Server2UUID = res.body.video.uuid 96 video1Server2UUID = res.body.video.uuid
97 video1Server2Id = res.body.video.id 97 video1Server2Id = res.body.video.id
98 98
99 await viewVideo(servers[ 1 ].url, video1Server2UUID) 99 await viewVideo(servers[1].url, video1Server2UUID)
100 } 100 }
101 101
102 await waitJobs(servers) 102 await waitJobs(servers)
103 103
104 // Server 1 and server 2 follow each other 104 // Server 1 and server 2 follow each other
105 await doubleFollow(servers[ 0 ], servers[ 1 ]) 105 await doubleFollow(servers[0], servers[1])
106 // Server 1 and server 3 follow each other 106 // Server 1 and server 3 follow each other
107 await doubleFollow(servers[ 0 ], servers[ 2 ]) 107 await doubleFollow(servers[0], servers[2])
108 // Server 2 and server 3 follow each other 108 // Server 2 and server 3 follow each other
109 await doubleFollow(servers[ 1 ], servers[ 2 ]) 109 await doubleFollow(servers[1], servers[2])
110 110
111 await waitJobs(servers) 111 await waitJobs(servers)
112} 112}
@@ -115,7 +115,7 @@ async function check1WebSeed (videoUUID?: string) {
115 if (!videoUUID) videoUUID = video1Server2UUID 115 if (!videoUUID) videoUUID = video1Server2UUID
116 116
117 const webseeds = [ 117 const webseeds = [
118 `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}` 118 `http://localhost:${servers[1].port}/static/webseed/${videoUUID}`
119 ] 119 ]
120 120
121 for (const server of servers) { 121 for (const server of servers) {
@@ -133,8 +133,8 @@ async function check2Webseeds (videoUUID?: string) {
133 if (!videoUUID) videoUUID = video1Server2UUID 133 if (!videoUUID) videoUUID = video1Server2UUID
134 134
135 const webseeds = [ 135 const webseeds = [
136 `http://localhost:${servers[ 0 ].port}/static/redundancy/${videoUUID}`, 136 `http://localhost:${servers[0].port}/static/redundancy/${videoUUID}`,
137 `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}` 137 `http://localhost:${servers[1].port}/static/webseed/${videoUUID}`
138 ] 138 ]
139 139
140 for (const server of servers) { 140 for (const server of servers) {
@@ -269,12 +269,12 @@ async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategyWithManu
269} 269}
270 270
271async function enableRedundancyOnServer1 () { 271async function enableRedundancyOnServer1 () {
272 await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true) 272 await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true)
273 273
274 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' }) 274 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' })
275 const follows: ActorFollow[] = res.body.data 275 const follows: ActorFollow[] = res.body.data
276 const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) 276 const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`)
277 const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) 277 const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`)
278 278
279 expect(server3).to.not.be.undefined 279 expect(server3).to.not.be.undefined
280 expect(server3.following.hostRedundancyAllowed).to.be.false 280 expect(server3.following.hostRedundancyAllowed).to.be.false
@@ -284,12 +284,12 @@ async function enableRedundancyOnServer1 () {
284} 284}
285 285
286async function disableRedundancyOnServer1 () { 286async function disableRedundancyOnServer1 () {
287 await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, false) 287 await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, false)
288 288
289 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' }) 289 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' })
290 const follows: ActorFollow[] = res.body.data 290 const follows: ActorFollow[] = res.body.data
291 const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) 291 const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`)
292 const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) 292 const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`)
293 293
294 expect(server3).to.not.be.undefined 294 expect(server3).to.not.be.undefined
295 expect(server3.following.hostRedundancyAllowed).to.be.false 295 expect(server3.following.hostRedundancyAllowed).to.be.false
@@ -434,8 +434,8 @@ describe('Test videos redundancy', function () {
434 it('Should view 2 times the first video to have > min_views config', async function () { 434 it('Should view 2 times the first video to have > min_views config', async function () {
435 this.timeout(80000) 435 this.timeout(80000)
436 436
437 await viewVideo(servers[ 0 ].url, video1Server2UUID) 437 await viewVideo(servers[0].url, video1Server2UUID)
438 await viewVideo(servers[ 2 ].url, video1Server2UUID) 438 await viewVideo(servers[2].url, video1Server2UUID)
439 439
440 await wait(10000) 440 await wait(10000)
441 await waitJobs(servers) 441 await waitJobs(servers)
@@ -620,7 +620,7 @@ describe('Test videos redundancy', function () {
620 await check1PlaylistRedundancies() 620 await check1PlaylistRedundancies()
621 await checkStatsWith2Webseed(strategy) 621 await checkStatsWith2Webseed(strategy)
622 622
623 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 2 server 2' }) 623 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 2 server 2' })
624 video2Server2UUID = res.body.video.uuid 624 video2Server2UUID = res.body.video.uuid
625 }) 625 })
626 626
@@ -652,8 +652,8 @@ describe('Test videos redundancy', function () {
652 652
653 await waitJobs(servers) 653 await waitJobs(servers)
654 654
655 killallServers([ servers[ 0 ] ]) 655 killallServers([ servers[0] ])
656 await reRunServer(servers[ 0 ], { 656 await reRunServer(servers[0], {
657 redundancy: { 657 redundancy: {
658 videos: { 658 videos: {
659 check_interval: '1 second', 659 check_interval: '1 second',
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts
index d5f0a5457..d7e3ed5be 100644
--- a/server/tests/api/search/search-activitypub-video-channels.ts
+++ b/server/tests/api/search/search-activitypub-video-channels.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -39,7 +39,7 @@ describe('Test ActivityPub video channels search', function () {
39 await setAccessTokensToServers(servers) 39 await setAccessTokensToServers(servers)
40 40
41 { 41 {
42 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: 'user1_server1', password: 'password' }) 42 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'user1_server1', password: 'password' })
43 const channel = { 43 const channel = {
44 name: 'channel1_server1', 44 name: 'channel1_server1',
45 displayName: 'Channel 1 server 1' 45 displayName: 'Channel 1 server 1'
@@ -49,7 +49,7 @@ describe('Test ActivityPub video channels search', function () {
49 49
50 { 50 {
51 const user = { username: 'user1_server2', password: 'password' } 51 const user = { username: 'user1_server2', password: 'password' }
52 await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) 52 await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password })
53 userServer2Token = await userLogin(servers[1], user) 53 userServer2Token = await userLogin(servers[1], user)
54 54
55 const channel = { 55 const channel = {
@@ -70,8 +70,8 @@ describe('Test ActivityPub video channels search', function () {
70 this.timeout(15000) 70 this.timeout(15000)
71 71
72 { 72 {
73 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3' 73 const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server3'
74 const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) 74 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
75 75
76 expect(res.body.total).to.equal(0) 76 expect(res.body.total).to.equal(0)
77 expect(res.body.data).to.be.an('array') 77 expect(res.body.data).to.be.an('array')
@@ -80,7 +80,7 @@ describe('Test ActivityPub video channels search', function () {
80 80
81 { 81 {
82 // Without token 82 // Without token
83 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' 83 const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2'
84 const res = await searchVideoChannel(servers[0].url, search) 84 const res = await searchVideoChannel(servers[0].url, search)
85 85
86 expect(res.body.total).to.equal(0) 86 expect(res.body.total).to.equal(0)
@@ -91,35 +91,35 @@ describe('Test ActivityPub video channels search', function () {
91 91
92 it('Should search a local video channel', async function () { 92 it('Should search a local video channel', async function () {
93 const searches = [ 93 const searches = [
94 'http://localhost:' + servers[ 0 ].port + '/video-channels/channel1_server1', 94 'http://localhost:' + servers[0].port + '/video-channels/channel1_server1',
95 'channel1_server1@localhost:' + servers[ 0 ].port 95 'channel1_server1@localhost:' + servers[0].port
96 ] 96 ]
97 97
98 for (const search of searches) { 98 for (const search of searches) {
99 const res = await searchVideoChannel(servers[ 0 ].url, search) 99 const res = await searchVideoChannel(servers[0].url, search)
100 100
101 expect(res.body.total).to.equal(1) 101 expect(res.body.total).to.equal(1)
102 expect(res.body.data).to.be.an('array') 102 expect(res.body.data).to.be.an('array')
103 expect(res.body.data).to.have.lengthOf(1) 103 expect(res.body.data).to.have.lengthOf(1)
104 expect(res.body.data[ 0 ].name).to.equal('channel1_server1') 104 expect(res.body.data[0].name).to.equal('channel1_server1')
105 expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 1') 105 expect(res.body.data[0].displayName).to.equal('Channel 1 server 1')
106 } 106 }
107 }) 107 })
108 108
109 it('Should search a remote video channel with URL or handle', async function () { 109 it('Should search a remote video channel with URL or handle', async function () {
110 const searches = [ 110 const searches = [
111 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2', 111 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2',
112 'channel1_server2@localhost:' + servers[ 1 ].port 112 'channel1_server2@localhost:' + servers[1].port
113 ] 113 ]
114 114
115 for (const search of searches) { 115 for (const search of searches) {
116 const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) 116 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
117 117
118 expect(res.body.total).to.equal(1) 118 expect(res.body.total).to.equal(1)
119 expect(res.body.data).to.be.an('array') 119 expect(res.body.data).to.be.an('array')
120 expect(res.body.data).to.have.lengthOf(1) 120 expect(res.body.data).to.have.lengthOf(1)
121 expect(res.body.data[ 0 ].name).to.equal('channel1_server2') 121 expect(res.body.data[0].name).to.equal('channel1_server2')
122 expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 2') 122 expect(res.body.data[0].displayName).to.equal('Channel 1 server 2')
123 } 123 }
124 }) 124 })
125 125
@@ -137,13 +137,13 @@ describe('Test ActivityPub video channels search', function () {
137 137
138 await waitJobs(servers) 138 await waitJobs(servers)
139 139
140 const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5) 140 const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[1].port, 0, 5)
141 expect(res.body.total).to.equal(0) 141 expect(res.body.total).to.equal(0)
142 expect(res.body.data).to.have.lengthOf(0) 142 expect(res.body.data).to.have.lengthOf(0)
143 }) 143 })
144 144
145 it('Should list video channel videos of server 2 with token', async function () { 145 it('Should list video channel videos of server 2 with token', async function () {
146 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5) 146 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[1].port, 0, 5)
147 147
148 expect(res.body.total).to.equal(1) 148 expect(res.body.total).to.equal(1)
149 expect(res.body.data[0].name).to.equal('video 1 server 2') 149 expect(res.body.data[0].name).to.equal('video 1 server 2')
@@ -159,7 +159,7 @@ describe('Test ActivityPub video channels search', function () {
159 // Expire video channel 159 // Expire video channel
160 await wait(10000) 160 await wait(10000)
161 161
162 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' 162 const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2'
163 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) 163 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
164 expect(res.body.total).to.equal(1) 164 expect(res.body.total).to.equal(1)
165 expect(res.body.data).to.have.lengthOf(1) 165 expect(res.body.data).to.have.lengthOf(1)
@@ -182,12 +182,12 @@ describe('Test ActivityPub video channels search', function () {
182 // Expire video channel 182 // Expire video channel
183 await wait(10000) 183 await wait(10000)
184 184
185 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' 185 const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2'
186 await searchVideoChannel(servers[0].url, search, servers[0].accessToken) 186 await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
187 187
188 await waitJobs(servers) 188 await waitJobs(servers)
189 189
190 const videoChannelName = 'channel1_server2@localhost:' + servers[ 1 ].port 190 const videoChannelName = 'channel1_server2@localhost:' + servers[1].port
191 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt') 191 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt')
192 192
193 expect(res.body.total).to.equal(2) 193 expect(res.body.total).to.equal(2)
@@ -204,7 +204,7 @@ describe('Test ActivityPub video channels search', function () {
204 // Expire video 204 // Expire video
205 await wait(10000) 205 await wait(10000)
206 206
207 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' 207 const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2'
208 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) 208 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
209 expect(res.body.total).to.equal(0) 209 expect(res.body.total).to.equal(0)
210 expect(res.body.data).to.have.lengthOf(0) 210 expect(res.body.data).to.have.lengthOf(0)
diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts
index dbfefadda..c62dfca0d 100644
--- a/server/tests/api/search/search-activitypub-videos.ts
+++ b/server/tests/api/search/search-activitypub-videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -34,12 +34,12 @@ describe('Test ActivityPub videos search', function () {
34 await setAccessTokensToServers(servers) 34 await setAccessTokensToServers(servers)
35 35
36 { 36 {
37 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1 on server 1' }) 37 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1 on server 1' })
38 videoServer1UUID = res.body.video.uuid 38 videoServer1UUID = res.body.video.uuid
39 } 39 }
40 40
41 { 41 {
42 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 on server 2' }) 42 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 on server 2' })
43 videoServer2UUID = res.body.video.uuid 43 videoServer2UUID = res.body.video.uuid
44 } 44 }
45 45
@@ -49,7 +49,7 @@ describe('Test ActivityPub videos search', function () {
49 it('Should not find a remote video', async function () { 49 it('Should not find a remote video', async function () {
50 { 50 {
51 const search = 'http://localhost:' + servers[1].port + '/videos/watch/43' 51 const search = 'http://localhost:' + servers[1].port + '/videos/watch/43'
52 const res = await searchVideoWithToken(servers[ 0 ].url, search, servers[ 0 ].accessToken) 52 const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
53 53
54 expect(res.body.total).to.equal(0) 54 expect(res.body.total).to.equal(0)
55 expect(res.body.data).to.be.an('array') 55 expect(res.body.data).to.be.an('array')
diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts
index 7882d9373..4801fe04a 100644
--- a/server/tests/api/search/search-videos.ts
+++ b/server/tests/api/search/search-videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -78,7 +78,7 @@ describe('Test videos search', function () {
78 const attributes5 = immutableAssign(attributes1, { name: attributes1.name + ' - 5', licence: 2, language: undefined }) 78 const attributes5 = immutableAssign(attributes1, { name: attributes1.name + ' - 5', licence: 2, language: undefined })
79 await uploadVideo(server.url, server.accessToken, attributes5) 79 await uploadVideo(server.url, server.accessToken, attributes5)
80 80
81 const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2 '] }) 81 const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2' ] })
82 await uploadVideo(server.url, server.accessToken, attributes6) 82 await uploadVideo(server.url, server.accessToken, attributes6)
83 83
84 const attributes7 = immutableAssign(attributes1, { 84 const attributes7 = immutableAssign(attributes1, {
@@ -269,16 +269,16 @@ describe('Test videos search', function () {
269 { 269 {
270 const res = await advancedVideosSearch(server.url, query) 270 const res = await advancedVideosSearch(server.url, query)
271 expect(res.body.total).to.equal(2) 271 expect(res.body.total).to.equal(2)
272 expect(res.body.data[ 0 ].name).to.equal('1111 2222 3333 - 3') 272 expect(res.body.data[0].name).to.equal('1111 2222 3333 - 3')
273 expect(res.body.data[ 1 ].name).to.equal('1111 2222 3333 - 4') 273 expect(res.body.data[1].name).to.equal('1111 2222 3333 - 4')
274 } 274 }
275 275
276 { 276 {
277 const res = await advancedVideosSearch(server.url, immutableAssign(query, { languageOneOf: [ 'pl', 'en', '_unknown' ] })) 277 const res = await advancedVideosSearch(server.url, immutableAssign(query, { languageOneOf: [ 'pl', 'en', '_unknown' ] }))
278 expect(res.body.total).to.equal(3) 278 expect(res.body.total).to.equal(3)
279 expect(res.body.data[ 0 ].name).to.equal('1111 2222 3333 - 3') 279 expect(res.body.data[0].name).to.equal('1111 2222 3333 - 3')
280 expect(res.body.data[ 1 ].name).to.equal('1111 2222 3333 - 4') 280 expect(res.body.data[1].name).to.equal('1111 2222 3333 - 4')
281 expect(res.body.data[ 2 ].name).to.equal('1111 2222 3333 - 5') 281 expect(res.body.data[2].name).to.equal('1111 2222 3333 - 5')
282 } 282 }
283 283
284 { 284 {
diff --git a/server/tests/api/server/auto-follows.ts b/server/tests/api/server/auto-follows.ts
index a06f578fc..5f48dc0eb 100644
--- a/server/tests/api/server/auto-follows.ts
+++ b/server/tests/api/server/auto-follows.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -59,9 +59,10 @@ async function server1Follows2 (servers: ServerInfo[]) {
59 59
60async function resetFollows (servers: ServerInfo[]) { 60async function resetFollows (servers: ServerInfo[]) {
61 try { 61 try {
62 await unfollow(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ]) 62 await unfollow(servers[0].url, servers[0].accessToken, servers[1])
63 await unfollow(servers[ 1 ].url, servers[ 1 ].accessToken, servers[ 0 ]) 63 await unfollow(servers[1].url, servers[1].accessToken, servers[0])
64 } catch { /* empty */ } 64 } catch { /* empty */
65 }
65 66
66 await waitJobs(servers) 67 await waitJobs(servers)
67 68
@@ -163,8 +164,8 @@ describe('Test auto follows', function () {
163 await wait(5000) 164 await wait(5000)
164 await waitJobs(servers) 165 await waitJobs(servers)
165 166
166 await checkFollow(servers[ 0 ], servers[ 1 ], false) 167 await checkFollow(servers[0], servers[1], false)
167 await checkFollow(servers[ 1 ], servers[ 0 ], false) 168 await checkFollow(servers[1], servers[0], false)
168 }) 169 })
169 170
170 it('Should auto follow the index', async function () { 171 it('Should auto follow the index', async function () {
@@ -187,7 +188,7 @@ describe('Test auto follows', function () {
187 await wait(5000) 188 await wait(5000)
188 await waitJobs(servers) 189 await waitJobs(servers)
189 190
190 await checkFollow(servers[ 0 ], servers[ 1 ], true) 191 await checkFollow(servers[0], servers[1], true)
191 192
192 await resetFollows(servers) 193 await resetFollows(servers)
193 }) 194 })
@@ -200,8 +201,8 @@ describe('Test auto follows', function () {
200 await wait(5000) 201 await wait(5000)
201 await waitJobs(servers) 202 await waitJobs(servers)
202 203
203 await checkFollow(servers[ 0 ], servers[ 1 ], false) 204 await checkFollow(servers[0], servers[1], false)
204 await checkFollow(servers[ 0 ], servers[ 2 ], true) 205 await checkFollow(servers[0], servers[2], true)
205 }) 206 })
206 }) 207 })
207 208
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts
index cf99e5c0a..642525455 100644
--- a/server/tests/api/server/config.ts
+++ b/server/tests/api/server/config.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
@@ -11,11 +11,14 @@ import {
11 getAbout, 11 getAbout,
12 getConfig, 12 getConfig,
13 getCustomConfig, 13 getCustomConfig,
14 killallServers, parallelTests, 14 killallServers,
15 parallelTests,
15 registerUser, 16 registerUser,
16 reRunServer, ServerInfo, 17 reRunServer,
18 ServerInfo,
17 setAccessTokensToServers, 19 setAccessTokensToServers,
18 updateCustomConfig, uploadVideo 20 updateCustomConfig,
21 uploadVideo
19} from '../../../../shared/extra-utils' 22} from '../../../../shared/extra-utils'
20import { ServerConfig } from '../../../../shared/models' 23import { ServerConfig } from '../../../../shared/models'
21 24
diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts
index e4e895acb..bd1b0e38a 100644
--- a/server/tests/api/server/contact-form.ts
+++ b/server/tests/api/server/contact-form.ts
@@ -1,16 +1,8 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import { cleanupTests, flushAndRunServer, ServerInfo, setAccessTokensToServers, wait } from '../../../../shared/extra-utils'
6 flushTests,
7 killallServers,
8 flushAndRunServer,
9 ServerInfo,
10 setAccessTokensToServers,
11 wait,
12 cleanupTests
13} from '../../../../shared/extra-utils'
14import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' 6import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
15import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 7import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
16import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' 8import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form'
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts
index c55a221f2..f18859e5d 100644
--- a/server/tests/api/server/email.ts
+++ b/server/tests/api/server/email.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts
index 46663bf7c..a73440286 100644
--- a/server/tests/api/server/follow-constraints.ts
+++ b/server/tests/api/server/follow-constraints.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -35,11 +35,11 @@ describe('Test follow constraints', function () {
35 await setAccessTokensToServers(servers) 35 await setAccessTokensToServers(servers)
36 36
37 { 37 {
38 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video server 1' }) 38 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video server 1' })
39 video1UUID = res.body.video.uuid 39 video1UUID = res.body.video.uuid
40 } 40 }
41 { 41 {
42 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video server 2' }) 42 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video server 2' })
43 video2UUID = res.body.video.uuid 43 video2UUID = res.body.video.uuid
44 } 44 }
45 45
@@ -47,7 +47,7 @@ describe('Test follow constraints', function () {
47 username: 'user1', 47 username: 'user1',
48 password: 'super_password' 48 password: 'super_password'
49 } 49 }
50 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) 50 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
51 userAccessToken = await userLogin(servers[0], user) 51 userAccessToken = await userLogin(servers[0], user)
52 52
53 await doubleFollow(servers[0], servers[1]) 53 await doubleFollow(servers[0], servers[1])
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts
index 1984c9eb1..cee85cc4b 100644
--- a/server/tests/api/server/follows-moderation.ts
+++ b/server/tests/api/server/follows-moderation.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -24,7 +24,7 @@ const expect = chai.expect
24 24
25async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') { 25async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') {
26 { 26 {
27 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) 27 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' })
28 expect(res.body.total).to.equal(1) 28 expect(res.body.total).to.equal(1)
29 29
30 const follow = res.body.data[0] as ActorFollow 30 const follow = res.body.data[0] as ActorFollow
@@ -34,7 +34,7 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc
34 } 34 }
35 35
36 { 36 {
37 const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) 37 const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' })
38 expect(res.body.total).to.equal(1) 38 expect(res.body.total).to.equal(1)
39 39
40 const follow = res.body.data[0] as ActorFollow 40 const follow = res.body.data[0] as ActorFollow
@@ -46,12 +46,12 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc
46 46
47async function checkNoFollowers (servers: ServerInfo[]) { 47async function checkNoFollowers (servers: ServerInfo[]) {
48 { 48 {
49 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) 49 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' })
50 expect(res.body.total).to.equal(0) 50 expect(res.body.total).to.equal(0)
51 } 51 }
52 52
53 { 53 {
54 const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) 54 const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' })
55 expect(res.body.total).to.equal(0) 55 expect(res.body.total).to.equal(0)
56 } 56 }
57} 57}
@@ -164,17 +164,17 @@ describe('Test follows moderation', function () {
164 await waitJobs(servers) 164 await waitJobs(servers)
165 165
166 { 166 {
167 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) 167 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' })
168 expect(res.body.total).to.equal(2) 168 expect(res.body.total).to.equal(2)
169 } 169 }
170 170
171 { 171 {
172 const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) 172 const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' })
173 expect(res.body.total).to.equal(1) 173 expect(res.body.total).to.equal(1)
174 } 174 }
175 175
176 { 176 {
177 const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' }) 177 const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' })
178 expect(res.body.total).to.equal(1) 178 expect(res.body.total).to.equal(1)
179 } 179 }
180 180
@@ -184,7 +184,7 @@ describe('Test follows moderation', function () {
184 await checkServer1And2HasFollowers(servers) 184 await checkServer1And2HasFollowers(servers)
185 185
186 { 186 {
187 const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' }) 187 const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' })
188 expect(res.body.total).to.equal(0) 188 expect(res.body.total).to.equal(0)
189 } 189 }
190 }) 190 })
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index 4ffa9e791..b686af4e4 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -78,14 +78,14 @@ describe('Test follows', function () {
78 }) 78 })
79 79
80 it('Should have 2 followings on server 1', async function () { 80 it('Should have 2 followings on server 1', async function () {
81 let res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 1, sort: 'createdAt' }) 81 let res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 1, sort: 'createdAt' })
82 let follows = res.body.data 82 let follows = res.body.data
83 83
84 expect(res.body.total).to.equal(2) 84 expect(res.body.total).to.equal(2)
85 expect(follows).to.be.an('array') 85 expect(follows).to.be.an('array')
86 expect(follows.length).to.equal(1) 86 expect(follows.length).to.equal(1)
87 87
88 res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 1, count: 1, sort: 'createdAt' }) 88 res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 1, count: 1, sort: 'createdAt' })
89 follows = follows.concat(res.body.data) 89 follows = follows.concat(res.body.data)
90 90
91 const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port) 91 const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port)
@@ -101,7 +101,7 @@ describe('Test follows', function () {
101 const sort = 'createdAt' 101 const sort = 'createdAt'
102 const start = 0 102 const start = 0
103 const count = 1 103 const count = 1
104 const url = servers[ 0 ].url 104 const url = servers[0].url
105 105
106 { 106 {
107 const search = ':' + servers[1].port 107 const search = ':' + servers[1].port
@@ -112,7 +112,7 @@ describe('Test follows', function () {
112 112
113 expect(res.body.total).to.equal(1) 113 expect(res.body.total).to.equal(1)
114 expect(follows.length).to.equal(1) 114 expect(follows.length).to.equal(1)
115 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 1 ].port) 115 expect(follows[0].following.host).to.equal('localhost:' + servers[1].port)
116 } 116 }
117 117
118 { 118 {
@@ -170,9 +170,9 @@ describe('Test follows', function () {
170 170
171 it('Should have 1 followers on server 2 and 3', async function () { 171 it('Should have 1 followers on server 2 and 3', async function () {
172 for (const server of [ servers[1], servers[2] ]) { 172 for (const server of [ servers[1], servers[2] ]) {
173 let res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' }) 173 const res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' })
174 174
175 let follows = res.body.data 175 const follows = res.body.data
176 expect(res.body.total).to.equal(1) 176 expect(res.body.total).to.equal(1)
177 expect(follows).to.be.an('array') 177 expect(follows).to.be.an('array')
178 expect(follows.length).to.equal(1) 178 expect(follows.length).to.equal(1)
@@ -181,7 +181,7 @@ describe('Test follows', function () {
181 }) 181 })
182 182
183 it('Should search/filter followers on server 2', async function () { 183 it('Should search/filter followers on server 2', async function () {
184 const url = servers[ 2 ].url 184 const url = servers[2].url
185 const start = 0 185 const start = 0
186 const count = 5 186 const count = 5
187 const sort = 'createdAt' 187 const sort = 'createdAt'
@@ -195,7 +195,7 @@ describe('Test follows', function () {
195 195
196 expect(res.body.total).to.equal(1) 196 expect(res.body.total).to.equal(1)
197 expect(follows.length).to.equal(1) 197 expect(follows.length).to.equal(1)
198 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 2 ].port) 198 expect(follows[0].following.host).to.equal('localhost:' + servers[2].port)
199 } 199 }
200 200
201 { 201 {
@@ -241,7 +241,7 @@ describe('Test follows', function () {
241 }) 241 })
242 242
243 it('Should have 0 followers on server 1', async function () { 243 it('Should have 0 followers on server 1', async function () {
244 const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) 244 const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' })
245 const follows = res.body.data 245 const follows = res.body.data
246 246
247 expect(res.body.total).to.equal(0) 247 expect(res.body.total).to.equal(0)
@@ -271,8 +271,8 @@ describe('Test follows', function () {
271 }) 271 })
272 272
273 it('Should not follow server 3 on server 1 anymore', async function () { 273 it('Should not follow server 3 on server 1 anymore', async function () {
274 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) 274 const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' })
275 let follows = res.body.data 275 const follows = res.body.data
276 276
277 expect(res.body.total).to.equal(1) 277 expect(res.body.total).to.equal(1)
278 expect(follows).to.be.an('array') 278 expect(follows).to.be.an('array')
@@ -282,9 +282,9 @@ describe('Test follows', function () {
282 }) 282 })
283 283
284 it('Should not have server 1 as follower on server 3 anymore', async function () { 284 it('Should not have server 1 as follower on server 3 anymore', async function () {
285 const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 1, sort: 'createdAt' }) 285 const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 1, sort: 'createdAt' })
286 286
287 let follows = res.body.data 287 const follows = res.body.data
288 expect(res.body.total).to.equal(0) 288 expect(res.body.total).to.equal(0)
289 expect(follows).to.be.an('array') 289 expect(follows).to.be.an('array')
290 expect(follows.length).to.equal(0) 290 expect(follows.length).to.equal(0)
@@ -336,59 +336,59 @@ describe('Test follows', function () {
336 tags: [ 'tag1', 'tag2', 'tag3' ] 336 tags: [ 'tag1', 'tag2', 'tag3' ]
337 } 337 }
338 338
339 await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-2' }) 339 await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-2' })
340 await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-3' }) 340 await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-3' })
341 await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4Attributes) 341 await uploadVideo(servers[2].url, servers[2].accessToken, video4Attributes)
342 await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-5' }) 342 await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-5' })
343 await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-6' }) 343 await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-6' })
344 344
345 { 345 {
346 const user = { username: 'captain', password: 'password' } 346 const user = { username: 'captain', password: 'password' }
347 await createUser({ url: servers[ 2 ].url, accessToken: servers[ 2 ].accessToken, username: user.username, password: user.password }) 347 await createUser({ url: servers[2].url, accessToken: servers[2].accessToken, username: user.username, password: user.password })
348 const userAccessToken = await userLogin(servers[ 2 ], user) 348 const userAccessToken = await userLogin(servers[2], user)
349 349
350 const resVideos = await getVideosList(servers[ 2 ].url) 350 const resVideos = await getVideosList(servers[2].url)
351 video4 = resVideos.body.data.find(v => v.name === 'server3-4') 351 video4 = resVideos.body.data.find(v => v.name === 'server3-4')
352 352
353 { 353 {
354 await rateVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, 'like') 354 await rateVideo(servers[2].url, servers[2].accessToken, video4.id, 'like')
355 await rateVideo(servers[ 2 ].url, userAccessToken, video4.id, 'dislike') 355 await rateVideo(servers[2].url, userAccessToken, video4.id, 'dislike')
356 } 356 }
357 357
358 { 358 {
359 { 359 {
360 const text = 'my super first comment' 360 const text = 'my super first comment'
361 const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text) 361 const res = await addVideoCommentThread(servers[2].url, servers[2].accessToken, video4.id, text)
362 const threadId = res.body.comment.id 362 const threadId = res.body.comment.id
363 363
364 const text1 = 'my super answer to thread 1' 364 const text1 = 'my super answer to thread 1'
365 const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1) 365 const childCommentRes = await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text1)
366 const childCommentId = childCommentRes.body.comment.id 366 const childCommentId = childCommentRes.body.comment.id
367 367
368 const text2 = 'my super answer to answer of thread 1' 368 const text2 = 'my super answer to answer of thread 1'
369 await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text2) 369 await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, childCommentId, text2)
370 370
371 const text3 = 'my second answer to thread 1' 371 const text3 = 'my second answer to thread 1'
372 await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text3) 372 await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text3)
373 } 373 }
374 374
375 { 375 {
376 const text = 'will be deleted' 376 const text = 'will be deleted'
377 const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text) 377 const res = await addVideoCommentThread(servers[2].url, servers[2].accessToken, video4.id, text)
378 const threadId = res.body.comment.id 378 const threadId = res.body.comment.id
379 379
380 const text1 = 'answer to deleted' 380 const text1 = 'answer to deleted'
381 await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1) 381 await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text1)
382 382
383 const text2 = 'will also be deleted' 383 const text2 = 'will also be deleted'
384 const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text2) 384 const childCommentRes = await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text2)
385 const childCommentId = childCommentRes.body.comment.id 385 const childCommentId = childCommentRes.body.comment.id
386 386
387 const text3 = 'my second answer to deleted' 387 const text3 = 'my second answer to deleted'
388 await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text3) 388 await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, childCommentId, text3)
389 389
390 await deleteVideoComment(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId) 390 await deleteVideoComment(servers[2].url, servers[2].accessToken, video4.id, threadId)
391 await deleteVideoComment(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId) 391 await deleteVideoComment(servers[2].url, servers[2].accessToken, video4.id, childCommentId)
392 } 392 }
393 } 393 }
394 394
@@ -406,7 +406,7 @@ describe('Test follows', function () {
406 await waitJobs(servers) 406 await waitJobs(servers)
407 407
408 // Server 1 follows server 3 408 // Server 1 follows server 3
409 await follow(servers[ 0 ].url, [ servers[ 2 ].url ], servers[ 0 ].accessToken) 409 await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken)
410 410
411 await waitJobs(servers) 411 await waitJobs(servers)
412 }) 412 })
@@ -424,7 +424,7 @@ describe('Test follows', function () {
424 }) 424 })
425 425
426 it('Should have propagated videos', async function () { 426 it('Should have propagated videos', async function () {
427 const res = await getVideosList(servers[ 0 ].url) 427 const res = await getVideosList(servers[0].url)
428 expect(res.body.total).to.equal(7) 428 expect(res.body.total).to.equal(7)
429 429
430 const video2 = res.body.data.find(v => v.name === 'server3-2') 430 const video2 = res.body.data.find(v => v.name === 'server3-2')
@@ -470,7 +470,7 @@ describe('Test follows', function () {
470 } 470 }
471 ] 471 ]
472 } 472 }
473 await completeVideoCheck(servers[ 0 ].url, video4, checkAttributes) 473 await completeVideoCheck(servers[0].url, video4, checkAttributes)
474 }) 474 })
475 475
476 it('Should have propagated comments', async function () { 476 it('Should have propagated comments', async function () {
@@ -481,34 +481,34 @@ describe('Test follows', function () {
481 expect(res1.body.data).to.have.lengthOf(2) 481 expect(res1.body.data).to.have.lengthOf(2)
482 482
483 { 483 {
484 const comment: VideoComment = res1.body.data[ 0 ] 484 const comment: VideoComment = res1.body.data[0]
485 expect(comment.inReplyToCommentId).to.be.null 485 expect(comment.inReplyToCommentId).to.be.null
486 expect(comment.text).equal('my super first comment') 486 expect(comment.text).equal('my super first comment')
487 expect(comment.videoId).to.equal(video4.id) 487 expect(comment.videoId).to.equal(video4.id)
488 expect(comment.id).to.equal(comment.threadId) 488 expect(comment.id).to.equal(comment.threadId)
489 expect(comment.account.name).to.equal('root') 489 expect(comment.account.name).to.equal('root')
490 expect(comment.account.host).to.equal('localhost:' + servers[ 2 ].port) 490 expect(comment.account.host).to.equal('localhost:' + servers[2].port)
491 expect(comment.totalReplies).to.equal(3) 491 expect(comment.totalReplies).to.equal(3)
492 expect(dateIsValid(comment.createdAt as string)).to.be.true 492 expect(dateIsValid(comment.createdAt as string)).to.be.true
493 expect(dateIsValid(comment.updatedAt as string)).to.be.true 493 expect(dateIsValid(comment.updatedAt as string)).to.be.true
494 494
495 const threadId = comment.threadId 495 const threadId = comment.threadId
496 496
497 const res2 = await getVideoThreadComments(servers[ 0 ].url, video4.id, threadId) 497 const res2 = await getVideoThreadComments(servers[0].url, video4.id, threadId)
498 498
499 const tree: VideoCommentThreadTree = res2.body 499 const tree: VideoCommentThreadTree = res2.body
500 expect(tree.comment.text).equal('my super first comment') 500 expect(tree.comment.text).equal('my super first comment')
501 expect(tree.children).to.have.lengthOf(2) 501 expect(tree.children).to.have.lengthOf(2)
502 502
503 const firstChild = tree.children[ 0 ] 503 const firstChild = tree.children[0]
504 expect(firstChild.comment.text).to.equal('my super answer to thread 1') 504 expect(firstChild.comment.text).to.equal('my super answer to thread 1')
505 expect(firstChild.children).to.have.lengthOf(1) 505 expect(firstChild.children).to.have.lengthOf(1)
506 506
507 const childOfFirstChild = firstChild.children[ 0 ] 507 const childOfFirstChild = firstChild.children[0]
508 expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') 508 expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
509 expect(childOfFirstChild.children).to.have.lengthOf(0) 509 expect(childOfFirstChild.children).to.have.lengthOf(0)
510 510
511 const secondChild = tree.children[ 1 ] 511 const secondChild = tree.children[1]
512 expect(secondChild.comment.text).to.equal('my second answer to thread 1') 512 expect(secondChild.comment.text).to.equal('my second answer to thread 1')
513 expect(secondChild.children).to.have.lengthOf(0) 513 expect(secondChild.children).to.have.lengthOf(0)
514 } 514 }
@@ -569,7 +569,7 @@ describe('Test follows', function () {
569 569
570 await waitJobs(servers) 570 await waitJobs(servers)
571 571
572 let res = await getVideosList(servers[ 0 ].url) 572 const res = await getVideosList(servers[0].url)
573 expect(res.body.total).to.equal(1) 573 expect(res.body.total).to.equal(1)
574 }) 574 })
575 575
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts
index 7e36067f1..2cf6e15ad 100644
--- a/server/tests/api/server/handle-down.ts
+++ b/server/tests/api/server/handle-down.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -8,6 +8,7 @@ import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-c
8 8
9import { 9import {
10 cleanupTests, 10 cleanupTests,
11 closeAllSequelize,
11 completeVideoCheck, 12 completeVideoCheck,
12 flushAndRunMultipleServers, 13 flushAndRunMultipleServers,
13 getVideo, 14 getVideo,
@@ -17,11 +18,12 @@ import {
17 reRunServer, 18 reRunServer,
18 ServerInfo, 19 ServerInfo,
19 setAccessTokensToServers, 20 setAccessTokensToServers,
21 setActorFollowScores,
20 unfollow, 22 unfollow,
21 updateVideo, 23 updateVideo,
22 uploadVideo, uploadVideoAndGetId, 24 uploadVideo,
23 wait, 25 uploadVideoAndGetId,
24 setActorFollowScores, closeAllSequelize 26 wait
25} from '../../../../shared/extra-utils' 27} from '../../../../shared/extra-utils'
26import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows' 28import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows'
27import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' 29import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs'
@@ -44,7 +46,7 @@ describe('Test handle downs', function () {
44 let missedVideo2: Video 46 let missedVideo2: Video
45 let unlistedVideo: Video 47 let unlistedVideo: Video
46 48
47 let videoIdsServer1: number[] = [] 49 const videoIdsServer1: number[] = []
48 50
49 const videoAttributes = { 51 const videoAttributes = {
50 name: 'my super name for server 1', 52 name: 'my super name for server 1',
@@ -137,7 +139,7 @@ describe('Test handle downs', function () {
137 139
138 // Remove server 2 follower 140 // Remove server 2 follower
139 for (let i = 0; i < 10; i++) { 141 for (let i = 0; i < 10; i++) {
140 await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) 142 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
141 } 143 }
142 144
143 await waitJobs(servers[0]) 145 await waitJobs(servers[0])
@@ -145,14 +147,14 @@ describe('Test handle downs', function () {
145 // Kill server 3 147 // Kill server 3
146 killallServers([ servers[2] ]) 148 killallServers([ servers[2] ])
147 149
148 const resLastVideo1 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) 150 const resLastVideo1 = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
149 missedVideo1 = resLastVideo1.body.video 151 missedVideo1 = resLastVideo1.body.video
150 152
151 const resLastVideo2 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) 153 const resLastVideo2 = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
152 missedVideo2 = resLastVideo2.body.video 154 missedVideo2 = resLastVideo2.body.video
153 155
154 // Unlisted video 156 // Unlisted video
155 let resVideo = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, unlistedVideoAttributes) 157 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, unlistedVideoAttributes)
156 unlistedVideo = resVideo.body.video 158 unlistedVideo = resVideo.body.video
157 159
158 // Add comments to video 2 160 // Add comments to video 2
@@ -174,7 +176,7 @@ describe('Test handle downs', function () {
174 await wait(11000) 176 await wait(11000)
175 177
176 // Only server 3 is still a follower of server 1 178 // Only server 3 is still a follower of server 1
177 const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) 179 const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' })
178 expect(res.body.data).to.be.an('array') 180 expect(res.body.data).to.be.an('array')
179 expect(res.body.data).to.have.lengthOf(1) 181 expect(res.body.data).to.have.lengthOf(1)
180 expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port) 182 expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port)
@@ -185,8 +187,8 @@ describe('Test handle downs', function () {
185 187
186 for (const state of states) { 188 for (const state of states) {
187 const res = await getJobsListPaginationAndSort({ 189 const res = await getJobsListPaginationAndSort({
188 url: servers[ 0 ].url, 190 url: servers[0].url,
189 accessToken: servers[ 0 ].accessToken, 191 accessToken: servers[0].accessToken,
190 state: state, 192 state: state,
191 start: 0, 193 start: 0,
192 count: 50, 194 count: 50,
@@ -209,7 +211,7 @@ describe('Test handle downs', function () {
209 211
210 await waitJobs(servers) 212 await waitJobs(servers)
211 213
212 const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) 214 const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' })
213 expect(res.body.data).to.be.an('array') 215 expect(res.body.data).to.be.an('array')
214 expect(res.body.data).to.have.lengthOf(2) 216 expect(res.body.data).to.have.lengthOf(2)
215 }) 217 })
@@ -221,8 +223,8 @@ describe('Test handle downs', function () {
221 expect(res1.body.data).to.be.an('array') 223 expect(res1.body.data).to.be.an('array')
222 expect(res1.body.data).to.have.lengthOf(11) 224 expect(res1.body.data).to.have.lengthOf(11)
223 225
224 await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, { }) 226 await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, {})
225 await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, { }) 227 await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, {})
226 228
227 await waitJobs(servers) 229 await waitJobs(servers)
228 230
@@ -313,14 +315,14 @@ describe('Test handle downs', function () {
313 this.timeout(120000) 315 this.timeout(120000)
314 316
315 for (let i = 0; i < 10; i++) { 317 for (let i = 0; i < 10; i++) {
316 const uuid = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'video ' + i })).uuid 318 const uuid = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video ' + i })).uuid
317 videoIdsServer1.push(uuid) 319 videoIdsServer1.push(uuid)
318 } 320 }
319 321
320 await waitJobs(servers) 322 await waitJobs(servers)
321 323
322 for (const id of videoIdsServer1) { 324 for (const id of videoIdsServer1) {
323 await getVideo(servers[ 1 ].url, id) 325 await getVideo(servers[1].url, id)
324 } 326 }
325 327
326 await waitJobs(servers) 328 await waitJobs(servers)
diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts
index 58d8c8c10..19c8836b5 100644
--- a/server/tests/api/server/jobs.ts
+++ b/server/tests/api/server/jobs.ts
@@ -1,8 +1,8 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { cleanupTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' 5import { cleanupTests, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
6import { doubleFollow } from '../../../../shared/extra-utils/server/follows' 6import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
7import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' 7import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs'
8import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers' 8import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers'
@@ -44,8 +44,8 @@ describe('Test jobs', function () {
44 it('Should list jobs with sort, pagination and job type', async function () { 44 it('Should list jobs with sort, pagination and job type', async function () {
45 { 45 {
46 const res = await getJobsListPaginationAndSort({ 46 const res = await getJobsListPaginationAndSort({
47 url: servers[ 1 ].url, 47 url: servers[1].url,
48 accessToken: servers[ 1 ].accessToken, 48 accessToken: servers[1].accessToken,
49 state: 'completed', 49 state: 'completed',
50 start: 1, 50 start: 1,
51 count: 2, 51 count: 2,
@@ -54,9 +54,9 @@ describe('Test jobs', function () {
54 expect(res.body.total).to.be.above(2) 54 expect(res.body.total).to.be.above(2)
55 expect(res.body.data).to.have.lengthOf(2) 55 expect(res.body.data).to.have.lengthOf(2)
56 56
57 let job: Job = res.body.data[ 0 ] 57 let job: Job = res.body.data[0]
58 // Skip repeat jobs 58 // Skip repeat jobs
59 if (job.type === 'videos-views') job = res.body.data[ 1 ] 59 if (job.type === 'videos-views') job = res.body.data[1]
60 60
61 expect(job.state).to.equal('completed') 61 expect(job.state).to.equal('completed')
62 expect(job.type.startsWith('activitypub-')).to.be.true 62 expect(job.type.startsWith('activitypub-')).to.be.true
@@ -67,8 +67,8 @@ describe('Test jobs', function () {
67 67
68 { 68 {
69 const res = await getJobsListPaginationAndSort({ 69 const res = await getJobsListPaginationAndSort({
70 url: servers[ 1 ].url, 70 url: servers[1].url,
71 accessToken: servers[ 1 ].accessToken, 71 accessToken: servers[1].accessToken,
72 state: 'completed', 72 state: 'completed',
73 start: 0, 73 start: 0,
74 count: 100, 74 count: 100,
diff --git a/server/tests/api/server/logs.ts b/server/tests/api/server/logs.ts
index d3c877408..b8714c7a1 100644
--- a/server/tests/api/server/logs.ts
+++ b/server/tests/api/server/logs.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/api/server/no-client.ts b/server/tests/api/server/no-client.ts
index 86edeb289..d0450aba0 100644
--- a/server/tests/api/server/no-client.ts
+++ b/server/tests/api/server/no-client.ts
@@ -9,7 +9,7 @@ describe('Start and stop server without web client routes', function () {
9 before(async function () { 9 before(async function () {
10 this.timeout(30000) 10 this.timeout(30000)
11 11
12 server = await flushAndRunServer(1, {}, ['--no-client']) 12 server = await flushAndRunServer(1, {}, [ '--no-client' ])
13 }) 13 })
14 14
15 it('Should fail getting the client', function () { 15 it('Should fail getting the client', function () {
diff --git a/server/tests/api/server/plugins.ts b/server/tests/api/server/plugins.ts
index b8a8a2fee..452d05012 100644
--- a/server/tests/api/server/plugins.ts
+++ b/server/tests/api/server/plugins.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
@@ -6,19 +6,28 @@ import {
6 cleanupTests, 6 cleanupTests,
7 closeAllSequelize, 7 closeAllSequelize,
8 flushAndRunServer, 8 flushAndRunServer,
9 getConfig, getMyUserInformation, getPluginPackageJSON, 9 getConfig,
10 getMyUserInformation,
10 getPlugin, 11 getPlugin,
12 getPluginPackageJSON,
11 getPluginRegisteredSettings, 13 getPluginRegisteredSettings,
12 getPluginsCSS, 14 getPluginsCSS,
13 installPlugin, killallServers, 15 getPublicSettings,
16 installPlugin,
17 killallServers,
14 listAvailablePlugins, 18 listAvailablePlugins,
15 listPlugins, reRunServer, 19 listPlugins,
20 reRunServer,
16 ServerInfo, 21 ServerInfo,
17 setAccessTokensToServers, 22 setAccessTokensToServers,
18 setPluginVersion, uninstallPlugin, 23 setPluginVersion,
19 updateCustomSubConfig, updateMyUser, updatePluginPackageJSON, updatePlugin, 24 uninstallPlugin,
25 updateCustomSubConfig,
26 updateMyUser,
27 updatePlugin,
28 updatePluginPackageJSON,
20 updatePluginSettings, 29 updatePluginSettings,
21 wait, getPublicSettings 30 wait
22} from '../../../../shared/extra-utils' 31} from '../../../../shared/extra-utils'
23import { PluginType } from '../../../../shared/models/plugins/plugin.type' 32import { PluginType } from '../../../../shared/models/plugins/plugin.type'
24import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model' 33import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model'
@@ -88,7 +97,7 @@ describe('Test plugins', function () {
88 expect(res2.body.total).to.be.at.least(2) 97 expect(res2.body.total).to.be.at.least(2)
89 expect(data2).to.have.lengthOf(2) 98 expect(data2).to.have.lengthOf(2)
90 99
91 expect(data1[0].npmName).to.not.equal(data2[ 0 ].npmName) 100 expect(data1[0].npmName).to.not.equal(data2[0].npmName)
92 } 101 }
93 102
94 { 103 {
diff --git a/server/tests/api/server/reverse-proxy.ts b/server/tests/api/server/reverse-proxy.ts
index b6b33a884..d0d79c4f6 100644
--- a/server/tests/api/server/reverse-proxy.ts
+++ b/server/tests/api/server/reverse-proxy.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
diff --git a/server/tests/api/server/stats.ts b/server/tests/api/server/stats.ts
index a01cd4b38..c207bb5f0 100644
--- a/server/tests/api/server/stats.ts
+++ b/server/tests/api/server/stats.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -9,13 +9,12 @@ import {
9 doubleFollow, 9 doubleFollow,
10 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
11 follow, 11 follow,
12 killallServers,
13 ServerInfo, 12 ServerInfo,
14 uploadVideo, 13 uploadVideo,
15 viewVideo, 14 viewVideo,
16 wait 15 wait
17} from '../../../../shared/extra-utils' 16} from '../../../../shared/extra-utils'
18import { flushTests, setAccessTokensToServers } from '../../../../shared/extra-utils/index' 17import { setAccessTokensToServers } from '../../../../shared/extra-utils/index'
19import { getStats } from '../../../../shared/extra-utils/server/stats' 18import { getStats } from '../../../../shared/extra-utils/server/stats'
20import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments' 19import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
21import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 20import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
@@ -36,7 +35,7 @@ describe('Test stats (excluding redundancy)', function () {
36 username: 'user1', 35 username: 'user1',
37 password: 'super_password' 36 password: 'super_password'
38 } 37 }
39 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) 38 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
40 39
41 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' }) 40 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' })
42 const videoUUID = resVideo.body.video.uuid 41 const videoUUID = resVideo.body.video.uuid
diff --git a/server/tests/api/server/tracker.ts b/server/tests/api/server/tracker.ts
index 9d7eec8ca..9d3a274d4 100644
--- a/server/tests/api/server/tracker.ts
+++ b/server/tests/api/server/tracker.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await,@typescript-eslint/no-floating-promises */
2 2
3import * as magnetUtil from 'magnet-uri' 3import * as magnetUtil from 'magnet-uri'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/api/users/blocklist.ts b/server/tests/api/users/blocklist.ts
index 05e58017a..21b9ae4f8 100644
--- a/server/tests/api/users/blocklist.ts
+++ b/server/tests/api/users/blocklist.ts
@@ -1,21 +1,20 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { AccountBlock, ServerBlock, UserNotificationType, Video } from '../../../../shared/index' 5import { AccountBlock, ServerBlock, Video } from '../../../../shared/index'
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 createUser, deleteVideoComment, 8 createUser,
9 deleteVideoComment,
9 doubleFollow, 10 doubleFollow,
10 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
11 flushTests,
12 killallServers,
13 ServerInfo, 12 ServerInfo,
14 uploadVideo, 13 uploadVideo,
15 userLogin 14 userLogin
16} from '../../../../shared/extra-utils/index' 15} from '../../../../shared/extra-utils/index'
17import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' 16import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
18import { getVideosListWithToken, getVideosList } from '../../../../shared/extra-utils/videos/videos' 17import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos'
19import { 18import {
20 addVideoCommentReply, 19 addVideoCommentReply,
21 addVideoCommentThread, 20 addVideoCommentThread,
@@ -79,7 +78,7 @@ async function checkCommentNotification (
79 const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text) 78 const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text)
80 const threadId = resComment.body.comment.id 79 const threadId = resComment.body.comment.id
81 80
82 await waitJobs([ mainServer, comment.server]) 81 await waitJobs([ mainServer, comment.server ])
83 82
84 const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30) 83 const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30)
85 const commentNotifications = res.body.data 84 const commentNotifications = res.body.data
@@ -90,7 +89,7 @@ async function checkCommentNotification (
90 89
91 await deleteVideoComment(comment.server.url, comment.token, comment.videoUUID, threadId) 90 await deleteVideoComment(comment.server.url, comment.token, comment.videoUUID, threadId)
92 91
93 await waitJobs([ mainServer, comment.server]) 92 await waitJobs([ mainServer, comment.server ])
94} 93}
95 94
96describe('Test blocklist', function () { 95describe('Test blocklist', function () {
@@ -109,7 +108,7 @@ describe('Test blocklist', function () {
109 108
110 { 109 {
111 const user = { username: 'user1', password: 'password' } 110 const user = { username: 'user1', password: 'password' }
112 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) 111 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
113 112
114 userToken1 = await userLogin(servers[0], user) 113 userToken1 = await userLogin(servers[0], user)
115 await uploadVideo(servers[0].url, userToken1, { name: 'video user 1' }) 114 await uploadVideo(servers[0].url, userToken1, { name: 'video user 1' })
@@ -117,14 +116,14 @@ describe('Test blocklist', function () {
117 116
118 { 117 {
119 const user = { username: 'moderator', password: 'password' } 118 const user = { username: 'moderator', password: 'password' }
120 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) 119 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
121 120
122 userModeratorToken = await userLogin(servers[0], user) 121 userModeratorToken = await userLogin(servers[0], user)
123 } 122 }
124 123
125 { 124 {
126 const user = { username: 'user2', password: 'password' } 125 const user = { username: 'user2', password: 'password' }
127 await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) 126 await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password })
128 127
129 userToken2 = await userLogin(servers[1], user) 128 userToken2 = await userLogin(servers[1], user)
130 await uploadVideo(servers[1].url, userToken2, { name: 'video user 2' }) 129 await uploadVideo(servers[1].url, userToken2, { name: 'video user 2' })
@@ -143,14 +142,14 @@ describe('Test blocklist', function () {
143 await doubleFollow(servers[0], servers[1]) 142 await doubleFollow(servers[0], servers[1])
144 143
145 { 144 {
146 const resComment = await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, 'comment root 1') 145 const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID1, 'comment root 1')
147 const resReply = await addVideoCommentReply(servers[ 0 ].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1') 146 const resReply = await addVideoCommentReply(servers[0].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1')
148 await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1') 147 await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1')
149 } 148 }
150 149
151 { 150 {
152 const resComment = await addVideoCommentThread(servers[ 0 ].url, userToken1, videoUUID1, 'comment user 1') 151 const resComment = await addVideoCommentThread(servers[0].url, userToken1, videoUUID1, 'comment user 1')
153 await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1') 152 await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1')
154 } 153 }
155 154
156 await waitJobs(servers) 155 await waitJobs(servers)
@@ -160,19 +159,19 @@ describe('Test blocklist', function () {
160 159
161 describe('When managing account blocklist', function () { 160 describe('When managing account blocklist', function () {
162 it('Should list all videos', function () { 161 it('Should list all videos', function () {
163 return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) 162 return checkAllVideos(servers[0].url, servers[0].accessToken)
164 }) 163 })
165 164
166 it('Should list the comments', function () { 165 it('Should list the comments', function () {
167 return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) 166 return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
168 }) 167 })
169 168
170 it('Should block a remote account', async function () { 169 it('Should block a remote account', async function () {
171 await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) 170 await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
172 }) 171 })
173 172
174 it('Should hide its videos', async function () { 173 it('Should hide its videos', async function () {
175 const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) 174 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
176 175
177 const videos: Video[] = res.body.data 176 const videos: Video[] = res.body.data
178 expect(videos).to.have.lengthOf(3) 177 expect(videos).to.have.lengthOf(3)
@@ -182,11 +181,11 @@ describe('Test blocklist', function () {
182 }) 181 })
183 182
184 it('Should block a local account', async function () { 183 it('Should block a local account', async function () {
185 await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') 184 await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1')
186 }) 185 })
187 186
188 it('Should hide its videos', async function () { 187 it('Should hide its videos', async function () {
189 const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) 188 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
190 189
191 const videos: Video[] = res.body.data 190 const videos: Video[] = res.body.data
192 expect(videos).to.have.lengthOf(2) 191 expect(videos).to.have.lengthOf(2)
@@ -196,17 +195,17 @@ describe('Test blocklist', function () {
196 }) 195 })
197 196
198 it('Should hide its comments', async function () { 197 it('Should hide its comments', async function () {
199 const resThreads = await getVideoCommentThreads(servers[ 0 ].url, videoUUID1, 0, 5, '-createdAt', servers[ 0 ].accessToken) 198 const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', servers[0].accessToken)
200 199
201 const threads: VideoComment[] = resThreads.body.data 200 const threads: VideoComment[] = resThreads.body.data
202 expect(threads).to.have.lengthOf(1) 201 expect(threads).to.have.lengthOf(1)
203 expect(threads[ 0 ].totalReplies).to.equal(0) 202 expect(threads[0].totalReplies).to.equal(0)
204 203
205 const t = threads.find(t => t.text === 'comment user 1') 204 const t = threads.find(t => t.text === 'comment user 1')
206 expect(t).to.be.undefined 205 expect(t).to.be.undefined
207 206
208 for (const thread of threads) { 207 for (const thread of threads) {
209 const res = await getVideoThreadComments(servers[ 0 ].url, videoUUID1, thread.id, servers[ 0 ].accessToken) 208 const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, servers[0].accessToken)
210 209
211 const tree: VideoCommentThreadTree = res.body 210 const tree: VideoCommentThreadTree = res.body
212 expect(tree.children).to.have.lengthOf(0) 211 expect(tree.children).to.have.lengthOf(0)
@@ -217,37 +216,37 @@ describe('Test blocklist', function () {
217 this.timeout(20000) 216 this.timeout(20000)
218 217
219 { 218 {
220 const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } 219 const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' }
221 await checkCommentNotification(servers[ 0 ], comment, 'absence') 220 await checkCommentNotification(servers[0], comment, 'absence')
222 } 221 }
223 222
224 { 223 {
225 const comment = { 224 const comment = {
226 server: servers[ 0 ], 225 server: servers[0],
227 token: userToken1, 226 token: userToken1,
228 videoUUID: videoUUID2, 227 videoUUID: videoUUID2,
229 text: 'hello @root@localhost:' + servers[ 0 ].port 228 text: 'hello @root@localhost:' + servers[0].port
230 } 229 }
231 await checkCommentNotification(servers[ 0 ], comment, 'absence') 230 await checkCommentNotification(servers[0], comment, 'absence')
232 } 231 }
233 }) 232 })
234 233
235 it('Should list all the videos with another user', async function () { 234 it('Should list all the videos with another user', async function () {
236 return checkAllVideos(servers[ 0 ].url, userToken1) 235 return checkAllVideos(servers[0].url, userToken1)
237 }) 236 })
238 237
239 it('Should list all the comments with another user', async function () { 238 it('Should list all the comments with another user', async function () {
240 return checkAllComments(servers[ 0 ].url, userToken1, videoUUID1) 239 return checkAllComments(servers[0].url, userToken1, videoUUID1)
241 }) 240 })
242 241
243 it('Should list blocked accounts', async function () { 242 it('Should list blocked accounts', async function () {
244 { 243 {
245 const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') 244 const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
246 const blocks: AccountBlock[] = res.body.data 245 const blocks: AccountBlock[] = res.body.data
247 246
248 expect(res.body.total).to.equal(2) 247 expect(res.body.total).to.equal(2)
249 248
250 const block = blocks[ 0 ] 249 const block = blocks[0]
251 expect(block.byAccount.displayName).to.equal('root') 250 expect(block.byAccount.displayName).to.equal('root')
252 expect(block.byAccount.name).to.equal('root') 251 expect(block.byAccount.name).to.equal('root')
253 expect(block.blockedAccount.displayName).to.equal('user2') 252 expect(block.blockedAccount.displayName).to.equal('user2')
@@ -256,12 +255,12 @@ describe('Test blocklist', function () {
256 } 255 }
257 256
258 { 257 {
259 const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt') 258 const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 1, 2, 'createdAt')
260 const blocks: AccountBlock[] = res.body.data 259 const blocks: AccountBlock[] = res.body.data
261 260
262 expect(res.body.total).to.equal(2) 261 expect(res.body.total).to.equal(2)
263 262
264 const block = blocks[ 0 ] 263 const block = blocks[0]
265 expect(block.byAccount.displayName).to.equal('root') 264 expect(block.byAccount.displayName).to.equal('root')
266 expect(block.byAccount.name).to.equal('root') 265 expect(block.byAccount.name).to.equal('root')
267 expect(block.blockedAccount.displayName).to.equal('user1') 266 expect(block.blockedAccount.displayName).to.equal('user1')
@@ -271,11 +270,11 @@ describe('Test blocklist', function () {
271 }) 270 })
272 271
273 it('Should unblock the remote account', async function () { 272 it('Should unblock the remote account', async function () {
274 await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) 273 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
275 }) 274 })
276 275
277 it('Should display its videos', async function () { 276 it('Should display its videos', async function () {
278 const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) 277 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
279 278
280 const videos: Video[] = res.body.data 279 const videos: Video[] = res.body.data
281 expect(videos).to.have.lengthOf(3) 280 expect(videos).to.have.lengthOf(3)
@@ -285,48 +284,48 @@ describe('Test blocklist', function () {
285 }) 284 })
286 285
287 it('Should unblock the local account', async function () { 286 it('Should unblock the local account', async function () {
288 await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') 287 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1')
289 }) 288 })
290 289
291 it('Should display its comments', function () { 290 it('Should display its comments', function () {
292 return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) 291 return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
293 }) 292 })
294 293
295 it('Should have a notification from a non blocked account', async function () { 294 it('Should have a notification from a non blocked account', async function () {
296 this.timeout(20000) 295 this.timeout(20000)
297 296
298 { 297 {
299 const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } 298 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
300 await checkCommentNotification(servers[ 0 ], comment, 'presence') 299 await checkCommentNotification(servers[0], comment, 'presence')
301 } 300 }
302 301
303 { 302 {
304 const comment = { 303 const comment = {
305 server: servers[ 0 ], 304 server: servers[0],
306 token: userToken1, 305 token: userToken1,
307 videoUUID: videoUUID2, 306 videoUUID: videoUUID2,
308 text: 'hello @root@localhost:' + servers[ 0 ].port 307 text: 'hello @root@localhost:' + servers[0].port
309 } 308 }
310 await checkCommentNotification(servers[ 0 ], comment, 'presence') 309 await checkCommentNotification(servers[0], comment, 'presence')
311 } 310 }
312 }) 311 })
313 }) 312 })
314 313
315 describe('When managing server blocklist', function () { 314 describe('When managing server blocklist', function () {
316 it('Should list all videos', function () { 315 it('Should list all videos', function () {
317 return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) 316 return checkAllVideos(servers[0].url, servers[0].accessToken)
318 }) 317 })
319 318
320 it('Should list the comments', function () { 319 it('Should list the comments', function () {
321 return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) 320 return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
322 }) 321 })
323 322
324 it('Should block a remote server', async function () { 323 it('Should block a remote server', async function () {
325 await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) 324 await addServerToAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
326 }) 325 })
327 326
328 it('Should hide its videos', async function () { 327 it('Should hide its videos', async function () {
329 const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) 328 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
330 329
331 const videos: Video[] = res.body.data 330 const videos: Video[] = res.body.data
332 expect(videos).to.have.lengthOf(2) 331 expect(videos).to.have.lengthOf(2)
@@ -339,81 +338,81 @@ describe('Test blocklist', function () {
339 }) 338 })
340 339
341 it('Should list all the videos with another user', async function () { 340 it('Should list all the videos with another user', async function () {
342 return checkAllVideos(servers[ 0 ].url, userToken1) 341 return checkAllVideos(servers[0].url, userToken1)
343 }) 342 })
344 343
345 it('Should hide its comments', async function () { 344 it('Should hide its comments', async function () {
346 this.timeout(10000) 345 this.timeout(10000)
347 346
348 const resThreads = await addVideoCommentThread(servers[ 1 ].url, userToken2, videoUUID1, 'hidden comment 2') 347 const resThreads = await addVideoCommentThread(servers[1].url, userToken2, videoUUID1, 'hidden comment 2')
349 const threadId = resThreads.body.comment.id 348 const threadId = resThreads.body.comment.id
350 349
351 await waitJobs(servers) 350 await waitJobs(servers)
352 351
353 await checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) 352 await checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
354 353
355 await deleteVideoComment(servers[ 1 ].url, userToken2, videoUUID1, threadId) 354 await deleteVideoComment(servers[1].url, userToken2, videoUUID1, threadId)
356 }) 355 })
357 356
358 it('Should not have notifications from blocked server', async function () { 357 it('Should not have notifications from blocked server', async function () {
359 this.timeout(20000) 358 this.timeout(20000)
360 359
361 { 360 {
362 const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } 361 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' }
363 await checkCommentNotification(servers[ 0 ], comment, 'absence') 362 await checkCommentNotification(servers[0], comment, 'absence')
364 } 363 }
365 364
366 { 365 {
367 const comment = { 366 const comment = {
368 server: servers[ 1 ], 367 server: servers[1],
369 token: userToken2, 368 token: userToken2,
370 videoUUID: videoUUID1, 369 videoUUID: videoUUID1,
371 text: 'hello @root@localhost:' + servers[ 0 ].port 370 text: 'hello @root@localhost:' + servers[0].port
372 } 371 }
373 await checkCommentNotification(servers[ 0 ], comment, 'absence') 372 await checkCommentNotification(servers[0], comment, 'absence')
374 } 373 }
375 }) 374 })
376 375
377 it('Should list blocked servers', async function () { 376 it('Should list blocked servers', async function () {
378 const res = await getServerBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') 377 const res = await getServerBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
379 const blocks: ServerBlock[] = res.body.data 378 const blocks: ServerBlock[] = res.body.data
380 379
381 expect(res.body.total).to.equal(1) 380 expect(res.body.total).to.equal(1)
382 381
383 const block = blocks[ 0 ] 382 const block = blocks[0]
384 expect(block.byAccount.displayName).to.equal('root') 383 expect(block.byAccount.displayName).to.equal('root')
385 expect(block.byAccount.name).to.equal('root') 384 expect(block.byAccount.name).to.equal('root')
386 expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) 385 expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port)
387 }) 386 })
388 387
389 it('Should unblock the remote server', async function () { 388 it('Should unblock the remote server', async function () {
390 await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) 389 await removeServerFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
391 }) 390 })
392 391
393 it('Should display its videos', function () { 392 it('Should display its videos', function () {
394 return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) 393 return checkAllVideos(servers[0].url, servers[0].accessToken)
395 }) 394 })
396 395
397 it('Should display its comments', function () { 396 it('Should display its comments', function () {
398 return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) 397 return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
399 }) 398 })
400 399
401 it('Should have notification from unblocked server', async function () { 400 it('Should have notification from unblocked server', async function () {
402 this.timeout(20000) 401 this.timeout(20000)
403 402
404 { 403 {
405 const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } 404 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
406 await checkCommentNotification(servers[ 0 ], comment, 'presence') 405 await checkCommentNotification(servers[0], comment, 'presence')
407 } 406 }
408 407
409 { 408 {
410 const comment = { 409 const comment = {
411 server: servers[ 1 ], 410 server: servers[1],
412 token: userToken2, 411 token: userToken2,
413 videoUUID: videoUUID1, 412 videoUUID: videoUUID1,
414 text: 'hello @root@localhost:' + servers[ 0 ].port 413 text: 'hello @root@localhost:' + servers[0].port
415 } 414 }
416 await checkCommentNotification(servers[ 0 ], comment, 'presence') 415 await checkCommentNotification(servers[0], comment, 'presence')
417 } 416 }
418 }) 417 })
419 }) 418 })
@@ -423,24 +422,24 @@ describe('Test blocklist', function () {
423 422
424 describe('When managing account blocklist', function () { 423 describe('When managing account blocklist', function () {
425 it('Should list all videos', async function () { 424 it('Should list all videos', async function () {
426 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 425 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
427 await checkAllVideos(servers[ 0 ].url, token) 426 await checkAllVideos(servers[0].url, token)
428 } 427 }
429 }) 428 })
430 429
431 it('Should list the comments', async function () { 430 it('Should list the comments', async function () {
432 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 431 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
433 await checkAllComments(servers[ 0 ].url, token, videoUUID1) 432 await checkAllComments(servers[0].url, token, videoUUID1)
434 } 433 }
435 }) 434 })
436 435
437 it('Should block a remote account', async function () { 436 it('Should block a remote account', async function () {
438 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) 437 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
439 }) 438 })
440 439
441 it('Should hide its videos', async function () { 440 it('Should hide its videos', async function () {
442 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 441 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
443 const res = await getVideosListWithToken(servers[ 0 ].url, token) 442 const res = await getVideosListWithToken(servers[0].url, token)
444 443
445 const videos: Video[] = res.body.data 444 const videos: Video[] = res.body.data
446 expect(videos).to.have.lengthOf(3) 445 expect(videos).to.have.lengthOf(3)
@@ -451,12 +450,12 @@ describe('Test blocklist', function () {
451 }) 450 })
452 451
453 it('Should block a local account', async function () { 452 it('Should block a local account', async function () {
454 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') 453 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'user1')
455 }) 454 })
456 455
457 it('Should hide its videos', async function () { 456 it('Should hide its videos', async function () {
458 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 457 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
459 const res = await getVideosListWithToken(servers[ 0 ].url, token) 458 const res = await getVideosListWithToken(servers[0].url, token)
460 459
461 const videos: Video[] = res.body.data 460 const videos: Video[] = res.body.data
462 expect(videos).to.have.lengthOf(2) 461 expect(videos).to.have.lengthOf(2)
@@ -467,18 +466,18 @@ describe('Test blocklist', function () {
467 }) 466 })
468 467
469 it('Should hide its comments', async function () { 468 it('Should hide its comments', async function () {
470 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 469 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
471 const resThreads = await getVideoCommentThreads(servers[ 0 ].url, videoUUID1, 0, 5, '-createdAt', token) 470 const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', token)
472 471
473 const threads: VideoComment[] = resThreads.body.data 472 const threads: VideoComment[] = resThreads.body.data
474 expect(threads).to.have.lengthOf(1) 473 expect(threads).to.have.lengthOf(1)
475 expect(threads[ 0 ].totalReplies).to.equal(0) 474 expect(threads[0].totalReplies).to.equal(0)
476 475
477 const t = threads.find(t => t.text === 'comment user 1') 476 const t = threads.find(t => t.text === 'comment user 1')
478 expect(t).to.be.undefined 477 expect(t).to.be.undefined
479 478
480 for (const thread of threads) { 479 for (const thread of threads) {
481 const res = await getVideoThreadComments(servers[ 0 ].url, videoUUID1, thread.id, token) 480 const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, token)
482 481
483 const tree: VideoCommentThreadTree = res.body 482 const tree: VideoCommentThreadTree = res.body
484 expect(tree.children).to.have.lengthOf(0) 483 expect(tree.children).to.have.lengthOf(0)
@@ -490,29 +489,29 @@ describe('Test blocklist', function () {
490 this.timeout(20000) 489 this.timeout(20000)
491 490
492 { 491 {
493 const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } 492 const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' }
494 await checkCommentNotification(servers[ 0 ], comment, 'absence') 493 await checkCommentNotification(servers[0], comment, 'absence')
495 } 494 }
496 495
497 { 496 {
498 const comment = { 497 const comment = {
499 server: servers[ 1 ], 498 server: servers[1],
500 token: userToken2, 499 token: userToken2,
501 videoUUID: videoUUID1, 500 videoUUID: videoUUID1,
502 text: 'hello @root@localhost:' + servers[ 0 ].port 501 text: 'hello @root@localhost:' + servers[0].port
503 } 502 }
504 await checkCommentNotification(servers[ 0 ], comment, 'absence') 503 await checkCommentNotification(servers[0], comment, 'absence')
505 } 504 }
506 }) 505 })
507 506
508 it('Should list blocked accounts', async function () { 507 it('Should list blocked accounts', async function () {
509 { 508 {
510 const res = await getAccountBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') 509 const res = await getAccountBlocklistByServer(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
511 const blocks: AccountBlock[] = res.body.data 510 const blocks: AccountBlock[] = res.body.data
512 511
513 expect(res.body.total).to.equal(2) 512 expect(res.body.total).to.equal(2)
514 513
515 const block = blocks[ 0 ] 514 const block = blocks[0]
516 expect(block.byAccount.displayName).to.equal('peertube') 515 expect(block.byAccount.displayName).to.equal('peertube')
517 expect(block.byAccount.name).to.equal('peertube') 516 expect(block.byAccount.name).to.equal('peertube')
518 expect(block.blockedAccount.displayName).to.equal('user2') 517 expect(block.blockedAccount.displayName).to.equal('user2')
@@ -521,12 +520,12 @@ describe('Test blocklist', function () {
521 } 520 }
522 521
523 { 522 {
524 const res = await getAccountBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt') 523 const res = await getAccountBlocklistByServer(servers[0].url, servers[0].accessToken, 1, 2, 'createdAt')
525 const blocks: AccountBlock[] = res.body.data 524 const blocks: AccountBlock[] = res.body.data
526 525
527 expect(res.body.total).to.equal(2) 526 expect(res.body.total).to.equal(2)
528 527
529 const block = blocks[ 0 ] 528 const block = blocks[0]
530 expect(block.byAccount.displayName).to.equal('peertube') 529 expect(block.byAccount.displayName).to.equal('peertube')
531 expect(block.byAccount.name).to.equal('peertube') 530 expect(block.byAccount.name).to.equal('peertube')
532 expect(block.blockedAccount.displayName).to.equal('user1') 531 expect(block.blockedAccount.displayName).to.equal('user1')
@@ -536,12 +535,12 @@ describe('Test blocklist', function () {
536 }) 535 })
537 536
538 it('Should unblock the remote account', async function () { 537 it('Should unblock the remote account', async function () {
539 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) 538 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
540 }) 539 })
541 540
542 it('Should display its videos', async function () { 541 it('Should display its videos', async function () {
543 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 542 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
544 const res = await getVideosListWithToken(servers[ 0 ].url, token) 543 const res = await getVideosListWithToken(servers[0].url, token)
545 544
546 const videos: Video[] = res.body.data 545 const videos: Video[] = res.body.data
547 expect(videos).to.have.lengthOf(3) 546 expect(videos).to.have.lengthOf(3)
@@ -552,12 +551,12 @@ describe('Test blocklist', function () {
552 }) 551 })
553 552
554 it('Should unblock the local account', async function () { 553 it('Should unblock the local account', async function () {
555 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') 554 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'user1')
556 }) 555 })
557 556
558 it('Should display its comments', async function () { 557 it('Should display its comments', async function () {
559 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 558 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
560 await checkAllComments(servers[ 0 ].url, token, videoUUID1) 559 await checkAllComments(servers[0].url, token, videoUUID1)
561 } 560 }
562 }) 561 })
563 562
@@ -565,43 +564,43 @@ describe('Test blocklist', function () {
565 this.timeout(20000) 564 this.timeout(20000)
566 565
567 { 566 {
568 const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' } 567 const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' }
569 await checkCommentNotification(servers[ 0 ], comment, 'presence') 568 await checkCommentNotification(servers[0], comment, 'presence')
570 } 569 }
571 570
572 { 571 {
573 const comment = { 572 const comment = {
574 server: servers[ 1 ], 573 server: servers[1],
575 token: userToken2, 574 token: userToken2,
576 videoUUID: videoUUID1, 575 videoUUID: videoUUID1,
577 text: 'hello @root@localhost:' + servers[ 0 ].port 576 text: 'hello @root@localhost:' + servers[0].port
578 } 577 }
579 await checkCommentNotification(servers[ 0 ], comment, 'presence') 578 await checkCommentNotification(servers[0], comment, 'presence')
580 } 579 }
581 }) 580 })
582 }) 581 })
583 582
584 describe('When managing server blocklist', function () { 583 describe('When managing server blocklist', function () {
585 it('Should list all videos', async function () { 584 it('Should list all videos', async function () {
586 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 585 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
587 await checkAllVideos(servers[ 0 ].url, token) 586 await checkAllVideos(servers[0].url, token)
588 } 587 }
589 }) 588 })
590 589
591 it('Should list the comments', async function () { 590 it('Should list the comments', async function () {
592 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 591 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
593 await checkAllComments(servers[ 0 ].url, token, videoUUID1) 592 await checkAllComments(servers[0].url, token, videoUUID1)
594 } 593 }
595 }) 594 })
596 595
597 it('Should block a remote server', async function () { 596 it('Should block a remote server', async function () {
598 await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) 597 await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
599 }) 598 })
600 599
601 it('Should hide its videos', async function () { 600 it('Should hide its videos', async function () {
602 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 601 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
603 const res1 = await getVideosList(servers[ 0 ].url) 602 const res1 = await getVideosList(servers[0].url)
604 const res2 = await getVideosListWithToken(servers[ 0 ].url, token) 603 const res2 = await getVideosListWithToken(servers[0].url, token)
605 604
606 for (const res of [ res1, res2 ]) { 605 for (const res of [ res1, res2 ]) {
607 const videos: Video[] = res.body.data 606 const videos: Video[] = res.body.data
@@ -619,60 +618,60 @@ describe('Test blocklist', function () {
619 it('Should hide its comments', async function () { 618 it('Should hide its comments', async function () {
620 this.timeout(10000) 619 this.timeout(10000)
621 620
622 const resThreads = await addVideoCommentThread(servers[ 1 ].url, userToken2, videoUUID1, 'hidden comment 2') 621 const resThreads = await addVideoCommentThread(servers[1].url, userToken2, videoUUID1, 'hidden comment 2')
623 const threadId = resThreads.body.comment.id 622 const threadId = resThreads.body.comment.id
624 623
625 await waitJobs(servers) 624 await waitJobs(servers)
626 625
627 await checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) 626 await checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
628 627
629 await deleteVideoComment(servers[ 1 ].url, userToken2, videoUUID1, threadId) 628 await deleteVideoComment(servers[1].url, userToken2, videoUUID1, threadId)
630 }) 629 })
631 630
632 it('Should not have notification from blocked instances by instance', async function () { 631 it('Should not have notification from blocked instances by instance', async function () {
633 this.timeout(20000) 632 this.timeout(20000)
634 633
635 { 634 {
636 const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } 635 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' }
637 await checkCommentNotification(servers[ 0 ], comment, 'absence') 636 await checkCommentNotification(servers[0], comment, 'absence')
638 } 637 }
639 638
640 { 639 {
641 const comment = { 640 const comment = {
642 server: servers[ 1 ], 641 server: servers[1],
643 token: userToken2, 642 token: userToken2,
644 videoUUID: videoUUID1, 643 videoUUID: videoUUID1,
645 text: 'hello @root@localhost:' + servers[ 0 ].port 644 text: 'hello @root@localhost:' + servers[0].port
646 } 645 }
647 await checkCommentNotification(servers[ 0 ], comment, 'absence') 646 await checkCommentNotification(servers[0], comment, 'absence')
648 } 647 }
649 }) 648 })
650 649
651 it('Should list blocked servers', async function () { 650 it('Should list blocked servers', async function () {
652 const res = await getServerBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') 651 const res = await getServerBlocklistByServer(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
653 const blocks: ServerBlock[] = res.body.data 652 const blocks: ServerBlock[] = res.body.data
654 653
655 expect(res.body.total).to.equal(1) 654 expect(res.body.total).to.equal(1)
656 655
657 const block = blocks[ 0 ] 656 const block = blocks[0]
658 expect(block.byAccount.displayName).to.equal('peertube') 657 expect(block.byAccount.displayName).to.equal('peertube')
659 expect(block.byAccount.name).to.equal('peertube') 658 expect(block.byAccount.name).to.equal('peertube')
660 expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) 659 expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port)
661 }) 660 })
662 661
663 it('Should unblock the remote server', async function () { 662 it('Should unblock the remote server', async function () {
664 await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) 663 await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
665 }) 664 })
666 665
667 it('Should list all videos', async function () { 666 it('Should list all videos', async function () {
668 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 667 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
669 await checkAllVideos(servers[ 0 ].url, token) 668 await checkAllVideos(servers[0].url, token)
670 } 669 }
671 }) 670 })
672 671
673 it('Should list the comments', async function () { 672 it('Should list the comments', async function () {
674 for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { 673 for (const token of [ userModeratorToken, servers[0].accessToken ]) {
675 await checkAllComments(servers[ 0 ].url, token, videoUUID1) 674 await checkAllComments(servers[0].url, token, videoUUID1)
676 } 675 }
677 }) 676 })
678 677
@@ -680,18 +679,18 @@ describe('Test blocklist', function () {
680 this.timeout(20000) 679 this.timeout(20000)
681 680
682 { 681 {
683 const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } 682 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
684 await checkCommentNotification(servers[ 0 ], comment, 'presence') 683 await checkCommentNotification(servers[0], comment, 'presence')
685 } 684 }
686 685
687 { 686 {
688 const comment = { 687 const comment = {
689 server: servers[ 1 ], 688 server: servers[1],
690 token: userToken2, 689 token: userToken2,
691 videoUUID: videoUUID1, 690 videoUUID: videoUUID1,
692 text: 'hello @root@localhost:' + servers[ 0 ].port 691 text: 'hello @root@localhost:' + servers[0].port
693 } 692 }
694 await checkCommentNotification(servers[ 0 ], comment, 'presence') 693 await checkCommentNotification(servers[0], comment, 'presence')
695 } 694 }
696 }) 695 })
697 }) 696 })
diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts
index 08017f89c..7d6b0c6a9 100644
--- a/server/tests/api/users/user-subscriptions.ts
+++ b/server/tests/api/users/user-subscriptions.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -13,16 +13,17 @@ import {
13 updateVideo, 13 updateVideo,
14 userLogin 14 userLogin
15} from '../../../../shared/extra-utils' 15} from '../../../../shared/extra-utils'
16import { killallServers, ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index' 16import { ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index'
17import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' 17import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
18import { Video, VideoChannel } from '../../../../shared/models/videos' 18import { Video, VideoChannel } from '../../../../shared/models/videos'
19import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 19import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
20import { 20import {
21 addUserSubscription, 21 addUserSubscription,
22 areSubscriptionsExist,
23 getUserSubscription,
22 listUserSubscriptions, 24 listUserSubscriptions,
23 listUserSubscriptionVideos, 25 listUserSubscriptionVideos,
24 removeUserSubscription, 26 removeUserSubscription
25 getUserSubscription, areSubscriptionsExist
26} from '../../../../shared/extra-utils/users/user-subscriptions' 27} from '../../../../shared/extra-utils/users/user-subscriptions'
27 28
28const expect = chai.expect 29const expect = chai.expect
@@ -116,7 +117,7 @@ describe('Test users subscriptions', function () {
116 117
117 it('Should get subscription', async function () { 118 it('Should get subscription', async function () {
118 { 119 {
119 const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:' + servers[2].port) 120 const res = await getUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port)
120 const videoChannel: VideoChannel = res.body 121 const videoChannel: VideoChannel = res.body
121 122
122 expect(videoChannel.name).to.equal('user3_channel') 123 expect(videoChannel.name).to.equal('user3_channel')
@@ -127,7 +128,7 @@ describe('Test users subscriptions', function () {
127 } 128 }
128 129
129 { 130 {
130 const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:' + servers[0].port) 131 const res = await getUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port)
131 const videoChannel: VideoChannel = res.body 132 const videoChannel: VideoChannel = res.body
132 133
133 expect(videoChannel.name).to.equal('root_channel') 134 expect(videoChannel.name).to.equal('root_channel')
@@ -146,7 +147,7 @@ describe('Test users subscriptions', function () {
146 'user3_channel@localhost:' + servers[0].port 147 'user3_channel@localhost:' + servers[0].port
147 ] 148 ]
148 149
149 const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris) 150 const res = await areSubscriptionsExist(servers[0].url, users[0].accessToken, uris)
150 const body = res.body 151 const body = res.body
151 152
152 expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true 153 expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts
index 791418318..591ce4959 100644
--- a/server/tests/api/users/users-multiple-servers.ts
+++ b/server/tests/api/users/users-multiple-servers.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -57,17 +57,17 @@ describe('Test users with multiple servers', function () {
57 password: 'password' 57 password: 'password'
58 } 58 }
59 const res = await createUser({ 59 const res = await createUser({
60 url: servers[ 0 ].url, 60 url: servers[0].url,
61 accessToken: servers[ 0 ].accessToken, 61 accessToken: servers[0].accessToken,
62 username: user.username, 62 username: user.username,
63 password: user.password 63 password: user.password
64 }) 64 })
65 userId = res.body.user.id 65 userId = res.body.user.id
66 userAccessToken = await userLogin(servers[ 0 ], user) 66 userAccessToken = await userLogin(servers[0], user)
67 } 67 }
68 68
69 { 69 {
70 const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {}) 70 const resVideo = await uploadVideo(servers[0].url, userAccessToken, {})
71 videoUUID = resVideo.body.video.uuid 71 videoUUID = resVideo.body.video.uuid
72 } 72 }
73 73
@@ -86,7 +86,6 @@ describe('Test users with multiple servers', function () {
86 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) 86 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
87 user = res.body 87 user = res.body
88 88
89 const account: Account = user.account
90 expect(user.account.displayName).to.equal('my super display name') 89 expect(user.account.displayName).to.equal('my super display name')
91 90
92 await waitJobs(servers) 91 await waitJobs(servers)
diff --git a/server/tests/api/users/users-verification.ts b/server/tests/api/users/users-verification.ts
index 7cd61f539..675ebf690 100644
--- a/server/tests/api/users/users-verification.ts
+++ b/server/tests/api/users/users-verification.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index 24203a731..502eac0bb 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -1,8 +1,8 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { User, UserRole, Video, MyUser, VideoPlaylistType } from '../../../../shared/index' 5import { MyUser, User, UserRole, Video, VideoPlaylistType } from '../../../../shared/index'
6import { 6import {
7 blockUser, 7 blockUser,
8 cleanupTests, 8 cleanupTests,
@@ -18,7 +18,8 @@ import {
18 getUsersList, 18 getUsersList,
19 getUsersListPaginationAndSort, 19 getUsersListPaginationAndSort,
20 getVideoChannel, 20 getVideoChannel,
21 getVideosList, installPlugin, 21 getVideosList,
22 installPlugin,
22 login, 23 login,
23 makePutBodyRequest, 24 makePutBodyRequest,
24 rateVideo, 25 rateVideo,
@@ -121,13 +122,13 @@ describe('Test users', function () {
121 122
122 it('Should be able to login with an insensitive username', async function () { 123 it('Should be able to login with an insensitive username', async function () {
123 const user = { username: 'RoOt', password: server.user.password } 124 const user = { username: 'RoOt', password: server.user.password }
124 const res = await login(server.url, server.client, user, 200) 125 await login(server.url, server.client, user, 200)
125 126
126 const user2 = { username: 'rOoT', password: server.user.password } 127 const user2 = { username: 'rOoT', password: server.user.password }
127 const res2 = await login(server.url, server.client, user2, 200) 128 await login(server.url, server.client, user2, 200)
128 129
129 const user3 = { username: 'ROOt', password: server.user.password } 130 const user3 = { username: 'ROOt', password: server.user.password }
130 const res3 = await login(server.url, server.client, user3, 200) 131 await login(server.url, server.client, user3, 200)
131 }) 132 })
132 }) 133 })
133 134
@@ -137,7 +138,7 @@ describe('Test users', function () {
137 const videoAttributes = {} 138 const videoAttributes = {}
138 await uploadVideo(server.url, accessToken, videoAttributes) 139 await uploadVideo(server.url, accessToken, videoAttributes)
139 const res = await getVideosList(server.url) 140 const res = await getVideosList(server.url)
140 const video = res.body.data[ 0 ] 141 const video = res.body.data[0]
141 142
142 expect(video.account.name).to.equal('root') 143 expect(video.account.name).to.equal('root')
143 videoId = video.id 144 videoId = video.id
@@ -167,8 +168,8 @@ describe('Test users', function () {
167 const ratings = res.body 168 const ratings = res.body
168 169
169 expect(ratings.total).to.equal(1) 170 expect(ratings.total).to.equal(1)
170 expect(ratings.data[ 0 ].video.id).to.equal(videoId) 171 expect(ratings.data[0].video.id).to.equal(videoId)
171 expect(ratings.data[ 0 ].rating).to.equal('like') 172 expect(ratings.data[0].rating).to.equal('like')
172 }) 173 })
173 174
174 it('Should retrieve ratings list by rating type', async function () { 175 it('Should retrieve ratings list by rating type', async function () {
@@ -307,7 +308,7 @@ describe('Test users', function () {
307 const videos = res.body.data 308 const videos = res.body.data
308 expect(videos).to.have.lengthOf(1) 309 expect(videos).to.have.lengthOf(1)
309 310
310 const video: Video = videos[ 0 ] 311 const video: Video = videos[0]
311 expect(video.name).to.equal('super user video') 312 expect(video.name).to.equal('super user video')
312 expect(video.thumbnailPath).to.not.be.null 313 expect(video.thumbnailPath).to.not.be.null
313 expect(video.previewPath).to.not.be.null 314 expect(video.previewPath).to.not.be.null
@@ -344,12 +345,12 @@ describe('Test users', function () {
344 expect(users).to.be.an('array') 345 expect(users).to.be.an('array')
345 expect(users.length).to.equal(2) 346 expect(users.length).to.equal(2)
346 347
347 const user = users[ 0 ] 348 const user = users[0]
348 expect(user.username).to.equal('user_1') 349 expect(user.username).to.equal('user_1')
349 expect(user.email).to.equal('user_1@example.com') 350 expect(user.email).to.equal('user_1@example.com')
350 expect(user.nsfwPolicy).to.equal('display') 351 expect(user.nsfwPolicy).to.equal('display')
351 352
352 const rootUser = users[ 1 ] 353 const rootUser = users[1]
353 expect(rootUser.username).to.equal('root') 354 expect(rootUser.username).to.equal('root')
354 expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com') 355 expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com')
355 expect(user.nsfwPolicy).to.equal('display') 356 expect(user.nsfwPolicy).to.equal('display')
@@ -367,7 +368,7 @@ describe('Test users', function () {
367 expect(total).to.equal(2) 368 expect(total).to.equal(2)
368 expect(users.length).to.equal(1) 369 expect(users.length).to.equal(1)
369 370
370 const user = users[ 0 ] 371 const user = users[0]
371 expect(user.username).to.equal('root') 372 expect(user.username).to.equal('root')
372 expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') 373 expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com')
373 expect(user.roleLabel).to.equal('Administrator') 374 expect(user.roleLabel).to.equal('Administrator')
@@ -383,7 +384,7 @@ describe('Test users', function () {
383 expect(total).to.equal(2) 384 expect(total).to.equal(2)
384 expect(users.length).to.equal(1) 385 expect(users.length).to.equal(1)
385 386
386 const user = users[ 0 ] 387 const user = users[0]
387 expect(user.username).to.equal('user_1') 388 expect(user.username).to.equal('user_1')
388 expect(user.email).to.equal('user_1@example.com') 389 expect(user.email).to.equal('user_1@example.com')
389 expect(user.nsfwPolicy).to.equal('display') 390 expect(user.nsfwPolicy).to.equal('display')
@@ -398,7 +399,7 @@ describe('Test users', function () {
398 expect(total).to.equal(2) 399 expect(total).to.equal(2)
399 expect(users.length).to.equal(1) 400 expect(users.length).to.equal(1)
400 401
401 const user = users[ 0 ] 402 const user = users[0]
402 expect(user.username).to.equal('user_1') 403 expect(user.username).to.equal('user_1')
403 expect(user.email).to.equal('user_1@example.com') 404 expect(user.email).to.equal('user_1@example.com')
404 expect(user.nsfwPolicy).to.equal('display') 405 expect(user.nsfwPolicy).to.equal('display')
@@ -413,13 +414,13 @@ describe('Test users', function () {
413 expect(total).to.equal(2) 414 expect(total).to.equal(2)
414 expect(users.length).to.equal(2) 415 expect(users.length).to.equal(2)
415 416
416 expect(users[ 0 ].username).to.equal('root') 417 expect(users[0].username).to.equal('root')
417 expect(users[ 0 ].email).to.equal('admin' + server.internalServerNumber + '@example.com') 418 expect(users[0].email).to.equal('admin' + server.internalServerNumber + '@example.com')
418 expect(users[ 0 ].nsfwPolicy).to.equal('display') 419 expect(users[0].nsfwPolicy).to.equal('display')
419 420
420 expect(users[ 1 ].username).to.equal('user_1') 421 expect(users[1].username).to.equal('user_1')
421 expect(users[ 1 ].email).to.equal('user_1@example.com') 422 expect(users[1].email).to.equal('user_1@example.com')
422 expect(users[ 1 ].nsfwPolicy).to.equal('display') 423 expect(users[1].nsfwPolicy).to.equal('display')
423 }) 424 })
424 425
425 it('Should search user by username', async function () { 426 it('Should search user by username', async function () {
@@ -429,7 +430,7 @@ describe('Test users', function () {
429 expect(res.body.total).to.equal(1) 430 expect(res.body.total).to.equal(1)
430 expect(users.length).to.equal(1) 431 expect(users.length).to.equal(1)
431 432
432 expect(users[ 0 ].username).to.equal('root') 433 expect(users[0].username).to.equal('root')
433 }) 434 })
434 435
435 it('Should search user by email', async function () { 436 it('Should search user by email', async function () {
@@ -440,8 +441,8 @@ describe('Test users', function () {
440 expect(res.body.total).to.equal(1) 441 expect(res.body.total).to.equal(1)
441 expect(users.length).to.equal(1) 442 expect(users.length).to.equal(1)
442 443
443 expect(users[ 0 ].username).to.equal('user_1') 444 expect(users[0].username).to.equal('user_1')
444 expect(users[ 0 ].email).to.equal('user_1@example.com') 445 expect(users[0].email).to.equal('user_1@example.com')
445 } 446 }
446 447
447 { 448 {
@@ -451,8 +452,8 @@ describe('Test users', function () {
451 expect(res.body.total).to.equal(2) 452 expect(res.body.total).to.equal(2)
452 expect(users.length).to.equal(2) 453 expect(users.length).to.equal(2)
453 454
454 expect(users[ 0 ].username).to.equal('root') 455 expect(users[0].username).to.equal('root')
455 expect(users[ 1 ].username).to.equal('user_1') 456 expect(users[1].username).to.equal('user_1')
456 } 457 }
457 }) 458 })
458 }) 459 })
@@ -691,7 +692,7 @@ describe('Test users', function () {
691 692
692 expect(res.body.total).to.equal(1) 693 expect(res.body.total).to.equal(1)
693 694
694 const video = res.body.data[ 0 ] 695 const video = res.body.data[0]
695 expect(video.account.name).to.equal('root') 696 expect(video.account.name).to.equal('root')
696 }) 697 })
697 }) 698 })
diff --git a/server/tests/api/videos/audio-only.ts b/server/tests/api/videos/audio-only.ts
index f12d730cc..ac7a0b89c 100644
--- a/server/tests/api/videos/audio-only.ts
+++ b/server/tests/api/videos/audio-only.ts
@@ -1,28 +1,21 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 checkDirectoryIsEmpty,
7 checkSegmentHash,
8 checkTmpIsEmpty,
9 cleanupTests, 6 cleanupTests,
10 doubleFollow, 7 doubleFollow,
11 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
12 getPlaylist, 9 getVideo,
13 getVideo, makeGetRequest, makeRawRequest, 10 root,
14 removeVideo, root,
15 ServerInfo, 11 ServerInfo,
16 setAccessTokensToServers, updateCustomSubConfig, 12 setAccessTokensToServers,
17 updateVideo,
18 uploadVideo, 13 uploadVideo,
19 waitJobs, webtorrentAdd 14 waitJobs
20} from '../../../../shared/extra-utils' 15} from '../../../../shared/extra-utils'
21import { VideoDetails } from '../../../../shared/models/videos' 16import { VideoDetails } from '../../../../shared/models/videos'
22import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
23import { join } from 'path' 17import { join } from 'path'
24import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' 18import { audio, getVideoStreamSize } from '@server/helpers/ffmpeg-utils'
25import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution, audio, getVideoStreamSize } from '@server/helpers/ffmpeg-utils'
26 19
27const expect = chai.expect 20const expect = chai.expect
28 21
@@ -87,14 +80,14 @@ describe('Test audio only video transcoding', function () {
87 80
88 it('0p transcoded video should not have video', async function () { 81 it('0p transcoded video should not have video', async function () {
89 const paths = [ 82 const paths = [
90 join(root(), 'test' + servers[ 0 ].internalServerNumber, 'videos', videoUUID + '-0.mp4'), 83 join(root(), 'test' + servers[0].internalServerNumber, 'videos', videoUUID + '-0.mp4'),
91 join(root(), 'test' + servers[ 0 ].internalServerNumber, 'streaming-playlists', 'hls', videoUUID, videoUUID + '-0-fragmented.mp4') 84 join(root(), 'test' + servers[0].internalServerNumber, 'streaming-playlists', 'hls', videoUUID, videoUUID + '-0-fragmented.mp4')
92 ] 85 ]
93 86
94 for (const path of paths) { 87 for (const path of paths) {
95 const { audioStream } = await audio.get(path) 88 const { audioStream } = await audio.get(path)
96 expect(audioStream[ 'codec_name' ]).to.be.equal('aac') 89 expect(audioStream['codec_name']).to.be.equal('aac')
97 expect(audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000) 90 expect(audioStream['bit_rate']).to.be.at.most(384 * 8000)
98 91
99 const size = await getVideoStreamSize(path) 92 const size = await getVideoStreamSize(path)
100 expect(size.height).to.equal(0) 93 expect(size.height).to.equal(0)
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts
index fa3e250ec..e3029f1ae 100644
--- a/server/tests/api/videos/multiple-servers.ts
+++ b/server/tests/api/videos/multiple-servers.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -63,9 +63,9 @@ describe('Test multiple servers', function () {
63 displayName: 'my channel', 63 displayName: 'my channel',
64 description: 'super channel' 64 description: 'super channel'
65 } 65 }
66 await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) 66 await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
67 const channelRes = await getVideoChannelsList(servers[ 0 ].url, 0, 1) 67 const channelRes = await getVideoChannelsList(servers[0].url, 0, 1)
68 videoChannelId = channelRes.body.data[ 0 ].id 68 videoChannelId = channelRes.body.data[0].id
69 } 69 }
70 70
71 // Server 1 and server 2 follow each other 71 // Server 1 and server 2 follow each other
@@ -163,7 +163,7 @@ describe('Test multiple servers', function () {
163 username: 'user1', 163 username: 'user1',
164 password: 'super_password' 164 password: 'super_password'
165 } 165 }
166 await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) 166 await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password })
167 const userAccessToken = await userLogin(servers[1], user) 167 const userAccessToken = await userLogin(servers[1], user)
168 168
169 const videoAttributes = { 169 const videoAttributes = {
@@ -762,12 +762,12 @@ describe('Test multiple servers', function () {
762 762
763 { 763 {
764 const text = 'my super first comment' 764 const text = 'my super first comment'
765 await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, text) 765 await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, text)
766 } 766 }
767 767
768 { 768 {
769 const text = 'my super second comment' 769 const text = 'my super second comment'
770 await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, text) 770 await addVideoCommentThread(servers[2].url, servers[2].accessToken, videoUUID, text)
771 } 771 }
772 772
773 await waitJobs(servers) 773 await waitJobs(servers)
@@ -777,7 +777,7 @@ describe('Test multiple servers', function () {
777 const threadId = res.body.data.find(c => c.text === 'my super first comment').id 777 const threadId = res.body.data.find(c => c.text === 'my super first comment').id
778 778
779 const text = 'my super answer to thread 1' 779 const text = 'my super answer to thread 1'
780 await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, videoUUID, threadId, text) 780 await addVideoCommentReply(servers[1].url, servers[1].accessToken, videoUUID, threadId, text)
781 } 781 }
782 782
783 await waitJobs(servers) 783 await waitJobs(servers)
@@ -790,10 +790,10 @@ describe('Test multiple servers', function () {
790 const childCommentId = res2.body.children[0].comment.id 790 const childCommentId = res2.body.children[0].comment.id
791 791
792 const text3 = 'my second answer to thread 1' 792 const text3 = 'my second answer to thread 1'
793 await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, threadId, text3) 793 await addVideoCommentReply(servers[2].url, servers[2].accessToken, videoUUID, threadId, text3)
794 794
795 const text2 = 'my super answer to answer of thread 1' 795 const text2 = 'my super answer to answer of thread 1'
796 await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, childCommentId, text2) 796 await addVideoCommentReply(servers[2].url, servers[2].accessToken, videoUUID, childCommentId, text2)
797 } 797 }
798 798
799 await waitJobs(servers) 799 await waitJobs(servers)
@@ -900,9 +900,9 @@ describe('Test multiple servers', function () {
900 it('Should delete the thread comments', async function () { 900 it('Should delete the thread comments', async function () {
901 this.timeout(10000) 901 this.timeout(10000)
902 902
903 const res = await getVideoCommentThreads(servers[ 0 ].url, videoUUID, 0, 5) 903 const res = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5)
904 const threadId = res.body.data.find(c => c.text === 'my super first comment').id 904 const threadId = res.body.data.find(c => c.text === 'my super first comment').id
905 await deleteVideoComment(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, threadId) 905 await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId)
906 906
907 await waitJobs(servers) 907 await waitJobs(servers)
908 }) 908 })
@@ -945,9 +945,9 @@ describe('Test multiple servers', function () {
945 it('Should delete a remote thread by the origin server', async function () { 945 it('Should delete a remote thread by the origin server', async function () {
946 this.timeout(5000) 946 this.timeout(5000)
947 947
948 const res = await getVideoCommentThreads(servers[ 0 ].url, videoUUID, 0, 5) 948 const res = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5)
949 const threadId = res.body.data.find(c => c.text === 'my super second comment').id 949 const threadId = res.body.data.find(c => c.text === 'my super second comment').id
950 await deleteVideoComment(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, threadId) 950 await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId)
951 951
952 await waitJobs(servers) 952 await waitJobs(servers)
953 }) 953 })
@@ -1021,7 +1021,7 @@ describe('Test multiple servers', function () {
1021 const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm') 1021 const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm')
1022 1022
1023 await req.attach('videofile', filePath) 1023 await req.attach('videofile', filePath)
1024 .expect(200) 1024 .expect(200)
1025 1025
1026 await waitJobs(servers) 1026 await waitJobs(servers)
1027 1027
@@ -1046,7 +1046,7 @@ describe('Test multiple servers', function () {
1046 duration: 5, 1046 duration: 5,
1047 commentsEnabled: true, 1047 commentsEnabled: true,
1048 downloadEnabled: true, 1048 downloadEnabled: true,
1049 tags: [ ], 1049 tags: [],
1050 privacy: VideoPrivacy.PUBLIC, 1050 privacy: VideoPrivacy.PUBLIC,
1051 channel: { 1051 channel: {
1052 displayName: 'Main root channel', 1052 displayName: 'Main root channel',
diff --git a/server/tests/api/videos/services.ts b/server/tests/api/videos/services.ts
index 17172331f..5505a845a 100644
--- a/server/tests/api/videos/services.ts
+++ b/server/tests/api/videos/services.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -31,8 +31,8 @@ describe('Test services', function () {
31 31
32 const res = await getOEmbed(server.url, oembedUrl) 32 const res = await getOEmbed(server.url, oembedUrl)
33 const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + 33 const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' +
34 `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` + 34 `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
35 'frameborder="0" allowfullscreen></iframe>' 35 'frameborder="0" allowfullscreen></iframe>'
36 const expectedThumbnailUrl = 'http://localhost:' + server.port + '/static/previews/' + server.video.uuid + '.jpg' 36 const expectedThumbnailUrl = 'http://localhost:' + server.port + '/static/previews/' + server.video.uuid + '.jpg'
37 37
38 expect(res.body.html).to.equal(expectedHtml) 38 expect(res.body.html).to.equal(expectedHtml)
@@ -53,8 +53,8 @@ describe('Test services', function () {
53 53
54 const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) 54 const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth)
55 const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + 55 const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' +
56 `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` + 56 `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
57 'frameborder="0" allowfullscreen></iframe>' 57 'frameborder="0" allowfullscreen></iframe>'
58 58
59 expect(res.body.html).to.equal(expectedHtml) 59 expect(res.body.html).to.equal(expectedHtml)
60 expect(res.body.title).to.equal(server.video.name) 60 expect(res.body.title).to.equal(server.video.name)
diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts
index 362d6b78f..596fff996 100644
--- a/server/tests/api/videos/single-server.ts
+++ b/server/tests/api/videos/single-server.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import { keyBy } from 'lodash' 4import { keyBy } from 'lodash'
diff --git a/server/tests/api/videos/video-abuse.ts b/server/tests/api/videos/video-abuse.ts
index 0cd6f22c7..cd6df7267 100644
--- a/server/tests/api/videos/video-abuse.ts
+++ b/server/tests/api/videos/video-abuse.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -183,9 +183,9 @@ describe('Test video abuses', function () {
183 const accountToBlock = 'root@localhost:' + servers[1].port 183 const accountToBlock = 'root@localhost:' + servers[1].port
184 184
185 { 185 {
186 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, accountToBlock) 186 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
187 187
188 const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) 188 const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
189 expect(res.body.total).to.equal(2) 189 expect(res.body.total).to.equal(2)
190 190
191 const abuse = res.body.data.find(a => a.reason === 'will mute this') 191 const abuse = res.body.data.find(a => a.reason === 'will mute this')
@@ -193,9 +193,9 @@ describe('Test video abuses', function () {
193 } 193 }
194 194
195 { 195 {
196 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, accountToBlock) 196 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
197 197
198 const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) 198 const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
199 expect(res.body.total).to.equal(3) 199 expect(res.body.total).to.equal(3)
200 } 200 }
201 }) 201 })
@@ -204,9 +204,9 @@ describe('Test video abuses', function () {
204 const serverToBlock = servers[1].host 204 const serverToBlock = servers[1].host
205 205
206 { 206 {
207 await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, servers[1].host) 207 await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host)
208 208
209 const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) 209 const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
210 expect(res.body.total).to.equal(2) 210 expect(res.body.total).to.equal(2)
211 211
212 const abuse = res.body.data.find(a => a.reason === 'will mute this') 212 const abuse = res.body.data.find(a => a.reason === 'will mute this')
@@ -214,9 +214,9 @@ describe('Test video abuses', function () {
214 } 214 }
215 215
216 { 216 {
217 await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, serverToBlock) 217 await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock)
218 218
219 const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) 219 const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
220 expect(res.body.total).to.equal(3) 220 expect(res.body.total).to.equal(3)
221 } 221 }
222 }) 222 })
diff --git a/server/tests/api/videos/video-blacklist.ts b/server/tests/api/videos/video-blacklist.ts
index 854b2f0cb..67bc0114c 100644
--- a/server/tests/api/videos/video-blacklist.ts
+++ b/server/tests/api/videos/video-blacklist.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import { orderBy } from 'lodash' 4import { orderBy } from 'lodash'
@@ -8,7 +8,8 @@ import {
8 cleanupTests, 8 cleanupTests,
9 createUser, 9 createUser,
10 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
11 getBlacklistedVideosList, getMyUserInformation, 11 getBlacklistedVideosList,
12 getMyUserInformation,
12 getMyVideos, 13 getMyVideos,
13 getVideosList, 14 getVideosList,
14 killallServers, 15 killallServers,
@@ -17,7 +18,6 @@ import {
17 searchVideo, 18 searchVideo,
18 ServerInfo, 19 ServerInfo,
19 setAccessTokensToServers, 20 setAccessTokensToServers,
20 setDefaultVideoChannel,
21 updateVideo, 21 updateVideo,
22 updateVideoBlacklist, 22 updateVideoBlacklist,
23 uploadVideo, 23 uploadVideo,
@@ -27,7 +27,7 @@ import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
27import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 27import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
28import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos' 28import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos'
29import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' 29import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
30import { User, UserRole, UserUpdateMe } from '../../../../shared/models/users' 30import { User, UserRole } from '../../../../shared/models/users'
31import { getMagnetURI, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports' 31import { getMagnetURI, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
32 32
33const expect = chai.expect 33const expect = chai.expect
@@ -40,7 +40,7 @@ describe('Test video blacklist', function () {
40 const res = await getVideosList(server.url) 40 const res = await getVideosList(server.url)
41 41
42 const videos = res.body.data 42 const videos = res.body.data
43 for (let video of videos) { 43 for (const video of videos) {
44 await addVideoToBlacklist(server.url, server.accessToken, video.id, 'super reason') 44 await addVideoToBlacklist(server.url, server.accessToken, video.id, 'super reason')
45 } 45 }
46 } 46 }
@@ -72,7 +72,7 @@ describe('Test video blacklist', function () {
72 72
73 it('Should not have the video blacklisted in videos list/search on server 1', async function () { 73 it('Should not have the video blacklisted in videos list/search on server 1', async function () {
74 { 74 {
75 const res = await getVideosList(servers[ 0 ].url) 75 const res = await getVideosList(servers[0].url)
76 76
77 expect(res.body.total).to.equal(0) 77 expect(res.body.total).to.equal(0)
78 expect(res.body.data).to.be.an('array') 78 expect(res.body.data).to.be.an('array')
@@ -80,7 +80,7 @@ describe('Test video blacklist', function () {
80 } 80 }
81 81
82 { 82 {
83 const res = await searchVideo(servers[ 0 ].url, 'name') 83 const res = await searchVideo(servers[0].url, 'name')
84 84
85 expect(res.body.total).to.equal(0) 85 expect(res.body.total).to.equal(0)
86 expect(res.body.data).to.be.an('array') 86 expect(res.body.data).to.be.an('array')
@@ -90,7 +90,7 @@ describe('Test video blacklist', function () {
90 90
91 it('Should have the blacklisted video in videos list/search on server 2', async function () { 91 it('Should have the blacklisted video in videos list/search on server 2', async function () {
92 { 92 {
93 const res = await getVideosList(servers[ 1 ].url) 93 const res = await getVideosList(servers[1].url)
94 94
95 expect(res.body.total).to.equal(2) 95 expect(res.body.total).to.equal(2)
96 expect(res.body.data).to.be.an('array') 96 expect(res.body.data).to.be.an('array')
@@ -98,7 +98,7 @@ describe('Test video blacklist', function () {
98 } 98 }
99 99
100 { 100 {
101 const res = await searchVideo(servers[ 1 ].url, 'video') 101 const res = await searchVideo(servers[1].url, 'video')
102 102
103 expect(res.body.total).to.equal(2) 103 expect(res.body.total).to.equal(2)
104 expect(res.body.data).to.be.an('array') 104 expect(res.body.data).to.be.an('array')
@@ -125,8 +125,8 @@ describe('Test video blacklist', function () {
125 125
126 it('Should display all the blacklisted videos when applying manual type filter', async function () { 126 it('Should display all the blacklisted videos when applying manual type filter', async function () {
127 const res = await getBlacklistedVideosList({ 127 const res = await getBlacklistedVideosList({
128 url: servers[ 0 ].url, 128 url: servers[0].url,
129 token: servers[ 0 ].accessToken, 129 token: servers[0].accessToken,
130 type: VideoBlacklistType.MANUAL 130 type: VideoBlacklistType.MANUAL
131 }) 131 })
132 132
@@ -139,8 +139,8 @@ describe('Test video blacklist', function () {
139 139
140 it('Should display nothing when applying automatic type filter', async function () { 140 it('Should display nothing when applying automatic type filter', async function () {
141 const res = await getBlacklistedVideosList({ 141 const res = await getBlacklistedVideosList({
142 url: servers[ 0 ].url, 142 url: servers[0].url,
143 token: servers[ 0 ].accessToken, 143 token: servers[0].accessToken,
144 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED 144 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
145 }) 145 })
146 146
@@ -152,7 +152,7 @@ describe('Test video blacklist', function () {
152 }) 152 })
153 153
154 it('Should get the correct sort when sorting by descending id', async function () { 154 it('Should get the correct sort when sorting by descending id', async function () {
155 const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-id' }) 155 const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-id' })
156 expect(res.body.total).to.equal(2) 156 expect(res.body.total).to.equal(2)
157 157
158 const blacklistedVideos = res.body.data 158 const blacklistedVideos = res.body.data
@@ -165,7 +165,7 @@ describe('Test video blacklist', function () {
165 }) 165 })
166 166
167 it('Should get the correct sort when sorting by descending video name', async function () { 167 it('Should get the correct sort when sorting by descending video name', async function () {
168 const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) 168 const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' })
169 expect(res.body.total).to.equal(2) 169 expect(res.body.total).to.equal(2)
170 170
171 const blacklistedVideos = res.body.data 171 const blacklistedVideos = res.body.data
@@ -178,7 +178,7 @@ describe('Test video blacklist', function () {
178 }) 178 })
179 179
180 it('Should get the correct sort when sorting by ascending creation date', async function () { 180 it('Should get the correct sort when sorting by ascending creation date', async function () {
181 const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: 'createdAt' }) 181 const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' })
182 expect(res.body.total).to.equal(2) 182 expect(res.body.total).to.equal(2)
183 183
184 const blacklistedVideos = res.body.data 184 const blacklistedVideos = res.body.data
@@ -195,7 +195,7 @@ describe('Test video blacklist', function () {
195 it('Should change the reason', async function () { 195 it('Should change the reason', async function () {
196 await updateVideoBlacklist(servers[0].url, servers[0].accessToken, videoId, 'my super reason updated') 196 await updateVideoBlacklist(servers[0].url, servers[0].accessToken, videoId, 'my super reason updated')
197 197
198 const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) 198 const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' })
199 const video = res.body.data.find(b => b.video.id === videoId) 199 const video = res.body.data.find(b => b.video.id === videoId)
200 200
201 expect(video.reason).to.equal('my super reason updated') 201 expect(video.reason).to.equal('my super reason updated')
@@ -231,7 +231,7 @@ describe('Test video blacklist', function () {
231 231
232 it('Should remove a video from the blacklist on server 1', async function () { 232 it('Should remove a video from the blacklist on server 1', async function () {
233 // Get one video in the blacklist 233 // Get one video in the blacklist
234 const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) 234 const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' })
235 videoToRemove = res.body.data[0] 235 videoToRemove = res.body.data[0]
236 blacklist = res.body.data.slice(1) 236 blacklist = res.body.data.slice(1)
237 237
@@ -252,7 +252,7 @@ describe('Test video blacklist', function () {
252 }) 252 })
253 253
254 it('Should not have the ex-blacklisted video in videos blacklist list on server 1', async function () { 254 it('Should not have the ex-blacklisted video in videos blacklist list on server 1', async function () {
255 const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) 255 const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' })
256 expect(res.body.total).to.equal(1) 256 expect(res.body.total).to.equal(1)
257 257
258 const videos = res.body.data 258 const videos = res.body.data
@@ -274,7 +274,7 @@ describe('Test video blacklist', function () {
274 video3UUID = res.body.video.uuid 274 video3UUID = res.body.video.uuid
275 } 275 }
276 { 276 {
277 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'Video 4' }) 277 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'Video 4' })
278 video4UUID = res.body.video.uuid 278 video4UUID = res.body.video.uuid
279 } 279 }
280 280
@@ -284,17 +284,17 @@ describe('Test video blacklist', function () {
284 it('Should blacklist video 3 and keep it federated', async function () { 284 it('Should blacklist video 3 and keep it federated', async function () {
285 this.timeout(10000) 285 this.timeout(10000)
286 286
287 await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video3UUID, 'super reason', false) 287 await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video3UUID, 'super reason', false)
288 288
289 await waitJobs(servers) 289 await waitJobs(servers)
290 290
291 { 291 {
292 const res = await getVideosList(servers[ 0 ].url) 292 const res = await getVideosList(servers[0].url)
293 expect(res.body.data.find(v => v.uuid === video3UUID)).to.be.undefined 293 expect(res.body.data.find(v => v.uuid === video3UUID)).to.be.undefined
294 } 294 }
295 295
296 { 296 {
297 const res = await getVideosList(servers[ 1 ].url) 297 const res = await getVideosList(servers[1].url)
298 expect(res.body.data.find(v => v.uuid === video3UUID)).to.not.be.undefined 298 expect(res.body.data.find(v => v.uuid === video3UUID)).to.not.be.undefined
299 } 299 }
300 }) 300 })
@@ -302,7 +302,7 @@ describe('Test video blacklist', function () {
302 it('Should unfederate the video', async function () { 302 it('Should unfederate the video', async function () {
303 this.timeout(10000) 303 this.timeout(10000)
304 304
305 await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID, 'super reason', true) 305 await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video4UUID, 'super reason', true)
306 306
307 await waitJobs(servers) 307 await waitJobs(servers)
308 308
@@ -315,7 +315,7 @@ describe('Test video blacklist', function () {
315 it('Should have the video unfederated even after an Update AP message', async function () { 315 it('Should have the video unfederated even after an Update AP message', async function () {
316 this.timeout(10000) 316 this.timeout(10000)
317 317
318 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID, { description: 'super description' }) 318 await updateVideo(servers[0].url, servers[0].accessToken, video4UUID, { description: 'super description' })
319 319
320 await waitJobs(servers) 320 await waitJobs(servers)
321 321
@@ -326,7 +326,7 @@ describe('Test video blacklist', function () {
326 }) 326 })
327 327
328 it('Should have the correct video blacklist unfederate attribute', async function () { 328 it('Should have the correct video blacklist unfederate attribute', async function () {
329 const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: 'createdAt' }) 329 const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' })
330 330
331 const blacklistedVideos: VideoBlacklist[] = res.body.data 331 const blacklistedVideos: VideoBlacklist[] = res.body.data
332 const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID) 332 const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID)
@@ -339,7 +339,7 @@ describe('Test video blacklist', function () {
339 it('Should remove the video from blacklist and refederate the video', async function () { 339 it('Should remove the video from blacklist and refederate the video', async function () {
340 this.timeout(10000) 340 this.timeout(10000)
341 341
342 await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID) 342 await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video4UUID)
343 343
344 await waitJobs(servers) 344 await waitJobs(servers)
345 345
@@ -362,9 +362,9 @@ describe('Test video blacklist', function () {
362 killallServers([ servers[0] ]) 362 killallServers([ servers[0] ])
363 363
364 const config = { 364 const config = {
365 'auto_blacklist': { 365 auto_blacklist: {
366 videos: { 366 videos: {
367 'of_users': { 367 of_users: {
368 enabled: true 368 enabled: true
369 } 369 }
370 } 370 }
@@ -375,8 +375,8 @@ describe('Test video blacklist', function () {
375 { 375 {
376 const user = { username: 'user_without_flag', password: 'password' } 376 const user = { username: 'user_without_flag', password: 'password' }
377 await createUser({ 377 await createUser({
378 url: servers[ 0 ].url, 378 url: servers[0].url,
379 accessToken: servers[ 0 ].accessToken, 379 accessToken: servers[0].accessToken,
380 username: user.username, 380 username: user.username,
381 adminFlags: UserAdminFlag.NONE, 381 adminFlags: UserAdminFlag.NONE,
382 password: user.password, 382 password: user.password,
@@ -393,8 +393,8 @@ describe('Test video blacklist', function () {
393 { 393 {
394 const user = { username: 'user_with_flag', password: 'password' } 394 const user = { username: 'user_with_flag', password: 'password' }
395 await createUser({ 395 await createUser({
396 url: servers[ 0 ].url, 396 url: servers[0].url,
397 accessToken: servers[ 0 ].accessToken, 397 accessToken: servers[0].accessToken,
398 username: user.username, 398 username: user.username,
399 adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST, 399 adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST,
400 password: user.password, 400 password: user.password,
@@ -411,8 +411,8 @@ describe('Test video blacklist', function () {
411 await uploadVideo(servers[0].url, userWithoutFlag, { name: 'blacklisted' }) 411 await uploadVideo(servers[0].url, userWithoutFlag, { name: 'blacklisted' })
412 412
413 const res = await getBlacklistedVideosList({ 413 const res = await getBlacklistedVideosList({
414 url: servers[ 0 ].url, 414 url: servers[0].url,
415 token: servers[ 0 ].accessToken, 415 token: servers[0].accessToken,
416 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED 416 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
417 }) 417 })
418 418
@@ -428,11 +428,11 @@ describe('Test video blacklist', function () {
428 name: 'URL import', 428 name: 'URL import',
429 channelId: channelOfUserWithoutFlag 429 channelId: channelOfUserWithoutFlag
430 } 430 }
431 await importVideo(servers[ 0 ].url, userWithoutFlag, attributes) 431 await importVideo(servers[0].url, userWithoutFlag, attributes)
432 432
433 const res = await getBlacklistedVideosList({ 433 const res = await getBlacklistedVideosList({
434 url: servers[ 0 ].url, 434 url: servers[0].url,
435 token: servers[ 0 ].accessToken, 435 token: servers[0].accessToken,
436 sort: 'createdAt', 436 sort: 'createdAt',
437 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED 437 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
438 }) 438 })
@@ -447,11 +447,11 @@ describe('Test video blacklist', function () {
447 name: 'Torrent import', 447 name: 'Torrent import',
448 channelId: channelOfUserWithoutFlag 448 channelId: channelOfUserWithoutFlag
449 } 449 }
450 await importVideo(servers[ 0 ].url, userWithoutFlag, attributes) 450 await importVideo(servers[0].url, userWithoutFlag, attributes)
451 451
452 const res = await getBlacklistedVideosList({ 452 const res = await getBlacklistedVideosList({
453 url: servers[ 0 ].url, 453 url: servers[0].url,
454 token: servers[ 0 ].accessToken, 454 token: servers[0].accessToken,
455 sort: 'createdAt', 455 sort: 'createdAt',
456 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED 456 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
457 }) 457 })
@@ -464,8 +464,8 @@ describe('Test video blacklist', function () {
464 await uploadVideo(servers[0].url, userWithFlag, { name: 'not blacklisted' }) 464 await uploadVideo(servers[0].url, userWithFlag, { name: 'not blacklisted' })
465 465
466 const res = await getBlacklistedVideosList({ 466 const res = await getBlacklistedVideosList({
467 url: servers[ 0 ].url, 467 url: servers[0].url,
468 token: servers[ 0 ].accessToken, 468 token: servers[0].accessToken,
469 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED 469 type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
470 }) 470 })
471 471
diff --git a/server/tests/api/videos/video-captions.ts b/server/tests/api/videos/video-captions.ts
index 5e13f5949..b4ecb39f4 100644
--- a/server/tests/api/videos/video-captions.ts
+++ b/server/tests/api/videos/video-captions.ts
@@ -1,16 +1,17 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 checkVideoFilesWereRemoved, cleanupTests, 6 checkVideoFilesWereRemoved,
7 cleanupTests,
7 doubleFollow, 8 doubleFollow,
8 flushAndRunMultipleServers, 9 flushAndRunMultipleServers,
9 removeVideo, 10 removeVideo,
10 uploadVideo, 11 uploadVideo,
11 wait 12 wait
12} from '../../../../shared/extra-utils' 13} from '../../../../shared/extra-utils'
13import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' 14import { ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
14import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 15import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
15import { 16import {
16 createVideoCaption, 17 createVideoCaption,
@@ -36,7 +37,7 @@ describe('Test video captions', function () {
36 37
37 await waitJobs(servers) 38 await waitJobs(servers)
38 39
39 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'my video name' }) 40 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'my video name' })
40 videoUUID = res.body.video.uuid 41 videoUUID = res.body.video.uuid
41 42
42 await waitJobs(servers) 43 await waitJobs(servers)
diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts
index 64ee2355a..dee6575b9 100644
--- a/server/tests/api/videos/video-change-ownership.ts
+++ b/server/tests/api/videos/video-change-ownership.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -38,7 +38,7 @@ describe('Test video change ownership - nominal', function () {
38 } 38 }
39 let firstUserAccessToken = '' 39 let firstUserAccessToken = ''
40 let secondUserAccessToken = '' 40 let secondUserAccessToken = ''
41 let lastRequestChangeOwnershipId = undefined 41 let lastRequestChangeOwnershipId = ''
42 42
43 before(async function () { 43 before(async function () {
44 this.timeout(50000) 44 this.timeout(50000)
@@ -48,15 +48,15 @@ describe('Test video change ownership - nominal', function () {
48 48
49 const videoQuota = 42000000 49 const videoQuota = 42000000
50 await createUser({ 50 await createUser({
51 url: servers[ 0 ].url, 51 url: servers[0].url,
52 accessToken: servers[ 0 ].accessToken, 52 accessToken: servers[0].accessToken,
53 username: firstUser.username, 53 username: firstUser.username,
54 password: firstUser.password, 54 password: firstUser.password,
55 videoQuota: videoQuota 55 videoQuota: videoQuota
56 }) 56 })
57 await createUser({ 57 await createUser({
58 url: servers[ 0 ].url, 58 url: servers[0].url,
59 accessToken: servers[ 0 ].accessToken, 59 accessToken: servers[0].accessToken,
60 username: secondUser.username, 60 username: secondUser.username,
61 password: secondUser.password, 61 password: secondUser.password,
62 videoQuota: videoQuota 62 videoQuota: videoQuota
@@ -209,7 +209,7 @@ describe('Test video change ownership - nominal', function () {
209}) 209})
210 210
211describe('Test video change ownership - quota too small', function () { 211describe('Test video change ownership - quota too small', function () {
212 let server: ServerInfo = undefined 212 let server: ServerInfo
213 const firstUser = { 213 const firstUser = {
214 username: 'first', 214 username: 'first',
215 password: 'My great password' 215 password: 'My great password'
@@ -220,14 +220,14 @@ describe('Test video change ownership - quota too small', function () {
220 } 220 }
221 let firstUserAccessToken = '' 221 let firstUserAccessToken = ''
222 let secondUserAccessToken = '' 222 let secondUserAccessToken = ''
223 let lastRequestChangeOwnershipId = undefined 223 let lastRequestChangeOwnershipId = ''
224 224
225 before(async function () { 225 before(async function () {
226 this.timeout(50000) 226 this.timeout(50000)
227 227
228 // Run one server 228 // Run one server
229 server = await flushAndRunServer(1) 229 server = await flushAndRunServer(1)
230 await setAccessTokensToServers([server]) 230 await setAccessTokensToServers([ server ])
231 231
232 const videoQuota = 42000000 232 const videoQuota = 42000000
233 const limitedVideoQuota = 10 233 const limitedVideoQuota = 10
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts
index 4f600cae8..f3a23bf17 100644
--- a/server/tests/api/videos/video-channels.ts
+++ b/server/tests/api/videos/video-channels.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -7,7 +7,8 @@ import {
7 cleanupTests, 7 cleanupTests,
8 createUser, 8 createUser,
9 doubleFollow, 9 doubleFollow,
10 flushAndRunMultipleServers, getVideo, 10 flushAndRunMultipleServers,
11 getVideo,
11 getVideoChannelVideos, 12 getVideoChannelVideos,
12 testImage, 13 testImage,
13 updateVideo, 14 updateVideo,
@@ -73,14 +74,14 @@ describe('Test video channels', function () {
73 description: 'super video channel description', 74 description: 'super video channel description',
74 support: 'super video channel support text' 75 support: 'super video channel support text'
75 } 76 }
76 const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) 77 const res = await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
77 secondVideoChannelId = res.body.videoChannel.id 78 secondVideoChannelId = res.body.videoChannel.id
78 } 79 }
79 80
80 // The channel is 1 is propagated to servers 2 81 // The channel is 1 is propagated to servers 2
81 { 82 {
82 const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' } 83 const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' }
83 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributesArg) 84 const res = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributesArg)
84 videoUUID = res.body.video.uuid 85 videoUUID = res.body.video.uuid
85 } 86 }
86 87
@@ -106,7 +107,7 @@ describe('Test video channels', function () {
106 107
107 it('Should have two video channels when getting account channels on server 1', async function () { 108 it('Should have two video channels when getting account channels on server 1', async function () {
108 const res = await getAccountVideoChannelsList({ 109 const res = await getAccountVideoChannelsList({
109 url: servers[ 0 ].url, 110 url: servers[0].url,
110 accountName: userInfo.account.name + '@' + userInfo.account.host 111 accountName: userInfo.account.name + '@' + userInfo.account.host
111 }) 112 })
112 113
@@ -127,7 +128,7 @@ describe('Test video channels', function () {
127 it('Should paginate and sort account channels', async function () { 128 it('Should paginate and sort account channels', async function () {
128 { 129 {
129 const res = await getAccountVideoChannelsList({ 130 const res = await getAccountVideoChannelsList({
130 url: servers[ 0 ].url, 131 url: servers[0].url,
131 accountName: userInfo.account.name + '@' + userInfo.account.host, 132 accountName: userInfo.account.name + '@' + userInfo.account.host,
132 start: 0, 133 start: 0,
133 count: 1, 134 count: 1,
@@ -137,13 +138,13 @@ describe('Test video channels', function () {
137 expect(res.body.total).to.equal(2) 138 expect(res.body.total).to.equal(2)
138 expect(res.body.data).to.have.lengthOf(1) 139 expect(res.body.data).to.have.lengthOf(1)
139 140
140 const videoChannel: VideoChannel = res.body.data[ 0 ] 141 const videoChannel: VideoChannel = res.body.data[0]
141 expect(videoChannel.name).to.equal('root_channel') 142 expect(videoChannel.name).to.equal('root_channel')
142 } 143 }
143 144
144 { 145 {
145 const res = await getAccountVideoChannelsList({ 146 const res = await getAccountVideoChannelsList({
146 url: servers[ 0 ].url, 147 url: servers[0].url,
147 accountName: userInfo.account.name + '@' + userInfo.account.host, 148 accountName: userInfo.account.name + '@' + userInfo.account.host,
148 start: 0, 149 start: 0,
149 count: 1, 150 count: 1,
@@ -153,13 +154,13 @@ describe('Test video channels', function () {
153 expect(res.body.total).to.equal(2) 154 expect(res.body.total).to.equal(2)
154 expect(res.body.data).to.have.lengthOf(1) 155 expect(res.body.data).to.have.lengthOf(1)
155 156
156 const videoChannel: VideoChannel = res.body.data[ 0 ] 157 const videoChannel: VideoChannel = res.body.data[0]
157 expect(videoChannel.name).to.equal('second_video_channel') 158 expect(videoChannel.name).to.equal('second_video_channel')
158 } 159 }
159 160
160 { 161 {
161 const res = await getAccountVideoChannelsList({ 162 const res = await getAccountVideoChannelsList({
162 url: servers[ 0 ].url, 163 url: servers[0].url,
163 accountName: userInfo.account.name + '@' + userInfo.account.host, 164 accountName: userInfo.account.name + '@' + userInfo.account.host,
164 start: 1, 165 start: 1,
165 count: 1, 166 count: 1,
@@ -169,14 +170,14 @@ describe('Test video channels', function () {
169 expect(res.body.total).to.equal(2) 170 expect(res.body.total).to.equal(2)
170 expect(res.body.data).to.have.lengthOf(1) 171 expect(res.body.data).to.have.lengthOf(1)
171 172
172 const videoChannel: VideoChannel = res.body.data[ 0 ] 173 const videoChannel: VideoChannel = res.body.data[0]
173 expect(videoChannel.name).to.equal('root_channel') 174 expect(videoChannel.name).to.equal('root_channel')
174 } 175 }
175 }) 176 })
176 177
177 it('Should have one video channel when getting account channels on server 2', async function () { 178 it('Should have one video channel when getting account channels on server 2', async function () {
178 const res = await getAccountVideoChannelsList({ 179 const res = await getAccountVideoChannelsList({
179 url: servers[ 1 ].url, 180 url: servers[1].url,
180 accountName: userInfo.account.name + '@' + userInfo.account.host 181 accountName: userInfo.account.name + '@' + userInfo.account.host
181 }) 182 })
182 183
@@ -349,15 +350,15 @@ describe('Test video channels', function () {
349 it('Should create the main channel with an uuid if there is a conflict', async function () { 350 it('Should create the main channel with an uuid if there is a conflict', async function () {
350 { 351 {
351 const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' } 352 const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' }
352 await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) 353 await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
353 } 354 }
354 355
355 { 356 {
356 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: 'toto', password: 'password' }) 357 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'toto', password: 'password' })
357 const accessToken = await userLogin(servers[ 0 ], { username: 'toto', password: 'password' }) 358 const accessToken = await userLogin(servers[0], { username: 'toto', password: 'password' })
358 359
359 const res = await getMyUserInformation(servers[ 0 ].url, accessToken) 360 const res = await getMyUserInformation(servers[0].url, accessToken)
360 const videoChannel = res.body.videoChannels[ 0 ] 361 const videoChannel = res.body.videoChannels[0]
361 expect(videoChannel.name).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/) 362 expect(videoChannel.name).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)
362 } 363 }
363 }) 364 })
diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts
index 06e4ff9c8..afb58e95a 100644
--- a/server/tests/api/videos/video-comments.ts
+++ b/server/tests/api/videos/video-comments.ts
@@ -1,17 +1,17 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' 5import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
6import { cleanupTests, testImage } from '../../../../shared/extra-utils' 6import { cleanupTests, testImage } from '../../../../shared/extra-utils'
7import { 7import {
8 createUser,
8 dateIsValid, 9 dateIsValid,
9 flushAndRunServer, 10 flushAndRunServer,
11 getAccessToken,
10 ServerInfo, 12 ServerInfo,
11 setAccessTokensToServers, 13 setAccessTokensToServers,
12 updateMyAvatar, 14 updateMyAvatar,
13 getAccessToken,
14 createUser,
15 uploadVideo 15 uploadVideo
16} from '../../../../shared/extra-utils/index' 16} from '../../../../shared/extra-utils/index'
17import { 17import {
diff --git a/server/tests/api/videos/video-description.ts b/server/tests/api/videos/video-description.ts
index db4d278bf..b8e98e45f 100644
--- a/server/tests/api/videos/video-description.ts
+++ b/server/tests/api/videos/video-description.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -8,7 +8,6 @@ import {
8 getVideo, 8 getVideo,
9 getVideoDescription, 9 getVideoDescription,
10 getVideosList, 10 getVideosList,
11 killallServers,
12 ServerInfo, 11 ServerInfo,
13 setAccessTokensToServers, 12 setAccessTokensToServers,
14 updateVideo, 13 updateVideo,
@@ -23,7 +22,7 @@ describe('Test video description', function () {
23 let servers: ServerInfo[] = [] 22 let servers: ServerInfo[] = []
24 let videoUUID = '' 23 let videoUUID = ''
25 let videoId: number 24 let videoId: number
26 let longDescription = 'my super description for server 1'.repeat(50) 25 const longDescription = 'my super description for server 1'.repeat(50)
27 26
28 before(async function () { 27 before(async function () {
29 this.timeout(40000) 28 this.timeout(40000)
@@ -61,7 +60,7 @@ describe('Test video description', function () {
61 60
62 // 30 characters * 6 -> 240 characters 61 // 30 characters * 6 -> 240 characters
63 const truncatedDescription = 'my super description for server 1'.repeat(7) + 62 const truncatedDescription = 'my super description for server 1'.repeat(7) +
64 'my super descrip...' 63 'my super descrip...'
65 64
66 expect(video.description).to.equal(truncatedDescription) 65 expect(video.description).to.equal(truncatedDescription)
67 } 66 }
diff --git a/server/tests/api/videos/video-hls.ts b/server/tests/api/videos/video-hls.ts
index bde3b5656..6555bc8b6 100644
--- a/server/tests/api/videos/video-hls.ts
+++ b/server/tests/api/videos/video-hls.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -10,13 +10,16 @@ import {
10 doubleFollow, 10 doubleFollow,
11 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
12 getPlaylist, 12 getPlaylist,
13 getVideo, makeGetRequest, makeRawRequest, 13 getVideo,
14 makeRawRequest,
14 removeVideo, 15 removeVideo,
15 ServerInfo, 16 ServerInfo,
16 setAccessTokensToServers, updateCustomSubConfig, 17 setAccessTokensToServers,
18 updateCustomSubConfig,
17 updateVideo, 19 updateVideo,
18 uploadVideo, 20 uploadVideo,
19 waitJobs, webtorrentAdd 21 waitJobs,
22 webtorrentAdd
20} from '../../../../shared/extra-utils' 23} from '../../../../shared/extra-utils'
21import { VideoDetails } from '../../../../shared/models/videos' 24import { VideoDetails } from '../../../../shared/models/videos'
22import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' 25import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
@@ -48,7 +51,9 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, hlsOn
48 51
49 expect(file.magnetUri).to.have.lengthOf.above(2) 52 expect(file.magnetUri).to.have.lengthOf.above(2)
50 expect(file.torrentUrl).to.equal(`${baseUrl}/static/torrents/${videoDetails.uuid}-${file.resolution.id}-hls.torrent`) 53 expect(file.torrentUrl).to.equal(`${baseUrl}/static/torrents/${videoDetails.uuid}-${file.resolution.id}-hls.torrent`)
51 expect(file.fileUrl).to.equal(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4`) 54 expect(file.fileUrl).to.equal(
55 `${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4`
56 )
52 expect(file.resolution.label).to.equal(resolution + 'p') 57 expect(file.resolution.label).to.equal(resolution + 'p')
53 58
54 await makeRawRequest(file.torrentUrl, 200) 59 await makeRawRequest(file.torrentUrl, 200)
@@ -66,7 +71,9 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, hlsOn
66 const masterPlaylist = res.text 71 const masterPlaylist = res.text
67 72
68 for (const resolution of resolutions) { 73 for (const resolution of resolutions) {
69 const reg = new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+,CODECS="avc1.64001f,mp4a.40.2"') 74 const reg = new RegExp(
75 '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+,CODECS="avc1.64001f,mp4a.40.2"'
76 )
70 77
71 expect(masterPlaylist).to.match(reg) 78 expect(masterPlaylist).to.match(reg)
72 expect(masterPlaylist).to.contain(`${resolution}.m3u8`) 79 expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
@@ -102,7 +109,7 @@ describe('Test HLS videos', function () {
102 it('Should upload a video and transcode it to HLS', async function () { 109 it('Should upload a video and transcode it to HLS', async function () {
103 this.timeout(120000) 110 this.timeout(120000)
104 111
105 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) 112 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1', fixture: 'video_short.webm' })
106 videoUUID = res.body.video.uuid 113 videoUUID = res.body.video.uuid
107 114
108 await waitJobs(servers) 115 await waitJobs(servers)
@@ -113,7 +120,7 @@ describe('Test HLS videos', function () {
113 it('Should upload an audio file and transcode it to HLS', async function () { 120 it('Should upload an audio file and transcode it to HLS', async function () {
114 this.timeout(120000) 121 this.timeout(120000)
115 122
116 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' }) 123 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video audio', fixture: 'sample.ogg' })
117 videoAudioUUID = res.body.video.uuid 124 videoAudioUUID = res.body.video.uuid
118 125
119 await waitJobs(servers) 126 await waitJobs(servers)
@@ -124,7 +131,7 @@ describe('Test HLS videos', function () {
124 it('Should update the video', async function () { 131 it('Should update the video', async function () {
125 this.timeout(10000) 132 this.timeout(10000)
126 133
127 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, { name: 'video 1 updated' }) 134 await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' })
128 135
129 await waitJobs(servers) 136 await waitJobs(servers)
130 137
@@ -134,8 +141,8 @@ describe('Test HLS videos', function () {
134 it('Should delete videos', async function () { 141 it('Should delete videos', async function () {
135 this.timeout(10000) 142 this.timeout(10000)
136 143
137 await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID) 144 await removeVideo(servers[0].url, servers[0].accessToken, videoUUID)
138 await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAudioUUID) 145 await removeVideo(servers[0].url, servers[0].accessToken, videoAudioUUID)
139 146
140 await waitJobs(servers) 147 await waitJobs(servers)
141 148
diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts
index 1233ed6eb..a67e528c6 100644
--- a/server/tests/api/videos/video-imports.ts
+++ b/server/tests/api/videos/video-imports.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -12,12 +12,11 @@ import {
12 getVideo, 12 getVideo,
13 getVideosList, 13 getVideosList,
14 immutableAssign, 14 immutableAssign,
15 killallServers,
16 ServerInfo, 15 ServerInfo,
17 setAccessTokensToServers 16 setAccessTokensToServers
18} from '../../../../shared/extra-utils' 17} from '../../../../shared/extra-utils'
19import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 18import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
20import { getMagnetURI, getYoutubeVideoUrl, importVideo, getMyVideoImports } from '../../../../shared/extra-utils/videos/video-imports' 19import { getMagnetURI, getMyVideoImports, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
21 20
22const expect = chai.expect 21const expect = chai.expect
23 22
@@ -88,12 +87,12 @@ describe('Test video imports', function () {
88 87
89 { 88 {
90 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) 89 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
91 channelIdServer1 = res.body.videoChannels[ 0 ].id 90 channelIdServer1 = res.body.videoChannels[0].id
92 } 91 }
93 92
94 { 93 {
95 const res = await getMyUserInformation(servers[1].url, servers[1].accessToken) 94 const res = await getMyUserInformation(servers[1].url, servers[1].accessToken)
96 channelIdServer2 = res.body.videoChannels[ 0 ].id 95 channelIdServer2 = res.body.videoChannels[0].id
97 } 96 }
98 97
99 await doubleFollow(servers[0], servers[1]) 98 await doubleFollow(servers[0], servers[1])
@@ -214,7 +213,7 @@ describe('Test video imports', function () {
214 213
215 await checkVideoServer2(server.url, res.body.data[0].uuid) 214 await checkVideoServer2(server.url, res.body.data[0].uuid)
216 215
217 const [ ,videoHttp, videoMagnet, videoTorrent ] = res.body.data 216 const [ , videoHttp, videoMagnet, videoTorrent ] = res.body.data
218 await checkVideosServer1(server.url, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid) 217 await checkVideosServer1(server.url, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid)
219 } 218 }
220 }) 219 })
diff --git a/server/tests/api/videos/video-nsfw.ts b/server/tests/api/videos/video-nsfw.ts
index ad6a4b43f..7eba8d7d9 100644
--- a/server/tests/api/videos/video-nsfw.ts
+++ b/server/tests/api/videos/video-nsfw.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -89,8 +89,8 @@ describe('Test video NSFW policy', function () {
89 89
90 const videos = res.body.data 90 const videos = res.body.data
91 expect(videos).to.have.lengthOf(2) 91 expect(videos).to.have.lengthOf(2)
92 expect(videos[ 0 ].name).to.equal('normal') 92 expect(videos[0].name).to.equal('normal')
93 expect(videos[ 1 ].name).to.equal('nsfw') 93 expect(videos[1].name).to.equal('nsfw')
94 } 94 }
95 }) 95 })
96 96
@@ -107,7 +107,7 @@ describe('Test video NSFW policy', function () {
107 107
108 const videos = res.body.data 108 const videos = res.body.data
109 expect(videos).to.have.lengthOf(1) 109 expect(videos).to.have.lengthOf(1)
110 expect(videos[ 0 ].name).to.equal('normal') 110 expect(videos[0].name).to.equal('normal')
111 } 111 }
112 }) 112 })
113 113
@@ -124,8 +124,8 @@ describe('Test video NSFW policy', function () {
124 124
125 const videos = res.body.data 125 const videos = res.body.data
126 expect(videos).to.have.lengthOf(2) 126 expect(videos).to.have.lengthOf(2)
127 expect(videos[ 0 ].name).to.equal('normal') 127 expect(videos[0].name).to.equal('normal')
128 expect(videos[ 1 ].name).to.equal('nsfw') 128 expect(videos[1].name).to.equal('nsfw')
129 } 129 }
130 }) 130 })
131 }) 131 })
@@ -154,8 +154,8 @@ describe('Test video NSFW policy', function () {
154 154
155 const videos = res.body.data 155 const videos = res.body.data
156 expect(videos).to.have.lengthOf(2) 156 expect(videos).to.have.lengthOf(2)
157 expect(videos[ 0 ].name).to.equal('normal') 157 expect(videos[0].name).to.equal('normal')
158 expect(videos[ 1 ].name).to.equal('nsfw') 158 expect(videos[1].name).to.equal('nsfw')
159 } 159 }
160 }) 160 })
161 161
@@ -171,8 +171,8 @@ describe('Test video NSFW policy', function () {
171 171
172 const videos = res.body.data 172 const videos = res.body.data
173 expect(videos).to.have.lengthOf(2) 173 expect(videos).to.have.lengthOf(2)
174 expect(videos[ 0 ].name).to.equal('normal') 174 expect(videos[0].name).to.equal('normal')
175 expect(videos[ 1 ].name).to.equal('nsfw') 175 expect(videos[1].name).to.equal('nsfw')
176 } 176 }
177 }) 177 })
178 178
@@ -188,7 +188,7 @@ describe('Test video NSFW policy', function () {
188 188
189 const videos = res.body.data 189 const videos = res.body.data
190 expect(videos).to.have.lengthOf(1) 190 expect(videos).to.have.lengthOf(1)
191 expect(videos[ 0 ].name).to.equal('normal') 191 expect(videos[0].name).to.equal('normal')
192 } 192 }
193 }) 193 })
194 194
@@ -198,8 +198,8 @@ describe('Test video NSFW policy', function () {
198 198
199 const videos = res.body.data 199 const videos = res.body.data
200 expect(videos).to.have.lengthOf(2) 200 expect(videos).to.have.lengthOf(2)
201 expect(videos[ 0 ].name).to.equal('normal') 201 expect(videos[0].name).to.equal('normal')
202 expect(videos[ 1 ].name).to.equal('nsfw') 202 expect(videos[1].name).to.equal('nsfw')
203 }) 203 })
204 204
205 it('Should display NSFW videos when the nsfw param === true', async function () { 205 it('Should display NSFW videos when the nsfw param === true', async function () {
@@ -208,7 +208,7 @@ describe('Test video NSFW policy', function () {
208 208
209 const videos = res.body.data 209 const videos = res.body.data
210 expect(videos).to.have.lengthOf(1) 210 expect(videos).to.have.lengthOf(1)
211 expect(videos[ 0 ].name).to.equal('nsfw') 211 expect(videos[0].name).to.equal('nsfw')
212 } 212 }
213 }) 213 })
214 214
@@ -218,7 +218,7 @@ describe('Test video NSFW policy', function () {
218 218
219 const videos = res.body.data 219 const videos = res.body.data
220 expect(videos).to.have.lengthOf(1) 220 expect(videos).to.have.lengthOf(1)
221 expect(videos[ 0 ].name).to.equal('normal') 221 expect(videos[0].name).to.equal('normal')
222 } 222 }
223 }) 223 })
224 224
@@ -228,8 +228,8 @@ describe('Test video NSFW policy', function () {
228 228
229 const videos = res.body.data 229 const videos = res.body.data
230 expect(videos).to.have.lengthOf(2) 230 expect(videos).to.have.lengthOf(2)
231 expect(videos[ 0 ].name).to.equal('normal') 231 expect(videos[0].name).to.equal('normal')
232 expect(videos[ 1 ].name).to.equal('nsfw') 232 expect(videos[1].name).to.equal('nsfw')
233 } 233 }
234 }) 234 })
235 }) 235 })
diff --git a/server/tests/api/videos/video-playlist-thumbnails.ts b/server/tests/api/videos/video-playlist-thumbnails.ts
index 73ab02c17..a93a0b7de 100644
--- a/server/tests/api/videos/video-playlist-thumbnails.ts
+++ b/server/tests/api/videos/video-playlist-thumbnails.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -8,14 +8,15 @@ import {
8 createVideoPlaylist, 8 createVideoPlaylist,
9 doubleFollow, 9 doubleFollow,
10 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
11 getVideoPlaylistsList, removeVideoFromPlaylist, 11 getVideoPlaylistsList,
12 removeVideoFromPlaylist,
13 reorderVideosPlaylist,
12 ServerInfo, 14 ServerInfo,
13 setAccessTokensToServers, 15 setAccessTokensToServers,
14 setDefaultVideoChannel, 16 setDefaultVideoChannel,
15 testImage, 17 testImage,
16 uploadVideoAndGetId, 18 uploadVideoAndGetId,
17 waitJobs, 19 waitJobs
18 reorderVideosPlaylist
19} from '../../../../shared/extra-utils' 20} from '../../../../shared/extra-utils'
20import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' 21import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
21 22
@@ -69,19 +70,19 @@ describe('Playlist thumbnail', function () {
69 this.timeout(30000) 70 this.timeout(30000)
70 71
71 const res = await createVideoPlaylist({ 72 const res = await createVideoPlaylist({
72 url: servers[ 1 ].url, 73 url: servers[1].url,
73 token: servers[ 1 ].accessToken, 74 token: servers[1].accessToken,
74 playlistAttrs: { 75 playlistAttrs: {
75 displayName: 'playlist without thumbnail', 76 displayName: 'playlist without thumbnail',
76 privacy: VideoPlaylistPrivacy.PUBLIC, 77 privacy: VideoPlaylistPrivacy.PUBLIC,
77 videoChannelId: servers[ 1 ].videoChannel.id 78 videoChannelId: servers[1].videoChannel.id
78 } 79 }
79 }) 80 })
80 playlistWithoutThumbnail = res.body.videoPlaylist.id 81 playlistWithoutThumbnail = res.body.videoPlaylist.id
81 82
82 const res2 = await addVideoInPlaylist({ 83 const res2 = await addVideoInPlaylist({
83 url: servers[ 1 ].url, 84 url: servers[1].url,
84 token: servers[ 1 ].accessToken, 85 token: servers[1].accessToken,
85 playlistId: playlistWithoutThumbnail, 86 playlistId: playlistWithoutThumbnail,
86 elementAttrs: { videoId: video1 } 87 elementAttrs: { videoId: video1 }
87 }) 88 })
@@ -99,20 +100,20 @@ describe('Playlist thumbnail', function () {
99 this.timeout(30000) 100 this.timeout(30000)
100 101
101 const res = await createVideoPlaylist({ 102 const res = await createVideoPlaylist({
102 url: servers[ 1 ].url, 103 url: servers[1].url,
103 token: servers[ 1 ].accessToken, 104 token: servers[1].accessToken,
104 playlistAttrs: { 105 playlistAttrs: {
105 displayName: 'playlist with thumbnail', 106 displayName: 'playlist with thumbnail',
106 privacy: VideoPlaylistPrivacy.PUBLIC, 107 privacy: VideoPlaylistPrivacy.PUBLIC,
107 videoChannelId: servers[ 1 ].videoChannel.id, 108 videoChannelId: servers[1].videoChannel.id,
108 thumbnailfile: 'thumbnail.jpg' 109 thumbnailfile: 'thumbnail.jpg'
109 } 110 }
110 }) 111 })
111 playlistWithThumbnail = res.body.videoPlaylist.id 112 playlistWithThumbnail = res.body.videoPlaylist.id
112 113
113 const res2 = await addVideoInPlaylist({ 114 const res2 = await addVideoInPlaylist({
114 url: servers[ 1 ].url, 115 url: servers[1].url,
115 token: servers[ 1 ].accessToken, 116 token: servers[1].accessToken,
116 playlistId: playlistWithThumbnail, 117 playlistId: playlistWithThumbnail,
117 elementAttrs: { videoId: video1 } 118 elementAttrs: { videoId: video1 }
118 }) 119 })
@@ -130,8 +131,8 @@ describe('Playlist thumbnail', function () {
130 this.timeout(30000) 131 this.timeout(30000)
131 132
132 const res = await addVideoInPlaylist({ 133 const res = await addVideoInPlaylist({
133 url: servers[ 1 ].url, 134 url: servers[1].url,
134 token: servers[ 1 ].accessToken, 135 token: servers[1].accessToken,
135 playlistId: playlistWithoutThumbnail, 136 playlistId: playlistWithoutThumbnail,
136 elementAttrs: { videoId: video2 } 137 elementAttrs: { videoId: video2 }
137 }) 138 })
@@ -159,8 +160,8 @@ describe('Playlist thumbnail', function () {
159 this.timeout(30000) 160 this.timeout(30000)
160 161
161 const res = await addVideoInPlaylist({ 162 const res = await addVideoInPlaylist({
162 url: servers[ 1 ].url, 163 url: servers[1].url,
163 token: servers[ 1 ].accessToken, 164 token: servers[1].accessToken,
164 playlistId: playlistWithThumbnail, 165 playlistId: playlistWithThumbnail,
165 elementAttrs: { videoId: video2 } 166 elementAttrs: { videoId: video2 }
166 }) 167 })
@@ -188,8 +189,8 @@ describe('Playlist thumbnail', function () {
188 this.timeout(30000) 189 this.timeout(30000)
189 190
190 await removeVideoFromPlaylist({ 191 await removeVideoFromPlaylist({
191 url: servers[ 1 ].url, 192 url: servers[1].url,
192 token: servers[ 1 ].accessToken, 193 token: servers[1].accessToken,
193 playlistId: playlistWithoutThumbnail, 194 playlistId: playlistWithoutThumbnail,
194 playlistElementId: withoutThumbnailE1 195 playlistElementId: withoutThumbnailE1
195 }) 196 })
@@ -206,8 +207,8 @@ describe('Playlist thumbnail', function () {
206 this.timeout(30000) 207 this.timeout(30000)
207 208
208 await removeVideoFromPlaylist({ 209 await removeVideoFromPlaylist({
209 url: servers[ 1 ].url, 210 url: servers[1].url,
210 token: servers[ 1 ].accessToken, 211 token: servers[1].accessToken,
211 playlistId: playlistWithThumbnail, 212 playlistId: playlistWithThumbnail,
212 playlistElementId: withThumbnailE1 213 playlistElementId: withThumbnailE1
213 }) 214 })
@@ -224,8 +225,8 @@ describe('Playlist thumbnail', function () {
224 this.timeout(30000) 225 this.timeout(30000)
225 226
226 await removeVideoFromPlaylist({ 227 await removeVideoFromPlaylist({
227 url: servers[ 1 ].url, 228 url: servers[1].url,
228 token: servers[ 1 ].accessToken, 229 token: servers[1].accessToken,
229 playlistId: playlistWithoutThumbnail, 230 playlistId: playlistWithoutThumbnail,
230 playlistElementId: withoutThumbnailE2 231 playlistElementId: withoutThumbnailE2
231 }) 232 })
@@ -242,8 +243,8 @@ describe('Playlist thumbnail', function () {
242 this.timeout(30000) 243 this.timeout(30000)
243 244
244 await removeVideoFromPlaylist({ 245 await removeVideoFromPlaylist({
245 url: servers[ 1 ].url, 246 url: servers[1].url,
246 token: servers[ 1 ].accessToken, 247 token: servers[1].accessToken,
247 playlistId: playlistWithThumbnail, 248 playlistId: playlistWithThumbnail,
248 playlistElementId: withThumbnailE2 249 playlistElementId: withThumbnailE2
249 }) 250 })
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts
index 9fd48ac7c..2bb97d7a8 100644
--- a/server/tests/api/videos/video-playlists.ts
+++ b/server/tests/api/videos/video-playlists.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -141,12 +141,12 @@ describe('Test video playlists', function () {
141 servers[2].videos = await Promise.all(serverPromises[2]) 141 servers[2].videos = await Promise.all(serverPromises[2])
142 } 142 }
143 143
144 nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'NSFW video', nsfw: true })).id 144 nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'NSFW video', nsfw: true })).id
145 145
146 { 146 {
147 await createUser({ 147 await createUser({
148 url: servers[ 0 ].url, 148 url: servers[0].url,
149 accessToken: servers[ 0 ].accessToken, 149 accessToken: servers[0].accessToken,
150 username: 'user1', 150 username: 'user1',
151 password: 'password' 151 password: 'password'
152 }) 152 })
@@ -158,17 +158,17 @@ describe('Test video playlists', function () {
158 158
159 describe('Get default playlists', function () { 159 describe('Get default playlists', function () {
160 it('Should list video playlist privacies', async function () { 160 it('Should list video playlist privacies', async function () {
161 const res = await getVideoPlaylistPrivacies(servers[ 0 ].url) 161 const res = await getVideoPlaylistPrivacies(servers[0].url)
162 162
163 const privacies = res.body 163 const privacies = res.body
164 expect(Object.keys(privacies)).to.have.length.at.least(3) 164 expect(Object.keys(privacies)).to.have.length.at.least(3)
165 165
166 expect(privacies[ 3 ]).to.equal('Private') 166 expect(privacies[3]).to.equal('Private')
167 }) 167 })
168 168
169 it('Should list watch later playlist', async function () { 169 it('Should list watch later playlist', async function () {
170 const url = servers[ 0 ].url 170 const url = servers[0].url
171 const accessToken = servers[ 0 ].accessToken 171 const accessToken = servers[0].accessToken
172 172
173 { 173 {
174 const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER) 174 const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER)
@@ -176,7 +176,7 @@ describe('Test video playlists', function () {
176 expect(res.body.total).to.equal(1) 176 expect(res.body.total).to.equal(1)
177 expect(res.body.data).to.have.lengthOf(1) 177 expect(res.body.data).to.have.lengthOf(1)
178 178
179 const playlist: VideoPlaylist = res.body.data[ 0 ] 179 const playlist: VideoPlaylist = res.body.data[0]
180 expect(playlist.displayName).to.equal('Watch later') 180 expect(playlist.displayName).to.equal('Watch later')
181 expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER) 181 expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER)
182 expect(playlist.type.label).to.equal('Watch later') 182 expect(playlist.type.label).to.equal('Watch later')
@@ -197,15 +197,15 @@ describe('Test video playlists', function () {
197 }) 197 })
198 198
199 it('Should get private playlist for a classic user', async function () { 199 it('Should get private playlist for a classic user', async function () {
200 const token = await generateUserAccessToken(servers[ 0 ], 'toto') 200 const token = await generateUserAccessToken(servers[0], 'toto')
201 201
202 const res = await getAccountPlaylistsListWithToken(servers[ 0 ].url, token, 'toto', 0, 5) 202 const res = await getAccountPlaylistsListWithToken(servers[0].url, token, 'toto', 0, 5)
203 203
204 expect(res.body.total).to.equal(1) 204 expect(res.body.total).to.equal(1)
205 expect(res.body.data).to.have.lengthOf(1) 205 expect(res.body.data).to.have.lengthOf(1)
206 206
207 const playlistId = res.body.data[ 0 ].id 207 const playlistId = res.body.data[0].id
208 await getPlaylistVideos(servers[ 0 ].url, token, playlistId, 0, 5) 208 await getPlaylistVideos(servers[0].url, token, playlistId, 0, 5)
209 }) 209 })
210 }) 210 })
211 211
@@ -215,14 +215,14 @@ describe('Test video playlists', function () {
215 this.timeout(30000) 215 this.timeout(30000)
216 216
217 await createVideoPlaylist({ 217 await createVideoPlaylist({
218 url: servers[ 0 ].url, 218 url: servers[0].url,
219 token: servers[ 0 ].accessToken, 219 token: servers[0].accessToken,
220 playlistAttrs: { 220 playlistAttrs: {
221 displayName: 'my super playlist', 221 displayName: 'my super playlist',
222 privacy: VideoPlaylistPrivacy.PUBLIC, 222 privacy: VideoPlaylistPrivacy.PUBLIC,
223 description: 'my super description', 223 description: 'my super description',
224 thumbnailfile: 'thumbnail.jpg', 224 thumbnailfile: 'thumbnail.jpg',
225 videoChannelId: servers[ 0 ].videoChannel.id 225 videoChannelId: servers[0].videoChannel.id
226 } 226 }
227 }) 227 })
228 228
@@ -233,7 +233,7 @@ describe('Test video playlists', function () {
233 expect(res.body.total).to.equal(1) 233 expect(res.body.total).to.equal(1)
234 expect(res.body.data).to.have.lengthOf(1) 234 expect(res.body.data).to.have.lengthOf(1)
235 235
236 const playlistFromList = res.body.data[ 0 ] as VideoPlaylist 236 const playlistFromList = res.body.data[0] as VideoPlaylist
237 237
238 const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid) 238 const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid)
239 const playlistFromGet = res2.body 239 const playlistFromGet = res2.body
@@ -266,12 +266,12 @@ describe('Test video playlists', function () {
266 266
267 { 267 {
268 const res = await createVideoPlaylist({ 268 const res = await createVideoPlaylist({
269 url: servers[ 1 ].url, 269 url: servers[1].url,
270 token: servers[ 1 ].accessToken, 270 token: servers[1].accessToken,
271 playlistAttrs: { 271 playlistAttrs: {
272 displayName: 'playlist 2', 272 displayName: 'playlist 2',
273 privacy: VideoPlaylistPrivacy.PUBLIC, 273 privacy: VideoPlaylistPrivacy.PUBLIC,
274 videoChannelId: servers[ 1 ].videoChannel.id 274 videoChannelId: servers[1].videoChannel.id
275 } 275 }
276 }) 276 })
277 playlistServer2Id1 = res.body.videoPlaylist.id 277 playlistServer2Id1 = res.body.videoPlaylist.id
@@ -279,13 +279,13 @@ describe('Test video playlists', function () {
279 279
280 { 280 {
281 const res = await createVideoPlaylist({ 281 const res = await createVideoPlaylist({
282 url: servers[ 1 ].url, 282 url: servers[1].url,
283 token: servers[ 1 ].accessToken, 283 token: servers[1].accessToken,
284 playlistAttrs: { 284 playlistAttrs: {
285 displayName: 'playlist 3', 285 displayName: 'playlist 3',
286 privacy: VideoPlaylistPrivacy.PUBLIC, 286 privacy: VideoPlaylistPrivacy.PUBLIC,
287 thumbnailfile: 'thumbnail.jpg', 287 thumbnailfile: 'thumbnail.jpg',
288 videoChannelId: servers[ 1 ].videoChannel.id 288 videoChannelId: servers[1].videoChannel.id
289 } 289 }
290 }) 290 })
291 291
@@ -293,24 +293,24 @@ describe('Test video playlists', function () {
293 playlistServer2UUID2 = res.body.videoPlaylist.uuid 293 playlistServer2UUID2 = res.body.videoPlaylist.uuid
294 } 294 }
295 295
296 for (let id of [ playlistServer2Id1, playlistServer2Id2 ]) { 296 for (const id of [ playlistServer2Id1, playlistServer2Id2 ]) {
297 await addVideoInPlaylist({ 297 await addVideoInPlaylist({
298 url: servers[ 1 ].url, 298 url: servers[1].url,
299 token: servers[ 1 ].accessToken, 299 token: servers[1].accessToken,
300 playlistId: id, 300 playlistId: id,
301 elementAttrs: { videoId: servers[ 1 ].videos[ 0 ].id, startTimestamp: 1, stopTimestamp: 2 } 301 elementAttrs: { videoId: servers[1].videos[0].id, startTimestamp: 1, stopTimestamp: 2 }
302 }) 302 })
303 await addVideoInPlaylist({ 303 await addVideoInPlaylist({
304 url: servers[ 1 ].url, 304 url: servers[1].url,
305 token: servers[ 1 ].accessToken, 305 token: servers[1].accessToken,
306 playlistId: id, 306 playlistId: id,
307 elementAttrs: { videoId: servers[ 1 ].videos[ 1 ].id } 307 elementAttrs: { videoId: servers[1].videos[1].id }
308 }) 308 })
309 } 309 }
310 310
311 await waitJobs(servers) 311 await waitJobs(servers)
312 312
313 for (const server of [ servers[ 0 ], servers[ 1 ] ]) { 313 for (const server of [ servers[0], servers[1] ]) {
314 const res = await getVideoPlaylistsList(server.url, 0, 5) 314 const res = await getVideoPlaylistsList(server.url, 0, 5)
315 315
316 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') 316 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
@@ -322,7 +322,7 @@ describe('Test video playlists', function () {
322 await testImage(server.url, 'thumbnail', playlist3.thumbnailPath) 322 await testImage(server.url, 'thumbnail', playlist3.thumbnailPath)
323 } 323 }
324 324
325 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) 325 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
326 expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined 326 expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined
327 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined 327 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined
328 }) 328 })
@@ -331,13 +331,13 @@ describe('Test video playlists', function () {
331 this.timeout(30000) 331 this.timeout(30000)
332 332
333 // Server 2 and server 3 follow each other 333 // Server 2 and server 3 follow each other
334 await doubleFollow(servers[ 1 ], servers[ 2 ]) 334 await doubleFollow(servers[1], servers[2])
335 335
336 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) 336 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
337 337
338 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') 338 const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
339 expect(playlist2).to.not.be.undefined 339 expect(playlist2).to.not.be.undefined
340 await testImage(servers[ 2 ].url, 'thumbnail-playlist', playlist2.thumbnailPath) 340 await testImage(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath)
341 341
342 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined 342 expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined
343 }) 343 })
@@ -349,25 +349,25 @@ describe('Test video playlists', function () {
349 this.timeout(30000) 349 this.timeout(30000)
350 350
351 { 351 {
352 const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, 'createdAt') 352 const res = await getVideoPlaylistsList(servers[2].url, 1, 2, 'createdAt')
353 353
354 expect(res.body.total).to.equal(3) 354 expect(res.body.total).to.equal(3)
355 355
356 const data: VideoPlaylist[] = res.body.data 356 const data: VideoPlaylist[] = res.body.data
357 expect(data).to.have.lengthOf(2) 357 expect(data).to.have.lengthOf(2)
358 expect(data[ 0 ].displayName).to.equal('playlist 2') 358 expect(data[0].displayName).to.equal('playlist 2')
359 expect(data[ 1 ].displayName).to.equal('playlist 3') 359 expect(data[1].displayName).to.equal('playlist 3')
360 } 360 }
361 361
362 { 362 {
363 const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, '-createdAt') 363 const res = await getVideoPlaylistsList(servers[2].url, 1, 2, '-createdAt')
364 364
365 expect(res.body.total).to.equal(3) 365 expect(res.body.total).to.equal(3)
366 366
367 const data: VideoPlaylist[] = res.body.data 367 const data: VideoPlaylist[] = res.body.data
368 expect(data).to.have.lengthOf(2) 368 expect(data).to.have.lengthOf(2)
369 expect(data[ 0 ].displayName).to.equal('playlist 2') 369 expect(data[0].displayName).to.equal('playlist 2')
370 expect(data[ 1 ].displayName).to.equal('my super playlist') 370 expect(data[1].displayName).to.equal('my super playlist')
371 } 371 }
372 }) 372 })
373 373
@@ -375,13 +375,13 @@ describe('Test video playlists', function () {
375 this.timeout(30000) 375 this.timeout(30000)
376 376
377 { 377 {
378 const res = await getVideoChannelPlaylistsList(servers[ 0 ].url, 'root_channel', 0, 2, '-createdAt') 378 const res = await getVideoChannelPlaylistsList(servers[0].url, 'root_channel', 0, 2, '-createdAt')
379 379
380 expect(res.body.total).to.equal(1) 380 expect(res.body.total).to.equal(1)
381 381
382 const data: VideoPlaylist[] = res.body.data 382 const data: VideoPlaylist[] = res.body.data
383 expect(data).to.have.lengthOf(1) 383 expect(data).to.have.lengthOf(1)
384 expect(data[ 0 ].displayName).to.equal('my super playlist') 384 expect(data[0].displayName).to.equal('my super playlist')
385 } 385 }
386 }) 386 })
387 387
@@ -389,37 +389,37 @@ describe('Test video playlists', function () {
389 this.timeout(30000) 389 this.timeout(30000)
390 390
391 { 391 {
392 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, '-createdAt') 392 const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, '-createdAt')
393 393
394 expect(res.body.total).to.equal(2) 394 expect(res.body.total).to.equal(2)
395 395
396 const data: VideoPlaylist[] = res.body.data 396 const data: VideoPlaylist[] = res.body.data
397 expect(data).to.have.lengthOf(1) 397 expect(data).to.have.lengthOf(1)
398 expect(data[ 0 ].displayName).to.equal('playlist 2') 398 expect(data[0].displayName).to.equal('playlist 2')
399 } 399 }
400 400
401 { 401 {
402 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, 'createdAt') 402 const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, 'createdAt')
403 403
404 expect(res.body.total).to.equal(2) 404 expect(res.body.total).to.equal(2)
405 405
406 const data: VideoPlaylist[] = res.body.data 406 const data: VideoPlaylist[] = res.body.data
407 expect(data).to.have.lengthOf(1) 407 expect(data).to.have.lengthOf(1)
408 expect(data[ 0 ].displayName).to.equal('playlist 3') 408 expect(data[0].displayName).to.equal('playlist 3')
409 } 409 }
410 410
411 { 411 {
412 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 0, 10, 'createdAt', '3') 412 const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '3')
413 413
414 expect(res.body.total).to.equal(1) 414 expect(res.body.total).to.equal(1)
415 415
416 const data: VideoPlaylist[] = res.body.data 416 const data: VideoPlaylist[] = res.body.data
417 expect(data).to.have.lengthOf(1) 417 expect(data).to.have.lengthOf(1)
418 expect(data[ 0 ].displayName).to.equal('playlist 3') 418 expect(data[0].displayName).to.equal('playlist 3')
419 } 419 }
420 420
421 { 421 {
422 const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 0, 10, 'createdAt', '4') 422 const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '4')
423 423
424 expect(res.body.total).to.equal(0) 424 expect(res.body.total).to.equal(0)
425 425
@@ -432,8 +432,8 @@ describe('Test video playlists', function () {
432 this.timeout(30000) 432 this.timeout(30000)
433 433
434 await createVideoPlaylist({ 434 await createVideoPlaylist({
435 url: servers[ 1 ].url, 435 url: servers[1].url,
436 token: servers[ 1 ].accessToken, 436 token: servers[1].accessToken,
437 playlistAttrs: { 437 playlistAttrs: {
438 displayName: 'playlist unlisted', 438 displayName: 'playlist unlisted',
439 privacy: VideoPlaylistPrivacy.UNLISTED 439 privacy: VideoPlaylistPrivacy.UNLISTED
@@ -441,8 +441,8 @@ describe('Test video playlists', function () {
441 }) 441 })
442 442
443 await createVideoPlaylist({ 443 await createVideoPlaylist({
444 url: servers[ 1 ].url, 444 url: servers[1].url,
445 token: servers[ 1 ].accessToken, 445 token: servers[1].accessToken,
446 playlistAttrs: { 446 playlistAttrs: {
447 displayName: 'playlist private', 447 displayName: 'playlist private',
448 privacy: VideoPlaylistPrivacy.PRIVATE 448 privacy: VideoPlaylistPrivacy.PRIVATE
@@ -453,18 +453,18 @@ describe('Test video playlists', function () {
453 453
454 for (const server of servers) { 454 for (const server of servers) {
455 const results = [ 455 const results = [
456 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[ 1 ].port, 0, 5, '-createdAt'), 456 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
457 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt') 457 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
458 ] 458 ]
459 459
460 expect(results[ 0 ].body.total).to.equal(2) 460 expect(results[0].body.total).to.equal(2)
461 expect(results[ 1 ].body.total).to.equal(3) 461 expect(results[1].body.total).to.equal(3)
462 462
463 for (const res of results) { 463 for (const res of results) {
464 const data: VideoPlaylist[] = res.body.data 464 const data: VideoPlaylist[] = res.body.data
465 expect(data).to.have.lengthOf(2) 465 expect(data).to.have.lengthOf(2)
466 expect(data[ 0 ].displayName).to.equal('playlist 3') 466 expect(data[0].displayName).to.equal('playlist 3')
467 expect(data[ 1 ].displayName).to.equal('playlist 2') 467 expect(data[1].displayName).to.equal('playlist 2')
468 } 468 }
469 } 469 }
470 }) 470 })
@@ -519,32 +519,32 @@ describe('Test video playlists', function () {
519 this.timeout(30000) 519 this.timeout(30000)
520 520
521 const addVideo = (elementAttrs: any) => { 521 const addVideo = (elementAttrs: any) => {
522 return addVideoInPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: playlistServer1Id, elementAttrs }) 522 return addVideoInPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: playlistServer1Id, elementAttrs })
523 } 523 }
524 524
525 const res = await createVideoPlaylist({ 525 const res = await createVideoPlaylist({
526 url: servers[ 0 ].url, 526 url: servers[0].url,
527 token: servers[ 0 ].accessToken, 527 token: servers[0].accessToken,
528 playlistAttrs: { 528 playlistAttrs: {
529 displayName: 'playlist 4', 529 displayName: 'playlist 4',
530 privacy: VideoPlaylistPrivacy.PUBLIC, 530 privacy: VideoPlaylistPrivacy.PUBLIC,
531 videoChannelId: servers[ 0 ].videoChannel.id 531 videoChannelId: servers[0].videoChannel.id
532 } 532 }
533 }) 533 })
534 534
535 playlistServer1Id = res.body.videoPlaylist.id 535 playlistServer1Id = res.body.videoPlaylist.id
536 playlistServer1UUID = res.body.videoPlaylist.uuid 536 playlistServer1UUID = res.body.videoPlaylist.uuid
537 537
538 await addVideo({ videoId: servers[ 0 ].videos[ 0 ].uuid, startTimestamp: 15, stopTimestamp: 28 }) 538 await addVideo({ videoId: servers[0].videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 })
539 await addVideo({ videoId: servers[ 2 ].videos[ 1 ].uuid, startTimestamp: 35 }) 539 await addVideo({ videoId: servers[2].videos[1].uuid, startTimestamp: 35 })
540 await addVideo({ videoId: servers[ 2 ].videos[ 2 ].uuid }) 540 await addVideo({ videoId: servers[2].videos[2].uuid })
541 { 541 {
542 const res = await addVideo({ videoId: servers[ 0 ].videos[ 3 ].uuid, stopTimestamp: 35 }) 542 const res = await addVideo({ videoId: servers[0].videos[3].uuid, stopTimestamp: 35 })
543 playlistElementServer1Video4 = res.body.videoPlaylistElement.id 543 playlistElementServer1Video4 = res.body.videoPlaylistElement.id
544 } 544 }
545 545
546 { 546 {
547 const res = await addVideo({ videoId: servers[ 0 ].videos[ 4 ].uuid, startTimestamp: 45, stopTimestamp: 60 }) 547 const res = await addVideo({ videoId: servers[0].videos[4].uuid, startTimestamp: 45, stopTimestamp: 60 })
548 playlistElementServer1Video5 = res.body.videoPlaylistElement.id 548 playlistElementServer1Video5 = res.body.videoPlaylistElement.id
549 } 549 }
550 550
@@ -567,35 +567,35 @@ describe('Test video playlists', function () {
567 const videoElements: VideoPlaylistElement[] = res.body.data 567 const videoElements: VideoPlaylistElement[] = res.body.data
568 expect(videoElements).to.have.lengthOf(6) 568 expect(videoElements).to.have.lengthOf(6)
569 569
570 expect(videoElements[ 0 ].video.name).to.equal('video 0 server 1') 570 expect(videoElements[0].video.name).to.equal('video 0 server 1')
571 expect(videoElements[ 0 ].position).to.equal(1) 571 expect(videoElements[0].position).to.equal(1)
572 expect(videoElements[ 0 ].startTimestamp).to.equal(15) 572 expect(videoElements[0].startTimestamp).to.equal(15)
573 expect(videoElements[ 0 ].stopTimestamp).to.equal(28) 573 expect(videoElements[0].stopTimestamp).to.equal(28)
574 574
575 expect(videoElements[ 1 ].video.name).to.equal('video 1 server 3') 575 expect(videoElements[1].video.name).to.equal('video 1 server 3')
576 expect(videoElements[ 1 ].position).to.equal(2) 576 expect(videoElements[1].position).to.equal(2)
577 expect(videoElements[ 1 ].startTimestamp).to.equal(35) 577 expect(videoElements[1].startTimestamp).to.equal(35)
578 expect(videoElements[ 1 ].stopTimestamp).to.be.null 578 expect(videoElements[1].stopTimestamp).to.be.null
579 579
580 expect(videoElements[ 2 ].video.name).to.equal('video 2 server 3') 580 expect(videoElements[2].video.name).to.equal('video 2 server 3')
581 expect(videoElements[ 2 ].position).to.equal(3) 581 expect(videoElements[2].position).to.equal(3)
582 expect(videoElements[ 2 ].startTimestamp).to.be.null 582 expect(videoElements[2].startTimestamp).to.be.null
583 expect(videoElements[ 2 ].stopTimestamp).to.be.null 583 expect(videoElements[2].stopTimestamp).to.be.null
584 584
585 expect(videoElements[ 3 ].video.name).to.equal('video 3 server 1') 585 expect(videoElements[3].video.name).to.equal('video 3 server 1')
586 expect(videoElements[ 3 ].position).to.equal(4) 586 expect(videoElements[3].position).to.equal(4)
587 expect(videoElements[ 3 ].startTimestamp).to.be.null 587 expect(videoElements[3].startTimestamp).to.be.null
588 expect(videoElements[ 3 ].stopTimestamp).to.equal(35) 588 expect(videoElements[3].stopTimestamp).to.equal(35)
589 589
590 expect(videoElements[ 4 ].video.name).to.equal('video 4 server 1') 590 expect(videoElements[4].video.name).to.equal('video 4 server 1')
591 expect(videoElements[ 4 ].position).to.equal(5) 591 expect(videoElements[4].position).to.equal(5)
592 expect(videoElements[ 4 ].startTimestamp).to.equal(45) 592 expect(videoElements[4].startTimestamp).to.equal(45)
593 expect(videoElements[ 4 ].stopTimestamp).to.equal(60) 593 expect(videoElements[4].stopTimestamp).to.equal(60)
594 594
595 expect(videoElements[ 5 ].video.name).to.equal('NSFW video') 595 expect(videoElements[5].video.name).to.equal('NSFW video')
596 expect(videoElements[ 5 ].position).to.equal(6) 596 expect(videoElements[5].position).to.equal(6)
597 expect(videoElements[ 5 ].startTimestamp).to.equal(5) 597 expect(videoElements[5].startTimestamp).to.equal(5)
598 expect(videoElements[ 5 ].stopTimestamp).to.be.null 598 expect(videoElements[5].stopTimestamp).to.be.null
599 599
600 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2) 600 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
601 expect(res3.body.data).to.have.lengthOf(2) 601 expect(res3.body.data).to.have.lengthOf(2)
@@ -616,18 +616,18 @@ describe('Test video playlists', function () {
616 before(async function () { 616 before(async function () {
617 this.timeout(30000) 617 this.timeout(30000)
618 618
619 groupUser1 = [ Object.assign({}, servers[ 0 ], { accessToken: userAccessTokenServer1 }) ] 619 groupUser1 = [ Object.assign({}, servers[0], { accessToken: userAccessTokenServer1 }) ]
620 groupWithoutToken1 = [ Object.assign({}, servers[ 0 ], { accessToken: undefined }) ] 620 groupWithoutToken1 = [ Object.assign({}, servers[0], { accessToken: undefined }) ]
621 group1 = [ servers[ 0 ] ] 621 group1 = [ servers[0] ]
622 group2 = [ servers[ 1 ], servers[ 2 ] ] 622 group2 = [ servers[1], servers[2] ]
623 623
624 const res = await createVideoPlaylist({ 624 const res = await createVideoPlaylist({
625 url: servers[ 0 ].url, 625 url: servers[0].url,
626 token: userAccessTokenServer1, 626 token: userAccessTokenServer1,
627 playlistAttrs: { 627 playlistAttrs: {
628 displayName: 'playlist 56', 628 displayName: 'playlist 56',
629 privacy: VideoPlaylistPrivacy.PUBLIC, 629 privacy: VideoPlaylistPrivacy.PUBLIC,
630 videoChannelId: servers[ 0 ].videoChannel.id 630 videoChannelId: servers[0].videoChannel.id
631 } 631 }
632 }) 632 })
633 633
@@ -635,7 +635,7 @@ describe('Test video playlists', function () {
635 playlistServer1UUID2 = res.body.videoPlaylist.uuid 635 playlistServer1UUID2 = res.body.videoPlaylist.uuid
636 636
637 const addVideo = (elementAttrs: any) => { 637 const addVideo = (elementAttrs: any) => {
638 return addVideoInPlaylist({ url: servers[ 0 ].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs }) 638 return addVideoInPlaylist({ url: servers[0].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs })
639 } 639 }
640 640
641 video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid 641 video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid
@@ -656,7 +656,7 @@ describe('Test video playlists', function () {
656 const position = 1 656 const position = 1
657 657
658 { 658 {
659 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PRIVATE }) 659 await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PRIVATE })
660 await waitJobs(servers) 660 await waitJobs(servers)
661 661
662 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 662 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
@@ -666,7 +666,7 @@ describe('Test video playlists', function () {
666 } 666 }
667 667
668 { 668 {
669 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PUBLIC }) 669 await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PUBLIC })
670 await waitJobs(servers) 670 await waitJobs(servers)
671 671
672 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 672 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
@@ -684,7 +684,7 @@ describe('Test video playlists', function () {
684 const position = 1 684 const position = 1
685 685
686 { 686 {
687 await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1, 'reason', true) 687 await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video1, 'reason', true)
688 await waitJobs(servers) 688 await waitJobs(servers)
689 689
690 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 690 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
@@ -694,7 +694,7 @@ describe('Test video playlists', function () {
694 } 694 }
695 695
696 { 696 {
697 await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1) 697 await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video1)
698 await waitJobs(servers) 698 await waitJobs(servers)
699 699
700 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 700 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
@@ -712,52 +712,52 @@ describe('Test video playlists', function () {
712 const position = 2 712 const position = 2
713 713
714 { 714 {
715 await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) 715 await addAccountToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
716 await waitJobs(servers) 716 await waitJobs(servers)
717 717
718 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) 718 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
719 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 719 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
720 720
721 await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) 721 await removeAccountFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
722 await waitJobs(servers) 722 await waitJobs(servers)
723 723
724 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 724 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
725 } 725 }
726 726
727 { 727 {
728 await addServerToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port) 728 await addServerToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
729 await waitJobs(servers) 729 await waitJobs(servers)
730 730
731 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) 731 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
732 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 732 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
733 733
734 await removeServerFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port) 734 await removeServerFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
735 await waitJobs(servers) 735 await waitJobs(servers)
736 736
737 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 737 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
738 } 738 }
739 739
740 { 740 {
741 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port) 741 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port)
742 await waitJobs(servers) 742 await waitJobs(servers)
743 743
744 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) 744 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
745 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 745 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
746 746
747 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port) 747 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port)
748 await waitJobs(servers) 748 await waitJobs(servers)
749 749
750 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 750 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
751 } 751 }
752 752
753 { 753 {
754 await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) 754 await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
755 await waitJobs(servers) 755 await waitJobs(servers)
756 756
757 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) 757 await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
758 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 758 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
759 759
760 await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) 760 await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
761 await waitJobs(servers) 761 await waitJobs(servers)
762 762
763 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) 763 await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
@@ -785,8 +785,8 @@ describe('Test video playlists', function () {
785 785
786 { 786 {
787 await reorderVideosPlaylist({ 787 await reorderVideosPlaylist({
788 url: servers[ 0 ].url, 788 url: servers[0].url,
789 token: servers[ 0 ].accessToken, 789 token: servers[0].accessToken,
790 playlistId: playlistServer1Id, 790 playlistId: playlistServer1Id,
791 elementAttrs: { 791 elementAttrs: {
792 startPosition: 2, 792 startPosition: 2,
@@ -813,8 +813,8 @@ describe('Test video playlists', function () {
813 813
814 { 814 {
815 await reorderVideosPlaylist({ 815 await reorderVideosPlaylist({
816 url: servers[ 0 ].url, 816 url: servers[0].url,
817 token: servers[ 0 ].accessToken, 817 token: servers[0].accessToken,
818 playlistId: playlistServer1Id, 818 playlistId: playlistServer1Id,
819 elementAttrs: { 819 elementAttrs: {
820 startPosition: 1, 820 startPosition: 1,
@@ -842,8 +842,8 @@ describe('Test video playlists', function () {
842 842
843 { 843 {
844 await reorderVideosPlaylist({ 844 await reorderVideosPlaylist({
845 url: servers[ 0 ].url, 845 url: servers[0].url,
846 token: servers[ 0 ].accessToken, 846 token: servers[0].accessToken,
847 playlistId: playlistServer1Id, 847 playlistId: playlistServer1Id,
848 elementAttrs: { 848 elementAttrs: {
849 startPosition: 6, 849 startPosition: 6,
@@ -868,7 +868,7 @@ describe('Test video playlists', function () {
868 ]) 868 ])
869 869
870 for (let i = 1; i <= elements.length; i++) { 870 for (let i = 1; i <= elements.length; i++) {
871 expect(elements[ i - 1 ].position).to.equal(i) 871 expect(elements[i - 1].position).to.equal(i)
872 } 872 }
873 } 873 }
874 } 874 }
@@ -878,8 +878,8 @@ describe('Test video playlists', function () {
878 this.timeout(30000) 878 this.timeout(30000)
879 879
880 await updateVideoPlaylistElement({ 880 await updateVideoPlaylistElement({
881 url: servers[ 0 ].url, 881 url: servers[0].url,
882 token: servers[ 0 ].accessToken, 882 token: servers[0].accessToken,
883 playlistId: playlistServer1Id, 883 playlistId: playlistServer1Id,
884 playlistElementId: playlistElementServer1Video4, 884 playlistElementId: playlistElementServer1Video4,
885 elementAttrs: { 885 elementAttrs: {
@@ -888,8 +888,8 @@ describe('Test video playlists', function () {
888 }) 888 })
889 889
890 await updateVideoPlaylistElement({ 890 await updateVideoPlaylistElement({
891 url: servers[ 0 ].url, 891 url: servers[0].url,
892 token: servers[ 0 ].accessToken, 892 token: servers[0].accessToken,
893 playlistId: playlistServer1Id, 893 playlistId: playlistServer1Id,
894 playlistElementId: playlistElementServer1Video5, 894 playlistElementId: playlistElementServer1Video5,
895 elementAttrs: { 895 elementAttrs: {
@@ -903,62 +903,62 @@ describe('Test video playlists', function () {
903 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10) 903 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
904 const elements: VideoPlaylistElement[] = res.body.data 904 const elements: VideoPlaylistElement[] = res.body.data
905 905
906 expect(elements[ 0 ].video.name).to.equal('video 3 server 1') 906 expect(elements[0].video.name).to.equal('video 3 server 1')
907 expect(elements[ 0 ].position).to.equal(1) 907 expect(elements[0].position).to.equal(1)
908 expect(elements[ 0 ].startTimestamp).to.equal(1) 908 expect(elements[0].startTimestamp).to.equal(1)
909 expect(elements[ 0 ].stopTimestamp).to.equal(35) 909 expect(elements[0].stopTimestamp).to.equal(35)
910 910
911 expect(elements[ 5 ].video.name).to.equal('video 4 server 1') 911 expect(elements[5].video.name).to.equal('video 4 server 1')
912 expect(elements[ 5 ].position).to.equal(6) 912 expect(elements[5].position).to.equal(6)
913 expect(elements[ 5 ].startTimestamp).to.equal(45) 913 expect(elements[5].startTimestamp).to.equal(45)
914 expect(elements[ 5 ].stopTimestamp).to.be.null 914 expect(elements[5].stopTimestamp).to.be.null
915 } 915 }
916 }) 916 })
917 917
918 it('Should check videos existence in my playlist', async function () { 918 it('Should check videos existence in my playlist', async function () {
919 const videoIds = [ 919 const videoIds = [
920 servers[ 0 ].videos[ 0 ].id, 920 servers[0].videos[0].id,
921 42000, 921 42000,
922 servers[ 0 ].videos[ 3 ].id, 922 servers[0].videos[3].id,
923 43000, 923 43000,
924 servers[ 0 ].videos[ 4 ].id 924 servers[0].videos[4].id
925 ] 925 ]
926 const res = await doVideosExistInMyPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, videoIds) 926 const res = await doVideosExistInMyPlaylist(servers[0].url, servers[0].accessToken, videoIds)
927 const obj = res.body as VideoExistInPlaylist 927 const obj = res.body as VideoExistInPlaylist
928 928
929 { 929 {
930 const elem = obj[ servers[ 0 ].videos[ 0 ].id ] 930 const elem = obj[servers[0].videos[0].id]
931 expect(elem).to.have.lengthOf(1) 931 expect(elem).to.have.lengthOf(1)
932 expect(elem[ 0 ].playlistElementId).to.exist 932 expect(elem[0].playlistElementId).to.exist
933 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) 933 expect(elem[0].playlistId).to.equal(playlistServer1Id)
934 expect(elem[ 0 ].startTimestamp).to.equal(15) 934 expect(elem[0].startTimestamp).to.equal(15)
935 expect(elem[ 0 ].stopTimestamp).to.equal(28) 935 expect(elem[0].stopTimestamp).to.equal(28)
936 } 936 }
937 937
938 { 938 {
939 const elem = obj[ servers[ 0 ].videos[ 3 ].id ] 939 const elem = obj[servers[0].videos[3].id]
940 expect(elem).to.have.lengthOf(1) 940 expect(elem).to.have.lengthOf(1)
941 expect(elem[ 0 ].playlistElementId).to.equal(playlistElementServer1Video4) 941 expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4)
942 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) 942 expect(elem[0].playlistId).to.equal(playlistServer1Id)
943 expect(elem[ 0 ].startTimestamp).to.equal(1) 943 expect(elem[0].startTimestamp).to.equal(1)
944 expect(elem[ 0 ].stopTimestamp).to.equal(35) 944 expect(elem[0].stopTimestamp).to.equal(35)
945 } 945 }
946 946
947 { 947 {
948 const elem = obj[ servers[ 0 ].videos[ 4 ].id ] 948 const elem = obj[servers[0].videos[4].id]
949 expect(elem).to.have.lengthOf(1) 949 expect(elem).to.have.lengthOf(1)
950 expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) 950 expect(elem[0].playlistId).to.equal(playlistServer1Id)
951 expect(elem[ 0 ].startTimestamp).to.equal(45) 951 expect(elem[0].startTimestamp).to.equal(45)
952 expect(elem[ 0 ].stopTimestamp).to.equal(null) 952 expect(elem[0].stopTimestamp).to.equal(null)
953 } 953 }
954 954
955 expect(obj[ 42000 ]).to.have.lengthOf(0) 955 expect(obj[42000]).to.have.lengthOf(0)
956 expect(obj[ 43000 ]).to.have.lengthOf(0) 956 expect(obj[43000]).to.have.lengthOf(0)
957 }) 957 })
958 958
959 it('Should automatically update updatedAt field of playlists', async function () { 959 it('Should automatically update updatedAt field of playlists', async function () {
960 const server = servers[ 1 ] 960 const server = servers[1]
961 const videoId = servers[ 1 ].videos[ 5 ].id 961 const videoId = servers[1].videos[5].id
962 962
963 async function getPlaylistNames () { 963 async function getPlaylistNames () {
964 const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt') 964 const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt')
@@ -974,8 +974,8 @@ describe('Test video playlists', function () {
974 const element2 = res2.body.videoPlaylistElement.id 974 const element2 = res2.body.videoPlaylistElement.id
975 975
976 const names1 = await getPlaylistNames() 976 const names1 = await getPlaylistNames()
977 expect(names1[ 0 ]).to.equal('playlist 3 updated') 977 expect(names1[0]).to.equal('playlist 3 updated')
978 expect(names1[ 1 ]).to.equal('playlist 2') 978 expect(names1[1]).to.equal('playlist 2')
979 979
980 await removeVideoFromPlaylist({ 980 await removeVideoFromPlaylist({
981 url: server.url, 981 url: server.url,
@@ -985,8 +985,8 @@ describe('Test video playlists', function () {
985 }) 985 })
986 986
987 const names2 = await getPlaylistNames() 987 const names2 = await getPlaylistNames()
988 expect(names2[ 0 ]).to.equal('playlist 2') 988 expect(names2[0]).to.equal('playlist 2')
989 expect(names2[ 1 ]).to.equal('playlist 3 updated') 989 expect(names2[1]).to.equal('playlist 3 updated')
990 990
991 await removeVideoFromPlaylist({ 991 await removeVideoFromPlaylist({
992 url: server.url, 992 url: server.url,
@@ -996,23 +996,23 @@ describe('Test video playlists', function () {
996 }) 996 })
997 997
998 const names3 = await getPlaylistNames() 998 const names3 = await getPlaylistNames()
999 expect(names3[ 0 ]).to.equal('playlist 3 updated') 999 expect(names3[0]).to.equal('playlist 3 updated')
1000 expect(names3[ 1 ]).to.equal('playlist 2') 1000 expect(names3[1]).to.equal('playlist 2')
1001 }) 1001 })
1002 1002
1003 it('Should delete some elements', async function () { 1003 it('Should delete some elements', async function () {
1004 this.timeout(30000) 1004 this.timeout(30000)
1005 1005
1006 await removeVideoFromPlaylist({ 1006 await removeVideoFromPlaylist({
1007 url: servers[ 0 ].url, 1007 url: servers[0].url,
1008 token: servers[ 0 ].accessToken, 1008 token: servers[0].accessToken,
1009 playlistId: playlistServer1Id, 1009 playlistId: playlistServer1Id,
1010 playlistElementId: playlistElementServer1Video4 1010 playlistElementId: playlistElementServer1Video4
1011 }) 1011 })
1012 1012
1013 await removeVideoFromPlaylist({ 1013 await removeVideoFromPlaylist({
1014 url: servers[ 0 ].url, 1014 url: servers[0].url,
1015 token: servers[ 0 ].accessToken, 1015 token: servers[0].accessToken,
1016 playlistId: playlistServer1Id, 1016 playlistId: playlistServer1Id,
1017 playlistElementId: playlistElementNSFW 1017 playlistElementId: playlistElementNSFW
1018 }) 1018 })
@@ -1027,17 +1027,17 @@ describe('Test video playlists', function () {
1027 const elements: VideoPlaylistElement[] = res.body.data 1027 const elements: VideoPlaylistElement[] = res.body.data
1028 expect(elements).to.have.lengthOf(4) 1028 expect(elements).to.have.lengthOf(4)
1029 1029
1030 expect(elements[ 0 ].video.name).to.equal('video 0 server 1') 1030 expect(elements[0].video.name).to.equal('video 0 server 1')
1031 expect(elements[ 0 ].position).to.equal(1) 1031 expect(elements[0].position).to.equal(1)
1032 1032
1033 expect(elements[ 1 ].video.name).to.equal('video 2 server 3') 1033 expect(elements[1].video.name).to.equal('video 2 server 3')
1034 expect(elements[ 1 ].position).to.equal(2) 1034 expect(elements[1].position).to.equal(2)
1035 1035
1036 expect(elements[ 2 ].video.name).to.equal('video 1 server 3') 1036 expect(elements[2].video.name).to.equal('video 1 server 3')
1037 expect(elements[ 2 ].position).to.equal(3) 1037 expect(elements[2].position).to.equal(3)
1038 1038
1039 expect(elements[ 3 ].video.name).to.equal('video 4 server 1') 1039 expect(elements[3].video.name).to.equal('video 4 server 1')
1040 expect(elements[ 3 ].position).to.equal(4) 1040 expect(elements[3].position).to.equal(4)
1041 } 1041 }
1042 }) 1042 })
1043 1043
@@ -1045,12 +1045,12 @@ describe('Test video playlists', function () {
1045 this.timeout(30000) 1045 this.timeout(30000)
1046 1046
1047 const res = await createVideoPlaylist({ 1047 const res = await createVideoPlaylist({
1048 url: servers[ 0 ].url, 1048 url: servers[0].url,
1049 token: servers[ 0 ].accessToken, 1049 token: servers[0].accessToken,
1050 playlistAttrs: { 1050 playlistAttrs: {
1051 displayName: 'my super public playlist', 1051 displayName: 'my super public playlist',
1052 privacy: VideoPlaylistPrivacy.PUBLIC, 1052 privacy: VideoPlaylistPrivacy.PUBLIC,
1053 videoChannelId: servers[ 0 ].videoChannel.id 1053 videoChannelId: servers[0].videoChannel.id
1054 } 1054 }
1055 }) 1055 })
1056 const videoPlaylistIds = res.body.videoPlaylist 1056 const videoPlaylistIds = res.body.videoPlaylist
@@ -1062,16 +1062,16 @@ describe('Test video playlists', function () {
1062 } 1062 }
1063 1063
1064 const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE } 1064 const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
1065 await updateVideoPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs }) 1065 await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
1066 1066
1067 await waitJobs(servers) 1067 await waitJobs(servers)
1068 1068
1069 for (const server of [ servers[ 1 ], servers[ 2 ] ]) { 1069 for (const server of [ servers[1], servers[2] ]) {
1070 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404) 1070 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404)
1071 } 1071 }
1072 await getVideoPlaylist(servers[ 0 ].url, videoPlaylistIds.uuid, 401) 1072 await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401)
1073 1073
1074 await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistIds.uuid, 200) 1074 await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200)
1075 }) 1075 })
1076 }) 1076 })
1077 1077
@@ -1080,7 +1080,7 @@ describe('Test video playlists', function () {
1080 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { 1080 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
1081 this.timeout(30000) 1081 this.timeout(30000)
1082 1082
1083 await deleteVideoPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, playlistServer1Id) 1083 await deleteVideoPlaylist(servers[0].url, servers[0].accessToken, playlistServer1Id)
1084 1084
1085 await waitJobs(servers) 1085 await waitJobs(servers)
1086 1086
@@ -1103,15 +1103,15 @@ describe('Test video playlists', function () {
1103 const finder = data => data.find(p => p.displayName === 'my super playlist') 1103 const finder = data => data.find(p => p.displayName === 'my super playlist')
1104 1104
1105 { 1105 {
1106 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) 1106 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
1107 expect(res.body.total).to.equal(3) 1107 expect(res.body.total).to.equal(3)
1108 expect(finder(res.body.data)).to.not.be.undefined 1108 expect(finder(res.body.data)).to.not.be.undefined
1109 } 1109 }
1110 1110
1111 await unfollow(servers[ 2 ].url, servers[ 2 ].accessToken, servers[ 0 ]) 1111 await unfollow(servers[2].url, servers[2].accessToken, servers[0])
1112 1112
1113 { 1113 {
1114 const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) 1114 const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
1115 expect(res.body.total).to.equal(1) 1115 expect(res.body.total).to.equal(1)
1116 1116
1117 expect(finder(res.body.data)).to.be.undefined 1117 expect(finder(res.body.data)).to.be.undefined
@@ -1121,12 +1121,12 @@ describe('Test video playlists', function () {
1121 it('Should delete a channel and put the associated playlist in private mode', async function () { 1121 it('Should delete a channel and put the associated playlist in private mode', async function () {
1122 this.timeout(30000) 1122 this.timeout(30000)
1123 1123
1124 const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'super_channel', displayName: 'super channel' }) 1124 const res = await addVideoChannel(servers[0].url, servers[0].accessToken, { name: 'super_channel', displayName: 'super channel' })
1125 const videoChannelId = res.body.videoChannel.id 1125 const videoChannelId = res.body.videoChannel.id
1126 1126
1127 const res2 = await createVideoPlaylist({ 1127 const res2 = await createVideoPlaylist({
1128 url: servers[ 0 ].url, 1128 url: servers[0].url,
1129 token: servers[ 0 ].accessToken, 1129 token: servers[0].accessToken,
1130 playlistAttrs: { 1130 playlistAttrs: {
1131 displayName: 'channel playlist', 1131 displayName: 'channel playlist',
1132 privacy: VideoPlaylistPrivacy.PUBLIC, 1132 privacy: VideoPlaylistPrivacy.PUBLIC,
@@ -1137,15 +1137,15 @@ describe('Test video playlists', function () {
1137 1137
1138 await waitJobs(servers) 1138 await waitJobs(servers)
1139 1139
1140 await deleteVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, 'super_channel') 1140 await deleteVideoChannel(servers[0].url, servers[0].accessToken, 'super_channel')
1141 1141
1142 await waitJobs(servers) 1142 await waitJobs(servers)
1143 1143
1144 const res3 = await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistUUID) 1144 const res3 = await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistUUID)
1145 expect(res3.body.displayName).to.equal('channel playlist') 1145 expect(res3.body.displayName).to.equal('channel playlist')
1146 expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE) 1146 expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE)
1147 1147
1148 await getVideoPlaylist(servers[ 1 ].url, videoPlaylistUUID, 404) 1148 await getVideoPlaylist(servers[1].url, videoPlaylistUUID, 404)
1149 }) 1149 })
1150 1150
1151 it('Should delete an account and delete its playlists', async function () { 1151 it('Should delete an account and delete its playlists', async function () {
@@ -1153,20 +1153,20 @@ describe('Test video playlists', function () {
1153 1153
1154 const user = { username: 'user_1', password: 'password' } 1154 const user = { username: 'user_1', password: 'password' }
1155 const res = await createUser({ 1155 const res = await createUser({
1156 url: servers[ 0 ].url, 1156 url: servers[0].url,
1157 accessToken: servers[ 0 ].accessToken, 1157 accessToken: servers[0].accessToken,
1158 username: user.username, 1158 username: user.username,
1159 password: user.password 1159 password: user.password
1160 }) 1160 })
1161 1161
1162 const userId = res.body.user.id 1162 const userId = res.body.user.id
1163 const userAccessToken = await userLogin(servers[ 0 ], user) 1163 const userAccessToken = await userLogin(servers[0], user)
1164 1164
1165 const resChannel = await getMyUserInformation(servers[ 0 ].url, userAccessToken) 1165 const resChannel = await getMyUserInformation(servers[0].url, userAccessToken)
1166 const userChannel = (resChannel.body as User).videoChannels[ 0 ] 1166 const userChannel = (resChannel.body as User).videoChannels[0]
1167 1167
1168 await createVideoPlaylist({ 1168 await createVideoPlaylist({
1169 url: servers[ 0 ].url, 1169 url: servers[0].url,
1170 token: userAccessToken, 1170 token: userAccessToken,
1171 playlistAttrs: { 1171 playlistAttrs: {
1172 displayName: 'playlist to be deleted', 1172 displayName: 'playlist to be deleted',
@@ -1180,17 +1180,17 @@ describe('Test video playlists', function () {
1180 const finder = data => data.find(p => p.displayName === 'playlist to be deleted') 1180 const finder = data => data.find(p => p.displayName === 'playlist to be deleted')
1181 1181
1182 { 1182 {
1183 for (const server of [ servers[ 0 ], servers[ 1 ] ]) { 1183 for (const server of [ servers[0], servers[1] ]) {
1184 const res = await getVideoPlaylistsList(server.url, 0, 15) 1184 const res = await getVideoPlaylistsList(server.url, 0, 15)
1185 expect(finder(res.body.data)).to.not.be.undefined 1185 expect(finder(res.body.data)).to.not.be.undefined
1186 } 1186 }
1187 } 1187 }
1188 1188
1189 await removeUser(servers[ 0 ].url, userId, servers[ 0 ].accessToken) 1189 await removeUser(servers[0].url, userId, servers[0].accessToken)
1190 await waitJobs(servers) 1190 await waitJobs(servers)
1191 1191
1192 { 1192 {
1193 for (const server of [ servers[ 0 ], servers[ 1 ] ]) { 1193 for (const server of [ servers[0], servers[1] ]) {
1194 const res = await getVideoPlaylistsList(server.url, 0, 15) 1194 const res = await getVideoPlaylistsList(server.url, 0, 15)
1195 expect(finder(res.body.data)).to.be.undefined 1195 expect(finder(res.body.data)).to.be.undefined
1196 } 1196 }
diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts
index e630ca84a..4bbbb90f3 100644
--- a/server/tests/api/videos/video-privacy.ts
+++ b/server/tests/api/videos/video-privacy.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -6,7 +6,8 @@ import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enu
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
9 getVideosList, getVideosListWithToken, 9 getVideosList,
10 getVideosListWithToken,
10 ServerInfo, 11 ServerInfo,
11 setAccessTokensToServers, 12 setAccessTokensToServers,
12 uploadVideo 13 uploadVideo
@@ -110,7 +111,7 @@ describe('Test video privacy', function () {
110 username: 'hello', 111 username: 'hello',
111 password: 'super password' 112 password: 'super password'
112 } 113 }
113 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) 114 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
114 115
115 anotherUserToken = await userLogin(servers[0], user) 116 anotherUserToken = await userLogin(servers[0], user)
116 await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, 403) 117 await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, 403)
@@ -174,7 +175,7 @@ describe('Test video privacy', function () {
174 privacy: VideoPrivacy.PUBLIC 175 privacy: VideoPrivacy.PUBLIC
175 } 176 }
176 177
177 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, privateVideoId, attribute) 178 await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
178 } 179 }
179 180
180 { 181 {
@@ -182,7 +183,7 @@ describe('Test video privacy', function () {
182 name: 'internal video becomes public', 183 name: 'internal video becomes public',
183 privacy: VideoPrivacy.PUBLIC 184 privacy: VideoPrivacy.PUBLIC
184 } 185 }
185 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, internalVideoId, attribute) 186 await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute)
186 } 187 }
187 188
188 await waitJobs(servers) 189 await waitJobs(servers)
diff --git a/server/tests/api/videos/video-schedule-update.ts b/server/tests/api/videos/video-schedule-update.ts
index 65a8eafb8..204f43611 100644
--- a/server/tests/api/videos/video-schedule-update.ts
+++ b/server/tests/api/videos/video-schedule-update.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -10,7 +10,6 @@ import {
10 getMyVideos, 10 getMyVideos,
11 getVideosList, 11 getVideosList,
12 getVideoWithToken, 12 getVideoWithToken,
13 killallServers,
14 ServerInfo, 13 ServerInfo,
15 setAccessTokensToServers, 14 setAccessTokensToServers,
16 updateVideo, 15 updateVideo,
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts
index 55eb76b3b..3e73ccbfa 100644
--- a/server/tests/api/videos/video-transcoder.ts
+++ b/server/tests/api/videos/video-transcoder.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -56,19 +56,19 @@ describe('Test video transcoding', function () {
56 56
57 for (const server of servers) { 57 for (const server of servers) {
58 const res = await getVideosList(server.url) 58 const res = await getVideosList(server.url)
59 const video = res.body.data[ 0 ] 59 const video = res.body.data[0]
60 60
61 const res2 = await getVideo(server.url, video.id) 61 const res2 = await getVideo(server.url, video.id)
62 const videoDetails = res2.body 62 const videoDetails = res2.body
63 expect(videoDetails.files).to.have.lengthOf(1) 63 expect(videoDetails.files).to.have.lengthOf(1)
64 64
65 const magnetUri = videoDetails.files[ 0 ].magnetUri 65 const magnetUri = videoDetails.files[0].magnetUri
66 expect(magnetUri).to.match(/\.webm/) 66 expect(magnetUri).to.match(/\.webm/)
67 67
68 const torrent = await webtorrentAdd(magnetUri, true) 68 const torrent = await webtorrentAdd(magnetUri, true)
69 expect(torrent.files).to.be.an('array') 69 expect(torrent.files).to.be.an('array')
70 expect(torrent.files.length).to.equal(1) 70 expect(torrent.files.length).to.equal(1)
71 expect(torrent.files[ 0 ].path).match(/\.webm$/) 71 expect(torrent.files[0].path).match(/\.webm$/)
72 } 72 }
73 }) 73 })
74 74
@@ -93,13 +93,13 @@ describe('Test video transcoding', function () {
93 93
94 expect(videoDetails.files).to.have.lengthOf(4) 94 expect(videoDetails.files).to.have.lengthOf(4)
95 95
96 const magnetUri = videoDetails.files[ 0 ].magnetUri 96 const magnetUri = videoDetails.files[0].magnetUri
97 expect(magnetUri).to.match(/\.mp4/) 97 expect(magnetUri).to.match(/\.mp4/)
98 98
99 const torrent = await webtorrentAdd(magnetUri, true) 99 const torrent = await webtorrentAdd(magnetUri, true)
100 expect(torrent.files).to.be.an('array') 100 expect(torrent.files).to.be.an('array')
101 expect(torrent.files.length).to.equal(1) 101 expect(torrent.files.length).to.equal(1)
102 expect(torrent.files[ 0 ].path).match(/\.mp4$/) 102 expect(torrent.files[0].path).match(/\.mp4$/)
103 } 103 }
104 }) 104 })
105 105
@@ -127,8 +127,8 @@ describe('Test video transcoding', function () {
127 const probe = await audio.get(path) 127 const probe = await audio.get(path)
128 128
129 if (probe.audioStream) { 129 if (probe.audioStream) {
130 expect(probe.audioStream[ 'codec_name' ]).to.be.equal('aac') 130 expect(probe.audioStream['codec_name']).to.be.equal('aac')
131 expect(probe.audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000) 131 expect(probe.audioStream['bit_rate']).to.be.at.most(384 * 8000)
132 } else { 132 } else {
133 this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) 133 this.fail('Could not retrieve the audio stream on ' + probe.absolutePath)
134 } 134 }
@@ -212,10 +212,10 @@ describe('Test video transcoding', function () {
212 const videoDetails: VideoDetails = res2.body 212 const videoDetails: VideoDetails = res2.body
213 213
214 expect(videoDetails.files).to.have.lengthOf(4) 214 expect(videoDetails.files).to.have.lengthOf(4)
215 expect(videoDetails.files[ 0 ].fps).to.be.above(58).and.below(62) 215 expect(videoDetails.files[0].fps).to.be.above(58).and.below(62)
216 expect(videoDetails.files[ 1 ].fps).to.be.below(31) 216 expect(videoDetails.files[1].fps).to.be.below(31)
217 expect(videoDetails.files[ 2 ].fps).to.be.below(31) 217 expect(videoDetails.files[2].fps).to.be.below(31)
218 expect(videoDetails.files[ 3 ].fps).to.be.below(31) 218 expect(videoDetails.files[3].fps).to.be.below(31)
219 219
220 for (const resolution of [ '240', '360', '480' ]) { 220 for (const resolution of [ '240', '360', '480' ]) {
221 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') 221 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
@@ -241,11 +241,11 @@ describe('Test video transcoding', function () {
241 fixture: 'video_short1.webm', 241 fixture: 'video_short1.webm',
242 waitTranscoding: true 242 waitTranscoding: true
243 } 243 }
244 const resVideo = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes) 244 const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
245 const videoId = resVideo.body.video.uuid 245 const videoId = resVideo.body.video.uuid
246 246
247 // Should be in transcode state 247 // Should be in transcode state
248 const { body } = await getVideo(servers[ 1 ].url, videoId) 248 const { body } = await getVideo(servers[1].url, videoId)
249 expect(body.name).to.equal('waiting video') 249 expect(body.name).to.equal('waiting video')
250 expect(body.state.id).to.equal(VideoState.TO_TRANSCODE) 250 expect(body.state.id).to.equal(VideoState.TO_TRANSCODE)
251 expect(body.state.label).to.equal('To transcode') 251 expect(body.state.label).to.equal('To transcode')
@@ -311,7 +311,7 @@ describe('Test video transcoding', function () {
311 311
312 const video = res.body.data.find(v => v.name === videoAttributes.name) 312 const video = res.body.data.find(v => v.name === videoAttributes.name)
313 313
314 for (const resolution of ['240', '360', '480', '720', '1080']) { 314 for (const resolution of [ '240', '360', '480', '720', '1080' ]) {
315 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') 315 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
316 const bitrate = await getVideoFileBitrate(path) 316 const bitrate = await getVideoFileBitrate(path)
317 const fps = await getVideoFileFPS(path) 317 const fps = await getVideoFileFPS(path)
@@ -341,7 +341,7 @@ describe('Test video transcoding', function () {
341 fixture 341 fixture
342 } 342 }
343 343
344 await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes) 344 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
345 345
346 await waitJobs(servers) 346 await waitJobs(servers)
347 347
@@ -354,7 +354,7 @@ describe('Test video transcoding', function () {
354 354
355 expect(videoDetails.files).to.have.lengthOf(4) 355 expect(videoDetails.files).to.have.lengthOf(4)
356 356
357 const magnetUri = videoDetails.files[ 0 ].magnetUri 357 const magnetUri = videoDetails.files[0].magnetUri
358 expect(magnetUri).to.contain('.mp4') 358 expect(magnetUri).to.contain('.mp4')
359 } 359 }
360 } 360 }
@@ -371,7 +371,7 @@ describe('Test video transcoding', function () {
371 this.timeout(60000) 371 this.timeout(60000)
372 372
373 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } 373 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
374 await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) 374 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg)
375 375
376 await waitJobs(servers) 376 await waitJobs(servers)
377 377
@@ -387,7 +387,7 @@ describe('Test video transcoding', function () {
387 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) 387 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
388 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) 388 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
389 389
390 const magnetUri = videoDetails.files[ 0 ].magnetUri 390 const magnetUri = videoDetails.files[0].magnetUri
391 expect(magnetUri).to.contain('.mp4') 391 expect(magnetUri).to.contain('.mp4')
392 } 392 }
393 }) 393 })
@@ -396,7 +396,7 @@ describe('Test video transcoding', function () {
396 this.timeout(60000) 396 this.timeout(60000)
397 397
398 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } 398 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' }
399 await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) 399 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg)
400 400
401 await waitJobs(servers) 401 await waitJobs(servers)
402 402
@@ -412,7 +412,7 @@ describe('Test video transcoding', function () {
412 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) 412 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
413 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) 413 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
414 414
415 const magnetUri = videoDetails.files[ 0 ].magnetUri 415 const magnetUri = videoDetails.files[0].magnetUri
416 expect(magnetUri).to.contain('.mp4') 416 expect(magnetUri).to.contain('.mp4')
417 } 417 }
418 }) 418 })
@@ -445,13 +445,13 @@ describe('Test video transcoding', function () {
445 const video = res.body.data.find(v => v.name === videoAttributes.name) 445 const video = res.body.data.find(v => v.name === videoAttributes.name)
446 446
447 { 447 {
448 const path = join(root(), 'test' + servers[ 1 ].internalServerNumber, 'videos', video.uuid + '-240.mp4') 448 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
449 const fps = await getVideoFileFPS(path) 449 const fps = await getVideoFileFPS(path)
450 expect(fps).to.be.equal(25) 450 expect(fps).to.be.equal(25)
451 } 451 }
452 452
453 { 453 {
454 const path = join(root(), 'test' + servers[ 1 ].internalServerNumber, 'videos', video.uuid + '-720.mp4') 454 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-720.mp4')
455 const fps = await getVideoFileFPS(path) 455 const fps = await getVideoFileFPS(path)
456 expect(fps).to.be.equal(59) 456 expect(fps).to.be.equal(59)
457 } 457 }
diff --git a/server/tests/api/videos/videos-filter.ts b/server/tests/api/videos/videos-filter.ts
index e1e65260f..95e12e43c 100644
--- a/server/tests/api/videos/videos-filter.ts
+++ b/server/tests/api/videos/videos-filter.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -7,8 +7,6 @@ import {
7 createUser, 7 createUser,
8 doubleFollow, 8 doubleFollow,
9 flushAndRunMultipleServers, 9 flushAndRunMultipleServers,
10 flushTests,
11 killallServers,
12 makeGetRequest, 10 makeGetRequest,
13 ServerInfo, 11 ServerInfo,
14 setAccessTokensToServers, 12 setAccessTokensToServers,
@@ -98,7 +96,7 @@ describe('Test videos filter validator', function () {
98 const namesResults = await getVideosNames(server, server.accessToken, 'local') 96 const namesResults = await getVideosNames(server, server.accessToken, 'local')
99 for (const names of namesResults) { 97 for (const names of namesResults) {
100 expect(names).to.have.lengthOf(1) 98 expect(names).to.have.lengthOf(1)
101 expect(names[ 0 ]).to.equal('public ' + server.serverNumber) 99 expect(names[0]).to.equal('public ' + server.serverNumber)
102 } 100 }
103 } 101 }
104 }) 102 })
@@ -111,9 +109,9 @@ describe('Test videos filter validator', function () {
111 for (const names of namesResults) { 109 for (const names of namesResults) {
112 expect(names).to.have.lengthOf(3) 110 expect(names).to.have.lengthOf(3)
113 111
114 expect(names[ 0 ]).to.equal('public ' + server.serverNumber) 112 expect(names[0]).to.equal('public ' + server.serverNumber)
115 expect(names[ 1 ]).to.equal('unlisted ' + server.serverNumber) 113 expect(names[1]).to.equal('unlisted ' + server.serverNumber)
116 expect(names[ 2 ]).to.equal('private ' + server.serverNumber) 114 expect(names[2]).to.equal('private ' + server.serverNumber)
117 } 115 }
118 } 116 }
119 } 117 }
diff --git a/server/tests/api/videos/videos-history.ts b/server/tests/api/videos/videos-history.ts
index c7e55c1ab..6f90e9a57 100644
--- a/server/tests/api/videos/videos-history.ts
+++ b/server/tests/api/videos/videos-history.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/api/videos/videos-overview.ts b/server/tests/api/videos/videos-overview.ts
index 975a5c87a..ca08ab5b1 100644
--- a/server/tests/api/videos/videos-overview.ts
+++ b/server/tests/api/videos/videos-overview.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/api/videos/videos-views-cleaner.ts b/server/tests/api/videos/videos-views-cleaner.ts
index fbddd40f4..d063d7973 100644
--- a/server/tests/api/videos/videos-views-cleaner.ts
+++ b/server/tests/api/videos/videos-views-cleaner.ts
@@ -1,20 +1,22 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 cleanupTests,
7 closeAllSequelize,
8 countVideoViewsOf,
9 doubleFollow,
6 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
7 flushTests,
8 killallServers, 11 killallServers,
9 reRunServer, 12 reRunServer,
10 flushAndRunServer,
11 ServerInfo, 13 ServerInfo,
12 setAccessTokensToServers, 14 setAccessTokensToServers,
13 uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests, closeAllSequelize 15 uploadVideoAndGetId,
16 viewVideo,
17 wait,
18 waitJobs
14} from '../../../../shared/extra-utils' 19} from '../../../../shared/extra-utils'
15import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews'
16import { VideosOverview } from '../../../../shared/models/overviews'
17import { listMyVideosHistory } from '../../../../shared/extra-utils/videos/video-history'
18 20
19const expect = chai.expect 21const expect = chai.expect
20 22
diff --git a/server/tests/cli/create-import-video-file-job.ts b/server/tests/cli/create-import-video-file-job.ts
index aca3216bb..dac049fe4 100644
--- a/server/tests/cli/create-import-video-file-job.ts
+++ b/server/tests/cli/create-import-video-file-job.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
@@ -71,7 +71,7 @@ describe('Test create import video jobs', function () {
71 const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body 71 const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body
72 72
73 expect(videoDetail.files).to.have.lengthOf(2) 73 expect(videoDetail.files).to.have.lengthOf(2)
74 const [originalVideo, transcodedVideo] = videoDetail.files 74 const [ originalVideo, transcodedVideo ] = videoDetail.files
75 assertVideoProperties(originalVideo, 720, 'webm', 218910) 75 assertVideoProperties(originalVideo, 720, 'webm', 218910)
76 assertVideoProperties(transcodedVideo, 480, 'webm', 69217) 76 assertVideoProperties(transcodedVideo, 480, 'webm', 69217)
77 77
@@ -95,7 +95,7 @@ describe('Test create import video jobs', function () {
95 const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body 95 const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body
96 96
97 expect(videoDetail.files).to.have.lengthOf(4) 97 expect(videoDetail.files).to.have.lengthOf(4)
98 const [originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240] = videoDetail.files 98 const [ originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240 ] = videoDetail.files
99 assertVideoProperties(originalVideo, 720, 'ogv', 140849) 99 assertVideoProperties(originalVideo, 720, 'ogv', 140849)
100 assertVideoProperties(transcodedVideo420, 480, 'mp4') 100 assertVideoProperties(transcodedVideo420, 480, 'mp4')
101 assertVideoProperties(transcodedVideo320, 360, 'mp4') 101 assertVideoProperties(transcodedVideo320, 360, 'mp4')
diff --git a/server/tests/cli/create-transcoding-job.ts b/server/tests/cli/create-transcoding-job.ts
index 7897ff1b3..997a9a1fd 100644
--- a/server/tests/cli/create-transcoding-job.ts
+++ b/server/tests/cli/create-transcoding-job.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
@@ -8,14 +8,13 @@ import {
8 doubleFollow, 8 doubleFollow,
9 execCLI, 9 execCLI,
10 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
11 flushTests,
12 getEnvCli, 11 getEnvCli,
13 getVideo, 12 getVideo,
14 getVideosList, 13 getVideosList,
15 killallServers,
16 ServerInfo, 14 ServerInfo,
17 setAccessTokensToServers, updateCustomSubConfig, 15 setAccessTokensToServers,
18 uploadVideo, wait 16 updateCustomSubConfig,
17 uploadVideo
19} from '../../../shared/extra-utils' 18} from '../../../shared/extra-utils'
20import { waitJobs } from '../../../shared/extra-utils/server/jobs' 19import { waitJobs } from '../../../shared/extra-utils/server/jobs'
21 20
@@ -23,7 +22,7 @@ const expect = chai.expect
23 22
24describe('Test create transcoding jobs', function () { 23describe('Test create transcoding jobs', function () {
25 let servers: ServerInfo[] = [] 24 let servers: ServerInfo[] = []
26 let videosUUID: string[] = [] 25 const videosUUID: string[] = []
27 26
28 const config = { 27 const config = {
29 transcoding: { 28 transcoding: {
@@ -54,7 +53,7 @@ describe('Test create transcoding jobs', function () {
54 await doubleFollow(servers[0], servers[1]) 53 await doubleFollow(servers[0], servers[1])
55 54
56 for (let i = 1; i <= 5; i++) { 55 for (let i = 1; i <= 5; i++) {
57 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video' + i }) 56 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' + i })
58 videosUUID.push(res.body.video.uuid) 57 videosUUID.push(res.body.video.uuid)
59 } 58 }
60 59
@@ -90,7 +89,7 @@ describe('Test create transcoding jobs', function () {
90 const res = await getVideosList(server.url) 89 const res = await getVideosList(server.url)
91 const videos = res.body.data 90 const videos = res.body.data
92 91
93 let infoHashes: { [ id: number ]: string } 92 let infoHashes: { [id: number]: string }
94 93
95 for (const video of videos) { 94 for (const video of videos) {
96 const res2 = await getVideo(server.url, video.uuid) 95 const res2 = await getVideo(server.url, video.uuid)
diff --git a/server/tests/cli/optimize-old-videos.ts b/server/tests/cli/optimize-old-videos.ts
index de5d672f5..e2e13598f 100644
--- a/server/tests/cli/optimize-old-videos.ts
+++ b/server/tests/cli/optimize-old-videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
@@ -28,7 +28,9 @@ const expect = chai.expect
28 28
29describe('Test optimize old videos', function () { 29describe('Test optimize old videos', function () {
30 let servers: ServerInfo[] = [] 30 let servers: ServerInfo[] = []
31 // eslint-disable-next-line @typescript-eslint/no-unused-vars
31 let video1UUID: string 32 let video1UUID: string
33 // eslint-disable-next-line @typescript-eslint/no-unused-vars
32 let video2UUID: string 34 let video2UUID: string
33 35
34 before(async function () { 36 before(async function () {
diff --git a/server/tests/cli/peertube.ts b/server/tests/cli/peertube.ts
index 15b6755f2..27fbde02d 100644
--- a/server/tests/cli/peertube.ts
+++ b/server/tests/cli/peertube.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { expect } from 'chai' 4import { expect } from 'chai'
@@ -6,15 +6,18 @@ import {
6 addVideoChannel, 6 addVideoChannel,
7 buildAbsoluteFixturePath, 7 buildAbsoluteFixturePath,
8 cleanupTests, 8 cleanupTests,
9 createUser, doubleFollow, 9 createUser,
10 doubleFollow,
10 execCLI, 11 execCLI,
11 flushAndRunServer, 12 flushAndRunServer,
12 getEnvCli, getLocalIdByUUID, 13 getEnvCli,
14 getLocalIdByUUID,
13 getVideo, 15 getVideo,
14 getVideosList, 16 getVideosList,
15 getVideosListWithToken, removeVideo, 17 removeVideo,
16 ServerInfo, 18 ServerInfo,
17 setAccessTokensToServers, uploadVideo, uploadVideoAndGetId, 19 setAccessTokensToServers,
20 uploadVideoAndGetId,
18 userLogin, 21 userLogin,
19 waitJobs 22 waitJobs
20} from '../../../shared/extra-utils' 23} from '../../../shared/extra-utils'
@@ -101,7 +104,7 @@ describe('Test CLI wrapper', function () {
101 104
102 const videos: Video[] = res.body.data 105 const videos: Video[] = res.body.data
103 106
104 const video: VideoDetails = (await getVideo(server.url, videos[ 0 ].uuid)).body 107 const video: VideoDetails = (await getVideo(server.url, videos[0].uuid)).body
105 108
106 expect(video.name).to.equal('test upload') 109 expect(video.name).to.equal('test upload')
107 expect(video.support).to.equal('support_text') 110 expect(video.support).to.equal('support_text')
@@ -250,7 +253,7 @@ describe('Test CLI wrapper', function () {
250 { 253 {
251 const env = getEnvCli(server) 254 const env = getEnvCli(server)
252 255
253 const params = `list-my-redundancies` 256 const params = 'list-my-redundancies'
254 const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`) 257 const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`)
255 258
256 expect(stdout).to.contain('super video') 259 expect(stdout).to.contain('super video')
@@ -271,7 +274,7 @@ describe('Test CLI wrapper', function () {
271 274
272 { 275 {
273 const env = getEnvCli(server) 276 const env = getEnvCli(server)
274 const params = `list-my-redundancies` 277 const params = 'list-my-redundancies'
275 const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`) 278 const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`)
276 279
277 expect(stdout).to.not.contain('super video') 280 expect(stdout).to.not.contain('super video')
diff --git a/server/tests/cli/plugins.ts b/server/tests/cli/plugins.ts
index a5257d671..7f19f14b7 100644
--- a/server/tests/cli/plugins.ts
+++ b/server/tests/cli/plugins.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { 4import {
diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts
index 144e67c44..304c8ca56 100644
--- a/server/tests/cli/prune-storage.ts
+++ b/server/tests/cli/prune-storage.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
@@ -11,9 +11,11 @@ import {
11 execCLI, 11 execCLI,
12 flushAndRunMultipleServers, 12 flushAndRunMultipleServers,
13 getAccount, 13 getAccount,
14 getEnvCli, makeGetRequest, makeRawRequest, 14 getEnvCli,
15 makeGetRequest,
15 ServerInfo, 16 ServerInfo,
16 setAccessTokensToServers, setDefaultVideoChannel, 17 setAccessTokensToServers,
18 setDefaultVideoChannel,
17 updateMyAvatar, 19 updateMyAvatar,
18 uploadVideo, 20 uploadVideo,
19 wait 21 wait
@@ -22,7 +24,6 @@ import { Account, VideoPlaylistPrivacy } from '../../../shared/models'
22import { createFile, readdir } from 'fs-extra' 24import { createFile, readdir } from 'fs-extra'
23import * as uuidv4 from 'uuid/v4' 25import * as uuidv4 from 'uuid/v4'
24import { join } from 'path' 26import { join } from 'path'
25import * as request from 'supertest'
26 27
27const expect = chai.expect 28const expect = chai.expect
28 29
@@ -61,7 +62,7 @@ async function assertCountAreOkay (servers: ServerInfo[]) {
61 62
62describe('Test prune storage scripts', function () { 63describe('Test prune storage scripts', function () {
63 let servers: ServerInfo[] 64 let servers: ServerInfo[]
64 const badNames: { [ directory: string ]: string[] } = {} 65 const badNames: { [directory: string]: string[] } = {}
65 66
66 before(async function () { 67 before(async function () {
67 this.timeout(120000) 68 this.timeout(120000)
@@ -92,20 +93,20 @@ describe('Test prune storage scripts', function () {
92 93
93 // Lazy load the remote avatar 94 // Lazy load the remote avatar
94 { 95 {
95 const res = await getAccount(servers[ 0 ].url, 'root@localhost:' + servers[ 1 ].port) 96 const res = await getAccount(servers[0].url, 'root@localhost:' + servers[1].port)
96 const account: Account = res.body 97 const account: Account = res.body
97 await makeGetRequest({ 98 await makeGetRequest({
98 url: servers[ 0 ].url, 99 url: servers[0].url,
99 path: account.avatar.path, 100 path: account.avatar.path,
100 statusCodeExpected: 200 101 statusCodeExpected: 200
101 }) 102 })
102 } 103 }
103 104
104 { 105 {
105 const res = await getAccount(servers[ 1 ].url, 'root@localhost:' + servers[ 0 ].port) 106 const res = await getAccount(servers[1].url, 'root@localhost:' + servers[0].port)
106 const account: Account = res.body 107 const account: Account = res.body
107 await makeGetRequest({ 108 await makeGetRequest({
108 url: servers[ 1 ].url, 109 url: servers[1].url,
109 path: account.avatar.path, 110 path: account.avatar.path,
110 statusCodeExpected: 200 111 statusCodeExpected: 200
111 }) 112 })
diff --git a/server/tests/cli/update-host.ts b/server/tests/cli/update-host.ts
index 55c43b32f..2070f16f5 100644
--- a/server/tests/cli/update-host.ts
+++ b/server/tests/cli/update-host.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
diff --git a/server/tests/client.ts b/server/tests/client.ts
index 778dcd08e..d61724e51 100644
--- a/server/tests/client.ts
+++ b/server/tests/client.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts
index 437470327..4510177cc 100644
--- a/server/tests/feeds/feeds.ts
+++ b/server/tests/feeds/feeds.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -51,7 +51,7 @@ describe('Test syndication feeds', () => {
51 51
52 { 52 {
53 const attr = { username: 'john', password: 'password' } 53 const attr = { username: 'john', password: 'password' }
54 await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: attr.username, password: attr.password }) 54 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: attr.username, password: attr.password })
55 userAccessToken = await userLogin(servers[0], attr) 55 userAccessToken = await userLogin(servers[0], attr)
56 56
57 const res = await getMyUserInformation(servers[0].url, userAccessToken) 57 const res = await getMyUserInformation(servers[0].url, userAccessToken)
@@ -61,7 +61,7 @@ describe('Test syndication feeds', () => {
61 } 61 }
62 62
63 { 63 {
64 await uploadVideo(servers[ 0 ].url, userAccessToken, { name: 'user video' }) 64 await uploadVideo(servers[0].url, userAccessToken, { name: 'user video' })
65 } 65 }
66 66
67 { 67 {
@@ -70,11 +70,11 @@ describe('Test syndication feeds', () => {
70 description: 'my super description for server 1', 70 description: 'my super description for server 1',
71 fixture: 'video_short.webm' 71 fixture: 'video_short.webm'
72 } 72 }
73 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) 73 const res = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
74 const videoId = res.body.video.id 74 const videoId = res.body.video.id
75 75
76 await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, 'super comment 1') 76 await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoId, 'super comment 1')
77 await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, 'super comment 2') 77 await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoId, 'super comment 2')
78 } 78 }
79 79
80 await waitJobs(servers) 80 await waitJobs(servers)
@@ -84,18 +84,18 @@ describe('Test syndication feeds', () => {
84 84
85 it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () { 85 it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () {
86 for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { 86 for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) {
87 const rss = await getXMLfeed(servers[ 0 ].url, feed) 87 const rss = await getXMLfeed(servers[0].url, feed)
88 expect(rss.text).xml.to.be.valid() 88 expect(rss.text).xml.to.be.valid()
89 89
90 const atom = await getXMLfeed(servers[ 0 ].url, feed, 'atom') 90 const atom = await getXMLfeed(servers[0].url, feed, 'atom')
91 expect(atom.text).xml.to.be.valid() 91 expect(atom.text).xml.to.be.valid()
92 } 92 }
93 }) 93 })
94 94
95 it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { 95 it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () {
96 for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { 96 for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) {
97 const json = await getJSONfeed(servers[ 0 ].url, feed) 97 const json = await getJSONfeed(servers[0].url, feed)
98 expect(JSON.parse(json.text)).to.be.jsonSchema({ 'type': 'object' }) 98 expect(JSON.parse(json.text)).to.be.jsonSchema({ type: 'object' })
99 } 99 }
100 }) 100 })
101 }) 101 })
@@ -118,11 +118,11 @@ describe('Test syndication feeds', () => {
118 const json = await getJSONfeed(server.url, 'videos') 118 const json = await getJSONfeed(server.url, 'videos')
119 const jsonObj = JSON.parse(json.text) 119 const jsonObj = JSON.parse(json.text)
120 expect(jsonObj.items.length).to.be.equal(2) 120 expect(jsonObj.items.length).to.be.equal(2)
121 expect(jsonObj.items[ 0 ].attachments).to.exist 121 expect(jsonObj.items[0].attachments).to.exist
122 expect(jsonObj.items[ 0 ].attachments.length).to.be.eq(1) 122 expect(jsonObj.items[0].attachments.length).to.be.eq(1)
123 expect(jsonObj.items[ 0 ].attachments[ 0 ].mime_type).to.be.eq('application/x-bittorrent') 123 expect(jsonObj.items[0].attachments[0].mime_type).to.be.eq('application/x-bittorrent')
124 expect(jsonObj.items[ 0 ].attachments[ 0 ].size_in_bytes).to.be.eq(218910) 124 expect(jsonObj.items[0].attachments[0].size_in_bytes).to.be.eq(218910)
125 expect(jsonObj.items[ 0 ].attachments[ 0 ].url).to.contain('720.torrent') 125 expect(jsonObj.items[0].attachments[0].url).to.contain('720.torrent')
126 } 126 }
127 }) 127 })
128 128
@@ -131,16 +131,16 @@ describe('Test syndication feeds', () => {
131 const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId }) 131 const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId })
132 const jsonObj = JSON.parse(json.text) 132 const jsonObj = JSON.parse(json.text)
133 expect(jsonObj.items.length).to.be.equal(1) 133 expect(jsonObj.items.length).to.be.equal(1)
134 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') 134 expect(jsonObj.items[0].title).to.equal('my super name for server 1')
135 expect(jsonObj.items[ 0 ].author.name).to.equal('root') 135 expect(jsonObj.items[0].author.name).to.equal('root')
136 } 136 }
137 137
138 { 138 {
139 const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId }) 139 const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId })
140 const jsonObj = JSON.parse(json.text) 140 const jsonObj = JSON.parse(json.text)
141 expect(jsonObj.items.length).to.be.equal(1) 141 expect(jsonObj.items.length).to.be.equal(1)
142 expect(jsonObj.items[ 0 ].title).to.equal('user video') 142 expect(jsonObj.items[0].title).to.equal('user video')
143 expect(jsonObj.items[ 0 ].author.name).to.equal('john') 143 expect(jsonObj.items[0].author.name).to.equal('john')
144 } 144 }
145 145
146 for (const server of servers) { 146 for (const server of servers) {
@@ -148,14 +148,14 @@ describe('Test syndication feeds', () => {
148 const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port }) 148 const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port })
149 const jsonObj = JSON.parse(json.text) 149 const jsonObj = JSON.parse(json.text)
150 expect(jsonObj.items.length).to.be.equal(1) 150 expect(jsonObj.items.length).to.be.equal(1)
151 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') 151 expect(jsonObj.items[0].title).to.equal('my super name for server 1')
152 } 152 }
153 153
154 { 154 {
155 const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port }) 155 const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port })
156 const jsonObj = JSON.parse(json.text) 156 const jsonObj = JSON.parse(json.text)
157 expect(jsonObj.items.length).to.be.equal(1) 157 expect(jsonObj.items.length).to.be.equal(1)
158 expect(jsonObj.items[ 0 ].title).to.equal('user video') 158 expect(jsonObj.items[0].title).to.equal('user video')
159 } 159 }
160 } 160 }
161 }) 161 })
@@ -165,16 +165,16 @@ describe('Test syndication feeds', () => {
165 const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId }) 165 const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId })
166 const jsonObj = JSON.parse(json.text) 166 const jsonObj = JSON.parse(json.text)
167 expect(jsonObj.items.length).to.be.equal(1) 167 expect(jsonObj.items.length).to.be.equal(1)
168 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') 168 expect(jsonObj.items[0].title).to.equal('my super name for server 1')
169 expect(jsonObj.items[ 0 ].author.name).to.equal('root') 169 expect(jsonObj.items[0].author.name).to.equal('root')
170 } 170 }
171 171
172 { 172 {
173 const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId }) 173 const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId })
174 const jsonObj = JSON.parse(json.text) 174 const jsonObj = JSON.parse(json.text)
175 expect(jsonObj.items.length).to.be.equal(1) 175 expect(jsonObj.items.length).to.be.equal(1)
176 expect(jsonObj.items[ 0 ].title).to.equal('user video') 176 expect(jsonObj.items[0].title).to.equal('user video')
177 expect(jsonObj.items[ 0 ].author.name).to.equal('john') 177 expect(jsonObj.items[0].author.name).to.equal('john')
178 } 178 }
179 179
180 for (const server of servers) { 180 for (const server of servers) {
@@ -182,14 +182,14 @@ describe('Test syndication feeds', () => {
182 const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port }) 182 const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port })
183 const jsonObj = JSON.parse(json.text) 183 const jsonObj = JSON.parse(json.text)
184 expect(jsonObj.items.length).to.be.equal(1) 184 expect(jsonObj.items.length).to.be.equal(1)
185 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') 185 expect(jsonObj.items[0].title).to.equal('my super name for server 1')
186 } 186 }
187 187
188 { 188 {
189 const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port }) 189 const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port })
190 const jsonObj = JSON.parse(json.text) 190 const jsonObj = JSON.parse(json.text)
191 expect(jsonObj.items.length).to.be.equal(1) 191 expect(jsonObj.items.length).to.be.equal(1)
192 expect(jsonObj.items[ 0 ].title).to.equal('user video') 192 expect(jsonObj.items[0].title).to.equal('user video')
193 } 193 }
194 } 194 }
195 }) 195 })
@@ -202,8 +202,8 @@ describe('Test syndication feeds', () => {
202 202
203 const jsonObj = JSON.parse(json.text) 203 const jsonObj = JSON.parse(json.text)
204 expect(jsonObj.items.length).to.be.equal(2) 204 expect(jsonObj.items.length).to.be.equal(2)
205 expect(jsonObj.items[ 0 ].html_content).to.equal('super comment 2') 205 expect(jsonObj.items[0].html_content).to.equal('super comment 2')
206 expect(jsonObj.items[ 1 ].html_content).to.equal('super comment 1') 206 expect(jsonObj.items[1].html_content).to.equal('super comment 1')
207 } 207 }
208 }) 208 })
209 }) 209 })
diff --git a/server/tests/helpers/comment-model.ts b/server/tests/helpers/comment-model.ts
index ebfd779e1..4c51b7000 100644
--- a/server/tests/helpers/comment-model.ts
+++ b/server/tests/helpers/comment-model.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
@@ -20,7 +20,7 @@ describe('Comment model', function () {
20 20
21 comment.text = '@florian @jean@localhost:9000 @flo @another@localhost:9000 @flo2@jean.com hello ' + 21 comment.text = '@florian @jean@localhost:9000 @flo @another@localhost:9000 @flo2@jean.com hello ' +
22 'email@localhost:9000 coucou.com no? @chocobozzz @chocobozzz @end' 22 'email@localhost:9000 coucou.com no? @chocobozzz @chocobozzz @end'
23 const result = comment.extractMentions().sort() 23 const result = comment.extractMentions().sort((a, b) => a.localeCompare(b))
24 24
25 expect(result).to.deep.equal([ 'another', 'chocobozzz', 'end', 'flo', 'florian', 'jean' ]) 25 expect(result).to.deep.equal([ 'another', 'chocobozzz', 'end', 'flo', 'florian', 'jean' ])
26 }) 26 })
diff --git a/server/tests/helpers/core-utils.ts b/server/tests/helpers/core-utils.ts
index 31fc6dd7c..c028b316d 100644
--- a/server/tests/helpers/core-utils.ts
+++ b/server/tests/helpers/core-utils.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
diff --git a/server/tests/helpers/request.ts b/server/tests/helpers/request.ts
index a754bc6e2..f8b2d599b 100644
--- a/server/tests/helpers/request.ts
+++ b/server/tests/helpers/request.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' 4import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
diff --git a/server/tests/misc-endpoints.ts b/server/tests/misc-endpoints.ts
index ab2dd3a0f..32b035c9e 100644
--- a/server/tests/misc-endpoints.ts
+++ b/server/tests/misc-endpoints.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts
index 510ec3151..ca57a4b51 100644
--- a/server/tests/plugins/action-hooks.ts
+++ b/server/tests/plugins/action-hooks.ts
@@ -1,6 +1,5 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { 4import {
6 cleanupTests, 5 cleanupTests,
@@ -17,18 +16,18 @@ import {
17 createUser, 16 createUser,
18 deleteVideoComment, 17 deleteVideoComment,
19 getPluginTestPath, 18 getPluginTestPath,
20 installPlugin, login, 19 installPlugin,
21 registerUser, removeUser, 20 registerUser,
21 removeUser,
22 setAccessTokensToServers, 22 setAccessTokensToServers,
23 unblockUser, updateUser, 23 unblockUser,
24 updateUser,
24 updateVideo, 25 updateVideo,
25 uploadVideo, 26 uploadVideo,
26 viewVideo, 27 userLogin,
27 userLogin 28 viewVideo
28} from '../../../shared/extra-utils' 29} from '../../../shared/extra-utils'
29 30
30const expect = chai.expect
31
32describe('Test plugin action hooks', function () { 31describe('Test plugin action hooks', function () {
33 let servers: ServerInfo[] 32 let servers: ServerInfo[]
34 let videoUUID: string 33 let videoUUID: string
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts
index 6a5ea4641..6c1fd40ba 100644
--- a/server/tests/plugins/filter-hooks.ts
+++ b/server/tests/plugins/filter-hooks.ts
@@ -1,34 +1,27 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import { cleanupTests, flushAndRunMultipleServers, ServerInfo } from '../../../shared/extra-utils/server/servers'
6 cleanupTests,
7 flushAndRunMultipleServers,
8 flushAndRunServer, killallServers, reRunServer,
9 ServerInfo,
10 waitUntilLog
11} from '../../../shared/extra-utils/server/servers'
12import { 6import {
13 addVideoCommentReply, 7 addVideoCommentReply,
14 addVideoCommentThread, 8 addVideoCommentThread,
15 deleteVideoComment, 9 doubleFollow,
10 getConfig,
16 getPluginTestPath, 11 getPluginTestPath,
17 getVideosList,
18 installPlugin,
19 removeVideo,
20 setAccessTokensToServers,
21 updateVideo,
22 uploadVideo,
23 viewVideo,
24 getVideosListPagination,
25 getVideo, 12 getVideo,
26 getVideoCommentThreads, 13 getVideoCommentThreads,
14 getVideosList,
15 getVideosListPagination,
27 getVideoThreadComments, 16 getVideoThreadComments,
28 getVideoWithToken, 17 getVideoWithToken,
18 installPlugin,
19 registerUser,
20 setAccessTokensToServers,
29 setDefaultVideoChannel, 21 setDefaultVideoChannel,
30 waitJobs, 22 updateVideo,
31 doubleFollow, getConfig, registerUser 23 uploadVideo,
24 waitJobs
32} from '../../../shared/extra-utils' 25} from '../../../shared/extra-utils'
33import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' 26import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
34import { VideoDetails } from '../../../shared/models/videos' 27import { VideoDetails } from '../../../shared/models/videos'
@@ -140,7 +133,7 @@ describe('Test plugin filter hooks', function () {
140 } 133 }
141 134
142 it('Should blacklist on upload', async function () { 135 it('Should blacklist on upload', async function () {
143 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video please blacklist me' }) 136 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video please blacklist me' })
144 await checkIsBlacklisted(res, true) 137 await checkIsBlacklisted(res, true)
145 }) 138 })
146 139
@@ -157,18 +150,18 @@ describe('Test plugin filter hooks', function () {
157 }) 150 })
158 151
159 it('Should blacklist on update', async function () { 152 it('Should blacklist on update', async function () {
160 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video' }) 153 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
161 const videoId = res.body.video.uuid 154 const videoId = res.body.video.uuid
162 await checkIsBlacklisted(res, false) 155 await checkIsBlacklisted(res, false)
163 156
164 await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, { name: 'please blacklist me' }) 157 await updateVideo(servers[0].url, servers[0].accessToken, videoId, { name: 'please blacklist me' })
165 await checkIsBlacklisted(res, true) 158 await checkIsBlacklisted(res, true)
166 }) 159 })
167 160
168 it('Should blacklist on remote upload', async function () { 161 it('Should blacklist on remote upload', async function () {
169 this.timeout(45000) 162 this.timeout(45000)
170 163
171 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'remote please blacklist me' }) 164 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'remote please blacklist me' })
172 await waitJobs(servers) 165 await waitJobs(servers)
173 166
174 await checkIsBlacklisted(res, true) 167 await checkIsBlacklisted(res, true)
@@ -177,7 +170,7 @@ describe('Test plugin filter hooks', function () {
177 it('Should blacklist on remote update', async function () { 170 it('Should blacklist on remote update', async function () {
178 this.timeout(45000) 171 this.timeout(45000)
179 172
180 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video' }) 173 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video' })
181 await waitJobs(servers) 174 await waitJobs(servers)
182 175
183 const videoId = res.body.video.uuid 176 const videoId = res.body.video.uuid
diff --git a/server/tests/plugins/translations.ts b/server/tests/plugins/translations.ts
index 88d91a033..8dc2043b8 100644
--- a/server/tests/plugins/translations.ts
+++ b/server/tests/plugins/translations.ts
@@ -1,38 +1,15 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers'
5import { 6import {
6 cleanupTests,
7 flushAndRunMultipleServers,
8 flushAndRunServer, killallServers, reRunServer,
9 ServerInfo,
10 waitUntilLog
11} from '../../../shared/extra-utils/server/servers'
12import {
13 addVideoCommentReply,
14 addVideoCommentThread,
15 deleteVideoComment,
16 getPluginTestPath, 7 getPluginTestPath,
17 getVideosList, 8 getPluginTranslations,
18 installPlugin, 9 installPlugin,
19 removeVideo,
20 setAccessTokensToServers, 10 setAccessTokensToServers,
21 updateVideo, 11 uninstallPlugin
22 uploadVideo,
23 viewVideo,
24 getVideosListPagination,
25 getVideo,
26 getVideoCommentThreads,
27 getVideoThreadComments,
28 getVideoWithToken,
29 setDefaultVideoChannel,
30 waitJobs,
31 doubleFollow, getVideoLanguages, getVideoLicences, getVideoCategories, uninstallPlugin, getPluginTranslations
32} from '../../../shared/extra-utils' 12} from '../../../shared/extra-utils'
33import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
34import { VideoDetails } from '../../../shared/models/videos'
35import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports'
36 13
37const expect = chai.expect 14const expect = chai.expect
38 15
@@ -69,7 +46,7 @@ describe('Test plugin translations', function () {
69 46
70 expect(res.body).to.deep.equal({ 47 expect(res.body).to.deep.equal({
71 'peertube-plugin-test': { 48 'peertube-plugin-test': {
72 'Hi': 'Coucou' 49 Hi: 'Coucou'
73 }, 50 },
74 'peertube-plugin-test-two': { 51 'peertube-plugin-test-two': {
75 'Hello world': 'Bonjour le monde' 52 'Hello world': 'Bonjour le monde'
@@ -95,7 +72,7 @@ describe('Test plugin translations', function () {
95 72
96 expect(res.body).to.deep.equal({ 73 expect(res.body).to.deep.equal({
97 'peertube-plugin-test': { 74 'peertube-plugin-test': {
98 'Hi': 'Coucou' 75 Hi: 'Coucou'
99 } 76 }
100 }) 77 })
101 } 78 }
diff --git a/server/tests/plugins/video-constants.ts b/server/tests/plugins/video-constants.ts
index 6562e2b45..5374b5ecc 100644
--- a/server/tests/plugins/video-constants.ts
+++ b/server/tests/plugins/video-constants.ts
@@ -1,38 +1,20 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers'
5import { 6import {
6 cleanupTests,
7 flushAndRunMultipleServers,
8 flushAndRunServer, killallServers, reRunServer,
9 ServerInfo,
10 waitUntilLog
11} from '../../../shared/extra-utils/server/servers'
12import {
13 addVideoCommentReply,
14 addVideoCommentThread,
15 deleteVideoComment,
16 getPluginTestPath, 7 getPluginTestPath,
17 getVideosList, 8 getVideo,
9 getVideoCategories,
10 getVideoLanguages,
11 getVideoLicences,
18 installPlugin, 12 installPlugin,
19 removeVideo,
20 setAccessTokensToServers, 13 setAccessTokensToServers,
21 updateVideo, 14 uninstallPlugin,
22 uploadVideo, 15 uploadVideo
23 viewVideo,
24 getVideosListPagination,
25 getVideo,
26 getVideoCommentThreads,
27 getVideoThreadComments,
28 getVideoWithToken,
29 setDefaultVideoChannel,
30 waitJobs,
31 doubleFollow, getVideoLanguages, getVideoLicences, getVideoCategories, uninstallPlugin
32} from '../../../shared/extra-utils' 16} from '../../../shared/extra-utils'
33import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
34import { VideoDetails } from '../../../shared/models/videos' 17import { VideoDetails } from '../../../shared/models/videos'
35import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports'
36 18
37const expect = chai.expect 19const expect = chai.expect
38 20
@@ -104,33 +86,33 @@ describe('Test plugin altering video constants', function () {
104 const res = await getVideoLanguages(server.url) 86 const res = await getVideoLanguages(server.url)
105 const languages = res.body 87 const languages = res.body
106 88
107 expect(languages[ 'en' ]).to.equal('English') 89 expect(languages['en']).to.equal('English')
108 expect(languages[ 'fr' ]).to.equal('French') 90 expect(languages['fr']).to.equal('French')
109 91
110 expect(languages[ 'al_bhed' ]).to.not.exist 92 expect(languages['al_bhed']).to.not.exist
111 expect(languages[ 'al_bhed2' ]).to.not.exist 93 expect(languages['al_bhed2']).to.not.exist
112 } 94 }
113 95
114 { 96 {
115 const res = await getVideoCategories(server.url) 97 const res = await getVideoCategories(server.url)
116 const categories = res.body 98 const categories = res.body
117 99
118 expect(categories[ 1 ]).to.equal('Music') 100 expect(categories[1]).to.equal('Music')
119 expect(categories[ 2 ]).to.equal('Films') 101 expect(categories[2]).to.equal('Films')
120 102
121 expect(categories[ 42 ]).to.not.exist 103 expect(categories[42]).to.not.exist
122 expect(categories[ 43 ]).to.not.exist 104 expect(categories[43]).to.not.exist
123 } 105 }
124 106
125 { 107 {
126 const res = await getVideoLicences(server.url) 108 const res = await getVideoLicences(server.url)
127 const licences = res.body 109 const licences = res.body
128 110
129 expect(licences[ 1 ]).to.equal('Attribution') 111 expect(licences[1]).to.equal('Attribution')
130 expect(licences[ 7 ]).to.equal('Public Domain Dedication') 112 expect(licences[7]).to.equal('Public Domain Dedication')
131 113
132 expect(licences[ 42 ]).to.not.exist 114 expect(licences[42]).to.not.exist
133 expect(licences[ 43 ]).to.not.exist 115 expect(licences[43]).to.not.exist
134 } 116 }
135 }) 117 })
136 118
diff --git a/server/tests/real-world/populate-database.ts b/server/tests/real-world/populate-database.ts
deleted file mode 100644
index b1c1688e7..000000000
--- a/server/tests/real-world/populate-database.ts
+++ /dev/null
@@ -1,122 +0,0 @@
1import { VideoRateType } from '../../../shared'
2import {
3 addVideoChannel,
4 createUser,
5 flushTests,
6 getVideosList,
7 killallServers,
8 rateVideo,
9 flushAndRunServer,
10 ServerInfo,
11 setAccessTokensToServers,
12 uploadVideo
13} from '../../../shared/extra-utils'
14import * as Bluebird from 'bluebird'
15
16start()
17 .catch(err => console.error(err))
18
19// ----------------------------------------------------------------------------
20
21async function start () {
22
23 console.log('Flushed tests.')
24
25 const server = await flushAndRunServer(6)
26
27 process.on('exit', async () => {
28 killallServers([ server ])
29 return
30 })
31 process.on('SIGINT', goodbye)
32 process.on('SIGTERM', goodbye)
33
34 await setAccessTokensToServers([ server ])
35
36 console.log('Servers ran.')
37
38 // Forever
39 const fakeTab = Array.from(Array(1000000).keys())
40 const funs = [
41 uploadCustom
42 // uploadCustom,
43 // uploadCustom,
44 // uploadCustom,
45 // likeCustom,
46 // createUserCustom,
47 // createCustomChannel
48 ]
49 const promises = []
50
51 for (const fun of funs) {
52 promises.push(
53 Bluebird.map(fakeTab, () => {
54 return fun(server).catch(err => console.error(err))
55 }, { concurrency: 3 })
56 )
57 }
58
59 await Promise.all(promises)
60}
61
62function getRandomInt (min, max) {
63 return Math.floor(Math.random() * (max - min)) + min
64}
65
66function createCustomChannel (server: ServerInfo) {
67 const videoChannel = {
68 name: Date.now().toString(),
69 displayName: Date.now().toString(),
70 description: Date.now().toString()
71 }
72
73 return addVideoChannel(server.url, server.accessToken, videoChannel)
74}
75
76function createUserCustom (server: ServerInfo) {
77 const username = Date.now().toString() + getRandomInt(0, 100000)
78 console.log('Creating user %s.', username)
79
80 return createUser({ url: server.url, accessToken: server.accessToken, username: username, password: 'coucou' })
81}
82
83function uploadCustom (server: ServerInfo) {
84 console.log('Uploading video.')
85
86 const videoAttributes = {
87 name: Date.now() + ' name',
88 category: 4,
89 nsfw: false,
90 licence: 2,
91 language: 'en',
92 description: Date.now() + ' description',
93 tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ],
94 fixture: 'video_short.mp4'
95 }
96
97 return uploadVideo(server.url, server.accessToken, videoAttributes)
98}
99
100function likeCustom (server: ServerInfo) {
101 return rateCustom(server, 'like')
102}
103
104function dislikeCustom (server: ServerInfo) {
105 return rateCustom(server, 'dislike')
106}
107
108async function rateCustom (server: ServerInfo, rating: VideoRateType) {
109 const res = await getVideosList(server.url)
110
111 const videos = res.body.data
112 if (videos.length === 0) return undefined
113
114 const videoToRate = videos[getRandomInt(0, videos.length)]
115
116 console.log('Rating (%s) video.', rating)
117 return rateVideo(server.url, server.accessToken, videoToRate.id, rating)
118}
119
120function goodbye () {
121 return process.exit(-1)
122}
diff --git a/server/tests/real-world/real-world.ts b/server/tests/real-world/real-world.ts
deleted file mode 100644
index cba5ac311..000000000
--- a/server/tests/real-world/real-world.ts
+++ /dev/null
@@ -1,375 +0,0 @@
1// /!\ Before imports /!\
2process.env.NODE_ENV = 'test'
3
4import * as program from 'commander'
5import { Video, VideoFile, VideoRateType } from '../../../shared'
6import { JobState } from '../../../shared/models'
7import {
8 flushAndRunMultipleServers,
9 flushTests, follow,
10 getVideo,
11 getVideosList, getVideosListPagination,
12 killallServers,
13 removeVideo,
14 ServerInfo as DefaultServerInfo,
15 setAccessTokensToServers,
16 updateVideo,
17 uploadVideo, viewVideo,
18 wait
19} from '../../../shared/extra-utils'
20import { getJobsListPaginationAndSort } from '../../../shared/extra-utils/server/jobs'
21
22interface ServerInfo extends DefaultServerInfo {
23 requestsNumber: number
24}
25
26program
27 .option('-c, --create [weight]', 'Weight for creating videos')
28 .option('-r, --remove [weight]', 'Weight for removing videos')
29 .option('-u, --update [weight]', 'Weight for updating videos')
30 .option('-v, --view [weight]', 'Weight for viewing videos')
31 .option('-l, --like [weight]', 'Weight for liking videos')
32 .option('-s, --dislike [weight]', 'Weight for disliking videos')
33 .option('-p, --servers [n]', 'Number of servers to run (3 or 6)', /^3|6$/, 3)
34 .option('-i, --interval-action [interval]', 'Interval in ms for an action')
35 .option('-I, --interval-integrity [interval]', 'Interval in ms for an integrity check')
36 .option('-f, --flush', 'Flush data on exit')
37 .option('-d, --difference', 'Display difference if integrity is not okay')
38 .parse(process.argv)
39
40const createWeight = program['create'] !== undefined ? parseInt(program['create'], 10) : 5
41const removeWeight = program['remove'] !== undefined ? parseInt(program['remove'], 10) : 4
42const updateWeight = program['update'] !== undefined ? parseInt(program['update'], 10) : 4
43const viewWeight = program['view'] !== undefined ? parseInt(program['view'], 10) : 4
44const likeWeight = program['like'] !== undefined ? parseInt(program['like'], 10) : 4
45const dislikeWeight = program['dislike'] !== undefined ? parseInt(program['dislike'], 10) : 4
46const flushAtExit = program['flush'] || false
47const actionInterval = program['intervalAction'] !== undefined ? parseInt(program['intervalAction'], 10) : 500
48const integrityInterval = program['intervalIntegrity'] !== undefined ? parseInt(program['intervalIntegrity'], 10) : 60000
49const displayDiffOnFail = program['difference'] || false
50
51const numberOfServers = 6
52
53console.log(
54 'Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.',
55 createWeight, updateWeight, removeWeight, viewWeight, likeWeight, dislikeWeight
56)
57
58if (flushAtExit) {
59 console.log('Program will flush data on exit.')
60} else {
61 console.log('Program will not flush data on exit.')
62}
63if (displayDiffOnFail) {
64 console.log('Program will display diff on failure.')
65} else {
66 console.log('Program will not display diff on failure')
67}
68console.log('Interval in ms for each action: %d.', actionInterval)
69console.log('Interval in ms for each integrity check: %d.', integrityInterval)
70
71console.log('Run servers...')
72
73start()
74
75// ----------------------------------------------------------------------------
76
77async function start () {
78 const servers = await runServers(numberOfServers)
79
80 process.on('exit', async () => {
81 await exitServers(servers, flushAtExit)
82
83 return
84 })
85 process.on('SIGINT', goodbye)
86 process.on('SIGTERM', goodbye)
87
88 console.log('Servers ran')
89 initializeRequestsPerServer(servers)
90
91 let checking = false
92
93 setInterval(async () => {
94 if (checking === true) return
95
96 const rand = getRandomInt(0, createWeight + updateWeight + removeWeight + viewWeight + likeWeight + dislikeWeight)
97
98 const numServer = getRandomNumServer(servers)
99 servers[numServer].requestsNumber++
100
101 if (rand < createWeight) {
102 await upload(servers, numServer)
103 } else if (rand < createWeight + updateWeight) {
104 await update(servers, numServer)
105 } else if (rand < createWeight + updateWeight + removeWeight) {
106 await remove(servers, numServer)
107 } else if (rand < createWeight + updateWeight + removeWeight + viewWeight) {
108 await view(servers, numServer)
109 } else if (rand < createWeight + updateWeight + removeWeight + viewWeight + likeWeight) {
110 await like(servers, numServer)
111 } else {
112 await dislike(servers, numServer)
113 }
114 }, actionInterval)
115
116 // The function will check the consistency between servers (should have the same videos with same attributes...)
117 setInterval(function () {
118 if (checking === true) return
119
120 console.log('Checking integrity...')
121 checking = true
122
123 const waitingInterval = setInterval(async () => {
124 const pendingRequests = await isTherePendingRequests(servers)
125 if (pendingRequests === true) {
126 console.log('A server has pending requests, waiting...')
127 return
128 }
129
130 // Even if there are no pending request, wait some potential processes
131 await wait(2000)
132 await checkIntegrity(servers)
133
134 initializeRequestsPerServer(servers)
135 checking = false
136 clearInterval(waitingInterval)
137 }, 10000)
138 }, integrityInterval)
139}
140
141function initializeRequestsPerServer (servers: ServerInfo[]) {
142 servers.forEach(server => server.requestsNumber = 0)
143}
144
145function getRandomInt (min, max) {
146 return Math.floor(Math.random() * (max - min)) + min
147}
148
149function getRandomNumServer (servers) {
150 return getRandomInt(0, servers.length)
151}
152
153async function runServers (numberOfServers: number) {
154 const servers: ServerInfo[] = (await flushAndRunMultipleServers(numberOfServers))
155 .map(s => Object.assign({ requestsNumber: 0 }, s))
156
157 // Get the access tokens
158 await setAccessTokensToServers(servers)
159
160 for (let i = 0; i < numberOfServers; i++) {
161 for (let j = 0; j < numberOfServers; j++) {
162 if (i === j) continue
163
164 await follow(servers[i].url, [ servers[j].url ], servers[i].accessToken)
165 }
166 }
167
168 return servers
169}
170
171async function exitServers (servers: ServerInfo[], flushAtExit: boolean) {
172 killallServers(servers)
173
174 if (flushAtExit) await flushTests()
175}
176
177function upload (servers: ServerInfo[], numServer: number) {
178 console.log('Uploading video to server ' + numServer)
179
180 const videoAttributes = {
181 name: Date.now() + ' name',
182 category: 4,
183 nsfw: false,
184 licence: 2,
185 language: 'en',
186 description: Date.now() + ' description',
187 tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ],
188 fixture: 'video_short1.webm'
189 }
190 return uploadVideo(servers[numServer].url, servers[numServer].accessToken, videoAttributes)
191}
192
193async function update (servers: ServerInfo[], numServer: number) {
194 const res = await getVideosList(servers[numServer].url)
195
196 const videos = res.body.data.filter(video => video.isLocal === true)
197 if (videos.length === 0) return undefined
198
199 const toUpdate = videos[getRandomInt(0, videos.length)].id
200 const attributes = {
201 name: Date.now() + ' name',
202 description: Date.now() + ' description',
203 tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ]
204 }
205
206 console.log('Updating video of server ' + numServer)
207
208 return updateVideo(servers[numServer].url, servers[numServer].accessToken, toUpdate, attributes)
209}
210
211async function remove (servers: ServerInfo[], numServer: number) {
212 const res = await getVideosList(servers[numServer].url)
213 const videos = res.body.data.filter(video => video.isLocal === true)
214 if (videos.length === 0) return undefined
215
216 const toRemove = videos[getRandomInt(0, videos.length)].id
217
218 console.log('Removing video from server ' + numServer)
219 return removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove)
220}
221
222async function view (servers: ServerInfo[], numServer: number) {
223 const res = await getVideosList(servers[numServer].url)
224
225 const videos = res.body.data
226 if (videos.length === 0) return undefined
227
228 const toView = videos[getRandomInt(0, videos.length)].id
229
230 console.log('Viewing video from server ' + numServer)
231 return viewVideo(servers[numServer].url, toView)
232}
233
234function like (servers: ServerInfo[], numServer: number) {
235 return rate(servers, numServer, 'like')
236}
237
238function dislike (servers: ServerInfo[], numServer: number) {
239 return rate(servers, numServer, 'dislike')
240}
241
242async function rate (servers: ServerInfo[], numServer: number, rating: VideoRateType) {
243 const res = await getVideosList(servers[numServer].url)
244
245 const videos = res.body.data
246 if (videos.length === 0) return undefined
247
248 const toRate = videos[getRandomInt(0, videos.length)].id
249
250 console.log('Rating (%s) video from server %d', rating, numServer)
251 return getVideo(servers[numServer].url, toRate)
252}
253
254async function checkIntegrity (servers: ServerInfo[]) {
255 const videos: Video[][] = []
256 const tasks: Promise<any>[] = []
257
258 // Fetch all videos and remove some fields that can differ between servers
259 for (const server of servers) {
260 const p = getVideosListPagination(server.url, 0, 1000000, '-createdAt')
261 .then(res => videos.push(res.body.data))
262 tasks.push(p)
263 }
264
265 await Promise.all(tasks)
266
267 let i = 0
268 for (const video of videos) {
269 const differences = areDifferences(video, videos[0])
270 if (differences !== undefined) {
271 console.error('Integrity not ok with server %d!', i + 1)
272
273 if (displayDiffOnFail) {
274 console.log(differences)
275 }
276
277 process.exit(-1)
278 }
279
280 i++
281 }
282
283 console.log('Integrity ok.')
284}
285
286function areDifferences (videos1: Video[], videos2: Video[]) {
287 // Remove some keys we don't want to compare
288 videos1.concat(videos2).forEach(video => {
289 delete video.id
290 delete video.isLocal
291 delete video.thumbnailPath
292 delete video.updatedAt
293 delete video.views
294 })
295
296 if (videos1.length !== videos2.length) {
297 return `Videos length are different (${videos1.length}/${videos2.length}).`
298 }
299
300 for (const video1 of videos1) {
301 const video2 = videos2.find(video => video.uuid === video1.uuid)
302
303 if (!video2) return 'Video ' + video1.uuid + ' is missing.'
304
305 for (const videoKey of Object.keys(video1)) {
306 const attribute1 = video1[videoKey]
307 const attribute2 = video2[videoKey]
308
309 if (videoKey === 'tags') {
310 if (attribute1.length !== attribute2.length) {
311 return 'Tags are different.'
312 }
313
314 attribute1.forEach(tag1 => {
315 if (attribute2.indexOf(tag1) === -1) {
316 return 'Tag ' + tag1 + ' is missing.'
317 }
318 })
319 } else if (videoKey === 'files') {
320 if (attribute1.length !== attribute2.length) {
321 return 'Video files are different.'
322 }
323
324 attribute1.forEach((videoFile1: VideoFile) => {
325 const videoFile2: VideoFile = attribute2.find(videoFile => videoFile.magnetUri === videoFile1.magnetUri)
326 if (!videoFile2) {
327 return `Video ${video1.uuid} has missing video file ${videoFile1.magnetUri}.`
328 }
329
330 if (videoFile1.size !== videoFile2.size || videoFile1.resolution.label !== videoFile2.resolution.label) {
331 return `Video ${video1.uuid} has different video file ${videoFile1.magnetUri}.`
332 }
333 })
334 } else {
335 if (attribute1 !== attribute2) {
336 return `Video ${video1.uuid} has different value for attribute ${videoKey}.`
337 }
338 }
339 }
340 }
341
342 return undefined
343}
344
345function goodbye () {
346 return process.exit(-1)
347}
348
349async function isTherePendingRequests (servers: ServerInfo[]) {
350 const states: JobState[] = [ 'waiting', 'active', 'delayed' ]
351 const tasks: Promise<any>[] = []
352 let pendingRequests = false
353
354 // Check if each server has pending request
355 for (const server of servers) {
356 for (const state of states) {
357 const p = getJobsListPaginationAndSort({
358 url: server.url,
359 accessToken: server.accessToken,
360 state: state,
361 start: 0,
362 count: 10,
363 sort: '-createdAt'
364 })
365 .then(res => {
366 if (res.body.total > 0) pendingRequests = true
367 })
368 tasks.push(p)
369 }
370 }
371
372 await Promise.all(tasks)
373
374 return pendingRequests
375}
diff --git a/server/tools/cli.ts b/server/tools/cli.ts
index 15ac6c6a8..d1a631b69 100644
--- a/server/tools/cli.ts
+++ b/server/tools/cli.ts
@@ -31,7 +31,7 @@ async function getAdminTokenOrDie (url: string, username: string, password: stri
31} 31}
32 32
33interface Settings { 33interface Settings {
34 remotes: any[], 34 remotes: any[]
35 default: number 35 default: number
36} 36}
37 37
@@ -90,9 +90,9 @@ function getRemoteObjectOrDie (
90 if (!program['url'] || !program['username'] || !program['password']) { 90 if (!program['url'] || !program['username'] || !program['password']) {
91 // No remote and we don't have program parameters: quit 91 // No remote and we don't have program parameters: quit
92 if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) { 92 if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) {
93 if (!program[ 'url' ]) console.error('--url field is required.') 93 if (!program['url']) console.error('--url field is required.')
94 if (!program[ 'username' ]) console.error('--username field is required.') 94 if (!program['username']) console.error('--username field is required.')
95 if (!program[ 'password' ]) console.error('--password field is required.') 95 if (!program['password']) console.error('--password field is required.')
96 96
97 return process.exit(-1) 97 return process.exit(-1)
98 } 98 }
@@ -112,9 +112,9 @@ function getRemoteObjectOrDie (
112 } 112 }
113 113
114 return { 114 return {
115 url: program[ 'url' ], 115 url: program['url'],
116 username: program[ 'username' ], 116 username: program['username'],
117 password: program[ 'password' ] 117 password: program['password']
118 } 118 }
119} 119}
120 120
@@ -150,8 +150,8 @@ async function buildVideoAttributesFromCommander (url: string, command: Command,
150 const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {} 150 const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {}
151 151
152 for (const key of Object.keys(defaultBooleanAttributes)) { 152 for (const key of Object.keys(defaultBooleanAttributes)) {
153 if (command[ key ] !== undefined) { 153 if (command[key] !== undefined) {
154 booleanAttributes[key] = command[ key ] 154 booleanAttributes[key] = command[key]
155 } else if (defaultAttributes[key] !== undefined) { 155 } else if (defaultAttributes[key] !== undefined) {
156 booleanAttributes[key] = defaultAttributes[key] 156 booleanAttributes[key] = defaultAttributes[key]
157 } else { 157 } else {
@@ -160,19 +160,19 @@ async function buildVideoAttributesFromCommander (url: string, command: Command,
160 } 160 }
161 161
162 const videoAttributes = { 162 const videoAttributes = {
163 name: command[ 'videoName' ] || defaultAttributes.name, 163 name: command['videoName'] || defaultAttributes.name,
164 category: command[ 'category' ] || defaultAttributes.category || undefined, 164 category: command['category'] || defaultAttributes.category || undefined,
165 licence: command[ 'licence' ] || defaultAttributes.licence || undefined, 165 licence: command['licence'] || defaultAttributes.licence || undefined,
166 language: command[ 'language' ] || defaultAttributes.language || undefined, 166 language: command['language'] || defaultAttributes.language || undefined,
167 privacy: command[ 'privacy' ] || defaultAttributes.privacy || VideoPrivacy.PUBLIC, 167 privacy: command['privacy'] || defaultAttributes.privacy || VideoPrivacy.PUBLIC,
168 support: command[ 'support' ] || defaultAttributes.support || undefined, 168 support: command['support'] || defaultAttributes.support || undefined,
169 description: command[ 'videoDescription' ] || defaultAttributes.description || undefined, 169 description: command['videoDescription'] || defaultAttributes.description || undefined,
170 tags: command[ 'tags' ] || defaultAttributes.tags || undefined 170 tags: command['tags'] || defaultAttributes.tags || undefined
171 } 171 }
172 172
173 Object.assign(videoAttributes, booleanAttributes) 173 Object.assign(videoAttributes, booleanAttributes)
174 174
175 if (command[ 'channelName' ]) { 175 if (command['channelName']) {
176 const res = await getVideoChannel(url, command['channelName']) 176 const res = await getVideoChannel(url, command['channelName'])
177 const videoChannel: VideoChannel = res.body 177 const videoChannel: VideoChannel = res.body
178 178
@@ -188,9 +188,9 @@ async function buildVideoAttributesFromCommander (url: string, command: Command,
188 188
189function getServerCredentials (program: any) { 189function getServerCredentials (program: any) {
190 return Promise.all([ getSettings(), getNetrc() ]) 190 return Promise.all([ getSettings(), getNetrc() ])
191 .then(([ settings, netrc ]) => { 191 .then(([ settings, netrc ]) => {
192 return getRemoteObjectOrDie(program, settings, netrc) 192 return getRemoteObjectOrDie(program, settings, netrc)
193 }) 193 })
194} 194}
195 195
196function getLogger (logLevel = 'info') { 196function getLogger (logLevel = 'info') {
diff --git a/server/tools/peertube-auth.ts b/server/tools/peertube-auth.ts
index acac75034..6b486e575 100644
--- a/server/tools/peertube-auth.ts
+++ b/server/tools/peertube-auth.ts
@@ -1,3 +1,5 @@
1// eslint-disable @typescript-eslint/no-unnecessary-type-assertion
2
1import { registerTSPaths } from '../helpers/register-ts-paths' 3import { registerTSPaths } from '../helpers/register-ts-paths'
2registerTSPaths() 4registerTSPaths()
3 5
@@ -5,7 +7,7 @@ import * as program from 'commander'
5import * as prompt from 'prompt' 7import * as prompt from 'prompt'
6import { getNetrc, getSettings, writeSettings } from './cli' 8import { getNetrc, getSettings, writeSettings } from './cli'
7import { isUserUsernameValid } from '../helpers/custom-validators/users' 9import { isUserUsernameValid } from '../helpers/custom-validators/users'
8import { getAccessToken, login } from '../../shared/extra-utils' 10import { getAccessToken } from '../../shared/extra-utils'
9import * as CliTable3 from 'cli-table3' 11import * as CliTable3 from 'cli-table3'
10 12
11async function delInstance (url: string) { 13async function delInstance (url: string) {
@@ -108,9 +110,9 @@ program
108 const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) 110 const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ])
109 111
110 const table = new CliTable3({ 112 const table = new CliTable3({
111 head: ['instance', 'login'], 113 head: [ 'instance', 'login' ],
112 colWidths: [30, 30] 114 colWidths: [ 30, 30 ]
113 }) as CliTable3.HorizontalTable 115 }) as any
114 116
115 settings.remotes.forEach(element => { 117 settings.remotes.forEach(element => {
116 if (!netrc.machines[element]) return 118 if (!netrc.machines[element]) return
diff --git a/server/tools/peertube-import-videos.ts b/server/tools/peertube-import-videos.ts
index c7e85b570..0efe87810 100644
--- a/server/tools/peertube-import-videos.ts
+++ b/server/tools/peertube-import-videos.ts
@@ -12,7 +12,7 @@ import { accessSync, constants } from 'fs'
12import { remove } from 'fs-extra' 12import { remove } from 'fs-extra'
13import { sha256 } from '../helpers/core-utils' 13import { sha256 } from '../helpers/core-utils'
14import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' 14import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl'
15import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getServerCredentials, getLogger } from './cli' 15import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getLogger, getServerCredentials } from './cli'
16 16
17type UserInfo = { 17type UserInfo = {
18 username: string 18 username: string
@@ -40,30 +40,29 @@ command
40 .option('-T, --tmpdir <tmpdir>', 'Working directory', __dirname) 40 .option('-T, --tmpdir <tmpdir>', 'Working directory', __dirname)
41 .parse(process.argv) 41 .parse(process.argv)
42 42
43let log = getLogger(program[ 'verbose' ]) 43const log = getLogger(program['verbose'])
44 44
45getServerCredentials(command) 45getServerCredentials(command)
46 .then(({ url, username, password }) => { 46 .then(({ url, username, password }) => {
47 if (!program[ 'targetUrl' ]) { 47 if (!program['targetUrl']) {
48 exitError('--target-url field is required.') 48 exitError('--target-url field is required.')
49 } 49 }
50 50
51 try { 51 try {
52 accessSync(program[ 'tmpdir' ], constants.R_OK | constants.W_OK) 52 accessSync(program['tmpdir'], constants.R_OK | constants.W_OK)
53 } catch (e) { 53 } catch (e) {
54 exitError('--tmpdir %s: directory does not exist or is not accessible', program[ 'tmpdir' ]) 54 exitError('--tmpdir %s: directory does not exist or is not accessible', program['tmpdir'])
55 } 55 }
56 56
57 url = normalizeTargetUrl(url) 57 url = normalizeTargetUrl(url)
58 program[ 'targetUrl' ] = normalizeTargetUrl(program[ 'targetUrl' ]) 58 program['targetUrl'] = normalizeTargetUrl(program['targetUrl'])
59 59
60 const user = { username, password } 60 const user = { username, password }
61 61
62 run(url, user) 62 run(url, user)
63 .catch(err => { 63 .catch(err => exitError(err))
64 exitError(err)
65 })
66 }) 64 })
65 .catch(err => console.error(err))
67 66
68async function run (url: string, user: UserInfo) { 67async function run (url: string, user: UserInfo) {
69 if (!user.password) { 68 if (!user.password) {
@@ -73,7 +72,7 @@ async function run (url: string, user: UserInfo) {
73 const youtubeDL = await safeGetYoutubeDL() 72 const youtubeDL = await safeGetYoutubeDL()
74 73
75 const options = [ '-j', '--flat-playlist', '--playlist-reverse' ] 74 const options = [ '-j', '--flat-playlist', '--playlist-reverse' ]
76 youtubeDL.getInfo(program[ 'targetUrl' ], options, processOptions, async (err, info) => { 75 youtubeDL.getInfo(program['targetUrl'], options, processOptions, async (err, info) => {
77 if (err) { 76 if (err) {
78 exitError(err.message) 77 exitError(err.message)
79 } 78 }
@@ -82,10 +81,10 @@ async function run (url: string, user: UserInfo) {
82 81
83 // Normalize utf8 fields 82 // Normalize utf8 fields
84 infoArray = [].concat(info) 83 infoArray = [].concat(info)
85 if (program[ 'first' ]) { 84 if (program['first']) {
86 infoArray = infoArray.slice(0, program[ 'first' ]) 85 infoArray = infoArray.slice(0, program['first'])
87 } else if (program[ 'last' ]) { 86 } else if (program['last']) {
88 infoArray = infoArray.slice(-program[ 'last' ]) 87 infoArray = infoArray.slice(-program['last'])
89 } 88 }
90 infoArray = infoArray.map(i => normalizeObject(i)) 89 infoArray = infoArray.map(i => normalizeObject(i))
91 90
@@ -93,22 +92,22 @@ async function run (url: string, user: UserInfo) {
93 92
94 for (const info of infoArray) { 93 for (const info of infoArray) {
95 await processVideo({ 94 await processVideo({
96 cwd: program[ 'tmpdir' ], 95 cwd: program['tmpdir'],
97 url, 96 url,
98 user, 97 user,
99 youtubeInfo: info 98 youtubeInfo: info
100 }) 99 })
101 } 100 }
102 101
103 log.info('Video/s for user %s imported: %s', user.username, program[ 'targetUrl' ]) 102 log.info('Video/s for user %s imported: %s', user.username, program['targetUrl'])
104 process.exit(0) 103 process.exit(0)
105 }) 104 })
106} 105}
107 106
108function processVideo (parameters: { 107function processVideo (parameters: {
109 cwd: string, 108 cwd: string
110 url: string, 109 url: string
111 user: { username: string, password: string }, 110 user: { username: string, password: string }
112 youtubeInfo: any 111 youtubeInfo: any
113}) { 112}) {
114 const { youtubeInfo, cwd, url, user } = parameters 113 const { youtubeInfo, cwd, url, user } = parameters
@@ -119,17 +118,17 @@ function processVideo (parameters: {
119 const videoInfo = await fetchObject(youtubeInfo) 118 const videoInfo = await fetchObject(youtubeInfo)
120 log.debug('Fetched object.', videoInfo) 119 log.debug('Fetched object.', videoInfo)
121 120
122 if (program[ 'since' ]) { 121 if (program['since']) {
123 if (buildOriginallyPublishedAt(videoInfo).getTime() < program[ 'since' ].getTime()) { 122 if (buildOriginallyPublishedAt(videoInfo).getTime() < program['since'].getTime()) {
124 log.info('Video "%s" has been published before "%s", don\'t upload it.\n', 123 log.info('Video "%s" has been published before "%s", don\'t upload it.\n',
125 videoInfo.title, formatDate(program[ 'since' ])) 124 videoInfo.title, formatDate(program['since']))
126 return res() 125 return res()
127 } 126 }
128 } 127 }
129 if (program[ 'until' ]) { 128 if (program['until']) {
130 if (buildOriginallyPublishedAt(videoInfo).getTime() > program[ 'until' ].getTime()) { 129 if (buildOriginallyPublishedAt(videoInfo).getTime() > program['until'].getTime()) {
131 log.info('Video "%s" has been published after "%s", don\'t upload it.\n', 130 log.info('Video "%s" has been published after "%s", don\'t upload it.\n',
132 videoInfo.title, formatDate(program[ 'until' ])) 131 videoInfo.title, formatDate(program['until']))
133 return res() 132 return res()
134 } 133 }
135 } 134 }
@@ -174,11 +173,11 @@ function processVideo (parameters: {
174} 173}
175 174
176async function uploadVideoOnPeerTube (parameters: { 175async function uploadVideoOnPeerTube (parameters: {
177 videoInfo: any, 176 videoInfo: any
178 videoPath: string, 177 videoPath: string
179 cwd: string, 178 cwd: string
180 url: string, 179 url: string
181 user: { username: string; password: string } 180 user: { username: string, password: string }
182}) { 181}) {
183 const { videoInfo, videoPath, cwd, url, user } = parameters 182 const { videoInfo, videoPath, cwd, url, user } = parameters
184 183
@@ -206,9 +205,9 @@ async function uploadVideoOnPeerTube (parameters: {
206 205
207 const defaultAttributes = { 206 const defaultAttributes = {
208 name: truncate(videoInfo.title, { 207 name: truncate(videoInfo.title, {
209 'length': CONSTRAINTS_FIELDS.VIDEOS.NAME.max, 208 length: CONSTRAINTS_FIELDS.VIDEOS.NAME.max,
210 'separator': /,? +/, 209 separator: /,? +/,
211 'omission': ' […]' 210 omission: ' […]'
212 }), 211 }),
213 category, 212 category,
214 licence, 213 licence,
@@ -255,7 +254,7 @@ async function uploadVideoOnPeerTube (parameters: {
255async function getCategory (categories: string[], url: string) { 254async function getCategory (categories: string[], url: string) {
256 if (!categories) return undefined 255 if (!categories) return undefined
257 256
258 const categoryString = categories[ 0 ] 257 const categoryString = categories[0]
259 258
260 if (categoryString === 'News & Politics') return 11 259 if (categoryString === 'News & Politics') return 11
261 260
@@ -263,7 +262,7 @@ async function getCategory (categories: string[], url: string) {
263 const categoriesServer = res.body 262 const categoriesServer = res.body
264 263
265 for (const key of Object.keys(categoriesServer)) { 264 for (const key of Object.keys(categoriesServer)) {
266 const categoryServer = categoriesServer[ key ] 265 const categoryServer = categoriesServer[key]
267 if (categoryString.toLowerCase() === categoryServer.toLowerCase()) return parseInt(key, 10) 266 if (categoryString.toLowerCase() === categoryServer.toLowerCase()) return parseInt(key, 10)
268 } 267 }
269 268
@@ -285,12 +284,12 @@ function normalizeObject (obj: any) {
285 // Deprecated key 284 // Deprecated key
286 if (key === 'resolution') continue 285 if (key === 'resolution') continue
287 286
288 const value = obj[ key ] 287 const value = obj[key]
289 288
290 if (typeof value === 'string') { 289 if (typeof value === 'string') {
291 newObj[ key ] = value.normalize() 290 newObj[key] = value.normalize()
292 } else { 291 } else {
293 newObj[ key ] = value 292 newObj[key] = value
294 } 293 }
295 } 294 }
296 295
@@ -302,7 +301,7 @@ function fetchObject (info: any) {
302 301
303 return new Promise<any>(async (res, rej) => { 302 return new Promise<any>(async (res, rej) => {
304 const youtubeDL = await safeGetYoutubeDL() 303 const youtubeDL = await safeGetYoutubeDL()
305 youtubeDL.getInfo(url, undefined, processOptions, async (err, videoInfo) => { 304 youtubeDL.getInfo(url, undefined, processOptions, (err, videoInfo) => {
306 if (err) return rej(err) 305 if (err) return rej(err)
307 306
308 const videoInfoWithUrl = Object.assign(videoInfo, { url }) 307 const videoInfoWithUrl = Object.assign(videoInfo, { url })
@@ -313,10 +312,10 @@ function fetchObject (info: any) {
313 312
314function buildUrl (info: any) { 313function buildUrl (info: any) {
315 const webpageUrl = info.webpage_url as string 314 const webpageUrl = info.webpage_url as string
316 if (webpageUrl && webpageUrl.match(/^https?:\/\//)) return webpageUrl 315 if (webpageUrl?.match(/^https?:\/\//)) return webpageUrl
317 316
318 const url = info.url as string 317 const url = info.url as string
319 if (url && url.match(/^https?:\/\//)) return url 318 if (url?.match(/^https?:\/\//)) return url
320 319
321 // It seems youtube-dl does not return the video url 320 // It seems youtube-dl does not return the video url
322 return 'https://www.youtube.com/watch?v=' + info.id 321 return 'https://www.youtube.com/watch?v=' + info.id
@@ -384,7 +383,7 @@ function parseDate (dateAsStr: string): Date {
384} 383}
385 384
386function formatDate (date: Date): string { 385function formatDate (date: Date): string {
387 return date.toISOString().split('T')[ 0 ] 386 return date.toISOString().split('T')[0]
388} 387}
389 388
390function exitError (message: string, ...meta: any[]) { 389function exitError (message: string, ...meta: any[]) {
diff --git a/server/tools/peertube-plugins.ts b/server/tools/peertube-plugins.ts
index b341c14c1..05b75fab2 100644
--- a/server/tools/peertube-plugins.ts
+++ b/server/tools/peertube-plugins.ts
@@ -1,3 +1,5 @@
1// eslint-disable @typescript-eslint/no-unnecessary-type-assertion
2
1import { registerTSPaths } from '../helpers/register-ts-paths' 3import { registerTSPaths } from '../helpers/register-ts-paths'
2registerTSPaths() 4registerTSPaths()
3 5
@@ -79,9 +81,9 @@ async function pluginsListCLI () {
79 const plugins: PeerTubePlugin[] = res.body.data 81 const plugins: PeerTubePlugin[] = res.body.data
80 82
81 const table = new CliTable3({ 83 const table = new CliTable3({
82 head: ['name', 'version', 'homepage'], 84 head: [ 'name', 'version', 'homepage' ],
83 colWidths: [ 50, 10, 50 ] 85 colWidths: [ 50, 10, 50 ]
84 }) as CliTable3.HorizontalTable 86 }) as any
85 87
86 for (const plugin of plugins) { 88 for (const plugin of plugins) {
87 const npmName = plugin.type === PluginType.PLUGIN 89 const npmName = plugin.type === PluginType.PLUGIN
@@ -124,7 +126,6 @@ async function installPluginCLI (options: any) {
124 } catch (err) { 126 } catch (err) {
125 console.error('Cannot install plugin.', err) 127 console.error('Cannot install plugin.', err)
126 process.exit(-1) 128 process.exit(-1)
127 return
128 } 129 }
129 130
130 console.log('Plugin installed.') 131 console.log('Plugin installed.')
@@ -156,7 +157,6 @@ async function updatePluginCLI (options: any) {
156 } catch (err) { 157 } catch (err) {
157 console.error('Cannot update plugin.', err) 158 console.error('Cannot update plugin.', err)
158 process.exit(-1) 159 process.exit(-1)
159 return
160 } 160 }
161 161
162 console.log('Plugin updated.') 162 console.log('Plugin updated.')
@@ -177,12 +177,11 @@ async function uninstallPluginCLI (options: any) {
177 await uninstallPlugin({ 177 await uninstallPlugin({
178 url, 178 url,
179 accessToken, 179 accessToken,
180 npmName: options[ 'npmName' ] 180 npmName: options['npmName']
181 }) 181 })
182 } catch (err) { 182 } catch (err) {
183 console.error('Cannot uninstall plugin.', err) 183 console.error('Cannot uninstall plugin.', err)
184 process.exit(-1) 184 process.exit(-1)
185 return
186 } 185 }
187 186
188 console.log('Plugin uninstalled.') 187 console.log('Plugin uninstalled.')
diff --git a/server/tools/peertube-redundancy.ts b/server/tools/peertube-redundancy.ts
index a71f48104..1ab58a438 100644
--- a/server/tools/peertube-redundancy.ts
+++ b/server/tools/peertube-redundancy.ts
@@ -1,3 +1,5 @@
1// eslint-disable @typescript-eslint/no-unnecessary-type-assertion
2
1import { registerTSPaths } from '../helpers/register-ts-paths' 3import { registerTSPaths } from '../helpers/register-ts-paths'
2registerTSPaths() 4registerTSPaths()
3 5
@@ -6,11 +8,12 @@ import { getAdminTokenOrDie, getServerCredentials } from './cli'
6import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' 8import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models'
7import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy } from '@shared/extra-utils/server/redundancy' 9import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy } from '@shared/extra-utils/server/redundancy'
8import validator from 'validator' 10import validator from 'validator'
9import bytes = require('bytes')
10import * as CliTable3 from 'cli-table3' 11import * as CliTable3 from 'cli-table3'
11import { parse } from 'url' 12import { URL } from 'url'
12import { uniq } from 'lodash' 13import { uniq } from 'lodash'
13 14
15import bytes = require('bytes')
16
14program 17program
15 .name('plugins') 18 .name('plugins')
16 .usage('[command] [options]') 19 .usage('[command] [options]')
@@ -65,7 +68,7 @@ async function listRedundanciesCLI (target: VideoRedundanciesTarget) {
65 68
66 const table = new CliTable3({ 69 const table = new CliTable3({
67 head: [ 'video id', 'video name', 'video url', 'files', 'playlists', 'by instances', 'total size' ] 70 head: [ 'video id', 'video name', 'video url', 'files', 'playlists', 'by instances', 'total size' ]
68 }) as CliTable3.HorizontalTable 71 }) as any
69 72
70 for (const redundancy of redundancies) { 73 for (const redundancy of redundancies) {
71 const webtorrentFiles = redundancy.redundancies.files 74 const webtorrentFiles = redundancy.redundancies.files
@@ -82,7 +85,7 @@ async function listRedundanciesCLI (target: VideoRedundanciesTarget) {
82 const instances = uniq( 85 const instances = uniq(
83 webtorrentFiles.concat(streamingPlaylists) 86 webtorrentFiles.concat(streamingPlaylists)
84 .map(r => r.fileUrl) 87 .map(r => r.fileUrl)
85 .map(u => parse(u).host) 88 .map(u => new URL(u).host)
86 ) 89 )
87 90
88 table.push([ 91 table.push([
@@ -104,7 +107,7 @@ async function addRedundancyCLI (options: { videoId: number }) {
104 const { url, username, password } = await getServerCredentials(program) 107 const { url, username, password } = await getServerCredentials(program)
105 const accessToken = await getAdminTokenOrDie(url, username, password) 108 const accessToken = await getAdminTokenOrDie(url, username, password)
106 109
107 if (!options[ 'video' ] || validator.isInt('' + options[ 'video' ]) === false) { 110 if (!options['video'] || validator.isInt('' + options['video']) === false) {
108 console.error('You need to specify the video id to duplicate and it should be a number.\n') 111 console.error('You need to specify the video id to duplicate and it should be a number.\n')
109 program.outputHelp() 112 program.outputHelp()
110 process.exit(-1) 113 process.exit(-1)
@@ -114,7 +117,7 @@ async function addRedundancyCLI (options: { videoId: number }) {
114 await addVideoRedundancy({ 117 await addVideoRedundancy({
115 url, 118 url,
116 accessToken, 119 accessToken,
117 videoId: options[ 'video' ] 120 videoId: options['video']
118 }) 121 })
119 122
120 console.log('Video will be duplicated by your instance!') 123 console.log('Video will be duplicated by your instance!')
@@ -137,13 +140,13 @@ async function removeRedundancyCLI (options: { videoId: number }) {
137 const { url, username, password } = await getServerCredentials(program) 140 const { url, username, password } = await getServerCredentials(program)
138 const accessToken = await getAdminTokenOrDie(url, username, password) 141 const accessToken = await getAdminTokenOrDie(url, username, password)
139 142
140 if (!options[ 'video' ] || validator.isInt('' + options[ 'video' ]) === false) { 143 if (!options['video'] || validator.isInt('' + options['video']) === false) {
141 console.error('You need to specify the video id to remove from your redundancies.\n') 144 console.error('You need to specify the video id to remove from your redundancies.\n')
142 program.outputHelp() 145 program.outputHelp()
143 process.exit(-1) 146 process.exit(-1)
144 } 147 }
145 148
146 const videoId = parseInt(options[ 'video' ] + '', 10) 149 const videoId = parseInt(options['video'] + '', 10)
147 150
148 let redundancies = await listVideoRedundanciesData(url, accessToken, 'my-videos') 151 let redundancies = await listVideoRedundanciesData(url, accessToken, 'my-videos')
149 let videoRedundancy = redundancies.find(r => videoId === r.id) 152 let videoRedundancy = redundancies.find(r => videoId === r.id)
diff --git a/server/tools/peertube-repl.ts b/server/tools/peertube-repl.ts
index ab6e215d9..7c936ae0d 100644
--- a/server/tools/peertube-repl.ts
+++ b/server/tools/peertube-repl.ts
@@ -1,6 +1,4 @@
1import { registerTSPaths } from '../helpers/register-ts-paths' 1import { registerTSPaths } from '../helpers/register-ts-paths'
2registerTSPaths()
3
4import * as repl from 'repl' 2import * as repl from 'repl'
5import * as path from 'path' 3import * as path from 'path'
6import * as _ from 'lodash' 4import * as _ from 'lodash'
@@ -23,6 +21,8 @@ import * as signupUtils from '../helpers/signup'
23import * as utils from '../helpers/utils' 21import * as utils from '../helpers/utils'
24import * as YoutubeDLUtils from '../helpers/youtube-dl' 22import * as YoutubeDLUtils from '../helpers/youtube-dl'
25 23
24registerTSPaths()
25
26const start = async () => { 26const start = async () => {
27 await initDatabaseModels(true) 27 await initDatabaseModels(true)
28 28
@@ -31,22 +31,39 @@ const start = async () => {
31 const initContext = (replServer) => { 31 const initContext = (replServer) => {
32 return (context) => { 32 return (context) => {
33 const properties = { 33 const properties = {
34 context, repl: replServer, env: process.env, 34 context,
35 lodash: _, path, 35 repl: replServer,
36 uuidv1, uuidv3, uuidv4, uuidv5, 36 env: process.env,
37 cli, logger, constants, 37 lodash: _,
38 Sequelize, sequelizeTypescript, modelsUtils, 38 path,
39 models: sequelizeTypescript.models, transaction: sequelizeTypescript.transaction, 39 uuidv1,
40 query: sequelizeTypescript.query, queryInterface: sequelizeTypescript.getQueryInterface(), 40 uuidv3,
41 uuidv4,
42 uuidv5,
43 cli,
44 logger,
45 constants,
46 Sequelize,
47 sequelizeTypescript,
48 modelsUtils,
49 models: sequelizeTypescript.models,
50 transaction: sequelizeTypescript.transaction,
51 query: sequelizeTypescript.query,
52 queryInterface: sequelizeTypescript.getQueryInterface(),
41 YoutubeDL, 53 YoutubeDL,
42 coreUtils, ffmpegUtils, peertubeCryptoUtils, signupUtils, utils, YoutubeDLUtils 54 coreUtils,
55 ffmpegUtils,
56 peertubeCryptoUtils,
57 signupUtils,
58 utils,
59 YoutubeDLUtils
43 } 60 }
44 61
45 for (let prop in properties) { 62 for (const prop in properties) {
46 Object.defineProperty(context, prop, { 63 Object.defineProperty(context, prop, {
47 configurable: false, 64 configurable: false,
48 enumerable: true, 65 enumerable: true,
49 value: properties[ prop ] 66 value: properties[prop]
50 }) 67 })
51 } 68 }
52 } 69 }
diff --git a/server/tools/peertube-upload.ts b/server/tools/peertube-upload.ts
index f604c9bee..8de952e7b 100644
--- a/server/tools/peertube-upload.ts
+++ b/server/tools/peertube-upload.ts
@@ -24,14 +24,14 @@ command
24 24
25getServerCredentials(command) 25getServerCredentials(command)
26 .then(({ url, username, password }) => { 26 .then(({ url, username, password }) => {
27 if (!program[ 'videoName' ] || !program[ 'file' ]) { 27 if (!program['videoName'] || !program['file']) {
28 if (!program[ 'videoName' ]) console.error('--video-name is required.') 28 if (!program['videoName']) console.error('--video-name is required.')
29 if (!program[ 'file' ]) console.error('--file is required.') 29 if (!program['file']) console.error('--file is required.')
30 30
31 process.exit(-1) 31 process.exit(-1)
32 } 32 }
33 33
34 if (isAbsolute(program[ 'file' ]) === false) { 34 if (isAbsolute(program['file']) === false) {
35 console.error('File path should be absolute.') 35 console.error('File path should be absolute.')
36 process.exit(-1) 36 process.exit(-1)
37 } 37 }
@@ -41,25 +41,26 @@ getServerCredentials(command)
41 process.exit(-1) 41 process.exit(-1)
42 }) 42 })
43 }) 43 })
44 .catch(err => console.error(err))
44 45
45async function run (url: string, username: string, password: string) { 46async function run (url: string, username: string, password: string) {
46 const accessToken = await getAccessToken(url, username, password) 47 const accessToken = await getAccessToken(url, username, password)
47 48
48 await access(program[ 'file' ], constants.F_OK) 49 await access(program['file'], constants.F_OK)
49 50
50 console.log('Uploading %s video...', program[ 'videoName' ]) 51 console.log('Uploading %s video...', program['videoName'])
51 52
52 const videoAttributes = await buildVideoAttributesFromCommander(url, program) 53 const videoAttributes = await buildVideoAttributesFromCommander(url, program)
53 54
54 Object.assign(videoAttributes, { 55 Object.assign(videoAttributes, {
55 fixture: program[ 'file' ], 56 fixture: program['file'],
56 thumbnailfile: program[ 'thumbnail' ], 57 thumbnailfile: program['thumbnail'],
57 previewfile: program[ 'preview' ] 58 previewfile: program['preview']
58 }) 59 })
59 60
60 try { 61 try {
61 await uploadVideo(url, accessToken, videoAttributes) 62 await uploadVideo(url, accessToken, videoAttributes)
62 console.log(`Video ${program[ 'videoName' ]} uploaded.`) 63 console.log(`Video ${program['videoName']} uploaded.`)
63 process.exit(0) 64 process.exit(0)
64 } catch (err) { 65 } catch (err) {
65 console.error(require('util').inspect(err)) 66 console.error(require('util').inspect(err))
diff --git a/server/tools/peertube-watch.ts b/server/tools/peertube-watch.ts
index 9ac1d05f9..5f7d1bb07 100644
--- a/server/tools/peertube-watch.ts
+++ b/server/tools/peertube-watch.ts
@@ -29,16 +29,10 @@ program
29 console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10') 29 console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10')
30 console.log() 30 console.log()
31 }) 31 })
32 .action((url, cmd) => { 32 .action((url, cmd) => run(url, cmd))
33 run(url, cmd)
34 .catch(err => {
35 console.error(err)
36 process.exit(-1)
37 })
38 })
39 .parse(process.argv) 33 .parse(process.argv)
40 34
41async function run (url: string, program: any) { 35function run (url: string, program: any) {
42 if (!url) { 36 if (!url) {
43 console.error('<url> positional argument is required.') 37 console.error('<url> positional argument is required.')
44 process.exit(-1) 38 process.exit(-1)
diff --git a/server/tools/peertube.ts b/server/tools/peertube.ts
index 9883bbf05..88dd5f7f6 100644
--- a/server/tools/peertube.ts
+++ b/server/tools/peertube.ts
@@ -1,13 +1,12 @@
1#!/usr/bin/env node 1#!/usr/bin/env node
2 2
3/* eslint-disable no-useless-escape */
4
3import { registerTSPaths } from '../helpers/register-ts-paths' 5import { registerTSPaths } from '../helpers/register-ts-paths'
4registerTSPaths() 6registerTSPaths()
5 7
6import * as program from 'commander' 8import * as program from 'commander'
7import { 9import { getSettings, version } from './cli'
8 version,
9 getSettings
10} from './cli'
11 10
12program 11program
13 .version(version, '-v, --version') 12 .version(version, '-v, --version')
@@ -26,14 +25,15 @@ program
26 25
27/* Not Yet Implemented */ 26/* Not Yet Implemented */
28program 27program
29 .command('diagnostic [action]', 28 .command(
30 'like couple therapy, but for your instance', 29 'diagnostic [action]',
31 { noHelp: true } as program.CommandOptions 30 'like couple therapy, but for your instance',
32 ).alias('d') 31 { noHelp: true } as program.CommandOptions
32 ).alias('d')
33 .command('admin', 33 .command('admin',
34 'manage an instance where you have elevated rights', 34 'manage an instance where you have elevated rights',
35 { noHelp: true } as program.CommandOptions 35 { noHelp: true } as program.CommandOptions
36 ).alias('a') 36 ).alias('a')
37 37
38// help on no command 38// help on no command
39if (!process.argv.slice(2).length) { 39if (!process.argv.slice(2).length) {
@@ -82,3 +82,4 @@ getSettings()
82 }) 82 })
83 .parse(process.argv) 83 .parse(process.argv)
84 }) 84 })
85 .catch(err => console.error(err))
diff --git a/server/typings/models/account/account-blocklist.ts b/server/typings/models/account/account-blocklist.ts
index c9cb55332..0d8bf11bd 100644
--- a/server/typings/models/account/account-blocklist.ts
+++ b/server/typings/models/account/account-blocklist.ts
@@ -12,7 +12,8 @@ export type MAccountBlocklist = Omit<AccountBlocklistModel, 'ByAccount' | 'Block
12 12
13export type MAccountBlocklistId = Pick<AccountBlocklistModel, 'id'> 13export type MAccountBlocklistId = Pick<AccountBlocklistModel, 'id'>
14 14
15export type MAccountBlocklistAccounts = MAccountBlocklist & 15export type MAccountBlocklistAccounts =
16 MAccountBlocklist &
16 Use<'ByAccount', MAccountDefault> & 17 Use<'ByAccount', MAccountDefault> &
17 Use<'BlockedAccount', MAccountDefault> 18 Use<'BlockedAccount', MAccountDefault>
18 19
@@ -20,6 +21,7 @@ export type MAccountBlocklistAccounts = MAccountBlocklist &
20 21
21// Format for API or AP object 22// Format for API or AP object
22 23
23export type MAccountBlocklistFormattable = Pick<MAccountBlocklist, 'createdAt'> & 24export type MAccountBlocklistFormattable =
25 Pick<MAccountBlocklist, 'createdAt'> &
24 Use<'ByAccount', MAccountFormattable> & 26 Use<'ByAccount', MAccountFormattable> &
25 Use<'BlockedAccount', MAccountFormattable> 27 Use<'BlockedAccount', MAccountFormattable>
diff --git a/server/typings/models/account/account.ts b/server/typings/models/account/account.ts
index adb1f3689..7b826ee04 100644
--- a/server/typings/models/account/account.ts
+++ b/server/typings/models/account/account.ts
@@ -21,7 +21,8 @@ type Use<K extends keyof AccountModel, M> = PickWith<AccountModel, K, M>
21 21
22// ############################################################################ 22// ############################################################################
23 23
24export type MAccount = Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' | 24export type MAccount =
25 Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' |
25 'VideoComments' | 'BlockedAccounts'> 26 'VideoComments' | 'BlockedAccounts'>
26 27
27// ############################################################################ 28// ############################################################################
@@ -34,62 +35,75 @@ export type MAccountUserId = Pick<MAccount, 'userId'>
34export type MAccountUrl = Use<'Actor', MActorUrl> 35export type MAccountUrl = Use<'Actor', MActorUrl>
35export type MAccountAudience = Use<'Actor', MActorAudience> 36export type MAccountAudience = Use<'Actor', MActorAudience>
36 37
37export type MAccountIdActor = MAccountId & 38export type MAccountIdActor =
39 MAccountId &
38 Use<'Actor', MActor> 40 Use<'Actor', MActor>
39 41
40export type MAccountIdActorId = MAccountId & 42export type MAccountIdActorId =
43 MAccountId &
41 Use<'Actor', MActorId> 44 Use<'Actor', MActorId>
42 45
43// ############################################################################ 46// ############################################################################
44 47
45// Default scope 48// Default scope
46export type MAccountDefault = MAccount & 49export type MAccountDefault =
50 MAccount &
47 Use<'Actor', MActorDefault> 51 Use<'Actor', MActorDefault>
48 52
49// Default with default association scopes 53// Default with default association scopes
50export type MAccountDefaultChannelDefault = MAccount & 54export type MAccountDefaultChannelDefault =
55 MAccount &
51 Use<'Actor', MActorDefault> & 56 Use<'Actor', MActorDefault> &
52 Use<'VideoChannels', MChannelDefault[]> 57 Use<'VideoChannels', MChannelDefault[]>
53 58
54// We don't need some actors attributes 59// We don't need some actors attributes
55export type MAccountLight = MAccount & 60export type MAccountLight =
61 MAccount &
56 Use<'Actor', MActorDefaultLight> 62 Use<'Actor', MActorDefaultLight>
57 63
58// ############################################################################ 64// ############################################################################
59 65
60// Full actor 66// Full actor
61export type MAccountActor = MAccount & 67export type MAccountActor =
68 MAccount &
62 Use<'Actor', MActor> 69 Use<'Actor', MActor>
63 70
64// Full actor with server 71// Full actor with server
65export type MAccountServer = MAccount & 72export type MAccountServer =
73 MAccount &
66 Use<'Actor', MActorServer> 74 Use<'Actor', MActorServer>
67 75
68// ############################################################################ 76// ############################################################################
69 77
70// For API 78// For API
71 79
72export type MAccountSummary = FunctionProperties<MAccount> & 80export type MAccountSummary =
81 FunctionProperties<MAccount> &
73 Pick<MAccount, 'id' | 'name'> & 82 Pick<MAccount, 'id' | 'name'> &
74 Use<'Actor', MActorSummary> 83 Use<'Actor', MActorSummary>
75 84
76export type MAccountSummaryBlocks = MAccountSummary & 85export type MAccountSummaryBlocks =
86 MAccountSummary &
77 Use<'BlockedAccounts', MAccountBlocklistId[]> 87 Use<'BlockedAccounts', MAccountBlocklistId[]>
78 88
79export type MAccountAPI = MAccount & 89export type MAccountAPI =
90 MAccount &
80 Use<'Actor', MActorAPI> 91 Use<'Actor', MActorAPI>
81 92
82// ############################################################################ 93// ############################################################################
83 94
84// Format for API or AP object 95// Format for API or AP object
85 96
86export type MAccountSummaryFormattable = FunctionProperties<MAccount> & 97export type MAccountSummaryFormattable =
98 FunctionProperties<MAccount> &
87 Pick<MAccount, 'id' | 'name'> & 99 Pick<MAccount, 'id' | 'name'> &
88 Use<'Actor', MActorSummaryFormattable> 100 Use<'Actor', MActorSummaryFormattable>
89 101
90export type MAccountFormattable = FunctionProperties<MAccount> & 102export type MAccountFormattable =
103 FunctionProperties<MAccount> &
91 Pick<MAccount, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'userId'> & 104 Pick<MAccount, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'userId'> &
92 Use<'Actor', MActorFormattable> 105 Use<'Actor', MActorFormattable>
93 106
94export type MAccountAP = Pick<MAccount, 'name' | 'description'> & 107export type MAccountAP =
108 Pick<MAccount, 'name' | 'description'> &
95 Use<'Actor', MActorAP> 109 Use<'Actor', MActorAP>
diff --git a/server/typings/models/account/actor-follow.ts b/server/typings/models/account/actor-follow.ts
index f44157eba..5d0c03c8d 100644
--- a/server/typings/models/account/actor-follow.ts
+++ b/server/typings/models/account/actor-follow.ts
@@ -20,22 +20,26 @@ export type MActorFollow = Omit<ActorFollowModel, 'ActorFollower' | 'ActorFollow
20 20
21// ############################################################################ 21// ############################################################################
22 22
23export type MActorFollowFollowingHost = MActorFollow & 23export type MActorFollowFollowingHost =
24 MActorFollow &
24 Use<'ActorFollowing', MActorUsername & MActorHost> 25 Use<'ActorFollowing', MActorUsername & MActorHost>
25 26
26// ############################################################################ 27// ############################################################################
27 28
28// With actors or actors default 29// With actors or actors default
29 30
30export type MActorFollowActors = MActorFollow & 31export type MActorFollowActors =
32 MActorFollow &
31 Use<'ActorFollower', MActor> & 33 Use<'ActorFollower', MActor> &
32 Use<'ActorFollowing', MActor> 34 Use<'ActorFollowing', MActor>
33 35
34export type MActorFollowActorsDefault = MActorFollow & 36export type MActorFollowActorsDefault =
37 MActorFollow &
35 Use<'ActorFollower', MActorDefault> & 38 Use<'ActorFollower', MActorDefault> &
36 Use<'ActorFollowing', MActorDefault> 39 Use<'ActorFollowing', MActorDefault>
37 40
38export type MActorFollowFull = MActorFollow & 41export type MActorFollowFull =
42 MActorFollow &
39 Use<'ActorFollower', MActorDefaultAccountChannel> & 43 Use<'ActorFollower', MActorDefaultAccountChannel> &
40 Use<'ActorFollowing', MActorDefaultAccountChannel> 44 Use<'ActorFollowing', MActorDefaultAccountChannel>
41 45
@@ -43,20 +47,24 @@ export type MActorFollowFull = MActorFollow &
43 47
44// For subscriptions 48// For subscriptions
45 49
46type SubscriptionFollowing = MActorDefault & 50type SubscriptionFollowing =
51 MActorDefault &
47 PickWith<ActorModel, 'VideoChannel', MChannelDefault> 52 PickWith<ActorModel, 'VideoChannel', MChannelDefault>
48 53
49export type MActorFollowActorsDefaultSubscription = MActorFollow & 54export type MActorFollowActorsDefaultSubscription =
55 MActorFollow &
50 Use<'ActorFollower', MActorDefault> & 56 Use<'ActorFollower', MActorDefault> &
51 Use<'ActorFollowing', SubscriptionFollowing> 57 Use<'ActorFollowing', SubscriptionFollowing>
52 58
53export type MActorFollowSubscriptions = MActorFollow & 59export type MActorFollowSubscriptions =
60 MActorFollow &
54 Use<'ActorFollowing', MActorChannelAccountActor> 61 Use<'ActorFollowing', MActorChannelAccountActor>
55 62
56// ############################################################################ 63// ############################################################################
57 64
58// Format for API or AP object 65// Format for API or AP object
59 66
60export type MActorFollowFormattable = Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> & 67export type MActorFollowFormattable =
68 Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> &
61 Use<'ActorFollower', MActorFormattable> & 69 Use<'ActorFollower', MActorFormattable> &
62 Use<'ActorFollowing', MActorFormattable> 70 Use<'ActorFollowing', MActorFormattable>
diff --git a/server/typings/models/account/actor.ts b/server/typings/models/account/actor.ts
index ee4ece755..1160e84cb 100644
--- a/server/typings/models/account/actor.ts
+++ b/server/typings/models/account/actor.ts
@@ -31,18 +31,23 @@ export type MActorLight = Omit<MActor, 'privateKey' | 'privateKey'>
31export type MActorHost = Use<'Server', MServerHost> 31export type MActorHost = Use<'Server', MServerHost>
32export type MActorRedundancyAllowedOpt = PickWithOpt<ActorModel, 'Server', MServerRedundancyAllowed> 32export type MActorRedundancyAllowedOpt = PickWithOpt<ActorModel, 'Server', MServerRedundancyAllowed>
33 33
34export type MActorDefaultLight = MActorLight & 34export type MActorDefaultLight =
35 MActorLight &
35 Use<'Server', MServerHost> & 36 Use<'Server', MServerHost> &
36 Use<'Avatar', MAvatar> 37 Use<'Avatar', MAvatar>
37 38
38export type MActorAccountId = MActor & 39export type MActorAccountId =
40 MActor &
39 Use<'Account', MAccountId> 41 Use<'Account', MAccountId>
40export type MActorAccountIdActor = MActor & 42export type MActorAccountIdActor =
43 MActor &
41 Use<'Account', MAccountIdActor> 44 Use<'Account', MAccountIdActor>
42 45
43export type MActorChannelId = MActor & 46export type MActorChannelId =
47 MActor &
44 Use<'VideoChannel', MChannelId> 48 Use<'VideoChannel', MChannelId>
45export type MActorChannelIdActor = MActor & 49export type MActorChannelIdActor =
50 MActor &
46 Use<'VideoChannel', MChannelIdActor> 51 Use<'VideoChannel', MChannelIdActor>
47 52
48export type MActorAccountChannelId = MActorAccountId & MActorChannelId 53export type MActorAccountChannelId = MActorAccountId & MActorChannelId
@@ -52,38 +57,45 @@ export type MActorAccountChannelIdActor = MActorAccountIdActor & MActorChannelId
52 57
53// Include raw account/channel/server 58// Include raw account/channel/server
54 59
55export type MActorAccount = MActor & 60export type MActorAccount =
61 MActor &
56 Use<'Account', MAccount> 62 Use<'Account', MAccount>
57 63
58export type MActorChannel = MActor & 64export type MActorChannel =
65 MActor &
59 Use<'VideoChannel', MChannel> 66 Use<'VideoChannel', MChannel>
60 67
61export type MActorDefaultAccountChannel = MActorDefault & MActorAccount & MActorChannel 68export type MActorDefaultAccountChannel = MActorDefault & MActorAccount & MActorChannel
62 69
63export type MActorServer = MActor & 70export type MActorServer =
71 MActor &
64 Use<'Server', MServer> 72 Use<'Server', MServer>
65 73
66// ############################################################################ 74// ############################################################################
67 75
68// Complex actor associations 76// Complex actor associations
69 77
70export type MActorDefault = MActor & 78export type MActorDefault =
79 MActor &
71 Use<'Server', MServer> & 80 Use<'Server', MServer> &
72 Use<'Avatar', MAvatar> 81 Use<'Avatar', MAvatar>
73 82
74// Actor with channel that is associated to an account and its actor 83// Actor with channel that is associated to an account and its actor
75// Actor -> VideoChannel -> Account -> Actor 84// Actor -> VideoChannel -> Account -> Actor
76export type MActorChannelAccountActor = MActor & 85export type MActorChannelAccountActor =
86 MActor &
77 Use<'VideoChannel', MChannelAccountActor> 87 Use<'VideoChannel', MChannelAccountActor>
78 88
79export type MActorFull = MActor & 89export type MActorFull =
90 MActor &
80 Use<'Server', MServer> & 91 Use<'Server', MServer> &
81 Use<'Avatar', MAvatar> & 92 Use<'Avatar', MAvatar> &
82 Use<'Account', MAccount> & 93 Use<'Account', MAccount> &
83 Use<'VideoChannel', MChannelAccountActor> 94 Use<'VideoChannel', MChannelAccountActor>
84 95
85// Same than ActorFull, but the account and the channel have their actor 96// Same than ActorFull, but the account and the channel have their actor
86export type MActorFullActor = MActor & 97export type MActorFullActor =
98 MActor &
87 Use<'Server', MServer> & 99 Use<'Server', MServer> &
88 Use<'Avatar', MAvatar> & 100 Use<'Avatar', MAvatar> &
89 Use<'Account', MAccountDefault> & 101 Use<'Account', MAccountDefault> &
@@ -93,29 +105,35 @@ export type MActorFullActor = MActor &
93 105
94// API 106// API
95 107
96export type MActorSummary = FunctionProperties<MActor> & 108export type MActorSummary =
109 FunctionProperties<MActor> &
97 Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> & 110 Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> &
98 Use<'Server', MServerHost> & 111 Use<'Server', MServerHost> &
99 Use<'Avatar', MAvatar> 112 Use<'Avatar', MAvatar>
100 113
101export type MActorSummaryBlocks = MActorSummary & 114export type MActorSummaryBlocks =
115 MActorSummary &
102 Use<'Server', MServerHostBlocks> 116 Use<'Server', MServerHostBlocks>
103 117
104export type MActorAPI = Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' | 118export type MActorAPI =
119 Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' |
105 'followersUrl' | 'followingUrl' | 'url' | 'createdAt' | 'updatedAt'> 120 'followersUrl' | 'followingUrl' | 'url' | 'createdAt' | 'updatedAt'>
106 121
107// ############################################################################ 122// ############################################################################
108 123
109// Format for API or AP object 124// Format for API or AP object
110 125
111export type MActorSummaryFormattable = FunctionProperties<MActor> & 126export type MActorSummaryFormattable =
127 FunctionProperties<MActor> &
112 Pick<MActor, 'url' | 'preferredUsername'> & 128 Pick<MActor, 'url' | 'preferredUsername'> &
113 Use<'Server', MServerHost> & 129 Use<'Server', MServerHost> &
114 Use<'Avatar', MAvatarFormattable> 130 Use<'Avatar', MAvatarFormattable>
115 131
116export type MActorFormattable = MActorSummaryFormattable & 132export type MActorFormattable =
133 MActorSummaryFormattable &
117 Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt'> & 134 Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt'> &
118 Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>> 135 Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>>
119 136
120export type MActorAP = MActor & 137export type MActorAP =
138 MActor &
121 Use<'Avatar', MAvatar> 139 Use<'Avatar', MAvatar>
diff --git a/server/typings/models/account/avatar.ts b/server/typings/models/account/avatar.ts
index 8af6cc787..21b47180f 100644
--- a/server/typings/models/account/avatar.ts
+++ b/server/typings/models/account/avatar.ts
@@ -7,5 +7,6 @@ export type MAvatar = AvatarModel
7 7
8// Format for API or AP object 8// Format for API or AP object
9 9
10export type MAvatarFormattable = FunctionProperties<MAvatar> & 10export type MAvatarFormattable =
11 FunctionProperties<MAvatar> &
11 Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'> 12 Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'>
diff --git a/server/typings/models/oauth/oauth-token.ts b/server/typings/models/oauth/oauth-token.ts
index 8ef042d4e..b24a95fd8 100644
--- a/server/typings/models/oauth/oauth-token.ts
+++ b/server/typings/models/oauth/oauth-token.ts
@@ -8,6 +8,7 @@ type Use<K extends keyof OAuthTokenModel, M> = PickWith<OAuthTokenModel, K, M>
8 8
9export type MOAuthToken = Omit<OAuthTokenModel, 'User' | 'OAuthClients'> 9export type MOAuthToken = Omit<OAuthTokenModel, 'User' | 'OAuthClients'>
10 10
11export type MOAuthTokenUser = MOAuthToken & 11export type MOAuthTokenUser =
12 MOAuthToken &
12 Use<'User', MUserAccountUrl> & 13 Use<'User', MUserAccountUrl> &
13 { user?: MUserAccountUrl } 14 { user?: MUserAccountUrl }
diff --git a/server/typings/models/server/plugin.ts b/server/typings/models/server/plugin.ts
index 94674c318..83eb83794 100644
--- a/server/typings/models/server/plugin.ts
+++ b/server/typings/models/server/plugin.ts
@@ -6,5 +6,6 @@ export type MPlugin = PluginModel
6 6
7// Format for API or AP object 7// Format for API or AP object
8 8
9export type MPluginFormattable = Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled' 9export type MPluginFormattable =
10 Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled'
10 | 'peertubeEngine' | 'description' | 'homepage' | 'settings' | 'createdAt' | 'updatedAt'> 11 | 'peertubeEngine' | 'description' | 'homepage' | 'settings' | 'createdAt' | 'updatedAt'>
diff --git a/server/typings/models/server/server-blocklist.ts b/server/typings/models/server/server-blocklist.ts
index c3e6230f2..ff6f49176 100644
--- a/server/typings/models/server/server-blocklist.ts
+++ b/server/typings/models/server/server-blocklist.ts
@@ -11,7 +11,8 @@ export type MServerBlocklist = Omit<ServerBlocklistModel, 'ByAccount' | 'Blocked
11 11
12// ############################################################################ 12// ############################################################################
13 13
14export type MServerBlocklistAccountServer = MServerBlocklist & 14export type MServerBlocklistAccountServer =
15 MServerBlocklist &
15 Use<'ByAccount', MAccountDefault> & 16 Use<'ByAccount', MAccountDefault> &
16 Use<'BlockedServer', MServer> 17 Use<'BlockedServer', MServer>
17 18
@@ -19,6 +20,7 @@ export type MServerBlocklistAccountServer = MServerBlocklist &
19 20
20// Format for API or AP object 21// Format for API or AP object
21 22
22export type MServerBlocklistFormattable = Pick<MServerBlocklist, 'createdAt'> & 23export type MServerBlocklistFormattable =
24 Pick<MServerBlocklist, 'createdAt'> &
23 Use<'ByAccount', MAccountFormattable> & 25 Use<'ByAccount', MAccountFormattable> &
24 Use<'BlockedServer', MServerFormattable> 26 Use<'BlockedServer', MServerFormattable>
diff --git a/server/typings/models/server/server.ts b/server/typings/models/server/server.ts
index 190cc0c28..b35e55aeb 100644
--- a/server/typings/models/server/server.ts
+++ b/server/typings/models/server/server.ts
@@ -13,12 +13,14 @@ export type MServer = Omit<ServerModel, 'Actors' | 'BlockedByAccounts'>
13export type MServerHost = Pick<MServer, 'host'> 13export type MServerHost = Pick<MServer, 'host'>
14export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'> 14export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'>
15 15
16export type MServerHostBlocks = MServerHost & 16export type MServerHostBlocks =
17 MServerHost &
17 Use<'BlockedByAccounts', MAccountBlocklistId[]> 18 Use<'BlockedByAccounts', MAccountBlocklistId[]>
18 19
19// ############################################################################ 20// ############################################################################
20 21
21// Format for API or AP object 22// Format for API or AP object
22 23
23export type MServerFormattable = FunctionProperties<MServer> & 24export type MServerFormattable =
25 FunctionProperties<MServer> &
24 Pick<MServer, 'host'> 26 Pick<MServer, 'host'>
diff --git a/server/typings/models/user/user-notification.ts b/server/typings/models/user/user-notification.ts
index 1cdc691b0..2080360e1 100644
--- a/server/typings/models/user/user-notification.ts
+++ b/server/typings/models/user/user-notification.ts
@@ -16,59 +16,73 @@ type Use<K extends keyof UserNotificationModel, M> = PickWith<UserNotificationMo
16 16
17// ############################################################################ 17// ############################################################################
18 18
19export namespace UserNotificationIncludes { 19export module UserNotificationIncludes {
20
20 export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name'> 21 export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name'>
21 export type VideoIncludeChannel = VideoInclude & 22 export type VideoIncludeChannel =
23 VideoInclude &
22 PickWith<VideoModel, 'VideoChannel', VideoChannelIncludeActor> 24 PickWith<VideoModel, 'VideoChannel', VideoChannelIncludeActor>
23 25
24 export type ActorInclude = Pick<ActorModel, 'preferredUsername' | 'getHost'> & 26 export type ActorInclude =
27 Pick<ActorModel, 'preferredUsername' | 'getHost'> &
25 PickWith<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> & 28 PickWith<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> &
26 PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> 29 PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>>
27 30
28 export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'> 31 export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'>
29 export type VideoChannelIncludeActor = VideoChannelInclude & 32 export type VideoChannelIncludeActor =
33 VideoChannelInclude &
30 PickWith<VideoChannelModel, 'Actor', ActorInclude> 34 PickWith<VideoChannelModel, 'Actor', ActorInclude>
31 35
32 export type AccountInclude = Pick<AccountModel, 'id' | 'name' | 'getDisplayName'> 36 export type AccountInclude = Pick<AccountModel, 'id' | 'name' | 'getDisplayName'>
33 export type AccountIncludeActor = AccountInclude & 37 export type AccountIncludeActor =
38 AccountInclude &
34 PickWith<AccountModel, 'Actor', ActorInclude> 39 PickWith<AccountModel, 'Actor', ActorInclude>
35 40
36 export type VideoCommentInclude = Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> & 41 export type VideoCommentInclude =
42 Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> &
37 PickWith<VideoCommentModel, 'Account', AccountIncludeActor> & 43 PickWith<VideoCommentModel, 'Account', AccountIncludeActor> &
38 PickWith<VideoCommentModel, 'Video', VideoInclude> 44 PickWith<VideoCommentModel, 'Video', VideoInclude>
39 45
40 export type VideoAbuseInclude = Pick<VideoAbuseModel, 'id'> & 46 export type VideoAbuseInclude =
47 Pick<VideoAbuseModel, 'id'> &
41 PickWith<VideoAbuseModel, 'Video', VideoInclude> 48 PickWith<VideoAbuseModel, 'Video', VideoInclude>
42 49
43 export type VideoBlacklistInclude = Pick<VideoBlacklistModel, 'id'> & 50 export type VideoBlacklistInclude =
51 Pick<VideoBlacklistModel, 'id'> &
44 PickWith<VideoAbuseModel, 'Video', VideoInclude> 52 PickWith<VideoAbuseModel, 'Video', VideoInclude>
45 53
46 export type VideoImportInclude = Pick<VideoImportModel, 'id' | 'magnetUri' | 'targetUrl' | 'torrentName'> & 54 export type VideoImportInclude =
55 Pick<VideoImportModel, 'id' | 'magnetUri' | 'targetUrl' | 'torrentName'> &
47 PickWith<VideoImportModel, 'Video', VideoInclude> 56 PickWith<VideoImportModel, 'Video', VideoInclude>
48 57
49 export type ActorFollower = Pick<ActorModel, 'preferredUsername' | 'getHost'> & 58 export type ActorFollower =
59 Pick<ActorModel, 'preferredUsername' | 'getHost'> &
50 PickWith<ActorModel, 'Account', AccountInclude> & 60 PickWith<ActorModel, 'Account', AccountInclude> &
51 PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> & 61 PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> &
52 PickWithOpt<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> 62 PickWithOpt<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>>
53 63
54 export type ActorFollowing = Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> & 64 export type ActorFollowing =
65 Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> &
55 PickWith<ActorModel, 'VideoChannel', VideoChannelInclude> & 66 PickWith<ActorModel, 'VideoChannel', VideoChannelInclude> &
56 PickWith<ActorModel, 'Account', AccountInclude> & 67 PickWith<ActorModel, 'Account', AccountInclude> &
57 PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> 68 PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>>
58 69
59 export type ActorFollowInclude = Pick<ActorFollowModel, 'id' | 'state'> & 70 export type ActorFollowInclude =
71 Pick<ActorFollowModel, 'id' | 'state'> &
60 PickWith<ActorFollowModel, 'ActorFollower', ActorFollower> & 72 PickWith<ActorFollowModel, 'ActorFollower', ActorFollower> &
61 PickWith<ActorFollowModel, 'ActorFollowing', ActorFollowing> 73 PickWith<ActorFollowModel, 'ActorFollowing', ActorFollowing>
62} 74}
63 75
64// ############################################################################ 76// ############################################################################
65 77
66export type MUserNotification = Omit<UserNotificationModel, 'User' | 'Video' | 'Comment' | 'VideoAbuse' | 'VideoBlacklist' | 78export type MUserNotification =
79 Omit<UserNotificationModel, 'User' | 'Video' | 'Comment' | 'VideoAbuse' | 'VideoBlacklist' |
67 'VideoImport' | 'Account' | 'ActorFollow'> 80 'VideoImport' | 'Account' | 'ActorFollow'>
68 81
69// ############################################################################ 82// ############################################################################
70 83
71export type UserNotificationModelForApi = MUserNotification & 84export type UserNotificationModelForApi =
85 MUserNotification &
72 Use<'Video', UserNotificationIncludes.VideoIncludeChannel> & 86 Use<'Video', UserNotificationIncludes.VideoIncludeChannel> &
73 Use<'Comment', UserNotificationIncludes.VideoCommentInclude> & 87 Use<'Comment', UserNotificationIncludes.VideoCommentInclude> &
74 Use<'VideoAbuse', UserNotificationIncludes.VideoAbuseInclude> & 88 Use<'VideoAbuse', UserNotificationIncludes.VideoAbuseInclude> &
diff --git a/server/typings/models/user/user.ts b/server/typings/models/user/user.ts
index 6ac19c20b..31cf075ef 100644
--- a/server/typings/models/user/user.ts
+++ b/server/typings/models/user/user.ts
@@ -29,36 +29,44 @@ export type MUserId = Pick<UserModel, 'id'>
29 29
30// With account 30// With account
31 31
32export type MUserAccountId = MUser & 32export type MUserAccountId =
33 MUser &
33 Use<'Account', MAccountId> 34 Use<'Account', MAccountId>
34 35
35export type MUserAccountUrl = MUser & 36export type MUserAccountUrl =
37 MUser &
36 Use<'Account', MAccountUrl & MAccountIdActorId> 38 Use<'Account', MAccountUrl & MAccountIdActorId>
37 39
38export type MUserAccount = MUser & 40export type MUserAccount =
41 MUser &
39 Use<'Account', MAccount> 42 Use<'Account', MAccount>
40 43
41export type MUserAccountDefault = MUser & 44export type MUserAccountDefault =
45 MUser &
42 Use<'Account', MAccountDefault> 46 Use<'Account', MAccountDefault>
43 47
44// With channel 48// With channel
45 49
46export type MUserNotifSettingChannelDefault = MUser & 50export type MUserNotifSettingChannelDefault =
51 MUser &
47 Use<'NotificationSetting', MNotificationSetting> & 52 Use<'NotificationSetting', MNotificationSetting> &
48 Use<'Account', MAccountDefaultChannelDefault> 53 Use<'Account', MAccountDefaultChannelDefault>
49 54
50// With notification settings 55// With notification settings
51 56
52export type MUserWithNotificationSetting = MUser & 57export type MUserWithNotificationSetting =
58 MUser &
53 Use<'NotificationSetting', MNotificationSetting> 59 Use<'NotificationSetting', MNotificationSetting>
54 60
55export type MUserNotifSettingAccount = MUser & 61export type MUserNotifSettingAccount =
62 MUser &
56 Use<'NotificationSetting', MNotificationSetting> & 63 Use<'NotificationSetting', MNotificationSetting> &
57 Use<'Account', MAccount> 64 Use<'Account', MAccount>
58 65
59// Default scope 66// Default scope
60 67
61export type MUserDefault = MUser & 68export type MUserDefault =
69 MUser &
62 Use<'NotificationSetting', MNotificationSetting> & 70 Use<'NotificationSetting', MNotificationSetting> &
63 Use<'Account', MAccountDefault> 71 Use<'Account', MAccountDefault>
64 72
@@ -67,12 +75,15 @@ export type MUserDefault = MUser &
67// Format for API or AP object 75// Format for API or AP object
68 76
69type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]> 77type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]>
70type MAccountWithChannelsAndSpecialPlaylists = MAccountWithChannels & 78type MAccountWithChannelsAndSpecialPlaylists =
79 MAccountWithChannels &
71 PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]> 80 PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]>
72 81
73export type MUserFormattable = MUserQuotaUsed & 82export type MUserFormattable =
83 MUserQuotaUsed &
74 Use<'Account', MAccountWithChannels> & 84 Use<'Account', MAccountWithChannels> &
75 PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable> 85 PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable>
76 86
77export type MMyUserFormattable = MUserFormattable & 87export type MMyUserFormattable =
88 MUserFormattable &
78 Use<'Account', MAccountWithChannelsAndSpecialPlaylists> 89 Use<'Account', MAccountWithChannelsAndSpecialPlaylists>
diff --git a/server/typings/models/video/schedule-video-update.ts b/server/typings/models/video/schedule-video-update.ts
index e6f478cdf..95a53d139 100644
--- a/server/typings/models/video/schedule-video-update.ts
+++ b/server/typings/models/video/schedule-video-update.ts
@@ -10,7 +10,8 @@ export type MScheduleVideoUpdate = Omit<ScheduleVideoUpdateModel, 'Video'>
10 10
11// ############################################################################ 11// ############################################################################
12 12
13export type MScheduleVideoUpdateVideoAll = MScheduleVideoUpdate & 13export type MScheduleVideoUpdateVideoAll =
14 MScheduleVideoUpdate &
14 Use<'Video', MVideoAPWithoutCaption & MVideoWithBlacklistLight> 15 Use<'Video', MVideoAPWithoutCaption & MVideoWithBlacklistLight>
15 16
16// Format for API or AP object 17// Format for API or AP object
diff --git a/server/typings/models/video/video-abuse.ts b/server/typings/models/video/video-abuse.ts
index e38c3f586..955ec4780 100644
--- a/server/typings/models/video/video-abuse.ts
+++ b/server/typings/models/video/video-abuse.ts
@@ -13,11 +13,13 @@ export type MVideoAbuse = Omit<VideoAbuseModel, 'Account' | 'Video' | 'toActivit
13 13
14export type MVideoAbuseId = Pick<VideoAbuseModel, 'id'> 14export type MVideoAbuseId = Pick<VideoAbuseModel, 'id'>
15 15
16export type MVideoAbuseVideo = MVideoAbuse & 16export type MVideoAbuseVideo =
17 MVideoAbuse &
17 Pick<VideoAbuseModel, 'toActivityPubObject'> & 18 Pick<VideoAbuseModel, 'toActivityPubObject'> &
18 Use<'Video', MVideo> 19 Use<'Video', MVideo>
19 20
20export type MVideoAbuseAccountVideo = MVideoAbuse & 21export type MVideoAbuseAccountVideo =
22 MVideoAbuse &
21 Pick<VideoAbuseModel, 'toActivityPubObject'> & 23 Pick<VideoAbuseModel, 'toActivityPubObject'> &
22 Use<'Video', MVideo> & 24 Use<'Video', MVideo> &
23 Use<'Account', MAccountDefault> 25 Use<'Account', MAccountDefault>
@@ -26,6 +28,7 @@ export type MVideoAbuseAccountVideo = MVideoAbuse &
26 28
27// Format for API or AP object 29// Format for API or AP object
28 30
29export type MVideoAbuseFormattable = MVideoAbuse & 31export type MVideoAbuseFormattable =
32 MVideoAbuse &
30 Use<'Account', MAccountFormattable> & 33 Use<'Account', MAccountFormattable> &
31 Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>> 34 Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>>
diff --git a/server/typings/models/video/video-blacklist.ts b/server/typings/models/video/video-blacklist.ts
index 7122a9dc0..ddb4db832 100644
--- a/server/typings/models/video/video-blacklist.ts
+++ b/server/typings/models/video/video-blacklist.ts
@@ -13,15 +13,18 @@ export type MVideoBlacklistUnfederated = Pick<MVideoBlacklist, 'unfederated'>
13 13
14// ############################################################################ 14// ############################################################################
15 15
16export type MVideoBlacklistLightVideo = MVideoBlacklistLight & 16export type MVideoBlacklistLightVideo =
17 MVideoBlacklistLight &
17 Use<'Video', MVideo> 18 Use<'Video', MVideo>
18 19
19export type MVideoBlacklistVideo = MVideoBlacklist & 20export type MVideoBlacklistVideo =
21 MVideoBlacklist &
20 Use<'Video', MVideo> 22 Use<'Video', MVideo>
21 23
22// ############################################################################ 24// ############################################################################
23 25
24// Format for API or AP object 26// Format for API or AP object
25 27
26export type MVideoBlacklistFormattable = MVideoBlacklist & 28export type MVideoBlacklistFormattable =
29 MVideoBlacklist &
27 Use<'Video', MVideoFormattable> 30 Use<'Video', MVideoFormattable>
diff --git a/server/typings/models/video/video-caption.ts b/server/typings/models/video/video-caption.ts
index eeddedb40..e7aff6956 100644
--- a/server/typings/models/video/video-caption.ts
+++ b/server/typings/models/video/video-caption.ts
@@ -13,13 +13,15 @@ export type MVideoCaption = Omit<VideoCaptionModel, 'Video'>
13export type MVideoCaptionLanguage = Pick<MVideoCaption, 'language'> 13export type MVideoCaptionLanguage = Pick<MVideoCaption, 'language'>
14export type MVideoCaptionLanguageUrl = Pick<MVideoCaption, 'language' | 'fileUrl' | 'getFileUrl'> 14export type MVideoCaptionLanguageUrl = Pick<MVideoCaption, 'language' | 'fileUrl' | 'getFileUrl'>
15 15
16export type MVideoCaptionVideo = MVideoCaption & 16export type MVideoCaptionVideo =
17 MVideoCaption &
17 Use<'Video', Pick<MVideo, 'id' | 'remote' | 'uuid'>> 18 Use<'Video', Pick<MVideo, 'id' | 'remote' | 'uuid'>>
18 19
19// ############################################################################ 20// ############################################################################
20 21
21// Format for API or AP object 22// Format for API or AP object
22 23
23export type MVideoCaptionFormattable = FunctionProperties<MVideoCaption> & 24export type MVideoCaptionFormattable =
25 FunctionProperties<MVideoCaption> &
24 Pick<MVideoCaption, 'language'> & 26 Pick<MVideoCaption, 'language'> &
25 Use<'Video', MVideoUUID> 27 Use<'Video', MVideoUUID>
diff --git a/server/typings/models/video/video-change-ownership.ts b/server/typings/models/video/video-change-ownership.ts
index e5b5bbc1d..971dc3db5 100644
--- a/server/typings/models/video/video-change-ownership.ts
+++ b/server/typings/models/video/video-change-ownership.ts
@@ -9,7 +9,8 @@ type Use<K extends keyof VideoChangeOwnershipModel, M> = PickWith<VideoChangeOwn
9 9
10export type MVideoChangeOwnership = Omit<VideoChangeOwnershipModel, 'Initiator' | 'NextOwner' | 'Video'> 10export type MVideoChangeOwnership = Omit<VideoChangeOwnershipModel, 'Initiator' | 'NextOwner' | 'Video'>
11 11
12export type MVideoChangeOwnershipFull = MVideoChangeOwnership & 12export type MVideoChangeOwnershipFull =
13 MVideoChangeOwnership &
13 Use<'Initiator', MAccountDefault> & 14 Use<'Initiator', MAccountDefault> &
14 Use<'NextOwner', MAccountDefault> & 15 Use<'NextOwner', MAccountDefault> &
15 Use<'Video', MVideoWithAllFiles> 16 Use<'Video', MVideoWithAllFiles>
@@ -18,7 +19,8 @@ export type MVideoChangeOwnershipFull = MVideoChangeOwnership &
18 19
19// Format for API or AP object 20// Format for API or AP object
20 21
21export type MVideoChangeOwnershipFormattable = Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> & 22export type MVideoChangeOwnershipFormattable =
23 Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> &
22 Use<'Initiator', MAccountFormattable> & 24 Use<'Initiator', MAccountFormattable> &
23 Use<'NextOwner', MAccountFormattable> & 25 Use<'NextOwner', MAccountFormattable> &
24 Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'url' | 'name'>> 26 Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'url' | 'name'>>
diff --git a/server/typings/models/video/video-channels.ts b/server/typings/models/video/video-channels.ts
index 292d0ac95..50f7c2d8a 100644
--- a/server/typings/models/video/video-channels.ts
+++ b/server/typings/models/video/video-channels.ts
@@ -35,32 +35,39 @@ export type MChannelId = Pick<MChannel, 'id'>
35 35
36// ############################################################################ 36// ############################################################################
37 37
38export type MChannelIdActor = MChannelId & 38export type MChannelIdActor =
39 MChannelId &
39 Use<'Actor', MActorAccountChannelId> 40 Use<'Actor', MActorAccountChannelId>
40 41
41export type MChannelUserId = Pick<MChannel, 'accountId'> & 42export type MChannelUserId =
43 Pick<MChannel, 'accountId'> &
42 Use<'Account', MAccountUserId> 44 Use<'Account', MAccountUserId>
43 45
44export type MChannelActor = MChannel & 46export type MChannelActor =
47 MChannel &
45 Use<'Actor', MActor> 48 Use<'Actor', MActor>
46 49
47export type MChannelUrl = Use<'Actor', MActorUrl> 50export type MChannelUrl = Use<'Actor', MActorUrl>
48 51
49// Default scope 52// Default scope
50export type MChannelDefault = MChannel & 53export type MChannelDefault =
54 MChannel &
51 Use<'Actor', MActorDefault> 55 Use<'Actor', MActorDefault>
52 56
53// ############################################################################ 57// ############################################################################
54 58
55// Not all association attributes 59// Not all association attributes
56 60
57export type MChannelLight = MChannel & 61export type MChannelLight =
62 MChannel &
58 Use<'Actor', MActorDefaultLight> 63 Use<'Actor', MActorDefaultLight>
59 64
60export type MChannelActorLight = MChannel & 65export type MChannelActorLight =
66 MChannel &
61 Use<'Actor', MActorLight> 67 Use<'Actor', MActorLight>
62 68
63export type MChannelAccountLight = MChannel & 69export type MChannelAccountLight =
70 MChannel &
64 Use<'Actor', MActorDefaultLight> & 71 Use<'Actor', MActorDefaultLight> &
65 Use<'Account', MAccountLight> 72 Use<'Account', MAccountLight>
66 73
@@ -68,24 +75,29 @@ export type MChannelAccountLight = MChannel &
68 75
69// Account associations 76// Account associations
70 77
71export type MChannelAccountActor = MChannel & 78export type MChannelAccountActor =
79 MChannel &
72 Use<'Account', MAccountActor> 80 Use<'Account', MAccountActor>
73 81
74export type MChannelAccountDefault = MChannel & 82export type MChannelAccountDefault =
83 MChannel &
75 Use<'Actor', MActorDefault> & 84 Use<'Actor', MActorDefault> &
76 Use<'Account', MAccountDefault> 85 Use<'Account', MAccountDefault>
77 86
78export type MChannelActorAccountActor = MChannel & 87export type MChannelActorAccountActor =
88 MChannel &
79 Use<'Account', MAccountActor> & 89 Use<'Account', MAccountActor> &
80 Use<'Actor', MActor> 90 Use<'Actor', MActor>
81 91
82// ############################################################################ 92// ############################################################################
83 93
84// Videos associations 94// Videos associations
85export type MChannelVideos = MChannel & 95export type MChannelVideos =
96 MChannel &
86 Use<'Videos', MVideo[]> 97 Use<'Videos', MVideo[]>
87 98
88export type MChannelActorAccountDefaultVideos = MChannel & 99export type MChannelActorAccountDefaultVideos =
100 MChannel &
89 Use<'Actor', MActorDefault> & 101 Use<'Actor', MActorDefault> &
90 Use<'Account', MAccountDefault> & 102 Use<'Account', MAccountDefault> &
91 Use<'Videos', MVideo[]> 103 Use<'Videos', MVideo[]>
@@ -94,14 +106,17 @@ export type MChannelActorAccountDefaultVideos = MChannel &
94 106
95// For API 107// For API
96 108
97export type MChannelSummary = FunctionProperties<MChannel> & 109export type MChannelSummary =
110 FunctionProperties<MChannel> &
98 Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> & 111 Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> &
99 Use<'Actor', MActorSummary> 112 Use<'Actor', MActorSummary>
100 113
101export type MChannelSummaryAccount = MChannelSummary & 114export type MChannelSummaryAccount =
115 MChannelSummary &
102 Use<'Account', MAccountSummaryBlocks> 116 Use<'Account', MAccountSummaryBlocks>
103 117
104export type MChannelAPI = MChannel & 118export type MChannelAPI =
119 MChannel &
105 Use<'Actor', MActorAPI> & 120 Use<'Actor', MActorAPI> &
106 Use<'Account', MAccountAPI> 121 Use<'Account', MAccountAPI>
107 122
@@ -109,18 +124,22 @@ export type MChannelAPI = MChannel &
109 124
110// Format for API or AP object 125// Format for API or AP object
111 126
112export type MChannelSummaryFormattable = FunctionProperties<MChannel> & 127export type MChannelSummaryFormattable =
128 FunctionProperties<MChannel> &
113 Pick<MChannel, 'id' | 'name'> & 129 Pick<MChannel, 'id' | 'name'> &
114 Use<'Actor', MActorSummaryFormattable> 130 Use<'Actor', MActorSummaryFormattable>
115 131
116export type MChannelAccountSummaryFormattable = MChannelSummaryFormattable & 132export type MChannelAccountSummaryFormattable =
133 MChannelSummaryFormattable &
117 Use<'Account', MAccountSummaryFormattable> 134 Use<'Account', MAccountSummaryFormattable>
118 135
119export type MChannelFormattable = FunctionProperties<MChannel> & 136export type MChannelFormattable =
137 FunctionProperties<MChannel> &
120 Pick<MChannel, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'support'> & 138 Pick<MChannel, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'support'> &
121 Use<'Actor', MActorFormattable> & 139 Use<'Actor', MActorFormattable> &
122 PickWithOpt<VideoChannelModel, 'Account', MAccountFormattable> 140 PickWithOpt<VideoChannelModel, 'Account', MAccountFormattable>
123 141
124export type MChannelAP = Pick<MChannel, 'name' | 'description' | 'support'> & 142export type MChannelAP =
143 Pick<MChannel, 'name' | 'description' | 'support'> &
125 Use<'Actor', MActorAP> & 144 Use<'Actor', MActorAP> &
126 Use<'Account', MAccountUrl> 145 Use<'Account', MAccountUrl>
diff --git a/server/typings/models/video/video-comment.ts b/server/typings/models/video/video-comment.ts
index d693f9186..d6e0b66f5 100644
--- a/server/typings/models/video/video-comment.ts
+++ b/server/typings/models/video/video-comment.ts
@@ -14,30 +14,37 @@ export type MCommentUrl = Pick<MComment, 'url'>
14 14
15// ############################################################################ 15// ############################################################################
16 16
17export type MCommentOwner = MComment & 17export type MCommentOwner =
18 MComment &
18 Use<'Account', MAccountDefault> 19 Use<'Account', MAccountDefault>
19 20
20export type MCommentVideo = MComment & 21export type MCommentVideo =
22 MComment &
21 Use<'Video', MVideoAccountLight> 23 Use<'Video', MVideoAccountLight>
22 24
23export type MCommentReply = MComment & 25export type MCommentReply =
26 MComment &
24 Use<'InReplyToVideoComment', MComment> 27 Use<'InReplyToVideoComment', MComment>
25 28
26export type MCommentOwnerVideo = MComment & 29export type MCommentOwnerVideo =
30 MComment &
27 Use<'Account', MAccountDefault> & 31 Use<'Account', MAccountDefault> &
28 Use<'Video', MVideoAccountLight> 32 Use<'Video', MVideoAccountLight>
29 33
30export type MCommentOwnerVideoReply = MComment & 34export type MCommentOwnerVideoReply =
35 MComment &
31 Use<'Account', MAccountDefault> & 36 Use<'Account', MAccountDefault> &
32 Use<'Video', MVideoAccountLight> & 37 Use<'Video', MVideoAccountLight> &
33 Use<'InReplyToVideoComment', MComment> 38 Use<'InReplyToVideoComment', MComment>
34 39
35export type MCommentOwnerReplyVideoLight = MComment & 40export type MCommentOwnerReplyVideoLight =
41 MComment &
36 Use<'Account', MAccountDefault> & 42 Use<'Account', MAccountDefault> &
37 Use<'InReplyToVideoComment', MComment> & 43 Use<'InReplyToVideoComment', MComment> &
38 Use<'Video', MVideoIdUrl> 44 Use<'Video', MVideoIdUrl>
39 45
40export type MCommentOwnerVideoFeed = MCommentOwner & 46export type MCommentOwnerVideoFeed =
47 MCommentOwner &
41 Use<'Video', MVideoFeed> 48 Use<'Video', MVideoFeed>
42 49
43// ############################################################################ 50// ############################################################################
@@ -48,10 +55,12 @@ export type MCommentAPI = MComment & { totalReplies: number }
48 55
49// Format for API or AP object 56// Format for API or AP object
50 57
51export type MCommentFormattable = MCommentTotalReplies & 58export type MCommentFormattable =
59 MCommentTotalReplies &
52 Use<'Account', MAccountFormattable> 60 Use<'Account', MAccountFormattable>
53 61
54export type MCommentAP = MComment & 62export type MCommentAP =
63 MComment &
55 Use<'Account', MAccountUrl> & 64 Use<'Account', MAccountUrl> &
56 PickWithOpt<VideoCommentModel, 'Video', MVideoUrl> & 65 PickWithOpt<VideoCommentModel, 'Video', MVideoUrl> &
57 PickWithOpt<VideoCommentModel, 'InReplyToVideoComment', MCommentUrl> 66 PickWithOpt<VideoCommentModel, 'InReplyToVideoComment', MCommentUrl>
diff --git a/server/typings/models/video/video-file.ts b/server/typings/models/video/video-file.ts
index 139b22b2c..3fcaca78f 100644
--- a/server/typings/models/video/video-file.ts
+++ b/server/typings/models/video/video-file.ts
@@ -10,22 +10,28 @@ type Use<K extends keyof VideoFileModel, M> = PickWith<VideoFileModel, K, M>
10 10
11export type MVideoFile = Omit<VideoFileModel, 'Video' | 'RedundancyVideos' | 'VideoStreamingPlaylist'> 11export type MVideoFile = Omit<VideoFileModel, 'Video' | 'RedundancyVideos' | 'VideoStreamingPlaylist'>
12 12
13export type MVideoFileVideo = MVideoFile & 13export type MVideoFileVideo =
14 MVideoFile &
14 Use<'Video', MVideo> 15 Use<'Video', MVideo>
15 16
16export type MVideoFileStreamingPlaylist = MVideoFile & 17export type MVideoFileStreamingPlaylist =
18 MVideoFile &
17 Use<'VideoStreamingPlaylist', MStreamingPlaylist> 19 Use<'VideoStreamingPlaylist', MStreamingPlaylist>
18 20
19export type MVideoFileStreamingPlaylistVideo = MVideoFile & 21export type MVideoFileStreamingPlaylistVideo =
22 MVideoFile &
20 Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> 23 Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo>
21 24
22export type MVideoFileVideoUUID = MVideoFile & 25export type MVideoFileVideoUUID =
26 MVideoFile &
23 Use<'Video', MVideoUUID> 27 Use<'Video', MVideoUUID>
24 28
25export type MVideoFileRedundanciesAll = MVideoFile & 29export type MVideoFileRedundanciesAll =
30 MVideoFile &
26 PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancy[]> 31 PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancy[]>
27 32
28export type MVideoFileRedundanciesOpt = MVideoFile & 33export type MVideoFileRedundanciesOpt =
34 MVideoFile &
29 PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> 35 PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]>
30 36
31export function isStreamingPlaylistFile (file: any): file is MVideoFileStreamingPlaylist { 37export function isStreamingPlaylistFile (file: any): file is MVideoFileStreamingPlaylist {
diff --git a/server/typings/models/video/video-import.ts b/server/typings/models/video/video-import.ts
index e119f17f9..4e5c2e4f0 100644
--- a/server/typings/models/video/video-import.ts
+++ b/server/typings/models/video/video-import.ts
@@ -9,18 +9,21 @@ type Use<K extends keyof VideoImportModel, M> = PickWith<VideoImportModel, K, M>
9 9
10export type MVideoImport = Omit<VideoImportModel, 'User' | 'Video'> 10export type MVideoImport = Omit<VideoImportModel, 'User' | 'Video'>
11 11
12export type MVideoImportVideo = MVideoImport & 12export type MVideoImportVideo =
13 MVideoImport &
13 Use<'Video', MVideo> 14 Use<'Video', MVideo>
14 15
15// ############################################################################ 16// ############################################################################
16 17
17type VideoAssociation = MVideoTag & MVideoAccountLight & MVideoThumbnail 18type VideoAssociation = MVideoTag & MVideoAccountLight & MVideoThumbnail
18 19
19export type MVideoImportDefault = MVideoImport & 20export type MVideoImportDefault =
21 MVideoImport &
20 Use<'User', MUser> & 22 Use<'User', MUser> &
21 Use<'Video', VideoAssociation> 23 Use<'Video', VideoAssociation>
22 24
23export type MVideoImportDefaultFiles = MVideoImport & 25export type MVideoImportDefaultFiles =
26 MVideoImport &
24 Use<'User', MUser> & 27 Use<'User', MUser> &
25 Use<'Video', VideoAssociation & MVideoWithFile> 28 Use<'Video', VideoAssociation & MVideoWithFile>
26 29
@@ -28,5 +31,6 @@ export type MVideoImportDefaultFiles = MVideoImport &
28 31
29// Format for API or AP object 32// Format for API or AP object
30 33
31export type MVideoImportFormattable = MVideoImport & 34export type MVideoImportFormattable =
35 MVideoImport &
32 PickWithOpt<VideoImportModel, 'Video', MVideoFormattable & MVideoTag> 36 PickWithOpt<VideoImportModel, 'Video', MVideoFormattable & MVideoTag>
diff --git a/server/typings/models/video/video-playlist-element.ts b/server/typings/models/video/video-playlist-element.ts
index 1aeff78d8..f33c76594 100644
--- a/server/typings/models/video/video-playlist-element.ts
+++ b/server/typings/models/video/video-playlist-element.ts
@@ -17,10 +17,12 @@ export type MVideoPlaylistElementLight = Pick<MVideoPlaylistElement, 'id' | 'vid
17 17
18// ############################################################################ 18// ############################################################################
19 19
20export type MVideoPlaylistVideoThumbnail = MVideoPlaylistElement & 20export type MVideoPlaylistVideoThumbnail =
21 MVideoPlaylistElement &
21 Use<'Video', MVideoThumbnail> 22 Use<'Video', MVideoThumbnail>
22 23
23export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = MVideoPlaylistElement & 24export type MVideoPlaylistElementVideoUrlPlaylistPrivacy =
25 MVideoPlaylistElement &
24 Use<'Video', MVideoUrl> & 26 Use<'Video', MVideoUrl> &
25 Use<'VideoPlaylist', MVideoPlaylistPrivacy> 27 Use<'VideoPlaylist', MVideoPlaylistPrivacy>
26 28
@@ -28,8 +30,10 @@ export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = MVideoPlaylistElement
28 30
29// Format for API or AP object 31// Format for API or AP object
30 32
31export type MVideoPlaylistElementFormattable = MVideoPlaylistElement & 33export type MVideoPlaylistElementFormattable =
34 MVideoPlaylistElement &
32 Use<'Video', MVideoFormattable> 35 Use<'Video', MVideoFormattable>
33 36
34export type MVideoPlaylistElementAP = MVideoPlaylistElement & 37export type MVideoPlaylistElementAP =
38 MVideoPlaylistElement &
35 Use<'Video', MVideoUrl> 39 Use<'Video', MVideoUrl>
diff --git a/server/typings/models/video/video-playlist.ts b/server/typings/models/video/video-playlist.ts
index a40c7aca9..49c27f4a7 100644
--- a/server/typings/models/video/video-playlist.ts
+++ b/server/typings/models/video/video-playlist.ts
@@ -22,30 +22,36 @@ export type MVideoPlaylistVideosLength = MVideoPlaylist & { videosLength?: numbe
22 22
23// With elements 23// With elements
24 24
25export type MVideoPlaylistWithElements = MVideoPlaylist & 25export type MVideoPlaylistWithElements =
26 MVideoPlaylist &
26 Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> 27 Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]>
27 28
28export type MVideoPlaylistIdWithElements = MVideoPlaylistId & 29export type MVideoPlaylistIdWithElements =
30 MVideoPlaylistId &
29 Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> 31 Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]>
30 32
31// ############################################################################ 33// ############################################################################
32 34
33// With account 35// With account
34 36
35export type MVideoPlaylistOwner = MVideoPlaylist & 37export type MVideoPlaylistOwner =
38 MVideoPlaylist &
36 Use<'OwnerAccount', MAccount> 39 Use<'OwnerAccount', MAccount>
37 40
38export type MVideoPlaylistOwnerDefault = MVideoPlaylist & 41export type MVideoPlaylistOwnerDefault =
42 MVideoPlaylist &
39 Use<'OwnerAccount', MAccountDefault> 43 Use<'OwnerAccount', MAccountDefault>
40 44
41// ############################################################################ 45// ############################################################################
42 46
43// With thumbnail 47// With thumbnail
44 48
45export type MVideoPlaylistThumbnail = MVideoPlaylist & 49export type MVideoPlaylistThumbnail =
50 MVideoPlaylist &
46 Use<'Thumbnail', MThumbnail> 51 Use<'Thumbnail', MThumbnail>
47 52
48export type MVideoPlaylistAccountThumbnail = MVideoPlaylist & 53export type MVideoPlaylistAccountThumbnail =
54 MVideoPlaylist &
49 Use<'OwnerAccount', MAccountDefault> & 55 Use<'OwnerAccount', MAccountDefault> &
50 Use<'Thumbnail', MThumbnail> 56 Use<'Thumbnail', MThumbnail>
51 57
@@ -53,7 +59,8 @@ export type MVideoPlaylistAccountThumbnail = MVideoPlaylist &
53 59
54// With channel 60// With channel
55 61
56export type MVideoPlaylistAccountChannelDefault = MVideoPlaylist & 62export type MVideoPlaylistAccountChannelDefault =
63 MVideoPlaylist &
57 Use<'OwnerAccount', MAccountDefault> & 64 Use<'OwnerAccount', MAccountDefault> &
58 Use<'VideoChannel', MChannelDefault> 65 Use<'VideoChannel', MChannelDefault>
59 66
@@ -61,7 +68,8 @@ export type MVideoPlaylistAccountChannelDefault = MVideoPlaylist &
61 68
62// With all associations 69// With all associations
63 70
64export type MVideoPlaylistFull = MVideoPlaylist & 71export type MVideoPlaylistFull =
72 MVideoPlaylist &
65 Use<'OwnerAccount', MAccountDefault> & 73 Use<'OwnerAccount', MAccountDefault> &
66 Use<'VideoChannel', MChannelDefault> & 74 Use<'VideoChannel', MChannelDefault> &
67 Use<'Thumbnail', MThumbnail> 75 Use<'Thumbnail', MThumbnail>
@@ -70,11 +78,13 @@ export type MVideoPlaylistFull = MVideoPlaylist &
70 78
71// For API 79// For API
72 80
73export type MVideoPlaylistAccountChannelSummary = MVideoPlaylist & 81export type MVideoPlaylistAccountChannelSummary =
82 MVideoPlaylist &
74 Use<'OwnerAccount', MAccountSummary> & 83 Use<'OwnerAccount', MAccountSummary> &
75 Use<'VideoChannel', MChannelSummary> 84 Use<'VideoChannel', MChannelSummary>
76 85
77export type MVideoPlaylistFullSummary = MVideoPlaylist & 86export type MVideoPlaylistFullSummary =
87 MVideoPlaylist &
78 Use<'Thumbnail', MThumbnail> & 88 Use<'Thumbnail', MThumbnail> &
79 Use<'OwnerAccount', MAccountSummary> & 89 Use<'OwnerAccount', MAccountSummary> &
80 Use<'VideoChannel', MChannelSummary> 90 Use<'VideoChannel', MChannelSummary>
@@ -83,10 +93,12 @@ export type MVideoPlaylistFullSummary = MVideoPlaylist &
83 93
84// Format for API or AP object 94// Format for API or AP object
85 95
86export type MVideoPlaylistFormattable = MVideoPlaylistVideosLength & 96export type MVideoPlaylistFormattable =
97 MVideoPlaylistVideosLength &
87 Use<'OwnerAccount', MAccountSummaryFormattable> & 98 Use<'OwnerAccount', MAccountSummaryFormattable> &
88 Use<'VideoChannel', MChannelSummaryFormattable> 99 Use<'VideoChannel', MChannelSummaryFormattable>
89 100
90export type MVideoPlaylistAP = MVideoPlaylist & 101export type MVideoPlaylistAP =
102 MVideoPlaylist &
91 Use<'Thumbnail', MThumbnail> & 103 Use<'Thumbnail', MThumbnail> &
92 Use<'VideoChannel', MChannelUrl> 104 Use<'VideoChannel', MChannelUrl>
diff --git a/server/typings/models/video/video-rate.ts b/server/typings/models/video/video-rate.ts
index f6bb527fc..64ce4965b 100644
--- a/server/typings/models/video/video-rate.ts
+++ b/server/typings/models/video/video-rate.ts
@@ -9,10 +9,12 @@ type Use<K extends keyof AccountVideoRateModel, M> = PickWith<AccountVideoRateMo
9 9
10export type MAccountVideoRate = Omit<AccountVideoRateModel, 'Video' | 'Account'> 10export type MAccountVideoRate = Omit<AccountVideoRateModel, 'Video' | 'Account'>
11 11
12export type MAccountVideoRateAccountUrl = MAccountVideoRate & 12export type MAccountVideoRateAccountUrl =
13 MAccountVideoRate &
13 Use<'Account', MAccountUrl> 14 Use<'Account', MAccountUrl>
14 15
15export type MAccountVideoRateAccountVideo = MAccountVideoRate & 16export type MAccountVideoRateAccountVideo =
17 MAccountVideoRate &
16 Use<'Account', MAccountAudience> & 18 Use<'Account', MAccountAudience> &
17 Use<'Video', MVideo> 19 Use<'Video', MVideo>
18 20
@@ -20,5 +22,6 @@ export type MAccountVideoRateAccountVideo = MAccountVideoRate &
20 22
21// Format for API or AP object 23// Format for API or AP object
22 24
23export type MAccountVideoRateFormattable = Pick<MAccountVideoRate, 'type'> & 25export type MAccountVideoRateFormattable =
26 Pick<MAccountVideoRate, 'type'> &
24 Use<'Video', MVideoFormattable> 27 Use<'Video', MVideoFormattable>
diff --git a/server/typings/models/video/video-redundancy.ts b/server/typings/models/video/video-redundancy.ts
index 25bdac057..5107aa7f4 100644
--- a/server/typings/models/video/video-redundancy.ts
+++ b/server/typings/models/video/video-redundancy.ts
@@ -16,16 +16,20 @@ export type MVideoRedundancyFileUrl = Pick<MVideoRedundancy, 'fileUrl'>
16 16
17// ############################################################################ 17// ############################################################################
18 18
19export type MVideoRedundancyFile = MVideoRedundancy & 19export type MVideoRedundancyFile =
20 MVideoRedundancy &
20 Use<'VideoFile', MVideoFile> 21 Use<'VideoFile', MVideoFile>
21 22
22export type MVideoRedundancyFileVideo = MVideoRedundancy & 23export type MVideoRedundancyFileVideo =
24 MVideoRedundancy &
23 Use<'VideoFile', MVideoFileVideo> 25 Use<'VideoFile', MVideoFileVideo>
24 26
25export type MVideoRedundancyStreamingPlaylistVideo = MVideoRedundancy & 27export type MVideoRedundancyStreamingPlaylistVideo =
28 MVideoRedundancy &
26 Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> 29 Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo>
27 30
28export type MVideoRedundancyVideo = MVideoRedundancy & 31export type MVideoRedundancyVideo =
32 MVideoRedundancy &
29 Use<'VideoFile', MVideoFileVideo> & 33 Use<'VideoFile', MVideoFileVideo> &
30 Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> 34 Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo>
31 35
@@ -33,6 +37,7 @@ export type MVideoRedundancyVideo = MVideoRedundancy &
33 37
34// Format for API or AP object 38// Format for API or AP object
35 39
36export type MVideoRedundancyAP = MVideoRedundancy & 40export type MVideoRedundancyAP =
41 MVideoRedundancy &
37 PickWithOpt<VideoRedundancyModel, 'VideoFile', MVideoFile & PickWith<VideoFileModel, 'Video', MVideoUrl>> & 42 PickWithOpt<VideoRedundancyModel, 'VideoFile', MVideoFile & PickWith<VideoFileModel, 'Video', MVideoUrl>> &
38 PickWithOpt<VideoRedundancyModel, 'VideoStreamingPlaylist', PickWith<VideoStreamingPlaylistModel, 'Video', MVideoUrl>> 43 PickWithOpt<VideoRedundancyModel, 'VideoStreamingPlaylist', PickWith<VideoStreamingPlaylistModel, 'Video', MVideoUrl>>
diff --git a/server/typings/models/video/video-share.ts b/server/typings/models/video/video-share.ts
index a7a90beeb..50ca75d26 100644
--- a/server/typings/models/video/video-share.ts
+++ b/server/typings/models/video/video-share.ts
@@ -9,9 +9,11 @@ type Use<K extends keyof VideoShareModel, M> = PickWith<VideoShareModel, K, M>
9 9
10export type MVideoShare = Omit<VideoShareModel, 'Actor' | 'Video'> 10export type MVideoShare = Omit<VideoShareModel, 'Actor' | 'Video'>
11 11
12export type MVideoShareActor = MVideoShare & 12export type MVideoShareActor =
13 MVideoShare &
13 Use<'Actor', MActorDefault> 14 Use<'Actor', MActorDefault>
14 15
15export type MVideoShareFull = MVideoShare & 16export type MVideoShareFull =
17 MVideoShare &
16 Use<'Actor', MActorDefault> & 18 Use<'Actor', MActorDefault> &
17 Use<'Video', MVideo> 19 Use<'Video', MVideo>
diff --git a/server/typings/models/video/video-streaming-playlist.ts b/server/typings/models/video/video-streaming-playlist.ts
index 6fd489945..3f54aa560 100644
--- a/server/typings/models/video/video-streaming-playlist.ts
+++ b/server/typings/models/video/video-streaming-playlist.ts
@@ -10,25 +10,31 @@ type Use<K extends keyof VideoStreamingPlaylistModel, M> = PickWith<VideoStreami
10 10
11export type MStreamingPlaylist = Omit<VideoStreamingPlaylistModel, 'Video' | 'RedundancyVideos' | 'VideoFiles'> 11export type MStreamingPlaylist = Omit<VideoStreamingPlaylistModel, 'Video' | 'RedundancyVideos' | 'VideoFiles'>
12 12
13export type MStreamingPlaylistFiles = MStreamingPlaylist & 13export type MStreamingPlaylistFiles =
14 MStreamingPlaylist &
14 Use<'VideoFiles', MVideoFile[]> 15 Use<'VideoFiles', MVideoFile[]>
15 16
16export type MStreamingPlaylistVideo = MStreamingPlaylist & 17export type MStreamingPlaylistVideo =
18 MStreamingPlaylist &
17 Use<'Video', MVideo> 19 Use<'Video', MVideo>
18 20
19export type MStreamingPlaylistFilesVideo = MStreamingPlaylist & 21export type MStreamingPlaylistFilesVideo =
22 MStreamingPlaylist &
20 Use<'VideoFiles', MVideoFile[]> & 23 Use<'VideoFiles', MVideoFile[]> &
21 Use<'Video', MVideo> 24 Use<'Video', MVideo>
22 25
23export type MStreamingPlaylistRedundanciesAll = MStreamingPlaylist & 26export type MStreamingPlaylistRedundanciesAll =
27 MStreamingPlaylist &
24 Use<'VideoFiles', MVideoFile[]> & 28 Use<'VideoFiles', MVideoFile[]> &
25 Use<'RedundancyVideos', MVideoRedundancy[]> 29 Use<'RedundancyVideos', MVideoRedundancy[]>
26 30
27export type MStreamingPlaylistRedundancies = MStreamingPlaylist & 31export type MStreamingPlaylistRedundancies =
32 MStreamingPlaylist &
28 Use<'VideoFiles', MVideoFile[]> & 33 Use<'VideoFiles', MVideoFile[]> &
29 Use<'RedundancyVideos', MVideoRedundancyFileUrl[]> 34 Use<'RedundancyVideos', MVideoRedundancyFileUrl[]>
30 35
31export type MStreamingPlaylistRedundanciesOpt = MStreamingPlaylist & 36export type MStreamingPlaylistRedundanciesOpt =
37 MStreamingPlaylist &
32 Use<'VideoFiles', MVideoFile[]> & 38 Use<'VideoFiles', MVideoFile[]> &
33 PickWithOpt<VideoStreamingPlaylistModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> 39 PickWithOpt<VideoStreamingPlaylistModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]>
34 40
diff --git a/server/typings/models/video/video.ts b/server/typings/models/video/video.ts
index 82d76f40c..7eff0a913 100644
--- a/server/typings/models/video/video.ts
+++ b/server/typings/models/video/video.ts
@@ -26,7 +26,8 @@ type Use<K extends keyof VideoModel, M> = PickWith<VideoModel, K, M>
26 26
27// ############################################################################ 27// ############################################################################
28 28
29export type MVideo = Omit<VideoModel, 'VideoChannel' | 'Tags' | 'Thumbnails' | 'VideoPlaylistElements' | 'VideoAbuses' | 29export type MVideo =
30 Omit<VideoModel, 'VideoChannel' | 'Tags' | 'Thumbnails' | 'VideoPlaylistElements' | 'VideoAbuses' |
30 'VideoFiles' | 'VideoStreamingPlaylists' | 'VideoShares' | 'AccountVideoRates' | 'VideoComments' | 'VideoViews' | 'UserVideoHistories' | 31 'VideoFiles' | 'VideoStreamingPlaylists' | 'VideoShares' | 'AccountVideoRates' | 'VideoComments' | 'VideoViews' | 'UserVideoHistories' |
31 'ScheduleVideoUpdate' | 'VideoBlacklist' | 'VideoImport' | 'VideoCaptions'> 32 'ScheduleVideoUpdate' | 'VideoBlacklist' | 'VideoImport' | 'VideoCaptions'>
32 33
@@ -44,50 +45,63 @@ export type MVideoFeed = Pick<MVideo, 'name' | 'uuid'>
44// Video raw associations: schedules, video files, tags, thumbnails, captions, streaming playlists 45// Video raw associations: schedules, video files, tags, thumbnails, captions, streaming playlists
45 46
46// "With" to not confuse with the VideoFile model 47// "With" to not confuse with the VideoFile model
47export type MVideoWithFile = MVideo & 48export type MVideoWithFile =
49 MVideo &
48 Use<'VideoFiles', MVideoFile[]> & 50 Use<'VideoFiles', MVideoFile[]> &
49 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> 51 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]>
50 52
51export type MVideoThumbnail = MVideo & 53export type MVideoThumbnail =
54 MVideo &
52 Use<'Thumbnails', MThumbnail[]> 55 Use<'Thumbnails', MThumbnail[]>
53 56
54export type MVideoIdThumbnail = MVideoId & 57export type MVideoIdThumbnail =
58 MVideoId &
55 Use<'Thumbnails', MThumbnail[]> 59 Use<'Thumbnails', MThumbnail[]>
56 60
57export type MVideoWithFileThumbnail = MVideo & 61export type MVideoWithFileThumbnail =
62 MVideo &
58 Use<'VideoFiles', MVideoFile[]> & 63 Use<'VideoFiles', MVideoFile[]> &
59 Use<'Thumbnails', MThumbnail[]> 64 Use<'Thumbnails', MThumbnail[]>
60 65
61export type MVideoThumbnailBlacklist = MVideo & 66export type MVideoThumbnailBlacklist =
67 MVideo &
62 Use<'Thumbnails', MThumbnail[]> & 68 Use<'Thumbnails', MThumbnail[]> &
63 Use<'VideoBlacklist', MVideoBlacklistLight> 69 Use<'VideoBlacklist', MVideoBlacklistLight>
64 70
65export type MVideoTag = MVideo & 71export type MVideoTag =
72 MVideo &
66 Use<'Tags', MTag[]> 73 Use<'Tags', MTag[]>
67 74
68export type MVideoWithSchedule = MVideo & 75export type MVideoWithSchedule =
76 MVideo &
69 PickWithOpt<VideoModel, 'ScheduleVideoUpdate', MScheduleVideoUpdate> 77 PickWithOpt<VideoModel, 'ScheduleVideoUpdate', MScheduleVideoUpdate>
70 78
71export type MVideoWithCaptions = MVideo & 79export type MVideoWithCaptions =
80 MVideo &
72 Use<'VideoCaptions', MVideoCaptionLanguage[]> 81 Use<'VideoCaptions', MVideoCaptionLanguage[]>
73 82
74export type MVideoWithStreamingPlaylist = MVideo & 83export type MVideoWithStreamingPlaylist =
84 MVideo &
75 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> 85 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]>
76 86
77// ############################################################################ 87// ############################################################################
78 88
79// Associations with not all their attributes 89// Associations with not all their attributes
80 90
81export type MVideoUserHistory = MVideo & 91export type MVideoUserHistory =
92 MVideo &
82 Use<'UserVideoHistories', MUserVideoHistoryTime[]> 93 Use<'UserVideoHistories', MUserVideoHistoryTime[]>
83 94
84export type MVideoWithBlacklistLight = MVideo & 95export type MVideoWithBlacklistLight =
96 MVideo &
85 Use<'VideoBlacklist', MVideoBlacklistLight> 97 Use<'VideoBlacklist', MVideoBlacklistLight>
86 98
87export type MVideoAccountLight = MVideo & 99export type MVideoAccountLight =
100 MVideo &
88 Use<'VideoChannel', MChannelAccountLight> 101 Use<'VideoChannel', MChannelAccountLight>
89 102
90export type MVideoWithRights = MVideo & 103export type MVideoWithRights =
104 MVideo &
91 Use<'VideoBlacklist', MVideoBlacklistLight> & 105 Use<'VideoBlacklist', MVideoBlacklistLight> &
92 Use<'Thumbnails', MThumbnail[]> & 106 Use<'Thumbnails', MThumbnail[]> &
93 Use<'VideoChannel', MChannelUserId> 107 Use<'VideoChannel', MChannelUserId>
@@ -96,12 +110,14 @@ export type MVideoWithRights = MVideo &
96 110
97// All files with some additional associations 111// All files with some additional associations
98 112
99export type MVideoWithAllFiles = MVideo & 113export type MVideoWithAllFiles =
114 MVideo &
100 Use<'VideoFiles', MVideoFile[]> & 115 Use<'VideoFiles', MVideoFile[]> &
101 Use<'Thumbnails', MThumbnail[]> & 116 Use<'Thumbnails', MThumbnail[]> &
102 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> 117 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]>
103 118
104export type MVideoAccountLightBlacklistAllFiles = MVideo & 119export type MVideoAccountLightBlacklistAllFiles =
120 MVideo &
105 Use<'VideoFiles', MVideoFile[]> & 121 Use<'VideoFiles', MVideoFile[]> &
106 Use<'Thumbnails', MThumbnail[]> & 122 Use<'Thumbnails', MThumbnail[]> &
107 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & 123 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> &
@@ -112,17 +128,21 @@ export type MVideoAccountLightBlacklistAllFiles = MVideo &
112 128
113// With account 129// With account
114 130
115export type MVideoAccountDefault = MVideo & 131export type MVideoAccountDefault =
132 MVideo &
116 Use<'VideoChannel', MChannelAccountDefault> 133 Use<'VideoChannel', MChannelAccountDefault>
117 134
118export type MVideoThumbnailAccountDefault = MVideo & 135export type MVideoThumbnailAccountDefault =
136 MVideo &
119 Use<'Thumbnails', MThumbnail[]> & 137 Use<'Thumbnails', MThumbnail[]> &
120 Use<'VideoChannel', MChannelAccountDefault> 138 Use<'VideoChannel', MChannelAccountDefault>
121 139
122export type MVideoWithChannelActor = MVideo & 140export type MVideoWithChannelActor =
141 MVideo &
123 Use<'VideoChannel', MChannelActor> 142 Use<'VideoChannel', MChannelActor>
124 143
125export type MVideoFullLight = MVideo & 144export type MVideoFullLight =
145 MVideo &
126 Use<'Thumbnails', MThumbnail[]> & 146 Use<'Thumbnails', MThumbnail[]> &
127 Use<'VideoBlacklist', MVideoBlacklistLight> & 147 Use<'VideoBlacklist', MVideoBlacklistLight> &
128 Use<'Tags', MTag[]> & 148 Use<'Tags', MTag[]> &
@@ -136,7 +156,8 @@ export type MVideoFullLight = MVideo &
136 156
137// API 157// API
138 158
139export type MVideoAP = MVideo & 159export type MVideoAP =
160 MVideo &
140 Use<'Tags', MTag[]> & 161 Use<'Tags', MTag[]> &
141 Use<'VideoChannel', MChannelAccountLight> & 162 Use<'VideoChannel', MChannelAccountLight> &
142 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & 163 Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> &
@@ -147,7 +168,8 @@ export type MVideoAP = MVideo &
147 168
148export type MVideoAPWithoutCaption = Omit<MVideoAP, 'VideoCaptions'> 169export type MVideoAPWithoutCaption = Omit<MVideoAP, 'VideoCaptions'>
149 170
150export type MVideoDetails = MVideo & 171export type MVideoDetails =
172 MVideo &
151 Use<'VideoBlacklist', MVideoBlacklistLight> & 173 Use<'VideoBlacklist', MVideoBlacklistLight> &
152 Use<'Tags', MTag[]> & 174 Use<'Tags', MTag[]> &
153 Use<'VideoChannel', MChannelAccountLight> & 175 Use<'VideoChannel', MChannelAccountLight> &
@@ -157,13 +179,15 @@ export type MVideoDetails = MVideo &
157 Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundancies[]> & 179 Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundancies[]> &
158 Use<'VideoFiles', MVideoFileRedundanciesOpt[]> 180 Use<'VideoFiles', MVideoFileRedundanciesOpt[]>
159 181
160export type MVideoForUser = MVideo & 182export type MVideoForUser =
183 MVideo &
161 Use<'VideoChannel', MChannelAccountDefault> & 184 Use<'VideoChannel', MChannelAccountDefault> &
162 Use<'ScheduleVideoUpdate', MScheduleVideoUpdate> & 185 Use<'ScheduleVideoUpdate', MScheduleVideoUpdate> &
163 Use<'VideoBlacklist', MVideoBlacklistLight> & 186 Use<'VideoBlacklist', MVideoBlacklistLight> &
164 Use<'Thumbnails', MThumbnail[]> 187 Use<'Thumbnails', MThumbnail[]>
165 188
166export type MVideoForRedundancyAPI = MVideo & 189export type MVideoForRedundancyAPI =
190 MVideo &
167 Use<'VideoFiles', MVideoFileRedundanciesAll[]> & 191 Use<'VideoFiles', MVideoFileRedundanciesAll[]> &
168 Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesAll[]> 192 Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesAll[]>
169 193
@@ -171,13 +195,15 @@ export type MVideoForRedundancyAPI = MVideo &
171 195
172// Format for API or AP object 196// Format for API or AP object
173 197
174export type MVideoFormattable = MVideo & 198export type MVideoFormattable =
199 MVideo &
175 PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> & 200 PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> &
176 Use<'VideoChannel', MChannelAccountSummaryFormattable> & 201 Use<'VideoChannel', MChannelAccountSummaryFormattable> &
177 PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> & 202 PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> &
178 PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>> 203 PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>>
179 204
180export type MVideoFormattableDetails = MVideoFormattable & 205export type MVideoFormattableDetails =
206 MVideoFormattable &
181 Use<'VideoChannel', MChannelFormattable> & 207 Use<'VideoChannel', MChannelFormattable> &
182 Use<'Tags', MTag[]> & 208 Use<'Tags', MTag[]> &
183 Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesOpt[]> & 209 Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesOpt[]> &
diff --git a/server/typings/utils.ts b/server/typings/utils.ts
index 24d43b258..55500d8c4 100644
--- a/server/typings/utils.ts
+++ b/server/typings/utils.ts
@@ -1,3 +1,5 @@
1/* eslint-disable @typescript-eslint/array-type */
2
1export type FunctionPropertyNames<T> = { 3export type FunctionPropertyNames<T> = {
2 [K in keyof T]: T[K] extends Function ? K : never 4 [K in keyof T]: T[K] extends Function ? K : never
3}[keyof T] 5}[keyof T]
diff --git a/shared/core-utils/miscs/miscs.ts b/shared/core-utils/miscs/miscs.ts
index 5de024c08..1eee22d82 100644
--- a/shared/core-utils/miscs/miscs.ts
+++ b/shared/core-utils/miscs/miscs.ts
@@ -11,7 +11,7 @@ function compareSemVer (a: string, b: string) {
11 const l = Math.min(segmentsA.length, segmentsB.length) 11 const l = Math.min(segmentsA.length, segmentsB.length)
12 12
13 for (let i = 0; i < l; i++) { 13 for (let i = 0; i < l; i++) {
14 const diff = parseInt(segmentsA[ i ], 10) - parseInt(segmentsB[ i ], 10) 14 const diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10)
15 15
16 if (diff) return diff 16 if (diff) return diff
17 } 17 }
diff --git a/shared/extra-utils/instances-index/mock-instances-index.ts b/shared/extra-utils/instances-index/mock-instances-index.ts
index cfa4523c1..c58e8bcf8 100644
--- a/shared/extra-utils/instances-index/mock-instances-index.ts
+++ b/shared/extra-utils/instances-index/mock-instances-index.ts
@@ -1,7 +1,7 @@
1import * as express from 'express' 1import * as express from 'express'
2 2
3export class MockInstancesIndex { 3export class MockInstancesIndex {
4 private indexInstances: { host: string, createdAt: string }[] = [] 4 private readonly indexInstances: { host: string, createdAt: string }[] = []
5 5
6 initialize () { 6 initialize () {
7 return new Promise(res => { 7 return new Promise(res => {
diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts
index d04003988..f4e86b85a 100644
--- a/shared/extra-utils/miscs/miscs.ts
+++ b/shared/extra-utils/miscs/miscs.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import { basename, dirname, isAbsolute, join, resolve } from 'path' 4import { basename, dirname, isAbsolute, join, resolve } from 'path'
@@ -10,11 +10,11 @@ import * as ffmpeg from 'fluent-ffmpeg'
10const expect = chai.expect 10const expect = chai.expect
11let webtorrent: WebTorrent.Instance 11let webtorrent: WebTorrent.Instance
12 12
13function immutableAssign <T, U> (target: T, source: U) { 13function immutableAssign<T, U> (target: T, source: U) {
14 return Object.assign<{}, T, U>({}, target, source) 14 return Object.assign<{}, T, U>({}, target, source)
15} 15}
16 16
17 // Default interval -> 5 minutes 17// Default interval -> 5 minutes
18function dateIsValid (dateString: string, interval = 300000) { 18function dateIsValid (dateString: string, interval = 300000) {
19 const dateToCheck = new Date(dateString) 19 const dateToCheck = new Date(dateString)
20 const now = new Date() 20 const now = new Date()
@@ -89,7 +89,7 @@ async function generateHighBitrateVideo () {
89 // a large file in the repo. The video needs to have a certain minimum length so 89 // a large file in the repo. The video needs to have a certain minimum length so
90 // that FFmpeg properly applies bitrate limits. 90 // that FFmpeg properly applies bitrate limits.
91 // https://stackoverflow.com/a/15795112 91 // https://stackoverflow.com/a/15795112
92 return new Promise<string>(async (res, rej) => { 92 return new Promise<string>((res, rej) => {
93 ffmpeg() 93 ffmpeg()
94 .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) 94 .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ])
95 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) 95 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
@@ -111,7 +111,7 @@ async function generateVideoWithFramerate (fps = 60) {
111 111
112 const exists = await pathExists(tempFixturePath) 112 const exists = await pathExists(tempFixturePath)
113 if (!exists) { 113 if (!exists) {
114 return new Promise<string>(async (res, rej) => { 114 return new Promise<string>((res, rej) => {
115 ffmpeg() 115 ffmpeg()
116 .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ]) 116 .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ])
117 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) 117 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
diff --git a/shared/extra-utils/miscs/sql.ts b/shared/extra-utils/miscs/sql.ts
index 42599c20e..5bd5d5d8a 100644
--- a/shared/extra-utils/miscs/sql.ts
+++ b/shared/extra-utils/miscs/sql.ts
@@ -1,7 +1,7 @@
1import { QueryTypes, Sequelize } from 'sequelize' 1import { QueryTypes, Sequelize } from 'sequelize'
2import { ServerInfo } from '../server/servers' 2import { ServerInfo } from '../server/servers'
3 3
4let sequelizes: { [ id: number ]: Sequelize } = {} 4const sequelizes: { [ id: number ]: Sequelize } = {}
5 5
6function getSequelize (internalServerNumber: number) { 6function getSequelize (internalServerNumber: number) {
7 if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber] 7 if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber]
@@ -52,7 +52,8 @@ async function countVideoViewsOf (internalServerNumber: number, uuid: string) {
52 const seq = getSequelize(internalServerNumber) 52 const seq = getSequelize(internalServerNumber)
53 53
54 // tslint:disable 54 // tslint:disable
55 const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'` 55 const query = 'SELECT SUM("videoView"."views") AS "total" FROM "videoView" ' +
56 `INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
56 57
57 const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } 58 const options = { type: QueryTypes.SELECT as QueryTypes.SELECT }
58 const [ { total } ] = await seq.query<{ total: number }>(query, options) 59 const [ { total } ] = await seq.query<{ total: number }>(query, options)
@@ -64,9 +65,10 @@ async function countVideoViewsOf (internalServerNumber: number, uuid: string) {
64 65
65async function closeAllSequelize (servers: ServerInfo[]) { 66async function closeAllSequelize (servers: ServerInfo[]) {
66 for (const server of servers) { 67 for (const server of servers) {
67 if (sequelizes[ server.internalServerNumber ]) { 68 if (sequelizes[server.internalServerNumber]) {
68 await sequelizes[ server.internalServerNumber ].close() 69 await sequelizes[server.internalServerNumber].close()
69 delete sequelizes[ server.internalServerNumber ] 70 // eslint-disable-next-line
71 delete sequelizes[server.internalServerNumber]
70 } 72 }
71 } 73 }
72} 74}
diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts
index 3532fb429..61167f212 100644
--- a/shared/extra-utils/requests/requests.ts
+++ b/shared/extra-utils/requests/requests.ts
@@ -1,25 +1,27 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { buildAbsoluteFixturePath, root } from '../miscs/miscs' 4import { buildAbsoluteFixturePath, root } from '../miscs/miscs'
3import { isAbsolute, join } from 'path' 5import { isAbsolute, join } from 'path'
4import { parse } from 'url' 6import { URL } from 'url'
5 7
6function get4KFileUrl () { 8function get4KFileUrl () {
7 return 'https://download.cpy.re/peertube/4k_file.txt' 9 return 'https://download.cpy.re/peertube/4k_file.txt'
8} 10}
9 11
10function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) { 12function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) {
11 const { host, protocol, pathname } = parse(url) 13 const { host, protocol, pathname } = new URL(url)
12 14
13 return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range }) 15 return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range })
14} 16}
15 17
16function makeGetRequest (options: { 18function makeGetRequest (options: {
17 url: string, 19 url: string
18 path?: string, 20 path?: string
19 query?: any, 21 query?: any
20 token?: string, 22 token?: string
21 statusCodeExpected?: number, 23 statusCodeExpected?: number
22 contentType?: string, 24 contentType?: string
23 range?: string 25 range?: string
24}) { 26}) {
25 if (!options.statusCodeExpected) options.statusCodeExpected = 400 27 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -36,9 +38,9 @@ function makeGetRequest (options: {
36} 38}
37 39
38function makeDeleteRequest (options: { 40function makeDeleteRequest (options: {
39 url: string, 41 url: string
40 path: string, 42 path: string
41 token?: string, 43 token?: string
42 statusCodeExpected?: number 44 statusCodeExpected?: number
43}) { 45}) {
44 if (!options.statusCodeExpected) options.statusCodeExpected = 400 46 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -53,12 +55,12 @@ function makeDeleteRequest (options: {
53} 55}
54 56
55function makeUploadRequest (options: { 57function makeUploadRequest (options: {
56 url: string, 58 url: string
57 method?: 'POST' | 'PUT', 59 method?: 'POST' | 'PUT'
58 path: string, 60 path: string
59 token?: string, 61 token?: string
60 fields: { [ fieldName: string ]: any }, 62 fields: { [ fieldName: string ]: any }
61 attaches: { [ attachName: string ]: any | any[] }, 63 attaches: { [ attachName: string ]: any | any[] }
62 statusCodeExpected?: number 64 statusCodeExpected?: number
63}) { 65}) {
64 if (!options.statusCodeExpected) options.statusCodeExpected = 400 66 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -101,10 +103,10 @@ function makeUploadRequest (options: {
101} 103}
102 104
103function makePostBodyRequest (options: { 105function makePostBodyRequest (options: {
104 url: string, 106 url: string
105 path: string, 107 path: string
106 token?: string, 108 token?: string
107 fields?: { [ fieldName: string ]: any }, 109 fields?: { [ fieldName: string ]: any }
108 statusCodeExpected?: number 110 statusCodeExpected?: number
109}) { 111}) {
110 if (!options.fields) options.fields = {} 112 if (!options.fields) options.fields = {}
@@ -121,10 +123,10 @@ function makePostBodyRequest (options: {
121} 123}
122 124
123function makePutBodyRequest (options: { 125function makePutBodyRequest (options: {
124 url: string, 126 url: string
125 path: string, 127 path: string
126 token?: string, 128 token?: string
127 fields: { [ fieldName: string ]: any }, 129 fields: { [ fieldName: string ]: any }
128 statusCodeExpected?: number 130 statusCodeExpected?: number
129}) { 131}) {
130 if (!options.statusCodeExpected) options.statusCodeExpected = 400 132 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -147,9 +149,9 @@ function makeHTMLRequest (url: string, path: string) {
147} 149}
148 150
149function updateAvatarRequest (options: { 151function updateAvatarRequest (options: {
150 url: string, 152 url: string
151 path: string, 153 path: string
152 accessToken: string, 154 accessToken: string
153 fixture: string 155 fixture: string
154}) { 156}) {
155 let filePath = '' 157 let filePath = ''
diff --git a/shared/extra-utils/search/videos.ts b/shared/extra-utils/search/videos.ts
index da806e692..4c52ea11c 100644
--- a/shared/extra-utils/search/videos.ts
+++ b/shared/extra-utils/search/videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as request from 'supertest' 3import * as request from 'supertest'
4import { VideosSearchQuery } from '../../models/search' 4import { VideosSearchQuery } from '../../models/search'
diff --git a/shared/extra-utils/server/clients.ts b/shared/extra-utils/server/clients.ts
index 273aac747..dc631e823 100644
--- a/shared/extra-utils/server/clients.ts
+++ b/shared/extra-utils/server/clients.ts
@@ -1,12 +1,12 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2import * as urlUtil from 'url' 2import { URL } from 'url'
3 3
4function getClient (url: string) { 4function getClient (url: string) {
5 const path = '/api/v1/oauth-clients/local' 5 const path = '/api/v1/oauth-clients/local'
6 6
7 return request(url) 7 return request(url)
8 .get(path) 8 .get(path)
9 .set('Host', urlUtil.parse(url).host) 9 .set('Host', new URL(url).host)
10 .set('Accept', 'application/json') 10 .set('Accept', 'application/json')
11 .expect(200) 11 .expect(200)
12 .expect('Content-Type', /json/) 12 .expect('Content-Type', /json/)
diff --git a/shared/extra-utils/server/contact-form.ts b/shared/extra-utils/server/contact-form.ts
index e002e03dd..d50f83241 100644
--- a/shared/extra-utils/server/contact-form.ts
+++ b/shared/extra-utils/server/contact-form.ts
@@ -2,11 +2,11 @@ import * as request from 'supertest'
2import { ContactForm } from '../../models/server' 2import { ContactForm } from '../../models/server'
3 3
4function sendContactForm (options: { 4function sendContactForm (options: {
5 url: string, 5 url: string
6 fromEmail: string, 6 fromEmail: string
7 fromName: string, 7 fromName: string
8 subject: string, 8 subject: string
9 body: string, 9 body: string
10 expectedStatus?: number 10 expectedStatus?: number
11}) { 11}) {
12 const path = '/api/v1/server/contact' 12 const path = '/api/v1/server/contact'
diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts
index 3f7729c20..006d59199 100644
--- a/shared/extra-utils/server/follows.ts
+++ b/shared/extra-utils/server/follows.ts
@@ -5,12 +5,12 @@ import { makePostBodyRequest } from '../requests/requests'
5import { ActivityPubActorType, FollowState } from '@shared/models' 5import { ActivityPubActorType, FollowState } from '@shared/models'
6 6
7function getFollowersListPaginationAndSort (options: { 7function getFollowersListPaginationAndSort (options: {
8 url: string, 8 url: string
9 start: number, 9 start: number
10 count: number, 10 count: number
11 sort: string, 11 sort: string
12 search?: string, 12 search?: string
13 actorType?: ActivityPubActorType, 13 actorType?: ActivityPubActorType
14 state?: FollowState 14 state?: FollowState
15}) { 15}) {
16 const { url, start, count, sort, search, state, actorType } = options 16 const { url, start, count, sort, search, state, actorType } = options
@@ -56,12 +56,12 @@ function rejectFollower (url: string, token: string, follower: string, statusCod
56} 56}
57 57
58function getFollowingListPaginationAndSort (options: { 58function getFollowingListPaginationAndSort (options: {
59 url: string, 59 url: string
60 start: number, 60 start: number
61 count: number, 61 count: number
62 sort: string, 62 sort: string
63 search?: string, 63 search?: string
64 actorType?: ActivityPubActorType, 64 actorType?: ActivityPubActorType
65 state?: FollowState 65 state?: FollowState
66}) { 66}) {
67 const { url, start, count, sort, search, state, actorType } = options 67 const { url, start, count, sort, search, state, actorType } = options
@@ -92,7 +92,7 @@ function follow (follower: string, following: string[], accessToken: string, exp
92 .post(path) 92 .post(path)
93 .set('Accept', 'application/json') 93 .set('Accept', 'application/json')
94 .set('Authorization', 'Bearer ' + accessToken) 94 .set('Authorization', 'Bearer ' + accessToken)
95 .send({ 'hosts': followingHosts }) 95 .send({ hosts: followingHosts })
96 .expect(expectedStatus) 96 .expect(expectedStatus)
97} 97}
98 98
diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts
index 56fe5fa2a..d984b3d1e 100644
--- a/shared/extra-utils/server/jobs.ts
+++ b/shared/extra-utils/server/jobs.ts
@@ -8,20 +8,20 @@ function getJobsList (url: string, accessToken: string, state: JobState) {
8 const path = '/api/v1/jobs/' + state 8 const path = '/api/v1/jobs/' + state
9 9
10 return request(url) 10 return request(url)
11 .get(path) 11 .get(path)
12 .set('Accept', 'application/json') 12 .set('Accept', 'application/json')
13 .set('Authorization', 'Bearer ' + accessToken) 13 .set('Authorization', 'Bearer ' + accessToken)
14 .expect(200) 14 .expect(200)
15 .expect('Content-Type', /json/) 15 .expect('Content-Type', /json/)
16} 16}
17 17
18function getJobsListPaginationAndSort (options: { 18function getJobsListPaginationAndSort (options: {
19 url: string, 19 url: string
20 accessToken: string, 20 accessToken: string
21 state: JobState, 21 state: JobState
22 start: number, 22 start: number
23 count: number, 23 count: number
24 sort: string, 24 sort: string
25 jobType?: JobType 25 jobType?: JobType
26}) { 26}) {
27 const { url, accessToken, state, start, count, sort, jobType } = options 27 const { url, accessToken, state, start, count, sort, jobType } = options
diff --git a/shared/extra-utils/server/plugins.ts b/shared/extra-utils/server/plugins.ts
index 5c0d1e511..2d02d823d 100644
--- a/shared/extra-utils/server/plugins.ts
+++ b/shared/extra-utils/server/plugins.ts
@@ -7,13 +7,13 @@ import { root } from '../miscs/miscs'
7import { join } from 'path' 7import { join } from 'path'
8 8
9function listPlugins (parameters: { 9function listPlugins (parameters: {
10 url: string, 10 url: string
11 accessToken: string, 11 accessToken: string
12 start?: number, 12 start?: number
13 count?: number, 13 count?: number
14 sort?: string, 14 sort?: string
15 pluginType?: PluginType, 15 pluginType?: PluginType
16 uninstalled?: boolean, 16 uninstalled?: boolean
17 expectedStatus?: number 17 expectedStatus?: number
18}) { 18}) {
19 const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters 19 const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters
@@ -35,13 +35,13 @@ function listPlugins (parameters: {
35} 35}
36 36
37function listAvailablePlugins (parameters: { 37function listAvailablePlugins (parameters: {
38 url: string, 38 url: string
39 accessToken: string, 39 accessToken: string
40 start?: number, 40 start?: number
41 count?: number, 41 count?: number
42 sort?: string, 42 sort?: string
43 pluginType?: PluginType, 43 pluginType?: PluginType
44 currentPeerTubeEngine?: string, 44 currentPeerTubeEngine?: string
45 search?: string 45 search?: string
46 expectedStatus?: number 46 expectedStatus?: number
47}) { 47}) {
@@ -67,9 +67,9 @@ function listAvailablePlugins (parameters: {
67} 67}
68 68
69function getPlugin (parameters: { 69function getPlugin (parameters: {
70 url: string, 70 url: string
71 accessToken: string, 71 accessToken: string
72 npmName: string, 72 npmName: string
73 expectedStatus?: number 73 expectedStatus?: number
74}) { 74}) {
75 const { url, accessToken, npmName, expectedStatus = 200 } = parameters 75 const { url, accessToken, npmName, expectedStatus = 200 } = parameters
@@ -84,10 +84,10 @@ function getPlugin (parameters: {
84} 84}
85 85
86function updatePluginSettings (parameters: { 86function updatePluginSettings (parameters: {
87 url: string, 87 url: string
88 accessToken: string, 88 accessToken: string
89 npmName: string, 89 npmName: string
90 settings: any, 90 settings: any
91 expectedStatus?: number 91 expectedStatus?: number
92}) { 92}) {
93 const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters 93 const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters
@@ -103,9 +103,9 @@ function updatePluginSettings (parameters: {
103} 103}
104 104
105function getPluginRegisteredSettings (parameters: { 105function getPluginRegisteredSettings (parameters: {
106 url: string, 106 url: string
107 accessToken: string, 107 accessToken: string
108 npmName: string, 108 npmName: string
109 expectedStatus?: number 109 expectedStatus?: number
110}) { 110}) {
111 const { url, accessToken, npmName, expectedStatus = 200 } = parameters 111 const { url, accessToken, npmName, expectedStatus = 200 } = parameters
@@ -120,8 +120,8 @@ function getPluginRegisteredSettings (parameters: {
120} 120}
121 121
122function getPublicSettings (parameters: { 122function getPublicSettings (parameters: {
123 url: string, 123 url: string
124 npmName: string, 124 npmName: string
125 expectedStatus?: number 125 expectedStatus?: number
126}) { 126}) {
127 const { url, npmName, expectedStatus = 200 } = parameters 127 const { url, npmName, expectedStatus = 200 } = parameters
@@ -135,8 +135,8 @@ function getPublicSettings (parameters: {
135} 135}
136 136
137function getPluginTranslations (parameters: { 137function getPluginTranslations (parameters: {
138 url: string, 138 url: string
139 locale: string, 139 locale: string
140 expectedStatus?: number 140 expectedStatus?: number
141}) { 141}) {
142 const { url, locale, expectedStatus = 200 } = parameters 142 const { url, locale, expectedStatus = 200 } = parameters
@@ -150,9 +150,9 @@ function getPluginTranslations (parameters: {
150} 150}
151 151
152function installPlugin (parameters: { 152function installPlugin (parameters: {
153 url: string, 153 url: string
154 accessToken: string, 154 accessToken: string
155 path?: string, 155 path?: string
156 npmName?: string 156 npmName?: string
157 expectedStatus?: number 157 expectedStatus?: number
158}) { 158}) {
@@ -169,9 +169,9 @@ function installPlugin (parameters: {
169} 169}
170 170
171function updatePlugin (parameters: { 171function updatePlugin (parameters: {
172 url: string, 172 url: string
173 accessToken: string, 173 accessToken: string
174 path?: string, 174 path?: string
175 npmName?: string 175 npmName?: string
176 expectedStatus?: number 176 expectedStatus?: number
177}) { 177}) {
@@ -188,8 +188,8 @@ function updatePlugin (parameters: {
188} 188}
189 189
190function uninstallPlugin (parameters: { 190function uninstallPlugin (parameters: {
191 url: string, 191 url: string
192 accessToken: string, 192 accessToken: string
193 npmName: string 193 npmName: string
194 expectedStatus?: number 194 expectedStatus?: number
195}) { 195}) {
diff --git a/shared/extra-utils/server/redundancy.ts b/shared/extra-utils/server/redundancy.ts
index 7b488e23e..08467e4c0 100644
--- a/shared/extra-utils/server/redundancy.ts
+++ b/shared/extra-utils/server/redundancy.ts
@@ -15,11 +15,11 @@ function updateRedundancy (url: string, accessToken: string, host: string, redun
15 15
16function listVideoRedundancies (options: { 16function listVideoRedundancies (options: {
17 url: string 17 url: string
18 accessToken: string, 18 accessToken: string
19 target: VideoRedundanciesTarget, 19 target: VideoRedundanciesTarget
20 start?: number, 20 start?: number
21 count?: number, 21 count?: number
22 sort?: string, 22 sort?: string
23 statusCodeExpected?: number 23 statusCodeExpected?: number
24}) { 24}) {
25 const path = '/api/v1/server/redundancy/videos' 25 const path = '/api/v1/server/redundancy/videos'
@@ -41,8 +41,8 @@ function listVideoRedundancies (options: {
41} 41}
42 42
43function addVideoRedundancy (options: { 43function addVideoRedundancy (options: {
44 url: string, 44 url: string
45 accessToken: string, 45 accessToken: string
46 videoId: number 46 videoId: number
47}) { 47}) {
48 const path = '/api/v1/server/redundancy/videos' 48 const path = '/api/v1/server/redundancy/videos'
@@ -58,8 +58,8 @@ function addVideoRedundancy (options: {
58} 58}
59 59
60function removeVideoRedundancy (options: { 60function removeVideoRedundancy (options: {
61 url: string, 61 url: string
62 accessToken: string, 62 accessToken: string
63 redundancyId: number 63 redundancyId: number
64}) { 64}) {
65 const { url, accessToken, redundancyId } = options 65 const { url, accessToken, redundancyId } = options
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts
index a0720d778..a0f0ce9c9 100644
--- a/shared/extra-utils/server/servers.ts
+++ b/shared/extra-utils/server/servers.ts
@@ -1,16 +1,15 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2 2
3import { ChildProcess, exec, fork } from 'child_process' 3import { ChildProcess, exec, fork } from 'child_process'
4import { join } from 'path' 4import { join } from 'path'
5import { root, wait } from '../miscs/miscs' 5import { root, wait } from '../miscs/miscs'
6import { copy, pathExists, readdir, readFile, remove } from 'fs-extra' 6import { copy, pathExists, readdir, readFile, remove } from 'fs-extra'
7import { existsSync } from 'fs'
8import { expect } from 'chai' 7import { expect } from 'chai'
9import { VideoChannel } from '../../models/videos' 8import { VideoChannel } from '../../models/videos'
10import { randomInt } from '../../core-utils/miscs/miscs' 9import { randomInt } from '../../core-utils/miscs/miscs'
11 10
12interface ServerInfo { 11interface ServerInfo {
13 app: ChildProcess, 12 app: ChildProcess
14 url: string 13 url: string
15 host: string 14 host: string
16 15
@@ -20,13 +19,13 @@ interface ServerInfo {
20 serverNumber: number 19 serverNumber: number
21 20
22 client: { 21 client: {
23 id: string, 22 id: string
24 secret: string 23 secret: string
25 } 24 }
26 25
27 user: { 26 user: {
28 username: string, 27 username: string
29 password: string, 28 password: string
30 email?: string 29 email?: string
31 } 30 }
32 31
@@ -57,7 +56,7 @@ function parallelTests () {
57} 56}
58 57
59function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { 58function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) {
60 let apps = [] 59 const apps = []
61 let i = 0 60 let i = 0
62 61
63 return new Promise<ServerInfo[]>(res => { 62 return new Promise<ServerInfo[]>(res => {
@@ -203,20 +202,20 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = []
203 202
204 // Capture things if we want to 203 // Capture things if we want to
205 for (const key of Object.keys(regexps)) { 204 for (const key of Object.keys(regexps)) {
206 const regexp = regexps[ key ] 205 const regexp = regexps[key]
207 const matches = data.toString().match(regexp) 206 const matches = data.toString().match(regexp)
208 if (matches !== null) { 207 if (matches !== null) {
209 if (key === 'client_id') server.client.id = matches[ 1 ] 208 if (key === 'client_id') server.client.id = matches[1]
210 else if (key === 'client_secret') server.client.secret = matches[ 1 ] 209 else if (key === 'client_secret') server.client.secret = matches[1]
211 else if (key === 'user_username') server.user.username = matches[ 1 ] 210 else if (key === 'user_username') server.user.username = matches[1]
212 else if (key === 'user_password') server.user.password = matches[ 1 ] 211 else if (key === 'user_password') server.user.password = matches[1]
213 } 212 }
214 } 213 }
215 214
216 // Check if all required sentences are here 215 // Check if all required sentences are here
217 for (const key of Object.keys(serverRunString)) { 216 for (const key of Object.keys(serverRunString)) {
218 if (data.toString().indexOf(key) !== -1) serverRunString[ key ] = true 217 if (data.toString().indexOf(key) !== -1) serverRunString[key] = true
219 if (serverRunString[ key ] === false) dontContinue = true 218 if (serverRunString[key] === false) dontContinue = true
220 } 219 }
221 220
222 // If no, there is maybe one thing not already initialized (client/user credentials generation...) 221 // If no, there is maybe one thing not already initialized (client/user credentials generation...)
diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts
index 627e17cc3..f87706f6a 100644
--- a/shared/extra-utils/users/accounts.ts
+++ b/shared/extra-utils/users/accounts.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as request from 'supertest' 3import * as request from 'supertest'
4import { expect } from 'chai' 4import { expect } from 'chai'
diff --git a/shared/extra-utils/users/blocklist.ts b/shared/extra-utils/users/blocklist.ts
index 5feb84179..39e720b42 100644
--- a/shared/extra-utils/users/blocklist.ts
+++ b/shared/extra-utils/users/blocklist.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests' 3import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests'
4 4
diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts
index f9bfb3cb3..4fe54a74a 100644
--- a/shared/extra-utils/users/login.ts
+++ b/shared/extra-utils/users/login.ts
@@ -60,7 +60,7 @@ function setAccessTokensToServers (servers: ServerInfo[]) {
60 const tasks: Promise<any>[] = [] 60 const tasks: Promise<any>[] = []
61 61
62 for (const server of servers) { 62 for (const server of servers) {
63 const p = serverLogin(server).then(t => server.accessToken = t) 63 const p = serverLogin(server).then(t => { server.accessToken = t })
64 tasks.push(p) 64 tasks.push(p)
65 } 65 }
66 66
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts
index 9a5fd7e86..f949878e4 100644
--- a/shared/extra-utils/users/user-notifications.ts
+++ b/shared/extra-utils/users/user-notifications.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' 3import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
4import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users' 4import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users'
@@ -54,6 +54,7 @@ function markAsReadNotifications (url: string, token: string, ids: number[], sta
54 statusCodeExpected 54 statusCodeExpected
55 }) 55 })
56} 56}
57
57function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) { 58function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) {
58 const path = '/api/v1/users/me/notifications/read-all' 59 const path = '/api/v1/users/me/notifications/read-all'
59 60
@@ -77,7 +78,7 @@ type CheckerBaseParams = {
77 server: ServerInfo 78 server: ServerInfo
78 emails: object[] 79 emails: object[]
79 socketNotifications: UserNotification[] 80 socketNotifications: UserNotification[]
80 token: string, 81 token: string
81 check?: { web: boolean, mail: boolean } 82 check?: { web: boolean, mail: boolean }
82} 83}
83 84
@@ -172,7 +173,7 @@ async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName
172 } 173 }
173 174
174 function emailFinder (email: object) { 175 function emailFinder (email: object) {
175 const text = email[ 'text' ] 176 const text = email['text']
176 return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1 177 return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1
177 } 178 }
178 179
@@ -195,7 +196,7 @@ async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string
195 } 196 }
196 197
197 function emailFinder (email: object) { 198 function emailFinder (email: object) {
198 const text: string = email[ 'text' ] 199 const text: string = email['text']
199 return text.includes(videoUUID) && text.includes('Your video') 200 return text.includes(videoUUID) && text.includes('Your video')
200 } 201 }
201 202
@@ -226,7 +227,7 @@ async function checkMyVideoImportIsFinished (
226 } 227 }
227 228
228 function emailFinder (email: object) { 229 function emailFinder (email: object) {
229 const text: string = email[ 'text' ] 230 const text: string = email['text']
230 const toFind = success ? ' finished' : ' error' 231 const toFind = success ? ' finished' : ' error'
231 232
232 return text.includes(url) && text.includes(toFind) 233 return text.includes(url) && text.includes(toFind)
@@ -251,7 +252,7 @@ async function checkUserRegistered (base: CheckerBaseParams, username: string, t
251 } 252 }
252 253
253 function emailFinder (email: object) { 254 function emailFinder (email: object) {
254 const text: string = email[ 'text' ] 255 const text: string = email['text']
255 256
256 return text.includes(' registered ') && text.includes(username) 257 return text.includes(' registered ') && text.includes(username)
257 } 258 }
@@ -291,7 +292,7 @@ async function checkNewActorFollow (
291 } 292 }
292 293
293 function emailFinder (email: object) { 294 function emailFinder (email: object) {
294 const text: string = email[ 'text' ] 295 const text: string = email['text']
295 296
296 return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) 297 return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
297 } 298 }
@@ -320,7 +321,7 @@ async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost:
320 } 321 }
321 322
322 function emailFinder (email: object) { 323 function emailFinder (email: object) {
323 const text: string = email[ 'text' ] 324 const text: string = email['text']
324 325
325 return text.includes('instance has a new follower') && text.includes(followerHost) 326 return text.includes('instance has a new follower') && text.includes(followerHost)
326 } 327 }
@@ -351,7 +352,7 @@ async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost
351 } 352 }
352 353
353 function emailFinder (email: object) { 354 function emailFinder (email: object) {
354 const text: string = email[ 'text' ] 355 const text: string = email['text']
355 356
356 return text.includes(' automatically followed a new instance') && text.includes(followingHost) 357 return text.includes(' automatically followed a new instance') && text.includes(followingHost)
357 } 358 }
@@ -385,7 +386,7 @@ async function checkCommentMention (
385 } 386 }
386 387
387 function emailFinder (email: object) { 388 function emailFinder (email: object) {
388 const text: string = email[ 'text' ] 389 const text: string = email['text']
389 390
390 return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName) 391 return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName)
391 } 392 }
@@ -394,6 +395,7 @@ async function checkCommentMention (
394} 395}
395 396
396let lastEmailCount = 0 397let lastEmailCount = 0
398
397async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { 399async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
398 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO 400 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
399 401
@@ -413,8 +415,9 @@ async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string,
413 } 415 }
414 416
415 const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}` 417 const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}`
418
416 function emailFinder (email: object) { 419 function emailFinder (email: object) {
417 return email[ 'text' ].indexOf(commentUrl) !== -1 420 return email['text'].indexOf(commentUrl) !== -1
418 } 421 }
419 422
420 await checkNotification(base, notificationChecker, emailFinder, type) 423 await checkNotification(base, notificationChecker, emailFinder, type)
@@ -444,7 +447,7 @@ async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUU
444 } 447 }
445 448
446 function emailFinder (email: object) { 449 function emailFinder (email: object) {
447 const text = email[ 'text' ] 450 const text = email['text']
448 return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 451 return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
449 } 452 }
450 453
@@ -469,8 +472,8 @@ async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, vi
469 } 472 }
470 473
471 function emailFinder (email: object) { 474 function emailFinder (email: object) {
472 const text = email[ 'text' ] 475 const text = email['text']
473 return text.indexOf(videoUUID) !== -1 && email[ 'text' ].indexOf('video-auto-blacklist/list') !== -1 476 return text.indexOf(videoUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1
474 } 477 }
475 478
476 await checkNotification(base, notificationChecker, emailFinder, type) 479 await checkNotification(base, notificationChecker, emailFinder, type)
@@ -496,7 +499,7 @@ async function checkNewBlacklistOnMyVideo (
496 } 499 }
497 500
498 function emailFinder (email: object) { 501 function emailFinder (email: object) {
499 const text = email[ 'text' ] 502 const text = email['text']
500 return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1 503 return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1
501 } 504 }
502 505
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts
index 2fe0e55c2..248af2d6e 100644
--- a/shared/extra-utils/users/users.ts
+++ b/shared/extra-utils/users/users.ts
@@ -9,14 +9,14 @@ import { UserUpdateMe } from '../../models/users'
9import { omit } from 'lodash' 9import { omit } from 'lodash'
10 10
11type CreateUserArgs = { 11type CreateUserArgs = {
12 url: string, 12 url: string
13 accessToken: string, 13 accessToken: string
14 username: string, 14 username: string
15 password: string, 15 password: string
16 videoQuota?: number, 16 videoQuota?: number
17 videoQuotaDaily?: number, 17 videoQuotaDaily?: number
18 role?: UserRole, 18 role?: UserRole
19 adminFlags?: UserAdminFlag, 19 adminFlags?: UserAdminFlag
20 specialStatus?: number 20 specialStatus?: number
21} 21}
22function createUser (parameters: CreateUserArgs) { 22function createUser (parameters: CreateUserArgs) {
@@ -74,8 +74,8 @@ function registerUser (url: string, username: string, password: string, specialS
74} 74}
75 75
76function registerUserWithChannel (options: { 76function registerUserWithChannel (options: {
77 url: string, 77 url: string
78 user: { username: string, password: string, displayName?: string }, 78 user: { username: string, password: string, displayName?: string }
79 channel: { name: string, displayName: string } 79 channel: { name: string, displayName: string }
80}) { 80}) {
81 const path = '/api/v1/users/register' 81 const path = '/api/v1/users/register'
@@ -230,8 +230,8 @@ function updateMyUser (options: { url: string, accessToken: string } & UserUpdat
230} 230}
231 231
232function updateMyAvatar (options: { 232function updateMyAvatar (options: {
233 url: string, 233 url: string
234 accessToken: string, 234 accessToken: string
235 fixture: string 235 fixture: string
236}) { 236}) {
237 const path = '/api/v1/users/me/avatar/pick' 237 const path = '/api/v1/users/me/avatar/pick'
@@ -241,14 +241,14 @@ function updateMyAvatar (options: {
241 241
242function updateUser (options: { 242function updateUser (options: {
243 url: string 243 url: string
244 userId: number, 244 userId: number
245 accessToken: string, 245 accessToken: string
246 email?: string, 246 email?: string
247 emailVerified?: boolean, 247 emailVerified?: boolean
248 videoQuota?: number, 248 videoQuota?: number
249 videoQuotaDaily?: number, 249 videoQuotaDaily?: number
250 password?: string, 250 password?: string
251 adminFlags?: UserAdminFlag, 251 adminFlags?: UserAdminFlag
252 role?: UserRole 252 role?: UserRole
253}) { 253}) {
254 const path = '/api/v1/users/' + options.userId 254 const path = '/api/v1/users/' + options.userId
diff --git a/shared/extra-utils/videos/video-blacklist.ts b/shared/extra-utils/videos/video-blacklist.ts
index e25a292fc..ba139ef95 100644
--- a/shared/extra-utils/videos/video-blacklist.ts
+++ b/shared/extra-utils/videos/video-blacklist.ts
@@ -13,11 +13,11 @@ function addVideoToBlacklist (
13 const path = '/api/v1/videos/' + videoId + '/blacklist' 13 const path = '/api/v1/videos/' + videoId + '/blacklist'
14 14
15 return request(url) 15 return request(url)
16 .post(path) 16 .post(path)
17 .send({ reason, unfederate }) 17 .send({ reason, unfederate })
18 .set('Accept', 'application/json') 18 .set('Accept', 'application/json')
19 .set('Authorization', 'Bearer ' + token) 19 .set('Authorization', 'Bearer ' + token)
20 .expect(specialStatus) 20 .expect(specialStatus)
21} 21}
22 22
23function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) { 23function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) {
@@ -35,20 +35,20 @@ function removeVideoFromBlacklist (url: string, token: string, videoId: number |
35 const path = '/api/v1/videos/' + videoId + '/blacklist' 35 const path = '/api/v1/videos/' + videoId + '/blacklist'
36 36
37 return request(url) 37 return request(url)
38 .delete(path) 38 .delete(path)
39 .set('Accept', 'application/json') 39 .set('Accept', 'application/json')
40 .set('Authorization', 'Bearer ' + token) 40 .set('Authorization', 'Bearer ' + token)
41 .expect(specialStatus) 41 .expect(specialStatus)
42} 42}
43 43
44function getBlacklistedVideosList (parameters: { 44function getBlacklistedVideosList (parameters: {
45 url: string, 45 url: string
46 token: string, 46 token: string
47 sort?: string, 47 sort?: string
48 type?: VideoBlacklistType, 48 type?: VideoBlacklistType
49 specialStatus?: number 49 specialStatus?: number
50}) { 50}) {
51 let { url, token, sort, type, specialStatus = 200 } = parameters 51 const { url, token, sort, type, specialStatus = 200 } = parameters
52 const path = '/api/v1/videos/blacklist/' 52 const path = '/api/v1/videos/blacklist/'
53 53
54 const query = { sort, type } 54 const query = { sort, type }
diff --git a/shared/extra-utils/videos/video-captions.ts b/shared/extra-utils/videos/video-captions.ts
index 8d67f617b..5bd533bba 100644
--- a/shared/extra-utils/videos/video-captions.ts
+++ b/shared/extra-utils/videos/video-captions.ts
@@ -6,12 +6,12 @@ import { buildAbsoluteFixturePath } from '../miscs/miscs'
6const expect = chai.expect 6const expect = chai.expect
7 7
8function createVideoCaption (args: { 8function createVideoCaption (args: {
9 url: string, 9 url: string
10 accessToken: string 10 accessToken: string
11 videoId: string | number 11 videoId: string | number
12 language: string 12 language: string
13 fixture: string, 13 fixture: string
14 mimeType?: string, 14 mimeType?: string
15 statusCodeExpected?: number 15 statusCodeExpected?: number
16}) { 16}) {
17 const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language 17 const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language
diff --git a/shared/extra-utils/videos/video-channels.ts b/shared/extra-utils/videos/video-channels.ts
index 053842331..51d433940 100644
--- a/shared/extra-utils/videos/video-channels.ts
+++ b/shared/extra-utils/videos/video-channels.ts
@@ -1,3 +1,5 @@
1/* eslint-disable @typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' 4import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model'
3import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' 5import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model'
@@ -22,11 +24,11 @@ function getVideoChannelsList (url: string, start: number, count: number, sort?:
22} 24}
23 25
24function getAccountVideoChannelsList (parameters: { 26function getAccountVideoChannelsList (parameters: {
25 url: string, 27 url: string
26 accountName: string, 28 accountName: string
27 start?: number, 29 start?: number
28 count?: number, 30 count?: number
29 sort?: string, 31 sort?: string
30 specialStatus?: number 32 specialStatus?: number
31}) { 33}) {
32 const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters 34 const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters
@@ -113,9 +115,9 @@ function getVideoChannel (url: string, channelName: string) {
113} 115}
114 116
115function updateVideoChannelAvatar (options: { 117function updateVideoChannelAvatar (options: {
116 url: string, 118 url: string
117 accessToken: string, 119 accessToken: string
118 fixture: string, 120 fixture: string
119 videoChannelName: string | number 121 videoChannelName: string | number
120}) { 122}) {
121 123
@@ -129,7 +131,7 @@ function setDefaultVideoChannel (servers: ServerInfo[]) {
129 131
130 for (const server of servers) { 132 for (const server of servers) {
131 const p = getMyUserInformation(server.url, server.accessToken) 133 const p = getMyUserInformation(server.url, server.accessToken)
132 .then(res => server.videoChannel = (res.body as User).videoChannels[0]) 134 .then(res => { server.videoChannel = (res.body as User).videoChannels[0] })
133 135
134 tasks.push(p) 136 tasks.push(p)
135 } 137 }
diff --git a/shared/extra-utils/videos/video-comments.ts b/shared/extra-utils/videos/video-comments.ts
index 0ebf69ced..81c48412d 100644
--- a/shared/extra-utils/videos/video-comments.ts
+++ b/shared/extra-utils/videos/video-comments.ts
@@ -1,3 +1,5 @@
1/* eslint-disable @typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { makeDeleteRequest } from '../requests/requests' 4import { makeDeleteRequest } from '../requests/requests'
3 5
diff --git a/shared/extra-utils/videos/video-imports.ts b/shared/extra-utils/videos/video-imports.ts
index 150cc94ed..8e5abd2f5 100644
--- a/shared/extra-utils/videos/video-imports.ts
+++ b/shared/extra-utils/videos/video-imports.ts
@@ -7,7 +7,7 @@ function getYoutubeVideoUrl () {
7} 7}
8 8
9function getMagnetURI () { 9function getMagnetURI () {
10 // tslint:disable:max-line-length 10 // eslint-disable-next-line max-len
11 return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4' 11 return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4'
12} 12}
13 13
diff --git a/shared/extra-utils/videos/video-playlists.ts b/shared/extra-utils/videos/video-playlists.ts
index 6762c5973..5bcc02570 100644
--- a/shared/extra-utils/videos/video-playlists.ts
+++ b/shared/extra-utils/videos/video-playlists.ts
@@ -123,9 +123,9 @@ function deleteVideoPlaylist (url: string, token: string, playlistId: number | s
123} 123}
124 124
125function createVideoPlaylist (options: { 125function createVideoPlaylist (options: {
126 url: string, 126 url: string
127 token: string, 127 token: string
128 playlistAttrs: VideoPlaylistCreate, 128 playlistAttrs: VideoPlaylistCreate
129 expectedStatus?: number 129 expectedStatus?: number
130}) { 130}) {
131 const path = '/api/v1/video-playlists' 131 const path = '/api/v1/video-playlists'
@@ -148,10 +148,10 @@ function createVideoPlaylist (options: {
148} 148}
149 149
150function updateVideoPlaylist (options: { 150function updateVideoPlaylist (options: {
151 url: string, 151 url: string
152 token: string, 152 token: string
153 playlistAttrs: VideoPlaylistUpdate, 153 playlistAttrs: VideoPlaylistUpdate
154 playlistId: number | string, 154 playlistId: number | string
155 expectedStatus?: number 155 expectedStatus?: number
156}) { 156}) {
157 const path = '/api/v1/video-playlists/' + options.playlistId 157 const path = '/api/v1/video-playlists/' + options.playlistId
@@ -174,9 +174,9 @@ function updateVideoPlaylist (options: {
174} 174}
175 175
176async function addVideoInPlaylist (options: { 176async function addVideoInPlaylist (options: {
177 url: string, 177 url: string
178 token: string, 178 token: string
179 playlistId: number | string, 179 playlistId: number | string
180 elementAttrs: VideoPlaylistElementCreate | { videoId: string } 180 elementAttrs: VideoPlaylistElementCreate | { videoId: string }
181 expectedStatus?: number 181 expectedStatus?: number
182}) { 182}) {
@@ -194,11 +194,11 @@ async function addVideoInPlaylist (options: {
194} 194}
195 195
196function updateVideoPlaylistElement (options: { 196function updateVideoPlaylistElement (options: {
197 url: string, 197 url: string
198 token: string, 198 token: string
199 playlistId: number | string, 199 playlistId: number | string
200 playlistElementId: number | string, 200 playlistElementId: number | string
201 elementAttrs: VideoPlaylistElementUpdate, 201 elementAttrs: VideoPlaylistElementUpdate
202 expectedStatus?: number 202 expectedStatus?: number
203}) { 203}) {
204 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId 204 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId
@@ -213,10 +213,10 @@ function updateVideoPlaylistElement (options: {
213} 213}
214 214
215function removeVideoFromPlaylist (options: { 215function removeVideoFromPlaylist (options: {
216 url: string, 216 url: string
217 token: string, 217 token: string
218 playlistId: number | string, 218 playlistId: number | string
219 playlistElementId: number, 219 playlistElementId: number
220 expectedStatus?: number 220 expectedStatus?: number
221}) { 221}) {
222 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId 222 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId
@@ -230,14 +230,14 @@ function removeVideoFromPlaylist (options: {
230} 230}
231 231
232function reorderVideosPlaylist (options: { 232function reorderVideosPlaylist (options: {
233 url: string, 233 url: string
234 token: string, 234 token: string
235 playlistId: number | string, 235 playlistId: number | string
236 elementAttrs: { 236 elementAttrs: {
237 startPosition: number, 237 startPosition: number
238 insertAfterPosition: number, 238 insertAfterPosition: number
239 reorderLength?: number 239 reorderLength?: number
240 }, 240 }
241 expectedStatus?: number 241 expectedStatus?: number
242}) { 242}) {
243 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder' 243 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder'
diff --git a/shared/extra-utils/videos/video-streaming-playlists.ts b/shared/extra-utils/videos/video-streaming-playlists.ts
index eb25011cb..e54da84aa 100644
--- a/shared/extra-utils/videos/video-streaming-playlists.ts
+++ b/shared/extra-utils/videos/video-streaming-playlists.ts
@@ -37,7 +37,7 @@ async function checkSegmentHash (
37 37
38 const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url) 38 const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
39 39
40 const sha256Server = resSha.body[ videoName ][range] 40 const sha256Server = resSha.body[videoName][range]
41 expect(sha256(res2.body)).to.equal(sha256Server) 41 expect(sha256(res2.body)).to.equal(sha256Server)
42} 42}
43 43
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts
index aa13273ae..39a06b0d7 100644
--- a/shared/extra-utils/videos/videos.ts
+++ b/shared/extra-utils/videos/videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { pathExists, readdir, readFile } from 'fs-extra' 4import { pathExists, readdir, readFile } from 'fs-extra'
@@ -488,7 +488,7 @@ async function completeVideoCheck (
488 description: string 488 description: string
489 publishedAt?: string 489 publishedAt?: string
490 support: string 490 support: string
491 originallyPublishedAt?: string, 491 originallyPublishedAt?: string
492 account: { 492 account: {
493 name: string 493 name: string
494 host: string 494 host: string
@@ -509,7 +509,7 @@ async function completeVideoCheck (
509 files: { 509 files: {
510 resolution: number 510 resolution: number
511 size: number 511 size: number
512 }[], 512 }[]
513 thumbnailfile?: string 513 thumbnailfile?: string
514 previewfile?: string 514 previewfile?: string
515 } 515 }
@@ -583,9 +583,10 @@ async function completeVideoCheck (
583 583
584 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100) 584 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
585 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100) 585 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
586 expect(file.size, 586 expect(
587 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')') 587 file.size,
588 .to.be.above(minSize).and.below(maxSize) 588 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')'
589 ).to.be.above(minSize).and.below(maxSize)
589 590
590 const torrent = await webtorrentAdd(file.magnetUri, true) 591 const torrent = await webtorrentAdd(file.magnetUri, true)
591 expect(torrent.files).to.be.an('array') 592 expect(torrent.files).to.be.an('array')
@@ -608,10 +609,10 @@ async function videoUUIDToId (url: string, id: number | string) {
608} 609}
609 610
610async function uploadVideoAndGetId (options: { 611async function uploadVideoAndGetId (options: {
611 server: ServerInfo, 612 server: ServerInfo
612 videoName: string, 613 videoName: string
613 nsfw?: boolean, 614 nsfw?: boolean
614 privacy?: VideoPrivacy, 615 privacy?: VideoPrivacy
615 token?: string 616 token?: string
616}) { 617}) {
617 const videoAttrs: any = { name: options.videoName } 618 const videoAttrs: any = { name: options.videoName }
diff --git a/shared/models/activitypub/activity.ts b/shared/models/activitypub/activity.ts
index 492b672c7..20ecf176c 100644
--- a/shared/models/activitypub/activity.ts
+++ b/shared/models/activitypub/activity.ts
@@ -8,12 +8,33 @@ import { ViewObject } from './objects/view-object'
8import { APObject } from './objects/object.model' 8import { APObject } from './objects/object.model'
9import { PlaylistObject } from './objects/playlist-object' 9import { PlaylistObject } from './objects/playlist-object'
10 10
11export type Activity = ActivityCreate | ActivityUpdate | 11export type Activity =
12 ActivityDelete | ActivityFollow | ActivityAccept | ActivityAnnounce | 12 ActivityCreate |
13 ActivityUndo | ActivityLike | ActivityReject | ActivityView | ActivityDislike | ActivityFlag 13 ActivityUpdate |
14 14 ActivityDelete |
15export type ActivityType = 'Create' | 'Update' | 'Delete' | 'Follow' | 'Accept' | 'Announce' | 'Undo' | 'Like' | 'Reject' | 15 ActivityFollow |
16 'View' | 'Dislike' | 'Flag' 16 ActivityAccept |
17 ActivityAnnounce |
18 ActivityUndo |
19 ActivityLike |
20 ActivityReject |
21 ActivityView |
22 ActivityDislike |
23 ActivityFlag
24
25export type ActivityType =
26 'Create' |
27 'Update' |
28 'Delete' |
29 'Follow' |
30 'Accept' |
31 'Announce' |
32 'Undo' |
33 'Like' |
34 'Reject' |
35 'View' |
36 'Dislike' |
37 'Flag'
17 38
18export interface ActivityAudience { 39export interface ActivityAudience {
19 to: string[] 40 to: string[]
@@ -66,17 +87,17 @@ export interface ActivityAnnounce extends BaseActivity {
66} 87}
67 88
68export interface ActivityUndo extends BaseActivity { 89export interface ActivityUndo extends BaseActivity {
69 type: 'Undo', 90 type: 'Undo'
70 object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce 91 object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce
71} 92}
72 93
73export interface ActivityLike extends BaseActivity { 94export interface ActivityLike extends BaseActivity {
74 type: 'Like', 95 type: 'Like'
75 object: APObject 96 object: APObject
76} 97}
77 98
78export interface ActivityView extends BaseActivity { 99export interface ActivityView extends BaseActivity {
79 type: 'View', 100 type: 'View'
80 actor: string 101 actor: string
81 object: APObject 102 object: APObject
82} 103}
@@ -89,7 +110,7 @@ export interface ActivityDislike extends BaseActivity {
89} 110}
90 111
91export interface ActivityFlag extends BaseActivity { 112export interface ActivityFlag extends BaseActivity {
92 type: 'Flag', 113 type: 'Flag'
93 content: string, 114 content: string
94 object: APObject | APObject[] 115 object: APObject | APObject[]
95} 116}
diff --git a/shared/models/activitypub/activitypub-actor.ts b/shared/models/activitypub/activitypub-actor.ts
index b8a2dc925..f022f3d02 100644
--- a/shared/models/activitypub/activitypub-actor.ts
+++ b/shared/models/activitypub/activitypub-actor.ts
@@ -1,4 +1,4 @@
1import { ActivityPubAttributedTo } from './objects/common-objects' 1import { ActivityIconObject, ActivityPubAttributedTo } from './objects/common-objects'
2 2
3export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization' 3export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization'
4 4
@@ -27,9 +27,5 @@ export interface ActivityPubActor {
27 publicKeyPem: string 27 publicKeyPem: string
28 } 28 }
29 29
30 icon: { 30 icon: ActivityIconObject
31 type: 'Image'
32 mediaType: 'image/png'
33 url: string
34 }
35} 31}
diff --git a/shared/models/activitypub/activitypub-signature.ts b/shared/models/activitypub/activitypub-signature.ts
index 1d9f4b3b3..fafdc246d 100644
--- a/shared/models/activitypub/activitypub-signature.ts
+++ b/shared/models/activitypub/activitypub-signature.ts
@@ -1,6 +1,6 @@
1export interface ActivityPubSignature { 1export interface ActivityPubSignature {
2 type: 'GraphSignature2012' 2 type: string
3 created: Date, 3 created: Date
4 creator: string 4 creator: string
5 signatureValue: string 5 signatureValue: string
6} 6}
diff --git a/shared/models/activitypub/objects/cache-file-object.ts b/shared/models/activitypub/objects/cache-file-object.ts
index 4b0a3a724..19a817582 100644
--- a/shared/models/activitypub/objects/cache-file-object.ts
+++ b/shared/models/activitypub/objects/cache-file-object.ts
@@ -2,7 +2,7 @@ import { ActivityVideoUrlObject, ActivityPlaylistUrlObject } from './common-obje
2 2
3export interface CacheFileObject { 3export interface CacheFileObject {
4 id: string 4 id: string
5 type: 'CacheFile', 5 type: 'CacheFile'
6 object: string 6 object: string
7 expires: string 7 expires: string
8 url: ActivityVideoUrlObject | ActivityPlaylistUrlObject 8 url: ActivityVideoUrlObject | ActivityPlaylistUrlObject
diff --git a/shared/models/activitypub/objects/common-objects.ts b/shared/models/activitypub/objects/common-objects.ts
index bab3ce366..e94d05429 100644
--- a/shared/models/activitypub/objects/common-objects.ts
+++ b/shared/models/activitypub/objects/common-objects.ts
@@ -7,9 +7,9 @@ export interface ActivityIdentifierObject {
7export interface ActivityIconObject { 7export interface ActivityIconObject {
8 type: 'Image' 8 type: 'Image'
9 url: string 9 url: string
10 mediaType: 'image/jpeg' 10 mediaType: 'image/jpeg' | 'image/png'
11 width: number 11 width?: number
12 height: number 12 height?: number
13} 13}
14 14
15export type ActivityVideoUrlObject = { 15export type ActivityVideoUrlObject = {
@@ -72,19 +72,21 @@ export interface ActivityMentionObject {
72 name: string 72 name: string
73} 73}
74 74
75export type ActivityTagObject = ActivityPlaylistSegmentHashesObject | 75export type ActivityTagObject =
76 ActivityPlaylistInfohashesObject | 76 ActivityPlaylistSegmentHashesObject
77 ActivityVideoUrlObject | 77 | ActivityPlaylistInfohashesObject
78 ActivityHashTagObject | 78 | ActivityVideoUrlObject
79 ActivityMentionObject | 79 | ActivityHashTagObject
80 ActivityBitTorrentUrlObject | 80 | ActivityMentionObject
81 ActivityMagnetUrlObject 81 | ActivityBitTorrentUrlObject
82 | ActivityMagnetUrlObject
82 83
83export type ActivityUrlObject = ActivityVideoUrlObject | 84export type ActivityUrlObject =
84 ActivityPlaylistUrlObject | 85 ActivityVideoUrlObject
85 ActivityBitTorrentUrlObject | 86 | ActivityPlaylistUrlObject
86 ActivityMagnetUrlObject | 87 | ActivityBitTorrentUrlObject
87 ActivityHtmlUrlObject 88 | ActivityMagnetUrlObject
89 | ActivityHtmlUrlObject
88 90
89export interface ActivityPubAttributedTo { 91export interface ActivityPubAttributedTo {
90 type: 'Group' | 'Person' 92 type: 'Group' | 'Person'
diff --git a/shared/models/activitypub/objects/video-abuse-object.ts b/shared/models/activitypub/objects/video-abuse-object.ts
index 5f1264a76..d9622b414 100644
--- a/shared/models/activitypub/objects/video-abuse-object.ts
+++ b/shared/models/activitypub/objects/video-abuse-object.ts
@@ -1,5 +1,5 @@
1export interface VideoAbuseObject { 1export interface VideoAbuseObject {
2 type: 'Flag', 2 type: 'Flag'
3 content: string 3 content: string
4 object: string | string[] 4 object: string | string[]
5} 5}
diff --git a/shared/models/activitypub/objects/video-torrent-object.ts b/shared/models/activitypub/objects/video-torrent-object.ts
index cadd0ea49..11de8fc56 100644
--- a/shared/models/activitypub/objects/video-torrent-object.ts
+++ b/shared/models/activitypub/objects/video-torrent-object.ts
@@ -20,8 +20,8 @@ export interface VideoTorrentObject {
20 subtitleLanguage: ActivityIdentifierObject[] 20 subtitleLanguage: ActivityIdentifierObject[]
21 views: number 21 views: number
22 sensitive: boolean 22 sensitive: boolean
23 commentsEnabled: boolean, 23 commentsEnabled: boolean
24 downloadEnabled: boolean, 24 downloadEnabled: boolean
25 waitTranscoding: boolean 25 waitTranscoding: boolean
26 state: VideoState 26 state: VideoState
27 published: string 27 published: string
diff --git a/shared/models/activitypub/objects/view-object.ts b/shared/models/activitypub/objects/view-object.ts
index 00348116a..4dd21ce8e 100644
--- a/shared/models/activitypub/objects/view-object.ts
+++ b/shared/models/activitypub/objects/view-object.ts
@@ -1,5 +1,5 @@
1export interface ViewObject { 1export interface ViewObject {
2 type: 'View', 2 type: 'View'
3 actor: string 3 actor: string
4 object: string 4 object: string
5} 5}
diff --git a/shared/models/i18n/i18n.ts b/shared/models/i18n/i18n.ts
index 032944281..9ae175df9 100644
--- a/shared/models/i18n/i18n.ts
+++ b/shared/models/i18n/i18n.ts
@@ -56,6 +56,8 @@ export function isDefaultLocale (locale: string) {
56} 56}
57 57
58export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) { 58export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) {
59 // FIXME: remove disable rule when the client is upgraded to typescript 3.7
60 // eslint-disable-next-line
59 return translations && translations[str] ? translations[str] : str 61 return translations && translations[str] ? translations[str] : str
60} 62}
61 63
diff --git a/shared/models/nodeinfo/index.d.ts b/shared/models/nodeinfo/index.d.ts
index 0a2d0492e..336cb66d2 100644
--- a/shared/models/nodeinfo/index.d.ts
+++ b/shared/models/nodeinfo/index.d.ts
@@ -98,7 +98,7 @@ export interface HttpNodeinfoDiasporaSoftwareNsSchema20 {
98 * The amount of users that signed in at least once in the last 30 days. 98 * The amount of users that signed in at least once in the last 30 days.
99 */ 99 */
100 activeMonth?: number 100 activeMonth?: number
101 }; 101 }
102 /** 102 /**
103 * The amount of posts that were made by users that are registered on this server. 103 * The amount of posts that were made by users that are registered on this server.
104 */ 104 */
diff --git a/shared/models/plugins/peertube-plugin-latest-version.model.ts b/shared/models/plugins/peertube-plugin-latest-version.model.ts
index dec4618fa..811a64429 100644
--- a/shared/models/plugins/peertube-plugin-latest-version.model.ts
+++ b/shared/models/plugins/peertube-plugin-latest-version.model.ts
@@ -1,5 +1,5 @@
1export interface PeertubePluginLatestVersionRequest { 1export interface PeertubePluginLatestVersionRequest {
2 currentPeerTubeEngine?: string, 2 currentPeerTubeEngine?: string
3 3
4 npmNames: string[] 4 npmNames: string[]
5} 5}
diff --git a/shared/models/plugins/plugin-package-json.model.ts b/shared/models/plugins/plugin-package-json.model.ts
index 3f3077671..c26e9ae5b 100644
--- a/shared/models/plugins/plugin-package-json.model.ts
+++ b/shared/models/plugins/plugin-package-json.model.ts
@@ -5,7 +5,7 @@ export type PluginTranslationPaths = {
5} 5}
6 6
7export type ClientScript = { 7export type ClientScript = {
8 script: string, 8 script: string
9 scopes: PluginClientScope[] 9 scopes: PluginClientScope[]
10} 10}
11 11
@@ -13,12 +13,12 @@ export type PluginPackageJson = {
13 name: string 13 name: string
14 version: string 14 version: string
15 description: string 15 description: string
16 engine: { peertube: string }, 16 engine: { peertube: string }
17 17
18 homepage: string, 18 homepage: string
19 author: string, 19 author: string
20 bugs: string, 20 bugs: string
21 library: string, 21 library: string
22 22
23 staticDirs: { [ name: string ]: string } 23 staticDirs: { [ name: string ]: string }
24 css: string[] 24 css: string[]
diff --git a/shared/models/plugins/server-hook.model.ts b/shared/models/plugins/server-hook.model.ts
index 80ecd9e24..20f89b86d 100644
--- a/shared/models/plugins/server-hook.model.ts
+++ b/shared/models/plugins/server-hook.model.ts
@@ -70,7 +70,7 @@ export const serverActionHookObject = {
70 // Fired when a user is updated by an admin/moderator 70 // Fired when a user is updated by an admin/moderator
71 'action:api.user.updated': true, 71 'action:api.user.updated': true,
72 72
73 // Fired when a user got a new oauth2 token 73 // Fired when a user got a new oauth2 token
74 'action:api.user.oauth2-got-token': true 74 'action:api.user.oauth2-got-token': true
75} 75}
76 76
diff --git a/shared/models/redundancy/video-redundancy.model.ts b/shared/models/redundancy/video-redundancy.model.ts
index 014f69634..fa6e05832 100644
--- a/shared/models/redundancy/video-redundancy.model.ts
+++ b/shared/models/redundancy/video-redundancy.model.ts
@@ -24,10 +24,12 @@ interface RedundancyInformation {
24 size: number 24 size: number
25} 25}
26 26
27// eslint-disable-next-line @typescript-eslint/no-empty-interface
27export interface FileRedundancyInformation extends RedundancyInformation { 28export interface FileRedundancyInformation extends RedundancyInformation {
28 29
29} 30}
30 31
32// eslint-disable-next-line @typescript-eslint/no-empty-interface
31export interface StreamingPlaylistRedundancyInformation extends RedundancyInformation { 33export interface StreamingPlaylistRedundancyInformation extends RedundancyInformation {
32 34
33} 35}
diff --git a/shared/models/server/custom-config.model.ts b/shared/models/server/custom-config.model.ts
index 032b91a29..07e17bda2 100644
--- a/shared/models/server/custom-config.model.ts
+++ b/shared/models/server/custom-config.model.ts
@@ -97,7 +97,7 @@ export interface CustomConfig {
97 videos: { 97 videos: {
98 http: { 98 http: {
99 enabled: boolean 99 enabled: boolean
100 }, 100 }
101 torrent: { 101 torrent: {
102 enabled: boolean 102 enabled: boolean
103 } 103 }
@@ -114,7 +114,7 @@ export interface CustomConfig {
114 114
115 followers: { 115 followers: {
116 instance: { 116 instance: {
117 enabled: boolean, 117 enabled: boolean
118 manualApproval: boolean 118 manualApproval: boolean
119 } 119 }
120 } 120 }
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts
index 19fd4c659..cf29d20d4 100644
--- a/shared/models/server/job.model.ts
+++ b/shared/models/server/job.model.ts
@@ -1,23 +1,24 @@
1export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed' 1export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed'
2 2
3export type JobType = 'activitypub-http-unicast' | 3export type JobType =
4 'activitypub-http-broadcast' | 4 | 'activitypub-http-unicast'
5 'activitypub-http-fetcher' | 5 | 'activitypub-http-broadcast'
6 'activitypub-follow' | 6 | 'activitypub-http-fetcher'
7 'video-file-import' | 7 | 'activitypub-follow'
8 'video-transcoding' | 8 | 'video-file-import'
9 'email' | 9 | 'video-transcoding'
10 'video-import' | 10 | 'email'
11 'videos-views' | 11 | 'video-import'
12 'activitypub-refresher' | 12 | 'videos-views'
13 'video-redundancy' 13 | 'activitypub-refresher'
14 | 'video-redundancy'
14 15
15export interface Job { 16export interface Job {
16 id: number 17 id: number
17 state: JobState 18 state: JobState
18 type: JobType 19 type: JobType
19 data: any, 20 data: any
20 error: any, 21 error: any
21 createdAt: Date | string 22 createdAt: Date | string
22 finishedOn: Date | string 23 finishedOn: Date | string
23 processedOn: Date | string 24 processedOn: Date | string
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts
index f1bb2153c..76e0d6f2d 100644
--- a/shared/models/server/server-config.model.ts
+++ b/shared/models/server/server-config.model.ts
@@ -46,7 +46,7 @@ export interface ServerConfig {
46 } 46 }
47 47
48 signup: { 48 signup: {
49 allowed: boolean, 49 allowed: boolean
50 allowedForCurrentIP: boolean 50 allowedForCurrentIP: boolean
51 requiresEmailVerification: boolean 51 requiresEmailVerification: boolean
52 } 52 }
@@ -97,7 +97,7 @@ export interface ServerConfig {
97 max: number 97 max: number
98 } 98 }
99 extensions: string[] 99 extensions: string[]
100 }, 100 }
101 file: { 101 file: {
102 extensions: string[] 102 extensions: string[]
103 } 103 }
@@ -107,7 +107,7 @@ export interface ServerConfig {
107 file: { 107 file: {
108 size: { 108 size: {
109 max: number 109 max: number
110 }, 110 }
111 extensions: string[] 111 extensions: string[]
112 } 112 }
113 } 113 }
diff --git a/shared/models/users/user.model.ts b/shared/models/users/user.model.ts
index 168851196..efb451014 100644
--- a/shared/models/users/user.model.ts
+++ b/shared/models/users/user.model.ts
@@ -1,6 +1,5 @@
1import { Account } from '../actors' 1import { Account } from '../actors'
2import { VideoChannel } from '../videos/channel/video-channel.model' 2import { VideoChannel } from '../videos/channel/video-channel.model'
3import { VideoPlaylist } from '../videos/playlist/video-playlist.model'
4import { UserRole } from './user-role' 3import { UserRole } from './user-role'
5import { NSFWPolicyType } from '../videos/nsfw-policy.type' 4import { NSFWPolicyType } from '../videos/nsfw-policy.type'
6import { UserNotificationSetting } from './user-notification-setting.model' 5import { UserNotificationSetting } from './user-notification-setting.model'
diff --git a/tslint.json b/tslint.json
deleted file mode 100644
index cfe2ac712..000000000
--- a/tslint.json
+++ /dev/null
@@ -1,19 +0,0 @@
1{
2 "extends": "tslint-config-standard",
3 "rules": {
4 "await-promise": [true, "Bluebird"],
5 "no-inferrable-types": true,
6 "eofline": true,
7 "indent": [true, "spaces"],
8 "ter-indent": [
9 true,
10 2,
11 {
12 "SwitchCase": 1
13 }
14 ],
15 "max-line-length": [true, 140],
16 "no-unused-variable": false, // Memory issues
17 "no-floating-promises": false
18 }
19}
diff --git a/yarn.lock b/yarn.lock
index 0a1ad1d61..6e75dab9a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -118,6 +118,11 @@
118 resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" 118 resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80"
119 integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== 119 integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw==
120 120
121"@types/eslint-visitor-keys@^1.0.0":
122 version "1.0.0"
123 resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
124 integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
125
121"@types/express-rate-limit@^3.3.0": 126"@types/express-rate-limit@^3.3.0":
122 version "3.3.3" 127 version "3.3.3"
123 resolved "https://registry.yarnpkg.com/@types/express-rate-limit/-/express-rate-limit-3.3.3.tgz#1be5c551be1615d243e3eec14dca091009c61113" 128 resolved "https://registry.yarnpkg.com/@types/express-rate-limit/-/express-rate-limit-3.3.3.tgz#1be5c551be1615d243e3eec14dca091009c61113"
@@ -163,6 +168,11 @@
163 dependencies: 168 dependencies:
164 "@types/node" "*" 169 "@types/node" "*"
165 170
171"@types/json-schema@^7.0.3":
172 version "7.0.4"
173 resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
174 integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==
175
166"@types/json5@^0.0.29": 176"@types/json5@^0.0.29":
167 version "0.0.29" 177 version "0.0.29"
168 resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" 178 resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
@@ -392,6 +402,49 @@
392 dependencies: 402 dependencies:
393 "@types/node" "*" 403 "@types/node" "*"
394 404
405"@typescript-eslint/eslint-plugin@^2.18.0":
406 version "2.18.0"
407 resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.18.0.tgz#f8cf272dfb057ecf1ea000fea1e0b3f06a32f9cb"
408 integrity sha512-kuO8WQjV+RCZvAXVRJfXWiJ8iYEtfHlKgcqqqXg9uUkIolEHuUaMmm8/lcO4xwCOtaw6mY0gStn2Lg4/eUXXYQ==
409 dependencies:
410 "@typescript-eslint/experimental-utils" "2.18.0"
411 eslint-utils "^1.4.3"
412 functional-red-black-tree "^1.0.1"
413 regexpp "^3.0.0"
414 tsutils "^3.17.1"
415
416"@typescript-eslint/experimental-utils@2.18.0":
417 version "2.18.0"
418 resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.18.0.tgz#e4eab839082030282496c1439bbf9fdf2a4f3da8"
419 integrity sha512-J6MopKPHuJYmQUkANLip7g9I82ZLe1naCbxZZW3O2sIxTiq/9YYoOELEKY7oPg0hJ0V/AQ225h2z0Yp+RRMXhw==
420 dependencies:
421 "@types/json-schema" "^7.0.3"
422 "@typescript-eslint/typescript-estree" "2.18.0"
423 eslint-scope "^5.0.0"
424
425"@typescript-eslint/parser@^2.10.0":
426 version "2.18.0"
427 resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.18.0.tgz#d5f7fc1839abd4a985394e40e9d2454bd56aeb1f"
428 integrity sha512-SJJPxFMEYEWkM6pGfcnjLU+NJIPo+Ko1QrCBL+i0+zV30ggLD90huEmMMhKLHBpESWy9lVEeWlQibweNQzyc+A==
429 dependencies:
430 "@types/eslint-visitor-keys" "^1.0.0"
431 "@typescript-eslint/experimental-utils" "2.18.0"
432 "@typescript-eslint/typescript-estree" "2.18.0"
433 eslint-visitor-keys "^1.1.0"
434
435"@typescript-eslint/typescript-estree@2.18.0":
436 version "2.18.0"
437 resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.18.0.tgz#cfbd16ed1b111166617d718619c19b62764c8460"
438 integrity sha512-gVHylf7FDb8VSi2ypFuEL3hOtoC4HkZZ5dOjXvVjoyKdRrvXAOPSzpNRnKMfaUUEiSLP8UF9j9X9EDLxC0lfZg==
439 dependencies:
440 debug "^4.1.1"
441 eslint-visitor-keys "^1.1.0"
442 glob "^7.1.6"
443 is-glob "^4.0.1"
444 lodash "^4.17.15"
445 semver "^6.3.0"
446 tsutils "^3.17.1"
447
395abbrev@1: 448abbrev@1:
396 version "1.1.1" 449 version "1.1.1"
397 resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 450 resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@@ -405,6 +458,16 @@ accepts@~1.3.4, accepts@~1.3.7:
405 mime-types "~2.1.24" 458 mime-types "~2.1.24"
406 negotiator "0.6.2" 459 negotiator "0.6.2"
407 460
461acorn-jsx@^5.1.0:
462 version "5.1.0"
463 resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384"
464 integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==
465
466acorn@^7.1.0:
467 version "7.1.0"
468 resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
469 integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
470
408addr-to-ip-port@^1.0.1, addr-to-ip-port@^1.4.2: 471addr-to-ip-port@^1.0.1, addr-to-ip-port@^1.4.2:
409 version "1.5.1" 472 version "1.5.1"
410 resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.1.tgz#bfada13fd6aeeeac19f1e9f7d84b4bbab45e5208" 473 resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.1.tgz#bfada13fd6aeeeac19f1e9f7d84b4bbab45e5208"
@@ -420,7 +483,7 @@ after@0.8.2:
420 resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" 483 resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
421 integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= 484 integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
422 485
423ajv@^6.5.5: 486ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5:
424 version "6.11.0" 487 version "6.11.0"
425 resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9" 488 resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
426 integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA== 489 integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
@@ -442,6 +505,13 @@ ansi-colors@3.2.3:
442 resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" 505 resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
443 integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== 506 integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
444 507
508ansi-escapes@^4.2.1:
509 version "4.3.0"
510 resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d"
511 integrity sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==
512 dependencies:
513 type-fest "^0.8.1"
514
445ansi-regex@^2.0.0: 515ansi-regex@^2.0.0:
446 version "2.1.1" 516 version "2.1.1"
447 resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 517 resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
@@ -530,6 +600,23 @@ array-flatten@1.1.1:
530 resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 600 resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
531 integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 601 integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
532 602
603array-includes@^3.0.3:
604 version "3.1.1"
605 resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348"
606 integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==
607 dependencies:
608 define-properties "^1.1.3"
609 es-abstract "^1.17.0"
610 is-string "^1.0.5"
611
612array.prototype.flat@^1.2.1:
613 version "1.2.3"
614 resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
615 integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==
616 dependencies:
617 define-properties "^1.1.3"
618 es-abstract "^1.17.0-next.1"
619
533arraybuffer.slice@~0.0.7: 620arraybuffer.slice@~0.0.7:
534 version "0.0.7" 621 version "0.0.7"
535 resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" 622 resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
@@ -557,6 +644,11 @@ assertion-error@^1.1.0:
557 resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 644 resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
558 integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 645 integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
559 646
647astral-regex@^1.0.0:
648 version "1.0.0"
649 resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
650 integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
651
560async-limiter@~1.0.0: 652async-limiter@~1.0.0:
561 version "1.0.1" 653 version "1.0.1"
562 resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" 654 resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
@@ -899,11 +991,6 @@ bufferutil@^4.0.0:
899 dependencies: 991 dependencies:
900 node-gyp-build "~3.7.0" 992 node-gyp-build "~3.7.0"
901 993
902builtin-modules@^1.1.1:
903 version "1.1.1"
904 resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
905 integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
906
907bull@^3.4.2: 994bull@^3.4.2:
908 version "3.12.1" 995 version "3.12.1"
909 resolved "https://registry.yarnpkg.com/bull/-/bull-3.12.1.tgz#ced62d0afca81c9264b44f1b6f39243df5d2e73f" 996 resolved "https://registry.yarnpkg.com/bull/-/bull-3.12.1.tgz#ced62d0afca81c9264b44f1b6f39243df5d2e73f"
@@ -943,6 +1030,11 @@ callsite@1.0.0:
943 resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" 1030 resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
944 integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= 1031 integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
945 1032
1033callsites@^3.0.0:
1034 version "3.1.0"
1035 resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
1036 integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
1037
946camelcase@^4.0.0: 1038camelcase@^4.0.0:
947 version "4.1.0" 1039 version "4.1.0"
948 resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" 1040 resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
@@ -1009,7 +1101,7 @@ chai@^4.1.1:
1009 pathval "^1.1.0" 1101 pathval "^1.1.0"
1010 type-detect "^4.0.5" 1102 type-detect "^4.0.5"
1011 1103
1012chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2: 1104chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
1013 version "2.4.2" 1105 version "2.4.2"
1014 resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 1106 resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
1015 integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 1107 integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -1026,6 +1118,11 @@ chalk@^3.0.0:
1026 ansi-styles "^4.1.0" 1118 ansi-styles "^4.1.0"
1027 supports-color "^7.1.0" 1119 supports-color "^7.1.0"
1028 1120
1121chardet@^0.7.0:
1122 version "0.7.0"
1123 resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
1124 integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
1125
1029charenc@~0.0.1: 1126charenc@~0.0.1:
1030 version "0.0.2" 1127 version "0.0.2"
1031 resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" 1128 resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
@@ -1128,6 +1225,18 @@ cli-boxes@^1.0.0:
1128 resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" 1225 resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
1129 integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= 1226 integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
1130 1227
1228cli-cursor@^3.1.0:
1229 version "3.1.0"
1230 resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
1231 integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
1232 dependencies:
1233 restore-cursor "^3.1.0"
1234
1235cli-width@^2.0.0:
1236 version "2.2.0"
1237 resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
1238 integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
1239
1131cliui@^5.0.0: 1240cliui@^5.0.0:
1132 version "5.0.0" 1241 version "5.0.0"
1133 resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" 1242 resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
@@ -1255,7 +1364,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
1255 dependencies: 1364 dependencies:
1256 delayed-stream "~1.0.0" 1365 delayed-stream "~1.0.0"
1257 1366
1258commander@^2.12.1, commander@^2.20.0, commander@^2.7.1: 1367commander@^2.20.0, commander@^2.7.1:
1259 version "2.20.3" 1368 version "2.20.3"
1260 resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 1369 resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
1261 integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 1370 integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -1346,6 +1455,11 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
1346 resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 1455 resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
1347 integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= 1456 integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
1348 1457
1458contains-path@^0.1.0:
1459 version "0.1.0"
1460 resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
1461 integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
1462
1349content-disposition@0.5.3: 1463content-disposition@0.5.3:
1350 version "0.5.3" 1464 version "0.5.3"
1351 resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 1465 resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
@@ -1446,6 +1560,17 @@ cross-spawn@^5.0.1:
1446 shebang-command "^1.2.0" 1560 shebang-command "^1.2.0"
1447 which "^1.2.9" 1561 which "^1.2.9"
1448 1562
1563cross-spawn@^6.0.5:
1564 version "6.0.5"
1565 resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
1566 integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
1567 dependencies:
1568 nice-try "^1.0.4"
1569 path-key "^2.0.1"
1570 semver "^5.5.0"
1571 shebang-command "^1.2.0"
1572 which "^1.2.9"
1573
1449cross-spawn@^7.0.0: 1574cross-spawn@^7.0.0:
1450 version "7.0.1" 1575 version "7.0.1"
1451 resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" 1576 resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
@@ -1495,7 +1620,7 @@ date-fns@^2.0.1:
1495 resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.9.0.tgz#d0b175a5c37ed5f17b97e2272bbc1fa5aec677d2" 1620 resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.9.0.tgz#d0b175a5c37ed5f17b97e2272bbc1fa5aec677d2"
1496 integrity sha512-khbFLu/MlzLjEzy9Gh8oY1hNt/Dvxw3J6Rbc28cVoYWQaC1S3YI4xwkF9ZWcjDLscbZlY9hISMr66RFzZagLsA== 1621 integrity sha512-khbFLu/MlzLjEzy9Gh8oY1hNt/Dvxw3J6Rbc28cVoYWQaC1S3YI4xwkF9ZWcjDLscbZlY9hISMr66RFzZagLsA==
1497 1622
1498debug@2.6.9, debug@^2.2.0: 1623debug@2.6.9, debug@^2.2.0, debug@^2.6.9:
1499 version "2.6.9" 1624 version "2.6.9"
1500 resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 1625 resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
1501 integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 1626 integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -1564,6 +1689,11 @@ deep-extend@^0.6.0:
1564 resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 1689 resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
1565 integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== 1690 integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
1566 1691
1692deep-is@~0.1.3:
1693 version "0.1.3"
1694 resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
1695 integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
1696
1567deep-object-diff@^1.1.0: 1697deep-object-diff@^1.1.0:
1568 version "1.1.0" 1698 version "1.1.0"
1569 resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" 1699 resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a"
@@ -1643,13 +1773,20 @@ dns-prefetch-control@0.2.0:
1643 resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz#73988161841f3dcc81f47686d539a2c702c88624" 1773 resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz#73988161841f3dcc81f47686d539a2c702c88624"
1644 integrity sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q== 1774 integrity sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q==
1645 1775
1646doctrine@0.7.2: 1776doctrine@1.5.0:
1647 version "0.7.2" 1777 version "1.5.0"
1648 resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" 1778 resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
1649 integrity sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM= 1779 integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=
1650 dependencies: 1780 dependencies:
1651 esutils "^1.1.6" 1781 esutils "^2.0.2"
1652 isarray "0.0.1" 1782 isarray "^1.0.0"
1783
1784doctrine@^3.0.0:
1785 version "3.0.0"
1786 resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
1787 integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
1788 dependencies:
1789 esutils "^2.0.2"
1653 1790
1654dont-sniff-mimetype@1.1.0: 1791dont-sniff-mimetype@1.1.0:
1655 version "1.1.0" 1792 version "1.1.0"
@@ -1815,14 +1952,14 @@ env-variable@0.0.x:
1815 resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.6.tgz#74ab20b3786c545b62b4a4813ab8cf22726c9808" 1952 resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.6.tgz#74ab20b3786c545b62b4a4813ab8cf22726c9808"
1816 integrity sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg== 1953 integrity sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg==
1817 1954
1818error-ex@^1.3.1: 1955error-ex@^1.2.0, error-ex@^1.3.1:
1819 version "1.3.2" 1956 version "1.3.2"
1820 resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 1957 resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
1821 integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 1958 integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
1822 dependencies: 1959 dependencies:
1823 is-arrayish "^0.2.1" 1960 is-arrayish "^0.2.1"
1824 1961
1825es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: 1962es-abstract@^1.17.0, es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2:
1826 version "1.17.4" 1963 version "1.17.4"
1827 resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" 1964 resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184"
1828 integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== 1965 integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==
@@ -1899,15 +2036,185 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5, escape-string-regexp@~1
1899 resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 2036 resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
1900 integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 2037 integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
1901 2038
2039eslint-config-standard-with-typescript@^12.0.1:
2040 version "12.0.1"
2041 resolved "https://registry.yarnpkg.com/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-12.0.1.tgz#60f941a3a942b50393715ca336e1c7ba76e3ab04"
2042 integrity sha512-v0DDNzsb36Oun3N04Y27Ca9DfF+S9Orrdtqa5anUUpwIu/MMqCRxYAcKdD0Uao+Gzqz9EjaFYjBKZCPFyXH5jw==
2043 dependencies:
2044 "@typescript-eslint/parser" "^2.10.0"
2045 eslint-config-standard "^14.1.0"
2046
2047eslint-config-standard@^14.1.0:
2048 version "14.1.0"
2049 resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz#b23da2b76fe5a2eba668374f246454e7058f15d4"
2050 integrity sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA==
2051
2052eslint-import-resolver-node@^0.3.2:
2053 version "0.3.3"
2054 resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404"
2055 integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==
2056 dependencies:
2057 debug "^2.6.9"
2058 resolve "^1.13.1"
2059
2060eslint-module-utils@^2.4.1:
2061 version "2.5.2"
2062 resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz#7878f7504824e1b857dd2505b59a8e5eda26a708"
2063 integrity sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==
2064 dependencies:
2065 debug "^2.6.9"
2066 pkg-dir "^2.0.0"
2067
2068eslint-plugin-es@^3.0.0:
2069 version "3.0.0"
2070 resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz#98cb1bc8ab0aa807977855e11ad9d1c9422d014b"
2071 integrity sha512-6/Jb/J/ZvSebydwbBJO1R9E5ky7YeElfK56Veh7e4QGFHCXoIXGH9HhVz+ibJLM3XJ1XjP+T7rKBLUa/Y7eIng==
2072 dependencies:
2073 eslint-utils "^2.0.0"
2074 regexpp "^3.0.0"
2075
2076eslint-plugin-import@^2.20.1:
2077 version "2.20.1"
2078 resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3"
2079 integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==
2080 dependencies:
2081 array-includes "^3.0.3"
2082 array.prototype.flat "^1.2.1"
2083 contains-path "^0.1.0"
2084 debug "^2.6.9"
2085 doctrine "1.5.0"
2086 eslint-import-resolver-node "^0.3.2"
2087 eslint-module-utils "^2.4.1"
2088 has "^1.0.3"
2089 minimatch "^3.0.4"
2090 object.values "^1.1.0"
2091 read-pkg-up "^2.0.0"
2092 resolve "^1.12.0"
2093
2094eslint-plugin-node@^11.0.0:
2095 version "11.0.0"
2096 resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.0.0.tgz#365944bb0804c5d1d501182a9bc41a0ffefed726"
2097 integrity sha512-chUs/NVID+sknFiJzxoN9lM7uKSOEta8GC8365hw1nDfwIPIjjpRSwwPvQanWv8dt/pDe9EV4anmVSwdiSndNg==
2098 dependencies:
2099 eslint-plugin-es "^3.0.0"
2100 eslint-utils "^2.0.0"
2101 ignore "^5.1.1"
2102 minimatch "^3.0.4"
2103 resolve "^1.10.1"
2104 semver "^6.1.0"
2105
2106eslint-plugin-promise@^4.2.1:
2107 version "4.2.1"
2108 resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
2109 integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
2110
2111eslint-plugin-standard@^4.0.1:
2112 version "4.0.1"
2113 resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4"
2114 integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==
2115
2116eslint-scope@^5.0.0:
2117 version "5.0.0"
2118 resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
2119 integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
2120 dependencies:
2121 esrecurse "^4.1.0"
2122 estraverse "^4.1.1"
2123
2124eslint-utils@^1.4.3:
2125 version "1.4.3"
2126 resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f"
2127 integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==
2128 dependencies:
2129 eslint-visitor-keys "^1.1.0"
2130
2131eslint-utils@^2.0.0:
2132 version "2.0.0"
2133 resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd"
2134 integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==
2135 dependencies:
2136 eslint-visitor-keys "^1.1.0"
2137
2138eslint-visitor-keys@^1.1.0:
2139 version "1.1.0"
2140 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
2141 integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
2142
2143eslint@^6.8.0:
2144 version "6.8.0"
2145 resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
2146 integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==
2147 dependencies:
2148 "@babel/code-frame" "^7.0.0"
2149 ajv "^6.10.0"
2150 chalk "^2.1.0"
2151 cross-spawn "^6.0.5"
2152 debug "^4.0.1"
2153 doctrine "^3.0.0"
2154 eslint-scope "^5.0.0"
2155 eslint-utils "^1.4.3"
2156 eslint-visitor-keys "^1.1.0"
2157 espree "^6.1.2"
2158 esquery "^1.0.1"
2159 esutils "^2.0.2"
2160 file-entry-cache "^5.0.1"
2161 functional-red-black-tree "^1.0.1"
2162 glob-parent "^5.0.0"
2163 globals "^12.1.0"
2164 ignore "^4.0.6"
2165 import-fresh "^3.0.0"
2166 imurmurhash "^0.1.4"
2167 inquirer "^7.0.0"
2168 is-glob "^4.0.0"
2169 js-yaml "^3.13.1"
2170 json-stable-stringify-without-jsonify "^1.0.1"
2171 levn "^0.3.0"
2172 lodash "^4.17.14"
2173 minimatch "^3.0.4"
2174 mkdirp "^0.5.1"
2175 natural-compare "^1.4.0"
2176 optionator "^0.8.3"
2177 progress "^2.0.0"
2178 regexpp "^2.0.1"
2179 semver "^6.1.2"
2180 strip-ansi "^5.2.0"
2181 strip-json-comments "^3.0.1"
2182 table "^5.2.3"
2183 text-table "^0.2.0"
2184 v8-compile-cache "^2.0.3"
2185
2186espree@^6.1.2:
2187 version "6.1.2"
2188 resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d"
2189 integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==
2190 dependencies:
2191 acorn "^7.1.0"
2192 acorn-jsx "^5.1.0"
2193 eslint-visitor-keys "^1.1.0"
2194
1902esprima@^4.0.0: 2195esprima@^4.0.0:
1903 version "4.0.1" 2196 version "4.0.1"
1904 resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 2197 resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
1905 integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 2198 integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
1906 2199
1907esutils@^1.1.6: 2200esquery@^1.0.1:
1908 version "1.1.6" 2201 version "1.0.1"
1909 resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375" 2202 resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
1910 integrity sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U= 2203 integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
2204 dependencies:
2205 estraverse "^4.0.0"
2206
2207esrecurse@^4.1.0:
2208 version "4.2.1"
2209 resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
2210 integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
2211 dependencies:
2212 estraverse "^4.1.0"
2213
2214estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
2215 version "4.3.0"
2216 resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
2217 integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
1911 2218
1912esutils@^2.0.2: 2219esutils@^2.0.2:
1913 version "2.0.3" 2220 version "2.0.3"
@@ -1980,13 +2287,13 @@ express-rate-limit@^4.0.4:
1980 resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-4.0.4.tgz#a495338ae9e58c856b66d1346ec0d86f43ba2e43" 2287 resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-4.0.4.tgz#a495338ae9e58c856b66d1346ec0d86f43ba2e43"
1981 integrity sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g== 2288 integrity sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g==
1982 2289
1983express-validator@^6.1.1: 2290express-validator@^6.4.0:
1984 version "6.3.1" 2291 version "6.4.0"
1985 resolved "https://registry.yarnpkg.com/express-validator/-/express-validator-6.3.1.tgz#5ad6ca3ce6141f33638608d006d26c217500f375" 2292 resolved "https://registry.yarnpkg.com/express-validator/-/express-validator-6.4.0.tgz#634f96b60d53112409e270c038ab818a36f56e47"
1986 integrity sha512-YQHQKP/zlUTN6d38uWwXgK3At5phK6R24pOB/ImWisMUz/U/1AC3ZXMgiZYhtH4ViYJ6UAiV0/nj8s1Qs3kmvw== 2293 integrity sha512-Fs+x0yDOSiUV+o5jIRloMyBxqpSzJiMM8KQW1IRVv2l49F6ATU0F9uPa+3K6vXNlLlhUjauv2FCGLFPMaNr24w==
1987 dependencies: 2294 dependencies:
1988 lodash "^4.17.15" 2295 lodash "^4.17.15"
1989 validator "^11.1.0" 2296 validator "^12.1.0"
1990 2297
1991express@^4.12.4, express@^4.13.3, express@^4.17.1: 2298express@^4.12.4, express@^4.13.3, express@^4.17.1:
1992 version "4.17.1" 2299 version "4.17.1"
@@ -2036,6 +2343,15 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.2:
2036 resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 2343 resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
2037 integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== 2344 integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
2038 2345
2346external-editor@^3.0.3:
2347 version "3.1.0"
2348 resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
2349 integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
2350 dependencies:
2351 chardet "^0.7.0"
2352 iconv-lite "^0.4.24"
2353 tmp "^0.0.33"
2354
2039extsprintf@1.3.0: 2355extsprintf@1.3.0:
2040 version "1.3.0" 2356 version "1.3.0"
2041 resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 2357 resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@@ -2061,6 +2377,11 @@ fast-json-stable-stringify@^2.0.0:
2061 resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 2377 resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
2062 integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 2378 integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
2063 2379
2380fast-levenshtein@~2.0.6:
2381 version "2.0.6"
2382 resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
2383 integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
2384
2064fast-safe-stringify@^2.0.4: 2385fast-safe-stringify@^2.0.4:
2065 version "2.0.7" 2386 version "2.0.7"
2066 resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" 2387 resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
@@ -2076,6 +2397,20 @@ fecha@^2.3.3:
2076 resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" 2397 resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
2077 integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== 2398 integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
2078 2399
2400figures@^3.0.0:
2401 version "3.1.0"
2402 resolved "https://registry.yarnpkg.com/figures/-/figures-3.1.0.tgz#4b198dd07d8d71530642864af2d45dd9e459c4ec"
2403 integrity sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==
2404 dependencies:
2405 escape-string-regexp "^1.0.5"
2406
2407file-entry-cache@^5.0.1:
2408 version "5.0.1"
2409 resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
2410 integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
2411 dependencies:
2412 flat-cache "^2.0.1"
2413
2079filestream@^5.0.0: 2414filestream@^5.0.0:
2080 version "5.0.0" 2415 version "5.0.0"
2081 resolved "https://registry.yarnpkg.com/filestream/-/filestream-5.0.0.tgz#79015f3bae95ad0f47ef818694846f085087b92e" 2416 resolved "https://registry.yarnpkg.com/filestream/-/filestream-5.0.0.tgz#79015f3bae95ad0f47ef818694846f085087b92e"
@@ -2111,6 +2446,13 @@ find-up@3.0.0, find-up@^3.0.0:
2111 dependencies: 2446 dependencies:
2112 locate-path "^3.0.0" 2447 locate-path "^3.0.0"
2113 2448
2449find-up@^2.0.0, find-up@^2.1.0:
2450 version "2.1.0"
2451 resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
2452 integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
2453 dependencies:
2454 locate-path "^2.0.0"
2455
2114find-up@^4.1.0: 2456find-up@^4.1.0:
2115 version "4.1.0" 2457 version "4.1.0"
2116 resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" 2458 resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@@ -2119,6 +2461,15 @@ find-up@^4.1.0:
2119 locate-path "^5.0.0" 2461 locate-path "^5.0.0"
2120 path-exists "^4.0.0" 2462 path-exists "^4.0.0"
2121 2463
2464flat-cache@^2.0.1:
2465 version "2.0.1"
2466 resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
2467 integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
2468 dependencies:
2469 flatted "^2.0.0"
2470 rimraf "2.6.3"
2471 write "1.0.3"
2472
2122flat@^4.1.0: 2473flat@^4.1.0:
2123 version "4.1.0" 2474 version "4.1.0"
2124 resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" 2475 resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
@@ -2133,6 +2484,11 @@ flat@^5.0.0:
2133 dependencies: 2484 dependencies:
2134 is-buffer "~2.0.4" 2485 is-buffer "~2.0.4"
2135 2486
2487flatted@^2.0.0:
2488 version "2.0.1"
2489 resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
2490 integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
2491
2136fluent-ffmpeg@^2.1.0: 2492fluent-ffmpeg@^2.1.0:
2137 version "2.1.2" 2493 version "2.1.2"
2138 resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74" 2494 resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74"
@@ -2243,6 +2599,11 @@ function-bind@^1.1.1:
2243 resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 2599 resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
2244 integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 2600 integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
2245 2601
2602functional-red-black-tree@^1.0.1:
2603 version "1.0.1"
2604 resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
2605 integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
2606
2246gauge@~2.7.3: 2607gauge@~2.7.3:
2247 version "2.7.4" 2608 version "2.7.4"
2248 resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 2609 resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
@@ -2306,7 +2667,7 @@ github-from-package@0.0.0:
2306 resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" 2667 resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
2307 integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= 2668 integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
2308 2669
2309glob-parent@~5.1.0: 2670glob-parent@^5.0.0, glob-parent@~5.1.0:
2310 version "5.1.0" 2671 version "5.1.0"
2311 resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" 2672 resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
2312 integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== 2673 integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
@@ -2337,7 +2698,7 @@ glob@7.1.3:
2337 once "^1.3.0" 2698 once "^1.3.0"
2338 path-is-absolute "^1.0.0" 2699 path-is-absolute "^1.0.0"
2339 2700
2340glob@^7.0.3, glob@^7.1.1, glob@^7.1.3: 2701glob@^7.0.3, glob@^7.1.3, glob@^7.1.6:
2341 version "7.1.6" 2702 version "7.1.6"
2342 resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 2703 resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
2343 integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 2704 integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -2356,6 +2717,13 @@ global-dirs@^0.1.0:
2356 dependencies: 2717 dependencies:
2357 ini "^1.3.4" 2718 ini "^1.3.4"
2358 2719
2720globals@^12.1.0:
2721 version "12.3.0"
2722 resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13"
2723 integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==
2724 dependencies:
2725 type-fest "^0.8.1"
2726
2359got@^6.7.1: 2727got@^6.7.1:
2360 version "6.7.1" 2728 version "6.7.1"
2361 resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" 2729 resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
@@ -2575,7 +2943,7 @@ i@0.3.x:
2575 resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" 2943 resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d"
2576 integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= 2944 integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=
2577 2945
2578iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.24: 2946iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.24:
2579 version "0.4.24" 2947 version "0.4.24"
2580 resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 2948 resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
2581 integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 2949 integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@@ -2599,6 +2967,16 @@ ignore-walk@^3.0.1:
2599 dependencies: 2967 dependencies:
2600 minimatch "^3.0.4" 2968 minimatch "^3.0.4"
2601 2969
2970ignore@^4.0.6:
2971 version "4.0.6"
2972 resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
2973 integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
2974
2975ignore@^5.1.1:
2976 version "5.1.4"
2977 resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
2978 integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==
2979
2602immediate-chunk-store@^2.0.0: 2980immediate-chunk-store@^2.0.0:
2603 version "2.1.0" 2981 version "2.1.0"
2604 resolved "https://registry.yarnpkg.com/immediate-chunk-store/-/immediate-chunk-store-2.1.0.tgz#3dbd3b5cc77182526188a8da47e38488a6627336" 2982 resolved "https://registry.yarnpkg.com/immediate-chunk-store/-/immediate-chunk-store-2.1.0.tgz#3dbd3b5cc77182526188a8da47e38488a6627336"
@@ -2606,6 +2984,14 @@ immediate-chunk-store@^2.0.0:
2606 dependencies: 2984 dependencies:
2607 queue-microtask "^1.1.2" 2985 queue-microtask "^1.1.2"
2608 2986
2987import-fresh@^3.0.0:
2988 version "3.2.1"
2989 resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
2990 integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
2991 dependencies:
2992 parent-module "^1.0.0"
2993 resolve-from "^4.0.0"
2994
2609import-lazy@^2.1.0: 2995import-lazy@^2.1.0:
2610 version "2.1.0" 2996 version "2.1.0"
2611 resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" 2997 resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
@@ -2649,6 +3035,25 @@ ini@^1.3.4, ini@~1.3.0:
2649 resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" 3035 resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
2650 integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== 3036 integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
2651 3037
3038inquirer@^7.0.0:
3039 version "7.0.4"
3040 resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703"
3041 integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==
3042 dependencies:
3043 ansi-escapes "^4.2.1"
3044 chalk "^2.4.2"
3045 cli-cursor "^3.1.0"
3046 cli-width "^2.0.0"
3047 external-editor "^3.0.3"
3048 figures "^3.0.0"
3049 lodash "^4.17.15"
3050 mute-stream "0.0.8"
3051 run-async "^2.2.0"
3052 rxjs "^6.5.3"
3053 string-width "^4.1.0"
3054 strip-ansi "^5.1.0"
3055 through "^2.3.6"
3056
2652ioredis@^4.14.1: 3057ioredis@^4.14.1:
2653 version "4.14.1" 3058 version "4.14.1"
2654 resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.14.1.tgz#b73ded95fcf220f106d33125a92ef6213aa31318" 3059 resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.14.1.tgz#b73ded95fcf220f106d33125a92ef6213aa31318"
@@ -2794,7 +3199,7 @@ is-generator@^1.0.2:
2794 resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3" 3199 resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3"
2795 integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM= 3200 integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=
2796 3201
2797is-glob@^4.0.1, is-glob@~4.0.1: 3202is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
2798 version "4.0.1" 3203 version "4.0.1"
2799 resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 3204 resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
2800 integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== 3205 integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
@@ -2838,7 +3243,7 @@ is-path-inside@^1.0.0:
2838 dependencies: 3243 dependencies:
2839 path-is-inside "^1.0.1" 3244 path-is-inside "^1.0.1"
2840 3245
2841is-promise@^2.1: 3246is-promise@^2.1, is-promise@^2.1.0:
2842 version "2.1.0" 3247 version "2.1.0"
2843 resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" 3248 resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
2844 integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= 3249 integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
@@ -2870,6 +3275,11 @@ is-stream@^2.0.0:
2870 resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" 3275 resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
2871 integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== 3276 integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
2872 3277
3278is-string@^1.0.5:
3279 version "1.0.5"
3280 resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
3281 integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
3282
2873is-symbol@^1.0.2: 3283is-symbol@^1.0.2:
2874 version "1.0.3" 3284 version "1.0.3"
2875 resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" 3285 resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
@@ -2897,7 +3307,7 @@ isarray@2.0.1:
2897 resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" 3307 resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
2898 integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= 3308 integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
2899 3309
2900isarray@~1.0.0: 3310isarray@^1.0.0, isarray@~1.0.0:
2901 version "1.0.0" 3311 version "1.0.0"
2902 resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 3312 resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
2903 integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 3313 integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
@@ -2959,6 +3369,11 @@ json-schema@0.2.3:
2959 resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 3369 resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
2960 integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= 3370 integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
2961 3371
3372json-stable-stringify-without-jsonify@^1.0.1:
3373 version "1.0.1"
3374 resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
3375 integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
3376
2962json-stringify-safe@~5.0.1: 3377json-stringify-safe@~5.0.1:
2963 version "5.0.1" 3378 version "5.0.1"
2964 resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 3379 resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
@@ -3055,6 +3470,14 @@ latest-version@^3.0.0:
3055 dependencies: 3470 dependencies:
3056 package-json "^4.0.0" 3471 package-json "^4.0.0"
3057 3472
3473levn@^0.3.0, levn@~0.3.0:
3474 version "0.3.0"
3475 resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
3476 integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
3477 dependencies:
3478 prelude-ls "~1.1.2"
3479 type-check "~0.3.2"
3480
3058libxmljs@0.19.7: 3481libxmljs@0.19.7:
3059 version "0.19.7" 3482 version "0.19.7"
3060 resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.7.tgz#96c2151b0b73f33dd29917edec82902587004e5a" 3483 resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.7.tgz#96c2151b0b73f33dd29917edec82902587004e5a"
@@ -3075,6 +3498,24 @@ load-ip-set@^2.1.0:
3075 simple-get "^3.0.0" 3498 simple-get "^3.0.0"
3076 split "^1.0.0" 3499 split "^1.0.0"
3077 3500
3501load-json-file@^2.0.0:
3502 version "2.0.0"
3503 resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
3504 integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
3505 dependencies:
3506 graceful-fs "^4.1.2"
3507 parse-json "^2.2.0"
3508 pify "^2.0.0"
3509 strip-bom "^3.0.0"
3510
3511locate-path@^2.0.0:
3512 version "2.0.0"
3513 resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
3514 integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
3515 dependencies:
3516 p-locate "^2.0.0"
3517 path-exists "^3.0.0"
3518
3078locate-path@^3.0.0: 3519locate-path@^3.0.0:
3079 version "3.0.0" 3520 version "3.0.0"
3080 resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 3521 resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
@@ -3487,7 +3928,7 @@ multistream@^4.0.0:
3487 dependencies: 3928 dependencies:
3488 readable-stream "^3.4.0" 3929 readable-stream "^3.4.0"
3489 3930
3490mute-stream@~0.0.4: 3931mute-stream@0.0.8, mute-stream@~0.0.4:
3491 version "0.0.8" 3932 version "0.0.8"
3492 resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" 3933 resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
3493 integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== 3934 integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
@@ -3502,6 +3943,11 @@ napi-build-utils@^1.0.1:
3502 resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" 3943 resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
3503 integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== 3944 integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
3504 3945
3946natural-compare@^1.4.0:
3947 version "1.4.0"
3948 resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
3949 integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
3950
3505ncp@1.0.x: 3951ncp@1.0.x:
3506 version "1.0.1" 3952 version "1.0.1"
3507 resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" 3953 resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246"
@@ -3536,6 +3982,11 @@ next-tick@1, next-tick@~1.0.0:
3536 resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" 3982 resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
3537 integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= 3983 integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
3538 3984
3985nice-try@^1.0.4:
3986 version "1.0.5"
3987 resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
3988 integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
3989
3539nocache@2.1.0: 3990nocache@2.1.0:
3540 version "2.1.0" 3991 version "2.1.0"
3541 resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" 3992 resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f"
@@ -3769,6 +4220,16 @@ object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0
3769 define-properties "^1.1.3" 4220 define-properties "^1.1.3"
3770 es-abstract "^1.17.0-next.1" 4221 es-abstract "^1.17.0-next.1"
3771 4222
4223object.values@^1.1.0:
4224 version "1.1.1"
4225 resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e"
4226 integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==
4227 dependencies:
4228 define-properties "^1.1.3"
4229 es-abstract "^1.17.0-next.1"
4230 function-bind "^1.1.1"
4231 has "^1.0.3"
4232
3772on-finished@^2.3.0, on-finished@~2.3.0: 4233on-finished@^2.3.0, on-finished@~2.3.0:
3773 version "2.3.0" 4234 version "2.3.0"
3774 resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 4235 resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
@@ -3822,6 +4283,18 @@ opn@^6.0.0:
3822 dependencies: 4283 dependencies:
3823 is-wsl "^1.1.0" 4284 is-wsl "^1.1.0"
3824 4285
4286optionator@^0.8.3:
4287 version "0.8.3"
4288 resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
4289 integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
4290 dependencies:
4291 deep-is "~0.1.3"
4292 fast-levenshtein "~2.0.6"
4293 levn "~0.3.0"
4294 prelude-ls "~1.1.2"
4295 type-check "~0.3.2"
4296 word-wrap "~1.2.3"
4297
3825os-homedir@^1.0.0: 4298os-homedir@^1.0.0:
3826 version "1.0.2" 4299 version "1.0.2"
3827 resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 4300 resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
@@ -3850,6 +4323,13 @@ p-finally@^2.0.0:
3850 resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" 4323 resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561"
3851 integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== 4324 integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==
3852 4325
4326p-limit@^1.1.0:
4327 version "1.3.0"
4328 resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
4329 integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
4330 dependencies:
4331 p-try "^1.0.0"
4332
3853p-limit@^2.0.0, p-limit@^2.2.0: 4333p-limit@^2.0.0, p-limit@^2.2.0:
3854 version "2.2.2" 4334 version "2.2.2"
3855 resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" 4335 resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
@@ -3857,6 +4337,13 @@ p-limit@^2.0.0, p-limit@^2.2.0:
3857 dependencies: 4337 dependencies:
3858 p-try "^2.0.0" 4338 p-try "^2.0.0"
3859 4339
4340p-locate@^2.0.0:
4341 version "2.0.0"
4342 resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
4343 integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
4344 dependencies:
4345 p-limit "^1.1.0"
4346
3860p-locate@^3.0.0: 4347p-locate@^3.0.0:
3861 version "3.0.0" 4348 version "3.0.0"
3862 resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 4349 resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
@@ -3878,6 +4365,11 @@ p-timeout@^3.1.0:
3878 dependencies: 4365 dependencies:
3879 p-finally "^1.0.0" 4366 p-finally "^1.0.0"
3880 4367
4368p-try@^1.0.0:
4369 version "1.0.0"
4370 resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
4371 integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
4372
3881p-try@^2.0.0: 4373p-try@^2.0.0:
3882 version "2.2.0" 4374 version "2.2.0"
3883 resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 4375 resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
@@ -3905,6 +4397,20 @@ packet-reader@1.0.0:
3905 resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" 4397 resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
3906 integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== 4398 integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
3907 4399
4400parent-module@^1.0.0:
4401 version "1.0.1"
4402 resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
4403 integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
4404 dependencies:
4405 callsites "^3.0.0"
4406
4407parse-json@^2.2.0:
4408 version "2.2.0"
4409 resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
4410 integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
4411 dependencies:
4412 error-ex "^1.2.0"
4413
3908parse-json@^4.0.0: 4414parse-json@^4.0.0:
3909 version "4.0.0" 4415 version "4.0.0"
3910 resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" 4416 resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -3977,7 +4483,7 @@ path-is-inside@^1.0.1:
3977 resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 4483 resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
3978 integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= 4484 integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
3979 4485
3980path-key@^2.0.0: 4486path-key@^2.0.0, path-key@^2.0.1:
3981 version "2.0.1" 4487 version "2.0.1"
3982 resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 4488 resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
3983 integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 4489 integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
@@ -3997,6 +4503,13 @@ path-to-regexp@0.1.7:
3997 resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 4503 resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
3998 integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 4504 integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
3999 4505
4506path-type@^2.0.0:
4507 version "2.0.0"
4508 resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
4509 integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
4510 dependencies:
4511 pify "^2.0.0"
4512
4000pathval@^1.1.0: 4513pathval@^1.1.0:
4001 version "1.1.0" 4514 version "1.1.0"
4002 resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" 4515 resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
@@ -4096,11 +4609,23 @@ piece-length@^2.0.1:
4096 resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-2.0.1.tgz#dbed4e78976955f34466d0a65304d0cb21914ac9" 4609 resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-2.0.1.tgz#dbed4e78976955f34466d0a65304d0cb21914ac9"
4097 integrity sha512-dBILiDmm43y0JPISWEmVGKBETQjwJe6mSU9GND+P9KW0SJGUwoU/odyH1nbalOP9i8WSYuqf1lQnaj92Bhw+Ug== 4610 integrity sha512-dBILiDmm43y0JPISWEmVGKBETQjwJe6mSU9GND+P9KW0SJGUwoU/odyH1nbalOP9i8WSYuqf1lQnaj92Bhw+Ug==
4098 4611
4612pify@^2.0.0:
4613 version "2.3.0"
4614 resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
4615 integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
4616
4099pify@^3.0.0: 4617pify@^3.0.0:
4100 version "3.0.0" 4618 version "3.0.0"
4101 resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" 4619 resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
4102 integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= 4620 integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
4103 4621
4622pkg-dir@^2.0.0:
4623 version "2.0.0"
4624 resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
4625 integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
4626 dependencies:
4627 find-up "^2.1.0"
4628
4104pkginfo@0.3.x: 4629pkginfo@0.3.x:
4105 version "0.3.1" 4630 version "0.3.1"
4106 resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" 4631 resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21"
@@ -4154,6 +4679,11 @@ prebuild-install@^5.3.3:
4154 tunnel-agent "^0.6.0" 4679 tunnel-agent "^0.6.0"
4155 which-pm-runs "^1.0.0" 4680 which-pm-runs "^1.0.0"
4156 4681
4682prelude-ls@~1.1.2:
4683 version "1.1.2"
4684 resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
4685 integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
4686
4157prepend-http@^1.0.1: 4687prepend-http@^1.0.1:
4158 version "1.0.4" 4688 version "1.0.4"
4159 resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" 4689 resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@@ -4164,6 +4694,11 @@ process-nextick-args@~2.0.0:
4164 resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 4694 resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
4165 integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 4695 integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
4166 4696
4697progress@^2.0.0:
4698 version "2.0.3"
4699 resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
4700 integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
4701
4167promise.prototype.finally@^3.1.1: 4702promise.prototype.finally@^3.1.1:
4168 version "3.1.2" 4703 version "3.1.2"
4169 resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067" 4704 resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067"
@@ -4339,6 +4874,23 @@ rdf-canonize@^1.0.2:
4339 node-forge "^0.9.1" 4874 node-forge "^0.9.1"
4340 semver "^6.3.0" 4875 semver "^6.3.0"
4341 4876
4877read-pkg-up@^2.0.0:
4878 version "2.0.0"
4879 resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
4880 integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
4881 dependencies:
4882 find-up "^2.0.0"
4883 read-pkg "^2.0.0"
4884
4885read-pkg@^2.0.0:
4886 version "2.0.0"
4887 resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
4888 integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
4889 dependencies:
4890 load-json-file "^2.0.0"
4891 normalize-package-data "^2.3.2"
4892 path-type "^2.0.0"
4893
4342read-pkg@^4.0.1: 4894read-pkg@^4.0.1:
4343 version "4.0.1" 4895 version "4.0.1"
4344 resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" 4896 resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
@@ -4464,6 +5016,16 @@ reflect-metadata@^0.1.12:
4464 resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" 5016 resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
4465 integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== 5017 integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
4466 5018
5019regexpp@^2.0.1:
5020 version "2.0.1"
5021 resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
5022 integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
5023
5024regexpp@^3.0.0:
5025 version "3.0.0"
5026 resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e"
5027 integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==
5028
4467registry-auth-token@^3.0.1: 5029registry-auth-token@^3.0.1:
4468 version "3.4.0" 5030 version "3.4.0"
4469 resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" 5031 resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
@@ -4531,6 +5093,11 @@ resolve-from@^2.0.0:
4531 resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" 5093 resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
4532 integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= 5094 integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=
4533 5095
5096resolve-from@^4.0.0:
5097 version "4.0.0"
5098 resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
5099 integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
5100
4534resolve-pkg@^1.0.0: 5101resolve-pkg@^1.0.0:
4535 version "1.0.0" 5102 version "1.0.0"
4536 resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9" 5103 resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9"
@@ -4538,13 +5105,21 @@ resolve-pkg@^1.0.0:
4538 dependencies: 5105 dependencies:
4539 resolve-from "^2.0.0" 5106 resolve-from "^2.0.0"
4540 5107
4541resolve@^1.10.0, resolve@^1.3.2: 5108resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1:
4542 version "1.15.0" 5109 version "1.15.0"
4543 resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5" 5110 resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
4544 integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw== 5111 integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
4545 dependencies: 5112 dependencies:
4546 path-parse "^1.0.6" 5113 path-parse "^1.0.6"
4547 5114
5115restore-cursor@^3.1.0:
5116 version "3.1.0"
5117 resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
5118 integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
5119 dependencies:
5120 onetime "^5.1.0"
5121 signal-exit "^3.0.2"
5122
4548retry-as-promised@^3.2.0: 5123retry-as-promised@^3.2.0:
4549 version "3.2.0" 5124 version "3.2.0"
4550 resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-3.2.0.tgz#769f63d536bec4783549db0777cb56dadd9d8543" 5125 resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-3.2.0.tgz#769f63d536bec4783549db0777cb56dadd9d8543"
@@ -4557,6 +5132,13 @@ revalidator@0.1.x:
4557 resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" 5132 resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b"
4558 integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= 5133 integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs=
4559 5134
5135rimraf@2.6.3:
5136 version "2.6.3"
5137 resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
5138 integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
5139 dependencies:
5140 glob "^7.1.3"
5141
4560rimraf@2.x.x, rimraf@^2.6.1, rimraf@^2.6.3: 5142rimraf@2.x.x, rimraf@^2.6.1, rimraf@^2.6.3:
4561 version "2.7.1" 5143 version "2.7.1"
4562 resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 5144 resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -4571,6 +5153,13 @@ rimraf@^3.0.0:
4571 dependencies: 5153 dependencies:
4572 glob "^7.1.3" 5154 glob "^7.1.3"
4573 5155
5156run-async@^2.2.0:
5157 version "2.3.0"
5158 resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
5159 integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
5160 dependencies:
5161 is-promise "^2.1.0"
5162
4574run-parallel-limit@^1.0.3: 5163run-parallel-limit@^1.0.3:
4575 version "1.0.5" 5164 version "1.0.5"
4576 resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7" 5165 resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7"
@@ -4591,7 +5180,7 @@ rusha@^0.8.1:
4591 resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a" 5180 resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a"
4592 integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo= 5181 integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo=
4593 5182
4594rxjs@^6.5.2: 5183rxjs@^6.5.2, rxjs@^6.5.3:
4595 version "6.5.4" 5184 version "6.5.4"
4596 resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" 5185 resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
4597 integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== 5186 integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
@@ -4635,7 +5224,7 @@ semver-diff@^2.0.0:
4635 dependencies: 5224 dependencies:
4636 semver "^5.0.3" 5225 semver "^5.0.3"
4637 5226
4638"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.7.0, semver@^5.7.1: 5227"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.7.0, semver@^5.7.1:
4639 version "5.7.1" 5228 version "5.7.1"
4640 resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 5229 resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
4641 integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 5230 integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -4645,7 +5234,7 @@ semver@4.3.2:
4645 resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" 5234 resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7"
4646 integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= 5235 integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=
4647 5236
4648semver@^6.3.0: 5237semver@^6.1.0, semver@^6.1.2, semver@^6.3.0:
4649 version "6.3.0" 5238 version "6.3.0"
4650 resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 5239 resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
4651 integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 5240 integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
@@ -4838,6 +5427,15 @@ sitemap@^5.0.0:
4838 sax "^1.2.4" 5427 sax "^1.2.4"
4839 xmlbuilder "^13.0.2" 5428 xmlbuilder "^13.0.2"
4840 5429
5430slice-ansi@^2.1.0:
5431 version "2.1.0"
5432 resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
5433 integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
5434 dependencies:
5435 ansi-styles "^3.2.0"
5436 astral-regex "^1.0.0"
5437 is-fullwidth-code-point "^2.0.0"
5438
4841smtp-connection@4.0.2: 5439smtp-connection@4.0.2:
4842 version "4.0.2" 5440 version "4.0.2"
4843 resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-4.0.2.tgz#d9dd68d38569f3ad9265473670d09d8f3ea518db" 5441 resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-4.0.2.tgz#d9dd68d38569f3ad9265473670d09d8f3ea518db"
@@ -5230,6 +5828,11 @@ strip-json-comments@2.0.1, strip-json-comments@~2.0.1:
5230 resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 5828 resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
5231 integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 5829 integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
5232 5830
5831strip-json-comments@^3.0.1:
5832 version "3.0.1"
5833 resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
5834 integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
5835
5233superagent@^3.8.3: 5836superagent@^3.8.3:
5234 version "3.8.3" 5837 version "3.8.3"
5235 resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" 5838 resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128"
@@ -5310,6 +5913,16 @@ swagger-parser@^8.0.4:
5310 swagger-methods "^2.0.1" 5913 swagger-methods "^2.0.1"
5311 z-schema "^4.2.2" 5914 z-schema "^4.2.2"
5312 5915
5916table@^5.2.3:
5917 version "5.4.6"
5918 resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
5919 integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
5920 dependencies:
5921 ajv "^6.10.2"
5922 lodash "^4.17.14"
5923 slice-ansi "^2.1.0"
5924 string-width "^3.0.0"
5925
5313tar-fs@^2.0.0: 5926tar-fs@^2.0.0:
5314 version "2.0.0" 5927 version "2.0.0"
5315 resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad" 5928 resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad"
@@ -5368,6 +5981,11 @@ text-hex@1.0.x:
5368 resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" 5981 resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
5369 integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== 5982 integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
5370 5983
5984text-table@^0.2.0:
5985 version "0.2.0"
5986 resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
5987 integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
5988
5371thirty-two@^1.0.1: 5989thirty-two@^1.0.1:
5372 version "1.0.2" 5990 version "1.0.2"
5373 resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" 5991 resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a"
@@ -5397,7 +6015,7 @@ through2@^2.0.3:
5397 readable-stream "~2.3.6" 6015 readable-stream "~2.3.6"
5398 xtend "~4.0.1" 6016 xtend "~4.0.1"
5399 6017
5400through@2: 6018through@2, through@^2.3.6:
5401 version "2.3.8" 6019 version "2.3.8"
5402 resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 6020 resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
5403 integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= 6021 integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
@@ -5420,7 +6038,7 @@ timers-ext@^0.1.5:
5420 es5-ext "~0.10.46" 6038 es5-ext "~0.10.46"
5421 next-tick "1" 6039 next-tick "1"
5422 6040
5423tmp@0.0.x: 6041tmp@0.0.x, tmp@^0.0.33:
5424 version "0.0.33" 6042 version "0.0.33"
5425 resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" 6043 resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
5426 integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== 6044 integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
@@ -5531,59 +6149,12 @@ tsconfig-paths@^3.9.0:
5531 minimist "^1.2.0" 6149 minimist "^1.2.0"
5532 strip-bom "^3.0.0" 6150 strip-bom "^3.0.0"
5533 6151
5534tslib@1.9.0: 6152tslib@^1.8.1, tslib@^1.9.0:
5535 version "1.9.0"
5536 resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
5537 integrity sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==
5538
5539tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
5540 version "1.10.0" 6153 version "1.10.0"
5541 resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" 6154 resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
5542 integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== 6155 integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
5543 6156
5544tslint-config-standard@^9.0.0: 6157tsutils@^3.17.1:
5545 version "9.0.0"
5546 resolved "https://registry.yarnpkg.com/tslint-config-standard/-/tslint-config-standard-9.0.0.tgz#349a94819d93d5f8d803e3c71cb58ef38eff88e0"
5547 integrity sha512-CAw9J743RnPMemQV/XQ4YyNreC+A1NItACfkm+cBedrOkz6CQfwlnbKn8anUXBfoa4Zo4tjAhblRbsMNcSLfSw==
5548 dependencies:
5549 tslint-eslint-rules "^5.3.1"
5550
5551tslint-eslint-rules@^5.3.1:
5552 version "5.4.0"
5553 resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz#e488cc9181bf193fe5cd7bfca213a7695f1737b5"
5554 integrity sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==
5555 dependencies:
5556 doctrine "0.7.2"
5557 tslib "1.9.0"
5558 tsutils "^3.0.0"
5559
5560tslint@^6.0.0:
5561 version "6.0.0"
5562 resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.0.0.tgz#1c0148beac4779924216302f192cdaa153618310"
5563 integrity sha512-9nLya8GBtlFmmFMW7oXXwoXS1NkrccqTqAtwXzdPV9e2mqSEvCki6iHL/Fbzi5oqbugshzgGPk7KBb2qNP1DSA==
5564 dependencies:
5565 "@babel/code-frame" "^7.0.0"
5566 builtin-modules "^1.1.1"
5567 chalk "^2.3.0"
5568 commander "^2.12.1"
5569 diff "^4.0.1"
5570 glob "^7.1.1"
5571 js-yaml "^3.13.1"
5572 minimatch "^3.0.4"
5573 mkdirp "^0.5.1"
5574 resolve "^1.3.2"
5575 semver "^5.3.0"
5576 tslib "^1.10.0"
5577 tsutils "^2.29.0"
5578
5579tsutils@^2.29.0:
5580 version "2.29.0"
5581 resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
5582 integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
5583 dependencies:
5584 tslib "^1.8.1"
5585
5586tsutils@^3.0.0:
5587 version "3.17.1" 6158 version "3.17.1"
5588 resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" 6159 resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
5589 integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== 6160 integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
@@ -5607,6 +6178,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
5607 resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 6178 resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
5608 integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= 6179 integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
5609 6180
6181type-check@~0.3.2:
6182 version "0.3.2"
6183 resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
6184 integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
6185 dependencies:
6186 prelude-ls "~1.1.2"
6187
5610type-detect@0.1.1: 6188type-detect@0.1.1:
5611 version "0.1.1" 6189 version "0.1.1"
5612 resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" 6190 resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822"
@@ -5617,6 +6195,11 @@ type-detect@^4.0.0, type-detect@^4.0.5:
5617 resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 6195 resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
5618 integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 6196 integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
5619 6197
6198type-fest@^0.8.1:
6199 version "0.8.1"
6200 resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
6201 integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
6202
5620type-is@1.6.15: 6203type-is@1.6.15:
5621 version "1.6.15" 6204 version "1.6.15"
5622 resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" 6205 resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
@@ -5815,6 +6398,11 @@ uuid@^3.1.0, uuid@^3.3.2, uuid@^3.3.3:
5815 resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" 6398 resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
5816 integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== 6399 integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
5817 6400
6401v8-compile-cache@^2.0.3:
6402 version "2.1.0"
6403 resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
6404 integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
6405
5818validate-npm-package-license@^3.0.1: 6406validate-npm-package-license@^3.0.1:
5819 version "3.0.4" 6407 version "3.0.4"
5820 resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" 6408 resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
@@ -5828,7 +6416,7 @@ validator@^10.11.0:
5828 resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" 6416 resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
5829 integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== 6417 integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
5830 6418
5831validator@^11.0.0, validator@^11.1.0: 6419validator@^11.0.0:
5832 version "11.1.0" 6420 version "11.1.0"
5833 resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4" 6421 resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4"
5834 integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg== 6422 integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg==
@@ -6005,6 +6593,11 @@ wkx@^0.4.8:
6005 dependencies: 6593 dependencies:
6006 "@types/node" "*" 6594 "@types/node" "*"
6007 6595
6596word-wrap@~1.2.3:
6597 version "1.2.3"
6598 resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
6599 integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
6600
6008wrap-ansi@^5.1.0: 6601wrap-ansi@^5.1.0:
6009 version "5.1.0" 6602 version "5.1.0"
6010 resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" 6603 resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
@@ -6037,6 +6630,13 @@ write-file-atomic@^2.0.0:
6037 imurmurhash "^0.1.4" 6630 imurmurhash "^0.1.4"
6038 signal-exit "^3.0.2" 6631 signal-exit "^3.0.2"
6039 6632
6633write@1.0.3:
6634 version "1.0.3"
6635 resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
6636 integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
6637 dependencies:
6638 mkdirp "^0.5.1"
6639
6040ws@^7.0.0, ws@^7.1.2: 6640ws@^7.0.0, ws@^7.1.2:
6041 version "7.2.1" 6641 version "7.2.1"
6042 resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e" 6642 resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
@@ -6190,10 +6790,10 @@ yn@3.1.1:
6190 resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 6790 resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
6191 integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 6791 integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
6192 6792
6193youtube-dl@^3.0.1: 6793youtube-dl@^3.0.2:
6194 version "3.0.1" 6794 version "3.0.2"
6195 resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-3.0.1.tgz#c9a159824ba61c67adcb2e1b3f7b7756ae4042b1" 6795 resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-3.0.2.tgz#66236bfbdc93127efe3a7f02894ec544b23e8aa7"
6196 integrity sha512-QsCf3CnzVPbSoXQPs78L8TIYTk6nCtcm6on3ZkhY02D+OJ3Kcup5cuZepB/TLN6TxAQuhoVK6p0tG2bmTItNVA== 6796 integrity sha512-LFFfpsYbRLpqKsnb4gzbnyN7fm190tJw3gJVSvfoEfnb/xYIPNT6i9G3jdzPDp/U5cwB3OSq63nUa7rUwxXAGA==
6197 dependencies: 6797 dependencies:
6198 debug "~4.1.1" 6798 debug "~4.1.1"
6199 execa "~3.2.0" 6799 execa "~3.2.0"