1#!/usr/bin/perl -w 2use Tk; 3use Tk::JPEG; 4use Tk::DialogBox; 5use Tk::BrowseEntry; 6use Tk::FBox; 7use Tk::TextUndo; 8#use POSIX; 9use strict; 10use MP3::Tag; 11 12### TODO 13# 14# make all buttons alive 15# 16# view binary data (as hex dump) 17# 18# delete/add more than one frame at once 19# 20# better open function 21# 22# ... 23# 24# doing changes automatically to all selected files 25# (like setting filename, applying Control-u to all filename, 26# deleting all ID3v2 frames or whatsoever) 27 28 29 30# 31# Sorry, but I know that this is ugly code... 32# 33 34use vars qw/$tktag $VERSION %element %var/; 35 36$VERSION="0.15"; 37 38$var{dir}= shift || "./"; #/mp3/unsorted"; 39$var{v2specent}={TIT2=>{name=>"Song"}, TPE1=>{name=>"Artist"}, 40 TALB=>{name=>"Album"}}; 41$var{filter}=""; 42$var{fnformat} = "%a - %s.mp3"; 43$var{autoinfo} = ["ID3v2","ID3v1","filename"]; 44formatstr($var{fnformat}); 45 46$tktag = MainWindow->new(); #main window 47create_window(); 48 49#&load_filelist; 50 &scan_dir; 51 &filter_and_show; 52 53MainLoop; 54 55exit 0; 56 57#################################### 58 59 60###### tk subs 61sub key_bindings { 62 $tktag->bind('<Control-U>'=>\&use_ucase); 63 $tktag->bind('<Control-u>'=>\&use_ucase_first); 64 $tktag->bind('<Control-l>'=>\&use_lcase); 65 $tktag->bind('<Control-space>'=>\&use_spaces); 66 $tktag->bind('<Control-S>'=>\&save); 67 $tktag->bind('<Control-f>'=>\&autosetfilename); 68 69 $tktag->bind('<Control-n>'=> 70 sub { 71 $element{filelist}->activate($element{filelist} 72 ->index("active")+1); 73 &select; }); 74} 75 76sub create_window { 77 my ($l); 78 79 &key_bindings; 80 81 $element{leftFrame} = $tktag->Frame(); 82 $element{rightFrame} = $tktag->Frame(); 83 $element{rightFrameMul} = $tktag->Frame(); 84 85 # create menu 86 $element{menu} = create_menu($tktag); 87 88 # special fonts 89 $tktag->fontCreate('C_big', -family => 'courier', -weight => 'bold', 90 -size => 18); 91 92 # create Filelist 93 $element{filelist} = $element{leftFrame}->Scrolled("Listbox", -width=>25, 94 -selectmode=>"extended", 95 -scrollbars=>"osre", 96 -takefocus=>1, 97 -exportselection=>0); 98 $element{filelist}->bind("<Double-1>" => \&select); 99 $element{filelist}->bind("<Key-Return>" => \&select); 100 $var{simple}=1; 101 $element{filelist}->bind("<1>" => \&check_multi); 102 $element{filelist}->bind("<Control-a>" => [$element{filelist}, 103 'selectionSet',"0","end"]); 104 my $filter=$element{leftFrame}->Frame(); 105 my $cbline=$filter->Frame(); 106 my $illine=$filter->Frame(); 107 $cbline->Checkbutton(-text => 'ID3v1', 108 -variable => \$var{v1filter}, 109 -command => \&filter_and_show, 110 -relief => 'flat')->pack(-side=>"left"); 111 $cbline->Checkbutton(-text => 'ID3v2', 112 -variable => \$var{v2filter}, 113 -command => \&filter_and_show, 114 -relief => 'flat')->pack(-side=>"left"); 115 $illine->Checkbutton(-text => 'Inverse', 116 -variable => \$var{filter_inv}, 117 -command => \&filter_and_show, 118 -relief => 'flat')->pack(-side=>"left"); 119 $illine->Label(-textvariable=>\$var{visiblefiles}, -relief=>"sunken", 120 width=>5)->pack(-side=>"left", -anchor=>"e"); 121 $cbline->pack(-side=>"top"); 122 $l=$filter->Entry(-textvariable=>\$var{filter}, -width=>25)->pack(-side=>"top"); 123 $l->bind("<FocusOut>" => \&filter_and_show); 124 $l->bind("<KeyPress-Return>" => \&filter_and_show); 125 $illine->pack(-side=>"top"); 126 $element{rightFrameMul}->Label(-text=>"Options for automatic processing ". 127 "of serveral files") 128 ->pack(-side=>"top", -expand=>1, -fill=>"x"); 129 # create filename-area 130 my $fn1area = $element{rightFrame}->Frame(Name=>"fnframe"); 131 my $fn2area = $element{rightFrame}->Frame(); 132 $element{filenamelabel} = $fn1area->Label(-text=>"Filename:") 133 ->pack(-side=>"left", anchor=>"w"); 134 $var{bgcolor}=$element{filenamelabel}->cget("-background"); 135 $l=$fn1area->Entry(-textvariable=>\$var{filename}, -validate=>"key", 136 -vcmd=>val_fn($element{filenamelabel})) 137 ->pack(-side=>"left", -fill=>"x", -expand=>"yes", -anchor=>"w"); 138 139 $fn1area->Button(-text=>"Save changes", -command=>\&save) 140 ->pack(-side=>"left", -anchor=>"w"); 141 $element{setfilename} = $fn2area->Menubutton(qw/-underline 0 -relief raised/, 142 -text => "Set Filename --", 143 -direction => "below"); 144 $element{setfilename}->configure(-menu => $element{setfilename}->menu); 145 $element{setfilename}->command(-label => "from ID3v1 Tag", 146 -command=>[\&setfilename, "ID3v1"]); 147 $element{setfilename}->command(-label => "from ID3v2 Tag", 148 -command=>[\&setfilename, "ID3v2"]); 149 $element{setfilename}->pack(-side=>"left", anchor=>"n", -padx=>15); 150 151 $element{setid3v1} = $fn2area->Menubutton(qw/-underline 0 -relief raised/, 152 -text => "Set ID3v1 --", 153 -direction => "below"); 154 $element{setid3v1}->configure(-menu => $element{setid3v1}->menu); 155 $element{setid3v1}->command(-label => "from Filename", 156 -command=>[\©fntov1]); 157 $element{setid3v1}->command(-label => "from ID3v2 Tag", 158 -command=>[\©v2tov1]); 159 $element{setid3v1}->pack(-side=>"left", anchor=>"n", -padx=>15); 160 161 $element{setid3v2} = $fn2area->Menubutton(qw/-underline 0 -relief raised/, 162 -text => "Set ID3v2 --", 163 -direction => "below"); 164 $element{setid3v2}->configure(-menu => $element{setid3v2}->menu); 165 $element{setid3v2}->command(-label => "from Filename", 166 -command=>[\©fntov2]); 167 $element{setid3v2}->command(-label => "from ID3v1 Tag", 168 -command=>\©v1tov2); 169 $element{setid3v2}->pack(-side=>"left", anchor=>"n", -padx=>15); 170 171 $element{removebutton} = $fn2area->Menubutton(qw/-underline 0 -relief raised/, 172 -text => "Remove --", 173 -direction => "below"); 174 $element{removebutton}->configure(-menu => $element{removebutton}->menu); 175 $element{removebutton}->command(-label => "File", 176 -command=>sub{ 177 $var{filename}=""; 178 $element{filenamelabel} 179 ->configure(-background=>"red");}); 180 $element{removebutton}->command(-label => "ID3v1 Tag", 181 -command=>sub{ 182 if (exists $var{v1}) { 183 &remove_id3v1; 184 $element{v1caption} 185 ->configure(-background=>"red");}}); 186 $element{removebutton}->command(-label => "ID3v2 Tag", 187 -command=>sub{ 188 if (exists $var{v2}) { 189 &remove_id3v2; 190 $element{v2caption} 191 ->configure(-background=>"red");}}); 192 $element{removebutton}->pack(-side=>"left", anchor=>"n", -padx=>15); 193 194 # create ID3v1 area 195 my $v1area = $element{rightFrame}->Frame(Name=>"v1frame"); 196 my $v1caption = $v1area->Frame(-background=>"red"); 197 my $v1labels = $v1area->Frame(); 198 my $v1entries = $v1area->Frame(); 199 my $v2apic = $v1area->Frame(); 200 my $a=0; 201 $element{v1caption}=$v1caption->Label(-text=>"ID3v1.1", -font=>"C_big", 202 -background=>"red", -relief=>"ridge") 203 ->pack(-side=>"top", -anchor=>"c", -expand=>"yes", -fill=>"x"); 204 $l = $v1labels->Label(-text=>"Song:")->pack(-side=>"top", -anchor=>"e"); 205 $v1entries->Entry(-textvariable=>\$var{v1song}, -width=>30, 206 -validate=>"key", -vcmd=>val_text($l,30)) 207 ->pack(-side=>"top", -anchor=>"w"); 208 $l = $v1labels->Label(-text=>"Artist:")->pack(-side=>"top", -anchor=>"e", 209 -pady=>2); 210 $v1entries->Entry(-textvariable=>\$var{v1artist}, -width=>30, 211 -validate=>"key", -vcmd=>&val_text($l,30)) 212 ->pack(-side=>"top", -anchor=>"w"); 213 $l = $v1labels->Label(-text=>"Album:")->pack(-side=>"top", -anchor=>"e"); 214 $v1entries->Entry(-textvariable=>\$var{v1album}, -width=>30, 215 -validate=>"key", -vcmd=>&val_text($l,30)) 216 ->pack(-side=>"top", -anchor=>"w"); 217 $l = $v1labels->Label(-text=>"Comment:")->pack(-side=>"top", -anchor=>"e", 218 -pady=>1); 219 $v1entries->Entry(-textvariable=>\$var{v1comment}, -width=>30, 220 -validate=>"key", -vcmd=>val_text($l,28)) 221 ->pack(-side=>"top", -anchor=>"w"); 222 $element{genrelabel} = $v1labels->Label(-text=>"Genre:")->pack(-side=>"top", 223 -anchor=>"e"); 224 my $genres = ["", sort @{MP3::Tag::genres()}]; 225 $v1entries->BrowseEntry(-variable => \$var{v1genre}, -choices => $genres, 226 -state=>"readonly", -browsecmd=> 227 sub { $element{genrelabel} 228 ->configure(-background=>"yellow"); 229 $element{v1caption} 230 ->configure(-background=>"yellow"); 231 push @{$var{labels}}, $element{genrelabel} }) 232 ->pack(-side=>"top", -anchor=>"w"); 233 $l = $v1labels->Label(-text=>"Year:")->pack(-side=>"top", -anchor=>"e"); 234 $v1entries->Entry(-textvariable=>\$var{v1year}, -width=>4, 235 -validate=>"key", -vcmd=>val_num($l,4)) 236 ->pack(-side=>"top", -anchor=>"w"); 237 $l = $v1labels->Label(-text=>"Track:")->pack(-side=>"top", -anchor=>"e", 238 -pady=>2); 239 $v1entries->Entry(-textvariable=>\$var{v1track}, -width=>4, 240 -validate=>"key", -vcmd=>val_num($l,3)) 241 ->pack(-side=>"top", -anchor=>"w"); 242 $element{apic} = $v2apic->Photo('apic'); 243 $element{apic}->blank; 244 $v2apic->Label(-image=>'apic', -height=>150, -width=>180) 245 ->pack(-side=>"top", -anchor=>"center"); 246 $element{apictext}=$v2apic->Label(-text=>"")->pack(-side=>"top", 247 -anchor=>"center"); 248 $v1caption->pack(-side=>"top", -expand=>"yes", -fill=>"x"); 249 $v1labels->pack(-side=>"left"); 250 $v1entries->pack(-side=>"left"); 251 $v2apic->pack(-side=>"right"); 252 253 # ID3v2 area 254 my $v2area = $element{rightFrame}->Frame(Name=>"v2frame"); 255 my $v2caption = $v2area->Frame(); 256 my $v2top = $v2area->Frame(); 257 my $v2right = $v2area->Frame(); 258 my $v2buttons = $v2top->Frame(); 259 my $v2labent = $v2top->Frame(); 260 my $v2labels = $v2labent->Frame(); 261 my $v2entries = $v2labent->Frame(); 262 my $v2parea = $v2right->Frame(); 263 my $v2iarea = $v2right->Frame(); 264 $element{v2caption}=$v2caption->Label(-text=>"ID3v2.3", -font=>"C_big", 265 -background=>"red", -relief=>"ridge") 266 ->pack(-side=>"top", -anchor=>"c", -fill=>"x", -expand=>"yes"); 267 while (my ($fname,$val) = each %{$var{v2specent}}) { 268 $val->{label} = $v2labels->Label(-text=>$val->{name})->pack(-side=>"top", 269 -anchor=>"e"); 270 $val->{entry} = $v2entries->Entry(-textvariable=>\$var{"v2$fname"}, 271 -width=>40, -validate=>"key", 272 -vcmd=>[\&val_v2,$element{v2caption}, 273 $val->{label}, $a]) 274 ->pack(-side=>"top", -anchor=>"w"); 275 } 276 $v2buttons->Button(-text=>"Add Frame", -command=>\&add_frame) 277 ->pack(-side=>"left", -anchor=>"c"); 278 $v2buttons->Button(-text=>"Delete Frame(s)", -command=>\&del_frame) 279 ->pack(-side=>"left", -anchor=>"c"); 280 $element{frames} = $v2iarea->Scrolled("Listbox", -scrollbars=>"re", -width=>"8", 281 -selectmode=>"browse", -takefocus=>1) 282 ->pack(-side=>"left"); 283 $element{frames}->bind("<Double-1>" => \&show_frame); 284 $element{frames}->bind("<Key-Return>" => \&show_frame); 285 $v2parea->Label(-textvariable=>\$var{longname})->pack(-side=>"top", 286 -anchor=>"n", -pady=>5); 287 $element{frameinfo} = $v2parea; 288 $v2labels->pack(-side=>"left"); 289 $v2entries->pack(-side=>"left"); 290 $v2labent->pack(-side=>"left", -anchor=>"nw"); 291 $v2buttons->pack(-side=>"left", -fill=>"y", -expand=>"yes"); 292 $v2iarea->pack(-side=>"left", -anchor=>"nw"); 293 $v2parea->pack(-side=>"left", -fill=>"both", -expand=>"yes", -anchor=>"nw"); 294 $v2caption->pack(-side=>"top", -expand=>"yes", -fill=>"x"); 295 $v2top->pack(-side=>"top", -fill=>"x", -expand=>"yes", -anchor=>"n"); 296 $v2right->pack(-side=>"left", -fill=>"both", -expand=>"yes", -anchor=>"n"); 297 298 # pack left Frame 299 $element{filelist}->pack(-side=>"top", -fill=>"y", -expand=>"yes"); 300 $filter->pack(-side=>"bottom"); 301 302 # pack right Frame 303 $fn1area->pack(-side=>"top", -anchor=>"nw", -expand=>"yes", -fill=>"x"); 304 $fn2area->pack(-side=>"top", -anchor=>"nw", -expand=>"yes", -fill=>"x"); 305 $v1area->pack(-side=>"top", -anchor=>"nw", -expand=>"yes", -fill=>"x", 306 -pady=>10); 307 $v2area->pack(-side=>"top", -anchor=>"nw", -expand=>"yes", -fill=>"x"); 308 $v2parea->pack(-side=>"top", -anchor=>"nw", -expand=>"yes", -fill=>"x"); 309 310 # pack main window 311 $element{menu}->pack(-side=>"top", -fill=>"x", -anchor=>"nw"); 312 $element{leftFrame}->pack(-side=>"left", -fill=>"y", -anchor=>"w"); 313 $element{rightFrame}->pack(-side=>"left",-fill=>"both",-expand=>"yes", 314 -anchor=>"nw"); 315 316 #prepare open dialog window 317 $element{open} = $tktag->DialogBox(-title=>"Open directory", 318 -buttons=>["Open", "Cancel"]); 319 $element{open}->add("Label", -text=>"Directory:")->pack(); 320 $element{open}->add("Entry", -width=>35, -textvariable=>\$var{dir})->pack(); 321 322 $element{fnformat} = $tktag->DialogBox(-title=>"Set filename format", 323 -buttons=>["Set", "Cancel"]); 324 $element{fnformat}->add("Label", -text=>"Format")->pack(); 325 $element{fnformat}->add("Entry", -width=>35, -textvariable=>\$var{fnformat}) 326 ->pack(); 327 $element{fnformat}->add("Label", 328 -text=>"%s - Song %l - Album\n%a - Artist". 329 " %t - Track\n %c - Comment ". 330 "%g - Genre\n %y - Year". 331 "\nSee also README file")->pack(); 332 333 $element{addelframe} = $tktag->DialogBox(-buttons=>["Ok", "Cancel"]); 334 $element{addelabel} = $element{addelframe}->add("Label") 335 ->pack(); 336 $element{addelistbox} = $element{addelframe}->add("Scrolled", "Listbox", 337 -scrollbars=>"osre", -width=>50) 338 ->pack(-fill=>"both", -expand=>1); 339 340} 341 342 343sub val_v2 { 344 my ($label1, $label2, $change) = @_; 345 if ($_[7] == -1) { 346 $change=0; 347 return 1; 348 } 349 return 1 if $change++; 350 $label1->configure(-background=>"yellow"); 351 if (defined $label2) { 352 $label2->configure(-background=>"yellow"); 353 push @{$var{labels}}, $label2; 354 } 355 return 1; 356} 357 358sub val_fn { 359 my ($label1, $change) = @_; 360 return 361 sub { 362 if ($_[4] == -1) { 363 $change=0; 364 return 1; 365 } 366 return 1 if $change++; 367 $label1->configure(-background=>"yellow"); 368 return 1; 369 } 370} 371 372 373sub val_text { 374 my ($label, $length, $change) = @_; 375 return 376 sub { 377 my ($pro, undef, undef, undef, $type) = @_; 378 return 0 if $type == 1 && length($pro) > $length; 379 if ($type == -1) { 380 $change=0; 381 return 1; 382 } 383 return 1 if $change++; 384 $label->configure(-background=>"yellow"); 385 $element{v1caption}->configure(-background=>"yellow"); 386 push @{$var{labels}}, $label; 387 return 1; 388 } 389} 390 391sub val_num { 392 my ($label, $length, $change) = @_; 393 return 394 sub { 395 my ($pro, undef, undef, undef, $type) = @_; 396 return 0 if $type == 1 && !($pro =~ /^\d{0,$length}$/o); 397 if ($type == -1) { 398 $change=0; 399 return 1; 400 } 401 return 1 if $change++; 402 $label->configure(-background=>"yellow"); 403 $element{v1caption}->configure(-background=>"yellow"); 404 push @{$var{labels}}, $label; 405 return 1; 406 } 407} 408 409sub create_menu { 410 my $menu = shift->Menu(-type=>"menubar"); 411 412 my $file=$menu->cascade(-label=>"File"); 413 $file->command(-label=>"Open", -command=>\&load_filelist); 414 $file->separator(); 415 $file->command(-label=>"Exit", -command=>sub {exit 0;}); 416 417 my $opts=$menu->cascade(-label=>"Options"); 418 $opts->command(-label=>"Filename format", -command=>\&filename_format); 419 420 return $menu; 421} 422 423sub tk_question { 424 my $text = shift; 425 my $ans = $tktag->messageBox(-text=>$text, -title=>"Question", -type=>"YesNo", 426 -default=>"No", -icon=>"question" ); 427 return $ans eq "Yes" ? 1 : 0; 428} 429 430sub tk_warning { 431 my $text = shift; 432 $tktag->messageBox(-text=>$text, -title=>"Warning", -buttons=>"Ok", 433 -icon=>"warning" ); 434} 435 436####### file subs 437 438sub load_filelist { 439 $element{open}->configure(-title=>"Open directory"); 440 my $answer = $element{open}->Show; 441 if ($answer eq "Open") { 442 $var{dir} =~ s!/$!!; 443 $var{dir} .= "/"; 444 &scan_dir; 445 &filter_and_show; 446 } 447} 448 449sub scan_dir { 450 delete $var{files}; 451 opendir(DIR, $var{dir}) or return; 452 $tktag->Busy; 453 $tktag->update; 454 my $file; 455 while (defined($file = readdir(DIR))) { 456 if (-d $var{dir} . $file) { 457 $var{files}->{$file}={dir=>$var{dir}, isDir=>1}; 458 } elsif (-f _) { 459 my $mp3=MP3::Tag->new($var{dir}.$file); 460 $var{files}->{$file}={dir=>$var{dir}}; 461 foreach ($mp3->getTags) { 462 $var{files}->{$file}->{$_}=1; 463 } 464 } 465 } 466 closedir DIR; 467 $tktag->Unbusy; 468} 469 470sub filter_and_show { 471 my (@files, @dirs, $name, $val, $filter); 472 $element{filelist}->delete("0", "end"); 473 if ($var{filter} ne "") { 474 $filter = qr/$var{filter}/i; 475 } 476 while (($name, $val)=each %{$var{files}}) { 477 if (exists $val->{isDir}) { 478 push @dirs, "[$name]"; 479 } else { 480 if (!$var{v1filter} || (!$var{filter_inv} && $val->{ID3v1}) 481 || ($var{filter_inv} && !$val->{ID3v1})) { 482 if (!$var{v2filter} || (!$var{filter_inv} && $val->{ID3v2}) 483 || ($var{filter_inv} && !$val->{ID3v2})) { 484 if (!$filter || (!$var{filter_inv} && $name =~ $filter) 485 || ($var{filter_inv} && !($name =~ $filter))) { 486 push @files, $name; 487 } 488 } 489 } 490 } 491 } 492 $element{filelist}->insert("end", sort @dirs); 493 $element{filelist}->insert("end", sort @files); 494 $var{visiblefiles}=$#files+1; 495} 496 497 498sub select { 499 my $active =$element{filelist}->get("active","active"); 500 if ($active =~ /^\[(.*)\]$/) { 501 if (exists $var{files}->{$1}->{isDir}) { 502 $var{dir}.="$1/"; 503 &scan_dir; 504 &filter_and_show; 505 return; 506 } 507 } 508 $var{filename}=$active; 509 $var{oldfilename} = $var{filename}; 510 my $filename = $var{dir}.$var{filename}; 511 $var{mp3}->close if exists $var{mp3}; 512 delete $var{v1}; 513 delete $var{v2}; 514 $element{filenamelabel}->configure(-background=>$var{bgcolor}); 515 $var{mp3} = MP3::Tag->new($filename); 516 $var{mp3}->getTags; 517 518 # remove old things 519 foreach (@{$var{fpack}}) { 520 $_->packForget(); 521 } 522 $var{fpack} = []; 523 $var{longname}=""; 524 if (exists $var{labels}) { 525 while (my $label = shift @{$var{labels}}) { 526 $label->configure(-background=>$var{bgcolor}); 527 } 528 } 529 530 # set information of ID3v1 tag 531 if (exists $var{mp3}->{ID3v1}) { 532 $element{v1caption}->configure(-background=>"green"); 533 $var{v1}=$var{mp3}->{ID3v1}; 534 ($var{v1song},$var{v1artist},$var{v1album},$var{v1year},$var{v1comment},$var{v1track},$var{v1genre}) 535 = $var{v1}->all(); 536 } else { 537 ($var{v1song},$var{v1artist},$var{v1album},$var{v1year},$var{v1comment},$var{v1track},$var{v1genre}) 538 = ("","","","","","",""); 539 $element{v1caption}->configure(-background=>"red"); 540 } 541 542 #set information of ID3v2 tag 543 if (exists $var{mp3}->{ID3v2}) { 544 $element{v2caption}->configure(-background=>"green"); 545 $var{v2}=$var{mp3}->{ID3v2}; 546 my $frames = $var{v2}->getFrameIDs; 547 while (my ($fname, $val) = each %{$var{v2specent}}) { 548 if (exists $frames->{$fname}) { 549 $var{"v2$fname"} = $var{v2}->getFrame($fname); 550 $val->{entry}->bind('<FocusOut>' => v2_specent_change($fname)); 551 } else { 552 $var{"v2$fname"} = ""; 553 $val->{entry}->bind('<FocusOut>' => v2_specent_create($fname)); 554 } 555 } 556 if (exists $frames->{"APIC"}) { 557 show_picture("APIC"); 558 } else { 559 $element{apic}->blank; 560 $element{apictext}->configure(-text=>""); 561 } 562 my @frames = sort keys %$frames; 563 $element{frames}->delete("0","end"); 564 $element{frames}->insert("end", @frames); 565 show_frame($frames[0],1); 566 } else { 567 while (my ($fname, $val) = each %{$var{v2specent}}) { 568 $var{"v2$fname"}=""; 569 $val->{entry}->bind('<FocusOut>' => v2_specent_create($fname)); 570 } 571 $element{v2caption}->configure(-background=>"red"); 572 $element{frames}->delete("0","end"); 573 $element{apic}->blank; 574 $element{apictext}->configure(-text=>""); 575 } 576} 577 578sub v2_specent_change { 579 my $fname = shift; 580 return sub { 581 $var{v2}->change_frame($fname, $var{"v2$fname"}); 582 if (exists $var{current_frame} && $var{current_frame} eq $fname) { 583 $var{frame_Text}->delete("0.1", "end"); 584 $var{frame_Text}->insert("0.1", $var{"v2$fname"}); 585 } 586 }; 587} 588 589sub v2_specent_create { 590 my $fname = shift; 591 return sub { 592 return if $var{"v2$fname"} eq ""; 593 $var{v2}=$var{mp3}->newTag("ID3v2") unless exists $var{v2}; 594 $var{v2}->add_frame($fname, $var{"v2$fname"}); 595 my @allframes = $element{frames}->get(0,"end"); 596 push @allframes, $fname; 597 $element{frames}->delete(0,"end"); 598 $element{frames}->insert("end", sort @allframes); 599 $var{v2specent}->{$fname}->{entry}->bind('<FocusOut>' => 600 v2_specent_change($fname)); 601 }; 602} 603 604sub show_frame { 605 my ($fname, $tagchanged) = @_; 606 if (ref $fname) { # called from listbox-bind 607 $fname = $fname->get("active"); 608 } 609 save_frameinfo() unless defined $tagchanged; 610 # delete last info 611 foreach (@{$var{fpack}}) { 612 $_->packForget(); 613 } 614 $var{fpack} = []; 615 $var{current_frame}=""; 616 return unless length($fname) == 4 || length($fname) == 6; 617 my $info; 618 $var{current_frame} = $fname; 619 ($info, $var{longname}) = $var{v2}->getFrame($fname); 620 (undef, $var{restrinp}) = $var{v2}->what_data($fname); 621 if (ref $info) { 622 my ($key, $value); 623 foreach $key (sort keys %$info) { 624 $value = $info->{$key}; 625 my $f = $element{frameinfo}->Frame(); 626 push @{$var{fpack}}, $f; 627 if ($key =~ s/^_//) { 628 my $l=$f->Label(-text=>"$key:", -justify=>"left") 629 ->pack(-side=>"left", -anchor=>"w"); 630 my $b=$f->Menubutton(qw/-underline 0 -relief raised/, 631 -text => "Data of " .length($value) . 632 " Bytes --", -direction => "below"); 633 $b->configure(-menu => $b->menu); 634 $var{"data_$key"}=$value; 635 $b->command(-label => "Save Data", -command=>[\&save_data,$key]); 636 $b->command(-label => "Load Data", -command=>[\&load_data,$key,$b, $l]); 637 $b->command(-label => "View Data", -command=>[\&view_data,$key]); 638 $b->pack(-side=>"left", anchor=>"n"); 639 } else { 640 my $l=$f->Label(-text=>"$key:", -justify=>"left") 641 ->pack(-side=>"left", -anchor=>"w"); 642 if (exists $var{restrinp}->{$key}) { 643 my $state="readonly"; 644 if (exists $var{restrinp}->{$key}->{"_FREE"}) { 645 $state="normal"; 646 delete $var{restrinp}->{$key}->{"_FREE"}; 647 } 648 $var{"frame_$key"}=$value; 649 my @inps=sort keys %{$var{restrinp}->{$key}}; 650 $f->BrowseEntry(-variable => \$var{"frame_$key"}, -choices => \@inps, 651 -state=>$state, -width=>37, -browsecmd=> 652 sub { $l->configure(-background=>"yellow"); 653 $element{v2caption} 654 ->configure(-background=>"yellow");}) 655 ->pack(-side=>"right", -anchor=>"e"); 656 657 } else { 658 $var{"frame_$key"} = $f->TextUndo(-height=>2, -width=>40, -wrap=>"word") 659 ->pack(-side=>"right", -anchor=>"e"); 660 $var{"frame_$key"}->insert("0.0", $value); 661 $var{"frame_$key"}->bind('<Double-1>' => 662 sub{ $var{"frame_$key"} 663 ->configure(-disable=>1);}); 664 push @{$var{fpack}}, $var{"frame_$key"}; 665 $var{"frame_$key"}->bind('<Key>'=>[\&yyy, $l]); 666 } 667 } 668 $f->pack(-side=>"top", -anchor=>"w", -fill=>"x", -expand=>"yes"); 669 } 670 } else { 671 if (exists $var{restrinp}->{Text}) { 672 my $state="readonly"; 673 if (exists $var{restrinp}->{Text}->{"_FREE"}) { 674 $state="normal"; 675 delete $var{restrinp}->{Text}->{"_FREE"}; 676 } 677 $var{"frame_Text"}=$info; 678 my @inps=sort keys %{$var{restrinp}->{Text}}; 679 push @{$var{fpack}},$element{frameinfo}->BrowseEntry( 680 -variable => \$var{"frame_Text"}, 681 -choices => \@inps, -width=>37, 682 -state=>$state, -browsecmd=> 683 sub { $element{v2caption} 684 ->configure(-background=>"yellow")}) 685 ->pack(-side=>"top", -anchor=>"n"); 686 } else { 687 $var{frame_Text} = $element{frameinfo}->TextUndo(-height=>2, -width=>40, 688 -wrap=>"word") 689 ->pack(-side=>"top", -anchor=>"n"); 690 $var{frame_Text}->insert("0.0", $info); 691 push @{$var{fpack}}, $var{frame_Text}; 692 if (exists $var{v2specent}->{$fname}) { 693 $var{frame_Text}->bind('<Key>'=>[\&xxx, $fname]); 694 } 695 } 696 } 697} 698 699sub save_frameinfo { 700 # save last info 701 return unless exists $var{current_frame}; 702 my ($format, $resinp) = $var{v2}->what_data($var{current_frame}); 703 my @data=(); 704 foreach (@$format) { 705 if (/^_/) { 706 push @data, $var{"data$_"}; 707 next; 708 } 709 my $d; 710 if ($var{"frame_$_"} =~ /Text/) { 711 $d= $var{"frame_$_"}->get("0.1","end"); 712 } else { 713 $d= $var{"frame_$_"}; 714 $d= $resinp->{$_}->{$d} if (defined $resinp->{$_}->{$d}); 715 }; 716 chomp $d; 717 $d =~ s/ +$//; 718 push @data, $d; 719 } 720 $var{v2}->change_frame($var{current_frame}, @data); 721} 722 723sub xxx { 724 my ($textobject, $fname) = @_; 725 my $text = $textobject->get("0.1","end"); 726 chomp($text); 727 $var{"v2$fname"} = $text; 728 $var{v2specent}->{$fname}->{label}->configure(-background=>"yellow"); 729 $element{v2caption}->configure(-background=>"yellow"); 730} 731 732sub yyy { 733 $_[1]->configure(-background=>"yellow"); 734 $element{v2caption}->configure(-background=>"yellow"); 735} 736 737 738sub show_picture { 739 my $fname = shift; 740 my $frame = $var{v2}->getFrame($fname); 741 if ($frame->{"MIME type"} =~ /image\/(gif|jpe?g|bmp)/i) { 742 my $type = lc $1; 743 $type =~ s/jpg/jpeg/; 744 open(TMP, ">/tmp/_tk_temp.jpg"); 745 binmode TMP; 746 print TMP $frame->{_Data}; 747 close TMP; 748 $element{apic}->configure(-format=>$1, -file=>"/tmp/_tk_temp.jpg"); 749 my $text .= $frame->{"Picture Type"}; 750 $text = $frame->{Description} if $text eq "Other"; 751 $text = "ID3v2.3-" . uc($fname) . ": ". $text; 752 $element{apictext}->configure(-text=>$text); 753 unlink "/tmp/_tk_temp.jpg"; 754 } 755} 756 757sub save { 758 # save changes to filename 759 if ($var{filename} ne $var{oldfilename}) { 760 return 0 unless change_filename(); 761 } 762 $element{filenamelabel}->configure(-background=>$var{bgcolor}); 763 #save changes of ID3v1 tag 764 if ($element{v1caption}->cget("-background") eq "yellow") { 765 my @fields; 766 for (qw/v1song v1artist v1album v1year v1comment v1track v1genre/) { 767 push @fields, $var{$_}; 768 } 769 $var{v1}=$var{mp3}->newTag("ID3v1") unless exists $var{v1}; 770 $var{v1}->all(@fields); 771 $var{v1}->writeTag; 772 $var{v1genre}=$var{v1}->genre(); 773 $element{v1caption}->configure(-background=>"green"); 774 } elsif (exists $var{v1} && $element{v1caption}->cget("-background") eq "red") { 775 $var{v1}->removeTag; 776 delete $var{v1}; 777 } 778 779 #save changes of ID3v2 tag 780 if ($element{v2caption}->cget("-background") eq "yellow") { 781 $var{v2}=$var{mp3}->newTag("ID3v2") unless exists $var{v2}; 782 save_frameinfo(); 783 while (my ($fname, $val)=each %{$var{v2specent}}) { 784 if ($var{"v2$fname"} ne "" && 785 $val->{label}->cget("-background") eq "yellow") { 786 my $d=$var{"v2$fname"}; 787 $d=~s/ +$//; 788 if (defined $var{v2}->getFrame($fname)) { 789 $var{v2}->change_frame($fname, $d); 790 } else { 791 $var{v2}->add_frame($fname, $d); 792 } 793 $val->{label}->configure(-background=>$var{bgcolor}); 794 } 795 } 796 $var{v2}->write_tag; 797 $element{v2caption}->configure(-background=>"green"); 798 foreach my $v2e ( @{$var{fpack}}) { 799 foreach ($v2e->children) { 800 $_->configure(-background=>$var{bgcolor}) if /Label/; 801 } 802 } 803 } elsif (exists $var{v2} && 804 $element{v2caption}->cget("-background") eq "red") { 805 $var{v2}->remove_tag; 806 delete $var{v2}; 807 } 808 if (exists $var{labels}) { 809 while (my $label = shift @{$var{labels}}) { 810 $label->configure(-background=>$var{bgcolor}); 811 } 812 } 813} 814 815sub change_filename { 816 my $success = 0; 817 if ($var{filename} eq "") { 818 if (tk_question("Filename is empty. Do you want to ". 819 "delete $var{oldfilename}?")) { 820 $var{mp3}->close; 821 if (unlink $var{dir}.$var{oldfilename}) { 822 remove_id3v1(); 823 remove_id3v2(); 824 $element{v1caption}->configure(-background=>"red"); 825 $element{v2caption}->configure(-background=>"red"); 826 $element{filelist}->delete("active","active"); 827 delete $var{files}->{$var{oldfilename}}; 828 $success = 1; 829 } else { 830 tk_warning("Cannot delete file."); 831 } 832 } 833 } elsif (-e $var{dir}.$var{filename}) { 834 if (-f _) { 835 if (tk_question("Files $var{filename} exists. Do you want". 836 " to overwrite it?")) { 837 goto re; 838 } 839 } else { 840 tk_warning("$var{filename} exists and it isn't a plain file.". 841 " Can't rename $var{oldfilename}!"); 842 } 843 } else { 844 re: 845 if (rename($var{dir}.$var{oldfilename}, $var{dir}.$var{filename}) || 846 (system("mv", $var{dir}.$var{oldfilename}, $var{dir}.$var{filename})==0)) { 847 $var{files}->{$var{filename}}=$var{files}->{$var{oldfilename}}; 848 delete $var{files}->{$var{oldfilename}}; 849 $var{oldfilename} = $var{filename}; 850 my $index=$element{filelist}->index("active"); 851 filter_and_show; 852 $element{filelist}->see($index); 853 $element{filelist}->activate($index); 854 $var{mp3}->{filename}=$var{dir}.$var{filename}; 855 $success = 1; 856 } else { 857 tk_warning("Couldn't rename $var{oldfilename} to $var{filename}"); 858 } 859 } 860 return $success; 861} 862 863sub remove_id3v1 { 864 for (qw/v1song v1artist v1album v1year v1comment v1track v1genre/) { 865 $var{$_} = ""; 866 } 867} 868 869sub remove_id3v2 { 870 for (keys %{$var{v2specent}}) { 871 $var{"v2$_"} = ""; 872 } 873 $element{frames}->delete("0","end"); 874 foreach (@{$var{fpack}}) { 875 $_->packForget(); 876 } 877 $var{fpack} = []; 878 $var{longname}=""; 879} 880 881sub add_frame { 882 return unless exists $var{mp3}; 883 $element{addelframe}->configure(-title=>"Add Frame"); 884 $element{addelabel}->configure(-text=>"Select a frame to add:"); 885 $element{addelistbox}->delete("0","end"); 886 $var{v2}=$var{mp3}->newTag("ID3v2") unless exists $var{v2}; 887 my $list = $var{v2}->supported_frames; 888 my @list = map {"$_ - $list->{$_}"} sort keys %$list; 889 $element{addelistbox}->insert("end",@list); 890 if ($element{addelframe}->Show() eq "Ok") { 891 $element{v2caption}->configure(-background=>"yellow"); 892 my $fname= substr $element{addelistbox}->get("active","active"),0,4; 893 $fname = $var{v2}->add_frame($fname); 894 my $index=0; 895 my $maxindex = $element{frames}->index("end"); 896 while ($index<$maxindex && $element{frames}->get($index,$index) lt $fname) { 897 $index++; 898 } 899 $element{frames}->insert($index, $fname); 900 $element{frames}->activate($index); 901 $element{frames}->selectionSet($index); 902 show_frame($fname); 903 } 904} 905 906sub del_frame { 907 return unless exists $var{v2}; 908 $element{addelframe}->configure(-title=>"Delete Frame"); 909 $element{addelabel}->configure(-text=>"Select a frame to delete:"); 910 $element{addelistbox}->delete("0","end"); 911 my $list = $var{v2}->getFrameIDs; 912 my @list = map {"$_ - $list->{$_}"} sort keys %$list; 913 $element{addelistbox}->insert("end",@list); 914 if ($element{addelframe}->Show() eq "Ok") { 915 $element{v2caption}->configure(-background=>"yellow"); 916 my $fname= $element{addelistbox}->get("active","active"); 917 $fname =~ s/^([A-Z0-9]+) .*/$1/; 918 $var{v2}->remove_frame($fname); 919 my $index=0; 920 my $maxindex = $element{frames}->index("end"); 921 while ($index<$maxindex && $element{frames}->get($index,$index) ne $fname) { 922 $index++; 923 } 924 $element{frames}->delete($index,$index); 925 if ($var{current_frame} eq $fname) { 926 show_frame($element{frames}->get("active"),1); 927 } 928 if (exists $var{v2specent}->{$fname}) { 929 $var{"v2$fname"}=""; 930 $var{v2specent}->{$fname}->{label}->configure(-background=>"yellow"); 931 } 932 } 933} 934 935sub check_multi { 936 my ($h,$w,%info); 937 my @sel = $element{filelist}->curselection(); 938 if ($#sel >0 && $var{simple}) { 939 $element{rightFrame}->packForget; 940 $element{rightFrameMul}->pack(-side=>"left",-fill=>"both", 941 -expand=>"yes", -anchor=>"nw"); 942 $var{simple}=0; 943 } elsif ($#sel == 0 && ! $var{simple}) { 944 $element{rightFrameMul}->packForget; 945 $element{rightFrame}->pack(-side=>"left",-fill=>"both", 946 -expand=>"yes", -anchor=>"nw"); 947 $var{simple}=1; 948 } 949} 950 951sub setfilename { 952 my $tag = shift; # may be 'ID3v1', 'ID3v2' or 'filename' 953 $tag =~ s/ID3//; 954 return undef unless exists $var{$tag} || $tag eq "filename"; 955 my $new = $var{setfilename}->{stencil}; 956 my $i=0; 957 foreach my $part (@{$var{setfilename}->{details}}) { 958 my $code=$part->{tag}; 959 if ($tag eq "v2") { 960 $code =~ s/song/TIT2/ || 961 $code =~ s/album/TALB/ || 962 $code =~ s/artist/TPE1/; 963 } 964 my $txt=""; 965 if ($tag eq "filename") { 966 if ($code eq "song" || $code eq "artist" || 967 $code eq "album" || $code eq "track") { 968 $txt = $var{mp3}->{filename}->$code($var{dir}.$var{filename}); 969 } 970 } else { 971 $txt = $var{"$tag$code"}; 972 } 973 $txt =~ s/ *$//; 974 $txt = substr $txt, 0, $part->{length} if exists $part->{length} && 975 ((! exists $part->{fill}) || exists $part->{precise} ); 976 $txt = $part->{fill} x ($part->{length}-length($txt)) . $txt 977 if exists $part->{fill}; 978 $new =~ s/%$i/$txt/; 979 $i++; 980 } 981 $new =~ s/ /_/g if exists $var{setfilename}->{nospaces}; 982 $var{filename}=$new; 983 $element{filenamelabel}->configure(-background=>"yellow"); 984 return 1; 985} 986 987sub formatstr { 988 my $format = shift; 989 my %tags = (s=>"song", a=>"artist", l=>"album", y=>"year", 990 g=>"genre", t=>"track"); 991 my @fmt; 992 993 while ($format =~ /%([0-9]*)(?:(!)?:(.))?([salygt])/g) { 994 my $t; 995 $t->{length}=$1 if defined $1 && $1 ne ""; 996 $t->{precise}=1 if defined $2 && $2 ne ""; 997 $t->{fill}=$3 if defined $3 && $3 ne ""; 998 $t->{tag} = $tags{$4} if defined $4 && $4 ne ""; 999 push @fmt, $t if defined $4 && $4 ne ""; 1000 } 1001 my $i=0; 1002 $format =~ s/%([0-9]*)(?:(!)?:(.))?([salygt])/"%".$i++/eg; 1003 $var{setfilename}->{stencil}=$format; 1004 $var{setfilename}->{details}=\@fmt; 1005} 1006 1007sub element_change { 1008 my $element = shift; 1009 1010 if ($element->PathName =~/v1/) { 1011 $element{v1caption}->configure(-background=>"yellow"); 1012 } elsif ($element->PathName =~/v2/) { 1013 $element{v2caption}->configure(-background=>"yellow"); 1014 } elsif ($element->PathName =~/fn/) { 1015 $element{filenamelabel}->configure(-background=>"yellow"); 1016 } 1017} 1018 1019sub use_ucase { 1020 my $element=shift; 1021 if ($element =~ /Entry/) { 1022 my $evar = $element->cget(-textvariable); 1023 my $ovar = $$evar; 1024 $$evar =~ tr/[a-z]/[A-Z]/; 1025 $$evar =~ s/\.MP3$/.mp3/; 1026 if ($ovar ne $$evar) { 1027 element_change($element); 1028 } 1029 } elsif ($element =~ /Text/) { 1030 my $text = $element->get("0.1","end"); 1031 chomp $text; 1032 return if $text eq ""; 1033 if ($text =~ tr/[a-z]/[A-Z]/) { 1034 element_change($element); 1035 $element->delete("0.1","end"); 1036 $element->insert("end",$text); 1037 } 1038 } 1039} 1040 1041sub use_lcase { 1042 my $element=shift; 1043 1044 if ($element =~ /Entry/) { 1045 my $evar = $element->cget(-textvariable); 1046 return if $$evar eq ""; 1047 if ($$evar =~ tr/[A-Z]/[a-z]/) { 1048 element_change($element); 1049 } 1050 } elsif ($element =~ /Text/) { 1051 my $text = $element->get("0.1","end"); 1052 chomp $text; 1053 return if $text eq ""; 1054 if ($text =~ tr/[A-Z]/[a-z]/) { 1055 element_change($element); 1056 $element->delete("0.1","end"); 1057 $element->insert("end",$text); 1058 } 1059 } 1060} 1061 1062sub use_ucase_first { 1063 my $element=shift; 1064 1065 if ($element =~ /Entry/) { 1066 my $evar = $element->cget(-textvariable); 1067 return if $$evar eq ""; 1068 my $ovar=$$evar; 1069 $$evar=ucase_first($$evar); 1070 if ($ovar ne $$evar) { 1071 element_change($element); 1072 } 1073 } elsif ($element =~ /Text/) { 1074 my $text = $element->get("0.1","end"); 1075 chomp $text; 1076 return if $text eq ""; 1077 my $otext = ucase_first($text); 1078 if ($otext ne $text) { 1079 $element->delete("0.1","end"); 1080 $element->insert("end",$otext); 1081 element_change($element); 1082 } 1083 } 1084} 1085 1086sub ucase_first { 1087 my $text=shift; 1088 $text =~ s/(\w+)/\L\u$1/gm; 1089 $text =~ s/('[A-Z])/\L$1/g; #'); 1090 $text =~ s/\.Mp3$/.mp3/; 1091 return $text; 1092} 1093 1094sub use_spaces { 1095 my $element=shift; 1096 if ($element =~ /Entry/) { 1097 my $evar = $element->cget(-textvariable); 1098 return if $$evar eq ""; 1099 my $ovar=$$evar; 1100 $$evar=spaces($$evar); 1101 if ($ovar ne $$evar) { 1102 element_change($element); 1103 } 1104 } 1105} 1106 1107sub spaces { 1108 my $text=shift; 1109 $text =~ s/%20/_/g; 1110 if ((($text =~ tr/././) >2)) { 1111 $text =~ s/\./ /g; 1112 $text =~ s/ (mp3)$/.$1/i; 1113 $text =~ s/(\w)-(\w)/$1 - $2/g; 1114 } elsif ($text =~ /_/) { 1115 $text =~ s/_/ /g; 1116 $text =~ s/(\w)-(\w)/$1 - $2/g; 1117 } else { 1118 $text =~ s/ /_/g; 1119 $text =~ s/_-_/-/g; 1120 } 1121 $text=~ s/ +/ /g; 1122 return $text; 1123} 1124 1125 1126sub filename_format { 1127 if ( $element{fnformat}->Show eq "Set") { 1128 formatstr($var{fnformat}); 1129 } 1130} 1131 1132sub view_data { 1133 my $key= shift; 1134 warn "Viewing of $key of $var{current_frame} not supported yet\n"; 1135} 1136 1137sub load_data { 1138 my ($key, $button,$label)= @_; 1139 my @types=(["All files", "*"]); 1140 my $file = $tktag->getOpenFile(-filetypes => \@types); 1141 if (open (LOAD, $file)) { 1142 binmode LOAD; 1143 local $/; 1144 undef $/; 1145 $var{"data_$key"}=<LOAD>; 1146 close LOAD; 1147 warn "Please set mime type according to new data\n"; 1148 $button->configure(-text => "Data of " .length($var{"data_$key"}) . 1149 " Bytes --"); 1150 $label->configure(-background=>"yellow"); 1151 $element{v2caption}->configure(-background=>"yellow"); 1152 } else { 1153 warn "Couldn't open $file for saving $var{current_frame}.$key"; 1154 } 1155} 1156 1157sub save_data { 1158 my $key= shift; 1159 my @types=(["All files", "*"]); 1160 my $file = $tktag->getSaveFile(-filetypes => \@types, 1161 -initialfile => 'Untitled', 1162 -defaultextension => '.dat'); 1163 if (open (SAVE, ">$file")) { 1164 binmode SAVE; 1165 print SAVE $var{"data_$key"}; 1166 close SAVE; 1167 } else { 1168 warn "Couldn't open $file for saving $var{current_frame}.$key"; 1169 } 1170} 1171 1172sub copyv1tov2 { 1173 my %v1tov2 = (artist=>"TPE1", album=>"TALB", song=>"TIT2", 1174 year=>"TYER", track=>"TRCK", comment=>"COMM", genre=>"TCON"); 1175 return unless exists $var{v1}; 1176 $var{v2}=$var{mp3}->newTag("ID3v2") unless exists $var{v2}; 1177 my $frames = $var{v2}->getFrameIDs; 1178 while (my ($v1,$v2) = each %v1tov2) { 1179 next if $var{"v1$v1"} eq ""; 1180 my ($data, $restr) = $var{v2}->what_data($v2); 1181 my @newdata; 1182 if ($#{$data}==0) { 1183 @newdata = ($var{"v1$v1"}); 1184 } else { 1185 foreach (@$data) { 1186 if ($_ eq "Text") { 1187 push @newdata, $var{"v1$v1"}; 1188 } else { 1189 push @newdata, ""; 1190 } 1191 } 1192 } 1193 if (exists $frames->{$v2}) { 1194 $var{v2}->change_frame($v2, @newdata); 1195 } else { 1196 $var{v2}->add_frame($v2, @newdata); 1197 add2framelist($v2); 1198 } 1199 if (exists $var{v2specent}->{$v2}) { 1200 $var{"v2$v2"}=$var{"v1$v1"}; 1201 $var{v2specent}->{$v2}->{label}->configure(-background=>"yellow"); 1202 } 1203 } 1204 $element{v2caption}->configure(-background=>"yellow"); 1205} 1206 1207sub copyv2tov1 { 1208} 1209 1210sub copyfntov1 { 1211 $var{v1}=$var{mp3}->newTag("ID3v1") unless exists $var{v1}; 1212 foreach (qw/song artist album track/) { 1213 $var{"v1$_"}=$var{mp3}->{filename}->$_($var{dir}.$var{filename}); 1214 } 1215} 1216 1217sub copyfntov2 { 1218} 1219 1220sub add2framelist { 1221 my $fname = shift; 1222 my $index=0; 1223 my $maxindex = $element{frames}->index("end"); 1224 while ($index<$maxindex && $element{frames}->get($index,$index) lt $fname) { 1225 $index++; 1226 } 1227 $element{frames}->insert($index, $fname); 1228 $element{frames}->activate($index); 1229 $element{frames}->selectionSet($index); 1230} 1231 1232sub autosetfilename { 1233 foreach (@{$var{autoinfo}}) { 1234 last if setfilename($_); 1235 } 1236} 1237