diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts index 08500ef5c..3af20ea0a 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts @@ -1,6 +1,6 @@ import { SortMeta } from 'primeng/api' import { switchMap } from 'rxjs/operators' -import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' +import { buildVideoEmbedLink, buildVideoOrPlaylistEmbed, decorateVideoLink } from 'src/assets/player/utils' import { environment } from 'src/environments/environment' import { Component, OnInit } from '@angular/core' import { DomSanitizer } from '@angular/platform-browser' @@ -147,8 +147,9 @@ export class VideoBlockListComponent extends RestTable implements OnInit { getVideoEmbed (entry: VideoBlacklist) { return buildVideoOrPlaylistEmbed( - buildVideoLink({ - baseUrl: `${environment.originServerUrl}/videos/embed/${entry.video.uuid}`, + decorateVideoLink({ + url: buildVideoEmbedLink(entry.video, environment.originServerUrl), + title: false, warningTitle: false }), diff --git a/client/src/app/+videos/+video-edit/shared/video-edit.component.html b/client/src/app/+videos/+video-edit/shared/video-edit.component.html index 50d030ac9..ee5a50611 100644 --- a/client/src/app/+videos/+video-edit/shared/video-edit.component.html +++ b/client/src/app/+videos/+video-edit/shared/video-edit.component.html @@ -45,7 +45,7 @@ - +
{{ formErrors.description }} diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts b/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts index 04f8f0d58..0e1c4c207 100644 --- a/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts +++ b/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts @@ -161,7 +161,7 @@ export class VideoCommentComponent implements OnInit, OnChanges { // Before HTML rendering restore line feed for markdown list compatibility const commentText = this.comment.text.replace(//g, '\r\n') const html = await this.markdownService.textMarkdownToHTML(commentText, true, true) - this.sanitizedCommentHTML = this.markdownService.processVideoTimestamps(html) + this.sanitizedCommentHTML = this.markdownService.processVideoTimestamps(this.video.shortUUID, html) this.newParentComments = this.parentComments.concat([ this.comment ]) if (this.comment.account) { diff --git a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts index 23d00d31a..870c7ae3f 100644 --- a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts +++ b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts @@ -80,6 +80,7 @@ export class VideoDescriptionComponent implements OnChanges { private async setVideoDescriptionHTML () { const html = await this.markdownService.textMarkdownToHTML(this.video.description) - this.videoHTMLDescription = this.markdownService.processVideoTimestamps(html) + + this.videoHTMLDescription = this.markdownService.processVideoTimestamps(this.video.shortUUID, html) } } diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts index 7460ae3fc..9212b78be 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts @@ -582,6 +582,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { videoCaptions: playerCaptions, + videoShortUUID: video.shortUUID, videoUUID: video.uuid }, diff --git a/client/src/app/core/renderer/markdown.service.ts b/client/src/app/core/renderer/markdown.service.ts index ca1bf4eb9..01d44864b 100644 --- a/client/src/app/core/renderer/markdown.service.ts +++ b/client/src/app/core/renderer/markdown.service.ts @@ -1,5 +1,5 @@ import * as MarkdownIt from 'markdown-it' -import { buildVideoLink } from 'src/assets/player/utils' +import { buildVideoLink, decorateVideoLink } from 'src/assets/player/utils' import { Injectable } from '@angular/core' import { COMPLETE_RULES, @@ -82,10 +82,14 @@ export class MarkdownService { return this.render({ name: 'customPageMarkdownIt', markdown, withEmoji: true, additionalAllowedTags }) } - processVideoTimestamps (html: string) { + processVideoTimestamps (videoShortUUID: string, html: string) { return html.replace(/((\d{1,2}):)?(\d{1,2}):(\d{1,2})/g, function (str, _, h, m, s) { const t = (3600 * +(h || 0)) + (60 * +(m || 0)) + (+(s || 0)) - const url = buildVideoLink({ startTime: t }) + + const url = decorateVideoLink({ + url: buildVideoLink({ shortUUID: videoShortUUID }), + startTime: t + }) return `${str}` }) } diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts index 67aa0e399..393108ac9 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts @@ -1,7 +1,7 @@ import * as debug from 'debug' import truncate from 'lodash-es/truncate' import { SortMeta } from 'primeng/api' -import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' +import { buildVideoEmbedLink, buildVideoOrPlaylistEmbed, decorateVideoLink } from 'src/assets/player/utils' import { environment } from 'src/environments/environment' import { Component, Input, OnInit, ViewChild } from '@angular/core' import { DomSanitizer } from '@angular/platform-browser' @@ -129,8 +129,8 @@ export class AbuseListTableComponent extends RestTable implements OnInit { getVideoEmbed (abuse: AdminAbuse) { return buildVideoOrPlaylistEmbed( - buildVideoLink({ - baseUrl: `${environment.originServerUrl}/videos/embed/${abuse.video.uuid}`, + decorateVideoLink({ + url: buildVideoEmbedLink(abuse.video, environment.originServerUrl), title: false, warningTitle: false, startTime: abuse.video.startAt, diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/embed-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/embed-markup.component.ts index 4462903db..ba8969d5b 100644 --- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/embed-markup.component.ts +++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/embed-markup.component.ts @@ -1,4 +1,4 @@ -import { buildPlaylistLink, buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' +import { buildPlaylistEmbedLink, buildVideoEmbedLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' import { environment } from 'src/environments/environment' import { Component, ElementRef, Input, OnInit } from '@angular/core' import { CustomMarkupComponent } from './shared' @@ -17,8 +17,8 @@ export class EmbedMarkupComponent implements CustomMarkupComponent, OnInit { ngOnInit () { const link = this.type === 'video' - ? buildVideoLink({ baseUrl: `${environment.originServerUrl}/videos/embed/${this.uuid}` }) - : buildPlaylistLink({ baseUrl: `${environment.originServerUrl}/video-playlists/embed/${this.uuid}` }) + ? buildVideoEmbedLink({ uuid: this.uuid }, environment.originServerUrl) + : buildPlaylistEmbedLink({ uuid: this.uuid }, environment.originServerUrl) this.el.nativeElement.innerHTML = buildVideoOrPlaylistEmbed(link, this.uuid) } diff --git a/client/src/app/shared/shared-forms/markdown-textarea.component.ts b/client/src/app/shared/shared-forms/markdown-textarea.component.ts index a233a4205..8f51d47df 100644 --- a/client/src/app/shared/shared-forms/markdown-textarea.component.ts +++ b/client/src/app/shared/shared-forms/markdown-textarea.component.ts @@ -6,6 +6,7 @@ import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@an import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' import { SafeHtml } from '@angular/platform-browser' import { MarkdownService, ScreenService } from '@app/core' +import { Video } from '@shared/models' @Component({ selector: 'my-markdown-textarea', @@ -33,7 +34,7 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit { @Input() markdownType: 'text' | 'enhanced' = 'text' @Input() customMarkdownRenderer?: (text: string) => Promise - @Input() markdownVideo = false + @Input() markdownVideo: Video @Input() name = 'description' @@ -147,7 +148,7 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit { } if (this.markdownVideo) { - html = this.markdownService.processVideoTimestamps(html) + html = this.markdownService.processVideoTimestamps(this.markdownVideo.shortUUID, html) } return html diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts index 4ca6f52ad..41f4fa30d 100644 --- a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts +++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts @@ -1,5 +1,5 @@ import { mapValues, pickBy } from 'lodash-es' -import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' +import { buildVideoOrPlaylistEmbed, decorateVideoLink } from 'src/assets/player/utils' import { Component, Input, OnInit, ViewChild } from '@angular/core' import { DomSanitizer, SafeHtml } from '@angular/platform-browser' import { Notifier } from '@app/core' @@ -57,11 +57,12 @@ export class VideoReportComponent extends FormReactive implements OnInit { getVideoEmbed () { return this.sanitizer.bypassSecurityTrustHtml( buildVideoOrPlaylistEmbed( - buildVideoLink({ - baseUrl: this.video.embedUrl, + decorateVideoLink({ + url: this.video.embedUrl, title: false, warningTitle: false }), + this.video.name ) ) diff --git a/client/src/app/shared/shared-share-modal/video-share.component.ts b/client/src/app/shared/shared-share-modal/video-share.component.ts index a41ff248b..cdfe50836 100644 --- a/client/src/app/shared/shared-share-modal/video-share.component.ts +++ b/client/src/app/shared/shared-share-modal/video-share.component.ts @@ -1,9 +1,15 @@ import { Component, ElementRef, Input, ViewChild } from '@angular/core' -import { Video, VideoDetails } from '@app/shared/shared-main' +import { VideoDetails } from '@app/shared/shared-main' import { VideoPlaylist } from '@app/shared/shared-video-playlist' import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { VideoCaption } from '@shared/models' -import { buildPlaylistLink, buildVideoLink, buildVideoOrPlaylistEmbed } from '../../../assets/player/utils' +import { + buildPlaylistLink, + buildVideoLink, + buildVideoOrPlaylistEmbed, + decoratePlaylistLink, + decorateVideoLink +} from '../../../assets/player/utils' type Customizations = { startAtCheckbox: boolean @@ -83,34 +89,34 @@ export class VideoShareComponent { } getVideoIframeCode () { - const options = this.getVideoOptions(this.video.embedUrl) + const embedUrl = decorateVideoLink({ url: this.video.embedUrl, ...this.getVideoOptions() }) - const embedUrl = buildVideoLink(options) return buildVideoOrPlaylistEmbed(embedUrl, this.video.name) } getPlaylistIframeCode () { - const options = this.getPlaylistOptions(this.playlist.embedUrl) + const embedUrl = decoratePlaylistLink({ url: this.playlist.embedUrl, ...this.getPlaylistOptions() }) - const embedUrl = buildPlaylistLink(options) return buildVideoOrPlaylistEmbed(embedUrl, this.playlist.displayName) } getVideoUrl () { - let baseUrl = this.customizations.originUrl ? this.video.originInstanceUrl : window.location.origin - baseUrl += Video.buildWatchUrl(this.video) + const baseUrl = this.customizations.originUrl + ? this.video.originInstanceUrl + : window.location.origin - const options = this.getVideoOptions(baseUrl) + return decorateVideoLink({ + url: buildVideoLink(this.video, baseUrl), - return buildVideoLink(options) + ...this.getVideoOptions() + }) } getPlaylistUrl () { - const base = window.location.origin + VideoPlaylist.buildWatchUrl(this.playlist) + const url = buildPlaylistLink(this.playlist) + if (!this.includeVideoInPlaylist) return url - if (!this.includeVideoInPlaylist) return base - - return base + '?playlistPosition=' + this.playlistPosition + return decoratePlaylistLink({ url, playlistPosition: this.playlistPosition }) } notSecure () { @@ -133,10 +139,8 @@ export class VideoShareComponent { } } - private getVideoOptions (baseUrl?: string) { + private getVideoOptions () { return { - baseUrl, - startTime: this.customizations.startAtCheckbox ? this.customizations.startAt : undefined, stopTime: this.customizations.stopAtCheckbox ? this.customizations.stopAt : undefined, diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index b071a0938..6f0b804cd 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts @@ -33,13 +33,14 @@ import { getStoredP2PEnabled } from './peertube-player-local-storage' import { NextPreviousVideoButtonOptions, P2PMediaLoaderPluginOptions, + PeerTubeLinkButtonOptions, PlaylistPluginOptions, UserWatching, VideoJSCaption, VideoJSPluginOptions } from './peertube-videojs-typings' import { TranslationsManager } from './translations-manager' -import { buildVideoLink, buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils' +import { buildVideoLink, buildVideoOrPlaylistEmbed, decorateVideoLink, getRtcConfig, isIOS, isSafari } from './utils' // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) (videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed' @@ -110,6 +111,7 @@ export interface CommonOptions extends CustomizationOptions { videoCaptions: VideoJSCaption[] videoUUID: string + videoShortUUID: string userWatching?: UserWatching @@ -175,7 +177,13 @@ export class PeertubePlayerManager { PeertubePlayerManager.alreadyPlayed = true }) - self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle) + self.addContextMenu({ + mode, + player, + videoShortUUID: options.common.videoShortUUID, + videoEmbedUrl: options.common.embedUrl, + videoEmbedTitle: options.common.embedTitle + }) player.bezels() player.stats({ @@ -218,7 +226,13 @@ export class PeertubePlayerManager { videojs(newVideoElement, videojsOptions, function (this: videojs.Player) { const player = this - self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle) + self.addContextMenu({ + mode, + player, + videoShortUUID: options.common.videoShortUUID, + videoEmbedUrl: options.common.embedUrl, + videoEmbedTitle: options.common.embedTitle + }) PeertubePlayerManager.onPlayerChange(player) }) @@ -295,6 +309,8 @@ export class PeertubePlayerManager { controlBar: { children: this.getControlBarChildren(mode, { + videoShortUUID: commonOptions.videoShortUUID, + captions: commonOptions.captions, peertubeLink: commonOptions.peertubeLink, theaterButton: commonOptions.theaterButton, @@ -409,6 +425,8 @@ export class PeertubePlayerManager { } private static getControlBarChildren (mode: PlayerMode, options: { + videoShortUUID: string + peertubeLink: boolean theaterButton: boolean captions: boolean @@ -497,7 +515,7 @@ export class PeertubePlayerManager { if (options.peertubeLink === true) { Object.assign(children, { - 'peerTubeLinkButton': {} + 'peerTubeLinkButton': { shortUUID: options.videoShortUUID } as PeerTubeLinkButtonOptions }) } @@ -514,7 +532,15 @@ export class PeertubePlayerManager { return children } - private static addContextMenu (mode: PlayerMode, player: videojs.Player, videoEmbedUrl: string, videoEmbedTitle: string) { + private static addContextMenu (options: { + mode: PlayerMode + player: videojs.Player + videoShortUUID: string + videoEmbedUrl: string + videoEmbedTitle: string + }) { + const { mode, player, videoEmbedTitle, videoEmbedUrl, videoShortUUID } = options + const content = () => { const isLoopEnabled = player.options_['loop'] const items = [ @@ -528,13 +554,15 @@ export class PeertubePlayerManager { { label: player.localize('Copy the video URL'), listener: function () { - copyToClipboard(buildVideoLink()) + copyToClipboard(buildVideoLink({ shortUUID: videoShortUUID })) } }, { label: player.localize('Copy the video URL at the current time'), listener: function (this: videojs.Player) { - copyToClipboard(buildVideoLink({ startTime: this.currentTime() })) + const url = buildVideoLink({ shortUUID: videoShortUUID }) + + copyToClipboard(decorateVideoLink({ url, startTime: this.currentTime() })) } }, { diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index 8afb424a7..d3c75990b 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts @@ -132,6 +132,10 @@ type NextPreviousVideoButtonOptions = { isDisabled: () => boolean } +type PeerTubeLinkButtonOptions = { + shortUUID: string +} + type WebtorrentPluginOptions = { playerElement: HTMLVideoElement @@ -225,5 +229,6 @@ export { VideoJSPluginOptions, LoadedQualityData, QualityLevelRepresentation, + PeerTubeLinkButtonOptions, QualityLevels } diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts index 2bb70d1fa..eb9302493 100644 --- a/client/src/assets/player/utils.ts +++ b/client/src/assets/player/utils.ts @@ -1,4 +1,4 @@ -import { VideoFile } from '@shared/models' +import { Video, VideoFile, VideoPlaylist } from '@shared/models' import { escapeHTML } from '@shared/core-utils/renderer' function toTitleCase (str: string) { @@ -43,8 +43,24 @@ function isMobile () { return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) } -function buildVideoLink (options: { - baseUrl?: string +function buildPlaylistLink (playlist: Pick, base?: string) { + return (base ?? window.location.origin) + '/w/p/' + playlist.shortUUID +} + +function buildVideoLink (video: Pick, base?: string) { + return (base ?? window.location.origin) + '/w/' + video.shortUUID +} + +function buildPlaylistEmbedLink (playlist: Pick, base?: string) { + return (base ?? window.location.origin) + '/video-playlists/embed/' + playlist.uuid +} + +function buildVideoEmbedLink (video: Pick, base?: string) { + return (base ?? window.location.origin) + '/videos/embed/' + video.uuid +} + +function decorateVideoLink (options: { + url: string startTime?: number stopTime?: number @@ -60,12 +76,8 @@ function buildVideoLink (options: { warningTitle?: boolean controls?: boolean peertubeLink?: boolean -} = {}) { - const { baseUrl } = options - - const url = baseUrl - ? baseUrl - : window.location.origin + window.location.pathname.replace('/embed/', '/w/') +}) { + const { url } = options const params = generateParams(window.location.search) @@ -92,16 +104,12 @@ function buildVideoLink (options: { return buildUrl(url, params) } -function buildPlaylistLink (options: { - baseUrl?: string +function decoratePlaylistLink (options: { + url: string playlistPosition?: number }) { - const { baseUrl } = options - - const url = baseUrl - ? baseUrl - : window.location.origin + window.location.pathname.replace('/video-playlists/embed/', '/w/p/') + const { url } = options const params = generateParams(window.location.search) @@ -224,8 +232,14 @@ export { timeToInt, secondsToTime, isWebRTCDisabled, + buildPlaylistLink, buildVideoLink, + decorateVideoLink, + decoratePlaylistLink, + buildPlaylistEmbedLink, + buildVideoEmbedLink, + buildVideoOrPlaylistEmbed, videoFileMaxByResolution, videoFileMinByResolution, diff --git a/client/src/assets/player/videojs-components/peertube-link-button.ts b/client/src/assets/player/videojs-components/peertube-link-button.ts index e73c95900..f47c165d9 100644 --- a/client/src/assets/player/videojs-components/peertube-link-button.ts +++ b/client/src/assets/player/videojs-components/peertube-link-button.ts @@ -1,11 +1,13 @@ -import { buildVideoLink } from '../utils' import videojs from 'video.js' +import { PeerTubeLinkButtonOptions } from '../peertube-videojs-typings' +import { buildVideoLink, decorateVideoLink } from '../utils' const Button = videojs.getComponent('Button') class PeerTubeLinkButton extends Button { + private shortUUID: string - constructor (player: videojs.Player, options?: videojs.ComponentOptions) { - super(player, options) + constructor (player: videojs.Player, options?: PeerTubeLinkButtonOptions) { + super(player, options as any) } createEl () { @@ -13,7 +15,7 @@ class PeerTubeLinkButton extends Button { } updateHref () { - this.el().setAttribute('href', buildVideoLink({ startTime: this.player().currentTime() })) + this.el().setAttribute('href', this.buildLink()) } handleClick () { @@ -22,7 +24,7 @@ class PeerTubeLinkButton extends Button { private buildElement () { const el = videojs.dom.createEl('a', { - href: buildVideoLink(), + href: this.buildLink(), innerHTML: 'PeerTube', title: this.player().localize('Video page (new window)'), className: 'vjs-peertube-link', @@ -33,6 +35,12 @@ class PeerTubeLinkButton extends Button { return el as HTMLButtonElement } + + private buildLink () { + const url = buildVideoLink({ shortUUID: this.shortUUID }) + + return decorateVideoLink({ url, startTime: this.player().currentTime() }) + } } videojs.registerComponent('PeerTubeLinkButton', PeerTubeLinkButton) diff --git a/shared/core-utils/miscs/date.ts b/shared/core-utils/common/date.ts similarity index 100% rename from shared/core-utils/miscs/date.ts rename to shared/core-utils/common/date.ts diff --git a/shared/core-utils/miscs/index.ts b/shared/core-utils/common/index.ts similarity index 82% rename from shared/core-utils/miscs/index.ts rename to shared/core-utils/common/index.ts index 7764e69ad..83f2ccbb6 100644 --- a/shared/core-utils/miscs/index.ts +++ b/shared/core-utils/common/index.ts @@ -1,4 +1,5 @@ export * from './date' export * from './miscs' -export * from './types' export * from './regexp' +export * from './types' +export * from './url diff --git a/shared/core-utils/miscs/miscs.ts b/shared/core-utils/common/miscs.ts similarity index 100% rename from shared/core-utils/miscs/miscs.ts rename to shared/core-utils/common/miscs.ts diff --git a/shared/core-utils/miscs/regexp.ts b/shared/core-utils/common/regexp.ts similarity index 100% rename from shared/core-utils/miscs/regexp.ts rename to shared/core-utils/common/regexp.ts diff --git a/shared/core-utils/miscs/types.ts b/shared/core-utils/common/types.ts similarity index 100% rename from shared/core-utils/miscs/types.ts rename to shared/core-utils/common/types.ts diff --git a/shared/core-utils/common/url.ts b/shared/core-utils/common/url.ts new file mode 100644 index 000000000..e69de29bb diff --git a/shared/core-utils/index.ts b/shared/core-utils/index.ts index 42d7cab1d..0b05dc9eb 100644 --- a/shared/core-utils/index.ts +++ b/shared/core-utils/index.ts @@ -1,7 +1,7 @@ export * from './abuse' +export * from './common' export * from './i18n' export * from './logs' -export * from './miscs' export * from './plugins' export * from './renderer' export * from './users'