[UI] Refactor TrackFile Modal

pull/94/head
Qstick 7 years ago
parent e3c6bc3263
commit 9be4ec4c15

@ -156,7 +156,7 @@ function HistoryDetails(props) {
);
}
if (eventType === 'episodeFileDeleted') {
if (eventType === 'trackFileDeleted') {
const {
reason
} = data;
@ -192,7 +192,7 @@ function HistoryDetails(props) {
);
}
if (eventType === 'episodeFileRenamed') {
if (eventType === 'trackFileRenamed') {
const {
sourcePath,
sourceRelativePath,

@ -19,9 +19,9 @@ function getHeaderTitle(eventType) {
return 'Download Failed';
case 'downloadFolderImported':
return 'Episode Imported';
case 'episodeFileDeleted':
case 'trackFileDeleted':
return 'Episode File Deleted';
case 'episodeFileRenamed':
case 'trackFileRenamed':
return 'Episode File Renamed';
default:
return 'Unknown';

@ -15,9 +15,9 @@ function getIconName(eventType) {
return icons.DOWNLOADED;
case 'downloadFailed':
return icons.DOWNLOADING;
case 'episodeFileDeleted':
case 'trackFileDeleted':
return icons.DELETE;
case 'episodeFileRenamed':
case 'trackFileRenamed':
return icons.ORGANIZE;
default:
return icons.UNKNOWN;
@ -43,9 +43,9 @@ function getTooltip(eventType, data) {
return 'Album downloaded successfully and picked up from download client';
case 'downloadFailed':
return 'Album download failed';
case 'episodeFileDeleted':
case 'trackFileDeleted':
return 'Track file deleted';
case 'episodeFileRenamed':
case 'trackFileRenamed':
return 'Track file renamed';
default:
return 'Unknown event';

@ -160,7 +160,7 @@ class QueueRow extends Component {
<EpisodeTitleLink
episodeId={episode.id}
artistId={series.id}
episodeFileId={episode.episodeFileId}
trackFileId={episode.trackFileId}
episodeEntity={episodeEntity}
episodeTitle={episode.title}
showOpenArtistButton={true}

@ -12,8 +12,8 @@ import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
import styles from './AlbumRow.css';
function getEpisodeCountKind(monitored, episodeFileCount, episodeCount) {
if (episodeFileCount === episodeCount && episodeCount > 0) {
function getEpisodeCountKind(monitored, trackFileCount, episodeCount) {
if (trackFileCount === episodeCount && episodeCount > 0) {
return kinds.SUCCESS;
}

@ -2,7 +2,7 @@ import _ from 'lodash';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createArtistSelector from 'Store/Selectors/createArtistSelector';
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
import createTrackFileSelector from 'Store/Selectors/createTrackFileSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
import AlbumRow from './AlbumRow';
@ -11,16 +11,16 @@ function createMapStateToProps() {
(state, { id }) => id,
(state, { sceneSeasonNumber }) => sceneSeasonNumber,
createArtistSelector(),
createEpisodeFileSelector(),
createTrackFileSelector(),
createCommandsSelector(),
(id, sceneSeasonNumber, series, episodeFile, commands) => {
(id, sceneSeasonNumber, series, trackFile, commands) => {
const alternateTitles = sceneSeasonNumber ? _.filter(series.alternateTitles, { sceneSeasonNumber }) : [];
return {
artistMonitored: series.monitored,
seriesType: series.seriesType,
episodeFilePath: episodeFile ? episodeFile.path : null,
episodeFileRelativePath: episodeFile ? episodeFile.relativePath : null,
trackFilePath: trackFile ? trackFile.path : null,
trackFileRelativePath: trackFile ? trackFile.relativePath : null,
alternateTitles
};
}

@ -18,7 +18,7 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import Popover from 'Components/Tooltip/Popover';
import Tooltip from 'Components/Tooltip/Tooltip';
import EpisodeFileEditorModal from 'EpisodeFile/Editor/EpisodeFileEditorModal';
import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal';
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfileNameConnector';
import ArtistPoster from 'Artist/ArtistPoster';
@ -179,7 +179,7 @@ class ArtistDetails extends Component {
isFetching,
isPopulated,
episodesError,
episodeFilesError,
trackFilesError,
previousArtist,
nextArtist,
onRefreshPress,
@ -198,12 +198,12 @@ class ArtistDetails extends Component {
const continuing = status === 'continuing';
let episodeFilesCountMessage = 'No track files';
let trackFilesCountMessage = 'No track files';
if (trackFileCount === 1) {
episodeFilesCountMessage = '1 track file';
trackFilesCountMessage = '1 track file';
} else if (trackFileCount > 1) {
episodeFilesCountMessage = `${trackFileCount} track files`;
trackFilesCountMessage = `${trackFileCount} track files`;
}
let expandIcon = icons.EXPAND_INDETERMINATE;
@ -345,7 +345,7 @@ class ArtistDetails extends Component {
<div className={styles.detailsLabels}>
<Label
className={styles.detailsLabel}
title={episodeFilesCountMessage}
title={trackFilesCountMessage}
size={sizes.LARGE}
>
<Icon
@ -469,7 +469,7 @@ class ArtistDetails extends Component {
<div className={styles.contentContainer}>
{
!isPopulated && !episodesError && !episodeFilesError &&
!isPopulated && !episodesError && !trackFilesError &&
<LoadingIndicator />
}
@ -479,7 +479,7 @@ class ArtistDetails extends Component {
}
{
!isFetching && episodeFilesError &&
!isFetching && trackFilesError &&
<div>Loading episode files failed</div>
}
@ -518,7 +518,7 @@ class ArtistDetails extends Component {
onModalClose={this.onOrganizeModalClose}
/>
<EpisodeFileEditorModal
<TrackFileEditorModal
isOpen={isManageEpisodesOpen}
artistId={id}
onModalClose={this.onManageEpisodesModalClose}
@ -563,7 +563,7 @@ ArtistDetails.propTypes = {
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
episodesError: PropTypes.object,
episodeFilesError: PropTypes.object,
trackFilesError: PropTypes.object,
previousArtist: PropTypes.object.isRequired,
nextArtist: PropTypes.object.isRequired,
onRefreshPress: PropTypes.func.isRequired,

@ -7,7 +7,7 @@ import { findCommand } from 'Utilities/Command';
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
import { fetchEpisodes, clearEpisodes } from 'Store/Actions/episodeActions';
import { fetchEpisodeFiles, clearEpisodeFiles } from 'Store/Actions/episodeFileActions';
import { fetchTrackFiles, clearTrackFiles } from 'Store/Actions/trackFileActions';
import { fetchQueueDetails, clearQueueDetails } from 'Store/Actions/queueActions';
import { executeCommand } from 'Store/Actions/commandActions';
import * as commandNames from 'Commands/commandNames';
@ -17,10 +17,10 @@ function createMapStateToProps() {
return createSelector(
(state, { nameSlug }) => nameSlug,
(state) => state.episodes,
(state) => state.episodeFiles,
(state) => state.trackFiles,
createAllArtistSelector(),
createCommandsSelector(),
(nameSlug, episodes, episodeFiles, allArtists, commands) => {
(nameSlug, episodes, trackFiles, allArtists, commands) => {
const sortedArtist = _.orderBy(allArtists, 'sortName');
const artistIndex = _.findIndex(sortedArtist, { nameSlug });
const series = sortedArtist[artistIndex];
@ -39,10 +39,10 @@ function createMapStateToProps() {
const isRenamingArtistCommand = findCommand(commands, { name: commandNames.RENAME_ARTIST });
const isRenamingArtist = !!(isRenamingArtistCommand && isRenamingArtistCommand.body.artistId.indexOf(series.id) > -1);
const isFetching = episodes.isFetching || episodeFiles.isFetching;
const isPopulated = episodes.isPopulated && episodeFiles.isPopulated;
const isFetching = episodes.isFetching || trackFiles.isFetching;
const isPopulated = episodes.isPopulated && trackFiles.isPopulated;
const episodesError = episodes.error;
const episodeFilesError = episodeFiles.error;
const trackFilesError = trackFiles.error;
const alternateTitles = _.reduce(series.alternateTitles, (acc, alternateTitle) => {
if ((alternateTitle.seasonNumber === -1 || alternateTitle.seasonNumber === undefined) &&
(alternateTitle.sceneSeasonNumber === -1 || alternateTitle.sceneSeasonNumber === undefined)) {
@ -62,7 +62,7 @@ function createMapStateToProps() {
isFetching,
isPopulated,
episodesError,
episodeFilesError,
trackFilesError,
previousArtist,
nextArtist
};
@ -73,8 +73,8 @@ function createMapStateToProps() {
const mapDispatchToProps = {
fetchEpisodes,
clearEpisodes,
fetchEpisodeFiles,
clearEpisodeFiles,
fetchTrackFiles,
clearTrackFiles,
fetchQueueDetails,
clearQueueDetails,
executeCommand
@ -125,13 +125,13 @@ class ArtistDetailsConnector extends Component {
const artistId = this.props.id;
this.props.fetchEpisodes({ artistId });
this.props.fetchEpisodeFiles({ artistId });
this.props.fetchTrackFiles({ artistId });
this.props.fetchQueueDetails({ artistId });
}
_unpopulate() {
this.props.clearEpisodes();
this.props.clearEpisodeFiles();
this.props.clearTrackFiles();
this.props.clearQueueDetails();
}
@ -174,8 +174,8 @@ ArtistDetailsConnector.propTypes = {
isRenamingArtist: PropTypes.bool.isRequired,
fetchEpisodes: PropTypes.func.isRequired,
clearEpisodes: PropTypes.func.isRequired,
fetchEpisodeFiles: PropTypes.func.isRequired,
clearEpisodeFiles: PropTypes.func.isRequired,
fetchTrackFiles: PropTypes.func.isRequired,
clearTrackFiles: PropTypes.func.isRequired,
fetchQueueDetails: PropTypes.func.isRequired,
clearQueueDetails: PropTypes.func.isRequired,
executeCommand: PropTypes.func.isRequired

@ -16,7 +16,7 @@ import MenuContent from 'Components/Menu/MenuContent';
import MenuItem from 'Components/Menu/MenuItem';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import EpisodeFileEditorModal from 'EpisodeFile/Editor/EpisodeFileEditorModal';
import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal';
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
import AlbumRowConnector from './AlbumRowConnector';
import styles from './ArtistDetailsSeason.css';
@ -287,7 +287,7 @@ class ArtistDetailsSeason extends Component {
onModalClose={this.onOrganizeModalClose}
/>
<EpisodeFileEditorModal
<TrackFileEditorModal
isOpen={isManageEpisodesOpen}
artistId={artistId}
onModalClose={this.onManageEpisodesModalClose}

@ -5,7 +5,7 @@ import { createSelector } from 'reselect';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
import * as calendarActions from 'Store/Actions/calendarActions';
import { fetchEpisodeFiles, clearEpisodeFiles } from 'Store/Actions/episodeFileActions';
import { fetchTrackFiles, clearTrackFiles } from 'Store/Actions/trackFileActions';
import { fetchQueueDetails, clearQueueDetails } from 'Store/Actions/queueActions';
import Calendar from './Calendar';
@ -22,8 +22,8 @@ function createMapStateToProps() {
const mapDispatchToProps = {
...calendarActions,
fetchEpisodeFiles,
clearEpisodeFiles,
fetchTrackFiles,
clearTrackFiles,
fetchQueueDetails,
clearQueueDetails
};
@ -52,12 +52,12 @@ class CalendarConnector extends Component {
if (hasDifferentItems(prevProps.items, items)) {
const albumIds = selectUniqueIds(items, 'id');
// const episodeFileIds = selectUniqueIds(items, 'episodeFileId');
// const trackFileIds = selectUniqueIds(items, 'trackFileId');
this.props.fetchQueueDetails({ albumIds });
// if (episodeFileIds.length) {
// this.props.fetchEpisodeFiles({ episodeFileIds });
// if (trackFileIds.length) {
// this.props.fetchTrackFiles({ trackFileIds });
// }
}
@ -69,7 +69,7 @@ class CalendarConnector extends Component {
componentWillUnmount() {
this.props.clearCalendar();
this.props.clearQueueDetails();
this.props.clearEpisodeFiles();
this.props.clearTrackFiles();
this.clearUpdateTimeout();
}
@ -136,8 +136,8 @@ CalendarConnector.propTypes = {
gotoCalendarPreviousRange: PropTypes.func.isRequired,
gotoCalendarNextRange: PropTypes.func.isRequired,
clearCalendar: PropTypes.func.isRequired,
fetchEpisodeFiles: PropTypes.func.isRequired,
clearEpisodeFiles: PropTypes.func.isRequired,
fetchTrackFiles: PropTypes.func.isRequired,
clearTrackFiles: PropTypes.func.isRequired,
fetchQueueDetails: PropTypes.func.isRequired,
clearQueueDetails: PropTypes.func.isRequired
};

@ -6,7 +6,7 @@ export const CLEAR_LOGS = 'ClearLog';
export const CUTOFF_UNMET_EPISODE_SEARCH = 'CutoffUnmetEpisodeSearch';
export const DELETE_LOG_FILES = 'DeleteLogFiles';
export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles';
export const DOWNLOADED_EPSIODES_SCAN = 'DownloadedEpisodesScan';
export const DOWNLOADED_ALBUMS_SCAN = 'DownloadedAlbumsScan';
export const EPISODE_SEARCH = 'AlbumSearch';
export const INTERACTIVE_IMPORT = 'ManualImport';
export const MISSING_ALBUM_SEARCH = 'MissingAlbumSearch';

@ -120,7 +120,7 @@ class SignalRConnector extends Component {
}
if (name === 'episodefile') {
this.handleEpisodeFile(body);
this.handleTrackFile(body);
return;
}
@ -206,10 +206,10 @@ class SignalRConnector extends Component {
}
}
handleEpisodeFile = (body) => {
handleTrackFile = (body) => {
if (body.action === 'updated') {
this.props.updateItem({
section: 'episodeFiles',
section: 'trackFiles',
...body.resource });
}
}

@ -8,7 +8,7 @@ import createEpisodeSelector from 'Store/Selectors/createEpisodeSelector';
import createArtistSelector from 'Store/Selectors/createArtistSelector';
import episodeEntities from 'Episode/episodeEntities';
import { fetchTracks, clearTracks } from 'Store/Actions/trackActions';
import { fetchEpisodeFiles, clearEpisodeFiles } from 'Store/Actions/episodeFileActions';
import { fetchTrackFiles, clearTrackFiles } from 'Store/Actions/trackFileActions';
import EpisodeDetailsModalContent from './EpisodeDetailsModalContent';
function createMapStateToProps() {
@ -38,8 +38,8 @@ const mapDispatchToProps = {
clearReleases,
fetchTracks,
clearTracks,
fetchEpisodeFiles,
clearEpisodeFiles,
fetchTrackFiles,
clearTrackFiles,
toggleEpisodeMonitored
};
@ -65,15 +65,14 @@ class EpisodeDetailsModalContentConnector extends Component {
const artistId = this.props.artistId;
const albumId = this.props.episodeId;
this.props.fetchTracks({ artistId, albumId });
// this.props.fetchEpisodeFiles({ artistId, albumId });
// this.props.fetchTrackFiles({ artistId, albumId });
}
_unpopulate() {
this.props.clearTracks();
// this.props.clearEpisodeFiles();
// this.props.clearTrackFiles();
}
//
// Listeners
@ -109,8 +108,8 @@ EpisodeDetailsModalContentConnector.propTypes = {
artistId: PropTypes.number.isRequired,
fetchTracks: PropTypes.func.isRequired,
clearTracks: PropTypes.func.isRequired,
fetchEpisodeFiles: PropTypes.func.isRequired,
clearEpisodeFiles: PropTypes.func.isRequired,
fetchTrackFiles: PropTypes.func.isRequired,
clearTrackFiles: PropTypes.func.isRequired,
clearReleases: PropTypes.func.isRequired,
toggleEpisodeMonitored: PropTypes.func.isRequired
};

@ -14,10 +14,10 @@ function EpisodeStatus(props) {
monitored,
grabbed,
queueItem,
episodeFile
trackFile
} = props;
const hasEpisodeFile = !!episodeFile;
const hasTrackFile = !!trackFile;
const isQueued = !!queueItem;
const hasAired = isBefore(airDateUtc);
@ -57,15 +57,15 @@ function EpisodeStatus(props) {
);
}
if (hasEpisodeFile) {
const quality = episodeFile.quality;
const isCutoffNotMet = episodeFile.qualityCutoffNotMet;
if (hasTrackFile) {
const quality = trackFile.quality;
const isCutoffNotMet = trackFile.qualityCutoffNotMet;
return (
<div className={styles.center}>
<EpisodeQuality
quality={quality}
size={episodeFile.size}
size={trackFile.size}
isCutoffNotMet={isCutoffNotMet}
title="Episode Downloaded"
/>
@ -121,7 +121,7 @@ EpisodeStatus.propTypes = {
monitored: PropTypes.bool,
grabbed: PropTypes.bool,
queueItem: PropTypes.object,
episodeFile: PropTypes.object
trackFile: PropTypes.object
};
export default EpisodeStatus;

@ -5,15 +5,15 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createEpisodeSelector from 'Store/Selectors/createEpisodeSelector';
import createQueueItemSelector from 'Store/Selectors/createQueueItemSelector';
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
import createTrackFileSelector from 'Store/Selectors/createTrackFileSelector';
import EpisodeStatus from './EpisodeStatus';
function createMapStateToProps() {
return createSelector(
createEpisodeSelector(),
createQueueItemSelector(),
createEpisodeFileSelector(),
(episode, queueItem, episodeFile) => {
createTrackFileSelector(),
(episode, queueItem, trackFile) => {
const result = _.pick(episode, [
'airDateUtc',
'monitored',
@ -21,7 +21,7 @@ function createMapStateToProps() {
]);
result.queueItem = queueItem;
result.episodeFile = episodeFile;
result.trackFile = trackFile;
return result;
}
@ -47,7 +47,7 @@ class EpisodeStatusConnector extends Component {
EpisodeStatusConnector.propTypes = {
episodeId: PropTypes.number.isRequired,
episodeFileId: PropTypes.number.isRequired
trackFileId: PropTypes.number.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(EpisodeStatusConnector);

@ -22,24 +22,24 @@ class EpisodeSummary extends Component {
super(props, context);
this.state = {
isRemoveEpisodeFileModalOpen: false
isRemoveTrackFileModalOpen: false
};
}
//
// Listeners
onRemoveEpisodeFilePress = () => {
this.setState({ isRemoveEpisodeFileModalOpen: true });
onRemoveTrackFilePress = () => {
this.setState({ isRemoveTrackFileModalOpen: true });
}
onConfirmRemoveEpisodeFile = () => {
this.props.onDeleteEpisodeFile();
this.setState({ isRemoveEpisodeFileModalOpen: false });
onConfirmRemoveTrackFile = () => {
this.props.onDeleteTrackFile();
this.setState({ isRemoveTrackFileModalOpen: false });
}
onRemoveEpisodeFileModalClose = () => {
this.setState({ isRemoveEpisodeFileModalOpen: false });
onRemoveTrackFileModalClose = () => {
this.setState({ isRemoveTrackFileModalOpen: false });
}
//
@ -125,13 +125,13 @@ class EpisodeSummary extends Component {
</div>
<ConfirmModal
isOpen={this.state.isRemoveEpisodeFileModalOpen}
isOpen={this.state.isRemoveTrackFileModalOpen}
kind={kinds.DANGER}
title="Delete Episode File"
message={`Are you sure you want to delete '${path}'?`}
confirmLabel="Delete"
onConfirm={this.onConfirmRemoveEpisodeFile}
onCancel={this.onRemoveEpisodeFileModalClose}
onConfirm={this.onConfirmRemoveTrackFile}
onCancel={this.onRemoveTrackFileModalClose}
/>
</div>
);
@ -149,7 +149,7 @@ EpisodeSummary.propTypes = {
size: PropTypes.number,
quality: PropTypes.object,
qualityCutoffNotMet: PropTypes.bool,
onDeleteEpisodeFile: PropTypes.func.isRequired
onDeleteTrackFile: PropTypes.func.isRequired
};
export default EpisodeSummary;

@ -1,9 +1,8 @@
import _ from 'lodash';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteEpisodeFile } from 'Store/Actions/episodeFileActions';
import { deleteTrackFile } from 'Store/Actions/trackFileActions';
import createEpisodeSelector from 'Store/Selectors/createEpisodeSelector';
import createTrackSelector from 'Store/Selectors/createTrackSelector';
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import createArtistSelector from 'Store/Selectors/createArtistSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
@ -11,18 +10,19 @@ import EpisodeSummary from './EpisodeSummary';
function createMapStateToProps() {
return createSelector(
(state, { episode }) => episode,
(state) => state.tracks,
createEpisodeSelector(),
createCommandsSelector(),
createDimensionsSelector(),
(albumId, tracks, episode, commands, dimensions) => {
(tracks, episode, commands, dimensions) => {
const items = _.filter(tracks.items, { albumId: episode.id });
return {
network: episode.label,
qualityProfileId: episode.profileId,
airDateUtc: episode.releaseDate,
overview: episode.overview,
items: tracks.items,
items,
columns: tracks.columns
};
}
@ -31,9 +31,9 @@ function createMapStateToProps() {
function createMapDispatchToProps(dispatch, props) {
return {
onDeleteEpisodeFile() {
dispatch(deleteEpisodeFile({
id: props.episodeFileId,
onDeleteTrackFile() {
dispatch(deleteTrackFile({
id: props.trackFileId,
episodeEntity: props.episodeEntity
}));
}

@ -3,8 +3,8 @@ import React, { Component } from 'react';
import TableRow from 'Components/Table/TableRow';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
import MediaInfoConnector from 'EpisodeFile/MediaInfoConnector';
import * as mediaInfoTypes from 'EpisodeFile/mediaInfoTypes';
import MediaInfoConnector from 'TrackFile/MediaInfoConnector';
import * as mediaInfoTypes from 'TrackFile/mediaInfoTypes';
import EpisodeStatusConnector from 'Episode/EpisodeStatusConnector';
import styles from './TrackDetailRow.css';
@ -83,7 +83,7 @@ class TrackDetailRow extends Component {
>
<MediaInfoConnector
type={mediaInfoTypes.AUDIO}
episodeFileId={trackFileId}
trackFileId={trackFileId}
/>
</TableRowCell>
);
@ -97,7 +97,7 @@ class TrackDetailRow extends Component {
>
<EpisodeStatusConnector
episodeId={id}
episodeFileId={trackFileId}
trackFileId={trackFileId}
/>
</TableRowCell>
);

@ -32,7 +32,7 @@ class InteractiveImportSelectFolderModalContentConnector extends Component {
this.props.addRecentFolder({ folder });
this.props.executeCommand({
name: commandNames.DOWNLOADED_EPSIODES_SCAN,
name: commandNames.DOWNLOADED_ALBUMS_SCAN,
path: folder
});

@ -236,7 +236,7 @@ class InteractiveImportModalContent extends Component {
{
isPopulated && !items.length &&
'No video files were found in the selected folder'
'No audio files were found in the selected folder'
}
</ModalBody>

@ -95,11 +95,11 @@ export const CLEAR_TRACKS = 'CLEAR_TRACKS';
//
// Episode Files
export const FETCH_EPISODE_FILES = 'FETCH_EPISODE_FILES';
export const CLEAR_EPISODE_FILES = 'CLEAR_EPISODE_FILES';
export const DELETE_EPISODE_FILE = 'DELETE_EPISODE_FILE';
export const DELETE_EPISODE_FILES = 'DELETE_EPISODE_FILES';
export const UPDATE_EPISODE_FILES = 'UPDATE_EPISODE_FILES';
export const FETCH_TRACK_FILES = 'FETCH_TRACK_FILES';
export const CLEAR_TRACK_FILES = 'CLEAR_TRACK_FILES';
export const DELETE_TRACK_FILE = 'DELETE_TRACK_FILE';
export const DELETE_TRACK_FILES = 'DELETE_TRACK_FILES';
export const UPDATE_TRACK_FILES = 'UPDATE_TRACK_FILES';
//
// Episode History

@ -1,9 +0,0 @@
import { createAction } from 'redux-actions';
import * as types from './actionTypes';
import episodeFileActionHandlers from './episodeFileActionHandlers';
export const fetchEpisodeFiles = episodeFileActionHandlers[types.FETCH_EPISODE_FILES];
export const deleteEpisodeFile = episodeFileActionHandlers[types.DELETE_EPISODE_FILE];
export const deleteEpisodeFiles = episodeFileActionHandlers[types.DELETE_EPISODE_FILES];
export const updateEpisodeFiles = episodeFileActionHandlers[types.UPDATE_EPISODE_FILES];
export const clearEpisodeFiles = createAction(types.CLEAR_EPISODE_FILES);

@ -7,33 +7,33 @@ import createRemoveItemHandler from './Creators/createRemoveItemHandler';
import * as types from './actionTypes';
import { set, removeItem, updateItem } from './baseActions';
const section = 'episodeFiles';
const deleteEpisodeFile = createRemoveItemHandler(section, '/trackFile');
const section = 'trackFiles';
const deleteTrackFile = createRemoveItemHandler(section, '/trackFile');
const episodeFileActionHandlers = {
[types.FETCH_EPISODE_FILES]: createFetchHandler(section, '/trackFile'),
const trackFileActionHandlers = {
[types.FETCH_TRACK_FILES]: createFetchHandler(section, '/trackFile'),
[types.DELETE_EPISODE_FILE]: function(payload) {
[types.DELETE_TRACK_FILE]: function(payload) {
return function(dispatch, getState) {
const {
id: episodeFileId,
id: trackFileId,
episodeEntity = episodeEntities.EPISODES
} = payload;
const episodeSection = _.last(episodeEntity.split('.'));
const deletePromise = deleteEpisodeFile(payload)(dispatch, getState);
const deletePromise = deleteTrackFile(payload)(dispatch, getState);
deletePromise.done(() => {
const episodes = getState().episodes.items;
const episodesWithRemovedFiles = _.filter(episodes, { episodeFileId });
const episodesWithRemovedFiles = _.filter(episodes, { trackFileId });
dispatch(batchActions([
...episodesWithRemovedFiles.map((episode) => {
return updateItem({
section: episodeSection,
...episode,
episodeFileId: 0,
trackFileId: 0,
hasFile: false
});
})
@ -42,31 +42,31 @@ const episodeFileActionHandlers = {
};
},
[types.DELETE_EPISODE_FILES]: function(payload) {
[types.DELETE_TRACK_FILES]: function(payload) {
return function(dispatch, getState) {
const {
episodeFileIds
trackFileIds
} = payload;
dispatch(set({ section, isDeleting: true }));
const promise = $.ajax({
url: '/episodeFile/bulk',
url: '/trackFile/bulk',
method: 'DELETE',
dataType: 'json',
data: JSON.stringify({ episodeFileIds })
data: JSON.stringify({ trackFileIds })
});
promise.done(() => {
const episodes = getState().episodes.items;
const episodesWithRemovedFiles = episodeFileIds.reduce((acc, episodeFileId) => {
acc.push(..._.filter(episodes, { episodeFileId }));
const episodesWithRemovedFiles = trackFileIds.reduce((acc, trackFileId) => {
acc.push(..._.filter(episodes, { trackFileId }));
return acc;
}, []);
dispatch(batchActions([
...episodeFileIds.map((id) => {
...trackFileIds.map((id) => {
return removeItem({ section, id });
}),
@ -74,7 +74,7 @@ const episodeFileActionHandlers = {
return updateItem({
section: 'episodes',
...episode,
episodeFileId: 0,
trackFileId: 0,
hasFile: false
});
}),
@ -97,10 +97,10 @@ const episodeFileActionHandlers = {
};
},
[types.UPDATE_EPISODE_FILES]: function(payload) {
[types.UPDATE_TRACK_FILES]: function(payload) {
return function(dispatch, getState) {
const {
episodeFileIds,
trackFileIds,
language,
quality
} = payload;
@ -108,7 +108,7 @@ const episodeFileActionHandlers = {
dispatch(set({ section, isSaving: true }));
const data = {
episodeFileIds
trackFileIds
};
if (language) {
@ -120,7 +120,7 @@ const episodeFileActionHandlers = {
}
const promise = $.ajax({
url: '/episodeFile/editor',
url: '/trackFile/editor',
method: 'PUT',
dataType: 'json',
data: JSON.stringify(data)
@ -128,7 +128,7 @@ const episodeFileActionHandlers = {
promise.done(() => {
dispatch(batchActions([
...episodeFileIds.map((id) => {
...trackFileIds.map((id) => {
const props = {};
if (language) {
@ -161,4 +161,4 @@ const episodeFileActionHandlers = {
}
};
export default episodeFileActionHandlers;
export default trackFileActionHandlers;

@ -0,0 +1,9 @@
import { createAction } from 'redux-actions';
import * as types from './actionTypes';
import trackFileActionHandlers from './trackFileActionHandlers';
export const fetchTrackFiles = trackFileActionHandlers[types.FETCH_TRACK_FILES];
export const deleteTrackFile = trackFileActionHandlers[types.DELETE_TRACK_FILE];
export const deleteTrackFiles = trackFileActionHandlers[types.DELETE_TRACK_FILES];
export const updateTrackFiles = trackFileActionHandlers[types.UPDATE_TRACK_FILES];
export const clearTrackFiles = createAction(types.CLEAR_TRACK_FILES);

@ -14,7 +14,7 @@ import queue, { defaultState as defaultQueueState } from './queueReducers';
import blacklist, { defaultState as defaultBlacklistState } from './blacklistReducers';
import episodes, { defaultState as defaultEpisodesState } from './episodeReducers';
import tracks, { defaultState as defaultTracksState } from './trackReducers';
import episodeFiles, { defaultState as defaultEpisodeFilesState } from './episodeFileReducers';
import trackFiles, { defaultState as defaultTrackFilesState } from './trackFileReducers';
import albumHistory, { defaultState as defaultAlbumHistoryState } from './albumHistoryReducers';
import releases, { defaultState as defaultReleasesState } from './releaseReducers';
import wanted, { defaultState as defaultWantedState } from './wantedReducers';
@ -43,7 +43,7 @@ export const defaultState = {
blacklist: defaultBlacklistState,
episodes: defaultEpisodesState,
tracks: defaultTracksState,
episodeFiles: defaultEpisodeFilesState,
trackFiles: defaultTrackFilesState,
albumHistory: defaultAlbumHistoryState,
releases: defaultReleasesState,
wanted: defaultWantedState,
@ -73,7 +73,7 @@ export default enableBatching(combineReducers({
blacklist,
episodes,
tracks,
episodeFiles,
trackFiles,
albumHistory,
releases,
wanted,

@ -16,19 +16,19 @@ export const defaultState = {
items: []
};
const reducerSection = 'episodeFiles';
const reducerSection = 'trackFiles';
const episodeFileReducers = handleActions({
const trackFileReducers = handleActions({
[types.SET]: createSetReducer(reducerSection),
[types.UPDATE]: createUpdateReducer(reducerSection),
[types.UPDATE_ITEM]: createUpdateItemReducer(reducerSection),
[types.REMOVE_ITEM]: createRemoveItemReducer(reducerSection),
[types.CLEAR_EPISODE_FILES]: (state) => {
[types.CLEAR_TRACK_FILES]: (state) => {
return Object.assign({}, state, defaultState);
}
}, defaultState);
export default episodeFileReducers;
export default trackFileReducers;

@ -1,18 +0,0 @@
import _ from 'lodash';
import { createSelector } from 'reselect';
function createEpisodeFileSelector() {
return createSelector(
(state, { episodeFileId }) => episodeFileId,
(state) => state.episodeFiles,
(episodeFileId, episodeFiles) => {
if (!episodeFileId) {
return null;
}
return _.find(episodeFiles.items, { id: episodeFileId });
}
);
}
export default createEpisodeFileSelector;

@ -0,0 +1,18 @@
import _ from 'lodash';
import { createSelector } from 'reselect';
function createTrackFileSelector() {
return createSelector(
(state, { trackFileId }) => trackFileId,
(state) => state.trackFiles,
(trackFileId, trackFiles) => {
if (!trackFileId) {
return null;
}
return _.find(trackFiles.items, { id: trackFileId });
}
);
}
export default createTrackFileSelector;

@ -1,9 +1,9 @@
import PropTypes from 'prop-types';
import React from 'react';
import Modal from 'Components/Modal/Modal';
import EpisodeFileEditorModalContentConnector from './EpisodeFileEditorModalContentConnector';
import TrackFileEditorModalContentConnector from './TrackFileEditorModalContentConnector';
function EpisodeFileEditorModal(props) {
function TrackFileEditorModal(props) {
const {
isOpen,
onModalClose,
@ -17,7 +17,7 @@ function EpisodeFileEditorModal(props) {
>
{
isOpen &&
<EpisodeFileEditorModalContentConnector
<TrackFileEditorModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
@ -26,9 +26,9 @@ function EpisodeFileEditorModal(props) {
);
}
EpisodeFileEditorModal.propTypes = {
TrackFileEditorModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default EpisodeFileEditorModal;
export default TrackFileEditorModal;

@ -15,13 +15,13 @@ import ModalBody from 'Components/Modal/ModalBody';
import ModalFooter from 'Components/Modal/ModalFooter';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import EpisodeFileEditorRow from './EpisodeFileEditorRow';
import styles from './EpisodeFileEditorModalContent.css';
import TrackFileEditorRow from './TrackFileEditorRow';
import styles from './TrackFileEditorModalContent.css';
const columns = [
{
name: 'episodeNumber',
label: 'Episode',
name: 'trackNumber',
label: 'Track',
isVisible: true
},
{
@ -29,11 +29,6 @@ const columns = [
label: 'Relative Path',
isVisible: true
},
{
name: 'airDateUtc',
label: 'Air Date',
isVisible: true
},
{
name: 'language',
label: 'Language',
@ -46,7 +41,7 @@ const columns = [
}
];
class EpisodeFileEditorModalContent extends Component {
class TrackFileEditorModalContent extends Component {
//
// Lifecycle
@ -76,7 +71,7 @@ class EpisodeFileEditorModalContent extends Component {
const selectedIds = getSelectedIds(this.state.selectedState);
return _.uniq(_.map(selectedIds, (id) => {
return _.find(this.props.items, { id }).episodeFileId;
return _.find(this.props.items, { id }).trackFileId;
}));
}
@ -135,7 +130,6 @@ class EpisodeFileEditorModalContent extends Component {
items,
languages,
qualities,
seriesType,
onModalClose
} = this.props;
@ -169,14 +163,14 @@ class EpisodeFileEditorModalContent extends Component {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Manage Episodes
Manage Tracks
</ModalHeader>
<ModalBody>
{
!items.length &&
<div>
No episode files to manage.
No track files to manage.
</div>
}
@ -193,9 +187,8 @@ class EpisodeFileEditorModalContent extends Component {
{
items.map((item) => {
return (
<EpisodeFileEditorRow
<TrackFileEditorRow
key={item.id}
seriesType={seriesType}
isSelected={selectedState[item.id]}
{...item}
onSelectedChange={this.onSelectedChange}
@ -250,8 +243,8 @@ class EpisodeFileEditorModalContent extends Component {
<ConfirmModal
isOpen={isConfirmDeleteModalOpen}
kind={kinds.DANGER}
title="Delete Selected Episode Files"
message={'Are you sure you want to delete the selected episode files?'}
title="Delete Selected Track Files"
message={'Are you sure you want to delete the selected track files?'}
confirmLabel="Delete"
onConfirm={this.onConfirmDelete}
onCancel={this.onConfirmDeleteModalClose}
@ -261,16 +254,15 @@ class EpisodeFileEditorModalContent extends Component {
}
}
EpisodeFileEditorModalContent.propTypes = {
TrackFileEditorModalContent.propTypes = {
isDeleting: PropTypes.bool.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
qualities: PropTypes.arrayOf(PropTypes.object).isRequired,
seriesType: PropTypes.string.isRequired,
onDeletePress: PropTypes.func.isRequired,
onLanguageChange: PropTypes.func.isRequired,
onQualityChange: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default EpisodeFileEditorModalContent;
export default TrackFileEditorModalContent;

@ -4,48 +4,49 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createArtistSelector from 'Store/Selectors/createArtistSelector';
import { deleteEpisodeFiles, updateEpisodeFiles } from 'Store/Actions/episodeFileActions';
import { deleteTrackFiles, updateTrackFiles } from 'Store/Actions/trackFileActions';
import { fetchTracks, clearTracks } from 'Store/Actions/trackActions';
import { fetchLanguageProfileSchema, fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
import EpisodeFileEditorModalContent from './EpisodeFileEditorModalContent';
import TrackFileEditorModalContent from './TrackFileEditorModalContent';
function createMapStateToProps() {
return createSelector(
(state, { seasonNumber }) => seasonNumber,
(state) => state.episodes,
(state) => state.episodeFiles,
(state, { albumId }) => albumId,
(state) => state.tracks,
(state) => state.trackFiles,
(state) => state.settings.languageProfiles.schema,
(state) => state.settings.qualityProfiles.schema,
createArtistSelector(),
(
seasonNumber,
episodes,
episodeFiles,
albumId,
tracks,
trackFiles,
languageProfilesSchema,
qualityProfileSchema,
series
) => {
const filtered = _.filter(episodes.items, (episode) => {
if (seasonNumber >= 0 && episode.seasonNumber !== seasonNumber) {
const filtered = _.filter(tracks.items, (track) => {
if (albumId >= 0 && track.albumId !== albumId) {
return false;
}
if (!episode.episodeFileId) {
if (!track.trackFileId) {
return false;
}
return _.some(episodeFiles.items, { id: episode.episodeFileId });
return _.some(trackFiles.items, { id: track.trackFileId });
});
const sorted = _.orderBy(filtered, ['seasonNumber', 'episodeNumber'], ['desc', 'desc']);
const sorted = _.orderBy(filtered, ['albumId', 'trackNumber'], ['desc', 'asc']);
const items = _.map(sorted, (episode) => {
const episodeFile = _.find(episodeFiles.items, { id: episode.episodeFileId });
const items = _.map(sorted, (track) => {
const trackFile = _.find(trackFiles.items, { id: track.trackFileId });
return {
relativePath: episodeFile.relativePath,
language: episodeFile.language,
quality: episodeFile.quality,
...episode
relativePath: trackFile.relativePath,
language: trackFile.language,
quality: trackFile.quality,
...track
};
});
@ -55,8 +56,8 @@ function createMapStateToProps() {
return {
items,
seriesType: series.seriesType,
isDeleting: episodeFiles.isDeleting,
isSaving: episodeFiles.isSaving,
isDeleting: trackFiles.isDeleting,
isSaving: trackFiles.isSaving,
languages,
qualities
};
@ -66,6 +67,14 @@ function createMapStateToProps() {
function createMapDispatchToProps(dispatch, props) {
return {
dispatchClearTracks() {
dispatch(clearTracks());
},
dispatchFetchTracks(updateProps) {
dispatch(fetchTracks(updateProps));
},
dispatchFetchLanguageProfileSchema(name, path) {
dispatch(fetchLanguageProfileSchema());
},
@ -74,16 +83,15 @@ function createMapDispatchToProps(dispatch, props) {
dispatch(fetchQualityProfileSchema());
},
dispatchUpdateEpisodeFiles(updateProps) {
dispatch(updateEpisodeFiles(updateProps));
dispatchUpdateTrackFiles(updateProps) {
dispatch(updateTrackFiles(updateProps));
},
onDeletePress(episodeFileIds) {
dispatch(deleteEpisodeFiles({ episodeFileIds }));
onDeletePress(trackFileIds) {
dispatch(deleteTrackFiles({ trackFileIds }));
},
onQualityChange(episodeFileIds, qualityId) {
onQualityChange(trackFileIds, qualityId) {
const quality = {
quality: _.find(this.props.qualities, { id: qualityId }),
revision: {
@ -92,34 +100,42 @@ function createMapDispatchToProps(dispatch, props) {
}
};
dispatch(updateEpisodeFiles({ episodeFileIds, quality }));
dispatch(updateTrackFiles({ trackFileIds, quality }));
}
};
}
class EpisodeFileEditorModalContentConnector extends Component {
class TrackFileEditorModalContentConnector extends Component {
//
// Lifecycle
componentDidMount() {
const artistId = this.props.artistId;
this.props.dispatchFetchTracks({ artistId });
this.props.dispatchFetchLanguageProfileSchema();
this.props.dispatchFetchQualityProfileSchema();
}
componentWillUnmount() {
this.props.dispatchClearTracks();
}
//
// Render
//
// Listeners
onLanguageChange = (episodeFileIds, languageId) => {
onLanguageChange = (trackFileIds, languageId) => {
const language = _.find(this.props.languages, { id: languageId });
this.props.dispatchUpdateEpisodeFiles({ episodeFileIds, language });
this.props.dispatchUpdateTrackFiles({ trackFileIds, language });
}
onQualityChange = (episodeFileIds, qualityId) => {
onQualityChange = (trackFileIds, qualityId) => {
const quality = {
quality: _.find(this.props.qualities, { id: qualityId }),
revision: {
@ -128,19 +144,21 @@ class EpisodeFileEditorModalContentConnector extends Component {
}
};
this.props.dispatchUpdateEpisodeFiles({ episodeFileIds, quality });
this.props.dispatchUpdateTrackFiles({ trackFileIds, quality });
}
render() {
const {
dispatchFetchLanguageProfileSchema,
dispatchFetchQualityProfileSchema,
dispatchUpdateEpisodeFiles,
dispatchUpdateTrackFiles,
dispatchFetchTracks,
dispatchClearTracks,
...otherProps
} = this.props;
return (
<EpisodeFileEditorModalContent
<TrackFileEditorModalContent
{...otherProps}
onLanguageChange={this.onLanguageChange}
onQualityChange={this.onQualityChange}
@ -149,14 +167,16 @@ class EpisodeFileEditorModalContentConnector extends Component {
}
}
EpisodeFileEditorModalContentConnector.propTypes = {
TrackFileEditorModalContentConnector.propTypes = {
artistId: PropTypes.number.isRequired,
seasonNumber: PropTypes.number,
albumId: PropTypes.number,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
qualities: PropTypes.arrayOf(PropTypes.object).isRequired,
dispatchFetchTracks: PropTypes.func.isRequired,
dispatchClearTracks: PropTypes.func.isRequired,
dispatchFetchLanguageProfileSchema: PropTypes.func.isRequired,
dispatchFetchQualityProfileSchema: PropTypes.func.isRequired,
dispatchUpdateEpisodeFiles: PropTypes.func.isRequired
dispatchUpdateTrackFiles: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, createMapDispatchToProps)(EpisodeFileEditorModalContentConnector);
export default connect(createMapStateToProps, createMapDispatchToProps)(TrackFileEditorModalContentConnector);

@ -7,17 +7,13 @@ import TableRow from 'Components/Table/TableRow';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import EpisodeQuality from 'Episode/EpisodeQuality';
import styles from './EpisodeFileEditorRow';
import styles from './TrackFileEditorRow';
function EpisodeFileEditorRow(props) {
function TrackFileEditorRow(props) {
const {
id,
seriesType,
seasonNumber,
episodeNumber,
absoluteEpisodeNumber,
trackNumber,
relativePath,
airDateUtc,
language,
quality,
isSelected,
@ -33,24 +29,13 @@ function EpisodeFileEditorRow(props) {
/>
<TableRowCell>
{seasonNumber}x{padNumber(episodeNumber, 2)}
{
seriesType === 'anime' && !!absoluteEpisodeNumber &&
<span className={styles.absoluteEpisodeNumber}>
({absoluteEpisodeNumber})
</span>
}
{padNumber(trackNumber, 2)}
</TableRowCell>
<TableRowCell>
{relativePath}
</TableRowCell>
<RelativeDateCellConnector
date={airDateUtc}
/>
<TableRowCell>
<Label>
{language.name}
@ -66,18 +51,14 @@ function EpisodeFileEditorRow(props) {
);
}
EpisodeFileEditorRow.propTypes = {
TrackFileEditorRow.propTypes = {
id: PropTypes.number.isRequired,
seriesType: PropTypes.string.isRequired,
seasonNumber: PropTypes.number.isRequired,
episodeNumber: PropTypes.number.isRequired,
absoluteEpisodeNumber: PropTypes.number,
trackNumber: PropTypes.number.isRequired,
relativePath: PropTypes.string.isRequired,
airDateUtc: PropTypes.string.isRequired,
language: PropTypes.object.isRequired,
quality: PropTypes.object.isRequired,
isSelected: PropTypes.bool,
onSelectedChange: PropTypes.func.isRequired
};
export default EpisodeFileEditorRow;
export default TrackFileEditorRow;

@ -39,7 +39,6 @@ function MediaInfo(props) {
);
}
return null;
}

@ -1,15 +1,15 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
import createTrackFileSelector from 'Store/Selectors/createTrackFileSelector';
import MediaInfo from './MediaInfo';
function createMapStateToProps() {
return createSelector(
createEpisodeFileSelector(),
(episodeFile) => {
if (episodeFile) {
createTrackFileSelector(),
(trackFile) => {
if (trackFile) {
return {
...episodeFile.mediaInfo
...trackFile.mediaInfo
};
}

@ -1,14 +1,14 @@
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
import createTrackFileSelector from 'Store/Selectors/createTrackFileSelector';
import EpisodeLanguage from 'Episode/EpisodeLanguage';
function createMapStateToProps() {
return createSelector(
createEpisodeFileSelector(),
(episodeFile) => {
createTrackFileSelector(),
(trackFile) => {
return {
language: episodeFile ? episodeFile.language : undefined
language: trackFile ? trackFile.language : undefined
};
}
);

@ -9,7 +9,7 @@ import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
import * as wantedActions from 'Store/Actions/wantedActions';
import { executeCommand } from 'Store/Actions/commandActions';
import { fetchQueueDetails, clearQueueDetails } from 'Store/Actions/queueActions';
import { fetchEpisodeFiles, clearEpisodeFiles } from 'Store/Actions/episodeFileActions';
import { fetchTrackFiles, clearTrackFiles } from 'Store/Actions/trackFileActions';
import * as commandNames from 'Commands/commandNames';
import CutoffUnmet from './CutoffUnmet';
@ -36,8 +36,8 @@ const mapDispatchToProps = {
executeCommand,
fetchQueueDetails,
clearQueueDetails,
fetchEpisodeFiles,
clearEpisodeFiles
fetchTrackFiles,
clearTrackFiles
};
class CutoffUnmetConnector extends Component {
@ -52,12 +52,12 @@ class CutoffUnmetConnector extends Component {
componentDidUpdate(prevProps) {
if (hasDifferentItems(prevProps.items, this.props.items)) {
const albumIds = selectUniqueIds(this.props.items, 'id');
const episodeFileIds = selectUniqueIds(this.props.items, 'episodeFileId');
const trackFileIds = selectUniqueIds(this.props.items, 'trackFileId');
this.props.fetchQueueDetails({ albumIds });
if (episodeFileIds.length) {
this.props.fetchEpisodeFiles({ episodeFileIds });
if (trackFileIds.length) {
this.props.fetchTrackFiles({ trackFileIds });
}
}
}
@ -65,7 +65,7 @@ class CutoffUnmetConnector extends Component {
componentWillUnmount() {
this.props.clearCutoffUnmet();
this.props.clearQueueDetails();
this.props.clearEpisodeFiles();
this.props.clearTrackFiles();
}
//
@ -173,8 +173,8 @@ CutoffUnmetConnector.propTypes = {
executeCommand: PropTypes.func.isRequired,
fetchQueueDetails: PropTypes.func.isRequired,
clearQueueDetails: PropTypes.func.isRequired,
fetchEpisodeFiles: PropTypes.func.isRequired,
clearEpisodeFiles: PropTypes.func.isRequired
fetchTrackFiles: PropTypes.func.isRequired,
clearTrackFiles: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(CutoffUnmetConnector);

@ -5,7 +5,7 @@ import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
import EpisodeStatusConnector from 'Episode/EpisodeStatusConnector';
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector';
import EpisodeFileLanguageConnector from 'EpisodeFile/EpisodeFileLanguageConnector';
import TrackFileLanguageConnector from 'TrackFile/TrackFileLanguageConnector';
import ArtistNameLink from 'Artist/ArtistNameLink';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRow from 'Components/Table/TableRow';
@ -16,7 +16,7 @@ import styles from './CutoffUnmetRow.css';
function CutoffUnmetRow(props) {
const {
id,
episodeFileId,
trackFileId,
series,
seasonNumber,
episodeNumber,
@ -109,8 +109,8 @@ function CutoffUnmetRow(props) {
key={name}
className={styles.language}
>
<EpisodeFileLanguageConnector
episodeFileId={episodeFileId}
<TrackFileLanguageConnector
trackFileId={trackFileId}
/>
</TableRowCell>
);
@ -124,7 +124,7 @@ function CutoffUnmetRow(props) {
>
<EpisodeStatusConnector
episodeId={id}
episodeFileId={episodeFileId}
trackFileId={trackFileId}
episodeEntity={episodeEntities.WANTED_CUTOFF_UNMET}
/>
</TableRowCell>
@ -151,7 +151,7 @@ function CutoffUnmetRow(props) {
CutoffUnmetRow.propTypes = {
id: PropTypes.number.isRequired,
episodeFileId: PropTypes.number,
trackFileId: PropTypes.number,
series: PropTypes.object.isRequired,
seasonNumber: PropTypes.number.isRequired,
episodeNumber: PropTypes.number.isRequired,

@ -15,7 +15,7 @@ import styles from './MissingRow.css';
function MissingRow(props) {
const {
id,
// episodeFileId,
// trackFileId,
artist,
// seasonNumber,
// episodeNumber,
@ -110,7 +110,7 @@ function MissingRow(props) {
// >
// <EpisodeStatusConnector
// episodeId={id}
// episodeFileId={episodeFileId}
// trackFileId={trackFileId}
// episodeEntity={episodeEntities.WANTED_MISSING}
// />
// </TableRowCell>
@ -137,7 +137,7 @@ function MissingRow(props) {
MissingRow.propTypes = {
id: PropTypes.number.isRequired,
// episodeFileId: PropTypes.number,
// trackFileId: PropTypes.number,
artist: PropTypes.object.isRequired,
// seasonNumber: PropTypes.number.isRequired,
// episodeNumber: PropTypes.number.isRequired,

@ -11,7 +11,6 @@ using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Music;
using NzbDrone.SignalR;
using Lidarr.Api.V3.Series;
using Lidarr.Http;
using Lidarr.Http.Extensions;
using Lidarr.Http.REST;
@ -49,16 +48,16 @@ namespace Lidarr.Api.V3.TrackFiles
UpdateResource = SetQuality;
DeleteResource = DeleteTrackFile;
Put["/editor"] = episodeFiles => SetQuality();
Delete["/bulk"] = episodeFiles => DeleteTrackFiles();
Put["/editor"] = trackFiles => SetQuality();
Delete["/bulk"] = trackFiles => DeleteTrackFiles();
}
private TrackFileResource GetTrackFile(int id)
{
var trackFile = _mediaFileService.Get(id);
var series = _artistService.GetArtist(trackFile.ArtistId);
var artist = _artistService.GetArtist(trackFile.ArtistId);
return trackFile.ToResource(series, _upgradableSpecification);
return trackFile.ToResource(artist, _upgradableSpecification);
}
private List<TrackFileResource> GetTrackFiles()
@ -72,7 +71,7 @@ namespace Lidarr.Api.V3.TrackFiles
throw new BadRequestException("artistId, albumId, or trackFileIds must be provided");
}
if (artistIdQuery.HasValue)
if (artistIdQuery.HasValue && !albumIdQuery.HasValue)
{
int artistId = Convert.ToInt32(artistIdQuery.Value);
var artist = _artistService.GetArtist(artistId);

@ -18,10 +18,10 @@ namespace Lidarr.Api.V3.Tracks
IBroadcastSignalRMessage signalRBroadcaster)
: base(trackService, artistService, upgradableSpecification, signalRBroadcaster)
{
GetResourceAll = GetEpisodes;
GetResourceAll = GetTracks;
}
private List<TrackResource> GetEpisodes()
private List<TrackResource> GetTracks()
{
var artistIdQuery = Request.Query.ArtistId;
var albumIdQuery = Request.Query.AlbumId;

Loading…
Cancel
Save