You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Lidarr/frontend/src/Store/Actions/releaseActions.js

346 lines
8.6 KiB

import { createAction } from 'redux-actions';
import { filterBuilderTypes, filterBuilderValueTypes, filterTypes, sortDirections } from 'Helpers/Props';
import { createThunk, handleThunks } from 'Store/thunks';
import createAjaxRequest from 'Utilities/createAjaxRequest';
import translate from 'Utilities/String/translate';
import createFetchHandler from './Creators/createFetchHandler';
import createHandleActions from './Creators/createHandleActions';
import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer';
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
//
// Variables
export const section = 'releases';
export const albumSection = 'releases.album';
export const artistSection = 'releases.artist';
let abortCurrentRequest = null;
//
// State
export const defaultState = {
isFetching: false,
isPopulated: false,
error: null,
items: [],
sortKey: 'releaseWeight',
sortDirection: sortDirections.ASCENDING,
sortPredicates: {
age: function(item, direction) {
return item.ageMinutes;
},
peers: function(item, direction) {
const seeders = item.seeders || 0;
const leechers = item.leechers || 0;
return seeders * 1000000 + leechers;
},
rejections: function(item, direction) {
const rejections = item.rejections;
const releaseWeight = item.releaseWeight;
if (rejections.length !== 0) {
return releaseWeight + 1000000;
}
return releaseWeight;
}
},
filters: [
{
key: 'all',
label: translate('All'),
filters: []
},
{
key: 'discography-pack',
label: translate('Discography'),
filters: [
{
key: 'discography',
value: true,
type: filterTypes.EQUAL
}
]
},
{
key: 'not-discography-pack',
label: translate('NotDiscography'),
filters: [
{
key: 'discography',
value: false,
type: filterTypes.EQUAL
}
]
}
],
filterPredicates: {
quality: function(item, value, type) {
const qualityId = item.quality.quality.id;
if (type === filterTypes.EQUAL) {
return qualityId === value;
}
if (type === filterTypes.NOT_EQUAL) {
return qualityId !== value;
}
// Default to false
return false;
},
rejectionCount: function(item, value, type) {
const rejectionCount = item.rejections.length;
switch (type) {
case filterTypes.EQUAL:
return rejectionCount === value;
case filterTypes.GREATER_THAN:
return rejectionCount > value;
case filterTypes.GREATER_THAN_OR_EQUAL:
return rejectionCount >= value;
case filterTypes.LESS_THAN:
return rejectionCount < value;
case filterTypes.LESS_THAN_OR_EQUAL:
return rejectionCount <= value;
case filterTypes.NOT_EQUAL:
return rejectionCount !== value;
default:
return false;
}
},
peers: function(item, value, type) {
const seeders = item.seeders || 0;
const leechers = item.leechers || 0;
const peers = seeders + leechers;
switch (type) {
case filterTypes.EQUAL:
return peers === value;
case filterTypes.GREATER_THAN:
return peers > value;
case filterTypes.GREATER_THAN_OR_EQUAL:
return peers >= value;
case filterTypes.LESS_THAN:
return peers < value;
case filterTypes.LESS_THAN_OR_EQUAL:
return peers <= value;
case filterTypes.NOT_EQUAL:
return peers !== value;
default:
return false;
}
}
},
filterBuilderProps: [
{
name: 'title',
label: translate('Title'),
type: filterBuilderTypes.STRING
},
{
name: 'age',
label: translate('Age'),
type: filterBuilderTypes.NUMBER
},
{
name: 'protocol',
label: translate('Protocol'),
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.PROTOCOL
},
{
name: 'indexerId',
label: translate('Indexer'),
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.INDEXER
},
{
name: 'size',
label: translate('Size'),
type: filterBuilderTypes.NUMBER,
valueType: filterBuilderValueTypes.BYTES
},
{
name: 'seeders',
label: translate('Seeders'),
type: filterBuilderTypes.NUMBER
},
{
name: 'leechers',
label: translate('Peers'),
type: filterBuilderTypes.NUMBER
},
{
name: 'quality',
label: translate('Quality'),
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.QUALITY
},
{
name: 'customFormatScore',
label: translate('CustomFormatScore'),
type: filterBuilderTypes.NUMBER
},
{
name: 'rejectionCount',
label: translate('RejectionCount'),
type: filterBuilderTypes.NUMBER
}
],
album: {
selectedFilterKey: 'all'
},
artist: {
selectedFilterKey: 'discography-pack'
}
};
export const persistState = [
'releases.selectedFilterKey',
'releases.album.customFilters',
'releases.artist.customFilters'
];
//
// Actions Types
export const FETCH_RELEASES = 'releases/fetchReleases';
export const CANCEL_FETCH_RELEASES = 'releases/cancelFetchReleases';
export const SET_RELEASES_SORT = 'releases/setReleasesSort';
export const CLEAR_RELEASES = 'releases/clearReleases';
export const GRAB_RELEASE = 'releases/grabRelease';
export const UPDATE_RELEASE = 'releases/updateRelease';
export const SET_ALBUM_RELEASES_FILTER = 'releases/setAlbumReleasesFilter';
export const SET_ARTIST_RELEASES_FILTER = 'releases/setArtistReleasesFilter';
//
// Action Creators
export const fetchReleases = createThunk(FETCH_RELEASES);
export const cancelFetchReleases = createThunk(CANCEL_FETCH_RELEASES);
export const setReleasesSort = createAction(SET_RELEASES_SORT);
export const clearReleases = createAction(CLEAR_RELEASES);
export const grabRelease = createThunk(GRAB_RELEASE);
export const updateRelease = createAction(UPDATE_RELEASE);
export const setAlbumReleasesFilter = createAction(SET_ALBUM_RELEASES_FILTER);
export const setArtistReleasesFilter = createAction(SET_ARTIST_RELEASES_FILTER);
//
// Helpers
const fetchReleasesHelper = createFetchHandler(section, '/release');
//
// Action Handlers
export const actionHandlers = handleThunks({
[FETCH_RELEASES]: function(getState, payload, dispatch) {
const abortRequest = fetchReleasesHelper(getState, payload, dispatch);
abortCurrentRequest = abortRequest;
},
[CANCEL_FETCH_RELEASES]: function(getState, payload, dispatch) {
if (abortCurrentRequest) {
abortCurrentRequest = abortCurrentRequest();
}
},
[GRAB_RELEASE]: function(getState, payload, dispatch) {
const guid = payload.guid;
dispatch(updateRelease({ guid, isGrabbing: true }));
const promise = createAjaxRequest({
url: '/release',
method: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(payload)
}).request;
promise.done((data) => {
dispatch(updateRelease({
guid,
isGrabbing: false,
isGrabbed: true,
grabError: null
}));
});
promise.fail((xhr) => {
const grabError = xhr.responseJSON && xhr.responseJSON.message || 'Failed to add to download queue';
dispatch(updateRelease({
guid,
isGrabbing: false,
isGrabbed: false,
grabError
}));
});
}
});
//
// Reducers
export const reducers = createHandleActions({
[CLEAR_RELEASES]: (state) => {
const {
album,
artist,
...otherDefaultState
} = defaultState;
return Object.assign({}, state, otherDefaultState);
},
[UPDATE_RELEASE]: (state, { payload }) => {
const guid = payload.guid;
const newState = Object.assign({}, state);
const items = newState.items;
const index = items.findIndex((item) => item.guid === guid);
// Don't try to update if there isnt a matching item (the user closed the modal)
if (index >= 0) {
const item = Object.assign({}, items[index], payload);
newState.items = [...items];
newState.items.splice(index, 1, item);
}
return newState;
},
[SET_RELEASES_SORT]: createSetClientSideCollectionSortReducer(section),
[SET_ALBUM_RELEASES_FILTER]: createSetClientSideCollectionFilterReducer(albumSection),
[SET_ARTIST_RELEASES_FILTER]: createSetClientSideCollectionFilterReducer(artistSection)
}, defaultState, section);