• R/O
  • HTTP
  • SSH
  • HTTPS

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

mp3ファイルにid3 tagを書き込みます。Rubyスクリプトです。


File Info

Rev. 8dded40246a881bf98390538d1b2920f32f3c4ab
大小 3,815 字节
时间 2011-07-11 14:40:52
作者 jakago
Log Message

initial commit

Content

#!/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