mirror of
https://github.com/kiwix/kiwix-tools.git
synced 2026-01-24 14:00:21 -05:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
773b9e5443 | ||
|
|
fbddabb10f | ||
|
|
3ad50ccf17 | ||
|
|
c265eb8b24 | ||
|
|
6f49e78eb4 | ||
|
|
d25329ecb4 | ||
|
|
bd8d0c3805 | ||
|
|
a01906d273 | ||
|
|
4bd18ce466 | ||
|
|
fb8c14a1e4 | ||
|
|
2acd276753 | ||
|
|
53b2dadfce | ||
|
|
eccf5e194c | ||
|
|
8356277562 |
16
Changelog
16
Changelog
@@ -1,3 +1,19 @@
|
||||
kiwix-tools 0.5.0
|
||||
=================
|
||||
|
||||
* Build kiwix-tools setting the RPATH
|
||||
* Compile without warning.
|
||||
|
||||
|
||||
kiwix-server
|
||||
------------
|
||||
|
||||
* Serve metadata information using the "/meta" url.
|
||||
* Serve an OPDS stream of all zim handled by kiwix-serve
|
||||
All informations cannot be infer from the zim file itself,
|
||||
you should use a library.xml to provide needed information (url, ...)
|
||||
* Update kiwix-serve to use the new API of kiwix-lib
|
||||
|
||||
kiwix-tools 0.4.0
|
||||
=================
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
project('kiwix-tools', 'cpp',
|
||||
version : '0.4.0',
|
||||
version : '0.5.0',
|
||||
license : 'GPL',
|
||||
default_options: ['c_std=c11', 'cpp_std=c++11'])
|
||||
default_options: ['c_std=c11', 'cpp_std=c++11', 'werror=true'])
|
||||
|
||||
compiler = meson.get_compiler('cpp')
|
||||
|
||||
@@ -11,7 +11,7 @@ if static_linkage
|
||||
endif
|
||||
|
||||
thread_dep = dependency('threads')
|
||||
kiwixlib_dep = dependency('kiwix', version:'>=1.0.0', static:static_linkage)
|
||||
kiwixlib_dep = dependency('kiwix', version:'>=2.0.0', static:static_linkage)
|
||||
microhttpd_dep = dependency('libmicrohttpd', static:static_linkage)
|
||||
z_dep = dependency('zlib', static:static_linkage)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
executable('kiwix-install', ['kiwix-install.cpp'],
|
||||
dependencies:all_deps,
|
||||
install:true)
|
||||
install:true,
|
||||
install_rpath: join_paths(get_option('prefix'), get_option('libdir')))
|
||||
|
||||
@@ -67,14 +67,128 @@ void usage()
|
||||
cerr << "\tkiwix-manage LIBRARY_PATH remove CONTENTID1 [CONTENTID2]" << endl;
|
||||
}
|
||||
|
||||
|
||||
void handle_show(kiwix::Manager* libraryManager, const std::string& libraryPath,
|
||||
int argc, char* argv[])
|
||||
{
|
||||
show(libraryManager->cloneLibrary());
|
||||
}
|
||||
|
||||
void handle_add(kiwix::Manager* libraryManager, const std::string& libraryPath,
|
||||
int argc, char* argv[])
|
||||
{
|
||||
string zimPath;
|
||||
string zimPathToSave = ".";
|
||||
string indexPath;
|
||||
kiwix::supportedIndexType indexBackend = kiwix::XAPIAN;
|
||||
string url;
|
||||
string origID = "";
|
||||
bool setCurrent = false;
|
||||
int option_index = 0;
|
||||
int c = 0;
|
||||
|
||||
if (argc > 3) {
|
||||
zimPath = argv[3];
|
||||
}
|
||||
|
||||
/* Options parsing */
|
||||
optind = 2;
|
||||
while (42) {
|
||||
static struct option long_options[]
|
||||
= {{"url", required_argument, 0, 'u'},
|
||||
{"origId", required_argument, 0, 'o'},
|
||||
{"indexPath", required_argument, 0, 'i'},
|
||||
{"indexBackend", required_argument, 0, 'b'},
|
||||
{"zimPathToSave", required_argument, 0, 'z'},
|
||||
{"current", no_argument, 0, 'c'},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
c = getopt_long(argc, argv, "cz:u:i:b:", long_options, &option_index);
|
||||
|
||||
if (c != -1) {
|
||||
switch (c) {
|
||||
case 'u':
|
||||
url = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
origID = optarg;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
setCurrent = true;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
indexPath = optarg;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
if (!strcmp(optarg, "xapian")) {
|
||||
indexBackend = kiwix::XAPIAN;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
zimPathToSave = optarg;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zimPath.empty()) {
|
||||
zimPathToSave = zimPathToSave == "." ? zimPath : zimPathToSave;
|
||||
string bookId = libraryManager->addBookFromPathAndGetId(
|
||||
zimPath, zimPathToSave, url, false);
|
||||
if (!bookId.empty()) {
|
||||
if (setCurrent)
|
||||
libraryManager->setCurrentBookId(bookId);
|
||||
/* Save the index infos if necessary */
|
||||
if (!indexPath.empty())
|
||||
libraryManager->setBookIndex(bookId, indexPath, indexBackend);
|
||||
} else {
|
||||
cerr << "Unable to build or save library file '" << libraryPath << "'"
|
||||
<< endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Invalid zim file path" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_remove(kiwix::Manager* libraryManager, const std::string& libraryPath,
|
||||
int argc, char* argv[])
|
||||
{
|
||||
unsigned int bookIndex = 0;
|
||||
const unsigned int totalBookCount = libraryManager->getBookCount(true, true);
|
||||
|
||||
if (argc > 3) {
|
||||
bookIndex = atoi(argv[3]);
|
||||
}
|
||||
|
||||
if (bookIndex > 0 && bookIndex <= totalBookCount) {
|
||||
libraryManager->removeBookByIndex(bookIndex - 1);
|
||||
} else {
|
||||
if (totalBookCount > 0) {
|
||||
std::cerr
|
||||
<< "Invalid book index number. Please give a number between 1 and "
|
||||
<< totalBookCount << std::endl;
|
||||
} else {
|
||||
std::cerr
|
||||
<< "Invalid book index number. Library is empty, no book to delete."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
string libraryPath = "";
|
||||
supportedAction action = NONE;
|
||||
string zimPath = "";
|
||||
kiwix::Manager libraryManager;
|
||||
int option_index = 0;
|
||||
int c = 0;
|
||||
|
||||
/* Argument parsing */
|
||||
if (argc > 2) {
|
||||
@@ -103,111 +217,11 @@ int main(int argc, char** argv)
|
||||
|
||||
/* SHOW */
|
||||
if (action == SHOW) {
|
||||
show(libraryManager.cloneLibrary());
|
||||
handle_show(&libraryManager, libraryPath, argc, argv);
|
||||
} else if (action == ADD) {
|
||||
string zimPath;
|
||||
string zimPathToSave = ".";
|
||||
string indexPath;
|
||||
kiwix::supportedIndexType indexBackend = kiwix::XAPIAN;
|
||||
string url;
|
||||
string origID = "";
|
||||
bool setCurrent = false;
|
||||
|
||||
if (argc > 3) {
|
||||
zimPath = argv[3];
|
||||
}
|
||||
|
||||
/* Options parsing */
|
||||
optind = 2;
|
||||
while (42) {
|
||||
static struct option long_options[]
|
||||
= {{"url", required_argument, 0, 'u'},
|
||||
{"origId", required_argument, 0, 'o'},
|
||||
{"indexPath", required_argument, 0, 'i'},
|
||||
{"indexBackend", required_argument, 0, 'b'},
|
||||
{"zimPathToSave", required_argument, 0, 'z'},
|
||||
{"current", no_argument, 0, 'c'},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
c = getopt_long(argc, argv, "cz:u:i:b:", long_options, &option_index);
|
||||
|
||||
if (c != -1) {
|
||||
switch (c) {
|
||||
case 'u':
|
||||
url = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
origID = optarg;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
setCurrent = true;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
indexPath = optarg;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
if (!strcmp(optarg, "xapian")) {
|
||||
indexBackend = kiwix::XAPIAN;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
zimPathToSave = optarg;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zimPath.empty()) {
|
||||
zimPathToSave = zimPathToSave == "." ? zimPath : zimPathToSave;
|
||||
string bookId = libraryManager.addBookFromPathAndGetId(
|
||||
zimPath, zimPathToSave, url, false);
|
||||
|
||||
if (!bookId.empty()) {
|
||||
if (setCurrent)
|
||||
libraryManager.setCurrentBookId(bookId);
|
||||
|
||||
/* Save the index infos if necessary */
|
||||
if (!indexPath.empty())
|
||||
libraryManager.setBookIndex(bookId, indexPath, indexBackend);
|
||||
|
||||
} else {
|
||||
cerr << "Unable to build or save library file '" << libraryPath << "'"
|
||||
<< endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Invalid zim file path" << std::endl;
|
||||
}
|
||||
|
||||
handle_add(&libraryManager, libraryPath, argc, argv);
|
||||
} else if (action == REMOVE) {
|
||||
unsigned int bookIndex = 0;
|
||||
const unsigned int totalBookCount = libraryManager.getBookCount(true, true);
|
||||
|
||||
if (argc > 3) {
|
||||
bookIndex = atoi(argv[3]);
|
||||
}
|
||||
|
||||
if (bookIndex > 0 && bookIndex <= totalBookCount) {
|
||||
libraryManager.removeBookByIndex(bookIndex - 1);
|
||||
} else {
|
||||
if (totalBookCount > 0) {
|
||||
std::cerr
|
||||
<< "Invalid book index number. Please give a number between 1 and "
|
||||
<< totalBookCount << std::endl;
|
||||
} else {
|
||||
std::cerr
|
||||
<< "Invalid book index number. Library is empty, no book to delete."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
handle_remove(&libraryManager, libraryPath, argc, argv);
|
||||
}
|
||||
|
||||
/* Rewrite the library file */
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
executable('kiwix-manage', ['kiwix-manage.cpp'],
|
||||
dependencies:all_deps,
|
||||
install:true)
|
||||
install:true,
|
||||
install_rpath: join_paths(get_option('prefix'), get_option('libdir')))
|
||||
|
||||
@@ -79,10 +79,8 @@ int main(int argc, char** argv)
|
||||
|
||||
/* Start to read an article */
|
||||
if (reader != NULL) {
|
||||
string mainPageUrl = reader->getMainPageUrl();
|
||||
string content;
|
||||
string contentType;
|
||||
unsigned int contentLength = 0;
|
||||
string suggestion;
|
||||
|
||||
if (pattern != NULL) {
|
||||
@@ -94,13 +92,6 @@ int main(int argc, char** argv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (reader->getContentByUrl(mainPageUrl, content, contentLength,
|
||||
contentType)) {
|
||||
cout << content << endl;
|
||||
}
|
||||
*/
|
||||
|
||||
delete reader;
|
||||
} else {
|
||||
cerr << "Unable instanciate the Kiwix reader." << endl;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
executable('kiwix-read', ['kiwix-read.cpp'],
|
||||
dependencies:all_deps,
|
||||
install:true)
|
||||
install:true,
|
||||
install_rpath: join_paths(get_option('prefix'), get_option('libdir')))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
executable('kiwix-search', ['kiwix-search.cpp'],
|
||||
dependencies:all_deps,
|
||||
install:true)
|
||||
install:true,
|
||||
install_rpath: join_paths(get_option('prefix'), get_option('libdir')))
|
||||
|
||||
@@ -51,6 +51,7 @@ extern "C" {
|
||||
#include <kiwix/manager.h>
|
||||
#include <kiwix/reader.h>
|
||||
#include <kiwix/searcher.h>
|
||||
#include <kiwix/opds_dumper.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -92,12 +93,14 @@ using namespace std;
|
||||
static bool noLibraryButtonFlag = false;
|
||||
static bool noSearchBarFlag = false;
|
||||
static string welcomeHTML;
|
||||
static string catalogOpenSearchDescription;
|
||||
static std::atomic_bool isVerbose(false);
|
||||
static std::string rootLocation = "";
|
||||
static std::map<std::string, std::string> extMimeTypes;
|
||||
static std::map<std::string, kiwix::Reader*> readers;
|
||||
static std::map<std::string, kiwix::Searcher*> searchers;
|
||||
static kiwix::Searcher* globalSearcher = nullptr;
|
||||
static kiwix::Manager libraryManager;
|
||||
static pthread_mutex_t searchLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t compressorLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t regexLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
@@ -218,8 +221,8 @@ static struct MHD_Response* build_response(const void* data,
|
||||
bool cacheEnabled)
|
||||
{
|
||||
/* Create the response */
|
||||
struct MHD_Response* response = MHD_create_response_from_data(
|
||||
length, const_cast<void*>(data), MHD_NO, MHD_YES);
|
||||
struct MHD_Response* response = MHD_create_response_from_buffer(
|
||||
length, const_cast<void*>(data), MHD_RESPMEM_MUST_COPY);
|
||||
|
||||
/* Make a redirection if necessary otherwise send the content */
|
||||
if (!httpRedirection.empty()) {
|
||||
@@ -292,22 +295,18 @@ static struct MHD_Response* build_homepage(RequestContext* request)
|
||||
}
|
||||
|
||||
struct RunningResponse {
|
||||
zim::Article* article;
|
||||
kiwix::Entry entry;
|
||||
int range_start;
|
||||
|
||||
RunningResponse(zim::Article* article,
|
||||
RunningResponse(kiwix::Entry entry,
|
||||
int range_start) :
|
||||
article(article),
|
||||
entry(entry),
|
||||
range_start(range_start)
|
||||
{}
|
||||
|
||||
~RunningResponse() {
|
||||
delete article;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ssize_t callback_reader_from_article(void* cls,
|
||||
ssize_t callback_reader_from_entry(void* cls,
|
||||
uint64_t pos,
|
||||
char* buf,
|
||||
size_t max)
|
||||
@@ -316,39 +315,39 @@ ssize_t callback_reader_from_article(void* cls,
|
||||
|
||||
size_t max_size_to_set = min<size_t>(
|
||||
max,
|
||||
response->article->getArticleSize() - pos - response->range_start);
|
||||
response->entry.getSize() - pos - response->range_start);
|
||||
|
||||
if (max_size_to_set <= 0) {
|
||||
return MHD_CONTENT_READER_END_WITH_ERROR;
|
||||
}
|
||||
|
||||
zim::Blob blob = response->article->getData(response->range_start+pos, max_size_to_set);
|
||||
zim::Blob blob = response->entry.getBlob(response->range_start+pos, max_size_to_set);
|
||||
memcpy(buf, blob.data(), max_size_to_set);
|
||||
return max_size_to_set;
|
||||
}
|
||||
|
||||
void callback_free_article(void* cls)
|
||||
void callback_free_response(void* cls)
|
||||
{
|
||||
RunningResponse* response = static_cast<RunningResponse*>(cls);
|
||||
delete response;
|
||||
}
|
||||
|
||||
static struct MHD_Response* build_callback_response_from_article(
|
||||
zim::Article& article, int range_start, int range_len, const std::string& mimeType)
|
||||
static struct MHD_Response* build_callback_response_from_entry(
|
||||
kiwix::Entry entry, int range_start, int range_len, const std::string& mimeType)
|
||||
{
|
||||
RunningResponse* run_response =
|
||||
new RunningResponse(new zim::Article(article), range_start);
|
||||
new RunningResponse(entry, range_start);
|
||||
|
||||
struct MHD_Response* response
|
||||
= MHD_create_response_from_callback(article.getArticleSize(),
|
||||
= MHD_create_response_from_callback(entry.getSize(),
|
||||
16384,
|
||||
callback_reader_from_article,
|
||||
callback_reader_from_entry,
|
||||
run_response,
|
||||
callback_free_article);
|
||||
callback_free_response);
|
||||
/* Tell the client that byte ranges are accepted */
|
||||
MHD_add_response_header(response, MHD_HTTP_HEADER_ACCEPT_RANGES, "bytes");
|
||||
std::ostringstream oss;
|
||||
oss << "bytes " << range_start << "-" << range_start + range_len - 1 << "/" << article.getArticleSize();
|
||||
oss << "bytes " << range_start << "-" << range_start + range_len - 1 << "/" << entry.getSize();
|
||||
|
||||
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_RANGE, oss.str().c_str());
|
||||
|
||||
@@ -382,6 +381,50 @@ get_from_humanReadableBookId(const std::string& humanReadableBookId) {
|
||||
return std::pair<kiwix::Reader*, kiwix::Searcher*>(reader, searcher);
|
||||
}
|
||||
|
||||
static struct MHD_Response* handle_meta(RequestContext* request)
|
||||
{
|
||||
std::string humanReadableBookId;
|
||||
std::string meta_name;
|
||||
try {
|
||||
humanReadableBookId = request->get_argument("content");
|
||||
meta_name = request->get_argument("name");
|
||||
} catch (const std::out_of_range& e) {
|
||||
return build_404(request, humanReadableBookId);
|
||||
}
|
||||
|
||||
auto reader = get_from_humanReadableBookId(humanReadableBookId).first;
|
||||
if (reader == nullptr) {
|
||||
return build_404(request, humanReadableBookId);
|
||||
}
|
||||
|
||||
std::string content;
|
||||
std::string mimeType = "text";
|
||||
|
||||
if (meta_name == "title") {
|
||||
content = reader->getTitle();
|
||||
} else if (meta_name == "description") {
|
||||
content = reader->getDescription();
|
||||
} else if (meta_name == "language") {
|
||||
content = reader->getLanguage();
|
||||
} else if (meta_name == "name") {
|
||||
content = reader->getName();
|
||||
} else if (meta_name == "tags") {
|
||||
content = reader->getTags();
|
||||
} else if (meta_name == "date") {
|
||||
content = reader->getDate();
|
||||
} else if (meta_name == "creator") {
|
||||
content = reader->getCreator();
|
||||
} else if (meta_name == "publisher") {
|
||||
content = reader->getPublisher();
|
||||
} else if (meta_name == "favicon") {
|
||||
reader->getFavicon(content, mimeType);
|
||||
} else {
|
||||
return build_404(request, humanReadableBookId);
|
||||
}
|
||||
|
||||
return build_response(content.data(), content.size(), "", mimeType, false, true);
|
||||
}
|
||||
|
||||
static struct MHD_Response* handle_suggest(RequestContext* request)
|
||||
{
|
||||
if (isVerbose.load()) {
|
||||
@@ -509,8 +552,14 @@ static struct MHD_Response* handle_search(RequestContext* request)
|
||||
auto variantsItr = variants.begin();
|
||||
|
||||
while (patternCorrespondingUrl.empty() && variantsItr != variants.end()) {
|
||||
reader->getPageUrlFromTitle(*variantsItr, patternCorrespondingUrl);
|
||||
variantsItr++;
|
||||
try {
|
||||
auto entry = reader->getEntryFromTitle(*variantsItr);
|
||||
entry = entry.getFinalEntry();
|
||||
patternCorrespondingUrl = entry.getPath();
|
||||
break;
|
||||
} catch(kiwix::NoEntry& e) {
|
||||
variantsItr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If article found then redirect directly to it */
|
||||
@@ -587,10 +636,75 @@ static struct MHD_Response* handle_random(RequestContext* request)
|
||||
return build_homepage(request);
|
||||
}
|
||||
|
||||
std::string randomUrl = reader->getRandomPageUrl();
|
||||
httpRedirection
|
||||
= rootLocation + "/" + humanReadableBookId + "/" + kiwix::urlEncode(randomUrl);
|
||||
return build_response("", 0, httpRedirection, "", false, false);
|
||||
try {
|
||||
auto entry = reader->getRandomPage();
|
||||
entry = entry.getFinalEntry();
|
||||
httpRedirection
|
||||
= rootLocation + "/" + humanReadableBookId + "/" + kiwix::urlEncode(entry.getPath());
|
||||
return build_response("", 0, httpRedirection, "", false, false);
|
||||
} catch(kiwix::NoEntry& e) {
|
||||
return build_404(request, humanReadableBookId);
|
||||
}
|
||||
}
|
||||
|
||||
static struct MHD_Response* handle_catalog(RequestContext* request)
|
||||
{
|
||||
if (isVerbose.load()) {
|
||||
printf("** running handle_catalog");
|
||||
}
|
||||
|
||||
std::string host;
|
||||
std::string url;
|
||||
try {
|
||||
host = request->get_header("Host");
|
||||
url = request->get_url_part(1);
|
||||
} catch (const std::out_of_range&) {
|
||||
return build_404(request, "");
|
||||
}
|
||||
|
||||
std::string content;
|
||||
std::string mimeType;
|
||||
|
||||
if (url == "searchdescription.xml") {
|
||||
content = catalogOpenSearchDescription;
|
||||
mimeType = "application/opensearchdescription+xml";
|
||||
} else {
|
||||
zim::Uuid uuid;
|
||||
kiwix::OPDSDumper opdsDumper;
|
||||
opdsDumper.setRootLocation(rootLocation);
|
||||
opdsDumper.setSearchDescriptionUrl("catalog/searchdescription.xml");
|
||||
mimeType = "application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8";
|
||||
kiwix::Library library_to_dump;
|
||||
if (url == "root.xml") {
|
||||
opdsDumper.setTitle("All zims");
|
||||
uuid = zim::Uuid::generate(host);
|
||||
library_to_dump = libraryManager.cloneLibrary();
|
||||
} else if (url == "search") {
|
||||
std::string query;
|
||||
try {
|
||||
query = request->get_argument("q");
|
||||
} catch (const std::out_of_range&) {
|
||||
return build_404(request, "");
|
||||
}
|
||||
opdsDumper.setTitle("Search result for " + query);
|
||||
uuid = zim::Uuid::generate();
|
||||
library_to_dump = libraryManager.filter(query);
|
||||
} else {
|
||||
return build_404(request, "");
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << uuid;
|
||||
opdsDumper.setId(ss.str());
|
||||
}
|
||||
opdsDumper.setLibrary(library_to_dump);
|
||||
content = opdsDumper.dumpOPDSFeed();
|
||||
}
|
||||
|
||||
bool deflated = request->can_compress() && compress_content(content, mimeType);
|
||||
return build_response(
|
||||
content.data(), content.size(), "", mimeType, deflated, false);
|
||||
}
|
||||
|
||||
static struct MHD_Response* handle_content(RequestContext* request)
|
||||
@@ -603,8 +717,7 @@ static struct MHD_Response* handle_content(RequestContext* request)
|
||||
std::string content;
|
||||
std::string mimeType;
|
||||
|
||||
bool found = false;
|
||||
zim::Article article;
|
||||
kiwix::Entry entry;
|
||||
|
||||
std::string humanReadableBookId;
|
||||
try {
|
||||
@@ -621,25 +734,9 @@ static struct MHD_Response* handle_content(RequestContext* request)
|
||||
auto urlStr = request->get_url().substr(humanReadableBookId.size()+1);
|
||||
|
||||
try {
|
||||
found = reader->getArticleObjectByDecodedUrl(urlStr, article);
|
||||
|
||||
if (found) {
|
||||
/* If redirect */
|
||||
unsigned int loopCounter = 0;
|
||||
while (article.isRedirect() && ++loopCounter < 42) {
|
||||
article = article.getRedirectArticle();
|
||||
}
|
||||
|
||||
/* To many loop */
|
||||
if (loopCounter == 42)
|
||||
found = false;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
found = false;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
entry = reader->getEntryFromPath(urlStr);
|
||||
entry = entry.getFinalEntry();
|
||||
} catch(kiwix::NoEntry& e) {
|
||||
if (isVerbose.load())
|
||||
printf("Failed to find %s\n", urlStr.c_str());
|
||||
|
||||
@@ -647,7 +744,7 @@ static struct MHD_Response* handle_content(RequestContext* request)
|
||||
}
|
||||
|
||||
try {
|
||||
mimeType = article.getMimeType();
|
||||
mimeType = entry.getMimetype();
|
||||
} catch (exception& e) {
|
||||
mimeType = "application/octet-stream";
|
||||
}
|
||||
@@ -660,14 +757,13 @@ static struct MHD_Response* handle_content(RequestContext* request)
|
||||
if (mimeType.find("text/") != string::npos
|
||||
|| mimeType.find("application/javascript") != string::npos
|
||||
|| mimeType.find("application/json") != string::npos) {
|
||||
zim::Blob raw_content = article.getData();
|
||||
zim::Blob raw_content = entry.getBlob();
|
||||
content = string(raw_content.data(), raw_content.size());
|
||||
|
||||
/* Special rewrite URL in case of ZIM file use intern *asbolute* url like
|
||||
* /A/Kiwix */
|
||||
if (mimeType.find("text/html") != string::npos) {
|
||||
baseUrl = "/" + std::string(1, article.getNamespace()) + "/"
|
||||
+ article.getUrl();
|
||||
baseUrl = "/" + entry.getPath();
|
||||
pthread_mutex_lock(®exLock);
|
||||
content = replaceRegex(content,
|
||||
"$1$2" + rootLocation + "/" + humanReadableBookId + "/$3/",
|
||||
@@ -696,12 +792,12 @@ static struct MHD_Response* handle_content(RequestContext* request)
|
||||
} else {
|
||||
int range_len;
|
||||
if (request->get_range().second == -1) {
|
||||
range_len = article.getArticleSize() - request->get_range().first;
|
||||
range_len = entry.getSize() - request->get_range().first;
|
||||
} else {
|
||||
range_len = request->get_range().second - request->get_range().first;
|
||||
}
|
||||
return build_callback_response_from_article(
|
||||
article,
|
||||
return build_callback_response_from_entry(
|
||||
entry,
|
||||
request->get_range().first,
|
||||
range_len,
|
||||
mimeType);
|
||||
@@ -750,6 +846,10 @@ static int accessHandlerCallback(void* cls,
|
||||
} else {
|
||||
if (startswith(request.get_url(), "/skin/")) {
|
||||
response = handle_skin(&request);
|
||||
} else if (startswith(request.get_url(), "/catalog")) {
|
||||
response = handle_catalog(&request);
|
||||
} else if (request.get_url() == "/meta") {
|
||||
response = handle_meta(&request);
|
||||
} else if (request.get_url() == "/search") {
|
||||
response = handle_search(&request);
|
||||
} else if (request.get_url() == "/suggest") {
|
||||
@@ -784,12 +884,11 @@ int main(int argc, char** argv)
|
||||
string rootPath;
|
||||
string interface;
|
||||
int serverPort = 80;
|
||||
int daemonFlag = false;
|
||||
int daemonFlag [[gnu::unused]] = false;
|
||||
int libraryFlag = false;
|
||||
string PPIDString;
|
||||
unsigned int PPID = 0;
|
||||
unsigned int nb_threads = std::thread::hardware_concurrency();
|
||||
kiwix::Manager libraryManager;
|
||||
|
||||
static struct option long_options[]
|
||||
= {{"daemon", no_argument, 0, 'd'},
|
||||
@@ -1029,6 +1128,11 @@ int main(int argc, char** argv)
|
||||
|
||||
introduceTaskbar(welcomeHTML, "");
|
||||
|
||||
/* Compute the OpenSearch description */
|
||||
catalogOpenSearchDescription = RESOURCE::opensearchdescription_xml;
|
||||
catalogOpenSearchDescription = replaceRegex(catalogOpenSearchDescription, rootLocation, "__ROOT_LOCATION__");
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Fork if necessary */
|
||||
if (daemonFlag) {
|
||||
|
||||
@@ -4,4 +4,5 @@ sources += server_resources
|
||||
|
||||
executable('kiwix-serve', sources,
|
||||
dependencies:all_deps,
|
||||
install:true)
|
||||
install:true,
|
||||
install_rpath: join_paths(get_option('prefix'), get_option('libdir')))
|
||||
|
||||
8
static/server/opensearchdescription.xml
Normal file
8
static/server/opensearchdescription.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||
<ShortName>Zim catalog search</ShortName>
|
||||
<Description>Search zim files in the catalog.</Description>
|
||||
<Url type="application/atom+xml;profile=opds-catalog"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom"
|
||||
template="/__ROOT_LOCATION__/catalog/search?q={searchTerms}"/>
|
||||
</OpenSearchDescription>
|
||||
@@ -22,3 +22,4 @@ include.html.part
|
||||
taskbar.css
|
||||
taskbar.html.part
|
||||
global_taskbar.html.part
|
||||
opensearchdescription.xml
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
set -e
|
||||
|
||||
REPO_NAME=${TRAVIS_REPO_SLUG#*/}
|
||||
ARCHIVE_NAME=deps_${PLATFORM}_${REPO_NAME}.tar.gz
|
||||
ARCHIVE_NAME=deps_${TRAVIS_OS_NAME}_${PLATFORM}_${REPO_NAME}.tar.gz
|
||||
|
||||
# Packages.
|
||||
case ${PLATFORM} in
|
||||
|
||||
Reference in New Issue
Block a user