mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-06 03:50:26 +02:00
Improve NSFW warning in player
This commit is contained in:
parent
f2556d80e3
commit
ee96cf3a19
10 changed files with 249 additions and 138 deletions
|
@ -13,6 +13,7 @@ my-select-checkbox {
|
|||
.playlists {
|
||||
.pt-badge {
|
||||
max-width: 200px;
|
||||
vertical-align: bottom;
|
||||
|
||||
@include ellipsis;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,9 @@
|
|||
--header-fg: #{pvar(--fg)};
|
||||
--header-bg: #{pvar(--bg)};
|
||||
|
||||
--player-overlay-fg: #{pvar(--fg-400)};
|
||||
--player-overlay-bg: #{pvar(--bg-secondary-400)};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
--tmp-header-height: #{$header-height};
|
||||
|
|
|
@ -204,7 +204,9 @@ $variables: (
|
|||
--alert-primary-bg: var(--alert-primary-bg),
|
||||
--alert-primary-border-color: var(--alert-primary-border-color),
|
||||
--embed-fg: var(--embed-fg),
|
||||
--embed-big-play-bg: var(--embed-big-play-bg)
|
||||
--embed-big-play-bg: var(--embed-big-play-bg),
|
||||
--player-overlay-fg: var(--player-overlay-fg),
|
||||
--player-overlay-bg: var(--player-overlay-bg)
|
||||
);
|
||||
|
||||
// SASS type check our CSS variables
|
||||
|
|
|
@ -20,7 +20,7 @@ import './shared/control-bar/theater-button'
|
|||
import './shared/control-bar/time-tooltip'
|
||||
import './shared/dock/peertube-dock-component'
|
||||
import './shared/dock/peertube-dock-plugin'
|
||||
import './shared/nsfw/peertube-nsfw-component'
|
||||
import './shared/nsfw/peertube-nsfw-info-component'
|
||||
import './shared/nsfw/peertube-nsfw-plugin'
|
||||
import './shared/hotkeys/peertube-hotkeys-plugin'
|
||||
import './shared/metrics/metrics-plugin'
|
||||
|
|
|
@ -1,49 +1,54 @@
|
|||
@use 'sass:math';
|
||||
@use '_variables' as *;
|
||||
@use '_mixins' as *;
|
||||
@use '_icons' as *;
|
||||
@use './_player-variables' as *;
|
||||
@use "sass:math";
|
||||
@use "_variables" as *;
|
||||
@use "_mixins" as *;
|
||||
@use "_icons" as *;
|
||||
@use "./_player-variables" as *;
|
||||
|
||||
.video-js.vjs-peertube-skin {
|
||||
--container-margin-x: 20px;
|
||||
--container-margin-y: 20px;
|
||||
--nsfw-info-margin-x: 20px;
|
||||
--nsfw-info-margin-y: 20px;
|
||||
--nsfw-font-size: 13px;
|
||||
|
||||
&.vjs-size-570 {
|
||||
--container-margin-x: 10px;
|
||||
--container-margin-y: 10px;
|
||||
}
|
||||
|
||||
.nsfw-container {
|
||||
font-size: 14px;
|
||||
position: absolute;
|
||||
top: var(--container-margin-y);
|
||||
right: var(--container-margin-x);
|
||||
width: 100%;
|
||||
width: fit-content;
|
||||
background-color: pvar(--bg-secondary-500);
|
||||
color: pvar(--fg-400);
|
||||
max-width: calc(40% - 2 * var(--container-margin-x));
|
||||
max-height: calc(100% - 2 * var(--container-margin-y));
|
||||
padding: 1rem;;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
|
||||
.nsfw-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: $font-bold;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
button,
|
||||
.nsfw-more-flags,
|
||||
.nsfw-more-summary {
|
||||
margin-top: 0.75rem;
|
||||
font-size: 13px;
|
||||
--nsfw-info-margin-x: 10px;
|
||||
--nsfw-info-margin-y: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nsfw-info,
|
||||
.nsfw-details {
|
||||
width: 100%;
|
||||
width: fit-content;
|
||||
background-color: pvar(--player-overlay-bg);
|
||||
color: pvar(--player-overlay-fg);
|
||||
max-width: calc(40% - 2 * var(--nsfw-info-margin-x));
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// NSFW info
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
.nsfw-info {
|
||||
position: absolute;
|
||||
top: var(--nsfw-info-margin-y);
|
||||
right: var(--nsfw-info-margin-x);
|
||||
max-height: calc(100% - 2 * var(--nsfw-info-margin-y));
|
||||
|
||||
font-size: var(--nsfw-font-size);
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0;
|
||||
color: pvar(--fg-450);
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
|
@ -55,20 +60,63 @@
|
|||
@include margin-left(5px);
|
||||
}
|
||||
}
|
||||
|
||||
.nsfw-more-content {
|
||||
strong {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.peertube-dock {
|
||||
.nsfw-container {
|
||||
.nsfw-info {
|
||||
top: unset;
|
||||
bottom: var(--container-margin-y);
|
||||
bottom: var(--nsfw-info-margin-y);
|
||||
max-width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// NSFW details
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
.nsfw-details-container {
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.nsfw-details {
|
||||
margin-left: auto;
|
||||
height: 100%;
|
||||
|
||||
.nsfw-details-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
line-height: 1.5;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.nsfw-details-flags + .nsfw-details-summary {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.nsfw-details-close {
|
||||
mask-image: url("./svg/x.svg");
|
||||
-webkit-mask-image: url("./svg/x.svg");
|
||||
mask-size: cover;
|
||||
-webkit-mask-size: cover;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: pvar(--player-overlay-fg);
|
||||
display: block;
|
||||
|
||||
@include margin-left(auto);
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
import { NSFWFlag } from '@peertube/peertube-models'
|
||||
import videojs from 'video.js'
|
||||
import { type PeerTubeNSFWPluginOptions } from './peertube-nsfw-plugin'
|
||||
|
||||
const Component = videojs.getComponent('Component')
|
||||
|
||||
class PeerTubeNSFWComponent extends Component {
|
||||
declare options_: videojs.ComponentOptions & PeerTubeNSFWPluginOptions
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
constructor (player: videojs.Player, options: videojs.ComponentOptions & PeerTubeNSFWPluginOptions) {
|
||||
super(player, options)
|
||||
}
|
||||
|
||||
createEl () {
|
||||
const el = super.createEl('div', { className: 'nsfw-container' })
|
||||
|
||||
const title = super.createEl('div', { className: 'nsfw-title' })
|
||||
title.textContent = this.player().localize('Sensitive content')
|
||||
|
||||
const content = super.createEl('div', { className: 'nsfw-content' })
|
||||
content.textContent = this.player().localize('This video contains sensitive content.')
|
||||
|
||||
el.appendChild(title)
|
||||
el.appendChild(content)
|
||||
|
||||
if (this.options_.flags || this.options_.summary) {
|
||||
const moreButton = super.createEl(
|
||||
'button',
|
||||
{ textContent: this.player().localize('Learn more') },
|
||||
{ type: 'button' }
|
||||
) as HTMLButtonElement
|
||||
|
||||
el.appendChild(moreButton)
|
||||
|
||||
moreButton.addEventListener('click', () => {
|
||||
this.appendMoreContent()
|
||||
|
||||
moreButton.style.display = 'none'
|
||||
})
|
||||
}
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
private appendMoreContent () {
|
||||
const moreContentEl = super.createEl('div', { className: 'nsfw-more-content' })
|
||||
|
||||
if (this.options_.flags) {
|
||||
const moreContentFlags = super.createEl('div', { className: 'nsfw-more-flags' })
|
||||
moreContentFlags.appendChild(super.createEl('strong', { textContent: this.player().localize('Content warning') }))
|
||||
moreContentFlags.appendChild(super.createEl('div', { textContent: this.buildFlagStrings().join(' - ') }))
|
||||
|
||||
moreContentEl.appendChild(moreContentFlags)
|
||||
}
|
||||
|
||||
if (this.options_.summary) {
|
||||
const moreContentSummary = super.createEl('div', { className: 'nsfw-more-summary' })
|
||||
moreContentSummary.appendChild(super.createEl('strong', { textContent: `Author note` }))
|
||||
moreContentSummary.appendChild(super.createEl('div', { textContent: this.options_.summary }))
|
||||
|
||||
moreContentEl.appendChild(moreContentSummary)
|
||||
}
|
||||
|
||||
this.el().appendChild(moreContentEl)
|
||||
}
|
||||
|
||||
private buildFlagStrings () {
|
||||
const flags = this.options_.flags
|
||||
const flagStrings: string[] = []
|
||||
|
||||
if ((flags & NSFWFlag.VIOLENT) === NSFWFlag.VIOLENT) {
|
||||
flagStrings.push(this.player().localize(`Violence`))
|
||||
}
|
||||
|
||||
if ((flags & NSFWFlag.EXPLICIT_SEX) === NSFWFlag.EXPLICIT_SEX) {
|
||||
flagStrings.push(this.player().localize(`Explicit Sex`))
|
||||
}
|
||||
|
||||
return flagStrings
|
||||
}
|
||||
}
|
||||
|
||||
videojs.registerComponent('PeerTubeNSFWComponent', PeerTubeNSFWComponent)
|
||||
|
||||
export {
|
||||
PeerTubeNSFWComponent
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
import { NSFWFlag } from '@peertube/peertube-models'
|
||||
import videojs from 'video.js'
|
||||
import { type PeerTubeNSFWPluginOptions } from './peertube-nsfw-plugin'
|
||||
|
||||
const Component = videojs.getComponent('Component')
|
||||
|
||||
class PeerTubeNSFWDetailsComponent extends Component {
|
||||
declare options_: videojs.ComponentOptions & PeerTubeNSFWPluginOptions
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
constructor (player: videojs.Player, options: videojs.ComponentOptions & PeerTubeNSFWPluginOptions) {
|
||||
super(player, options)
|
||||
}
|
||||
|
||||
createEl () {
|
||||
// Overlay
|
||||
const el = super.createEl('div', { className: 'nsfw-details-container' })
|
||||
|
||||
const nsfwDetails = super.createEl('div', { className: 'nsfw-details' })
|
||||
el.appendChild(nsfwDetails)
|
||||
|
||||
const closeButton = super.createEl('button', {
|
||||
className: 'nsfw-details-close',
|
||||
title: this.player().localize('Close details'),
|
||||
type: 'button'
|
||||
}) as HTMLButtonElement
|
||||
|
||||
closeButton.addEventListener('click', () => {
|
||||
this.trigger('hideDetails')
|
||||
})
|
||||
|
||||
nsfwDetails.appendChild(closeButton)
|
||||
|
||||
const content = super.createEl('div', { className: 'nsfw-details-content' })
|
||||
nsfwDetails.appendChild(content)
|
||||
|
||||
if (this.options_.flags) {
|
||||
const flags = super.createEl('div', { className: 'nsfw-details-flags' })
|
||||
|
||||
const label = super.createEl('strong', { textContent: this.player().localize('This video contains sensitive content, including:') })
|
||||
flags.appendChild(label)
|
||||
|
||||
flags.appendChild(super.createEl('div', { textContent: this.buildFlagStrings().join(' - ') }))
|
||||
|
||||
content.appendChild(flags)
|
||||
}
|
||||
|
||||
if (this.options_.summary) {
|
||||
const summary = super.createEl('div', { className: 'nsfw-details-summary' })
|
||||
|
||||
const label = super.createEl('strong', { textContent: this.player().localize('Uploader note:') })
|
||||
summary.appendChild(label)
|
||||
|
||||
summary.appendChild(super.createEl('div', { textContent: this.options_.summary }))
|
||||
|
||||
content.appendChild(summary)
|
||||
}
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
private buildFlagStrings () {
|
||||
const flags = this.options_.flags
|
||||
const flagStrings: string[] = []
|
||||
|
||||
if ((flags & NSFWFlag.VIOLENT) === NSFWFlag.VIOLENT) {
|
||||
flagStrings.push(this.player().localize(`Potentially violent content`))
|
||||
}
|
||||
|
||||
if ((flags & NSFWFlag.EXPLICIT_SEX) === NSFWFlag.EXPLICIT_SEX) {
|
||||
flagStrings.push(this.player().localize(`Potentially sexually explicit content`))
|
||||
}
|
||||
|
||||
return flagStrings
|
||||
}
|
||||
}
|
||||
|
||||
videojs.registerComponent('PeerTubeNSFWDetailsComponent', PeerTubeNSFWDetailsComponent)
|
||||
|
||||
export {
|
||||
PeerTubeNSFWDetailsComponent
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import videojs from 'video.js'
|
||||
import { type PeerTubeNSFWPluginOptions } from './peertube-nsfw-plugin'
|
||||
|
||||
const Component = videojs.getComponent('Component')
|
||||
|
||||
class PeerTubeNSFWInfoComponent extends Component {
|
||||
declare options_: videojs.ComponentOptions & PeerTubeNSFWPluginOptions
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
constructor (player: videojs.Player, options: videojs.ComponentOptions & PeerTubeNSFWPluginOptions) {
|
||||
super(player, options)
|
||||
}
|
||||
|
||||
createEl () {
|
||||
const el = super.createEl('div', { className: 'nsfw-info' })
|
||||
|
||||
const content = super.createEl('strong')
|
||||
content.textContent = this.player().localize('This video contains sensitive content.')
|
||||
el.appendChild(content)
|
||||
|
||||
if (this.options_.flags || this.options_.summary) {
|
||||
const moreButton = super.createEl(
|
||||
'button',
|
||||
{ textContent: this.player().localize('Learn more') },
|
||||
{ type: 'button' }
|
||||
) as HTMLButtonElement
|
||||
|
||||
el.appendChild(moreButton)
|
||||
|
||||
moreButton.addEventListener('click', () => {
|
||||
this.trigger('showDetails')
|
||||
})
|
||||
}
|
||||
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
||||
videojs.registerComponent('PeerTubeNSFWInfoComponent', PeerTubeNSFWInfoComponent)
|
||||
|
||||
export {
|
||||
PeerTubeNSFWInfoComponent
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import videojs from 'video.js'
|
||||
import { PeerTubeNSFWComponent } from './peertube-nsfw-component'
|
||||
import { PeerTubeNSFWInfoComponent } from './peertube-nsfw-info-component'
|
||||
import { PeerTubeNSFWDetailsComponent } from './peertube-nsfw-details-component'
|
||||
|
||||
const Plugin = videojs.getPlugin('plugin')
|
||||
|
||||
|
@ -9,7 +10,8 @@ export type PeerTubeNSFWPluginOptions = {
|
|||
}
|
||||
|
||||
class PeerTubeNSFWPlugin extends Plugin {
|
||||
declare private nsfwComponent: PeerTubeNSFWComponent
|
||||
declare private nsfwInfoComponent: PeerTubeNSFWInfoComponent
|
||||
declare private nsfwDetailsComponent: PeerTubeNSFWDetailsComponent
|
||||
|
||||
constructor (player: videojs.Player, options: videojs.PlayerOptions & PeerTubeNSFWPluginOptions) {
|
||||
super(player, options)
|
||||
|
@ -17,18 +19,33 @@ class PeerTubeNSFWPlugin extends Plugin {
|
|||
player.ready(() => {
|
||||
player.addClass('peertube-nsfw')
|
||||
|
||||
this.nsfwComponent = new PeerTubeNSFWComponent(player, options)
|
||||
player.addChild(this.nsfwComponent)
|
||||
this.nsfwInfoComponent = new PeerTubeNSFWInfoComponent(player, options)
|
||||
player.addChild(this.nsfwInfoComponent)
|
||||
|
||||
this.nsfwDetailsComponent = new PeerTubeNSFWDetailsComponent(player, options)
|
||||
this.nsfwDetailsComponent.hide()
|
||||
player.addChild(this.nsfwDetailsComponent)
|
||||
|
||||
this.nsfwInfoComponent.on('showDetails', () => {
|
||||
this.nsfwDetailsComponent.show()
|
||||
this.nsfwInfoComponent.hide()
|
||||
})
|
||||
|
||||
this.nsfwDetailsComponent.on('hideDetails', () => {
|
||||
this.nsfwInfoComponent.show()
|
||||
this.nsfwDetailsComponent.hide()
|
||||
})
|
||||
})
|
||||
|
||||
player.one('play', () => {
|
||||
this.nsfwComponent.hide()
|
||||
this.nsfwInfoComponent.hide()
|
||||
})
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.nsfwComponent?.dispose()
|
||||
this.player.removeChild(this.nsfwComponent)
|
||||
this.nsfwInfoComponent?.dispose()
|
||||
this.player.removeChild(this.nsfwInfoComponent)
|
||||
this.player.removeChild(this.nsfwDetailsComponent)
|
||||
this.player.removeClass('peertube-nsfw')
|
||||
|
||||
super.dispose()
|
||||
|
|
|
@ -87,13 +87,16 @@ const playerKeys = {
|
|||
'Audio only': 'Audio only',
|
||||
'Sensitive content': 'Sensitive content',
|
||||
'This video contains sensitive content.': 'This video contains sensitive content.',
|
||||
'This video contains sensitive content, including:': 'This video contains sensitive content, including:',
|
||||
'Learn more': 'Learn more',
|
||||
'Content warning': 'Content warning',
|
||||
'Violence': 'Violence',
|
||||
'Shocking Content': 'Shocking Content',
|
||||
'Explicit Sex': 'Explicit Sex',
|
||||
'Upload speed:': 'Upload speed:',
|
||||
'Download speed:': 'Download speed:'
|
||||
'Download speed:': 'Download speed:',
|
||||
'Uploader note:': 'Uploader note:',
|
||||
'Close': 'Close'
|
||||
}
|
||||
Object.assign(playerKeys, videojs)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue