1
/* $Id: tag-renamer.c 1450 2006-06-17 19:10:02Z jannis $ */
3
* Copyright (c) 2006 Jannis Pohlmann <jannis@xfce.org>
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful, but
11
* WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
32
#include <taglib/tag_c.h>
36
#include <tag-renamer.h>
37
#include <audio-tags-page.h>
38
#include <media-tags-provider.h>
42
static GType tag_renamer_format_type;
47
tag_renamer_format_get_type (void)
49
return tag_renamer_format_type;
55
tag_renamer_register_enum_types (ThunarxProviderPlugin *plugin)
57
static const GEnumValue tag_renamer_format_values[] =
59
{ TAG_RENAMER_FORMAT_TITLE, "TAG_RENAMER_FORMAT_TITLE", N_ ("Title"), },
60
{ TAG_RENAMER_FORMAT_ARTIST_TITLE, "TAG_RENAMER_FORMAT_ARTIST_TITLE", N_ ("Artist - Title"), },
61
{ TAG_RENAMER_FORMAT_TRACK_TITLE, "TAG_RENAMER_FORMAT_TRACK_TITLE", N_ ("Track - Title"), },
62
{ TAG_RENAMER_FORMAT_TRACK_ARTIST_TITLE, "TAG_RENAMER_FORMAT_TRACK_ARTIST_TITLE", N_ ("Track - Artist - Title"), },
63
{ TAG_RENAMER_FORMAT_TRACK_DOT_TITLE, "TAG_RENAMER_FORMAT_TRACK_DOT_TITLE", N_ ("Track. Title"), },
64
{ TAG_RENAMER_FORMAT_TRACK_DOT_ARTIST_TITLE, "TAG_RENAMER_FORMAT_TRACK_DOT_ARTIST_TITLE", N_ ("Track. Artist - Title"), },
65
{ TAG_RENAMER_FORMAT_ARTIST_TRACK_TITLE, "TAG_RENAMER_FORMAT_ARTIST_TRACK_TITLE", N_ ("Artist - Track - Title"), },
69
tag_renamer_format_type = thunarx_provider_plugin_register_enum (plugin, "TagRenamerFormat", tag_renamer_format_values);
74
/* Property identifiers */
86
static void tag_renamer_class_init (TagRenamerClass *klass);
87
static void tag_renamer_init (TagRenamer *tag_renamer);
88
static void tag_renamer_finalize (GObject *object);
89
static void tag_renamer_get_property (GObject *object,
93
static void tag_renamer_set_property (GObject *object,
97
static void tag_renamer_realize (GtkWidget *widget);
98
static gchar *tag_renamer_process (ThunarxRenamer *renamer,
99
ThunarxFileInfo *file,
102
static GList *tag_renamer_get_actions (ThunarxRenamer *renamer,
105
static void tag_renamer_edit_tags_activated (GtkAction *action,
106
ThunarxFileInfo *file);
110
struct _TagRenamerClass
112
ThunarxRenamerClass __parent__;
117
ThunarxRenamer __parent__;
120
GtkTooltips *tooltips;
123
TagRenamerFormat format;
124
gboolean replace_spaces;
132
THUNARX_DEFINE_TYPE (TagRenamer, tag_renamer, THUNARX_TYPE_RENAMER);
137
tag_renamer_class_init (TagRenamerClass *klass)
139
ThunarxRenamerClass *thunarxrenamer_class;
140
GtkWidgetClass *gtkwidget_class;
141
GObjectClass *gobject_class;
143
gobject_class = G_OBJECT_CLASS (klass);
144
gobject_class->finalize = tag_renamer_finalize;
145
gobject_class->get_property = tag_renamer_get_property;
146
gobject_class->set_property = tag_renamer_set_property;
148
gtkwidget_class = GTK_WIDGET_CLASS (klass);
149
gtkwidget_class->realize = tag_renamer_realize;
151
thunarxrenamer_class = THUNARX_RENAMER_CLASS (klass);
152
thunarxrenamer_class->process = tag_renamer_process;
153
thunarxrenamer_class->get_actions = tag_renamer_get_actions;
158
* Naming format used for renaming the selected files.
160
g_object_class_install_property (gobject_class,
162
g_param_spec_enum ("format",
165
TYPE_TAG_RENAMER_FORMAT,
166
TAG_RENAMER_FORMAT_TRACK_TITLE,
170
* TagRenamer:replace-spaces:
172
* Whether spaces should be replaced with _ or not
174
g_object_class_install_property (gobject_class,
176
g_param_spec_boolean ("replace-spaces",
183
* TagRenamer:lowercase:
185
* Whether all chars will be converted to lowercase.
187
g_object_class_install_property (gobject_class,
189
g_param_spec_boolean ("lowercase",
200
tag_renamer_init (TagRenamer *tag_renamer)
202
AtkRelationSet *relations;
203
AtkRelation *relation;
212
/* Allocate shared tooltips */
213
tag_renamer->tooltips = gtk_tooltips_new ();
214
exo_gtk_object_ref_sink (GTK_OBJECT (tag_renamer->tooltips));
216
table = gtk_table_new (2, 3, FALSE);
217
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
218
gtk_table_set_col_spacings (GTK_TABLE (table), 12);
219
gtk_box_pack_start (GTK_BOX (tag_renamer), table, FALSE, FALSE, 0);
220
gtk_widget_show (table);
223
label = gtk_label_new_with_mnemonic (_("_Format:"));
224
gtk_misc_set_alignment (GTK_MISC (label), 0.05f, 0.5f);
225
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
226
gtk_widget_show (label);
228
/* Format combo box */
229
combo = gtk_combo_box_new_text ();
230
klass = g_type_class_ref (TYPE_TAG_RENAMER_FORMAT);
231
for (n = 0; n < klass->n_values; ++n)
232
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _(klass->values[n].value_nick));
233
exo_mutual_binding_new (G_OBJECT (tag_renamer), "format", G_OBJECT (combo), "active");
234
gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
235
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
236
g_type_class_unref (klass);
237
gtk_widget_show (combo);
239
/* Set Atk label relation for the combo box */
240
object = gtk_widget_get_accessible (combo);
241
relations = atk_object_ref_relation_set (gtk_widget_get_accessible (label));
242
relation = atk_relation_new (&object, 1, ATK_RELATION_LABEL_FOR);
243
atk_relation_set_add (relations, relation);
244
g_object_unref (G_OBJECT (relation));
246
button = gtk_check_button_new_with_mnemonic (_("_Underscores"));
247
exo_mutual_binding_new (G_OBJECT (button), "active", G_OBJECT (tag_renamer), "replace-spaces");
248
gtk_tooltips_set_tip (tag_renamer->tooltips, button, _("Activating this option will replace all spaces in the target filename "
249
"with underscores."), NULL);
250
gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
251
gtk_widget_show (button);
253
button = gtk_check_button_new_with_mnemonic (_("_Lowercase"));
254
exo_mutual_binding_new (G_OBJECT (button), "active", G_OBJECT (tag_renamer), "lowercase");
255
gtk_tooltips_set_tip (tag_renamer->tooltips, button, _("If you activate this, the resulting filename will only contain lowercase letters."), NULL);
256
gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
257
gtk_widget_show (button);
259
/* TODO add entry for custom format here */
261
/* Set initial values */
262
tag_renamer->artist = g_strdup ("");
263
tag_renamer->title = g_strdup ("");
264
tag_renamer_set_artist (tag_renamer, _("Unknown Artist"));
265
tag_renamer_set_title (tag_renamer, _("Unknown Title"));
271
tag_renamer_finalize (GObject *object)
273
TagRenamer *tag_renamer = TAG_RENAMER (object);
275
/* release the tooltips */
276
g_object_unref (G_OBJECT (tag_renamer->tooltips));
279
g_free (tag_renamer->artist);
280
g_free (tag_renamer->title);
282
(*G_OBJECT_CLASS (tag_renamer_parent_class)->finalize) (object);
288
tag_renamer_get_property (GObject *object,
293
TagRenamer *tag_renamer = TAG_RENAMER (object);
298
g_value_set_enum (value, tag_renamer_get_format (tag_renamer));
301
case PROP_REPLACE_SPACES:
302
g_value_set_boolean (value, tag_renamer_get_replace_spaces (tag_renamer));
306
g_value_set_boolean (value, tag_renamer_get_lowercase (tag_renamer));
310
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
318
tag_renamer_set_property (GObject *object,
323
TagRenamer *tag_renamer = TAG_RENAMER (object);
328
tag_renamer_set_format (tag_renamer, g_value_get_enum (value));
331
case PROP_REPLACE_SPACES:
332
tag_renamer_set_replace_spaces (tag_renamer, g_value_get_boolean (value));
336
tag_renamer_set_lowercase (tag_renamer, g_value_get_boolean (value));
340
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
348
tag_renamer_realize (GtkWidget *widget)
350
/* Realize the widget */
351
(*GTK_WIDGET_CLASS (tag_renamer_parent_class)->realize) (widget);
357
tag_renamer_process (ThunarxRenamer *renamer,
358
ThunarxFileInfo *file,
362
TagRenamer *tag_renamer = TAG_RENAMER (renamer);
364
TagLib_File *taglib_file;
365
TagLib_Tag *taglib_tag;
366
const TagLib_AudioProperties *taglib_properties;
368
gchar *result = NULL;
376
/* Strip of the file:// from the URI */
377
uri = thunarx_file_info_get_uri (file);
378
filename = g_filename_from_uri (uri, NULL, NULL);
380
/* Return if URI could not be resolved */
381
if (G_UNLIKELY (filename == NULL))
382
return g_strdup (text);
384
/* Load taglib file */
385
taglib_file = taglib_file_new (filename);
387
/* Don't change anything if taglib file could not be allocated */
388
if (G_UNLIKELY (taglib_file == NULL))
391
return g_strdup (text);
395
taglib_tag = taglib_file_tag (taglib_file);
397
/* Abort if tag info could not be loaded */
398
if (G_UNLIKELY (taglib_tag == NULL))
400
taglib_file_free (taglib_file);
402
return g_strdup (text);
405
/* Load tag properties */
406
taglib_properties = taglib_file_audioproperties (taglib_file);
409
artist = g_strdup (taglib_tag_artist (taglib_tag));
410
title = g_strdup (taglib_tag_title (taglib_tag));
411
track_num = taglib_tag_track (taglib_tag);
413
/* Strip additional whitespace from the tags */
417
/* Replace missing artist tag */
418
if (G_UNLIKELY (g_utf8_strlen (artist, -1) == 0))
419
artist = g_strdup (tag_renamer_get_artist (tag_renamer));
421
/* Replace missing song title tag */
422
if (G_UNLIKELY (g_utf8_strlen (title, -1) == 0))
423
title = g_strdup (tag_renamer_get_title (tag_renamer));
426
track = g_strdup ("00");
428
track = g_strdup_printf ("%02d", taglib_tag_track (taglib_tag));
430
/* Replace special chars with underscores */
431
artist = g_strdelimit (artist, G_DIR_SEPARATOR_S, '_');
432
title = g_strdelimit (title, G_DIR_SEPARATOR_S, '_');
433
track = g_strdelimit (track, G_DIR_SEPARATOR_S, '_');
435
switch (tag_renamer_get_format (tag_renamer))
437
case TAG_RENAMER_FORMAT_TRACK_DOT_TITLE:
438
result = g_strconcat (track, ". ", title, NULL);
441
case TAG_RENAMER_FORMAT_TRACK_DOT_ARTIST_TITLE:
442
result = g_strconcat (track, ". ", artist, " - ", title, NULL);
445
case TAG_RENAMER_FORMAT_TRACK_TITLE:
446
result = g_strconcat (track, " - ", title, NULL);
449
case TAG_RENAMER_FORMAT_TRACK_ARTIST_TITLE:
450
result = g_strconcat (track, " - ", artist, " - ", title, NULL);
453
case TAG_RENAMER_FORMAT_TITLE:
454
result = g_strconcat (title, NULL);
457
case TAG_RENAMER_FORMAT_ARTIST_TITLE:
458
result = g_strconcat (artist, " - ", title, NULL);
461
case TAG_RENAMER_FORMAT_ARTIST_TRACK_TITLE:
462
result = g_strconcat (artist, " - ", track, " - ", title, NULL);
466
result = g_strdup (text);
470
/* Replace spaces if requested */
471
if (tag_renamer_get_replace_spaces (tag_renamer))
472
result = g_strdelimit (result, " ", '_');
474
/* Convert to lowercase if requested */
475
if (tag_renamer_get_lowercase (tag_renamer))
478
result = g_utf8_strdown (result, -1);
489
/* Free tag info strings */
490
taglib_tag_free_strings ();
492
/* Destroy the taglib file */
493
taglib_file_free (taglib_file);
501
tag_renamer_get_actions (ThunarxRenamer *renamer,
507
GList *actions = NULL;
508
ThunarxFileInfo *info;
510
if (g_list_length (files) != 1)
513
file = g_list_first (files);
515
if (G_UNLIKELY (file == NULL))
518
info = THUNARX_FILE_INFO (file->data);
520
if (G_LIKELY (media_tags_get_audio_file_supported (info)))
522
/* Edit tags action */
523
action = gtk_action_new ("edit-tags", _("Edit _Tags"), _("Edit ID3/OGG tags of this file."), GTK_STOCK_EDIT);
524
g_object_set_data_full (G_OBJECT (action), "window", g_object_ref (G_OBJECT (window)), (GDestroyNotify)g_object_unref);
525
g_signal_connect (G_OBJECT (action), "activate", G_CALLBACK (tag_renamer_edit_tags_activated), info);
526
actions = g_list_prepend (actions, action);
537
* Allocates a new #TagRenamer instance.
539
* Return value: the newly allocated #TagRenamer.
542
tag_renamer_new (void)
544
return g_object_new (TYPE_TAG_RENAMER,
545
"name", _("Audio Tags"),
552
* tag_renamer_get_format:
553
* @tag_renamer : a #TagRenamer.
555
* Returns the current #TagRenamerFormat
556
* for the @tag_renamer.
558
* Return value: the current naming format of @tag_renamer.
561
tag_renamer_get_format (TagRenamer *tag_renamer)
563
g_return_val_if_fail (IS_TAG_RENAMER (tag_renamer), TAG_RENAMER_FORMAT_TRACK_TITLE);
564
return tag_renamer->format;
570
* tag_renamer_set_format:
571
* @tag_renamer : a #TagRenamer.
572
* @format : the new #TagRenamerFormat.
574
* Sets the #TagRenamerFormat of the @tag_renamer
575
* to the specified @format.
578
tag_renamer_set_format (TagRenamer *tag_renamer,
579
TagRenamerFormat format)
581
g_return_if_fail (IS_TAG_RENAMER (tag_renamer));
583
/* Check if we already use that format */
584
if (G_UNLIKELY (tag_renamer->format == format))
587
/* Apply the new format */
588
tag_renamer->format = format;
590
/* Notify listeners */
591
g_object_notify (G_OBJECT (tag_renamer), "format");
593
/* Emit the "changed" signal */
594
thunarx_renamer_changed (THUNARX_RENAMER (tag_renamer));
600
* tag_renamer_get_replace_spaces:
601
* @tag_renamer : a #TagRenamer.
603
* Returns whether spaces are going to be replaced with underscores or not.
605
* Return value: whether spaces are going to be replaced or not.
608
tag_renamer_get_replace_spaces (TagRenamer *tag_renamer)
610
g_return_val_if_fail (IS_TAG_RENAMER (tag_renamer), FALSE);
611
return tag_renamer->replace_spaces;
617
* tag_renamer_set_replace_spaces:
618
* @tag_renamer : a #TagRenamer.
619
* @replace : a boolean flag.
621
* Sets whether spaces are going to be replaced with underscores or not.
624
tag_renamer_set_replace_spaces (TagRenamer *tag_renamer,
627
g_return_if_fail (IS_TAG_RENAMER (tag_renamer));
629
/* Abort if flag is already set */
630
if (G_UNLIKELY (tag_renamer->replace_spaces == replace))
633
/* Apply the new setting */
634
tag_renamer->replace_spaces = replace;
636
/* Notify listeners */
637
g_object_notify (G_OBJECT (tag_renamer), "replace-spaces");
639
/* Emit the "changed" signal */
640
thunarx_renamer_changed (THUNARX_RENAMER (tag_renamer));
646
* tag_renamer_get_lowercase:
647
* @tag_renamer : a #TagRenamer.
649
* Returns whether the resulting filename will be completely lowercase.
651
* Return value: whether all letters will be lowercase.
654
tag_renamer_get_lowercase (TagRenamer *tag_renamer)
656
g_return_val_if_fail (IS_TAG_RENAMER (tag_renamer), FALSE);
657
return tag_renamer->lowercase;
663
* tag_renamer_set_lowercase:
664
* @tag_renamer : a #TagRenamer.
665
* @lowercase : a boolean flag.
667
* Sets whether all letters are going to be converted to lowercase.
670
tag_renamer_set_lowercase (TagRenamer *tag_renamer,
673
g_return_if_fail (IS_TAG_RENAMER (tag_renamer));
675
/* Abort if flag is already set */
676
if (G_UNLIKELY (tag_renamer->lowercase == lowercase))
679
/* Apply the new setting */
680
tag_renamer->lowercase = lowercase;
682
/* Notify listeners */
683
g_object_notify (G_OBJECT (tag_renamer), "lowercase");
685
/* Emit the "changed" signal */
686
thunarx_renamer_changed (THUNARX_RENAMER (tag_renamer));
692
* tag_renamer_get_artist:
693
* @tag_renamer : a #TagRenamer.
695
* Returns the artist name to use if the artist tag is missing.
697
* Return value: default artist name to use if a file lacks of an artist tag.
700
tag_renamer_get_artist (TagRenamer *tag_renamer)
702
g_return_val_if_fail (IS_TAG_RENAMER (tag_renamer), _("Unknown Artist"));
703
return tag_renamer->artist;
709
* tag_renamer_set_artist:
710
* @tag_renamer : a #TagRenamer.
711
* @artist : a nul-terminated string.
713
* Sets the artist name to use if a file is missing an artist tag.
716
tag_renamer_set_artist (TagRenamer *tag_renamer,
719
g_return_if_fail (IS_TAG_RENAMER (tag_renamer));
721
/* Abort if flag is already set */
722
if (G_UNLIKELY (tag_renamer->artist != NULL))
723
if (G_UNLIKELY (g_utf8_collate (tag_renamer->artist, artist) == 0))
727
if (G_LIKELY (tag_renamer->artist != NULL))
728
g_free (tag_renamer->artist);
730
/* Apply the new setting */
731
tag_renamer->artist = g_strdup (artist);
733
/* Emit the "changed" signal */
734
thunarx_renamer_changed (THUNARX_RENAMER (tag_renamer));
740
* tag_renamer_get_title:
741
* @tag_renamer : a #TagRenamer.
743
* Returns the song title to use if the title tag is missing.
745
* Return value: song title to use if a file lacks of a title tag.
748
tag_renamer_get_title (TagRenamer *tag_renamer)
750
g_return_val_if_fail (IS_TAG_RENAMER (tag_renamer), _("Unknown Title"));
751
return tag_renamer->title;
757
* tag_renamer_set_title:
758
* @tag_renamer : a #TagRenamer.
759
* @title : a nul-terminated string.
761
* Sets the song title to use if a file is missing a title tag.
764
tag_renamer_set_title (TagRenamer *tag_renamer,
767
g_return_if_fail (IS_TAG_RENAMER (tag_renamer));
769
/* Abort if flag is already set */
770
if (G_UNLIKELY (g_utf8_collate (tag_renamer->title, title) == 0))
774
if (G_UNLIKELY (tag_renamer->title != NULL))
775
if (G_LIKELY (tag_renamer->title != NULL))
776
g_free (tag_renamer->title);
778
/* Apply the new setting */
779
tag_renamer->title = g_strdup (title);
781
/* Emit the "changed" signal */
782
thunarx_renamer_changed (THUNARX_RENAMER (tag_renamer));
788
tag_renamer_edit_tags_activated (GtkAction *action,
789
ThunarxFileInfo *file)
794
/* Determine the parent window */
795
window = g_object_get_data (G_OBJECT (action), "window");
796
if (G_UNLIKELY (window == NULL))
799
dialog = audio_tags_page_dialog_new (window, file);
801
gtk_dialog_run (GTK_DIALOG (dialog));
802
gtk_widget_destroy (dialog);