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.
- checksums.yaml +4 -4
- data/lib/ektoplayer/application.rb +49 -19
- data/lib/ektoplayer/bindings.rb +91 -87
- data/lib/ektoplayer/browsepage.rb +14 -27
- data/lib/ektoplayer/common.rb +12 -67
- data/lib/ektoplayer/compat.rb +5 -11
- data/lib/ektoplayer/config.rb +52 -17
- data/lib/ektoplayer/controllers/browser.rb +10 -5
- data/lib/ektoplayer/database.rb +7 -20
- data/lib/ektoplayer/download/externaldownload.rb +65 -0
- data/lib/ektoplayer/download/rubydownload.rb +69 -0
- data/lib/ektoplayer/icurses/curses.rb +18 -2
- data/lib/ektoplayer/icurses/{ffi_ncurses.rb → ffi-ncurses.rb} +1 -0
- data/lib/ektoplayer/icurses/ncurses.rb +10 -0
- data/lib/ektoplayer/icurses.rb +13 -5
- data/lib/ektoplayer/models/browser.rb +11 -11
- data/lib/ektoplayer/models/player.rb +4 -5
- data/lib/ektoplayer/operations/browser.rb +9 -1
- data/lib/ektoplayer/operations/playlist.rb +1 -1
- data/lib/ektoplayer/players/mpg_wrapper_player.rb +98 -40
- data/lib/ektoplayer/theme.rb +78 -63
- data/lib/ektoplayer/trackloader.rb +25 -74
- data/lib/ektoplayer/ui/colors.rb +33 -5
- data/lib/ektoplayer/ui/widgets/container.rb +1 -1
- data/lib/ektoplayer/ui/widgets/listwidget.rb +35 -34
- data/lib/ektoplayer/ui/widgets.rb +19 -0
- data/lib/ektoplayer/ui.rb +22 -23
- data/lib/ektoplayer/updater.rb +3 -4
- data/lib/ektoplayer/views/browser.rb +7 -2
- data/lib/ektoplayer/views/help.rb +5 -2
- data/lib/ektoplayer/views/info.rb +22 -27
- data/lib/ektoplayer/views/playinginfo.rb +20 -19
- data/lib/ektoplayer/views/playlist.rb +8 -3
- data/lib/ektoplayer/views/progressbar.rb +26 -33
- data/lib/ektoplayer/views/splash.rb +14 -22
- data/lib/ektoplayer/views/trackrenderer.rb +14 -10
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1567475105c5b1d0e3a099a4324ca19cdd67efe8
|
4
|
+
data.tar.gz: e48caa107e5f934866a720023a5cb86fbb9153a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
-
|
17
|
-
|
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
|
-
|
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, '
|
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
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
-
|
138
|
-
|
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
|
data/lib/ektoplayer/bindings.rb
CHANGED
@@ -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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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!
|
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'
|
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
|
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;
|
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[
|
44
|
-
@page_urls << option[
|
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[
|
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[
|
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')[
|
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[
|
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[
|
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(
|
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(
|
116
|
-
case ti[
|
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, "
|
131
|
+
Application.log(self, "#{src} #{@albums.size} albums found")
|
145
132
|
rescue
|
146
133
|
Application.log(self, src, $!)
|
147
134
|
end
|
data/lib/ektoplayer/common.rb
CHANGED
@@ -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
|
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(
|
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
|
-
|
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)
|
data/lib/ektoplayer/compat.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
unless Array.respond_to? :sum
|
2
2
|
class Array
|
3
|
-
def sum
|
4
|
-
|
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
|
-
|
16
|
-
|
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
|