✍🏽 Manual search override for AirDC++ query

This commit is contained in:
Rishi Ghan
2022-04-19 14:36:21 -07:00
parent ab19f37007
commit a40b08c990
3 changed files with 765 additions and 585 deletions

View File

@@ -31,85 +31,84 @@ function sleep(ms: number): Promise<NodeJS.Timeout> {
export const search =
(data: SearchData, ADCPPSocket: any, credentials: any) =>
async (dispatch) => {
try {
if (!ADCPPSocket.isConnected()) {
await ADCPPSocket.connect(
credentials.username,
credentials.password,
true,
);
}
const instance: SearchInstance = await ADCPPSocket.post("search");
dispatch({
type: AIRDCPP_SEARCH_IN_PROGRESS,
});
// We want to get notified about every new result in order to make the user experience better
await ADCPPSocket.addListener(
`search`,
"search_result_added",
async (groupedResult) => {
// ...add the received result in the UI
// (it's probably a good idea to have some kind of throttling for the UI updates as there can be thousands of results)
dispatch({
type: AIRDCPP_SEARCH_RESULTS_ADDED,
groupedResult,
});
},
instance.id,
async (dispatch) => {
try {
if (!ADCPPSocket.isConnected()) {
await ADCPPSocket.connect(
credentials.username,
credentials.password,
true,
);
// We also want to update the existing items in our list when new hits arrive for the previously listed files/directories
await ADCPPSocket.addListener(
`search`,
"search_result_updated",
async (groupedResult) => {
// ...update properties of the existing result in the UI
dispatch({
type: AIRDCPP_SEARCH_RESULTS_UPDATED,
groupedResult,
});
},
instance.id,
);
// We need to show something to the user in case the search won't yield any results so that he won't be waiting forever)
// Wait for 5 seconds for any results to arrive after the searches were sent to the hubs
await ADCPPSocket.addListener(
`search`,
"search_hub_searches_sent",
async (searchInfo) => {
await sleep(5000);
// Check the number of received results (in real use cases we should know that even without calling the API)
const currentInstance = await ADCPPSocket.get(
`search/${instance.id}`,
);
if (currentInstance.result_count === 0) {
// ...nothing was received, show an informative message to the user
console.log("No more search results.");
}
// The search can now be considered to be "complete"
// If there's an "in progress" indicator in the UI, that could also be disabled here
dispatch({
type: AIRDCPP_HUB_SEARCHES_SENT,
searchInfo,
instance,
});
},
instance.id,
);
// Finally, perform the actual search
await ADCPPSocket.post(`search/${instance.id}/hub_search`, data);
} catch (error) {
console.log(error);
throw error;
}
};
const instance: SearchInstance = await ADCPPSocket.post("search");
dispatch({
type: AIRDCPP_SEARCH_IN_PROGRESS,
});
// We want to get notified about every new result in order to make the user experience better
await ADCPPSocket.addListener(
`search`,
"search_result_added",
async (groupedResult) => {
// ...add the received result in the UI
// (it's probably a good idea to have some kind of throttling for the UI updates as there can be thousands of results)
dispatch({
type: AIRDCPP_SEARCH_RESULTS_ADDED,
groupedResult,
});
},
instance.id,
);
// We also want to update the existing items in our list when new hits arrive for the previously listed files/directories
await ADCPPSocket.addListener(
`search`,
"search_result_updated",
async (groupedResult) => {
// ...update properties of the existing result in the UI
dispatch({
type: AIRDCPP_SEARCH_RESULTS_UPDATED,
groupedResult,
});
},
instance.id,
);
// We need to show something to the user in case the search won't yield any results so that he won't be waiting forever)
// Wait for 5 seconds for any results to arrive after the searches were sent to the hubs
await ADCPPSocket.addListener(
`search`,
"search_hub_searches_sent",
async (searchInfo) => {
await sleep(5000);
// Check the number of received results (in real use cases we should know that even without calling the API)
const currentInstance = await ADCPPSocket.get(
`search/${instance.id}`,
);
if (currentInstance.result_count === 0) {
// ...nothing was received, show an informative message to the user
console.log("No more search results.");
}
// The search can now be considered to be "complete"
// If there's an "in progress" indicator in the UI, that could also be disabled here
dispatch({
type: AIRDCPP_HUB_SEARCHES_SENT,
searchInfo,
instance,
});
},
instance.id,
);
// Finally, perform the actual search
await ADCPPSocket.post(`search/${instance.id}/hub_search`, data);
} catch (error) {
console.log(error);
throw error;
}
};
export const downloadAirDCPPItem =
(
@@ -119,122 +118,126 @@ export const downloadAirDCPPItem =
ADCPPSocket: any,
credentials: any,
): void =>
async (dispatch) => {
try {
if (!ADCPPSocket.isConnected()) {
await ADCPPSocket.connect(
`${credentials.username}`,
`${credentials.password}`,
true,
);
}
let bundleDBImportResult = {};
const downloadResult = await ADCPPSocket.post(
`search/${instanceId}/results/${resultId}/download`,
async (dispatch) => {
try {
if (!ADCPPSocket.isConnected()) {
await ADCPPSocket.connect(
`${credentials.username}`,
`${credentials.password}`,
true,
);
let bundleId;
let directoryIds;
if (!isNil(downloadResult.bundle_info)) {
bundleId = downloadResult.bundle_info.id;
}
if (!isNil(downloadResult.directory_download_ids)) {
directoryIds = downloadResult.directory_download_ids.map(
(item) => item.id,
);
}
if (!isNil(downloadResult)) {
bundleDBImportResult = await axios({
method: "POST",
url: `${LIBRARY_SERVICE_BASE_URI}/applyAirDCPPDownloadMetadata`,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
data: {
resultId,
comicObjectId,
searchInstanceId: instanceId,
bundleId,
directoryIds,
},
});
dispatch({
type: AIRDCPP_RESULT_DOWNLOAD_INITIATED,
downloadResult: downloadResult,
bundleDBImportResult,
});
dispatch({
type: IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
comicBookDetail: bundleDBImportResult.data,
IMS_inProgress: false,
});
}
} catch (error) {
throw error;
}
};
let bundleDBImportResult = {};
const downloadResult = await ADCPPSocket.post(
`search/${instanceId}/results/${resultId}/download`,
);
export const getDownloadProgress =
(comicObjectId: string, ADCPPSocket: any, credentials: any): void =>
async (dispatch) => {
try {
if (!ADCPPSocket.isConnected()) {
await ADCPPSocket.connect(
`${credentials.username}`,
`${credentials.password}`,
true,
);
}
await ADCPPSocket.addListener(
`queue`,
"queue_bundle_tick",
async (downloadProgressData) => {
dispatch({
type: AIRDCPP_DOWNLOAD_PROGRESS_TICK,
downloadProgressData,
});
},
let bundleId;
let directoryIds;
if (!isNil(downloadResult.bundle_info)) {
bundleId = downloadResult.bundle_info.id;
}
if (!isNil(downloadResult.directory_download_ids)) {
directoryIds = downloadResult.directory_download_ids.map(
(item) => item.id,
);
// File status listener
await ADCPPSocket.addListener(`queue`, "queue_file_status", async (data) => console.log("FILE STATUS", data));
} catch (error) {
throw error;
}
};
export const getBundlesForComic =
(comicObjectId: string, ADCPPSocket: any, credentials: any) =>
async (dispatch) => {
try {
if (!ADCPPSocket.isConnected()) {
await ADCPPSocket.connect(
`${credentials.username}`,
`${credentials.password}`,
true,
);
}
const comicObject = await axios({
if (!isNil(downloadResult)) {
bundleDBImportResult = await axios({
method: "POST",
url: `${LIBRARY_SERVICE_BASE_URI}/getComicBookById`,
url: `${LIBRARY_SERVICE_BASE_URI}/applyAirDCPPDownloadMetadata`,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
data: {
id: `${comicObjectId}`,
resultId,
comicObjectId,
searchInstanceId: instanceId,
bundleId,
directoryIds,
},
});
// get only the bundles applicable for the comic
const filteredBundles = comicObject.data.acquisition.directconnect.map(
async ({ bundleId }) => {
return await ADCPPSocket.get(`queue/bundles/${bundleId}`);
},
);
dispatch({
type: AIRDCPP_BUNDLES_FETCHED,
bundles: await Promise.all(filteredBundles),
type: AIRDCPP_RESULT_DOWNLOAD_INITIATED,
downloadResult: downloadResult,
bundleDBImportResult,
});
dispatch({
type: IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
comicBookDetail: bundleDBImportResult.data,
IMS_inProgress: false,
});
} catch (error) {
throw error;
}
};
} catch (error) {
throw error;
}
};
export const getDownloadProgress =
(comicObjectId: string, ADCPPSocket: any, credentials: any): void =>
async (dispatch) => {
try {
if (!ADCPPSocket.isConnected()) {
await ADCPPSocket.connect(
`${credentials.username}`,
`${credentials.password}`,
true,
);
}
await ADCPPSocket.addListener(
`queue`,
"queue_bundle_tick",
async (downloadProgressData) => {
dispatch({
type: AIRDCPP_DOWNLOAD_PROGRESS_TICK,
downloadProgressData,
});
},
);
// File status listener
await ADCPPSocket.addListener(
`queue`,
"queue_file_status",
async (data) => console.log("FILE STATUS", data),
);
} catch (error) {
throw error;
}
};
export const getBundlesForComic =
(comicObjectId: string, ADCPPSocket: any, credentials: any) =>
async (dispatch) => {
try {
if (!ADCPPSocket.isConnected()) {
await ADCPPSocket.connect(
`${credentials.username}`,
`${credentials.password}`,
true,
);
}
const comicObject = await axios({
method: "POST",
url: `${LIBRARY_SERVICE_BASE_URI}/getComicBookById`,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
data: {
id: `${comicObjectId}`,
},
});
// get only the bundles applicable for the comic
const filteredBundles = comicObject.data.acquisition.directconnect.map(
async ({ bundleId }) => {
return await ADCPPSocket.get(`queue/bundles/${bundleId}`);
},
);
dispatch({
type: AIRDCPP_BUNDLES_FETCHED,
bundles: await Promise.all(filteredBundles),
});
} catch (error) {
throw error;
}
};

View File

@@ -24,7 +24,6 @@ interface IAcquisitionPanelProps {
export const AcquisitionPanel = (
props: IAcquisitionPanelProps,
): ReactElement => {
console.log(props);
const issueName = props.query.issue.name;
const sanitizedIssueName = issueName.replace(/[^a-zA-Z0-9 ]/g, " ");
@@ -67,8 +66,19 @@ export const AcquisitionPanel = (
const getDCPPSearchResults = useCallback(
async (searchQuery) => {
const manualQuery = {
query: {
pattern: `${searchQuery.issueName}`,
extensions: ["cbz", "cbr", "cb7"],
},
hub_urls: map(
userSettings.directConnect.client.hubs,
(item) => item.value,
),
priority: 5,
};
dispatch(
search(searchQuery, ADCPPSocket, {
search(manualQuery, ADCPPSocket, {
username: `${userSettings.directConnect.client.host.username}`,
password: `${userSettings.directConnect.client.host.password}`,
}),
@@ -113,7 +123,10 @@ export const AcquisitionPanel = (
issueName,
}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<div className="column is-three-quarters">
<form
onSubmit={handleSubmit}
className="column is-three-quarters"
>
<div className="box search">
<div className="columns">
<Field name="issueName">
@@ -135,12 +148,12 @@ export const AcquisitionPanel = (
<div className="column">
<button
type="submit"
className={
isAirDCPPSearchInProgress
? "button is-loading is-warning"
: "button"
}
onClick={() => getDCPPSearchResults(dcppQuery)}
>
<span className="icon is-small">
<img src="/img/airdcpp_logo.svg" />
@@ -150,7 +163,7 @@ export const AcquisitionPanel = (
</div>
</div>
</div>
</div>
</form>
)}
/>
) : (

964
yarn.lock

File diff suppressed because it is too large Load Diff