ektoplayer 0.1.12 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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