mirror of
https://github.com/simon987/sist2.git
synced 2025-12-13 15:29:04 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4da28249e | |||
| 483a454c8d | |||
| 018ac86640 | |||
| 398f1aead4 | |||
| d19a75926b | |||
| 1ac8b40e3d | |||
| a8505cb8c1 |
@@ -26,6 +26,7 @@ add_executable(
|
|||||||
src/parsing/arc.c src/parsing/arc.h
|
src/parsing/arc.c src/parsing/arc.h
|
||||||
src/parsing/doc.c src/parsing/doc.h
|
src/parsing/doc.c src/parsing/doc.h
|
||||||
src/log.c src/log.h
|
src/log.c src/log.h
|
||||||
|
src/parsing/cbr.h src/parsing/cbr.c
|
||||||
|
|
||||||
# argparse
|
# argparse
|
||||||
argparse/argparse.h argparse/argparse.c
|
argparse/argparse.h argparse/argparse.c
|
||||||
@@ -136,6 +137,8 @@ TARGET_LINK_LIBRARIES(
|
|||||||
${PROJECT_SOURCE_DIR}/lib/libcrypto.a
|
${PROJECT_SOURCE_DIR}/lib/libcrypto.a
|
||||||
${PROJECT_SOURCE_DIR}/lib/libssl.a
|
${PROJECT_SOURCE_DIR}/lib/libssl.a
|
||||||
dl
|
dl
|
||||||
|
|
||||||
|
pcre
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_target(
|
add_custom_target(
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ docker stop sist2
|
|||||||
|
|
||||||
File type | Library | Content | Thumbnail | Metadata
|
File type | Library | Content | Thumbnail | Metadata
|
||||||
:---|:---|:---|:---|:---
|
:---|:---|:---|:---|:---
|
||||||
pdf,xps,cbz,fb2,epub | MuPDF | text+ocr | yes, `png` | title |
|
pdf,xps,cbz,cbr,fb2,epub | MuPDF | text+ocr | yes, `png` | title |
|
||||||
`audio/*` | ffmpeg | - | yes, `jpeg` | ID3 tags |
|
`audio/*` | ffmpeg | - | yes, `jpeg` | ID3 tags |
|
||||||
`video/*` | ffmpeg | - | yes, `jpeg` | title, comment, artist |
|
`video/*` | ffmpeg | - | yes, `jpeg` | title, comment, artist |
|
||||||
`image/*` | ffmpeg | - | yes, `jpeg` | [Common EXIF tags](https://github.com/simon987/sist2/blob/efdde2734eca9b14a54f84568863b7ffd59bdba3/src/parsing/media.c#L190) |
|
`image/*` | ffmpeg | - | yes, `jpeg` | [Common EXIF tags](https://github.com/simon987/sist2/blob/efdde2734eca9b14a54f84568863b7ffd59bdba3/src/parsing/media.c#L190) |
|
||||||
@@ -120,7 +120,7 @@ To check if a media file can be parsed without *seek*, execute `cat file.mp4 | f
|
|||||||
|
|
||||||
### OCR
|
### OCR
|
||||||
|
|
||||||
You can enable OCR support for pdf,xps,cbz,fb2,epub file types with the
|
You can enable OCR support for pdf,xps,cbz,cbr,fb2,epub file types with the
|
||||||
`--ocr <lang>` option. Download the language data files with your
|
`--ocr <lang>` option. Download the language data files with your
|
||||||
package manager (`apt install tesseract-ocr-eng`) or directly [from Github](https://github.com/tesseract-ocr/tesseract/wiki/Data-Files).
|
package manager (`apt install tesseract-ocr-eng`) or directly [from Github](https://github.com/tesseract-ocr/tesseract/wiki/Data-Files).
|
||||||
|
|
||||||
|
|||||||
22
src/cli.c
22
src/cli.c
@@ -162,6 +162,26 @@ int scan_args_validate(scan_args_t *args, int argc, const char **argv) {
|
|||||||
args->tesseract_path = path;
|
args->tesseract_path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args->exclude_regex != NULL) {
|
||||||
|
const char *error;
|
||||||
|
int error_offset;
|
||||||
|
|
||||||
|
pcre *re = pcre_compile(args->exclude_regex, 0, &error, &error_offset, 0);
|
||||||
|
if (error != NULL) {
|
||||||
|
LOG_FATALF("cli.c", "pcre_compile returned error: %s (offset:%d)", error, error_offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
pcre_extra *re_extra = pcre_study(re, 0, &error);
|
||||||
|
if (error != NULL) {
|
||||||
|
LOG_FATALF("cli.c", "pcre_study returned error: %s", error)
|
||||||
|
}
|
||||||
|
|
||||||
|
ScanCtx.exclude = re;
|
||||||
|
ScanCtx.exclude_extra = re_extra;
|
||||||
|
} else {
|
||||||
|
ScanCtx.exclude = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUGF("cli.c", "arg quality=%f", args->quality)
|
LOG_DEBUGF("cli.c", "arg quality=%f", args->quality)
|
||||||
LOG_DEBUGF("cli.c", "arg size=%d", args->size)
|
LOG_DEBUGF("cli.c", "arg size=%d", args->size)
|
||||||
LOG_DEBUGF("cli.c", "arg content_size=%d", args->content_size)
|
LOG_DEBUGF("cli.c", "arg content_size=%d", args->content_size)
|
||||||
@@ -175,6 +195,8 @@ int scan_args_validate(scan_args_t *args, int argc, const char **argv) {
|
|||||||
LOG_DEBUGF("cli.c", "arg archive=%s", args->archive)
|
LOG_DEBUGF("cli.c", "arg archive=%s", args->archive)
|
||||||
LOG_DEBUGF("cli.c", "arg tesseract_lang=%s", args->tesseract_lang)
|
LOG_DEBUGF("cli.c", "arg tesseract_lang=%s", args->tesseract_lang)
|
||||||
LOG_DEBUGF("cli.c", "arg tesseract_path=%s", args->tesseract_path)
|
LOG_DEBUGF("cli.c", "arg tesseract_path=%s", args->tesseract_path)
|
||||||
|
LOG_DEBUGF("cli.c", "arg exclude=%s", args->exclude_regex)
|
||||||
|
LOG_DEBUGF("cli.c", "arg fast=%d", args->fast)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,14 @@ typedef struct scan_args {
|
|||||||
archive_mode_t archive_mode;
|
archive_mode_t archive_mode;
|
||||||
char *tesseract_lang;
|
char *tesseract_lang;
|
||||||
const char *tesseract_path;
|
const char *tesseract_path;
|
||||||
|
char *exclude_regex;
|
||||||
|
int fast;
|
||||||
} scan_args_t;
|
} scan_args_t;
|
||||||
|
|
||||||
scan_args_t *scan_args_create();
|
scan_args_t *scan_args_create();
|
||||||
|
|
||||||
void scan_args_destroy(scan_args_t *args);
|
void scan_args_destroy(scan_args_t *args);
|
||||||
|
|
||||||
int scan_args_validate(scan_args_t *args, int argc, const char **argv);
|
int scan_args_validate(scan_args_t *args, int argc, const char **argv);
|
||||||
|
|
||||||
typedef struct index_args {
|
typedef struct index_args {
|
||||||
@@ -45,12 +49,15 @@ typedef struct web_args {
|
|||||||
} web_args_t;
|
} web_args_t;
|
||||||
|
|
||||||
index_args_t *index_args_create();
|
index_args_t *index_args_create();
|
||||||
|
|
||||||
void index_args_destroy(index_args_t *args);
|
void index_args_destroy(index_args_t *args);
|
||||||
|
|
||||||
web_args_t *web_args_create();
|
web_args_t *web_args_create();
|
||||||
|
|
||||||
void web_args_destroy(web_args_t *args);
|
void web_args_destroy(web_args_t *args);
|
||||||
|
|
||||||
int index_args_validate(index_args_t *args, int argc, const char **argv);
|
int index_args_validate(index_args_t *args, int argc, const char **argv);
|
||||||
|
|
||||||
int web_args_validate(web_args_t *args, int argc, const char **argv);
|
int web_args_validate(web_args_t *args, int argc, const char **argv);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ struct {
|
|||||||
pthread_mutex_t mupdf_mu;
|
pthread_mutex_t mupdf_mu;
|
||||||
char * tesseract_lang;
|
char * tesseract_lang;
|
||||||
const char * tesseract_path;
|
const char * tesseract_path;
|
||||||
|
pcre *exclude;
|
||||||
|
pcre_extra *exclude_extra;
|
||||||
|
int fast;
|
||||||
} ScanCtx;
|
} ScanCtx;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ typedef struct es_indexer {
|
|||||||
|
|
||||||
static es_indexer_t *Indexer;
|
static es_indexer_t *Indexer;
|
||||||
|
|
||||||
|
void delete_queue(int max);
|
||||||
|
|
||||||
void print_json(cJSON *document, const char uuid_str[UUID_STR_LEN]) {
|
void print_json(cJSON *document, const char uuid_str[UUID_STR_LEN]) {
|
||||||
|
|
||||||
cJSON *line = cJSON_CreateObject();
|
cJSON *line = cJSON_CreateObject();
|
||||||
@@ -64,7 +66,7 @@ void execute_update_script(const char *script, const char index_id[UUID_STR_LEN]
|
|||||||
cJSON *term_obj = cJSON_AddObjectToObject(query, "term");
|
cJSON *term_obj = cJSON_AddObjectToObject(query, "term");
|
||||||
cJSON_AddStringToObject(term_obj, "index", index_id);
|
cJSON_AddStringToObject(term_obj, "index", index_id);
|
||||||
|
|
||||||
char * str = cJSON_Print(body);
|
char *str = cJSON_Print(body);
|
||||||
|
|
||||||
char bulk_url[4096];
|
char bulk_url[4096];
|
||||||
snprintf(bulk_url, 4096, "%s/sist2/_update_by_query?pretty", Indexer->es_url);
|
snprintf(bulk_url, 4096, "%s/sist2/_update_by_query?pretty", Indexer->es_url);
|
||||||
@@ -87,24 +89,18 @@ void execute_update_script(const char *script, const char index_id[UUID_STR_LEN]
|
|||||||
cJSON_Delete(resp);
|
cJSON_Delete(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void elastic_flush() {
|
void *create_bulk_buffer(int max, int *count, size_t *buf_len) {
|
||||||
|
|
||||||
if (Indexer == NULL) {
|
|
||||||
Indexer = create_indexer(IndexCtx.es_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
es_bulk_line_t *line = Indexer->line_head;
|
es_bulk_line_t *line = Indexer->line_head;
|
||||||
|
*count = 0;
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
size_t buf_size = 0;
|
size_t buf_size = 0;
|
||||||
size_t buf_cur = 0;
|
size_t buf_cur = 0;
|
||||||
char *buf = malloc(1);
|
char *buf = malloc(1);
|
||||||
|
|
||||||
while (line != NULL) {
|
while (line != NULL && *count < max) {
|
||||||
char action_str[512];
|
char action_str[512];
|
||||||
snprintf(action_str, 512,
|
snprintf(action_str, 512,
|
||||||
"{\"index\":{\"_id\":\"%s\", \"_type\":\"_doc\", \"_index\":\"sist2\"}}\n", line->uuid_str);
|
"{\"index\":{\"_id\":\"%s\", \"_type\":\"_doc\", \"_index\":\"sist2\"}}\n", line->uuid_str);
|
||||||
size_t action_str_len = strlen(action_str);
|
size_t action_str_len = strlen(action_str);
|
||||||
|
|
||||||
size_t line_len = strlen(line->line);
|
size_t line_len = strlen(line->line);
|
||||||
@@ -116,17 +112,20 @@ void elastic_flush() {
|
|||||||
memcpy(buf + buf_cur, line->line, line_len);
|
memcpy(buf + buf_cur, line->line, line_len);
|
||||||
buf_cur += line_len;
|
buf_cur += line_len;
|
||||||
|
|
||||||
es_bulk_line_t *tmp = line;
|
|
||||||
line = line->next;
|
line = line->next;
|
||||||
free(tmp);
|
(*count)++;
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
buf = realloc(buf, buf_size + 1);
|
buf = realloc(buf, buf_size + 1);
|
||||||
*(buf+buf_cur) = '\0';
|
*(buf + buf_cur) = '\0';
|
||||||
|
|
||||||
Indexer->line_head = NULL;
|
*buf_len = buf_cur;
|
||||||
Indexer->line_tail = NULL;
|
return buf;
|
||||||
Indexer->queued = 0;
|
}
|
||||||
|
|
||||||
|
void _elastic_flush(int max) {
|
||||||
|
size_t buf_len;
|
||||||
|
int count;
|
||||||
|
void *buf = create_bulk_buffer(max, &count, &buf_len);
|
||||||
|
|
||||||
char bulk_url[4096];
|
char bulk_url[4096];
|
||||||
snprintf(bulk_url, 4096, "%s/sist2/_bulk?pipeline=tie", Indexer->es_url);
|
snprintf(bulk_url, 4096, "%s/sist2/_bulk?pipeline=tie", Indexer->es_url);
|
||||||
@@ -136,15 +135,33 @@ void elastic_flush() {
|
|||||||
LOG_FATALF("elastic.c", "Could not connect to %s, make sure that elasticsearch is running!\n", IndexCtx.es_url)
|
LOG_FATALF("elastic.c", "Could not connect to %s, make sure that elasticsearch is running!\n", IndexCtx.es_url)
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("elastic.c", "Indexed %d documents (%zukB) <%d>", count, buf_cur / 1024, r->status_code);
|
if (r->status_code == 413) {
|
||||||
|
|
||||||
if (r->status_code != 200 && r->status_code != 413) {
|
if (max <= 1) {
|
||||||
|
LOG_ERRORF("elastic.c", "Single document too large, giving up: {%s}", Indexer->line_head->uuid_str)
|
||||||
|
free_response(r);
|
||||||
|
free(buf);
|
||||||
|
delete_queue(1);
|
||||||
|
if (Indexer->queued != 0) {
|
||||||
|
elastic_flush();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARNINGF("elastic.c", "Payload too large, retrying (%d documents)", count);
|
||||||
|
|
||||||
|
free_response(r);
|
||||||
|
free(buf);
|
||||||
|
_elastic_flush(max / 2);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if (r->status_code != 200) {
|
||||||
cJSON *ret_json = cJSON_Parse(r->body);
|
cJSON *ret_json = cJSON_Parse(r->body);
|
||||||
if (cJSON_GetObjectItem(ret_json, "errors")->valueint != 0) {
|
if (cJSON_GetObjectItem(ret_json, "errors")->valueint != 0) {
|
||||||
cJSON *err;
|
cJSON *err;
|
||||||
cJSON_ArrayForEach(err, cJSON_GetObjectItem(ret_json, "items")) {
|
cJSON_ArrayForEach(err, cJSON_GetObjectItem(ret_json, "items")) {
|
||||||
if (cJSON_GetObjectItem(cJSON_GetObjectItem(err, "index"), "status")->valueint != 201) {
|
if (cJSON_GetObjectItem(cJSON_GetObjectItem(err, "index"), "status")->valueint != 201) {
|
||||||
char* str = cJSON_Print(err);
|
char *str = cJSON_Print(err);
|
||||||
LOG_ERRORF("elastic.c", "%s\n", str);
|
LOG_ERRORF("elastic.c", "%s\n", str);
|
||||||
cJSON_free(str);
|
cJSON_free(str);
|
||||||
}
|
}
|
||||||
@@ -152,12 +169,44 @@ void elastic_flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cJSON_Delete(ret_json);
|
cJSON_Delete(ret_json);
|
||||||
|
delete_queue(Indexer->queued);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LOG_INFOF("elastic.c", "Indexed %d documents (%zukB) <%d>", count, buf_len / 1024, r->status_code);
|
||||||
|
|
||||||
|
delete_queue(max);
|
||||||
|
|
||||||
|
if (Indexer->queued != 0) {
|
||||||
|
elastic_flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free_response(r);
|
free_response(r);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void delete_queue(int max) {
|
||||||
|
for (int i = 0; i < max; i++) {
|
||||||
|
es_bulk_line_t *tmp = Indexer->line_head;
|
||||||
|
Indexer->line_head = tmp->next;
|
||||||
|
if (Indexer->line_head == NULL) {
|
||||||
|
Indexer->line_tail = NULL;
|
||||||
|
} else {
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
Indexer->queued -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void elastic_flush() {
|
||||||
|
|
||||||
|
if (Indexer == NULL) {
|
||||||
|
Indexer = create_indexer(IndexCtx.es_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
_elastic_flush(Indexer->queued);
|
||||||
|
}
|
||||||
|
|
||||||
void elastic_index_line(es_bulk_line_t *line) {
|
void elastic_index_line(es_bulk_line_t *line) {
|
||||||
|
|
||||||
if (Indexer == NULL) {
|
if (Indexer == NULL) {
|
||||||
@@ -194,7 +243,7 @@ es_indexer_t *create_indexer(const char *url) {
|
|||||||
return indexer;
|
return indexer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_indexer(char * script, char index_id[UUID_STR_LEN]) {
|
void destroy_indexer(char *script, char index_id[UUID_STR_LEN]) {
|
||||||
|
|
||||||
char url[4096];
|
char url[4096];
|
||||||
|
|
||||||
@@ -285,7 +334,7 @@ cJSON *elastic_get_document(const char *uuid_str) {
|
|||||||
char *elastic_get_status() {
|
char *elastic_get_status() {
|
||||||
char url[4096];
|
char url[4096];
|
||||||
snprintf(url, 4096,
|
snprintf(url, 4096,
|
||||||
"%s/_cluster/state/metadata/sist2?filter_path=metadata.indices.*.state", WebCtx.es_url);
|
"%s/_cluster/state/metadata/sist2?filter_path=metadata.indices.*.state", WebCtx.es_url);
|
||||||
|
|
||||||
response_t *r = web_get(url);
|
response_t *r = web_get(url);
|
||||||
cJSON *json = NULL;
|
cJSON *json = NULL;
|
||||||
|
|||||||
@@ -28,8 +28,18 @@ parse_job_t *create_fs_parse_job(const char *filepath, const struct stat *info,
|
|||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sub_strings[30];
|
||||||
|
#define EXCLUDED(str) (pcre_exec(ScanCtx.exclude, ScanCtx.exclude_extra, filepath, strlen(filepath), 0, 0, sub_strings, sizeof(sub_strings)) >= 0)
|
||||||
|
|
||||||
int handle_entry(const char *filepath, const struct stat *info, int typeflag, struct FTW *ftw) {
|
int handle_entry(const char *filepath, const struct stat *info, int typeflag, struct FTW *ftw) {
|
||||||
if (ftw->level <= ScanCtx.depth && typeflag == FTW_F && S_ISREG(info->st_mode)) {
|
|
||||||
|
if (typeflag == FTW_F && S_ISREG(info->st_mode) && ftw->level <= ScanCtx.depth) {
|
||||||
|
|
||||||
|
if (ScanCtx.exclude != NULL && EXCLUDED(filepath)) {
|
||||||
|
LOG_DEBUGF("walk.c", "Excluded: %s", filepath)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
parse_job_t *job = create_fs_parse_job(filepath, info, ftw->base);
|
parse_job_t *job = create_fs_parse_job(filepath, info, ftw->base);
|
||||||
tpool_add_work(ScanCtx.pool, parse, job);
|
tpool_add_work(ScanCtx.pool, parse, job);
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/main.c
14
src/main.c
@@ -6,7 +6,7 @@
|
|||||||
#define EPILOG "Made by simon987 <me@simon987.net>. Released under GPL-3.0"
|
#define EPILOG "Made by simon987 <me@simon987.net>. Released under GPL-3.0"
|
||||||
|
|
||||||
|
|
||||||
static const char *const Version = "1.2.12";
|
static const char *const Version = "1.2.15";
|
||||||
static const char *const usage[] = {
|
static const char *const usage[] = {
|
||||||
"sist2 scan [OPTION]... PATH",
|
"sist2 scan [OPTION]... PATH",
|
||||||
"sist2 index [OPTION]... INDEX",
|
"sist2 index [OPTION]... INDEX",
|
||||||
@@ -53,12 +53,15 @@ void sist2_scan(scan_args_t *args) {
|
|||||||
ScanCtx.index.desc.root_len = (short) strlen(ScanCtx.index.desc.root);
|
ScanCtx.index.desc.root_len = (short) strlen(ScanCtx.index.desc.root);
|
||||||
ScanCtx.tesseract_lang = args->tesseract_lang;
|
ScanCtx.tesseract_lang = args->tesseract_lang;
|
||||||
ScanCtx.tesseract_path = args->tesseract_path;
|
ScanCtx.tesseract_path = args->tesseract_path;
|
||||||
|
ScanCtx.fast = args->fast;
|
||||||
|
|
||||||
init_dir(ScanCtx.index.path);
|
init_dir(ScanCtx.index.path);
|
||||||
|
|
||||||
ScanCtx.mime_table = mime_get_mime_table();
|
ScanCtx.mime_table = mime_get_mime_table();
|
||||||
ScanCtx.ext_table = mime_get_ext_table();
|
ScanCtx.ext_table = mime_get_ext_table();
|
||||||
|
|
||||||
|
cbr_init();
|
||||||
|
|
||||||
char store_path[PATH_MAX];
|
char store_path[PATH_MAX];
|
||||||
snprintf(store_path, PATH_MAX, "%sthumbs", ScanCtx.index.path);
|
snprintf(store_path, PATH_MAX, "%sthumbs", ScanCtx.index.path);
|
||||||
mkdir(store_path, S_IWUSR | S_IRUSR | S_IXUSR);
|
mkdir(store_path, S_IWUSR | S_IRUSR | S_IXUSR);
|
||||||
@@ -238,6 +241,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
"shallow: Don't parse archives inside archives. DEFAULT: recurse"),
|
"shallow: Don't parse archives inside archives. DEFAULT: recurse"),
|
||||||
OPT_STRING(0, "ocr", &scan_args->tesseract_lang, "Tesseract language (use tesseract --list-langs to see "
|
OPT_STRING(0, "ocr", &scan_args->tesseract_lang, "Tesseract language (use tesseract --list-langs to see "
|
||||||
"which are installed on your machine)"),
|
"which are installed on your machine)"),
|
||||||
|
OPT_STRING('e', "exclude", &scan_args->exclude_regex, "Files that match this regex will not be scanned"),
|
||||||
|
OPT_BOOLEAN(0, "fast", &scan_args->fast, "Only index file names & mime type"),
|
||||||
|
|
||||||
OPT_GROUP("Index options"),
|
OPT_GROUP("Index options"),
|
||||||
OPT_STRING(0, "es-url", &common_es_url, "Elasticsearch url with port. DEFAULT=http://localhost:9200"),
|
OPT_STRING(0, "es-url", &common_es_url, "Elasticsearch url with port. DEFAULT=http://localhost:9200"),
|
||||||
@@ -284,9 +289,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
sist2_scan(scan_args);
|
sist2_scan(scan_args);
|
||||||
|
|
||||||
}
|
} else if (strcmp(argv[0], "index") == 0) {
|
||||||
|
|
||||||
else if (strcmp(argv[0], "index") == 0) {
|
|
||||||
|
|
||||||
int err = index_args_validate(index_args, argc, argv);
|
int err = index_args_validate(index_args, argc, argv);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
@@ -302,8 +305,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
sist2_web(web_args);
|
sist2_web(web_args);
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
fprintf(stderr, "Invalid command: '%s'\n", argv[0]);
|
fprintf(stderr, "Invalid command: '%s'\n", argv[0]);
|
||||||
argparse_usage(&argparse);
|
argparse_usage(&argparse);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#include "arc.h"
|
#include "arc.h"
|
||||||
#include "src/ctx.h"
|
#include "src/ctx.h"
|
||||||
|
|
||||||
#define ARC_BUF_SIZE 8192
|
|
||||||
|
|
||||||
int should_parse_filtered_file(const char *filepath, int ext) {
|
int should_parse_filtered_file(const char *filepath, int ext) {
|
||||||
char tmp[PATH_MAX * 2];
|
char tmp[PATH_MAX * 2];
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define SIST2_ARC_H
|
#define SIST2_ARC_H
|
||||||
|
|
||||||
#include "src/sist.h"
|
#include "src/sist.h"
|
||||||
|
#define ARC_BUF_SIZE 8192
|
||||||
|
|
||||||
int should_parse_filtered_file(const char *filepath, int ext);
|
int should_parse_filtered_file(const char *filepath, int ext);
|
||||||
|
|
||||||
|
|||||||
52
src/parsing/cbr.c
Normal file
52
src/parsing/cbr.c
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#import "cbr.h"
|
||||||
|
#import "src/ctx.h"
|
||||||
|
|
||||||
|
unsigned int cbr_mime;
|
||||||
|
unsigned int cbz_mime;
|
||||||
|
|
||||||
|
void cbr_init() {
|
||||||
|
cbr_mime = mime_get_mime_by_string(ScanCtx.mime_table, "application/x-cbr");
|
||||||
|
cbz_mime = mime_get_mime_by_string(ScanCtx.mime_table, "application/x-cbz");
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_cbr(unsigned int mime) {
|
||||||
|
return mime == cbr_mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_cbr(void *buf, size_t buf_len, document_t *doc) {
|
||||||
|
char *out_buf = malloc(buf_len * 2);
|
||||||
|
size_t out_buf_used = 0;
|
||||||
|
|
||||||
|
struct archive *rar_in = archive_read_new();
|
||||||
|
archive_read_support_filter_none(rar_in);
|
||||||
|
archive_read_support_format_rar(rar_in);
|
||||||
|
|
||||||
|
archive_read_open_memory(rar_in, buf, buf_len);
|
||||||
|
|
||||||
|
struct archive *zip_out = archive_write_new();
|
||||||
|
archive_write_set_format_zip(zip_out);
|
||||||
|
archive_write_open_memory(zip_out, out_buf, buf_len * 2, &out_buf_used);
|
||||||
|
|
||||||
|
struct archive_entry *entry;
|
||||||
|
while (archive_read_next_header(rar_in, &entry) == ARCHIVE_OK) {
|
||||||
|
archive_write_header(zip_out, entry);
|
||||||
|
|
||||||
|
char arc_buf[ARC_BUF_SIZE];
|
||||||
|
int len = archive_read_data(rar_in, arc_buf, ARC_BUF_SIZE);
|
||||||
|
while (len > 0) {
|
||||||
|
archive_write_data(zip_out, arc_buf, len);
|
||||||
|
len = archive_read_data(rar_in, arc_buf, ARC_BUF_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
archive_write_close(zip_out);
|
||||||
|
archive_write_free(zip_out);
|
||||||
|
|
||||||
|
archive_read_close(rar_in);
|
||||||
|
archive_read_free(rar_in);
|
||||||
|
|
||||||
|
doc->mime = cbz_mime;
|
||||||
|
parse_pdf(out_buf, out_buf_used, doc);
|
||||||
|
doc->mime = cbr_mime;
|
||||||
|
free(out_buf);
|
||||||
|
}
|
||||||
12
src/parsing/cbr.h
Normal file
12
src/parsing/cbr.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef SIST2_CBR_H
|
||||||
|
#define SIST2_CBR_H
|
||||||
|
|
||||||
|
#include "src/sist.h"
|
||||||
|
|
||||||
|
void cbr_init();
|
||||||
|
|
||||||
|
int is_cbr(unsigned int mime);
|
||||||
|
|
||||||
|
void parse_cbr(void *buf, size_t buf_len, document_t *doc);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
#define MIME_EMPTY 1
|
#define MIME_EMPTY 1
|
||||||
|
|
||||||
#define DONT_PARSE 0x80000000
|
#define DONT_PARSE 0x80000000
|
||||||
#define SHOULD_PARSE(mime_id) (mime_id & DONT_PARSE) != DONT_PARSE && mime_id != 0
|
#define SHOULD_PARSE(mime_id) (ScanCtx.fast == 0 && (mime_id & DONT_PARSE) != DONT_PARSE && mime_id != 0)
|
||||||
|
|
||||||
#define PDF_MASK 0x40000000
|
#define PDF_MASK 0x40000000
|
||||||
#define IS_PDF(mime_id) (mime_id & PDF_MASK) == PDF_MASK
|
#define IS_PDF(mime_id) (mime_id & PDF_MASK) == PDF_MASK
|
||||||
|
|||||||
@@ -149,6 +149,13 @@ void parse(void *arg) {
|
|||||||
if (doc_buf != buf && doc_buf != NULL) {
|
if (doc_buf != buf && doc_buf != NULL) {
|
||||||
free(doc_buf);
|
free(doc_buf);
|
||||||
}
|
}
|
||||||
|
} else if (is_cbr(doc.mime)) {
|
||||||
|
void *cbr_buf = read_all(job, (char *) buf, bytes_read);
|
||||||
|
parse_cbr(cbr_buf, doc.size, &doc);
|
||||||
|
|
||||||
|
if (cbr_buf != buf && cbr_buf != NULL) {
|
||||||
|
free(cbr_buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Parent meta
|
//Parent meta
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <libxml/xmlstring.h>
|
#include <libxml/xmlstring.h>
|
||||||
#define BOOL int
|
#define BOOL int
|
||||||
#include <tesseract/capi.h>
|
#include <tesseract/capi.h>
|
||||||
|
#include <pcre.h>
|
||||||
|
|
||||||
#include <onion/onion.h>
|
#include <onion/onion.h>
|
||||||
#include <onion/handler.h>
|
#include <onion/handler.h>
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
#include "parsing/font.h"
|
#include "parsing/font.h"
|
||||||
#include "parsing/arc.h"
|
#include "parsing/arc.h"
|
||||||
#include "parsing/doc.h"
|
#include "parsing/doc.h"
|
||||||
|
#include "parsing/cbr.h"
|
||||||
#include "cli.h"
|
#include "cli.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "utf8.h/utf8.h"
|
#include "utf8.h/utf8.h"
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ typedef int (*read_func_t)(struct vfile *, void *buf, size_t size);
|
|||||||
typedef void (*close_func_t)(struct vfile *);
|
typedef void (*close_func_t)(struct vfile *);
|
||||||
|
|
||||||
typedef struct vfile {
|
typedef struct vfile {
|
||||||
|
|
||||||
union {
|
union {
|
||||||
int fd;
|
int fd;
|
||||||
struct archive *arc;
|
struct archive *arc;
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ text_buffer_t text_buffer_create(int max_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void text_buffer_terminate_string(text_buffer_t *buf) {
|
void text_buffer_terminate_string(text_buffer_t *buf) {
|
||||||
if (*(buf->dyn_buffer.buf + buf->dyn_buffer.cur - 1) == ' ') {
|
if (buf->dyn_buffer.cur > 0 && *(buf->dyn_buffer.buf + buf->dyn_buffer.cur - 1) == ' ') {
|
||||||
*(buf->dyn_buffer.buf + buf->dyn_buffer.cur - 1) = '\0';
|
*(buf->dyn_buffer.buf + buf->dyn_buffer.cur - 1) = '\0';
|
||||||
} else {
|
} else {
|
||||||
dyn_buffer_write_char(&buf->dyn_buffer, '\0');
|
dyn_buffer_write_char(&buf->dyn_buffer, '\0');
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -102,6 +102,7 @@ body {
|
|||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
|
padding: .25rem 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item:first-child {
|
.list-group-item:first-child {
|
||||||
@@ -199,7 +200,7 @@ body {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 175px;
|
max-height: 175px;
|
||||||
margin: 0 auto 0;
|
margin: 0 auto 0;
|
||||||
padding: 3px 3px 0 3px;
|
padding: 3px 3px 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
@@ -208,7 +209,7 @@ body {
|
|||||||
display: block;
|
display: block;
|
||||||
max-width: 64px;
|
max-width: 64px;
|
||||||
max-height: 64px;
|
max-height: 64px;
|
||||||
margin: 0 auto 0;
|
margin: 0 auto;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
@@ -391,10 +392,6 @@ option {
|
|||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item {
|
|
||||||
padding: .25rem 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper-sm {
|
.wrapper-sm {
|
||||||
min-width: 64px;
|
min-width: 64px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ function infoButtonCb(hit) {
|
|||||||
"bitrate", "artist", "album", "album_artist", "genre", "title", "font_name", "tag"
|
"bitrate", "artist", "album", "album_artist", "genre", "title", "font_name", "tag"
|
||||||
]);
|
]);
|
||||||
Object.keys(doc)
|
Object.keys(doc)
|
||||||
.filter(key => key.startsWith("_keyword.") || key.startsWith("_text.") || displayFields.has(key) || key.startsWith("exif_"))
|
.filter(key => key.startsWith("_keyword.") || key.startsWith("_text.") || displayFields.has(key) || key.startsWith("exif_"))
|
||||||
.forEach(key => {
|
.forEach(key => {
|
||||||
tbody.append($("<tr>")
|
tbody.append($("<tr>")
|
||||||
.append($("<td>").text(key))
|
.append($("<td>").text(key))
|
||||||
@@ -377,6 +377,7 @@ function makeThumbnail(mimeCategory, hit, imgWrapper, small) {
|
|||||||
|| hit["_source"]["mime"] === "application/pdf"
|
|| hit["_source"]["mime"] === "application/pdf"
|
||||||
|| hit["_source"]["mime"] === "application/epub+zip"
|
|| hit["_source"]["mime"] === "application/epub+zip"
|
||||||
|| hit["_source"]["mime"] === "application/x-cbz"
|
|| hit["_source"]["mime"] === "application/x-cbz"
|
||||||
|
|| hit["_source"]["mime"] === "application/x-cbr"
|
||||||
|| hit["_source"].hasOwnProperty("font_name")
|
|| hit["_source"].hasOwnProperty("font_name")
|
||||||
) {
|
) {
|
||||||
thumbnail = document.createElement("img");
|
thumbnail = document.createElement("img");
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<nav class="navbar navbar-expand-lg">
|
<nav class="navbar navbar-expand-lg">
|
||||||
<a class="navbar-brand" href="/">sist2</a>
|
<a class="navbar-brand" href="/">sist2</a>
|
||||||
<span class="badge badge-pill version">v1.2.12</span>
|
<span class="badge badge-pill version">v1.2.15</span>
|
||||||
<span class="tagline">Lightning-fast file system indexer and search tool </span>
|
<span class="tagline">Lightning-fast file system indexer and search tool </span>
|
||||||
<a style="margin-left: auto" id="theme" class="btn" title="Toggle theme" href="/">Theme</a>
|
<a style="margin-left: auto" id="theme" class="btn" title="Toggle theme" href="/">Theme</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
Reference in New Issue
Block a user