Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

shetane

macrumors newbie
Jan 9, 2012
1
0
I have a french iTunes account, would that have anything to do with it not working for me?
 

ebengtso

macrumors newbie
Oct 8, 2011
9
1
here the version updated for french, dutch and german, and a small bug fix when the track iTunes id could not be found

PHP:
#!/usr/bin/env ruby
# reviewed by Erik B on January 21 2012
# by @tapbot_paul
# Don't blame me if this nukes your metadata, formats your drive, kills your kids
# This script goes through any iCloud Matched songs in your iTunes library and tries to update the 
# metadata from the iTunes Store
# Will run against selected tracks or if nothing selected entire library
# install the required gems with the following commands
# sudo gem install json
# sudo gem install rb-appscript
# then run the script with "ruby meta.rb"
require 'rubygems'
require 'appscript'
require 'json'
require 'open-uri'

class Track
  attr_reader :iTunes_id
  attr_reader :iTunes_track
def initialize(iTunes_track)
  @iTunes_track = iTunes_track
  path = @iTunes_track.location.get.path
  file_string = File.open(path, 'r').read(1024) # data always seems to be around 600-700 bytes in
  index = file_string.index('song')
  if index
    @iTunes_id = file_string[index+4,4].unpack('N')[0]
  else
    puts "Couldn't find @iTunes_track id #{iTunes_track.name.get}"
  end
end

def valid?
  @iTunes_id.nil?
end

def update_track(result)
  @iTunes_track.name.set(result['trackName'])
  @iTunes_track.album.set(result['collectionName'])
  @iTunes_track.artist.set(result['artistName'])
  @iTunes_track.track_count.set(result['trackCount'])
  @iTunes_track.track_number.set(result['trackNumber'])
  @iTunes_track.genre.set(result['primaryGenreName'])
  @iTunes_track.disc_count.set(result['discCount'])
  @iTunes_track.disc_number.set(result['discNumber'])
end

end

WORK_SIZE = 100
STDOUT.sync = true
tracks = []

app = Appscript.app.by_name("iTunes")

iTunes_tracks = app.selection.get
if iTunes_tracks.count == 0
  iTunes_tracks = app.library_playlists[1].tracks.get
end

print "Reading #{iTunes_tracks.count} tracks "
iTunes_tracks.each do | iTunes_track |
  begin
      if iTunes_track.kind.get == 'Matched AAC audio file' or iTunes_track.kind.get == 'Fichier audio AAC acheté' or iTunes_track.kind.get =='Fichier audio AAC mis en correspondance' or iTunes_track.kind.get == 'Fichier audio AAC' or iTunes_track.kind.get == 'Abgeglichene AAC-Audiodatei'
      track = Track.new(iTunes_track)
      print "Track #{track}"
      unless track.valid?
        tracks << track
        print '*' if ((tracks.count % WORK_SIZE) == 0)
      end
    end
  rescue StandardError => e
    puts e
  end
end
puts ''

# all 2 char countries codes lots currently not valid %w(AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS BH BD BB BY BE BZ BJ BM BT BO BQ BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CD CK CR CI HR CU CW CY CZ DK DJ DM DO EC EG SV GQ ER EE ET FK FO FJ FI FR GF PF TF GA GM GE DE GH GI GR GL GD GP GU GT GG GN GW GY HT HM VA HN HK HU IS IN ID IR IQ IE IM IL IT JM JP JE JO KZ KE KI KP KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS MA MZ MM NA NR NP NL NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA RE RO RU RW BL SH KN LC MF PM VC WS SM ST SA SN RS SC SL SG SX SK SI SB SO ZA GS SS ES LK SD SR SJ SZ SE CH SY TW TJ TZ TH TL TG TK TO TT TN TR TM TC TV UG UA AE GB US UM UY UZ VU VE VN VG VI WF EH YE ZM ZW)

countries = %w(US GB AU FR DE CA IT JP DZ AO AI AG AR AM AT AZ BS BH BD BB BY BE BZ BM BO BW BR BN BG CM KY CL CN CO CR CI HR CY CZ DK DM DO EC EG SV EE ET FI GH GR GD GT GY HN HK HU IS IN ID IE IL JM JO KZ KE KR KW LV LB LY LI LT LU MO MK MG MY MV ML MT MU MX MD MS MM NP NL NZ NI NE NG NO OM PK PA PY PE PH PL PT QA RO RU KN LC VC SA SN RS SG SK SI ZA ES LK SR SE CH TW TZ TH TT TN TR TC UG UA AE UY UZ VE VN VG YE)

puts "Found #{tracks.count} matched tracks"
countries.each do | country |
  print "Querying #{country} store for #{tracks.count} tracks "
  counter = 0
  tracks.dup.each.each_slice(WORK_SIZE) do | subtracks |
    ids = subtracks.map { | track | track.iTunes_id }
    iTunesHash = JSON.parse(open("http://itunes.apple.com/lookup?id=#{ids.join(',')}&country=#{country}").read)
    print '*'
    iTunesHash['results'].each do | result |
      result_id = result['trackId']
      subtracks.each do | track |
        if result_id == track.iTunes_id
          track.update_track(result)
          tracks.delete(track)
          counter += 1
          break
        end
      end
    end
  end
  puts " #{counter} updated"
  break if tracks.empty?
end

puts "Couldn't find meatadata for #{tracks.count} tracks" if tracks.count != 0
 
Last edited:

bkonings

macrumors newbie
Sep 17, 2009
23
4
Dutch + fix for no genre in store

I changed the script just a little to fit my needs and figured i'd share it :)
Changes:

- Added support for Dutch
- I had a problem with one song that returned no genre (nil), it made the script fail. I changed it to check for Genre=nil, if so the tag is not written.
Added filling Album Artist with the artist name, again fitted my needs, put a # before @iTunes_track.album_artist.set(result['artistName']) if you don't want it. The true Album Artist data doesn't seem to be provided by Apple so that couldn't be used.
-Added filling year tag (including check if the date is available)

(a sample of the data provided: http://itunes.apple.com/lookup?id=487985217 )

PHP:
#!/usr/bin/env ruby
# reviewed by Erik B on January 21 2012
# by @tapbot_paul
# Don't blame me if this nukes your metadata, formats your drive, kills your kids
# This script goes through any iCloud Matched songs in your iTunes library and tries to update the 
# metadata from the iTunes Store
# Will run against selected tracks or if nothing selected entire library
# install the required gems with the following commands
# sudo gem install json
# sudo gem install rb-appscript
# then run the script with "ruby meta.rb"
require 'rubygems'
require 'appscript'
require 'json'
require 'open-uri'

class Track
  attr_reader :iTunes_id
  attr_reader :iTunes_track
def initialize(iTunes_track)
  @iTunes_track = iTunes_track
  path = @iTunes_track.location.get.path
  file_string = File.open(path, 'r').read(1024) # data always seems to be around 600-700 bytes in
  index = file_string.index('song')
  if index
    @iTunes_id = file_string[index+4,4].unpack('N')[0]
  else
    puts "Couldn't find @iTunes_track id #{iTunes_track.name.get}"
  end
end

def valid?
  @iTunes_id.nil?
end

def update_track(result)
  @iTunes_track.name.set(result['trackName'])
  @iTunes_track.album.set(result['collectionName'])
  @iTunes_track.artist.set(result['artistName'])
  @iTunes_track.track_count.set(result['trackCount'])
  @iTunes_track.track_number.set(result['trackNumber'])
  if result['primaryGenreName'] != nil
   @iTunes_track.genre.set(result['primaryGenreName'])
  end
  @iTunes_track.disc_count.set(result['discCount'])
  @iTunes_track.disc_number.set(result['discNumber'])
  @iTunes_track.album_artist.set(result['artistName'])
  if result['releaseDate'] != nil
  releasedate = result['releaseDate']
  releaseyear = releasedate[0..3]
    @iTunes_track.year.set(releaseyear)
  end
  
end

end

WORK_SIZE = 100
STDOUT.sync = true
tracks = []

app = Appscript.app.by_name("iTunes")

iTunes_tracks = app.selection.get
if iTunes_tracks.count == 0
  iTunes_tracks = app.library_playlists[1].tracks.get
end

print "Reading #{iTunes_tracks.count} tracks "
iTunes_tracks.each do | iTunes_track |
  begin
    if iTunes_track.kind.get == 'Matched AAC audio file' or iTunes_track.kind.get == 'Gematcht AAC-audiobestand' or iTunes_track.kind.get == 'Fichier audio AAC acheté' or iTunes_track.kind.get == 'Abgeglichene AAC-Audiodatei'
      track = Track.new(iTunes_track)
      print "Track #{track}"
      unless track.valid?
        tracks << track
        print '*' if ((tracks.count % WORK_SIZE) == 0)
      end
    end
  rescue StandardError => e
    puts e
  end
end
puts ''

# all 2 char countries codes lots currently not valid %w(AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS BH BD BB BY BE BZ BJ BM BT BO BQ BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CD CK CR CI HR CU CW CY CZ DK DJ DM DO EC EG SV GQ ER EE ET FK FO FJ FI FR GF PF TF GA GM GE DE GH GI GR GL GD GP GU GT GG GN GW GY HT HM VA HN HK HU IS IN ID IR IQ IE IM IL IT JM JP JE JO KZ KE KI KP KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS MA MZ MM NA NR NP NL NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA RE RO RU RW BL SH KN LC MF PM VC WS SM ST SA SN RS SC SL SG SX SK SI SB SO ZA GS SS ES LK SD SR SJ SZ SE CH SY TW TJ TZ TH TL TG TK TO TT TN TR TM TC TV UG UA AE GB US UM UY UZ VU VE VN VG VI WF EH YE ZM ZW)

countries = %w(US GB AU FR DE CA IT JP DZ AO AI AG AR AM AT AZ BS BH BD BB BY BE BZ BM BO BW BR BN BG CM KY CL CN CO CR CI HR CY CZ DK DM DO EC EG SV EE ET FI GH GR GD GT GY HN HK HU IS IN ID IE IL JM JO KZ KE KR KW LV LB LY LI LT LU MO MK MG MY MV ML MT MU MX MD MS MM NP NL NZ NI NE NG NO OM PK PA PY PE PH PL PT QA RO RU KN LC VC SA SN RS SG SK SI ZA ES LK SR SE CH TW TZ TH TT TN TR TC UG UA AE UY UZ VE VN VG YE)

puts "Found #{tracks.count} matched tracks"
countries.each do | country |
  print "Querying #{country} store for #{tracks.count} tracks "
  counter = 0
  tracks.dup.each.each_slice(WORK_SIZE) do | subtracks |
    ids = subtracks.map { | track | track.iTunes_id }
    iTunesHash = JSON.parse(open("http://itunes.apple.com/lookup?id=#{ids.join(',')}&country=#{country}").read)
        print '*'
    iTunesHash['results'].each do | result |
      result_id = result['trackId']
      subtracks.each do | track |
        if result_id == track.iTunes_id
          track.update_track(result)
          tracks.delete(track)
          counter += 1
          break
        end
      end
    end
  end
  puts " #{counter} updated"
  break if tracks.empty?
end

puts "Couldn't find meatadata for #{tracks.count} tracks" if tracks.count != 0
 
Last edited:

Schirkan

macrumors newbie
Jan 23, 2012
2
0
iTunes Match Tagger for Windows

Hello!

I've portet your script to C# and made a nice GUI:

iTunesMatchTagger1.jpg


Download at http://code.google.com/p/itunes-match-tagger

Should work with german, english and frensh iTunes.
 
Last edited:

pologringo

macrumors newbie
Jan 28, 2012
2
0
Problem with itune sMatch Tagger

Hi all,

@Schirkan, you had a great idea to adapt the Ruby script to Windows. Unfortunately, I can't make it works. I always have the result: "0 tracks found". I'm in Peru, I have my iTunes Match account in Peru, in French language; I tried tu switch iTunes in few languages and I also tried with another iTunes accounts in USA and France (but both without iTunes Match). And the result is always the same :( Any idea?

Please check my screencopy. It's just an example; the result is the same with any track.

Thank you.
 

Attachments

  • itunes.png
    itunes.png
    80.9 KB · Views: 425

ebengtso

macrumors newbie
Oct 8, 2011
9
1
Hi all,

@Schirkan, you had a great idea to adapt the Ruby script to Windows. Unfortunately, I can't make it works. I always have the result: "0 tracks found". I'm in Peru, I have my iTunes Match account in Peru, in French language; I tried tu switch iTunes in few languages and I also tried with another iTunes accounts in USA and France (but both without iTunes Match). And the result is always the same :( Any idea?

Please check my screencopy. It's just an example; the result is the same with any track.

Thank you.

Here the condition updated in ruby

Code:
    if iTunes_track.kind.get == 'Matched AAC audio file' or iTunes_track.kind.get == 'Fichier audio AAC acheté' or iTunes_track.kind.get =='Fichier audio AAC mis en correspondance' or iTunes_track.kind.get == 'Fichier audio AAC' or iTunes_track.kind.get == 'Abgeglichene AAC-Audiodatei'
 

ebengtso

macrumors newbie
Oct 8, 2011
9
1
Here the condition updated in ruby

Code:
    if iTunes_track.kind.get == 'Matched AAC audio file' or iTunes_track.kind.get == 'Fichier audio AAC acheté' or iTunes_track.kind.get =='Fichier audio AAC mis en correspondance' or iTunes_track.kind.get == 'Fichier audio AAC' or iTunes_track.kind.get == 'Abgeglichene AAC-Audiodatei'

Here a few languages I found in Localisable.strings of iTunes

French

Code:
"5000.006" = "Fichier audio AAC";
"5000.008" = "Fichier audio AAC protégé";
"5000.010" = "Fichier audio AAC acheté";
"5000.011" = "Fichier audio AAC mis en correspondance";

English

Code:
"5000.006" = "AAC audio file";
"5000.008" = "Protected AAC audio file";
"5000.010" = "Purchased AAC audio file";
"5000.011" = "Matched AAC audio file";

German

Code:
"5000.006" = "AAC-Audiodatei";
"5000.008" = "Geschützte AAC-Audiodatei";
"5000.010" = "Gekaufte AAC-Audiodatei";
"5000.011" = "Abgeglichene AAC-Audiodatei";

Spanish

Code:
"5000.006" = "Archivo de audio AAC";
"5000.008" = "Archivo de audio AAC protegido";
"5000.010" = "Archivo de audio AAC comprado";
"5000.011" = "Archivo de audio AAC coincidente";

Portuguese
Code:
"5000.006" = "Arq. áudio AAC";
"5000.008" = "Arq. áudio AAC prot.";
"5000.010" = "Arq. áudio AAC compr.";
"5000.011" = "Arq. áudio AAC disponibilizado";

Portuguese PT
Code:
"5000.006" = "Áudio AAC";
"5000.008" = "Áudio AAC protegido";
"5000.010" = "Áudio AAC comprado";
"5000.011" = "Ficheiro de áudio AAC correspondente";

Swedish
Code:
"5000.006" = "AAC-ljudfil";
"5000.008" = "Skyddad AAC-ljudfil";
"5000.010" = "Köpt AAC-ljudfil";
"5000.011" = "Matchad AAC-ljudfil";

Italian
Code:
"5000.006" = "Doc. audio AAC";
"5000.008" = "Doc. audio AAC protetto";
"5000.010" = "Doc. audio AAC acquistato";
"5000.011" = "Doc. audio AAC corrispondente";

Dutch
Code:
"5000.006" = "AAC-audiobestand";
"5000.008" = "Beveiligd AAC-audiobestand";
"5000.010" = "Aangeschaft AAC-audiobestand";
"5000.011" = "Gematcht AAC-audiobestand";

Japanese
Code:
"5000.006" = "AAC オーディオファイル";
"5000.008" = "保護された AAC オーディオファイル";
"5000.010" = "購入した AAC オーディオファイル";
"5000.011" = "一致した AAC オーディオファイル";

A few other languages are localized in iTunes. I leave for the readers the exercise

Code:
cd /Applications/iTunes.app/Contents/Resources
Code:
ls -d *.lproj
Code:
Dutch.lproj	Japanese.lproj	fi.lproj	pt.lproj	zh_CN.lproj
English.lproj	Spanish.lproj	hu.lproj	pt_PT.lproj	zh_TW.lproj
French.lproj	cs.lproj	ko.lproj	ru.lproj
German.lproj	da.lproj	no.lproj	sv.lproj
Italian.lproj	en_GB.lproj	pl.lproj	tr.lproj
Code:
cd sv.lproj
Code:
iconv -f UTF-16 -t UTF-8 Localizable.strings | grep 'AAC'
 

Schirkan

macrumors newbie
Jan 23, 2012
2
0
New version 1.2 is available: Download

iTunes-Language support for: german, english, frensch, dutch, spanish, portuguese, swedish, italian and japanese
thx to ebengtso

Only tested with german iTunes...
 

pologringo

macrumors newbie
Jan 28, 2012
2
0
New version 1.2 is available: Download

iTunes-Language support for: german, english, frensch, dutch, spanish, portuguese, swedish, italian and japanese
thx to ebengtso

Only tested with german iTunes...

Hi,

For me, it's working perfectly in French. Great job!

BTW, a suggestion: perhaps an option for the main window "Always on top" would be great.
 

ved100

macrumors newbie
Jan 30, 2012
4
0
Works with Brazilian Portuguese iTunes! But it cant find some matched brazilian musics, I dont know why. Works great with international music.
Thanks for the GUI!!
 

Logic19

macrumors newbie
Jan 24, 2012
3
0
I can't get the script to work on my Mac.

Is it possible for someone to make a nice app for a mac?
 

Meti

macrumors newbie
May 6, 2012
1
0
It seems to me that the german term 'Abgeglichene AAC-Audiodatei' (in english 'Matched AAC audio file' ) has been changed to 'Passende AAC-Audiodatei' .

I don't know if the english term was changed too. Could anyone check that?

Also it doesn't seem to be a different term for replaced songs (matched and downloaded from iCloud) and for matched but not replaced songs. In german they are both 'Passende AAC-Audiodatei'. I could not find the term 'Abgeglichene AAC-Audiodatei'.

If you want to try the script on a german iTunes library you can just add
or iTunes_track.kind.get == 'Passende AAC-Audiodatei'
at the end of the following line:

Code:
 if iTunes_track.kind.get == 'Matched AAC audio file' or iTunes_track.kind.get == 'Gematcht AAC-audiobestand' or iTunes_track.kind.get == 'Fichier audio AAC acheté' or iTunes_track.kind.get == 'Abgeglichene AAC-Audiodatei'

like this:

Code:
 if iTunes_track.kind.get == 'Matched AAC audio file' or iTunes_track.kind.get == 'Gematcht AAC-audiobestand' or iTunes_track.kind.get == 'Fichier audio AAC acheté' or iTunes_track.kind.get == 'Abgeglichene AAC-Audiodatei' or iTunes_track.kind.get == 'Passende AAC-Audiodatei'
 

imthenachoman

macrumors member
Aug 18, 2008
65
0
I took @tapbot_paul's version and made a Python version (mostly so I could learn Python) with some more verbose output that only checks valid countries (there are 134 that Apple understands) and it creates playlists of the updated/not-updated tracks.

However, I cannot figure out why there are some Track IDs that Apple doesn't have information for. I've checked every country. Does anyone have information on this?
 

Slash366

macrumors newbie
Sep 10, 2011
25
4
@ imthenachoman

sorry not going to be able to answer your question but maybe you can help me with one. can i ask how were you able to view what track id is attached to the file?

i'm quite interested in seeing what the track id is for certain tracks to identify which album it's come from.

thanks..
 

imthenachoman

macrumors member
Aug 18, 2008
65
0
Any way to do this on windows yet? Would love to have all my tracks fully tagged.

@.:max:.: Have you seen http://code.google.com/p/itunes-match-tagger/?

----------

@ imthenachoman

sorry not going to be able to answer your question but maybe you can help me with one. can i ask how were you able to view what track id is attached to the file?

i'm quite interested in seeing what the track id is for certain tracks to identify which album it's come from.

thanks..

its included in the first 1024 bytes of the file. the below python line would tell you what it is:

Code:
# need this package
from struct import unpack

# open the file in byte mode and read the 1024 bytes
data = open( "/path/to/file", "rb" ).read( 1024 )

# find the index of "song" which is where the track ID starts
index = data.index( "song" )

# if we found an index unpack the next 4 bytes starting from index and get the first item
if( index )
    trackID = unpack( "!I", data[index+4:index+4+4] )[0]


----------

does anyone know how to get the m4a file specifications? im trying to figure out exactly how @tapbot_paul figured out where exactly the iTunes ID was.
 

stege

macrumors newbie
Oct 15, 2009
25
0
hi everyone!
I've downloaded the script and Xcode. But when i try to run it in terminal I got the followings errors:

sudo gem install json

Building native extensions. This could take a while...
ERROR: Error installing json:
ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb
mkmf.rb can't find header files for ruby at /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/ruby.h


Gem files will remain installed in /Library/Ruby/Gems/1.8/gems/json-1.7.3 for inspection.
Results logged to /Library/Ruby/Gems/1.8/gems/json-1.7.3/ext/json/ext/parser/gem_make.out





sudo gem install rb-appscript

Building native extensions. This could take a while...
ERROR: Error installing rb-appscript:
ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb
mkmf.rb can't find header files for ruby at /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/ruby.h


Gem files will remain installed in /Library/Ruby/Gems/1.8/gems/rb-appscript-0.6.1 for inspection.
Results logged to /Library/Ruby/Gems/1.8/gems/rb-appscript-0.6.1/gem_make.out


I'm not really into terminal, could you please help me?
what is the problem here?
thanks!!
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.