Compare commits
1 Commits
service-st
...
rishighan-
| Author | SHA1 | Date | |
|---|---|---|---|
| 540c711904 |
10
README.md
10
README.md
@@ -4,16 +4,6 @@ ThreeTwo! _aims to be_ a comic book curation app.
|
|||||||
|
|
||||||
[](https://github.com/rishighan/threetwo/actions/workflows/docker-image.yml)
|
[](https://github.com/rishighan/threetwo/actions/workflows/docker-image.yml)
|
||||||
|
|
||||||
### Screenshots
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### 🦄 Early Development Support Channel
|
### 🦄 Early Development Support Channel
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,10 @@
|
|||||||
"babel-preset-minify": "^0.5.2",
|
"babel-preset-minify": "^0.5.2",
|
||||||
"better-docs": "^2.7.2",
|
"better-docs": "^2.7.2",
|
||||||
"comlink-loader": "^2.0.0",
|
"comlink-loader": "^2.0.0",
|
||||||
|
"compromise": "^13.11.3",
|
||||||
|
"compromise-dates": "^2.2.1",
|
||||||
|
"compromise-numbers": "^1.4.0",
|
||||||
|
"compromise-sentences": "^0.3.0",
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.28.0",
|
||||||
"dayjs": "^1.10.6",
|
"dayjs": "^1.10.6",
|
||||||
"ellipsize": "^0.1.0",
|
"ellipsize": "^0.1.0",
|
||||||
@@ -59,9 +63,9 @@
|
|||||||
"pretty-bytes": "^5.6.0",
|
"pretty-bytes": "^5.6.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"qs": "^6.10.5",
|
"qs": "^6.10.5",
|
||||||
"react": "^18.2.0",
|
"react": "^18.1.0",
|
||||||
"react-collapsible": "^2.9.0",
|
"react-collapsible": "^2.9.0",
|
||||||
"react-comic-viewer": "^0.4.0",
|
"react-comic-viewer": "^0.3.5",
|
||||||
"react-day-picker": "^8.0.6",
|
"react-day-picker": "^8.0.6",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
"react-fast-compare": "^3.2.0",
|
"react-fast-compare": "^3.2.0",
|
||||||
@@ -134,6 +138,7 @@
|
|||||||
"bulma": "^0.9.3",
|
"bulma": "^0.9.3",
|
||||||
"clean-webpack-plugin": "^1.0.0",
|
"clean-webpack-plugin": "^1.0.0",
|
||||||
"comlink": "^4.3.0",
|
"comlink": "^4.3.0",
|
||||||
|
"compromise-strict": "^0.0.2",
|
||||||
"concurrently": "^4.0.0",
|
"concurrently": "^4.0.0",
|
||||||
"copy-webpack-plugin": "^9.0.1",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
"css-loader": "^5.1.2",
|
"css-loader": "^5.1.2",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -4,10 +4,7 @@ import {
|
|||||||
PriorityEnum,
|
PriorityEnum,
|
||||||
SearchResponse,
|
SearchResponse,
|
||||||
} from "threetwo-ui-typings";
|
} from "threetwo-ui-typings";
|
||||||
import {
|
import { LIBRARY_SERVICE_BASE_URI, SEARCH_SERVICE_BASE_URI } from "../constants/endpoints";
|
||||||
LIBRARY_SERVICE_BASE_URI,
|
|
||||||
SEARCH_SERVICE_BASE_URI,
|
|
||||||
} from "../constants/endpoints";
|
|
||||||
import {
|
import {
|
||||||
AIRDCPP_SEARCH_RESULTS_ADDED,
|
AIRDCPP_SEARCH_RESULTS_ADDED,
|
||||||
AIRDCPP_SEARCH_RESULTS_UPDATED,
|
AIRDCPP_SEARCH_RESULTS_UPDATED,
|
||||||
@@ -21,8 +18,6 @@ import {
|
|||||||
IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
|
IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
|
||||||
AIRDCPP_TRANSFERS_FETCHED,
|
AIRDCPP_TRANSFERS_FETCHED,
|
||||||
LIBRARY_ISSUE_BUNDLES,
|
LIBRARY_ISSUE_BUNDLES,
|
||||||
AIRDCPP_SOCKET_CONNECTED,
|
|
||||||
AIRDCPP_SOCKET_DISCONNECTED,
|
|
||||||
} from "../constants/action-types";
|
} from "../constants/action-types";
|
||||||
import { isNil } from "lodash";
|
import { isNil } from "lodash";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
@@ -37,199 +32,190 @@ function sleep(ms: number): Promise<NodeJS.Timeout> {
|
|||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const toggleAirDCPPSocketConnectionStatus =
|
|
||||||
(status: String, payload?: any) => async (dispatch) => {
|
|
||||||
switch (status) {
|
|
||||||
case "connected":
|
|
||||||
dispatch({
|
|
||||||
type: AIRDCPP_SOCKET_CONNECTED,
|
|
||||||
data: payload,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "disconnected":
|
|
||||||
dispatch({
|
|
||||||
type: AIRDCPP_SOCKET_DISCONNECTED,
|
|
||||||
data: payload,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
console.log("Can't set AirDC++ socket status.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export const search =
|
export const search =
|
||||||
(data: SearchData, ADCPPSocket: any, credentials: any) =>
|
(data: SearchData, ADCPPSocket: any, credentials: any) =>
|
||||||
async (dispatch) => {
|
async (dispatch) => {
|
||||||
try {
|
try {
|
||||||
if (!ADCPPSocket.isConnected()) {
|
if (!ADCPPSocket.isConnected()) {
|
||||||
await ADCPPSocket();
|
await ADCPPSocket.connect(
|
||||||
}
|
credentials.username,
|
||||||
const instance: SearchInstance = await ADCPPSocket.post("search");
|
credentials.password,
|
||||||
dispatch({
|
true,
|
||||||
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
|
const instance: SearchInstance = await ADCPPSocket.post("search");
|
||||||
console.log("No more search results.");
|
dispatch({
|
||||||
}
|
type: AIRDCPP_SEARCH_IN_PROGRESS,
|
||||||
|
});
|
||||||
|
|
||||||
// The search can now be considered to be "complete"
|
// We want to get notified about every new result in order to make the user experience better
|
||||||
// If there's an "in progress" indicator in the UI, that could also be disabled here
|
await ADCPPSocket.addListener(
|
||||||
dispatch({
|
`search`,
|
||||||
type: AIRDCPP_HUB_SEARCHES_SENT,
|
"search_result_added",
|
||||||
searchInfo,
|
async (groupedResult) => {
|
||||||
instance,
|
// ...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)
|
||||||
},
|
|
||||||
instance.id,
|
dispatch({
|
||||||
);
|
type: AIRDCPP_SEARCH_RESULTS_ADDED,
|
||||||
// Finally, perform the actual search
|
groupedResult,
|
||||||
await ADCPPSocket.post(`search/${instance.id}/hub_search`, data);
|
});
|
||||||
} catch (error) {
|
},
|
||||||
console.log(error);
|
instance.id,
|
||||||
throw error;
|
);
|
||||||
}
|
|
||||||
};
|
// 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 =
|
export const downloadAirDCPPItem =
|
||||||
(
|
(searchInstanceId: Number,
|
||||||
searchInstanceId: Number,
|
|
||||||
resultId: String,
|
resultId: String,
|
||||||
comicObjectId: String,
|
comicObjectId: String,
|
||||||
name: String,
|
name: String, size: Number, type: any,
|
||||||
size: Number,
|
|
||||||
type: any,
|
|
||||||
ADCPPSocket: any,
|
ADCPPSocket: any,
|
||||||
credentials: any,
|
credentials: any,
|
||||||
): void =>
|
): void =>
|
||||||
async (dispatch) => {
|
async (dispatch) => {
|
||||||
try {
|
try {
|
||||||
if (!ADCPPSocket.isConnected()) {
|
if (!ADCPPSocket.isConnected()) {
|
||||||
await ADCPPSocket.connect();
|
await ADCPPSocket.connect(
|
||||||
}
|
`${credentials.username}`,
|
||||||
let bundleDBImportResult = {};
|
`${credentials.password}`,
|
||||||
const downloadResult = await ADCPPSocket.post(
|
true,
|
||||||
`search/${searchInstanceId}/results/${resultId}/download`,
|
);
|
||||||
);
|
}
|
||||||
|
let bundleDBImportResult = {};
|
||||||
|
const downloadResult = await ADCPPSocket.post(
|
||||||
|
`search/${searchInstanceId}/results/${resultId}/download`,
|
||||||
|
);
|
||||||
|
|
||||||
if (!isNil(downloadResult)) {
|
if (!isNil(downloadResult)) {
|
||||||
bundleDBImportResult = await axios({
|
bundleDBImportResult = await axios({
|
||||||
|
method: "POST",
|
||||||
|
url: `${LIBRARY_SERVICE_BASE_URI}/applyAirDCPPDownloadMetadata`,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
bundleId: downloadResult.bundle_info.id,
|
||||||
|
comicObjectId,
|
||||||
|
name,
|
||||||
|
size,
|
||||||
|
type,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: AIRDCPP_RESULT_DOWNLOAD_INITIATED,
|
||||||
|
downloadResult,
|
||||||
|
bundleDBImportResult,
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
|
||||||
|
comicBookDetail: bundleDBImportResult.data,
|
||||||
|
IMS_inProgress: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
} 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",
|
method: "POST",
|
||||||
url: `${LIBRARY_SERVICE_BASE_URI}/applyAirDCPPDownloadMetadata`,
|
url: `${LIBRARY_SERVICE_BASE_URI}/getComicBookById`,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
bundleId: downloadResult.bundle_info.id,
|
id: `${comicObjectId}`,
|
||||||
comicObjectId,
|
|
||||||
name,
|
|
||||||
size,
|
|
||||||
type,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// get only the bundles applicable for the comic
|
||||||
dispatch({
|
if (comicObject.data.acquisition.directconnect) {
|
||||||
type: AIRDCPP_RESULT_DOWNLOAD_INITIATED,
|
const filteredBundles = comicObject.data.acquisition.directconnect.downloads.map(
|
||||||
downloadResult,
|
|
||||||
bundleDBImportResult,
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: IMS_COMIC_BOOK_DB_OBJECT_FETCHED,
|
|
||||||
comicBookDetail: bundleDBImportResult.data,
|
|
||||||
IMS_inProgress: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getBundlesForComic =
|
|
||||||
(comicObjectId: string, ADCPPSocket: any, credentials: any) =>
|
|
||||||
async (dispatch) => {
|
|
||||||
try {
|
|
||||||
if (!ADCPPSocket.isConnected()) {
|
|
||||||
await ADCPPSocket.connect();
|
|
||||||
}
|
|
||||||
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
|
|
||||||
if (comicObject.data.acquisition.directconnect) {
|
|
||||||
const filteredBundles =
|
|
||||||
comicObject.data.acquisition.directconnect.downloads.map(
|
|
||||||
async ({ bundleId }) => {
|
async ({ bundleId }) => {
|
||||||
return await ADCPPSocket.get(`queue/bundles/${bundleId}`);
|
return await ADCPPSocket.get(`queue/bundles/${bundleId}`);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: AIRDCPP_BUNDLES_FETCHED,
|
type: AIRDCPP_BUNDLES_FETCHED,
|
||||||
bundles: await Promise.all(filteredBundles),
|
bundles: await Promise.all(filteredBundles),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
};
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getTransfers =
|
export const getTransfers =
|
||||||
(ADCPPSocket: any, credentials: any) => async (dispatch) => {
|
(ADCPPSocket: any, credentials: any) => async (dispatch) => {
|
||||||
try {
|
try {
|
||||||
if (!ADCPPSocket.isConnected()) {
|
if (!ADCPPSocket.isConnected()) {
|
||||||
await ADCPPSocket.connect();
|
await ADCPPSocket.connect(
|
||||||
|
`${credentials.username}`,
|
||||||
|
`${credentials.password}`,
|
||||||
|
true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const bundles = await ADCPPSocket.get("queue/bundles/1/85", {});
|
const bundles = await ADCPPSocket.get("queue/bundles/1/85", {});
|
||||||
if (!isNil(bundles)) {
|
if (!isNil(bundles)) {
|
||||||
@@ -248,6 +234,7 @@ export const getTransfers =
|
|||||||
type: LIBRARY_ISSUE_BUNDLES,
|
type: LIBRARY_ISSUE_BUNDLES,
|
||||||
issue_bundles,
|
issue_bundles,
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import {
|
|||||||
CV_WEEKLY_PULLLIST_FETCHED,
|
CV_WEEKLY_PULLLIST_FETCHED,
|
||||||
} from "../constants/action-types";
|
} from "../constants/action-types";
|
||||||
import { success } from "react-notification-system-redux";
|
import { success } from "react-notification-system-redux";
|
||||||
|
import { removeLeadingPeriod } from "../shared/utils/formatting.utils";
|
||||||
import { isNil, map } from "lodash";
|
import { isNil, map } from "lodash";
|
||||||
|
|
||||||
export async function walkFolder(path: string): Promise<Array<IFolderData>> {
|
export async function walkFolder(path: string): Promise<Array<IFolderData>> {
|
||||||
@@ -60,6 +60,15 @@ export async function walkFolder(path: string): Promise<Array<IFolderData>> {
|
|||||||
* @return the comic book metadata
|
* @return the comic book metadata
|
||||||
*/
|
*/
|
||||||
export const fetchComicBookMetadata = () => async (dispatch) => {
|
export const fetchComicBookMetadata = () => async (dispatch) => {
|
||||||
|
const extractionOptions = {
|
||||||
|
extractTarget: "cover",
|
||||||
|
targetExtractionFolder: "./userdata/covers",
|
||||||
|
extractionMode: "bulk",
|
||||||
|
paginationOptions: {
|
||||||
|
pageLimit: 25,
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
dispatch({
|
dispatch({
|
||||||
type: LS_IMPORT_CALL_IN_PROGRESS,
|
type: LS_IMPORT_CALL_IN_PROGRESS,
|
||||||
});
|
});
|
||||||
@@ -77,7 +86,7 @@ export const fetchComicBookMetadata = () => async (dispatch) => {
|
|||||||
dispatch({
|
dispatch({
|
||||||
type: LS_IMPORT,
|
type: LS_IMPORT,
|
||||||
meta: { remote: true },
|
meta: { remote: true },
|
||||||
data: {},
|
data: { extractionOptions },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
export const toggleImportQueueStatus = (options) => async (dispatch) => {
|
export const toggleImportQueueStatus = (options) => async (dispatch) => {
|
||||||
@@ -127,24 +136,21 @@ export const getComicBooks = (options) => async (dispatch) => {
|
|||||||
* @returns Nothing.
|
* @returns Nothing.
|
||||||
* @param payload
|
* @param payload
|
||||||
*/
|
*/
|
||||||
export const importToDB = (sourceName: string, metadata?: any) => (dispatch) => {
|
export const importToDB = (sourceName: string, payload?: any) => (dispatch) => {
|
||||||
try {
|
try {
|
||||||
const comicBookMetadata = {
|
const comicBookMetadata = {
|
||||||
importType: "new",
|
rawFileDetails: {
|
||||||
payload: {
|
name: "",
|
||||||
rawFileDetails: {
|
},
|
||||||
name: "",
|
importStatus: {
|
||||||
|
isImported: true,
|
||||||
|
tagged: false,
|
||||||
|
matchedResult: {
|
||||||
|
score: "0",
|
||||||
},
|
},
|
||||||
importStatus: {
|
},
|
||||||
isImported: true,
|
sourcedMetadata: payload || null,
|
||||||
tagged: false,
|
acquisition: { source: { wanted: true, name: sourceName } },
|
||||||
matchedResult: {
|
|
||||||
score: "0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sourcedMetadata: metadata || null,
|
|
||||||
acquisition: { source: { wanted: true, name: sourceName } },
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
dispatch({
|
dispatch({
|
||||||
type: IMS_CV_METADATA_IMPORT_CALL_IN_PROGRESS,
|
type: IMS_CV_METADATA_IMPORT_CALL_IN_PROGRESS,
|
||||||
@@ -253,32 +259,33 @@ export const fetchComicVineMatches =
|
|||||||
* @param {any} options Options object
|
* @param {any} options Options object
|
||||||
* @returns {any}
|
* @returns {any}
|
||||||
*/
|
*/
|
||||||
export const extractComicArchive =
|
export const extractComicArchive = (path: string, options: any) => async (dispatch) => {
|
||||||
|
const comicBookPages: string[] = [];
|
||||||
|
dispatch({
|
||||||
|
type: IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_IN_PROGRESS,
|
||||||
|
});
|
||||||
|
const extractedComicBookArchive = await axios({
|
||||||
|
method: "POST",
|
||||||
|
url: `${LIBRARY_SERVICE_BASE_URI}/uncompressFullArchive`,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
filePath: path,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
map(extractedComicBookArchive.data, (page) => {
|
||||||
|
console.log(page);
|
||||||
|
const pageFilePath = removeLeadingPeriod(page);
|
||||||
|
const imagePath = encodeURI(`${LIBRARY_SERVICE_HOST}${pageFilePath}`);
|
||||||
|
comicBookPages.push(imagePath);
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_SUCCESS,
|
||||||
|
extractedComicBookArchive: comicBookPages,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
(path: string, options: any): any =>
|
|
||||||
async (dispatch) => {
|
|
||||||
dispatch({
|
|
||||||
type: IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_IN_PROGRESS,
|
|
||||||
});
|
|
||||||
await axios({
|
|
||||||
method: "POST",
|
|
||||||
url: `${LIBRARY_SERVICE_BASE_URI}/uncompressFullArchive`,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
filePath: path,
|
|
||||||
options,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description
|
|
||||||
* @param {any} query
|
|
||||||
* @param {any} options
|
|
||||||
* @returns {any}
|
|
||||||
*/
|
|
||||||
export const searchIssue = (query, options) => async (dispatch) => {
|
export const searchIssue = (query, options) => async (dispatch) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: SS_SEARCH_IN_PROGRESS,
|
type: SS_SEARCH_IN_PROGRESS,
|
||||||
|
|||||||
@@ -62,10 +62,6 @@ pre {
|
|||||||
margin-left: -300px;
|
margin-left: -300px;
|
||||||
min-width: 500px;
|
min-width: 500px;
|
||||||
}
|
}
|
||||||
.airdcpp-status {
|
|
||||||
min-width: 300px;
|
|
||||||
line-height: 1.7rem;
|
|
||||||
}
|
|
||||||
body {
|
body {
|
||||||
background: #454a59;
|
background: #454a59;
|
||||||
}
|
}
|
||||||
@@ -360,10 +356,6 @@ pre {
|
|||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comic-viewer {
|
|
||||||
border: 1px solid red;
|
|
||||||
}
|
|
||||||
|
|
||||||
// comicvine metadata
|
// comicvine metadata
|
||||||
.comicvine-metadata {
|
.comicvine-metadata {
|
||||||
background-color: #f2f1f9;
|
background-color: #f2f1f9;
|
||||||
|
|||||||
@@ -18,11 +18,8 @@ import {
|
|||||||
AirDCPPSocketContext,
|
AirDCPPSocketContext,
|
||||||
} from "../context/AirDCPPSocket";
|
} from "../context/AirDCPPSocket";
|
||||||
import { isEmpty, isUndefined } from "lodash";
|
import { isEmpty, isUndefined } from "lodash";
|
||||||
import {
|
import { AIRDCPP_DOWNLOAD_PROGRESS_TICK } from "../constants/action-types";
|
||||||
AIRDCPP_DOWNLOAD_PROGRESS_TICK,
|
import { useDispatch } from "react-redux";
|
||||||
LS_SINGLE_IMPORT,
|
|
||||||
} from "../constants/action-types";
|
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method that initializes an AirDC++ socket connection
|
* Method that initializes an AirDC++ socket connection
|
||||||
@@ -33,7 +30,6 @@ import { useDispatch, useSelector } from "react-redux";
|
|||||||
const AirDCPPSocketComponent = (): ReactElement => {
|
const AirDCPPSocketComponent = (): ReactElement => {
|
||||||
const airDCPPConfiguration = useContext(AirDCPPSocketContext);
|
const airDCPPConfiguration = useContext(AirDCPPSocketContext);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initializeAirDCPPEventListeners = async () => {
|
const initializeAirDCPPEventListeners = async () => {
|
||||||
if (
|
if (
|
||||||
@@ -46,7 +42,9 @@ const AirDCPPSocketComponent = (): ReactElement => {
|
|||||||
"queue_bundle_added",
|
"queue_bundle_added",
|
||||||
async (data) => {
|
async (data) => {
|
||||||
console.log("JEMEN:", data);
|
console.log("JEMEN:", data);
|
||||||
},
|
|
||||||
|
|
||||||
|
}
|
||||||
);
|
);
|
||||||
// download tick listener
|
// download tick listener
|
||||||
await airDCPPConfiguration.airDCPPState.socket.addListener(
|
await airDCPPConfiguration.airDCPPState.socket.addListener(
|
||||||
@@ -64,18 +62,9 @@ const AirDCPPSocketComponent = (): ReactElement => {
|
|||||||
`queue`,
|
`queue`,
|
||||||
"queue_bundle_status",
|
"queue_bundle_status",
|
||||||
async (bundleData) => {
|
async (bundleData) => {
|
||||||
let count = 0;
|
|
||||||
if (bundleData.status.completed && bundleData.status.downloaded) {
|
if (bundleData.status.completed && bundleData.status.downloaded) {
|
||||||
// dispatch the action for raw import, with the metadata
|
// dispatch the action for raw import, with the metadata
|
||||||
if (count < 1) {
|
console.log("IM THE MAN UP IN THIS")
|
||||||
console.log(`[AirDCPP]: Download complete.`);
|
|
||||||
dispatch({
|
|
||||||
type: LS_SINGLE_IMPORT,
|
|
||||||
meta: { remote: true },
|
|
||||||
data: bundleData,
|
|
||||||
});
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -103,10 +92,7 @@ export const App = (): ReactElement => {
|
|||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Dashboard />} />
|
<Route path="/" element={<Dashboard />} />
|
||||||
<Route path="/import" element={<Import path={"./comics"} />} />
|
<Route path="/import" element={<Import path={"./comics"} />} />
|
||||||
<Route
|
<Route path="/library" element={<TabulatedContentContainer category="library" />} />
|
||||||
path="/library"
|
|
||||||
element={<TabulatedContentContainer category="library" />}
|
|
||||||
/>
|
|
||||||
<Route path="/library-grid" element={<LibraryGrid />} />
|
<Route path="/library-grid" element={<LibraryGrid />} />
|
||||||
<Route path="/downloads" element={<Downloads data={{}} />} />
|
<Route path="/downloads" element={<Downloads data={{}} />} />
|
||||||
<Route path="/search" element={<Search />} />
|
<Route path="/search" element={<Search />} />
|
||||||
@@ -119,18 +105,9 @@ export const App = (): ReactElement => {
|
|||||||
element={<VolumeDetail />}
|
element={<VolumeDetail />}
|
||||||
/>
|
/>
|
||||||
<Route path="/settings" element={<Settings />} />
|
<Route path="/settings" element={<Settings />} />
|
||||||
<Route
|
<Route path="/pull-list/all" element={<TabulatedContentContainer category="pullList" />} />
|
||||||
path="/pull-list/all"
|
<Route path="/wanted/all" element={<TabulatedContentContainer category="wanted" />} />
|
||||||
element={<TabulatedContentContainer category="pullList" />}
|
<Route path="/volumes/all" element={<TabulatedContentContainer category="volumes" />} />
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="/wanted/all"
|
|
||||||
element={<TabulatedContentContainer category="wanted" />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="/volumes/all"
|
|
||||||
element={<TabulatedContentContainer category="volumes" />}
|
|
||||||
/>
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
</AirDCPPSocketContextProvider>
|
</AirDCPPSocketContextProvider>
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import ellipsize from "ellipsize";
|
|||||||
import { Form, Field } from "react-final-form";
|
import { Form, Field } from "react-final-form";
|
||||||
import { isEmpty, isNil, map } from "lodash";
|
import { isEmpty, isNil, map } from "lodash";
|
||||||
import { AirDCPPSocketContext } from "../../context/AirDCPPSocket";
|
import { AirDCPPSocketContext } from "../../context/AirDCPPSocket";
|
||||||
|
|
||||||
interface IAcquisitionPanelProps {
|
interface IAcquisitionPanelProps {
|
||||||
query: any;
|
query: any;
|
||||||
comicObjectId: any;
|
comicObjectId: any;
|
||||||
@@ -97,12 +96,9 @@ export const AcquisitionPanel = (
|
|||||||
(searchInstanceId, resultId, name, size, type) => {
|
(searchInstanceId, resultId, name, size, type) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
downloadAirDCPPItem(
|
downloadAirDCPPItem(
|
||||||
searchInstanceId,
|
searchInstanceId, resultId,
|
||||||
resultId,
|
|
||||||
props.comicObjectId,
|
props.comicObjectId,
|
||||||
name,
|
name, size, type,
|
||||||
size,
|
|
||||||
type,
|
|
||||||
airDCPPConfiguration.airDCPPState.socket,
|
airDCPPConfiguration.airDCPPState.socket,
|
||||||
{
|
{
|
||||||
username: `${airDCPPConfiguration.airDCPPState.settings.directConnect.client.host.username}`,
|
username: `${airDCPPConfiguration.airDCPPState.settings.directConnect.client.host.username}`,
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const extractedComicBook = useSelector(
|
const extractedComicBook = useSelector(
|
||||||
(state: RootState) => state.fileOps.extractedComicBookArchive.reading,
|
(state: RootState) => state.fileOps.extractedComicBookArchive,
|
||||||
);
|
);
|
||||||
const { comicObjectId } = useParams<{ comicObjectId: string }>();
|
const { comicObjectId } = useParams<{ comicObjectId: string }>();
|
||||||
|
|
||||||
@@ -74,21 +74,13 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
|
|
||||||
const openModal = useCallback((filePath) => {
|
const openModal = useCallback((filePath) => {
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
dispatch(
|
dispatch(extractComicArchive(filePath));
|
||||||
extractComicArchive(filePath, {
|
|
||||||
type: "full",
|
|
||||||
purpose: "reading",
|
|
||||||
imageResizeOptions: {
|
|
||||||
baseWidth: 1024,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const afterOpenModal = useCallback((things) => {
|
const afterOpenModal = useCallback((things) => {
|
||||||
// references are now sync'd and can be accessed.
|
// references are now sync'd and can be accessed.
|
||||||
// subtitle.style.color = "#f00";
|
// subtitle.style.color = "#f00";
|
||||||
console.log("kolaveri", things);
|
console.log(things);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const closeModal = useCallback(() => {
|
const closeModal = useCallback(() => {
|
||||||
@@ -102,7 +94,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
<>
|
<>
|
||||||
<div className="card search-criteria-card">
|
<div className="card search-criteria-card">
|
||||||
<div className="card-content">
|
<div className="card-content">
|
||||||
<ComicVineSearchForm data={rawFileDetails} />
|
<ComicVineSearchForm data={rawFileDetails}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="is-size-5 mt-3 mb-2 ml-3">Searching for:</p>
|
<p className="is-size-5 mt-3 mb-2 ml-3">Searching for:</p>
|
||||||
@@ -120,9 +112,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
comicVineSearchResults,
|
comicVineSearchResults,
|
||||||
comicObjectId,
|
comicObjectId,
|
||||||
}}
|
}}
|
||||||
/>
|
/>) : (<div className="progress-indicator-container" >
|
||||||
) : (
|
|
||||||
<div className="progress-indicator-container">
|
|
||||||
<div className="indicator">
|
<div className="indicator">
|
||||||
<Loader
|
<Loader
|
||||||
type="MutatingDots"
|
type="MutatingDots"
|
||||||
@@ -133,17 +123,17 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
visible={comicVineAPICallProgress}
|
visible={comicVineAPICallProgress}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div >)}
|
||||||
)}
|
</>),
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
editComicBookMetadata: {
|
editComicBookMetadata: {
|
||||||
content: () => <EditMetadataPanel />,
|
content: () => <EditMetadataPanel />,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// check for the availability of CV metadata
|
// check for the availability of CV metadata
|
||||||
const isComicBookMetadataAvailable =
|
const isComicBookMetadataAvailable =
|
||||||
!isUndefined(comicvine) && !isUndefined(comicvine.volumeInformation);
|
!isUndefined(comicvine) && !isUndefined(comicvine.volumeInformation);
|
||||||
@@ -259,7 +249,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* raw file details */}
|
{/* raw file details */}
|
||||||
<div className="column">
|
<div className="column is-three-fifths">
|
||||||
{!isUndefined(rawFileDetails) &&
|
{!isUndefined(rawFileDetails) &&
|
||||||
!isEmpty(rawFileDetails.cover) && (
|
!isEmpty(rawFileDetails.cover) && (
|
||||||
<>
|
<>
|
||||||
@@ -290,7 +280,6 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
|
|||||||
<ComicViewer
|
<ComicViewer
|
||||||
pages={extractedComicBook}
|
pages={extractedComicBook}
|
||||||
direction="ltr"
|
direction="ltr"
|
||||||
className={{closeButton: "border: 1px solid red;"}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import Card from "../Carda";
|
|||||||
export const ComicVineDetails = (props): ReactElement => {
|
export const ComicVineDetails = (props): ReactElement => {
|
||||||
const { data, updatedAt } = props;
|
const { data, updatedAt } = props;
|
||||||
return (
|
return (
|
||||||
<div className="column is-half">
|
<div className="column is-two-thirds">
|
||||||
<div className="comic-detail comicvine-metadata">
|
<div className="comic-detail comicvine-metadata">
|
||||||
<dl>
|
<dl>
|
||||||
<dt>ComicVine Metadata</dt>
|
<dt>ComicVine Metadata</dt>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const RawFileDetails = (props): ReactElement => {
|
|||||||
const { rawFileDetails, inferredMetadata } = props.data;
|
const { rawFileDetails, inferredMetadata } = props.data;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="comic-detail raw-file-details column is-three-fifths">
|
<div className="comic-detail raw-file-details">
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Raw File Details</dt>
|
<dt>Raw File Details</dt>
|
||||||
<dd className="is-size-7">
|
<dd className="is-size-7">
|
||||||
@@ -38,8 +38,7 @@ export const RawFileDetails = (props): ReactElement => {
|
|||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="content comic-detail raw-file-details mt-3">
|
||||||
<div className="content comic-detail raw-file-details mt-3 column is-three-fifths">
|
|
||||||
<dl>
|
<dl>
|
||||||
{/* inferred metadata */}
|
{/* inferred metadata */}
|
||||||
<dt>Inferred Issue Metadata</dt>
|
<dt>Inferred Issue Metadata</dt>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const ArchiveOperations = (props): ReactElement => {
|
|||||||
(state: RootState) => state.fileOps.comicBookExtractionInProgress,
|
(state: RootState) => state.fileOps.comicBookExtractionInProgress,
|
||||||
);
|
);
|
||||||
const extractedComicBookArchive = useSelector(
|
const extractedComicBookArchive = useSelector(
|
||||||
(state: RootState) => state.fileOps.extractedComicBookArchive.analysis,
|
(state: RootState) => state.fileOps.extractedComicBookArchive,
|
||||||
);
|
);
|
||||||
|
|
||||||
const imageAnalysisResult = useSelector((state: RootState) => {
|
const imageAnalysisResult = useSelector((state: RootState) => {
|
||||||
@@ -23,15 +23,7 @@ export const ArchiveOperations = (props): ReactElement => {
|
|||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const unpackComicArchive = useCallback(() => {
|
const unpackComicArchive = useCallback(() => {
|
||||||
dispatch(
|
dispatch(extractComicArchive(data.rawFileDetails.filePath));
|
||||||
extractComicArchive(data.rawFileDetails.filePath, {
|
|
||||||
type: "full",
|
|
||||||
purpose: "analysis",
|
|
||||||
imageResizeOptions: {
|
|
||||||
baseWidth: 275,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// sliding panel config
|
// sliding panel config
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
getComicBooks,
|
getComicBooks,
|
||||||
} from "../../actions/fileops.actions";
|
} from "../../actions/fileops.actions";
|
||||||
import { getLibraryStatistics } from "../../actions/comicinfo.actions";
|
import { getLibraryStatistics } from "../../actions/comicinfo.actions";
|
||||||
import { isEmpty, isNil } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
|
|
||||||
export const Dashboard = (): ReactElement => {
|
export const Dashboard = (): ReactElement => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -43,7 +43,7 @@ export const Dashboard = (): ReactElement => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const recentComics = useSelector(
|
const recentComics = useSelector(
|
||||||
(state: RootState) => state.fileOps.recentComics
|
(state: RootState) => state.fileOps.recentComics,
|
||||||
);
|
);
|
||||||
const wantedComics = useSelector(
|
const wantedComics = useSelector(
|
||||||
(state: RootState) => state.fileOps.wantedComics,
|
(state: RootState) => state.fileOps.wantedComics,
|
||||||
@@ -60,7 +60,7 @@ export const Dashboard = (): ReactElement => {
|
|||||||
<section className="section">
|
<section className="section">
|
||||||
<h1 className="title">Dashboard</h1>
|
<h1 className="title">Dashboard</h1>
|
||||||
|
|
||||||
{!isEmpty(recentComics) ? (
|
{!isEmpty(recentComics) && !isEmpty(recentComics.docs) ? (
|
||||||
<>
|
<>
|
||||||
{/* Pull List */}
|
{/* Pull List */}
|
||||||
<PullList issues={recentComics} />
|
<PullList issues={recentComics} />
|
||||||
@@ -74,8 +74,9 @@ export const Dashboard = (): ReactElement => {
|
|||||||
<WantedComicsList comics={wantedComics} />
|
<WantedComicsList comics={wantedComics} />
|
||||||
)}
|
)}
|
||||||
{/* Recent imports */}
|
{/* Recent imports */}
|
||||||
|
{!isEmpty(recentComics) && (
|
||||||
<RecentlyImported comicBookCovers={recentComics} />
|
<RecentlyImported comicBookCovers={recentComics} />
|
||||||
|
)}
|
||||||
{/* Volumes */}
|
{/* Volumes */}
|
||||||
{!isEmpty(volumeGroups) && (
|
{!isEmpty(volumeGroups) && (
|
||||||
<VolumeGroups volumeGroups={volumeGroups} />
|
<VolumeGroups volumeGroups={volumeGroups} />
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const PullList = ({ issues }: PullListProps): ReactElement => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(
|
dispatch(
|
||||||
getWeeklyPullList({
|
getWeeklyPullList({
|
||||||
startDate: "2022-12-25",
|
startDate: "2022-11-15",
|
||||||
pageSize: "15",
|
pageSize: "15",
|
||||||
currentPage: "1",
|
currentPage: "1",
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { ReactElement } from "react";
|
|||||||
import Card from "../Carda";
|
import Card from "../Carda";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import ellipsize from "ellipsize";
|
import ellipsize from "ellipsize";
|
||||||
|
import { escapePoundSymbol } from "../../shared/utils/formatting.utils";
|
||||||
import { isEmpty, isNil, isUndefined, map } from "lodash";
|
import { isEmpty, isNil, isUndefined, map } from "lodash";
|
||||||
import { detectIssueTypes } from "../../shared/utils/tradepaperback.utils";
|
import { detectIssueTypes } from "../../shared/utils/tradepaperback.utils";
|
||||||
import Masonry from "react-masonry-css";
|
import Masonry from "react-masonry-css";
|
||||||
@@ -23,6 +24,7 @@ export const RecentlyImported = ({
|
|||||||
700: 2,
|
700: 2,
|
||||||
600: 2,
|
600: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="content mt-5">
|
<div className="content mt-5">
|
||||||
@@ -39,7 +41,7 @@ export const RecentlyImported = ({
|
|||||||
columnClassName="recent-comics-column"
|
columnClassName="recent-comics-column"
|
||||||
>
|
>
|
||||||
{map(
|
{map(
|
||||||
comicBookCovers,
|
comicBookCovers.docs,
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
_id,
|
_id,
|
||||||
@@ -62,6 +64,7 @@ export const RecentlyImported = ({
|
|||||||
comicInfo,
|
comicInfo,
|
||||||
locg,
|
locg,
|
||||||
});
|
});
|
||||||
|
|
||||||
const isComicBookMetadataAvailable =
|
const isComicBookMetadataAvailable =
|
||||||
!isUndefined(comicvine) &&
|
!isUndefined(comicvine) &&
|
||||||
!isUndefined(comicvine.volumeInformation);
|
!isUndefined(comicvine.volumeInformation);
|
||||||
@@ -120,7 +123,7 @@ export const RecentlyImported = ({
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
{/* metadata card */}
|
{/* metadata card */}
|
||||||
{!isNil(name) && (
|
{!isNil(name) ? (
|
||||||
<Card orientation="horizontal" hasDetails imageUrl={coverURL}>
|
<Card orientation="horizontal" hasDetails imageUrl={coverURL}>
|
||||||
<dd className="is-size-9">
|
<dd className="is-size-9">
|
||||||
<dl>
|
<dl>
|
||||||
@@ -135,7 +138,7 @@ export const RecentlyImported = ({
|
|||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
) : null}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useDispatch, useSelector } from "react-redux";
|
|||||||
import { searchIssue } from "../../actions/fileops.actions";
|
import { searchIssue } from "../../actions/fileops.actions";
|
||||||
import ellipsize from "ellipsize";
|
import ellipsize from "ellipsize";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that tabulates the contents of the user's ThreeTwo Library.
|
* Component that tabulates the contents of the user's ThreeTwo Library.
|
||||||
*
|
*
|
||||||
@@ -19,10 +20,9 @@ export const Library = (): ReactElement => {
|
|||||||
const searchResults = useSelector(
|
const searchResults = useSelector(
|
||||||
(state: RootState) => state.fileOps.libraryComics,
|
(state: RootState) => state.fileOps.libraryComics,
|
||||||
);
|
);
|
||||||
const searchError = useSelector((state: RootState) => {
|
const searchError = useSelector(
|
||||||
console.log(state);
|
(state: RootState) => state.fileOps.librarySearchError,
|
||||||
return state.fileOps.librarySearchError;
|
);
|
||||||
});
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@@ -36,7 +36,7 @@ export const Library = (): ReactElement => {
|
|||||||
from: 0,
|
from: 0,
|
||||||
},
|
},
|
||||||
type: "all",
|
type: "all",
|
||||||
trigger: "libraryPage",
|
trigger: "libraryPage"
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -89,67 +89,63 @@ export const Library = (): ReactElement => {
|
|||||||
const WantedStatus = ({ value }) => {
|
const WantedStatus = ({ value }) => {
|
||||||
return !value ? <span className="tag is-info is-light">Wanted</span> : null;
|
return !value ? <span className="tag is-info is-light">Wanted</span> : null;
|
||||||
};
|
};
|
||||||
const columns = useMemo(
|
const columns = useMemo(() => [
|
||||||
() => [
|
{
|
||||||
{
|
header: "Comic Metadata",
|
||||||
header: "Comic Metadata",
|
footer: 1,
|
||||||
footer: 1,
|
columns: [
|
||||||
columns: [
|
{
|
||||||
{
|
header: "File Details",
|
||||||
header: "File Details",
|
id: "fileDetails",
|
||||||
id: "fileDetails",
|
minWidth: 400,
|
||||||
minWidth: 400,
|
accessorKey: "_source",
|
||||||
accessorKey: "_source",
|
cell: info => {
|
||||||
cell: (info) => {
|
return <MetadataPanel data={info.getValue()} />;
|
||||||
return <MetadataPanel data={info.getValue()} />;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
header: "ComicInfo.xml",
|
{
|
||||||
accessorKey: "_source.sourcedMetadata.comicInfo",
|
header: "ComicInfo.xml",
|
||||||
align: "center",
|
accessorKey: "_source.sourcedMetadata.comicInfo",
|
||||||
minWidth: 250,
|
align: "center",
|
||||||
cell: (info) =>
|
minWidth: 250,
|
||||||
!isEmpty(info.getValue()) ? (
|
cell: info =>
|
||||||
<ComicInfoXML data={info.getValue()} />
|
!isEmpty(info.getValue()) ? (
|
||||||
) : (
|
<ComicInfoXML data={info.getValue()} />
|
||||||
<span className="tag mt-5">No ComicInfo.xml</span>
|
) : (
|
||||||
),
|
<span className="tag mt-5">No ComicInfo.xml</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Additional Metadata",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
header: "Publisher",
|
||||||
|
accessorKey:
|
||||||
|
"_source.sourcedMetadata.comicvine.volumeInformation",
|
||||||
|
cell: info => {
|
||||||
|
return (
|
||||||
|
!isNil(info.getValue()) && (
|
||||||
|
<h6 className="is-size-7 has-text-weight-bold">
|
||||||
|
{info.getValue().publisher.name}
|
||||||
|
</h6>
|
||||||
|
)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
},
|
{
|
||||||
{
|
header: "Something",
|
||||||
header: "Additional Metadata",
|
accessorKey: "_source.acquisition.source.wanted",
|
||||||
columns: [
|
cell: info => {
|
||||||
{
|
!isUndefined(info.getValue()) ?
|
||||||
header: "Publisher",
|
<WantedStatus value={info.getValue().toString()} /> : "Nothing";
|
||||||
accessorKey: "_source.sourcedMetadata.comicvine.volumeInformation",
|
|
||||||
cell: (info) => {
|
|
||||||
return (
|
|
||||||
!isNil(info.getValue()) && (
|
|
||||||
<h6 className="is-size-7 has-text-weight-bold">
|
|
||||||
{info.getValue().publisher.name}
|
|
||||||
</h6>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
header: "Something",
|
],
|
||||||
accessorKey: "_source.acquisition.source.wanted",
|
}
|
||||||
cell: (info) => {
|
], []);
|
||||||
!isUndefined(info.getValue()) ? (
|
|
||||||
<WantedStatus value={info.getValue().toString()} />
|
|
||||||
) : (
|
|
||||||
"Nothing"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pagination control that fetches the next x (pageSize) items
|
* Pagination control that fetches the next x (pageSize) items
|
||||||
@@ -177,6 +173,7 @@ export const Library = (): ReactElement => {
|
|||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pagination control that fetches the previous x (pageSize) items
|
* Pagination control that fetches the previous x (pageSize) items
|
||||||
* based on the y (pageIndex) offset from the ThreeTwo Elasticsearch index
|
* based on the y (pageIndex) offset from the ThreeTwo Elasticsearch index
|
||||||
@@ -202,7 +199,7 @@ export const Library = (): ReactElement => {
|
|||||||
from,
|
from,
|
||||||
},
|
},
|
||||||
type: "all",
|
type: "all",
|
||||||
trigger: "libraryPage",
|
trigger: "libraryPage"
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -211,13 +208,14 @@ export const Library = (): ReactElement => {
|
|||||||
// ImportStatus.propTypes = {
|
// ImportStatus.propTypes = {
|
||||||
// value: PropTypes.bool.isRequired,
|
// value: PropTypes.bool.isRequired,
|
||||||
// };
|
// };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="container">
|
<section className="container">
|
||||||
<div className="section">
|
<div className="section">
|
||||||
<div className="header-area">
|
<div className="header-area">
|
||||||
<h1 className="title">Library</h1>
|
<h1 className="title">Library</h1>
|
||||||
</div>
|
</div>
|
||||||
{!isEmpty(searchResults) ? (
|
{!isUndefined(searchResults.hits) && (
|
||||||
<div>
|
<div>
|
||||||
<div className="library">
|
<div className="library">
|
||||||
<T2Table
|
<T2Table
|
||||||
@@ -232,26 +230,6 @@ export const Library = (): ReactElement => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<div className="columns">
|
|
||||||
<div className="column is-two-thirds">
|
|
||||||
<article className="message is-link">
|
|
||||||
<div className="message-body">
|
|
||||||
No comics were found in the library, Elasticsearch reports no
|
|
||||||
indices. Try importing a few comics into the library and come
|
|
||||||
back.
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
<pre>
|
|
||||||
{!isUndefined(searchError.data) &&
|
|
||||||
JSON.stringify(
|
|
||||||
searchError.data.meta.body.error.root_cause,
|
|
||||||
null,
|
|
||||||
4,
|
|
||||||
)}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,25 +1,15 @@
|
|||||||
import React, { useContext } from "react";
|
import React from "react";
|
||||||
import { SearchBar } from "./GlobalSearchBar/SearchBar";
|
import { SearchBar } from "./GlobalSearchBar/SearchBar";
|
||||||
import { DownloadProgressTick } from "./ComicDetail/DownloadProgressTick";
|
import { DownloadProgressTick } from "./ComicDetail/DownloadProgressTick";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { isUndefined } from "lodash";
|
import { isUndefined } from "lodash";
|
||||||
import { format, fromUnixTime } from "date-fns";
|
|
||||||
|
|
||||||
const Navbar: React.FunctionComponent = (props) => {
|
const Navbar: React.FunctionComponent = (props) => {
|
||||||
const downloadProgressTick = useSelector(
|
const downloadProgressTick = useSelector(
|
||||||
(state: RootState) => state.airdcpp.downloadProgressData,
|
(state: RootState) => state.airdcpp.downloadProgressData,
|
||||||
);
|
);
|
||||||
|
|
||||||
const airDCPPSocketConnectionStatus = useSelector(
|
|
||||||
(state: RootState) => state.airdcpp.isAirDCPPSocketConnected,
|
|
||||||
);
|
|
||||||
const airDCPPSessionInfo = useSelector(
|
|
||||||
(state: RootState) => state.airdcpp.airDCPPSessionInfo,
|
|
||||||
);
|
|
||||||
const socketDisconnectionReason = useSelector(
|
|
||||||
(state: RootState) => state.airdcpp.socketDisconnectionReason,
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<nav className="navbar is-fixed-top">
|
<nav className="navbar is-fixed-top">
|
||||||
<div className="navbar-brand">
|
<div className="navbar-brand">
|
||||||
@@ -82,66 +72,18 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
<div className="navbar-item has-dropdown is-hoverable">
|
<div className="navbar-item has-dropdown is-hoverable">
|
||||||
<a className="navbar-link is-arrowless">
|
<a className="navbar-link is-arrowless">
|
||||||
<i className="fa-solid fa-download"></i>
|
<i className="fa-solid fa-download"></i>
|
||||||
{downloadProgressTick && <div className="pulsating-circle"></div>}
|
{downloadProgressTick && (
|
||||||
|
<div className="pulsating-circle"></div>
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
{!isUndefined(downloadProgressTick) ? (
|
{!isUndefined(downloadProgressTick) ? (
|
||||||
<div className="navbar-dropdown is-right">
|
<div className="navbar-dropdown download-progress-meter">
|
||||||
<a className="navbar-item">
|
<a className="navbar-item">
|
||||||
<DownloadProgressTick data={downloadProgressTick} />
|
<DownloadProgressTick data={downloadProgressTick} />
|
||||||
</a> </div>
|
</a>
|
||||||
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{/* AirDC++ socket connection status */}
|
|
||||||
<div className="navbar-item has-dropdown is-hoverable">
|
|
||||||
{airDCPPSocketConnectionStatus ? (
|
|
||||||
<>
|
|
||||||
<a className="navbar-link is-arrowless has-text-success">
|
|
||||||
<i className="fa-solid fa-bolt"></i>
|
|
||||||
</a>
|
|
||||||
<div className="navbar-dropdown pt-4 pr-2 pl-2 is-right airdcpp-status">
|
|
||||||
{/* AirDC++ Session Information */}
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Last login was{" "}
|
|
||||||
<span className="tag">
|
|
||||||
{format(
|
|
||||||
fromUnixTime(airDCPPSessionInfo.user.last_login),
|
|
||||||
"dd MMMM, yyyy",
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<hr className="navbar-divider" />
|
|
||||||
<p>
|
|
||||||
<span className="tag has-text-success">
|
|
||||||
{airDCPPSessionInfo.user.username}
|
|
||||||
</span>
|
|
||||||
connected to{" "}
|
|
||||||
<span className="tag has-text-success">
|
|
||||||
{airDCPPSessionInfo.system_info.client_version}
|
|
||||||
</span>{" "}
|
|
||||||
with session ID{" "}
|
|
||||||
<span className="tag has-text-success">
|
|
||||||
{airDCPPSessionInfo.session_id}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* <pre>{JSON.stringify(airDCPPSessionInfo, null, 2)}</pre> */}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<a className="navbar-link is-arrowless has-text-danger">
|
|
||||||
<i className="fa-solid fa-bolt"></i>
|
|
||||||
</a>
|
|
||||||
<div className="navbar-dropdown pr-2 pl-2 is-right">
|
|
||||||
<pre>
|
|
||||||
{JSON.stringify(socketDisconnectionReason, null, 2)}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="navbar-item has-dropdown is-hoverable is-mega">
|
<div className="navbar-item has-dropdown is-hoverable is-mega">
|
||||||
<div className="navbar-link flex">Blog</div>
|
<div className="navbar-link flex">Blog</div>
|
||||||
<div id="blogDropdown" className="navbar-dropdown">
|
<div id="blogDropdown" className="navbar-dropdown">
|
||||||
|
|||||||
@@ -81,8 +81,6 @@ export const IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_IN_PROGRESS =
|
|||||||
export const IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_FAILED =
|
export const IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_FAILED =
|
||||||
"IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_FAILED";
|
"IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_CALL_FAILED";
|
||||||
|
|
||||||
export const COMICBOOK_EXTRACTION_SUCCESS = "COMICBOOK_EXTRACTION_SUCCESS";
|
|
||||||
|
|
||||||
// Image file stats
|
// Image file stats
|
||||||
export const IMG_ANALYSIS_CALL_IN_PROGRESS = "IMG_ANALYSIS_CALL_IN_PROGRESS";
|
export const IMG_ANALYSIS_CALL_IN_PROGRESS = "IMG_ANALYSIS_CALL_IN_PROGRESS";
|
||||||
export const IMG_ANALYSIS_DATA_FETCH_SUCCESS =
|
export const IMG_ANALYSIS_DATA_FETCH_SUCCESS =
|
||||||
@@ -115,8 +113,6 @@ export const AIRDCPP_FILE_DOWNLOAD_COMPLETED =
|
|||||||
export const LS_SINGLE_IMPORT = "LS_SINGLE_IMPORT";
|
export const LS_SINGLE_IMPORT = "LS_SINGLE_IMPORT";
|
||||||
export const AIRDCPP_BUNDLES_FETCHED = "AIRDCPP_BUNDLES_FETCHED";
|
export const AIRDCPP_BUNDLES_FETCHED = "AIRDCPP_BUNDLES_FETCHED";
|
||||||
export const AIRDCPP_DOWNLOAD_PROGRESS_TICK = "AIRDCPP_DOWNLOAD_PROGRESS_TICK";
|
export const AIRDCPP_DOWNLOAD_PROGRESS_TICK = "AIRDCPP_DOWNLOAD_PROGRESS_TICK";
|
||||||
export const AIRDCPP_SOCKET_CONNECTED = "AIRDCPP_SOCKET_CONNECTED";
|
|
||||||
export const AIRDCPP_SOCKET_DISCONNECTED = "AIRDCPP_SOCKET_DISCONNECTED";
|
|
||||||
|
|
||||||
// Transfers
|
// Transfers
|
||||||
export const AIRDCPP_TRANSFERS_FETCHED = "AIRDCPP_TRANSFERS_FETCHED";
|
export const AIRDCPP_TRANSFERS_FETCHED = "AIRDCPP_TRANSFERS_FETCHED";
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { isEmpty, isUndefined } from "lodash";
|
import { isEmpty, isUndefined } from "lodash";
|
||||||
import React, { createContext, useEffect, useState } from "react";
|
import React, { createContext, useEffect, useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { toggleAirDCPPSocketConnectionStatus } from "../actions/airdcpp.actions";
|
|
||||||
import { getSettings } from "../actions/settings.actions";
|
import { getSettings } from "../actions/settings.actions";
|
||||||
|
|
||||||
import AirDCPPSocket from "../services/DcppSearchService";
|
import AirDCPPSocket from "../services/DcppSearchService";
|
||||||
|
|
||||||
const AirDCPPSocketContextProvider = ({ children }) => {
|
const AirDCPPSocketContextProvider = ({ children }) => {
|
||||||
@@ -14,7 +12,7 @@ const AirDCPPSocketContextProvider = ({ children }) => {
|
|||||||
airDCPPState: {
|
airDCPPState: {
|
||||||
settings: settingsObject,
|
settings: settingsObject,
|
||||||
socket: {},
|
socket: {},
|
||||||
socketConectionInformation: {},
|
socketConnectionInformation: {},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -53,35 +51,16 @@ const AirDCPPSocketContextProvider = ({ children }) => {
|
|||||||
client: { host },
|
client: { host },
|
||||||
},
|
},
|
||||||
} = configuration;
|
} = configuration;
|
||||||
|
|
||||||
const initializedAirDCPPSocket = new AirDCPPSocket({
|
const initializedAirDCPPSocket = new AirDCPPSocket({
|
||||||
protocol: `${host.protocol}`,
|
protocol: `${host.protocol}`,
|
||||||
hostname: `${host.hostname}:${host.port}`,
|
hostname: `${host.hostname}:${host.port}`,
|
||||||
username: `${host.username}`,
|
|
||||||
password: `${host.password}`,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// connect and disconnect handlers
|
const socketConnectionInformation = await initializedAirDCPPSocket.connect(
|
||||||
initializedAirDCPPSocket.onConnected = (sessionInfo) => {
|
`${host.username}`,
|
||||||
dispatch(toggleAirDCPPSocketConnectionStatus("connected", sessionInfo));
|
`${host.password}`,
|
||||||
};
|
true,
|
||||||
initializedAirDCPPSocket.onDisconnected = async (
|
);
|
||||||
reason,
|
|
||||||
code,
|
|
||||||
wasClean,
|
|
||||||
) => {
|
|
||||||
dispatch(
|
|
||||||
toggleAirDCPPSocketConnectionStatus("disconnected", {
|
|
||||||
reason,
|
|
||||||
code,
|
|
||||||
wasClean,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const socketConnectionInformation = await initializedAirDCPPSocket.connect();
|
|
||||||
|
|
||||||
// update the state with the new socket connection information
|
|
||||||
persistSettings({
|
persistSettings({
|
||||||
...airDCPPState,
|
...airDCPPState,
|
||||||
airDCPPState: {
|
airDCPPState: {
|
||||||
@@ -101,7 +80,7 @@ const AirDCPPSocketContextProvider = ({ children }) => {
|
|||||||
};
|
};
|
||||||
const AirDCPPSocketContext = createContext({
|
const AirDCPPSocketContext = createContext({
|
||||||
airDCPPState: {},
|
airDCPPState: {},
|
||||||
saveSettings: () => { },
|
saveSettings: () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export { AirDCPPSocketContext, AirDCPPSocketContextProvider };
|
export { AirDCPPSocketContext, AirDCPPSocketContextProvider };
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import {
|
|||||||
AIRDCPP_BUNDLES_FETCHED,
|
AIRDCPP_BUNDLES_FETCHED,
|
||||||
AIRDCPP_TRANSFERS_FETCHED,
|
AIRDCPP_TRANSFERS_FETCHED,
|
||||||
LIBRARY_ISSUE_BUNDLES,
|
LIBRARY_ISSUE_BUNDLES,
|
||||||
AIRDCPP_SOCKET_CONNECTED,
|
|
||||||
AIRDCPP_SOCKET_DISCONNECTED,
|
|
||||||
} from "../constants/action-types";
|
} from "../constants/action-types";
|
||||||
import { LOCATION_CHANGE } from "redux-first-history";
|
import { LOCATION_CHANGE } from "redux-first-history";
|
||||||
import { isNil, isUndefined } from "lodash";
|
import { isNil, isUndefined } from "lodash";
|
||||||
@@ -26,9 +24,6 @@ const initialState = {
|
|||||||
downloadFileStatus: {},
|
downloadFileStatus: {},
|
||||||
bundles: [],
|
bundles: [],
|
||||||
transfers: [],
|
transfers: [],
|
||||||
isAirDCPPSocketConnected: false,
|
|
||||||
airDCPPSessionInfo: {},
|
|
||||||
socketDisconnectionReason: {},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function airdcppReducer(state = initialState, action) {
|
function airdcppReducer(state = initialState, action) {
|
||||||
@@ -100,23 +95,8 @@ function airdcppReducer(state = initialState, action) {
|
|||||||
...state,
|
...state,
|
||||||
transfers: action.bundles,
|
transfers: action.bundles,
|
||||||
};
|
};
|
||||||
|
|
||||||
case AIRDCPP_SOCKET_CONNECTED:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
isAirDCPPSocketConnected: true,
|
|
||||||
airDCPPSessionInfo: action.data,
|
|
||||||
};
|
|
||||||
|
|
||||||
case AIRDCPP_SOCKET_DISCONNECTED:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
isAirDCPPSocketConnected: false,
|
|
||||||
socketDisconnectionReason: action.data,
|
|
||||||
};
|
|
||||||
case LOCATION_CHANGE:
|
case LOCATION_CHANGE:
|
||||||
return {
|
return {
|
||||||
...state,
|
|
||||||
searchResults: [],
|
searchResults: [],
|
||||||
isAirDCPPSearchInProgress: false,
|
isAirDCPPSearchInProgress: false,
|
||||||
searchInfo: null,
|
searchInfo: null,
|
||||||
@@ -125,6 +105,7 @@ function airdcppReducer(state = initialState, action) {
|
|||||||
bundleDBImportResult: null,
|
bundleDBImportResult: null,
|
||||||
// bundles: [],
|
// bundles: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,7 @@ import {
|
|||||||
SS_SEARCH_FAILED,
|
SS_SEARCH_FAILED,
|
||||||
SS_SEARCH_RESULTS_FETCHED_SPECIAL,
|
SS_SEARCH_RESULTS_FETCHED_SPECIAL,
|
||||||
VOLUMES_FETCHED,
|
VOLUMES_FETCHED,
|
||||||
COMICBOOK_EXTRACTION_SUCCESS,
|
|
||||||
} from "../constants/action-types";
|
} from "../constants/action-types";
|
||||||
import { removeLeadingPeriod } from "../shared/utils/formatting.utils";
|
|
||||||
import { LIBRARY_SERVICE_HOST } from "../constants/endpoints";
|
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
IMSCallInProgress: false,
|
IMSCallInProgress: false,
|
||||||
IMGCallInProgress: false,
|
IMGCallInProgress: false,
|
||||||
@@ -46,10 +42,7 @@ const initialState = {
|
|||||||
isComicVineMetadataImportInProgress: false,
|
isComicVineMetadataImportInProgress: false,
|
||||||
comicVineMetadataImportError: {},
|
comicVineMetadataImportError: {},
|
||||||
rawImportError: {},
|
rawImportError: {},
|
||||||
extractedComicBookArchive: {
|
extractedComicBookArchive: [],
|
||||||
reading: [],
|
|
||||||
analysis: [],
|
|
||||||
},
|
|
||||||
recentComics: [],
|
recentComics: [],
|
||||||
wantedComics: [],
|
wantedComics: [],
|
||||||
libraryComics: [],
|
libraryComics: [],
|
||||||
@@ -88,7 +81,7 @@ function fileOpsReducer(state = initialState, action) {
|
|||||||
case IMS_RECENT_COMICS_FETCHED:
|
case IMS_RECENT_COMICS_FETCHED:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
recentComics: action.data.docs,
|
recentComics: action.data,
|
||||||
};
|
};
|
||||||
case IMS_WANTED_COMICS_FETCHED:
|
case IMS_WANTED_COMICS_FETCHED:
|
||||||
return {
|
return {
|
||||||
@@ -138,7 +131,13 @@ function fileOpsReducer(state = initialState, action) {
|
|||||||
comicBookExtractionInProgress: true,
|
comicBookExtractionInProgress: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case IMS_COMIC_BOOK_ARCHIVE_EXTRACTION_SUCCESS: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
extractedComicBookArchive: action.extractedComicBookArchive,
|
||||||
|
comicBookExtractionInProgress: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
case LOCATION_CHANGE: {
|
case LOCATION_CHANGE: {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@@ -153,44 +152,11 @@ function fileOpsReducer(state = initialState, action) {
|
|||||||
}
|
}
|
||||||
case LS_COVER_EXTRACTED: {
|
case LS_COVER_EXTRACTED: {
|
||||||
console.log("BASH", action);
|
console.log("BASH", action);
|
||||||
if(state.recentComics.length === 5) {
|
|
||||||
state.recentComics.pop();
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
librarySearchResultCount: state.librarySearchResultCount + 1,
|
librarySearchResultCount: state.librarySearchResultCount + 1,
|
||||||
recentComics: [...state.recentComics, action.result.data.importResult]
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case COMICBOOK_EXTRACTION_SUCCESS: {
|
|
||||||
const comicBookPages: string[] = [];
|
|
||||||
map(action.result.files, (page) => {
|
|
||||||
const pageFilePath = removeLeadingPeriod(page);
|
|
||||||
const imagePath = encodeURI(`${LIBRARY_SERVICE_HOST}${pageFilePath}`);
|
|
||||||
comicBookPages.push(imagePath);
|
|
||||||
});
|
|
||||||
|
|
||||||
switch (action.result.purpose) {
|
|
||||||
case "reading":
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
extractedComicBookArchive: {
|
|
||||||
reading: comicBookPages,
|
|
||||||
},
|
|
||||||
comicBookExtractionInProgress: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
case "analysis":
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
extractedComicBookArchive: {
|
|
||||||
analysis: comicBookPages,
|
|
||||||
},
|
|
||||||
comicBookExtractionInProgress: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case LS_QUEUE_DRAINED: {
|
case LS_QUEUE_DRAINED: {
|
||||||
console.log("drained", action);
|
console.log("drained", action);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class AirDCPPSocket {
|
|||||||
}
|
}
|
||||||
const options = {
|
const options = {
|
||||||
url: `${socketProtocol}://${configuration.hostname}/api/v1/`,
|
url: `${socketProtocol}://${configuration.hostname}/api/v1/`,
|
||||||
autoReconnect: true,
|
autoReconnect: false,
|
||||||
reconnectInterval: 5,
|
reconnectInterval: 5,
|
||||||
logLevel: "verbose",
|
logLevel: "verbose",
|
||||||
ignoredListenerEvents: [
|
ignoredListenerEvents: [
|
||||||
@@ -18,8 +18,6 @@ class AirDCPPSocket {
|
|||||||
"hash_statistics",
|
"hash_statistics",
|
||||||
"hub_counts_updated",
|
"hub_counts_updated",
|
||||||
],
|
],
|
||||||
username: `${configuration.username}`,
|
|
||||||
password: `${configuration.password}`,
|
|
||||||
};
|
};
|
||||||
const AirDCPPSocketInstance = Socket(options, window.WebSocket as any);
|
const AirDCPPSocketInstance = Socket(options, window.WebSocket as any);
|
||||||
return AirDCPPSocketInstance;
|
return AirDCPPSocketInstance;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ function sleep(ms: number): Promise<NodeJS.Timeout> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const search = async (data: SearchData) => {
|
export const search = async (data: SearchData) => {
|
||||||
await SocketService.connect();
|
await SocketService.connect("admin", "password");
|
||||||
const instance: SearchInstance = await SocketService.post("search");
|
const instance: SearchInstance = await SocketService.post("search");
|
||||||
const unsubscribe = await SocketService.addListener(
|
const unsubscribe = await SocketService.addListener(
|
||||||
"search",
|
"search",
|
||||||
|
|||||||
@@ -67,10 +67,7 @@ export const determineCoverFile = (data) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const determineExternalMetadata = (
|
export const determineExternalMetadata = (metadataSource, source) => {
|
||||||
metadataSource: string,
|
|
||||||
source: any
|
|
||||||
) => {
|
|
||||||
switch (metadataSource) {
|
switch (metadataSource) {
|
||||||
case "comicvine":
|
case "comicvine":
|
||||||
return {
|
return {
|
||||||
|
|||||||
135
yarn.lock
135
yarn.lock
@@ -1283,7 +1283,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.0.0"
|
tslib "^2.0.0"
|
||||||
|
|
||||||
"@emotion/babel-plugin@^11.7.1":
|
"@emotion/babel-plugin@^11.3.0", "@emotion/babel-plugin@^11.7.1":
|
||||||
version "11.9.2"
|
version "11.9.2"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz#723b6d394c89fb2ef782229d92ba95a740576e95"
|
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz#723b6d394c89fb2ef782229d92ba95a740576e95"
|
||||||
integrity sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==
|
integrity sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==
|
||||||
@@ -1317,45 +1317,28 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||||
|
|
||||||
"@emotion/hash@^0.9.0":
|
"@emotion/is-prop-valid@^1.1.0", "@emotion/is-prop-valid@^1.1.1":
|
||||||
version "0.9.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7"
|
|
||||||
integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==
|
|
||||||
|
|
||||||
"@emotion/is-prop-valid@^1.1.0":
|
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.3.tgz#f0907a416368cf8df9e410117068e20fe87c0a3a"
|
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.3.tgz#f0907a416368cf8df9e410117068e20fe87c0a3a"
|
||||||
integrity sha512-RFg04p6C+1uO19uG8N+vqanzKqiM9eeV1LDOG3bmkYmuOj7NbKNlFC/4EZq5gnwAIlcC/jOT24f8Td0iax2SXA==
|
integrity sha512-RFg04p6C+1uO19uG8N+vqanzKqiM9eeV1LDOG3bmkYmuOj7NbKNlFC/4EZq5gnwAIlcC/jOT24f8Td0iax2SXA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@emotion/memoize" "^0.7.4"
|
"@emotion/memoize" "^0.7.4"
|
||||||
|
|
||||||
"@emotion/is-prop-valid@^1.1.2":
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83"
|
|
||||||
integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==
|
|
||||||
dependencies:
|
|
||||||
"@emotion/memoize" "^0.8.0"
|
|
||||||
|
|
||||||
"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5":
|
"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5":
|
||||||
version "0.7.5"
|
version "0.7.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
|
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
|
||||||
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
|
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
|
||||||
|
|
||||||
"@emotion/memoize@^0.8.0":
|
"@emotion/react@11.7.1":
|
||||||
version "0.8.0"
|
version "11.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
|
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.7.1.tgz#3f800ce9b20317c13e77b8489ac4a0b922b2fe07"
|
||||||
integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
|
integrity sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw==
|
||||||
|
|
||||||
"@emotion/react@11.9.0":
|
|
||||||
version "11.9.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.9.0.tgz#b6d42b1db3bd7511e7a7c4151dc8bc82e14593b8"
|
|
||||||
integrity sha512-lBVSF5d0ceKtfKCDQJveNAtkC7ayxpVlgOohLgXqRwqWr9bOf4TZAFFyIcNngnV6xK6X4x2ZeXq7vliHkoVkxQ==
|
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@emotion/babel-plugin" "^11.7.1"
|
|
||||||
"@emotion/cache" "^11.7.1"
|
"@emotion/cache" "^11.7.1"
|
||||||
"@emotion/serialize" "^1.0.3"
|
"@emotion/serialize" "^1.0.2"
|
||||||
"@emotion/utils" "^1.1.0"
|
"@emotion/sheet" "^1.1.0"
|
||||||
|
"@emotion/utils" "^1.0.0"
|
||||||
"@emotion/weak-memoize" "^0.2.5"
|
"@emotion/weak-memoize" "^0.2.5"
|
||||||
hoist-non-react-statics "^3.3.1"
|
hoist-non-react-statics "^3.3.1"
|
||||||
|
|
||||||
@@ -1383,32 +1366,21 @@
|
|||||||
"@emotion/utils" "^1.0.0"
|
"@emotion/utils" "^1.0.0"
|
||||||
csstype "^3.0.2"
|
csstype "^3.0.2"
|
||||||
|
|
||||||
"@emotion/serialize@^1.0.3":
|
"@emotion/sheet@^1.1.0", "@emotion/sheet@^1.1.1":
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0"
|
|
||||||
integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==
|
|
||||||
dependencies:
|
|
||||||
"@emotion/hash" "^0.9.0"
|
|
||||||
"@emotion/memoize" "^0.8.0"
|
|
||||||
"@emotion/unitless" "^0.8.0"
|
|
||||||
"@emotion/utils" "^1.2.0"
|
|
||||||
csstype "^3.0.2"
|
|
||||||
|
|
||||||
"@emotion/sheet@^1.1.1":
|
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.1.tgz#015756e2a9a3c7c5f11d8ec22966a8dbfbfac787"
|
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.1.tgz#015756e2a9a3c7c5f11d8ec22966a8dbfbfac787"
|
||||||
integrity sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA==
|
integrity sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA==
|
||||||
|
|
||||||
"@emotion/styled@11.8.1":
|
"@emotion/styled@11.6.0":
|
||||||
version "11.8.1"
|
version "11.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.8.1.tgz#856f6f63aceef0eb783985fa2322e2bf66d04e17"
|
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.6.0.tgz#9230d1a7bcb2ebf83c6a579f4c80e0664132d81d"
|
||||||
integrity sha512-OghEVAYBZMpEquHZwuelXcRjRJQOVayvbmNR0zr174NHdmMgrNkLC6TljKC5h9lZLkN5WGrdUcrKlOJ4phhoTQ==
|
integrity sha512-mxVtVyIOTmCAkFbwIp+nCjTXJNgcz4VWkOYQro87jE2QBTydnkiYusMrRGFtzuruiGK4dDaNORk4gH049iiQuw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@emotion/babel-plugin" "^11.7.1"
|
"@emotion/babel-plugin" "^11.3.0"
|
||||||
"@emotion/is-prop-valid" "^1.1.2"
|
"@emotion/is-prop-valid" "^1.1.1"
|
||||||
"@emotion/serialize" "^1.0.2"
|
"@emotion/serialize" "^1.0.2"
|
||||||
"@emotion/utils" "^1.1.0"
|
"@emotion/utils" "^1.0.0"
|
||||||
|
|
||||||
"@emotion/stylis@^0.8.4":
|
"@emotion/stylis@^0.8.4":
|
||||||
version "0.8.5"
|
version "0.8.5"
|
||||||
@@ -1420,21 +1392,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||||
|
|
||||||
"@emotion/unitless@^0.8.0":
|
|
||||||
version "0.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db"
|
|
||||||
integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==
|
|
||||||
|
|
||||||
"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0":
|
"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf"
|
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf"
|
||||||
integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==
|
integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==
|
||||||
|
|
||||||
"@emotion/utils@^1.2.0":
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561"
|
|
||||||
integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==
|
|
||||||
|
|
||||||
"@emotion/weak-memoize@^0.2.5":
|
"@emotion/weak-memoize@^0.2.5":
|
||||||
version "0.2.5"
|
version "0.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
|
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
|
||||||
@@ -6686,6 +6648,13 @@ character-reference-invalid@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560"
|
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560"
|
||||||
integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==
|
integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==
|
||||||
|
|
||||||
|
chevrotain@7.0.3:
|
||||||
|
version "7.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-7.0.3.tgz#f9621971a726eba804f7763edace2183d157c5d7"
|
||||||
|
integrity sha512-G634q7M5EiqNNv+0MKcQES2jmqabbi4PvUDpzjG2t+i1XQFaMCz0o8BZ8lbQbZex4RqkzJ3pOy+UwNLFlQm4eg==
|
||||||
|
dependencies:
|
||||||
|
regexp-to-ast "0.5.0"
|
||||||
|
|
||||||
chokidar@^2.1.8:
|
chokidar@^2.1.8:
|
||||||
version "2.1.8"
|
version "2.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
|
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
|
||||||
@@ -7113,7 +7082,14 @@ compromise-sentences@^0.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/compromise-sentences/-/compromise-sentences-0.3.0.tgz#61d34039323155bc20dad10f24340daaabf86e26"
|
resolved "https://registry.yarnpkg.com/compromise-sentences/-/compromise-sentences-0.3.0.tgz#61d34039323155bc20dad10f24340daaabf86e26"
|
||||||
integrity sha512-L6d5PXmmyPyWRMoJURYOM0yILhtV37zCOy9ZW8Xd6KgY+2qQBTwuokekaGL9MDpSH3/grRDL+AHKytYpGrTEmA==
|
integrity sha512-L6d5PXmmyPyWRMoJURYOM0yILhtV37zCOy9ZW8Xd6KgY+2qQBTwuokekaGL9MDpSH3/grRDL+AHKytYpGrTEmA==
|
||||||
|
|
||||||
compromise@^13.11.4:
|
compromise-strict@^0.0.2:
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/compromise-strict/-/compromise-strict-0.0.2.tgz#e4bf4cc386e8795c6408d3606ebb2cd31cab9fbd"
|
||||||
|
integrity sha512-1ApkPa6kjmyS1ZFhDRZgttDcnVv+Ci8U0kIIsxRBLCN0vautyPm6FROvBwoLimlU3pgIH3hMIpdNdVfe2yj3Gw==
|
||||||
|
dependencies:
|
||||||
|
chevrotain "7.0.3"
|
||||||
|
|
||||||
|
compromise@^13.11.3, compromise@^13.11.4:
|
||||||
version "13.11.4"
|
version "13.11.4"
|
||||||
resolved "https://registry.yarnpkg.com/compromise/-/compromise-13.11.4.tgz#3136e6d2c2cca822ba7cebd140c9f27f405b67f1"
|
resolved "https://registry.yarnpkg.com/compromise/-/compromise-13.11.4.tgz#3136e6d2c2cca822ba7cebd140c9f27f405b67f1"
|
||||||
integrity sha512-nBITcNdqIHSVDDluaG6guyFFCSNXN+Hu87fU8VlhkE5Z0PwTZN1nro2O7a8JcUH88nB5EOzrxd9zKfXLSNFqcg==
|
integrity sha512-nBITcNdqIHSVDDluaG6guyFFCSNXN+Hu87fU8VlhkE5Z0PwTZN1nro2O7a8JcUH88nB5EOzrxd9zKfXLSNFqcg==
|
||||||
@@ -7666,9 +7642,9 @@ decimal.js@^10.2.1:
|
|||||||
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
|
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
|
||||||
|
|
||||||
decode-uri-component@^0.2.0:
|
decode-uri-component@^0.2.0:
|
||||||
version "0.2.2"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
|
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||||
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
|
integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==
|
||||||
|
|
||||||
decompress-response@^3.2.0, decompress-response@^3.3.0:
|
decompress-response@^3.2.0, decompress-response@^3.3.0:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
@@ -11993,9 +11969,9 @@ json2mq@^0.2.0:
|
|||||||
string-convert "^0.2.0"
|
string-convert "^0.2.0"
|
||||||
|
|
||||||
json5@^1.0.1:
|
json5@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
|
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
|
||||||
integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
|
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
|
||||||
dependencies:
|
dependencies:
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
|
|
||||||
@@ -12959,9 +12935,9 @@ minimist-options@4.1.0:
|
|||||||
kind-of "^6.0.3"
|
kind-of "^6.0.3"
|
||||||
|
|
||||||
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
|
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
|
||||||
version "1.2.7"
|
version "1.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||||
integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
|
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||||
|
|
||||||
minipass-collect@^1.0.2:
|
minipass-collect@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
@@ -15305,20 +15281,20 @@ react-collapsible@^2.9.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-collapsible/-/react-collapsible-2.10.0.tgz#57330f9f4f968a41ece49c651b56cf30f9a06d19"
|
resolved "https://registry.yarnpkg.com/react-collapsible/-/react-collapsible-2.10.0.tgz#57330f9f4f968a41ece49c651b56cf30f9a06d19"
|
||||||
integrity sha512-kEVsmlFfXBMTCnU5gwIv19MdmPAhbIPzz5Er37TiJSzRKS0IHrqAKQyQeHEmtoGIQMTcVI46FzE4z3NlVTx77A==
|
integrity sha512-kEVsmlFfXBMTCnU5gwIv19MdmPAhbIPzz5Er37TiJSzRKS0IHrqAKQyQeHEmtoGIQMTcVI46FzE4z3NlVTx77A==
|
||||||
|
|
||||||
react-comic-viewer@^0.4.0:
|
react-comic-viewer@^0.3.5:
|
||||||
version "0.4.0"
|
version "0.3.5"
|
||||||
resolved "https://registry.yarnpkg.com/react-comic-viewer/-/react-comic-viewer-0.4.0.tgz#81e170c4d3924f3312171e3fc7d5d4485466c301"
|
resolved "https://registry.yarnpkg.com/react-comic-viewer/-/react-comic-viewer-0.3.5.tgz#ab5f9ba74a4aa2e748c29d11b43e40d2a042d9ba"
|
||||||
integrity sha512-tdse0Vn6cJzEbFUZMlEBcY1LrH+LfCKodJInl5Y5lyIZyKARoejLrQNlJPnarvNcPW0qm6yQkYioaI56pq0U1w==
|
integrity sha512-xMjvu/JVJ821dYWOuOiZlEEMpgdmUeUtznoRjBlMaFi6WJI52V55/6E+ICg8VqROwiMwmWjp65rGhF1P8hlRLg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@emotion/react" "11.9.0"
|
"@emotion/react" "11.7.1"
|
||||||
"@emotion/styled" "11.8.1"
|
"@emotion/styled" "11.6.0"
|
||||||
"@react-hook/window-size" "^3.0.7"
|
"@react-hook/window-size" "^3.0.7"
|
||||||
"@rooks/use-did-update" "^4.10.0"
|
"@rooks/use-did-update" "^4.10.0"
|
||||||
"@rooks/use-outside-click-ref" "4.11.2"
|
"@rooks/use-outside-click-ref" "4.11.2"
|
||||||
nanoid "^3.1.25"
|
nanoid "^3.1.25"
|
||||||
react-full-screen "1.1.0"
|
react-full-screen "1.1.0"
|
||||||
react-icons "4.3.1"
|
react-icons "4.3.1"
|
||||||
react-swipeable "6.2.2"
|
react-swipeable "6.2.0"
|
||||||
screenfull "^5.1.0"
|
screenfull "^5.1.0"
|
||||||
|
|
||||||
react-day-picker@^8.0.6:
|
react-day-picker@^8.0.6:
|
||||||
@@ -15558,10 +15534,10 @@ react-stickynode@^4.0.0:
|
|||||||
shallowequal "^1.0.0"
|
shallowequal "^1.0.0"
|
||||||
subscribe-ui-event "^2.0.6"
|
subscribe-ui-event "^2.0.6"
|
||||||
|
|
||||||
react-swipeable@6.2.2:
|
react-swipeable@6.2.0:
|
||||||
version "6.2.2"
|
version "6.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-swipeable/-/react-swipeable-6.2.2.tgz#52ba570f3a7a90db7093094ec476f3d151f727d1"
|
resolved "https://registry.yarnpkg.com/react-swipeable/-/react-swipeable-6.2.0.tgz#057271cb7a6fb4af9d2a3f6d80ccdf33e2f64d47"
|
||||||
integrity sha512-Oz7nSFrssvq2yvy05aNL3F+yBUqSvLsK6x1mu+rQFOpMdQVnt4izKt1vyjvvTb70q6GQOaSpaB6qniROW2MAzQ==
|
integrity sha512-nWQ8dEM8e/uswZLSIkXUsAnQmnX4MTcryOHBQIQYRMJFDpgDBSiVbKsz/BZVCIScF4NtJh16oyxwaNOepR6xSw==
|
||||||
|
|
||||||
react-syntax-highlighter@^15.4.5:
|
react-syntax-highlighter@^15.4.5:
|
||||||
version "15.5.0"
|
version "15.5.0"
|
||||||
@@ -15593,7 +15569,7 @@ react-transition-group@4.4.2, react-transition-group@^4.3.0:
|
|||||||
loose-envify "^1.4.0"
|
loose-envify "^1.4.0"
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
react@^18.2.0:
|
react@^18.1.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
||||||
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
||||||
@@ -15841,6 +15817,11 @@ regex-not@^1.0.0, regex-not@^1.0.2:
|
|||||||
extend-shallow "^3.0.2"
|
extend-shallow "^3.0.2"
|
||||||
safe-regex "^1.1.0"
|
safe-regex "^1.1.0"
|
||||||
|
|
||||||
|
regexp-to-ast@0.5.0:
|
||||||
|
version "0.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz#56c73856bee5e1fef7f73a00f1473452ab712a24"
|
||||||
|
integrity sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==
|
||||||
|
|
||||||
regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3:
|
regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3:
|
||||||
version "1.4.3"
|
version "1.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
|
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
|
||||||
|
|||||||
Reference in New Issue
Block a user