ipod_db 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
data/Guardfile CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  guard 'bundler' do
5
5
  watch('Gemfile')
6
+ watch('ipod_db.gemspec')
6
7
  end
7
8
 
8
9
  guard 'minitest' do
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  NAME
5
5
  ====
6
6
 
7
- ipod_db v0.2.8
7
+ ipod_db v0.2.9
8
8
 
9
9
  SYNOPSIS
10
10
  ========
data/bin/ipod CHANGED
@@ -2,38 +2,29 @@
2
2
 
3
3
  Main {
4
4
  version IpodDB::VERSION
5
+ author 'artm <femistofel@gmail.com>'
6
+ name 'ipod_db'
5
7
 
6
8
  description <<-__
7
9
  A couple of tools for working with iPod Shuffle (2nd gen) database from
8
10
  command line. Each subcommand understands -h/--help flag.
9
11
  __
10
12
 
11
- author 'artm <femistofel@gmail.com>'
12
-
13
- name 'ipod_db'
14
- config(
15
- ipod_root: "/media/#{ENV['USER']}/IPOD",
16
- group_together: [
17
- # Just an example
18
- [ "60-Second", "Science Talk", "This Week in Science" ],
19
- [ "StarShipSofa", "Tales To Terrify" ],
20
- ])
21
13
  option('books','b') {
22
14
  argument_required
23
15
  default 'books'
24
16
  description 'subdirectory of ipod with bookmarkable media'
25
17
  }
18
+
26
19
  option('songs','s') {
27
20
  argument_required
28
21
  default 'songs'
29
22
  description 'subdirectory of ipod with non-bookmarkable media'
30
23
  }
24
+
31
25
  option('version','v') {
32
26
  description 'show package version and exit'
33
27
  }
34
- IgnorePlaybackPosUnder = 10
35
- IgnoreProgressUnder = 0.01
36
- FinishedProgress = 0.97
37
28
 
38
29
  def run
39
30
  if param['version'].given?
@@ -96,7 +87,7 @@ Main {
96
87
  track numbers to delete from device (ranges like
97
88
  2-5 are accepted too). As a special case, the word
98
89
  'done' means all finished tracks, i.e. with play count
99
- above zero or progress above #{ (100*FinishedProgress).floor }%
90
+ above zero or progress above #{ (100*Ipod::Track::FinishedProgress).floor }%
100
91
  __
101
92
  }
102
93
  option('pretend','n') {
@@ -123,7 +114,9 @@ Main {
123
114
  end
124
115
 
125
116
  def ls
126
- @ipod_db.each_track_with_index {|track,i| list_track i, track}
117
+ @ipod_db.each_track_with_index do |track,i|
118
+ list_track i, Ipod::Track.new(track.merge(ipod_root: @ipod_root))
119
+ end
127
120
  end
128
121
 
129
122
  def rm
@@ -133,8 +126,8 @@ Main {
133
126
  unless @pretend
134
127
  if agree "Are you sure you want them gone (Y/n)?", true
135
128
  FileUtils.rm tracks.map{|i,path|resolve_ipod_path path}
129
+ sync
136
130
  end
137
- sync
138
131
  end
139
132
  end
140
133
 
@@ -146,10 +139,6 @@ Main {
146
139
  File.join @ipod_root, ipath
147
140
  end
148
141
 
149
- def track_length( path )
150
- TagLib::FileRef.open(path){|file| file.audio_properties.length}
151
- end
152
-
153
142
  def load_ipod_db
154
143
  @ipod_root = config['ipod_root']
155
144
  unless IpodDB.looks_like_ipod? @ipod_root
@@ -189,48 +178,35 @@ Main {
189
178
  IpodDB::ExtToFileType.include? File.extname(path)
190
179
  end
191
180
 
192
- def track_info track
193
- info = Map.new
194
- info['playcount'] = track.playcount if track.fetch('playcount',0) > 0
195
- info['skipcount'] = track.skippedcount if track.fetch('skippedcount',0) > 0
196
- if track.fetch('bookmarktime',0) > 0
197
- abs_path = resolve_ipod_path track.filename
198
- total_time = track_length(abs_path)
199
- # ipod keeps time in 256 ms increments
200
- pos = [total_time, track.bookmarktime * 0.256].min
201
- progress = pos / total_time
202
- if pos > IgnorePlaybackPosUnder && progress >= IgnoreProgressUnder
203
- info['pos'] = Pretty.seconds pos
204
- info['total'] = Pretty.seconds total_time
205
- info['progress'] = progress
206
- end
207
- end
208
- info
209
- end
210
-
211
181
  def list_track i, track
212
- abs_path = resolve_ipod_path track.filename
213
- exists = File.exists?(abs_path)
214
- track_color = exists ? :green : :red
215
-
216
- listing_entry = "%2d: %s" % [i,track.filename.apply_format( color: track_color )]
182
+ listing_entry = "%2d: %s" % [i,track.filename.apply_format( color: track_color(track))]
217
183
  listing_entry = listing_entry.bold if @ipod_db.playback_state.trackno == i
218
184
  puts listing_entry
185
+ display_progress track
186
+ end
187
+
188
+ def track_color track
189
+ if track.exists? then
190
+ if track.finished?
191
+ :cyan
192
+ else
193
+ :green
194
+ end
195
+ else
196
+ :red
197
+ end
198
+ end
219
199
 
220
- return unless exists
200
+ def display_progress track
201
+ if track.exists? and track.pos >= IgnoreProgressUnder and
202
+ track.progress.between?(IgnoreProgressUnder,Ipod::Track::FinishedProgress)
221
203
 
222
- info = track_info(track)
223
- if info.include? 'progress'
224
204
  progress = ProgressBar.create(
225
- format: " [%b #{info.pos.yellow} %P%%%i] #{info.total.yellow}",
226
- starting_at: (100*info.progress),
205
+ format: " [%b #{Pretty.seconds(track.pos).yellow} %P%%%i] #{Pretty.seconds(track.length).yellow}",
206
+ starting_at: (100*track.progress),
227
207
  )
228
208
  puts
229
209
  end
230
- ['pos','total','progress'].each{|f| info.delete(f)}
231
- if info.count > 0
232
- puts " " + info.map{|label,value| "#{label}: #{value.to_s.yellow}"}.join(" ")
233
- end
234
210
  end
235
211
 
236
212
  def parse_track_list args
@@ -254,10 +230,6 @@ Main {
254
230
  tracks
255
231
  end
256
232
 
257
- def finished? track
258
- track.fetch('playcount',0) > 0 || track_info(track).fetch('progress',0) >= FinishedProgress
259
- end
260
-
261
233
  def spread paths, group_lambda = lambda {|path| track_group(path)}
262
234
  bins = paths.group_by &group_lambda
263
235
  bins.each do |key, bin|
@@ -274,6 +246,17 @@ Main {
274
246
  end
275
247
  File.dirname(track)
276
248
  end
249
+
250
+ IgnorePlaybackPosUnder = 10
251
+ IgnoreProgressUnder = 0.01
252
+
253
+ config({
254
+ ipod_root: "/media/#{ENV['USER']}/IPOD",
255
+ group_together: [
256
+ # Just an example
257
+ [ "60-Second", "Science Talk", "This Week in Science" ],
258
+ [ "StarShipSofa", "Tales To Terrify" ],
259
+ ]})
277
260
  }
278
261
 
279
262
  BEGIN {
@@ -282,7 +265,6 @@ BEGIN {
282
265
  require 'pathname'
283
266
  require 'smart_colored/extend'
284
267
  require 'map'
285
- require 'taglib'
286
268
  require 'ruby-progressbar'
287
269
  require 'highline/import'
288
270
  require 'fileutils'
@@ -290,6 +272,7 @@ BEGIN {
290
272
 
291
273
  # our own
292
274
  require 'ipod_db'
275
+ require 'ipod/track'
293
276
  require 'pretty'
294
277
  require 'spread'
295
278
  }
data/ipod_db.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
29
29
  s.add_development_dependency 'rake'
30
30
  s.add_development_dependency 'bundler', '~> 1.3'
31
31
  # not sure where this belongs, they are part of my development process
32
- s.add_development_dependency 'purdytest'
32
+ s.add_development_dependency 'minitest-reporters'
33
33
  s.add_development_dependency 'guard'
34
34
  s.add_development_dependency 'guard-minitest'
35
35
  s.add_development_dependency 'guard-bundler'
data/lib/ipod/track.rb ADDED
@@ -0,0 +1,54 @@
1
+ require 'ostruct'
2
+ require 'taglib'
3
+ require 'fileutils'
4
+
5
+ module Ipod
6
+ class Track < OpenStruct
7
+ FinishedProgress = 0.97
8
+ SecondsPerTick = 0.256
9
+
10
+ def absolute_path
11
+ File.join ipod_root, filename
12
+ end
13
+
14
+ def exists?
15
+ @exists ||= File.exists? absolute_path
16
+ end
17
+
18
+ def finished?
19
+ playcount > 0 or progress > FinishedProgress
20
+ end
21
+
22
+ def progress
23
+ pos / length
24
+ end
25
+
26
+ def pos
27
+ Track.ticks_to_sec(bookmarktime)
28
+ end
29
+
30
+ def length
31
+ #
32
+ # if file is writable TagLib opens it read-write and appears to write something when the file
33
+ # gets closed, or in any case closing a file open read-write is slow on slow media.
34
+ #
35
+ # if file is readonly TagLib still opens it but closing is much faster.
36
+ #
37
+ old_stat = File::Stat.new(absolute_path)
38
+ begin
39
+ FileUtils.chmod('a-w', absolute_path)
40
+ TagLib::FileRef.open(absolute_path){|file| file.audio_properties.length}
41
+ ensure
42
+ FileUtils.chmod(old_stat.mode, absolute_path)
43
+ end
44
+ end
45
+
46
+ def self.sec_to_ticks(sec)
47
+ sec / SecondsPerTick
48
+ end
49
+
50
+ def self.ticks_to_sec(ticks)
51
+ ticks * SecondsPerTick
52
+ end
53
+ end
54
+ end
@@ -1,3 +1,3 @@
1
1
  class IpodDB
2
- VERSION = '0.2.8'
2
+ VERSION = '0.2.9'
3
3
  end
@@ -0,0 +1,68 @@
1
+ require "spec_helper"
2
+ require "ipod/track"
3
+
4
+ describe Ipod::Track do
5
+
6
+ describe "#exists?" do
7
+
8
+ it "knows if file exists" do
9
+ track = Ipod::Track.new filename: "/books/chapter1.mp3", ipod_root: "/mount/ipod"
10
+
11
+ File.mock_stub :exists?, true, ["/mount/ipod/books/chapter1.mp3"] do
12
+ assert track.exists?
13
+ end
14
+ end
15
+
16
+ it "knows if file doesn't exist" do
17
+ track = Ipod::Track.new filename: "/books/chapter1.mp3", ipod_root: "/mount/ipod"
18
+
19
+ File.mock_stub :exists?, false, ["/mount/ipod/books/chapter1.mp3"] do
20
+ refute track.exists?
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ describe '#finished?' do
27
+
28
+ it 'is true if playcount > 0' do
29
+ track = Ipod::Track.new playcount: 1
30
+ assert track.finished?
31
+ end
32
+
33
+ it 'is true if progress above threshold' do
34
+ track = Ipod::Track.new playcount: 0, bookmarktime: Ipod::Track.sec_to_ticks(99)
35
+ track.stub :length, 100 do
36
+ assert track.finished?
37
+ end
38
+ end
39
+
40
+ it 'is false if progress below threshold' do
41
+ track = Ipod::Track.new playcount: 0, bookmarktime: Ipod::Track.sec_to_ticks(5)
42
+ track.stub :length, 100 do
43
+ refute track.finished?
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ describe '#pos' do
50
+
51
+ it 'represents bookmarktime in seconds' do
52
+ track = Ipod::Track.new bookmarktime: 1
53
+ assert_in_delta track.pos, Ipod::Track::SecondsPerTick
54
+ end
55
+
56
+ end
57
+
58
+ describe '#progress' do
59
+
60
+ it 'represents progress in track' do
61
+ track = Ipod::Track.new bookmarktime: Ipod::Track.sec_to_ticks(25)
62
+ track.stub :length, 100 do
63
+ assert_in_delta track.progress, 0.25
64
+ end
65
+ end
66
+
67
+ end
68
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  require 'minitest/autorun'
2
- require 'purdytest'
2
+ require "minitest/reporters"
3
+ MiniTest::Reporters.use! [
4
+ MiniTest::Reporters::DefaultReporter.new,
5
+ MiniTest::Reporters::GuardReporter.new,
6
+ ]
3
7
  $LOAD_PATH.push "File.dirname(__FILE__)/../lib"
4
8
  require 'bindata'
5
9
 
@@ -51,3 +55,14 @@ module Enumerable
51
55
  ds
52
56
  end
53
57
  end
58
+
59
+ class Object
60
+ def mock_stub name, retval, args=[], &block
61
+ mock = MiniTest::Mock.new
62
+ mock.expect name, retval, args
63
+ stub name, proc{|*args| mock.method_missing(name,*args)} do
64
+ yield
65
+ end
66
+ mock.verify
67
+ end
68
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ipod_db
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.2.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-03 00:00:00.000000000 Z
12
+ date: 2013-04-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bindata
@@ -172,7 +172,7 @@ dependencies:
172
172
  - !ruby/object:Gem::Version
173
173
  version: '1.3'
174
174
  - !ruby/object:Gem::Dependency
175
- name: purdytest
175
+ name: minitest-reporters
176
176
  requirement: !ruby/object:Gem::Requirement
177
177
  none: false
178
178
  requirements:
@@ -303,10 +303,12 @@ files:
303
303
  - doc/ITunesDB - wikiPodLinux.html
304
304
  - ipod_db.gemspec
305
305
  - lib/bindata/itypes.rb
306
+ - lib/ipod/track.rb
306
307
  - lib/ipod_db.rb
307
308
  - lib/ipod_db/version.rb
308
309
  - lib/pretty.rb
309
310
  - lib/spread.rb
311
+ - spec/ipod/track_spec.rb
310
312
  - spec/ipod_db_spec.rb
311
313
  - spec/spec_helper.rb
312
314
  - spec/spread_spec.rb
@@ -332,7 +334,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
332
334
  version: '0'
333
335
  segments:
334
336
  - 0
335
- hash: 1960172244731333251
337
+ hash: 4257127508463692162
336
338
  required_rubygems_version: !ruby/object:Gem::Requirement
337
339
  none: false
338
340
  requirements:
@@ -341,7 +343,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
341
343
  version: '0'
342
344
  segments:
343
345
  - 0
344
- hash: 1960172244731333251
346
+ hash: 4257127508463692162
345
347
  requirements: []
346
348
  rubyforge_project:
347
349
  rubygems_version: 1.8.23
@@ -349,6 +351,7 @@ signing_key:
349
351
  specification_version: 3
350
352
  summary: ipod database access
351
353
  test_files:
354
+ - spec/ipod/track_spec.rb
352
355
  - spec/ipod_db_spec.rb
353
356
  - spec/spec_helper.rb
354
357
  - spec/spread_spec.rb