Add ability for client to create server logs
This commit is contained in:
parent
654d4ede7f
commit
42b4063699
97 changed files with 828 additions and 261 deletions
|
@ -2,11 +2,12 @@ import { SortMeta } from 'primeng/api'
|
|||
import { Component, OnInit, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { AuthService, ConfirmService, LocalStorageService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
|
||||
import { prepareIcu, getAPIHost } from '@app/helpers'
|
||||
import { getAPIHost, prepareIcu } from '@app/helpers'
|
||||
import { AdvancedInputFilter } from '@app/shared/shared-forms'
|
||||
import { Actor, DropdownAction } from '@app/shared/shared-main'
|
||||
import { AccountMutedStatus, BlocklistService, UserBanModalComponent, UserModerationDisplayType } from '@app/shared/shared-moderation'
|
||||
import { UserAdminService } from '@app/shared/shared-users'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { User, UserRole } from '@shared/models'
|
||||
|
||||
type UserForList = User & {
|
||||
|
@ -149,7 +150,7 @@ export class UserListComponent extends RestTable implements OnInit {
|
|||
this.selectedColumns = JSON.parse(result)
|
||||
return
|
||||
} catch (err) {
|
||||
console.error('Cannot load selected columns.', err)
|
||||
logger.error('Cannot load selected columns.', err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Component, OnInit } from '@angular/core'
|
|||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service'
|
||||
import { ComponentPagination, ConfirmService, hasMoreItems, Notifier, PluginService } from '@app/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { PeerTubePluginIndex, PluginType } from '@shared/models'
|
||||
|
||||
@Component({
|
||||
|
@ -94,7 +95,7 @@ export class PluginSearchComponent implements OnInit {
|
|||
},
|
||||
|
||||
error: err => {
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
|
||||
const message = $localize`The plugin index is not available. Please retry later.`
|
||||
this.notifier.error(message)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { LogLevel } from '@shared/models'
|
||||
import omit from 'lodash-es/omit'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { ServerLogLevel } from '@shared/models'
|
||||
|
||||
export class LogRow {
|
||||
date: Date
|
||||
localeDate: string
|
||||
level: LogLevel
|
||||
level: ServerLogLevel
|
||||
message: string
|
||||
meta: string
|
||||
|
||||
|
@ -33,7 +34,7 @@ export class LogRow {
|
|||
this.meta = JSON.stringify(message, null, 2)
|
||||
this.message = ''
|
||||
} catch (err) {
|
||||
console.error('Cannot parse audit message.', err)
|
||||
logger.error('Cannot parse audit message.', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
|
||||
import { LocalStorageService, Notifier } from '@app/core'
|
||||
import { LogLevel } from '@shared/models'
|
||||
import { ServerLogLevel } from '@shared/models'
|
||||
import { LogRow } from './log-row.model'
|
||||
import { LogsService } from './logs.service'
|
||||
|
||||
|
@ -17,11 +17,11 @@ export class LogsComponent implements OnInit {
|
|||
|
||||
logs: LogRow[] = []
|
||||
timeChoices: { id: string, label: string, dateFormat: string }[] = []
|
||||
levelChoices: { id: LogLevel, label: string }[] = []
|
||||
levelChoices: { id: ServerLogLevel, label: string }[] = []
|
||||
logTypeChoices: { id: 'audit' | 'standard', label: string }[] = []
|
||||
|
||||
startDate: string
|
||||
level: LogLevel
|
||||
level: ServerLogLevel
|
||||
logType: 'audit' | 'standard'
|
||||
tagsOneOf: string[] = []
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { catchError, map } from 'rxjs/operators'
|
|||
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { RestExtractor, RestService } from '@app/core'
|
||||
import { LogLevel } from '@shared/models'
|
||||
import { ServerLogLevel } from '@shared/models'
|
||||
import { environment } from '../../../../environments/environment'
|
||||
import { LogRow } from './log-row.model'
|
||||
|
||||
|
@ -22,7 +22,7 @@ export class LogsService {
|
|||
isAuditLog: boolean
|
||||
startDate: string
|
||||
tagsOneOf?: string[]
|
||||
level?: LogLevel
|
||||
level?: ServerLogLevel
|
||||
endDate?: string
|
||||
}): Observable<any[]> {
|
||||
const { isAuditLog, startDate, endDate, tagsOneOf } = options
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { PluginService } from '@app/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
@Component({
|
||||
templateUrl: './plugin-pages.component.html'
|
||||
|
@ -26,7 +27,7 @@ export class PluginPagesComponent implements AfterViewInit {
|
|||
|
||||
const registered = this.pluginService.getRegisteredClientRoute(path)
|
||||
if (!registered) {
|
||||
console.log('Could not find registered route %s.', path, this.pluginService.getAllRegisteredClientRoutes())
|
||||
logger.info(`Could not find registered route ${path}`, this.pluginService.getAllRegisteredClientRoutes())
|
||||
|
||||
return this.router.navigate([ '/404' ], { skipLocationChange: true })
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Observable } from 'rxjs'
|
||||
import { map } from 'rxjs/operators'
|
||||
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { ResultList } from '@shared/models'
|
||||
|
||||
export abstract class AbstractLazyLoadResolver <T> implements Resolve<any> {
|
||||
|
@ -10,7 +11,7 @@ export abstract class AbstractLazyLoadResolver <T> implements Resolve<any> {
|
|||
const url = route.params.url
|
||||
|
||||
if (!url) {
|
||||
console.error('Could not find url param.', { params: route.params })
|
||||
logger.error('Could not find url param.', { params: route.params })
|
||||
return this.router.navigateByUrl('/404')
|
||||
}
|
||||
|
||||
|
@ -18,7 +19,7 @@ export abstract class AbstractLazyLoadResolver <T> implements Resolve<any> {
|
|||
.pipe(
|
||||
map(result => {
|
||||
if (result.data.length !== 1) {
|
||||
console.error('Cannot find result for this URL')
|
||||
logger.error('Cannot find result for this URL')
|
||||
return this.router.navigateByUrl('/404')
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { ConfirmService, Notifier, ServerService } from '@app/core'
|
|||
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { VideoDetails } from '@app/shared/shared-main'
|
||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { secondsToTime } from '@shared/core-utils'
|
||||
import { VideoStudioTask, VideoStudioTaskCut } from '@shared/models'
|
||||
import { VideoStudioService } from '../shared'
|
||||
|
@ -97,7 +98,7 @@ export class VideoStudioEditComponent extends FormReactive implements OnInit {
|
|||
this.loadingBar.useRef().complete()
|
||||
this.isRunningEdition = false
|
||||
this.notifier.error(err.message)
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import { VideoCaptionAddModalComponent } from './video-caption-add-modal.compone
|
|||
import { VideoCaptionEditModalComponent } from './video-caption-edit-modal/video-caption-edit-modal.component'
|
||||
import { VideoEditType } from './video-edit.type'
|
||||
import { VideoSource } from '@shared/models/videos/video-source'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
type VideoLanguages = VideoConstant<string> & { group?: string }
|
||||
type PluginField = {
|
||||
|
@ -443,7 +444,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
|||
|
||||
const oldChannel = this.userVideoChannels.find(c => c.id === oldChannelId)
|
||||
if (!newChannel || !oldChannel) {
|
||||
console.error('Cannot find new or old channel.')
|
||||
logger.error('Cannot find new or old channel.')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import { FormValidatorService } from '@app/shared/shared-forms'
|
|||
import { Video, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
|
||||
import { LiveVideoService } from '@app/shared/shared-video-live'
|
||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { LiveVideo, LiveVideoCreate, LiveVideoLatencyMode, LiveVideoUpdate, PeerTubeProblemDocument, ServerErrorCode } from '@shared/models'
|
||||
import { VideoSend } from './video-send'
|
||||
|
||||
|
@ -141,7 +142,7 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
|
|||
error: err => {
|
||||
this.error = err.message
|
||||
scrollToTop()
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import { scrollToTop } from '@app/helpers'
|
|||
import { FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main'
|
||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { PeerTubeProblemDocument, ServerErrorCode, VideoUpdate } from '@shared/models'
|
||||
import { hydrateFormFromVideo } from '../shared/video-edit-utils'
|
||||
import { VideoSend } from './video-send'
|
||||
|
@ -139,7 +140,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Af
|
|||
error: err => {
|
||||
this.error = err.message
|
||||
scrollToTop()
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { scrollToTop } from '@app/helpers'
|
|||
import { FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main'
|
||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { VideoUpdate } from '@shared/models'
|
||||
import { hydrateFormFromVideo } from '../shared/video-edit-utils'
|
||||
import { VideoSend } from './video-send'
|
||||
|
@ -128,7 +129,7 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterV
|
|||
error: err => {
|
||||
this.error = err.message
|
||||
scrollToTop()
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { truncate } from 'lodash-es'
|
||||
import { UploadState, UploadxOptions, UploadxService } from 'ngx-uploadx'
|
||||
import { isIOS } from '@root-helpers/web-browser'
|
||||
import { HttpErrorResponse, HttpEventType, HttpHeaders } from '@angular/common/http'
|
||||
import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
|
@ -9,6 +8,8 @@ import { genericUploadErrorHandler, scrollToTop } from '@app/helpers'
|
|||
import { FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { BytesPipe, Video, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
|
||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { isIOS } from '@root-helpers/web-browser'
|
||||
import { HttpStatusCode, VideoCreateResult } from '@shared/models'
|
||||
import { UploaderXFormData } from './uploaderx-form-data'
|
||||
import { VideoSend } from './video-send'
|
||||
|
@ -264,7 +265,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
|
|||
error: err => {
|
||||
this.error = err.message
|
||||
scrollToTop()
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
|
|||
import { Video, VideoCaptionEdit, VideoCaptionService, VideoDetails, VideoEdit, VideoService } from '@app/shared/shared-main'
|
||||
import { LiveVideoService } from '@app/shared/shared-video-live'
|
||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { LiveVideo, LiveVideoUpdate, VideoPrivacy } from '@shared/models'
|
||||
import { hydrateFormFromVideo } from './shared/video-edit-utils'
|
||||
import { VideoSource } from '@shared/models/videos/video-source'
|
||||
import { hydrateFormFromVideo } from './shared/video-edit-utils'
|
||||
|
||||
@Component({
|
||||
selector: 'my-videos-update',
|
||||
|
@ -156,7 +157,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
|
|||
this.loadingBar.useRef().complete()
|
||||
this.isUpdatingVideo = false
|
||||
this.notifier.error(err.message)
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'
|
||||
import { MarkdownService, Notifier } from '@app/core'
|
||||
import { VideoDetails, VideoService } from '@app/shared/shared-main'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-description',
|
||||
|
@ -75,7 +76,7 @@ export class VideoDescriptionComponent implements OnChanges {
|
|||
private updateVideoDescription (description: string) {
|
||||
this.video.description = description
|
||||
this.setVideoDescriptionHTML()
|
||||
.catch(err => console.error(err))
|
||||
.catch(err => logger.error(err))
|
||||
}
|
||||
|
||||
private async setVideoDescriptionHTML () {
|
||||
|
|
|
@ -24,6 +24,7 @@ import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/sha
|
|||
import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
|
||||
import { LiveVideoService } from '@app/shared/shared-video-live'
|
||||
import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { isP2PEnabled } from '@root-helpers/video'
|
||||
import { timeToInt } from '@shared/core-utils'
|
||||
import {
|
||||
|
@ -225,7 +226,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
: parseInt(positionParam + '', 10)
|
||||
|
||||
if (isNaN(this.playlistPosition)) {
|
||||
console.error(`playlistPosition query param '${positionParam}' was parsed as NaN, defaulting to 1.`)
|
||||
logger.error(`playlistPosition query param '${positionParam}' was parsed as NaN, defaulting to 1.`)
|
||||
this.playlistPosition = 1
|
||||
}
|
||||
|
||||
|
@ -378,7 +379,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
this.buildPlayer(urlOptions, loggedInOrAnonymousUser)
|
||||
.catch(err => console.error('Cannot build the player', err))
|
||||
.catch(err => logger.error('Cannot build the player', err))
|
||||
|
||||
this.setOpenGraphTags()
|
||||
|
||||
|
@ -550,7 +551,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
this.player.dispose()
|
||||
this.player = undefined
|
||||
} catch (err) {
|
||||
console.error('Cannot dispose player.', err)
|
||||
logger.error('Cannot dispose player.', err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -717,7 +718,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
private handleLiveStateChange (newState: VideoState) {
|
||||
if (newState !== VideoState.PUBLISHED) return
|
||||
|
||||
console.log('Loading video after live update.')
|
||||
logger.info('Loading video after live update.')
|
||||
|
||||
const videoUUID = this.video.uuid
|
||||
|
||||
|
@ -728,11 +729,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
|
||||
private handleLiveViewsChange (newViewers: number) {
|
||||
if (!this.video) {
|
||||
console.error('Cannot update video live views because video is no defined.')
|
||||
logger.error('Cannot update video live views because video is no defined.')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Updating live views.')
|
||||
logger.info('Updating live views.')
|
||||
|
||||
this.video.viewers = newViewers
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||
import { forkJoin, delay } from 'rxjs'
|
||||
import { delay, forkJoin } from 'rxjs'
|
||||
import { filter, first, map } from 'rxjs/operators'
|
||||
import { DOCUMENT, getLocaleDirection, PlatformLocation } from '@angular/common'
|
||||
import { AfterViewInit, Component, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core'
|
||||
|
@ -20,18 +20,19 @@ import {
|
|||
import { HooksService } from '@app/core/plugins/hooks.service'
|
||||
import { PluginService } from '@app/core/plugins/plugin.service'
|
||||
import { AccountSetupWarningModalComponent } from '@app/modal/account-setup-warning-modal.component'
|
||||
import { AdminWelcomeModalComponent } from '@app/modal/admin-welcome-modal.component'
|
||||
import { CustomModalComponent } from '@app/modal/custom-modal.component'
|
||||
import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
|
||||
import { AdminWelcomeModalComponent } from '@app/modal/admin-welcome-modal.component'
|
||||
import { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||
import { getShortLocale } from '@shared/core-utils/i18n'
|
||||
import { BroadcastMessageLevel, HTMLServerConfig, UserRole } from '@shared/models'
|
||||
import { MenuService } from './core/menu/menu.service'
|
||||
import { POP_STATE_MODAL_DISMISS } from './helpers'
|
||||
import { InstanceService } from './shared/shared-instance'
|
||||
import { GlobalIconName } from './shared/shared-icons'
|
||||
import { InstanceService } from './shared/shared-instance'
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
|
@ -221,7 +222,7 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||
/* eslint-disable no-eval */
|
||||
eval(this.serverConfig.instance.customizations.javascript)
|
||||
} catch (err) {
|
||||
console.error('Cannot eval custom JavaScript.', err)
|
||||
logger.error('Cannot eval custom JavaScript.', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
|
|||
import { Injectable } from '@angular/core'
|
||||
import { Router } from '@angular/router'
|
||||
import { Notifier } from '@app/core/notification/notifier.service'
|
||||
import { objectToUrlEncoded, peertubeLocalStorage, UserTokens } from '@root-helpers/index'
|
||||
import { logger, objectToUrlEncoded, peertubeLocalStorage, UserTokens } from '@root-helpers/index'
|
||||
import { HttpStatusCode, MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models'
|
||||
import { environment } from '../../../environments/environment'
|
||||
import { RestExtractor } from '../rest/rest-extractor.service'
|
||||
|
@ -90,7 +90,7 @@ export class AuthService {
|
|||
peertubeLocalStorage.setItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID, this.clientId)
|
||||
peertubeLocalStorage.setItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_SECRET, this.clientSecret)
|
||||
|
||||
console.log('Client credentials loaded.')
|
||||
logger.info('Client credentials loaded.')
|
||||
},
|
||||
|
||||
error: err => {
|
||||
|
@ -177,7 +177,7 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
|
|||
}
|
||||
},
|
||||
|
||||
error: err => console.error(err)
|
||||
error: err => logger.error(err)
|
||||
})
|
||||
|
||||
this.user = null
|
||||
|
@ -190,7 +190,7 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
|
|||
refreshAccessToken () {
|
||||
if (this.refreshingTokenObservable) return this.refreshingTokenObservable
|
||||
|
||||
console.log('Refreshing token...')
|
||||
logger.info('Refreshing token...')
|
||||
|
||||
const refreshToken = this.getRefreshToken()
|
||||
|
||||
|
@ -212,8 +212,8 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
|
|||
catchError(err => {
|
||||
this.refreshingTokenObservable = null
|
||||
|
||||
console.error(err)
|
||||
console.log('Cannot refresh token -> logout...')
|
||||
logger.error(err)
|
||||
logger.info('Cannot refresh token -> logout...')
|
||||
this.logout()
|
||||
this.router.navigate([ '/login' ])
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { MessageService } from 'primeng/api'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
@Injectable()
|
||||
export class Notifier {
|
||||
|
@ -10,21 +11,21 @@ export class Notifier {
|
|||
info (text: string, title?: string, timeout?: number, sticky?: boolean) {
|
||||
if (!title) title = $localize`Info`
|
||||
|
||||
console.info(`${title}: ${text}`)
|
||||
logger.info(`${title}: ${text}`)
|
||||
return this.notify('info', text, title, timeout, sticky)
|
||||
}
|
||||
|
||||
error (text: string, title?: string, timeout?: number, sticky?: boolean) {
|
||||
if (!title) title = $localize`Error`
|
||||
|
||||
console.error(`${title}: ${text}`)
|
||||
logger.error(`${title}: ${text}`)
|
||||
return this.notify('error', text, title, timeout, sticky)
|
||||
}
|
||||
|
||||
success (text: string, title?: string, timeout?: number, sticky?: boolean) {
|
||||
if (!title) title = $localize`Success`
|
||||
|
||||
console.log(`${title}: ${text}`)
|
||||
logger.info(`${title}: ${text}`)
|
||||
return this.notify('success', text, title, timeout, sticky)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import { from, Observable } from 'rxjs'
|
|||
import { mergeMap, switchMap } from 'rxjs/operators'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { PluginService } from '@app/core/plugins/plugin.service'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { ClientActionHookName, ClientFilterHookName, PluginClientScope } from '@shared/models'
|
||||
import { AuthService, AuthStatus } from '../auth'
|
||||
|
||||
|
@ -50,7 +51,7 @@ export class HooksService {
|
|||
runAction<T, U extends ClientActionHookName> (hookName: U, scope: PluginClientScope, params?: T) {
|
||||
this.pluginService.ensurePluginsAreLoaded(scope)
|
||||
.then(() => this.pluginService.runHook(hookName, undefined, params))
|
||||
.catch((err: any) => console.error('Fatal hook error.', { err }))
|
||||
.catch((err: any) => logger.error('Fatal hook error.', err))
|
||||
}
|
||||
|
||||
async wrapObject<T, U extends ClientFilterHookName> (result: T, scope: PluginClientScope, hookName: U) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'
|
|||
import { Router } from '@angular/router'
|
||||
import { dateToHuman } from '@app/helpers'
|
||||
import { HttpStatusCode, ResultList } from '@shared/models'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
@Injectable()
|
||||
export class RestExtractor {
|
||||
|
@ -64,7 +65,7 @@ export class RestExtractor {
|
|||
if (err.error instanceof Error) {
|
||||
// A client-side or network error occurred. Handle it accordingly.
|
||||
const errorMessage = err.error.detail || err.error.title
|
||||
console.error('An error occurred:', errorMessage)
|
||||
logger.error('An error occurred:', errorMessage)
|
||||
|
||||
return errorMessage
|
||||
}
|
||||
|
@ -75,12 +76,12 @@ export class RestExtractor {
|
|||
|
||||
if (err.status !== undefined) {
|
||||
const errorMessage = this.buildServerErrorMessage(err)
|
||||
console.error(`Backend returned code ${err.status}, errorMessage is: ${errorMessage}`)
|
||||
logger.error(`Backend returned code ${err.status}, errorMessage is: ${errorMessage}`)
|
||||
|
||||
return errorMessage
|
||||
}
|
||||
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import * as debug from 'debug'
|
||||
import debug from 'debug'
|
||||
import { LazyLoadEvent, SortMeta } from 'primeng/api'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||
import { RestPagination } from './rest-pagination'
|
||||
|
||||
const logger = debug('peertube:tables:RestTable')
|
||||
const debugLogger = debug('peertube:tables:RestTable')
|
||||
|
||||
export abstract class RestTable {
|
||||
|
||||
|
@ -34,7 +35,7 @@ export abstract class RestTable {
|
|||
try {
|
||||
this.sort = JSON.parse(result)
|
||||
} catch (err) {
|
||||
console.error('Cannot load sort of local storage key ' + this.getSortLocalStorageKey(), err)
|
||||
logger.error('Cannot load sort of local storage key ' + this.getSortLocalStorageKey(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +45,7 @@ export abstract class RestTable {
|
|||
}
|
||||
|
||||
loadLazy (event: LazyLoadEvent) {
|
||||
logger('Load lazy %o.', event)
|
||||
debugLogger('Load lazy %o.', event)
|
||||
|
||||
this.sort = {
|
||||
order: event.sortOrder,
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Injectable } from '@angular/core'
|
|||
import { ComponentPaginationLight } from './component-pagination.model'
|
||||
import { RestPagination } from './rest-pagination'
|
||||
|
||||
const logger = debug('peertube:rest')
|
||||
const debugLogger = debug('peertube:rest')
|
||||
|
||||
interface QueryStringFilterPrefixes {
|
||||
[key: string]: {
|
||||
|
@ -88,7 +88,7 @@ export class RestService {
|
|||
const prefixeStrings = Object.values(prefixes)
|
||||
.map(p => p.prefix)
|
||||
|
||||
logger(`Built tokens "${tokens.join(', ')}" for prefixes "${prefixeStrings.join(', ')}"`)
|
||||
debugLogger(`Built tokens "${tokens.join(', ')}" for prefixes "${prefixeStrings.join(', ')}"`)
|
||||
|
||||
// Search is the querystring minus defined filters
|
||||
const searchTokens = tokens.filter(t => {
|
||||
|
@ -127,7 +127,7 @@ export class RestService {
|
|||
|
||||
const search = searchTokens.join(' ') || undefined
|
||||
|
||||
logger('Built search: ' + search, additionalFilters)
|
||||
debugLogger('Built search: ' + search, additionalFilters)
|
||||
|
||||
return {
|
||||
search,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ComponentRef, Injectable } from '@angular/core'
|
||||
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { DisableForReuseHook } from './disable-for-reuse-hook'
|
||||
import { PeerTubeRouterService, RouterSetting } from './peertube-router.service'
|
||||
|
||||
|
@ -22,7 +23,7 @@ export class CustomReuseStrategy implements RouteReuseStrategy {
|
|||
const key = this.generateKey(route)
|
||||
this.recentlyUsed = key
|
||||
|
||||
console.log('Storing component %s to reuse later.', key)
|
||||
logger.info(`Storing component ${key} to reuse later.`)
|
||||
|
||||
const componentRef = (handle as any).componentRef as ComponentRef<DisableForReuseHook>
|
||||
componentRef.instance.disableForReuse()
|
||||
|
@ -46,7 +47,7 @@ export class CustomReuseStrategy implements RouteReuseStrategy {
|
|||
const key = this.generateKey(route)
|
||||
this.recentlyUsed = key
|
||||
|
||||
console.log('Reusing component %s.', key)
|
||||
logger.info(`Reusing component ${key}.`)
|
||||
|
||||
const handle = this.storedRouteHandles.get(key)
|
||||
if (!handle) return handle;
|
||||
|
@ -66,7 +67,7 @@ export class CustomReuseStrategy implements RouteReuseStrategy {
|
|||
this.storedRouteHandles.forEach((r, key) => {
|
||||
if (key === this.recentlyUsed) return
|
||||
|
||||
console.log('Removing stored component %s.', key);
|
||||
logger.info(`Removing stored component ${key}`);
|
||||
|
||||
(r as any).componentRef.destroy()
|
||||
this.storedRouteHandles.delete(key)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import * as debug from 'debug'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { NavigationCancel, NavigationEnd, Router } from '@angular/router'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { ServerService } from '../server'
|
||||
import { SessionStorageService } from '../wrappers/storage.service'
|
||||
|
||||
const logger = debug('peertube:router:RedirectService')
|
||||
const debugLogger = debug('peertube:router:RedirectService')
|
||||
|
||||
@Injectable()
|
||||
export class RedirectService {
|
||||
|
@ -40,7 +41,7 @@ export class RedirectService {
|
|||
this.latestSessionUrl = this.storage.getItem(RedirectService.SESSION_STORAGE_LATEST_SESSION_URL_KEY)
|
||||
this.storage.removeItem(RedirectService.SESSION_STORAGE_LATEST_SESSION_URL_KEY)
|
||||
|
||||
logger('Loaded latest session URL %s', this.latestSessionUrl)
|
||||
debugLogger('Loaded latest session URL %s', this.latestSessionUrl)
|
||||
|
||||
// Track previous url
|
||||
this.currentUrl = this.router.url
|
||||
|
@ -51,8 +52,8 @@ export class RedirectService {
|
|||
this.previousUrl = this.currentUrl
|
||||
this.currentUrl = event.url
|
||||
|
||||
logger('Previous URL is %s, current URL is %s', this.previousUrl, this.currentUrl)
|
||||
logger('Setting %s as latest URL in session storage.', this.currentUrl)
|
||||
debugLogger('Previous URL is %s, current URL is %s', this.previousUrl, this.currentUrl)
|
||||
debugLogger('Setting %s as latest URL in session storage.', this.currentUrl)
|
||||
|
||||
this.storage.setItem(RedirectService.SESSION_STORAGE_LATEST_SESSION_URL_KEY, this.currentUrl)
|
||||
}
|
||||
|
@ -84,18 +85,14 @@ export class RedirectService {
|
|||
|
||||
this.redirectingToHomepage = true
|
||||
|
||||
console.log('Redirecting to %s...', this.defaultRoute)
|
||||
logger.info(`Redirecting to ${this.defaultRoute}...`)
|
||||
|
||||
this.router.navigateByUrl(this.defaultRoute, { skipLocationChange })
|
||||
.then(() => this.redirectingToHomepage = false)
|
||||
.catch(() => {
|
||||
this.redirectingToHomepage = false
|
||||
|
||||
console.error(
|
||||
'Cannot navigate to %s, resetting default route to %s.',
|
||||
this.defaultRoute,
|
||||
RedirectService.INIT_DEFAULT_ROUTE
|
||||
)
|
||||
logger.error(`Cannot navigate to ${this.defaultRoute}, resetting default route to ${RedirectService.INIT_DEFAULT_ROUTE}`)
|
||||
|
||||
this.defaultRoute = RedirectService.INIT_DEFAULT_ROUTE
|
||||
return this.router.navigateByUrl(this.defaultRoute, { skipLocationChange })
|
||||
|
@ -104,18 +101,18 @@ export class RedirectService {
|
|||
}
|
||||
|
||||
private doRedirect (redirectUrl: string, fallbackRoute?: string) {
|
||||
logger('Redirecting on %s', redirectUrl)
|
||||
debugLogger('Redirecting on %s', redirectUrl)
|
||||
|
||||
if (this.isValidRedirection(redirectUrl)) {
|
||||
return this.router.navigateByUrl(redirectUrl)
|
||||
}
|
||||
|
||||
logger('%s is not a valid redirection, try fallback route %s', redirectUrl, fallbackRoute)
|
||||
debugLogger('%s is not a valid redirection, try fallback route %s', redirectUrl, fallbackRoute)
|
||||
if (fallbackRoute) {
|
||||
return this.router.navigateByUrl(fallbackRoute)
|
||||
}
|
||||
|
||||
logger('There was no fallback route, redirecting to homepage')
|
||||
debugLogger('There was no fallback route, redirecting to homepage')
|
||||
return this.redirectToHomepage()
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ import { ViewportScroller } from '@angular/common'
|
|||
import { Injectable } from '@angular/core'
|
||||
import { RouterSetting } from '../'
|
||||
import { PeerTubeRouterService } from './peertube-router.service'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
const logger = debug('peertube:main:ScrollService')
|
||||
const debugLogger = debug('peertube:main:ScrollService')
|
||||
|
||||
@Injectable()
|
||||
export class ScrollService {
|
||||
|
@ -57,8 +58,8 @@ export class ScrollService {
|
|||
if (nextSearchParams.toString() !== previousSearchParams.toString()) {
|
||||
this.resetScroll = true
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Cannot parse URL to check next scroll.', e)
|
||||
} catch (err) {
|
||||
logger.error('Cannot parse URL to check next scroll.', err)
|
||||
this.resetScroll = true
|
||||
}
|
||||
})
|
||||
|
@ -67,7 +68,7 @@ export class ScrollService {
|
|||
private consumeScroll () {
|
||||
// Handle anchors/restore position
|
||||
this.peertubeRouter.getScrollEvents().subscribe(e => {
|
||||
logger('Will schedule scroll after router event %o.', { e, resetScroll: this.resetScroll })
|
||||
debugLogger('Will schedule scroll after router event %o.', { e, resetScroll: this.resetScroll })
|
||||
|
||||
// scrollToAnchor first to preserve anchor position when using history navigation
|
||||
if (e.anchor) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { first, map, share, shareReplay, switchMap, tap } from 'rxjs/operators'
|
|||
import { HttpClient } from '@angular/common/http'
|
||||
import { Inject, Injectable, LOCALE_ID } from '@angular/core'
|
||||
import { getDevLocale, isOnDevLocale, sortBy } from '@app/helpers'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { getCompleteLocale, isDefaultLocale, peertubeTranslate } from '@shared/core-utils/i18n'
|
||||
import { HTMLServerConfig, ServerConfig, ServerStats, VideoConstant } from '@shared/models'
|
||||
import { environment } from '../../../environments/environment'
|
||||
|
@ -43,7 +44,7 @@ export class ServerService {
|
|||
} catch (err) {
|
||||
// Expected in dev mode since we can't inject the config in the HTML
|
||||
if (environment.production !== false) {
|
||||
console.error('Cannot load config locally. Fallback to API.')
|
||||
logger.error('Cannot load config locally. Fallback to API.')
|
||||
}
|
||||
|
||||
return this.getConfig()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Injectable } from '@angular/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { capitalizeFirstLetter } from '@root-helpers/string'
|
||||
import { UserLocalStorageKeys } from '@root-helpers/users'
|
||||
import { HTMLServerConfig, ServerConfigTheme } from '@shared/models'
|
||||
|
@ -57,7 +58,7 @@ export class ThemeService {
|
|||
private injectThemes (themes: ServerConfigTheme[], fromLocalStorage = false) {
|
||||
this.themes = themes
|
||||
|
||||
console.log('Injecting %d themes.', this.themes.length)
|
||||
logger.info(`Injecting ${this.themes.length} themes.`)
|
||||
|
||||
const head = this.getHeadElement()
|
||||
|
||||
|
@ -117,13 +118,13 @@ export class ThemeService {
|
|||
|
||||
const currentTheme = this.getCurrentTheme()
|
||||
|
||||
console.log('Enabling %s theme.', currentTheme)
|
||||
logger.info(`Enabling ${currentTheme} theme.`)
|
||||
|
||||
this.loadTheme(currentTheme)
|
||||
|
||||
const theme = this.getTheme(currentTheme)
|
||||
if (theme) {
|
||||
console.log('Adding scripts of theme %s.', currentTheme)
|
||||
logger.info(`Adding scripts of theme ${currentTheme}`)
|
||||
|
||||
this.pluginService.addPlugin(theme, true)
|
||||
|
||||
|
@ -165,7 +166,7 @@ export class ThemeService {
|
|||
this.injectThemes([ lastActiveTheme ], true)
|
||||
this.updateCurrentTheme()
|
||||
} catch (err) {
|
||||
console.error('Cannot parse last active theme.', err)
|
||||
logger.error('Cannot parse last active theme.', err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +174,7 @@ export class ThemeService {
|
|||
private removeThemePlugins (themeName: string) {
|
||||
const oldTheme = this.getTheme(themeName)
|
||||
if (oldTheme) {
|
||||
console.log('Removing scripts of old theme %s.', themeName)
|
||||
logger.info(`Removing scripts of old theme ${themeName}.`)
|
||||
this.pluginService.removePlugin(oldTheme)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
import { filter, throttleTime } from 'rxjs'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { AuthService, AuthStatus } from '@app/core/auth'
|
||||
import { UserLocalStorageKeys, UserTokens } from '@root-helpers/users'
|
||||
import { getBoolOrDefault } from '@root-helpers/local-storage-utils'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { UserLocalStorageKeys, UserTokens } from '@root-helpers/users'
|
||||
import { UserRole, UserUpdateMe } from '@shared/models'
|
||||
import { NSFWPolicyType } from '@shared/models/videos'
|
||||
import { ServerService } from '../server'
|
||||
|
@ -95,7 +96,7 @@ export class UserLocalStorageService {
|
|||
: null
|
||||
} catch (err) {
|
||||
videoLanguages = null
|
||||
console.error('Cannot parse desired video languages from localStorage.', err)
|
||||
logger.error('Cannot parse desired video languages from localStorage.', err)
|
||||
}
|
||||
|
||||
const htmlConfig = this.server.getHTMLConfig()
|
||||
|
@ -142,7 +143,7 @@ export class UserLocalStorageService {
|
|||
|
||||
this.localStorageService.setItem(key, localStorageValue)
|
||||
} catch (err) {
|
||||
console.error(`Cannot set ${key}->${value} in localStorage. Likely due to a value impossible to stringify.`, err)
|
||||
logger.error(`Cannot set ${key}->${value} in localStorage. Likely due to a value impossible to stringify.`, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { ListKeyManager } from '@angular/cdk/a11y'
|
|||
import { AfterViewChecked, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core'
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router'
|
||||
import { AuthService, ServerService } from '@app/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { HTMLServerConfig, SearchTargetType } from '@shared/models'
|
||||
import { SuggestionComponent, SuggestionPayload, SuggestionPayloadType } from './suggestion.component'
|
||||
|
||||
|
@ -91,7 +92,7 @@ export class SearchTypeaheadComponent implements OnInit, AfterViewChecked, OnDes
|
|||
|
||||
const activeIndex = this.suggestionItems.toArray().findIndex(i => i.result.default === true)
|
||||
if (activeIndex === -1) {
|
||||
console.error('Cannot find active index.', { suggestionItems: this.suggestionItems })
|
||||
logger.error('Cannot find active index.', { suggestionItems: this.suggestionItems })
|
||||
}
|
||||
|
||||
this.updateItemsState(activeIndex)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { environment } from '../../environments/environment'
|
||||
import IntlMessageFormat from 'intl-messageformat'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { environment } from '../../environments/environment'
|
||||
|
||||
function isOnDevLocale () {
|
||||
return environment.production === false && window.location.search === '?lang=fr'
|
||||
|
@ -19,14 +20,14 @@ function prepareIcu (icu: string) {
|
|||
try {
|
||||
return msg.format(context) as string
|
||||
} catch (err) {
|
||||
if (!alreadyWarned) console.warn('Cannot format ICU %s.', icu, err)
|
||||
if (!alreadyWarned) logger.warn(`Cannot format ICU ${icu}.`, err)
|
||||
|
||||
alreadyWarned = true
|
||||
return fallback
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Cannot build intl message %s.', icu, err)
|
||||
logger.warn(`Cannot build intl message ${icu}.`, err)
|
||||
|
||||
return (_context: unknown, fallback: string) => fallback
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
|
|||
import { PluginsManager } from '@root-helpers/plugins-manager'
|
||||
import { HTMLServerConfig, ServerConfig, UserRight, VideoConstant } from '@shared/models'
|
||||
|
||||
const logger = debug('peertube:menu:MenuComponent')
|
||||
const debugLogger = debug('peertube:menu:MenuComponent')
|
||||
|
||||
@Component({
|
||||
selector: 'my-menu',
|
||||
|
@ -295,8 +295,8 @@ export class MenuComponent implements OnInit {
|
|||
.pipe(
|
||||
switchMap(() => this.user.computeCanSeeVideosLink(this.userService.getMyVideoQuotaUsed()))
|
||||
).subscribe(res => {
|
||||
if (res === true) logger('User can see videos link.')
|
||||
else logger('User cannot see videos link.')
|
||||
if (res === true) debugLogger('User can see videos link.')
|
||||
else debugLogger('User cannot see videos link.')
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Component, ElementRef, ViewChild } from '@angular/core'
|
||||
import { Notifier, ServerService, User, UserService } from '@app/core'
|
||||
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||
|
||||
@Component({
|
||||
|
@ -71,7 +72,7 @@ export class AccountSetupWarningModalComponent {
|
|||
|
||||
this.userService.updateMyProfile({ noAccountSetupWarningModal: true })
|
||||
.subscribe({
|
||||
next: () => console.log('We will not open the account setup modal again.'),
|
||||
next: () => logger.info('We will not open the account setup modal again.'),
|
||||
|
||||
error: err => this.notifier.error(err.message)
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Component, ElementRef, ViewChild } from '@angular/core'
|
||||
import { Notifier, User, UserService } from '@app/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||
|
||||
@Component({
|
||||
|
@ -42,7 +43,7 @@ export class AdminWelcomeModalComponent {
|
|||
|
||||
this.userService.updateMyProfile({ noWelcomeModal: true })
|
||||
.subscribe({
|
||||
next: () => console.log('We will not open the welcome modal again.'),
|
||||
next: () => logger.info('We will not open the welcome modal again.'),
|
||||
|
||||
error: err => this.notifier.error(err.message)
|
||||
})
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Component, ElementRef, ViewChild, Input } from '@angular/core'
|
||||
import { Component, ElementRef, Input, ViewChild } from '@angular/core'
|
||||
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
@Component({
|
||||
selector: 'my-custom-modal',
|
||||
|
@ -29,7 +30,7 @@ export class CustomModalComponent {
|
|||
confirm?: { value: string, action?: () => void }
|
||||
}) {
|
||||
if (this.modalRef instanceof NgbModalRef && this.modalService.hasOpenModals()) {
|
||||
console.error('Cannot open another custom modal, one is already opened.')
|
||||
logger.error('Cannot open another custom modal, one is already opened.')
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Location } from '@angular/common'
|
|||
import { Component, ElementRef, ViewChild } from '@angular/core'
|
||||
import { Notifier, User, UserService } from '@app/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||
import { About, ServerConfig } from '@shared/models/server'
|
||||
|
||||
|
@ -64,7 +65,7 @@ export class InstanceConfigWarningModalComponent {
|
|||
|
||||
this.userService.updateMyProfile({ noInstanceConfigWarningModal: true })
|
||||
.subscribe({
|
||||
next: () => console.log('We will not open the instance config warning modal again.'),
|
||||
next: () => logger.info('We will not open the instance config warning modal again.'),
|
||||
|
||||
error: err => this.notifier.error(err.message)
|
||||
})
|
||||
|
|
|
@ -8,13 +8,14 @@ import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable }
|
|||
import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main'
|
||||
import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation'
|
||||
import { VideoCommentService } from '@app/shared/shared-video-comment'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { AbuseState, AdminAbuse } from '@shared/models'
|
||||
import { AdvancedInputFilter } from '../shared-forms'
|
||||
import { AbuseMessageModalComponent } from './abuse-message-modal.component'
|
||||
import { ModerationCommentModalComponent } from './moderation-comment-modal.component'
|
||||
import { ProcessedAbuse } from './processed-abuse.model'
|
||||
|
||||
const logger = debug('peertube:moderation:AbuseListTableComponent')
|
||||
const debugLogger = debug('peertube:moderation:AbuseListTableComponent')
|
||||
|
||||
@Component({
|
||||
selector: 'my-abuse-list-table',
|
||||
|
@ -158,7 +159,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
|
|||
const abuse = this.abuses.find(a => a.id === event.abuseId)
|
||||
|
||||
if (!abuse) {
|
||||
console.error('Cannot find abuse %d.', event.abuseId)
|
||||
logger.error(`Cannot find abuse ${event.abuseId}`)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -177,7 +178,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
|
|||
}
|
||||
|
||||
protected reloadData () {
|
||||
logger('Loading data.')
|
||||
debugLogger('Loading data.')
|
||||
|
||||
const options = {
|
||||
pagination: this.pagination,
|
||||
|
|
|
@ -3,6 +3,7 @@ import { AuthService, HtmlRendererService, Notifier } from '@app/core'
|
|||
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { AbuseMessage, UserAbuse } from '@shared/models'
|
||||
import { ABUSE_MESSAGE_VALIDATOR } from '../form-validators/abuse-validators'
|
||||
import { AbuseService } from '../shared-moderation'
|
||||
|
@ -72,7 +73,7 @@ export class AbuseMessageModalComponent extends FormReactive implements OnInit {
|
|||
|
||||
error: err => {
|
||||
this.sendingMessage = false
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
this.notifier.error('Sorry but you cannot send this message. Please retry later')
|
||||
}
|
||||
})
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
VideosListMarkupComponent
|
||||
} from './peertube-custom-tags'
|
||||
import { CustomMarkupComponent } from './peertube-custom-tags/shared'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
type AngularBuilderFunction = (el: HTMLElement) => ComponentRef<CustomMarkupComponent>
|
||||
type HTMLBuilderFunction = (el: HTMLElement) => HTMLElement
|
||||
|
@ -70,7 +71,7 @@ export class CustomMarkupService {
|
|||
// Insert as first child
|
||||
e.insertBefore(element, e.firstChild)
|
||||
} catch (err) {
|
||||
console.error('Cannot inject component %s.', selector, err)
|
||||
logger.error(`Cannot inject component ${selector}`, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ export class CustomMarkupService {
|
|||
|
||||
this.dynamicElementService.injectElement(e, component)
|
||||
} catch (err) {
|
||||
console.error('Cannot inject component %s.', selector, err)
|
||||
logger.error(`Cannot inject component ${selector}`, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ export type AdvancedInputFilterChild = {
|
|||
value: string
|
||||
}
|
||||
|
||||
const logger = debug('peertube:AdvancedInputFilterComponent')
|
||||
const debugLogger = debug('peertube:AdvancedInputFilterComponent')
|
||||
|
||||
@Component({
|
||||
selector: 'my-advanced-input-filter',
|
||||
|
@ -98,7 +98,7 @@ export class AdvancedInputFilterComponent implements OnInit, AfterViewInit {
|
|||
.subscribe(params => {
|
||||
const search = params.search || ''
|
||||
|
||||
logger('On route search change "%s".', search)
|
||||
debugLogger('On route search change "%s".', search)
|
||||
|
||||
if (this.searchValue === search) return
|
||||
|
||||
|
@ -132,7 +132,7 @@ export class AdvancedInputFilterComponent implements OnInit, AfterViewInit {
|
|||
return
|
||||
}
|
||||
|
||||
logger('On search "%s".', this.searchValue)
|
||||
debugLogger('On search "%s".', this.searchValue)
|
||||
|
||||
this.search.emit(this.searchValue)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
ViewContainerRef
|
||||
} from '@angular/core'
|
||||
|
||||
const logger = debug('peertube:main:DeferLoadingDirective')
|
||||
const debugLogger = debug('peertube:main:DeferLoadingDirective')
|
||||
|
||||
@Directive({
|
||||
selector: '[myDeferLoading]'
|
||||
|
@ -52,7 +52,7 @@ export class DeferLoadingDirective implements AfterViewInit, OnDestroy {
|
|||
load () {
|
||||
if (this.isLoaded()) return
|
||||
|
||||
logger('Loading component')
|
||||
debugLogger('Loading component')
|
||||
|
||||
this.viewContainer.clear()
|
||||
this.view = this.viewContainer.createEmbeddedView(this.template, {}, 0)
|
||||
|
|
|
@ -17,7 +17,7 @@ import { ScreenService } from '@app/core'
|
|||
import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import * as debug from 'debug'
|
||||
|
||||
const logger = debug('peertube:main:ListOverflowItem')
|
||||
const debugLogger = debug('peertube:main:ListOverflowItem')
|
||||
|
||||
export interface ListOverflowItem {
|
||||
label: string
|
||||
|
@ -66,7 +66,7 @@ export class ListOverflowComponent<T extends ListOverflowItem> implements AfterV
|
|||
let showItemsUntilIndexExcluded: number
|
||||
let accWidth = 0
|
||||
|
||||
logger('Parent width is %d', parentWidth)
|
||||
debugLogger('Parent width is %d', parentWidth)
|
||||
|
||||
for (const [ index, el ] of this.itemsRendered.toArray().entries()) {
|
||||
accWidth += el.nativeElement.getBoundingClientRect().width
|
||||
|
@ -79,7 +79,7 @@ export class ListOverflowComponent<T extends ListOverflowItem> implements AfterV
|
|||
e.style.visibility = shouldBeVisible ? 'inherit' : 'hidden'
|
||||
}
|
||||
|
||||
logger('Accumulated children width is %d so exclude index is %d', accWidth, showItemsUntilIndexExcluded)
|
||||
debugLogger('Accumulated children width is %d so exclude index is %d', accWidth, showItemsUntilIndexExcluded)
|
||||
|
||||
this.showItemsUntilIndexExcluded = showItemsUntilIndexExcluded
|
||||
this.cdr.markForCheck()
|
||||
|
|
|
@ -2,6 +2,7 @@ import { AuthUser } from '@app/core'
|
|||
import { Account } from '@app/shared/shared-main/account/account.model'
|
||||
import { Actor } from '@app/shared/shared-main/account/actor.model'
|
||||
import { VideoChannel } from '@app/shared/shared-main/video-channel/video-channel.model'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import {
|
||||
AbuseState,
|
||||
ActorInfo,
|
||||
|
@ -234,7 +235,7 @@ export class UserNotification implements UserNotificationServer {
|
|||
}
|
||||
} catch (err) {
|
||||
this.type = null
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { VideoPlaylist } from '../shared-video-playlist'
|
|||
import { SearchService } from './search.service'
|
||||
import { AdvancedSearch } from './advanced-search.model'
|
||||
|
||||
const logger = debug('peertube:search:FindInBulkService')
|
||||
const debugLogger = debug('peertube:search:FindInBulkService')
|
||||
|
||||
type BulkObservables <P extends number | string, R> = {
|
||||
notifier: Subject<P>
|
||||
|
@ -36,7 +36,7 @@ export class FindInBulkService {
|
|||
}
|
||||
|
||||
getVideo (uuid: string): Observable<Video> {
|
||||
logger('Schedule video fetch for uuid %s.', uuid)
|
||||
debugLogger('Schedule video fetch for uuid %s.', uuid)
|
||||
|
||||
return this.getData({
|
||||
observableObject: this.getVideoInBulk,
|
||||
|
@ -46,7 +46,7 @@ export class FindInBulkService {
|
|||
}
|
||||
|
||||
getChannel (handle: string): Observable<VideoChannel> {
|
||||
logger('Schedule channel fetch for handle %s.', handle)
|
||||
debugLogger('Schedule channel fetch for handle %s.', handle)
|
||||
|
||||
return this.getData({
|
||||
observableObject: this.getChannelInBulk,
|
||||
|
@ -56,7 +56,7 @@ export class FindInBulkService {
|
|||
}
|
||||
|
||||
getPlaylist (uuid: string): Observable<VideoPlaylist> {
|
||||
logger('Schedule playlist fetch for uuid %s.', uuid)
|
||||
debugLogger('Schedule playlist fetch for uuid %s.', uuid)
|
||||
|
||||
return this.getData({
|
||||
observableObject: this.getPlaylistInBulk,
|
||||
|
@ -94,7 +94,7 @@ export class FindInBulkService {
|
|||
}
|
||||
|
||||
private getVideosInBulk (uuids: string[]) {
|
||||
logger('Fetching videos %s.', uuids.join(', '))
|
||||
debugLogger('Fetching videos %s.', uuids.join(', '))
|
||||
|
||||
return this.searchService.searchVideos({
|
||||
uuids,
|
||||
|
@ -104,7 +104,7 @@ export class FindInBulkService {
|
|||
}
|
||||
|
||||
private getChannelsInBulk (handles: string[]) {
|
||||
logger('Fetching channels %s.', handles.join(', '))
|
||||
debugLogger('Fetching channels %s.', handles.join(', '))
|
||||
|
||||
return this.searchService.searchVideoChannels({
|
||||
handles,
|
||||
|
@ -114,7 +114,7 @@ export class FindInBulkService {
|
|||
}
|
||||
|
||||
private getPlaylistsInBulk (uuids: string[]) {
|
||||
logger('Fetching playlists %s.', uuids.join(', '))
|
||||
debugLogger('Fetching playlists %s.', uuids.join(', '))
|
||||
|
||||
return this.searchService.searchVideoPlaylists({
|
||||
uuids,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Component, Input, OnInit } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { USER_HANDLE_VALIDATOR } from '../form-validators/user-validators'
|
||||
|
||||
@Component({
|
||||
|
@ -59,7 +60,7 @@ export class RemoteSubscribeComponent extends FormReactive implements OnInit {
|
|||
})
|
||||
.then(window.open)
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
|
||||
this.notifier.error($localize`Cannot fetch information of this remote account`)
|
||||
})
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Video, VideoChannel, VideoChannelService, VideoService } from '@app/sha
|
|||
import { ActorFollow, ResultList, VideoChannel as VideoChannelServer, VideoSortField } from '@shared/models'
|
||||
import { environment } from '../../../environments/environment'
|
||||
|
||||
const logger = debug('peertube:subscriptions:UserSubscriptionService')
|
||||
const debugLogger = debug('peertube:subscriptions:UserSubscriptionService')
|
||||
|
||||
type SubscriptionExistResult = { [ uri: string ]: boolean }
|
||||
type SubscriptionExistResultObservable = { [ uri: string ]: Observable<boolean> }
|
||||
|
@ -176,17 +176,17 @@ export class UserSubscriptionService {
|
|||
}
|
||||
|
||||
doesSubscriptionExist (nameWithHost: string) {
|
||||
logger('Running subscription check for %d.', nameWithHost)
|
||||
debugLogger('Running subscription check for %d.', nameWithHost)
|
||||
|
||||
if (nameWithHost in this.myAccountSubscriptionCache) {
|
||||
logger('Found cache for %d.', nameWithHost)
|
||||
debugLogger('Found cache for %d.', nameWithHost)
|
||||
|
||||
return of(this.myAccountSubscriptionCache[nameWithHost])
|
||||
}
|
||||
|
||||
this.existsSubject.next(nameWithHost)
|
||||
|
||||
logger('Fetching from network for %d.', nameWithHost)
|
||||
debugLogger('Fetching from network for %d.', nameWithHost)
|
||||
return this.existsObservable.pipe(
|
||||
filter(existsResult => existsResult[nameWithHost] !== undefined),
|
||||
map(existsResult => existsResult[nameWithHost]),
|
||||
|
|
|
@ -4,6 +4,7 @@ import { tap } from 'rxjs/operators'
|
|||
import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core'
|
||||
import { AuthService, HooksService, Notifier } from '@app/core'
|
||||
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { VideoCaption, VideoFile, VideoPrivacy } from '@shared/models'
|
||||
import { BytesPipe, NumberFormatterPipe, VideoDetails, VideoService } from '../shared-main'
|
||||
|
||||
|
@ -142,7 +143,7 @@ export class VideoDownloadComponent {
|
|||
.find(f => f.resolution.id === this.resolutionId)
|
||||
|
||||
if (!file) {
|
||||
console.error('Could not find file with resolution %d.', this.resolutionId)
|
||||
logger.error(`Could not find file with resolution ${this.resolutionId}`)
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
@ -175,7 +176,7 @@ export class VideoDownloadComponent {
|
|||
.find(c => c.language.id === this.subtitleLanguageId)
|
||||
|
||||
if (!caption) {
|
||||
console.error('Cannot find caption %s.', this.subtitleLanguageId)
|
||||
logger.error(`Cannot find caption ${this.subtitleLanguageId}`)
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { UserRight } from '@shared/models'
|
|||
import { PeertubeModalService } from '../shared-main'
|
||||
import { VideoFilters } from './video-filters.model'
|
||||
|
||||
const logger = debug('peertube:videos:VideoFiltersHeaderComponent')
|
||||
const debugLogger = debug('peertube:videos:VideoFiltersHeaderComponent')
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-filters-header',
|
||||
|
@ -54,7 +54,7 @@ export class VideoFiltersHeaderComponent implements OnInit, OnDestroy {
|
|||
})
|
||||
|
||||
this.form.valueChanges.subscribe(values => {
|
||||
logger('Loading values from form: %O', values)
|
||||
debugLogger('Loading values from form: %O', values)
|
||||
|
||||
this.filters.load(values)
|
||||
this.filtersChanged.emit()
|
||||
|
@ -105,6 +105,6 @@ export class VideoFiltersHeaderComponent implements OnInit, OnDestroy {
|
|||
const defaultValues = this.filters.toFormObject()
|
||||
this.form.patchValue(defaultValues, { emitEvent })
|
||||
|
||||
logger('Patched form: %O', defaultValues)
|
||||
debugLogger('Patched form: %O', defaultValues)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,13 +14,14 @@ import {
|
|||
UserService
|
||||
} from '@app/core'
|
||||
import { GlobalIconName } from '@app/shared/shared-icons'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { isLastMonth, isLastWeek, isThisMonth, isToday, isYesterday } from '@shared/core-utils'
|
||||
import { ResultList, UserRight, VideoSortField } from '@shared/models'
|
||||
import { Syndication, Video } from '../shared-main'
|
||||
import { VideoFilters, VideoFilterScope } from './video-filters.model'
|
||||
import { MiniatureDisplayOptions } from './video-miniature.component'
|
||||
|
||||
const logger = debug('peertube:videos:VideosListComponent')
|
||||
const debugLogger = debug('peertube:videos:VideosListComponent')
|
||||
|
||||
export type HeaderAction = {
|
||||
iconName: GlobalIconName
|
||||
|
@ -245,7 +246,7 @@ export class VideosListComponent implements OnInit, OnChanges, OnDestroy {
|
|||
error: err => {
|
||||
const message = $localize`Cannot load more videos. Try again later.`
|
||||
|
||||
console.error(message, { err })
|
||||
logger.error(message, err)
|
||||
this.notifier.error(message)
|
||||
}
|
||||
})
|
||||
|
@ -323,7 +324,7 @@ export class VideosListComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
onFiltersChanged (customizedByUser: boolean) {
|
||||
logger('Running on filters changed')
|
||||
debugLogger('Running on filters changed')
|
||||
|
||||
this.updateUrl(customizedByUser)
|
||||
|
||||
|
@ -364,7 +365,7 @@ export class VideosListComponent implements OnInit, OnChanges, OnDestroy {
|
|||
if (!items || items.length === 0) this.syndicationItems = undefined
|
||||
else this.syndicationItems = items
|
||||
})
|
||||
.catch(err => console.error('Cannot get syndication items.', err))
|
||||
.catch(err => logger.error('Cannot get syndication items.', err))
|
||||
}
|
||||
|
||||
private updateUrl (customizedByUser: boolean) {
|
||||
|
@ -375,7 +376,7 @@ export class VideosListComponent implements OnInit, OnChanges, OnDestroy {
|
|||
? { ...baseQuery, c: customizedByUser }
|
||||
: baseQuery
|
||||
|
||||
logger('Will inject %O in URL query', queryParams)
|
||||
debugLogger('Will inject %O in URL query', queryParams)
|
||||
|
||||
const baseRoute = this.baseRouteBuilderFunction
|
||||
? this.baseRouteBuilderFunction(this.filters)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Observable, Subject } from 'rxjs'
|
||||
import { AfterContentInit, Component, ContentChildren, EventEmitter, Input, Output, QueryList, TemplateRef } from '@angular/core'
|
||||
import { ComponentPagination, Notifier, User } from '@app/core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { ResultList, VideoSortField } from '@shared/models'
|
||||
import { PeerTubeTemplateDirective, Video } from '../shared-main'
|
||||
import { MiniatureDisplayOptions } from './video-miniature.component'
|
||||
|
@ -128,7 +129,7 @@ export class VideosSelectionComponent implements AfterContentInit {
|
|||
error: err => {
|
||||
const message = $localize`Cannot load more videos. Try again later.`
|
||||
|
||||
console.error(message, { err })
|
||||
logger.error(message, err)
|
||||
this.notifier.error(message)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
import { VIDEO_PLAYLIST_DISPLAY_NAME_VALIDATOR } from '../form-validators/video-playlist-validators'
|
||||
import { CachedPlaylist, VideoPlaylistService } from './video-playlist.service'
|
||||
|
||||
const logger = debug('peertube:playlists:VideoAddToPlaylistComponent')
|
||||
const debugLogger = debug('peertube:playlists:VideoAddToPlaylistComponent')
|
||||
|
||||
type PlaylistElement = {
|
||||
enabled: boolean
|
||||
|
@ -110,7 +110,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
}
|
||||
|
||||
reload () {
|
||||
logger('Reloading component')
|
||||
debugLogger('Reloading component')
|
||||
|
||||
this.videoPlaylists = []
|
||||
this.videoPlaylistSearch = undefined
|
||||
|
@ -121,7 +121,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
}
|
||||
|
||||
load () {
|
||||
logger('Loading component')
|
||||
debugLogger('Loading component')
|
||||
|
||||
this.listenToVideoPlaylistChange()
|
||||
|
||||
|
@ -331,7 +331,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
}
|
||||
|
||||
private rebuildPlaylists (existResult: VideoExistInPlaylist[]) {
|
||||
logger('Got existing results for %d.', this.video.id, existResult)
|
||||
debugLogger('Got existing results for %d.', this.video.id, existResult)
|
||||
|
||||
const oldPlaylists = this.videoPlaylists
|
||||
|
||||
|
@ -359,7 +359,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
this.videoPlaylists.push(playlistSummary)
|
||||
}
|
||||
|
||||
logger('Rebuilt playlist state for video %d.', this.video.id, this.videoPlaylists)
|
||||
debugLogger('Rebuilt playlist state for video %d.', this.video.id, this.videoPlaylists)
|
||||
|
||||
this.cd.markForCheck()
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import { environment } from '../../../environments/environment'
|
|||
import { VideoPlaylistElement } from './video-playlist-element.model'
|
||||
import { VideoPlaylist } from './video-playlist.model'
|
||||
|
||||
const logger = debug('peertube:playlists:VideoPlaylistService')
|
||||
const debugLogger = debug('peertube:playlists:VideoPlaylistService')
|
||||
|
||||
export type CachedPlaylist = VideoPlaylist | { id: number, displayName: string }
|
||||
|
||||
|
@ -287,15 +287,15 @@ export class VideoPlaylistService {
|
|||
}
|
||||
|
||||
runPlaylistCheck (videoId: number) {
|
||||
logger('Running playlist check.')
|
||||
debugLogger('Running playlist check.')
|
||||
|
||||
if (this.videoExistsCache[videoId]) {
|
||||
logger('Found cache for %d.', videoId)
|
||||
debugLogger('Found cache for %d.', videoId)
|
||||
|
||||
return this.videoExistsInPlaylistCacheSubject.next({ [videoId]: this.videoExistsCache[videoId] })
|
||||
}
|
||||
|
||||
logger('Fetching from network for %d.', videoId)
|
||||
debugLogger('Fetching from network for %d.', videoId)
|
||||
return this.videoExistsInPlaylistNotifier.next(videoId)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
function getStoredVolume () {
|
||||
const value = getLocalStorage('volume')
|
||||
if (value !== null && value !== undefined) {
|
||||
|
@ -81,7 +83,7 @@ function getStoredVideoWatchHistory (videoUUID?: string) {
|
|||
|
||||
data = JSON.parse(value)
|
||||
} catch (error) {
|
||||
console.error('Cannot parse video watch history from local storage: ', error)
|
||||
logger.error('Cannot parse video watch history from local storage/', error)
|
||||
}
|
||||
|
||||
data = data || {}
|
||||
|
|
|
@ -23,6 +23,7 @@ import './shared/mobile/peertube-mobile-plugin'
|
|||
import './shared/mobile/peertube-mobile-buttons'
|
||||
import './shared/hotkeys/peertube-hotkeys-plugin'
|
||||
import videojs from 'video.js'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { PluginsManager } from '@root-helpers/plugins-manager'
|
||||
import { isMobile } from '@root-helpers/web-browser'
|
||||
import { saveAverageBandwidth } from './peertube-player-local-storage'
|
||||
|
@ -145,7 +146,7 @@ export class PeertubePlayerManager {
|
|||
return
|
||||
}
|
||||
|
||||
console.log('Fast forwarding HLS to recover from an error.')
|
||||
logger.info('Fast forwarding HLS to recover from an error.')
|
||||
|
||||
this.videojsDecodeErrors++
|
||||
|
||||
|
@ -170,7 +171,7 @@ export class PeertubePlayerManager {
|
|||
return
|
||||
}
|
||||
|
||||
console.log('Fallback to webtorrent.')
|
||||
logger.info('Fallback to webtorrent.')
|
||||
|
||||
this.rebuildAndUpdateVideoElement(currentPlayer, options.common)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { HybridLoaderSettings } from '@peertube/p2p-media-loader-core'
|
||||
import { HlsJsEngineSettings } from '@peertube/p2p-media-loader-hlsjs'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { LiveVideoLatencyMode } from '@shared/models'
|
||||
import { getAverageBandwidthInStore } from '../../peertube-player-local-storage'
|
||||
import { P2PMediaLoader, P2PMediaLoaderPluginOptions } from '../../types'
|
||||
|
@ -61,7 +62,7 @@ export class HLSOptionsBuilder {
|
|||
private getP2PMediaLoaderOptions (redundancyUrlManager: RedundancyUrlManager): HlsJsEngineSettings {
|
||||
let consumeOnly = false
|
||||
if ((navigator as any)?.connection?.type === 'cellular') {
|
||||
console.log('We are on a cellular connection: disabling seeding.')
|
||||
logger.info('We are on a cellular connection: disabling seeding.')
|
||||
consumeOnly = true
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { PeerTubeMobileButtons } from './peertube-mobile-buttons'
|
||||
import videojs from 'video.js'
|
||||
import debug from 'debug'
|
||||
import videojs from 'video.js'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { PeerTubeMobileButtons } from './peertube-mobile-buttons'
|
||||
|
||||
const logger = debug('peertube:player:mobile')
|
||||
const debugLogger = debug('peertube:player:mobile')
|
||||
|
||||
const Plugin = videojs.getPlugin('plugin')
|
||||
|
||||
|
@ -45,7 +46,7 @@ class PeerTubeMobilePlugin extends Plugin {
|
|||
if (!this.player.isFullscreen() || this.isPortraitVideo()) return
|
||||
|
||||
screen.orientation.lock('landscape')
|
||||
.catch(err => console.error('Cannot lock screen to landscape.', err))
|
||||
.catch(err => logger.error('Cannot lock screen to landscape.', err))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -61,7 +62,7 @@ class PeerTubeMobilePlugin extends Plugin {
|
|||
}
|
||||
|
||||
if (this.lastTapEvent && event.timeStamp - this.lastTapEvent.timeStamp < PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS) {
|
||||
logger('Detected double tap')
|
||||
debugLogger('Detected double tap')
|
||||
|
||||
this.lastTapEvent = undefined
|
||||
this.onDoubleTap(event)
|
||||
|
@ -71,7 +72,7 @@ class PeerTubeMobilePlugin extends Plugin {
|
|||
this.newActiveState = !this.player.userActive()
|
||||
|
||||
this.tapTimeout = setTimeout(() => {
|
||||
logger('No double tap detected, set user active state to %s.', this.newActiveState)
|
||||
debugLogger('No double tap detected, set user active state to %s.', this.newActiveState)
|
||||
|
||||
this.player.userActive(this.newActiveState)
|
||||
}, PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS)
|
||||
|
@ -100,19 +101,19 @@ class PeerTubeMobilePlugin extends Plugin {
|
|||
const rect = this.findPlayerTarget((event.target as HTMLElement)).getBoundingClientRect()
|
||||
const offsetX = event.targetTouches[0].pageX - rect.left
|
||||
|
||||
logger('Calculating double tap zone (player width: %d, offset X: %d)', playerWidth, offsetX)
|
||||
debugLogger('Calculating double tap zone (player width: %d, offset X: %d)', playerWidth, offsetX)
|
||||
|
||||
if (offsetX > 0.66 * playerWidth) {
|
||||
if (this.seekAmount < 0) this.seekAmount = 0
|
||||
|
||||
this.seekAmount += 10
|
||||
|
||||
logger('Will forward %d seconds', this.seekAmount)
|
||||
debugLogger('Will forward %d seconds', this.seekAmount)
|
||||
} else if (offsetX < 0.33 * playerWidth) {
|
||||
if (this.seekAmount > 0) this.seekAmount = 0
|
||||
|
||||
this.seekAmount -= 10
|
||||
logger('Will rewind %d seconds', this.seekAmount)
|
||||
debugLogger('Will rewind %d seconds', this.seekAmount)
|
||||
}
|
||||
|
||||
this.peerTubeMobileButtons.displayFastSeek(this.seekAmount)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import Hlsjs, { ErrorData, HlsConfig, Level, LevelSwitchingData, ManifestParsedData } from 'hls.js'
|
||||
import videojs from 'video.js'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { HlsjsConfigHandlerOptions, PeerTubeResolution, VideoJSTechHLS } from '../../types'
|
||||
|
||||
type ErrorCounts = {
|
||||
|
@ -17,14 +18,14 @@ type HookFn = (player: videojs.Player, hljs: Hlsjs) => void
|
|||
|
||||
const registerSourceHandler = function (vjs: typeof videojs) {
|
||||
if (!Hlsjs.isSupported()) {
|
||||
console.warn('Hls.js is not supported in this browser!')
|
||||
logger.warn('Hls.js is not supported in this browser!')
|
||||
return
|
||||
}
|
||||
|
||||
const html5 = vjs.getTech('Html5')
|
||||
|
||||
if (!html5) {
|
||||
console.error('No Hml5 tech found in videojs')
|
||||
logger.error('No Hml5 tech found in videojs')
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -120,7 +121,7 @@ class Html5Hlsjs {
|
|||
|
||||
if (!mediaError) return
|
||||
|
||||
console.log(mediaError)
|
||||
logger.info(mediaError)
|
||||
switch (mediaError.code) {
|
||||
case mediaError.MEDIA_ERR_ABORTED:
|
||||
errorTxt = 'You aborted the video playback'
|
||||
|
@ -141,7 +142,7 @@ class Html5Hlsjs {
|
|||
errorTxt = mediaError.message
|
||||
}
|
||||
|
||||
console.error('MEDIA_ERROR: ', errorTxt)
|
||||
logger.error(`MEDIA_ERROR: ${errorTxt}`)
|
||||
})
|
||||
|
||||
this.initialize()
|
||||
|
@ -212,20 +213,20 @@ class Html5Hlsjs {
|
|||
|
||||
private _handleMediaError (error: any) {
|
||||
if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] === 1) {
|
||||
console.info('trying to recover media error')
|
||||
logger.info('trying to recover media error')
|
||||
this.hls.recoverMediaError()
|
||||
return
|
||||
}
|
||||
|
||||
if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] === 2) {
|
||||
console.info('2nd try to recover media error (by swapping audio codec')
|
||||
logger.info('2nd try to recover media error (by swapping audio codec')
|
||||
this.hls.swapAudioCodec()
|
||||
this.hls.recoverMediaError()
|
||||
return
|
||||
}
|
||||
|
||||
if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] > 2) {
|
||||
console.info('bubbling media error up to VIDEOJS')
|
||||
logger.info('bubbling media error up to VIDEOJS')
|
||||
this.hls.destroy()
|
||||
this.tech.error = () => error
|
||||
this.tech.trigger('error')
|
||||
|
@ -234,7 +235,7 @@ class Html5Hlsjs {
|
|||
|
||||
private _handleNetworkError (error: any) {
|
||||
if (this.errorCounts[Hlsjs.ErrorTypes.NETWORK_ERROR] <= this.maxNetworkErrorRecovery) {
|
||||
console.info('trying to recover network error')
|
||||
logger.info('trying to recover network error')
|
||||
|
||||
// Wait 1 second and retry
|
||||
setTimeout(() => this.hls.startLoad(), 1000)
|
||||
|
@ -247,7 +248,7 @@ class Html5Hlsjs {
|
|||
return
|
||||
}
|
||||
|
||||
console.info('bubbling network error up to VIDEOJS')
|
||||
logger.info('bubbling network error up to VIDEOJS')
|
||||
this.hls.destroy()
|
||||
this.tech.error = () => error
|
||||
this.tech.trigger('error')
|
||||
|
@ -262,8 +263,8 @@ class Html5Hlsjs {
|
|||
if (this.errorCounts[data.type]) this.errorCounts[data.type] += 1
|
||||
else this.errorCounts[data.type] = 1
|
||||
|
||||
if (data.fatal) console.warn(error.message)
|
||||
else console.error(error.message, data)
|
||||
if (data.fatal) logger.warn(error.message)
|
||||
else logger.error(error.message, { data })
|
||||
|
||||
if (data.type === Hlsjs.ErrorTypes.NETWORK_ERROR) {
|
||||
error.code = 2
|
||||
|
@ -273,7 +274,7 @@ class Html5Hlsjs {
|
|||
this._handleMediaError(error)
|
||||
} else if (data.fatal) {
|
||||
this.hls.destroy()
|
||||
console.info('bubbling error up to VIDEOJS')
|
||||
logger.info('bubbling error up to VIDEOJS')
|
||||
this.tech.error = () => error as any
|
||||
this.tech.trigger('error')
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from '@peertub
|
|||
import { timeToInt } from '@shared/core-utils'
|
||||
import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../../types'
|
||||
import { registerConfigPlugin, registerSourceHandler } from './hls-plugin'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
registerConfigPlugin(videojs)
|
||||
registerSourceHandler(videojs)
|
||||
|
@ -43,11 +44,11 @@ class P2pMediaLoaderPlugin extends Plugin {
|
|||
|
||||
// FIXME: typings https://github.com/Microsoft/TypeScript/issues/14080
|
||||
if (!(videojs as any).Html5Hlsjs) {
|
||||
console.warn('HLS.js does not seem to be supported. Try to fallback to built in HLS.')
|
||||
logger.warn('HLS.js does not seem to be supported. Try to fallback to built in HLS.')
|
||||
|
||||
if (!player.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
const message = 'Cannot fallback to built-in HLS'
|
||||
console.warn(message)
|
||||
logger.warn(message)
|
||||
|
||||
player.ready(() => player.trigger('error', new Error(message)))
|
||||
return
|
||||
|
@ -114,7 +115,7 @@ class P2pMediaLoaderPlugin extends Plugin {
|
|||
this.p2pEngine = this.options.loader.getEngine()
|
||||
|
||||
this.p2pEngine.on(Events.SegmentError, (segment: Segment, err) => {
|
||||
console.error('Segment error.', segment, err)
|
||||
logger.error(`Segment ${segment.id} error.`, err)
|
||||
|
||||
this.options.redundancyUrlManager.removeBySegmentUrl(segment.requestUrl)
|
||||
})
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { basename, dirname } from 'path'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
class RedundancyUrlManager {
|
||||
|
||||
|
@ -7,7 +8,7 @@ class RedundancyUrlManager {
|
|||
}
|
||||
|
||||
removeBySegmentUrl (segmentUrl: string) {
|
||||
console.log('Removing redundancy of segment URL %s.', segmentUrl)
|
||||
logger.info(`Removing redundancy of segment URL ${segmentUrl}.`)
|
||||
|
||||
const baseUrl = dirname(segmentUrl)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { wait } from '@root-helpers/utils'
|
||||
import { Segment } from '@peertube/p2p-media-loader-core'
|
||||
import { basename } from 'path'
|
||||
import { Segment } from '@peertube/p2p-media-loader-core'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { wait } from '@root-helpers/utils'
|
||||
|
||||
type SegmentsJSON = { [filename: string]: string | { [byterange: string]: string } }
|
||||
|
||||
|
@ -23,7 +24,7 @@ function segmentValidatorFactory (segmentsSha256Url: string, isLive: boolean) {
|
|||
}
|
||||
|
||||
if (!segmentValue) {
|
||||
console.log('Refetching sha segments for %s.', filename)
|
||||
logger.info(`Refetching sha segments for ${filename}`)
|
||||
|
||||
await wait(1000)
|
||||
|
||||
|
@ -71,7 +72,7 @@ function fetchSha256Segments (url: string) {
|
|||
return fetch(url)
|
||||
.then(res => res.json() as Promise<SegmentsJSON>)
|
||||
.catch(err => {
|
||||
console.error('Cannot get sha256 segments', err)
|
||||
logger.error('Cannot get sha256 segments', err)
|
||||
return {}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import debug from 'debug'
|
||||
import videojs from 'video.js'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { isMobile } from '@root-helpers/web-browser'
|
||||
import { timeToInt } from '@shared/core-utils'
|
||||
import { VideoView, VideoViewEvent } from '@shared/models/videos'
|
||||
|
@ -15,7 +16,7 @@ import {
|
|||
import { PeerTubePluginOptions, VideoJSCaption } from '../../types'
|
||||
import { SettingsButton } from '../settings/settings-menu-button'
|
||||
|
||||
const logger = debug('peertube:player:peertube')
|
||||
const debugLogger = debug('peertube:player:peertube')
|
||||
|
||||
const Plugin = videojs.getPlugin('plugin')
|
||||
|
||||
|
@ -176,7 +177,7 @@ class PeerTubePlugin extends Plugin {
|
|||
lastCurrentTime = currentTime
|
||||
|
||||
this.notifyUserIsWatching(currentTime, lastViewEvent)
|
||||
.catch(err => console.error('Cannot notify user is watching.', err))
|
||||
.catch(err => logger.error('Cannot notify user is watching.', err))
|
||||
|
||||
lastViewEvent = undefined
|
||||
|
||||
|
@ -249,7 +250,7 @@ class PeerTubePlugin extends Plugin {
|
|||
(this.player as any).cache_.inactivityTimeout = timeout
|
||||
this.player.options_.inactivityTimeout = timeout
|
||||
|
||||
logger('Set player inactivity to ' + timeout)
|
||||
debugLogger('Set player inactivity to ' + timeout)
|
||||
}
|
||||
|
||||
private initCaptions () {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import videojs from 'video.js'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { secondsToTime } from '@shared/core-utils'
|
||||
import { PlayerNetworkInfo as EventPlayerNetworkInfo } from '../../types'
|
||||
import { bytes } from '../common'
|
||||
|
@ -125,7 +126,7 @@ class StatsCard extends Component {
|
|||
|
||||
this.populateInfoValues(options)
|
||||
} catch (err) {
|
||||
console.error('Cannot update stats.', err)
|
||||
logger.error('Cannot update stats.', err)
|
||||
clearInterval(this.updateInterval)
|
||||
}
|
||||
}, this.intervalMs)
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
// We use temporary IndexDB (all data are removed on destroy) to avoid RAM issues
|
||||
// Thanks @santiagogil and @Feross
|
||||
|
||||
import { EventEmitter } from 'events'
|
||||
import Dexie from 'dexie'
|
||||
import { EventEmitter } from 'events'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
|
||||
class ChunkDatabase extends Dexie {
|
||||
chunks: Dexie.Table<{ id: number, buf: Buffer }, number>
|
||||
|
@ -104,7 +105,7 @@ export class PeertubeChunkStore extends EventEmitter {
|
|||
return this.db.chunks.bulkPut(processing.map(p => ({ id: p.id, buf: p.buf })))
|
||||
})
|
||||
} catch (err) {
|
||||
console.log('Cannot bulk insert chunks. Store them in memory.', { err })
|
||||
logger.info('Cannot bulk insert chunks. Store them in memory.', err)
|
||||
|
||||
processing.forEach(p => {
|
||||
this.memoryChunks[p.id] = p.buf
|
||||
|
@ -143,7 +144,7 @@ export class PeertubeChunkStore extends EventEmitter {
|
|||
return cb(null, buf.slice(offset, len + offset))
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
return cb(err)
|
||||
})
|
||||
}
|
||||
|
@ -176,7 +177,7 @@ export class PeertubeChunkStore extends EventEmitter {
|
|||
|
||||
return cb()
|
||||
} catch (err) {
|
||||
console.error('Cannot destroy peertube chunk store.', err)
|
||||
logger.error('Cannot destroy peertube chunk store.', err)
|
||||
return cb(err)
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +205,7 @@ export class PeertubeChunkStore extends EventEmitter {
|
|||
databasesToDeleteInfo = await this.expirationDB.databases.where('expiration').below(now).toArray()
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('Cannot update expiration of fetch expired databases.', err)
|
||||
logger.error('Cannot update expiration of fetch expired databases.', err)
|
||||
}
|
||||
|
||||
for (const databaseToDeleteInfo of databasesToDeleteInfo) {
|
||||
|
@ -214,7 +215,7 @@ export class PeertubeChunkStore extends EventEmitter {
|
|||
|
||||
private async dropDatabase (databaseName: string) {
|
||||
const dbToDelete = new ChunkDatabase(databaseName)
|
||||
console.log('Destroying IndexDB database %s.', databaseName)
|
||||
logger.info(`Destroying IndexDB database ${databaseName}`)
|
||||
|
||||
try {
|
||||
await dbToDelete.delete()
|
||||
|
@ -223,7 +224,7 @@ export class PeertubeChunkStore extends EventEmitter {
|
|||
return this.expirationDB.databases.where({ name: databaseName }).delete()
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('Cannot delete %s.', databaseName, err)
|
||||
logger.error(`Cannot delete ${databaseName}.`, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Thanks: https://github.com/feross/render-media
|
||||
|
||||
const MediaElementWrapper = require('mediasource')
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { extname } from 'path'
|
||||
const Videostream = require('videostream')
|
||||
|
||||
|
@ -77,8 +78,8 @@ function renderMedia (file: any, elem: HTMLVideoElement, opts: RenderMediaOption
|
|||
}
|
||||
|
||||
function fallbackToMediaSource (useVP9 = false) {
|
||||
if (useVP9 === true) console.log('Falling back to media source with VP9 enabled.')
|
||||
else console.log('Falling back to media source..')
|
||||
if (useVP9 === true) logger.info('Falling back to media source with VP9 enabled.')
|
||||
else logger.info('Falling back to media source..')
|
||||
|
||||
useMediaSource(useVP9)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import videojs from 'video.js'
|
||||
import * as WebTorrent from 'webtorrent'
|
||||
import { logger } from '@root-helpers/logger'
|
||||
import { isIOS } from '@root-helpers/web-browser'
|
||||
import { timeToInt } from '@shared/core-utils'
|
||||
import { VideoFile } from '@shared/models'
|
||||
|
@ -210,7 +211,7 @@ class WebTorrentPlugin extends Plugin {
|
|||
if (destroyRenderer === true && this.renderer && this.renderer.destroy) this.renderer.destroy()
|
||||
|
||||
this.webtorrent.remove(videoFile.magnetUri)
|
||||
console.log('Removed ' + videoFile.magnetUri)
|
||||
logger.info(`Removed ${videoFile.magnetUri}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,7 +257,7 @@ class WebTorrentPlugin extends Plugin {
|
|||
) {
|
||||
if (!magnetOrTorrentUrl) return this.fallbackToHttp(options, done)
|
||||
|
||||
console.log('Adding ' + magnetOrTorrentUrl + '.')
|
||||
logger.info(`Adding ${magnetOrTorrentUrl}.`)
|
||||
|
||||
const oldTorrent = this.torrent
|
||||
const torrentOptions = {
|
||||
|
@ -269,7 +270,7 @@ class WebTorrentPlugin extends Plugin {
|
|||
}
|
||||
|
||||
this.torrent = this.webtorrent.add(magnetOrTorrentUrl, torrentOptions, torrent => {
|
||||
console.log('Added ' + magnetOrTorrentUrl + '.')
|
||||
logger.info(`Added ${magnetOrTorrentUrl}.`)
|
||||
|
||||
if (oldTorrent) {
|
||||
// Pause the old torrent
|
||||
|
@ -309,7 +310,7 @@ class WebTorrentPlugin extends Plugin {
|
|||
}, options.delay || 0)
|
||||
})
|
||||
|
||||
this.torrent.on('error', (err: any) => console.error(err))
|
||||
this.torrent.on('error', (err: any) => logger.error(err))
|
||||
|
||||
this.torrent.on('warning', (err: any) => {
|
||||
// We don't support HTTP tracker but we don't care -> we use the web socket tracker
|
||||
|
@ -317,13 +318,13 @@ class WebTorrentPlugin extends Plugin {
|
|||
|
||||
// Users don't care about issues with WebRTC, but developers do so log it in the console
|
||||
if (err.message.indexOf('Ice connection failed') !== -1) {
|
||||
console.log(err)
|
||||
logger.info(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Magnet hash is not up to date with the torrent file, add directly the torrent file
|
||||
if (err.message.indexOf('incorrect info hash') !== -1) {
|
||||
console.error('Incorrect info hash detected, falling back to torrent file.')
|
||||
logger.error('Incorrect info hash detected, falling back to torrent file.')
|
||||
const newOptions = { forcePlay: true, seek: options.seek }
|
||||
return this.addTorrent(this.torrent['xs'], previousVideoFile, newOptions, done)
|
||||
}
|
||||
|
@ -333,7 +334,7 @@ class WebTorrentPlugin extends Plugin {
|
|||
this.handleError(err)
|
||||
}
|
||||
|
||||
console.warn(err)
|
||||
logger.warn(err)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -348,7 +349,7 @@ class WebTorrentPlugin extends Plugin {
|
|||
return
|
||||
}
|
||||
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
this.player.pause()
|
||||
this.player.posterImage.show()
|
||||
this.player.removeClass('vjs-has-autoplay')
|
||||
|
@ -465,10 +466,10 @@ class WebTorrentPlugin extends Plugin {
|
|||
|
||||
// Lower resolution
|
||||
if (this.isPlayerWaiting() && file.resolution.id < this.currentVideoFile.resolution.id) {
|
||||
console.log('Downgrading automatically the resolution to: %s', file.resolution.label)
|
||||
logger.info(`Downgrading automatically the resolution to: ${file.resolution.label}`)
|
||||
changeResolution = true
|
||||
} else if (file.resolution.id > this.currentVideoFile.resolution.id) { // Higher resolution
|
||||
console.log('Upgrading automatically the resolution to: %s', file.resolution.label)
|
||||
logger.info(`Upgrading automatically the resolution to: ${file.resolution.label}`)
|
||||
changeResolution = true
|
||||
changeResolutionDelay = this.CONSTANTS.AUTO_QUALITY_HIGHER_RESOLUTION_DELAY
|
||||
}
|
||||
|
@ -577,7 +578,7 @@ class WebTorrentPlugin extends Plugin {
|
|||
|
||||
// The renderer returns an error when we destroy it, so skip them
|
||||
if (this.destroyingFakeRenderer === false && err) {
|
||||
console.error('Cannot render new torrent in fake video element.', err)
|
||||
logger.error('Cannot render new torrent in fake video element.', err)
|
||||
}
|
||||
|
||||
// Load the future file at the correct time (in delay MS - 2 seconds)
|
||||
|
@ -593,7 +594,7 @@ class WebTorrentPlugin extends Plugin {
|
|||
try {
|
||||
this.fakeRenderer.destroy()
|
||||
} catch (err) {
|
||||
console.log('Cannot destroy correctly fake renderer.', err)
|
||||
logger.info('Cannot destroy correctly fake renderer.', err)
|
||||
}
|
||||
}
|
||||
this.fakeRenderer = undefined
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { logger } from '@root-helpers/logger'
|
||||
import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '@shared/core-utils/i18n'
|
||||
|
||||
export class TranslationsManager {
|
||||
|
@ -11,7 +12,7 @@ export class TranslationsManager {
|
|||
return fetch(path + '/server.json')
|
||||
.then(res => res.json())
|
||||
.catch(err => {
|
||||
console.error('Cannot get server translations', err)
|
||||
logger.error('Cannot get server translations', err)
|
||||
return undefined
|
||||
})
|
||||
}
|
||||
|
@ -33,7 +34,7 @@ export class TranslationsManager {
|
|||
return json
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Cannot get player translations', err)
|
||||
logger.error('Cannot get player translations', err)
|
||||
return undefined
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,11 +3,14 @@ import { enableDebugTools } from '@angular/platform-browser'
|
|||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
|
||||
import { AppModule } from './app/app.module'
|
||||
import { environment } from './environments/environment'
|
||||
import { logger } from './root-helpers'
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode()
|
||||
}
|
||||
|
||||
logger.registerServerSending(environment.apiUrl)
|
||||
|
||||
const bootstrap = () => platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule)
|
||||
.then(bootstrapModule => {
|
||||
|
@ -22,7 +25,7 @@ const bootstrap = () => platformBrowserDynamic()
|
|||
return bootstrapModule
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
return null
|
||||
})
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { logger } from './logger'
|
||||
|
||||
function imageToDataURL (input: File | Blob) {
|
||||
return new Promise<string>(res => {
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onerror = err => console.error('Cannot read input file.', err)
|
||||
reader.onerror = err => logger.error('Cannot read input file.', err)
|
||||
reader.onloadend = () => res(reader.result as string)
|
||||
reader.readAsDataURL(input)
|
||||
})
|
||||
|
|
|
@ -2,6 +2,7 @@ export * from './users'
|
|||
export * from './bytes'
|
||||
export * from './images'
|
||||
export * from './local-storage-utils'
|
||||
export * from './logger'
|
||||
export * from './peertube-web-storage'
|
||||
export * from './plugins-manager'
|
||||
export * from './string'
|
||||
|
|
138
client/src/root-helpers/logger.ts
Normal file
138
client/src/root-helpers/logger.ts
Normal file
|
@ -0,0 +1,138 @@
|
|||
import { ClientLogCreate } from '@shared/models/server'
|
||||
import { peertubeLocalStorage } from './peertube-web-storage'
|
||||
import { UserTokens } from './users'
|
||||
|
||||
export type LoggerHook = (message: LoggerMessage, meta?: LoggerMeta) => void
|
||||
export type LoggerLevel = 'info' | 'warn' | 'error'
|
||||
|
||||
export type LoggerMessage = string | Error | object
|
||||
export type LoggerMeta = Error | { [ id: string ]: any, err?: Error }
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
logger: Logger
|
||||
}
|
||||
}
|
||||
|
||||
class Logger {
|
||||
private readonly hooks: { level: LoggerLevel, hook: LoggerHook }[] = []
|
||||
|
||||
info (message: LoggerMessage, meta?: LoggerMeta) {
|
||||
this.runHooks('info', message, meta)
|
||||
|
||||
if (meta) console.log(message, meta)
|
||||
else console.log(message)
|
||||
}
|
||||
|
||||
warn (message: LoggerMessage, meta?: LoggerMeta) {
|
||||
this.runHooks('warn', message, meta)
|
||||
|
||||
if (meta) console.warn(message, meta)
|
||||
else console.warn(message)
|
||||
}
|
||||
|
||||
error (message: LoggerMessage, meta?: LoggerMeta) {
|
||||
this.runHooks('error', message, meta)
|
||||
|
||||
if (meta) console.error(message, meta)
|
||||
else console.error(message)
|
||||
}
|
||||
|
||||
addHook (level: LoggerLevel, hook: LoggerHook) {
|
||||
this.hooks.push({ level, hook })
|
||||
}
|
||||
|
||||
registerServerSending (serverUrl: string) {
|
||||
this.addHook('warn', (message, meta) => this.sendClientLog(serverUrl, this.buildServerLogPayload('warn', message, meta)))
|
||||
this.addHook('error', (message, meta) => this.sendClientLog(serverUrl, this.buildServerLogPayload('error', message, meta)))
|
||||
}
|
||||
|
||||
sendClientLog (serverUrl: string, payload: ClientLogCreate | null) {
|
||||
if (!payload) return
|
||||
|
||||
const headers = new Headers({
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
|
||||
try {
|
||||
const tokens = UserTokens.getUserTokens(peertubeLocalStorage)
|
||||
|
||||
if (tokens) headers.set('Authorization', `${tokens.tokenType} ${tokens.accessToken}`)
|
||||
} catch (err) {
|
||||
console.error('Cannot set tokens to client log sender.', { err })
|
||||
}
|
||||
|
||||
try {
|
||||
fetch(serverUrl + '/api/v1/server/logs/client', {
|
||||
headers,
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('Cannot send client warn/error to server.', err)
|
||||
}
|
||||
}
|
||||
|
||||
private buildServerLogPayload (level: Extract<LoggerLevel, 'warn' | 'error'>, message: LoggerMessage, meta?: LoggerMeta) {
|
||||
if (!message) return null
|
||||
|
||||
return {
|
||||
message: this.buildMessageServerLogPayload(message),
|
||||
userAgent: navigator.userAgent,
|
||||
url: window.location.href,
|
||||
level,
|
||||
stackTrace: this.buildStackServerLogPayload(message, meta),
|
||||
meta: this.buildMetaServerLogPayload(meta)
|
||||
}
|
||||
}
|
||||
|
||||
private buildMessageServerLogPayload (message: LoggerMessage) {
|
||||
if (typeof message === 'string') return message
|
||||
if (message instanceof Error) return message.message
|
||||
|
||||
return JSON.stringify(message)
|
||||
}
|
||||
|
||||
private buildStackServerLogPayload (message: LoggerMessage, meta?: LoggerMeta) {
|
||||
if (message instanceof Error) return message.stack
|
||||
if (meta instanceof Error) return meta.stack
|
||||
if (meta?.err instanceof Error) return meta.err.stack
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
private buildMetaServerLogPayload (meta?: LoggerMeta) {
|
||||
if (!meta) return undefined
|
||||
if (meta instanceof Error) return undefined
|
||||
|
||||
let result: string
|
||||
|
||||
try {
|
||||
result = JSON.stringify(meta, (key, value) => {
|
||||
if (key === 'err') return undefined
|
||||
|
||||
return value
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('Cannot stringify meta.', err)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private runHooks (level: LoggerLevel, message: LoggerMessage, meta?: LoggerMeta) {
|
||||
for (const hookObj of this.hooks) {
|
||||
if (hookObj.level !== level) continue
|
||||
|
||||
hookObj.hook(message, meta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const logger = window.logger || new Logger()
|
||||
window.logger = logger
|
||||
|
||||
export {
|
||||
logger
|
||||
}
|
|
@ -21,6 +21,7 @@ import {
|
|||
} from '@shared/models'
|
||||
import { environment } from '../environments/environment'
|
||||
import { ClientScript } from '../types'
|
||||
import { logger } from './logger'
|
||||
|
||||
interface HookStructValue extends RegisterClientHookOptions {
|
||||
plugin: ServerConfigPlugin
|
||||
|
@ -48,7 +49,7 @@ type OnSettingsScripts = (pluginInfo: PluginInfo, options: RegisterClientSetting
|
|||
|
||||
type OnClientRoute = (options: RegisterClientRouteOptions) => void
|
||||
|
||||
const logger = debug('peertube:plugins')
|
||||
const debugLogger = debug('peertube:plugins')
|
||||
|
||||
class PluginsManager {
|
||||
private hooks: Hooks = {}
|
||||
|
@ -109,10 +110,10 @@ class PluginsManager {
|
|||
const hookType = getHookType(hookName)
|
||||
|
||||
for (const hook of this.hooks[hookName]) {
|
||||
console.log('Running hook %s of plugin %s.', hookName, hook.plugin.name)
|
||||
logger.info(`Running hook ${hookName} of plugin ${hook.plugin.name}`)
|
||||
|
||||
result = await internalRunHook(hook.handler, hookType, result, params, err => {
|
||||
console.error('Cannot run hook %s of script %s of plugin %s.', hookName, hook.clientScript.script, hook.plugin.name, err)
|
||||
logger.error(`Cannot run hook ${hookName} of script ${hook.clientScript.script} of plugin ${hook.plugin.name}`, err)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -170,7 +171,7 @@ class PluginsManager {
|
|||
|
||||
this.loadingScopes[scope] = true
|
||||
|
||||
logger('Loading scope %s', scope)
|
||||
debugLogger('Loading scope %s', scope)
|
||||
|
||||
try {
|
||||
if (!isReload) this.loadedScopes.push(scope)
|
||||
|
@ -180,7 +181,7 @@ class PluginsManager {
|
|||
this.loadingScopes[scope] = false
|
||||
this.pluginsLoaded[scope].next(true)
|
||||
|
||||
logger('Nothing to load for scope %s', scope)
|
||||
debugLogger('Nothing to load for scope %s', scope)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -200,9 +201,9 @@ class PluginsManager {
|
|||
this.pluginsLoaded[scope].next(true)
|
||||
this.loadingScopes[scope] = false
|
||||
|
||||
logger('Scope %s loaded', scope)
|
||||
debugLogger('Scope %s loaded', scope)
|
||||
} catch (err) {
|
||||
console.error('Cannot load plugins by scope %s.', scope, err)
|
||||
logger.error(`Cannot load plugins by scope ${scope}`, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +212,7 @@ class PluginsManager {
|
|||
|
||||
const registerHook = (options: RegisterClientHookOptions) => {
|
||||
if (clientHookObject[options.target] !== true) {
|
||||
console.error('Unknown hook %s of plugin %s. Skipping.', options.target, plugin.name)
|
||||
logger.error(`Unknown hook ${options.target} of plugin ${plugin.name}. Skipping.`)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -252,7 +253,7 @@ class PluginsManager {
|
|||
|
||||
const peertubeHelpers = this.peertubeHelpersFactory(pluginInfo)
|
||||
|
||||
console.log('Loading script %s of plugin %s.', clientScript.script, plugin.name)
|
||||
logger.info(`Loading script ${clientScript.script} of plugin ${plugin.name}`)
|
||||
|
||||
const absURL = (environment.apiUrl || window.location.origin) + clientScript.script
|
||||
return dynamicImport(absURL)
|
||||
|
@ -266,7 +267,7 @@ class PluginsManager {
|
|||
})
|
||||
})
|
||||
.then(() => this.sortHooksByPriority())
|
||||
.catch(err => console.error('Cannot import or register plugin %s.', pluginInfo.plugin.name, err))
|
||||
.catch(err => logger.error(`Cannot import or register plugin ${pluginInfo.plugin.name}`, err))
|
||||
}
|
||||
|
||||
private sortHooksByPriority () {
|
||||
|
@ -294,7 +295,7 @@ async function dynamicImport (url: string) {
|
|||
// eslint-disable-next-line no-new-func
|
||||
return new Function(`return import('${url}')`)()
|
||||
} catch {
|
||||
console.log('Fallback to import polyfill')
|
||||
logger.info('Fallback to import polyfill')
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const vector = '$importModule$' + Math.random().toString(32).slice(2)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import './embed.scss'
|
||||
|
||||
import * as Channel from 'jschannel'
|
||||
import { logger } from '../../root-helpers'
|
||||
import { PeerTubeResolution, PeerTubeTextTrack } from '../player/definitions'
|
||||
import { PeerTubeEmbed } from './embed'
|
||||
|
||||
|
@ -59,7 +59,7 @@ export class PeerTubeEmbedApi {
|
|||
}
|
||||
|
||||
private setResolution (resolutionId: number) {
|
||||
console.log('set resolution %d', resolutionId)
|
||||
logger.info(`Set resolution ${resolutionId}`)
|
||||
|
||||
if (this.isWebtorrent()) {
|
||||
if (resolutionId === -1 && this.embed.player.webtorrent().isAutoResolutionPossible() === false) return
|
||||
|
|
|
@ -6,7 +6,7 @@ import { peertubeTranslate } from '../../../../shared/core-utils/i18n'
|
|||
import { HTMLServerConfig, LiveVideo, ResultList, VideoDetails, VideoPlaylist, VideoPlaylistElement } from '../../../../shared/models'
|
||||
import { PeertubePlayerManager } from '../../assets/player'
|
||||
import { TranslationsManager } from '../../assets/player/translations-manager'
|
||||
import { getParamString } from '../../root-helpers'
|
||||
import { getParamString, logger } from '../../root-helpers'
|
||||
import { PeerTubeEmbedApi } from './embed-api'
|
||||
import { AuthHTTP, LiveManager, PeerTubePlugin, PlayerManagerOptions, PlaylistFetcher, PlaylistTracker, VideoFetcher } from './shared'
|
||||
import { PlayerHTML } from './shared/player-html'
|
||||
|
@ -31,6 +31,8 @@ export class PeerTubeEmbed {
|
|||
private playlistTracker: PlaylistTracker
|
||||
|
||||
constructor (videoWrapperId: string) {
|
||||
logger.registerServerSending(window.location.origin)
|
||||
|
||||
this.http = new AuthHTTP()
|
||||
|
||||
this.videoFetcher = new VideoFetcher(this.http)
|
||||
|
@ -43,7 +45,7 @@ export class PeerTubeEmbed {
|
|||
try {
|
||||
this.config = JSON.parse(window['PeerTubeServerConfig'])
|
||||
} catch (err) {
|
||||
console.error('Cannot parse HTML config.', err)
|
||||
logger.error('Cannot parse HTML config.', err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +127,7 @@ export class PeerTubeEmbed {
|
|||
async playNextPlaylistVideo () {
|
||||
const next = this.playlistTracker.getNextPlaylistElement()
|
||||
if (!next) {
|
||||
console.log('Next element not found in playlist.')
|
||||
logger.info('Next element not found in playlist.')
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -137,7 +139,7 @@ export class PeerTubeEmbed {
|
|||
async playPreviousPlaylistVideo () {
|
||||
const previous = this.playlistTracker.getPreviousPlaylistElement()
|
||||
if (!previous) {
|
||||
console.log('Previous element not found in playlist.')
|
||||
logger.info('Previous element not found in playlist.')
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -343,5 +345,5 @@ PeerTubeEmbed.main()
|
|||
.catch(err => {
|
||||
(window as any).displayIncompatibleBrowser()
|
||||
|
||||
console.error('Cannot init embed.', err)
|
||||
logger.error('Cannot init embed.', err)
|
||||
})
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { peertubeTranslate } from '../../../../../shared/core-utils/i18n'
|
||||
import { VideoDetails } from '../../../../../shared/models'
|
||||
import { logger } from '../../../root-helpers'
|
||||
import { Translations } from './translations'
|
||||
|
||||
export class PlayerHTML {
|
||||
|
@ -29,7 +30,7 @@ export class PlayerHTML {
|
|||
}
|
||||
|
||||
displayError (text: string, translations: Translations) {
|
||||
console.error(text)
|
||||
logger.error(text)
|
||||
|
||||
// Remove video element
|
||||
if (this.playerElement) {
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
getParamString,
|
||||
getParamToggle,
|
||||
isP2PEnabled,
|
||||
logger,
|
||||
peertubeLocalStorage,
|
||||
UserLocalStorageKeys
|
||||
} from '../../../root-helpers'
|
||||
|
@ -137,7 +138,7 @@ export class PlayerManagerOptions {
|
|||
else this.mode = 'webtorrent'
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Cannot get params from URL.', err)
|
||||
logger.error('Cannot get params from URL.', err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { HttpStatusCode, ResultList, VideoPlaylistElement } from '../../../../../shared/models'
|
||||
import { logger } from '../../../root-helpers'
|
||||
import { AuthHTTP } from './auth-http'
|
||||
|
||||
export class PlaylistFetcher {
|
||||
|
@ -18,7 +19,7 @@ export class PlaylistFetcher {
|
|||
playlistResponse = await playlistPromise
|
||||
isResponseOk = playlistResponse.status === HttpStatusCode.OK_200
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
isResponseOk = false
|
||||
}
|
||||
|
||||
|
@ -49,7 +50,7 @@ export class PlaylistFetcher {
|
|||
}
|
||||
|
||||
if (i === 10) {
|
||||
console.error('Cannot fetch all playlists elements, there are too many!')
|
||||
logger.error('Cannot fetch all playlists elements, there are too many!')
|
||||
}
|
||||
|
||||
return elements
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { VideoPlaylist, VideoPlaylistElement } from '../../../../../shared/models'
|
||||
import { logger } from '../../../root-helpers'
|
||||
|
||||
export class PlaylistTracker {
|
||||
private currentPlaylistElement: VideoPlaylistElement
|
||||
|
@ -68,7 +69,7 @@ export class PlaylistTracker {
|
|||
setPosition (position: number) {
|
||||
this.currentPlaylistElement = this.playlistElements.find(e => e.position === position)
|
||||
if (!this.currentPlaylistElement || !this.currentPlaylistElement.video) {
|
||||
console.error('Current playlist element is not valid.', this.currentPlaylistElement)
|
||||
logger.error('Current playlist element is not valid.', this.currentPlaylistElement)
|
||||
this.currentPlaylistElement = this.getNextPlaylistElement()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { HttpStatusCode, LiveVideo, VideoDetails } from '../../../../../shared/models'
|
||||
import { logger } from '../../../root-helpers'
|
||||
import { AuthHTTP } from './auth-http'
|
||||
|
||||
export class VideoFetcher {
|
||||
|
@ -17,7 +18,7 @@ export class VideoFetcher {
|
|||
videoResponse = await videoPromise
|
||||
isResponseOk = videoResponse.status === HttpStatusCode.OK_200
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
logger.error(err)
|
||||
|
||||
isResponseOk = false
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import './test-embed.scss'
|
||||
import { PeerTubeResolution, PlayerEventType } from '../player/definitions'
|
||||
import { PeerTubePlayer } from '../player/player'
|
||||
import { logger } from '../../root-helpers'
|
||||
|
||||
window.addEventListener('load', async () => {
|
||||
const urlParts = window.location.href.split('/')
|
||||
|
@ -20,14 +21,14 @@ window.addEventListener('load', async () => {
|
|||
const mainElement = document.querySelector('#host')
|
||||
mainElement.appendChild(iframe)
|
||||
|
||||
console.log('Document finished loading.')
|
||||
logger.info('Document finished loading.')
|
||||
const player = new PeerTubePlayer(document.querySelector('iframe'))
|
||||
|
||||
window['player'] = player
|
||||
|
||||
console.log('Awaiting player ready...')
|
||||
logger.info('Awaiting player ready...')
|
||||
await player.ready
|
||||
console.log('Player is ready.')
|
||||
logger.info('Player is ready.')
|
||||
|
||||
const monitoredEvents = [
|
||||
'pause',
|
||||
|
@ -37,8 +38,8 @@ window.addEventListener('load', async () => {
|
|||
]
|
||||
|
||||
monitoredEvents.forEach(e => {
|
||||
player.addEventListener(e as PlayerEventType, (param) => console.log(`PLAYER: event '${e}' received`, param))
|
||||
console.log(`PLAYER: now listening for event '${e}'`)
|
||||
player.addEventListener(e as PlayerEventType, (param) => logger.info(`PLAYER: event '${e}' received`, { param }))
|
||||
logger.info(`PLAYER: now listening for event '${e}'`)
|
||||
|
||||
player.getCurrentPosition()
|
||||
.then(position => {
|
||||
|
|
7
client/src/standalone/videos/tsconfig.json
Normal file
7
client/src/standalone/videos/tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": [
|
||||
"src/standalone/videos/embed.ts",
|
||||
"src/standalone/videos/test-embed.ts"
|
||||
]
|
||||
}
|
|
@ -69,7 +69,7 @@ module.exports = function () {
|
|||
{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
configFile: helpers.root('tsconfig.json')
|
||||
configFile: helpers.root('src/standalone/videos/tsconfig.json')
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -27,6 +27,10 @@ rates_limit:
|
|||
# 3 attempts in 5 min
|
||||
window: 5 minutes
|
||||
max: 3
|
||||
receive_client_log:
|
||||
# 10 attempts in 10 min
|
||||
window: 10 minutes
|
||||
max: 10
|
||||
|
||||
# Proxies to trust to get real client IP
|
||||
# If you run PeerTube just behind a local proxy (nginx), keep 'loopback'
|
||||
|
@ -168,15 +172,22 @@ object_storage:
|
|||
|
||||
log:
|
||||
level: 'info' # 'debug' | 'info' | 'warn' | 'error'
|
||||
|
||||
rotation:
|
||||
enabled : true # Enabled by default, if disabled make sure that 'storage.logs' is pointing to a folder handled by logrotate
|
||||
max_file_size: 12MB
|
||||
max_files: 20
|
||||
|
||||
anonymize_ip: false
|
||||
|
||||
log_ping_requests: true
|
||||
log_tracker_unknown_infohash: true
|
||||
|
||||
prettify_sql: false
|
||||
|
||||
# Accept warn/error logs coming from the client
|
||||
accept_client_log: true
|
||||
|
||||
# Highly experimental support of Open Telemetry
|
||||
open_telemetry:
|
||||
metrics:
|
||||
|
|
|
@ -25,6 +25,10 @@ rates_limit:
|
|||
# 3 attempts in 5 min
|
||||
window: 5 minutes
|
||||
max: 3
|
||||
receive_client_log:
|
||||
# 10 attempts in 10 min
|
||||
window: 10 minutes
|
||||
max: 10
|
||||
|
||||
# Proxies to trust to get real client IP
|
||||
# If you run PeerTube just behind a local proxy (nginx), keep 'loopback'
|
||||
|
@ -166,15 +170,22 @@ object_storage:
|
|||
|
||||
log:
|
||||
level: 'info' # 'debug' | 'info' | 'warn' | 'error'
|
||||
|
||||
rotation:
|
||||
enabled : true # Enabled by default, if disabled make sure that 'storage.logs' is pointing to a folder handled by logrotate
|
||||
max_file_size: 12MB
|
||||
max_files: 20
|
||||
|
||||
anonymize_ip: false
|
||||
|
||||
log_ping_requests: true
|
||||
log_tracker_unknown_infohash: true
|
||||
|
||||
prettify_sql: false
|
||||
|
||||
# Accept warn/error logs coming from the client
|
||||
accept_client_log: true
|
||||
|
||||
# Highly experimental support of Open Telemetry
|
||||
open_telemetry:
|
||||
metrics:
|
||||
|
|
|
@ -3,15 +3,29 @@ import { readdir, readFile } from 'fs-extra'
|
|||
import { join } from 'path'
|
||||
import { isArray } from '@server/helpers/custom-validators/misc'
|
||||
import { logger, mtimeSortFilesDesc } from '@server/helpers/logger'
|
||||
import { LogLevel } from '../../../../shared/models/server/log-level.type'
|
||||
import { pick } from '@shared/core-utils'
|
||||
import { ClientLogCreate, HttpStatusCode } from '@shared/models'
|
||||
import { ServerLogLevel } from '../../../../shared/models/server/server-log-level.type'
|
||||
import { UserRight } from '../../../../shared/models/users'
|
||||
import { CONFIG } from '../../../initializers/config'
|
||||
import { AUDIT_LOG_FILENAME, LOG_FILENAME, MAX_LOGS_OUTPUT_CHARACTERS } from '../../../initializers/constants'
|
||||
import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares'
|
||||
import { getAuditLogsValidator, getLogsValidator } from '../../../middlewares/validators/logs'
|
||||
import { asyncMiddleware, authenticate, buildRateLimiter, ensureUserHasRight, optionalAuthenticate } from '../../../middlewares'
|
||||
import { createClientLogValidator, getAuditLogsValidator, getLogsValidator } from '../../../middlewares/validators/logs'
|
||||
|
||||
const createClientLogRateLimiter = buildRateLimiter({
|
||||
windowMs: CONFIG.RATES_LIMIT.RECEIVE_CLIENT_LOG.WINDOW_MS,
|
||||
max: CONFIG.RATES_LIMIT.RECEIVE_CLIENT_LOG.MAX
|
||||
})
|
||||
|
||||
const logsRouter = express.Router()
|
||||
|
||||
logsRouter.post('/logs/client',
|
||||
createClientLogRateLimiter,
|
||||
optionalAuthenticate,
|
||||
createClientLogValidator,
|
||||
createClientLog
|
||||
)
|
||||
|
||||
logsRouter.get('/logs',
|
||||
authenticate,
|
||||
ensureUserHasRight(UserRight.MANAGE_LOGS),
|
||||
|
@ -34,6 +48,21 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function createClientLog (req: express.Request, res: express.Response) {
|
||||
const logInfo = req.body as ClientLogCreate
|
||||
|
||||
const meta = {
|
||||
tags: [ 'client' ],
|
||||
username: res.locals.oauth?.token?.User?.username,
|
||||
|
||||
...pick(logInfo, [ 'userAgent', 'stackTrace', 'meta', 'url' ])
|
||||
}
|
||||
|
||||
logger.log(logInfo.level, `Client log: ${logInfo.message}`, meta)
|
||||
|
||||
return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
|
||||
}
|
||||
|
||||
const auditLogNameFilter = generateLogNameFilter(AUDIT_LOG_FILENAME)
|
||||
async function getAuditLogs (req: express.Request, res: express.Response) {
|
||||
const output = await generateOutput({
|
||||
|
@ -63,7 +92,7 @@ async function generateOutput (options: {
|
|||
startDateQuery: string
|
||||
endDateQuery?: string
|
||||
|
||||
level: LogLevel
|
||||
level: ServerLogLevel
|
||||
nameFilter: RegExp
|
||||
tagsOneOf?: string[]
|
||||
}) {
|
||||
|
@ -104,7 +133,7 @@ async function getOutputFromFile (options: {
|
|||
path: string
|
||||
startDate: Date
|
||||
endDate: Date
|
||||
level: LogLevel
|
||||
level: ServerLogLevel
|
||||
currentSize: number
|
||||
tagsOneOf: Set<string>
|
||||
}) {
|
||||
|
@ -116,7 +145,7 @@ async function getOutputFromFile (options: {
|
|||
|
||||
let logTime: number
|
||||
|
||||
const logsLevel: { [ id in LogLevel ]: number } = {
|
||||
const logsLevel: { [ id in ServerLogLevel ]: number } = {
|
||||
audit: -1,
|
||||
debug: 0,
|
||||
info: 1,
|
||||
|
|
|
@ -1,14 +1,42 @@
|
|||
import validator from 'validator'
|
||||
import { CONSTRAINTS_FIELDS } from '@server/initializers/constants'
|
||||
import { ClientLogLevel, ServerLogLevel } from '@shared/models'
|
||||
import { exists } from './misc'
|
||||
import { LogLevel } from '../../../shared/models/server/log-level.type'
|
||||
|
||||
const logLevels: LogLevel[] = [ 'debug', 'info', 'warn', 'error' ]
|
||||
const serverLogLevels: Set<ServerLogLevel> = new Set([ 'debug', 'info', 'warn', 'error' ])
|
||||
const clientLogLevels: Set<ClientLogLevel> = new Set([ 'warn', 'error' ])
|
||||
|
||||
function isValidLogLevel (value: any) {
|
||||
return exists(value) && logLevels.includes(value)
|
||||
return exists(value) && serverLogLevels.has(value)
|
||||
}
|
||||
|
||||
function isValidClientLogMessage (value: any) {
|
||||
return typeof value === 'string' && validator.isLength(value, CONSTRAINTS_FIELDS.LOGS.CLIENT_MESSAGE)
|
||||
}
|
||||
|
||||
function isValidClientLogLevel (value: any) {
|
||||
return exists(value) && clientLogLevels.has(value)
|
||||
}
|
||||
|
||||
function isValidClientLogStackTrace (value: any) {
|
||||
return typeof value === 'string' && validator.isLength(value, CONSTRAINTS_FIELDS.LOGS.CLIENT_STACK_TRACE)
|
||||
}
|
||||
|
||||
function isValidClientLogMeta (value: any) {
|
||||
return typeof value === 'string' && validator.isLength(value, CONSTRAINTS_FIELDS.LOGS.CLIENT_META)
|
||||
}
|
||||
|
||||
function isValidClientLogUserAgent (value: any) {
|
||||
return typeof value === 'string' && validator.isLength(value, CONSTRAINTS_FIELDS.LOGS.CLIENT_USER_AGENT)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
isValidLogLevel
|
||||
isValidLogLevel,
|
||||
isValidClientLogMessage,
|
||||
isValidClientLogStackTrace,
|
||||
isValidClientLogMeta,
|
||||
isValidClientLogLevel,
|
||||
isValidClientLogUserAgent
|
||||
}
|
||||
|
|
|
@ -149,6 +149,10 @@ const CONFIG = {
|
|||
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.login.window')),
|
||||
MAX: config.get<number>('rates_limit.login.max')
|
||||
},
|
||||
RECEIVE_CLIENT_LOG: {
|
||||
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.receive_client_log.window')),
|
||||
MAX: config.get<number>('rates_limit.receive_client_log.max')
|
||||
},
|
||||
ASK_SEND_EMAIL: {
|
||||
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.ask_send_email.window')),
|
||||
MAX: config.get<number>('rates_limit.ask_send_email.max')
|
||||
|
@ -165,7 +169,8 @@ const CONFIG = {
|
|||
ANONYMIZE_IP: config.get<boolean>('log.anonymize_ip'),
|
||||
LOG_PING_REQUESTS: config.get<boolean>('log.log_ping_requests'),
|
||||
LOG_TRACKER_UNKNOWN_INFOHASH: config.get<boolean>('log.log_tracker_unknown_infohash'),
|
||||
PRETTIFY_SQL: config.get<boolean>('log.prettify_sql')
|
||||
PRETTIFY_SQL: config.get<boolean>('log.prettify_sql'),
|
||||
ACCEPT_CLIENT_LOG: config.get<boolean>('log.accept_client_log')
|
||||
},
|
||||
OPEN_TELEMETRY: {
|
||||
METRICS: {
|
||||
|
|
|
@ -365,6 +365,12 @@ const CONSTRAINTS_FIELDS = {
|
|||
VIDEO_STUDIO: {
|
||||
TASKS: { min: 1, max: 10 }, // Number of tasks
|
||||
CUT_TIME: { min: 0 } // Value
|
||||
},
|
||||
LOGS: {
|
||||
CLIENT_MESSAGE: { min: 1, max: 1000 }, // Length
|
||||
CLIENT_STACK_TRACE: { min: 1, max: 5000 }, // Length
|
||||
CLIENT_META: { min: 1, max: 5000 }, // Length
|
||||
CLIENT_USER_AGENT: { min: 1, max: 200 } // Length
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,56 @@
|
|||
import express from 'express'
|
||||
import { query } from 'express-validator'
|
||||
import { body, query } from 'express-validator'
|
||||
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc'
|
||||
import { isStringArray } from '@server/helpers/custom-validators/search'
|
||||
import { isValidLogLevel } from '../../helpers/custom-validators/logs'
|
||||
import { CONFIG } from '@server/initializers/config'
|
||||
import { HttpStatusCode } from '@shared/models'
|
||||
import {
|
||||
isValidClientLogLevel,
|
||||
isValidClientLogMessage,
|
||||
isValidClientLogMeta,
|
||||
isValidClientLogStackTrace,
|
||||
isValidClientLogUserAgent,
|
||||
isValidLogLevel
|
||||
} from '../../helpers/custom-validators/logs'
|
||||
import { isDateValid, toArray } from '../../helpers/custom-validators/misc'
|
||||
import { logger } from '../../helpers/logger'
|
||||
import { areValidationErrors } from './shared'
|
||||
|
||||
const createClientLogValidator = [
|
||||
body('message')
|
||||
.custom(isValidClientLogMessage).withMessage('Should have a valid log message'),
|
||||
|
||||
body('url')
|
||||
.custom(isUrlValid).withMessage('Should have a valid log url'),
|
||||
|
||||
body('level')
|
||||
.custom(isValidClientLogLevel).withMessage('Should have a valid log message'),
|
||||
|
||||
body('stackTrace')
|
||||
.optional()
|
||||
.custom(isValidClientLogStackTrace).withMessage('Should have a valid log stack trace'),
|
||||
|
||||
body('meta')
|
||||
.optional()
|
||||
.custom(isValidClientLogMeta).withMessage('Should have a valid log meta'),
|
||||
|
||||
body('userAgent')
|
||||
.optional()
|
||||
.custom(isValidClientLogUserAgent).withMessage('Should have a valid log user agent'),
|
||||
|
||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
logger.debug('Checking createClientLogValidator parameters.', { parameters: req.query })
|
||||
|
||||
if (CONFIG.LOG.ACCEPT_CLIENT_LOG !== true) {
|
||||
return res.sendStatus(HttpStatusCode.FORBIDDEN_403)
|
||||
}
|
||||
|
||||
if (areValidationErrors(req, res)) return
|
||||
|
||||
return next()
|
||||
}
|
||||
]
|
||||
|
||||
const getLogsValidator = [
|
||||
query('startDate')
|
||||
.custom(isDateValid).withMessage('Should have a start date that conforms to ISO 8601'),
|
||||
|
@ -49,5 +94,6 @@ const getAuditLogsValidator = [
|
|||
|
||||
export {
|
||||
getLogsValidator,
|
||||
getAuditLogsValidator
|
||||
getAuditLogsValidator,
|
||||
createClientLogValidator
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import 'mocha'
|
||||
import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
|
||||
import { expect } from 'chai'
|
||||
import { HttpStatusCode } from '@shared/models'
|
||||
import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
|
||||
|
||||
describe('Test logs API validators', function () {
|
||||
const path = '/api/v1/server/logs'
|
||||
|
@ -95,6 +96,62 @@ describe('Test logs API validators', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('When creating client logs', function () {
|
||||
const base = {
|
||||
level: 'warn' as 'warn',
|
||||
message: 'my super message',
|
||||
url: 'https://example.com/toto'
|
||||
}
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
it('Should fail with an invalid level', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, level: '' as any }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, level: undefined }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, level: 'toto' as any }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid message', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, message: undefined }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, message: '' }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, message: 'm'.repeat(2500) }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid url', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, url: undefined }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, url: 'toto' }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid stackTrace', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, stackTrace: 's'.repeat(10000) }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid userAgent', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, userAgent: 's'.repeat(500) }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid meta', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, meta: 's'.repeat(10000) }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, stackTrace: 'stackTrace', meta: '{toto}', userAgent: 'userAgent' } })
|
||||
})
|
||||
|
||||
it('Should rate limit log creation', async function () {
|
||||
let fail = false
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
try {
|
||||
await server.logs.createLogClient({ token: null, payload: base })
|
||||
} catch {
|
||||
fail = true
|
||||
}
|
||||
}
|
||||
|
||||
expect(fail).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import 'mocha'
|
||||
import * as chai from 'chai'
|
||||
import { HttpStatusCode } from '@shared/models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
|
@ -198,6 +199,70 @@ describe('Test logs', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('When creating log from the client', function () {
|
||||
|
||||
it('Should create a warn client log', async function () {
|
||||
const now = new Date()
|
||||
|
||||
await server.logs.createLogClient({
|
||||
payload: {
|
||||
level: 'warn',
|
||||
url: 'http://example.com',
|
||||
message: 'my super client message'
|
||||
},
|
||||
token: null
|
||||
})
|
||||
|
||||
const body = await logsCommand.getLogs({ startDate: now })
|
||||
const logsString = JSON.stringify(body)
|
||||
|
||||
expect(logsString.includes('my super client message')).to.be.true
|
||||
})
|
||||
|
||||
it('Should create an error authenticated client log', async function () {
|
||||
const now = new Date()
|
||||
|
||||
await server.logs.createLogClient({
|
||||
payload: {
|
||||
url: 'https://example.com/page1',
|
||||
level: 'error',
|
||||
message: 'my super client message 2',
|
||||
userAgent: 'super user agent',
|
||||
meta: '{hello}',
|
||||
stackTrace: 'super stack trace'
|
||||
}
|
||||
})
|
||||
|
||||
const body = await logsCommand.getLogs({ startDate: now })
|
||||
const logsString = JSON.stringify(body)
|
||||
|
||||
expect(logsString.includes('my super client message 2')).to.be.true
|
||||
expect(logsString.includes('super user agent')).to.be.true
|
||||
expect(logsString.includes('super stack trace')).to.be.true
|
||||
expect(logsString.includes('{hello}')).to.be.true
|
||||
expect(logsString.includes('https://example.com/page1')).to.be.true
|
||||
})
|
||||
|
||||
it('Should refuse to create client logs', async function () {
|
||||
await server.kill()
|
||||
|
||||
await server.run({
|
||||
log: {
|
||||
accept_client_log: false
|
||||
}
|
||||
})
|
||||
|
||||
await server.logs.createLogClient({
|
||||
payload: {
|
||||
level: 'warn',
|
||||
url: 'http://example.com',
|
||||
message: 'my super client message'
|
||||
},
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
|
|
11
shared/models/server/client-log-create.model.ts
Normal file
11
shared/models/server/client-log-create.model.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { ClientLogLevel } from './client-log-level.type'
|
||||
|
||||
export interface ClientLogCreate {
|
||||
message: string
|
||||
url: string
|
||||
level: ClientLogLevel
|
||||
|
||||
stackTrace?: string
|
||||
userAgent?: string
|
||||
meta?: string
|
||||
}
|
1
shared/models/server/client-log-level.type.ts
Normal file
1
shared/models/server/client-log-level.type.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export type ClientLogLevel = 'warn' | 'error'
|
|
@ -1,14 +1,16 @@
|
|||
export * from './about.model'
|
||||
export * from './broadcast-message-level.type'
|
||||
export * from './client-log-create.model'
|
||||
export * from './client-log-level.type'
|
||||
export * from './contact-form.model'
|
||||
export * from './custom-config.model'
|
||||
export * from './debug.model'
|
||||
export * from './emailer.model'
|
||||
export * from './job.model'
|
||||
export * from './log-level.type'
|
||||
export * from './peertube-problem-document.model'
|
||||
export * from './server-config.model'
|
||||
export * from './server-debug.model'
|
||||
export * from './server-error-code.enum'
|
||||
export * from './server-follow-create.model'
|
||||
export * from './server-log-level.type'
|
||||
export * from './server-stats.model'
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'audit'
|
1
shared/models/server/server-log-level.type.ts
Normal file
1
shared/models/server/server-log-level.type.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export type ServerLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'audit'
|
|
@ -1,12 +1,25 @@
|
|||
import { HttpStatusCode, LogLevel } from '@shared/models'
|
||||
import { ClientLogCreate, HttpStatusCode, ServerLogLevel } from '@shared/models'
|
||||
import { AbstractCommand, OverrideCommandOptions } from '../shared'
|
||||
|
||||
export class LogsCommand extends AbstractCommand {
|
||||
|
||||
createLogClient (options: OverrideCommandOptions & { payload: ClientLogCreate }) {
|
||||
const path = '/api/v1/server/logs/client'
|
||||
|
||||
return this.postBodyRequest({
|
||||
...options,
|
||||
|
||||
path,
|
||||
fields: options.payload,
|
||||
implicitToken: true,
|
||||
defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
}
|
||||
|
||||
getLogs (options: OverrideCommandOptions & {
|
||||
startDate: Date
|
||||
endDate?: Date
|
||||
level?: LogLevel
|
||||
level?: ServerLogLevel
|
||||
tagsOneOf?: string[]
|
||||
}) {
|
||||
const { startDate, endDate, tagsOneOf, level } = options
|
||||
|
|
|
@ -330,26 +330,21 @@ x-tagGroups:
|
|||
- name: Search
|
||||
tags:
|
||||
- Search
|
||||
- name: Custom pages
|
||||
tags:
|
||||
- Homepage
|
||||
- name: Moderation
|
||||
tags:
|
||||
- Abuses
|
||||
- Video Blocks
|
||||
- Account Blocks
|
||||
- Server Blocks
|
||||
- name: Instance Configuration
|
||||
- name: Instance
|
||||
tags:
|
||||
- Config
|
||||
- Homepage
|
||||
- Instance Follows
|
||||
- Instance Redundancy
|
||||
- Plugins
|
||||
- name: Stats
|
||||
tags:
|
||||
- Stats
|
||||
- name: Jobs
|
||||
tags:
|
||||
- Logs
|
||||
- Job
|
||||
paths:
|
||||
'/accounts/{name}':
|
||||
|
@ -4316,6 +4311,58 @@ paths:
|
|||
schema:
|
||||
$ref: '#/components/schemas/ServerStats'
|
||||
|
||||
/server/logs/client:
|
||||
post:
|
||||
tags:
|
||||
- Logs
|
||||
summary: Send client log
|
||||
operationId: sendClientLog
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SendClientLog'
|
||||
responses:
|
||||
'204':
|
||||
description: successful operation
|
||||
|
||||
/server/logs:
|
||||
get:
|
||||
tags:
|
||||
- Logs
|
||||
summary: Get instance logs
|
||||
operationId: getInstanceLogs
|
||||
security:
|
||||
- OAuth2:
|
||||
- admin
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
/server/audit-logs:
|
||||
get:
|
||||
tags:
|
||||
- Logs
|
||||
summary: Get instance audit logs
|
||||
operationId: getInstanceAuditLogs
|
||||
security:
|
||||
- OAuth2:
|
||||
- admin
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
'/feeds/video-comments.{format}':
|
||||
get:
|
||||
|
@ -6526,6 +6573,31 @@ components:
|
|||
enabled:
|
||||
type: boolean
|
||||
|
||||
SendClientLog:
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
description: URL of the current user page
|
||||
level:
|
||||
enum:
|
||||
- error
|
||||
- warn
|
||||
stackTrace:
|
||||
type: string
|
||||
description: Stack trace of the error if there is one
|
||||
userAgent:
|
||||
type: string
|
||||
description: User agent of the web browser that sends the message
|
||||
meta:
|
||||
type: string
|
||||
description: Additional information regarding this log
|
||||
required:
|
||||
- message
|
||||
- url
|
||||
- level
|
||||
|
||||
ServerStats:
|
||||
properties:
|
||||
totalUsers:
|
||||
|
|
Loading…
Reference in a new issue