Created
July 11, 2011 05:06
-
-
Save jakago/1075337 to your computer and use it in GitHub Desktop.
Write id3 tag into mp3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby -Ku | |
require 'nkf' | |
require 'tempfile' | |
require 'fileutils' | |
def encode_size( int32 ) | |
result = String.new() | |
result << ((int32 & (0x0000007f << 21)) >> 21).chr | |
result << ((int32 & (0x0000007f << 14)) >> 14).chr | |
result << ((int32 & (0x0000007f << 7)) >> 7).chr | |
result << (int32 & 0x0000007f).chr | |
return result | |
end | |
# identifier and string must be UTF-8 | |
def ascii_frame( identifier, string ) | |
ascii_mark = "\x00" | |
result = String.new() | |
if identifier.size == 3 && string.size > 0 | |
frame_data = NKF.nkf( "-l -W", string ) | |
if frame_data.size > 0 | |
frame_data = ascii_mark + frame_data + "\x00" | |
result << identifier | |
result << ((frame_data.size & 0x00ff0000) >> 16).chr | |
result << ((frame_data.size & 0x0000ff00) >> 8).chr | |
result << (frame_data.size & 0x000000ff).chr | |
result << frame_data | |
end | |
end | |
return result | |
end | |
# identifier and string must be UTF-8 | |
def unicode_frame( identifier, string ) | |
unicode_mark = "\x01" | |
result = String.new() | |
if identifier.size == 3 && string.size > 0 | |
frame_data = NKF.nkf( "-w16L -W", string ) | |
if frame_data.size > 0 | |
frame_data = unicode_mark + frame_data + "\x00\x00" | |
result << identifier | |
result << ((frame_data.size & 0x00ff0000) >> 16).chr | |
result << ((frame_data.size & 0x0000ff00) >> 8).chr | |
result << (frame_data.size & 0x000000ff).chr | |
result << frame_data | |
end | |
end | |
return result | |
end | |
def create_tag( album, title, year, artist, genre ) | |
tag_bytes = String.new() | |
frames = String.new() | |
frames << unicode_frame( "TAL", album ); | |
frames << unicode_frame( "TT2", title ); | |
frames << ascii_frame( "TYE", year ); | |
frames << unicode_frame( "TP1", artist ); | |
frames << ascii_frame( "TCO", "(#{genre})" ); | |
if frames.size > 0 | |
tag_bytes << "ID3\x02\x00\x00" | |
tag_bytes << encode_size( frames.size ) | |
tag_bytes << frames | |
end | |
return tag_bytes | |
end | |
def decode_size( byte4 ) | |
return ((byte4[0] & 0x7f) << 21) + ((byte4[1] & 0x7f) << 14) + | |
((byte4[2] & 0x7f) << 7) + (byte4[3] & 0x7f) | |
end | |
# calculate tag size of ID3v2.2.0~ID3v2.4.0 | |
def tag_size( buffer ) | |
#offset_identifier = 0 | |
offset_version = 3 | |
#offset_flags = 5 | |
offset_size = 6 | |
offset_data = 10 | |
identifier = "ID3" | |
result = 0 | |
if buffer.size > offset_data && buffer[0,3] == identifier | |
# ID3v2.2.0, ID3v2.3.0 and ID3v2.4.0 only | |
if buffer[offset_version] >= "2"[0] && buffer[offset_version] <= "4"[0] && buffer[offset_version + 1] == "0"[0] | |
result = decode_size( buffer[offset_size,4] ) + offset_data | |
end | |
end | |
return result; | |
end | |
def make_temp_name( original ) | |
temp_file = Tempfile.open( File.basename( original ) ) | |
result = temp_file.path | |
temp_file.close! | |
return result | |
end | |
def id3tag( full_path, album, title, year, artist, genre ) | |
src_file = nil | |
dst_file = nil | |
original_file_moved = false | |
begin | |
tag_bytes = create_tag( album, title, year, artist, genre ) | |
raise "Failed to create ID3 tag." if tag_bytes.size <= 0 | |
temp_name = make_temp_name( full_path ) | |
FileUtils.move( full_path, temp_name ) | |
original_file_moved = true | |
src_file = File.open( temp_name, "r" ) | |
src_file.binmode | |
dst_file = File.open( full_path, "w" ) | |
dst_file.binmode | |
raise "Failed to write working copy." if dst_file.write( tag_bytes ) != tag_bytes.size | |
buffer = src_file.read | |
skip = tag_size( buffer ) | |
raise "Failed to write working copy." if dst_file.write( buffer[skip..-1] ) != buffer.size - skip | |
dst_file.close | |
dst_file = nil | |
src_file.close | |
File.unlink( temp_name ) | |
src_file = nil | |
rescue | |
puts( $! ) | |
( src_file.close if src_file ) rescue false | |
( dst_file.close if dst_file ) rescue false | |
( File.unlink( full_path ) if dst_file ) rescue false | |
( FileUtils.move( temp_name, full_path ) if original_file_moved ) rescue false | |
end | |
end | |
#id3tag( "foo.mp3", "album", "title", "2011", "artist", "101" ) # 101 == Speech |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment