Lidarr/frontend/src/InteractiveImport/Interactive/InteractiveImportModalConte...

636 lines
19 KiB
JavaScript
Raw Normal View History

2017-09-04 02:20:56 +00:00
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
2020-09-07 01:33:10 +00:00
import SelectInput from 'Components/Form/SelectInput';
2017-09-04 02:20:56 +00:00
import Icon from 'Components/Icon';
2020-09-07 01:33:10 +00:00
import Button from 'Components/Link/Button';
2017-09-04 02:20:56 +00:00
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Menu from 'Components/Menu/Menu';
import MenuButton from 'Components/Menu/MenuButton';
import MenuContent from 'Components/Menu/MenuContent';
import SelectedMenuItem from 'Components/Menu/SelectedMenuItem';
2017-09-04 02:20:56 +00:00
import ModalBody from 'Components/Modal/ModalBody';
2020-09-07 01:33:10 +00:00
import ModalContent from 'Components/Modal/ModalContent';
2017-09-04 02:20:56 +00:00
import ModalFooter from 'Components/Modal/ModalFooter';
2020-09-07 01:33:10 +00:00
import ModalHeader from 'Components/Modal/ModalHeader';
2017-09-04 02:20:56 +00:00
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
2020-09-07 01:33:10 +00:00
import { align, icons, kinds, scrollDirections } from 'Helpers/Props';
import SelectAlbumModal from 'InteractiveImport/Album/SelectAlbumModal';
import SelectAlbumReleaseModal from 'InteractiveImport/AlbumRelease/SelectAlbumReleaseModal';
2020-09-07 01:33:10 +00:00
import SelectArtistModal from 'InteractiveImport/Artist/SelectArtistModal';
import ConfirmImportModal from 'InteractiveImport/Confirmation/ConfirmImportModal';
import SelectIndexerFlagsModal from 'InteractiveImport/IndexerFlags/SelectIndexerFlagsModal';
2020-09-07 01:33:10 +00:00
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
2023-01-14 17:45:54 +00:00
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
2020-09-07 01:33:10 +00:00
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
2020-09-07 01:33:10 +00:00
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected';
2017-09-04 02:20:56 +00:00
import InteractiveImportRow from './InteractiveImportRow';
import styles from './InteractiveImportModalContent.css';
const COLUMNS = [
2017-09-04 02:20:56 +00:00
{
2020-02-09 19:15:43 +00:00
name: 'path',
2023-08-21 01:05:59 +00:00
label: () => translate('Path'),
2017-09-04 02:20:56 +00:00
isSortable: true,
isVisible: true
},
{
name: 'artist',
2023-08-21 01:05:59 +00:00
label: () => translate('Artist'),
2017-09-04 02:20:56 +00:00
isSortable: true,
isVisible: true
},
{
name: 'album',
2023-08-21 01:05:59 +00:00
label: () => translate('Album'),
2017-09-04 02:20:56 +00:00
isVisible: true
},
{
name: 'tracks',
2023-08-21 01:05:59 +00:00
label: () => translate('Tracks'),
2017-09-04 02:20:56 +00:00
isVisible: true
},
2023-01-14 17:45:54 +00:00
{
name: 'releaseGroup',
2023-08-21 01:05:59 +00:00
label: () => translate('ReleaseGroup'),
2023-01-14 17:45:54 +00:00
isVisible: true
},
2017-09-04 02:20:56 +00:00
{
name: 'quality',
2023-08-21 01:05:59 +00:00
label: () => translate('Quality'),
2017-09-04 02:20:56 +00:00
isSortable: true,
isVisible: true
},
{
name: 'size',
2023-08-21 01:05:59 +00:00
label: () => translate('Size'),
isSortable: true,
2017-09-04 02:20:56 +00:00
isVisible: true
},
{
name: 'customFormats',
label: React.createElement(Icon, {
name: icons.INTERACTIVE,
title: () => translate('CustomFormat')
}),
isSortable: true,
isVisible: true
},
{
name: 'indexerFlags',
label: React.createElement(Icon, {
name: icons.FLAG,
title: () => translate('IndexerFlags')
}),
isSortable: true,
isVisible: true
},
2017-09-04 02:20:56 +00:00
{
name: 'rejections',
label: React.createElement(Icon, {
name: icons.DANGER,
kind: kinds.DANGER,
title: () => translate('Rejections')
2017-09-04 02:20:56 +00:00
}),
isSortable: true,
2017-09-04 02:20:56 +00:00
isVisible: true
}
];
const filterExistingFilesOptions = {
ALL: 'all',
NEW: 'new'
};
const importModeOptions = [
2023-08-21 01:05:59 +00:00
{ key: 'chooseImportMode', value: () => translate('ChooseImportMethod'), disabled: true },
{ key: 'move', value: () => translate('MoveFiles') },
{ key: 'copy', value: () => translate('HardlinkCopyFiles') }
];
const SELECT = 'select';
const ARTIST = 'artist';
const ALBUM = 'album';
const ALBUM_RELEASE = 'albumRelease';
2023-01-14 17:45:54 +00:00
const RELEASE_GROUP = 'releaseGroup';
const QUALITY = 'quality';
const INDEXER_FLAGS = 'indexerFlags';
const replaceExistingFilesOptions = {
COMBINE: 'combine',
DELETE: 'delete'
};
2017-09-04 02:20:56 +00:00
class InteractiveImportModalContent extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
allSelected: false,
allUnselected: false,
lastToggled: null,
selectedState: {},
invalidRowsSelected: [],
selectModalOpen: null,
albumsImported: [],
isConfirmImportModalOpen: false,
showClearTracks: false,
inconsistentAlbumReleases: false
2017-09-04 02:20:56 +00:00
};
}
componentDidUpdate(prevProps) {
const selectedIds = this.getSelectedIds();
const selectedItems = _.filter(this.props.items, (x) => _.includes(selectedIds, x.id));
const selectionHasTracks = _.some(selectedItems, (x) => x.tracks.length);
if (this.state.showClearTracks !== selectionHasTracks) {
this.setState({ showClearTracks: selectionHasTracks });
}
const inconsistent = _(selectedItems)
.map((x) => ({ albumId: x.album ? x.album.id : 0, releaseId: x.albumReleaseId }))
.groupBy('albumId')
.mapValues((album) => _(album).groupBy((x) => x.releaseId).values().value().length)
.values()
.some((x) => x !== undefined && x > 1);
if (inconsistent !== this.state.inconsistentAlbumReleases) {
this.setState({ inconsistentAlbumReleases: inconsistent });
}
}
2017-09-04 02:20:56 +00:00
//
// Control
getSelectedIds = () => {
return getSelectedIds(this.state.selectedState);
2021-12-24 18:18:14 +00:00
};
2017-09-04 02:20:56 +00:00
//
// Listeners
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
2021-12-24 18:18:14 +00:00
};
2017-09-04 02:20:56 +00:00
onSelectedChange = ({ id, value, shiftKey = false }) => {
this.setState((state) => {
return toggleSelected(state, this.props.items, id, value, shiftKey);
});
2021-12-24 18:18:14 +00:00
};
2017-09-04 02:20:56 +00:00
onValidRowChange = (id, isValid) => {
this.setState((state, props) => {
// make sure to exclude any invalidRows that are no longer present in props
const diff = _.difference(state.invalidRowsSelected, _.map(props.items, 'id'));
const currentInvalid = _.difference(state.invalidRowsSelected, diff);
const newstate = isValid ? _.without(currentInvalid, id) : _.union(currentInvalid, [id]);
return { invalidRowsSelected: newstate };
2017-09-04 02:20:56 +00:00
});
2021-12-24 18:18:14 +00:00
};
2017-09-04 02:20:56 +00:00
onImportSelectedPress = () => {
if (!this.props.replaceExistingFiles) {
this.onConfirmImportPress();
return;
}
// potentially deleting files
const selectedIds = this.getSelectedIds();
const albumsImported = _(this.props.items)
.filter((x) => _.includes(selectedIds, x.id))
.keyBy((x) => x.album.id)
.map((x) => x.album)
.value();
console.log(albumsImported);
this.setState({
albumsImported,
isConfirmImportModalOpen: true
});
2021-12-24 18:18:14 +00:00
};
onConfirmImportPress = () => {
const {
downloadId,
showImportMode,
importMode,
onImportSelectedPress
} = this.props;
2017-09-04 02:20:56 +00:00
const selected = this.getSelectedIds();
const finalImportMode = downloadId || !showImportMode ? 'auto' : importMode;
2017-09-04 02:20:56 +00:00
onImportSelectedPress(selected, finalImportMode);
2021-12-24 18:18:14 +00:00
};
2017-09-04 02:20:56 +00:00
onFilterExistingFilesChange = (value) => {
this.props.onFilterExistingFilesChange(value !== filterExistingFilesOptions.ALL);
2021-12-24 18:18:14 +00:00
};
onReplaceExistingFilesChange = (value) => {
this.props.onReplaceExistingFilesChange(value === replaceExistingFilesOptions.DELETE);
2021-12-24 18:18:14 +00:00
};
2017-09-04 02:20:56 +00:00
onImportModeChange = ({ value }) => {
this.props.onImportModeChange(value);
2021-12-24 18:18:14 +00:00
};
2017-09-04 02:20:56 +00:00
onSelectModalSelect = ({ value }) => {
this.setState({ selectModalOpen: value });
2021-12-24 18:18:14 +00:00
};
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
2019-02-16 14:49:24 +00:00
onClearTrackMappingPress = () => {
const selectedIds = this.getSelectedIds();
selectedIds.forEach((id) => {
this.props.updateInteractiveImportItem({
id,
tracks: [],
rejections: []
});
});
2021-12-24 18:18:14 +00:00
};
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
2019-02-16 14:49:24 +00:00
onGetTrackMappingPress = () => {
this.props.saveInteractiveImportItem({ ids: this.getSelectedIds() });
2021-12-24 18:18:14 +00:00
};
onSelectModalClose = () => {
this.setState({ selectModalOpen: null });
2021-12-24 18:18:14 +00:00
};
onConfirmImportModalClose = () => {
this.setState({ isConfirmImportModalOpen: false });
2021-12-24 18:18:14 +00:00
};
2017-09-04 02:20:56 +00:00
//
// Render
render() {
const {
downloadId,
allowArtistChange,
showFilterExistingFiles,
showReplaceExistingFiles,
showImportMode,
filterExistingFiles,
replaceExistingFiles,
2017-09-04 02:20:56 +00:00
title,
folder,
isFetching,
isPopulated,
isSaving,
2017-09-04 02:20:56 +00:00
error,
items,
sortKey,
sortDirection,
importMode,
interactiveImportErrorMessage,
onSortPress,
onModalClose
} = this.props;
const {
allSelected,
allUnselected,
selectedState,
invalidRowsSelected,
selectModalOpen,
albumsImported,
isConfirmImportModalOpen,
showClearTracks,
inconsistentAlbumReleases
2017-09-04 02:20:56 +00:00
} = this.state;
const allColumns = _.cloneDeep(COLUMNS);
const columns = allColumns.map((column) => {
const showIndexerFlags = items.some((item) => item.indexerFlags);
if (!showIndexerFlags) {
const indexerFlagsColumn = allColumns.find((c) => c.name === 'indexerFlags');
if (indexerFlagsColumn) {
indexerFlagsColumn.isVisible = false;
}
}
return column;
});
2017-09-04 02:20:56 +00:00
const selectedIds = this.getSelectedIds();
const selectedItem = selectedIds.length ? _.find(items, { id: selectedIds[0] }) : null;
const errorMessage = getErrorMessage(error, 'Unable to load manual import items');
2017-09-04 02:20:56 +00:00
const bulkSelectOptions = [
{ key: SELECT, value: translate('Select...'), disabled: true },
{ key: ALBUM, value: translate('SelectAlbum') },
{ key: ALBUM_RELEASE, value: translate('SelectAlbumRelease') },
2023-01-14 17:45:54 +00:00
{ key: QUALITY, value: translate('SelectQuality') },
{ key: RELEASE_GROUP, value: translate('SelectReleaseGroup') },
{ key: INDEXER_FLAGS, value: translate('SelectIndexerFlags') }
2017-09-04 02:20:56 +00:00
];
if (allowArtistChange) {
bulkSelectOptions.splice(1, 0, {
key: ARTIST,
value: translate('SelectArtist')
});
}
2017-09-04 02:20:56 +00:00
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{translate('ManualImport')} - {title || folder}
2017-09-04 02:20:56 +00:00
</ModalHeader>
<ModalBody scrollDirection={scrollDirections.BOTH}>
<div className={styles.filterContainer}>
{
showFilterExistingFiles &&
<Menu alignMenu={align.RIGHT}>
<MenuButton>
<Icon
name={icons.FILTER}
size={22}
/>
<div className={styles.filterText}>
{
filterExistingFiles ? translate('UnmappedFilesOnly') : translate('AllFiles')
}
</div>
</MenuButton>
<MenuContent>
<SelectedMenuItem
name={filterExistingFilesOptions.ALL}
isSelected={!filterExistingFiles}
onPress={this.onFilterExistingFilesChange}
>
{translate('AllFiles')}
</SelectedMenuItem>
<SelectedMenuItem
name={filterExistingFilesOptions.NEW}
isSelected={filterExistingFiles}
onPress={this.onFilterExistingFilesChange}
>
{translate('UnmappedFilesOnly')}
</SelectedMenuItem>
</MenuContent>
</Menu>
}
{
showReplaceExistingFiles &&
<Menu alignMenu={align.RIGHT}>
<MenuButton>
<Icon
name={icons.CLONE}
size={22}
/>
<div className={styles.filterText}>
{
replaceExistingFiles ? 'Existing files will be deleted' : 'Combine with existing files'
}
</div>
</MenuButton>
<MenuContent>
<SelectedMenuItem
name={replaceExistingFiles.COMBINE}
isSelected={!replaceExistingFiles}
onPress={this.onReplaceExistingFilesChange}
>
{translate('CombineWithExistingFiles')}
</SelectedMenuItem>
<SelectedMenuItem
name={replaceExistingFilesOptions.DELETE}
isSelected={replaceExistingFiles}
onPress={this.onReplaceExistingFilesChange}
>
{translate('ReplaceExistingFiles')}
</SelectedMenuItem>
</MenuContent>
</Menu>
}
</div>
{
isFetching &&
<LoadingIndicator />
}
{
error &&
<div>{errorMessage}</div>
}
{
isPopulated && !!items.length && !isFetching && !isFetching &&
2017-09-04 02:20:56 +00:00
<Table
columns={columns}
horizontalScroll={true}
2017-09-04 02:20:56 +00:00
selectAll={true}
allSelected={allSelected}
allUnselected={allUnselected}
sortKey={sortKey}
sortDirection={sortDirection}
onSortPress={onSortPress}
onSelectAllChange={this.onSelectAllChange}
>
<TableBody>
{
items.map((item) => {
return (
<InteractiveImportRow
key={item.id}
isSelected={selectedState[item.id]}
isSaving={isSaving}
2017-09-04 02:20:56 +00:00
{...item}
allowArtistChange={allowArtistChange}
columns={columns}
2017-09-04 02:20:56 +00:00
onSelectedChange={this.onSelectedChange}
onValidRowChange={this.onValidRowChange}
/>
);
})
}
</TableBody>
</Table>
}
{
isPopulated && !items.length && !isFetching &&
2017-09-25 02:58:13 +00:00
'No audio files were found in the selected folder'
2017-09-04 02:20:56 +00:00
}
</ModalBody>
<ModalFooter className={styles.footer}>
<div className={styles.leftButtons}>
{
!downloadId && showImportMode ?
2017-09-04 02:20:56 +00:00
<SelectInput
className={styles.importMode}
name="importMode"
value={importMode}
values={importModeOptions}
onChange={this.onImportModeChange}
/> :
null
}
2017-09-04 02:20:56 +00:00
<SelectInput
className={styles.bulkSelect}
name="select"
value={SELECT}
values={bulkSelectOptions}
isDisabled={!selectedIds.length}
onChange={this.onSelectModalSelect}
/>
{
showClearTracks ? (
<Button
onPress={this.onClearTrackMappingPress}
isDisabled={!selectedIds.length}
>
Clear Tracks
</Button>
) : (
<Button
onPress={this.onGetTrackMappingPress}
isDisabled={!selectedIds.length}
>
Map Tracks
</Button>
)
}
2017-09-04 02:20:56 +00:00
</div>
<div className={styles.rightButtons}>
<Button onPress={onModalClose}>
{translate('Cancel')}
2017-09-04 02:20:56 +00:00
</Button>
{
interactiveImportErrorMessage &&
<span className={styles.errorMessage}>{interactiveImportErrorMessage}</span>
}
<Button
kind={kinds.SUCCESS}
isDisabled={!selectedIds.length || !!invalidRowsSelected.length || inconsistentAlbumReleases}
2017-09-04 02:20:56 +00:00
onPress={this.onImportSelectedPress}
>
{translate('Import')}
2017-09-04 02:20:56 +00:00
</Button>
</div>
</ModalFooter>
<SelectArtistModal
isOpen={selectModalOpen === ARTIST}
2017-09-04 02:20:56 +00:00
ids={selectedIds}
onModalClose={this.onSelectModalClose}
2017-09-04 02:20:56 +00:00
/>
<SelectAlbumModal
isOpen={selectModalOpen === ALBUM}
2017-09-04 02:20:56 +00:00
ids={selectedIds}
artistId={selectedItem && selectedItem.artist && selectedItem.artist.id}
onModalClose={this.onSelectModalClose}
2017-09-04 02:20:56 +00:00
/>
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
2019-02-16 14:49:24 +00:00
<SelectAlbumReleaseModal
isOpen={selectModalOpen === ALBUM_RELEASE}
importIdsByAlbum={_.chain(items).filter((x) => x.album).groupBy((x) => x.album.id).mapValues((x) => x.map((y) => y.id)).value()}
albums={_.chain(items).filter((x) => x.album).keyBy((x) => x.album.id).mapValues((x) => ({ matchedReleaseId: x.albumReleaseId, album: x.album })).values().value()}
onModalClose={this.onSelectModalClose}
/>
2023-01-14 17:45:54 +00:00
<SelectReleaseGroupModal
isOpen={selectModalOpen === RELEASE_GROUP}
ids={selectedIds}
releaseGroup=""
onModalClose={this.onSelectModalClose}
/>
<SelectQualityModal
isOpen={selectModalOpen === QUALITY}
ids={selectedIds}
qualityId={0}
proper={false}
real={false}
onModalClose={this.onSelectModalClose}
/>
<SelectIndexerFlagsModal
isOpen={selectModalOpen === INDEXER_FLAGS}
ids={selectedIds}
indexerFlags={0}
onModalClose={this.onSelectModalClose}
/>
<ConfirmImportModal
isOpen={isConfirmImportModalOpen}
albums={albumsImported}
onModalClose={this.onConfirmImportModalClose}
onConfirmImportPress={this.onConfirmImportPress}
/>
2017-09-04 02:20:56 +00:00
</ModalContent>
);
}
}
InteractiveImportModalContent.propTypes = {
downloadId: PropTypes.string,
allowArtistChange: PropTypes.bool.isRequired,
showImportMode: PropTypes.bool.isRequired,
showFilterExistingFiles: PropTypes.bool.isRequired,
showReplaceExistingFiles: PropTypes.bool.isRequired,
filterExistingFiles: PropTypes.bool.isRequired,
replaceExistingFiles: PropTypes.bool.isRequired,
2017-09-04 02:20:56 +00:00
importMode: PropTypes.string.isRequired,
title: PropTypes.string,
folder: PropTypes.string,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
isSaving: PropTypes.bool.isRequired,
2017-09-04 02:20:56 +00:00
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
sortKey: PropTypes.string,
sortDirection: PropTypes.string,
interactiveImportErrorMessage: PropTypes.string,
onSortPress: PropTypes.func.isRequired,
onFilterExistingFilesChange: PropTypes.func.isRequired,
onReplaceExistingFilesChange: PropTypes.func.isRequired,
2017-09-04 02:20:56 +00:00
onImportModeChange: PropTypes.func.isRequired,
onImportSelectedPress: PropTypes.func.isRequired,
saveInteractiveImportItem: PropTypes.func.isRequired,
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
2019-02-16 14:49:24 +00:00
updateInteractiveImportItem: PropTypes.func.isRequired,
2017-09-04 02:20:56 +00:00
onModalClose: PropTypes.func.isRequired
};
InteractiveImportModalContent.defaultProps = {
allowArtistChange: true,
showFilterExistingFiles: false,
showReplaceExistingFiles: false,
showImportMode: true,
2017-09-04 02:20:56 +00:00
importMode: 'move'
};
export default InteractiveImportModalContent;