iEPGクラス再び、RubyでPVRを作ろう!その15の2
ということで、ソースコード ## iEPGD Class# (c) 2008-09 B.O# re-written# to support V1 and V2 of iEPG# for V1 reference , http://350ml.net/labo/iepg.html# thanks to "AKINO Yoh, 350ml.net"#require 'set'class IEPG < Hash # keywords @@Header = "Content-type:" @@V1SingleContent = "x-tv-program-info" @@V2SingleContent = "x-tv-program-digital-info" @@V1MultiContent = "x-multi-tv-program-info" @@V2MultiContent = "x-multi-tv-program-digital-info" @@V1Mandatory = [ "version:", "station:", "start:", "end:" ] @@V1Axuary = [ "year:", "month:" , "date:", "program-title:", "program-subtitle:", "performer:", "genre:" , "subgenre:" ] @@V2Mandatory = [ "version:", "station:", "station-name:", "program-title:", "program-id:", "start:", "end:" ] @@V2Axuary = [ "year:", "month:" , "date:", "genre-1:", "subgenre-1:", "program-subtitle:", "performer:", "genre:" , "subgenre:" ] @@Memo = "_memo:" # adding memo section, needs to be @@OneDay = 24*60*60 @@KeywordTimeRelated = Set[ "year:", "month:", "date:", "start:", "end:"] attr_reader :timeStart, :timeEnd # member method def initialize #self.default = "" @timeStart = Time.now @timeEnd = Time.now end #def initialize def to_s( format = nil ) if format != nil #summary mode str = String.new( format ) for key, value in self str.gsub!( /%#{key}/, value ) end str.gsub!( /%D/ ,@timeStart.strftime("%Y%m%d")) str.gsub!( /%eD/, @timeEnd.strftime("%Y%m%d")) str.gsub!( /%T/, @timeStart.strftime("%H%M")) str.gsub!( /%eT/, @timeEnd.strftime("%H%M")) str.gsub!( /%%/, "%") return str end #to reproduce .tvipd file single content mode keywords = [ @@Header ] + ( ( self[ "version:" ] == "1" ) ? ( @@V1Mandatory + @@V1Axuary ) : ( @@V2Mandatory + @@V2Axuary ) ) keywordsInSelf = self.keys s = "" keywords.each {|key| s += key + (self[ key ] || "") +"\n" keywordsInSelf.delete( key ) } # if there are anything else in hash, put them for safty sake, except _memo: keywordsInSelf.each {|key| if( key != @@Memo ) s += key + self[ key ] +"\n" keywordsInSelf.delete( key ) end } # handle memo section s += "\n" + (self[ @@Memo ] || "") +"\n" end # to_s def <=>( other ) self.timeStart <=> other.timeStart end #def <=>( other ) def sameProgram?( other ) if (var = self[ "version:"]) != other[ "version:"] raise __FILE__ + __LINE__.to_s + "Error mixed versions" end if ver == "2" format = "%station:%program-id:" else format = "%station:%program-title:%D%T" end return self.to_s( format ) == other.to_s( format ) end #def sameProgram?( other ) def []=(key, value) tmp = super if( @@KeywordTimeRelated.include?( key ) ) timeNow = Time.now year = self[ "year:" ] || timeNow.year month = self[ "month:" ] || timeNow.month day = self[ "date:" ] || timeNow.day start_time = self[ "start:" ] || "0:0" end_time = self[ "end:" ] || "0:0" _start = start_time.split(":") _end = end_time.split(":") @timeStart = Time.local( year, month, day, _start[0], _start[1] ) @timeEnd = Time.local( year, month, day, _end[0], _end[1] ) if @timeEnd <= @timeStart @timeEnd += @@OneDay end end tmp end # # class methods # def IEPG.File2Array( filespec ) f = open( filespec ) s = f.read f.close lines = s.split(/$/) lines.each {|line| line.strip! } IEPG.Lines2Array( lines ) end #def IEPG.File2Array( filespec ) def IEPG.Lines2Array( lines ) if lines[0] =~ /^Content-type: *application\/#{@@V1SingleContent}|#{@@V2SingleContent}/ # single content if ( (tmp = IEPG::fromLines( lines )) != nil ) return [ tmp ] end elsif lines[0] =~ /^Content-type: *application\/#{@@V1MultiContent}|#{@@V2MultiContent}/ # multi contents ar = Array.new i, boundary = catch :found_boundary do for i in 1..( lines.length() -1 ) # find boundary string throw(:found_boundary,[i, $1.strip]) if lines[i] =~ /^boundary:(.*)$/ end raise __FILE__ + __LINE__.to_s + "Error boundary cannot be found" end # catch for i in (i+1)..( lines.length() -1 ) break if lines[i] =~ /^#{boundary}/ end s=i for i in (i+1)..( lines.length() -1 ) if lines[i] =~ /^#{boundary}/ if (tmp = IEPG::fromLines( lines[(s+1)..(i-1)] )) ar << tmp end s=i return ar if lines[i] =~ /^#{boundary}--/ # really end end end #for raise __FILE__ + __LINE__.to_s + "Error, maybe no BOUNDARY's end" end #elsif lines[0] =~ /^Content-type: *appl... raise __FILE__ + __LINE__.to_s + "Error, unexpected file format" end # def IEPG.Lines2Array( inlines ) # read one iEPGd from lines # return a iEPGd def IEPG.fromLines( lines) if !( lines[0] =~ /^#{@@Header} *(.*)$/ ) # checking 1st line raise __FILE__ + __LINE__.to_s + "Error unexpected format :" + lines[0] end contentType = $1.strip if !(contentType =~ /application\/#{@@V1SingleContent}|#{@@V2SingleContent}/ ) raise __FILE__ + __LINE__.to_s + "Error unexpected content type:" + lines[0] end #check charset contentType =~ /charset=(.*)/ if (charset = $1.strip) != "shift_jis" raise __FILE__ + __LINE__.to_s + "Error unexpected charset type:" + charset end tmp = IEPG.new for i in 0..( lines.length() -1 ) break if !(lines[i] =~ /(.*?:)(.*)/ ) tmp[ "#{$1.strip}" ] = $2.strip end #for # check memo section if lines[i].strip == "" if (i = i +1 ) <= lines.length() -1 tmp[ @@Memo ] = lines[i..-1].join("\n") end end # set year, month and date, if missing now=Time.now for key, value in { "year:" => "%Y", "month:" => "%m", "date:" => "%d" } tmp[key] = tmp[key] || now.strftime( value ) end tmp end #def fromLines( lines)end #class IEPG < Hash#--------------------------------------------------------------