mirror of
https://github.com/LBRYFoundation/lbry-desktop.git
synced 2025-09-03 20:35:17 +00:00
Merge pull request #2295 from lbryio/web-video
fix: load correct video player on web
This commit is contained in:
commit
4721ab1f2c
5 changed files with 129 additions and 128 deletions
|
@ -87,7 +87,6 @@
|
||||||
"reselect": "^3.0.0",
|
"reselect": "^3.0.0",
|
||||||
"semver": "^5.3.0",
|
"semver": "^5.3.0",
|
||||||
"source-map-support": "^0.5.4",
|
"source-map-support": "^0.5.4",
|
||||||
"stream-to-blob-url": "^2.1.1",
|
|
||||||
"three": "^0.93.0",
|
"three": "^0.93.0",
|
||||||
"tree-kill": "^1.1.0",
|
"tree-kill": "^1.1.0",
|
||||||
"video.js": "^7.2.2",
|
"video.js": "^7.2.2",
|
||||||
|
|
|
@ -1,40 +1,73 @@
|
||||||
/* eslint-disable */
|
// @flow
|
||||||
import React from 'react';
|
import type { Claim } from 'types/claim';
|
||||||
|
import * as React from 'react';
|
||||||
import { remote } from 'electron';
|
import { remote } from 'electron';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import player from 'render-media';
|
import player from 'render-media';
|
||||||
import toBlobURL from 'stream-to-blob-url';
|
|
||||||
import FileRender from 'component/fileRender';
|
import FileRender from 'component/fileRender';
|
||||||
import Thumbnail from 'component/common/thumbnail';
|
|
||||||
import LoadingScreen from 'component/common/loading-screen';
|
import LoadingScreen from 'component/common/loading-screen';
|
||||||
|
|
||||||
class MediaPlayer extends React.PureComponent {
|
type Props = {
|
||||||
static MP3_CONTENT_TYPES = ['audio/mpeg3', 'audio/mpeg'];
|
contentType: string,
|
||||||
|
mediaType: string,
|
||||||
|
downloadCompleted: boolean,
|
||||||
|
playingUri: ?string,
|
||||||
|
volume: number,
|
||||||
|
position: ?number,
|
||||||
|
downloadPath: string,
|
||||||
|
fileName: string,
|
||||||
|
claim: Claim,
|
||||||
|
onStartCb: ?() => void,
|
||||||
|
onFinishCb: ?() => void,
|
||||||
|
savePosition: number => void,
|
||||||
|
changeVolume: number => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
hasMetadata: boolean,
|
||||||
|
unplayable: boolean,
|
||||||
|
fileSource: ?{
|
||||||
|
url?: string,
|
||||||
|
fileName?: string,
|
||||||
|
contentType?: string,
|
||||||
|
downloadPath?: string,
|
||||||
|
fileType?: string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
class MediaPlayer extends React.PureComponent<Props, State> {
|
||||||
static SANDBOX_TYPES = ['application/x-lbry', 'application/x-ext-lbry'];
|
static SANDBOX_TYPES = ['application/x-lbry', 'application/x-ext-lbry'];
|
||||||
static FILE_MEDIA_TYPES = ['text', 'script', 'e-book', 'comic-book', 'document', '3D-file'];
|
static FILE_MEDIA_TYPES = [
|
||||||
|
'text',
|
||||||
|
'script',
|
||||||
|
'e-book',
|
||||||
|
'comic-book',
|
||||||
|
'document',
|
||||||
|
'3D-file',
|
||||||
|
// The web can use the new video player, which has it's own file renderer
|
||||||
|
// @if TARGET='web'
|
||||||
|
'video',
|
||||||
|
'audio',
|
||||||
|
// @endif
|
||||||
|
];
|
||||||
static SANDBOX_SET_BASE_URL = 'http://localhost:5278/set/';
|
static SANDBOX_SET_BASE_URL = 'http://localhost:5278/set/';
|
||||||
static SANDBOX_CONTENT_BASE_URL = 'http://localhost:5278';
|
static SANDBOX_CONTENT_BASE_URL = 'http://localhost:5278';
|
||||||
|
|
||||||
constructor(props) {
|
mediaContainer: { current: React.ElementRef<any> };
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
hasMetadata: false,
|
hasMetadata: false,
|
||||||
startedPlaying: false,
|
|
||||||
unplayable: false,
|
unplayable: false,
|
||||||
fileSource: null,
|
fileSource: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.togglePlayListener = this.togglePlay.bind(this);
|
this.mediaContainer = React.createRef();
|
||||||
this.toggleFullScreenVideo = this.toggleFullScreen.bind(this);
|
(this: any).togglePlay = this.togglePlay.bind(this);
|
||||||
}
|
(this: any).toggleFullScreen = this.toggleFullScreen.bind(this);
|
||||||
|
|
||||||
componentDidUpdate(nextProps) {
|
|
||||||
const el = this.refs.media.children[0];
|
|
||||||
if (this.props.playingUri && !nextProps.playingUri && !el.paused) {
|
|
||||||
el.pause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -42,6 +75,7 @@ class MediaPlayer extends React.PureComponent {
|
||||||
|
|
||||||
// Temp hack to force the video to play if the metadataloaded event was never fired
|
// Temp hack to force the video to play if the metadataloaded event was never fired
|
||||||
// Will be removed with the new video player
|
// Will be removed with the new video player
|
||||||
|
// @if TARGET='app'
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const { hasMetadata } = this.state;
|
const { hasMetadata } = this.state;
|
||||||
if (!hasMetadata) {
|
if (!hasMetadata) {
|
||||||
|
@ -49,47 +83,38 @@ class MediaPlayer extends React.PureComponent {
|
||||||
this.playMedia();
|
this.playMedia();
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
// @endif
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(next) {
|
// @if TARGET='app'
|
||||||
const el = this.media.children[0];
|
componentDidUpdate(prevProps: Props) {
|
||||||
if (!this.props.paused && next.paused && !el.paused) el.pause();
|
const { downloadCompleted } = this.props;
|
||||||
}
|
const { fileSource } = this.state;
|
||||||
|
|
||||||
componentDidUpdate() {
|
const el = this.mediaContainer.current;
|
||||||
const { contentType, downloadCompleted } = this.props;
|
|
||||||
const { startedPlaying, fileSource } = this.state;
|
|
||||||
|
|
||||||
if (this.playableType() && !startedPlaying && downloadCompleted) {
|
if (this.props.playingUri && !prevProps.playingUri && !el.paused) {
|
||||||
const container = this.media.children[0];
|
el.pause();
|
||||||
|
} else if (this.isSupportedFile() && !fileSource && downloadCompleted) {
|
||||||
if (MediaPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
|
||||||
this.renderAudio(this.media, true);
|
|
||||||
} else {
|
|
||||||
player.append(
|
|
||||||
this.file(),
|
|
||||||
container,
|
|
||||||
{ autoplay: true, controls: true },
|
|
||||||
renderMediaCallback.bind(this)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (this.fileType() && !fileSource && downloadCompleted) {
|
|
||||||
this.renderFile();
|
this.renderFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @endif
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
document.removeEventListener('keydown', this.togglePlayListener);
|
document.removeEventListener('keydown', this.togglePlay);
|
||||||
const mediaElement = this.media.children[0];
|
const mediaElement = this.mediaContainer.current.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.removeEventListener('click', this.togglePlayListener);
|
mediaElement.removeEventListener('click', this.togglePlay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleFullScreen(event) {
|
toggleFullScreen() {
|
||||||
const mediaElement = this.media.children[0];
|
const mediaElement = this.mediaContainer.current;
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
|
// $FlowFixMe
|
||||||
if (document.webkitIsFullScreen) {
|
if (document.webkitIsFullScreen) {
|
||||||
|
// $FlowFixMe
|
||||||
document.webkitExitFullscreen();
|
document.webkitExitFullscreen();
|
||||||
} else {
|
} else {
|
||||||
mediaElement.webkitRequestFullScreen();
|
mediaElement.webkitRequestFullScreen();
|
||||||
|
@ -98,19 +123,17 @@ class MediaPlayer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
playMedia() {
|
playMedia() {
|
||||||
const { hasMetadata } = this.state;
|
// @if TARGET='app'
|
||||||
|
const container = this.mediaContainer.current;
|
||||||
const container = this.media;
|
|
||||||
const {
|
const {
|
||||||
downloadCompleted,
|
downloadCompleted,
|
||||||
contentType,
|
|
||||||
changeVolume,
|
changeVolume,
|
||||||
volume,
|
volume,
|
||||||
position,
|
position,
|
||||||
claim,
|
|
||||||
onStartCb,
|
|
||||||
onFinishCb,
|
onFinishCb,
|
||||||
savePosition,
|
savePosition,
|
||||||
|
downloadPath,
|
||||||
|
fileName,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const renderMediaCallback = error => {
|
const renderMediaCallback = error => {
|
||||||
|
@ -121,29 +144,29 @@ class MediaPlayer extends React.PureComponent {
|
||||||
const win32FullScreenChange = () => {
|
const win32FullScreenChange = () => {
|
||||||
const win = remote.BrowserWindow.getFocusedWindow();
|
const win = remote.BrowserWindow.getFocusedWindow();
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
|
// $FlowFixMe
|
||||||
win.setMenu(document.webkitIsFullScreen ? null : remote.Menu.getApplicationMenu());
|
win.setMenu(document.webkitIsFullScreen ? null : remote.Menu.getApplicationMenu());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// use renderAudio override for mp3
|
|
||||||
if (MediaPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
|
||||||
this.renderAudio(container, null, false);
|
|
||||||
}
|
|
||||||
// Render custom viewer: FileRender
|
// Render custom viewer: FileRender
|
||||||
else if (this.fileType()) {
|
if (this.isSupportedFile() && downloadCompleted) {
|
||||||
downloadCompleted && this.renderFile();
|
this.renderFile();
|
||||||
}
|
}
|
||||||
// Render default viewer: render-media (video, audio, img, iframe)
|
// Render default viewer: render-media (video, audio, img, iframe)
|
||||||
else {
|
else {
|
||||||
player.append(
|
player.append(
|
||||||
this.file(),
|
{
|
||||||
|
name: fileName,
|
||||||
|
createReadStream: opts => fs.createReadStream(downloadPath, opts),
|
||||||
|
},
|
||||||
container,
|
container,
|
||||||
{ autoplay: true, controls: true },
|
{ autoplay: true, controls: true },
|
||||||
renderMediaCallback.bind(this)
|
renderMediaCallback.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('keydown', this.togglePlayListener);
|
document.addEventListener('keydown', this.togglePlay);
|
||||||
const mediaElement = container.children[0];
|
const mediaElement = container.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
if (position) {
|
if (position) {
|
||||||
|
@ -152,7 +175,7 @@ class MediaPlayer extends React.PureComponent {
|
||||||
|
|
||||||
mediaElement.addEventListener('loadedmetadata', () => this.refreshMetadata());
|
mediaElement.addEventListener('loadedmetadata', () => this.refreshMetadata());
|
||||||
mediaElement.addEventListener('timeupdate', () => savePosition(mediaElement.currentTime));
|
mediaElement.addEventListener('timeupdate', () => savePosition(mediaElement.currentTime));
|
||||||
mediaElement.addEventListener('click', this.togglePlayListener);
|
mediaElement.addEventListener('click', this.togglePlay);
|
||||||
mediaElement.addEventListener('ended', () => {
|
mediaElement.addEventListener('ended', () => {
|
||||||
if (onFinishCb) {
|
if (onFinishCb) {
|
||||||
onFinishCb();
|
onFinishCb();
|
||||||
|
@ -164,34 +187,45 @@ class MediaPlayer extends React.PureComponent {
|
||||||
changeVolume(mediaElement.volume);
|
changeVolume(mediaElement.volume);
|
||||||
});
|
});
|
||||||
mediaElement.volume = volume;
|
mediaElement.volume = volume;
|
||||||
mediaElement.addEventListener('dblclick', this.toggleFullScreenVideo);
|
mediaElement.addEventListener('dblclick', this.toggleFullScreen);
|
||||||
}
|
}
|
||||||
|
// @endif
|
||||||
|
|
||||||
|
// On the web, we have viewers for every file like normal people
|
||||||
|
|
||||||
|
// @if TARGET='web'
|
||||||
|
if (this.isSupportedFile()) {
|
||||||
|
this.renderFile();
|
||||||
|
}
|
||||||
|
// @endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @if TARGET='app'
|
||||||
refreshMetadata() {
|
refreshMetadata() {
|
||||||
const { onStartCb } = this.props;
|
const { onStartCb } = this.props;
|
||||||
this.setState({ hasMetadata: true, startedPlaying: true });
|
this.setState({ hasMetadata: true });
|
||||||
|
|
||||||
if (onStartCb) {
|
if (onStartCb) {
|
||||||
onStartCb();
|
onStartCb();
|
||||||
}
|
}
|
||||||
this.media.children[0].play();
|
|
||||||
}
|
|
||||||
|
|
||||||
setReady() {
|
const playerElement = this.mediaContainer.current;
|
||||||
this.setState({ ready: true });
|
if (playerElement) {
|
||||||
|
playerElement.children[0].play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// @endif
|
||||||
|
|
||||||
togglePlay(event) {
|
togglePlay(event: any) {
|
||||||
// ignore all events except click and spacebar keydown, or input events in a form control
|
// ignore all events except click and spacebar keydown, or input events in a form control
|
||||||
if (
|
if (
|
||||||
event.type === 'keydown' &&
|
event.type === 'keydown' &&
|
||||||
(event.code !== 'Space' || event.target.tagName.toLowerCase() === 'input')
|
(event.code !== 'Space' || (event.target && event.target.tagName.toLowerCase() === 'input'))
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const mediaElement = this.media.children[0];
|
const mediaElement = this.mediaContainer.current.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
if (!mediaElement.paused) {
|
if (!mediaElement.paused) {
|
||||||
mediaElement.pause();
|
mediaElement.pause();
|
||||||
|
@ -201,32 +235,21 @@ class MediaPlayer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file() {
|
playableType(): boolean {
|
||||||
const { downloadPath, fileName } = this.props;
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: fileName,
|
|
||||||
createReadStream: opts => fs.createReadStream(downloadPath, opts),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
playableType() {
|
|
||||||
const { mediaType } = this.props;
|
const { mediaType } = this.props;
|
||||||
|
|
||||||
return ['audio', 'video'].indexOf(mediaType) !== -1;
|
return ['audio', 'video'].indexOf(mediaType) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
supportedType() {
|
isRenderMediaSupported() {
|
||||||
// Files supported by render-media
|
// Files supported by render-media
|
||||||
const { contentType, mediaType } = this.props;
|
const { contentType } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
Object.values(player.mime).indexOf(contentType) !== -1 ||
|
Object.values(player.mime).indexOf(contentType) !== -1 ||
|
||||||
MediaPlayer.SANDBOX_TYPES.indexOf(contentType) > -1
|
MediaPlayer.SANDBOX_TYPES.indexOf(contentType) > -1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fileType() {
|
isSupportedFile() {
|
||||||
// This files are supported using a custom viewer
|
// This files are supported using a custom viewer
|
||||||
const { mediaType, contentType } = this.props;
|
const { mediaType, contentType } = this.props;
|
||||||
|
|
||||||
|
@ -238,7 +261,7 @@ class MediaPlayer extends React.PureComponent {
|
||||||
|
|
||||||
renderFile() {
|
renderFile() {
|
||||||
// This is what render-media does with unplayable files
|
// This is what render-media does with unplayable files
|
||||||
const { claim, fileName, downloadPath, contentType, mediaType } = this.props;
|
const { claim, fileName, downloadPath, contentType } = this.props;
|
||||||
|
|
||||||
if (MediaPlayer.SANDBOX_TYPES.indexOf(contentType) > -1) {
|
if (MediaPlayer.SANDBOX_TYPES.indexOf(contentType) > -1) {
|
||||||
const outpoint = `${claim.txid}:${claim.nout}`;
|
const outpoint = `${claim.txid}:${claim.nout}`;
|
||||||
|
@ -259,36 +282,15 @@ class MediaPlayer extends React.PureComponent {
|
||||||
fileType: path.extname(fileName).substring(1),
|
fileType: path.extname(fileName).substring(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Readable stream from file
|
|
||||||
fileSource.stream = opts => fs.createReadStream(downloadPath, opts);
|
|
||||||
|
|
||||||
// Blob url from stream
|
|
||||||
fileSource.blob = callback =>
|
|
||||||
toBlobURL(fs.createReadStream(downloadPath), contentType, callback);
|
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
this.setState({ fileSource });
|
this.setState({ fileSource });
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAudio(container, autoplay) {
|
showLoadingScreen(isFileType: boolean, isPlayableType: boolean) {
|
||||||
if (container.firstChild) {
|
|
||||||
container.firstChild.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear the container
|
|
||||||
const { downloadPath } = this.props;
|
|
||||||
const audio = document.createElement('audio');
|
|
||||||
audio.autoplay = autoplay;
|
|
||||||
audio.controls = true;
|
|
||||||
audio.src = downloadPath;
|
|
||||||
container.appendChild(audio);
|
|
||||||
}
|
|
||||||
|
|
||||||
showLoadingScreen(isFileType, isPlayableType) {
|
|
||||||
const { mediaType, contentType } = this.props;
|
const { mediaType, contentType } = this.props;
|
||||||
const { hasMetadata, unplayable, unsupported, fileSource } = this.state;
|
const { unplayable, fileSource, hasMetadata } = this.state;
|
||||||
|
|
||||||
const loader = {
|
const loader: { isLoading: boolean, loadingStatus: ?string } = {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
loadingStatus: null,
|
loadingStatus: null,
|
||||||
};
|
};
|
||||||
|
@ -306,7 +308,7 @@ class MediaPlayer extends React.PureComponent {
|
||||||
const isLbryPackage = /application\/x(-ext)?-lbry$/.test(contentType);
|
const isLbryPackage = /application\/x(-ext)?-lbry$/.test(contentType);
|
||||||
const isUnsupported =
|
const isUnsupported =
|
||||||
(mediaType === 'application' && !isLbryPackage) ||
|
(mediaType === 'application' && !isLbryPackage) ||
|
||||||
(!this.supportedType() && !isFileType && !isPlayableType);
|
(!this.isRenderMediaSupported() && !isFileType && !isPlayableType);
|
||||||
// Media (audio, video)
|
// Media (audio, video)
|
||||||
const isUnplayable = isPlayableType && unplayable;
|
const isUnplayable = isPlayableType && unplayable;
|
||||||
const isLoadingMetadata = isPlayableType && (!hasMetadata && !unplayable);
|
const isLoadingMetadata = isPlayableType && (!hasMetadata && !unplayable);
|
||||||
|
@ -320,7 +322,7 @@ class MediaPlayer extends React.PureComponent {
|
||||||
} else if (isUnsupported || isUnplayable) {
|
} else if (isUnsupported || isUnplayable) {
|
||||||
loader.loadingStatus = isUnsupported ? unsupportedMessage : unplayableMessage;
|
loader.loadingStatus = isUnsupported ? unsupportedMessage : unplayableMessage;
|
||||||
} else if (isLbryPackage && !isLoadingFile) {
|
} else if (isLbryPackage && !isLoadingFile) {
|
||||||
loader.loadingStatus = false;
|
loader.loadingStatus = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return loader;
|
return loader;
|
||||||
|
@ -330,7 +332,7 @@ class MediaPlayer extends React.PureComponent {
|
||||||
const { mediaType } = this.props;
|
const { mediaType } = this.props;
|
||||||
const { fileSource } = this.state;
|
const { fileSource } = this.state;
|
||||||
|
|
||||||
const isFileType = this.fileType();
|
const isFileType = this.isSupportedFile();
|
||||||
const isFileReady = fileSource && isFileType;
|
const isFileReady = fileSource && isFileType;
|
||||||
const isPlayableType = this.playableType();
|
const isPlayableType = this.playableType();
|
||||||
const { isLoading, loadingStatus } = this.showLoadingScreen(isFileType, isPlayableType);
|
const { isLoading, loadingStatus } = this.showLoadingScreen(isFileType, isPlayableType);
|
||||||
|
@ -340,11 +342,9 @@ class MediaPlayer extends React.PureComponent {
|
||||||
{loadingStatus && <LoadingScreen status={loadingStatus} spinner={isLoading} />}
|
{loadingStatus && <LoadingScreen status={loadingStatus} spinner={isLoading} />}
|
||||||
{isFileReady && <FileRender source={fileSource} mediaType={mediaType} />}
|
{isFileReady && <FileRender source={fileSource} mediaType={mediaType} />}
|
||||||
<div
|
<div
|
||||||
className={'content__view--container'}
|
className="content__view--container"
|
||||||
style={{ opacity: isLoading ? 0 : 1 }}
|
style={{ opacity: isLoading ? 0 : 1 }}
|
||||||
ref={container => {
|
ref={this.mediaContainer}
|
||||||
this.media = container;
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
@ -352,4 +352,3 @@ class MediaPlayer extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MediaPlayer;
|
export default MediaPlayer;
|
||||||
/* eslint-disable */
|
|
||||||
|
|
|
@ -92,14 +92,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--link:not(:disabled) {
|
.button--link {
|
||||||
html[data-mode='dark'] & {
|
word-break: break-all;
|
||||||
&:not(:hover) {
|
&:not(:disabled) {
|
||||||
color: $lbry-teal-4;
|
html[data-mode='dark'] & {
|
||||||
}
|
&:not(:hover) {
|
||||||
|
color: $lbry-teal-4;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $lbry-teal-3;
|
color: $lbry-teal-3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,9 @@
|
||||||
|
|
||||||
// Removing the play button because we have autoplay turned on
|
// Removing the play button because we have autoplay turned on
|
||||||
// These are classes added by video.js
|
// These are classes added by video.js
|
||||||
// .video-js .vjs-big-play-button {
|
.video-js .vjs-big-play-button {
|
||||||
// display: none;
|
display: none;
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.document-viewer {
|
.document-viewer {
|
||||||
|
|
|
@ -9340,7 +9340,7 @@ stream-shift@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
|
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
|
||||||
|
|
||||||
stream-to-blob-url@^2.0.0, stream-to-blob-url@^2.1.1:
|
stream-to-blob-url@^2.0.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/stream-to-blob-url/-/stream-to-blob-url-2.1.1.tgz#e1ac97f86ca8e9f512329a48e7830ce9a50beef2"
|
resolved "https://registry.yarnpkg.com/stream-to-blob-url/-/stream-to-blob-url-2.1.1.tgz#e1ac97f86ca8e9f512329a48e7830ce9a50beef2"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
Loading…
Add table
Reference in a new issue