PageRenderTime 54ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/archive-utils.rb

https://github.com/sonota/zip-player
Ruby | 525 lines | 348 code | 115 blank | 62 comment | 50 complexity | dab09079c8b856af7a3de8653b85d1d4 MD5 | raw file
  1. #!/usr/bin/ruby
  2. # -*- coding: utf-8 -*-
  3. $LOAD_PATH << File.dirname(__FILE__)
  4. require "kconv"
  5. require "pp"
  6. require "rubygems"
  7. require "channel"
  8. require "zipruby"
  9. require "vorbis_comment"
  10. require "id3lib"
  11. require "flacinfo"
  12. # $DIR_CACHE_SUB = "cache_sub"
  13. # $DIR_TEMP = "temp_xxx"
  14. def kconv_u16tou8(str)
  15. Kconv.kconv( str, Kconv::UTF8, Kconv::UTF16 )
  16. end
  17. def get_id3_frame(path, id)
  18. #tag = ID3Lib::Tag.new(path)
  19. tag = ID3Lib::Tag.new(path, ID3Lib::V2)
  20. tag.each do |frame|
  21. if frame[:id] == id
  22. if frame[:textenc] && frame[:text]
  23. if frame[:textenc] == 1
  24. frame[:text_u8] = kconv_u16tou8( frame[:text] )
  25. else
  26. frame[:text_u8] = frame[:text]
  27. end
  28. end
  29. return frame
  30. end
  31. end
  32. # if failed with ID3Lib::V2 then
  33. tag = ID3Lib::Tag.new(path, ID3Lib::V1)
  34. tag.each do |frame|
  35. if frame[:id] == id
  36. if frame[:textenc] && frame[:text]
  37. if frame[:textenc] == 1
  38. frame[:text_u8] = kconv_u16tou8( frame[:text] )
  39. else
  40. frame[:text_u8] = frame[:text]
  41. end
  42. end
  43. return frame
  44. end
  45. end
  46. nil
  47. end
  48. def read_file(arc_path, target)
  49. # $stderr.puts "xxarc_path = #{arc_path}"
  50. content = nil
  51. case File.extname(arc_path)
  52. when /^\.zip$/i
  53. Zip::Archive.open(arc_path) do |ar|
  54. n = ar.num_files # number of entries
  55. n.times do |i|
  56. entry_name = ar.get_name(i) # get entry name from archive
  57. next if entry_name != target
  58. # puts entry_name ## 内部パス
  59. # open entry
  60. ar.fopen(entry_name) do |f| # or ar.fopen(i) do |f|
  61. name = f.name # name of the file
  62. size = f.size # size of file (uncompressed)
  63. comp_size = f.comp_size # size of file (compressed)
  64. content = f.read # read entry content
  65. end
  66. end
  67. end
  68. end
  69. return content
  70. end
  71. def file_list_zip(arc_path)
  72. # STDERR.puts arc_path
  73. result = []
  74. Zip::Archive.open(arc_path) do |ar|
  75. n = ar.num_files # number of entries
  76. n.times do |i|
  77. result << ar.get_name(i) # get entry name from archive
  78. end
  79. end
  80. return result
  81. end
  82. def entry_exist?(arc_path, entry)
  83. file_list_zip(arc_path).include? entry
  84. end
  85. def get_tracks_zip(target)
  86. Zip::Archive.open($filename) do |ar|
  87. n = ar.num_files # number of entries
  88. n.times do |i|
  89. entry_name = ar.get_name(i) # get entry name from archive
  90. next if entry_name != target
  91. # puts entry_name ## 内部パス
  92. # open entry
  93. ar.fopen(entry_name) do |f| # or ar.fopen(i) do |f|
  94. name = f.name # name of the file
  95. size = f.size # size of file (uncompressed)
  96. comp_size = f.comp_size # size of file (compressed)
  97. content = f.read # read entry content
  98. end
  99. end
  100. # Zip::Archive includes Enumerable
  101. entry_names = ar.map do |f|
  102. f.name
  103. end
  104. end
  105. end
  106. def arc_root_dir(arc_path)
  107. list = file_list_zip(arc_path).map{ |path|
  108. path.sub(/^(.+?)\/.*$/, '\1')
  109. }
  110. if list.all?{|x| list.first == x }
  111. return list.first
  112. else
  113. return nil
  114. end
  115. end
  116. ## copy from archive to file or dir
  117. ## todo: rename cp_from_arc
  118. def arc_cp(arc_path, entry, dest_path)
  119. $stderr.puts "arc_path: #{arc_path} / dest_path: #{dest_path}" if $DEBUG
  120. temp_path = nil
  121. raise "could not find #{arc_path}" if not File.exist?(arc_path)
  122. Zip::Archive.open( arc_path ) do |ar|
  123. ar.each do |zf|
  124. # warn "^^ #{zf.name} ^^^^^^^^^^^^^^^^^^^^^^^"
  125. next if zf.name != entry
  126. # puts zf.name
  127. if zf.directory?
  128. FileUtils.mkdir_p(zf.name)
  129. else
  130. #dirname = File.dirname(zf.name)
  131. if File.directory? dest_path
  132. FileUtils.mkdir_p( dest_path ) unless File.exist?( dest_dir )
  133. temp_path = File.join( dest_path, File.basename(zf.name) )
  134. else
  135. temp_path = dest_path
  136. end
  137. #warn "temp_path = #{temp_path}"
  138. open( temp_path, 'wb') do |f|
  139. f << zf.read
  140. end
  141. end
  142. end
  143. end
  144. return temp_path
  145. end
  146. def arc_rm(arc_path, entry)
  147. Zip::Archive.open(arc_path) do |ar|
  148. n = ar.num_files # number of entries
  149. n.times do |i|
  150. entry_name = ar.get_name(i) # get entry name from archive
  151. ar.fopen(entry_name) do |f| # or ar.fopen(i) do |f|
  152. if f.name == entry
  153. f.delete()
  154. end
  155. end
  156. end
  157. end
  158. end
  159. def arc_mv(arc_path, entry, newentry)
  160. $stderr.puts "arc_mv"
  161. arc_cp(arc_path, entry, newentry)
  162. arc_rm(arc_path, entry)
  163. end
  164. ## copy/overwrite file to archive
  165. ## not move
  166. def arc_add_overwrite(arc_path, path, entry)
  167. # puts "arc_path = #{arc_path}"
  168. # puts "path = #{path}"
  169. # puts "entry = #{entry}"
  170. temp_path = "____gqwhrkahfjk1ahfh2jek7af"
  171. arc_rm(arc_path, entry)
  172. FileUtils.cp( path, temp_path )
  173. Zip::Archive.open(arc_path) {|ar|
  174. ar.add_file(entry, temp_path)
  175. }
  176. FileUtils.rm temp_path
  177. end
  178. def read_metadata(path, local_path)
  179. ext = File.extname(path)
  180. title = album_title = nil
  181. tr_num = nil
  182. artists = []
  183. license = {}
  184. release_url = nil
  185. pub_date = nil
  186. case ext
  187. when ".ogg", ".oga"
  188. comment = VorbisComment.new(local_path)
  189. title = comment.fields["TITLE"].join(" / ")
  190. album_title = comment.fields["ALBUM"].join(" / ") rescue nil
  191. comment.fields["ARTIST"].map{|a|
  192. artists << {'name'=>a}
  193. }
  194. license['url'] = comment.fields["LICENSE"].join(" / ") if comment.fields["LICENSE"]
  195. license['verify_at'] = comment.fields["VERIFY_AT"].join(" / ") if comment.fields["VERIFY_AT"]
  196. if comment.fields["TRACKNUMBER"]
  197. tr_num = comment.fields["TRACKNUMBER"].to_s
  198. end
  199. when /\.flac$/i
  200. return Anbt::Flac::metadata(local_path)
  201. when ".mp3", ".MP3"
  202. frame = get_id3_frame(local_path, :TIT2 )
  203. title = frame[:text_u8] rescue title = nil
  204. frame = get_id3_frame(local_path, :TALB)
  205. album_title = frame[:text_u8] rescue album_title = nil
  206. frame = get_id3_frame(local_path, :TPE1)
  207. artist_name = begin
  208. frame[:text_u8]
  209. rescue
  210. path
  211. end
  212. artists << {
  213. 'name'=>artist_name
  214. }
  215. #license['url'] = get_id3_frame(local_path, :WCOP)
  216. temp_url = get_id3_frame(local_path, :WCOP)
  217. if not temp_url.nil?
  218. lincense = {
  219. "url" => temp_url,
  220. "verify_at" => nil
  221. }
  222. end
  223. release_url = get_id3_frame(local_path, :WOAF)
  224. tr_num = get_id3_frame(local_path, :TRCK)[:text_u8] rescue nil
  225. pub_date = get_id3_frame(local_path, :TYER)[:text] rescue nil
  226. end
  227. {
  228. 'title' => title,
  229. 'artists' => artists,
  230. 'license' => license,
  231. 'release_url' => release_url,
  232. 'track_number' => tr_num,
  233. 'album_title' => album_title,
  234. 'pub_date' => pub_date,
  235. 'comment' => comment
  236. }
  237. end
  238. # result << audio2track(temp_audio_path, template, entry)
  239. def audio2track(path, dir_temp, arc_template=nil, entry=nil)
  240. puts "audio2track()" if $DEBUG
  241. #puts path, arc_template.path, entry
  242. if arc_template
  243. audio_path = File.join(dir_temp, File.basename(path))
  244. else
  245. audio_path = File.join($PREFS.DIR_CACHE_SUB, path)
  246. end
  247. tr = Track.new
  248. tag = read_metadata(path, audio_path)
  249. if arc_template
  250. tr.path = "%s#%s" % [ arc_template.path, entry ]
  251. tr.album['id'] = arc_template.album['id'] if arc_template.album['id']
  252. else
  253. tr.path = File.join($PREFS.DIR_CACHE_SUB, path)
  254. end
  255. tr.title = tag['title']
  256. tr.album['title'] = tag['album_title']
  257. tr.cast_date = Time.now
  258. tr.track_number = tag['track_number'] if tag['track_number']
  259. tr.licenses << tag['license'] if not tag['license'].empty?
  260. if tag['artists'].empty? && arc_template
  261. ## template を優先
  262. tr.artists = arc_template.artists
  263. else
  264. ## タグを優先
  265. tr.artists = tag['artists']
  266. end
  267. if arc_template
  268. tr.release_url = arc_template.release_url
  269. tr.album['title'] = arc_template.album['title']
  270. if arc_template.licenses
  271. tr.licenses = arc_template.licenses
  272. elsif arc_template.license_url
  273. tr.license_url = arc_template.license_url
  274. end
  275. end
  276. #puts "RRRRRRRRRRRRRRRRRRRRRRRRRR", tr.path if $VERBOSE
  277. tr
  278. end
  279. def arc_get_tracks(arc_path, template, dir_temp)
  280. $stderr.puts "++++++++++ #{arc_path}" if $VERBOSE
  281. #local_path = File.join( $PREFS.DIR_CACHE_SUB, arc_path )
  282. tracks = []
  283. case File.extname(arc_path)
  284. when /^\.zip$/i
  285. #list = file_list_zip(local_path)
  286. list = file_list_zip(arc_path).
  287. select{|e| /^__MACOSX\// !~ e }
  288. count = 1
  289. list.each do |entry|
  290. ext = File.extname(entry)
  291. next unless /^\.(ogg|oga|flac|mp3)$/ =~ ext
  292. ## 一時ファイル取り出す
  293. #temp_audio_path = arc_cp(local_path, entry, File.join($PREFS.DIR_TEMP, "000#{ext}") )
  294. temp_audio_path = arc_cp(arc_path,
  295. entry,
  296. File.join(dir_temp, "000#{ext}")
  297. )
  298. ## タグ読む
  299. begin
  300. tracks << audio2track(temp_audio_path, dir_temp, template, entry)
  301. rescue => e
  302. puts e.message, e.backtrace
  303. puts temp_audio_path, entry, arc_path
  304. exit 1
  305. end
  306. FileUtils.rm(temp_audio_path)
  307. $stderr.print "t#{count} "
  308. count += 1
  309. end
  310. $stderr.print "\n"
  311. else
  312. raise "File type not recongnized: #{arc_path} ."
  313. end
  314. #puts result.to_yaml
  315. return tracks
  316. end
  317. def append_to_playlist(playlist, tr)
  318. # pp 6666699999, [].include?( tr.to_ezhash),
  319. # playlist.map{|e| e.to_ezhash}.include?( tr.to_ezhash ),
  320. # playlist.map{|e| e.to_ezhash}
  321. #if not playlist.map{|e| e.to_ezhash}.include?( tr.to_ezhash )
  322. playlist << tr
  323. #end
  324. end
  325. def make_template_track(info, arc_path)
  326. template = Track.new
  327. if info
  328. if info['album']
  329. template.album['title'] = if info['album']['title']
  330. info['album']['title']
  331. else
  332. info['album_title']
  333. end
  334. template.album['id'] = if info['album']['id']
  335. info['album']['id']
  336. else
  337. info['album_id']
  338. end
  339. end
  340. puts "track template: "
  341. pp template
  342. template.release_url = info["release_url"] if info["release_url"]
  343. if info["licenses"]
  344. template.licenses = info["licenses"]
  345. elsif info["license_url"]
  346. $stderr.puts "license_url is obsolete!"
  347. #template.license_url = info["license_url"]
  348. end
  349. template.artists = info["artists"] if info["artists"]
  350. end
  351. template.path = arc_path
  352. template
  353. end
  354. def append_tracks_from_archive(playlist,
  355. arc_path, # basename
  356. temp_dir
  357. )
  358. warn "Archive: #{arc_path}"
  359. entries = file_list_zip(arc_path)
  360. # info 取得
  361. info = nil
  362. entries.each {|entry|
  363. if /info.yaml$/ =~ entry
  364. puts "info.yaml exist."
  365. temp = read_file(arc_path, entry)
  366. info = YAML.load( temp )
  367. pp info if $DEBUG
  368. end
  369. }
  370. if $DEBUG
  371. pp info
  372. end
  373. # テンプレートtrack作成
  374. template = make_template_track(info, arc_path)
  375. tracks = arc_get_tracks(arc_path, template, temp_dir)
  376. tracks.sort_by{|tr| tr.track_number }.each do |track|
  377. append_to_playlist(playlist, track)
  378. end
  379. end
  380. def append_single_file(playlist, path)
  381. STDERR.puts "F: #{path}"
  382. #track = get_track(path)
  383. track = audio2track(path)
  384. # pp track
  385. append_to_playlist(playlist, track)
  386. end
  387. if $0 == __FILE__
  388. # file = ARGV[0]
  389. # #target = ARGV[1]
  390. # playlist = [123]
  391. # case File.extname(file)
  392. # when /^\.(zip)$/
  393. # append_tracks_from_archive(playlist, file)
  394. # else
  395. # append_single_file(playlist, file)
  396. # end
  397. # puts playlist.to_yaml
  398. # tag = read_metadata("Yoma_Aoki__02 - girl age ガールエージ.mp3",
  399. # "test/sample/Yoma_Aoki__02 - girl age ガールエージ.mp3")
  400. path = ARGV[0]
  401. # tag = ID3Lib::Tag.new(path, ID3Lib::V1)
  402. # pp tag; puts "====================================="
  403. # tag = ID3Lib::Tag.new(path, ID3Lib::V2)
  404. # pp tag; puts "====================================="
  405. tag = ID3Lib::Tag.new(path).each{|t|
  406. pp t; puts "====================================="
  407. }
  408. tag = read_metadata(ARGV[0], ARGV[0])
  409. pp tag
  410. end