diff --git a/docker-compose.yml b/docker-compose.yml
index 5b4adca..c8f4d1c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,4 +1,4 @@
-version: "3.7"
+version: "3.3"
services:
threetwo:
diff --git a/package.json b/package.json
index 93170e0..ec42243 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,10 @@
"calibre-opds": "^1.0.7",
"chokidar": "^3.5.2",
"comlink-loader": "^2.0.0",
+ "compromise": "^13.11.3",
+ "compromise-dates": "^2.2.1",
+ "compromise-numbers": "^1.4.0",
+ "compromise-sentences": "^0.3.0",
"dayjs": "^1.10.6",
"ellipsize": "^0.1.0",
"event-stream": "^4.0.1",
@@ -44,6 +48,7 @@
"fs-extra": "^9.1.0",
"http-response-stream": "^1.0.7",
"jsdoc": "^3.6.7",
+ "ml-classify-text": "^2.0.0",
"opds-extra": "^3.0.9",
"pretty-bytes": "^5.6.0",
"react": "^17.0.1",
@@ -98,10 +103,7 @@
"bulma": "^0.9.3",
"clean-webpack-plugin": "^1.0.0",
"comlink": "^4.3.0",
- "compromise": "^13.10.5",
- "compromise-dates": "^2.0.1",
- "compromise-numbers": "^1.2.0",
- "compromise-sentences": "^0.2.0",
+ "compromise-strict": "^0.0.2",
"concurrently": "^4.0.0",
"connected-react-router": "^6.9.1",
"css-loader": "^5.1.2",
diff --git a/src/client/assets/scss/App.scss b/src/client/assets/scss/App.scss
index 618fe11..dab2aef 100644
--- a/src/client/assets/scss/App.scss
+++ b/src/client/assets/scss/App.scss
@@ -76,7 +76,13 @@ $border-color: red;
}
}
.card-content {
- padding: 1rem;
+ .card-title {
+ margin-bottom: 0.2rem;
+ }
+ .cv-icon, i {
+ margin: 4px 4px 4px 0;
+ }
+ padding: 0.5rem 1rem;
}
}
.card-container {
diff --git a/src/client/components/AcquisitionPanel.tsx b/src/client/components/AcquisitionPanel.tsx
index dcc71b4..8d7b0fa 100644
--- a/src/client/components/AcquisitionPanel.tsx
+++ b/src/client/components/AcquisitionPanel.tsx
@@ -110,8 +110,8 @@ export const AcquisitionPanel = (
)}
{/* AirDC++ results */}
-
- {!isNil(airDCPPSearchResults) && !isEmpty(airDCPPSearchResults) && (
+
+ {!isNil(airDCPPSearchResults) && !isEmpty(airDCPPSearchResults) ? (
@@ -182,6 +182,17 @@ export const AcquisitionPanel = (
})}
+ ) : (
+
+
+
+ Searching via AirDC++ is still in{" "}
+ alpha. Some searches may take arbitrarily long,
+ or may not work at all. Searches from ADCS hubs are more
+ reliable than NMDCS ones.
+
+
+
)}
>
diff --git a/src/client/components/Carda.tsx b/src/client/components/Carda.tsx
index 5d783cf..ca5b027 100644
--- a/src/client/components/Carda.tsx
+++ b/src/client/components/Carda.tsx
@@ -32,7 +32,9 @@ const renderCard = (props): ReactElement => {
{props.hasDetails && (
- {isNil(props.title) ? "No Name" : props.title}
+
+ {isNil(props.title) ? "No Name" : props.title}
+
{props.children}
)}
diff --git a/src/client/components/ComicDetail.tsx b/src/client/components/ComicDetail.tsx
index d4f2f07..f17b806 100644
--- a/src/client/components/ComicDetail.tsx
+++ b/src/client/components/ComicDetail.tsx
@@ -16,6 +16,7 @@ import { isEmpty, isUndefined, isNil } from "lodash";
import { RootState } from "threetwo-ui-typings";
import { fetchComicVineMatches } from "../actions/fileops.actions";
import { getComicBookDetailById } from "../actions/comicinfo.actions";
+import { detectTradePaperbacks } from "../shared/utils/tradepaperback.utils";
import dayjs from "dayjs";
const prettyBytes = require("pretty-bytes");
@@ -115,11 +116,17 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
- Total issues in this volume:{" "}
+ Total issues in this volume:
{
comicBookDetailData.sourcedMetadata.comicvine
.volumeInformation.count_of_issues
}
+ {JSON.stringify(
+ detectTradePaperbacks(
+ comicBookDetailData.sourcedMetadata.comicvine
+ .volumeInformation.description,
+ ),
+ )}
@@ -274,6 +281,9 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
}),
};
+ // Determine which cover image to use:
+ // 1. from the locally imported, non-CV-scraped version, or
+ // 2. from the CV-scraped version
let imagePath = "";
let comicBookTitle = "";
if (!isNil(comicBookDetailData.rawFileDetails)) {
diff --git a/src/client/components/RecentlyImported.tsx b/src/client/components/RecentlyImported.tsx
index 8e04ca1..df9ce7e 100644
--- a/src/client/components/RecentlyImported.tsx
+++ b/src/client/components/RecentlyImported.tsx
@@ -39,7 +39,16 @@ export const RecentlyImported = ({
imageUrl={imagePath}
hasDetails
title={comicName ? titleElement : null}
- >
+ >
+ {!isNil(sourcedMetadata.comicvine) && (
+
+
+
+
+
+
+ )}
+
);
})}
diff --git a/src/client/shared/utils/tradepaperback.utils.ts b/src/client/shared/utils/tradepaperback.utils.ts
new file mode 100644
index 0000000..5bf742b
--- /dev/null
+++ b/src/client/shared/utils/tradepaperback.utils.ts
@@ -0,0 +1,34 @@
+import Classifier from "ml-classify-text";
+
+export const detectTradePaperbacks = (deck: string): any => {
+ const classifier = new Classifier({ nGramMin: 2, nGramMax: 2 });
+ const positiveTPBIdentifiers = [
+ "trade paperbacks",
+ "TPB",
+ "paperback",
+ "hardcover",
+ "collects the following issues",
+ "collected issues",
+ "collecting the issues",
+ "collecting the following issues",
+ "collected editions",
+ ];
+ const negativeTPBIdentifiers = ["mini-series"];
+
+ classifier.train(positiveTPBIdentifiers, "Possibly a trade paperback");
+ classifier.train(negativeTPBIdentifiers, "Not a trade paperback");
+ if (deck) {
+
+ console.log("DEC", deck);
+ const predictions = classifier.predict(deck);
+
+ if (predictions.length) {
+ predictions.forEach((prediction) => {
+ console.log(`${prediction.label} (${prediction.confidence})`);
+ return prediction;
+ });
+ } else {
+ console.log("No predictions returned.");
+ }
+ }
+};
diff --git a/src/client/shared/utils/trainingData.json b/src/client/shared/utils/trainingData.json
new file mode 100644
index 0000000..0897e1d
--- /dev/null
+++ b/src/client/shared/utils/trainingData.json
@@ -0,0 +1,14 @@
+[
+ {"phrase": "Twelve issue mini-series.", "result": {"not_a_paperback": 1}},
+ {"phrase": "Trade paperback collecting Jean Grey #7-11.", "result": {"paperback": 1}},
+ {"phrase": "Trade paperback collecting Iron Fist #6-7 & 73-77", "result": {"paperback ": 1}},
+ {"phrase": "Collected Editions", "result": {"paperback": 1}},
+ {"phrase": "Six issue mini-series.", "result": {"not_a_paperback": 1}},
+ {"phrase": "Four issue mini-series.", "result": {"not_a_paperback": 1}},
+ {"phrase": "Seventy-two issue digital prequel to the Injustice 2 video game.", "result": {"not_a_paperback": 1}},
+ {"phrase": "Total issues in this volume:50", "result": {"paperback": 1}},
+ {"phrase": "Five issue mini-series.", "result": {"not_a_paperback": 1}},
+ {"phrase": "Digital mini-series.", "result": {"not_a_paperback": 1}},
+ {"phrase": "Six issue mini-series.", "result": {"not_a_paperback": 1}},
+ {"phrase": "Six issue mini-series.", "result": {"not_a_paperback": 1}}
+ ]
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index ec52264..1bf3363 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3605,6 +3605,13 @@ character-parser@^2.1.1:
dependencies:
is-regex "^1.0.3"
+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:
version "2.1.8"
resolved "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz"
@@ -3968,27 +3975,34 @@ compression@^1.7.4:
safe-buffer "5.1.2"
vary "~1.1.2"
-compromise-dates@^2.0.1:
+compromise-dates@^2.2.1:
version "2.2.1"
- resolved "https://registry.npmjs.org/compromise-dates/-/compromise-dates-2.2.1.tgz"
+ resolved "https://registry.yarnpkg.com/compromise-dates/-/compromise-dates-2.2.1.tgz#c04d22f1f95850e5ce8b0ab225b1671639207369"
integrity sha512-mtdK67DR4EvowLLh0YJ3aMxMtKXDViQBJTNNdHI5ck+DVhCCd7rYnNcwC2eSES+3tup1JB9+InOzmvyEuFyjLQ==
dependencies:
spacetime "6.16.0"
spacetime-holiday "0.1.0"
-compromise-numbers@^1.2.0:
+compromise-numbers@^1.4.0:
version "1.4.0"
- resolved "https://registry.npmjs.org/compromise-numbers/-/compromise-numbers-1.4.0.tgz"
+ resolved "https://registry.yarnpkg.com/compromise-numbers/-/compromise-numbers-1.4.0.tgz#22e545923243333bc1e8a2e82da2e922afb50400"
integrity sha512-3ceRpwZIWduVSMYn54ET1ELdI7bvXQk42uDwxffxiJBxgKCwcCfVbiLuTG62cI+qTHchwLDh4vp9i3WARXROFQ==
-compromise-sentences@^0.2.0:
- version "0.2.0"
- resolved "https://registry.npmjs.org/compromise-sentences/-/compromise-sentences-0.2.0.tgz"
- integrity sha512-GiXGHoVz4Q9QdooAcNEhsXqcTw2lfxIdgjLJYLszyt2bJKXZTJIhH5DT9tixpbzIWeRTQAJdC+/CRVkqAyL2pA==
+compromise-sentences@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/compromise-sentences/-/compromise-sentences-0.3.0.tgz#61d34039323155bc20dad10f24340daaabf86e26"
+ integrity sha512-L6d5PXmmyPyWRMoJURYOM0yILhtV37zCOy9ZW8Xd6KgY+2qQBTwuokekaGL9MDpSH3/grRDL+AHKytYpGrTEmA==
-compromise@^13.10.5:
+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:
version "13.11.3"
- resolved "https://registry.npmjs.org/compromise/-/compromise-13.11.3.tgz"
+ resolved "https://registry.yarnpkg.com/compromise/-/compromise-13.11.3.tgz#3f6b687fbefdbd1ef674f263f6e5c06b29c324d9"
integrity sha512-oKYButHtXcDyEe2et5XlniFWyFTpDOy3z7zB501EEgTN9xeZHIib1Xq4AOSJw6HCZmwGHh1nx3MGy/MbGHFtWQ==
dependencies:
efrt-unpack "2.2.0"
@@ -4843,7 +4857,7 @@ ee-first@1.1.1:
efrt-unpack@2.2.0:
version "2.2.0"
- resolved "https://registry.npmjs.org/efrt-unpack/-/efrt-unpack-2.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/efrt-unpack/-/efrt-unpack-2.2.0.tgz#b05dbec0fb8cb346a27840e00c969df9c72fee52"
integrity sha512-9xUSSj7qcUxz+0r4X3+bwUNttEfGfK5AH+LVa1aTpqdAfrN5VhROYCfcF+up4hp5OL7IUKcZJJrzAGipQRDoiQ==
electron-to-chromium@^1.3.723:
@@ -8947,6 +8961,13 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+ml-classify-text@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ml-classify-text/-/ml-classify-text-2.0.0.tgz#932bee8bf3a7adbe3f6259136f77c57672fa6ad0"
+ integrity sha512-1+8kc07uZoat5Q8gbdYBjwuvNPDTwvt8t9+ZL7CHVErbKD3w95rnCcsmJWJcz9LWWjP2pMlgolgzKCiZklc2MA==
+ dependencies:
+ xregexp "^4.3.0"
+
moment@^2.14.1, moment@^2.22.1, moment@^2.29.1:
version "2.29.1"
resolved "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz"
@@ -11232,6 +11253,11 @@ regexp-clone@1.0.0, regexp-clone@^1.0.0:
resolved "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz"
integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==
+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.2.0, regexp.prototype.flags@^1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz"
@@ -12150,12 +12176,12 @@ source-map@^0.7.3, source-map@~0.7.2:
spacetime-holiday@0.1.0:
version "0.1.0"
- resolved "https://registry.npmjs.org/spacetime-holiday/-/spacetime-holiday-0.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/spacetime-holiday/-/spacetime-holiday-0.1.0.tgz#e680d17e0ac26e36b2101ee4ac40eb642b6d31d4"
integrity sha512-rYIpSDbHnznZRstUrmYYFAaruW8e96t+1JfS0b6qMiAAQ2DrkLKc8oMotAAkB9qMTUwXXf5bIkdTHfP434uitQ==
spacetime@6.16.0:
version "6.16.0"
- resolved "https://registry.npmjs.org/spacetime/-/spacetime-6.16.0.tgz"
+ resolved "https://registry.yarnpkg.com/spacetime/-/spacetime-6.16.0.tgz#f213963392eafc380716c3857b23251de87db97f"
integrity sha512-mkuniNOp6ssfPyJidj81tb54zKxK4vEKPTmcUsC/NEGIF8S07ppoSotdg6numT1/26rthQYmdxMY/M5a9WeJVQ==
sparse-bitfield@^3.0.3:
@@ -13984,6 +14010,13 @@ xpath@^0.0.32:
resolved "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz"
integrity sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==
+xregexp@^4.3.0:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.4.1.tgz#c84a88fa79e9ab18ca543959712094492185fe65"
+ integrity sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==
+ dependencies:
+ "@babel/runtime-corejs3" "^7.12.1"
+
xregexp@^5.0.2:
version "5.0.2"
resolved "https://registry.npmjs.org/xregexp/-/xregexp-5.0.2.tgz"