Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature1499 #1561

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions packages/app/app/actions/blacklist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { flow, omit } from 'lodash';
import { store } from '@nuclear/core';
import { areTracksEqualByName, getTrackItem } from '@nuclear/ui';

import { safeAddUuid } from './helpers';

export const READ_BLACKLISTED = 'READ_BLACKLISTED';
export const BLACKLIST_TRACK = 'BLACKLIST_TRACK';
export const REMOVE_BLACKLISTED_TRACK = 'REMOVE_BLACKLISTED_TRACK';

export function addToBlacklist(track) {
const clonedTrack = flow(safeAddUuid, getTrackItem)(track);

let blacklist = store.get('blacklist');
const filteredTracks = blacklist.filter(t => !areTracksEqualByName(t, track));
blacklist = [...filteredTracks, omit(clonedTrack, 'streams')];

store.set('blacklist', blacklist);

return {
type: BLACKLIST_TRACK,
payload: blacklist
};
}

export function removeBlacklistedTrack(track) {
let blacklist = store.get('blacklist');
blacklist = blacklist.filter(t => !areTracksEqualByName(t, track));

store.set('blacklist', blacklist);

return {
type: REMOVE_BLACKLISTED_TRACK,
payload: blacklist
};
}

export function readBlacklist() {
const blacklist = store.get('blacklist');
return {
type: READ_BLACKLISTED,
payload: blacklist
};
}
18 changes: 16 additions & 2 deletions packages/app/app/components/PlayQueue/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo, useState } from 'react';
import React, { useEffect, useState } from 'react';
import classnames from 'classnames';
import _, { head } from 'lodash';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
Expand All @@ -8,7 +8,7 @@ import { areEqual, FixedSizeList as List } from 'react-window';

import { Playlist } from '@nuclear/core';
import { StreamData } from '@nuclear/core/src/plugins/plugins.types';
import { formatDuration, QueueItem } from '@nuclear/ui';
import { areTracksEqualByName, formatDuration, QueueItem } from '@nuclear/ui';

import { PluginsState } from '../../reducers/plugins';
import { QueueItem as QueueItemType, QueueStore } from '../../reducers/queue';
Expand All @@ -22,6 +22,8 @@ import { StreamVerificationContainer } from '../../containers/StreamVerification
import styles from './styles.scss';
import AutoSizer from 'react-virtualized-auto-sizer';
import { QueueItemClone } from './QueueItemClone';
import { useSelector } from 'react-redux';
import { blacklistSelector } from '../../selectors/blacklist';

type PlayQueueProps = {
actions: PlayQueueActions;
Expand Down Expand Up @@ -70,6 +72,18 @@ const PlayQueue: React.FC<PlayQueueProps> = ({
}) => {
const { t } = useTranslation('queue');
const [isFileHovered, setFileHovered] = useState(false);
const blacklisted = useSelector(blacklistSelector);

useEffect(() => {
for (let i = 0; i < queue.queueItems.length; i++){
for (let j = 0; j < blacklisted.length; j++) {
if (areTracksEqualByName(queue.queueItems[i], blacklisted[j])){
removeFromQueue(i);
return;
}
}
}
}, [queue.queueItems]);

const onDropFile = (event) => {
event.preventDefault();
Expand Down
95 changes: 89 additions & 6 deletions packages/app/app/components/Settings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import React from 'react';
import React, { useEffect } from 'react';
import { ipcRenderer, remote } from 'electron';
import { Button, Input, Radio, Segment, Icon } from 'semantic-ui-react';
import cx from 'classnames';
import _ from 'lodash';
import { useTranslation } from 'react-i18next';
import { SettingType } from '@nuclear/core';
import { Dropdown, Range } from '@nuclear/ui';
import { Dropdown, Range, TrackTable } from '@nuclear/ui';
import i18n from '@nuclear/i18n';

import Header from '../Header';
import Spacer from '../Spacer';

import { connect } from 'react-redux';
import styles from './styles.scss';
import { LastFmSocialIntegration } from './Integrations/LastFmSocialIntegration';
import { MastodonSocialIntegration } from './Integrations/MastodonSocialIntegration';
import { RootState } from '../../reducers';
import { playlistsSelectors } from '../../selectors/playlists';
import { useSelector } from 'react-redux';
import { blacklistSelector } from '../../selectors/blacklist';
import * as BlacklistActions from '../../actions/blacklist';
import { useDispatch } from 'react-redux';
import { bindActionCreators } from 'redux';

const volumeSliderColors = {
fillColor: { r: 248, g: 248, b: 242, a: 1 },
Expand Down Expand Up @@ -45,6 +50,7 @@ export type SettingsProps = {
mastodon: RootState['mastodon'];
settings: RootState['settings'];
options: object;
blacklistActions: object;
}

const Settings: React.FC<SettingsProps> = ({
Expand All @@ -54,8 +60,16 @@ const Settings: React.FC<SettingsProps> = ({
importfavs,
mastodon,
settings,
options
options,
blacklistActions
}) => {
const dispatch = useDispatch();
const blacklisted = useSelector(blacklistSelector);

useEffect(() => {
dispatch(BlacklistActions.readBlacklist());
}, [dispatch]);

const isChecked = (option) => {
return typeof settings[option.name] !== 'undefined'
? settings[option.name]
Expand Down Expand Up @@ -145,6 +159,58 @@ const Settings: React.FC<SettingsProps> = ({
</span>
);

const trackTableTranslation = useTranslation('track-table').t;
const trackTableStrings = {
addSelectedTracksToQueue: trackTableTranslation('add-selected-tracks-to-queue'),
addSelectedTracksToDownloads: trackTableTranslation('add-selected-tracks-to-downloads'),
addSelectedTracksToFavorites: trackTableTranslation('add-selected-tracks-to-favorites'),
playSelectedTracksNow: trackTableTranslation('play-selected-tracks-now'),
tracksSelectedLabelSingular: trackTableTranslation('tracks-selected-label-singular'),
tracksSelectedLabelPlural: trackTableTranslation('tracks-selected-label-plural')
};
const playlists = useSelector(playlistsSelectors.localPlaylists);
const popupTranstation = useTranslation('track-popup').t;
const popupStrings = {
textAddToQueue: popupTranstation('add-to-queue'),
textPlayNow: popupTranstation('play-now'),
textPlayNext: popupTranstation('play-next'),
textAddToFavorites: popupTranstation('add-to-favorite'),
textAddToPlaylist: popupTranstation('add-to-playlist'),
textCreatePlaylist: popupTranstation('create-playlist'),
textAddToDownloads: popupTranstation('download'),
textAddToBlacklist: popupTranstation('blacklist'),
createPlaylistDialog: {
title: popupTranstation('create-playlist-dialog-title'),
placeholder: popupTranstation('create-playlist-dialog-placeholder'),
accept: popupTranstation('create-playlist-dialog-accept'),
cancel: popupTranstation('create-playlist-dialog-cancel')
}
};
const renderTableOption = () => (
<TrackTable
tracks={blacklisted}
positionHeader={<Icon name='hashtag' />}
thumbnailHeader={<Icon name='image' />}
artistHeader={t('artist')}
titleHeader={t('title')}
albumHeader={t('album')}
durationHeader={t('duration')}
strings={trackTableStrings}
playlists={playlists.data}
popupActionStrings={popupStrings}
isTrackFavorite={null}
onDelete={blacklistActions}
displayPosition={false}
displayThumbnail={false}
displayAlbum={false}
displayDuration={false}
displayFavorite={false}
displayCustom={false}
selectable={false}
displayButtons={false}
/>
);

const renderSliderOption = (option) => (
<div className={styles.slider_container}>
<label>{t('less')}</label>
Expand Down Expand Up @@ -212,6 +278,8 @@ const Settings: React.FC<SettingsProps> = ({
renderNodeOption(option)}
{option.type === SettingType.DIRECTORY &&
renderDirectoryOption(option)}
{option.type === SettingType.TABLE &&
renderTableOption()}
</div>
);

Expand Down Expand Up @@ -261,4 +329,19 @@ const Settings: React.FC<SettingsProps> = ({
);
};

export default Settings;
function mapStateToProps(state) {
return {
blacklist: state.blacklist
};
}

function mapDispatchToProps(dispatch) {
return {
blacklistActions: bindActionCreators(BlacklistActions.removeBlacklistedTrack, dispatch)
};
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(Settings);
35 changes: 32 additions & 3 deletions packages/app/app/containers/QueuePopupButtons/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as QueueActions from '../../actions/queue';
import * as FavoritesActions from '../../actions/favorites';
import * as ToastActions from '../../actions/toasts';
import * as PlaylistsActions from '../../actions/playlists';
import * as BlacklistActions from '../../actions/blacklist';
import { safeAddUuid } from '../../actions/helpers';
import { normalizeTrack } from '../../utils';
import { addTrackToPlaylist } from '../../components/PlayQueue/QueueMenu/QueueMenuMore';
Expand All @@ -23,10 +24,12 @@ const QueuePopupButtons = ({
withAddToFavorites,
withAddToDownloads,
withAddToPlaylist,
withAddToBlacklist,
handlePlayNow,
handleAddFavorite,
handleAddToDownloads,
handleAddToPlaylist
handleAddToPlaylist,
handleAddToBlacklist
}) => (
<>
{withPlayNow && (
Expand Down Expand Up @@ -69,6 +72,14 @@ const QueuePopupButtons = ({
label='Download'
/>
)}
{withAddToBlacklist && (
<PopupButton
onClick={handleAddToBlacklist}
ariaLabel='Blacklist this track'
icon='lock'
label='Blacklist'
/>
)}
</>
);

Expand All @@ -86,6 +97,7 @@ const mapDispatchToProps = dispatch => ({
downloadsActions: bindActionCreators(DownloadsActions, dispatch),
queueActions: bindActionCreators(QueueActions, dispatch),
favoritesActions: bindActionCreators(FavoritesActions, dispatch),
blacklistActions: bindActionCreators(BlacklistActions, dispatch),
playlistsActions: bindActionCreators(PlaylistsActions, dispatch),
toastActions: bindActionCreators(ToastActions, dispatch)
});
Expand All @@ -104,7 +116,8 @@ QueuePopupButtons.propTypes = {
withPlayNow: PropTypes.bool,
withAddToFavorites: PropTypes.bool,
withAddToDownloads: PropTypes.bool,
withAddToPlaylist: PropTypes.bool
withAddToPlaylist: PropTypes.bool,
withAddToBlacklist: PropTypes.bool
};

QueuePopupButtons.defaultProps = {
Expand All @@ -115,7 +128,8 @@ QueuePopupButtons.defaultProps = {
withAddToPlaylist: true,
withPlayNow: true,
withAddToFavorites: true,
withAddToDownloads: true
withAddToDownloads: true,
withAddToBlacklist: true
};

export default compose(
Expand All @@ -141,6 +155,21 @@ export default compose(
settings
);
},
handleAddToBlacklist: ({
track,
settings,
blacklistActions,
toastActions
}) => () => {
const normalizedTrack = normalizeTrack(track);
blacklistActions.addToBlacklist(normalizedTrack);
toastActions.info(
'Track added to blacklist',
`${track.artist} - ${track.name} has been added to blacklist.`,
<img src={getThumbnail(normalizedTrack)} />,
settings
);
},
handleAddToDownloads: ({
track,
settings,
Expand Down
1 change: 1 addition & 0 deletions packages/app/app/containers/TrackPopupContainer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const useTrackPopupProps = (track, thumb) => {
textAddToPlaylist: t('add-to-playlist'),
textCreatePlaylist: t('create-playlist'),
textAddToDownloads: t('download'),
textAddToBlacklist: t('blacklist'),
createPlaylistDialog: {
title: t('create-playlist-dialog-title'),
placeholder: t('create-playlist-dialog-placeholder'),
Expand Down
5 changes: 4 additions & 1 deletion packages/app/app/containers/TrackPopupContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type TrackPopupContainerProps = {
withAddToFavorites?: boolean;
withAddToPlaylist?: boolean;
withAddToDownloads?: boolean;
withAddToBlacklist?: boolean;
};

const TrackPopupContainer: React.FC<TrackPopupContainerProps> = ({
Expand All @@ -31,7 +32,8 @@ const TrackPopupContainer: React.FC<TrackPopupContainerProps> = ({
withPlayNow=true,
withAddToFavorites=true,
withAddToPlaylist=true,
withAddToDownloads=true
withAddToDownloads=true,
withAddToBlacklist=true
}) => {
const props = useTrackPopupProps(track, thumb);

Expand All @@ -47,6 +49,7 @@ const TrackPopupContainer: React.FC<TrackPopupContainerProps> = ({
withAddToFavorites={withAddToFavorites}
withAddToPlaylist={withAddToPlaylist}
withAddToDownloads={withAddToDownloads}
withAddToBlacklist={withAddToBlacklist}

{...props}
/>;
Expand Down
7 changes: 7 additions & 0 deletions packages/app/app/containers/TrackTableContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import * as queueActions from '../../actions/queue';
import * as playerActions from '../../actions/player';
import * as playlistActions from '../../actions/playlists';
import * as favoritesActions from '../../actions/favorites';
import * as blacklistActions from '../../actions/blacklist';
import { favoritesSelectors } from '../../selectors/favorites';
import { safeAddUuid } from '../../actions/helpers';

Expand Down Expand Up @@ -71,6 +72,10 @@ function TrackTableContainer<T extends Track> ({
dispatch(favoritesActions.addFavoriteTrack(track));
}, [dispatch]);

const onAddToBlacklist = useCallback((track: Track) => {
dispatch(blacklistActions.addToBlacklist(track));
}, [dispatch]);

const onRemoveFromFavorites = useCallback((track: Track) => {
dispatch(favoritesActions.removeFavoriteTrack(track));
}, [dispatch]);
Expand Down Expand Up @@ -117,6 +122,7 @@ function TrackTableContainer<T extends Track> ({
textAddToPlaylist: popupTranstation('add-to-playlist'),
textCreatePlaylist: popupTranstation('create-playlist'),
textAddToDownloads: popupTranstation('download'),
textAddToBlacklist: popupTranstation('blacklist'),
createPlaylistDialog: {
title: popupTranstation('create-playlist-dialog-title'),
placeholder: popupTranstation('create-playlist-dialog-placeholder'),
Expand Down Expand Up @@ -151,6 +157,7 @@ function TrackTableContainer<T extends Track> ({
onPlayNext={onPlayNext}
onPlayAll={onPlayAll}
onAddToFavorites={Boolean(displayAddToFavorites) && onAddToFavorites}
onAddToBlacklist={onAddToBlacklist}
onRemoveFromFavorites={onRemoveFromFavorites}
onAddToDownloads={Boolean(displayAddToDownloads) && onAddToDownloads}
onAddToPlaylist={onAddToPlaylist}
Expand Down
Loading
Loading