parent
5fec72395c
commit
0a7f18e843
@ -0,0 +1,219 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import MonitorToggleButton from 'Components/MonitorToggleButton';
|
||||||
|
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||||
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
|
import TableRow from 'Components/Table/TableRow';
|
||||||
|
import Label from 'Components/Label';
|
||||||
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
|
import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
|
||||||
|
import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector';
|
||||||
|
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
||||||
|
|
||||||
|
import styles from './AlbumRow.css';
|
||||||
|
|
||||||
|
function getEpisodeCountKind(monitored, episodeFileCount, episodeCount) {
|
||||||
|
if (episodeFileCount === episodeCount && episodeCount > 0) {
|
||||||
|
return kinds.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!monitored) {
|
||||||
|
return kinds.WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kinds.DANGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AlbumRow extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifecycle
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isDetailsModalOpen: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Listeners
|
||||||
|
|
||||||
|
onManualSearchPress = () => {
|
||||||
|
this.setState({ isDetailsModalOpen: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
onDetailsModalClose = () => {
|
||||||
|
this.setState({ isDetailsModalOpen: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onMonitorAlbumPress = (monitored, options) => {
|
||||||
|
this.props.onMonitorAlbumPress(this.props.id, monitored, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
artistId,
|
||||||
|
monitored,
|
||||||
|
statistics,
|
||||||
|
duration,
|
||||||
|
releaseDate,
|
||||||
|
title,
|
||||||
|
isSaving,
|
||||||
|
artistMonitored,
|
||||||
|
path,
|
||||||
|
columns
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
trackCount,
|
||||||
|
trackFileCount,
|
||||||
|
totalTrackCount
|
||||||
|
} = statistics;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
{
|
||||||
|
columns.map((column) => {
|
||||||
|
const {
|
||||||
|
name,
|
||||||
|
isVisible
|
||||||
|
} = column;
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'monitored') {
|
||||||
|
return (
|
||||||
|
<TableRowCell
|
||||||
|
key={name}
|
||||||
|
className={styles.monitored}
|
||||||
|
>
|
||||||
|
<MonitorToggleButton
|
||||||
|
monitored={monitored}
|
||||||
|
isDisabled={!artistMonitored}
|
||||||
|
isSaving={isSaving}
|
||||||
|
onPress={this.onMonitorAlbumPress}
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'title') {
|
||||||
|
return (
|
||||||
|
<TableRowCell
|
||||||
|
key={name}
|
||||||
|
className={styles.title}
|
||||||
|
>
|
||||||
|
<EpisodeTitleLink
|
||||||
|
episodeId={id}
|
||||||
|
artistId={artistId}
|
||||||
|
episodeTitle={title}
|
||||||
|
showOpenSeriesButton={false}
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'path') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
{
|
||||||
|
path
|
||||||
|
}
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'trackCount') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
{
|
||||||
|
statistics.trackCount
|
||||||
|
}
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'duration') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
{
|
||||||
|
formatTimeSpan(duration)
|
||||||
|
}
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'releaseDate') {
|
||||||
|
return (
|
||||||
|
<RelativeDateCellConnector
|
||||||
|
key={name}
|
||||||
|
date={releaseDate}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'status') {
|
||||||
|
return (
|
||||||
|
<TableRowCell
|
||||||
|
key={name}
|
||||||
|
className={styles.status}
|
||||||
|
>
|
||||||
|
<Label
|
||||||
|
title={`${totalTrackCount} tracks total. ${trackFileCount} tracks with files.`}
|
||||||
|
kind={getEpisodeCountKind(monitored, trackFileCount, trackCount)}
|
||||||
|
size={sizes.MEDIUM}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
<span>{trackFileCount} / {trackCount}</span>
|
||||||
|
}
|
||||||
|
</Label>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'actions') {
|
||||||
|
return (
|
||||||
|
<EpisodeSearchCellConnector
|
||||||
|
key={name}
|
||||||
|
episodeId={id}
|
||||||
|
artistId={artistId}
|
||||||
|
episodeTitle={title}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AlbumRow.propTypes = {
|
||||||
|
id: PropTypes.number.isRequired,
|
||||||
|
artistId: PropTypes.number.isRequired,
|
||||||
|
monitored: PropTypes.bool.isRequired,
|
||||||
|
releaseDate: PropTypes.string.isRequired,
|
||||||
|
duration: PropTypes.number.isRequired,
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
isSaving: PropTypes.bool,
|
||||||
|
unverifiedSceneNumbering: PropTypes.bool,
|
||||||
|
artistMonitored: PropTypes.bool.isRequired,
|
||||||
|
statistics: PropTypes.object.isRequired,
|
||||||
|
path: PropTypes.string,
|
||||||
|
mediaInfo: PropTypes.object,
|
||||||
|
alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
onMonitorAlbumPress: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlbumRow;
|
@ -0,0 +1,36 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
|
import Label from 'Components/Label';
|
||||||
|
import Link from 'Components/Link/Link';
|
||||||
|
import styles from './ArtistDetailsLinks.css';
|
||||||
|
|
||||||
|
function ArtistDetailsLinks(props) {
|
||||||
|
const {
|
||||||
|
foreignArtistId
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.links}>
|
||||||
|
<Link
|
||||||
|
className={styles.link}
|
||||||
|
to={`https://musicbrainz.org/artist/${foreignArtistId}`}
|
||||||
|
>
|
||||||
|
<Label
|
||||||
|
className={styles.linkLabel}
|
||||||
|
kind={kinds.INFO}
|
||||||
|
size={sizes.LARGE}
|
||||||
|
>
|
||||||
|
Musicbrainz
|
||||||
|
</Label>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArtistDetailsLinks.propTypes = {
|
||||||
|
foreignArtistId: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ArtistDetailsLinks;
|
@ -1,266 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import MonitorToggleButton from 'Components/MonitorToggleButton';
|
|
||||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
|
||||||
import TableRow from 'Components/Table/TableRow';
|
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
|
||||||
import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector';
|
|
||||||
import EpisodeNumber from 'Episode/EpisodeNumber';
|
|
||||||
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
|
||||||
import EpisodeStatusConnector from 'Episode/EpisodeStatusConnector';
|
|
||||||
import EpisodeFileLanguageConnector from 'EpisodeFile/EpisodeFileLanguageConnector';
|
|
||||||
import MediaInfoConnector from 'EpisodeFile/MediaInfoConnector';
|
|
||||||
import * as mediaInfoTypes from 'EpisodeFile/mediaInfoTypes';
|
|
||||||
|
|
||||||
import styles from './EpisodeRow.css';
|
|
||||||
|
|
||||||
class EpisodeRow extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isDetailsModalOpen: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onManualSearchPress = () => {
|
|
||||||
this.setState({ isDetailsModalOpen: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
onDetailsModalClose = () => {
|
|
||||||
this.setState({ isDetailsModalOpen: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
onMonitorEpisodePress = (monitored, options) => {
|
|
||||||
this.props.onMonitorEpisodePress(this.props.id, monitored, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
artistId,
|
|
||||||
episodeFileId,
|
|
||||||
monitored,
|
|
||||||
seasonNumber,
|
|
||||||
episodeNumber,
|
|
||||||
absoluteEpisodeNumber,
|
|
||||||
sceneSeasonNumber,
|
|
||||||
sceneEpisodeNumber,
|
|
||||||
sceneAbsoluteEpisodeNumber,
|
|
||||||
airDateUtc,
|
|
||||||
title,
|
|
||||||
unverifiedSceneNumbering,
|
|
||||||
isSaving,
|
|
||||||
seriesMonitored,
|
|
||||||
seriesType,
|
|
||||||
episodeFilePath,
|
|
||||||
episodeFileRelativePath,
|
|
||||||
alternateTitles,
|
|
||||||
columns
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow>
|
|
||||||
{
|
|
||||||
columns.map((column) => {
|
|
||||||
const {
|
|
||||||
name,
|
|
||||||
isVisible
|
|
||||||
} = column;
|
|
||||||
|
|
||||||
if (!isVisible) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'monitored') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.monitored}
|
|
||||||
>
|
|
||||||
<MonitorToggleButton
|
|
||||||
monitored={monitored}
|
|
||||||
isDisabled={!seriesMonitored}
|
|
||||||
isSaving={isSaving}
|
|
||||||
onPress={this.onMonitorEpisodePress}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'episodeNumber') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.episodeNumber}
|
|
||||||
>
|
|
||||||
<EpisodeNumber
|
|
||||||
seasonNumber={seasonNumber}
|
|
||||||
episodeNumber={episodeNumber}
|
|
||||||
absoluteEpisodeNumber={absoluteEpisodeNumber}
|
|
||||||
unverifiedSceneNumbering={unverifiedSceneNumbering}
|
|
||||||
seriesType={seriesType}
|
|
||||||
sceneSeasonNumber={sceneSeasonNumber}
|
|
||||||
sceneEpisodeNumber={sceneEpisodeNumber}
|
|
||||||
sceneAbsoluteEpisodeNumber={sceneAbsoluteEpisodeNumber}
|
|
||||||
alternateTitles={alternateTitles}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'title') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.title}
|
|
||||||
>
|
|
||||||
<EpisodeTitleLink
|
|
||||||
episodeId={id}
|
|
||||||
artistId={artistId}
|
|
||||||
episodeTitle={title}
|
|
||||||
showOpenSeriesButton={false}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'path') {
|
|
||||||
return (
|
|
||||||
<TableRowCell key={name}>
|
|
||||||
{
|
|
||||||
episodeFilePath
|
|
||||||
}
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'relativePath') {
|
|
||||||
return (
|
|
||||||
<TableRowCell key={name}>
|
|
||||||
{
|
|
||||||
episodeFileRelativePath
|
|
||||||
}
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'airDateUtc') {
|
|
||||||
return (
|
|
||||||
<RelativeDateCellConnector
|
|
||||||
key={name}
|
|
||||||
date={airDateUtc}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'language') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.language}
|
|
||||||
>
|
|
||||||
<EpisodeFileLanguageConnector
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'audioInfo') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.audio}
|
|
||||||
>
|
|
||||||
<MediaInfoConnector
|
|
||||||
type={mediaInfoTypes.AUDIO}
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'videoCodec') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.video}
|
|
||||||
>
|
|
||||||
<MediaInfoConnector
|
|
||||||
type={mediaInfoTypes.VIDEO}
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'status') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.status}
|
|
||||||
>
|
|
||||||
<EpisodeStatusConnector
|
|
||||||
episodeId={id}
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'actions') {
|
|
||||||
return (
|
|
||||||
<EpisodeSearchCellConnector
|
|
||||||
key={name}
|
|
||||||
episodeId={id}
|
|
||||||
artistId={artistId}
|
|
||||||
episodeTitle={title}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EpisodeRow.propTypes = {
|
|
||||||
id: PropTypes.number.isRequired,
|
|
||||||
artistId: PropTypes.number.isRequired,
|
|
||||||
episodeFileId: PropTypes.number,
|
|
||||||
monitored: PropTypes.bool.isRequired,
|
|
||||||
seasonNumber: PropTypes.number.isRequired,
|
|
||||||
episodeNumber: PropTypes.number.isRequired,
|
|
||||||
absoluteEpisodeNumber: PropTypes.number,
|
|
||||||
sceneSeasonNumber: PropTypes.number,
|
|
||||||
sceneEpisodeNumber: PropTypes.number,
|
|
||||||
sceneAbsoluteEpisodeNumber: PropTypes.number,
|
|
||||||
airDateUtc: PropTypes.string,
|
|
||||||
title: PropTypes.string.isRequired,
|
|
||||||
isSaving: PropTypes.bool,
|
|
||||||
unverifiedSceneNumbering: PropTypes.bool,
|
|
||||||
seriesMonitored: PropTypes.bool.isRequired,
|
|
||||||
seriesType: PropTypes.string.isRequired,
|
|
||||||
episodeFilePath: PropTypes.string,
|
|
||||||
episodeFileRelativePath: PropTypes.string,
|
|
||||||
mediaInfo: PropTypes.object,
|
|
||||||
alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
onMonitorEpisodePress: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EpisodeRow;
|
|
@ -1,70 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import { kinds, sizes } from 'Helpers/Props';
|
|
||||||
import Label from 'Components/Label';
|
|
||||||
import Link from 'Components/Link/Link';
|
|
||||||
import styles from './SeriesDetailsLinks.css';
|
|
||||||
|
|
||||||
function SeriesDetailsLinks(props) {
|
|
||||||
const {
|
|
||||||
foreignArtistId,
|
|
||||||
tvMazeId,
|
|
||||||
imdbId
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.links}>
|
|
||||||
<Link
|
|
||||||
className={styles.link}
|
|
||||||
to={`https://musicbrainz.org/artist/${foreignArtistId}`}
|
|
||||||
>
|
|
||||||
<Label
|
|
||||||
className={styles.linkLabel}
|
|
||||||
kind={kinds.INFO}
|
|
||||||
size={sizes.LARGE}
|
|
||||||
>
|
|
||||||
Musicbrainz
|
|
||||||
</Label>
|
|
||||||
</Link>
|
|
||||||
{
|
|
||||||
!!tvMazeId &&
|
|
||||||
<Link
|
|
||||||
className={styles.link}
|
|
||||||
to={`http://www.tvmaze.com/shows/${tvMazeId}/_`}
|
|
||||||
>
|
|
||||||
<Label
|
|
||||||
className={styles.linkLabel}
|
|
||||||
kind={kinds.INFO}
|
|
||||||
size={sizes.LARGE}
|
|
||||||
>
|
|
||||||
TV Maze
|
|
||||||
</Label>
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
!!imdbId &&
|
|
||||||
<Link
|
|
||||||
className={styles.link}
|
|
||||||
to={`http://imdb.com/title/${imdbId}/`}
|
|
||||||
>
|
|
||||||
<Label
|
|
||||||
className={styles.linkLabel}
|
|
||||||
kind={kinds.INFO}
|
|
||||||
size={sizes.LARGE}
|
|
||||||
>
|
|
||||||
IMDB
|
|
||||||
</Label>
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SeriesDetailsLinks.propTypes = {
|
|
||||||
foreignArtistId: PropTypes.string.isRequired,
|
|
||||||
tvMazeId: PropTypes.number,
|
|
||||||
imdbId: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SeriesDetailsLinks;
|
|
Loading…
Reference in new issue