diff --git a/doc/lkt.1 b/doc/lkt.1 index d1ce04e5380170d681ef25c6670d445a445a2354..73c36811edd4d8ab56b7b51d306c3c4f0fd5fdb1 100644 --- a/doc/lkt.1 +++ b/doc/lkt.1 @@ -129,6 +129,34 @@ Search and prints the number of karas that match the query Search in the queue and prints the karas that match the query .PP +\fISTICKERS-COMMANDS\fP +.PP +.PD 0 +.TP +.PD +\fBsticker get\fP <type> <uri> [ <name> [ <op> <value> ] ] +List the stickers of an object \fIuri\fP. The object \fItype\fP can be +\fIkara\fP or \fIplt\fP. + +A condition can be defined on the value of the sticker with an operator +\fIop\fP and an integer value \fIvalue\fP. Supported operators are \fI<\fP, +\fI=\fP and \fI>\fP. Operations are not strict. +.TP +\fBsticker set\fP <type> <uri> <name> <value> +Set the value of a sticker \fIname\fP to \fIvalue\fP for the object with the +id \fIuri\fP +.TP +\fBsticker delete\fP <type> <uri> [name] +Delete all the stickers or only one (specified by \fIname\fP) of the object with +the id \fIuri\fP +.TP +\fBksticker\fP ... +An alias for the sticker commands with the type \fIkara\fP +.TP +\fBpsticker\fP ... +An alias for the sticker commands with the type \fIplt\fP +.PP + \fIADMIN-COMMANDS\fP .PP .PD 0 diff --git a/inc/lektor/bufferfd.h b/inc/lektor/bufferfd.h index ffc4aacd4cf2fc56693cb4bdf501d2840c82fa92..8e03dc79903a51e1391d250ff284290e1ecda014 100644 --- a/inc/lektor/bufferfd.h +++ b/inc/lektor/bufferfd.h @@ -42,7 +42,7 @@ ssize_t bufferfd_bytes(struct bufferfd *bf, size_t n, uint8_t *res); ssize_t bufferfd_byte(struct bufferfd *bf, uint8_t *res); /* Consume `n` bytes without returning them. */ -ssize_t bufferfd_skip(struct bufferfd *bf, size_t n); +ssize_t bufferfd_skip(struct bufferfd *bf, const size_t n); /* Move the file cursor to the absolute position `pos` (0 is the beginning of * the file). diff --git a/inc/lektor/mkv.h b/inc/lektor/mkv.h index 21b3808c0b7ea7d3d27f99d101787729fafa5de2..e4479001a9e14d8f768074f7087bd483919ab623 100644 --- a/inc/lektor/mkv.h +++ b/inc/lektor/mkv.h @@ -37,15 +37,7 @@ struct kara_metadata { int song_number; }; -enum kara_action { - kara_action_none = 0, /* Do nothing */ - kara_action_add = (1 << 1), /* Add to database */ - kara_action_delete = (1 << 2), /* Delete from database */ - kara_action_unavail = (1 << 3), /* Mark kara as unavailable */ -}; - struct kara { - enum kara_action action; /* What to do with this kara. */ size_t id; /* Should never be NULL. NEVER!! */ struct kara_metadata mdt; /* The metadata of the kara. */ char filename[PATH_MAX]; /* The path to the matroska file. */ @@ -55,9 +47,14 @@ struct kara { Returns 0 on success and -1 on error. */ int kara_metadata_read(struct kara_metadata *dst, const char *filename); -/* Write metadata to a mkv file */ +/* Write metadata to a mkv file. Returns 0 on success and -1 on error */ int kara_metadata_write(struct kara_metadata *mdt, const char *filename, const char *mkvpropedit); +/* Check if the mdt of the kara `filename` is the same as the `mdt`. + Returns 0 on success and -1 on error or if the metadata are + not equals. */ +int kara_metadata_equals(struct kara_metadata *mdt, const char *filename); + /* Set the metadata for the file according to its path. */ int metadata_set_file(char *karapath, const char *mkvpropedit); diff --git a/src/main/lkt.c b/src/main/lkt.c index 87282296a414035f9f0bcbd0674441680e2e2348..267a94b8779921b6539a536b2db46abf370b424d 100644 --- a/src/main/lkt.c +++ b/src/main/lkt.c @@ -795,11 +795,19 @@ static struct lkt_cmd_opt options_admin[] = { LKT_OPT_NULL, }; +static struct lkt_cmd_opt options_stickers[] = { + { .name = "get", .call = stickers_get__ }, + { .name = "set", .call = stickers_set__ }, + { .name = "delete", .call = stickers_delete__ }, + LKT_OPT_NULL, +}; + #define sub_command(name) /* Create sub-commands here */ \ noreturn void name ## __(struct lkt_cmd_args *args) { \ fail_if(!args->argc, "Invalid command, specify a sub command for " #name); \ lkt_cmd_parse(options_ ## name, args->argc, args->argv); \ } +sub_command(stickers) sub_command(search) sub_command(plt) sub_command(admin) @@ -825,6 +833,7 @@ static struct lkt_cmd_opt options_[] = { { .name = "plt", .call = plt__ }, { .name = "search", .call = search__ }, { .name = "admin", .call = admin__ }, + { .name = "stickers", .call = stickers__ }, LKT_OPT_NULL, }; diff --git a/src/mkv/bufferfd.c b/src/mkv/bufferfd.c index f41eefd501c3a9ad9f5b504e003a8359a6032849..3de8ac4eee492bdc2ebc81b5aea142969e4639f1 100644 --- a/src/mkv/bufferfd.c +++ b/src/mkv/bufferfd.c @@ -5,8 +5,8 @@ #include <lektor/bufferfd.h> -static ssize_t -bufferfd_fill(struct bufferfd *bf) +static inline ssize_t +__fill(struct bufferfd *bf) { if (bf->len <= bf->pos) { ssize_t n = read(bf->fd, bf->buffer, BUFFER_MAX); @@ -24,8 +24,7 @@ bufferfd_fill(struct bufferfd *bf) ssize_t bufferfd_bytes(struct bufferfd *bf, size_t n, uint8_t *res) { - // TODO repeat until n is reached - ssize_t r = bufferfd_fill(bf); + ssize_t r = __fill(bf); /* TODO repeat until n is reached */ if (r < (ssize_t) n) return -1; @@ -41,14 +40,19 @@ bufferfd_byte(struct bufferfd *bf, uint8_t *res) return bufferfd_bytes(bf, 1, res); } -ssize_t -bufferfd_skip(struct bufferfd *bf, size_t n) +static inline ssize_t +__skip(struct bufferfd *bf, const size_t n, const size_t b_size) { - // TODO less dirty bomb - uint8_t b[4096]; + uint8_t b[b_size]; return bufferfd_bytes(bf, n, b); } +ssize_t +bufferfd_skip(struct bufferfd *bf, const size_t n) +{ + return __skip(bf, n, n > BUFFER_MAX ? BUFFER_MAX : n); +} + ssize_t bufferfd_seek(struct bufferfd *bf, size_t pos) { diff --git a/src/mkv/mkv.c b/src/mkv/mkv.c index fe1b6fff80086c99968c79fb866793a318fc5800..6b0623bbd9d833a9e9c89e674b8539a7cd18feb5 100644 --- a/src/mkv/mkv.c +++ b/src/mkv/mkv.c @@ -23,14 +23,14 @@ #define EBML_MKV_TAGS 0x1254c367 #define EBML_MKV_TAG 0x00007373 #define EBML_MKV_TAG_TARGETS 0x000063c0 -#define EBML_MKV_TAG_TTV 0x000068ca // TargetTypeValue -#define EBML_MKV_TAG_SIMPLE 0x000067c8 // SimpleTag +#define EBML_MKV_TAG_TTV 0x000068ca /* TargetTypeValue */ +#define EBML_MKV_TAG_SIMPLE 0x000067c8 /* SimpleTag */ #define EBML_MKV_TAG_NAME 0x000045a3 #define EBML_MKV_TAG_STRING 0x00004487 #define EBML_MKV_TAG_BINARY 0x00004485 -#define EBML_MKV_CRC32 0x0000000bf // CRC-32, they skip it in mpv (demux/ebml.c:463 aprox) -#define EBML_MKV_VOID 0x0000000ec // VOID element +#define EBML_MKV_CRC32 0x0000000bf /* CRC-32, they skip it in mpv (demux/ebml.c:463 aprox) */ +#define EBML_MKV_VOID 0x0000000ec /* VOID element */ /* mkv_read_* functions take data from the bufferfd and parse the next "*" (one * of the following): @@ -537,3 +537,19 @@ error: close(file.fd); return status_code; } + +int +kara_metadata_equals(struct kara_metadata *mdt, const char *filename) +{ + struct kara_metadata kara_mdt; /* FIXME: Less dirty bomb */ + if (kara_metadata_read(&kara_mdt, filename)) + return -1; + return ! (STR_MATCH(kara_mdt.song_name, mdt->song_name) && + STR_MATCH(kara_mdt.source_name, mdt->source_name) && + STR_MATCH(kara_mdt.category, mdt->category) && + STR_MATCH(kara_mdt.language, mdt->language) && + STR_MATCH(kara_mdt.author_name, mdt->author_name) && + STR_MATCH(kara_mdt.song_type, mdt->song_type) && + kara_mdt.song_number == mdt->song_number); +} + diff --git a/src/mkv/write.c b/src/mkv/write.c index d366c6bf3dc86999c5bba1357d72b5e771efb711..7faa39996cb8a41d77b0de36ca0004f032e48fbf 100644 --- a/src/mkv/write.c +++ b/src/mkv/write.c @@ -108,8 +108,7 @@ kara_metadata_write(struct kara_metadata *mdt, const char *filename, const char char *const metadafilepath = &tmpfilepath[4]; const char *const args1[] = { mkvpropedit, "-t", "all:", filename, NULL }; const char *const args2[] = { mkvpropedit, "-t", tmpfilepath, filename, NULL }; - int fd; - bool sta = false; + int fd, sta = -1; memset(tmpfilepath, 0, PATH_MAX); strncat(tmpfilepath, "all:/tmp/lektor.metadata.XXXXXX", PATH_MAX - 1); @@ -128,7 +127,7 @@ kara_metadata_write(struct kara_metadata *mdt, const char *filename, const char if (!mkvpropedit__(args1) || !mkvpropedit__(args2)) goto error; - sta = true; + sta = 0; error: close(fd); unlink(metadafilepath); @@ -207,7 +206,7 @@ metadata_set_directory(const char *kara_dir, const char *mkvpropedit) if (dir->d_type == DT_REG && metadata_from_path(path, &meta) && - kara_metadata_write(&meta, path, mkvpropedit)) + ! kara_metadata_write(&meta, path, mkvpropedit)) continue; else if (dir->d_type == DT_DIR && !STR_MATCH(dir->d_name, ".") && @@ -226,6 +225,6 @@ metadata_set_file(char *karapath, const char *mkvpropedit) struct kara_metadata meta; return metadata_from_path(karapath, &meta) && - kara_metadata_write(&meta, karapath, mkvpropedit); + ! kara_metadata_write(&meta, karapath, mkvpropedit); } diff --git a/src/net/downloader.c b/src/net/downloader.c index b25ebac890df8e24b9ce60e3f6a43c0010beda0b..a076deef22967bc8079f39795a66b0689b4b90b8 100644 --- a/src/net/downloader.c +++ b/src/net/downloader.c @@ -325,7 +325,10 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec struct kara kara; char url[URL_MAX_LEN]; long filestamp, timestamp; + char mkvpropedit[PATH_MAX]; RETURN_UNLESS(len > 0 && json_object_get_array(json), "Json invalid or array empty", NOTHING); + RETURN_UNLESS(database_config_get_text(db, "externals", "mkvpropedit", mkvpropedit, PATH_MAX - 1), + "Can't get the mkvpropedit executable path", NOTHING); LOG_INFO_SCT("REPO", "Starting to process json for repo %s", repo->name); for (i = 0; i < len; ++i) { @@ -346,25 +349,29 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec } safe_snprintf(kara.filename + kara_dir_len, PATH_MAX - kara_dir_len, "%d.mkv", integer); + /* Reads the json */ + err |= safe_json_get_string(kara_json, "song_name", kara.mdt.song_name, LEKTOR_TAG_MAX); + err |= safe_json_get_string(kara_json, "source_name", kara.mdt.source_name, LEKTOR_TAG_MAX); + err |= safe_json_get_string(kara_json, "category", kara.mdt.category, LEKTOR_TAG_MAX); + err |= safe_json_get_string(kara_json, "language", kara.mdt.language, LEKTOR_TAG_MAX); + err |= safe_json_get_string(kara_json, "author_name", kara.mdt.author_name, LEKTOR_TAG_MAX); + err |= safe_json_get_string(kara_json, "song_type", kara.mdt.song_type, LEKTOR_TAG_MAX); + if (err || safe_json_get_int32(kara_json, "song_number", &kara.mdt.song_number)) { + LOG_WARN_SCT("REPO", "Json is invalid for kara '%ld', skip it", kara.id); + continue; + } + /* Timestamp verification */ if (safe_json_get_long(kara_json, "unix_timestamp", ×tamp)) continue; filestamp = get_mtime(kara.filename); - if (database_get_timestamp(db) >= filestamp && filestamp > timestamp) { + if (database_get_timestamp(db) >= filestamp && filestamp > timestamp && + ! kara_metadata_equals(&kara.mdt, kara.filename)) { LOG_INFO_SCT("REPO", "Ignore kara '%ld' with path '%s'", kara.id, kara.filename); continue; } LOG_WARN_SCT("REPO", "Download kara '%ld' with path '%s'", kara.id, kara.filename); - err |= safe_json_get_string(kara_json, "song_name", kara.mdt.song_name, LEKTOR_TAG_MAX); - err |= safe_json_get_string(kara_json, "source_name", kara.mdt.source_name, LEKTOR_TAG_MAX); - err |= safe_json_get_string(kara_json, "category", kara.mdt.category, LEKTOR_TAG_MAX); - err |= safe_json_get_string(kara_json, "language", kara.mdt.language, LEKTOR_TAG_MAX); - err |= safe_json_get_string(kara_json, "author_name", kara.mdt.author_name, LEKTOR_TAG_MAX); - err |= safe_json_get_string(kara_json, "song_type", kara.mdt.song_type, LEKTOR_TAG_MAX); - RETURN_IF(err || safe_json_get_int32(kara_json, "song_number", &kara.mdt.song_number), - "Invalid json", NOTHING); - if (!database_update_add((sqlite3 *) db, kara.filename, &kara.mdt, kara.id, false)) { LOG_ERROR_SCT("REPO", "Could not add unavailable kara %ld to db", kara.id); continue; @@ -377,6 +384,11 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec continue; } + if (kara_metadata_write(&kara.mdt, kara.filename, mkvpropedit)) { + LOG_WARN_SCT("REPO", "Could not write metadata to kara '%ld' with path '%s'", kara.id, kara.filename); + continue; + } + if (!database_update_set_available((sqlite3 *) db, kara.id)) { LOG_WARN_SCT("REPO", "Could not set kara %ld available", kara.id); continue;