diff --git a/package.json b/package.json index b03ce2a..ca7f602 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@types/through2": "^2.0.36", "airdcpp-apisocket": "^2.4.1", "antd": "^4.16.5", + "array-sort-by": "^1.2.1", "babel-polyfill": "^6.26.0", "better-docs": "^2.3.2", "calibre-opds": "^1.0.7", diff --git a/src/client/actions/fileops.actions.tsx b/src/client/actions/fileops.actions.tsx index 88a2ef0..3a754cb 100644 --- a/src/client/actions/fileops.actions.tsx +++ b/src/client/actions/fileops.actions.tsx @@ -15,11 +15,7 @@ import { CV_CLEANUP, } from "../constants/action-types"; import { refineQuery } from "../shared/utils/filenameparser.utils"; -import { - matchScorer, - compareCoverImageHashes, -} from "../shared/utils/searchmatchscorer.utils"; -import { assign, each } from "lodash"; +import sortBy from "array-sort-by"; export async function walkFolder(path: string): Promise> { return axios @@ -134,31 +130,26 @@ export const fetchComicVineMatches = (searchPayload) => (dispatch) => { sort: "name%3Aasc", query: issueSearchQuery.searchParams.searchTerms.name, fieldList: "id", - limit: "10", + limit: "20", offset: "0", resources: "issue", + scorerConfiguration: { + searchQuery: { + issue: issueSearchQuery, + series: seriesSearchQuery, + }, + rawFileDetails: searchPayload.rawFileDetails, + }, + }, + transformResponse: (r) => { + const matches = JSON.parse(r); + return sortBy(matches, (match) => -match.score); }, - transformResponse: (r) => JSON.parse(r), }) .then((response) => { - const searchMatches = response.data.results; - each(searchMatches, (match) => assign(match, { score: 0 })); - const results = matchScorer( - searchMatches, - { - issue: issueSearchQuery, - series: seriesSearchQuery, - }, - searchPayload.rawFileDetails, - ); - const scoredResults = compareCoverImageHashes( - searchPayload.rawFileDetails, - results, - ); - dispatch({ type: CV_SEARCH_SUCCESS, - searchResults: scoredResults, + searchResults: response.data, searchQueryObject: { issue: issueSearchQuery, series: seriesSearchQuery, diff --git a/src/client/components/MatchResult.tsx b/src/client/components/MatchResult.tsx index 8efc9ca..4ca2871 100644 --- a/src/client/components/MatchResult.tsx +++ b/src/client/components/MatchResult.tsx @@ -16,12 +16,9 @@ export const MatchResult = (props: MatchResultProps) => { {map(props.matchData, (match, idx) => { - return ( - - {match.score} diff --git a/src/client/shared/utils/filenameparser.utils.ts b/src/client/shared/utils/filenameparser.utils.ts index 81405ba..8af30d8 100644 --- a/src/client/shared/utils/filenameparser.utils.ts +++ b/src/client/shared/utils/filenameparser.utils.ts @@ -68,7 +68,6 @@ export const preprocess = (inputString: string) => { export const tokenize = (inputString: string) => { const doc = nlp(inputString); const sentence = doc.sentences().json(); - const number = doc.numbers().fractions(); // regexes to match constituent parts of the search string // and isolate the search terms @@ -147,8 +146,8 @@ export const tokenize = (inputString: string) => { export const extractNumerals = (inputString: string): MatchArray[string] => { // Searches through the given string left-to-right, building an ordered list of - // "issue number-like" re.match objects. For example, this method finds - // matches substrings like: 3, #4, 5a, 6.00, 10.0b, .5, -1.0 + // "issue number-like" re.match objects. For example, this method finds + // matches substrings like: 3, #4, 5a, 6.00, 10.0b, .5, -1.0 const matches: MatchArray[string] = []; xregexp.forEach(inputString, /(^|[_\s#])(-?\d*\.?\d\w*)/gmu, (match) => { matches.push(match); @@ -156,7 +155,7 @@ export const extractNumerals = (inputString: string): MatchArray[string] => { return matches; }; -export const refineQuery = (inputString) => { +export const refineQuery = (inputString: string) => { const queryObj = tokenize(inputString); const removedYears = xor( queryObj.sentence_tokens.normalized, diff --git a/src/client/shared/utils/searchmatchscorer.utils.ts b/src/client/shared/utils/searchmatchscorer.utils.ts deleted file mode 100644 index 2c8f9b5..0000000 --- a/src/client/shared/utils/searchmatchscorer.utils.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2015 Rishi Ghan - * - The MIT License (MIT) - -Copyright (c) 2015 Rishi Ghan - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - */ - -/* - * Revision History: - * Initial: 2021/07/29 Rishi Ghan - */ - -import { each, map, isUndefined, isNull, assign } from "lodash"; -const stringSimilarity = require("string-similarity"); -import axios from "axios"; - -export const matchScorer = (searchMatches, searchQuery, rawFileDetails) => { - // 1. Check if it exists in the db (score: 0) - // 2. Check if issue name matches strongly (score: ++) - // 3. Check if issue number matches strongly (score: ++) - // 4. Check if issue covers hash match strongly (score: +++) - // 5. Check if issue year matches strongly (score: +) - - each(searchMatches, (match, idx) => { - // check for the issue name match - - if ( - !isNull(searchQuery.issue.searchParams.searchTerms.name) && - !isNull(match.name) - ) { - const issueNameScore = stringSimilarity.compareTwoStrings( - searchQuery.issue.searchParams.searchTerms.name, - match.name, - ); - match.score = issueNameScore; - } - - // issue number matches - if ( - !isNull(searchQuery.issue.searchParams.searchTerms.number) && - !isNull(match.issue_number) - ) { - if ( - parseInt(searchQuery.issue.searchParams.searchTerms.number, 10) === - parseInt(match.issue_number, 10) - ) { - match.score += 1; - } - } - - return match; - }); - - return searchMatches; -}; - -export const compareCoverImageHashes = (original, matches) => { - // cover matches - // calculate the image hashes of the covers and compare the Levenshtein Distance - each(matches, async (match) => { - const result = await axios.request({ - url: "http://localhost:3000/api/imagetransformation/calculateLevenshteinDistance", - method: "POST", - data: { - imagePath: original.path, - imagePath2: match.image.small_url, - options: { - match_id: match.id, - }, - }, - }); - - if (result.data.levenshteinDistance === 0) { - match.score += 4; - } else { - match.score -= 4; - } - }); - return matches; -}; diff --git a/yarn.lock b/yarn.lock index e94b5d7..a258c40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2325,7 +2325,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.1.0, ajv@^6.1.1, ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2611,6 +2611,15 @@ array-includes@^3.1.1, array-includes@^3.1.2, array-includes@^3.1.3: get-intrinsic "^1.1.1" is-string "^1.0.5" +array-sort-by@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/array-sort-by/-/array-sort-by-1.2.1.tgz#d684b9daf413975e4dc4870d285225181c4517ff" + integrity sha512-n9/QOUEHspBsztm1rzKPQx0+tVIpAJf7QTTciLIArb6P4dvZ8fNlk8fhGGuCHkU1+oZtsnZAuPPYtaFEjEofIw== + dependencies: + core-js "^2.5.3" + optionalDependencies: + ajv "^6.1.1" + array-tree-filter@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" @@ -4197,7 +4206,7 @@ core-js-pure@^3.15.0: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.15.2.tgz#c8e0874822705f3385d3197af9348f7c9ae2e3ce" integrity sha512-D42L7RYh1J2grW8ttxoY1+17Y4wXZeKe7uyplAI3FkNQyI5OgBIAjUfFiTPfL1rs0qLpxaabITNbjKl1Sp82tA== -core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5: +core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.3, core-js@^2.6.5: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==