This commit is contained in:
2026-03-29 14:01:52 +03:00
commit 0611279128
210 changed files with 60454 additions and 0 deletions

296
comment.c Normal file
View File

@@ -0,0 +1,296 @@
/*
* Copyright 2008-2013 Various Authors
* Copyright 2004-2007 Timo Hirvonen
*
* 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 2 of the
* License, or (at your option) 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, see <http://www.gnu.org/licenses/>.
*/
#include "comment.h"
#include "xmalloc.h"
#include "utils.h"
#include "uchar.h"
#include <string.h>
#include <strings.h>
static int is_various_artists(const char *a)
{
return strcasecmp(a, "Various Artists") == 0 ||
strcasecmp(a, "Various") == 0 ||
strcasecmp(a, "VA") == 0 ||
strcasecmp(a, "V/A") == 0;
}
int track_is_compilation(const struct keyval *comments)
{
const char *c, *a, *aa;
c = keyvals_get_val(comments, "compilation");
if (c && is_freeform_true(c))
return 1;
c = keyvals_get_val(comments, "partofacompilation");
if (c && is_freeform_true(c))
return 1;
aa = keyvals_get_val(comments, "albumartist");
if (aa && is_various_artists(aa))
return 1;
a = keyvals_get_val(comments, "artist");
if (a && is_various_artists(a))
return 1;
if (aa && a && !u_strcase_equal(aa, a))
return 1;
return 0;
}
int track_is_va_compilation(const struct keyval *comments)
{
const char *c, *a, *aa;
aa = keyvals_get_val(comments, "albumartist");
if (aa)
return is_various_artists(aa);
a = keyvals_get_val(comments, "artist");
if (a && is_various_artists(a))
return 1;
c = keyvals_get_val(comments, "compilation");
if (c && is_freeform_true(c))
return 1;
c = keyvals_get_val(comments, "partofacompilation");
if (c && is_freeform_true(c))
return 1;
return 0;
}
const char *comments_get_albumartist(const struct keyval *comments)
{
const char *val = keyvals_get_val(comments, "albumartist");
if (!val || strcmp(val, "") == 0)
val = keyvals_get_val(comments, "artist");
return val;
}
const char *comments_get_artistsort(const struct keyval *comments)
{
const char *val;
if (track_is_va_compilation(comments))
return NULL;
val = keyvals_get_val(comments, "albumartistsort");
if (!track_is_compilation(comments)) {
if (!val || strcmp(val, "") == 0)
val = keyvals_get_val(comments, "artistsort");
}
if (!val || strcmp(val, "") == 0)
return NULL;
return val;
}
int comments_get_int(const struct keyval *comments, const char *key)
{
const char *val;
long int ival;
val = keyvals_get_val(comments, key);
if (val == NULL)
return -1;
while (*val && !(*val >= '0' && *val <= '9'))
val++;
if (str_to_int(val, &ival) == -1)
return -1;
return ival;
}
int comments_get_signed_int(const struct keyval *comments, const char *key, long int *ival)
{
const char *val;
val = keyvals_get_val(comments, key);
if (val == NULL)
return -1;
while (*val && !(*val == '+' || *val == '-' || (*val >= '0' && *val <= '9')))
val++;
return str_to_int(val, ival);
}
double comments_get_double(const struct keyval *comments, const char *key)
{
const char *val;
char *end;
double d;
val = keyvals_get_val(comments, key);
if (!val || strcmp(val, "") == 0)
goto error;
d = strtod(val, &end);
if (val == end)
goto error;
return d;
error:
return strtod("NAN", NULL);
}
/* Return date as an integer in the form YYYYMMDD, for sorting purposes.
* This function is not year 10000 compliant. */
int comments_get_date(const struct keyval *comments, const char *key)
{
const char *val;
char *endptr;
int year, month, day;
long int ival;
val = keyvals_get_val(comments, key);
if (val == NULL)
return -1;
year = strtol(val, &endptr, 10);
/* Looking for a four-digit number */
if (year < 1000 || year > 9999)
return -1;
ival = year * 10000;
if (*endptr == '-' || *endptr == ' ' || *endptr == '/') {
month = strtol(endptr+1, &endptr, 10);
if (month < 1 || month > 12)
return ival;
ival += month * 100;
}
if (*endptr == '-' || *endptr == ' ' || *endptr == '/') {
day = strtol(endptr+1, &endptr, 10);
if (day < 1 || day > 31)
return ival;
ival += day;
}
return ival;
}
static const char *interesting[] = {
"artist", "album", "title", "tracknumber", "discnumber", "totaldiscs", "genre",
"date", "compilation", "partofacompilation", "albumartist", "artistsort", "albumartistsort",
"albumsort",
"originaldate",
"r128_track_gain",
"r128_album_gain",
"replaygain_track_gain",
"replaygain_track_peak",
"replaygain_album_gain",
"replaygain_album_peak",
"musicbrainz_trackid",
"comment",
"bpm",
"arranger", "composer", "conductor", "lyricist", "performer",
"remixer", "label", "publisher", "work", "opus",
"subtitle", "media",
NULL
};
static struct {
const char *old;
const char *new;
} key_map[] = {
{ "album_artist", "albumartist" },
{ "album artist", "albumartist" },
{ "disc", "discnumber" },
{ "part", "discnumber" },
{ "partnumber", "discnumber" },
{ "disctotal", "totaldiscs" },
{ "tempo", "bpm" },
{ "track", "tracknumber" },
{ "WM/Year", "date" },
{ "WM/ArtistSortOrder", "artistsort" },
{ "WM/AlbumArtistSortOrder", "albumartistsort" },
{ "WM/AlbumSortOrder", "albumsort" },
{ "WM/OriginalReleaseYear", "originaldate" },
{ "WM/Media", "media" },
{ "sourcemedia", "media" },
{ "MusicBrainz Track Id", "musicbrainz_trackid" },
{ "version", "subtitle" },
/* ffmpeg id3 */
{ "artist-sort", "artistsort" },
{ "TSO2", "albumartistsort" },
{ "album-sort", "albumsort" },
/* ffmpeg mp4 */
{ "sort_artist", "artistsort" },
{ "sort_album_artist", "albumartistsort" },
{ "sort_album", "albumsort" },
{ NULL, NULL }
};
static const char *fix_key(const char *key)
{
int i;
for (i = 0; interesting[i]; i++) {
if (!strcasecmp(key, interesting[i]))
return interesting[i];
}
for (i = 0; key_map[i].old; i++) {
if (!strcasecmp(key, key_map[i].old))
return key_map[i].new;
}
return NULL;
}
int comments_add(struct growing_keyvals *c, const char *key, char *val)
{
if (!strcasecmp(key, "songwriter")) {
int r = comments_add_const(c, "lyricist", val);
return comments_add(c, "composer", val) && r;
}
key = fix_key(key);
if (!key) {
free(val);
return 0;
}
if (!strcmp(key, "tracknumber") || !strcmp(key, "discnumber")) {
char *slash = strchr(val, '/');
if (slash)
*slash = 0;
}
/* don't add duplicates */
if (keyvals_get_val_growing(c, key)) {
free(val);
return 0;
}
keyvals_add(c, key, val);
return 1;
}
int comments_add_const(struct growing_keyvals *c, const char *key, const char *val)
{
return comments_add(c, key, xstrdup(val));
}