mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-24 18:47:23 +00:00
get metadata from douban and google while editing.
This commit is contained in:
parent
4a2b5b46a3
commit
e100702345
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Get Metadata from Douban api
|
|
||||||
* Created by idalin<dalin.lin@gmail.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
var get_meta_btn = '<li>' +
|
|
||||||
'<a href="#" id="get_meta" data-toggle="modal" data-target="#metaModal">' +
|
|
||||||
'获取Meta</a></li>';
|
|
||||||
$('#main-nav').prepend(get_meta_btn);
|
|
||||||
var douban = 'https://api.douban.com';
|
|
||||||
var search = '/v2/book/search';
|
|
||||||
var get_info = '/v2/book/';
|
|
||||||
var get_info_by_isbn = '/v2/book/isbn/ ';
|
|
||||||
|
|
||||||
$.ajaxSetup({
|
|
||||||
type: "GET",
|
|
||||||
dataType: "jsonp",
|
|
||||||
jsonp: 'callback',
|
|
||||||
async: false
|
|
||||||
});
|
|
||||||
|
|
||||||
get_meta = function (id) {
|
|
||||||
var url = douban + get_info + id;
|
|
||||||
console.log('getting book meta:' + id);
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
success: function (meta) {
|
|
||||||
console.log(meta);
|
|
||||||
//$('#metaModal').modal('hide');
|
|
||||||
$('#description').val(meta.summary);
|
|
||||||
$('#bookAuthor').val(meta.author.join(' & '));
|
|
||||||
$('#book_title').val(meta.title);
|
|
||||||
var tags = '';
|
|
||||||
for (var i = 0; i < meta.tags.length; i++) {
|
|
||||||
tags = tags + meta.tags[i].title + ',';
|
|
||||||
}
|
|
||||||
$('#tags').val(tags);
|
|
||||||
$('#rating').val(Math.round(meta.rating.average / 4));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get_meta_by_isbn = function (isbn) {
|
|
||||||
var url = douban + get_info_by_isbn + isbn;
|
|
||||||
}
|
|
||||||
|
|
||||||
search_book = function (title) {
|
|
||||||
var url = douban + search + '?q=' + title + '&fields=id,title,author,publisher,isbn13,image,summary';
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
success: function (data) {
|
|
||||||
if (data.books.length < 1) {
|
|
||||||
$('#meta-info').html('<p class="text-danger">搜索不到对应的书籍</p>');
|
|
||||||
} else {
|
|
||||||
$('#meta-info').html('<ul id="book-list" class="media-list"></ul>');
|
|
||||||
for (var i = 0; i < data.books.length; i++) {
|
|
||||||
var book = '<li class="media">' +
|
|
||||||
'<img class="pull-left img-responsive" data-toggle="modal" data-target="#metaModal" src="' +
|
|
||||||
data.books[i].image + '" alt="Cover" onclick="javascript:get_meta(' +
|
|
||||||
data.books[i].id + ')">' +
|
|
||||||
'<div class="media-body">' +
|
|
||||||
'<h4 class="media-heading"><a href="https://book.douban.com/subject/' +
|
|
||||||
data.books[i].id + '" target="_blank">' + data.books[i].title + '</a></h4>' +
|
|
||||||
'<p>作者:' + data.books[i].author + '</p>' +
|
|
||||||
'<p>出版社:' + data.books[i].publisher + '</p>' +
|
|
||||||
'<p>简介:' + data.books[i].summary + '</p>' +
|
|
||||||
'</div>' +
|
|
||||||
'</li>';
|
|
||||||
$("#book-list").append(book);
|
|
||||||
if(i>20){break;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function () {
|
|
||||||
$('#meta-info').html('<p class="text-danger">搜索出错</p>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#get_meta').click(function () {
|
|
||||||
var book_title = $('#book_title').val();
|
|
||||||
if (book_title) {
|
|
||||||
// console.log(book_title);
|
|
||||||
search_book(book_title);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
179
cps/static/js/get_meta.js
Normal file
179
cps/static/js/get_meta.js
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* Get Metadata from Douban Books api and Google Books api
|
||||||
|
* Created by idalin<dalin.lin@gmail.com>
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
var douban = 'https://api.douban.com';
|
||||||
|
var db_search = '/v2/book/search';
|
||||||
|
var db_get_info = '/v2/book/';
|
||||||
|
var db_get_info_by_isbn = '/v2/book/isbn/ ';
|
||||||
|
var db_done = false;
|
||||||
|
|
||||||
|
var google = 'https://www.googleapis.com/';
|
||||||
|
var gg_search = '/books/v1/volumes';
|
||||||
|
var gg_get_info = '/books/v1/volumes/';
|
||||||
|
var gg_done = false;
|
||||||
|
|
||||||
|
var db_results = [];
|
||||||
|
var gg_results = [];
|
||||||
|
var show_flag = 0;
|
||||||
|
String.prototype.replaceAll = function (s1, s2) {
|
||||||
|
return this.replace(new RegExp(s1, "gm"), s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajaxSetup({
|
||||||
|
type: "GET",
|
||||||
|
dataType: "jsonp",
|
||||||
|
jsonp: 'callback',
|
||||||
|
});
|
||||||
|
|
||||||
|
gg_search_book = function (title) {
|
||||||
|
title = title.replaceAll(/\s+/, '+');
|
||||||
|
var url = google + gg_search + '?q=' + title;
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
success: function (data) {
|
||||||
|
gg_results = data.items;
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
gg_done = true;
|
||||||
|
show_result();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get_meta = function (source, id) {
|
||||||
|
var meta;
|
||||||
|
if (source == 'google') {;
|
||||||
|
meta = gg_results[id];
|
||||||
|
$('#description').val(meta.volumeInfo.description);
|
||||||
|
$('#bookAuthor').val(meta.volumeInfo.authors.join(' & '));
|
||||||
|
$('#book_title').val(meta.volumeInfo.title);
|
||||||
|
if (meta.volumeInfo.categories) {
|
||||||
|
var tags = meta.volumeInfo.categories.join(',');
|
||||||
|
$('#tags').val(tags);
|
||||||
|
}
|
||||||
|
if (meta.volumeInfo.averageRating) {
|
||||||
|
$('#rating').val(Math.round(meta.volumeInfo.averageRating));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (source == 'douban') {
|
||||||
|
meta = db_results[id];
|
||||||
|
$('#description').val(meta.summary);
|
||||||
|
$('#bookAuthor').val(meta.author.join(' & '));
|
||||||
|
$('#book_title').val(meta.title);
|
||||||
|
var tags = '';
|
||||||
|
for (var i = 0; i < meta.tags.length; i++) {
|
||||||
|
tags = tags + meta.tags[i].title + ',';
|
||||||
|
}
|
||||||
|
$('#tags').val(tags);
|
||||||
|
$('#rating').val(Math.round(meta.rating.average / 2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_search = function (keyword) {
|
||||||
|
show_flag = 0;
|
||||||
|
$('#meta-info').text('Loading...');
|
||||||
|
var keyword = $('#keyword').val();
|
||||||
|
if (keyword) {
|
||||||
|
db_search_book(keyword);
|
||||||
|
gg_search_book(keyword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db_search_book = function (title) {
|
||||||
|
var url = douban + db_search + '?q=' + title + '&fields=all&count=10';
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
success: function (data) {
|
||||||
|
db_results = data.books;
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
$('#meta-info').html('<p class="text-danger">Search error!</p>');
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
db_done = true;
|
||||||
|
show_result();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
show_result = function () {
|
||||||
|
show_flag++;
|
||||||
|
if (show_flag == 1) {
|
||||||
|
$('#meta-info').html('<ul id="book-list" class="media-list"></ul>');
|
||||||
|
}
|
||||||
|
if (gg_done && db_done) {
|
||||||
|
if (gg_results.length < 1 && db_results.length < 1) {
|
||||||
|
$('#meta-info').html('<p class="text-danger">No Result! Please try anonther keyword.</p>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gg_done && gg_results.length > 0) {
|
||||||
|
for (var i = 0; i < gg_results.length; i++) {
|
||||||
|
var book = gg_results[i];
|
||||||
|
var book_cover;
|
||||||
|
if (book.volumeInfo.imageLinks) {
|
||||||
|
book_cover = book.volumeInfo.imageLinks.thumbnail;
|
||||||
|
} else {
|
||||||
|
book_cover = '/static/generic_cover.jpg';
|
||||||
|
}
|
||||||
|
var book_html = '<li class="media">' +
|
||||||
|
'<img class="pull-left img-responsive" data-toggle="modal" data-target="#metaModal" src="' +
|
||||||
|
book_cover + '" alt="Cover" style="width:100px;height:150px" onclick=\'javascript:get_meta("google",' +
|
||||||
|
i + ')\'>' +
|
||||||
|
'<div class="media-body">' +
|
||||||
|
'<h4 class="media-heading"><a href="https://books.google.com/books?id=' +
|
||||||
|
book.id + '" target="_blank">' + book.volumeInfo.title + '</a></h4>' +
|
||||||
|
'<p>Author:' + book.volumeInfo.authors + '</p>' +
|
||||||
|
'<p>Publisher:' + book.volumeInfo.publisher + '</p>' +
|
||||||
|
'<p>Description:' + book.volumeInfo.description + '</p>' +
|
||||||
|
'<p>Source:<a href="https://books.google.com" target="_blank">Google Books</a></p>' +
|
||||||
|
'</div>' +
|
||||||
|
'</li>';
|
||||||
|
$("#book-list").append(book_html);
|
||||||
|
}
|
||||||
|
gg_done = false;
|
||||||
|
}
|
||||||
|
if (db_done && db_results.length > 0) {
|
||||||
|
for (var i = 0; i < db_results.length; i++) {
|
||||||
|
var book = db_results[i];
|
||||||
|
var book_html = '<li class="media">' +
|
||||||
|
'<img class="pull-left img-responsive" data-toggle="modal" data-target="#metaModal" src="' +
|
||||||
|
book.image + '" alt="Cover" style="width:100px;height: 150px" onclick=\'javascript:get_meta("douban",' +
|
||||||
|
i + ')\'>' +
|
||||||
|
'<div class="media-body">' +
|
||||||
|
'<h4 class="media-heading"><a href="https://book.douban.com/subject/' +
|
||||||
|
book.id + '" target="_blank">' + book.title + '</a></h4>' +
|
||||||
|
'<p>Author:' + book.author + '</p>' +
|
||||||
|
'<p>Publisher:' + book.publisher + '</p>' +
|
||||||
|
'<p>Description:' + book.summary + '</p>' +
|
||||||
|
'<p>Source:<a href="https://book.douban.com" target="_blank">Douban Books</a></p>' +
|
||||||
|
'</div>' +
|
||||||
|
'</li>';
|
||||||
|
$("#book-list").append(book_html);
|
||||||
|
}
|
||||||
|
db_done = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#do-search').click(function () {
|
||||||
|
var keyword = $('#keyword').val();
|
||||||
|
if (keyword) {
|
||||||
|
do_search(keyword);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#get_meta').click(function () {
|
||||||
|
var book_title = $('#book_title').val();
|
||||||
|
if (book_title) {
|
||||||
|
$('#keyword').val(book_title);
|
||||||
|
do_search(book_title);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -1,13 +1,9 @@
|
|||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %} {% block body %} {% if book %}
|
||||||
{% block body %}
|
|
||||||
{% if book %}
|
|
||||||
<div class="col-sm-3 col-lg-3 col-xs-12">
|
<div class="col-sm-3 col-lg-3 col-xs-12">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
{% if book.has_cover %}
|
{% if book.has_cover %}
|
||||||
<img src="{{ url_for('get_cover', cover_path=book.path.replace('\\','/')) }}" />
|
<img src="{{ url_for('get_cover', cover_path=book.path.replace('\\','/')) }}" /> {% else %}
|
||||||
{% else %}
|
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" /> {% endif %}
|
||||||
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" />
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
@ -51,31 +47,20 @@
|
|||||||
<input type="text" class="form-control typeahead" name="languages" id="languages" value="{% for language in book.languages %}{{language.language_name.strip()}}, {% endfor %}">
|
<input type="text" class="form-control typeahead" name="languages" id="languages" value="{% for language in book.languages %}{{language.language_name.strip()}}, {% endfor %}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if cc|length > 0 %}
|
{% if cc|length > 0 %} {% for c in cc %}
|
||||||
{% for c in cc %}
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ 'custom_column_' ~ c.id }}">{{ c.name }}</label>
|
<label for="{{ 'custom_column_' ~ c.id }}">{{ c.name }}</label> {% if c.datatype == 'bool' %}
|
||||||
{% if c.datatype == 'bool' %}
|
|
||||||
<select name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}" class="form-control">
|
<select name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}" class="form-control">
|
||||||
<option value="None" {% if book['custom_column_' ~ c.id]|length == 0 %} selected {% endif %}></option>
|
<option value="None" {% if book['custom_column_' ~ c.id]|length == 0 %} selected {% endif %}></option>
|
||||||
<option value="True" {% if book['custom_column_' ~ c.id]|length > 0 %}{% if book['custom_column_' ~ c.id][0].value ==true %}selected{% endif %}{% endif %} >{{_('Yes')}}</option>
|
<option value="True" {% if book['custom_column_' ~ c.id]|length > 0 %}{% if book['custom_column_' ~ c.id][0].value ==true %}selected{% endif %}{% endif %} >{{_('Yes')}}</option>
|
||||||
<option value="False" {% if book['custom_column_' ~ c.id]|length > 0 %}{% if book['custom_column_' ~ c.id][0].value ==false %}selected{% endif %}{% endif %}>{{_('No')}}</option>
|
<option value="False" {% if book['custom_column_' ~ c.id]|length > 0 %}{% if book['custom_column_' ~ c.id][0].value ==false %}selected{% endif %}{% endif %}>{{_('No')}}</option>
|
||||||
</select>
|
</select> {% endif %} {% if c.datatype in ['text', 'series'] and not c.is_multiple %}
|
||||||
{% endif %}
|
<input type="text" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}" {% if book[
|
||||||
{% if c.datatype in ['text', 'series'] and not c.is_multiple %}
|
'custom_column_' ~ c.id]|length> 0 %} value="{{ book['custom_column_' ~ c.id][0].value }}" {% endif %}> {% endif %} {% if c.datatype
|
||||||
<input type="text" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}"
|
in ['text', 'series'] and c.is_multiple %}
|
||||||
{% if book['custom_column_' ~ c.id]|length > 0 %}
|
<input type="text" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}" {% if book[
|
||||||
value="{{ book['custom_column_' ~ c.id][0].value }}"
|
'custom_column_' ~ c.id]|length> 0 %} value="{% for column in book['custom_column_' ~ c.id] %}{{ column.value.strip() }}{% if
|
||||||
{% endif %}>
|
not loop.last %}, {% endif %}{% endfor %}"{% endif %}> {% endif %} {% if c.datatype == 'enumeration' %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if c.datatype in ['text', 'series'] and c.is_multiple %}
|
|
||||||
<input type="text" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}"
|
|
||||||
{% if book['custom_column_' ~ c.id]|length > 0 %}
|
|
||||||
value="{% for column in book['custom_column_' ~ c.id] %}{{ column.value.strip() }}{% if not loop.last %}, {% endif %}{% endfor %}"{% endif %}>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if c.datatype == 'enumeration' %}
|
|
||||||
<select class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}">
|
<select class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}">
|
||||||
<option></option>
|
<option></option>
|
||||||
{% for opt in c.get_display_dict().enum_values %}
|
{% for opt in c.get_display_dict().enum_values %}
|
||||||
@ -85,18 +70,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
>{{ opt }}</option>
|
>{{ opt }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select> {% endif %} {% if c.datatype == 'rating' %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if c.datatype == 'rating' %}
|
|
||||||
<input type="number" min="1" max="5" step="1" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}"
|
<input type="number" min="1" max="5" step="1" class="form-control" name="{{ 'custom_column_' ~ c.id }}" id="{{ 'custom_column_' ~ c.id }}"
|
||||||
{% if book['custom_column_' ~ c.id]|length > 0 %}
|
{% if book[ 'custom_column_' ~ c.id]|length> 0 %} value="{{ '%d' % (book['custom_column_' ~ c.id][0].value /
|
||||||
value="{{ '%d' % (book['custom_column_' ~ c.id][0].value / 2) }}"
|
2) }}" {% endif %}> {% endif %}
|
||||||
{% endif %}>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %} {% endif %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
@ -104,6 +83,7 @@
|
|||||||
<input name="detail_view" type="checkbox" checked> {{_('view book after edit')}}
|
<input name="detail_view" type="checkbox" checked> {{_('view book after edit')}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="#" id="get_meta" class="btn btn-default" data-toggle="modal" data-target="#metaModal">{{_('Get Meta Data')}}</a>
|
||||||
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
|
<button type="submit" class="btn btn-default">{{_('Submit')}}</button>
|
||||||
<a href="{{ url_for('show_book',id=book.id) }}" class="btn btn-default">{{_('Back')}}</a>
|
<a href="{{ url_for('show_book',id=book.id) }}" class="btn btn-default">{{_('Back')}}</a>
|
||||||
</form>
|
</form>
|
||||||
@ -115,6 +95,14 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
<h4 class="modal-title" id="metaModalLabel">{{_('Get meta data')}}</h4>
|
<h4 class="modal-title" id="metaModalLabel">{{_('Get meta data')}}</h4>
|
||||||
|
<form class="form-inline">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="sr-only" for="keyword">Keyword</label>
|
||||||
|
<input type="text" class="form-control" id="keyword" placeholder="{{_(" Search keyword ")}}">
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-default" id="do-search">{{_("Go!")}}</button>
|
||||||
|
<span>{{_('Click the cover to load meta data to the form')}}</span>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" id="meta-info">
|
<div class="modal-body" id="meta-info">
|
||||||
{{_("Loading...")}}
|
{{_("Loading...")}}
|
||||||
@ -125,13 +113,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %} {% block js %}
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
<script src="{{ url_for('static', filename='js/libs/typeahead.bundle.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/libs/typeahead.bundle.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/edit_books.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/edit_books.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/douban_meta.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/get_meta.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %} {% block header %}
|
||||||
{% block header %}
|
<link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen"> {% endblock %}
|
||||||
<link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen">
|
|
||||||
{% endblock %}
|
|
Loading…
Reference in New Issue
Block a user