From 412fa3b7a219545a4262374e70f8a44f392e800c Mon Sep 17 00:00:00 2001 From: Josh Coalson Date: Thu, 11 Jul 2002 06:15:30 +0000 Subject: [PATCH] Daisuke Shimamura's id3 v1/v2 + i18n patches --- configure.in | 43 +++ src/plugin_xmms/Makefile.am | 17 +- src/plugin_xmms/Makefile.lite | 6 +- src/plugin_xmms/charset.c | 306 ++++++++++++++++++++ src/plugin_xmms/charset.h | 57 ++++ src/plugin_xmms/configure.c | 258 +++++++++++++++++ src/plugin_xmms/configure.h | 42 +++ src/plugin_xmms/fileinfo.c | 325 ++++++++++++++++++++++ src/plugin_xmms/genres.h | 187 +++++++++++++ src/plugin_xmms/id3_tag.c | 508 ++++++++++++++++++++++++++++++++++ src/plugin_xmms/id3_tag.h | 67 +++++ src/plugin_xmms/mylocale.h | 55 ++++ src/plugin_xmms/plugin.c | 118 +++----- src/plugin_xmms/wrap_id3.c | 272 ++++++++++++++++++ src/plugin_xmms/wrap_id3.h | 24 ++ 15 files changed, 2209 insertions(+), 76 deletions(-) create mode 100644 src/plugin_xmms/charset.c create mode 100644 src/plugin_xmms/charset.h create mode 100644 src/plugin_xmms/configure.c create mode 100644 src/plugin_xmms/configure.h create mode 100644 src/plugin_xmms/fileinfo.c create mode 100644 src/plugin_xmms/genres.h create mode 100644 src/plugin_xmms/id3_tag.c create mode 100644 src/plugin_xmms/id3_tag.h create mode 100644 src/plugin_xmms/mylocale.h create mode 100644 src/plugin_xmms/wrap_id3.c create mode 100644 src/plugin_xmms/wrap_id3.h diff --git a/configure.in b/configure.in index 5a297c16..683584fe 100644 --- a/configure.in +++ b/configure.in @@ -104,6 +104,49 @@ AM_CONDITIONAL(FLaC__HAS_XMMS, test x$XMMS_INPUT_PLUGIN_DIR != x) SHARE_LIBS='$(top_builddir)/src/share/libutf8.a $(top_builddir)/src/share/libgetopt.a' +dnl check for i18n(internationalization) +AM_WITH_NLS +AM_ICONV +AM_LANGINFO_CODESET + +dnl check id3lib librairies +LIBS_save_blah_blah_blah=$LIBS +LIBS="" +AC_SEARCH_LIBS(ID3Tag_Link,"id3" "id3 -lstdc++" "id3 -lz" "id3 -lz -lstdc++", + [have_id3lib=yes], + [AC_MSG_WARN([id3lib not found - ID3v2 will not be supported, internal function support only id3v1])]) +AM_CONDITIONAL(FLaC__HAS_ID3LIB, [test x$have_id3lib = xyes]) +if test x$have_id3lib = xyes ; then +AC_DEFINE(FLAC__HAS_ID3LIB) +ID3LIBS=$LIBS +fi +AC_SUBST(ID3LIBS) + +dnl expected version for cross compiling +ID3LIB_MAJOR=3 +ID3LIB_MINOR=8 +ID3LIB_PATCH=0 + +AC_MSG_CHECKING(for id3lib version) + AC_TRY_RUN([ +#include +#include +int +main () +{ + FILE *output; + output=fopen("conftest.id3","w"); + fprintf(output,"ID3LIB_MAJOR=%d\nID3LIB_MINOR=%d\nID3LIB_PATCH=%d\n",ID3LIB_MAJOR_VERSION,ID3LIB_MINOR_VERSION,ID3LIB_PATCH_VERSION); + fclose(output); + exit(0); +} +], . conftest.id3; echo "${ID3LIB_MAJOR}.${ID3LIB_MINOR}.${ID3LIB_PATCH}", AC_MSG_WARN(could not determine id3lib version),[echo $ac_n "cross compiling; assuming ${ID3LIB_MAJOR}.${ID3LIB_MINOR}.${ID3LIB_PATCH} $ac_c"]) +AC_DEFINE_UNQUOTED(ID3LIB_MAJOR, $ID3LIB_MAJOR) +AC_DEFINE_UNQUOTED(ID3LIB_MINOR, $ID3LIB_MINOR) +AC_DEFINE_UNQUOTED(ID3LIB_PATCH, $ID3LIB_PATCH) + +LIBS=$LIBS_save_blah_blah_blah + AC_CHECK_PROGS(NASM, nasm) AM_CONDITIONAL(FLaC__HAS_NASM, test -n "$NASM") if test -n "$NASM" ; then diff --git a/src/plugin_xmms/Makefile.am b/src/plugin_xmms/Makefile.am index d2d3c1bf..08bc019d 100644 --- a/src/plugin_xmms/Makefile.am +++ b/src/plugin_xmms/Makefile.am @@ -20,15 +20,26 @@ # EXTRA_DIST = \ - Makefile.lite + Makefile.lite \ + id3_tag.c CFLAGS = @CFLAGS@ @XMMS_CFLAGS@ xmmsinputplugindir = @XMMS_INPUT_PLUGIN_DIR@ + # Don't build a static library LIBTOOL = $(top_builddir)/libtool-disable-static xmmsinputplugin_LTLIBRARIES = libxmms-flac.la -libxmms_flac_la_SOURCES = plugin.c + +plugin_sources = plugin.c wrap_id3.c configure.c charset.c +id3v2_sources = id3_tag.c + +if FLaC__HAS_ID3LIB +libxmms_flac_la_SOURCES = $(plugin_sources) $(id3v2_sources) +else +libxmms_flac_la_SOURCES = $(plugin_sources) +endif + # work around the bug in libtool where its relinking fails with a different DESTDIR # for libtool bug info see: # http://mail.gnu.org/pipermail/bug-libtool/2002-February/003018.html @@ -37,5 +48,5 @@ libxmms_flac_la_SOURCES = plugin.c # for fix info see: # http://lists.freshrpms.net/pipermail/rpm-list/2002-April/000746.html # the workaround is the extra '-L$(top_builddir)/src/libFLAC/.libs' -libxmms_flac_la_LIBADD = $(top_builddir)/src/libFLAC/libFLAC.la -L$(top_builddir)/src/libFLAC/.libs @XMMS_LIBS@ +libxmms_flac_la_LIBADD = $(top_builddir)/src/libFLAC/libFLAC.la -L$(top_builddir)/src/libFLAC/.libs @XMMS_LIBS@ @ID3LIBS@ libxmms_flac_la_LDFLAGS = -module -avoid-version diff --git a/src/plugin_xmms/Makefile.lite b/src/plugin_xmms/Makefile.lite index 15011cd2..e1c3c8df 100644 --- a/src/plugin_xmms/Makefile.lite +++ b/src/plugin_xmms/Makefile.lite @@ -24,7 +24,11 @@ INCLUDES = $(shell xmms-config --cflags) -I./include -I../../include LIBS = ../../obj/lib/libFLAC.a OBJS = \ - plugin.o + plugin.o \ + configure.o \ + wrap_id3.o \ + charset.o + include ../../build/lib.mk diff --git a/src/plugin_xmms/charset.c b/src/plugin_xmms/charset.c new file mode 100644 index 00000000..d5b3e5a3 --- /dev/null +++ b/src/plugin_xmms/charset.c @@ -0,0 +1,306 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002 Daisuke Shimamura + * + * Almost from charset.c + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 1999-2001 Håvard Kvålen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +#ifdef HAVE_ICONV +#include +#endif + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + +#include "charset.h" +#include "mylocale.h" +#include "configure.h" + + +/**************** + * Declarations * + ****************/ + +#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) ) +const CharsetInfo charset_trans_array[] = { + {N_("Arabic (IBM-864)"), "IBM864" }, + {N_("Arabic (ISO-8859-6)"), "ISO-8859-6" }, + {N_("Arabic (Windows-1256)"), "windows-1256" }, + {N_("Baltic (ISO-8859-13)"), "ISO-8859-13" }, + {N_("Baltic (ISO-8859-4)"), "ISO-8859-4" }, + {N_("Baltic (Windows-1257)"), "windows-1257" }, + {N_("Celtic (ISO-8859-14)"), "ISO-8859-14" }, + {N_("Central European (IBM-852)"), "IBM852" }, + {N_("Central European (ISO-8859-2)"), "ISO-8859-2" }, + {N_("Central European (Windows-1250)"), "windows-1250" }, + {N_("Chinese Simplified (GB18030)"), "gb18030" }, + {N_("Chinese Simplified (GB2312)"), "GB2312" }, + {N_("Chinese Traditional (Big5)"), "Big5" }, + {N_("Chinese Traditional (Big5-HKSCS)"), "Big5-HKSCS" }, + {N_("Cyrillic (IBM-855)"), "IBM855" }, + {N_("Cyrillic (ISO-8859-5)"), "ISO-8859-5" }, + {N_("Cyrillic (ISO-IR-111)"), "ISO-IR-111" }, + {N_("Cyrillic (KOI8-R)"), "KOI8-R" }, + {N_("Cyrillic (Windows-1251)"), "windows-1251" }, + {N_("Cyrillic/Russian (CP-866)"), "IBM866" }, + {N_("Cyrillic/Ukrainian (KOI8-U)"), "KOI8-U" }, + {N_("English (US-ASCII)"), "us-ascii" }, + {N_("Greek (ISO-8859-7)"), "ISO-8859-7" }, + {N_("Greek (Windows-1253)"), "windows-1253" }, + {N_("Hebrew (IBM-862)"), "IBM862" }, + {N_("Hebrew (Windows-1255)"), "windows-1255" }, + {N_("Japanese (EUC-JP)"), "EUC-JP" }, + {N_("Japanese (ISO-2022-JP)"), "ISO-2022-JP" }, + {N_("Japanese (Shift_JIS)"), "Shift_JIS" }, + {N_("Korean (EUC-KR)"), "EUC-KR" }, + {N_("Nordic (ISO-8859-10)"), "ISO-8859-10" }, + {N_("South European (ISO-8859-3)"), "ISO-8859-3" }, + {N_("Thai (TIS-620)"), "TIS-620" }, + {N_("Turkish (IBM-857)"), "IBM857" }, + {N_("Turkish (ISO-8859-9)"), "ISO-8859-9" }, + {N_("Turkish (Windows-1254)"), "windows-1254" }, + {N_("Unicode (UTF-7)"), "UTF-7" }, + {N_("Unicode (UTF-8)"), "UTF-8" }, + {N_("Unicode (UTF-16BE)"), "UTF-16BE" }, + {N_("Unicode (UTF-16LE)"), "UTF-16LE" }, + {N_("Unicode (UTF-32BE)"), "UTF-32BE" }, + {N_("Unicode (UTF-32LE)"), "UTF-32LE" }, + {N_("Vietnamese (VISCII)"), "VISCII" }, + {N_("Vietnamese (Windows-1258)"), "windows-1258" }, + {N_("Visual Hebrew (ISO-8859-8)"), "ISO-8859-8" }, + {N_("Western (IBM-850)"), "IBM850" }, + {N_("Western (ISO-8859-1)"), "ISO-8859-1" }, + {N_("Western (ISO-8859-15)"), "ISO-8859-15" }, + {N_("Western (Windows-1252)"), "windows-1252" } + + /* + * From this point, character sets aren't supported by iconv + */ +/* {N_("Arabic (IBM-864-I)"), "IBM864i" }, + {N_("Arabic (ISO-8859-6-E)"), "ISO-8859-6-E" }, + {N_("Arabic (ISO-8859-6-I)"), "ISO-8859-6-I" }, + {N_("Arabic (MacArabic)"), "x-mac-arabic" }, + {N_("Armenian (ARMSCII-8)"), "armscii-8" }, + {N_("Central European (MacCE)"), "x-mac-ce" }, + {N_("Chinese Simplified (GBK)"), "x-gbk" }, + {N_("Chinese Simplified (HZ)"), "HZ-GB-2312" }, + {N_("Chinese Traditional (EUC-TW)"), "x-euc-tw" }, + {N_("Croatian (MacCroatian)"), "x-mac-croatian" }, + {N_("Cyrillic (MacCyrillic)"), "x-mac-cyrillic" }, + {N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian" }, + {N_("Farsi (MacFarsi)"), "x-mac-farsi"}, + {N_("Greek (MacGreek)"), "x-mac-greek" }, + {N_("Gujarati (MacGujarati)"), "x-mac-gujarati" }, + {N_("Gurmukhi (MacGurmukhi)"), "x-mac-gurmukhi" }, + {N_("Hebrew (ISO-8859-8-E)"), "ISO-8859-8-E" }, + {N_("Hebrew (ISO-8859-8-I)"), "ISO-8859-8-I" }, + {N_("Hebrew (MacHebrew)"), "x-mac-hebrew" }, + {N_("Hindi (MacDevanagari)"), "x-mac-devanagari" }, + {N_("Icelandic (MacIcelandic)"), "x-mac-icelandic" }, + {N_("Korean (JOHAB)"), "x-johab" }, + {N_("Korean (UHC)"), "x-windows-949" }, + {N_("Romanian (MacRomanian)"), "x-mac-romanian" }, + {N_("Turkish (MacTurkish)"), "x-mac-turkish" }, + {N_("User Defined"), "x-user-defined" }, + {N_("Vietnamese (TCVN)"), "x-viet-tcvn5712" }, + {N_("Vietnamese (VPS)"), "x-viet-vps" }, + {N_("Western (MacRoman)"), "x-mac-roman" }, + // charsets whithout posibly translatable names + {"T61.8bit", "T61.8bit" }, + {"x-imap4-modified-utf7", "x-imap4-modified-utf7"}, + {"x-u-escaped", "x-u-escaped" }, + {"windows-936", "windows-936" } +*/ +}; + +/************* + * Functions * + *************/ + +char* get_current_charset (void) +{ + char *charset = getenv("CHARSET"); + +#ifdef HAVE_LANGINFO_CODESET + if (!charset) + charset = nl_langinfo(CODESET); +#endif + if (!charset) + charset = "ISO-8859-1"; + + return charset; +} + + +#ifdef HAVE_ICONV +static char* convert_string (const char *string, char *from, char *to) +{ + size_t outleft, outsize, length; + iconv_t cd; + char *out, *outptr; + const char *input = string; + + if (!string) + return NULL; + + length = strlen(string); + + /* g_message("converting %s from %s to %s", string, from, to); */ + if ((cd = iconv_open(to, from)) == (iconv_t)-1) + { + g_warning("convert_string(): Conversion not supported. Charsets: %s -> %s", from, to); + return g_strdup(string); + } + + /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */ + /* + 1 for nul in case len == 1 */ + outsize = ((length + 3) & ~3) + 1; + out = g_malloc(outsize); + outleft = outsize - 1; + outptr = out; + + retry: + if (iconv(cd, &input, &length, &outptr, &outleft) == -1) + { + int used; + switch (errno) + { + case E2BIG: + used = outptr - out; + outsize = (outsize - 1) * 2 + 1; + out = g_realloc(out, outsize); + outptr = out + used; + outleft = outsize - 1 - used; + goto retry; + case EINVAL: + break; + case EILSEQ: + /* Invalid sequence, try to get the + rest of the string */ + input++; + length = strlen(input); + goto retry; + default: + g_warning("convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno)); + break; + } + } + *outptr = '\0'; + + iconv_close(cd); + return out; +} +#else +static char* convert_string (const char *string, char *from, char *to) +{ + if (!string) + return NULL; + return g_strdup(string); +} +#endif + +/* + * Commons conversion functions + */ +char* convert_from_file_to_user (const char *string) +{ + char *file_charset = flac_cfg.file_char_set; + char *user_charset = flac_cfg.user_char_set; + + return convert_string(string,file_charset,user_charset); +} + +char* convert_from_user_to_file (const char *string) +{ + char *file_charset = flac_cfg.file_char_set; + char *user_charset = flac_cfg.user_char_set; + + return convert_string(string,user_charset,file_charset); +} + + +GList *Charset_Create_List (void) +{ + GList *list = NULL; + guint i; + + for (i=0; i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef __CHARSET_H__ +#define __CHARSET_H__ + + +/*************** + * Declaration * + ***************/ + +typedef struct { + gchar *charset_title; + gchar *charset_name; +} CharsetInfo; + +/* translated charset titles */ +extern const CharsetInfo charset_trans_array[]; + +/************** + * Prototypes * + **************/ + +gchar* get_current_charset (void); + +gchar* convert_from_file_to_user (const gchar *string); +gchar* convert_from_user_to_file (const gchar *string); + +GList *Charset_Create_List (void); +gchar *Charset_Get_Name_From_Title (gchar *charset_title); +gchar *Charset_Get_Title_From_Name (gchar *charset_name); + +gboolean test_conversion_charset (char *from, char *to); + + +#endif /* __CHARSET_H__ */ + diff --git a/src/plugin_xmms/configure.c b/src/plugin_xmms/configure.c new file mode 100644 index 00000000..83c9ec31 --- /dev/null +++ b/src/plugin_xmms/configure.c @@ -0,0 +1,258 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002 Daisuke Shimamura + * + * Based on mpg123 plugin + * and prefs.c - 2000/05/06 + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 2000-2002 Jerome Couderc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mylocale.h" +#include "charset.h" +#include "configure.h" + +/* + * Initialize Global Valueable + */ +flac_config_t flac_cfg = { + FALSE, + NULL, + FALSE, + NULL, + NULL +}; + + +static GtkWidget *flac_configurewin = NULL; +static GtkWidget *vbox, *notebook; + +static GtkWidget *title_tag_override, *title_tag_box, *title_tag_entry, *title_desc; +static GtkWidget *convert_char_set, *fileCharacterSetEntry, *userCharacterSetEntry; + +static gchar *gtk_entry_get_text_1 (GtkWidget *widget); +static void flac_configurewin_ok(GtkWidget * widget, gpointer data); +static void configure_destroy(GtkWidget * w, gpointer data); +static void title_tag_override_cb(GtkWidget * w, gpointer data); +static void convert_char_set_cb(GtkWidget * w, gpointer data); + +static void flac_configurewin_ok(GtkWidget * widget, gpointer data) +{ + ConfigFile *cfg; + gchar *filename; + + g_free(flac_cfg.tag_format); + flac_cfg.tag_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_tag_entry))); + flac_cfg.file_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(fileCharacterSetEntry)); + flac_cfg.user_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(userCharacterSetEntry)); + + filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL); + cfg = xmms_cfg_open_file(filename); + if (!cfg) + cfg = xmms_cfg_new(); + xmms_cfg_write_boolean(cfg, "flac", "tag_override", flac_cfg.tag_override); + xmms_cfg_write_string(cfg, "flac", "tag_format", flac_cfg.tag_format); + xmms_cfg_write_boolean(cfg, "flac", "convert_char_set", flac_cfg.convert_char_set); + xmms_cfg_write_string(cfg, "flac", "file_char_set", flac_cfg.file_char_set); + xmms_cfg_write_string(cfg, "flac", "user_char_set", flac_cfg.user_char_set); + xmms_cfg_write_file(cfg, filename); + xmms_cfg_free(cfg); + g_free(filename); + gtk_widget_destroy(flac_configurewin); +} + +static void configure_destroy(GtkWidget * w, gpointer data) +{ +} + +static void title_tag_override_cb(GtkWidget * w, gpointer data) +{ + flac_cfg.tag_override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_tag_override)); + + gtk_widget_set_sensitive(title_tag_box, flac_cfg.tag_override); + gtk_widget_set_sensitive(title_desc, flac_cfg.tag_override); + +} + +static void convert_char_set_cb(GtkWidget * w, gpointer data) +{ + flac_cfg.convert_char_set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(convert_char_set)); + + gtk_widget_set_sensitive(fileCharacterSetEntry, flac_cfg.convert_char_set); + gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.convert_char_set); +} + +void FLAC_XMMS__configure(void) +{ + GtkWidget *title_frame, *title_tag_vbox, *title_tag_label; + GtkWidget *label, *hbox; + GtkWidget *bbox, *ok, *cancel; + GList *list; + + if (flac_configurewin != NULL) { + gdk_window_raise(flac_configurewin->window); + return; + } + flac_configurewin = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &flac_configurewin); + gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(configure_destroy), &flac_configurewin); + gtk_window_set_title(GTK_WINDOW(flac_configurewin), _("Flac Configuration")); + gtk_window_set_policy(GTK_WINDOW(flac_configurewin), FALSE, FALSE, FALSE); + gtk_container_border_width(GTK_CONTAINER(flac_configurewin), 10); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(flac_configurewin), vbox); + + notebook = gtk_notebook_new(); + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + + /* Title config.. */ + + title_frame = gtk_frame_new(_("ID3 Tags:")); + gtk_container_border_width(GTK_CONTAINER(title_frame), 5); + + title_tag_vbox = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(title_tag_vbox), 5); + gtk_container_add(GTK_CONTAINER(title_frame), title_tag_vbox); + + /* Convert Char Set */ + + convert_char_set = gtk_check_button_new_with_label(_("Convert Character Set")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(convert_char_set), flac_cfg.convert_char_set); + gtk_signal_connect(GTK_OBJECT(convert_char_set), "clicked", convert_char_set_cb, NULL); + gtk_box_pack_start(GTK_BOX(title_tag_vbox), convert_char_set, FALSE, FALSE, 0); + // Combo boxes... + hbox = gtk_hbox_new(FALSE,4); + gtk_container_add(GTK_CONTAINER(title_tag_vbox),hbox); + label = gtk_label_new(_("Convert character set from :")); + gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0); + fileCharacterSetEntry = gtk_combo_new(); + gtk_box_pack_start(GTK_BOX(hbox),fileCharacterSetEntry,TRUE,TRUE,0); + + label = gtk_label_new (_("to :")); + gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0); + userCharacterSetEntry = gtk_combo_new(); + gtk_box_pack_start(GTK_BOX(hbox),userCharacterSetEntry,TRUE,TRUE,0); + + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),FALSE); + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),FALSE); + gtk_combo_set_value_in_list(GTK_COMBO(fileCharacterSetEntry),TRUE,FALSE); + gtk_combo_set_value_in_list(GTK_COMBO(userCharacterSetEntry),TRUE,FALSE); + + list = Charset_Create_List(); + gtk_combo_set_popdown_strings(GTK_COMBO(fileCharacterSetEntry),list); + gtk_combo_set_popdown_strings(GTK_COMBO(userCharacterSetEntry),list); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.file_char_set)); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.user_char_set)); + gtk_widget_set_sensitive(fileCharacterSetEntry, flac_cfg.convert_char_set); + gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.convert_char_set); + + /* Override Tagging Format */ + + title_tag_override = gtk_check_button_new_with_label(_("Override generic titles")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_tag_override), flac_cfg.tag_override); + gtk_signal_connect(GTK_OBJECT(title_tag_override), "clicked", title_tag_override_cb, NULL); + gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_override, FALSE, FALSE, 0); + + title_tag_box = gtk_hbox_new(FALSE, 5); + gtk_widget_set_sensitive(title_tag_box, flac_cfg.tag_override); + gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_box, FALSE, FALSE, 0); + + title_tag_label = gtk_label_new(_("Title format:")); + gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_label, FALSE, FALSE, 0); + + title_tag_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(title_tag_entry), flac_cfg.tag_format); + gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_entry, TRUE, TRUE, 0); + + title_desc = xmms_titlestring_descriptions("pafFetnygc", 2); + gtk_widget_set_sensitive(title_desc, flac_cfg.tag_override); + gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_desc, FALSE, FALSE, 0); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), title_frame, gtk_label_new(_("Title"))); + + /* Buttons */ + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + ok = gtk_button_new_with_label(_("Ok")); + gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(flac_configurewin_ok), NULL); + GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); + gtk_widget_grab_default(ok); + + cancel = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(flac_configurewin)); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); + + gtk_widget_show_all(flac_configurewin); +} + +void FLAC_XMMS__aboutbox() +{ + static GtkWidget *about_window; + + if (about_window) + gdk_window_raise(about_window->window); + + about_window = xmms_show_message( + _("About Flac Plugin"), + _("Flac Plugin by Josh Coalson\n" + "contributions by\n" + "......\n" + "......\n" + "and\n" + "Daisuke Shimamura\n" + "Visit http://flac.sourceforge.net/"), + _("Ok"), FALSE, NULL, NULL); + gtk_signal_connect(GTK_OBJECT(about_window), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &about_window); +} + +/* + * Get text of an Entry or a ComboBox + */ +static gchar *gtk_entry_get_text_1 (GtkWidget *widget) +{ + if (GTK_IS_COMBO(widget)) + { + return gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(widget)->entry)); + }else if (GTK_IS_ENTRY(widget)) + { + return gtk_entry_get_text(GTK_ENTRY(widget)); + }else + { + return NULL; + } +} + diff --git a/src/plugin_xmms/configure.h b/src/plugin_xmms/configure.h new file mode 100644 index 00000000..1b030503 --- /dev/null +++ b/src/plugin_xmms/configure.h @@ -0,0 +1,42 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002 Daisuke Shimamura + * + * Based on mpg123 plugin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __CONFIGURE_H__ +#define __CONFIGURE_H__ + +#include + +typedef struct { + gboolean tag_override; + gchar *tag_format; + gboolean convert_char_set; + gchar *file_char_set; + gchar *user_char_set; +} flac_config_t; + +extern flac_config_t flac_cfg; + +extern void FLAC_XMMS__configure(void); +extern void FLAC_XMMS__aboutbox(); + +#endif + + + diff --git a/src/plugin_xmms/fileinfo.c b/src/plugin_xmms/fileinfo.c new file mode 100644 index 00000000..30170734 --- /dev/null +++ b/src/plugin_xmms/fileinfo.c @@ -0,0 +1,325 @@ +/* XMMS - Cross-platform multimedia player + * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies + * Copyright (C) 1999,2000 Håvard Kvålen + * Copyright (C) 2002 Daisuke Shimamura + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include +#include "FLAC/all.h" +#include "id3_tag.h" +#include "configure.h" + +gboolean get_file_info(char *filename, flac_file_info_struct *tmp_file_info) +{ + FLAC__StreamMetadata streaminfo; + + if(0 == filename) + filename = ""; + + if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) { + return FALSE; + } + + tmp_file_info->sample_rate = streaminfo.data.stream_info.sample_rate; + tmp_file_info->channels = streaminfo.data.stream_info.channels; + tmp_file_info->bits_per_sample = streaminfo.data.stream_info.bits_per_sample; + tmp_file_info->total_samples = streaminfo.data.stream_info.total_samples; + + tmp_file_info->length_in_msec = streaminfo.data.stream_info.total_samples * 10 / (streaminfo.data.stream_info.sample_rate / 100); + + return TRUE; +} + +static GtkWidget *window = NULL; +static GtkWidget *filename_entry, *id3_frame; +static GtkWidget *title_entry, *artist_entry, *album_entry, *year_entry, *tracknum_entry, *comment_entry; +static GtkWidget *genre_combo; +static GtkWidget *flac_level, *flac_bitrate, *flac_samplerate, *flac_flags; +static GtkWidget *flac_fileinfo, *flac_genre; + +static gchar *current_filename = NULL; + +extern gchar *flac_filename; +extern gint flac_bitrate, flac_frequency, flac_layer, flac_lsf, flac_mode; +extern gboolean flac_stereo, flac_flac25; + +#define MAX_STR_LEN 100 + +static void set_entry_tag(GtkEntry * entry, gchar * tag, gint length) +{ + gint stripped_len; + gchar *text; + + stripped_len = flac_strip_spaces(tag, length); + text = g_strdup_printf("%-*.*s", stripped_len, stripped_len, tag); + gtk_entry_set_text(entry, text); + g_free(text); +} + +static void get_entry_tag(GtkEntry * entry, gchar * tag, gint length) +{ + gchar *text; + + text = gtk_entry_get_text(entry); + memset(tag, ' ', length); + memcpy(tag, text, strlen(text) > length ? length : strlen(text)); +} + +static gint genre_comp_func(gconstpointer a, gconstpointer b) +{ + return strcasecmp(a, b); +} + +static gchar* channel_mode_name(int mode) +{ + static const gchar *channel_mode[] = + {N_("Mono"), N_("Stereo")}; + if (mode < 1 || mode > 2) + return ""; + return gettext(channel_mode[mode]); +} + +void FLAC_XMMS__file_info_box(char *filename) +{ + gint i; + FILE *fh; + gchar *tmp, *title; + + gboolean rc; + +#ifdef FLAC__HAS_ID3LIB + File_Tag tag; + Initialize_File_Tag_Item (&tag); + rc = Id3tag_Read_File_Tag (filename, &tag); +#else + id3v2_struct tag; + memset(&tag, 0, sizeof(tag)); + rc = get_id3v1_tag_as_v2_(filename, &tag); +#endif + + if (!window) + { + GtkWidget *vbox, *hbox, *left_vbox, *table; + GtkWidget *flac_frame, *flac_box; + GtkWidget *label, *filename_hbox; + GtkWidget *bbox, *save, *remove_id3, *cancel; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE); + gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window); + gtk_container_set_border_width(GTK_CONTAINER(window), 10); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(window), vbox); + + filename_hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, FALSE, TRUE, 0); + + label = gtk_label_new(_("Filename:")); + gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0); + filename_entry = gtk_entry_new(); + gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE); + gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, TRUE, TRUE, 0); + + hbox = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + + left_vbox = gtk_vbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(hbox), left_vbox, FALSE, FALSE, 0); + + id3_frame = gtk_frame_new(_("ID3 Tag:")); + gtk_box_pack_start(GTK_BOX(left_vbox), id3_frame, FALSE, FALSE, 0); + + table = gtk_table_new(5, 5, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + gtk_container_add(GTK_CONTAINER(id3_frame), table); + + label = gtk_label_new(_("Title:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 5, 5); + + title_entry = gtk_entry_new_with_max_length(30); + gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Artist:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 5, 5); + + artist_entry = gtk_entry_new_with_max_length(30); + gtk_table_attach(GTK_TABLE(table), artist_entry, 1, 4, 1, 2, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Album:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 5, 5); + + album_entry = gtk_entry_new_with_max_length(30); + gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Comment:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 5, 5); + + comment_entry = gtk_entry_new_with_max_length(30); + gtk_table_attach(GTK_TABLE(table), comment_entry, 1, 4, 3, 4, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Year:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 5, 5); + + year_entry = gtk_entry_new_with_max_length(4); + gtk_widget_set_usize(year_entry, 40, -1); + gtk_table_attach(GTK_TABLE(table), year_entry, 1, 2, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Track number:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5, GTK_FILL, GTK_FILL, 5, 5); + + tracknum_entry = gtk_entry_new_with_max_length(3); + gtk_widget_set_usize(tracknum_entry, 40, -1); + gtk_table_attach(GTK_TABLE(table), tracknum_entry, 3, 4, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Genre:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 5, 5); + + genre_combo = gtk_combo_new(); + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), FALSE); + if (!genre_list) + { + for (i = 0; i < GENRE_MAX; i++) + genre_list = g_list_prepend(genre_list, (char *) flac_id3_genres[i]); + genre_list = g_list_prepend(genre_list, ""); + genre_list = g_list_sort(genre_list, genre_comp_func); + } + gtk_combo_set_popdown_strings(GTK_COMBO(genre_combo), genre_list); + + gtk_table_attach(GTK_TABLE(table), genre_combo, 1, 4, 5, 6, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(left_vbox), bbox, FALSE, FALSE, 0); + + save = gtk_button_new_with_label(_("Save")); + gtk_signal_connect(GTK_OBJECT(save), "clicked", GTK_SIGNAL_FUNC(save_cb), NULL); + GTK_WIDGET_SET_FLAGS(save, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), save, TRUE, TRUE, 0); + gtk_widget_grab_default(save); + + remove_id3 = gtk_button_new_with_label(_("Remove ID3")); + gtk_signal_connect(GTK_OBJECT(remove_id3), "clicked", GTK_SIGNAL_FUNC(remove_id3_cb), NULL); + GTK_WIDGET_SET_FLAGS(remove_id3, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), remove_id3, TRUE, TRUE, 0); + + cancel = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window)); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); + + flac_frame = gtk_frame_new(_("FLAC Info:")); + gtk_box_pack_start(GTK_BOX(hbox), flac_frame, FALSE, FALSE, 0); + + flac_box = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(flac_frame), flac_box); + gtk_container_set_border_width(GTK_CONTAINER(flac_box), 10); + gtk_box_set_spacing(GTK_BOX(flac_box), 0); + + flac_level = gtk_label_new(""); + gtk_widget_set_usize(flac_level, 120, -2); + gtk_misc_set_alignment(GTK_MISC(flac_level), 0, 0); + gtk_box_pack_start(GTK_BOX(flac_box), flac_level, FALSE, FALSE, 0); + + flac_bitrate = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_bitrate), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_bitrate), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_bitrate, FALSE, FALSE, 0); + + flac_samplerate = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_samplerate), 0, 0); + gtk_box_pack_start(GTK_BOX(flac_box), flac_samplerate, FALSE, FALSE, 0); + + flac_flags = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_flags), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_flags), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_flags, FALSE, FALSE, 0); + + flac_fileinfo = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_fileinfo), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_fileinfo), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_fileinfo, FALSE, FALSE, 0); + + gtk_widget_show_all(window); + } + + if (current_filename) + g_free(current_filename); + current_filename = g_strdup(filename); + + title = g_strdup_printf(_("File Info - %s"), g_basename(filename)); + gtk_window_set_title(GTK_WINDOW(window), title); + g_free(title); + + gtk_entry_set_text(GTK_ENTRY(filename_entry), filename); + gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1); + + if (tag.title != NULL && strlen(tag.title) > 0) + { + gtk_entry_set_text(GTK_ENTRY(title_entry), tag.title); + } + else + { + title = g_strdup(g_basename(filename)); + if ((tmp = strrchr(title, '.')) != NULL) + *tmp = '\0'; + gtk_entry_set_text(GTK_ENTRY(title_entry), title); + g_free(title); + } + + gtk_entry_set_text(GTK_ENTRY(artist_entry), tag.artist); + gtk_entry_set_text(GTK_ENTRY(album_entry), tag.album); + gtk_entry_set_text(GTK_ENTRY(year_entry), tag.year); + gtk_entry_set_text(GTK_ENTRY(tracknum_entry), tag.track); + gtk_entry_set_text(GTK_ENTRY(comment_entry), tag.comment); + gtk_entry_set_text(GTK_ENTRY(genre_entry), tag.genre); + + gtk_label_set_text(GTK_LABEL(flac_level), ""); + gtk_label_set_text(GTK_LABEL(flac_bitrate), ""); + gtk_label_set_text(GTK_LABEL(flac_samplerate), ""); + gtk_label_set_text(GTK_LABEL(flac_flags), ""); + gtk_label_set_text(GTK_LABEL(flac_fileinfo), ""); + + if (!strncasecmp(filename, "http://", 7)) + { + file_info_http(filename); + return; + } + + gtk_widget_set_sensitive(id3_frame, TRUE); + + label_set_text(flac_bitrate, _("Bits/Samples: %d"), tmp_file_info->bits_per_sample); + /* tmp_file_info->length_in_msec */ + + label_set_text(flac_samplerate, _("Samplerate: %ld Hz"), tmp_file_info->sample_rate); + label_set_text(flac_channel, _("Channel: %s"), channel_mode_name(tmp_file_info->channel); +#if 0 + label_set_text(flac_fileinfo, _("%d frames\nFilesize: %lu B"), num_frames, ftell(fh)); +#endif +} + + diff --git a/src/plugin_xmms/genres.h b/src/plugin_xmms/genres.h new file mode 100644 index 00000000..7dc2aea0 --- /dev/null +++ b/src/plugin_xmms/genres.h @@ -0,0 +1,187 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002 Daisuke Shimamura + * + * Based on genres.h - EasyTAG - Jerome Couderc 2000/05/29 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifndef __GENRES_H__ +#define __GENRES_H__ + + +/* GENRE_MAX is the last genre number that can be used */ +#define GENRE_MAX ( sizeof(id3_genres)/sizeof(id3_genres[0]) - 1 ) +#define ID3_INVALID_GENRE 255 + + +/* + * Do not sort genres!! + * Last Update: 2000/04/30 + */ +static char *id3_genres[] = +{ + "Blues", /* 0 */ + "Classic Rock", + "Country", + "Dance", + "Disco", + "Funk", /* 5 */ + "Grunge", + "Hip-Hop", + "Jazz", + "Metal", + "New Age", /* 10 */ + "Oldies", + "Other", + "Pop", + "R&B", + "Rap", /* 15 */ + "Reggae", + "Rock", + "Techno", + "Industrial", + "Alternative", /* 20 */ + "Ska", + "Death Metal", + "Pranks", + "Soundtrack", + "Euro-Techno", /* 25 */ + "Ambient", + "Trip-Hop", + "Vocal", + "Jazz+Funk", + "Fusion", /* 30 */ + "Trance", + "Classical", + "Instrumental", + "Acid", + "House", /* 35 */ + "Game", + "Sound Clip", + "Gospel", + "Noise", + "Altern Rock", /* 40 */ + "Bass", + "Soul", + "Punk", + "Space", + "Meditative", /* 45 */ + "Instrumental Pop", + "Instrumental Rock", + "Ethnic", + "Gothic", + "Darkwave", /* 50 */ + "Techno-Industrial", + "Electronic", + "Pop-Folk", + "Eurodance", + "Dream", /* 55 */ + "Southern Rock", + "Comedy", + "Cult", + "Gangsta", + "Top 40", /* 60 */ + "Christian Rap", + "Pop/Funk", + "Jungle", + "Native American", + "Cabaret", /* 65 */ + "New Wave", + "Psychadelic", + "Rave", + "Showtunes", + "Trailer", /* 70 */ + "Lo-Fi", + "Tribal", + "Acid Punk", + "Acid Jazz", + "Polka", /* 75 */ + "Retro", + "Musical", + "Rock & Roll", + "Hard Rock", + "Folk", /* 80 */ + "Folk/Rock", + "National Folk", + "Fast Fusion", + "Swing", + "Bebob", /* 85 */ + "Latin", + "Revival", + "Celtic", + "Bluegrass", + "Avantgarde", /* 90 */ + "Gothic Rock", + "Progressive Rock", + "Psychedelic Rock", + "Symphonic Rock", + "Slow Rock", /* 95 */ + "Big Band", + "Chorus", + "Easy Listening", + "Acoustic", + "Humour", /* 100 */ + "Speech", + "Chanson", + "Opera", + "Chamber Music", + "Sonata", /* 105 */ + "Symphony", + "Booty Bass", + "Primus", + "Porn Groove", + "Satire", /* 110 */ + "Slow Jam", + "Club", + "Tango", + "Samba", + "Folklore", /* 115 */ + "Ballad", + "Power Ballad", + "Rhythmic Soul", + "Freestyle", + "Duet", /* 120 */ + "Punk Rock", + "Drum Solo", + "A Capella", + "Euro-House", + "Dance Hall", /* 125 */ + "Goa", + "Drum & Bass", + "Club-House", + "Hardcore", + "Terror", /* 130 */ + "Indie", + "BritPop", + "Negerpunk", + "Polsk Punk", + "Beat", /* 135 */ + "Christian Gangsta Rap", + "Heavy Metal", + "Black Metal", + "Crossover", + "Contemporary Christian",/* 140 */ + "Christian Rock", + "Merengue", + "Salsa", + "Thrash Metal", + "Anime", /* 145 */ + "JPop", + "Synthpop" +}; + +#endif /* __GENRES_H__ */ diff --git a/src/plugin_xmms/id3_tag.c b/src/plugin_xmms/id3_tag.c new file mode 100644 index 00000000..c47e4be2 --- /dev/null +++ b/src/plugin_xmms/id3_tag.c @@ -0,0 +1,508 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002 Daisuke Shimamura + * + * Almost from id3_tag.c - 2001/02/16 + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 2001-2002 Jerome Couderc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "configure.h" +#include "genres.h" +#include "charset.h" +#include "mylocale.h" +#include "id3_tag.h" + +/**************** + * Declarations * + ****************/ +#define ID3V2_MAX_STRING_LEN 4096 +#define NUMBER_TRACK_FORMATED 1 + +/************** + * Prototypes * + **************/ +static size_t ID3Tag_Link_1 (ID3Tag *id3tag, const char *filename); +static size_t ID3Field_GetASCII_1 (const ID3Field *field, char *buffer, size_t maxChars, index_t itemNum); + +static gchar *Id3tag_Genre_To_String (unsigned char genre_code); +static void Strip_String (gchar *string); + +/************* + * Functions * + *************/ +/* + * Read id3v1.x / id3v2 tag and load data into the File_Tag structure using id3lib functions. + * Returns TRUE on success, else FALSE. + * If a tag entry exists (ex: title), we allocate memory, else value stays to NULL + */ +gboolean Id3tag_Read_File_Tag (gchar *filename, File_Tag *FileTag) +{ + FILE *file; + ID3Tag *id3_tag = NULL; /* Tag defined by the id3lib */ + gchar *string, *string1, *string2; + gboolean USE_CHARACTER_SET_TRANSLATION; + + USE_CHARACTER_SET_TRANSLATION = flac_cfg.convert_char_set; + + if (!filename || !FileTag) + return FALSE; + + if ( (file=fopen(filename,"r"))==NULL ) + { + g_print(_("ERROR while opening file: '%s' (%s).\n\a"),filename,g_strerror(errno)); + return FALSE; + } + fclose(file); // We close it cause id3lib opens/closes file itself + + + /* Get data from tag */ + if ( (id3_tag = ID3Tag_New()) ) + { + ID3Frame *id3_frame; + ID3Field *id3_field; + luint frm_size; + luint num_chars; + guint field_num = 0; // First field + + /* Link the file to the tag */ + frm_size = ID3Tag_Link_1(id3_tag,filename); + + string = g_malloc(ID3V2_MAX_STRING_LEN+1); + + /********* + * Title * + *********/ + if ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_TITLE)) ) + { + if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_TEXT)) ) + { + // Note: if 'num_chars' is equal to 0, then the field is empty or corrupted! + if ( (num_chars=ID3Field_GetASCII_1(id3_field,string,ID3V2_MAX_STRING_LEN,field_num)) > 0 + && string != NULL ) + { + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(string); + Strip_String(string1); + FileTag->title = g_strdup(string1); + g_free(string1); + }else + { + Strip_String(string); + FileTag->title = g_strdup(string); + } + } + } + } + + + /********** + * Artist * + **********/ + if ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_LEADARTIST)) ) + { + if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_TEXT)) ) + { + if ( (num_chars=ID3Field_GetASCII_1(id3_field,string,ID3V2_MAX_STRING_LEN,field_num)) > 0 + && string != NULL ) + { + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(string); + Strip_String(string1); + FileTag->artist = g_strdup(string1); + g_free(string1); + }else + { + Strip_String(string); + FileTag->artist = g_strdup(string); + } + } + } + } + + + /********* + * Album * + *********/ + if ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_ALBUM)) ) + { + if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_TEXT)) ) + { + if ( (num_chars=ID3Field_GetASCII_1(id3_field,string,ID3V2_MAX_STRING_LEN,field_num)) > 0 + && string != NULL ) + { + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(string); + Strip_String(string1); + FileTag->album = g_strdup(string1); + g_free(string1); + }else + { + Strip_String(string); + FileTag->album = g_strdup(string); + } + } + } + } + + + /******** + * Year * + ********/ + if ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_YEAR)) ) + { + if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_TEXT)) ) + { + if ( (num_chars=ID3Field_GetASCII_1(id3_field,string,ID3V2_MAX_STRING_LEN,field_num)) > 0 + && string != NULL ) + { + gchar *tmp_str; + + Strip_String(string); + + /* Fix for id3lib 3.7.x: if the id3v1.x tag was filled with spaces + * instead of zeroes, then the year field contains garbages! */ + tmp_str = string; + while (isdigit(*tmp_str)) tmp_str++; + *tmp_str = 0; + /* End of fix for id3lib 3.7.x */ + + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(string); + Strip_String(string1); + FileTag->year = g_strdup(string1); + g_free(string1); + }else + { + Strip_String(string); + FileTag->year = g_strdup(string); + } + } + } + } + + + /************************* + * Track and Total Track * + *************************/ + if ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_TRACKNUM)) ) + { + if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_TEXT)) ) + { + if ( (num_chars=ID3Field_GetASCII_1(id3_field,string,ID3V2_MAX_STRING_LEN,field_num)) > 0 + && string != NULL ) + { + + Strip_String(string); + + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(string); + string2 = strchr(string1,'/'); + if (NUMBER_TRACK_FORMATED) + { + if (string2) + { + FileTag->track_total = g_strdup_printf("%.2d",atoi(string2+1)); // Just to have numbers like this : '01', '05', '12', ... + *string2 = '\0'; + } + FileTag->track = g_strdup_printf("%.2d",atoi(string1)); // Just to have numbers like this : '01', '05', '12', ... + }else + { + if (string2) + { + FileTag->track_total = g_strdup(string2+1); + *string2 = '\0'; + } + FileTag->track = g_strdup(string1); + } + g_free(string1); + }else + { + string2 = strchr(string,'/'); + if (NUMBER_TRACK_FORMATED) + { + if (string2) + { + FileTag->track_total = g_strdup_printf("%.2d",atoi(string2+1)); // Just to have numbers like this : '01', '05', '12', ... + *string2 = '\0'; + } + FileTag->track = g_strdup_printf("%.2d",atoi(string)); // Just to have numbers like this : '01', '05', '12', ... + }else + { + if (string2) + { + FileTag->track_total = g_strdup(string2+1); + *string2 = '\0'; + } + FileTag->track = g_strdup(string); + } + } + } + } + } + + + /********* + * Genre * + *********/ + if ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_CONTENTTYPE)) ) + { + if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_TEXT)) ) + { + /* + * We manipulate only the name of the genre + */ + if ( (num_chars=ID3Field_GetASCII_1(id3_field,string,ID3V2_MAX_STRING_LEN,field_num)) > 0 + && string != NULL ) + { + gchar *tmp; + + Strip_String(string); + + if ( (string[0]=='(') && (tmp=strchr(string,')')) && (strlen((tmp+1))>0) ) + { + + /* Convert a genre written as '(3)Dance' into 'Dance' */ + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(tmp+1); + FileTag->genre = g_strdup(string1); + g_free(string1); + }else + { + FileTag->genre = g_strdup(tmp+1); + } + + }else if ( (string[0]=='(') && (tmp=strchr(string,')')) ) + { + + /* Convert a genre written as '(3)' into 'Dance' */ + *tmp = 0; + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(Id3tag_Genre_To_String(atoi(string+1))); + FileTag->genre = g_strdup(string1); + g_free(string1); + }else + { + FileTag->genre = g_strdup(Id3tag_Genre_To_String(atoi(string+1))); + } + + }else + { + + /* Genre is already written as 'Dance' */ + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(string); + FileTag->genre = g_strdup(string1); + g_free(string1); + }else + { + FileTag->genre = g_strdup(string); + } + + } + } + } + } + + + /*********** + * Comment * + ***********/ + if ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_COMMENT)) ) + { + if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_TEXT)) ) + { + if ( (num_chars=ID3Field_GetASCII_1(id3_field,string,ID3V2_MAX_STRING_LEN,field_num)) > 0 + && string != NULL ) + { + if (USE_CHARACTER_SET_TRANSLATION) + { + string1 = convert_from_file_to_user(string); + Strip_String(string1); + FileTag->comment = g_strdup(string1); + g_free(string1); + }else + { + Strip_String(string); + FileTag->comment = g_strdup(string); + } + } + } + /*if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_DESCRIPTION)) ) + { + gchar *comment1 = g_malloc0(MAX_STRING_LEN+1); + num_chars = ID3Field_GetASCII(id3_field,comment1,MAX_STRING_LEN,Item_Num); + g_free(comment1); + } + if ( (id3_field = ID3Frame_GetField(id3_frame,ID3FN_LANGUAGE)) ) + { + gchar *comment2 = g_malloc0(MAX_STRING_LEN+1); + num_chars = ID3Field_GetASCII(id3_field,comment2,MAX_STRING_LEN,Item_Num); + g_free(comment2); + }*/ + } + g_free(string); + + /* Free allocated data */ + ID3Tag_Delete(id3_tag); + } + + return TRUE; +} + +void Initialize_File_Tag_Item (File_Tag *FileTag) +{ + if (FileTag) + { + FileTag->key = 0; + FileTag->saved = FALSE; + FileTag->title = NULL; + FileTag->artist = NULL; + FileTag->album = NULL; + FileTag->track = NULL; + FileTag->track_total = NULL; + FileTag->year = NULL; + FileTag->genre = NULL; + FileTag->comment = NULL; + } +} + +/* + * Frees a File_Tag item. + */ +gboolean Free_File_Tag_Item (File_Tag *FileTag) +{ + if (!FileTag) return FALSE; + + if (FileTag->title) g_free(FileTag->title); + if (FileTag->artist) g_free(FileTag->artist); + if (FileTag->album) g_free(FileTag->album); + if (FileTag->year) g_free(FileTag->year); + if (FileTag->track) g_free(FileTag->track); + if (FileTag->track_total) g_free(FileTag->track_total); + if (FileTag->genre) g_free(FileTag->genre); + if (FileTag->comment) g_free(FileTag->comment); + + return TRUE; +} + +/* + * Returns the name of a genre code if found + * Three states for genre code : + * - defined (0 to GENRE_MAX) + * - undefined/unknown (GENRE_MAX+1 to ID3_INVALID_GENRE-1) + * - invalid (>ID3_INVALID_GENRE) + */ +static gchar *Id3tag_Genre_To_String (unsigned char genre_code) +{ + if (genre_code>=ID3_INVALID_GENRE) /* empty */ + return ""; + else if (genre_code>GENRE_MAX) /* unknown tag */ + return "Unknown"; + else /* known tag */ + return id3_genres[genre_code]; +} + + + +/* + * As the ID3Tag_Link function of id3lib-3.8.0pre2 returns the ID3v1 tags + * when a file has both ID3v1 and ID3v2 tags, we first try to explicitely + * get the ID3v2 tags with ID3Tag_LinkWithFlags and, if we cannot get them, + * fall back to the ID3v1 tags. + * (Written by Holger Schemel). + */ +static size_t ID3Tag_Link_1 (ID3Tag *id3tag, const char *filename) +{ + size_t offset; + +# if ( (ID3LIB_MAJOR >= 3) && (ID3LIB_MINOR >= 8) ) + /* First, try to get the ID3v2 tags */ + offset = ID3Tag_LinkWithFlags(id3tag,filename,ID3TT_ID3V2); + if (offset == 0) + { + /* No ID3v2 tags available => try to get the ID3v1 tags */ + offset = ID3Tag_LinkWithFlags(id3tag,filename,ID3TT_ID3V1); + } +# else + /* Function 'ID3Tag_LinkWithFlags' is not defined up to id3lib-.3.7.13 */ + offset = ID3Tag_Link(id3tag,filename); +# endif + //g_print("ID3 TAG SIZE: %d\t%s\n",offset,g_basename(filename)); + return offset; +} + + +/* + * As the ID3Field_GetASCII function differs with the version of id3lib, we must redefine it. + */ +static size_t ID3Field_GetASCII_1(const ID3Field *field, char *buffer, size_t maxChars, index_t itemNum) +{ + + /* Defined by id3lib: ID3LIB_MAJOR_VERSION, ID3LIB_MINOR_VERSION, ID3LIB_PATCH_VERSION + * Defined by autoconf: ID3LIB_MAJOR, ID3LIB_MINOR, ID3LIB_PATCH + * + * <= 3.7.12 : first item num is 1 for ID3Field_GetASCII + * = 3.7.13 : first item num is 0 for ID3Field_GetASCII + * >= 3.8.0 : doesn't need item num for ID3Field_GetASCII + */ + //g_print("id3lib version: %d.%d.%d\n",ID3LIB_MAJOR,ID3LIB_MINOR,ID3LIB_PATCH); +# if (ID3LIB_MAJOR >= 3) + // (>= 3.x.x) +# if (ID3LIB_MINOR <= 7) + // (3.0.0 to 3.7.x) +# if (ID3LIB_PATCH >= 13) + // (>= 3.7.13) + return ID3Field_GetASCII(field,buffer,maxChars,itemNum); +# else + return ID3Field_GetASCII(field,buffer,maxChars,itemNum+1); +# endif +# else + // (>= to 3.8.0) + //return ID3Field_GetASCII(field,buffer,maxChars); + return ID3Field_GetASCIIItem(field,buffer,maxChars,itemNum); +# endif +# else + // Not tested (< 3.x.x) + return ID3Field_GetASCII(field,buffer,maxChars,itemNum+1); +# endif +} + +/* + * Delete spaces at the end and the beginning of the string + */ +static void Strip_String (gchar *string) +{ + if (!string) return; + string = g_strstrip(string); +} + diff --git a/src/plugin_xmms/id3_tag.h b/src/plugin_xmms/id3_tag.h new file mode 100644 index 00000000..605e9dc2 --- /dev/null +++ b/src/plugin_xmms/id3_tag.h @@ -0,0 +1,67 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002 Daisuke Shimamura + * + * Based on id3_tag.h - 2001/02/16 + * et_core.h - 2001/10/21 + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 2001-2002 Jerome Couderc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ID3TAG_H__ +#define __ID3TAG_H__ + +#include + +/*************** + * Declaration * + ***************/ + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +/* + * Description of each item of the TagList list + */ +typedef struct _File_Tag File_Tag; +struct _File_Tag +{ + gulong key; /* Incremented value */ + gboolean saved; /* Set to TRUE if this tag had been saved */ + gchar *title; /* Title of track */ + gchar *artist; /* Artist name */ + gchar *album; /* Album name */ + gchar *year; /* Year of track */ + gchar *track; /* Position of track in the album */ + gchar *track_total; /* The number of tracks for the album (ex: 12/20) */ + gchar *genre; /* Genre of song */ + gchar *comment; /* Comment */ +}; + +/************** + * Prototypes * + **************/ +void Initialize_File_Tag_Item (File_Tag *FileTag); +gboolean Free_File_Tag_Item (File_Tag *FileTag); +gboolean Id3tag_Read_File_Tag (gchar *filename, File_Tag *FileTag); + +#endif /* __ID3TAG_H__ */ diff --git a/src/plugin_xmms/mylocale.h b/src/plugin_xmms/mylocale.h new file mode 100644 index 00000000..4bed7f8a --- /dev/null +++ b/src/plugin_xmms/mylocale.h @@ -0,0 +1,55 @@ +/* libxmms-flac - XMMS FLAC input plugin + * + * locale.h - 2000/05/05 13:10 Jerome Couderc + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 1999-2001 H蛆ard Kvè™±en + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* + * Gettext support for EasyTAG + */ + + + +#ifndef __MY_LOCALE_H__ +#define __MY_LOCALE_H__ + + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# define _(String) gettext (String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + + +#endif /* __MY_LOCALE_H__ */ diff --git a/src/plugin_xmms/plugin.c b/src/plugin_xmms/plugin.c index 60521826..f4e40c8b 100644 --- a/src/plugin_xmms/plugin.c +++ b/src/plugin_xmms/plugin.c @@ -22,27 +22,25 @@ #include #include -#include "xmms/plugin.h" -#include "xmms/util.h" +#include +#include +#include +#include + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + #include "FLAC/all.h" +#include "configure.h" +#include "wrap_id3.h" +#include "charset.h" #ifdef min #undef min #endif #define min(x,y) ((x)<(y)?(x):(y)) -typedef struct { - FLAC__byte raw[128]; - char title[31]; - char artist[31]; - char album[31]; - char comment[31]; - unsigned year; - unsigned track; /* may be 0 if v1 (not v1.1) tag */ - unsigned genre; - char description[1024]; /* the formatted description passed to xmms */ -} id3v1_struct; - typedef struct { FLAC__bool abort_flag; FLAC__bool is_playing; @@ -67,7 +65,6 @@ static int FLAC_XMMS__get_time(); static void FLAC_XMMS__cleanup(); static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length); -static FLAC__bool get_id3v1_tag_(const char *filename, id3v1_struct *tag); static void *play_loop_(void *arg); static FLAC__bool safe_decoder_init_(const char *filename, FLAC__FileDecoder *decoder); static void safe_decoder_finish_(FLAC__FileDecoder *decoder); @@ -76,15 +73,14 @@ static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *d static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - InputPlugin flac_ip = { NULL, NULL, "FLAC Player v" FLAC__VERSION_STRING, FLAC_XMMS__init, - NULL, - NULL, + FLAC_XMMS__aboutbox, + FLAC_XMMS__configure, FLAC_XMMS__is_our_file, NULL, FLAC_XMMS__play_file, @@ -101,7 +97,7 @@ InputPlugin flac_ip = NULL, NULL, FLAC_XMMS__get_song_info, - NULL, /* file_info_box */ + NULL, /* file_info_box */ NULL }; @@ -122,6 +118,30 @@ InputPlugin *get_iplugin_info() void FLAC_XMMS__init() { + ConfigFile *cfg; + + flac_cfg.tag_override = FALSE; + g_free(flac_cfg.tag_format); + flac_cfg.convert_char_set = FALSE; + + cfg = xmms_cfg_open_default_file(); + xmms_cfg_read_boolean(cfg, "flac", "tag_override", &flac_cfg.tag_override); + if (!xmms_cfg_read_string(cfg, "flac", "tag_format", + &flac_cfg.tag_format)) + flac_cfg.tag_format = g_strdup("%p - %t"); + + xmms_cfg_read_boolean(cfg, "flac", "convert_char_set", &flac_cfg.convert_char_set); + if (!xmms_cfg_read_string(cfg, "flac", "file_char_set", + &flac_cfg.file_char_set)) + { + flac_cfg.file_char_set = get_current_charset(); + } + if (!xmms_cfg_read_string(cfg, "flac", "user_char_set", + &flac_cfg.user_char_set)) + { + flac_cfg.user_char_set = get_current_charset(); + } + decoder_ = FLAC__file_decoder_new(); } @@ -139,7 +159,7 @@ int FLAC_XMMS__is_our_file(char *filename) void FLAC_XMMS__play_file(char *filename) { FILE *f; - id3v1_struct tag; + gchar *ret; reservoir_samples_ = 0; audio_error_ = false; @@ -166,8 +186,10 @@ void FLAC_XMMS__play_file(char *filename) return; } - (void)get_id3v1_tag_(filename, &tag); - flac_ip.set_info(tag.description, file_info_.length_in_msec, file_info_.sample_rate * file_info_.channels * file_info_.bits_per_sample, file_info_.sample_rate, file_info_.channels); + ret = flac_format_song_title(filename); + flac_ip.set_info(ret, file_info_.length_in_msec, file_info_.sample_rate * file_info_.channels * file_info_.bits_per_sample, file_info_.sample_rate, file_info_.channels); + + g_free(ret); file_info_.seek_to_in_sec = -1; file_info_.play_thread_open = true; @@ -219,7 +241,6 @@ void FLAC_XMMS__cleanup() void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec) { - id3v1_struct tag; FLAC__StreamMetadata streaminfo; if(0 == filename) @@ -238,9 +259,7 @@ void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec) } if(title) { - (void)get_id3v1_tag_(filename, &tag); - *title = g_malloc(strlen(tag.description)+1); - strcpy(*title, tag.description); + *title = flac_format_song_title(filename); } if(length_in_msec) *length_in_msec = streaminfo.data.stream_info.total_samples * 10 / (streaminfo.data.stream_info.sample_rate / 100); @@ -250,52 +269,6 @@ void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec) * local routines **********************************************************************/ -FLAC__bool get_id3v1_tag_(const char *filename, id3v1_struct *tag) -{ - const char *temp; - FILE *f = fopen(filename, "rb"); - memset(tag, 0, sizeof(id3v1_struct)); - - /* set the title and description to the filename by default */ - temp = strrchr(filename, '/'); - if(!temp) - temp = filename; - else - temp++; - strcpy(tag->description, temp); - *strrchr(tag->description, '.') = '\0'; - strncpy(tag->title, tag->description, 30); tag->title[30] = '\0'; - - if(0 == f) - return false; - if(-1 == fseek(f, -128, SEEK_END)) { - fclose(f); - return false; - } - if(fread(tag->raw, 1, 128, f) < 128) { - fclose(f); - return false; - } - fclose(f); - if(strncmp(tag->raw, "TAG", 3)) - return false; - else { - char year_str[5]; - - memcpy(tag->title, tag->raw+3, 30); - memcpy(tag->artist, tag->raw+33, 30); - memcpy(tag->album, tag->raw+63, 30); - memcpy(year_str, tag->raw+93, 4); year_str[4] = '\0'; tag->year = atoi(year_str); - memcpy(tag->comment, tag->raw+97, 30); - tag->genre = (unsigned)((FLAC__byte)tag->raw[127]); - tag->track = (unsigned)((FLAC__byte)tag->raw[126]); - - sprintf(tag->description, "%s - %s", tag->artist, tag->title); - - return true; - } -} - void *play_loop_(void *arg) { (void)arg; @@ -463,3 +436,4 @@ void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorS if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) file_info->abort_flag = true; } + diff --git a/src/plugin_xmms/wrap_id3.c b/src/plugin_xmms/wrap_id3.c new file mode 100644 index 00000000..b1585315 --- /dev/null +++ b/src/plugin_xmms/wrap_id3.c @@ -0,0 +1,272 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2000,2001,2002 Josh Coalson + * Copyright (C) 2002 Daisuke Shimamura + * + * Based on FLAC plugin.c and mpg123 plugin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mylocale.h" +#include "configure.h" + +#ifdef FLAC__HAS_ID3LIB +#include +#include "id3_tag.h" + +#else +#include "charset.h" +#include "genres.h" + +typedef struct id3v1tag_t { + char tag[3]; /* always "TAG": defines ID3v1 tag 128 bytes before EOF */ + char title[30]; + char artist[30]; + char album[30]; + char year[4]; + union { + struct { + char comment[30]; + } v1_0; + struct { + char comment[28]; + char __zero; + unsigned char track; + } v1_1; + } u; + unsigned char genre; +} id3v1_struct; + +typedef struct id3tag_t { + char title[64]; + char artist[64]; + char album[64]; + char comment[256]; + char genre[256]; + char year[16]; + char track[16]; +} id3v2_struct; + +static gboolean get_id3v1_tag_as_v2_(const char *filename, id3v2_struct *tag); +static void flac_id3v1_to_id3v2(id3v1_struct *v1, id3v2_struct *v2); +static const char *flac_get_id3_genre(unsigned char genre_code); +#endif /* FLAC__HAS_ID3LIB */ + +static gchar *extname(const char *filename); +static char* flac_getstr(char* str); +static int flac_getnum(char* str); + +/* + * Function flac_format_song_title (tag, filename) + * + * Create song title according to `tag' and/or `filename' and + * return it. The title must be subsequently freed using g_free(). + * + */ +gchar *flac_format_song_title(gchar * filename) +{ + gchar *ret = NULL; + TitleInput *input = NULL; + gboolean rc; + +#ifdef FLAC__HAS_ID3LIB + File_Tag tag; + Initialize_File_Tag_Item (&tag); + rc = Id3tag_Read_File_Tag (filename, &tag); +#else + id3v2_struct tag; + memset(&tag, 0, sizeof(tag)); + rc = get_id3v1_tag_as_v2_(filename, &tag); +#endif + XMMS_NEW_TITLEINPUT(input); + + if (rc) + { + input->performer = flac_getstr(tag.artist); + input->album_name = flac_getstr(tag.album); + input->track_name = flac_getstr(tag.title); + input->track_number = flac_getnum(tag.track); + input->year = flac_getnum(tag.year); + input->genre = flac_getstr(tag.genre); + input->comment = flac_getstr(tag.comment); + } + input->file_name = g_basename(filename); + input->file_path = filename; + input->file_ext = extname(filename); + ret = xmms_get_titlestring(flac_cfg.tag_override ? + flac_cfg.tag_format : + xmms_get_gentitle_format(), input); + g_free(input); + + if (!ret) + { + /* + * Format according to filename. + */ + ret = g_strdup(g_basename(filename)); + if (extname(ret) != NULL) + *(extname(ret) - 1) = '\0'; /* removes period */ + } + +#ifdef FLAC__HAS_ID3LIB + Free_File_Tag_Item (&tag); +#endif + return ret; +} + +/* + * Function extname (filename) + * + * Return pointer within filename to its extenstion, or NULL if + * filename has no extension. + * + */ +static gchar *extname(const char *filename) +{ + gchar *ext = strrchr(filename, '.'); + + if (ext != NULL) + ++ext; + + return ext; +} + +static char* flac_getstr(char* str) +{ + if (str && strlen(str) > 0) + return str; + return NULL; +} + +static int flac_getnum(char* str) +{ + if (str && strlen(str) > 0) + return atoi(str); + return 0; +} + +#ifndef FLAC__HAS_ID3LIB +/* + * Function get_idv2_tag_(filename, ID3v2tag) + * + * Get ID3v2 tag from file. + * + */ +static gboolean get_id3v1_tag_as_v2_(const char *filename, id3v2_struct *id3v2tag) +{ + FILE *file; + id3v1_struct id3v1tag; + + memset(id3v2tag, 0, sizeof(id3v2_struct)); + + if ((file = fopen(filename, "rb")) != 0) + { + if ((fseek(file, -1 * sizeof (id3v1tag), SEEK_END) == 0) && + (fread(&id3v1tag, 1, sizeof (id3v1tag), file) == sizeof (id3v1tag)) && + (strncmp(id3v1tag.tag, "TAG", 3) == 0)) + { + flac_id3v1_to_id3v2(&id3v1tag, id3v2tag); + + if (flac_cfg.convert_char_set) + { + gchar *string; + + string = convert_from_file_to_user(id3v2tag->title); + strcpy(id3v2tag->title, string); + g_free(string); + + string = convert_from_file_to_user(id3v2tag->artist); + strcpy(id3v2tag->artist, string); + g_free(string); + + string = convert_from_file_to_user(id3v2tag->album); + strcpy(id3v2tag->album, string); + g_free(string); + + string = convert_from_file_to_user(id3v2tag->comment); + strcpy(id3v2tag->comment, string); + g_free(string); + + string = convert_from_file_to_user(id3v2tag->genre); + strcpy(id3v2tag->genre, string); + g_free(string); + + string = convert_from_file_to_user(id3v2tag->year); + strcpy(id3v2tag->year, string); + g_free(string); + + string = convert_from_file_to_user(id3v2tag->track); + strcpy(id3v2tag->track, string); + g_free(string); + } + } + + } + else + { + return FALSE; + } + + return TRUE; +} + +/* + * Function flac_id3v1_to_id3v2 (v1, v2) + * + * Convert ID3v1 tag `v1' to ID3v2 tag `v2'. + * + */ +static void flac_id3v1_to_id3v2(id3v1_struct *v1, id3v2_struct *v2) +{ + memset(v2,0,sizeof(id3v2_struct)); + strncpy(v2->title, v1->title, 30); + strncpy(v2->artist, v1->artist, 30); + strncpy(v2->album, v1->album, 30); + strncpy(v2->comment, v1->u.v1_0.comment, 30); + strncpy(v2->genre, flac_get_id3_genre(v1->genre), sizeof (v2->genre)); + strncpy(v2->year, v1->year, 4); + + /* Check for v1.1 tags. */ + if (v1->u.v1_1.__zero == 0) + sprintf(v2->track, "%d", v1->u.v1_1.track); + else + strcpy(v2->track, "0"); + + g_strstrip(v2->title); + g_strstrip(v2->artist); + g_strstrip(v2->album); + g_strstrip(v2->comment); + g_strstrip(v2->genre); + g_strstrip(v2->year); + g_strstrip(v2->track); +} + +static const char *flac_get_id3_genre(unsigned char genre_code) +{ + if (genre_code < GENRE_MAX) + return gettext(id3_genres[genre_code]); + + return ""; +} +#endif /* ifndef FLAC__HAS_ID3LIB */ diff --git a/src/plugin_xmms/wrap_id3.h b/src/plugin_xmms/wrap_id3.h new file mode 100644 index 00000000..9ee4c2a3 --- /dev/null +++ b/src/plugin_xmms/wrap_id3.h @@ -0,0 +1,24 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002 Daisuke Shimamura + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FLAC_ID3_H__ +#define __FLAC_ID3_H__ + +gchar *flac_format_song_title(gchar * filename); + +#endif