mirror of
https://github.com/kiwix/kiwix-tools.git
synced 2026-01-17 10:27:44 -05:00
Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdb9b28d35 | ||
|
|
43e1740d52 | ||
|
|
7e8d02990e | ||
|
|
c337cf174e | ||
|
|
8a64083d5b | ||
|
|
d0687e40a6 | ||
|
|
14b0b901f1 | ||
|
|
336cbe691d | ||
|
|
26b4dd5f57 | ||
|
|
8882a716a0 | ||
|
|
fede5ef9b6 | ||
|
|
c5b293c6f3 | ||
|
|
d57a37cde6 | ||
|
|
7d2bec3e39 | ||
|
|
472de06e6d | ||
|
|
51a4a4e8ef | ||
|
|
6e310c7147 | ||
|
|
790bd03bd7 | ||
|
|
15c6252db4 | ||
|
|
6fd22dec61 | ||
|
|
c332c123fe | ||
|
|
e4eafd7459 | ||
|
|
16a29127a1 | ||
|
|
7fa0579ea1 | ||
|
|
978dc47865 | ||
|
|
b7793f6e75 | ||
|
|
8095ae9ea8 | ||
|
|
286f599b3e | ||
|
|
174b236312 | ||
|
|
c7e9d44b38 | ||
|
|
3a80951c23 | ||
|
|
ffaecb5389 | ||
|
|
7b25308248 | ||
|
|
7ac14aa64f | ||
|
|
3c8da8c74c | ||
|
|
9ed3fc353b | ||
|
|
51051752f1 | ||
|
|
4e8a8533c4 | ||
|
|
fd2a0decd3 | ||
|
|
624fb32091 | ||
|
|
067a40a156 | ||
|
|
cfa22365fe | ||
|
|
d5066ba6bf | ||
|
|
f1ec1ec182 | ||
|
|
d1802c52a2 | ||
|
|
38088ee321 | ||
|
|
0f445e9791 | ||
|
|
1032a46c57 | ||
|
|
cbe8f1df87 | ||
|
|
2fe5ec1d7c | ||
|
|
eba80b92ef | ||
|
|
c1e635bd4e | ||
|
|
c8be8fbad8 | ||
|
|
640f907fb2 | ||
|
|
eb407956b9 | ||
|
|
422dde9ff2 | ||
|
|
f691f85724 | ||
|
|
fd4f228a41 | ||
|
|
bf40d4ff91 | ||
|
|
74fecd34e6 | ||
|
|
881fe9f41d | ||
|
|
c23e0bc38a | ||
|
|
d4d32aa2e8 | ||
|
|
4a88c44626 | ||
|
|
0cc5b18488 | ||
|
|
88a32a152f | ||
|
|
4b8c8c5f6f | ||
|
|
f0568ff4a7 | ||
|
|
ccdfe9839d | ||
|
|
221f3ef340 | ||
|
|
0785636ca5 | ||
|
|
a3429fdc88 | ||
|
|
f99b6965e9 | ||
|
|
228402b505 | ||
|
|
a9f8364333 | ||
|
|
9f06c9c5eb | ||
|
|
0efbb2461d | ||
|
|
b251e18af1 | ||
|
|
5c040d3ee6 | ||
|
|
bb1afb5120 | ||
|
|
8fccbc4c99 | ||
|
|
d0dc9ac81b | ||
|
|
f9edd75f6c | ||
|
|
9571148375 | ||
|
|
282b85c341 | ||
|
|
4c3acd06de | ||
|
|
4cd9d78d21 | ||
|
|
efd4a1434e | ||
|
|
dfc601dacf | ||
|
|
7c254544ca | ||
|
|
b22ee94f10 | ||
|
|
3766c4882b | ||
|
|
26da54f9c3 | ||
|
|
4433421c48 | ||
|
|
c00f0be7ef | ||
|
|
773b9e5443 | ||
|
|
fbddabb10f | ||
|
|
3ad50ccf17 | ||
|
|
c265eb8b24 | ||
|
|
6f49e78eb4 | ||
|
|
d25329ecb4 | ||
|
|
bd8d0c3805 | ||
|
|
a01906d273 | ||
|
|
4bd18ce466 | ||
|
|
fb8c14a1e4 | ||
|
|
2acd276753 | ||
|
|
53b2dadfce | ||
|
|
eccf5e194c | ||
|
|
8356277562 |
11
.travis.yml
11
.travis.yml
@@ -2,22 +2,11 @@ language: cpp
|
||||
dist: trusty
|
||||
sudo: required
|
||||
cache: ccache
|
||||
before_install:
|
||||
- eval "${MATRIX_EVAL}"
|
||||
- ${CXX} --version
|
||||
install: travis/install_deps.sh
|
||||
script: travis/compile.sh
|
||||
env:
|
||||
global:
|
||||
- MATRIX_EVAL="CC=gcc-5 && CXX=g++-5"
|
||||
matrix:
|
||||
- PLATFORM="native_static"
|
||||
- PLATFORM="native_dyn"
|
||||
- PLATFORM="win32_static"
|
||||
- PLATFORM="win32_dyn"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-5
|
||||
|
||||
128
Changelog
128
Changelog
@@ -1,3 +1,131 @@
|
||||
kiwix-tools 1.2.0
|
||||
=================
|
||||
|
||||
* Remove rpath for installed binaries.
|
||||
|
||||
kiwix-serve
|
||||
-----------
|
||||
|
||||
* New Dockerfile of kiwix-serve
|
||||
* New --nodatealiases option
|
||||
* Do not use POLL on windows
|
||||
|
||||
kiwix-manage
|
||||
------------
|
||||
|
||||
* Do not show all books if book ids has been provided.
|
||||
* Be able to add several zim files in the same time in a library.
|
||||
|
||||
kiwix-tools 1.1.0
|
||||
=================
|
||||
|
||||
kiwix-serve
|
||||
-----------
|
||||
|
||||
* Fix bug about handling of absolute url in old zim file.
|
||||
* All the catalog to be searched by tags.
|
||||
|
||||
kiwix-tools 1.0.0
|
||||
=================
|
||||
|
||||
* [CI] Use the new deps archive xz
|
||||
* Move version 1.0.0. There is no need to stay in pre 1.0 version.
|
||||
|
||||
kiwix-serve
|
||||
-----------
|
||||
|
||||
* Correctly implement redirection.
|
||||
kiwix-serve now return a 302 http status code instead of resolving the
|
||||
redirection internally and return the content.
|
||||
|
||||
|
||||
kiwix-tools 0.9.0
|
||||
=================
|
||||
|
||||
* Update README
|
||||
* Update man pages
|
||||
* Remove support of external indexes (manage, search, serve)
|
||||
* Update build system as we don't use ctpp2 anymore
|
||||
* Update to last kiwix-lib API.
|
||||
|
||||
kiwix-manage
|
||||
------------
|
||||
|
||||
* Update usage.
|
||||
|
||||
|
||||
kiwix-tools 0.8.0
|
||||
=================
|
||||
|
||||
kiwix-manage
|
||||
------------
|
||||
|
||||
* Be able to remove several books from the library in one command.
|
||||
|
||||
kiwix-tools 0.7.0
|
||||
=================
|
||||
|
||||
* Adapt to kiwix-lib new API
|
||||
|
||||
kiwix-serve
|
||||
-----------
|
||||
|
||||
* Dumps only valid books in the opdsfeed.
|
||||
* Allow the opds feed to be filtered by lang and paginated.
|
||||
|
||||
kiwix-manage
|
||||
------------
|
||||
|
||||
* Add a download command to download a remote book locally
|
||||
* Book are referenced by bookId not index.
|
||||
* No more indexType option as it is always XAPIAN.
|
||||
|
||||
kiwix-tools 0.6.1
|
||||
=================
|
||||
|
||||
kiwix-serve
|
||||
-----------
|
||||
|
||||
* Update README.
|
||||
* Fix crash when `--library` flag is provided without value.
|
||||
* Correctly handle mimetype of file without extension on 64bits.
|
||||
* Minor fixes
|
||||
|
||||
kiwix-tools 0.6.0
|
||||
=================
|
||||
|
||||
* remove kiwix-install tool.
|
||||
|
||||
kiwix-serve
|
||||
-----------
|
||||
|
||||
* Improved taskbar #160
|
||||
* Fix global page when using the option `--nosearchbar`
|
||||
* Return 404 for missing resources
|
||||
* Fix compilation for gcc 4.8.
|
||||
|
||||
kiwix-manage
|
||||
------------
|
||||
|
||||
* Returns proper exit code (not always 0)
|
||||
|
||||
|
||||
kiwix-tools 0.5.0
|
||||
=================
|
||||
|
||||
* Build kiwix-tools setting the RPATH
|
||||
* Compile without warning.
|
||||
|
||||
|
||||
kiwix-serve
|
||||
------------
|
||||
|
||||
* 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
|
||||
=================
|
||||
|
||||
|
||||
108
README.md
108
README.md
@@ -1,14 +1,14 @@
|
||||
Kiwix tools
|
||||
===========
|
||||
|
||||
The Kiwix tools gathers kiwix command line tools.
|
||||
The Kiwix tools is a collection of Kiwix related command line tools.
|
||||
|
||||
Disclaimer
|
||||
----------
|
||||
|
||||
This document assumes you have a little knowledge about software
|
||||
compilation. If you experience difficulties with the dependencies or
|
||||
with the Kiwix libary compilation itself, we recommend to have a look
|
||||
with the Kiwix tools compilation itself, we recommend to have a look
|
||||
to [kiwix-build](https://github.com/kiwix/kiwix-build).
|
||||
|
||||
Preamble
|
||||
@@ -16,18 +16,18 @@ Preamble
|
||||
|
||||
Although the Kiwix tools can be compiled/cross-compiled on/for many
|
||||
sytems, the following documentation explains how to do it on POSIX
|
||||
ones. It is primarly though for GNU/Linux systems and has been tested
|
||||
ones. It is primarly thought for GNU/Linux systems and has been tested
|
||||
on recent releases of Ubuntu and Fedora.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
The Kiwix tools rely on a few third parts software libraries. They
|
||||
are prerequisites to the Kiwix library compilation. Following
|
||||
The Kiwix tools rely on a few third party software libraries. They are
|
||||
prerequisites to the Kiwix tools compilation. Therefore, following
|
||||
libraries need to be available:
|
||||
|
||||
* Kiwix lib ....................... https://github.com/kiwix/kiwix-lib
|
||||
(no package for now)
|
||||
(no package so far)
|
||||
* Libmicrohttpd .......... https://www.gnu.org/software/libmicrohttpd/
|
||||
(package libmicrohttpd-dev on Ubuntu)
|
||||
* CTPP2 ..................................... http://ctpp.havoc.ru/en/
|
||||
@@ -53,47 +53,26 @@ If you compile manually Libmicrohttpd, you might need to compile it
|
||||
without GNU TLS, a bug here will empeach further compilation of Kiwix
|
||||
tools otherwise.
|
||||
|
||||
Environnement
|
||||
Environment
|
||||
-------------
|
||||
|
||||
The Kiwix library builds using [Meson](http://mesonbuild.com/) version
|
||||
0.34 or higher. Meson relies itself on Ninja, pkg-config and few other
|
||||
compilation tools.
|
||||
|
||||
Install first the few common compilation tools:
|
||||
* Automake
|
||||
* Libtool
|
||||
* Virtualenv
|
||||
The Kiwix tools build using [Meson](http://mesonbuild.com/) version
|
||||
0.39 or higher. Meson relies itself on Ninja, pkg-config and few other
|
||||
compilation tools. Install them first:
|
||||
* Meson
|
||||
* Ninja
|
||||
* Pkg-config
|
||||
|
||||
Then install Meson itself:
|
||||
```
|
||||
virtualenv -p python3 ./ # Create virtualenv
|
||||
source bin/activate # Activate the virtualenv
|
||||
pip install meson # Install Meson
|
||||
hash -r # Refresh bash paths
|
||||
```
|
||||
|
||||
Finally download and build Ninja locally:
|
||||
```
|
||||
git clone git://github.com/ninja-build/ninja.git
|
||||
cd ninja
|
||||
git checkout release
|
||||
./configure.py --bootstrap
|
||||
mkdir ../bin
|
||||
cp ninja ../bin
|
||||
cd ..
|
||||
```
|
||||
These tools should be packaged if you use a cutting edge operating
|
||||
system. If not, have a look to the "Troubleshooting" section.
|
||||
|
||||
Compilation
|
||||
-----------
|
||||
|
||||
Once all dependencies are installed, you can compile kiwix-lib with:
|
||||
Once all dependencies are installed, you can compile Kiwix tools with:
|
||||
```
|
||||
mkdir build
|
||||
meson . build
|
||||
cd build
|
||||
ninja
|
||||
ninja -C build
|
||||
```
|
||||
|
||||
By default, it will compile dynamic linked libraries. If you want
|
||||
@@ -105,16 +84,61 @@ Depending of you system, `ninja` may be called `ninja-build`.
|
||||
Installation
|
||||
------------
|
||||
|
||||
If you want to install the Kiwix tools you just have compiled on your
|
||||
system, here we go:
|
||||
If you want to install the Kiwix tools, here we go:
|
||||
|
||||
```
|
||||
ninja install
|
||||
ninja -C build install
|
||||
```
|
||||
|
||||
You might need to run the command as root (or using 'sudo'), depending
|
||||
where you want to install the Kiwix tools. After the installation
|
||||
succeeded, you may need to run ldconfig (as root).
|
||||
|
||||
Uninstallation
|
||||
------------
|
||||
|
||||
If you want to uninstall the Kiwix tools:
|
||||
|
||||
```
|
||||
ninja -C build uninstall
|
||||
```
|
||||
|
||||
Like for the installation, you might need to run the command as root
|
||||
(or using 'sudo').
|
||||
|
||||
Docker
|
||||
------
|
||||
|
||||
An official Docker image of `kiwix-serve` can be found at
|
||||
https://hub.docker.com/r/kiwix/kiwix-serve.
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
If you need to install Meson "manually":
|
||||
```
|
||||
virtualenv -p python3 ./ # Create virtualenv
|
||||
source bin/activate # Activate the virtualenv
|
||||
pip3 install meson # Install Meson
|
||||
hash -r # Refresh bash paths
|
||||
```
|
||||
|
||||
If you need to install Ninja "manually":
|
||||
```
|
||||
git clone git://github.com/ninja-build/ninja.git
|
||||
cd ninja
|
||||
git checkout release
|
||||
./configure.py --bootstrap
|
||||
mkdir ../bin
|
||||
cp ninja ../bin
|
||||
cd ..
|
||||
```
|
||||
|
||||
You might need to run the command as root, depending where you want to
|
||||
install the libraries.
|
||||
If the compilation still fails, you might need to get a more recent
|
||||
version of a dependency than the one packaged by your Linux
|
||||
distribution. Try then with a source tarball distributed by the
|
||||
problematic upstream project or even directly from the source code
|
||||
repository.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
15
docker/server/Dockerfile
Normal file
15
docker/server/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM alpine:latest
|
||||
LABEL maintainer Emmanuel Engelhart <kelson@kiwix.org>
|
||||
|
||||
# Install kiwix-serve
|
||||
WORKDIR /
|
||||
RUN apk add --no-cache curl bzip2
|
||||
RUN curl -kL https://download.kiwix.org/release/kiwix-tools/kiwix-tools_linux-x86_64-1.1.0.tar.gz | tar -xz && \
|
||||
mv kiwix-tools*/kiwix-serve /usr/local/bin && \
|
||||
rm -r kiwix-tools*
|
||||
|
||||
# Run kiwix-serve
|
||||
EXPOSE 80
|
||||
VOLUME /data
|
||||
WORKDIR /data
|
||||
ENTRYPOINT ["/usr/local/bin/kiwix-serve", "--port", "80"]
|
||||
13
docker/server/README.md
Normal file
13
docker/server/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
kiwix-serve Docker image
|
||||
========================
|
||||
|
||||
* Download a ZIM file from <https://wiki.kiwix.org/wiki/Content>
|
||||
|
||||
* Given `wikipedia.zim` resides in `/tmp/zim/`, execute the following:
|
||||
|
||||
```
|
||||
docker run -v /tmp/zim:/data -p 8080:80 kiwix/kiwix-serve wikipedia.zim
|
||||
```
|
||||
|
||||

|
||||

|
||||
BIN
docker/server/pictures/screenshot_1.png
Normal file
BIN
docker/server/pictures/screenshot_1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
docker/server/pictures/screenshot_2.png
Normal file
BIN
docker/server/pictures/screenshot_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 199 KiB |
@@ -1,7 +1,7 @@
|
||||
project('kiwix-tools', 'cpp',
|
||||
version : '0.4.0',
|
||||
version : '1.2.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:'>=4.1.0', static:static_linkage)
|
||||
microhttpd_dep = dependency('libmicrohttpd', static:static_linkage)
|
||||
z_dep = dependency('zlib', static:static_linkage)
|
||||
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2014 Emmanuel Engelhart <kelson@kiwix.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <kiwix/common/pathTools.h>
|
||||
#include <kiwix/manager.h>
|
||||
#include <kiwix/reader.h>
|
||||
|
||||
enum supportedAction { NONE, ADDCONTENT };
|
||||
|
||||
void usage()
|
||||
{
|
||||
cout << "Usage: kiwix-install [--verbose] addcontent ZIM_PATH KIWIX_PATH"
|
||||
<< endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
/* Init the variables */
|
||||
const char* contentPath = NULL;
|
||||
const char* kiwixPath = NULL;
|
||||
supportedAction action = NONE;
|
||||
bool verboseFlag = false;
|
||||
int option_index = 0;
|
||||
int c = 0;
|
||||
|
||||
/* Argument parsing */
|
||||
while (42) {
|
||||
static struct option long_options[]
|
||||
= {{"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0}};
|
||||
|
||||
if (c != -1) {
|
||||
c = getopt_long(argc, argv, "vi", long_options, &option_index);
|
||||
|
||||
switch (c) {
|
||||
case 'v':
|
||||
verboseFlag = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (optind < argc) {
|
||||
if (action == NONE) {
|
||||
string actionString = argv[optind++];
|
||||
if (actionString == "addcontent" || actionString == "ADDCONTENT") {
|
||||
action = ADDCONTENT;
|
||||
}
|
||||
} else if (contentPath == NULL) {
|
||||
contentPath = argv[optind++];
|
||||
} else if (kiwixPath == NULL) {
|
||||
kiwixPath = argv[optind++];
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we have enough arguments */
|
||||
if (contentPath == NULL || kiwixPath == NULL) {
|
||||
usage();
|
||||
}
|
||||
|
||||
/* Make the action */
|
||||
if (action == ADDCONTENT) {
|
||||
/* Check if the content path exists and is readable */
|
||||
if (verboseFlag) {
|
||||
std::cout << "Check if the ZIM file exists..." << std::endl;
|
||||
}
|
||||
if (!fileExists(contentPath)) {
|
||||
cerr << "The content path '" << contentPath
|
||||
<< "' does not exist or is not readable." << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Check if this is a ZIM file */
|
||||
try {
|
||||
if (verboseFlag) {
|
||||
std::cout << "Check if the ZIM file is valid..." << std::endl;
|
||||
}
|
||||
kiwix::Reader* reader = new kiwix::Reader(contentPath);
|
||||
delete reader;
|
||||
} catch (exception& e) {
|
||||
cerr << "The content available at '" << contentPath
|
||||
<< "' is not a ZIM file." << endl;
|
||||
exit(1);
|
||||
}
|
||||
string contentFilename = getLastPathElement(contentPath);
|
||||
|
||||
/* Check if kiwixPath/kiwix/kiwix.exe exists */
|
||||
if (verboseFlag) {
|
||||
std::cout << "Check if the Kiwix path is valid..." << std::endl;
|
||||
}
|
||||
string kiwixBinaryPath = computeAbsolutePath(kiwixPath, "kiwix/kiwix.exe");
|
||||
if (!fileExists(kiwixBinaryPath)) {
|
||||
kiwixBinaryPath = computeAbsolutePath(kiwixPath, "kiwix/kiwix");
|
||||
if (!fileExists(kiwixBinaryPath)) {
|
||||
cerr << "Unable to find the Kiwix binary at '" << kiwixBinaryPath
|
||||
<< "[.exe]'." << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the directory "data" structure exists */
|
||||
if (verboseFlag) {
|
||||
std::cout << "Check the target data directory structure..." << std::endl;
|
||||
}
|
||||
string dataPath = computeAbsolutePath(kiwixPath, "data/");
|
||||
if (!fileExists(dataPath)) {
|
||||
makeDirectory(dataPath);
|
||||
}
|
||||
|
||||
/* Check if the directory "data/content" structure exists */
|
||||
string dataContentPath = computeAbsolutePath(kiwixPath, "data/content/");
|
||||
if (!fileExists(dataContentPath)) {
|
||||
makeDirectory(dataContentPath);
|
||||
}
|
||||
|
||||
/* Check if the directory "data/library" structure exists */
|
||||
string dataLibraryPath = computeAbsolutePath(kiwixPath, "data/library/");
|
||||
if (!fileExists(dataLibraryPath)) {
|
||||
makeDirectory(dataLibraryPath);
|
||||
}
|
||||
|
||||
/* Copy the file to the data/content directory */
|
||||
if (verboseFlag) {
|
||||
std::cout << "Copy ZIM file to the target directory..." << std::endl;
|
||||
}
|
||||
string newContentPath
|
||||
= computeAbsolutePath(dataContentPath, contentFilename);
|
||||
if (!fileExists(newContentPath)
|
||||
|| getFileSize(contentPath) != getFileSize(newContentPath)) {
|
||||
copyFile(contentPath, newContentPath);
|
||||
}
|
||||
|
||||
/* Add the file to the library.xml */
|
||||
if (verboseFlag) {
|
||||
std::cout << "Create the library XML file..." << std::endl;
|
||||
}
|
||||
kiwix::Manager libraryManager;
|
||||
string libraryPath
|
||||
= computeAbsolutePath(dataLibraryPath, contentFilename + ".xml");
|
||||
string bookId = libraryManager.addBookFromPathAndGetId(
|
||||
newContentPath, "../content/" + contentFilename, "", false);
|
||||
if (!bookId.empty()) {
|
||||
libraryManager.setCurrentBookId(bookId);
|
||||
libraryManager.writeFile(libraryPath);
|
||||
} else {
|
||||
cerr << "Unable to build or save library file '" << libraryPath << "'"
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
executable('kiwix-install', ['kiwix-install.cpp'],
|
||||
dependencies:all_deps,
|
||||
install:true)
|
||||
@@ -1,40 +0,0 @@
|
||||
.TH KIWIX 1 "21 May 2012"
|
||||
.SH NAME
|
||||
kiwix\-install \- Installeur de fichiers ZIM
|
||||
.SH SYNOPSIS
|
||||
.IX Header SYNOPSIS
|
||||
kiwix\-install [\-\-verbose|-v] [\-\-backend|\-b=xapian|clucene] [\-\-buildIndex|\-i] addcontent ZIM_PATH KIWIX_PATH
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Créé une arborescence contenant Kiwix et des données pour redistribution.
|
||||
.br
|
||||
Si demandé, créé aussi un index plein texte.
|
||||
|
||||
.TP
|
||||
\fB\-\-verbose\fR
|
||||
Active le mode verbeux de la sortie.
|
||||
|
||||
.TP
|
||||
\fB\-\-backend=xapian|clucene\fR
|
||||
Séléctionne un moteur d'indexation.
|
||||
|
||||
.TP
|
||||
\fB\-\-buildIndex\fR
|
||||
Créer un index plein texte pour le fichier ZIM.
|
||||
|
||||
.TP
|
||||
\fBZIM_PATH\fR
|
||||
Chemin du fichier de contenu ZIM.
|
||||
|
||||
.TP
|
||||
\fBKIWIX_PATH\fR
|
||||
Chemin d'accès dossier kiwix/.
|
||||
.br
|
||||
Le chemin doit contenit le binaire statique de Kiwix.
|
||||
|
||||
.SH SEE ALSO
|
||||
kiwix(1) kiwix\-serve(1) kiwix\-manage(1)
|
||||
.SH AUTHOR
|
||||
Emmanuel Engelhart <kelson@kiwix.org>
|
||||
.br
|
||||
Vasudev Kamath <kamathvasudev@gmail.com> (Manual)
|
||||
@@ -1,52 +0,0 @@
|
||||
.TH KIWIX 1 "12 juin 2012"
|
||||
.SH NAME
|
||||
Kiwix \- Lecteur hors-ligne de fichiers ZIM
|
||||
.SH SYNOPSIS
|
||||
.B kiwix [-jsconsole] [-articleByUrl] [-articleByTitle] [FILE]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Kiwix est un lecteur de content au format ZIM.
|
||||
.br
|
||||
Les fichiers ZIM sont des archives de contenus compressés (généralement HTML)
|
||||
.br
|
||||
Les fichiers ZIM les plus populaires sont ceux de Wikipédia et Wikileaks.
|
||||
|
||||
.TP
|
||||
\fB\-jsconsole\fR
|
||||
Active la console de debogage JavaScript de Xulrunner.
|
||||
\fB\-articleByUrl url\fR
|
||||
Ouvre un article en particulier en renseignant son url. FILE doit être donné.
|
||||
.TP
|
||||
\fB\-articleByTitle title\fR
|
||||
Ouvre un article en particulier en renseignant son titre. FILE doit être donné.
|
||||
|
||||
.PP
|
||||
Fonctionnalités:
|
||||
* Lecteur de ZIM natif
|
||||
* Moteur de recherche plein texte
|
||||
* Signets et Notes
|
||||
* Serveur Web pour diffuser les fichiers ZIM sur le réseau
|
||||
* Export HTML et PDF
|
||||
* Traduits dans de nombreuses langues
|
||||
* Suggestions de recherche
|
||||
* Indexation des fichiers ZIM
|
||||
* Onglets de navigation
|
||||
* Bibliothèque de contenus intégrée
|
||||
|
||||
.SH SEE ALSO
|
||||
kiwix\-install(1) kiwix\-serve(1)
|
||||
.br
|
||||
kiwix\-manage(1)
|
||||
|
||||
|
||||
.SH TROUBLESHOOTING
|
||||
Aller à http://reportabug.kiwix.org pour plus de détails sur comment rapporter un bogue.
|
||||
|
||||
.SH AUTHORS
|
||||
Emmanuel Engelhart <kelson@kiwix.org>
|
||||
Guillaume Duhamel <gduhamel@linterweb.com>
|
||||
Fabien Coullon <fcoulon@linterweb.com>
|
||||
Renaud Gaudin <rgaudin@gmail.com>
|
||||
Wilfredo Rodriguez <wilfredor@kiwix.org>
|
||||
.br
|
||||
Vasudev Kamath <kamathvasudev@gmail.com> (Manual)
|
||||
@@ -1,4 +1,3 @@
|
||||
install_man('kiwix-install.1',
|
||||
'kiwix-manage.1',
|
||||
install_man('kiwix-manage.1',
|
||||
'kiwix-serve.1',
|
||||
install_dir:get_option('mandir')+'/fr/man1')
|
||||
install_dir:get_option('mandir')+'/fr/man1')
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
.TH KIWIX 1 "21 May 2012"
|
||||
.SH NAME
|
||||
kiwix\-install \- Kiwix ZIM Installer
|
||||
.SH SYNOPSIS
|
||||
.IX Header SYNOPSIS
|
||||
kiwix\-install [\-\-verbose|-v] [\-\-backend|\-b=xapian|clucene] [\-\-buildIndex|\-i] addcontent ZIM_PATH KIWIX_PATH
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Creates a standalone Kiwix + data hierarchy.
|
||||
.br
|
||||
If specified, also creates a full\-text index.
|
||||
|
||||
.TP
|
||||
\fB\-\-verbose\fR
|
||||
Enable verbose output.
|
||||
|
||||
.TP
|
||||
\fB\-\-backend=xapian|clucene\fR
|
||||
Select an indexing backend.
|
||||
|
||||
.TP
|
||||
\fB\-\-buildIndex\fR
|
||||
Build an index for the ZIM file.
|
||||
|
||||
.TP
|
||||
\fBZIM_PATH\fR
|
||||
ZIM content file path.
|
||||
|
||||
.TP
|
||||
\fBKIWIX_PATH\fR
|
||||
Path to the kiwix/ folder.
|
||||
.br
|
||||
The path must contain the kiwix standalone binary.
|
||||
|
||||
.SH SEE ALSO
|
||||
kiwix(1) kiwix\-serve(1) kiwix\-manage(1)
|
||||
.SH AUTHOR
|
||||
Emmanuel Engelhart <kelson@kiwix.org>
|
||||
.br
|
||||
Vasudev Kamath <kamathvasudev@gmail.com> (Manual)
|
||||
@@ -15,12 +15,12 @@ kiwix\-manage LIBRARY_PATH add ZIM_PATH ...
|
||||
.PP
|
||||
\fBkiwix\-manage\fP tool for managing a kiwix library.
|
||||
.PP
|
||||
Allows one to manage the content of the kiwix library. Library file is an XML flat file
|
||||
listing ZIM files with all necessary information like favicon, date, creator,
|
||||
description, indexpath, filepath, title, source/metalink etc.
|
||||
Allows one to manage the content of the kiwix library. The library file is a
|
||||
flat XML file listing ZIM files with all necessary information like favicon,
|
||||
date, creator, description, indexpath, filepath, title, source/metalink, etc.
|
||||
.
|
||||
.PP
|
||||
Example library file can be found at http://www.kiwix.org/library\.xml
|
||||
Example library file can be found at https://www.kiwix.org/library\.xml
|
||||
.br
|
||||
.TP
|
||||
\fBadd\fR
|
||||
@@ -55,7 +55,7 @@ Path to full-text index for that ZIM file.
|
||||
Set the content location of the ZIM file over the network for in\-kiwix download.
|
||||
|
||||
.SH SEE ALSO
|
||||
kiwix(1) kiwix\-install(1) kiwix\-serve(1)
|
||||
kiwix(1) kiwix\-serve(1)
|
||||
.SH AUTHOR
|
||||
Emmanuel Engelhart <kelson@kiwix.org>
|
||||
.br
|
||||
|
||||
@@ -9,7 +9,7 @@ kiwix\-serve [\-\-index=INDEX_PATH] [\-\-port=PORT] [\-\-verbose] [\-\-daemon] [
|
||||
kiwix\-serve \-\-library [\-\-port=PORT] [\-\-verbose] [\-\-daemon] [\-\-attachToProcess=PID] LIBRARY_PATH
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Stand\-alone HTTP server for serving ZIM content over the network.
|
||||
Stand\-alone HTTP server for serving ZIM contents over the network.
|
||||
|
||||
.TP
|
||||
\fB\-\-index=INDEX_PATH\fR
|
||||
@@ -27,7 +27,7 @@ Enable verbose output.
|
||||
|
||||
.TP
|
||||
\fB\-\-daemon\fR
|
||||
Run the server as a daemon
|
||||
Run the server as a daemon.
|
||||
|
||||
.TP
|
||||
\fB\-\-attachToProcess=PID\fR
|
||||
@@ -49,12 +49,11 @@ Serves the contents of a library file instead of a single ZIM file.
|
||||
\fBLIBRARY_PATH\fR
|
||||
Kiwix library file path.
|
||||
.br
|
||||
Library is XML file created using \fBkiwix-manage\fB.
|
||||
Library is an XML file created using \fBkiwix-manage\fB.
|
||||
|
||||
.SH SEE ALSO
|
||||
kiwix(1) kiwix\-manage(1)
|
||||
.br
|
||||
kiwix\-install(1)
|
||||
|
||||
.SH AUTHOR
|
||||
Emmanuel Engelhart <kelson@kiwix.org>
|
||||
.br
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
install_man('kiwix-install.1',
|
||||
'kiwix-manage.1',
|
||||
install_man('kiwix-manage.1',
|
||||
'kiwix-serve.1')
|
||||
subdir('fr')
|
||||
|
||||
@@ -21,36 +21,40 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <getopt.h>
|
||||
#include <kiwix/common/pathTools.h>
|
||||
#include <kiwix/tools/pathTools.h>
|
||||
#include <kiwix/tools/stringTools.h>
|
||||
#include <kiwix/manager.h>
|
||||
#include <kiwix/downloader.h>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum supportedAction { NONE, ADD, SHOW, REMOVE };
|
||||
enum supportedAction { NONE, ADD, SHOW, REMOVE, DOWNLOAD };
|
||||
|
||||
void show(kiwix::Library library)
|
||||
void show(kiwix::Library* library, const std::string& bookId)
|
||||
{
|
||||
std::vector<kiwix::Book>::iterator itr;
|
||||
unsigned int inc = 1;
|
||||
for (itr = library.books.begin(); itr != library.books.end(); ++itr) {
|
||||
std::cout << "#" << inc++ << std::endl
|
||||
<< "id:\t\t" << itr->id << std::endl
|
||||
<< "path:\t\t" << itr->path << std::endl
|
||||
<< "indexpath:\t" << itr->indexPath << std::endl
|
||||
<< "url:\t\t" << itr->url << std::endl
|
||||
<< "title:\t\t" << itr->title << std::endl
|
||||
<< "name:\t\t" << itr->name << std::endl
|
||||
<< "tags:\t\t" << itr->tags << std::endl
|
||||
<< "description:\t" << itr->description << std::endl
|
||||
<< "creator:\t" << itr->creator << std::endl
|
||||
<< "date:\t\t" << itr->date << std::endl
|
||||
<< "articleCount:\t" << itr->articleCount << std::endl
|
||||
<< "mediaCount:\t" << itr->mediaCount << std::endl
|
||||
<< "size:\t\t" << itr->size << " KB" << std::endl
|
||||
<< std::endl;
|
||||
try {
|
||||
auto& book = library->getBookById(bookId);
|
||||
std::cout << "id:\t\t" << book.getId() << std::endl
|
||||
<< "path:\t\t" << book.getPath() << std::endl
|
||||
<< "url:\t\t" << book.getUrl() << std::endl
|
||||
<< "title:\t\t" << book.getTitle() << std::endl
|
||||
<< "name:\t\t" << book.getName() << std::endl
|
||||
<< "tags:\t\t" << book.getTags() << std::endl
|
||||
<< "description:\t" << book.getDescription() << std::endl
|
||||
<< "creator:\t" << book.getCreator() << std::endl
|
||||
<< "date:\t\t" << book.getDate() << std::endl
|
||||
<< "articleCount:\t" << book.getArticleCount() << std::endl
|
||||
<< "mediaCount:\t" << book.getMediaCount() << std::endl
|
||||
<< "size:\t\t" << book.getSize() << " KB" << std::endl;
|
||||
} catch (std::out_of_range&) {
|
||||
std::cout << "No book " << bookId << " in the library" << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void usage()
|
||||
@@ -58,7 +62,6 @@ void usage()
|
||||
cerr << "Usage:" << endl;
|
||||
cerr << "\tkiwix-manage LIBRARY_PATH add ZIM_PATH "
|
||||
"[--zimPathToSave=../content/foobar.zim] [--current] "
|
||||
"[--indexBackend=xapian] [--indexPath=FULLTEXT_IDX_PATH] "
|
||||
"[--url=http://...metalink]"
|
||||
<< endl;
|
||||
cerr << "\tkiwix-manage LIBRARY_PATH show [CONTENTID1] [CONTENTID2] ... "
|
||||
@@ -67,14 +70,188 @@ void usage()
|
||||
cerr << "\tkiwix-manage LIBRARY_PATH remove CONTENTID1 [CONTENTID2]" << endl;
|
||||
}
|
||||
|
||||
|
||||
bool handle_show(kiwix::Library* library, const std::string& libraryPath,
|
||||
int argc, char* argv[])
|
||||
{
|
||||
if (argc > 3 ) {
|
||||
for(auto i=3; i<argc; i++) {
|
||||
std::string bookId = argv[i];
|
||||
show(library, bookId);
|
||||
}
|
||||
} else {
|
||||
auto booksIds = library->getBooksIds();
|
||||
for(auto& bookId: booksIds) {
|
||||
show(library, bookId);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool handle_add(kiwix::Library* library, const std::string& libraryPath,
|
||||
int argc, char* argv[])
|
||||
{
|
||||
string zimPath;
|
||||
string zimPathToSave = ".";
|
||||
string url;
|
||||
string origID = "";
|
||||
int option_index = 0;
|
||||
int c = 0;
|
||||
bool resultCode = 0;
|
||||
|
||||
if (argc <= 3) {
|
||||
std::cerr << "Path to zim file to add is missing in the command line" << std::endl;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Options parsing */
|
||||
optind = 3;
|
||||
static struct option long_options[] = {
|
||||
{"url", required_argument, 0, 'u'},
|
||||
{"origId", required_argument, 0, 'o'},
|
||||
{"zimPathToSave", required_argument, 0, 'z'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
bool has_option = false;
|
||||
while (true) {
|
||||
c = getopt_long(argc, argv, "cz:u:", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
has_option = true;
|
||||
switch (c) {
|
||||
case 'u':
|
||||
url = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
origID = optarg;
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
zimPathToSave = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
std::cerr << "Path to zim file to add is missing in the command line" << std::endl;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (has_option && argc-optind > 1) {
|
||||
std::cerr << "You cannot give option and several zim files to add" << std::endl;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
kiwix::Manager manager(library);
|
||||
|
||||
for(auto i=optind; i<argc; i++) {
|
||||
std::string zimPath = argv[i];
|
||||
if (!zimPath.empty()) {
|
||||
zimPathToSave = zimPathToSave == "." ? zimPath : zimPathToSave;
|
||||
manager.addBookFromPathAndGetId(zimPath, zimPathToSave, url, false);
|
||||
} else {
|
||||
std::cerr << "Invalid zim file path" << std::endl;
|
||||
resultCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return(resultCode);
|
||||
}
|
||||
|
||||
bool handle_remove(kiwix::Library* library, const std::string& libraryPath,
|
||||
int argc, char* argv[])
|
||||
{
|
||||
std::string bookId;
|
||||
const unsigned int totalBookCount = library->getBookCount(true, true);
|
||||
bool exitCode = 0;
|
||||
|
||||
if (argc <= 3) {
|
||||
std::cerr << "BookId to remove missing in the command line" << std::endl;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (!totalBookCount) {
|
||||
std::cerr << "Library is empty, no book to delete."
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 3; i<argc; i++) {
|
||||
bookId = argv[i];
|
||||
|
||||
if (!library->removeBookById(bookId)) {
|
||||
std::cerr << "Invalid book id '" << bookId << "'." << std::endl;
|
||||
exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return(exitCode);
|
||||
}
|
||||
|
||||
bool handle_download(kiwix::Library* library, const std::string& libraryPath,
|
||||
int argc, char* argv[])
|
||||
{
|
||||
std::string bookId;
|
||||
bool exitCode = false;
|
||||
|
||||
if (argc > 3) {
|
||||
bookId = argv[3];
|
||||
}
|
||||
|
||||
auto& book = library->getBookById(bookId);
|
||||
auto did = book.getDownloadId();
|
||||
kiwix::Downloader downloader;
|
||||
kiwix::Download* download = nullptr;
|
||||
if (!did.empty()) {
|
||||
std::cout << "try resume " << did << std::endl;
|
||||
try {
|
||||
download = downloader.getDownload(did);
|
||||
} catch(...) {}
|
||||
}
|
||||
if (nullptr == download || download->getStatus() == kiwix::Download::K_UNKNOWN) {
|
||||
download = downloader.startDownload(book.getUrl());
|
||||
book.setDownloadId(download->getDid());
|
||||
}
|
||||
int step = 60*5;
|
||||
while (step--) {
|
||||
download->updateStatus();
|
||||
if (download->getStatus() == kiwix::Download::K_COMPLETE) {
|
||||
auto followingId = download->getFollowedBy();
|
||||
if (followingId.empty()) {
|
||||
book.setPath(download->getPath());
|
||||
book.setDownloadId("");
|
||||
std::cout << "File downloaded to " << book.getPath() << std::endl;
|
||||
break;
|
||||
} else {
|
||||
download = downloader.getDownload(followingId);
|
||||
}
|
||||
} else if (download->getStatus() == kiwix::Download::K_ACTIVE) {
|
||||
std::cout << download->getDid() << " : "
|
||||
<< kiwix::beautifyFileSize(download->getCompletedLength()) << "/"
|
||||
<< kiwix::beautifyFileSize(download->getTotalLength())
|
||||
<< " (" << kiwix::beautifyFileSize(download->getDownloadSpeed()) << "/s) "
|
||||
<< " [" << kiwix::beautifyFileSize(download->getVerifiedLength()) << "]"
|
||||
<< "[" << step << "] \n" << std::flush;
|
||||
} else if (download->getStatus() == kiwix::Download::K_ERROR) {
|
||||
std::cout << "File Error" << std::endl;
|
||||
exitCode = true;
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
downloader.close();
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
string libraryPath = "";
|
||||
supportedAction action = NONE;
|
||||
string zimPath = "";
|
||||
kiwix::Manager libraryManager;
|
||||
int option_index = 0;
|
||||
int c = 0;
|
||||
kiwix::Library library;
|
||||
|
||||
/* Argument parsing */
|
||||
if (argc > 2) {
|
||||
@@ -87,6 +264,8 @@ int main(int argc, char** argv)
|
||||
action = SHOW;
|
||||
else if (actionString == "remove" || actionString == "delete")
|
||||
action = REMOVE;
|
||||
else if (actionString == "download")
|
||||
action = DOWNLOAD;
|
||||
}
|
||||
|
||||
/* Print usage)) if necessary */
|
||||
@@ -99,121 +278,32 @@ int main(int argc, char** argv)
|
||||
libraryPath = isRelativePath(libraryPath)
|
||||
? computeAbsolutePath(getCurrentDirectory(), libraryPath)
|
||||
: libraryPath;
|
||||
libraryManager.readFile(libraryPath, false);
|
||||
kiwix::Manager manager(&library);
|
||||
manager.readFile(libraryPath, false);
|
||||
|
||||
/* SHOW */
|
||||
if (action == SHOW) {
|
||||
show(libraryManager.cloneLibrary());
|
||||
} 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;
|
||||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
bool exitCode = 0;
|
||||
switch (action) {
|
||||
case SHOW:
|
||||
exitCode = handle_show(&library, libraryPath, argc, argv);
|
||||
break;
|
||||
case ADD:
|
||||
exitCode = handle_add(&library, libraryPath, argc, argv);
|
||||
break;
|
||||
case REMOVE:
|
||||
exitCode = handle_remove(&library, libraryPath, argc, argv);
|
||||
break;
|
||||
case DOWNLOAD:
|
||||
exitCode = handle_download(&library, libraryPath, argc, argv);
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Rewrite the library file */
|
||||
if (action == REMOVE || action == ADD) {
|
||||
libraryManager.writeFile(libraryPath);
|
||||
if (action == REMOVE || action == ADD || action == DOWNLOAD) {
|
||||
library.writeToFile(libraryPath);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
exit(exitCode);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
subdir('installer')
|
||||
subdir('manager')
|
||||
subdir('reader')
|
||||
subdir('searcher')
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -27,8 +27,7 @@ void usage()
|
||||
{
|
||||
cout << "Usage: kiwix-search [OPTIONS] ZIM PATTERN" << endl << endl
|
||||
<< " kiwix-search allows to find articles based on the a fulltext search pattern." << endl << endl
|
||||
<< " ZIM is the full path of the ZIM file. This can also be a disctinct fulltext" << endl
|
||||
<< " index directory (usually distributed with the *.idx extension)." << endl
|
||||
<< " ZIM is the full path of the ZIM file." << endl
|
||||
<< " PATTERN is/are word(s) - or part of - to search in the ZIM." << endl << endl
|
||||
<< " -s, --suggestion\tSuggest article titles based on the few letters of the PATTERN instead of making a fulltext search. Work a bit like a completion solution." << endl
|
||||
<< " -v, --verbose\t\tGive details about the search process" << endl;
|
||||
@@ -102,12 +101,8 @@ int main(int argc, char** argv)
|
||||
searcher = new kiwix::Searcher();
|
||||
searcher->add_reader(reader, "");
|
||||
} else {
|
||||
try {
|
||||
searcher = new kiwix::Searcher(zimPath, NULL, "");
|
||||
} catch (...) {
|
||||
cerr << "Unable to search through zim '" << zimPath << "'." << endl;
|
||||
exit(1);
|
||||
}
|
||||
cerr << "Unable to search through zim '" << zimPath << "'." << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Start the indexing */
|
||||
|
||||
@@ -44,13 +44,14 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <getopt.h>
|
||||
#include <kiwix/common/otherTools.h>
|
||||
#include <kiwix/common/pathTools.h>
|
||||
#include <kiwix/common/regexTools.h>
|
||||
#include <kiwix/common/stringTools.h>
|
||||
#include <kiwix/tools/otherTools.h>
|
||||
#include <kiwix/tools/pathTools.h>
|
||||
#include <kiwix/tools/regexTools.h>
|
||||
#include <kiwix/tools/stringTools.h>
|
||||
#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>
|
||||
@@ -78,6 +79,7 @@ extern "C" {
|
||||
#include <netdb.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
@@ -91,22 +93,37 @@ using namespace std;
|
||||
|
||||
static bool noLibraryButtonFlag = false;
|
||||
static bool noSearchBarFlag = false;
|
||||
static bool noDateAliasesFlag = 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::Library library;
|
||||
static pthread_mutex_t searchLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t compressorLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t regexLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
std::pair<kiwix::Reader*, kiwix::Searcher*>
|
||||
get_from_humanReadableBookId(const std::string& humanReadableBookId) {
|
||||
kiwix::Searcher* searcher
|
||||
= searchers.find(humanReadableBookId) != searchers.end()
|
||||
? searchers.find(humanReadableBookId)->second
|
||||
: globalSearcher;
|
||||
kiwix::Reader* reader = readers.find(humanReadableBookId) != readers.end()
|
||||
? readers.find(humanReadableBookId)->second
|
||||
: NULL;
|
||||
return std::pair<kiwix::Reader*, kiwix::Searcher*>(reader, searcher);
|
||||
}
|
||||
|
||||
/* Try to get the mimeType from the file extension */
|
||||
static std::string getMimeTypeForFile(const std::string& filename)
|
||||
{
|
||||
std::string mimeType = "text/plain";
|
||||
unsigned int pos = filename.find_last_of(".");
|
||||
auto pos = filename.find_last_of(".");
|
||||
|
||||
if (pos != std::string::npos) {
|
||||
std::string extension = filename.substr(pos + 1);
|
||||
@@ -135,7 +152,10 @@ static bool startswith(const std::string& base, const std::string& start)
|
||||
|
||||
void introduceTaskbar(string& content, const string& humanReadableBookId)
|
||||
{
|
||||
string zimTitle;
|
||||
|
||||
pthread_mutex_lock(®exLock);
|
||||
|
||||
if (!noSearchBarFlag) {
|
||||
content = appendToFirstOccurence(
|
||||
content,
|
||||
@@ -157,10 +177,18 @@ void introduceTaskbar(string& content, const string& humanReadableBookId)
|
||||
RESOURCE::taskbar_html_part,
|
||||
humanReadableBookId,
|
||||
"__CONTENT__"));
|
||||
|
||||
auto reader = get_from_humanReadableBookId(humanReadableBookId).first;
|
||||
if (reader != nullptr) {
|
||||
zimTitle = reader->getTitle();
|
||||
}
|
||||
}
|
||||
content = replaceRegex(content, rootLocation, "__ROOT_LOCATION__");
|
||||
content = replaceRegex(content, replaceRegex(humanReadableBookId, "%26", "&"), "__CONTENT_ESCAPED__");
|
||||
}
|
||||
|
||||
content = replaceRegex(content, rootLocation, "__ROOT_LOCATION__");
|
||||
content = replaceRegex(content, replaceRegex(zimTitle, "%26", "&"), "__ZIM_TITLE__");
|
||||
content = replaceRegex(content, replaceRegex(humanReadableBookId, "%26", "&"), "__CONTENT_ESCAPED__");
|
||||
|
||||
pthread_mutex_unlock(®exLock);
|
||||
}
|
||||
|
||||
@@ -218,8 +246,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 +320,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,44 +340,44 @@ 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());
|
||||
|
||||
MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_LENGTH,
|
||||
std::to_string(range_len).c_str());
|
||||
kiwix::to_string(range_len).c_str());
|
||||
|
||||
/* Specify the mime type */
|
||||
MHD_add_response_header(
|
||||
@@ -370,16 +394,48 @@ static struct MHD_Response* build_callback_response_from_article(
|
||||
return response;
|
||||
}
|
||||
|
||||
std::pair<kiwix::Reader*, kiwix::Searcher*>
|
||||
get_from_humanReadableBookId(const std::string& humanReadableBookId) {
|
||||
kiwix::Searcher* searcher
|
||||
= searchers.find(humanReadableBookId) != searchers.end()
|
||||
? searchers.find(humanReadableBookId)->second
|
||||
: globalSearcher;
|
||||
kiwix::Reader* reader = readers.find(humanReadableBookId) != readers.end()
|
||||
? readers.find(humanReadableBookId)->second
|
||||
: NULL;
|
||||
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)
|
||||
@@ -400,7 +456,7 @@ static struct MHD_Response* handle_suggest(RequestContext* request)
|
||||
humanReadableBookId = request->get_argument("content");
|
||||
term = request->get_argument("term");
|
||||
} catch (const std::out_of_range&) {
|
||||
return build_homepage(request);
|
||||
return build_404(request, "");
|
||||
}
|
||||
|
||||
if (isVerbose.load()) {
|
||||
@@ -483,9 +539,9 @@ static struct MHD_Response* handle_search(RequestContext* request)
|
||||
|
||||
/* Retrive geo search */
|
||||
bool has_geo_query = false;
|
||||
float latitude;
|
||||
float longitude;
|
||||
float distance;
|
||||
float latitude = 0;
|
||||
float longitude = 0;
|
||||
float distance = 0;
|
||||
try {
|
||||
latitude = request->get_argument<float>("latitude");
|
||||
longitude = request->get_argument<float>("longitude");
|
||||
@@ -509,8 +565,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 */
|
||||
@@ -579,18 +641,108 @@ static struct MHD_Response* handle_random(RequestContext* request)
|
||||
try {
|
||||
humanReadableBookId = request->get_argument("content");
|
||||
} catch (const std::out_of_range&) {
|
||||
return build_homepage(request);
|
||||
return build_404(request, "");
|
||||
}
|
||||
|
||||
auto reader = get_from_humanReadableBookId(humanReadableBookId).first;
|
||||
if (reader == nullptr) {
|
||||
return build_homepage(request);
|
||||
return build_404(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");
|
||||
opdsDumper.setId(kiwix::to_string(uuid));
|
||||
opdsDumper.setLibrary(&library);
|
||||
mimeType = "application/atom+xml;profile=opds-catalog;kind=acquisition; charset=utf-8";
|
||||
std::vector<std::string> bookIdsToDump;
|
||||
if (url == "root.xml") {
|
||||
opdsDumper.setTitle("All zims");
|
||||
uuid = zim::Uuid::generate(host);
|
||||
|
||||
bookIdsToDump = library.listBooksIds(
|
||||
kiwix::VALID|kiwix::LOCAL|kiwix::REMOTE);
|
||||
} else if (url == "search") {
|
||||
std::string query;
|
||||
std::string language;
|
||||
std::vector<std::string> tags;
|
||||
size_t count(10);
|
||||
size_t startIndex(0);
|
||||
try {
|
||||
query = request->get_argument("q");
|
||||
} catch (const std::out_of_range&) {}
|
||||
try {
|
||||
language = request->get_argument("lang");
|
||||
} catch (const std::out_of_range&) {}
|
||||
try {
|
||||
count = stoul(request->get_argument("count"));
|
||||
} catch (...) {}
|
||||
try {
|
||||
startIndex = stoul(request->get_argument("start"));
|
||||
} catch (...) {}
|
||||
try {
|
||||
tags.push_back(request->get_argument("tag"));
|
||||
} catch (...) {}
|
||||
opdsDumper.setTitle("Search result for " + query);
|
||||
uuid = zim::Uuid::generate();
|
||||
bookIdsToDump = library.listBooksIds(
|
||||
kiwix::VALID|kiwix::LOCAL|kiwix::REMOTE,
|
||||
kiwix::UNSORTED,
|
||||
query,
|
||||
language,
|
||||
"", // creator
|
||||
"", // publisher
|
||||
tags);
|
||||
auto totalResults = bookIdsToDump.size();
|
||||
bookIdsToDump.erase(bookIdsToDump.begin(), bookIdsToDump.begin()+startIndex);
|
||||
if (count>0 && bookIdsToDump.size() > count) {
|
||||
bookIdsToDump.resize(count);
|
||||
}
|
||||
opdsDumper.setOpenSearchInfo(totalResults, startIndex, bookIdsToDump.size());
|
||||
} else {
|
||||
return build_404(request, "");
|
||||
}
|
||||
|
||||
content = opdsDumper.dumpOPDSFeed(bookIdsToDump);
|
||||
}
|
||||
|
||||
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 +755,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 {
|
||||
@@ -615,31 +766,31 @@ static struct MHD_Response* handle_content(RequestContext* request)
|
||||
|
||||
auto reader = get_from_humanReadableBookId(humanReadableBookId).first;
|
||||
if (reader == nullptr) {
|
||||
return build_homepage(request);
|
||||
if (humanReadableBookId.size() == 0){
|
||||
return build_homepage(request);
|
||||
} else {
|
||||
return build_404(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 (urlStr[0] == '/') {
|
||||
urlStr = urlStr.substr(1);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
try {
|
||||
entry = reader->getEntryFromPath(urlStr);
|
||||
if (entry.isRedirect() || urlStr.empty()) {
|
||||
// If urlStr is empty, we want to mainPage.
|
||||
// We must do a redirection to the real page.
|
||||
entry = entry.getFinalEntry();
|
||||
std::string httpRedirection = (
|
||||
rootLocation + "/" + humanReadableBookId + "/" +
|
||||
kiwix::urlEncode(entry.getPath()));
|
||||
request->httpResponseCode = MHD_HTTP_FOUND;
|
||||
return build_response("", 0, httpRedirection, "", false, false);
|
||||
}
|
||||
} catch(kiwix::NoEntry& e) {
|
||||
if (isVerbose.load())
|
||||
printf("Failed to find %s\n", urlStr.c_str());
|
||||
|
||||
@@ -647,7 +798,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 +811,12 @@ 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();
|
||||
pthread_mutex_lock(®exLock);
|
||||
content = replaceRegex(content,
|
||||
"$1$2" + rootLocation + "/" + humanReadableBookId + "/$3/",
|
||||
@@ -675,10 +824,6 @@ static struct MHD_Response* handle_content(RequestContext* request)
|
||||
content = replaceRegex(content,
|
||||
"$1$2" + rootLocation + "/" + humanReadableBookId + "/$3/",
|
||||
"(@import[ ]+)([\"|\']{0,1})/([A-Z|\\-])/");
|
||||
content = replaceRegex(
|
||||
content,
|
||||
"<head><base href=\"" + rootLocation + "/" + humanReadableBookId + baseUrl + "\" />",
|
||||
"<head>");
|
||||
pthread_mutex_unlock(®exLock);
|
||||
introduceTaskbar(content, humanReadableBookId);
|
||||
} else if (mimeType.find("text/css") != string::npos) {
|
||||
@@ -696,12 +841,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);
|
||||
@@ -746,10 +891,14 @@ static int accessHandlerCallback(void* cls,
|
||||
request.httpResponseCode = request.has_range() ? MHD_HTTP_PARTIAL_CONTENT : MHD_HTTP_OK;
|
||||
|
||||
if (! request.is_valid_url()) {
|
||||
response = build_homepage(&request);
|
||||
response = build_404(&request, "");
|
||||
} 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") {
|
||||
@@ -775,29 +924,40 @@ static int accessHandlerCallback(void* cls,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool hasHumanReadableIdCollision(const string &humanReadableId,
|
||||
const string &zimPath)
|
||||
{
|
||||
if (readers.find(humanReadableId) != readers.end()) {
|
||||
cerr << "Path collision: " << readers[humanReadableId]->getZimFilePath()
|
||||
<< " and " << zimPath << " can't share the same URL path /"
|
||||
<< humanReadableId << "/. Therefore, only "
|
||||
<< zimPath << " will be served." << endl;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
struct MHD_Daemon* daemon;
|
||||
vector<string> zimPathes;
|
||||
string libraryPath;
|
||||
string indexPath;
|
||||
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'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"library", no_argument, 0, 'l'},
|
||||
{"nolibrarybutton", no_argument, 0, 'm'},
|
||||
{"nodatealiases", no_argument, 0, 'z'},
|
||||
{"nosearchbar", no_argument, 0, 'n'},
|
||||
{"index", required_argument, 0, 'i'},
|
||||
{"attachToProcess", required_argument, 0, 'a'},
|
||||
{"port", required_argument, 0, 'p'},
|
||||
{"interface", required_argument, 0, 'f'},
|
||||
@@ -809,7 +969,7 @@ int main(int argc, char** argv)
|
||||
while (true) {
|
||||
int option_index = 0;
|
||||
int c
|
||||
= getopt_long(argc, argv, "mndvli:a:p:f:t:r:", long_options, &option_index);
|
||||
= getopt_long(argc, argv, "mndvla:p:f:t:r:", long_options, &option_index);
|
||||
|
||||
if (c != -1) {
|
||||
switch (c) {
|
||||
@@ -825,12 +985,12 @@ int main(int argc, char** argv)
|
||||
case 'n':
|
||||
noSearchBarFlag = true;
|
||||
break;
|
||||
case 'z':
|
||||
noDateAliasesFlag = true;
|
||||
break;
|
||||
case 'm':
|
||||
noLibraryButtonFlag = true;
|
||||
break;
|
||||
case 'i':
|
||||
indexPath = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
serverPort = atoi(optarg);
|
||||
break;
|
||||
@@ -860,28 +1020,28 @@ int main(int argc, char** argv)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (optind <= argc) {
|
||||
if (optind < argc) {
|
||||
if (libraryFlag) {
|
||||
libraryPath = argv[optind++];
|
||||
} else {
|
||||
while (optind < argc)
|
||||
zimPathes.push_back(std::string(argv[optind++]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print usage)) if necessary */
|
||||
if (zimPathes.empty() && libraryPath.empty()) {
|
||||
cerr << "Usage: kiwix-serve [--index=INDEX_PATH] [--port=PORT] [--verbose] "
|
||||
"[--nosearchbar] [--nolibrarybutton] [--daemon] "
|
||||
"[--nosearchbar] [--nolibrarybutton] [--nodatealiases] [--daemon] "
|
||||
"[--attachToProcess=PID] [--interface=IF_NAME] "
|
||||
"[--urlRootLocation=/URL_ROOT] "
|
||||
"[--threads=NB_THREAD(" << nb_threads << ")] ZIM_PATH+"
|
||||
<< endl;
|
||||
cerr << " kiwix-serve --library [--port=PORT] [--verbose] [--daemon] "
|
||||
"[--nosearchbar] [--nolibrarybutton] [--attachToProcess=PID] "
|
||||
"[--nosearchbar] [--nolibrarybutton] [--nodatealiases] [--attachToProcess=PID] "
|
||||
"[--interface=IF_NAME] [--urlRootLocation=/URL_ROOT] "
|
||||
"[--threads=NB_THREAD(" << nb_threads << ")] LIBRARY_PATH "
|
||||
<< endl;
|
||||
@@ -891,12 +1051,8 @@ int main(int argc, char** argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((zimPathes.size() > 1) && !indexPath.empty()) {
|
||||
cerr << "You cannot set a indexPath if you also set several zimPathes";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Setup the library manager and get the list of books */
|
||||
kiwix::Manager manager(&library);
|
||||
if (libraryFlag) {
|
||||
vector<string> libraryPaths = kiwix::split(libraryPath, ";");
|
||||
vector<string>::iterator itr;
|
||||
@@ -910,7 +1066,7 @@ int main(int argc, char** argv)
|
||||
= isRelativePath(*itr)
|
||||
? computeAbsolutePath(getCurrentDirectory(), *itr)
|
||||
: *itr;
|
||||
retVal = libraryManager.readFile(libraryPath, true);
|
||||
retVal = manager.readFile(libraryPath, true);
|
||||
} catch (...) {
|
||||
retVal = false;
|
||||
}
|
||||
@@ -924,74 +1080,60 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
/* Check if the library is not empty (or only remote books)*/
|
||||
if (libraryManager.getBookCount(true, false) == 0) {
|
||||
if (library.getBookCount(true, false) == 0) {
|
||||
cerr << "The XML library file '" << libraryPath
|
||||
<< "' is empty (or has only remote books)." << endl;
|
||||
}
|
||||
} else {
|
||||
std::vector<std::string>::iterator it;
|
||||
for (it = zimPathes.begin(); it != zimPathes.end(); it++) {
|
||||
if (!libraryManager.addBookFromPath(*it, *it, "", false)) {
|
||||
if (!manager.addBookFromPath(*it, *it, "", false)) {
|
||||
cerr << "Unable to add the ZIM file '" << *it
|
||||
<< "' to the internal library." << endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (!indexPath.empty()) {
|
||||
libraryManager.setBookIndex(libraryManager.getBooksIds()[0], indexPath);
|
||||
}
|
||||
}
|
||||
|
||||
/* Instance the readers and searcher and build the corresponding maps */
|
||||
vector<string> booksIds = libraryManager.getBooksIds();
|
||||
vector<string>::iterator itr;
|
||||
kiwix::Book currentBook;
|
||||
vector<string> booksIds = library.listBooksIds(kiwix::LOCAL);
|
||||
globalSearcher = new kiwix::Searcher();
|
||||
globalSearcher->setProtocolPrefix(rootLocation + "/");
|
||||
globalSearcher->setSearchProtocolPrefix(rootLocation + "/" + "search?");
|
||||
for (itr = booksIds.begin(); itr != booksIds.end(); ++itr) {
|
||||
bool zimFileOk = false;
|
||||
libraryManager.getBookById(*itr, currentBook);
|
||||
std::string zimPath = currentBook.pathAbsolute;
|
||||
for (auto& bookId: booksIds) {
|
||||
auto& currentBook = library.getBookById(bookId);
|
||||
auto zimPath = currentBook.getPath();
|
||||
|
||||
if (!zimPath.empty()) {
|
||||
indexPath = currentBook.indexPathAbsolute;
|
||||
/* Instanciate the ZIM file handler */
|
||||
kiwix::Reader* reader = NULL;
|
||||
try {
|
||||
reader = new kiwix::Reader(zimPath);
|
||||
} catch (...) {
|
||||
cerr << "Unable to open the ZIM file '" << zimPath << "'." << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Instanciate the ZIM file handler */
|
||||
kiwix::Reader* reader = NULL;
|
||||
try {
|
||||
reader = new kiwix::Reader(zimPath);
|
||||
zimFileOk = true;
|
||||
} catch (...) {
|
||||
cerr << "Unable to open the ZIM file '" << zimPath << "'." << endl;
|
||||
}
|
||||
auto humanReadableId = currentBook.getHumanReadableIdFromPath();
|
||||
hasHumanReadableIdCollision(humanReadableId, currentBook.getPath());
|
||||
readers[humanReadableId] = reader;
|
||||
|
||||
if (zimFileOk) {
|
||||
string humanReadableId = currentBook.getHumanReadableIdFromPath();
|
||||
readers[humanReadableId] = reader;
|
||||
if (reader->hasFulltextIndex()) {
|
||||
kiwix::Searcher* searcher = new kiwix::Searcher(humanReadableId);
|
||||
searcher->setProtocolPrefix(rootLocation + "/");
|
||||
searcher->setSearchProtocolPrefix(rootLocation + "/" + "search?");
|
||||
searcher->add_reader(reader, humanReadableId);
|
||||
globalSearcher->add_reader(reader, humanReadableId);
|
||||
searchers[humanReadableId] = searcher;
|
||||
} else {
|
||||
searchers[humanReadableId] = nullptr;
|
||||
}
|
||||
|
||||
if ( reader->hasFulltextIndex()) {
|
||||
kiwix::Searcher* searcher = new kiwix::Searcher(humanReadableId);
|
||||
searcher->setProtocolPrefix(rootLocation + "/");
|
||||
searcher->setSearchProtocolPrefix(rootLocation + "/" + "search?");
|
||||
searcher->add_reader(reader, humanReadableId);
|
||||
globalSearcher->add_reader(reader, humanReadableId);
|
||||
searchers[humanReadableId] = searcher;
|
||||
} else if ( !indexPath.empty() ) {
|
||||
try {
|
||||
kiwix::Searcher* searcher = new kiwix::Searcher(indexPath, reader, humanReadableId);
|
||||
searcher->setProtocolPrefix(rootLocation + "/");
|
||||
searcher->setSearchProtocolPrefix(rootLocation + "/" + "search?");
|
||||
searchers[humanReadableId] = searcher;
|
||||
} catch (...) {
|
||||
cerr << "Unable to open the search index '" << indexPath << "'."
|
||||
<< endl;
|
||||
searchers[humanReadableId] = nullptr;
|
||||
}
|
||||
} else {
|
||||
searchers[humanReadableId] = nullptr;
|
||||
}
|
||||
}
|
||||
/* Deal with noDateAliases */
|
||||
if (noDateAliasesFlag) {
|
||||
string alias = replaceRegex(humanReadableId, "", "_[[:digit:]]{4}-[[:digit:]]{2}$");
|
||||
hasHumanReadableIdCollision(alias, currentBook.getPath());
|
||||
readers[alias] = readers[humanReadableId];
|
||||
searchers[alias] = searchers[humanReadableId];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,24 +1141,25 @@ int main(int argc, char** argv)
|
||||
string welcomeBooksHtml
|
||||
= ""
|
||||
"<div class='book__list'>";
|
||||
for (itr = booksIds.begin(); itr != booksIds.end(); ++itr) {
|
||||
libraryManager.getBookById(*itr, currentBook);
|
||||
for (auto& bookId: booksIds) {
|
||||
auto& currentBook = library.getBookById(bookId);
|
||||
|
||||
if (!currentBook.path.empty()
|
||||
if (!currentBook.getPath().empty()
|
||||
&& readers.find(currentBook.getHumanReadableIdFromPath())
|
||||
!= readers.end()) {
|
||||
welcomeBooksHtml += ""
|
||||
"<a href='" + rootLocation + "/" + currentBook.getHumanReadableIdFromPath() + "/'>"
|
||||
"<div class='book'>"
|
||||
"<div class='book__background' style='background-image: url(data:" + currentBook.faviconMimeType+ ";base64," + currentBook.favicon + ");'>"
|
||||
"<div class='book__title' title='" + currentBook.title + "'>" + currentBook.title + "</div>"
|
||||
"<div class='book__description' title='" + currentBook.description + "'>" + currentBook.description + "</div>"
|
||||
"<div class='book__background' style=\"background-image: url('/meta?content="
|
||||
+ currentBook.getHumanReadableIdFromPath() + "&name=favicon');\">"
|
||||
"<div class='book__title' title='" + currentBook.getTitle() + "'>" + currentBook.getTitle() + "</div>"
|
||||
"<div class='book__description' title='" + currentBook.getDescription() + "'>" + currentBook.getDescription() + "</div>"
|
||||
"<div class='book__info'>"
|
||||
"" + kiwix::beautifyInteger(atoi(currentBook.articleCount.c_str())) + " articles, " + kiwix::beautifyInteger(atoi(currentBook.mediaCount.c_str())) + " medias"
|
||||
"" + kiwix::beautifyInteger(currentBook.getArticleCount()) + " articles, " + kiwix::beautifyInteger(currentBook.getMediaCount()) + " medias"
|
||||
"</div>"
|
||||
"</div>"
|
||||
"</div>"
|
||||
"</a>";
|
||||
"</a>\n";
|
||||
}
|
||||
}
|
||||
welcomeBooksHtml += ""
|
||||
@@ -1029,6 +1172,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) {
|
||||
@@ -1137,7 +1285,7 @@ int main(int argc, char** argv)
|
||||
#endif
|
||||
|
||||
} else {
|
||||
daemon = MHD_start_daemon(MHD_USE_POLL_INTERNALLY,
|
||||
daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY,
|
||||
serverPort,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
#include <string.h>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
|
||||
RequestContext::RequestContext(struct MHD_Connection* connection,
|
||||
std::string rootLocation,
|
||||
const std::string& _url,
|
||||
const std::string& method,
|
||||
const std::string& version) :
|
||||
connection(connection),
|
||||
full_url(_url),
|
||||
url(_url),
|
||||
valid_url(true),
|
||||
@@ -196,16 +196,6 @@ std::string RequestContext::get_argument(const std::string& name) {
|
||||
return arguments.at(name);
|
||||
}
|
||||
|
||||
template<>
|
||||
unsigned int RequestContext::get_argument(const std::string& name) {
|
||||
return std::stoi(arguments.at(name).c_str());
|
||||
}
|
||||
|
||||
template<>
|
||||
float RequestContext::get_argument(const std::string& name) {
|
||||
return std::stof(arguments.at(name).c_str());
|
||||
}
|
||||
|
||||
std::string RequestContext::get_header(const std::string& name) {
|
||||
return headers.at(name);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define REQUEST_CONTEXT_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -62,7 +63,13 @@ class RequestContext {
|
||||
|
||||
std::string get_header(const std::string& name);
|
||||
template<typename T=std::string>
|
||||
T get_argument(const std::string& name);
|
||||
T get_argument(const std::string& name) {
|
||||
std::istringstream stream(arguments.at(name));
|
||||
T v;
|
||||
stream >> v;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
RequestMethod get_method();
|
||||
std::string get_url();
|
||||
@@ -78,7 +85,6 @@ class RequestContext {
|
||||
int httpResponseCode;
|
||||
|
||||
private:
|
||||
struct MHD_Connection* connection;
|
||||
std::string full_url;
|
||||
std::string url;
|
||||
bool valid_url;
|
||||
@@ -96,5 +102,7 @@ class RequestContext {
|
||||
static int fill_argument(void *, enum MHD_ValueKind, const char*, const char*);
|
||||
};
|
||||
|
||||
template<> std::string RequestContext::get_argument(const std::string& name);
|
||||
|
||||
|
||||
#endif //REQUEST_CONTEXT_H
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="kiwix_searchform">
|
||||
<form class="kiwixsearch" method="GET" action="__ROOT_LOCATION__/search" id="kiwixsearchform">
|
||||
<input autocomplete="off" class="ui-autocomplete-input" id="kiwixsearchbox" name="pattern" type="text">
|
||||
<input type="submit" value="Search">
|
||||
<input type="submit" value="🔍">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
9
static/server/opensearchdescription.xml
Normal file
9
static/server/opensearchdescription.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?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"
|
||||
indexOffset="0"
|
||||
template="/__ROOT_LOCATION__/catalog/search?q={searchTerms}&lang={language}&count={count}&start={startIndex}"/>
|
||||
</OpenSearchDescription>
|
||||
@@ -22,3 +22,4 @@ include.html.part
|
||||
taskbar.css
|
||||
taskbar.html.part
|
||||
global_taskbar.html.part
|
||||
opensearchdescription.xml
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
<span id="kiwixtoolbar" class="ui-widget-header">
|
||||
<div class="kiwix_centered">
|
||||
<div class="kiwix_button_wrapper">
|
||||
<a id="kiwix_serve_taskbar_library_button" href="__ROOT_LOCATION__/"><button>Library</button></a>
|
||||
<a id="kiwix_serve_taskbar_home_button" href="__ROOT_LOCATION__/__CONTENT__/"><button>Home</button></a>
|
||||
<a id="kiwix_serve_taskbar_random_button" href="__ROOT_LOCATION__/random?content=__CONTENT_ESCAPED__"><button>Random</button></a>
|
||||
<a id="kiwix_serve_taskbar_library_button" href="__ROOT_LOCATION__/"><button>🏠</button></a>
|
||||
<a id="kiwix_serve_taskbar_home_button" href="__ROOT_LOCATION__/__CONTENT__/"><button>__ZIM_TITLE__</button></a>
|
||||
<a id="kiwix_serve_taskbar_random_button" href="__ROOT_LOCATION__/random?content=__CONTENT_ESCAPED__"><button>🎲</button></a>
|
||||
</div>
|
||||
<div class="kiwix_searchform">
|
||||
<form class="kiwixsearch" method="GET" action="__ROOT_LOCATION__/search" id="kiwixsearchform">
|
||||
<input type="hidden" name="content" value="__CONTENT__" />
|
||||
<input autocomplete="off" class="ui-autocomplete-input" id="kiwixsearchbox" name="pattern" type="text">
|
||||
<input type="submit" value="Search">
|
||||
<input type="submit" value="🔍">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,6 @@ esac
|
||||
cd ${TRAVIS_BUILD_DIR}
|
||||
export PKG_CONFIG_PATH=${INSTALL_DIR}/lib/x86_64-linux-gnu/pkgconfig
|
||||
export PATH=${INSTALL_DIR}/bin:$PATH
|
||||
meson . build -Dctpp2-install-prefix=${INSTALL_DIR} ${MESON_OPTION}
|
||||
meson . build ${MESON_OPTION}
|
||||
cd build
|
||||
ninja
|
||||
|
||||
@@ -3,33 +3,36 @@
|
||||
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.xz
|
||||
|
||||
# Packages.
|
||||
case ${PLATFORM} in
|
||||
"native_static")
|
||||
PACKAGES="gcc cmake libbz2-dev ccache zlib1g-dev uuid-dev libctpp2-dev"
|
||||
PACKAGES="gcc python3.5 cmake libbz2-dev ccache zlib1g-dev uuid-dev"
|
||||
;;
|
||||
"native_dyn")
|
||||
PACKAGES="gcc cmake libbz2-dev ccache zlib1g-dev uuid-dev libctpp2-dev libmicrohttpd-dev"
|
||||
PACKAGES="gcc python3.5 cmake libbz2-dev ccache zlib1g-dev uuid-dev libmicrohttpd-dev"
|
||||
;;
|
||||
"win32_static")
|
||||
PACKAGES="g++-mingw-w64-i686 gcc-mingw-w64-i686 gcc-mingw-w64-base mingw-w64-tools ccache"
|
||||
PACKAGES="g++-mingw-w64-i686 gcc-mingw-w64-i686 gcc-mingw-w64-base mingw-w64-tools ccache python3.5"
|
||||
;;
|
||||
"win32_dyn")
|
||||
PACKAGES="g++-mingw-w64-i686 gcc-mingw-w64-i686 gcc-mingw-w64-base mingw-w64-tools ccache"
|
||||
PACKAGES="g++-mingw-w64-i686 gcc-mingw-w64-i686 gcc-mingw-w64-base mingw-w64-tools ccache python3.5"
|
||||
;;
|
||||
"android_arm")
|
||||
PACKAGES="gcc cmake ccache"
|
||||
PACKAGES="gcc python3.5 cmake ccache"
|
||||
;;
|
||||
"android_arm64")
|
||||
PACKAGES="gcc cmake ccache"
|
||||
PACKAGES="gcc python3.5 cmake ccache"
|
||||
;;
|
||||
esac
|
||||
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qq python3-pip ${PACKAGES}
|
||||
sudo pip3 install meson==0.43.0
|
||||
wget https://bootstrap.pypa.io/get-pip.py
|
||||
python3.5 get-pip.py --user
|
||||
python3.5 -m pip install --user --upgrade pip
|
||||
python3.5 -m pip install --user meson==0.49.2
|
||||
|
||||
# Ninja
|
||||
cd $HOME
|
||||
@@ -42,6 +45,4 @@ sudo cp ninja /bin
|
||||
# Dependencies comming from kiwix-build.
|
||||
cd ${HOME}
|
||||
wget http://tmp.kiwix.org/ci/${ARCHIVE_NAME}
|
||||
mkdir -p BUILD_${PLATFORM}
|
||||
cd BUILD_${PLATFORM}
|
||||
tar xf ${HOME}/${ARCHIVE_NAME}
|
||||
|
||||
Reference in New Issue
Block a user