340 lines
7.8 KiB
JavaScript
340 lines
7.8 KiB
JavaScript
import _ from 'lodash';
|
|
import { createAction } from 'redux-actions';
|
|
import { batchActions } from 'redux-batched-actions';
|
|
import { createThunk, handleThunks } from 'Store/thunks';
|
|
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
|
import getNewSeries from 'Utilities/Series/getNewSeries';
|
|
import * as seriesTypes from 'Utilities/Series/seriesTypes';
|
|
import getSectionState from 'Utilities/State/getSectionState';
|
|
import updateSectionState from 'Utilities/State/updateSectionState';
|
|
import { removeItem, set, updateItem } from './baseActions';
|
|
import createHandleActions from './Creators/createHandleActions';
|
|
import { fetchRootFolders } from './rootFolderActions';
|
|
|
|
//
|
|
// Variables
|
|
|
|
export const section = 'importSeries';
|
|
let concurrentLookups = 0;
|
|
let abortCurrentLookup = null;
|
|
const queue = [];
|
|
|
|
//
|
|
// State
|
|
|
|
export const defaultState = {
|
|
isLookingUpSeries: false,
|
|
isImporting: false,
|
|
isImported: false,
|
|
importError: null,
|
|
items: []
|
|
};
|
|
|
|
//
|
|
// Actions Types
|
|
|
|
export const QUEUE_LOOKUP_SERIES = 'importSeries/queueLookupSeries';
|
|
export const START_LOOKUP_SERIES = 'importSeries/startLookupSeries';
|
|
export const CANCEL_LOOKUP_SERIES = 'importSeries/cancelLookupSeries';
|
|
export const LOOKUP_UNSEARCHED_SERIES = 'importSeries/lookupUnsearchedSeries';
|
|
export const CLEAR_IMPORT_SERIES = 'importSeries/clearImportSeries';
|
|
export const SET_IMPORT_SERIES_VALUE = 'importSeries/setImportSeriesValue';
|
|
export const IMPORT_SERIES = 'importSeries/importSeries';
|
|
|
|
//
|
|
// Action Creators
|
|
|
|
export const queueLookupSeries = createThunk(QUEUE_LOOKUP_SERIES);
|
|
export const startLookupSeries = createThunk(START_LOOKUP_SERIES);
|
|
export const importSeries = createThunk(IMPORT_SERIES);
|
|
export const lookupUnsearchedSeries = createThunk(LOOKUP_UNSEARCHED_SERIES);
|
|
export const clearImportSeries = createAction(CLEAR_IMPORT_SERIES);
|
|
export const cancelLookupSeries = createAction(CANCEL_LOOKUP_SERIES);
|
|
|
|
export const setImportSeriesValue = createAction(SET_IMPORT_SERIES_VALUE, (payload) => {
|
|
return {
|
|
section,
|
|
...payload
|
|
};
|
|
});
|
|
|
|
//
|
|
// Action Handlers
|
|
|
|
export const actionHandlers = handleThunks({
|
|
|
|
[QUEUE_LOOKUP_SERIES]: function(getState, payload, dispatch) {
|
|
const {
|
|
name,
|
|
path,
|
|
relativePath,
|
|
term,
|
|
topOfQueue = false
|
|
} = payload;
|
|
|
|
const state = getState().importSeries;
|
|
const item = _.find(state.items, { id: name }) || {
|
|
id: name,
|
|
term,
|
|
path,
|
|
relativePath,
|
|
isFetching: false,
|
|
isPopulated: false,
|
|
error: null
|
|
};
|
|
|
|
dispatch(updateItem({
|
|
section,
|
|
...item,
|
|
term,
|
|
isQueued: true,
|
|
items: []
|
|
}));
|
|
|
|
const itemIndex = queue.indexOf(item.id);
|
|
|
|
if (itemIndex >= 0) {
|
|
queue.splice(itemIndex, 1);
|
|
}
|
|
|
|
if (topOfQueue) {
|
|
queue.unshift(item.id);
|
|
} else {
|
|
queue.push(item.id);
|
|
}
|
|
|
|
if (term && term.length > 2) {
|
|
dispatch(startLookupSeries({ start: true }));
|
|
}
|
|
},
|
|
|
|
[START_LOOKUP_SERIES]: function(getState, payload, dispatch) {
|
|
if (concurrentLookups >= 1) {
|
|
return;
|
|
}
|
|
|
|
const state = getState().importSeries;
|
|
|
|
const {
|
|
isLookingUpSeries,
|
|
items
|
|
} = state;
|
|
|
|
const queueId = queue[0];
|
|
|
|
if (payload.start && !isLookingUpSeries) {
|
|
dispatch(set({ section, isLookingUpSeries: true }));
|
|
} else if (!isLookingUpSeries) {
|
|
return;
|
|
} else if (!queueId) {
|
|
dispatch(set({ section, isLookingUpSeries: false }));
|
|
return;
|
|
}
|
|
|
|
concurrentLookups++;
|
|
queue.splice(0, 1);
|
|
|
|
const queued = items.find((i) => i.id === queueId);
|
|
|
|
dispatch(updateItem({
|
|
section,
|
|
id: queued.id,
|
|
isFetching: true
|
|
}));
|
|
|
|
const { request, abortRequest } = createAjaxRequest({
|
|
url: '/series/lookup',
|
|
data: {
|
|
term: queued.term
|
|
}
|
|
});
|
|
|
|
abortCurrentLookup = abortRequest;
|
|
|
|
request.done((data) => {
|
|
const selectedSeries = queued.selectedSeries || data[0];
|
|
|
|
const itemProps = {
|
|
section,
|
|
id: queued.id,
|
|
isFetching: false,
|
|
isPopulated: true,
|
|
error: null,
|
|
items: data,
|
|
isQueued: false,
|
|
selectedSeries,
|
|
updateOnly: true
|
|
};
|
|
|
|
if (selectedSeries && selectedSeries.seriesType !== seriesTypes.STANDARD) {
|
|
itemProps.seriesType = selectedSeries.seriesType;
|
|
}
|
|
|
|
dispatch(updateItem(itemProps));
|
|
});
|
|
|
|
request.fail((xhr) => {
|
|
dispatch(updateItem({
|
|
section,
|
|
id: queued.id,
|
|
isFetching: false,
|
|
isPopulated: false,
|
|
error: xhr,
|
|
isQueued: false,
|
|
updateOnly: true
|
|
}));
|
|
});
|
|
|
|
request.always(() => {
|
|
concurrentLookups--;
|
|
|
|
dispatch(startLookupSeries());
|
|
});
|
|
},
|
|
|
|
[LOOKUP_UNSEARCHED_SERIES]: function(getState, payload, dispatch) {
|
|
const state = getState().importSeries;
|
|
|
|
if (state.isLookingUpSeries) {
|
|
return;
|
|
}
|
|
|
|
state.items.forEach((item) => {
|
|
const id = item.id;
|
|
|
|
if (
|
|
!item.isPopulated &&
|
|
!queue.includes(id)
|
|
) {
|
|
queue.push(item.id);
|
|
}
|
|
});
|
|
|
|
if (queue.length) {
|
|
dispatch(startLookupSeries({ start: true }));
|
|
}
|
|
},
|
|
|
|
[IMPORT_SERIES]: function(getState, payload, dispatch) {
|
|
dispatch(set({ section, isImporting: true }));
|
|
|
|
const ids = payload.ids;
|
|
const items = getState().importSeries.items;
|
|
const addedIds = [];
|
|
|
|
const allNewSeries = ids.reduce((acc, id) => {
|
|
const item = items.find((i) => i.id === id);
|
|
const selectedSeries = item.selectedSeries;
|
|
|
|
// Make sure we have a selected series and
|
|
// the same series hasn't been added yet.
|
|
if (selectedSeries && !acc.some((a) => a.tvdbId === selectedSeries.tvdbId)) {
|
|
const newSeries = getNewSeries(_.cloneDeep(selectedSeries), item);
|
|
newSeries.path = item.path;
|
|
|
|
addedIds.push(id);
|
|
acc.push(newSeries);
|
|
}
|
|
|
|
return acc;
|
|
}, []);
|
|
|
|
const promise = createAjaxRequest({
|
|
url: '/series/import',
|
|
method: 'POST',
|
|
contentType: 'application/json',
|
|
data: JSON.stringify(allNewSeries)
|
|
}).request;
|
|
|
|
promise.done((data) => {
|
|
dispatch(batchActions([
|
|
set({
|
|
section,
|
|
isImporting: false,
|
|
isImported: true,
|
|
importError: null
|
|
}),
|
|
|
|
...data.map((series) => updateItem({ section: 'series', ...series })),
|
|
|
|
...addedIds.map((id) => removeItem({ section, id }))
|
|
]));
|
|
|
|
dispatch(fetchRootFolders());
|
|
});
|
|
|
|
promise.fail((xhr) => {
|
|
dispatch(batchActions([
|
|
set({
|
|
section,
|
|
isImporting: false,
|
|
isImported: true,
|
|
importError: xhr
|
|
}),
|
|
|
|
...addedIds.map((id) => updateItem({
|
|
section,
|
|
id
|
|
}))
|
|
]));
|
|
});
|
|
}
|
|
});
|
|
|
|
//
|
|
// Reducers
|
|
|
|
export const reducers = createHandleActions({
|
|
|
|
[CANCEL_LOOKUP_SERIES]: function(state) {
|
|
queue.splice(0, queue.length);
|
|
|
|
const items = state.items.map((item) => {
|
|
if (item.isQueued) {
|
|
return {
|
|
...item,
|
|
isQueued: false
|
|
};
|
|
}
|
|
|
|
return item;
|
|
});
|
|
|
|
return Object.assign({}, state, {
|
|
isLookingUpSeries: false,
|
|
items
|
|
});
|
|
},
|
|
|
|
[CLEAR_IMPORT_SERIES]: function(state) {
|
|
if (abortCurrentLookup) {
|
|
abortCurrentLookup();
|
|
|
|
abortCurrentLookup = null;
|
|
}
|
|
|
|
queue.splice(0, queue.length);
|
|
|
|
return Object.assign({}, state, defaultState);
|
|
},
|
|
|
|
[SET_IMPORT_SERIES_VALUE]: function(state, { payload }) {
|
|
const newState = getSectionState(state, section);
|
|
const items = newState.items;
|
|
const index = items.findIndex((item) => item.id === payload.id);
|
|
|
|
newState.items = [...items];
|
|
|
|
if (index >= 0) {
|
|
const item = items[index];
|
|
|
|
newState.items.splice(index, 1, { ...item, ...payload });
|
|
} else {
|
|
newState.items.push({ ...payload });
|
|
}
|
|
|
|
return updateSectionState(state, section, newState);
|
|
}
|
|
|
|
}, defaultState, section);
|