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
@@ -1,15 +1,20 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'open3'
|
3
3
|
require 'scanf'
|
4
|
+
require 'time'
|
4
5
|
|
5
6
|
require_relative '../events'
|
6
7
|
|
7
|
-
|
8
|
+
unless system('mpg123 --version >/dev/null 2>/dev/null')
|
9
|
+
fail LoadError, 'MpgWrapperPlayer: /bin/mpg123 not found'
|
10
|
+
end
|
8
11
|
|
9
12
|
class MpgWrapperPlayer
|
10
13
|
attr_reader :events, :file
|
11
14
|
|
12
15
|
STATE_STOPPED, STATE_PAUSED, STATE_PLAYING = 0, 1, 2
|
16
|
+
CMD_FORMAT = 'FORMAT'.freeze
|
17
|
+
CMD_SAMPLE = 'SAMPLE'.freeze
|
13
18
|
|
14
19
|
def initialize
|
15
20
|
@events = Events.new(:play, :pause, :stop, :position_change)
|
@@ -18,21 +23,34 @@ class MpgWrapperPlayer
|
|
18
23
|
@state = 0
|
19
24
|
@file = ''
|
20
25
|
|
21
|
-
@
|
22
|
-
|
26
|
+
@polling_interval = 0.9
|
27
|
+
|
28
|
+
@seconds_played = @seconds_total = 0
|
29
|
+
@track_completed = nil
|
23
30
|
end
|
24
31
|
|
32
|
+
def can_http?; true; end
|
33
|
+
|
25
34
|
def play(file=nil)
|
26
35
|
start_mpg123_thread
|
36
|
+
@track_completed = :track_completed
|
27
37
|
@file = file if file
|
28
38
|
write("L #{@file}")
|
39
|
+
Thread.new { sleep 3; write(CMD_FORMAT) }
|
29
40
|
end
|
30
41
|
|
31
42
|
def pause; write(?P) if @state == STATE_PLAYING end
|
32
|
-
def
|
33
|
-
|
43
|
+
def toggle; write(?P) end
|
44
|
+
|
45
|
+
def stop
|
46
|
+
stop_polling_thread
|
47
|
+
@track_completed = nil
|
48
|
+
@seconds_played = @seconds_total = 0
|
49
|
+
@events.trigger(:position_change)
|
50
|
+
@events.trigger(:stop)
|
51
|
+
write(?Q) if @state != STATE_STOPPED
|
52
|
+
end
|
34
53
|
|
35
|
-
def level; 30 end
|
36
54
|
def paused?; @state == STATE_PAUSED end
|
37
55
|
def stopped?; @state == STATE_STOPPED end
|
38
56
|
def playing?; @state == STATE_PLAYING end
|
@@ -43,21 +61,70 @@ class MpgWrapperPlayer
|
|
43
61
|
return :stopped if stopped?
|
44
62
|
end
|
45
63
|
|
46
|
-
def position; @seconds_played
|
47
|
-
def length; @
|
48
|
-
def position_percent; Float(@seconds_played) / length end
|
64
|
+
def position; @seconds_played end
|
65
|
+
def length; @seconds_total end
|
49
66
|
|
50
|
-
def
|
67
|
+
def position_percent
|
68
|
+
@seconds_played.to_f / length rescue 0.0
|
69
|
+
end
|
70
|
+
|
71
|
+
def seek(seconds) write("J #{seconds}s") end
|
51
72
|
def rewind(seconds = 2) write("J -#{seconds}s") end
|
52
|
-
def forward(seconds = 2) write("J +#{seconds}s")
|
73
|
+
def forward(seconds = 2) write("J +#{seconds}s") end
|
53
74
|
alias :backward :rewind
|
54
75
|
|
55
76
|
private def write(string)
|
56
|
-
@lock.synchronize
|
57
|
-
@mpg123_in.write(string + ?\n)
|
58
|
-
end
|
77
|
+
@lock.synchronize { @mpg123_in.write(string + ?\n) }
|
59
78
|
rescue
|
60
|
-
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def use_polling(interval)
|
83
|
+
@polling_interval = interval
|
84
|
+
start_polling_thread
|
85
|
+
end
|
86
|
+
|
87
|
+
private def start_polling_thread
|
88
|
+
write('SILENCE')
|
89
|
+
@polling_thread ||= Thread.new do
|
90
|
+
loop do
|
91
|
+
sleep @polling_interval
|
92
|
+
write(CMD_SAMPLE)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private def stop_polling_thread
|
98
|
+
@polling_thread.kill if @polling_thread
|
99
|
+
@polling_thread = nil
|
100
|
+
end
|
101
|
+
|
102
|
+
define_method '@FORMAT' do |line|
|
103
|
+
@sample_rate, channels = line.scanf('%d %d')
|
104
|
+
end
|
105
|
+
|
106
|
+
define_method '@SAMPLE' do |line|
|
107
|
+
@sample_rate ||= 44100
|
108
|
+
samples_played, samples_total = line.scanf('%f %f')
|
109
|
+
@seconds_played = samples_played / @sample_rate rescue 0.0
|
110
|
+
@seconds_total = samples_total / @sample_rate rescue 0.0
|
111
|
+
@events.trigger(:position_change)
|
112
|
+
end
|
113
|
+
|
114
|
+
define_method '@F' do |line|
|
115
|
+
_, _, @seconds_played, seconds_remaining = line.scanf('%d %d %f %f')
|
116
|
+
@seconds_total = @seconds_played + seconds_remaining
|
117
|
+
@events.trigger(:position_change)
|
118
|
+
end
|
119
|
+
|
120
|
+
define_method '@P' do |line|
|
121
|
+
if (@state = line.to_i) == STATE_STOPPED
|
122
|
+
@events.trigger(:stop, @track_completed)
|
123
|
+
elsif @state == STATE_PAUSED
|
124
|
+
@events.trigger(:pause)
|
125
|
+
elsif @state == STATE_PLAYING
|
126
|
+
@events.trigger(:play)
|
127
|
+
end
|
61
128
|
end
|
62
129
|
|
63
130
|
private def start_mpg123_thread
|
@@ -65,43 +132,34 @@ class MpgWrapperPlayer
|
|
65
132
|
unless @mpg123_thread
|
66
133
|
Thread.new do
|
67
134
|
begin
|
68
|
-
@mpg123_in, @mpg123_out,
|
69
|
-
Open3.popen3('mpg123', '-o', 'jack,pulse,alsa,oss', '--fuzzy', '-R')
|
135
|
+
@mpg123_in, @mpg123_out, mpg123_err, @mpg123_thread =
|
136
|
+
Open3.popen3('mpg123', '-o', 'jack,pulse,alsa,oss', '--fuzzy', '-b', '1024', '-R')
|
70
137
|
|
71
138
|
while (line = @mpg123_out.readline)
|
72
|
-
|
73
|
-
|
74
|
-
@seconds_played, @seconds_remaining =
|
75
|
-
line.scanf('@F %d %d %f %f')
|
76
|
-
@events.trigger(:position_change)
|
77
|
-
elsif line[1] == ?P
|
78
|
-
if (@state = line[3].to_i) == STATE_STOPPED
|
79
|
-
if @seconds_remaining < 3
|
80
|
-
@events.trigger(:stop, :track_completed)
|
81
|
-
else
|
82
|
-
@events.trigger(:stop)
|
83
|
-
end
|
84
|
-
elsif @state == STATE_PAUSED
|
85
|
-
@events.trigger(:pause)
|
86
|
-
elsif @state == STATE_PLAYING
|
87
|
-
@events.trigger(:play)
|
88
|
-
end
|
89
|
-
end
|
139
|
+
cmd, line = line.split(' ', 2)
|
140
|
+
send(cmd, line) rescue nil
|
90
141
|
end
|
91
142
|
rescue
|
92
143
|
Ektoplayer::Application.log(self, $!)
|
93
144
|
ensure
|
94
|
-
|
95
|
-
|
96
|
-
|
145
|
+
begin msg = mpg123_err.read
|
146
|
+
rescue
|
147
|
+
msg = ''
|
148
|
+
end
|
149
|
+
|
150
|
+
Ektoplayer::Application.log(self, 'player closed:', msg)
|
151
|
+
@mpg123_thread.kill if @mpg123_thread
|
152
|
+
(@mpg123_in.close rescue nil) if @mpg123_in
|
153
|
+
(@mpg123_out.close rescue nil) if @mpg123_out
|
97
154
|
@mpg123_thread = nil
|
98
|
-
|
99
|
-
@mpg123_out.close
|
155
|
+
stop_polling_thread
|
100
156
|
end
|
101
157
|
end
|
102
158
|
|
103
159
|
sleep 0.1 while not @mpg123_thread
|
104
160
|
end
|
105
161
|
end
|
162
|
+
|
163
|
+
start_polling_thread if @polling_interval > 0
|
106
164
|
end
|
107
165
|
end
|
data/lib/ektoplayer/theme.rb
CHANGED
@@ -5,64 +5,74 @@ module Ektoplayer
|
|
5
5
|
attr_reader :current, :theme
|
6
6
|
|
7
7
|
def initialize
|
8
|
-
@current = 0
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
8
|
+
@theme, @current = {}, 0
|
9
|
+
|
10
|
+
@theme[0] = {
|
11
|
+
:default => [-1, -1 ].freeze,
|
12
|
+
:'url' => [:default, :default, :underline].freeze,
|
13
|
+
:'tabbar.selected' => [:default, :default, :bold ].freeze
|
14
|
+
}
|
15
|
+
@theme[8] = {
|
16
|
+
:default => [-1, -1 ].freeze,
|
17
|
+
:'url' => [:magenta, :default, :underline].freeze,
|
18
|
+
|
19
|
+
:'info.head' => [:blue, :default, :bold ].freeze,
|
20
|
+
:'info.tag' => [:blue ].freeze,
|
21
|
+
:'info.value' => [:magenta ].freeze,
|
22
|
+
:'info.description' => [:blue ].freeze,
|
23
|
+
:'info.download.file' => [:blue ].freeze,
|
24
|
+
:'info.download.percent' => [:magenta ].freeze,
|
25
|
+
:'info.download.error' => [:red ].freeze,
|
26
|
+
|
27
|
+
:'progressbar.progress' => [:blue ].freeze,
|
28
|
+
:'progressbar.rest' => [:black ].freeze,
|
29
|
+
|
30
|
+
:'tabbar.selected' => [:blue ].freeze,
|
31
|
+
:'tabbar.unselected' => [:white ].freeze,
|
32
|
+
|
33
|
+
:'list.item_even' => [:blue ].freeze,
|
34
|
+
:'list.item_odd' => [:blue ].freeze,
|
35
|
+
:'list.item_selection' => [:magenta ].freeze,
|
36
|
+
|
37
|
+
:'playinginfo.position' => [:magenta ].freeze,
|
38
|
+
:'playinginfo.state' => [:cyan ].freeze,
|
39
|
+
|
40
|
+
:'help.widget_name' => [:blue, :default, :bold ].freeze,
|
41
|
+
:'help.key_name' => [:blue ].freeze,
|
42
|
+
:'help.command_name' => [:magenta ].freeze,
|
43
|
+
:'help.command_desc' => [:yellow ].freeze
|
44
|
+
}
|
45
|
+
@theme[256] = {
|
46
|
+
:'default' => [:white, 233 ].freeze,
|
47
|
+
:'url' => [97, :default, :underline ].freeze,
|
48
|
+
|
49
|
+
:'info.head' => [32, :default, :bold ].freeze,
|
50
|
+
:'info.tag' => [74 ].freeze,
|
51
|
+
:'info.value' => [67 ].freeze,
|
52
|
+
:'info.description' => [67 ].freeze,
|
53
|
+
:'info.download.file' => [75 ].freeze,
|
54
|
+
:'info.download.percent' => [68 ].freeze,
|
55
|
+
:'info.download.error' => [:red ].freeze,
|
56
|
+
|
57
|
+
:'progressbar.progress' => [23 ].freeze,
|
58
|
+
:'progressbar.rest' => [:black ].freeze,
|
59
|
+
|
60
|
+
:'tabbar.selected' => [75 ].freeze,
|
61
|
+
:'tabbar.unselected' => [250 ].freeze,
|
62
|
+
|
63
|
+
:'list.item_even' => [26 ].freeze,
|
64
|
+
:'list.item_odd' => [25 ].freeze,
|
65
|
+
:'list.item_selection' => [97 ].freeze,
|
66
|
+
|
67
|
+
:'playinginfo.position' => [97 ].freeze,
|
68
|
+
:'playinginfo.state' => [37 ].freeze,
|
69
|
+
|
70
|
+
:'help.widget_name' => [33 ].freeze,
|
71
|
+
:'help.key_name' => [75 ].freeze,
|
72
|
+
:'help.command_name' => [68 ].freeze,
|
73
|
+
:'help.command_desc' => [29 ].freeze
|
74
|
+
}
|
75
|
+
@theme.freeze
|
66
76
|
end
|
67
77
|
|
68
78
|
def color(name, *defs, theme: 8)
|
@@ -81,16 +91,21 @@ module Ektoplayer
|
|
81
91
|
@current = colors
|
82
92
|
|
83
93
|
UI::Colors.reset
|
94
|
+
UI::Colors.default_fg(@theme[@current][:default][0])
|
95
|
+
UI::Colors.default_bg(@theme[@current][:default][1])
|
96
|
+
|
84
97
|
@theme.values.map(&:keys).flatten.each do |name|
|
98
|
+
next if name == :default
|
99
|
+
|
85
100
|
defs ||= @theme[256][name] if @current == 256
|
86
101
|
defs ||= @theme[8][name] if @current >= 8
|
87
102
|
defs ||= @theme[0][name]
|
88
103
|
|
89
|
-
unless defs
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
104
|
+
#unless defs
|
105
|
+
# defs ||= @theme[256][:default] if @current == 256
|
106
|
+
# defs ||= @theme[8][:default] if @current >= 8
|
107
|
+
# defs ||= @theme[0][:default]
|
108
|
+
#end
|
94
109
|
|
95
110
|
UI::Colors.set(name, *defs)
|
96
111
|
end
|
@@ -1,10 +1,16 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'net/https'
|
3
2
|
require 'uri'
|
4
3
|
|
5
|
-
require_relative 'events'
|
6
4
|
require_relative 'common'
|
7
5
|
|
6
|
+
begin
|
7
|
+
require_relative 'download/externaldownload'
|
8
|
+
DownloadThread = ExternalDownload
|
9
|
+
rescue LoadError
|
10
|
+
require_relative 'download/rubydownload'
|
11
|
+
DownloadThread = RubyDownload
|
12
|
+
end
|
13
|
+
|
8
14
|
module Ektoplayer
|
9
15
|
class Trackloader
|
10
16
|
attr_reader :downloads
|
@@ -21,7 +27,7 @@ module Ektoplayer
|
|
21
27
|
@database.get_archives(url).select {|_|_['archive_type'] == 'MP3'}[0]
|
22
28
|
)
|
23
29
|
|
24
|
-
r['archive_filename'] = URI.unescape(
|
30
|
+
r['archive_filename'] = URI.unescape(r['archive_url'])
|
25
31
|
r['archive_basename'] = File.basename(r['archive_filename'], '.zip')
|
26
32
|
r['album_path'] = File.join(Config[:archive_dir], r['archive_basename'])
|
27
33
|
r
|
@@ -34,7 +40,9 @@ module Ektoplayer
|
|
34
40
|
archive_file = File.join(Config[:download_dir], track_info['archive_filename'])
|
35
41
|
return if File.exists? archive_file
|
36
42
|
|
37
|
-
|
43
|
+
archive_url = Application.archive_url(track_info['archive_url'])
|
44
|
+
Application.log(self, 'starting download:', archive_url)
|
45
|
+
dl = DownloadThread.new(archive_url, archive_file)
|
38
46
|
|
39
47
|
if Config[:auto_extract_to_archive_dir]
|
40
48
|
dl.events.on(:completed) do
|
@@ -50,8 +58,8 @@ module Ektoplayer
|
|
50
58
|
end
|
51
59
|
|
52
60
|
dl.events.on(:failed) do |reason|
|
53
|
-
Application.log(self, dl.
|
54
|
-
FileUtils::rm(dl.
|
61
|
+
Application.log(self, dl.filename, dl.url, reason)
|
62
|
+
FileUtils::rm(dl.filename) rescue nil
|
55
63
|
end
|
56
64
|
|
57
65
|
@downloads << dl.start!
|
@@ -59,7 +67,7 @@ module Ektoplayer
|
|
59
67
|
Application.log(self, $!)
|
60
68
|
end
|
61
69
|
|
62
|
-
def get_track_file(url, reload: false)
|
70
|
+
def get_track_file(url, reload: false, http_okay: false)
|
63
71
|
begin
|
64
72
|
track_info = get_track_infos(url)
|
65
73
|
album_files = Dir.glob(File.join(track_info['album_path'], '*.mp3'))
|
@@ -69,31 +77,33 @@ module Ektoplayer
|
|
69
77
|
Application.log(self, 'could not load track from archive_dir:', $!)
|
70
78
|
end
|
71
79
|
|
72
|
-
|
80
|
+
real_url = Application.track_url(url)
|
81
|
+
url_obj = URI.parse(real_url)
|
73
82
|
basename = File.basename(url_obj.path)
|
74
83
|
cache_file = File.join(Config[:cache_dir], basename)
|
75
|
-
temp_file = File.join(Config[:temp_dir], basename)
|
84
|
+
temp_file = File.join(Config[:temp_dir], '~ekto-' + basename)
|
76
85
|
|
77
86
|
(File.delete(cache_file) rescue nil) if reload
|
78
87
|
(File.delete(temp_file) rescue nil) if reload
|
79
88
|
|
80
89
|
return cache_file if File.file?(cache_file)
|
81
90
|
return temp_file if File.file?(temp_file)
|
91
|
+
return real_url if http_okay
|
82
92
|
|
83
|
-
|
93
|
+
Application.log(self, 'starting download:', real_url)
|
94
|
+
dl = DownloadThread.new(real_url, temp_file)
|
84
95
|
|
85
96
|
if Config[:use_cache]
|
86
97
|
dl.events.on(:completed) do
|
87
|
-
|
88
|
-
rescue
|
98
|
+
FileUtils::mv(temp_file, cache_file) rescue (
|
89
99
|
Application.log(self, 'mv failed', temp_file, cache_file, $!)
|
90
|
-
|
100
|
+
)
|
91
101
|
end
|
92
102
|
end
|
93
103
|
|
94
104
|
dl.events.on(:failed) do |reason|
|
95
|
-
Application.log(self, dl.
|
96
|
-
FileUtils::rm(dl.
|
105
|
+
Application.log(self, dl.filename, dl.url, reason)
|
106
|
+
FileUtils::rm(dl.filename) rescue nil
|
97
107
|
end
|
98
108
|
|
99
109
|
@downloads << dl.start!
|
@@ -103,63 +113,4 @@ module Ektoplayer
|
|
103
113
|
Application.log(self, $!)
|
104
114
|
end
|
105
115
|
end
|
106
|
-
|
107
|
-
class DownloadThread
|
108
|
-
attr_reader :events, :url, :progress, :total, :file, :filename, :error
|
109
|
-
|
110
|
-
def initialize(url, filename)
|
111
|
-
@events = Events.new(:completed, :failed, :progress)
|
112
|
-
@url = URI.parse(url)
|
113
|
-
@filename = filename
|
114
|
-
@file = File.open(filename, ?w)
|
115
|
-
@progress = 0
|
116
|
-
@error = nil
|
117
|
-
@tries = 3
|
118
|
-
end
|
119
|
-
|
120
|
-
def start!
|
121
|
-
Application.log(self, 'starting download:', @url)
|
122
|
-
|
123
|
-
Thread.new do
|
124
|
-
begin
|
125
|
-
loop do
|
126
|
-
begin
|
127
|
-
http = Net::HTTP.new(@url.host, @url.port)
|
128
|
-
@file.rewind
|
129
|
-
@progress, @total = 0, nil
|
130
|
-
|
131
|
-
http.request(Net::HTTP::Get.new(@url.request_uri)) do |res|
|
132
|
-
fail res.body unless res.code == '200'
|
133
|
-
|
134
|
-
@total = res.header['Content-Length'].to_i
|
135
|
-
|
136
|
-
res.read_body do |chunk|
|
137
|
-
@progress += chunk.size
|
138
|
-
@events.trigger(:progress, @progress)
|
139
|
-
@file << chunk
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
fail 'filesize mismatch' if @progress != @total
|
144
|
-
@file.flush
|
145
|
-
@events.trigger(:completed)
|
146
|
-
break
|
147
|
-
rescue
|
148
|
-
if (@tries -= 1) < 1
|
149
|
-
@events.trigger(:failed, (@error = $!))
|
150
|
-
break
|
151
|
-
end
|
152
|
-
Application.log(self, 'retrying failed DL', $!)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
ensure
|
156
|
-
@file.close
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
sleep 0.1 while @total.nil?
|
161
|
-
sleep 0.2
|
162
|
-
self
|
163
|
-
end
|
164
|
-
end
|
165
116
|
end
|
data/lib/ektoplayer/ui/colors.rb
CHANGED
@@ -11,6 +11,7 @@ module UI
|
|
11
11
|
|
12
12
|
def ColorFader._fade(colors, size)
|
13
13
|
return [] if size < 1
|
14
|
+
return [colors[0]] * size if colors.size == 1
|
14
15
|
|
15
16
|
part_len = (size / colors.size)
|
16
17
|
diff = size - part_len * colors.size
|
@@ -22,13 +23,13 @@ module UI
|
|
22
23
|
|
23
24
|
def ColorFader._fade2(colors, size)
|
24
25
|
half = size / 2
|
25
|
-
ColorFader._fade(colors, half) + ColorFader._fade(colors, size - half)
|
26
|
+
ColorFader._fade(colors, half) + ColorFader._fade(colors.reverse, size - half)
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
30
|
class Colors
|
30
31
|
COLORS = {
|
31
|
-
none:
|
32
|
+
none: -1,
|
32
33
|
white: ICurses::COLOR_WHITE,
|
33
34
|
black: ICurses::COLOR_BLACK,
|
34
35
|
red: ICurses::COLOR_RED,
|
@@ -48,7 +49,10 @@ module UI
|
|
48
49
|
bold: ICurses::A_BOLD, standout: ICurses::A_STANDOUT,
|
49
50
|
blink: ICurses::A_BLINK, underline: ICurses::A_UNDERLINE
|
50
51
|
}
|
51
|
-
ATTRIBUTES.default_proc = proc
|
52
|
+
ATTRIBUTES.default_proc = proc do |h,key|
|
53
|
+
fail "Unknown attribute #{key}" unless key.is_a?Integer
|
54
|
+
key
|
55
|
+
end
|
52
56
|
ATTRIBUTES.freeze
|
53
57
|
|
54
58
|
def self.start
|
@@ -57,11 +61,35 @@ module UI
|
|
57
61
|
@@volatile ||= {}
|
58
62
|
@@volatile_ids ||= {}
|
59
63
|
@@cached ||= Hash.new { |h,k| h[k] = {} }
|
64
|
+
@@default_fg = @@default_bg = -1
|
60
65
|
end
|
61
66
|
def self.reset; self.start end
|
62
67
|
|
68
|
+
def self.default_fg(color)
|
69
|
+
@@default_fg = COLORS[color]
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.default_bg(color)
|
73
|
+
@@default_bg = COLORS[color]
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.default_colors(fg = -1, bg = -1)
|
77
|
+
self.default_fg(fg)
|
78
|
+
self.default_bg(bg)
|
79
|
+
end
|
80
|
+
|
63
81
|
def self.init_pair_cached(fg, bg)
|
64
|
-
fg
|
82
|
+
if !fg or fg == :default
|
83
|
+
fg = @@default_fg
|
84
|
+
else
|
85
|
+
fg = COLORS[fg]
|
86
|
+
end
|
87
|
+
|
88
|
+
if !bg or bg == :default
|
89
|
+
bg = @@default_bg
|
90
|
+
else
|
91
|
+
bg = COLORS[bg]
|
92
|
+
end
|
65
93
|
|
66
94
|
unless id = @@cached[fg][bg]
|
67
95
|
id = @@cached[fg][bg] = @@id
|
@@ -81,7 +109,7 @@ module UI
|
|
81
109
|
def self.[](name) @@aliases[name] || 0 end
|
82
110
|
def self.get(name) @@aliases[name] || 0 end
|
83
111
|
|
84
|
-
def self.set(name, fg, bg =
|
112
|
+
def self.set(name, fg, bg = nil, *attrs)
|
85
113
|
@@aliases[name] = self.init_pair_cached(fg, bg)
|
86
114
|
attrs.each { |attr| @@aliases[name] |= ATTRIBUTES[attr] }
|
87
115
|
@@aliases[name]
|
@@ -73,7 +73,7 @@ module UI
|
|
73
73
|
|
74
74
|
def draw; visible_widgets.each(&:draw) end
|
75
75
|
def refresh; visible_widgets.each(&:refresh) end
|
76
|
-
def layout; @widgets.each(&:layout)
|
76
|
+
def layout; @widgets.each(&:layout) end
|
77
77
|
|
78
78
|
def on_key_press(key)
|
79
79
|
@selected.key_press(key) if @selected
|