Skip to content

Commit

Permalink
rebasing changes into feature branch (#34)
Browse files Browse the repository at this point in the history
* feat: Use Do Not Track for Vimeo service (#31)

https://vimeo.zendesk.com/hc/en-us/articles/360001494447-Player-parameters-overview

* Some minor cleanups (#32)

* fix: Do not leak comment tags to HTML

* feat: Clean up z-index hacks

There were a lot of unnessecary z-index rules, cleaning up the DOM should avoid them

* feat: avoid using z-index at all

Since z-index can collide with other elements outside of the embed

* feat: init styles clean up

There should be an init style before consent styles are loaded

* feat: Use data attribute instead of class in HTML

Putting services as class names might run into conflict with other styles on a wiki
For example, the wiki might have another element with the class name youtube
This should help mitigate it

* feat: add Spotify oembed integration

* docs: Add notes on Bilibili and Niconico API

* refactor: Update oembed calls

Add an optional config dict for accessing info endpoint data

Soundcloud Oembed seems fine, tested with https://soundcloud.com/oembed?format=json&url=https://soundcloud.com/turbokevin/turbokevin-chase-the-sun

Co-authored-by: Hannes <[email protected]>

Co-authored-by: Hannes <[email protected]>
  • Loading branch information
alistair3149 and octfx authored Oct 17, 2022
1 parent 463dfbe commit e62ab84
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 48 deletions.
31 changes: 17 additions & 14 deletions includes/EmbedService/EmbedHtmlFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static function toHtml( AbstractEmbedService $service, array $config = []
'class' => 'embedvideo thumbinner',
'style' => '',
'innerClass' => 'embedvideowrap',
'service' => '',
'withConsent' => false,
'description' => '',
],
Expand All @@ -54,12 +55,12 @@ public static function toHtml( AbstractEmbedService $service, array $config = []
: '';

$template = <<<HTML
<div class="thumb %s" style="width: %dpx;"><!--
--><div class="%s" style="%s"><!--
--><div class="%s" style="width: %dpx">%s%s</div>%s<!--
--></div><!--
--></div>
HTML;
<div class="thumb %s" style="width: %dpx;">
<div class="%s" style="%s">
<div class="%s" data-service="%s" style="width: %dpx">%s%s</div>%s
</div>
</div>
HTML;

return sprintf(
$template,
Expand All @@ -68,6 +69,7 @@ public static function toHtml( AbstractEmbedService $service, array $config = []
$config['class'] ?? '',
$config['style'] ?? '',
$config['innerClass'] ?? '',
$config['service'] ?? '',
$width,
( $config['withConsent'] ?? false ) === true ? self::makeConsentContainerHtml( $service ) : '',
$service,
Expand Down Expand Up @@ -133,10 +135,10 @@ public static function makeThumbHtml( AbstractEmbedService $service ): string {

// phpcs:disable
return <<<HTML
<picture class="embedvideo-consent__thumbnail"><!--
--><img src="{$url}" loading="lazy" class="embedvideo-consent__thumbnail__image" alt="Thumbnail for {$service->getTitle()}"/><!--
--></picture>
HTML;
<picture class="embedvideo-consent__thumbnail">
<img src="{$url}" loading="lazy" class="embedvideo-consent__thumbnail__image" alt="Thumbnail for {$service->getTitle()}"/>
</picture>
HTML;
// phpcs:enable
} catch ( Exception $e ) {
return '';
Expand Down Expand Up @@ -165,7 +167,7 @@ public static function makeTitleHtml( AbstractEmbedService $service ): string {
*/
public static function makeConsentContainerHtml( AbstractEmbedService $service ): string {
$template = <<<HTML
<div class="embedvideo-consent" data-show-privacy-notice="%s"><!--
<div class="embedvideo-consent" data-show-privacy-notice="%s">%s<!--
--><div class="embedvideo-consent__overlay%s">%s<!--
--><div class="embedvideo-consent__message"><!--
-->%s<!--
Expand All @@ -178,7 +180,7 @@ public static function makeConsentContainerHtml( AbstractEmbedService $service )
--><span class="embedvideo-consent__dismiss">%s</span><!--
--></div><!--
--></div><!--
--></div>%s<!--
--></div><!--
--></div>
HTML;

Expand All @@ -198,6 +200,8 @@ public static function makeConsentContainerHtml( AbstractEmbedService $service )
$template,
// data-show-privacy-notice
$showPrivacyNotice,
// thumbnail
self::makeThumbHtml( $service ),
// __overlay class
$titleHtml !== '' ? ' embedvideo-consent__overlay--hastitle' : '',
// __title
Expand All @@ -215,8 +219,7 @@ public static function makeConsentContainerHtml( AbstractEmbedService $service )
// Continue
( new Message( 'embedvideo-consent-privacy-notice-continue' ) )->text(),
// Dismiss
( new Message( 'embedvideo-consent-privacy-notice-dismiss' ) )->text(),
self::makeThumbHtml( $service )
( new Message( 'embedvideo-consent-privacy-notice-dismiss' ) )->text()
);
}

Expand Down
2 changes: 1 addition & 1 deletion includes/EmbedService/Vimeo.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ final class Vimeo extends AbstractEmbedService {
* @inheritDoc
*/
public function getBaseUrl(): string {
return '//player.vimeo.com/video/%1$s';
return '//player.vimeo.com/video/%1$s?dnt=true';
}

/**
Expand Down
3 changes: 2 additions & 1 deletion includes/EmbedVideo.php
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,10 @@ private function makeHtmlFormatConfig( $embedService, $addClass = null ): array
$styleString = '';
$innerClassString = implode( ' ', array_filter( [
'embedvideowrap',
$embedService::getServiceName(),
// This should probably be added as a RL variable
$this->config->get( 'EmbedVideoFetchExternalThumbnails' ) ? '' : 'no-fetch'
] ) );
$serviceString = $embedService::getServiceName();
$outerClassString = 'embedvideo ';

if ( $this->container === 'frame' ) {
Expand All @@ -470,6 +470,7 @@ private function makeHtmlFormatConfig( $embedService, $addClass = null ): array
'class' => $classString,
'style' => $styleString,
'innerClass' => $innerClassString,
'service' => $serviceString,
// phpcs:ignore Generic.Files.LineLength.TooLong
'withConsent' => !( $this->service instanceof OEmbedServiceInterface ) && $this->config->get( 'EmbedVideoRequireConsent' ),
'description' => $this->description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public function toHtml( $options = [] ): string {

return EmbedHtmlFormatter::toHtml( $service, [
'outerClass' => 'embedvideo local-embed',
'service' => 'local-embed',
'withConsent' => true,
'description' => $this->parameters['description'] ?? null,
] );
Expand Down
80 changes: 59 additions & 21 deletions resources/ext.embedVideo.consent.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@
(function () {
const fetchThumb = async (url, parent, outerDiv) => {
let callUrl;
if (outerDiv.classList.contains('youtube') || outerDiv.classList.contains('youtubevideolist') || outerDiv.classList.contains('youtubeplaylist')) {
callUrl = 'https://www.youtube-nocookie.com/oembed?url=https://www.youtube.com/watch?v=';
} else if(outerDiv.classList.contains('vimeo')) {
callUrl = 'https://vimeo.com/api/oembed.json?url=https://vimeo.com/'
} else if(outerDiv.classList.contains('spotifytrack')) {
// does not work callUrl = 'https://open.spotify.com/oembed?url=https://open.spotify.com/track/'
return;
} else {
return;
/**
* An optional configuration dict for accessing data from the 'info' endpoint for titles and thumbnails
* @type {{dataKey: null, titleKey: string, thumbnailKey: string}}
*/
const dataConfig = {
'dataKey': null,
'titleKey': 'title',
'thumbnailKey': 'thumbnail_url',
}

switch( outerDiv.getAttribute('data-service') ) {
case 'bilibili':
// Not Oembed
callUrl = 'https://api.bilibili.com/x/web-interface/view?bvid=';
dataConfig['dataKey'] = 'data';
dataConfig['thumbnailKey'] = 'pic';
break;
case 'niconico':
// Not Oembed
// The official API is in XML sadly
//callUrl = 'https://ext.nicovideo.jp/api/getthumbinfo/';
break;
case 'soundcloud':
callUrl = 'https://soundcloud.com/oembed?format=json&url=';
break;
case 'spotifyalbum':
callUrl = 'https://open.spotify.com/oembed?url=https://open.spotify.com/album/';
break;
case 'spotifyartist':
callUrl = 'https://open.spotify.com/oembed?url=https://open.spotify.com/artist/';
break;
case 'spotifytrack':
callUrl = 'https://open.spotify.com/oembed?url=https://open.spotify.com/track/';
break;
case 'vimeo':
callUrl = 'https://vimeo.com/api/oembed.json?url=https://vimeo.com/';
break;
case 'youtube':
case 'youtubevideolist':
case 'youtubeplaylist':
callUrl = 'https://www.youtube-nocookie.com/oembed?url=https://www.youtube.com/watch?v=';
break;
}

// Some url manipulation foo which tries to get the id of the requested video
if (url.substr(0, 1) === '/') {
if (url.substring(0, 1) === '/') {
url = 'http:' + url;
}

Expand All @@ -29,8 +62,8 @@
return;
}

if (id.substr(-1) === '?') {
id = id.substr(0, id.length - 1)
if (id.substring(-1) === '?') {
id = id.substring(0, id.length - 1)
}

// Do the actual fetch
Expand All @@ -42,25 +75,30 @@
return result.json();
})
.then(json => {
if (typeof json.thumbnail_url === 'undefined' || parent.querySelectorAll('.embedvideo-consent__thumbnail').length > 0) {
if (dataConfig.dataKey !== null) {
json = json[dataConfig.dataKey];
}

if (typeof json[dataConfig.thumbnailKey] === 'undefined' || parent.querySelectorAll('.embedvideo-consent__thumbnail').length > 0) {
return;
}

const picture = document.createElement('picture'),
const
overlay = parent.querySelector('.embedvideo-consent__overlay'),
picture = document.createElement('picture'),
image = document.createElement('img');

picture.classList.add('embedvideo-consent__thumbnail');
image.src = json.thumbnail_url;
image.src = json[dataConfig.thumbnailKey];
image.setAttribute('loading', 'lazy');
image.classList.add('embedvideo-consent__thumbnail__image');
picture.appendChild(image);
parent.appendChild(picture);
picture.append(image);
parent.prepend(picture);

if (typeof json.title !== 'undefined' && json.title.length > 0) {
const title = document.createElement('div'),
overlay = parent.querySelector('.embedvideo-consent__overlay');
if (typeof json[dataConfig.titleKey] !== 'undefined' && json[dataConfig.titleKey].length > 0) {
const title = document.createElement('div');
title.classList.add('embedvideo-consent__title');
title.innerText = json.title;
title.innerText = json[dataConfig.titleKey];
overlay.classList.add('embedvideo-consent__overlay--hastitle');
overlay.prepend(title);
}
Expand Down
12 changes: 1 addition & 11 deletions resources/ext.embedVideo.consent.less
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
.embedvideo-consent {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
background-color: #eaecf0;

.hidden,
&.hidden {
display: none;
}

&__overlay {
cursor: pointer;
z-index: 1;
color: #54595d;
display: flex;
justify-content: center;
Expand All @@ -35,7 +25,6 @@
width: inherit;
height: inherit;
position: absolute;
z-index: -1;
transition: opacity 250ms ease;
}
}
Expand All @@ -54,6 +43,7 @@
}

&__message {
position: absolute;
border: 1px solid currentColor;
margin: 1rem;
padding: 0.5rem 1rem;
Expand Down
16 changes: 16 additions & 0 deletions resources/ext.embedVideo.styles.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
.embedvideo {
// Act as placeholder styles
&-consent {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
background-color: #eaecf0;

&__overlay {
// Hide until ready
display: none;
}
}

&.tcenter,
&.ev_center,
&.ev_center > .embedvideowrap {
Expand Down

0 comments on commit e62ab84

Please sign in to comment.