Commit 26cc64bd authored by cbartondock's avatar cbartondock

Use google scholar to fetch metadata

parent c0623a94
...@@ -27,6 +27,15 @@ import json ...@@ -27,6 +27,15 @@ import json
from shutil import copyfile from shutil import copyfile
from uuid import uuid4 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 flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response from flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response
from flask_babel import gettext as _ from flask_babel import gettext as _
from flask_login import current_user, login_required from flask_login import current_user, login_required
...@@ -996,6 +1005,26 @@ def convert_bookformat(book_id): ...@@ -996,6 +1005,26 @@ def convert_bookformat(book_id):
flash(_(u"There was an error converting this book: %(res)s", res=rtn), category="error") 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)) return redirect(url_for('editbook.edit_book', book_id=book_id))
@editbook.route("/scholarsearch/<query>",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 'Scholarly not installed'
@editbook.route("/ajax/editbooks/<param>", methods=['POST']) @editbook.route("/ajax/editbooks/<param>", methods=['POST'])
@login_required_if_no_ano @login_required_if_no_ano
@edit_required @edit_required
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -19,310 +19,375 @@ ...@@ -19,310 +19,375 @@
* Google Books api document: https://developers.google.com/books/docs/v1/using * 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) * Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only)
* ComicVine api document: https://comicvine.gamespot.com/api/documentation * ComicVine api document: https://comicvine.gamespot.com/api/documentation
*/ */
/* global _, i18nMsg, tinymce */ /* global _, i18nMsg, tinymce */
var dbResults = []; var dbResults = [];
var ggResults = []; var ggResults = [];
var cvResults = []; var cvResults = [];
var gsResults = [];
$(function () { $(function () {
var msg = i18nMsg; var msg = i18nMsg;
var douban = "https://api.douban.com"; var douban = "https://api.douban.com";
var dbSearch = "/v2/book/search"; var dbSearch = "/v2/book/search";
var dbDone = 0; var dbDone = 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 showFlag = 0;
var templates = {
bookResult: _.template(
$("#template-book-result").html()
)
};
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 ampSeparatedAuthors = (book.authors || []).join(" & "); var google = "https://www.googleapis.com";
$("#bookAuthor").val(ampSeparatedAuthors); var ggSearch = "/books/v1/volumes";
$("#book_title").val(book.title); var ggDone = 0;
$("#tags").val(uniqueTags.join(","));
$("#rating").data("rating").setValue(Math.round(book.rating)); var comicvine = "https://comicvine.gamespot.com";
$(".cover img").attr("src", book.cover); var cvSearch = "/api/search/";
$("#cover_url").val(book.cover); var cvDone = 0;
$("#pubdate").val(book.publishedDate);
$("#publisher").val(book.publisher); var googlescholar = window.location.href.split('/admin/book')[0];
if (typeof book.series !== "undefined") { var gsSearch = "/scholarsearch/"
$("#series").val(book.series); var gsDone = 0;
}
var showFlag = 0;
var templates = {
bookResult: _.template(
$("#template-book-result").html()
)
};
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 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 () { function showResult () {
showFlag++; showFlag++;
if (showFlag === 1) { if (showFlag === 1) {
$("#meta-info").html("<ul id=\"book-list\" class=\"media-list\"></ul>"); $("#meta-info").html("<ul id=\"book-list\" class=\"media-list\"></ul>");
} }
if ((ggDone === 3 || (ggDone === 1 && ggResults.length === 0)) && if ((ggDone === 3 || (ggDone === 1 && ggResults.length === 0)) &&
(dbDone === 3 || (dbDone === 1 && dbResults.length === 0)) && (dbDone === 3 || (dbDone === 1 && dbResults.length === 0)) &&
(cvDone === 3 || (cvDone === 1 && cvResults.length === 0))) { (cvDone === 3 || (cvDone === 1 && cvResults.length === 0)) &&
$("#meta-info").html("<p class=\"text-danger\">" + msg.no_result + "</p>"); (gsDone === 3 || (gsDone === 1 && gsResults.length === 0))) {
return; $("#meta-info").html("<p class=\"text-danger\">" + msg.no_result + "</p>");
} return;
function formatDate (date) { }
var d = new Date(date), function formatDate (date) {
month = "" + (d.getMonth() + 1), var d = new Date(date),
day = "" + d.getDate(), month = "" + (d.getMonth() + 1),
year = d.getFullYear(); 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 (month.length < 2) {
} month = "0" + month;
}
if (day.length < 2) {
day = "0" + day;
}
if (ggResults.length > 0) { return [year, month, day].join("-");
if (ggDone < 2) { }
ggResults.forEach(function(result) { function generateID (title) {
var book = { return title.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0).toString().substr(0,12);
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 (ggResults.length > 0) {
if (dbDone < 2) { if (ggDone < 2) {
dbResults.forEach(function(result) { ggResults.forEach(function(result) {
var seriesTitle = ""; var book = {
if (result.series) { id: result.id,
seriesTitle = result.series.title; title: result.volumeInfo.title,
} authors: result.volumeInfo.authors || [],
var dateFomers = result.pubdate.split("-"); description: result.volumeInfo.description || "",
var publishedYear = parseInt(dateFomers[0], 10); publisher: result.volumeInfo.publisher || "",
var publishedMonth = parseInt(dateFomers[1], 10); publishedDate: result.volumeInfo.publishedDate || "",
var publishedDate = new Date(publishedYear, publishedMonth - 1, 1); tags: result.volumeInfo.categories || [],
rating: result.volumeInfo.averageRating || 0,
publishedDate = formatDate(publishedDate); cover: result.volumeInfo.imageLinks ?
result.volumeInfo.imageLinks.thumbnail : location + "/../../../static/generic_cover.jpg",
var book = { url: "https://books.google.com/books?id=" + result.id,
id: result.id, source: {
title: result.title, id: "google",
authors: result.author || [], description: "Google Books",
description: result.summary, url: "https://books.google.com/"
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) { var $book = $(templates.bookResult(book));
cvResults.forEach(function(result) { $book.find("img").on("click", function () {
var seriesTitle = ""; populateForm(book);
if (result.volume.name) { });
seriesTitle = result.volume.name;
} $("#book-list").append($book);
var dateFomers = ""; });
if (result.store_date) { ggDone = 2;
dateFomers = result.store_date.split("-"); } else {
} else { ggDone = 3;
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) { if (gsResults.length > 0) {
$.ajax({ if (gsDone < 2) {
url: google + ggSearch + "?q=" + title.replace(/\s+/gm, "+"), gsResults.forEach(function(result) {
type: "GET", var book = {
dataType: "jsonp", id: generateID(result.bib.title),
jsonp: "callback", title: result.bib.title,
success: function success(data) { authors: result.bib.author || [],
if ("items" in data) { description: result.bib.abstract || "",
ggResults = data.items; publisher: result.bib.venue || "",
} publishedDate: result.bib.pub_year ? result.bib.pub_year+"-01-01" : "",
}, tags: [],
complete: function complete() { rating: 0,
ggDone = 1; series: "",
showResult(); cover: null,
$("#show-google").trigger("change"); 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;
}
} }
function dbSearchBook (title) { if (dbResults.length > 0) {
var apikey = "054022eaeae0b00e0fc068c0c0a2102a"; if (dbDone < 2) {
$.ajax({ dbResults.forEach(function(result) {
url: douban + dbSearch + "?apikey=" + apikey + "&q=" + title + "&fields=all&count=10", var seriesTitle = "";
type: "GET", if (result.series) {
dataType: "jsonp", seriesTitle = result.series.title;
jsonp: "callback", }
success: function success(data) { var dateFomers = result.pubdate.split("-");
dbResults = data.books; var publishedYear = parseInt(dateFomers[0], 10);
}, var publishedMonth = parseInt(dateFomers[1], 10);
error: function error() { var publishedDate = new Date(publishedYear, publishedMonth - 1, 1);
$("#meta-info").html("<p class=\"text-danger\">" + msg.search_error + "!</p>" + $("#meta-info")[0].innerHTML);
}, publishedDate = formatDate(publishedDate);
complete: function complete() {
dbDone = 1; var book = {
showResult(); id: result.id,
$("#show-douban").trigger("change"); 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);
function cvSearchBook (title) { var book = {
var apikey = "57558043c53943d5d1e96a9ad425b0eb85532ee6"; id: result.id,
title = encodeURIComponent(title); title: seriesTitle + " #" + ("00" + result.issue_number).slice(-3) + " - " + result.name,
$.ajax({ authors: result.author || [],
url: comicvine + cvSearch + "?api_key=" + apikey + "&resources=issue&query=" + title + "&sort=name:desc&format=jsonp", description: result.description,
type: "GET", publisher: "",
dataType: "jsonp", publishedDate: publishedDate || "",
jsonp: "json_callback", tags: ["Comics", seriesTitle],
success: function success(data) { rating: 0,
cvResults = data.results; series: seriesTitle || "",
}, cover: result.image.original_url,
error: function error() { url: result.site_detail_url,
$("#meta-info").html("<p class=\"text-danger\">" + msg.search_error + "!</p>" + $("#meta-info")[0].innerHTML); source: {
}, id: "comicvine",
complete: function complete() { description: "ComicVine Books",
cvDone = 1; url: "https://comicvine.gamespot.com/"
showResult();
$("#show-comics").trigger("change");
} }
};
var $book = $(templates.bookResult(book));
$book.find("img").on("click", function () {
populateForm(book);
});
$("#book-list").append($book);
}); });
cvDone = 2;
} else {
cvDone = 3;
}
} }
}
function doSearch (keyword) { function ggSearchBook (title) {
showFlag = 0; $.ajax({
dbDone = ggDone = cvDone = 0; url: google + ggSearch + "?q=" + title.replace(/\s+/gm, "+"),
dbResults = []; type: "GET",
ggResults = []; dataType: "jsonp",
cvResults = []; jsonp: "callback",
$("#meta-info").text(msg.loading); success: function success(data) {
if (keyword) { if ("items" in data) {
dbSearchBook(keyword); ggResults = data.items;
ggSearchBook(keyword);
cvSearchBook(keyword);
} }
} },
complete: function complete() {
ggDone = 1;
showResult();
$("#show-google").trigger("change");
}
});
}
$("#meta-search").on("submit", function (e) { function dbSearchBook (title) {
e.preventDefault(); var apikey = "054022eaeae0b00e0fc068c0c0a2102a";
var keyword = $("#keyword").val(); $.ajax({
if (keyword) { url: douban + dbSearch + "?apikey=" + apikey + "&q=" + title + "&fields=all&count=10",
doSearch(keyword); type: "GET",
} dataType: "jsonp",
jsonp: "callback",
success: function success(data) {
dbResults = data.books;
},
error: function error() {
$("#meta-info").html("<p class=\"text-danger\">" + msg.search_error + "!</p>" + $("#meta-info")[0].innerHTML);
},
complete: function complete() {
dbDone = 1;
showResult();
$("#show-douban").trigger("change");
}
}); });
}
$("#get_meta").click(function () { function cvSearchBook (title) {
var bookTitle = $("#book_title").val(); var apikey = "57558043c53943d5d1e96a9ad425b0eb85532ee6";
if (bookTitle) { title = encodeURIComponent(title);
$("#keyword").val(bookTitle); $.ajax({
doSearch(bookTitle); 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("<p class=\"text-danger\">" + msg.search_error + "!</p>" + $("#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);
}
});
}); });
...@@ -227,6 +227,10 @@ ...@@ -227,6 +227,10 @@
<input type="checkbox" id="show-comics" class="pill" data-control="comicvine" checked> <input type="checkbox" id="show-comics" class="pill" data-control="comicvine" checked>
<label for="show-comics">ComicVine <span class="glyphicon glyphicon-ok"></span></label> <label for="show-comics">ComicVine <span class="glyphicon glyphicon-ok"></span></label>
<input type="checkbox" id="show-googlescholar" class="pill" data-control="googlescholar" checked>
<label for="show-googlescholar">Google Scholar <span class="glyphicon glyphicon-ok"></span></label>
</div> </div>
<div id="meta-info"> <div id="meta-info">
...@@ -248,7 +252,7 @@ ...@@ -248,7 +252,7 @@
<img class="pull-left img-responsive" <img class="pull-left img-responsive"
data-toggle="modal" data-toggle="modal"
data-target="#metaModal" data-target="#metaModal"
src="<%= cover %>" src="<%= cover || "{{ url_for('static', filename='img/academicpaper.svg') }}" %>"
alt="Cover" alt="Cover"
> >
<div class="media-body"> <div class="media-body">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment