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
@@ -24,12 +24,14 @@ module Ektoplayer
24
24
 
25
25
  def self.parse_simple_format(format)
26
26
  self._parse_markup(format).map do |fmt|
27
- attrs = []
28
- attrs << :bold if fmt[:bold]
29
- attrs << :blink if fmt[:blink]
30
- attrs << :standout if fmt[:standout]
31
- attrs << :underline if fmt[:underline]
32
- fmt[:curses_attrs] = [ (fmt[:fg] and fmt[:fg].to_sym), (fmt[:bg] and fmt[:bg].to_sym), *attrs]
27
+ fmt[:curses_attrs] = [
28
+ (fmt[:fg] and Integer(fmt[:fg]) rescue fmt[:fg].to_sym),
29
+ (fmt[:bg] and Integer(fmt[:bg]) rescue fmt[:bg].to_sym),
30
+ ]
31
+ fmt[:curses_attrs] << :bold if fmt[:bold]
32
+ fmt[:curses_attrs] << :blink if fmt[:blink]
33
+ fmt[:curses_attrs] << :standout if fmt[:standout]
34
+ fmt[:curses_attrs] << :underline if fmt[:underline]
33
35
  fmt
34
36
  end
35
37
  end
@@ -56,14 +58,28 @@ module Ektoplayer
56
58
  <album rel="30" fg="red" />
57
59
  <title rel="33" fg="yellow" />
58
60
  <styles rel="20" fg="cyan" />
59
- <bpm size="4" fg="green" justify="right" />}.squeeze(' ').freeze
61
+ <bpm size="3" fg="green" justify="right" />}.squeeze(' ').freeze
60
62
 
61
- DEFAULT_PLAYINGINFO_FORMAT1 =
63
+ DEFAULT_PLAYINGINFO_FORMAT_TOP =
62
64
  '<text fg="black">&lt;&lt; </text><title bold="on" fg="yellow" /><text fg="black"> &gt;&gt;</text>'.freeze
63
65
 
64
- DEFAULT_PLAYINGINFO_FORMAT2 =
66
+ DEFAULT_PLAYINGINFO_FORMAT_BOTTOM =
65
67
  '<artist bold="on" fg="blue" /><text> - </text><album bold="on" fg="red" /><text> (</text><year fg="cyan" /><text>)</text>'.freeze
66
68
 
69
+ DEFAULT_PLAYLIST_FORMAT_256 = %{
70
+ <number size="3" fg="97" />
71
+ <artist rel="25" fg="24" />
72
+ <album rel="30" fg="160" />
73
+ <title rel="33" fg="178" />
74
+ <styles rel="20" fg="37" />
75
+ <bpm size="3" fg="28" justify="right" />}.squeeze(' ').freeze
76
+
77
+ DEFAULT_PLAYINGINFO_FORMAT_TOP_256 =
78
+ '<text fg="236">&lt;&lt; </text><title bold="on" fg="178" /><text fg="236"> &gt;&gt;</text>'.freeze
79
+
80
+ DEFAULT_PLAYINGINFO_FORMAT_BOTTOM_256 =
81
+ '<artist bold="on" fg="24" /><text> - </text><album bold="on" fg="160" /><text> (</text><year fg="37" /><text>)</text>'.freeze
82
+
67
83
  def register(key, description, default, method=nil)
68
84
  # parameter `description` is used by tools/mkconfig.rb, but not here
69
85
 
@@ -118,7 +134,7 @@ module Ektoplayer
118
134
 
119
135
  reg :playlist_load_newest,
120
136
  %{How many tracks from database should be added to
121
- the playlist on application start.}, 300
137
+ the playlist on application start.}, 1000
122
138
 
123
139
  reg :use_cache,
124
140
  %{Enable/disable local mp3 cache.
@@ -143,12 +159,20 @@ module Ektoplayer
143
159
  'Number of donwload threads during database update',
144
160
  20, lambda { |v| fail if Integer(v) < 1; Integer(v) }
145
161
 
146
- reg 'browser.format', 'Format of browser columns',
162
+ # - Playlist
163
+ reg 'playlist.format', 'Format of playlist columns',
147
164
  DEFAULT_PLAYLIST_FORMAT, ColumnFormat.method(:parse_column_format)
148
165
 
149
- reg 'playlist.format', 'Format of playlist columns',
166
+ reg 'playlist.format_256', 'Format of playlist columns (256 colors)',
167
+ DEFAULT_PLAYLIST_FORMAT_256, ColumnFormat.method(:parse_column_format)
168
+
169
+ # - Browser
170
+ reg 'browser.format', 'Format of browser columns',
150
171
  DEFAULT_PLAYLIST_FORMAT, ColumnFormat.method(:parse_column_format)
151
172
 
173
+ reg 'browser.format_256', 'Format of browser columns (256 colors)',
174
+ DEFAULT_PLAYLIST_FORMAT_256, ColumnFormat.method(:parse_column_format)
175
+
152
176
  # - Progressbar
153
177
  reg 'progressbar.display',
154
178
  'Enable/disable progressbar', true
@@ -163,12 +187,24 @@ module Ektoplayer
163
187
  reg 'playinginfo.display',
164
188
  'Enable/display playinginfo', true
165
189
 
166
- reg 'playinginfo.format1',
167
- 'Format of first line in playinginfo', DEFAULT_PLAYINGINFO_FORMAT1,
190
+ reg 'playinginfo.format_top',
191
+ 'Format of first line in playinginfo',
192
+ DEFAULT_PLAYINGINFO_FORMAT_TOP,
193
+ ColumnFormat.method(:parse_simple_format)
194
+
195
+ reg 'playinginfo.format_top_256',
196
+ 'Format of first line in playinginfo (256 colors)',
197
+ DEFAULT_PLAYINGINFO_FORMAT_TOP_256,
198
+ ColumnFormat.method(:parse_simple_format)
199
+
200
+ reg 'playinginfo.format_bottom',
201
+ 'Format of second line in playinginfo',
202
+ DEFAULT_PLAYINGINFO_FORMAT_BOTTOM,
168
203
  ColumnFormat.method(:parse_simple_format)
169
204
 
170
- reg 'playinginfo.format2',
171
- 'Format of second line in playinginfo', DEFAULT_PLAYINGINFO_FORMAT2,
205
+ reg 'playinginfo.format_bottom_256',
206
+ 'Format of second line in playinginfo (256 colors)',
207
+ DEFAULT_PLAYINGINFO_FORMAT_BOTTOM_256,
172
208
  ColumnFormat.method(:parse_simple_format)
173
209
 
174
210
  # - Tabbar
@@ -232,7 +268,6 @@ module Ektoplayer
232
268
  begin
233
269
  cb = callbacks[command.to_sym]
234
270
  cb.call(*args)
235
- #fail "Command '#{command}' given args: #{args.size}, wanted #{cb.arity}" if args.size != cb.arity
236
271
  rescue
237
272
  fail "#{file}:#{$.}: #{command}: #{$!}"
238
273
  end
@@ -16,19 +16,24 @@ module Ektoplayer
16
16
  each { |op| register.(op, &view.method(op)) }
17
17
 
18
18
  register.(:enter) do
19
- operations.send(:'browser.enter', view.selected)
19
+ selection = view.get_selection
20
+
21
+ operations.send(:'browser.enter', selection[0])
22
+
23
+ if selection.size > 1
24
+ selection[1..-1].each do |index|
25
+ operations.send(:'browser.add_to_playlist', index)
26
+ end
27
+ end
20
28
  end
21
29
 
22
30
  register.(:add_to_playlist) do
23
- #if tracks = browser.tracks(view.selected)
24
31
  view.get_selection.each do |index|
25
32
  operations.send(:'browser.add_to_playlist', index)
26
33
  end
27
- #end
28
34
  end
29
35
 
30
- # TODO: mouse?
31
- view.mouse.on(65536) do view.up(5) end
36
+ view.mouse.on(65536) do view.up(5) end
32
37
  view.mouse.on(2097152) do view.down(5) end
33
38
 
34
39
  [ICurses::BUTTON1_DOUBLE_CLICKED, ICurses::BUTTON3_CLICKED].each do |btn|
@@ -25,12 +25,7 @@ module Ektoplayer
25
25
 
26
26
  a.artist AS album_artist,
27
27
  a.title AS album,
28
- a.released_by AS released_by,
29
- a.released_by_url AS released_by_url,
30
- a.posted_by AS posted_by,
31
- a.posted_by_url AS posted_by_url,
32
28
  a.cover_url AS cover_url,
33
- a.category AS category,
34
29
  a.description AS description,
35
30
  a.date AS date,
36
31
  a.rating AS rating,
@@ -75,12 +70,7 @@ module Ektoplayer
75
70
  url TEXT NOT NULL,
76
71
  title TEXT NOT NULL,
77
72
  artist TEXT,
78
- released_by TEXT,
79
- released_by_url TEXT,
80
- posted_by TEXT,
81
- posted_by_url TEXT,
82
73
  cover_url TEXT,
83
- category TEXT,
84
74
  description TEXT,
85
75
  date DATE,
86
76
  rating FLOAT NOT NULL DEFAULT -1,
@@ -144,10 +134,8 @@ module Ektoplayer
144
134
  insert_into(table, hash, mode: :replace)
145
135
  end
146
136
 
147
- def execute(query, params=nil)
148
- stm = @db.prepare query
149
- stm.bind_params(*params) if params
150
- stm.execute.to_a
137
+ def execute(query, params=[])
138
+ @db.execute(query, *params)
151
139
  rescue
152
140
  Application.log(self, $!)
153
141
  end
@@ -156,7 +144,7 @@ module Ektoplayer
156
144
  columns: ?*,
157
145
  filters: [],
158
146
  group_by: 'url',
159
- order_by: 'album, number',
147
+ order_by: 'album,number',
160
148
  limit: nil
161
149
  )
162
150
  where_clauses, where_params = [], []
@@ -182,7 +170,7 @@ module Ektoplayer
182
170
 
183
171
  limit = "LIMIT #{limit}" if limit
184
172
 
185
- stm = @db.prepare SELECT % {
173
+ query = SELECT % {
186
174
  SELECT_COLUMNS: columns,
187
175
  WHERE: where_clauses.join(' '),
188
176
  GROUP_BY: group_by,
@@ -190,8 +178,7 @@ module Ektoplayer
190
178
  LIMIT: limit
191
179
  }
192
180
 
193
- stm.bind_params(*where_params)
194
- stm.execute.to_a
181
+ @db.execute(query, *where_params)
195
182
  rescue
196
183
  Application.log(self, $!)
197
184
  end
@@ -201,11 +188,11 @@ module Ektoplayer
201
188
  end
202
189
 
203
190
  def track_count
204
- @db.execute('SELECT COUNT(*) FROM tracks')[0][0]
191
+ @db.get_first_value('SELECT COUNT(*) FROM tracks')
205
192
  end
206
193
 
207
194
  def album_count
208
- @db.execute('SELECT COUNT(*) FROM albums')[0][0]
195
+ @db.get_first_value('SELECT COUNT(*) FROM albums')
209
196
  end
210
197
  end
211
198
  end
@@ -0,0 +1,65 @@
1
+ require 'open3'
2
+ require 'uri'
3
+
4
+ require_relative '../events'
5
+
6
+ class ExternalDownload
7
+ attr_reader :events, :url, :progress, :filename, :error
8
+
9
+ def initialize(url, filename)
10
+ @events = Events.new(:completed, :failed)
11
+ @url = URI.parse(url)
12
+ @filename = filename
13
+ @progress = 0
14
+ @error = nil
15
+ @tries = 3
16
+ end
17
+
18
+ def self.get_wget_cmd(url, file)
19
+ %w(wget -nv --show-progress --progress=dot:binary -O) + [file, url]
20
+ end
21
+
22
+ def self.get_curl_cmd(url, file)
23
+ %w(curl -# -o) + [file, url]
24
+ end
25
+
26
+ def start!
27
+ Thread.new do
28
+ args = CMD.(@url.to_s, @filename)
29
+ dl_in, dl_out, dl_err, @dl_proc = Open3.popen3(*args)
30
+
31
+ begin
32
+ while (line = dl_err.readpartial(1024))
33
+ @last_line = line
34
+
35
+ if (progress = line.scan(/(\d+(\.\d+)?%)/)[0][0].delete(?%).to_f rescue nil)
36
+ @progress = progress
37
+ end
38
+ end
39
+ rescue
40
+ nil
41
+ end
42
+
43
+ begin
44
+ @dl_proc.join
45
+ raise if @dl_proc.value.exitstatus > 0
46
+ @progress = 100.0
47
+ @events.trigger(:completed)
48
+ rescue
49
+ @events.trigger(:failed, (@error = @last_line))
50
+ end
51
+ end
52
+
53
+ sleep 0.1 while @dl_proc.nil?
54
+ sleep 0.2
55
+ self
56
+ end
57
+
58
+ if system('wget --version >/dev/null 2>/dev/null')
59
+ CMD = method :get_wget_cmd
60
+ elsif system('curl --version >/dev/null 2>/dev/null')
61
+ CMD = method :get_curl_cmd
62
+ else
63
+ fail LoadError, 'wget/curl not installed'
64
+ end
65
+ end
@@ -0,0 +1,69 @@
1
+ require 'net/https'
2
+ require 'uri'
3
+
4
+ require_relative '../events'
5
+
6
+ class RubyDownload
7
+ attr_reader :events, :url, :filename, :error
8
+
9
+ def initialize(url, filename)
10
+ @events = Events.new(:completed, :failed)
11
+ @url = URI.parse(url)
12
+ @filename = filename
13
+ @bytes_read = 0
14
+ @error, @total = nil, nil
15
+ @tries = 3
16
+ end
17
+
18
+ def progress
19
+ (@bytes_read.to_f / @total * 100) rescue 0).clamp(0, 100).to_f
20
+ end
21
+
22
+ def start!
23
+ Thread.new do
24
+ success = false
25
+
26
+ @tries.times do |try|
27
+ begin
28
+ do_download
29
+ @events.trigger(:completed)
30
+ success = true
31
+ break
32
+ rescue
33
+ @_lasterror = $!
34
+ sleep 3
35
+ end
36
+ end
37
+
38
+ unless success
39
+ @events.trigger(:failed, @_lasterror)
40
+ end
41
+ end
42
+
43
+ sleep 0.1 while @total.nil?
44
+ sleep 0.2
45
+ self
46
+ end
47
+
48
+ private def do_download
49
+ @file = File.open(filename, ?w)
50
+ @bytes_read, @total, @error = 0, nil, nil
51
+
52
+ http = Net::HTTP.new(@url.host, @url.port)
53
+
54
+ http.request(Net::HTTP::Get.new(@url.request_uri)) do |res|
55
+ fail res.body unless res.code == '200'
56
+
57
+ @total = res.header['Content-Length'].to_i
58
+
59
+ res.read_body do |chunk|
60
+ @bytes_read += chunk.size
61
+ @file << chunk
62
+ end
63
+ end
64
+
65
+ fail 'filesize mismatch' if @bytes_read != @total
66
+ ensure
67
+ (@file.close rescue nil) if @file
68
+ end
69
+ end
@@ -17,10 +17,25 @@ module Curses
17
17
  alias_method :"get#{method}", method.to_sym
18
18
  end
19
19
 
20
+ def leaveok(*_); end # Curses does not
21
+ def notimeout(*_); end # provide these functions
22
+
20
23
  alias :timeout :timeout=
21
- alias :notimeout :nodelay= #todo
22
24
  alias :nodelay :nodelay=
23
25
 
26
+ def bkgd(attr)
27
+ @bkgd_color = attr
28
+ end
29
+ alias :bkgdset :bkgd
30
+
31
+ def erase
32
+ setpos(0, 0)
33
+ attrset((@bkgd_color or 0))
34
+ addstr(' ' * (maxx * maxy))
35
+ attroff((@bkgd_color or 0))
36
+ setpos(0, 0)
37
+ end
38
+
24
39
  alias :mvwin :move # 'fix' this Gem
25
40
  def move(y, x)
26
41
  setpos(y, x)
@@ -28,7 +43,8 @@ module Curses
28
43
  end
29
44
 
30
45
  class Pad < Window
31
- alias :pnoutrefresh :refresh
46
+ alias :pnoutrefresh :noutrefresh
47
+ alias :prefresh :refresh
32
48
  end
33
49
  end
34
50
 
@@ -55,6 +55,7 @@ module FFI::NCurses
55
55
  end
56
56
 
57
57
  %w(getcurx getcury getmaxx getmaxy getbegx getbegy
58
+ clearok idlok idcok immedok leaveok setscrreg scrollok nl nonl
58
59
  keypad nodelay notimeout prefresh pnoutrefresh).each do |meth|
59
60
 
60
61
  define_method(meth) do |*args|
@@ -17,6 +17,7 @@ module Ncurses
17
17
  end
18
18
 
19
19
  %w(getcurx getcury getmaxx getmaxy getbegx getbegy
20
+ clearok idlok idcok immedok leaveok setscrreg scrollok nl nonl
20
21
  keypad nodelay notimeout prefresh pnoutrefresh).each do |meth|
21
22
  define_method(meth) do |*args|
22
23
  Ncurses.send(meth, @w, *args)
@@ -36,6 +37,15 @@ module Ncurses
36
37
  end
37
38
  end
38
39
  end
40
+
41
+ if $USING_CURSES == 'ncurses'
42
+ ### FIX: 'attrset' in ncurses is broken!
43
+ def attrset(attributes)
44
+ Ncurses.send(:wattr_get, @w, old_a=[], old_c=[], nil)
45
+ Ncurses.send(:wattroff, @w, old_a[0] | old_c[0])
46
+ Ncurses.send(:wattron, @w, attributes)
47
+ end
48
+ end
39
49
  end
40
50
  end
41
51
 
@@ -9,13 +9,21 @@
9
9
  end
10
10
 
11
11
  fail %{
12
- No interface for ncurses found. Please install one of the following gems
13
- - curses
14
- - ffi-ncurses
15
- - ncurses-ruby
16
- - ncursesw
12
+ No module for ncurses found. Please install one of the following gems:
13
+ - ffi-ncurses (preferred)
14
+ - ncursesw (good)
15
+ - ncurses-ruby (good)
16
+ - curses (works...)
17
17
 
18
18
  Maybe your distribution ships one of these already as a package.
19
+
20
+ Arch Linux:
21
+ yaourt -S ruby-curses # or
22
+ yaourt -S ruby-ncursesw
23
+
24
+ Debian / Ubuntu:
25
+ apt-get install ruby-ncurses
26
+
19
27
  } unless $USING_CURSES
20
28
 
21
29
  require_relative 'icurses/sugar'
@@ -6,13 +6,11 @@ module Ektoplayer
6
6
  PARENT_DIRECTORY = '..'.freeze
7
7
 
8
8
  PATHS = {
9
- artist: [:artist ].freeze,
10
- album: [:album ].freeze,
11
- style: [:style ].freeze,
12
- year: [:year ].freeze,
13
- title: [].freeze,
14
- released_by: [:released_by].freeze,
15
- posted_by: [:posted_by ].freeze
9
+ artist: [:artist].freeze,
10
+ album: [:album ].freeze,
11
+ style: [:style ].freeze,
12
+ year: [:year ].freeze,
13
+ title: [].freeze
16
14
  }.freeze
17
15
 
18
16
  def initialize(client)
@@ -36,16 +34,18 @@ module Ektoplayer
36
34
  end
37
35
 
38
36
  def enter(index)
39
- return unless (sub = current.enter(index))
37
+ return false unless (sub = current.enter(index))
40
38
  return back() if sub == :parent
41
39
  @stack.push(sub)
42
40
  @events.trigger(:changed)
41
+ true
43
42
  end
44
43
 
45
44
  def back
46
- return unless @stack.size > 1
45
+ return false unless @stack.size > 1
47
46
  @stack.pop
48
47
  @events.trigger(:changed)
48
+ true
49
49
  end
50
50
 
51
51
  class BrowsableCollection
@@ -91,7 +91,7 @@ module Ektoplayer
91
91
  return [] if index == 0
92
92
  return [ @contents[index] ]
93
93
  else
94
- @database.select(filters: new_filters(index)).map.to_a
94
+ @database.select(filters: new_filters(index))
95
95
  end
96
96
  end
97
97
 
@@ -121,7 +121,7 @@ module Ektoplayer
121
121
 
122
122
  def tracks(index)
123
123
  @database.select(
124
- order_by: CONTENTS[index].to_s + ",album,year,number".sub(",#{CONTENTS[index]}", '')
124
+ order_by: 'album,' + CONTENTS[index].to_s + ",album,number"
125
125
  )
126
126
  end
127
127
  end
@@ -8,11 +8,12 @@ module Ektoplayer
8
8
  super()
9
9
  @client = client
10
10
  @player = MpgWrapperPlayer.new
11
- @events.register(:position_change, :track_completed, :pause, :stop, :play)
12
- @player.events.on_all(&@events.method(:trigger))
11
+ @events = @player.events
12
+ #@events.register(:position_change, :track_completed, :pause, :stop, :play)
13
+ #@player.events.on_all(&@events.method(:trigger))
13
14
 
14
15
  %w(pause toggle stop forward backward seek
15
- length position position_percent level).each do |m|
16
+ length position position_percent can_http?).each do |m|
16
17
  self.define_singleton_method(m, &@player.method(m))
17
18
  end
18
19
  end
@@ -21,8 +22,6 @@ module Ektoplayer
21
22
  Application.log(self, 'playing', file)
22
23
  @player.play(file) rescue Application.log(self, $!)
23
24
  end
24
-
25
- def close; @player.close end
26
25
  end
27
26
  end
28
27
  end
@@ -7,8 +7,16 @@ module Ektoplayer
7
7
  # +add_to_playlist+:: see
8
8
  def initialize(operations, browser, playlist)
9
9
  register = operations.with_register('browser.')
10
- register.(:enter, &browser.method(:enter))
11
10
  register.(:back, &browser.method(:back))
11
+
12
+ register.(:enter) do |index|
13
+ unless browser.enter(index)
14
+ tracks = browser.tracks(index)
15
+ playlist.add(*tracks)
16
+ operations.send(:'playlist.play', playlist.size - tracks.size)
17
+ end
18
+ end
19
+
12
20
  register.(:add_to_playlist) do |index|
13
21
  tracks = browser.tracks(index)
14
22
  playlist.add(*tracks)
@@ -35,7 +35,7 @@ module Ektoplayer
35
35
  return unless track = @playlist[index]
36
36
  @playlist.current_playing=(index)
37
37
  Thread.new do
38
- @player.play(@trackloader.get_track_file(track['url']))
38
+ @player.play(@trackloader.get_track_file(track['url'], http_okay: @player.can_http?))
39
39
  end.join(0.3) # prevent too many hits
40
40
  end
41
41