Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jwplayer transcode seek support. Remove video.js #268

Merged
merged 1 commit into from
Dec 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions ui/v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@
"react-router-dom": "5.0.0",
"react-scripts": "3.3.0",
"react-use": "9.1.2",
"subscriptions-transport-ws": "^0.9.16",
"video.js": "^7.6.0"
"subscriptions-transport-ws": "^0.9.16"
},
"scripts": {
"start": "react-scripts start",
Expand Down
2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/jwplayer.controls.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/jwplayer.core.controls.html5.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/jwplayer.core.controls.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/jwplayer.core.controls.polyfills.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/jwplayer.core.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/jwplayer.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/polyfills.webvtt.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/provider.html5.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ui/v2/public/jwplayer/vttparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,4 @@ COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQ

The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders.
*/
(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[10],{92:function(t,e,r){"use strict";r.r(e);var n=r(42),i=r(64),s=/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/,a=/^-?\d+$/,u=/\r\n|\n/,o=/^NOTE($|[ \t])/,c=/^[^\sa-zA-Z-]+/,l=/:/,f=/\s/,h=/^\s+/,g=/-->/,d=/^WEBVTT([ \t].*)?$/,p=function(t,e){this.window=t,this.state="INITIAL",this.buffer="",this.decoder=e||new b,this.regionList=[],this.maxCueBatch=1e3};function b(){return{decode:function(t){if(!t)return"";if("string"!=typeof t)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(t))}}}function v(){this.values=Object.create(null)}v.prototype={set:function(t,e){this.get(t)||""===e||(this.values[t]=e)},get:function(t,e,r){return r?this.has(t)?this.values[t]:e[r]:this.has(t)?this.values[t]:e},has:function(t){return t in this.values},alt:function(t,e,r){for(var n=0;n<r.length;++n)if(e===r[n]){this.set(t,e);break}},integer:function(t,e){a.test(e)&&this.set(t,parseInt(e,10))},percent:function(t,e){return(e=parseFloat(e))>=0&&e<=100&&(this.set(t,e),!0)}};var E=new i.a(0,0,0),w="middle"===E.align?"middle":"center";function T(t,e,r){var n=t;function i(){var e=function(t){function e(t,e,r,n){return 3600*(0|t)+60*(0|e)+(0|r)+(0|n)/1e3}var r=t.match(s);return r?r[3]?e(r[1],r[2],r[3].replace(":",""),r[4]):r[1]>59?e(r[1],r[2],0,r[4]):e(0,r[1],r[2],r[4]):null}(t);if(null===e)throw new Error("Malformed timestamp: "+n);return t=t.replace(c,""),e}function a(){t=t.replace(h,"")}if(a(),e.startTime=i(),a(),"--\x3e"!==t.substr(0,3))throw new Error("Malformed time stamp (time stamps must be separated by '--\x3e'): "+n);t=t.substr(3),a(),e.endTime=i(),a(),function(t,e){var n=new v;!function(t,e,r,n){for(var i=n?t.split(n):[t],s=0;s<=i.length;s+=1)if("string"==typeof i[s]){var a=i[s].split(r);if(2===a.length)e(a[0],a[1])}}(t,(function(t,e){switch(t){case"region":for(var i=r.length-1;i>=0;i--)if(r[i].id===e){n.set(t,r[i].region);break}break;case"vertical":n.alt(t,e,["rl","lr"]);break;case"line":var s=e.split(","),a=s[0];n.integer(t,a),n.percent(t,a)&&n.set("snapToLines",!1),n.alt(t,a,["auto"]),2===s.length&&n.alt("lineAlign",s[1],["start",w,"end"]);break;case"position":var u=e.split(",");n.percent(t,u[0]),2===u.length&&n.alt("positionAlign",u[1],["start",w,"end","line-left","line-right","auto"]);break;case"size":n.percent(t,e);break;case"align":n.alt(t,e,["start",w,"end","left","right"])}}),l,f),e.region=n.get("region",null),e.vertical=n.get("vertical","");var i=n.get("line","auto");"auto"===i&&-1===E.line&&(i=-1),e.line=i,e.lineAlign=n.get("lineAlign","start"),e.snapToLines=n.get("snapToLines",!0),e.size=n.get("size",100),e.align=n.get("align",w);var s=n.get("position","auto");"auto"===s&&50===E.position&&(s="start"===e.align||"left"===e.align?0:"end"===e.align||"right"===e.align?100:50),e.position=s}(t,e)}p.prototype={parse:function(t,e){var r,s=this;function a(){for(var t=s.buffer,e=0;e<t.length&&"\r"!==t[e]&&"\n"!==t[e];)++e;var r=t.substr(0,e);return"\r"===t[e]&&++e,"\n"===t[e]&&++e,s.buffer=t.substr(e),r}function c(){"CUETEXT"===s.state&&s.cue&&s.oncue&&s.oncue(s.cue),s.cue=null,s.state="INITIAL"===s.state?"BADWEBVTT":"BADCUE"}t&&(s.buffer+=s.decoder.decode(t,{stream:!0}));try{if("INITIAL"===s.state){if(!u.test(s.buffer))return this;var f=(r=a()).match(d);if(!f||!f[0])throw new Error("Malformed WebVTT signature.");s.state="HEADER"}}catch(t){return c(),this}var h=!1,p=0;!function t(){try{for(;s.buffer&&p<=s.maxCueBatch;){if(!u.test(s.buffer))return s.flush(),this;switch(h?h=!1:r=a(),s.state){case"HEADER":l.test(r)||r||(s.state="ID");break;case"NOTE":r||(s.state="ID");break;case"ID":if(o.test(r)){s.state="NOTE";break}if(!r)break;if(s.cue=new i.a(0,0,""),s.state="CUE",!g.test(r)){s.cue.id=r;break}case"CUE":try{T(r,s.cue,s.regionList)}catch(t){s.cue=null,s.state="BADCUE";break}s.state="CUETEXT";break;case"CUETEXT":var f=g.test(r);if(!r||f&&(h=!0)){s.oncue&&(p+=1,s.oncue(s.cue)),s.cue=null,s.state="ID";break}s.cue.text&&(s.cue.text+="\n"),s.cue.text+=r;break;case"BADCUE":r||(s.state="ID")}}if(p=0,s.buffer)Object(n.b)(t);else if(!e)return s.flush(),this}catch(t){return c(),this}}()},flush:function(){try{if(this.buffer+=this.decoder.decode(),(this.cue||"HEADER"===this.state)&&(this.buffer+="\n\n",this.parse(void 0,!0)),"INITIAL"===this.state)throw new Error("Malformed WebVTT signature.")}catch(t){throw t}return this.onflush&&this.onflush(),this}},e.default=p}}]);
(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[10],{97:function(t,e,r){"use strict";r.r(e);var n=r(42),i=r(67),s=/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/,a=/^-?\d+$/,u=/\r\n|\n/,o=/^NOTE($|[ \t])/,c=/^[^\sa-zA-Z-]+/,l=/:/,f=/\s/,h=/^\s+/,g=/-->/,d=/^WEBVTT([ \t].*)?$/,p=function(t,e){this.window=t,this.state="INITIAL",this.buffer="",this.decoder=e||new b,this.regionList=[],this.maxCueBatch=1e3};function b(){return{decode:function(t){if(!t)return"";if("string"!=typeof t)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(t))}}}function v(){this.values=Object.create(null)}v.prototype={set:function(t,e){this.get(t)||""===e||(this.values[t]=e)},get:function(t,e,r){return r?this.has(t)?this.values[t]:e[r]:this.has(t)?this.values[t]:e},has:function(t){return t in this.values},alt:function(t,e,r){for(var n=0;n<r.length;++n)if(e===r[n]){this.set(t,e);break}},integer:function(t,e){a.test(e)&&this.set(t,parseInt(e,10))},percent:function(t,e){return(e=parseFloat(e))>=0&&e<=100&&(this.set(t,e),!0)}};var E=new i.a(0,0,0),w="middle"===E.align?"middle":"center";function T(t,e,r){var n=t;function i(){var e=function(t){function e(t,e,r,n){return 3600*(0|t)+60*(0|e)+(0|r)+(0|n)/1e3}var r=t.match(s);return r?r[3]?e(r[1],r[2],r[3].replace(":",""),r[4]):r[1]>59?e(r[1],r[2],0,r[4]):e(0,r[1],r[2],r[4]):null}(t);if(null===e)throw new Error("Malformed timestamp: "+n);return t=t.replace(c,""),e}function a(){t=t.replace(h,"")}if(a(),e.startTime=i(),a(),"--\x3e"!==t.substr(0,3))throw new Error("Malformed time stamp (time stamps must be separated by '--\x3e'): "+n);t=t.substr(3),a(),e.endTime=i(),a(),function(t,e){var n=new v;!function(t,e,r,n){for(var i=n?t.split(n):[t],s=0;s<=i.length;s+=1)if("string"==typeof i[s]){var a=i[s].split(r);if(2===a.length)e(a[0],a[1])}}(t,(function(t,e){switch(t){case"region":for(var i=r.length-1;i>=0;i--)if(r[i].id===e){n.set(t,r[i].region);break}break;case"vertical":n.alt(t,e,["rl","lr"]);break;case"line":var s=e.split(","),a=s[0];n.integer(t,a),n.percent(t,a)&&n.set("snapToLines",!1),n.alt(t,a,["auto"]),2===s.length&&n.alt("lineAlign",s[1],["start",w,"end"]);break;case"position":var u=e.split(",");n.percent(t,u[0]),2===u.length&&n.alt("positionAlign",u[1],["start",w,"end","line-left","line-right","auto"]);break;case"size":n.percent(t,e);break;case"align":n.alt(t,e,["start",w,"end","left","right"])}}),l,f),e.region=n.get("region",null),e.vertical=n.get("vertical","");var i=n.get("line","auto");"auto"===i&&-1===E.line&&(i=-1),e.line=i,e.lineAlign=n.get("lineAlign","start"),e.snapToLines=n.get("snapToLines",!0),e.size=n.get("size",100),e.align=n.get("align",w);var s=n.get("position","auto");"auto"===s&&50===E.position&&(s="start"===e.align||"left"===e.align?0:"end"===e.align||"right"===e.align?100:50),e.position=s}(t,e)}p.prototype={parse:function(t,e){var r,s=this;function a(){for(var t=s.buffer,e=0;e<t.length&&"\r"!==t[e]&&"\n"!==t[e];)++e;var r=t.substr(0,e);return"\r"===t[e]&&++e,"\n"===t[e]&&++e,s.buffer=t.substr(e),r}function c(){"CUETEXT"===s.state&&s.cue&&s.oncue&&s.oncue(s.cue),s.cue=null,s.state="INITIAL"===s.state?"BADWEBVTT":"BADCUE"}t&&(s.buffer+=s.decoder.decode(t,{stream:!0}));try{if("INITIAL"===s.state){if(!u.test(s.buffer))return this;var f=(r=a()).match(d);if(!f||!f[0])throw new Error("Malformed WebVTT signature.");s.state="HEADER"}}catch(t){return c(),this}var h=!1,p=0;!function t(){try{for(;s.buffer&&p<=s.maxCueBatch;){if(!u.test(s.buffer))return s.flush(),this;switch(h?h=!1:r=a(),s.state){case"HEADER":l.test(r)||r||(s.state="ID");break;case"NOTE":r||(s.state="ID");break;case"ID":if(o.test(r)){s.state="NOTE";break}if(!r)break;if(s.cue=new i.a(0,0,""),s.state="CUE",!g.test(r)){s.cue.id=r;break}case"CUE":try{T(r,s.cue,s.regionList)}catch(t){s.cue=null,s.state="BADCUE";break}s.state="CUETEXT";break;case"CUETEXT":var f=g.test(r);if(!r||f&&(h=!0)){s.oncue&&(p+=1,s.oncue(s.cue)),s.cue=null,s.state="ID";break}s.cue.text&&(s.cue.text+="\n"),s.cue.text+=r;break;case"BADCUE":r||(s.state="ID")}}if(p=0,s.buffer)Object(n.b)(t);else if(!e)return s.flush(),this}catch(t){return c(),this}}()},flush:function(){try{if(this.buffer+=this.decoder.decode(),(this.cue||"HEADER"===this.state)&&(this.buffer+="\n\n",this.parse(void 0,!0)),"INITIAL"===this.state)throw new Error("Malformed WebVTT signature.")}catch(t){throw t}return this.onflush&&this.onflush(),this}},e.default=p}}]);
134 changes: 25 additions & 109 deletions ui/v2/src/components/scenes/ScenePlayer/ScenePlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import ReactJWPlayer from "react-jw-player";
import * as GQL from "../../../core/generated-graphql";
import { SceneHelpers } from "../helpers";
import { ScenePlayerScrubber } from "./ScenePlayerScrubber";
import videojs from "video.js";
import "video.js/dist/video-js.css";
import { StashService } from "../../../core/StashService";

interface IScenePlayerProps {
Expand All @@ -21,84 +19,6 @@ interface IScenePlayerState {
scrubberPosition: number;
}

interface IVideoJSPlayerProps extends IScenePlayerProps {
videoJSOptions: videojs.PlayerOptions
}

export class VideoJSPlayer extends React.Component<IVideoJSPlayerProps> {
private player: any;
private videoNode: any;

constructor(props: IVideoJSPlayerProps) {
super(props);
}

componentDidMount() {
this.player = videojs(this.videoNode, this.props.videoJSOptions);

SceneHelpers.registerJSPlayer(this.player);

this.player.src(this.props.scene.paths.stream);

// hack duration
this.player.duration = () => { return this.props.scene.file.duration; };
this.player.start = 0;
this.player.oldCurrentTime = this.player.currentTime;
this.player.currentTime = (time: any) => {
if( time == undefined )
{
return this.player.oldCurrentTime() + this.player.start;
}
this.player.start = time;
this.player.oldCurrentTime(0);
this.player.src(this.props.scene.paths.stream + "?start=" + time);
this.player.play();

return this;
};

// dirty hack - make this player look like JWPlayer
this.player.seek = this.player.currentTime;
this.player.getPosition = this.player.currentTime;

this.player.ready(() => {
this.player.on("timeupdate", () => {
this.props.onTime();
});

this.player.on("seeked", () => {
this.props.onSeeked();
});

this.props.onReady();
});
}

componentWillUnmount() {
if (this.player) {
this.player.dispose();
SceneHelpers.deregisterJSPlayer();
}
}

render() {
return (
<div>
<div className="vjs-player" data-vjs-player>
<video
ref={ node => this.videoNode = node }
className="video-js vjs-default-skin vjs-big-play-centered"
poster={this.props.scene.paths.screenshot}
controls
preload="auto">
<track kind="chapters" label="Markers" src={this.props.scene.paths.chapters_vtt} default></track>
</video>
</div>
</div>
);
}
}

@HotkeysTarget
export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePlayerState> {
private player: any;
Expand All @@ -123,7 +43,6 @@ export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePl
}

renderPlayer() {
if (this.props.scene.is_streamable) {
const config = this.makeJWPlayerConfig(this.props.scene);
return (
<ReactJWPlayer
Expand All @@ -135,22 +54,6 @@ export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePl
onTime={this.onTime}
/>
);
} else {
// don't render videoJS until config is loaded
if (this.props.config) {
const config = this.makeVideoJSConfig(this.props.scene);
return (
<VideoJSPlayer
videoJSOptions={config}
scene={this.props.scene}
timestamp={this.props.timestamp}
onReady={this.onReady}
onSeeked={this.onSeeked}
onTime={this.onTime}>
</VideoJSPlayer>
)
}
}
}

public render() {
Expand Down Expand Up @@ -216,8 +119,27 @@ export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePl
if (!scene.paths.stream) { return {}; }

let repeat = this.shouldRepeat(scene);
let getDurationHook: (() => GQL.Maybe<number>) | undefined = undefined;
let seekHook: ((seekToPosition: number, _videoTag: any) => void) | undefined = undefined;
let getCurrentTimeHook: ((_videoTag: any) => number) | undefined = undefined;

if (!this.props.scene.is_streamable) {
getDurationHook = () => {
return this.props.scene.file.duration;
};

seekHook = (seekToPosition: number, _videoTag: any) => {
_videoTag.start = seekToPosition;
_videoTag.src = (this.props.scene.paths.stream + "?start=" + seekToPosition);
_videoTag.play();
};

getCurrentTimeHook = (_videoTag: any) => {
return _videoTag.currentTime + _videoTag.start;
}
}

return {
let ret = {
file: scene.paths.stream,
image: scene.paths.screenshot,
tracks: [
Expand All @@ -241,19 +163,13 @@ export class ScenePlayerImpl extends React.Component<IScenePlayerProps, IScenePl
repeat: repeat,
playbackRateControls: true,
playbackRates: [0.75, 1, 1.5, 2, 3, 4],
getDurationHook: getDurationHook,
seekHook: seekHook,
getCurrentTimeHook: getCurrentTimeHook
};
}

private makeVideoJSConfig(scene: GQL.SceneDataFragment) {
if (!scene.paths.stream) { return {}; }

let repeat = this.shouldRepeat(scene);

return {
autoplay: this.props.autoplay || (this.props.config ? this.props.config.autostartVideo : false),
loop: repeat,
};
}
return ret;
}

private onReady() {
this.player = SceneHelpers.getPlayer();
Expand Down
13 changes: 0 additions & 13 deletions ui/v2/src/components/scenes/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,8 @@ export class SceneHelpers {
);
}

public static registerJSPlayer(player : videojs.Player) {
this.videoJSPlayer = player;
}

public static deregisterJSPlayer() {
this.videoJSPlayer = null;
}

public static getJWPlayerId(): string { return "main-jwplayer"; }
public static getPlayer(): any {
// return videoJSPlayer if it is set, otherwise use jwplayer()
if (this.videoJSPlayer) {
return this.videoJSPlayer;
}

return (window as any).jwplayer("main-jwplayer");
}
}
Loading