diff options
-rw-r--r-- | deadbeef.h | 22 | ||||
-rw-r--r-- | junklib.c | 362 | ||||
-rw-r--r-- | junklib.h | 13 | ||||
-rw-r--r-- | plugins.c | 4 | ||||
-rw-r--r-- | plugins/gtkui/callbacks.h | 4 | ||||
-rw-r--r-- | plugins/gtkui/deadbeef.glade | 3 | ||||
-rw-r--r-- | plugins/gtkui/interface.c | 15 | ||||
-rw-r--r-- | plugins/gtkui/trkproperties.c | 40 |
8 files changed, 413 insertions, 50 deletions
@@ -29,6 +29,7 @@ #include <stdint.h> #include <time.h> +#include <stdio.h> #ifdef __cplusplus extern "C" { @@ -102,6 +103,21 @@ typedef struct DB_metaInfo_s { struct DB_metaInfo_s *next; } DB_metaInfo_t; +// FIXME: that needs to be in separate plugin +typedef struct DB_id3v2_frame_s { + struct DB_id3v2_frame_s *next; + char id[5]; + uint32_t size; + uint8_t data[0]; +} DB_id3v2_frame_t; + +typedef struct DB_id3v2_tag_s { + uint8_t version[2]; + uint8_t flags; + uint32_t size; + DB_id3v2_frame_t *frames; +} DB_id3v2_tag_t; + // plugin types enum { DB_PLUGIN_DECODER = 1, @@ -389,11 +405,15 @@ typedef struct { void (*volume_set_amp) (float amp); float (*volume_get_amp) (void); float (*volume_get_min_db) (void); - // junk reading + // junk reading/writing int (*junk_read_id3v1) (DB_playItem_t *it, DB_FILE *fp); int (*junk_read_id3v2) (DB_playItem_t *it, DB_FILE *fp); + int (*junk_read_id3v2_full) (DB_playItem_t *it, DB_id3v2_tag_t *tag, DB_FILE *fp); + void (*junk_free_id3v2) (DB_id3v2_tag_t *tag); + int (*junk_write_id3v2) (const char *fname, DB_id3v2_tag_t *tag); int (*junk_read_ape) (DB_playItem_t *it, DB_FILE *fp); int (*junk_get_leading_size) (DB_FILE *fp); + int (*junk_get_leading_size_stdio) (FILE *fp); void (*junk_copy) (DB_playItem_t *from, DB_playItem_t *first, DB_playItem_t *last); const char * (*junk_detect_charset) (const char *s); void (*junk_recode) (const char *in, int inlen, char *out, int outlen, const char *cs); @@ -21,6 +21,7 @@ #include <string.h> #define LIBICONV_PLUG #include <iconv.h> +#include <limits.h> #include "playlist.h" #include "utf8.h" #include "plugins.h" @@ -28,10 +29,12 @@ #include "config.h" #endif +#pragma GCC optimize("O0") + #define UTF8 "utf-8" -//#define trace(...) { fprintf(stderr, __VA_ARGS__); } -#define trace(fmt,...) +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) @@ -704,6 +707,32 @@ id3v2_string_read (int version, uint8_t *out, int sz, int unsync, const uint8_t } int +junk_get_leading_size_stdio (FILE *fp) { + uint8_t header[10]; + int pos = ftell (fp); + if (fread (header, 1, 10, fp) != 10) { + fseek (fp, pos, SEEK_SET); + return -1; // too short + } + fseek (fp, pos, SEEK_SET); + if (strncmp (header, "ID3", 3)) { + return -1; // no tag + } + uint8_t flags = header[5]; + if (flags & 15) { + return -1; // unsupported + } + int footerpresent = (flags & (1<<4)) ? 1 : 0; + // check for bad size + if ((header[9] & 0x80) || (header[8] & 0x80) || (header[7] & 0x80) || (header[6] & 0x80)) { + return -1; // bad header + } + uint32_t size = (header[9] << 0) | (header[8] << 7) | (header[7] << 14) | (header[6] << 21); + //trace ("junklib: leading junk size %d\n", size); + return size + 10 + 10 * footerpresent; +} + +int junk_get_leading_size (DB_FILE *fp) { uint8_t header[10]; int pos = deadbeef->ftell (fp); @@ -715,18 +744,10 @@ junk_get_leading_size (DB_FILE *fp) { if (strncmp (header, "ID3", 3)) { return -1; // no tag } -// uint8_t version_major = header[3]; -// uint8_t version_minor = header[4]; -// if (version_major > 4 || version_major < 2) { -// return -1; // unsupported -// } uint8_t flags = header[5]; if (flags & 15) { return -1; // unsupported } -// int unsync = (flags & (1<<7)) ? 1 : 0; -// int extheader = (flags & (1<<6)) ? 1 : 0; -// int expindicator = (flags & (1<<5)) ? 1 : 0; int footerpresent = (flags & (1<<4)) ? 1 : 0; // check for bad size if ((header[9] & 0x80) || (header[8] & 0x80) || (header[7] & 0x80) || (header[6] & 0x80)) { @@ -738,9 +759,205 @@ junk_get_leading_size (DB_FILE *fp) { } int -junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { +junk_write_id3v2 (const char *fname, DB_id3v2_tag_t *tag) { +/* +steps: +1. write tag to a new file +2. open source file, and skip id3v2 tag +3. copy remaining part of source file into new file +4. move new file in place of original file +*/ + FILE *out = NULL; + FILE *fp = NULL; + char *buffer = NULL; + int err = -1; + + char tmppath[PATH_MAX]; + snprintf (tmppath, sizeof (tmppath), "%s.temp.mp3", fname); + fprintf (stderr, "going to write tags to %s\n", tmppath); + +// int fd = mkstemp ("ddb-id3v2"); +// if (!fd) { +// fprintf (stderr, "junk_write_id3v2: failed to open temp file\n"); +// return -1; +// } +// out = fdopen (fd, "w+b"); + out = fopen (tmppath, "w+b"); + if (!out) { + fprintf (stderr, "junk_write_id3v2: failed to fdopen temp file\n"); + goto error; + } + + // write tag header + if (fwrite ("ID3", 1, 3, out) != 3) { + fprintf (stderr, "junk_write_id3v2: failed to write ID3 signature\n"); + goto error; + } + + if (fwrite (tag->version, 1, 2, out) != 2) { + fprintf (stderr, "junk_write_id3v2: failed to write tag version\n"); + goto error; + } + if (fwrite (&tag->flags, 1, 1, out) != 1) { + fprintf (stderr, "junk_write_id3v2: failed to write tag flags\n"); + goto error; + } + uint8_t flags = tag->flags; + flags &= ~(1<<6); // we don't (yet?) write ext header + flags &= ~(1<<4); // we don't write footer + + if (fwrite (&flags, 1, 1, out) != 1) { + fprintf (stderr, "junk_write_id3v2: failed to write tag flags\n"); + goto error; + } + uint8_t tagsize[4]; + + // run through list of frames, and calculate size + uint32_t sz = 0; + int frm = 0; + for (DB_id3v2_frame_t *f = tag->frames; f; f = f->next) { + printf ("frame %d: %s, size %d\n", frm++, f->id, f->size); + sz += 3; + if (tag->version[0] > 2) { + sz++; + } + sz += f->size; + } + + tagsize[0] |= (sz >> 21) & 0x7f; + tagsize[1] |= (sz >> 14) & 0x7f; + tagsize[2] |= (sz >> 7) & 0x7f; + tagsize[3] |= sz & 0x7f; + if (fwrite (tagsize, 1, 4, out) != 4) { + fprintf (stderr, "junk_write_id3v2: failed to write tag size\n"); + goto error; + } +#if 0 + int extheader = tag->flags & (1<<6); + if (extheader) { + uint8_t extsize[4]; + extsize[0] = (tag->ext_size >> 24) & 0xff; + extsize[1] = (tag->ext_size >> 16) & 0xff; + extsize[2] = (tag->ext_size >> 8) & 0xff; + extsize[3] = tag->ext_size & 0xff; + if (fwrite (extsize, 1, 4, out) != 4) { + fprintf (stderr, "junk_write_id3v2: failed to write ext header size\n"); + goto error; + } + uint8_t extflags[2]; + uint16_t ext_flags = tag->ext_flags &~ 0x8000; + extflags[0] = (tag->ext_flags >> 8) & 0xff; + extflags[1] = tag->ext_flags & 0xff; + if (fwrite (extflags, 1, 2, out) != 2) { + fprintf (stderr, "junk_write_id3v2: failed to write ext header flags\n"); + goto error; + } + uint8_t extpad[4]; + extpad[0] = (tag->ext_pad >> 24) & 0xff; + extpad[1] = (tag->ext_pad >> 16) & 0xff; + extpad[2] = (tag->ext_pad >> 8) & 0xff; + extpad[3] = tag->ext_pad & 0xff; + if (fwrite (extpad, 1, 4, out) != 4) { + fprintf (stderr, "junk_write_id3v2: failed to write ext padding\n"); + goto error; + } + } +#endif + + // write frames + for (DB_id3v2_frame_t *f = tag->frames; f; f = f->next) { + int id_size = 3; + uint8_t frame_size[4]; + if (tag->version[0] > 2) { + id_size = 4; + } + if (tag->version[0] == 3) { + frame_size[0] = (f->size >> 24) & 0xff; + frame_size[1] = (f->size >> 16) & 0xff; + frame_size[2] = (f->size >> 8) & 0xff; + frame_size[3] = f->size & 0xff; + } + else if (tag->version[0] == 4) { + frame_size[0] = (f->size >> 21) & 0x7f; + frame_size[1] = (f->size >> 14) & 0x7f; + frame_size[2] = (f->size >> 7) & 0x7f; + frame_size[3] = f->size & 0x7f; + } + if (fwrite (f->id, 1, 4, out) != 4) { + fprintf (stderr, "junk_write_id3v2: failed to write frame id %s\n", f->id); + goto error; + } + if (fwrite (frame_size, 1, 4, out) != 4) { + fprintf (stderr, "junk_write_id3v2: failed to write frame size, id %s, size %d\n", f->id, f->size); + goto error; + } + if (fwrite (f->data, 1, f->size, out) != f->size) { + fprintf (stderr, "junk_write_id3v2: failed to write frame data, id %s, size %s\n", f->id, f->size); + goto error; + } + sz += f->size; + } + + // skip id3v2 tag + fp = fopen (fname, "rb"); + if (!fp) { + fprintf (stderr, "junk_write_id3v2: failed to open source file %s\n", fname); + goto error; + } + int skip= junk_get_leading_size_stdio (fp); + if (skip > 0) { + fseek (fp, skip, SEEK_SET); + } + else { + rewind (fp); + } + + buffer = malloc (8192); + int rb = 0; + for (;;) { + rb = fread (buffer, 1, 8192, 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 + } + } + + err = 0; + +error: + if (out) { + fclose (out); + } + if (fp) { + fclose (fp); + } + if (buffer) { + free (buffer); + } + return err; +} + +void +junk_free_id3v2 (DB_id3v2_tag_t *tag) { + while (tag->frames) { + DB_id3v2_frame_t *next = tag->frames->next; + free (tag->frames); + tag->frames = next; + } +} + +int +junk_read_id3v2_full (playItem_t *it, DB_id3v2_tag_t *tag_store, DB_FILE *fp) { + DB_id3v2_frame_t *tail = NULL; int title_added = 0; - if (!it || !fp) { + if (!fp) { trace ("bad call to junk_read_id3v2!\n"); return -1; } @@ -755,11 +972,12 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { uint8_t version_major = header[3]; uint8_t version_minor = header[4]; if (version_major > 4 || version_major < 2) { -// trace ("id3v2.%d.%d is unsupported\n", version_major, version_minor); + trace ("id3v2.%d.%d is unsupported\n", version_major, version_minor); return -1; // unsupported } uint8_t flags = header[5]; if (flags & 15) { + trace ("unrecognized flags: one of low 15 bits is set, value=0x%x\n", (int)flags); return -1; // unsupported } int unsync = (flags & (1<<7)) ? 1 : 0; @@ -768,6 +986,7 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { int footerpresent = (flags & (1<<4)) ? 1 : 0; // check for bad size if ((header[9] & 0x80) || (header[8] & 0x80) || (header[7] & 0x80) || (header[6] & 0x80)) { + trace ("bad header size\n"); return -1; // bad header } uint32_t size = (header[9] << 0) | (header[8] << 7) | (header[7] << 14) | (header[6] << 21); @@ -777,41 +996,47 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { // it->startoffset = startoffset; // } -// trace ("tag size: %d\n", size); - + trace ("tag size: %d\n", size); + if (tag_store) { + tag_store->version[0] = version_major; + tag_store->version[1] = version_minor; + tag_store->flags = flags; + tag_store->size = size; + } - // try to read full tag if size is small enough - if (size > 1000000) { - return -1; + uint8_t *tag = malloc (size); + if (!tag) { + fprintf (stderr, "junklib: out of memory while reading id3v2, tried to alloc %d bytes\n", size); } - uint8_t tag[size]; if (deadbeef->fread (tag, 1, size, fp) != size) { - return -1; // bad size + goto error; // bad size } uint8_t *readptr = tag; int crcpresent = 0; trace ("version: 2.%d.%d, unsync: %d, extheader: %d, experimental: %d\n", version_major, version_minor, unsync, extheader, expindicator); if (extheader) { - if (size < 6) { - return -1; // bad size - } uint32_t sz = (readptr[3] << 0) | (header[2] << 8) | (header[1] << 16) | (header[0] << 24); - readptr += 4; + //if (size < 6) { + // goto error; // bad size + //} + readptr += sz; if (size < sz) { return -1; // bad size } +#if 0 uint16_t extflags = (readptr[1] << 0) | (readptr[0] << 8); readptr += 2; uint32_t pad = (readptr[3] << 0) | (header[2] << 8) | (header[1] << 16) | (header[0] << 24); readptr += 4; - if (extflags & 0x80000000) { + if (extflags & 0x8000) { crcpresent = 1; } if (crcpresent && sz != 10) { return -1; // bad header } readptr += 4; // skip crc +#endif } char * (*convstr)(const unsigned char *, int); if (version_major == 3) { @@ -866,6 +1091,24 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { // err = 1; break; // frame must be at least 1 byte long } + if (tag_store) { + DB_id3v2_frame_t *frm = malloc (sizeof (DB_id3v2_frame_t) + sz); + if (!frm) { + fprintf (stderr, "junklib: failed to alloc %d bytes for id3v2 frame %s\n", sizeof (DB_id3v2_frame_t) + sz, frameid); + goto error; + } + memset (frm, 0, sizeof (DB_id3v2_frame_t)); + if (tail) { + tail->next = frm; + } + tail = frm; + if (!tag_store->frames) { + tag_store->frames = frm; + } + strcpy (frm->id, frameid); + memcpy (frm->data, readptr, sz); + frm->size = sz; + } uint8_t flags1 = readptr[0]; uint8_t flags2 = readptr[1]; readptr += 2; @@ -961,13 +1204,14 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { id3v2_string_read (version_major, &str[0], sz, unsync, readptr); track = convstr (str, sz); - - char *slash = strchr (track, '/'); - if (slash) { - // split into track/number - *slash = 0; - slash++; - numtracks = strdup (slash); + if (track) { + char *slash = strchr (track, '/'); + if (slash) { + // split into track/number + *slash = 0; + slash++; + numtracks = strdup (slash); + } } } else if (!strcmp (frameid, "TPOS")) { @@ -1150,6 +1394,23 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { if (sz < 1) { break; // frame must be at least 1 byte long } + if (tag_store) { + DB_id3v2_frame_t *frm = malloc (sizeof (DB_id3v2_frame_t) + sz); + if (!frm) { + fprintf (stderr, "junklib: failed to alloc %d bytes for id3v2.2 frame %s\n", sizeof (DB_id3v2_frame_t) + sz, frameid); + goto error; + } + if (tail) { + tail->next = frm; + } + tail = frm; + if (!tag_store->frames) { + tag_store->frames = frm; + } + strcpy (frm->id, frameid); + memcpy (frm->data, readptr, sz); + frm->size = sz; + } // trace ("found id3v2.2 frame: %s, size=%d\n", frameid, sz); if (!strcmp (frameid, "TEN")) { char str[sz+2]; @@ -1245,12 +1506,14 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { id3v2_string_read (version_major, &str[0], sz, unsync, readptr); str[sz] = 0; track = convstr (str, sz); - char *slash = strchr (track, '/'); - if (slash) { - // split into track/number - *slash = 0; - slash++; - numtracks = strdup (slash); + if (track) { + char *slash = strchr (track, '/'); + if (slash) { + // split into track/number + *slash = 0; + slash++; + numtracks = strdup (slash); + } } } else if (!strcmp (frameid, "TYE")) { @@ -1316,7 +1579,7 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { trace ("id3v2.%d (unsupported!)\n", version_minor); } } - if (!err) { + if (!err && it) { if (artist) { pl_add_meta (it, "artist", artist); free (artist); @@ -1396,12 +1659,31 @@ junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { } return 0; } - else { + else if (err) { trace ("error parsing id3v2\n"); } + + return 0; + +error: + if (tag) { + free (tag); + } + if (tag_store) { + while (tag_store->frames) { + DB_id3v2_frame_t *next = tag_store->frames->next; + free (tag_store->frames); + tag_store->frames = next; + } + } return -1; } +int +junk_read_id3v2 (playItem_t *it, DB_FILE *fp) { + return junk_read_id3v2_full (it, NULL, fp); +} + const char * junk_detect_charset (const char *s) { // check if that's already utf8 @@ -18,6 +18,7 @@ #ifndef __JUNKLIB_H #define __JUNKLIB_H +#include <stdio.h> #include "deadbeef.h" struct playItem_s; @@ -26,12 +27,24 @@ int junk_read_id3v1 (struct playItem_s *it, DB_FILE *fp); int +junk_read_id3v2_full (struct playItem_s *it, DB_id3v2_tag_t *tag, DB_FILE *fp); + +int +junk_write_id3v2 (const char *fname, DB_id3v2_tag_t *tag); + +void +junk_free_id3v2 (DB_id3v2_tag_t *tag); + +int junk_read_id3v2 (struct playItem_s *it, DB_FILE *fp); int junk_read_ape (struct playItem_s *it, DB_FILE *fp); int +junk_get_leading_size_stdio (FILE *fp); + +int junk_get_leading_size (DB_FILE *fp); const char * @@ -180,8 +180,12 @@ static DB_functions_t deadbeef_api = { // junk reading .junk_read_id3v1 = (int (*)(DB_playItem_t *it, DB_FILE *fp))junk_read_id3v1, .junk_read_id3v2 = (int (*)(DB_playItem_t *it, DB_FILE *fp))junk_read_id3v2, + .junk_read_id3v2_full = (int (*)(DB_playItem_t *, DB_id3v2_tag_t *tag, DB_FILE *fp))junk_read_id3v2_full, + .junk_free_id3v2 = junk_free_id3v2, + .junk_write_id3v2 = junk_write_id3v2, .junk_read_ape = (int (*)(DB_playItem_t *it, DB_FILE *fp))junk_read_ape, .junk_get_leading_size = junk_get_leading_size, + .junk_get_leading_size_stdio = junk_get_leading_size_stdio, .junk_detect_charset = junk_detect_charset, .junk_recode = junk_recode, // vfs diff --git a/plugins/gtkui/callbacks.h b/plugins/gtkui/callbacks.h index 8010ed26..d8b11651 100644 --- a/plugins/gtkui/callbacks.h +++ b/plugins/gtkui/callbacks.h @@ -777,3 +777,7 @@ on_toggle_tabs (GtkMenuItem *menuitem, void on_toggle_eq (GtkMenuItem *menuitem, gpointer user_data); + +void +on_write_tags_clicked (GtkButton *button, + gpointer user_data); diff --git a/plugins/gtkui/deadbeef.glade b/plugins/gtkui/deadbeef.glade index 28252d9e..480b70d3 100644 --- a/plugins/gtkui/deadbeef.glade +++ b/plugins/gtkui/deadbeef.glade @@ -1931,7 +1931,7 @@ <property name="spacing">0</property> <child> - <widget class="GtkButton" id="button2"> + <widget class="GtkButton" id="write_tags"> <property name="visible">True</property> <property name="can_default">True</property> <property name="can_focus">True</property> @@ -1939,6 +1939,7 @@ <property name="use_underline">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> + <signal name="clicked" handler="on_write_tags_clicked" last_modification_time="Sat, 27 Mar 2010 20:48:33 GMT"/> </widget> </child> </widget> diff --git a/plugins/gtkui/interface.c b/plugins/gtkui/interface.c index fc877db3..6f7e5f21 100644 --- a/plugins/gtkui/interface.c +++ b/plugins/gtkui/interface.c @@ -1114,7 +1114,7 @@ create_trackproperties (void) GtkWidget *scrolledwindow5; GtkWidget *metalist; GtkWidget *hbuttonbox1; - GtkWidget *button2; + GtkWidget *write_tags; GtkWidget *label64; trackproperties = gtk_window_new (GTK_WINDOW_TOPLEVEL); @@ -1315,10 +1315,10 @@ create_trackproperties (void) gtk_box_pack_start (GTK_BOX (vbox16), hbuttonbox1, FALSE, FALSE, 0); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_END); - button2 = gtk_button_new_with_mnemonic ("Write"); - gtk_widget_show (button2); - gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2); - GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); + write_tags = gtk_button_new_with_mnemonic ("Write"); + gtk_widget_show (write_tags); + gtk_container_add (GTK_CONTAINER (hbuttonbox1), write_tags); + GTK_WIDGET_SET_FLAGS (write_tags, GTK_CAN_DEFAULT); label64 = gtk_label_new ("Full"); gtk_widget_show (label64); @@ -1330,6 +1330,9 @@ create_trackproperties (void) g_signal_connect ((gpointer) trackproperties, "delete_event", G_CALLBACK (on_trackproperties_delete_event), NULL); + g_signal_connect ((gpointer) write_tags, "clicked", + G_CALLBACK (on_write_tags_clicked), + NULL); /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF (trackproperties, trackproperties, "trackproperties"); @@ -1369,7 +1372,7 @@ create_trackproperties (void) GLADE_HOOKUP_OBJECT (trackproperties, scrolledwindow5, "scrolledwindow5"); GLADE_HOOKUP_OBJECT (trackproperties, metalist, "metalist"); GLADE_HOOKUP_OBJECT (trackproperties, hbuttonbox1, "hbuttonbox1"); - GLADE_HOOKUP_OBJECT (trackproperties, button2, "button2"); + GLADE_HOOKUP_OBJECT (trackproperties, write_tags, "write_tags"); GLADE_HOOKUP_OBJECT (trackproperties, label64, "label64"); return trackproperties; diff --git a/plugins/gtkui/trkproperties.c b/plugins/gtkui/trkproperties.c index a3e2a413..216f414e 100644 --- a/plugins/gtkui/trkproperties.c +++ b/plugins/gtkui/trkproperties.c @@ -25,9 +25,8 @@ #include "../../deadbeef.h" #include "gtkui.h" -#pragma GCC optimize("O0") - static GtkWidget *trackproperties; +static DB_playItem_t *track; gboolean on_trackproperties_delete_event (GtkWidget *widget, @@ -35,6 +34,10 @@ on_trackproperties_delete_event (GtkWidget *widget, gpointer user_data) { trackproperties = NULL; + if (track) { + deadbeef->pl_item_unref (track); + track = NULL; + } return FALSE; } @@ -45,6 +48,10 @@ on_trackproperties_key_press_event (GtkWidget *widget, { if (event->keyval == GDK_Escape) { trackproperties = NULL; + if (track) { + deadbeef->pl_item_unref (track); + track = NULL; + } gtk_widget_destroy (widget); } return FALSE; @@ -62,6 +69,10 @@ on_metadata_edited (GtkCellRendererText *renderer, gchar *path, gchar *new_text, void show_track_properties_dlg (DB_playItem_t *it) { + if (it) { + deadbeef->pl_item_ref (it); + } + track = it; if (!trackproperties) { trackproperties = create_trackproperties (); gtk_window_set_transient_for (GTK_WINDOW (trackproperties), GTK_WINDOW (mainwin)); @@ -183,3 +194,28 @@ show_track_properties_dlg (DB_playItem_t *it) { gtk_window_present (GTK_WINDOW (widget)); } +void +on_write_tags_clicked (GtkButton *button, + gpointer user_data) +{ + return; + DB_id3v2_tag_t tag; + memset (&tag, 0, sizeof (tag)); + DB_FILE *fp = deadbeef->fopen (track->fname); + if (fp) { + if (deadbeef->junk_read_id3v2_full (NULL, &tag, fp) < 0) { + fprintf (stderr, "failed to read tags from %s\n", track->fname); + goto error; + } + if (deadbeef->junk_write_id3v2 (track->fname, &tag) < 0) { + fprintf (stderr, "failed to write tags to %s\n", track->fname); + goto error; + } + } +error: + if (fp) { + deadbeef->fclose (fp); + } + deadbeef->junk_free_id3v2 (&tag); +} + |