Module: ID3
- Defined in:
- lib/id3/id3.rb,
lib/id3/tag1.rb,
lib/id3/tag2.rb,
lib/id3/frame.rb,
lib/id3/version.rb,
lib/id3/constants.rb,
lib/id3/frame_array.rb,
lib/id3/generic_tag.rb,
lib/id3/module_methods.rb
Overview
Module ID3 - MODULE METHODS
Defined Under Namespace
Classes: Frame, FrameArray, GenericTag, Tag1, Tag2
Constant Summary collapse
- VERSION =
'1.0.0'
- Version =
CONSTANTS
VERSION
- ID3v1tagSize =
ID3v1 and ID3v1.1 have fixed size tags
128
- ID3v1versionbyte =
125
- ID3v2headerSize =
10
- ID3v2major =
3
- ID3v2minor =
4
- ID3v2flags =
5
- ID3v2tagSize =
6
- VERSIONS =
SUPPORTED_VERSIONS = ["1.0", "1.1", "2.2.0", "2.3.0", "2.4.0"]
- SUPPORTED_SYMBOLS =
{ "1.0" => { "ARTIST"=>33..62 , "ALBUM"=>63..92 ,"TITLE"=>3..32, "YEAR"=>93..96 , "COMMENT"=>97..126,"GENREID"=>127, # "VERSION"=>"1.0" } , "1.1" => { "ARTIST"=>33..62 , "ALBUM"=>63..92 ,"TITLE"=>3..32, "YEAR"=>93..96 , "COMMENT"=>97..124, "TRACKNUM"=>126, "GENREID"=>127, # "VERSION"=>"1.1" } , "2.2.0" => {"CONTENTGROUP"=>"TT1", "TITLE"=>"TT2", "SUBTITLE"=>"TT3", "ARTIST"=>"TP1", "BAND"=>"TP2", "CONDUCTOR"=>"TP3", "MIXARTIST"=>"TP4", "COMPOSER"=>"TCM", "LYRICIST"=>"TXT", "LANGUAGE"=>"TLA", "CONTENTTYPE"=>"TCO", "ALBUM"=>"TAL", "TRACKNUM"=>"TRK", "PARTINSET"=>"TPA", "ISRC"=>"TRC", "DATE"=>"TDA", "YEAR"=>"TYE", "TIME"=>"TIM", "RECORDINGDATES"=>"TRD", "ORIGYEAR"=>"TOR", "BPM"=>"TBP", "MEDIATYPE"=>"TMT", "FILETYPE"=>"TFT", "COPYRIGHT"=>"TCR", "PUBLISHER"=>"TPB", "ENCODEDBY"=>"TEN", "ENCODERSETTINGS"=>"TSS", "SONGLEN"=>"TLE", "SIZE"=>"TSI", "PLAYLISTDELAY"=>"TDY", "INITIALKEY"=>"TKE", "ORIGALBUM"=>"TOT", "ORIGFILENAME"=>"TOF", "ORIGARTIST"=>"TOA", "ORIGLYRICIST"=>"TOL", "USERTEXT"=>"TXX", "WWWAUDIOFILE"=>"WAF", "WWWARTIST"=>"WAR", "WWWAUDIOSOURCE"=>"WAS", "WWWCOMMERCIALINFO"=>"WCM", "WWWCOPYRIGHT"=>"WCP", "WWWPUBLISHER"=>"WPB", "WWWUSER"=>"WXX", "UNIQUEFILEID"=>"UFI", "INVOLVEDPEOPLE"=>"IPL", "UNSYNCEDLYRICS"=>"ULT", "COMMENT"=>"COM", "CDID"=>"MCI", "EVENTTIMING"=>"ETC", "MPEGLOOKUP"=>"MLL", "SYNCEDTEMPO"=>"STC", "SYNCEDLYRICS"=>"SLT", "VOLUMEADJ"=>"RVA", "EQUALIZATION"=>"EQU", "REVERB"=>"REV", "PICTURE"=>"PIC", "GENERALOBJECT"=>"GEO", "PLAYCOUNTER"=>"CNT", "POPULARIMETER"=>"POP", "BUFFERSIZE"=>"BUF", "CRYPTEDMETA"=>"CRM", "AUDIOCRYPTO"=>"CRA", "LINKED"=>"LNK" } , "2.3.0" => {"CONTENTGROUP"=>"TIT1", "TITLE"=>"TIT2", "SUBTITLE"=>"TIT3", "ARTIST"=>"TPE1", "BAND"=>"TPE2", "CONDUCTOR"=>"TPE3", "MIXARTIST"=>"TPE4", "COMPOSER"=>"TCOM", "LYRICIST"=>"TEXT", "LANGUAGE"=>"TLAN", "CONTENTTYPE"=>"TCON", "ALBUM"=>"TALB", "TRACKNUM"=>"TRCK", "PARTINSET"=>"TPOS", "ISRC"=>"TSRC", "DATE"=>"TDAT", "YEAR"=>"TYER", "TIME"=>"TIME", "RECORDINGDATES"=>"TRDA", "ORIGYEAR"=>"TORY", "SIZE"=>"TSIZ", "BPM"=>"TBPM", "MEDIATYPE"=>"TMED", "FILETYPE"=>"TFLT", "COPYRIGHT"=>"TCOP", "PUBLISHER"=>"TPUB", "ENCODEDBY"=>"TENC", "ENCODERSETTINGS"=>"TSSE", "SONGLEN"=>"TLEN", "PLAYLISTDELAY"=>"TDLY", "INITIALKEY"=>"TKEY", "ORIGALBUM"=>"TOAL", "ORIGFILENAME"=>"TOFN", "ORIGARTIST"=>"TOPE", "ORIGLYRICIST"=>"TOLY", "FILEOWNER"=>"TOWN", "NETRADIOSTATION"=>"TRSN", "NETRADIOOWNER"=>"TRSO", "USERTEXT"=>"TXXX", "WWWAUDIOFILE"=>"WOAF", "WWWARTIST"=>"WOAR", "WWWAUDIOSOURCE"=>"WOAS", "WWWCOMMERCIALINFO"=>"WCOM", "WWWCOPYRIGHT"=>"WCOP", "WWWPUBLISHER"=>"WPUB", "WWWRADIOPAGE"=>"WORS", "WWWPAYMENT"=>"WPAY", "WWWUSER"=>"WXXX", "UNIQUEFILEID"=>"UFID", "INVOLVEDPEOPLE"=>"IPLS", "UNSYNCEDLYRICS"=>"USLT", "COMMENT"=>"COMM", "TERMSOFUSE"=>"USER", "CDID"=>"MCDI", "EVENTTIMING"=>"ETCO", "MPEGLOOKUP"=>"MLLT", "SYNCEDTEMPO"=>"SYTC", "SYNCEDLYRICS"=>"SYLT", "VOLUMEADJ"=>"RVAD", "EQUALIZATION"=>"EQUA", "REVERB"=>"RVRB", "PICTURE"=>"APIC", "GENERALOBJECT"=>"GEOB", "PLAYCOUNTER"=>"PCNT", "POPULARIMETER"=>"POPM", "BUFFERSIZE"=>"RBUF", "AUDIOCRYPTO"=>"AENC", "LINKEDINFO"=>"LINK", "POSITIONSYNC"=>"POSS", "COMMERCIAL"=>"COMR", "CRYPTOREG"=>"ENCR", "GROUPINGREG"=>"GRID", "PRIVATE"=>"PRIV" } , "2.4.0" => {"CONTENTGROUP"=>"TIT1", "TITLE"=>"TIT2", "SUBTITLE"=>"TIT3", "ARTIST"=>"TPE1", "BAND"=>"TPE2", "CONDUCTOR"=>"TPE3", "MIXARTIST"=>"TPE4", "COMPOSER"=>"TCOM", "LYRICIST"=>"TEXT", "LANGUAGE"=>"TLAN", "CONTENTTYPE"=>"TCON", "ALBUM"=>"TALB", "TRACKNUM"=>"TRCK", "PARTINSET"=>"TPOS", "ISRC"=>"TSRC", "RECORDINGTIME"=>"TDRC", "ORIGRELEASETIME"=>"TDOR", "BPM"=>"TBPM", "MEDIATYPE"=>"TMED", "FILETYPE"=>"TFLT", "COPYRIGHT"=>"TCOP", "PUBLISHER"=>"TPUB", "ENCODEDBY"=>"TENC", "ENCODERSETTINGS"=>"TSSE", "SONGLEN"=>"TLEN", "PLAYLISTDELAY"=>"TDLY", "INITIALKEY"=>"TKEY", "ORIGALBUM"=>"TOAL", "ORIGFILENAME"=>"TOFN", "ORIGARTIST"=>"TOPE", "ORIGLYRICIST"=>"TOLY", "FILEOWNER"=>"TOWN", "NETRADIOSTATION"=>"TRSN", "NETRADIOOWNER"=>"TRSO", "USERTEXT"=>"TXXX", "SETSUBTITLE"=>"TSST", "MOOD"=>"TMOO", "PRODUCEDNOTICE"=>"TPRO", "ENCODINGTIME"=>"TDEN", "RELEASETIME"=>"TDRL", "TAGGINGTIME"=>"TDTG", "ALBUMSORTORDER"=>"TSOA", "PERFORMERSORTORDER"=>"TSOP", "TITLESORTORDER"=>"TSOT", "WWWAUDIOFILE"=>"WOAF", "WWWARTIST"=>"WOAR", "WWWAUDIOSOURCE"=>"WOAS", "WWWCOMMERCIALINFO"=>"WCOM", "WWWCOPYRIGHT"=>"WCOP", "WWWPUBLISHER"=>"WPUB", "WWWRADIOPAGE"=>"WORS", "WWWPAYMENT"=>"WPAY", "WWWUSER"=>"WXXX", "UNIQUEFILEID"=>"UFID", "MUSICIANCREDITLIST"=>"TMCL", "INVOLVEDPEOPLE2"=>"TIPL", "UNSYNCEDLYRICS"=>"USLT", "COMMENT"=>"COMM", "TERMSOFUSE"=>"USER", "CDID"=>"MCDI", "EVENTTIMING"=>"ETCO", "MPEGLOOKUP"=>"MLLT", "SYNCEDTEMPO"=>"SYTC", "SYNCEDLYRICS"=>"SYLT", "VOLUMEADJ2"=>"RVA2", "EQUALIZATION2"=>"EQU2", "REVERB"=>"RVRB", "PICTURE"=>"APIC", "GENERALOBJECT"=>"GEOB", "PLAYCOUNTER"=>"PCNT", "POPULARIMETER"=>"POPM", "BUFFERSIZE"=>"RBUF", "AUDIOCRYPTO"=>"AENC", "LINKEDINFO"=>"LINK", "POSITIONSYNC"=>"POSS", "COMMERCIAL"=>"COMR", "CRYPTOREG"=>"ENCR", "GROUPINGREG"=>"GRID", "PRIVATE"=>"PRIV", "OWNERSHIP"=>"OWNE", "SIGNATURE"=>"SIGN", "SEEKFRAME"=>"SEEK", "AUDIOSEEKPOINT"=>"ASPI" } }
- TAG_HEADER_FLAG_MASK =
Flags in the ID3-Tag Header:
{ # the mask is inverse, for error detection # those flags are supposed to be zero! "2.2.0" => 0x3F, # 0xC0 , "2.3.0" => 0x1F, # 0xE0 , "2.4.0" => 0x0F # 0xF0 }
- TAG_HEADER_FLAGS =
{ "2.2.0" => { "Unsynchronisation" => 0x80 , "Compression" => 0x40 , } , "2.3.0" => { "Unsynchronisation" => 0x80 , "ExtendedHeader" => 0x40 , "Experimental" => 0x20 , } , "2.4.0" => { "Unsynchronisation" => 0x80 , "ExtendedHeader" => 0x40 , "Experimental" => 0x20 , "Footer" => 0x10 , } }
- FRAME_HEADER_FLAG_MASK =
Flags in the ID3-Frame Header:
{ # the mask is inverse, for error detection # those flags are supposed to be zero! "2.3.0" => 0x1F1F, # 0xD0D0 , "2.4.0" => 0x8FB0 # 0x704F , }
- FRAME_HEADER_FLAGS =
{ "2.3.0" => { "TagAlterPreservation" => 0x8000 , "FileAlterPreservation" => 0x4000 , "ReadOnly" => 0x2000 , "Compression" => 0x0080 , "Encryption" => 0x0040 , "GroupIdentity" => 0x0020 , } , "2.4.0" => { "TagAlterPreservation" => 0x4000 , "FileAlterPreservation" => 0x2000 , "ReadOnly" => 0x1000 , "GroupIdentity" => 0x0040 , "Compression" => 0x0008 , "Encryption" => 0x0004 , "Unsynchronisation" => 0x0002 , "DataLengthIndicator" => 0x0001 , } }
- FRAMETYPE2FRAMENAME =
the FrameTypes are not visible to the user - they are just a mechanism to define only one parser for multiple FraneNames..
{ "TEXT" => %w(TENTGROUP TITLE SUBTITLE ARTIST BAND CONDUCTOR MIXARTIST COMPOSER LYRICIST LANGUAGE CONTENTTYPE ALBUM TRACKNUM PARTINSET ISRC DATE YEAR TIME RECORDINGDATES ORIGYEAR BPM MEDIATYPE FILETYPE COPYRIGHT PUBLISHER ENCODEDBY ENCODERSETTINGS SONGLEN SIZE PLAYLISTDELAY INITIALKEY ORIGALBUM ORIGFILENAME ORIGARTIST ORIGLYRICIST FILEOWNER NETRADIOSTATION NETRADIOOWNER SETSUBTITLE MOOD PRODUCEDNOTICE ALBUMSORTORDER PERFORMERSORTORDER TITLESORTORDER INVOLVEDPEOPLE), "USERTEXT" => "USERTEXT", "WEB" => %w(WWWAUDIOFILE WWWARTIST WWWAUDIOSOURCE WWWCOMMERCIALINFO WWWCOPYRIGHT WWWPUBLISHER WWWRADIOPAGE WWWPAYMENT) , "WWWUSER" => "WWWUSER", "LTEXT" => "TERMSOFUSE" , "PICTURE" => "PICTURE" , "UNSYNCEDLYRICS" => "UNSYNCEDLYRICS" , "COMMENT" => "COMMENT" , "PLAYCOUNTER" => "PLAYCOUNTER" , "POPULARIMETER" => "POPULARIMETER", "BINARY" => %w( CDID ) , # Cee Dee I Dee # For the following Frames there are no parser stings defined .. the user has access to the raw data # The following frames are good examples for completely useless junk which was put into the ID3-definitions.. what were they smoking? # "UNPARSED" => %w(UNIQUEFILEID OWNERSHIP SYNCEDTEMPO MPEGLOOKUP REVERB SYNCEDLYRICS CONTENTGROUP GENERALOBJECT VOLUMEADJ AUDIOCRYPTO CRYPTEDMETA BUFFERSIZE EVENTTIMING EQUALIZATION LINKED PRIVATE LINKEDINFO POSITIONSYNC GROUPINGREG CRYPTOREG COMMERCIAL SEEKFRAME AUDIOSEEKPOINT SIGNATURE EQUALIZATION2 VOLUMEADJ2 MUSICIANCREDITLIST INVOLVEDPEOPLE2 RECORDINGTIME ORIGRELEASETIME ENCODINGTIME RELEASETIME TAGGINGTIME) }
- VARS =
0
- PACKING =
1
- TEXT_ENCODINGS =
String Encodings: See id3v2.4.0-structure document, at section 4.
see also: http://en.wikipedia.org/wiki/ID3#ID3v2_Chapters Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: $00 ISO-8859-1 [ISO-8859-1]. Terminated with $00. (ASCII) $01 [UCS-2] in ID3v2.2,ID3v2.3 / UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM All in ID3v2.4 strings in the same frame SHALL have the same byteorder. Terminated with $00 00. $02 UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM. (ID3v2.4 only) Terminated with $00 00. $03 UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00. (ID3v2.4 only)
["ISO-8859-1", "UTF-16", "UTF-16BE", "UTF-8"]
- FRAME_PARSER =
NOTE: please note that all the first array entries need to be hashes, in order for Ruby 1.9 to handle this correctly!
{ "TEXT" => [ %w(encoding text) , 'CZ*' ] , "USERTEXT" => [ %w(encoding description value) , 'CZ*Z*' ] , "PICTURE" => [ %w(encoding mime_type pict_type description picture) , 'CZ*CZ*a*' ] , "WEB" => [ %w(url) , 'Z*' ] , "WWWUSER" => [ %w(encoding description url) , 'CZ*Z*' ] , "LTEXT" => [ %w(encoding language text) , 'CZ*Z*' ] , "UNSYNCEDLYRICS" => [ %w(encoding language content text) , 'Ca3Z*Z*' ] , "COMMENT" => [ %w(encoding language short long) , 'Ca3Z*Z*' ] , "PLAYCOUNTER" => [%w(counter), 'C*'] , "POPULARIMETER" => [%w(email rating counter), 'Z*CC*'] , "BINARY" => [ %w(binary) , 'a*' ] , "UNPARSED" => [ %w(raw) , 'a*' ] # how would we do value checking for this? }
- Symbol2framename =
ID3::SUPPORTED_SYMBOLS
- Framename2symbol =
Hash.new
- FrameType2FrameName =
ID3::FRAMETYPE2FRAMENAME
- FrameName2FrameType =
FrameType2FrameName.invert
Class Method Summary collapse
-
.hasID3tag?(filename) ⇒ Boolean
—————————————————————————- hasID3tag? returns string with all versions found, space separated returns false otherwise.
-
.hasID3v1tag?(filename) ⇒ Boolean
—————————————————————————- hasID3v1tag? returns string with version 1.0 or 1.1 if tag was found returns false otherwise.
-
.hasID3v2tag?(filename) ⇒ Boolean
—————————————————————————- hasID3v2tag? returns string with version 2.2.0, 2.3.0 or 2.4.0 if tag found returns false otherwise.
-
.id3_versions ⇒ Object
—————————————————————————- id3_versions.
-
.mungeSize(size) ⇒ Object
———————————————————————- convert the size into 4 bytes to be written into an id3v2 header.
-
.removeID3v1tag(filename) ⇒ Object
—————————————————————————- removeID3v1tag returns nil if no v1 tag was found, or it couldn’t be removed returns true if v1 tag found and it was removed..
-
.unmungeSize(bytes) ⇒ Object
———————————————————————- convert the 4 bytes found in the id3v2 header and return the size.
Class Method Details
.hasID3tag?(filename) ⇒ Boolean
hasID3tag?
returns string with all versions found, space separated
returns false otherwise
66 67 68 69 70 71 72 73 74 |
# File 'lib/id3/module_methods.rb', line 66 def ID3.hasID3tag?(filename) v1 = ID3.hasID3v1tag?(filename) v2 = ID3.hasID3v2tag?(filename) return false if !v1 && !v2 return v1 if !v2 return v2 if !v1 return "#{v1} #{v2}" end |
.hasID3v1tag?(filename) ⇒ Boolean
hasID3v1tag?
returns string with version 1.0 or 1.1 if tag was found
returns false otherwise
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/id3/module_methods.rb', line 21 def ID3.hasID3v1tag?(filename) hasID3v1tag = false # be careful with empty or corrupt files.. return false if File.size(filename) < ID3v1tagSize f = File.open(filename, 'rb:binary') f.seek(-ID3v1tagSize, IO::SEEK_END) if (f.read(3) == "TAG") f.seek(-ID3v1tagSize + ID3v1versionbyte, IO::SEEK_END) c = f.get_byte # this is character 125 of the tag if (c == 0) hasID3v1tag = "1.0" else hasID3v1tag = "1.1" end end f.close return hasID3v1tag end |
.hasID3v2tag?(filename) ⇒ Boolean
hasID3v2tag?
returns string with version 2.2.0, 2.3.0 or 2.4.0 if tag found
returns false otherwise
47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/id3/module_methods.rb', line 47 def ID3.hasID3v2tag?(filename) hasID3v2tag = false f = File.open(filename, 'rb:binary') if (f.read(3) == "ID3") major = f.get_byte minor = f.get_byte version = "2." + major.to_s + '.' + minor.to_s hasID3v2tag = version end f.close return hasID3v2tag end |
.id3_versions ⇒ Object
id3_versions
12 13 14 |
# File 'lib/id3/module_methods.rb', line 12 def ID3.id3_versions [ hasID3v1tag?(filename) ,hasID3v2tag?(filename) ].compact # returns Array of ID3 tag versions found end |
.mungeSize(size) ⇒ Object
convert the size into 4 bytes to be written into an id3v2 header
114 115 116 117 118 119 120 121 122 123 |
# File 'lib/id3/module_methods.rb', line 114 def ID3.mungeSize(size) bytes = Array.new(4,0) j = 0; i = 3 while i >= 0 bytes[j],size = size.divmod(128**i) j += 1 i -= 1 end return bytes end |
.removeID3v1tag(filename) ⇒ Object
removeID3v1tag
returns nil if no v1 tag was found, or it couldn't be removed
returns true if v1 tag found and it was removed..
in the future:
returns ID3.Tag1 object if a v1 tag was found and removed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/id3/module_methods.rb', line 84 def ID3.removeID3v1tag(filename) stat = File.stat(filename) if stat.file? && stat.writable? && ID3.hasID3v1tag?(filename) # CAREFUL: this does not check if there really is a valid tag, # that's why we need to check above!! newsize = stat.size - ID3v1tagSize File.open(filename, "r+") { |f| f.truncate(newsize) } return true else return nil end end |
.unmungeSize(bytes) ⇒ Object
convert the 4 bytes found in the id3v2 header and return the size
102 103 104 105 106 107 108 109 110 111 |
# File 'lib/id3/module_methods.rb', line 102 def ID3.unmungeSize(bytes) size = 0 j = 0; i = 3 while i >= 0 size += 128**i * (bytes.getbyte(j) & 0x7f) j += 1 i -= 1 end return size end |