Sélectionner une révision Git
write.c 8,54 Kio
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#include <lektor/mkv.h>
#include <pcre.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
static const char *METADATA_TEMPLATE =
" <?xml version=\"1.0\" encoding=\"UTF-8\"?> "
" <Tags> "
" <Tag> "
" <Targets> "
" <TargetTypeValue>70</TargetTypeValue> "
" </Targets> "
" <Simple> "
" <Name>TITLE</Name> "
" <String>%s</String> "
" </Simple> "
" </Tag> "
" <Tag> "
" <Simple> "
" <Name>TITLE</Name> "
" <String>%s</String> "
" </Simple> "
" <Simple> "
" <Name>CONTENT_TYPE</Name> "
" <String>%s</String> "
" </Simple> "
" <Simple> "
" <Name>ADDRESS</Name> "
" <String>%s</String> "
" </Simple> "
" <Simple> "
" <Name>ARTIST</Name> "
" <String>%s</String> "
" </Simple> "
" <Simple> "
" <Name>GENRE</Name> "
" <String>%s</String> "
" </Simple> "
" <Simple> "
" <Name>TRACK</Name> "
" <String>%d</String> "
" </Simple> "
" </Tag> "
" </Tags> ";
static bool
mkvpropedit__(const char *const args[])
{
pid_t pid;
int wstatus, status, fd;
if ((pid = fork()) == 0) {
if ((fd = open("/dev/null", O_WRONLY | O_TRUNC)) < 0) {
fprintf(stderr, " ! call_mkvpropedit: can't to open /dev/null in O_WRONLY O_TRUNC\n");
return false;
}
if (dup2(fd, 1) < 0) {
fprintf(stderr, " ! call_mkvpropedit: failed to duplicate /dev/null to stdout\n");
return false;
}
execv(args[0], (char *const *) args);
exit(EXIT_FAILURE);
}
else if (pid < 0) {
fprintf(stderr, " ! metadata_write: failed to fork: %s\n", strerror(errno));
return false;
}
else {
do {
if (waitpid(pid, &wstatus, WUNTRACED | WCONTINUED) == -1) {
fprintf(stderr, " ! metadata_write: Failed to wait children: %s\n",
strerror(errno));
return false;
}
} while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
if ((status = WEXITSTATUS(wstatus))) {
fprintf(stderr, " ! metadata_write: children failed with status %d", status);
return false;
}
}
return true;
}
int
kara_metadata_write(struct kara_metadata *mdt, const char *filename, const char *mkvpropedit)
{
char tmpfilepath[PATH_MAX];
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;
memset(tmpfilepath, 0, PATH_MAX);
strncat(tmpfilepath, "all:/tmp/lektor.metadata.XXXXXX", PATH_MAX - 1);
if ((fd = mkstemp(metadafilepath)) < 0) {
fprintf(stderr, " ! metadata_write: failed to create temporary file: %s\n",
strerror(errno));
goto error;
}
if (dprintf(fd, METADATA_TEMPLATE, mdt->source_name, mdt->song_name, mdt->category,
mdt->language, mdt->author_name, mdt->song_type, mdt->song_number) < 0) {
fprintf(stderr, " ! metadata_write: failed to write to temporary file: %s\n",
metadafilepath);
goto error;
}
if (!mkvpropedit__(args1) || !mkvpropedit__(args2))
goto error;
sta = true;
error:
close(fd);
unlink(metadafilepath);
return sta;
}
static bool
metadata_from_path(char *const mkvfile, struct kara_metadata *meta)
{
pcre *regex = NULL;
pcre_extra *pcre_extra = NULL;
bool sta = false;
const int sub_str_vec_len = 30;
int pcre_error_offset, pcre_exec_ret, sub_str_vec[sub_str_vec_len], i, num;
char num_str[LEKTOR_TAG_MAX];
const char *substr;
char *copy_to;
static const char *rgx =
"^\\/(?:.+)\\/(vo|va|amv|cdg|autres|vocaloid)\\/"
"(jp|fr|en|ru|sp|it|ch|latin|multi|undefined)\\/(.+)\\/"
"(.+) - (OP|ED|IS|AMV|VOCA|PV|MV|LIVE)(\\d*) - (.+)\\.mkv$";
const char *pcre_error_str = NULL;
if ((regex = pcre_compile(rgx, 0, &pcre_error_str, &pcre_error_offset, NULL)) == NULL) {
fprintf(stderr, " ! metadata_from_path: failed to compile regex\n");
return false;
}
pcre_extra = pcre_study(regex, 0, &pcre_error_str);
if (pcre_error_str != NULL) {
fprintf(stderr, " ! metadata_from_path: failed to study regex: %s\n", pcre_error_str);
goto error;
}
memset(meta, 0, sizeof(struct kara_metadata));
memset(num_str, 0, LEKTOR_TAG_MAX * sizeof(char));
pcre_exec_ret = pcre_exec(regex, pcre_extra, mkvfile, strlen(mkvfile), 0, 0,
sub_str_vec, sub_str_vec_len);
if (pcre_exec_ret < 0) {
fprintf(stderr, " ! metadata_from_path: PCRE error\n");
goto error;
}
if (pcre_exec_ret == 0) {
// To much -> error in our case //
fprintf(stderr, " ! metadata_from_path: To much matches found for file: %s\n", mkvfile);
goto error;
}
for (i = 1; i < pcre_exec_ret; ++i) {
pcre_get_substring(mkvfile, sub_str_vec, pcre_exec_ret, i, &substr);
if (i == 1)
copy_to = meta->song_type;
else if (i == 2)
copy_to = meta->language;
else if (i == 3)
copy_to = meta->author_name;
else if (i == 4)
copy_to = meta->source_name;
else if (i == 5)
copy_to = meta->category;
else if (i == 6)
copy_to = num_str;
else if (i == 7)
copy_to = meta->song_name;
else {
pcre_free_substring(substr);
goto error;
}
snprintf(copy_to, LEKTOR_TAG_MAX, "%s", substr);
pcre_free_substring(substr);
}
meta->song_number = ((num = atoi(num_str)) <= 0) ? 1 : num;
sta = true;
error:
pcre_free(regex);
if (pcre_extra != NULL) {
#ifdef PCRE_CONFIG_JIT
pcre_free_study(pcre_extra);
#else
pcre_free(pcre_extra);
#endif
}
return sta;
}
int
metadata_set_directory(const char *kara_dir, const char *mkvpropedit)
{
DIR *d;
struct dirent *dir;
char path[PATH_MAX];
struct kara_metadata meta;
memset(path, 0, PATH_MAX * sizeof(char));
d = opendir(kara_dir);
if (!d) {
fprintf(stderr, " ! metadata_set_directory: Failed to open directory '%s': %s\n",
kara_dir, strerror(errno));
return 1;
}
while (NULL != (dir = readdir(d))) {
strncpy(path, kara_dir, PATH_MAX - 1);
strncat(path, "/", PATH_MAX - 1);
strncat(path, dir->d_name, PATH_MAX - 1);
if (dir->d_type == DT_REG &&
metadata_from_path(path, &meta) &&
kara_metadata_write(&meta, path, mkvpropedit))
continue;
else if (dir->d_type == DT_DIR &&
strcmp(dir->d_name, ".") != 0 &&
strcmp(dir->d_name, "..") != 0)
metadata_set_directory(path, mkvpropedit);
}
fprintf(stderr, " * metadata_set_directory: Passed directory '%s'\n", kara_dir);
closedir(d);
return false;
}
int
metadata_set_file(char *karapath, const char *mkvpropedit)
{
struct kara_metadata meta;
return metadata_from_path(karapath, &meta) &&
kara_metadata_write(&meta, karapath, mkvpropedit);
}