Skip to content

Commit

Permalink
feat: Start work on evl/vplayer
Browse files Browse the repository at this point in the history
In reference to #69
  • Loading branch information
octfx committed Oct 16, 2023
1 parent 5c8a4fd commit c42adcf
Show file tree
Hide file tree
Showing 13 changed files with 476 additions and 166 deletions.
2 changes: 2 additions & 0 deletions EmbedVideo.i18n.magic.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
$magicWords['en'] = [
'ev' => [ 0, 'ev' ],
'evu' => [ 0, 'evu' ],
'evl' => [ 0, 'evl' ],
'vlink' => [ 0, 'vlink' ],
'ev_start' => [ 0, 'start=$1' ],
'ev_end' => [ 0, 'end=$1' ],
'cover' => [ 0, 'cover=$1' ],
Expand Down
53 changes: 48 additions & 5 deletions extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,58 @@
"embedvideo": "MediaWiki\\Extension\\EmbedVideo\\ApiEmbedVideo"
},
"ResourceModules": {
"ext.embedVideo.messages": {
"messages": [
"embedvideo-service-archiveorg",
"embedvideo-service-bilibili",
"embedvideo-service-dailymotion",
"embedvideo-service-kakaotv",
"embedvideo-service-loom",
"embedvideo-service-navertv",
"embedvideo-service-niconico",
"embedvideo-service-soundcloud",
"embedvideo-service-sharepoint",
"embedvideo-service-spotify",
"embedvideo-service-twitch",
"embedvideo-service-videolink",
"embedvideo-service-vimeo",
"embedvideo-service-youtube",
"embedvideo-service-localvideo",
"embedvideo-service-externalvideo",
"embedvideo-consent-privacy-notice-text",
"embedvideo-consent-privacy-policy"
]
},
"ext.embedVideo.videolink": {
"es6": true,
"packageFiles": [
"ext.embedVideo.videolink.js",
{ "name": "fetchFactory.js", "file": "fetchers/fetchFactory.js" },
{ "name": "queryKeyParser.js", "file": "fetchers/queryKeyParser.js" },
{ "name": "bilibili.js", "file": "fetchers/bilibili.js" },
{ "name": "niconico.js", "file": "fetchers/niconico.js" },
{ "name": "oembed.js", "file": "fetchers/oembed.js" },
{ "name": "iframe.js", "file": "modules/iframe.js" }
],
"styles": [
"ext.embedVideo.consent.less"
],
"position": "top",
"targets": [
"desktop",
"mobile"
]
},
"ext.embedVideo.consent": {
"es6": true,
"packageFiles": [
"ext.embedVideo.consent.js",
{ "name": "fetchFactory.js", "file": "fetchers/fetchFactory.js" },
{ "name": "queryKeyParser.js", "file": "fetchers/queryKeyParser.js" },
{ "name": "bilibili.js", "file": "fetchers/bilibili.js" },
{ "name": "niconico.js", "file": "fetchers/niconico.js" },
{ "name": "oembed.js", "file": "fetchers/oembed.js" }
{ "name": "fetchFactory.js", "file": "fetchers/fetchFactory.js" },
{ "name": "queryKeyParser.js", "file": "fetchers/queryKeyParser.js" },
{ "name": "bilibili.js", "file": "fetchers/bilibili.js" },
{ "name": "niconico.js", "file": "fetchers/niconico.js" },
{ "name": "oembed.js", "file": "fetchers/oembed.js" },
{ "name": "iframe.js", "file": "modules/iframe.js" }
],
"styles": [
"ext.embedVideo.consent.less"
Expand Down
1 change: 1 addition & 0 deletions i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"embedvideo-service-sharepoint": "SharePoint",
"embedvideo-service-spotify": "Spotify",
"embedvideo-service-twitch": "Twitch",
"embedvideo-service-videolink": "Video Link",
"embedvideo-service-vimeo": "Vimeo",
"embedvideo-service-youtube": "YouTube",
"embedvideo-service-localvideo": "Local File",
Expand Down
21 changes: 21 additions & 0 deletions includes/EmbedService/AbstractEmbedService.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Config;
use InvalidArgumentException;
use JsonException;
use MediaTransformOutput;
use MediaWiki\MediaWikiServices;
use RuntimeException;
Expand Down Expand Up @@ -480,6 +481,26 @@ public function getTitle(): ?string {
return $this->title;
}

/**
* @param null|int $width
* @param null|int $height
* @return string
* @throws JsonException
*/
public function getIframeConfig( ?int $width = 0, ?int $height = 0 ): string {
$attributes = [];
if ( !empty( $width ) && $width !== $this->getDefaultWidth() ) {
$attributes['width'] = $width;
}
if ( !empty( $height ) && $height !== $this->getDefaultHeight() ) {
$attributes['height'] = $height;
}

$attributes['src'] = $this->getUrl();

return json_encode( $attributes, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES );
}

/**
* A convenience method generating the final HTML from a service
*
Expand Down
11 changes: 1 addition & 10 deletions includes/EmbedService/EmbedHtmlFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,9 @@ public static function toHtml( AbstractEmbedService $service, array $config = []
->makeConfig( 'EmbedVideo' )
->get( 'EmbedVideoRequireConsent' );
if ( $consent === true ) {
$attributes = [];
if ( $width !== $service->getDefaultWidth() ) {
$attributes['width'] = $width;
}
if ( $height !== $service->getDefaultHeight() ) {
$attributes['height'] = $height;
}

$attributes['src'] = $service->getUrl();
$iframeConfig = sprintf(
"data-iframeconfig='%s'",
json_encode( $attributes, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES )
$service->getIframeConfig( $width, $height )
);
}
} catch ( JsonException | ConfigException $e ) {
Expand Down
4 changes: 4 additions & 0 deletions includes/EmbedService/EmbedServiceFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ final class EmbedServiceFactory {
Twitch::class,
TwitchClip::class,
TwitchVod::class,
VideoLink::class,
Vimeo::class,
YouTube::class,
YouTubeOEmbed::class,
Expand Down Expand Up @@ -117,6 +118,9 @@ public static function newFromName( string $serviceName, string $id ): AbstractE
case 'twitchvod':
return new TwitchVod( $id );

case 'videolink':
return new VideoLink( $id );

case 'vimeo':
return new Vimeo( $id );

Expand Down
18 changes: 18 additions & 0 deletions includes/EmbedService/VideoLink.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare( strict_types=1 );

namespace MediaWiki\Extension\EmbedVideo\EmbedService;

/**
* Service used in empty <vplayer/> elements
*/
final class VideoLink extends AbstractEmbedService {

/**
* @inheritDoc
*/
public function getBaseUrl(): string {
return '';
}
}
118 changes: 115 additions & 3 deletions includes/EmbedVideo.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use MediaWiki\Extension\EmbedVideo\EmbedService\EmbedHtmlFormatter;
use MediaWiki\Extension\EmbedVideo\EmbedService\EmbedServiceFactory;
use MediaWiki\Extension\EmbedVideo\EmbedService\OEmbedServiceInterface;
use MediaWiki\Html\Html;
use MediaWiki\MediaWikiServices;
use Parser;
use PPFrame;
Expand Down Expand Up @@ -128,6 +129,75 @@ public static function parseEV( Parser $parser, PPFrame $frame, array $args, boo
return ( new EmbedVideo( $parser, $expandedArgs, $fromTag ) )->output();
}

/**
* Parse the values input from the {{#evl}} or {{#vlink}} parser function
*
* @param Parser $parser The active Parser instance
* @param PPFrame $frame Frame
* @param array $args Arguments
*
* @return array Parser options and the HTML comments of cached attributes
*/
public static function parseEVL( Parser $parser, PPFrame $frame, array $args ): array {
$expandedArgs = [
'id' => null,
'text' => null,
'video' => null,
'player' => null,
'service' => null,
];

$keys = array_keys( $expandedArgs );

foreach ( $args as $key => $arg ) {
$value = trim( $frame->expand( $arg ) );

if ( str_contains( $value, '=' ) ) {
$parts = array_map( 'trim', explode( '=', $value ) );

$expandedArgs[$parts[0]] = $parts[1] ?? null;
} else {
$expandedArgs[$keys[$key]] = $value;
}
}

if ( empty( $expandedArgs['service'] ) ) {
$expandedArgs['service'] = 'youtube';
}

$ev = new EmbedVideo( $parser, $expandedArgs, true );

try {
$ev->init();
$ev->addModules();

if ( empty( $ev->args['text'] ) ) {
throw new InvalidArgumentException( $ev->error( 'missingparams', $ev->args['service'] )[0] );
}
} catch ( InvalidArgumentException $e ) {
return [
$e->getMessage(),
'noparse' => true,
'isHTML' => true
];
}

$linkConfig = [
'data-iframeconfig' => $ev->service->getIframeConfig( $ev->args['width'], $ev->args['height'] ),
'data-service' => $ev->args['service'],
'data-privacy-url' => $ev->service->getPrivacyPolicyUrl(),
'data-player' => $ev->args['player'] ?? 'default',
'class' => 'embedvideo-evl vplink',
'href' => '#',
];

return [
Html::element( 'a', $linkConfig, $ev->args['text'] ),
'noparse' => true,
'isHTML' => true
];
}

/**
* Parse a service tag like <youtube>
*
Expand All @@ -138,13 +208,54 @@ public static function parseEV( Parser $parser, PPFrame $frame, array $args, boo
* @return array
*/
public static function parseEVTag( $input, array $args, Parser $parser, PPFrame $frame ): array {
if ( !isset( $args['id'] ) ) {
if ( !isset( $args['id'] ) && !empty( $input ) ) {
$args['id'] = $input;
}

return self::parseEV( $parser, $frame, $args, true );
}

/**
* Parse a service tag like <evlplayer> or <vplayer>
*
* @param string $input The content of the tag i.e. the video id
* @param array $args
* @param Parser $parser
* @param PPFrame $frame
* @return array
*/
public static function parseEVLTag( $input, array $args, Parser $parser, PPFrame $frame ): array {
$args['player'] = $args['id'] ?? 'default';
$args['id'] = $args['defaultid'] ?? null;
$args['service'] = $args['service'] ?? 'youtube';

if ( empty( $args['id'] ) ) {
$args['id'] = '-1';
$args['service'] = 'videolink';
}

if ( !isset( $args['title'] ) ) {
$args['title'] = $input;
}

if ( !isset( $args['service'] ) ) {
$args['service'] = 'youtube';
}

$args['width'] = $args['w'] ?? null;
$args['height'] = $args['h'] ?? null;
$args['class'] = ( $args['class'] ?? '' ) . ' evlplayer evlplayer-' . $args['player'];

$args = array_filter( $args );

$parser->getOutput()->addModules( [
'ext.embedVideo.videolink',
'ext.embedVideo.messages',
] );

return self::parseEV( $parser, $frame, $args, true );
}

/**
* Wrapper for service specific tag calls
*
Expand Down Expand Up @@ -471,7 +582,8 @@ private function makeHtmlFormatConfig( $embedService ): array {
$classString = implode( ' ', array_filter( [
'embedvideo',
// This should probably be added as a RL variable
$this->config->get( 'EmbedVideoFetchExternalThumbnails' ) ? '' : 'no-fetch'
$this->config->get( 'EmbedVideoFetchExternalThumbnails' ) ? '' : 'no-fetch',
strip_tags( $this->args['class'] ?? '' ),
] ) );
$serviceString = $embedService::getServiceName();
$styleString = '';
Expand Down Expand Up @@ -521,8 +633,8 @@ private function addModules(): void {
] );

$serviceAttributes = $this->service->getIframeAttributes();
$serviceAttributes['height'] = $this->service->getDefaultHeight();
$serviceAttributes['width'] = $this->service->getDefaultWidth();
$serviceAttributes['height'] = $this->service->getDefaultHeight();

$this->parser->getOutput()->setJsConfigVar(
sprintf( 'ev-%s-config', $this->service::getServiceName() ),
Expand Down
24 changes: 18 additions & 6 deletions includes/EmbedVideoHooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,24 +105,36 @@ public static function setup(): void {
*/
public function onParserFirstCallInit( $parser ): void {
try {
$parser->setHook( 'embedvideo', [ EmbedVideo::class, 'parseEVTag' ] );

$parser->setFunctionHook(
'ev',
[ EmbedVideo::class, 'parseEV' ],
Parser::SFH_OBJECT_ARGS
);

$parser->setHook( 'embedvideo', [ EmbedVideo::class, 'parseEVTag' ] );
} catch ( MWException $e ) {
wfLogWarning( $e->getMessage() );
}

try {
$parser->setFunctionHook(
'evu',
[ EmbedVideo::class, 'parseEVU' ],
Parser::SFH_OBJECT_ARGS
);

$parser->setFunctionHook(
'evl',
[ EmbedVideo::class, 'parseEVL' ],
Parser::SFH_OBJECT_ARGS
);

$parser->setFunctionHook(
'vlink',
[ EmbedVideo::class, 'parseEVL' ],
Parser::SFH_OBJECT_ARGS
);

$parser->setHook( 'evlplayer', [ EmbedVideo::class, 'parseEVLTag' ] );
$parser->setHook( 'vplayer', [ EmbedVideo::class, 'parseEVLTag' ] );
} catch ( MWException $e ) {
dd( $e->getMessage() );
wfLogWarning( $e->getMessage() );
}

Expand Down
Loading

0 comments on commit c42adcf

Please sign in to comment.