ektoplayer 0.1.12 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ektoplayer/application.rb +49 -19
  3. data/lib/ektoplayer/bindings.rb +91 -87
  4. data/lib/ektoplayer/browsepage.rb +14 -27
  5. data/lib/ektoplayer/common.rb +12 -67
  6. data/lib/ektoplayer/compat.rb +5 -11
  7. data/lib/ektoplayer/config.rb +52 -17
  8. data/lib/ektoplayer/controllers/browser.rb +10 -5
  9. data/lib/ektoplayer/database.rb +7 -20
  10. data/lib/ektoplayer/download/externaldownload.rb +65 -0
  11. data/lib/ektoplayer/download/rubydownload.rb +69 -0
  12. data/lib/ektoplayer/icurses/curses.rb +18 -2
  13. data/lib/ektoplayer/icurses/{ffi_ncurses.rb → ffi-ncurses.rb} +1 -0
  14. data/lib/ektoplayer/icurses/ncurses.rb +10 -0
  15. data/lib/ektoplayer/icurses.rb +13 -5
  16. data/lib/ektoplayer/models/browser.rb +11 -11
  17. data/lib/ektoplayer/models/player.rb +4 -5
  18. data/lib/ektoplayer/operations/browser.rb +9 -1
  19. data/lib/ektoplayer/operations/playlist.rb +1 -1
  20. data/lib/ektoplayer/players/mpg_wrapper_player.rb +98 -40
  21. data/lib/ektoplayer/theme.rb +78 -63
  22. data/lib/ektoplayer/trackloader.rb +25 -74
  23. data/lib/ektoplayer/ui/colors.rb +33 -5
  24. data/lib/ektoplayer/ui/widgets/container.rb +1 -1
  25. data/lib/ektoplayer/ui/widgets/listwidget.rb +35 -34
  26. data/lib/ektoplayer/ui/widgets.rb +19 -0
  27. data/lib/ektoplayer/ui.rb +22 -23
  28. data/lib/ektoplayer/updater.rb +3 -4
  29. data/lib/ektoplayer/views/browser.rb +7 -2
  30. data/lib/ektoplayer/views/help.rb +5 -2
  31. data/lib/ektoplayer/views/info.rb +22 -27
  32. data/lib/ektoplayer/views/playinginfo.rb +20 -19
  33. data/lib/ektoplayer/views/playlist.rb +8 -3
  34. data/lib/ektoplayer/views/progressbar.rb +26 -33
  35. data/lib/ektoplayer/views/splash.rb +14 -22
  36. data/lib/ektoplayer/views/trackrenderer.rb +14 -10
  37. metadata +7 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fb06ab1d760e586affdc548cf3c622323736700c
4
- data.tar.gz: 147c4ab4a4a71f4acae9bcc963da610daba75f2c
3
+ metadata.gz: 1567475105c5b1d0e3a099a4324ca19cdd67efe8
4
+ data.tar.gz: e48caa107e5f934866a720023a5cb86fbb9153a9
5
5
  SHA512:
6
- metadata.gz: ab09617d8346b932adb34879a6400c79af7c8e14e348908161d0bd9f1bfc1b9a35547504c1dbdda0d281dda13435a2b3fdf03b6a0ed45d3710cc761d4ff1d0dc
7
- data.tar.gz: ec888b4104511631aa3d3366896e2591252d398cfeece159bd7027de2860470b6b7144b03998af879461f75af5fbd17fcdf1ccad7ae910a1df1b8853550f44e9
6
+ metadata.gz: f5b706485a36e6398a981314c93f244ad4c85e35afbe55cce4e2d211752059abd3cfe743316d5edc85011f01002ecf35b5895e0aab54551bff565e407b1e7db0
7
+ data.tar.gz: 12636fee134acc3f234ddbb6f7637e6a2ca0186998d76929820eb1f5a36c347ed5ec6c86aab8f128be13cf7240b9d01ad8e68c68b3dd15ac8347c783cb765ead
@@ -10,15 +10,39 @@ require 'date'
10
10
 
11
11
  module Ektoplayer
12
12
  class Application
13
- VERSION = '0.1.12'.freeze
13
+ VERSION = '0.1.16'.freeze
14
14
  GITHUB_URL = 'https://github.com/braph/ektoplayer'.freeze
15
15
  EKTOPLAZM_URL = 'http://www.ektoplazm.com'.freeze
16
- EKTOPLAZM_ALBUM_BASE_URL = EKTOPLAZM_URL + '/free-music'.freeze
17
- EKTOPLAZM_COVER_BASE_URL = EKTOPLAZM_URL + '/img'.freeze
16
+
17
+ EKTOPLAZM_ALBUM_BASE_URL = "#{EKTOPLAZM_URL}/free-music".freeze
18
+ EKTOPLAZM_COVER_BASE_URL = "#{EKTOPLAZM_URL}/img".freeze
19
+ EKTOPLAZM_TRACK_BASE_URL = "#{EKTOPLAZM_URL}/mp3".freeze
20
+ EKTOPLAZM_STYLE_BASE_URL = "#{EKTOPLAZM_URL}/style".freeze
21
+ EKTOPLAZM_ARCHIVE_BASE_URL = "#{EKTOPLAZM_URL}/files".freeze
18
22
 
19
23
  CONFIG_DIR = File.join(Dir.home, '.config', 'ektoplayer').freeze
20
24
  CONFIG_FILE = File.join(CONFIG_DIR, 'ektoplayer.rc').freeze
21
25
 
26
+ def self.album_url(album)
27
+ "#{EKTOPLAZM_ALBUM_BASE_URL}/#{album}"
28
+ end
29
+
30
+ def self.cover_url(cover)
31
+ "#{EKTOPLAZM_COVER_BASE_URL}/#{cover}"
32
+ end
33
+
34
+ def self.track_url(track)
35
+ "#{EKTOPLAZM_TRACK_BASE_URL}/#{track}"
36
+ end
37
+
38
+ def self.style_url(style)
39
+ "#{EKTOPLAZM_STYLE_BASE_URL}/#{style}"
40
+ end
41
+
42
+ def self.archive_url(archive)
43
+ "#{EKTOPLAZM_ARCHIVE_BASE_URL}/#{archive}"
44
+ end
45
+
22
46
  def self.log(from, *msgs)
23
47
  func = caller[0][/`.*'/][1..-2]
24
48
  from = from.class unless from.is_a?String
@@ -36,7 +60,7 @@ module Ektoplayer
36
60
  end
37
61
 
38
62
  def run
39
- #Thread.abort_on_exception=(true)
63
+ puts "\033]0;ektoplayer\007"
40
64
  Thread.report_on_exception=(true) if Thread.respond_to? :report_on_exception
41
65
 
42
66
  # make each configuration object globally accessible as a singleton
@@ -71,7 +95,7 @@ module Ektoplayer
71
95
  end
72
96
 
73
97
  UI::Canvas.run do
74
- Application.log(self, 'running with ncurses interface:', $USING_CURSES)
98
+ Application.log(self, "using '#{$USING_CURSES}' with #{ICurses.colors} colors available")
75
99
 
76
100
  if Config[:use_colors] == :auto
77
101
  Theme.use_colors(ICurses.colors >= 256 ? 256 : 8)
@@ -90,7 +114,12 @@ module Ektoplayer
90
114
 
91
115
  # ... operations ...
92
116
  operations = Operations::Operations.new
93
- operations.register(:quit, &method(:exit))
117
+ operations.register(:quit) do
118
+ Thread.list.each { |t| t.kill if t != Thread.current }
119
+ FileUtils.rm(Dir.glob(File.join(Config[:temp_dir], '~ekto-*'))) rescue nil
120
+ raise SystemExit
121
+ end
122
+
94
123
  operations.register(:reload, &browser.method(:reload))
95
124
  operations.register(:update, &database.method(:update))
96
125
  operations.register(:refresh) { UI::Canvas.update_screen(true, true) }
@@ -117,25 +146,26 @@ module Ektoplayer
117
146
  main_w.playinginfo.attach(playlist, player)
118
147
 
119
148
  # ... events ...
120
- database.events.on(:update_finished, &browser.method(:reload ))
149
+ database.events.on(:update_finished, &browser.method(:reload))
121
150
  player.events.on(:stop) do |reason|
122
151
  operations.send(:'playlist.play_next') if reason == :track_completed
123
152
  end
124
153
 
125
154
  if Config[:prefetch]
126
- trackloader_mutex = Mutex.new
127
- @prefetch_thread = nil
128
- player.events.on(:position_change) do
129
- @prefetch_thread ||= Thread.new do
130
- if player.length > 30 and player.position_percent > 0.7
131
- trackloader_mutex.synchronize do
132
- trackloader.get_track_file(playlist[playlist.get_next_pos]['url'])
133
- sleep 30
134
- end
135
- end
155
+ Thread.new do
156
+ current_download_track = nil
157
+
158
+ loop do
159
+ sleep 5
136
160
 
137
- sleep 10
138
- @prefetch_thread = nil
161
+ next_track = playlist.get_next_pos
162
+ next if current_download_track == next_track
163
+
164
+ if player.length > 30 and player.position_percent > 0.5
165
+ trackloader.get_track_file(playlist[next_track]['url'])
166
+ current_download_track = next_track
167
+ sleep 5
168
+ end
139
169
  end
140
170
  end
141
171
  end
@@ -69,104 +69,108 @@ module Ektoplayer
69
69
  %w(browser playlist).each { |w| reg("#{w}.#{cmd}", desc) }
70
70
  end
71
71
 
72
- @bindings = {
73
- global: {
74
- :'splash.show' => [?`, ?^ ],
75
- :'playlist.show' => [?1 ],
76
- :'browser.show' => [?2 ],
77
- :'info.show' => [?3 ],
78
- :'help.show' => [?4, ICurses::KEY_F1 ],
79
-
80
- :'playinginfo.toggle' => [?!, ICurses::KEY_F2 ],
81
- :'progressbar.toggle' => [?%, ICurses::KEY_F3 ],
82
- :'tabbar.toggle' => [?=, ICurses::KEY_F4 ],
83
-
84
- :'player.forward' => [?f, ICurses::KEY_RIGHT ],
85
- :'player.backward' => [?b, ICurses::KEY_LEFT ],
86
- :'player.stop' => [?s ],
87
- :'player.toggle' => [?p ],
88
-
89
- :'playlist.play_next' => [?> ],
90
- :'playlist.play_prev' => [?< ],
91
-
92
- :'tabs.next' => [?l, ?}, '^i' ],
93
- :'tabs.prev' => [?h, ?{, 353 ],
94
-
95
- :quit => [?q ],
96
- :refresh => ['^l' ],
97
- :reload => ['^r' ],
98
- :update => [?U ]},
99
- playlist: {
100
- # movement
101
- :'playlist.top' => [?g, ICurses::KEY_HOME ],
102
- :'playlist.bottom' => [?G, ICurses::KEY_END ],
103
- :'playlist.up' => [?k, ICurses::KEY_UP ],
104
- :'playlist.down' => [?j, ICurses::KEY_DOWN ],
105
- :'playlist.page_down' => ['^d', ICurses::KEY_NPAGE ],
106
- :'playlist.page_up' => ['^u', ICurses::KEY_PPAGE ],
107
- # selection
108
- :'playlist.toggle_selection' => ['^v' ],
109
- # search
110
- :'playlist.search_next' => [?n ],
111
- :'playlist.search_prev' => [?N ],
112
- :'playlist.search_up' => [?? ],
113
- :'playlist.search_down' => [?/ ],
114
- # playlist
115
- :'playlist.play' => [ ICurses::KEY_ENTER ],
116
- :'playlist.download_album' => [?$ ],
117
- :'playlist.reload' => [?r ],
118
- :'playlist.goto_current' => [?o ],
119
- :'playlist.clear' => [?c ],
120
- :'playlist.delete' => [?d ],
121
- # other
122
- :'player.toggle' => [' ' ]},
123
- browser: {
124
- # movement
125
- :'browser.top' => [?g, ICurses::KEY_HOME ],
126
- :'browser.bottom' => [?G, ICurses::KEY_END ],
127
- :'browser.up' => [?k, ICurses::KEY_UP ],
128
- :'browser.down' => [?j, ICurses::KEY_DOWN ],
129
- :'browser.page_up' => ['^u', ICurses::KEY_PPAGE ],
130
- :'browser.page_down' => ['^d', ICurses::KEY_NPAGE ],
131
- # selection
132
- :'browser.toggle_selection' => ['^v' ],
133
- # search
134
- :'browser.search_next' => [?n ],
135
- :'browser.search_prev' => [?N ],
136
- :'browser.search_up' => [?? ],
137
- :'browser.search_down' => [?/ ],
138
- # browser
139
- :'browser.add_to_playlist' => [' ', ?a ],
140
- :'browser.enter' => [ ICurses::KEY_ENTER ],
141
- :'browser.back' => [?B, ICurses::KEY_BACKSPACE ]},
142
- help: {
143
- :'help.top' => [?g, ICurses::KEY_HOME ],
144
- :'help.bottom' => [?G, ICurses::KEY_END ],
145
- :'help.up' => [?k, ICurses::KEY_UP ],
146
- :'help.down' => [?j, ICurses::KEY_DOWN ],
147
- :'help.page_up' => ['^u', ICurses::KEY_PPAGE ],
148
- :'help.page_down' => ['^d', ICurses::KEY_NPAGE ]},
149
- info: {
150
- :'info.top' => [?g, ICurses::KEY_HOME ],
151
- :'info.bottom' => [?G, ICurses::KEY_END ],
152
- :'info.up' => [?k, ICurses::KEY_UP ],
153
- :'info.down' => [?j, ICurses::KEY_DOWN ],
154
- :'info.page_up' => ['^u', ICurses::KEY_PPAGE ],
155
- :'info.page_down' => ['^d', ICurses::KEY_NPAGE ]},
156
- splash: {}
72
+ @bindings = { }
73
+ @bindings[:global] = {
74
+ :'splash.show' => [?`, ?^ ],
75
+ :'playlist.show' => [?1 ],
76
+ :'browser.show' => [?2 ],
77
+ :'info.show' => [?3 ],
78
+ :'help.show' => [?4, ICurses::KEY_F1 ],
79
+
80
+ :'playinginfo.toggle' => [?!, ?\\, ICurses::KEY_F2 ],
81
+ :'progressbar.toggle' => [?%, ?~, ICurses::KEY_F3 ],
82
+ :'tabbar.toggle' => [?=, ICurses::KEY_F4 ],
83
+
84
+ :'player.forward' => [?f, ICurses::KEY_RIGHT ],
85
+ :'player.backward' => [?b, ICurses::KEY_LEFT ],
86
+ :'player.stop' => [?s ],
87
+ :'player.toggle' => [?p ],
88
+
89
+ :'playlist.play_next' => [?> ],
90
+ :'playlist.play_prev' => [?< ],
91
+
92
+ :'tabs.next' => [?l, ?}, '^i' ],
93
+ :'tabs.prev' => [?h, ?{, 353 ],
94
+
95
+ :quit => [?q ],
96
+ :refresh => ['^l' ],
97
+ :reload => ['^r' ],
98
+ :update => [?U ]
99
+ }
100
+ @bindings[:playlist] = {
101
+ # movement
102
+ :'playlist.top' => [?g, ICurses::KEY_HOME ],
103
+ :'playlist.bottom' => [?G, ICurses::KEY_END ],
104
+ :'playlist.up' => [?k, ICurses::KEY_UP ],
105
+ :'playlist.down' => [?j, ICurses::KEY_DOWN ],
106
+ :'playlist.page_down' => ['^d', ICurses::KEY_NPAGE ],
107
+ :'playlist.page_up' => ['^u', ICurses::KEY_PPAGE ],
108
+ # selection
109
+ :'playlist.toggle_selection' => ['^v' ],
110
+ # search
111
+ :'playlist.search_next' => [?n ],
112
+ :'playlist.search_prev' => [?N ],
113
+ :'playlist.search_up' => [?? ],
114
+ :'playlist.search_down' => [?/ ],
115
+ # playlist
116
+ :'playlist.play' => [ ICurses::KEY_ENTER ],
117
+ :'playlist.download_album' => [?$ ],
118
+ :'playlist.reload' => [?r ],
119
+ :'playlist.goto_current' => [?o ],
120
+ :'playlist.clear' => [?c ],
121
+ :'playlist.delete' => [?d ],
122
+ # other
123
+ :'player.toggle' => [' ' ]
124
+ }
125
+ @bindings[:browser] = {
126
+ # movement
127
+ :'browser.top' => [?g, ICurses::KEY_HOME ],
128
+ :'browser.bottom' => [?G, ICurses::KEY_END ],
129
+ :'browser.up' => [?k, ICurses::KEY_UP ],
130
+ :'browser.down' => [?j, ICurses::KEY_DOWN ],
131
+ :'browser.page_up' => ['^u', ICurses::KEY_PPAGE ],
132
+ :'browser.page_down' => ['^d', ICurses::KEY_NPAGE ],
133
+ # selection
134
+ :'browser.toggle_selection' => ['^v' ],
135
+ # search
136
+ :'browser.search_next' => [?n ],
137
+ :'browser.search_prev' => [?N ],
138
+ :'browser.search_up' => [?? ],
139
+ :'browser.search_down' => [?/ ],
140
+ # browser
141
+ :'browser.add_to_playlist' => [' ', ?a ],
142
+ :'browser.enter' => [ ICurses::KEY_ENTER ],
143
+ :'browser.back' => [?B, ICurses::KEY_BACKSPACE ]
144
+ }
145
+ @bindings[:help] = {
146
+ :'help.top' => [?g, ICurses::KEY_HOME ],
147
+ :'help.bottom' => [?G, ICurses::KEY_END ],
148
+ :'help.up' => [?k, ICurses::KEY_UP ],
149
+ :'help.down' => [?j, ICurses::KEY_DOWN ],
150
+ :'help.page_up' => ['^u', ICurses::KEY_PPAGE ],
151
+ :'help.page_down' => ['^d', ICurses::KEY_NPAGE ]
152
+ }
153
+ @bindings[:info] = {
154
+ :'info.top' => [?g, ICurses::KEY_HOME ],
155
+ :'info.bottom' => [?G, ICurses::KEY_END ],
156
+ :'info.up' => [?k, ICurses::KEY_UP ],
157
+ :'info.down' => [?j, ICurses::KEY_DOWN ],
158
+ :'info.page_up' => ['^u', ICurses::KEY_PPAGE ],
159
+ :'info.page_down' => ['^d', ICurses::KEY_NPAGE ]
157
160
  }
161
+ @bindings[:splash] = {}
158
162
 
159
163
  @bindings.default_proc = proc { |h,k| fail "Unknown widget #{k}" }
160
164
  @bindings.each do |widget, hash|
161
165
  hash.default_proc = proc { |h,k| h[k] = [] }
162
166
  hash.values.each do |keys|
163
- keys.map! { |key| parse_key(key) }
167
+ keys.map!(&method(:parse_key))
164
168
  end
165
169
  end
166
170
  end
167
171
 
168
172
  def keyname(key)
169
- return 'SPACE' if (key == ' ' or key == 32)
173
+ return 'SPACE' if (key == ' ' or key == 32)
170
174
 
171
175
  name = ICurses.keyname(key)
172
176
  if name.start_with? 'KEY_'
@@ -9,8 +9,7 @@ require 'open-uri'
9
9
 
10
10
  module Ektoplayer
11
11
  class BrowsePage
12
- ALBUM_KEYS = %w(url title artist date category styles cover_url description
13
- download_count released_by released_by_url posted_by posted_by_url
12
+ ALBUM_KEYS = %w(url title artist date styles cover_url description download_count
14
13
  archive_urls rating votes tracks).map(&:to_sym).freeze
15
14
 
16
15
  TRACK_KEYS = %w(url album_url number title remix artist bpm).map(&:to_sym).freeze
@@ -21,7 +20,7 @@ module Ektoplayer
21
20
  BrowsePage.new(src)
22
21
  end
23
22
 
24
- def styles; @@styles or [] end
23
+ def styles; @@styles or [] end
25
24
  def first_page_url; @page_urls[0] end
26
25
  def last_page_url; @page_urls[-1] end
27
26
  def current_page_url; @page_urls[@current_page_index] end
@@ -40,24 +39,23 @@ module Ektoplayer
40
39
 
41
40
  @page_urls = []
42
41
  doc.css('.wp-pagenavi option').each_with_index do |option, i|
43
- @current_page_index = i if option[:selected]
44
- @page_urls << option[:value]
42
+ @current_page_index = i if option['selected']
43
+ @page_urls << option['value']
45
44
  end
46
45
 
47
46
  @@styles ||= begin
48
47
  doc.xpath('//a[contains(@href, "http") and contains(@href, "/style/")]').map do |a|
49
- [ a.text, a[:href] ]
48
+ [ a.text, File.basename(a['href']) ]
50
49
  end.to_h
51
50
  end
52
51
 
53
52
  doc.xpath('//div[starts-with(@id, "post-")]').each do |post|
54
53
  album = { tracks: [] }
55
54
  album[:date] = Date.parse(post.at_css('.d').text).iso8601 rescue nil
56
- album[:category] = post.at_css('.c a').text rescue nil
57
55
 
58
56
  album[:styles] = []
59
57
  post.css('.style a').map do |a|
60
- @@styles[a.text] = a[:href]
58
+ @@styles[a.text] = File.basename(a['href'])
61
59
  album[:styles] << a.text
62
60
  end
63
61
 
@@ -65,7 +63,7 @@ module Ektoplayer
65
63
  to_html.sub(/^<p>/, '').sub(/<\/p>$/, '') rescue ''
66
64
 
67
65
  begin album[:cover_url] = File.basename(
68
- URI.parse(post.at_css('.cover')[:src]).path
66
+ URI.parse(post.at_css('.cover')['src']).path
69
67
  )
70
68
  rescue
71
69
  end
@@ -74,23 +72,11 @@ module Ektoplayer
74
72
 
75
73
  post.css('h1 a').each do |a|
76
74
  album[:title] = a.text
77
- album[:url] = File.basename(URI.parse(a[:href]).path)
75
+ album[:url] = File.basename(URI.parse(a['href']).path)
78
76
  end
79
77
 
80
- post.xpath('.//a[@rel="tag"]').each do |a|
81
- album[:released_by] = a.text
82
- album[:released_by_url] = File.basename(URI.parse(a[:href]).path)
83
- # todo
84
- end
85
-
86
- post.xpath('.//a[@rel="author external"]').each do |a|
87
- album[:posted_by] = a.text
88
- album[:posted_by_url] = File.basename(URI.parse(a[:href]).path)
89
- # todo
90
- end
91
-
92
78
  album[:archive_urls] = post.css('.dll a').map do |a|
93
- [ a.text.split[0] , a[:href] ]
79
+ [ a.text.split[0] , File.basename(a['href']) ]
94
80
  end.to_h
95
81
 
96
82
  begin
@@ -102,8 +88,9 @@ module Ektoplayer
102
88
  end
103
89
 
104
90
  begin
105
- base64_tracklist = post.at_css(:script).text.scan(/soundFile:"(.*)"/)[0][0]
91
+ base64_tracklist = post.at_css('script').text.scan(/soundFile:"(.*)"/)[0][0]
106
92
  tracklist_urls = Base64.decode64(base64_tracklist).split(?,)
93
+ tracklist_urls.map! { |url| File.basename(url) }
107
94
  rescue
108
95
  # Sometimes there are no tracks:
109
96
  # http://www.ektoplazm.com/free-music/dj-basilisk-the-colours-of-ektoplazm
@@ -112,8 +99,8 @@ module Ektoplayer
112
99
 
113
100
  post.css('.tl').each do |album_track_list|
114
101
  track = nil
115
- album_track_list.css(:span).each do |ti|
116
- case ti[:class]
102
+ album_track_list.css('span').each do |ti|
103
+ case ti['class']
117
104
  when ?n
118
105
  album[:tracks] << track if track and track[:url]
119
106
  track = { url: tracklist_urls.shift }
@@ -141,7 +128,7 @@ module Ektoplayer
141
128
  @albums << album
142
129
  end
143
130
 
144
- Application.log(self, "completed; #{src} #{@albums.size} albums found")
131
+ Application.log(self, "#{src} #{@albums.size} albums found")
145
132
  rescue
146
133
  Application.log(self, src, $!)
147
134
  end
@@ -1,63 +1,9 @@
1
1
  require 'thread'
2
2
  require 'open3'
3
3
 
4
- class ConditionSignals
5
- def initialize
6
- @mutex, @cond = Mutex.new, ConditionVariable.new
7
- @curr_signal = nil
8
- @signal_hooks = {}
9
-
10
- Thread.new do
11
- @mutex.synchronize do
12
- loop do
13
- @cond.wait(@mutex)
14
-
15
- if @signal_hooks.key? @curr_signal
16
- @signal_hooks[@curr_signal].()
17
- end
18
- end
19
- end
20
- end
21
- end
22
-
23
- def wait(name, timeout=nil)
24
- @mutex.synchronize do
25
- loop do
26
- @cond.wait(@mutex, timeout)
27
- return if @curr_signal == name
28
- end
29
- end
30
- end
31
-
32
- def signal(name)
33
- @curr_signal = name
34
- @cond.broadcast
35
- end
36
-
37
- def on(name, &block)
38
- @signal_hooks[name] = block
39
- end
40
- end
41
-
42
4
  class Dir
43
5
  def Dir.size(path)
44
- Dir.glob(File.join(path, '**', ?*)).map { |f| File.size(f) }.sum
45
- end
46
- end
47
-
48
- class String
49
- def chunks(n)
50
- return [self] if n < 1
51
-
52
- if (chunk_size = self.size / n) < 1
53
- return [self]
54
- end
55
-
56
- (n - 1).times.map do |i|
57
- self.slice((chunk_size * i)..(chunk_size * (i + 1) - 1))
58
- end + [
59
- self.slice((chunk_size * (n-1))..-1)
60
- ]
6
+ Dir.glob(File.join(path, '**', ?*)).map(&File.method(:size)).sum
61
7
  end
62
8
  end
63
9
 
@@ -81,28 +27,27 @@ module Common
81
27
  end
82
28
 
83
29
  def self.extract_zip(zip_file, dest)
30
+ absolute_path = File.absolute_path(zip_file)
31
+ # try 'unzip'
32
+ out, err, status = Open3.capture3('unzip', absolute_path, chdir: dest)
33
+ fail err unless status.exitstatus == 0
34
+ rescue Errno::ENOENT
35
+ # try '7zip'
36
+ out, err, status = Open3.capture3('7z', ?x, absolute_path, chdir: dest)
37
+ fail err unless status.exitstatus == 0
38
+ rescue Errno::ENOENT
84
39
  # try RubyZip gem
85
40
  require 'zip'
86
41
 
87
- Zip::File.open(zip_file) do |zip_obj|
42
+ Zip::File.open(absolute_path) do |zip_obj|
88
43
  zip_obj.each do |f|
89
44
  f.extract(File.join(dest, f.name))
90
45
  end
91
46
  end
92
47
  rescue LoadError
93
- # try 'unzip'
94
- out, err, status = Open3.capture3('unzip', ?x, zip_file, chdir: dest)
95
- fail err unless status.exitcode == 0
96
- rescue Error::ENOENT
97
- # try '7zip'
98
- out, err, status = Open3.capture3('7z', ?x, zip_file, chdir: dest)
99
- fail err unless status.exitcode == 0
100
- rescue Error::ENOENT
101
48
  fail 'neither RubzZip gem nor /bin/unzip or /bin/7z found'
102
49
  rescue
103
- # something failed ...
104
- Ektoplayer::Application.log(self, "error extracting zip", zip, dest, $!)
105
- fail $!
50
+ Ektoplayer::Application.log(self, "error extracting zip", zip_file, dest, $!)
106
51
  end
107
52
 
108
53
  def self.with_hash_zip(keys, values)
@@ -1,9 +1,7 @@
1
1
  unless Array.respond_to? :sum
2
2
  class Array
3
- def sum
4
- result = 0
5
- self.each { |i| result += i }
6
- result
3
+ def sum
4
+ reduce(:+)
7
5
  end
8
6
  end
9
7
  end
@@ -11,13 +9,9 @@ end
11
9
  unless Integer.respond_to? :clamp
12
10
  class Integer
13
11
  def clamp(min, max)
14
- if self < min
15
- min
16
- elsif self > max
17
- max
18
- else
19
- self
20
- end
12
+ return min if self < min
13
+ return max if self > max
14
+ self
21
15
  end
22
16
  end
23
17
  end