cleanup
This commit is contained in:
parent
ba2ccd45fe
commit
90bcde49e7
8 changed files with 16 additions and 507 deletions
|
@ -34,7 +34,6 @@ function FileDownloadLink(props: Props) {
|
||||||
return (
|
return (
|
||||||
<ToolTip label={__('Open file')}>
|
<ToolTip label={__('Open file')}>
|
||||||
<Button
|
<Button
|
||||||
title="Remove from library"
|
|
||||||
button="link"
|
button="link"
|
||||||
icon={ICONS.EXTERNAL}
|
icon={ICONS.EXTERNAL}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
@ -8,14 +8,6 @@ import AppViewer from 'component/viewers/appViewer';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
// This is half complete, the video viewer works fine for audio, it just doesn't look pretty
|
|
||||||
// const AudioViewer = React.lazy<*>(() =>
|
|
||||||
// import(
|
|
||||||
// /* webpackChunkName: "audioViewer" */
|
|
||||||
// 'component/viewers/audioViewer'
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
|
|
||||||
const DocumentViewer = React.lazy<*>(() =>
|
const DocumentViewer = React.lazy<*>(() =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "documentViewer" */
|
/* webpackChunkName: "documentViewer" */
|
||||||
|
@ -131,7 +123,7 @@ class FileRender extends React.PureComponent<Props> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for a valid fileType or mediaType
|
// Check for a valid fileType or mediaType
|
||||||
let viewer = fileType ? fileTypes[fileType] : mediaTypes[mediaType];
|
let viewer = (fileType && fileTypes[fileType]) || mediaTypes[mediaType];
|
||||||
|
|
||||||
// Check for Human-readable files
|
// Check for Human-readable files
|
||||||
if (!viewer && readableFiles.includes(mediaType)) {
|
if (!viewer && readableFiles.includes(mediaType)) {
|
||||||
|
|
|
@ -34,8 +34,6 @@ export default function FileViewer(props: Props) {
|
||||||
thumbnail,
|
thumbnail,
|
||||||
streamingUrl,
|
streamingUrl,
|
||||||
isStreamable,
|
isStreamable,
|
||||||
// Add this back for full-screen support
|
|
||||||
// viewerContainer,
|
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const isPlayable = ['audio', 'video'].indexOf(mediaType) !== -1;
|
const isPlayable = ['audio', 'video'].indexOf(mediaType) !== -1;
|
||||||
|
|
|
@ -1,300 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import * as ICONS from 'constants/icons';
|
|
||||||
import Button from 'component/button';
|
|
||||||
import Tooltip from 'component/common/tooltip';
|
|
||||||
import { stopContextMenu } from 'util/context-menu';
|
|
||||||
import butterchurn from 'butterchurn';
|
|
||||||
import detectButterchurnSupport from 'butterchurn/lib/isSupported.min';
|
|
||||||
import butterchurnPresets from 'butterchurn-presets';
|
|
||||||
import jsmediatags from 'jsmediatags/dist/jsmediatags';
|
|
||||||
import WaveSurfer from 'wavesurfer.js';
|
|
||||||
|
|
||||||
import styles from './audioViewer.module.scss';
|
|
||||||
|
|
||||||
const isButterchurnSupported = detectButterchurnSupport();
|
|
||||||
|
|
||||||
const EQ_BANDS_SIMPLE = [55, 150, 250, 400, 500, 1000, 2000, 4000, 8000, 16000];
|
|
||||||
/*
|
|
||||||
const EQ_LOWSHELF = EQ_BANDS_SIMPLE.shift();
|
|
||||||
const EQ_HIGHSHELF = EQ_BANDS_SIMPLE.pop();
|
|
||||||
|
|
||||||
const eqFilters = EQ.map(function(band) {
|
|
||||||
var filter = wavesurfer.backend.ac.createBiquadFilter();
|
|
||||||
filter.type = 'peaking';
|
|
||||||
filter.gain.value = 0;
|
|
||||||
filter.Q.value = 1;
|
|
||||||
filter.frequency.value = band.f;
|
|
||||||
return filter;
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
source: {
|
|
||||||
url: string,
|
|
||||||
stream: string => void,
|
|
||||||
downloadCompleted: string,
|
|
||||||
downloadPath: string,
|
|
||||||
status: string,
|
|
||||||
},
|
|
||||||
contentType: string,
|
|
||||||
poster?: string,
|
|
||||||
claim: StreamClaim,
|
|
||||||
};
|
|
||||||
|
|
||||||
const presets = [
|
|
||||||
require('butterchurn-presets/presets/converted/Flexi - when monopolies were the future [simple warp + non-reactive moebius].json'),
|
|
||||||
require('butterchurn-presets/presets/converted/Rovastar & Loadus - FractalDrop (Active Sparks Mix).json'),
|
|
||||||
require('butterchurn-presets/presets/converted/shifter - tumbling cubes (ripples).json'),
|
|
||||||
require('butterchurn-presets/presets/converted/ORB - Blue Emotion.json'),
|
|
||||||
require('butterchurn-presets/presets/converted/shifter - urchin mod.json'),
|
|
||||||
require('butterchurn-presets/presets/converted/Stahlregen & fishbrain + flexi + geiss - The Machine that conquered the Aether.json'),
|
|
||||||
require('butterchurn-presets/presets/converted/Zylot - Crosshair Dimension (Light of Ages).json'),
|
|
||||||
];
|
|
||||||
|
|
||||||
class AudioVideoViewer extends React.PureComponent {
|
|
||||||
// audioNode: ?HTMLAudioElement;
|
|
||||||
// player: ?{ dispose: () => void };
|
|
||||||
|
|
||||||
state = {
|
|
||||||
playing: false,
|
|
||||||
enableMilkdrop: isButterchurnSupported,
|
|
||||||
showEqualizer: false,
|
|
||||||
showSongDetails: true,
|
|
||||||
enableArt: true,
|
|
||||||
artLoaded: false,
|
|
||||||
artist: null,
|
|
||||||
title: null,
|
|
||||||
album: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const me = this;
|
|
||||||
const { contentType, poster, claim, source } = me.props;
|
|
||||||
|
|
||||||
const path = source.downloadCompleted ? source.downloadPath : source.url;
|
|
||||||
const sources = [
|
|
||||||
{
|
|
||||||
src: path,
|
|
||||||
type: contentType,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const audioNode = this.audioNode;
|
|
||||||
|
|
||||||
audioNode.crossOrigin = 'anonymous';
|
|
||||||
audioNode.autostart = true;
|
|
||||||
|
|
||||||
const canvasHeight = me.canvasNode.offsetHeight;
|
|
||||||
const canvasWidth = me.canvasNode.offsetWidth;
|
|
||||||
|
|
||||||
// Required for canvas, nuance of rendering
|
|
||||||
me.canvasNode.height = canvasHeight;
|
|
||||||
me.canvasNode.width = canvasWidth;
|
|
||||||
|
|
||||||
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
|
||||||
const audioContext = new AudioContext();
|
|
||||||
|
|
||||||
const audioSource = audioContext.createMediaElementSource(audioNode);
|
|
||||||
audioSource.connect(audioContext.destination);
|
|
||||||
|
|
||||||
if (isButterchurnSupported) {
|
|
||||||
const visualizer = (me.visualizer = butterchurn.createVisualizer(audioContext, me.canvasNode, {
|
|
||||||
height: canvasHeight,
|
|
||||||
width: canvasWidth,
|
|
||||||
pixelRatio: window.devicePixelRatio || 1,
|
|
||||||
textureRatio: 1,
|
|
||||||
}));
|
|
||||||
|
|
||||||
visualizer.connectAudio(audioSource);
|
|
||||||
visualizer.loadPreset(presets[Math.floor(Math.random() * presets.length)], 2.0);
|
|
||||||
|
|
||||||
me._frameCycle = () => {
|
|
||||||
requestAnimationFrame(me._frameCycle);
|
|
||||||
|
|
||||||
if (me.state.enableMilkdrop === true) {
|
|
||||||
visualizer.render();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
me._frameCycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
const wavesurfer = WaveSurfer.create({
|
|
||||||
barWidth: 3,
|
|
||||||
container: this.waveNode,
|
|
||||||
waveColor: '#000',
|
|
||||||
progressColor: '#fff',
|
|
||||||
mediaControls: true,
|
|
||||||
responsive: true,
|
|
||||||
normalize: true,
|
|
||||||
backend: 'MediaElement',
|
|
||||||
minPxPerSec: 100,
|
|
||||||
height: this.waveNode.offsetHeight,
|
|
||||||
});
|
|
||||||
|
|
||||||
wavesurfer.load(audioNode);
|
|
||||||
|
|
||||||
jsmediatags.Config.setDisallowedXhrHeaders(['If-Modified-Since', 'Range']);
|
|
||||||
jsmediatags.read(path, {
|
|
||||||
onSuccess: function(result) {
|
|
||||||
const { album, artist, title, picture } = result.tags;
|
|
||||||
|
|
||||||
if (picture) {
|
|
||||||
const byteArray = new Uint8Array(picture.data);
|
|
||||||
const blob = new Blob([byteArray], { type: picture.type });
|
|
||||||
const albumArtUrl = URL.createObjectURL(blob);
|
|
||||||
me.artNode.src = albumArtUrl;
|
|
||||||
|
|
||||||
me.setState({ artLoaded: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
me.setState({
|
|
||||||
album,
|
|
||||||
artist,
|
|
||||||
title,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: function(error) {
|
|
||||||
console.log(':(', error.type, error.info);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if (this.player) {
|
|
||||||
this.player.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill the render loop
|
|
||||||
this._frameCycle = () => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const me = this;
|
|
||||||
const { contentType, poster, claim, source } = me.props;
|
|
||||||
const {
|
|
||||||
album,
|
|
||||||
artist,
|
|
||||||
title,
|
|
||||||
enableMilkdrop,
|
|
||||||
showEqualizer,
|
|
||||||
showSongDetails,
|
|
||||||
enableArt,
|
|
||||||
artLoaded,
|
|
||||||
playing,
|
|
||||||
userActive,
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const renderArt = enableArt && artLoaded;
|
|
||||||
|
|
||||||
const path = source.downloadCompleted ? source.downloadPath : source.url;
|
|
||||||
|
|
||||||
const playButton = (
|
|
||||||
<div
|
|
||||||
onClick={() => {
|
|
||||||
const audioNode = this.audioNode;
|
|
||||||
if (audioNode.paused) {
|
|
||||||
audioNode.play();
|
|
||||||
} else {
|
|
||||||
audioNode.pause();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className={playing ? styles.playButtonPause : styles.playButtonPlay}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={userActive ? styles.userActive : styles.wrapper}
|
|
||||||
onMouseEnter={() => me.setState({ userActive: true })}
|
|
||||||
onMouseLeave={() => me.setState({ userActive: false })}
|
|
||||||
onContextMenu={stopContextMenu}
|
|
||||||
>
|
|
||||||
<div className={enableMilkdrop ? styles.containerWithMilkdrop : styles.container}>
|
|
||||||
<div style={{ position: 'absolute', top: 0, right: 0 }}>
|
|
||||||
<Tooltip onComponent body={__('Toggle Visualizer')}>
|
|
||||||
<Button
|
|
||||||
icon={enableMilkdrop ? ICONS.VISUALIZER_ON : ICONS.VISUALIZER_OFF}
|
|
||||||
onClick={() => {
|
|
||||||
if (!isButterchurnSupported) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get new preset
|
|
||||||
this.visualizer.loadPreset(presets[Math.floor(Math.random() * presets.length)], 2.0);
|
|
||||||
|
|
||||||
this.setState({ enableMilkdrop: !enableMilkdrop });
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip onComponent body={__('Toggle Album Art')}>
|
|
||||||
<Button
|
|
||||||
icon={enableArt ? ICONS.MUSIC_ART_ON : ICONS.MUSIC_ART_OFF}
|
|
||||||
onClick={() => this.setState({ enableArt: !enableArt })}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip onComponent body={__('Toggle Details')}>
|
|
||||||
<Button
|
|
||||||
icon={showSongDetails ? ICONS.MUSIC_DETAILS_ON : ICONS.MUSIC_DETAILS_OFF}
|
|
||||||
onClick={() => this.setState({ showSongDetails: !showSongDetails })}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip onComponent body={__('Equalizer')}>
|
|
||||||
<Button icon={ICONS.MUSIC_EQUALIZER} onClick={() => this.setState({ showEqualizer: !showEqualizer })} />
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<div ref={node => (this.waveNode = node)} className={styles.wave} />
|
|
||||||
<div className={styles.infoContainer}>
|
|
||||||
<div className={renderArt ? styles.infoArtContainer : styles.infoArtContainerHidden}>
|
|
||||||
<img className={styles.infoArtImage} ref={node => (this.artNode = node)} />
|
|
||||||
{renderArt && playButton}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
showSongDetails
|
|
||||||
? renderArt
|
|
||||||
? styles.songDetailsContainer
|
|
||||||
: styles.songDetailsContainerNoArt
|
|
||||||
: styles.songDetailsContainerHidden
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className={renderArt ? styles.songDetails : styles.songDetailsNoArt}>
|
|
||||||
{artist && (
|
|
||||||
<div className={styles.detailsLineArtist}>
|
|
||||||
<Button icon={ICONS.MUSIC_ARTIST} className={styles.detailsIconArtist} />
|
|
||||||
{artist}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{title && (
|
|
||||||
<div className={styles.detailsLineSong}>
|
|
||||||
<Button icon={ICONS.MUSIC_SONG} className={styles.detailsIconSong} />
|
|
||||||
{title}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{album && (
|
|
||||||
<div className={styles.detailsLineAlbum}>
|
|
||||||
<Button icon={ICONS.MUSIC_ALBUM} className={styles.detailsIconAlbum} />
|
|
||||||
{album}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{!renderArt && <div className={styles.playButtonDetachedContainer}>{playButton}</div>}
|
|
||||||
</div>
|
|
||||||
<canvas
|
|
||||||
ref={node => (this.canvasNode = node)}
|
|
||||||
className={enableMilkdrop ? styles.milkdrop : styles.milkdropDisabled}
|
|
||||||
/>
|
|
||||||
<audio
|
|
||||||
ref={node => (this.audioNode = node)}
|
|
||||||
src={path}
|
|
||||||
style={{ position: 'absolute', top: '-100px' }}
|
|
||||||
onPlay={() => this.setState({ playing: true })}
|
|
||||||
onPause={() => this.setState({ playing: false })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AudioVideoViewer;
|
|
|
@ -1,193 +0,0 @@
|
||||||
.wrapper {
|
|
||||||
composes: 'file-render__viewer' from global;
|
|
||||||
}
|
|
||||||
|
|
||||||
.userActive {
|
|
||||||
composes: wrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
background: #212529;
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.containerWithMilkdrop {
|
|
||||||
composes: container;
|
|
||||||
|
|
||||||
background: rgba(50, 50, 55, 0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.wave {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -20%;
|
|
||||||
height: 40%;
|
|
||||||
opacity: 0.5;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.infoContainer {
|
|
||||||
padding: 0 20%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
min-height: 42%;
|
|
||||||
align-self: center;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: -10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.infoArtContainer {
|
|
||||||
align-self: flex-start;
|
|
||||||
width: 40%;
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
background: rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.infoArtContainerHidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.infoArtImage {
|
|
||||||
display: block;
|
|
||||||
opacity: 1;
|
|
||||||
transition: opacity 0.7s;
|
|
||||||
|
|
||||||
.userActive & {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.songDetailsContainer {
|
|
||||||
text-align: left;
|
|
||||||
padding: 3%;
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.songDetailsContainerHidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.songDetailsContainerNoArt {
|
|
||||||
composes: songDetailsContainer;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.songDetails {
|
|
||||||
width: 150%;
|
|
||||||
text-shadow: 2px 2px 3px #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.songDetailsNoArt {
|
|
||||||
composes: songDetails;
|
|
||||||
|
|
||||||
width: 200%;
|
|
||||||
margin-left: -50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailsIcon {
|
|
||||||
color: rgba(255, 255, 255, 0.5);
|
|
||||||
top: -3px;
|
|
||||||
padding-right: 10px;
|
|
||||||
width: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailsIconArtist {
|
|
||||||
composes: detailsIcon;
|
|
||||||
|
|
||||||
top: -3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailsIconSong {
|
|
||||||
composes: detailsIcon;
|
|
||||||
|
|
||||||
top: -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailsIconAlbum {
|
|
||||||
composes: detailsIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailsLineArtist {
|
|
||||||
font-size: 26px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailsLineSong {
|
|
||||||
font-size: 34px;
|
|
||||||
line-height: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.detailsLineAlbum {
|
|
||||||
font-size: 20px;
|
|
||||||
padding-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.playButton {
|
|
||||||
position: absolute;
|
|
||||||
border: 5px solid #fff;
|
|
||||||
border-radius: 45px;
|
|
||||||
color: #fff;
|
|
||||||
font-family: arial;
|
|
||||||
font-size: 60px;
|
|
||||||
left: 50%;
|
|
||||||
line-height: 80px;
|
|
||||||
margin-left: -45px;
|
|
||||||
padding-left: 20px;
|
|
||||||
bottom: 50%;
|
|
||||||
margin-bottom: -45px;
|
|
||||||
height: 90px;
|
|
||||||
width: 90px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.7s;
|
|
||||||
|
|
||||||
.userActive & {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.playButtonPlay {
|
|
||||||
composes: playButton;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
display: block;
|
|
||||||
content: '▶';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.playButtonPause {
|
|
||||||
composes: playButton;
|
|
||||||
|
|
||||||
font-size: 50px;
|
|
||||||
line-height: 75px;
|
|
||||||
padding-left: 20px;
|
|
||||||
letter-spacing: -24px;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
display: block;
|
|
||||||
content: '▎▎';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.playButtonDetachedContainer {
|
|
||||||
bottom: 35%;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.milkdrop {
|
|
||||||
top: 0;
|
|
||||||
z-index: 100;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.milkdropDisabled {
|
|
||||||
display: none;
|
|
||||||
}
|
|
|
@ -39,7 +39,7 @@ export default history =>
|
||||||
content: contentReducer,
|
content: contentReducer,
|
||||||
costInfo: costInfoReducer,
|
costInfo: costInfoReducer,
|
||||||
fileInfo: fileInfoReducer,
|
fileInfo: fileInfoReducer,
|
||||||
file: fileReducer, // Why is this not in `fileInfoReducer`?
|
file: fileReducer,
|
||||||
homepage: homepageReducer,
|
homepage: homepageReducer,
|
||||||
notifications: notificationsReducer,
|
notifications: notificationsReducer,
|
||||||
publish: publishReducer,
|
publish: publishReducer,
|
||||||
|
|
|
@ -193,12 +193,15 @@ export const doCheckSubscription = (subscriptionUri: string, shouldNotify?: bool
|
||||||
getState: GetState
|
getState: GetState
|
||||||
) => {
|
) => {
|
||||||
// no dispatching FETCH_CHANNEL_CLAIMS_STARTED; causes loading issues on <SubscriptionsPage>
|
// no dispatching FETCH_CHANNEL_CLAIMS_STARTED; causes loading issues on <SubscriptionsPage>
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const shouldAutoDownload = makeSelectClientSetting(SETTINGS.AUTO_DOWNLOAD)(state);
|
const shouldAutoDownload = makeSelectClientSetting(SETTINGS.AUTO_DOWNLOAD)(state);
|
||||||
const savedSubscription = state.subscriptions.subscriptions.find(sub => sub.uri === subscriptionUri);
|
const savedSubscription = state.subscriptions.subscriptions.find(sub => sub.uri === subscriptionUri);
|
||||||
|
|
||||||
if (!savedSubscription) {
|
if (!savedSubscription) {
|
||||||
throw Error(`Trying to find new content for ${subscriptionUri} but it doesn't exist in your subscriptions`);
|
throw Error(`Trying to find new content for ${subscriptionUri} but it doesn't exist in your subscriptions`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We may be duplicating calls here. Can this logic be baked into doFetchClaimsByChannel?
|
// We may be duplicating calls here. Can this logic be baked into doFetchClaimsByChannel?
|
||||||
Lbry.claim_search({
|
Lbry.claim_search({
|
||||||
channel: subscriptionUri,
|
channel: subscriptionUri,
|
||||||
|
@ -208,34 +211,42 @@ export const doCheckSubscription = (subscriptionUri: string, shouldNotify?: bool
|
||||||
page_size: PAGE_SIZE,
|
page_size: PAGE_SIZE,
|
||||||
}).then(claimListByChannel => {
|
}).then(claimListByChannel => {
|
||||||
const { items: claimsInChannel } = claimListByChannel;
|
const { items: claimsInChannel } = claimListByChannel;
|
||||||
|
|
||||||
// may happen if subscribed to an abandoned channel or an empty channel
|
// may happen if subscribed to an abandoned channel or an empty channel
|
||||||
if (!claimsInChannel || !claimsInChannel.length) {
|
if (!claimsInChannel || !claimsInChannel.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if the latest subscription currently saved is actually the latest subscription
|
// Determine if the latest subscription currently saved is actually the latest subscription
|
||||||
const latestIndex = claimsInChannel.findIndex(
|
const latestIndex = claimsInChannel.findIndex(
|
||||||
claim => `${claim.name}#${claim.claim_id}` === savedSubscription.latest
|
claim => `${claim.name}#${claim.claim_id}` === savedSubscription.latest
|
||||||
);
|
);
|
||||||
|
|
||||||
// If latest is -1, it is a newly subscribed channel or there have been 10+ claims published since last viewed
|
// If latest is -1, it is a newly subscribed channel or there have been 10+ claims published since last viewed
|
||||||
const latestIndexToNotify = latestIndex === -1 ? 10 : latestIndex;
|
const latestIndexToNotify = latestIndex === -1 ? 10 : latestIndex;
|
||||||
|
|
||||||
// If latest is 0, nothing has changed
|
// If latest is 0, nothing has changed
|
||||||
// Do not download/notify about new content, it would download/notify 10 claims per channel
|
// Do not download/notify about new content, it would download/notify 10 claims per channel
|
||||||
if (latestIndex !== 0 && savedSubscription.latest) {
|
if (latestIndex !== 0 && savedSubscription.latest) {
|
||||||
let downloadCount = 0;
|
let downloadCount = 0;
|
||||||
|
|
||||||
const newUnread = [];
|
const newUnread = [];
|
||||||
claimsInChannel.slice(0, latestIndexToNotify).forEach(claim => {
|
claimsInChannel.slice(0, latestIndexToNotify).forEach(claim => {
|
||||||
const uri = buildURI({ contentName: claim.name, claimId: claim.claim_id }, true);
|
const uri = buildURI({ contentName: claim.name, claimId: claim.claim_id }, true);
|
||||||
const shouldDownload =
|
const shouldDownload =
|
||||||
shouldAutoDownload && Boolean(downloadCount < SUBSCRIPTION_DOWNLOAD_LIMIT && !claim.value.fee);
|
shouldAutoDownload && Boolean(downloadCount < SUBSCRIPTION_DOWNLOAD_LIMIT && !claim.value.fee);
|
||||||
|
|
||||||
// Add the new content to the list of "un-read" subscriptions
|
// Add the new content to the list of "un-read" subscriptions
|
||||||
if (shouldNotify) {
|
if (shouldNotify) {
|
||||||
newUnread.push(uri);
|
newUnread.push(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldDownload) {
|
if (shouldDownload) {
|
||||||
downloadCount += 1;
|
downloadCount += 1;
|
||||||
dispatch(doPurchaseUri(uri, { cost: 0 }, true));
|
dispatch(doPurchaseUri(uri, { cost: 0 }, true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
doUpdateUnreadSubscriptions(
|
doUpdateUnreadSubscriptions(
|
||||||
subscriptionUri,
|
subscriptionUri,
|
||||||
|
@ -244,6 +255,7 @@ export const doCheckSubscription = (subscriptionUri: string, shouldNotify?: bool
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the latest piece of content for a channel
|
// Set the latest piece of content for a channel
|
||||||
// This allows the app to know if there has been new content since it was last set
|
// This allows the app to know if there has been new content since it was last set
|
||||||
dispatch(
|
dispatch(
|
||||||
|
@ -261,6 +273,7 @@ export const doCheckSubscription = (subscriptionUri: string, shouldNotify?: bool
|
||||||
buildURI({ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id }, false)
|
buildURI({ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id }, false)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// calling FETCH_CHANNEL_CLAIMS_COMPLETED after not calling STARTED
|
// calling FETCH_CHANNEL_CLAIMS_COMPLETED after not calling STARTED
|
||||||
// means it will delete a non-existant fetchingChannelClaims[uri]
|
// means it will delete a non-existant fetchingChannelClaims[uri]
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
|
@ -208,7 +208,7 @@ reducers[ACTIONS.WINDOW_FOCUSED] = state =>
|
||||||
|
|
||||||
reducers[ACTIONS.VOLUME_CHANGED] = (state, action) =>
|
reducers[ACTIONS.VOLUME_CHANGED] = (state, action) =>
|
||||||
Object.assign({}, state, {
|
Object.assign({}, state, {
|
||||||
muted: action.data.volume,
|
volume: action.data.volume,
|
||||||
});
|
});
|
||||||
|
|
||||||
reducers[ACTIONS.VOLUME_MUTED] = (state, action) =>
|
reducers[ACTIONS.VOLUME_MUTED] = (state, action) =>
|
||||||
|
|
Loading…
Reference in a new issue