diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2010-04-06 23:40:33 +0200 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2010-04-06 23:40:33 +0200 |
commit | 4cf0cf6185fffcd26ed4db15a832647d7409d86a (patch) | |
tree | 3d19eec29b216536ad09b2dd80b96a3dab75fc26 | |
parent | 9c6e2108adbcedccee5a2984b1d8ffc57e6b1087 (diff) |
moved high level id3v2/apev2/id3v1 tag writer into junklib;
added tag writer to wavpack plugin
-rw-r--r-- | deadbeef.h | 9 | ||||
-rw-r--r-- | junklib.c | 334 | ||||
-rw-r--r-- | junklib.h | 3 | ||||
-rw-r--r-- | plugins.c | 1 | ||||
-rw-r--r-- | plugins/gtkui/callbacks.h | 16 | ||||
-rw-r--r-- | plugins/gtkui/deadbeef.glade | 367 | ||||
-rw-r--r-- | plugins/gtkui/interface.c | 100 | ||||
-rw-r--r-- | plugins/gtkui/prefwin.c | 44 | ||||
-rw-r--r-- | plugins/mpgmad/mpgmad.c | 332 | ||||
-rw-r--r-- | plugins/wavpack/wavpack.c | 27 |
10 files changed, 814 insertions, 419 deletions
@@ -104,6 +104,14 @@ typedef struct DB_metaInfo_s { } DB_metaInfo_t; // FIXME: that needs to be in separate plugin + +#define JUNK_STRIP_ID3V2 1 +#define JUNK_STRIP_APEV2 2 +#define JUNK_STRIP_ID3V1 4 +#define JUNK_WRITE_ID3V2 8 +#define JUNK_WRITE_APEV2 16 +#define JUNK_WRITE_ID3V1 32 + typedef struct DB_id3v2_frame_s { struct DB_id3v2_frame_s *next; char id[5]; @@ -454,6 +462,7 @@ typedef struct { const char * (*junk_detect_charset) (const char *s); int (*junk_recode) (const char *in, int inlen, char *out, int outlen, const char *cs); int (*junk_iconv) (const char *in, int inlen, char *out, int outlen, const char *cs_in, const char *cs_out); + int (*junk_rewrite_tags) (DB_playItem_t *it, uint32_t flags, int id3v2_version, const char *id3v1_encoding); // vfs DB_FILE* (*fopen) (const char *fname); void (*fclose) (DB_FILE *f); @@ -24,6 +24,7 @@ #include <limits.h> #include <errno.h> #include <ctype.h> +#include <unistd.h> #include "playlist.h" #include "utf8.h" #include "plugins.h" @@ -2778,3 +2779,336 @@ junk_recode (const char *in, int inlen, char *out, int outlen, const char *cs) { return junk_iconv (in, inlen, out, outlen, cs, UTF8); } +int +junk_rewrite_tags (playItem_t *it, uint32_t junk_flags, int id3v2_version, const char *id3v1_encoding) { + int err = -1; + char *buffer = NULL; + DB_FILE *fp = NULL; + FILE *out = NULL; + + // get options + int strip_id3v2 = junk_flags & JUNK_STRIP_ID3V2; + int strip_id3v1 = junk_flags & JUNK_STRIP_ID3V1; + int strip_apev2 = junk_flags & JUNK_STRIP_APEV2; + int write_id3v2 = junk_flags & JUNK_WRITE_ID3V2; + int write_id3v1 = junk_flags & JUNK_WRITE_ID3V1; + int write_apev2 = junk_flags & JUNK_WRITE_APEV2; + + // find the beginning and the end of audio data + fp = deadbeef->fopen (it->fname); + if (!fp) { + return -1; + } + + int fsize = deadbeef->fgetlength (fp); + int id3v2_size = 0; + int id3v2_start = deadbeef->junk_id3v2_find (fp, &id3v2_size); + if (id3v2_start == -1) { + id3v2_size = -1; + } + + int32_t apev2_size; + uint32_t flags, numitems; + int apev2_start = deadbeef->junk_apev2_find (fp, &apev2_size, &flags, &numitems); + if (apev2_start == -1) { + apev2_start = 0; + } + + if (!strip_apev2 && !write_apev2) { + apev2_start = 0; + } + + int id3v1_start = deadbeef->junk_id3v1_find (fp); + if (id3v1_start == -1) { + id3v1_start = 0; + } + + int header = id3v2_start + id3v2_size; + int footer = fsize; + + if (id3v1_start > 0) { + footer = id3v1_start; + } + if (apev2_start > 0) { + footer = min (footer, apev2_start); + } + + // mapping between ddb metadata names and id3v2/apev2 names + const char *md[] = { + "artist", "TPE1", "Artist", + "band", "TPE2", NULL, + "disc", "TPOS", "Media", + "title", "TIT2", "Title", + "album", "TALB", "Album", + "copyright", "TCOP", "Copyright", + "genre", "TCON", "Genre", + "vendor", "TENC", NULL, + "performer", "TPE3", NULL, + "composer", "TCOM", "Composer", + "year", NULL, "Year", + "comment", NULL, "Comment", + "copyright", NULL, "Copyright", + "cuesheet", NULL, "Cuesheet", + NULL + }; + // "TRCK" -- special case + // "TYER"/"TDRC" -- special case + + // open output file + out = NULL; + char tmppath[PATH_MAX]; + snprintf (tmppath, sizeof (tmppath), "%s.temp", it->fname); + + out = fopen (tmppath, "w+b"); + trace ("will write tags into %s\n", tmppath); + if (!out) { + fprintf (stderr, "cmp3_write_metadata: failed to open temp file %s\n", tmppath); + goto error; + } + + DB_id3v2_tag_t id3v2; + DB_apev2_tag_t apev2; + + memset (&id3v2, 0, sizeof (id3v2)); + memset (&apev2, 0, sizeof (apev2)); + + if (!strip_id3v2 && !write_id3v2 && id3v2_size > 0) { + if (deadbeef->fseek (fp, id3v2_start, SEEK_SET) == -1) { + trace ("cmp3_write_metadata: failed to seek to original id3v2 tag position in %s\n", it->fname); + goto error; + } + uint8_t *buf = malloc (id3v2_size); + if (!buf) { + trace ("cmp3_write_metadata: failed to alloc %d bytes for id3v2 tag\n", id3v2_size); + goto error; + } + if (deadbeef->fread (buf, 1, id3v2_size, fp) != id3v2_size) { + trace ("cmp3_write_metadata: failed to read original id3v2 tag from %s\n", it->fname); + free (buf); + goto error; + } + if (fwrite (buf, 1, id3v2_size, out) != id3v2_size) { + trace ("cmp3_write_metadata: failed to copy original id3v2 tag from %s to temp file\n", it->fname); + free (buf); + goto error; + } + free (buf); + } + else if (write_id3v2) { + if (id3v2_size <= 0 || strip_id3v2 || deadbeef->junk_id3v2_read_full (NULL, &id3v2, fp) != 0) { + deadbeef->junk_id3v2_free (&id3v2); + memset (&id3v2, 0, sizeof (id3v2)); + id3v2.version[0] = id3v2_version; + } + // convert to required version + while (id3v2.version[0] != id3v2_version) { + DB_id3v2_tag_t converted; + memset (&converted, 0, sizeof (converted)); + if (id3v2.version[0] == 2) { + if (deadbeef->junk_id3v2_convert_22_to_24 (&id3v2, &converted) != 0) { + goto error; + } + deadbeef->junk_id3v2_free (&id3v2); + memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t)); + continue; + } + else if (id3v2.version[0] == 3) { + if (deadbeef->junk_id3v2_convert_23_to_24 (&id3v2, &converted) != 0) { + goto error; + } + deadbeef->junk_id3v2_free (&id3v2); + memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t)); + continue; + } + else if (id3v2.version[0] == 4) { + if (deadbeef->junk_id3v2_convert_24_to_23 (&id3v2, &converted) != 0) { + goto error; + } + deadbeef->junk_id3v2_free (&id3v2); + memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t)); + continue; + } + } + + DB_id3v2_frame_t *(*add_frame) (DB_id3v2_tag_t *tag, const char *frame_id, const char *value); + if (id3v2_version == 3) { + add_frame = deadbeef->junk_id3v2_add_text_frame_23; + } + else { + add_frame = deadbeef->junk_id3v2_add_text_frame_24; + } + + // add all basic frames + for (int i = 0; md[i]; i += 3) { + if (md[i+1]) { + const char *val = pl_find_meta (it, md[i]); + if (val) { + deadbeef->junk_id3v2_remove_frames (&id3v2, md[i+1]); + add_frame (&id3v2, md[i+1], val); + } + } + } + + // add tracknumber/totaltracks + const char *track = pl_find_meta (it, "track"); + const char *totaltracks = pl_find_meta (it, "numtracks"); + if (track && totaltracks) { + char s[100]; + snprintf (s, sizeof (s), "%s/%s", track, totaltracks); + junk_id3v2_remove_frames (&id3v2, "TRCK"); + add_frame (&id3v2, "TRCK", s); + } + else if (track) { + junk_id3v2_remove_frames (&id3v2, "TRCK"); + add_frame (&id3v2, "TRCK", track); + } + + // add year/date + const char *year = pl_find_meta (it, "year"); + if (year) { + // FIXME: format check + if (id3v2.version[0] == 3) { + junk_id3v2_remove_frames (&id3v2, "TYER"); + add_frame (&id3v2, "TYER", year); + } + else { + junk_id3v2_remove_frames (&id3v2, "TDRC"); + add_frame (&id3v2, "TDRC", year); + } + } + + // write tag + if (junk_id3v2_write (out, &id3v2) != 0) { + trace ("cmp3_write_metadata: failed to write id3v2 tag to %s\n", it->fname) + goto error; + } + } + + // now write audio data + buffer = malloc (8192); + deadbeef->fseek (fp, header, SEEK_SET); + int writesize = fsize; + if (footer > 0) { + writesize -= (fsize - footer); + } + writesize -= header; + trace ("writesize: %d, id3v1_start: %d, apev2_start: %d, footer: %d\n", writesize, id3v1_start, apev2_start, footer); + + while (writesize > 0) { + int rb = min (8192, writesize); + rb = deadbeef->fread (buffer, 1, rb, fp); + if (rb < 0) { + fprintf (stderr, "junk_write_id3v2: error reading input data\n"); + goto error; + } + if (fwrite (buffer, 1, rb, out) != rb) { + fprintf (stderr, "junk_write_id3v2: error writing output file\n"); + goto error; + } + if (rb == 0) { + break; // eof + } + writesize -= rb; + } + + if (!write_apev2 && !strip_apev2 && apev2_start != 0) { + if (deadbeef->fseek (fp, apev2_start, SEEK_SET) == -1) { + trace ("cmp3_write_metadata: failed to seek to original apev2 tag position in %s\n", it->fname); + goto error; + } + uint8_t *buf = malloc (apev2_size); + if (!buf) { + trace ("cmp3_write_metadata: failed to alloc %d bytes for apev2 tag\n", apev2_size); + goto error; + } + if (deadbeef->fread (buf, 1, apev2_size, fp) != apev2_size) { + trace ("cmp3_write_metadata: failed to read original apev2 tag from %s\n", it->fname); + free (buf); + goto error; + } + if (fwrite (buf, 1, apev2_size, out) != apev2_size) { + trace ("cmp3_write_metadata: failed to copy original apev2 tag from %s to temp file\n", it->fname); + free (buf); + goto error; + } + free (buf); + } + else if (write_apev2) { + if (!strip_apev2 || junk_apev2_read_full (NULL, &apev2, fp) != 0) { + deadbeef->junk_apev2_free (&apev2); + memset (&apev2, 0, sizeof (apev2)); + } + // add all basic frames + for (int i = 0; md[i]; i += 3) { + if (md[i+2]) { + const char *val = pl_find_meta (it, md[i]); + if (val) { + junk_apev2_remove_frames (&apev2, md[i+2]); + junk_apev2_add_text_frame (&apev2, md[i+2], val); + } + } + } + + // add tracknumber/totaltracks + const char *track = pl_find_meta (it, "track"); + const char *totaltracks = pl_find_meta (it, "numtracks"); + if (track && totaltracks) { + char s[100]; + snprintf (s, sizeof (s), "%s/%s", track, totaltracks); + junk_apev2_remove_frames (&apev2, "Track"); + junk_apev2_add_text_frame (&apev2, "Track", s); + } + else if (track) { + junk_apev2_remove_frames (&apev2, "Track"); + junk_apev2_add_text_frame (&apev2, "Track", track); + } + + // write tag + if (deadbeef->junk_apev2_write (out, &apev2, 0, 1) != 0) { + trace ("cmp3_write_metadata: failed to write apev2 tag to %s\n", it->fname) + goto error; + } + } + + if (!write_id3v1 && !strip_id3v1 && id3v1_start != 0) { + if (deadbeef->fseek (fp, id3v1_start, SEEK_SET) == -1) { + trace ("cmp3_write_metadata: failed to seek to original id3v1 tag position in %s\n", it->fname); + goto error; + } + char buf[128]; + if (deadbeef->fread (buf, 1, 128, fp) != 128) { + trace ("cmp3_write_metadata: failed to read original id3v1 tag from %s\n", it->fname); + goto error; + } + if (fwrite (buf, 1, 128, out) != 128) { + trace ("cmp3_write_metadata: failed to copy id3v1 tag from %s to temp file\n", it->fname); + goto error; + } + } + else if (write_id3v1) { + if (junk_id3v1_write (out, it) != 0) { + trace ("cmp3_write_metadata: failed to write id3v1 tag to %s\n", it->fname) + goto error; + } + } + + err = 0; +error: + if (fp) { + deadbeef->fclose (fp); + } + if (out) { + fclose (out); + } + if (buffer) { + free (buffer); + } + if (!err) { + rename (tmppath, it->fname); + } + else { + unlink (tmppath); + } + return err; +} + @@ -104,4 +104,7 @@ junk_iconv (const char *in, int inlen, char *out, int outlen, const char *cs_in, int junk_recode (const char *in, int inlen, char *out, int outlen, const char *cs); +int +junk_rewrite_tags (struct playItem_s *it, uint32_t junk_flags, int id3v2_version, const char *id3v1_encoding); + #endif // __JUNKLIB_H @@ -210,6 +210,7 @@ static DB_functions_t deadbeef_api = { .junk_detect_charset = junk_detect_charset, .junk_recode = junk_recode, .junk_iconv = junk_iconv, + .junk_rewrite_tags = (int (*) (DB_playItem_t *it, uint32_t flags, int id3v2_version, const char *id3v1_encoding))junk_rewrite_tags, // vfs .fopen = vfs_fopen, .fclose = vfs_fclose, diff --git a/plugins/gtkui/callbacks.h b/plugins/gtkui/callbacks.h index 876bfa2f..d397a0da 100644 --- a/plugins/gtkui/callbacks.h +++ b/plugins/gtkui/callbacks.h @@ -913,3 +913,19 @@ on_listview_selected_text_color_set (GtkColorButton *colorbutton, void on_listview_cursor_color_set (GtkColorButton *colorbutton, gpointer user_data); + +void +on_wv_write_apev2_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_wv_write_id3v1_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_wv_strip_apev2_toggled (GtkToggleButton *togglebutton, + gpointer user_data); + +void +on_wv_strip_id3v1_toggled (GtkToggleButton *togglebutton, + gpointer user_data); diff --git a/plugins/gtkui/deadbeef.glade b/plugins/gtkui/deadbeef.glade index 03eb8cf4..3606c124 100644 --- a/plugins/gtkui/deadbeef.glade +++ b/plugins/gtkui/deadbeef.glade @@ -3753,102 +3753,248 @@ SOCKS5_HOSTNAME</property> </child> <child> - <widget class="GtkFrame" id="frame6"> + <widget class="GtkHBox" id="hbox41"> <property name="visible">True</property> - <property name="label_xalign">0</property> - <property name="label_yalign">0.5</property> - <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> <child> - <widget class="GtkAlignment" id="alignment4"> + <widget class="GtkFrame" id="frame6"> <property name="visible">True</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xscale">1</property> - <property name="yscale">1</property> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">12</property> - <property name="right_padding">0</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> <child> - <widget class="GtkVBox" id="vbox20"> - <property name="border_width">12</property> + <widget class="GtkAlignment" id="alignment4"> <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">8</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">12</property> + <property name="right_padding">0</property> <child> - <widget class="GtkHBox" id="hbox37"> + <widget class="GtkVBox" id="vbox20"> + <property name="border_width">12</property> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">8</property> <child> - <widget class="GtkCheckButton" id="ape_write_id3v2"> + <widget class="GtkHBox" id="hbox37"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Write ID3v2.4</property> - <property name="use_underline">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> - <property name="active">False</property> - <property name="inconsistent">False</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_ape_write_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:42 GMT"/> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkCheckButton" id="ape_write_id3v2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Write ID3v2.4</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_ape_write_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:42 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="ape_write_apev2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Write APEv2</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_ape_write_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:46 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> </widget> <packing> <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> + <property name="expand">True</property> + <property name="fill">True</property> </packing> </child> <child> - <widget class="GtkCheckButton" id="ape_write_apev2"> + <widget class="GtkHBox" id="hbox45"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Write APEv2</property> - <property name="use_underline">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> - <property name="active">False</property> - <property name="inconsistent">False</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_ape_write_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:46 GMT"/> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkCheckButton" id="ape_strip_id3v2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Strip ID3v2</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_ape_strip_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:50 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="ape_strip_apev2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Strip APEv2</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_ape_strip_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:54 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> </widget> <packing> <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> + <property name="expand">True</property> + <property name="fill">True</property> </packing> </child> </widget> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> </child> + </widget> + </child> + + <child> + <widget class="GtkLabel" id="label70"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>APE</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkFrame" id="frame7"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <widget class="GtkAlignment" id="alignment5"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">1</property> + <property name="yscale">1</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">12</property> + <property name="right_padding">0</property> <child> - <widget class="GtkHBox" id="hbox41"> + <widget class="GtkVBox" id="vbox_wv"> + <property name="border_width">12</property> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">8</property> <child> - <widget class="GtkCheckButton" id="ape_strip_id3v2"> + <widget class="GtkHBox" id="hbox44"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Strip ID3v2</property> - <property name="use_underline">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> - <property name="active">False</property> - <property name="inconsistent">False</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_ape_strip_id3v2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:50 GMT"/> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkCheckButton" id="wv_write_apev2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Write APEv2</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_wv_write_apev2_toggled" last_modification_time="Tue, 06 Apr 2010 19:36:17 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="wv_write_id3v1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Write ID3v1</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_wv_write_id3v1_toggled" last_modification_time="Tue, 06 Apr 2010 19:36:13 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> </widget> <packing> <property name="padding">0</property> @@ -3858,17 +4004,50 @@ SOCKS5_HOSTNAME</property> </child> <child> - <widget class="GtkCheckButton" id="ape_strip_apev2"> + <widget class="GtkHBox" id="hbox43"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Strip APEv2</property> - <property name="use_underline">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> - <property name="active">False</property> - <property name="inconsistent">False</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_ape_strip_apev2_toggled" last_modification_time="Tue, 30 Mar 2010 20:44:54 GMT"/> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkCheckButton" id="wv_strip_apev2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Strip APEv2</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_wv_strip_apev2_toggled" last_modification_time="Tue, 06 Apr 2010 19:40:53 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="wv_strip_id3v1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Strip ID3v1</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_wv_strip_id3v1_toggled" last_modification_time="Tue, 06 Apr 2010 19:40:57 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> </widget> <packing> <property name="padding">0</property> @@ -3877,37 +4056,37 @@ SOCKS5_HOSTNAME</property> </packing> </child> </widget> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> </child> </widget> </child> - </widget> - </child> - <child> - <widget class="GtkLabel" id="label70"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>APE</b></property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> + <child> + <widget class="GtkLabel" id="label79"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>WavPack</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="type">label_item</property> + </packing> + </child> </widget> <packing> - <property name="type">label_item</property> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> </packing> </child> </widget> @@ -4287,7 +4466,7 @@ SOCKS5_HOSTNAME</property> </widget> <packing> <property name="padding">0</property> - <property name="expand">True</property> + <property name="expand">False</property> <property name="fill">True</property> </packing> </child> diff --git a/plugins/gtkui/interface.c b/plugins/gtkui/interface.c index f6fce1d2..b195f329 100644 --- a/plugins/gtkui/interface.c +++ b/plugins/gtkui/interface.c @@ -1473,16 +1473,27 @@ create_prefwin (void) GtkWidget *label71; GtkWidget *id3v1_encoding; GtkWidget *label68; + GtkWidget *hbox41; GtkWidget *frame6; GtkWidget *alignment4; GtkWidget *vbox20; GtkWidget *hbox37; GtkWidget *ape_write_id3v2; GtkWidget *ape_write_apev2; - GtkWidget *hbox41; + GtkWidget *hbox45; GtkWidget *ape_strip_id3v2; GtkWidget *ape_strip_apev2; GtkWidget *label70; + GtkWidget *frame7; + GtkWidget *alignment5; + GtkWidget *vbox_wv; + GtkWidget *hbox44; + GtkWidget *wv_write_apev2; + GtkWidget *wv_write_id3v1; + GtkWidget *hbox43; + GtkWidget *wv_strip_apev2; + GtkWidget *wv_strip_id3v1; + GtkWidget *label79; GtkWidget *label67; GtkWidget *hpaned1; GtkWidget *scrolledwindow2; @@ -1518,7 +1529,7 @@ create_prefwin (void) notebook2 = gtk_notebook_new (); gtk_widget_show (notebook2); - gtk_box_pack_start (GTK_BOX (dialog_vbox2), notebook2, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (dialog_vbox2), notebook2, FALSE, TRUE, 0); vbox10 = gtk_vbox_new (FALSE, 8); gtk_widget_show (vbox10); @@ -2023,9 +2034,13 @@ create_prefwin (void) gtk_frame_set_label_widget (GTK_FRAME (frame5), label68); gtk_label_set_use_markup (GTK_LABEL (label68), TRUE); + hbox41 = gtk_hbox_new (TRUE, 0); + gtk_widget_show (hbox41); + gtk_box_pack_start (GTK_BOX (vbox18), hbox41, FALSE, TRUE, 0); + frame6 = gtk_frame_new (NULL); gtk_widget_show (frame6); - gtk_box_pack_start (GTK_BOX (vbox18), frame6, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox41), frame6, TRUE, TRUE, 0); gtk_frame_set_shadow_type (GTK_FRAME (frame6), GTK_SHADOW_NONE); alignment4 = gtk_alignment_new (0.5, 0.5, 1, 1); @@ -2050,23 +2065,67 @@ create_prefwin (void) gtk_widget_show (ape_write_apev2); gtk_box_pack_start (GTK_BOX (hbox37), ape_write_apev2, FALSE, FALSE, 0); - hbox41 = gtk_hbox_new (FALSE, 8); - gtk_widget_show (hbox41); - gtk_box_pack_start (GTK_BOX (vbox20), hbox41, TRUE, TRUE, 0); + hbox45 = gtk_hbox_new (FALSE, 8); + gtk_widget_show (hbox45); + gtk_box_pack_start (GTK_BOX (vbox20), hbox45, TRUE, TRUE, 0); ape_strip_id3v2 = gtk_check_button_new_with_mnemonic ("Strip ID3v2"); gtk_widget_show (ape_strip_id3v2); - gtk_box_pack_start (GTK_BOX (hbox41), ape_strip_id3v2, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox45), ape_strip_id3v2, FALSE, FALSE, 0); ape_strip_apev2 = gtk_check_button_new_with_mnemonic ("Strip APEv2"); gtk_widget_show (ape_strip_apev2); - gtk_box_pack_start (GTK_BOX (hbox41), ape_strip_apev2, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox45), ape_strip_apev2, FALSE, FALSE, 0); label70 = gtk_label_new ("<b>APE</b>"); gtk_widget_show (label70); gtk_frame_set_label_widget (GTK_FRAME (frame6), label70); gtk_label_set_use_markup (GTK_LABEL (label70), TRUE); + frame7 = gtk_frame_new (NULL); + gtk_widget_show (frame7); + gtk_box_pack_start (GTK_BOX (hbox41), frame7, TRUE, TRUE, 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame7), GTK_SHADOW_NONE); + + alignment5 = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_widget_show (alignment5); + gtk_container_add (GTK_CONTAINER (frame7), alignment5); + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment5), 0, 0, 12, 0); + + vbox_wv = gtk_vbox_new (FALSE, 8); + gtk_widget_show (vbox_wv); + gtk_container_add (GTK_CONTAINER (alignment5), vbox_wv); + gtk_container_set_border_width (GTK_CONTAINER (vbox_wv), 12); + + hbox44 = gtk_hbox_new (FALSE, 8); + gtk_widget_show (hbox44); + gtk_box_pack_start (GTK_BOX (vbox_wv), hbox44, FALSE, FALSE, 0); + + wv_write_apev2 = gtk_check_button_new_with_mnemonic ("Write APEv2"); + gtk_widget_show (wv_write_apev2); + gtk_box_pack_start (GTK_BOX (hbox44), wv_write_apev2, FALSE, FALSE, 0); + + wv_write_id3v1 = gtk_check_button_new_with_mnemonic ("Write ID3v1"); + gtk_widget_show (wv_write_id3v1); + gtk_box_pack_start (GTK_BOX (hbox44), wv_write_id3v1, FALSE, FALSE, 0); + + hbox43 = gtk_hbox_new (FALSE, 8); + gtk_widget_show (hbox43); + gtk_box_pack_start (GTK_BOX (vbox_wv), hbox43, FALSE, FALSE, 0); + + wv_strip_apev2 = gtk_check_button_new_with_mnemonic ("Strip APEv2"); + gtk_widget_show (wv_strip_apev2); + gtk_box_pack_start (GTK_BOX (hbox43), wv_strip_apev2, FALSE, FALSE, 0); + + wv_strip_id3v1 = gtk_check_button_new_with_mnemonic ("Strip ID3v1"); + gtk_widget_show (wv_strip_id3v1); + gtk_box_pack_start (GTK_BOX (hbox43), wv_strip_id3v1, FALSE, FALSE, 0); + + label79 = gtk_label_new ("<b>WavPack</b>"); + gtk_widget_show (label79); + gtk_frame_set_label_widget (GTK_FRAME (frame7), label79); + gtk_label_set_use_markup (GTK_LABEL (label79), TRUE); + label67 = gtk_label_new ("Tag writer"); gtk_widget_show (label67); gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 5), label67); @@ -2287,6 +2346,18 @@ create_prefwin (void) g_signal_connect ((gpointer) ape_strip_apev2, "toggled", G_CALLBACK (on_ape_strip_apev2_toggled), NULL); + g_signal_connect ((gpointer) wv_write_apev2, "toggled", + G_CALLBACK (on_wv_write_apev2_toggled), + NULL); + g_signal_connect ((gpointer) wv_write_id3v1, "toggled", + G_CALLBACK (on_wv_write_id3v1_toggled), + NULL); + g_signal_connect ((gpointer) wv_strip_apev2, "toggled", + G_CALLBACK (on_wv_strip_apev2_toggled), + NULL); + g_signal_connect ((gpointer) wv_strip_id3v1, "toggled", + G_CALLBACK (on_wv_strip_id3v1_toggled), + NULL); g_signal_connect ((gpointer) pref_pluginlist, "cursor_changed", G_CALLBACK (on_pref_pluginlist_cursor_changed), NULL); @@ -2396,16 +2467,27 @@ create_prefwin (void) GLADE_HOOKUP_OBJECT (prefwin, label71, "label71"); GLADE_HOOKUP_OBJECT (prefwin, id3v1_encoding, "id3v1_encoding"); GLADE_HOOKUP_OBJECT (prefwin, label68, "label68"); + GLADE_HOOKUP_OBJECT (prefwin, hbox41, "hbox41"); GLADE_HOOKUP_OBJECT (prefwin, frame6, "frame6"); GLADE_HOOKUP_OBJECT (prefwin, alignment4, "alignment4"); GLADE_HOOKUP_OBJECT (prefwin, vbox20, "vbox20"); GLADE_HOOKUP_OBJECT (prefwin, hbox37, "hbox37"); GLADE_HOOKUP_OBJECT (prefwin, ape_write_id3v2, "ape_write_id3v2"); GLADE_HOOKUP_OBJECT (prefwin, ape_write_apev2, "ape_write_apev2"); - GLADE_HOOKUP_OBJECT (prefwin, hbox41, "hbox41"); + GLADE_HOOKUP_OBJECT (prefwin, hbox45, "hbox45"); GLADE_HOOKUP_OBJECT (prefwin, ape_strip_id3v2, "ape_strip_id3v2"); GLADE_HOOKUP_OBJECT (prefwin, ape_strip_apev2, "ape_strip_apev2"); GLADE_HOOKUP_OBJECT (prefwin, label70, "label70"); + GLADE_HOOKUP_OBJECT (prefwin, frame7, "frame7"); + GLADE_HOOKUP_OBJECT (prefwin, alignment5, "alignment5"); + GLADE_HOOKUP_OBJECT (prefwin, vbox_wv, "vbox_wv"); + GLADE_HOOKUP_OBJECT (prefwin, hbox44, "hbox44"); + GLADE_HOOKUP_OBJECT (prefwin, wv_write_apev2, "wv_write_apev2"); + GLADE_HOOKUP_OBJECT (prefwin, wv_write_id3v1, "wv_write_id3v1"); + GLADE_HOOKUP_OBJECT (prefwin, hbox43, "hbox43"); + GLADE_HOOKUP_OBJECT (prefwin, wv_strip_apev2, "wv_strip_apev2"); + GLADE_HOOKUP_OBJECT (prefwin, wv_strip_id3v1, "wv_strip_id3v1"); + GLADE_HOOKUP_OBJECT (prefwin, label79, "label79"); GLADE_HOOKUP_OBJECT (prefwin, label67, "label67"); GLADE_HOOKUP_OBJECT (prefwin, hpaned1, "hpaned1"); GLADE_HOOKUP_OBJECT (prefwin, scrolledwindow2, "scrolledwindow2"); diff --git a/plugins/gtkui/prefwin.c b/plugins/gtkui/prefwin.c index 55a50f41..256debb0 100644 --- a/plugins/gtkui/prefwin.c +++ b/plugins/gtkui/prefwin.c @@ -453,6 +453,10 @@ on_preferences_activate (GtkMenuItem *menuitem, int ape_strip_apev2 = deadbeef->conf_get_int ("ape.strip_apev2", 0); int ape_write_id3v2 = deadbeef->conf_get_int ("ape.write_id3v2", 0); int ape_write_apev2 = deadbeef->conf_get_int ("ape.write_apev2", 1); + int wv_strip_apev2 = deadbeef->conf_get_int ("wv.strip_apev2", 0); + int wv_strip_id3v1 = deadbeef->conf_get_int ("wv.strip_id3v1", 0); + int wv_write_apev2 = deadbeef->conf_get_int ("wv.write_apev2", 1); + int wv_write_id3v1 = deadbeef->conf_get_int ("wv.write_id3v1", 0); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "strip_id3v2")), strip_id3v2); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "strip_id3v1")), strip_id3v1); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "strip_apev2")), strip_apev2); @@ -466,6 +470,11 @@ on_preferences_activate (GtkMenuItem *menuitem, gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "ape_write_apev2")), ape_write_apev2); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "ape_write_id3v2")), ape_write_id3v2); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "wv_strip_id3v1")), wv_strip_id3v1); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "wv_strip_apev2")), wv_strip_apev2); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "wv_write_apev2")), wv_write_apev2); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lookup_widget (prefwin, "wv_write_id3v1")), wv_write_id3v1); + gtk_dialog_run (GTK_DIALOG (prefwin)); gtk_widget_destroy (prefwin); prefwin = NULL; @@ -566,6 +575,13 @@ on_pref_close_send_to_tray_clicked (GtkButton *button, } void +on_mmb_delete_playlist_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + deadbeef->conf_set_int ("gtkui.mmb_delete_playlist", gtk_toggle_button_get_active (togglebutton)); +} + +void on_pref_pluginlist_cursor_changed (GtkTreeView *treeview, gpointer user_data) { @@ -950,10 +966,34 @@ on_ape_strip_apev2_toggled (GtkToggleButton *togglebutton, deadbeef->conf_set_int ("ape.strip_apev2", gtk_toggle_button_get_active (togglebutton)); } + void -on_mmb_delete_playlist_toggled (GtkToggleButton *togglebutton, +on_wv_write_apev2_toggled (GtkToggleButton *togglebutton, gpointer user_data) { - deadbeef->conf_set_int ("gtkui.mmb_delete_playlist", gtk_toggle_button_get_active (togglebutton)); + deadbeef->conf_set_int ("wv.write_apev2", gtk_toggle_button_get_active (togglebutton)); +} + + +void +on_wv_write_id3v1_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + deadbeef->conf_set_int ("wv.write_id3v1", gtk_toggle_button_get_active (togglebutton)); +} + +void +on_wv_strip_apev2_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + deadbeef->conf_set_int ("wv.strip_apev2", gtk_toggle_button_get_active (togglebutton)); +} + + +void +on_wv_strip_id3v1_toggled (GtkToggleButton *togglebutton, + gpointer user_data) +{ + deadbeef->conf_set_int ("wv.strip_id3v1", gtk_toggle_button_get_active (togglebutton)); } diff --git a/plugins/mpgmad/mpgmad.c b/plugins/mpgmad/mpgmad.c index 98b20e85..9a6e4def 100644 --- a/plugins/mpgmad/mpgmad.c +++ b/plugins/mpgmad/mpgmad.c @@ -1189,335 +1189,41 @@ cmp3_read_metadata (DB_playItem_t *it) { int cmp3_write_metadata (DB_playItem_t *it) { - int err = -1; - char *buffer = NULL; - DB_FILE *fp = NULL; - FILE *out = NULL; - // get options + int strip_id3v2 = deadbeef->conf_get_int ("mp3.strip_id3v2", 0); int strip_id3v1 = deadbeef->conf_get_int ("mp3.strip_id3v2", 0); int strip_apev2 = deadbeef->conf_get_int ("mp3.strip_apev2", 0); int write_id3v2 = deadbeef->conf_get_int ("mp3.write_id3v2", 1); int write_id3v1 = deadbeef->conf_get_int ("mp3.write_id3v1", 0); int write_apev2 = deadbeef->conf_get_int ("mp3.write_apev2", 1); - int id3v2_version = deadbeef->conf_get_int ("mp3.id3v2_version", 3); - if (id3v2_version != 3 && id3v2_version != 4) { - id3v2_version = 3; - } - const char *id3v1_encoding = deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1"); - - // find the beginning and the end of audio data - fp = deadbeef->fopen (it->fname); - if (!fp) { - return -1; - } - - int fsize = deadbeef->fgetlength (fp); - int id3v2_size = 0; - int id3v2_start = deadbeef->junk_id3v2_find (fp, &id3v2_size); - if (id3v2_start == -1) { - id3v2_size = -1; - } - int32_t apev2_size; - uint32_t flags, numitems; - int apev2_start = deadbeef->junk_apev2_find (fp, &apev2_size, &flags, &numitems); - if (apev2_start == -1) { - apev2_start = 0; + uint32_t junk_flags = 0; + if (strip_id3v2) { + junk_flags |= JUNK_STRIP_ID3V2; } - - if (!strip_apev2 && !write_apev2) { - apev2_start = 0; + if (strip_id3v1) { + junk_flags |= JUNK_STRIP_ID3V1; } - - int id3v1_start = deadbeef->junk_id3v1_find (fp); - if (id3v1_start == -1) { - id3v1_start = 0; + if (strip_apev2) { + junk_flags |= JUNK_STRIP_APEV2; } - - int header = id3v2_start + id3v2_size; - int footer = fsize; - - if (id3v1_start > 0) { - footer = id3v1_start; + if (write_id3v2) { + junk_flags |= JUNK_WRITE_ID3V2; } - if (apev2_start > 0) { - footer = min (footer, apev2_start); + if (write_id3v1) { + junk_flags |= JUNK_WRITE_ID3V1; } - - // mapping between ddb metadata names and id3v2/apev2 names - const char *md[] = { - "artist", "TPE1", "Artist", - "band", "TPE2", NULL, - "disc", "TPOS", "Media", - "title", "TIT2", "Title", - "album", "TALB", "Album", - "copyright", "TCOP", "Copyright", - "genre", "TCON", "Genre", - "vendor", "TENC", NULL, - "performer", "TPE3", NULL, - "composer", "TCOM", "Composer", - "year", NULL, "Year", - "comment", NULL, "Comment", - "copyright", NULL, "Copyright", - "cuesheet", NULL, "Cuesheet", - NULL - }; - // "TRCK" -- special case - // "TYER"/"TDRC" -- special case - - // open output file - out = NULL; - char tmppath[PATH_MAX]; - snprintf (tmppath, sizeof (tmppath), "%s.temp.mp3", it->fname); - - out = fopen (tmppath, "w+b"); - trace ("will write tags into %s\n", tmppath); - if (!out) { - fprintf (stderr, "cmp3_write_metadata: failed to open temp file %s\n", tmppath); - goto error; + if (write_apev2) { + junk_flags |= JUNK_WRITE_APEV2; } - DB_id3v2_tag_t id3v2; - DB_apev2_tag_t apev2; - - memset (&id3v2, 0, sizeof (id3v2)); - memset (&apev2, 0, sizeof (apev2)); - - if (!strip_id3v2 && !write_id3v2 && id3v2_size > 0) { - if (deadbeef->fseek (fp, id3v2_start, SEEK_SET) == -1) { - trace ("cmp3_write_metadata: failed to seek to original id3v2 tag position in %s\n", it->fname); - goto error; - } - uint8_t *buf = malloc (id3v2_size); - if (!buf) { - trace ("cmp3_write_metadata: failed to alloc %d bytes for id3v2 tag\n", id3v2_size); - goto error; - } - if (deadbeef->fread (buf, 1, id3v2_size, fp) != id3v2_size) { - trace ("cmp3_write_metadata: failed to read original id3v2 tag from %s\n", it->fname); - free (buf); - goto error; - } - if (fwrite (buf, 1, id3v2_size, out) != id3v2_size) { - trace ("cmp3_write_metadata: failed to copy original id3v2 tag from %s to temp file\n", it->fname); - free (buf); - goto error; - } - free (buf); - } - else if (write_id3v2) { - if (id3v2_size <= 0 || strip_id3v2 || deadbeef->junk_id3v2_read_full (NULL, &id3v2, fp) != 0) { - deadbeef->junk_id3v2_free (&id3v2); - memset (&id3v2, 0, sizeof (id3v2)); - id3v2.version[0] = id3v2_version; - } - // convert to required version - while (id3v2.version[0] != id3v2_version) { - DB_id3v2_tag_t converted; - memset (&converted, 0, sizeof (converted)); - if (id3v2.version[0] == 2) { - if (deadbeef->junk_id3v2_convert_22_to_24 (&id3v2, &converted) != 0) { - goto error; - } - deadbeef->junk_id3v2_free (&id3v2); - memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t)); - continue; - } - else if (id3v2.version[0] == 3) { - if (deadbeef->junk_id3v2_convert_23_to_24 (&id3v2, &converted) != 0) { - goto error; - } - deadbeef->junk_id3v2_free (&id3v2); - memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t)); - continue; - } - else if (id3v2.version[0] == 4) { - if (deadbeef->junk_id3v2_convert_24_to_23 (&id3v2, &converted) != 0) { - goto error; - } - deadbeef->junk_id3v2_free (&id3v2); - memcpy (&id3v2, &converted, sizeof (DB_id3v2_tag_t)); - continue; - } - } - - DB_id3v2_frame_t *(*add_frame) (DB_id3v2_tag_t *tag, const char *frame_id, const char *value); - if (id3v2_version == 3) { - add_frame = deadbeef->junk_id3v2_add_text_frame_23; - } - else { - add_frame = deadbeef->junk_id3v2_add_text_frame_24; - } - - // add all basic frames - for (int i = 0; md[i]; i += 3) { - if (md[i+1]) { - const char *val = deadbeef->pl_find_meta (it, md[i]); - if (val) { - deadbeef->junk_id3v2_remove_frames (&id3v2, md[i+1]); - add_frame (&id3v2, md[i+1], val); - } - } - } - - // add tracknumber/totaltracks - const char *track = deadbeef->pl_find_meta (it, "track"); - const char *totaltracks = deadbeef->pl_find_meta (it, "numtracks"); - if (track && totaltracks) { - char s[100]; - snprintf (s, sizeof (s), "%s/%s", track, totaltracks); - deadbeef->junk_id3v2_remove_frames (&id3v2, "TRCK"); - add_frame (&id3v2, "TRCK", s); - } - else if (track) { - deadbeef->junk_id3v2_remove_frames (&id3v2, "TRCK"); - add_frame (&id3v2, "TRCK", track); - } - - // add year/date - const char *year = deadbeef->pl_find_meta (it, "year"); - if (year) { - // FIXME: format check - if (id3v2.version[0] == 3) { - deadbeef->junk_id3v2_remove_frames (&id3v2, "TYER"); - add_frame (&id3v2, "TYER", year); - } - else { - deadbeef->junk_id3v2_remove_frames (&id3v2, "TDRC"); - add_frame (&id3v2, "TDRC", year); - } - } - - // write tag - if (deadbeef->junk_id3v2_write (out, &id3v2) != 0) { - trace ("cmp3_write_metadata: failed to write id3v2 tag to %s\n", it->fname) - goto error; - } - } - - // now write audio data - buffer = malloc (8192); - deadbeef->fseek (fp, header, SEEK_SET); - int writesize = fsize; - if (footer > 0) { - writesize -= (fsize - footer); - } - writesize -= header; - trace ("writesize: %d, id3v1_start: %d, apev2_start: %d, footer: %d\n", writesize, id3v1_start, apev2_start, footer); - - while (writesize > 0) { - int rb = min (8192, writesize); - rb = deadbeef->fread (buffer, 1, rb, fp); - if (rb < 0) { - fprintf (stderr, "junk_write_id3v2: error reading input data\n"); - goto error; - } - if (fwrite (buffer, 1, rb, out) != rb) { - fprintf (stderr, "junk_write_id3v2: error writing output file\n"); - goto error; - } - if (rb == 0) { - break; // eof - } - writesize -= rb; - } - - if (!write_apev2 && !strip_apev2 && apev2_start != 0) { - if (deadbeef->fseek (fp, apev2_start, SEEK_SET) == -1) { - trace ("cmp3_write_metadata: failed to seek to original apev2 tag position in %s\n", it->fname); - goto error; - } - uint8_t *buf = malloc (apev2_size); - if (!buf) { - trace ("cmp3_write_metadata: failed to alloc %d bytes for apev2 tag\n", apev2_size); - goto error; - } - if (deadbeef->fread (buf, 1, apev2_size, fp) != apev2_size) { - trace ("cmp3_write_metadata: failed to read original apev2 tag from %s\n", it->fname); - free (buf); - goto error; - } - if (fwrite (buf, 1, apev2_size, out) != apev2_size) { - trace ("cmp3_write_metadata: failed to copy original apev2 tag from %s to temp file\n", it->fname); - free (buf); - goto error; - } - free (buf); - } - else if (write_apev2) { - if (!strip_apev2 || deadbeef->junk_apev2_read_full (NULL, &apev2, fp) != 0) { - deadbeef->junk_apev2_free (&apev2); - memset (&apev2, 0, sizeof (apev2)); - } - // add all basic frames - for (int i = 0; md[i]; i += 3) { - if (md[i+2]) { - const char *val = deadbeef->pl_find_meta (it, md[i]); - if (val) { - deadbeef->junk_apev2_remove_frames (&apev2, md[i+2]); - deadbeef->junk_apev2_add_text_frame (&apev2, md[i+2], val); - } - } - } - - // add tracknumber/totaltracks - const char *track = deadbeef->pl_find_meta (it, "track"); - const char *totaltracks = deadbeef->pl_find_meta (it, "numtracks"); - if (track && totaltracks) { - char s[100]; - snprintf (s, sizeof (s), "%s/%s", track, totaltracks); - deadbeef->junk_apev2_remove_frames (&apev2, "Track"); - deadbeef->junk_apev2_add_text_frame (&apev2, "Track", s); - } - else if (track) { - deadbeef->junk_apev2_remove_frames (&apev2, "Track"); - deadbeef->junk_apev2_add_text_frame (&apev2, "Track", track); - } - - // write tag - if (deadbeef->junk_apev2_write (out, &apev2, 0, 1) != 0) { - trace ("cmp3_write_metadata: failed to write apev2 tag to %s\n", it->fname) - goto error; - } - } - - if (!write_id3v1 && !strip_id3v1 && id3v1_start != 0) { - if (deadbeef->fseek (fp, id3v1_start, SEEK_SET) == -1) { - trace ("cmp3_write_metadata: failed to seek to original id3v1 tag position in %s\n", it->fname); - goto error; - } - char buf[128]; - if (deadbeef->fread (buf, 1, 128, fp) != 128) { - trace ("cmp3_write_metadata: failed to read original id3v1 tag from %s\n", it->fname); - goto error; - } - if (fwrite (buf, 1, 128, out) != 128) { - trace ("cmp3_write_metadata: failed to copy id3v1 tag from %s to temp file\n", it->fname); - goto error; - } - } - else if (write_id3v1) { - if (deadbeef->junk_id3v1_write (out, it) != 0) { - trace ("cmp3_write_metadata: failed to write id3v1 tag to %s\n", it->fname) - goto error; - } - } - - err = 0; -error: - if (fp) { - deadbeef->fclose (fp); - } - if (out) { - fclose (out); - } - if (buffer) { - free (buffer); + int id3v2_version = deadbeef->conf_get_int ("mp3.id3v2_version", 3); + if (id3v2_version != 3 && id3v2_version != 4) { + id3v2_version = 3; } -// unlink (tmppath); - return err; + const char *id3v1_encoding = deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1"); + return deadbeef->junk_rewrite_tags (it, junk_flags, id3v2_version, id3v1_encoding); } static const char *exts[] = { diff --git a/plugins/wavpack/wavpack.c b/plugins/wavpack/wavpack.c index ffbd1bd1..f3205570 100644 --- a/plugins/wavpack/wavpack.c +++ b/plugins/wavpack/wavpack.c @@ -330,7 +330,31 @@ wv_read_metadata (DB_playItem_t *it) { return 0; } -static const char * exts[] = { "wv", NULL }; +int +wv_write_metadata (DB_playItem_t *it) { + int strip_apev2 = deadbeef->conf_get_int ("wv.strip_apev2", 0); + int strip_id3v1 = deadbeef->conf_get_int ("wv.strip_id3v1", 0); + int write_apev2 = deadbeef->conf_get_int ("wv.write_apev2", 1); + int write_id3v1 = deadbeef->conf_get_int ("wv.write_id3v1", 0); + + uint32_t junk_flags = 0; + if (strip_id3v1) { + junk_flags |= JUNK_STRIP_ID3V1; + } + if (strip_apev2) { + junk_flags |= JUNK_STRIP_APEV2; + } + if (write_id3v1) { + junk_flags |= JUNK_WRITE_ID3V1; + } + if (write_apev2) { + junk_flags |= JUNK_WRITE_APEV2; + } + + return deadbeef->junk_rewrite_tags (it, junk_flags, 0, NULL); +} + +static const char *exts[] = { "wv", NULL }; static const char *filetypes[] = { "wv", NULL }; // define plugin interface @@ -353,6 +377,7 @@ static DB_decoder_t plugin = { .seek_sample = wv_seek_sample, .insert = wv_insert, .read_metadata = wv_read_metadata, + .write_metadata = wv_write_metadata, .exts = exts, .filetypes = filetypes }; |