summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deadbeef.h22
-rw-r--r--junklib.c362
-rw-r--r--junklib.h13
-rw-r--r--plugins.c4
-rw-r--r--plugins/gtkui/callbacks.h4
-rw-r--r--plugins/gtkui/deadbeef.glade3
-rw-r--r--plugins/gtkui/interface.c15
-rw-r--r--plugins/gtkui/trkproperties.c40
8 files changed, 413 insertions, 50 deletions
diff --git a/deadbeef.h b/deadbeef.h
index f52a6326..de254a43 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -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);
diff --git a/junklib.c b/junklib.c
index f67b54d6..4104a4f0 100644
--- a/junklib.c
+++ b/junklib.c
@@ -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
diff --git a/junklib.h b/junklib.h
index 8d1a40ca..2566e135 100644
--- a/junklib.h
+++ b/junklib.h
@@ -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 *
diff --git a/plugins.c b/plugins.c
index 8992f449..58166e5c 100644
--- a/plugins.c
+++ b/plugins.c
@@ -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);
+}
+