From 251780bed6bd00cb60a779f4a1c08c1a2efb7d7f Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Sun, 16 May 2021 13:24:42 +0200 Subject: [PATCH] Added google scholar as metadata provider --- cps/about.py | 7 + cps/editbooks.py | 26 ++ cps/static/css/caliBlur.css | 40 +- cps/static/img/academicpaper.svg | 1 + cps/static/js/get_meta.js | 643 +++++++++++++++++-------------- cps/templates/book_edit.html | 6 +- cps/templates/detail.html | 4 +- optional-requirements.txt | 1 + 8 files changed, 415 insertions(+), 313 deletions(-) create mode 100644 cps/static/img/academicpaper.svg diff --git a/cps/about.py b/cps/about.py index 10e68e69..66c0ef40 100644 --- a/cps/about.py +++ b/cps/about.py @@ -54,6 +54,12 @@ try: except ImportError: greenlet_Version = None +try: + from scholarly import scholarly + scholarly_version = _(u'installed') +except ImportError: + scholarly_version = _(u'not installed') + from . import services about = flask.Blueprint('about', __name__) @@ -79,6 +85,7 @@ _VERSIONS = OrderedDict( iso639=isoLanguages.__version__, pytz=pytz.__version__, Unidecode = unidecode_version, + Scholarly = scholarly_version, Flask_SimpleLDAP = u'installed' if bool(services.ldap) else None, python_LDAP = services.ldapVersion if bool(services.ldapVersion) else None, Goodreads = u'installed' if bool(services.goodreads_support) else None, diff --git a/cps/editbooks.py b/cps/editbooks.py index 0cbdf751..83def9de 100644 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -27,6 +27,15 @@ import json from shutil import copyfile from uuid import uuid4 +# Improve this to check if scholarly is available in a global way, like other pythonic libraries +have_scholar = True +try: + from scholarly import scholarly +except ImportError: + have_scholar = False + pass + + from babel import Locale as LC from babel.core import UnknownLocaleError from flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response @@ -1058,6 +1067,23 @@ def convert_bookformat(book_id): flash(_(u"There was an error converting this book: %(res)s", res=rtn), category="error") return redirect(url_for('editbook.edit_book', book_id=book_id)) +@editbook.route("/scholarsearch/",methods=['GET']) +@login_required_if_no_ano +@edit_required +def scholar_search(query): + if have_scholar: + scholar_gen = scholarly.search_pubs(' '.join(query.split('+'))) + i=0 + result = [] + for publication in scholar_gen: + del publication['source'] + result.append(publication) + i+=1 + if(i>=10): + break + return Response(json.dumps(result),mimetype='application/json') + else: + return [] @editbook.route("/ajax/editbooks/", methods=['POST']) @login_required_if_no_ano diff --git a/cps/static/css/caliBlur.css b/cps/static/css/caliBlur.css index e2f8445d..f479f07f 100644 --- a/cps/static/css/caliBlur.css +++ b/cps/static/css/caliBlur.css @@ -1498,7 +1498,7 @@ body > div.container-fluid > div.row-fluid > div.col-sm-10 > div.discover > form } #books > .cover > a:hover, #books_rand > .cover > a:hover, .book.isotope-item > .cover > a:hover, body > div.container-fluid > div.row-fluid > div.col-sm-10 > div.discover > form > div.col-sm-12 > div.col-sm-12 > div.col-sm-2 > a:hover { - outline: solid var(--color-secondary); + /* outline: solid var(--color-secondary); */ font-size: 50px; -o-transition: outline 0s; transition: outline 0s; @@ -3133,7 +3133,7 @@ div.btn-group[role=group][aria-label="Download, send to Kindle, reading"] > div. float: left } -#add-to-shelf, #btnGroupDrop1, #read-in-browser, #sendbtn, .book-meta .btn-toolbar > .btn-group > .btn-group:nth-child(1) > a:first-of-type, .book-meta .btn-toolbar > .btn-group > .btn-warning, .btn-toolbar > .btn-group > #btnGroupDrop2, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 { +#add-to-shelf, #btnGroupDrop1, #readbtn, #sendbtn, .book-meta .btn-toolbar > .btn-group > .btn-group:nth-child(1) > a:first-of-type, .book-meta .btn-toolbar > .btn-group > .btn-warning, .btn-toolbar > .btn-group > #btnGroupDrop2, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 { background: 0 0; color: transparent; width: 50px; @@ -3142,20 +3142,16 @@ div.btn-group[role=group][aria-label="Download, send to Kindle, reading"] > div. overflow: hidden; padding: 0 } -#readbtn { - height: 100%; - padding: 16px; -} #add-to-shelf > span.caret, #btnGroupDrop1 > span.caret, #read-in-browser > span.caret, .btn-toolbar > .btn-group > #btnGroupDrop2 > span.caret, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span.caret { padding-bottom: 5px } -#add-to-shelf > span, #btnGroupDrop1 > span, #read-in-browser > span, #sendbtn > span, .book-meta .btn-toolbar > .btn-group > .btn-group:nth-child(1) > a:first-of-type > span, .book-meta .btn-toolbar > .btn-group > .btn-warning > span, .btn-toolbar > .btn-group > #btnGroupDrop2 > span, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span { +#add-to-shelf > span, #btnGroupDrop1 > span, #readbtn > span, #sendbtn > span, .book-meta .btn-toolbar > .btn-group > .btn-group:nth-child(1) > a:first-of-type > span, .book-meta .btn-toolbar > .btn-group > .btn-warning > span, .btn-toolbar > .btn-group > #btnGroupDrop2 > span, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span { color: hsla(0, 0%, 100%, .7) } -#add-to-shelf:hover span, #btnGroupDrop1:hover > span, #read-in-browser:hover > span, #sendbtn:hover > span, .book-meta .btn-toolbar > .btn-group > .btn-group:nth-child(1) > a:first-of-type:hover > span, .book-meta .btn-toolbar > .btn-group > .btn-warning:hover > span, .btn-toolbar > .btn-group > #btnGroupDrop2:hover > span, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2:hover > span { +#add-to-shelf:hover span, #btnGroupDrop1:hover > span, #readbtn:hover > span, #sendbtn:hover > span, .book-meta .btn-toolbar > .btn-group > .btn-group:nth-child(1) > a:first-of-type:hover > span, .book-meta .btn-toolbar > .btn-group > .btn-warning:hover > span, .btn-toolbar > .btn-group > #btnGroupDrop2:hover > span, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2:hover > span { color: #fff } @@ -3165,13 +3161,13 @@ div.btn-group[role=group][aria-label="Download, send to Kindle, reading"] > div. font-size: 18px } -#sendbtn > span, .book-meta .btn-toolbar > .btn-group > .btn-group:nth-child(1) > a:first-of-type > span, .book-meta .btn-toolbar > .btn-group > .btn-warning > span.glyphicon-edit { +#sendbtn > span, #readbtn > span, .book-meta .btn-toolbar > .btn-group > .btn-group:nth-child(1) > a:first-of-type > span, .book-meta .btn-toolbar > .btn-group > .btn-warning > span.glyphicon-edit { font-size: 16px; line-height: 54px; width: 100% } -#read-in-browser > span.glyphicon-eye-open:before, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span.glyphicon-eye-open:before { +#readbtn > span.glyphicon-book:before, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span.glyphicon-book:before { content: "\e352"; font-family: Glyphicons Regular, serif; font-size: 18px; @@ -3294,7 +3290,9 @@ div.btn-group[role=group][aria-label="Download, send to Kindle, reading"] .dropd -ms-transform-origin: center top; transform-origin: center top; border: 0; - left: 0 !important + left: 0 !important; + max-height: 80%; + overflow-y: auto; } .dropdown-menu > li > a { @@ -5163,11 +5161,11 @@ body.login > div.navbar.navbar-default.navbar-static-top > div > div.navbar-head right: 5px } -#read-in-browser[aria-expanded=true], #shelf-actions > .btn-group.open, .downloadBtn.open, .profileDrop[aria-expanded=true] { +#shelf-actions > .btn-group.open, .downloadBtn.open, .profileDrop[aria-expanded=true] { pointer-events: none } -#btnGroupDrop1[aria-expanded=true] > span, #read-in-browser[aria-expanded=true] > span, #shelf-actions > .btn-group.open > #add-to-shelf > span { +#btnGroupDrop1[aria-expanded=true] > span, #shelf-actions > .btn-group.open > #add-to-shelf > span { color: #fff } @@ -7484,14 +7482,14 @@ body.edituser.admin > div.container-fluid > div.row-fluid > div.col-sm-10 > div. margin-left: 8px } -#read-in-browser > span.caret, .btn-toolbar > .btn-group > #btnGroupDrop2 > span.caret, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span.caret { +.btn-toolbar > .btn-group > #btnGroupDrop2 > span.caret, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span.caret { position: absolute; margin-left: 0; left: 33px; top: 28px } -#read-in-browser > span.glyphicon-eye-open:before, .btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span.glyphicon-eye-open:before { +.btn-toolbar > .btn-group > .btn-group > #btnGroupDrop2 > span.glyphicon-eye-open:before { margin-left: 8px } @@ -7892,7 +7890,7 @@ body.mailset > div.container-fluid > div > div.col-sm-10 > div.discover .glyphic } } -#sendbtn2 { +#sendbtn2, #read-in-browser { background: 0 0; color: transparent; width: 50px; @@ -7902,15 +7900,15 @@ body.mailset > div.container-fluid > div > div.col-sm-10 > div.discover .glyphic padding: 0 } -#sendbtn2 > span { +#sendbtn2 > span, #read-in-browser > span { color: hsla(0, 0%, 100%, .7) } -#sendbtn2 > span.glyphicon-send:before { +#sendbtn2 > span.glyphicon-send:before, #read-in-browser > span.glyphicon-book:before { margin-left: 8px } -#sendbtn2 > span.caret { +#sendbtn2> span.caret, #read-in-browser > span.caret { position: absolute; margin-left: 0; left: 33px; @@ -7918,11 +7916,11 @@ body.mailset > div.container-fluid > div > div.col-sm-10 > div.discover .glyphic padding-bottom: 5px } -#sendbtn2:focus span, #sendbtn2:hover span { +#sendbtn2:focus span, #sendbtn2:hover span, #read-in-browser:focus span, #read-in-browser:hover span { color: #fff } -#sendbtn2[aria-expanded=true] { +#sendbtn2[aria-expanded=true], #read-in-browser[aria-expanded=true] { pointer-events: none } diff --git a/cps/static/img/academicpaper.svg b/cps/static/img/academicpaper.svg new file mode 100644 index 00000000..ae71a953 --- /dev/null +++ b/cps/static/img/academicpaper.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cps/static/js/get_meta.js b/cps/static/js/get_meta.js index 04c1d270..19f8e929 100644 --- a/cps/static/js/get_meta.js +++ b/cps/static/js/get_meta.js @@ -19,310 +19,375 @@ * Google Books api document: https://developers.google.com/books/docs/v1/using * Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only) * ComicVine api document: https://comicvine.gamespot.com/api/documentation -*/ + */ /* global _, i18nMsg, tinymce */ var dbResults = []; var ggResults = []; var cvResults = []; +var gsResults = []; $(function () { - var msg = i18nMsg; - var douban = "https://api.douban.com"; - var dbSearch = "/v2/book/search"; - var dbDone = 0; + var msg = i18nMsg; + var douban = "https://api.douban.com"; + var dbSearch = "/v2/book/search"; + var dbDone = 0; - var google = "https://www.googleapis.com"; - var ggSearch = "/books/v1/volumes"; - var ggDone = 0; + var google = "https://www.googleapis.com"; + var ggSearch = "/books/v1/volumes"; + var ggDone = 0; - var comicvine = "https://comicvine.gamespot.com"; - var cvSearch = "/api/search/"; - var cvDone = 0; + var comicvine = "https://comicvine.gamespot.com"; + var cvSearch = "/api/search/"; + var cvDone = 0; - var showFlag = 0; + var googlescholar = window.location.href.split('/admin/book')[0]; + var gsSearch = "/scholarsearch/" + var gsDone = 0; - var templates = { - bookResult: _.template( - $("#template-book-result").html() - ) - }; + var showFlag = 0; - function populateForm (book) { - tinymce.get("description").setContent(book.description); - var uniqueTags = []; - $.each(book.tags, function(i, el) { - if ($.inArray(el, uniqueTags) === -1) uniqueTags.push(el); - }); + var templates = { + bookResult: _.template( + $("#template-book-result").html() + ) + }; - var ampSeparatedAuthors = (book.authors || []).join(" & "); - $("#bookAuthor").val(ampSeparatedAuthors); - $("#book_title").val(book.title); - $("#tags").val(uniqueTags.join(",")); - $("#rating").data("rating").setValue(Math.round(book.rating)); - $(".cover img").attr("src", book.cover); - $("#cover_url").val(book.cover); - $("#pubdate").val(book.publishedDate); - $("#publisher").val(book.publisher); - if (typeof book.series !== "undefined") { - $("#series").val(book.series); - } - } - - function showResult () { - showFlag++; - if (showFlag === 1) { - $("#meta-info").html(""); - } - if ((ggDone === 3 || (ggDone === 1 && ggResults.length === 0)) && - (dbDone === 3 || (dbDone === 1 && dbResults.length === 0)) && - (cvDone === 3 || (cvDone === 1 && cvResults.length === 0))) { - $("#meta-info").html("

" + msg.no_result + "

"); - return; - } - function formatDate (date) { - var d = new Date(date), - month = "" + (d.getMonth() + 1), - day = "" + d.getDate(), - year = d.getFullYear(); - - if (month.length < 2) { - month = "0" + month; - } - if (day.length < 2) { - day = "0" + day; - } - - return [year, month, day].join("-"); - } - - if (ggResults.length > 0) { - if (ggDone < 2) { - ggResults.forEach(function(result) { - var book = { - id: result.id, - title: result.volumeInfo.title, - authors: result.volumeInfo.authors || [], - description: result.volumeInfo.description || "", - publisher: result.volumeInfo.publisher || "", - publishedDate: result.volumeInfo.publishedDate || "", - tags: result.volumeInfo.categories || [], - rating: result.volumeInfo.averageRating || 0, - cover: result.volumeInfo.imageLinks ? - result.volumeInfo.imageLinks.thumbnail : location + "/../../../static/generic_cover.jpg", - url: "https://books.google.com/books?id=" + result.id, - source: { - id: "google", - description: "Google Books", - url: "https://books.google.com/" - } - }; - - var $book = $(templates.bookResult(book)); - $book.find("img").on("click", function () { - populateForm(book); - }); - - $("#book-list").append($book); - }); - ggDone = 2; - } else { - ggDone = 3; - } - } - - if (dbResults.length > 0) { - if (dbDone < 2) { - dbResults.forEach(function(result) { - var seriesTitle = ""; - if (result.series) { - seriesTitle = result.series.title; - } - var dateFomers = result.pubdate.split("-"); - var publishedYear = parseInt(dateFomers[0], 10); - var publishedMonth = parseInt(dateFomers[1], 10); - var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); - - publishedDate = formatDate(publishedDate); - - var book = { - id: result.id, - title: result.title, - authors: result.author || [], - description: result.summary, - publisher: result.publisher || "", - publishedDate: publishedDate || "", - tags: result.tags.map(function(tag) { - return tag.title.toLowerCase().replace(/,/g, "_"); - }), - rating: result.rating.average || 0, - series: seriesTitle || "", - cover: result.image, - url: "https://book.douban.com/subject/" + result.id, - source: { - id: "douban", - description: "Douban Books", - url: "https://book.douban.com/" - } - }; - - if (book.rating > 0) { - book.rating /= 2; - } - - var $book = $(templates.bookResult(book)); - $book.find("img").on("click", function () { - populateForm(book); - }); - - $("#book-list").append($book); - }); - dbDone = 2; - } else { - dbDone = 3; - } - } - if (cvResults.length > 0) { - if (cvDone < 2) { - cvResults.forEach(function(result) { - var seriesTitle = ""; - if (result.volume.name) { - seriesTitle = result.volume.name; - } - var dateFomers = ""; - if (result.store_date) { - dateFomers = result.store_date.split("-"); - } else { - dateFomers = result.date_added.split("-"); - } - var publishedYear = parseInt(dateFomers[0], 10); - var publishedMonth = parseInt(dateFomers[1], 10); - var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); - - publishedDate = formatDate(publishedDate); - - var book = { - id: result.id, - title: seriesTitle + " #" + ("00" + result.issue_number).slice(-3) + " - " + result.name, - authors: result.author || [], - description: result.description, - publisher: "", - publishedDate: publishedDate || "", - tags: ["Comics", seriesTitle], - rating: 0, - series: seriesTitle || "", - cover: result.image.original_url, - url: result.site_detail_url, - source: { - id: "comicvine", - description: "ComicVine Books", - url: "https://comicvine.gamespot.com/" - } - }; - - var $book = $(templates.bookResult(book)); - $book.find("img").on("click", function () { - populateForm(book); - }); - - $("#book-list").append($book); - }); - cvDone = 2; - } else { - cvDone = 3; - } - } - } - - function ggSearchBook (title) { - $.ajax({ - url: google + ggSearch + "?q=" + title.replace(/\s+/gm, "+"), - type: "GET", - dataType: "jsonp", - jsonp: "callback", - success: function success(data) { - if ("items" in data) { - ggResults = data.items; - } - }, - complete: function complete() { - ggDone = 1; - showResult(); - $("#show-google").trigger("change"); - } - }); - } - - function dbSearchBook (title) { - var apikey = "054022eaeae0b00e0fc068c0c0a2102a"; - $.ajax({ - url: douban + dbSearch + "?apikey=" + apikey + "&q=" + title + "&fields=all&count=10", - type: "GET", - dataType: "jsonp", - jsonp: "callback", - success: function success(data) { - dbResults = data.books; - }, - error: function error() { - $("#meta-info").html("

" + msg.search_error + "!

" + $("#meta-info")[0].innerHTML); - }, - complete: function complete() { - dbDone = 1; - showResult(); - $("#show-douban").trigger("change"); - } - }); - } - - function cvSearchBook (title) { - var apikey = "57558043c53943d5d1e96a9ad425b0eb85532ee6"; - title = encodeURIComponent(title); - $.ajax({ - url: comicvine + cvSearch + "?api_key=" + apikey + "&resources=issue&query=" + title + "&sort=name:desc&format=jsonp", - type: "GET", - dataType: "jsonp", - jsonp: "json_callback", - success: function success(data) { - cvResults = data.results; - }, - error: function error() { - $("#meta-info").html("

" + msg.search_error + "!

" + $("#meta-info")[0].innerHTML); - }, - complete: function complete() { - cvDone = 1; - showResult(); - $("#show-comics").trigger("change"); - } - }); - } - - function doSearch (keyword) { - showFlag = 0; - dbDone = ggDone = cvDone = 0; - dbResults = []; - ggResults = []; - cvResults = []; - $("#meta-info").text(msg.loading); - if (keyword) { - dbSearchBook(keyword); - ggSearchBook(keyword); - cvSearchBook(keyword); - } - } - - $("#meta-search").on("submit", function (e) { - e.preventDefault(); - var keyword = $("#keyword").val(); - if (keyword) { - doSearch(keyword); - } + function populateForm (book) { + tinymce.get("description").setContent(book.description); + var uniqueTags = []; + $.each(book.tags, function(i, el) { + if ($.inArray(el, uniqueTags) === -1) uniqueTags.push(el); }); - $("#get_meta").click(function () { - var bookTitle = $("#book_title").val(); - if (bookTitle) { - $("#keyword").val(bookTitle); - doSearch(bookTitle); + var ampSeparatedAuthors = (book.authors || []).join(" & "); + $("#bookAuthor").val(ampSeparatedAuthors); + $("#book_title").val(book.title); + $("#tags").val(uniqueTags.join(",")); + $("#rating").data("rating").setValue(Math.round(book.rating)); + if(book.cover !== null){ + $(".cover img").attr("src", book.cover); + $("#cover_url").val(book.cover); + } + $("#pubdate").val(book.publishedDate); + $("#publisher").val(book.publisher); + if (typeof book.series !== "undefined") { + $("#series").val(book.series); + } + } + + function showResult () { + showFlag++; + if (showFlag === 1) { + $("#meta-info").html(""); + } + if ((ggDone === 3 || (ggDone === 1 && ggResults.length === 0)) && + (dbDone === 3 || (dbDone === 1 && dbResults.length === 0)) && + (cvDone === 3 || (cvDone === 1 && cvResults.length === 0)) && + (gsDone === 3 || (gsDone === 1 && gsResults.length === 0))) { + $("#meta-info").html("

" + msg.no_result + "

"); + return; + } + function formatDate (date) { + var d = new Date(date), + month = "" + (d.getMonth() + 1), + day = "" + d.getDate(), + year = d.getFullYear(); + + if (month.length < 2) { + month = "0" + month; + } + if (day.length < 2) { + day = "0" + day; + } + + return [year, month, day].join("-"); + } + function generateID (title) { + return title.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0).toString().substr(0,12); + } + + if (ggResults.length > 0) { + if (ggDone < 2) { + ggResults.forEach(function(result) { + var book = { + id: result.id, + title: result.volumeInfo.title, + authors: result.volumeInfo.authors || [], + description: result.volumeInfo.description || "", + publisher: result.volumeInfo.publisher || "", + publishedDate: result.volumeInfo.publishedDate || "", + tags: result.volumeInfo.categories || [], + rating: result.volumeInfo.averageRating || 0, + cover: result.volumeInfo.imageLinks ? + result.volumeInfo.imageLinks.thumbnail : location + "/../../../static/generic_cover.jpg", + url: "https://books.google.com/books?id=" + result.id, + source: { + id: "google", + description: "Google Books", + url: "https://books.google.com/" + } + }; + + var $book = $(templates.bookResult(book)); + $book.find("img").on("click", function () { + populateForm(book); + }); + + $("#book-list").append($book); + }); + ggDone = 2; + } else { + ggDone = 3; + } + } + + if (gsResults.length > 0) { + if (gsDone < 2) { + gsResults.forEach(function(result) { + var book = { + id: generateID(result.bib.title), + title: result.bib.title, + authors: result.bib.author || [], + description: result.bib.abstract || "", + publisher: result.bib.venue || "", + publishedDate: result.bib.pub_year ? result.bib.pub_year+"-01-01" : "", + tags: [], + rating: 0, + series: "", + cover: null, + url: result.pub_url || result.eprint_url || "", + source: { + id: "googlescholar", + description: "Google Scholar", + link: "https://scholar.google.com/" + } + } + var $book = $(templates.bookResult(book)); + $book.find("img").on("click", function () { + populateForm(book); + }); + + $("#book-list").append($book); + + }); + gsDone = 2; + } + else { + gsDone = 3; + } + } + + if (dbResults.length > 0) { + if (dbDone < 2) { + dbResults.forEach(function(result) { + var seriesTitle = ""; + if (result.series) { + seriesTitle = result.series.title; + } + var dateFomers = result.pubdate.split("-"); + var publishedYear = parseInt(dateFomers[0], 10); + var publishedMonth = parseInt(dateFomers[1], 10); + var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); + + publishedDate = formatDate(publishedDate); + + var book = { + id: result.id, + title: result.title, + authors: result.author || [], + description: result.summary, + publisher: result.publisher || "", + publishedDate: publishedDate || "", + tags: result.tags.map(function(tag) { + return tag.title.toLowerCase().replace(/,/g, "_"); + }), + rating: result.rating.average || 0, + series: seriesTitle || "", + cover: result.image, + url: "https://book.douban.com/subject/" + result.id, + source: { + id: "douban", + description: "Douban Books", + url: "https://book.douban.com/" + } + }; + + if (book.rating > 0) { + book.rating /= 2; + } + + var $book = $(templates.bookResult(book)); + $book.find("img").on("click", function () { + populateForm(book); + }); + + $("#book-list").append($book); + }); + dbDone = 2; + } else { + dbDone = 3; + } + } + if (cvResults.length > 0) { + if (cvDone < 2) { + cvResults.forEach(function(result) { + var seriesTitle = ""; + if (result.volume.name) { + seriesTitle = result.volume.name; + } + var dateFomers = ""; + if (result.store_date) { + dateFomers = result.store_date.split("-"); + } else { + dateFomers = result.date_added.split("-"); + } + var publishedYear = parseInt(dateFomers[0], 10); + var publishedMonth = parseInt(dateFomers[1], 10); + var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); + + publishedDate = formatDate(publishedDate); + + var book = { + id: result.id, + title: seriesTitle + " #" + ("00" + result.issue_number).slice(-3) + " - " + result.name, + authors: result.author || [], + description: result.description, + publisher: "", + publishedDate: publishedDate || "", + tags: ["Comics", seriesTitle], + rating: 0, + series: seriesTitle || "", + cover: result.image.original_url, + url: result.site_detail_url, + source: { + id: "comicvine", + description: "ComicVine Books", + url: "https://comicvine.gamespot.com/" + } + }; + + var $book = $(templates.bookResult(book)); + $book.find("img").on("click", function () { + populateForm(book); + }); + + $("#book-list").append($book); + }); + cvDone = 2; + } else { + cvDone = 3; + } + } + } + + function ggSearchBook (title) { + $.ajax({ + url: google + ggSearch + "?q=" + title.replace(/\s+/gm, "+"), + type: "GET", + dataType: "jsonp", + jsonp: "callback", + success: function success(data) { + if ("items" in data) { + ggResults = data.items; } + }, + complete: function complete() { + ggDone = 1; + showResult(); + $("#show-google").trigger("change"); + } }); + } + + function dbSearchBook (title) { + var apikey = "054022eaeae0b00e0fc068c0c0a2102a"; + $.ajax({ + url: douban + dbSearch + "?apikey=" + apikey + "&q=" + title + "&fields=all&count=10", + type: "GET", + dataType: "jsonp", + jsonp: "callback", + success: function success(data) { + dbResults = data.books; + }, + error: function error() { + $("#meta-info").html("

" + msg.search_error + "!

" + $("#meta-info")[0].innerHTML); + }, + complete: function complete() { + dbDone = 1; + showResult(); + $("#show-douban").trigger("change"); + } + }); + } + + function cvSearchBook (title) { + var apikey = "57558043c53943d5d1e96a9ad425b0eb85532ee6"; + title = encodeURIComponent(title); + $.ajax({ + url: comicvine + cvSearch + "?api_key=" + apikey + "&resources=issue&query=" + title + "&sort=name:desc&format=jsonp", + type: "GET", + dataType: "jsonp", + jsonp: "json_callback", + success: function success(data) { + cvResults = data.results; + }, + error: function error() { + $("#meta-info").html("

" + msg.search_error + "!

" + $("#meta-info")[0].innerHTML); + }, + complete: function complete() { + cvDone = 1; + showResult(); + $("#show-comics").trigger("change"); + } + }); + } + + function gsSearchBook (title) { + $.ajax({ + url: googlescholar + gsSearch + title.replace(/\s+/gm,'+'), + type: "GET", + dataType: "json", + success: function success(data) { + gsResults = data; + }, + complete: function complete() { + gsDone = 1; + showResult(); + $("#show-googlescholar").trigger("change"); + } + }) + } + + function doSearch (keyword) { + showFlag = 0; + dbDone = ggDone = cvDone = 0; + dbResults = []; + ggResults = []; + cvResults = []; + gsResults = []; + $("#meta-info").text(msg.loading); + if (keyword) { + dbSearchBook(keyword); + ggSearchBook(keyword); + cvSearchBook(keyword); + gsSearchBook(keyword); + } + } + + $("#meta-search").on("submit", function (e) { + e.preventDefault(); + var keyword = $("#keyword").val(); + if (keyword) { + doSearch(keyword); + } + }); + + $("#get_meta").click(function () { + var bookTitle = $("#book_title").val(); + if (bookTitle) { + $("#keyword").val(bookTitle); + doSearch(bookTitle); + } + }); }); diff --git a/cps/templates/book_edit.html b/cps/templates/book_edit.html index a14e2b72..42e9801c 100644 --- a/cps/templates/book_edit.html +++ b/cps/templates/book_edit.html @@ -246,6 +246,10 @@ + + + +
@@ -267,7 +271,7 @@ " alt="Cover" >
diff --git a/cps/templates/detail.html b/cps/templates/detail.html index 7f79e769..dd1934a5 100644 --- a/cps/templates/detail.html +++ b/cps/templates/detail.html @@ -57,7 +57,7 @@
{% if reader_list|length > 1 %} {% else %} - {{_('Read in Browser')}} - {{reader_list[0]}} + {{_('Read in Browser')}} - {{reader_list[0]}} {% endif %}
{% endif %} diff --git a/optional-requirements.txt b/optional-requirements.txt index 4273ec24..1fa84d50 100644 --- a/optional-requirements.txt +++ b/optional-requirements.txt @@ -32,6 +32,7 @@ SQLAlchemy-Utils>=0.33.5,<0.38.0 # extracting metadata lxml>=3.8.0,<4.7.0 rarfile>=2.7 +scholarly>=1.2.0, <1.3 # other natsort>=2.2.0,<7.2.0