ektoplayer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +49 -0
  3. data/bin/ektoplayer +7 -0
  4. data/lib/ektoplayer.rb +10 -0
  5. data/lib/ektoplayer/application.rb +148 -0
  6. data/lib/ektoplayer/bindings.rb +230 -0
  7. data/lib/ektoplayer/browsepage.rb +138 -0
  8. data/lib/ektoplayer/client.rb +18 -0
  9. data/lib/ektoplayer/common.rb +91 -0
  10. data/lib/ektoplayer/config.rb +247 -0
  11. data/lib/ektoplayer/controllers/browser.rb +47 -0
  12. data/lib/ektoplayer/controllers/controller.rb +9 -0
  13. data/lib/ektoplayer/controllers/help.rb +21 -0
  14. data/lib/ektoplayer/controllers/info.rb +22 -0
  15. data/lib/ektoplayer/controllers/mainwindow.rb +40 -0
  16. data/lib/ektoplayer/controllers/playlist.rb +60 -0
  17. data/lib/ektoplayer/database.rb +199 -0
  18. data/lib/ektoplayer/events.rb +56 -0
  19. data/lib/ektoplayer/models/browser.rb +127 -0
  20. data/lib/ektoplayer/models/database.rb +49 -0
  21. data/lib/ektoplayer/models/model.rb +15 -0
  22. data/lib/ektoplayer/models/player.rb +28 -0
  23. data/lib/ektoplayer/models/playlist.rb +72 -0
  24. data/lib/ektoplayer/models/search.rb +42 -0
  25. data/lib/ektoplayer/models/trackloader.rb +17 -0
  26. data/lib/ektoplayer/mp3player.rb +151 -0
  27. data/lib/ektoplayer/operations/browser.rb +19 -0
  28. data/lib/ektoplayer/operations/operations.rb +26 -0
  29. data/lib/ektoplayer/operations/player.rb +11 -0
  30. data/lib/ektoplayer/operations/playlist.rb +67 -0
  31. data/lib/ektoplayer/theme.rb +102 -0
  32. data/lib/ektoplayer/trackloader.rb +146 -0
  33. data/lib/ektoplayer/ui.rb +404 -0
  34. data/lib/ektoplayer/ui/colors.rb +105 -0
  35. data/lib/ektoplayer/ui/widgets.rb +195 -0
  36. data/lib/ektoplayer/ui/widgets/container.rb +125 -0
  37. data/lib/ektoplayer/ui/widgets/labelwidget.rb +43 -0
  38. data/lib/ektoplayer/ui/widgets/listwidget.rb +332 -0
  39. data/lib/ektoplayer/ui/widgets/tabbedcontainer.rb +110 -0
  40. data/lib/ektoplayer/updater.rb +77 -0
  41. data/lib/ektoplayer/views/browser.rb +25 -0
  42. data/lib/ektoplayer/views/help.rb +46 -0
  43. data/lib/ektoplayer/views/info.rb +208 -0
  44. data/lib/ektoplayer/views/mainwindow.rb +64 -0
  45. data/lib/ektoplayer/views/playinginfo.rb +135 -0
  46. data/lib/ektoplayer/views/playlist.rb +39 -0
  47. data/lib/ektoplayer/views/progressbar.rb +51 -0
  48. data/lib/ektoplayer/views/splash.rb +99 -0
  49. data/lib/ektoplayer/views/trackrenderer.rb +137 -0
  50. data/lib/ektoplayer/views/volumemeter.rb +74 -0
  51. metadata +164 -0
@@ -0,0 +1,39 @@
1
+ require_relative '../ui/widgets/listwidget'
2
+ require_relative '../config'
3
+
4
+ require_relative 'trackrenderer'
5
+
6
+ module Ektoplayer
7
+ module Views
8
+ class Playlist < UI::ListWidget
9
+ def initialize(**opts)
10
+ super(**opts)
11
+ self.item_renderer=(TrackRenderer.new(
12
+ width: @size.width, format: Config[:'playlist.format']
13
+ ))
14
+ end
15
+
16
+ def attach(playlist)
17
+ self.list=(playlist.to_a)
18
+
19
+ playlist.events.on(:changed) do
20
+ with_lock { self.list=(playlist.to_a); want_redraw }
21
+ end
22
+
23
+ playlist.events.on(:current_changed) do
24
+ self.current_playing=(playlist.current_playing)
25
+ end
26
+ end
27
+
28
+ def render(index, **opts)
29
+ opts[:marked] = true if index == @current_playing
30
+ super(index, **opts)
31
+ end
32
+
33
+ def current_playing=(p)
34
+ return if @current_playing == p
35
+ with_lock { @current_playing = p; want_redraw }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,51 @@
1
+ require_relative '../ui/widgets'
2
+ require_relative '../config'
3
+ require_relative '../theme'
4
+
5
+ module Ektoplayer
6
+ module Views
7
+ class ProgressBar < UI::Window
8
+ def attach(player)
9
+ player.events.on(:position_change) do
10
+ self.percent_playing = player.position_percent
11
+ end
12
+
13
+ view=self # TODO
14
+ [Curses::BUTTON1_CLICKED, Curses::BUTTON2_CLICKED, Curses::BUTTON3_CLICKED].
15
+ each do |button|
16
+ view.mouse.on(button) do |mevent|
17
+ pos = Float(mevent.x) / (self.size.width - 1) * player.length rescue player.position
18
+ player.seek(pos.to_i)
19
+ end
20
+ end
21
+ end
22
+
23
+ def percent_playing=(percent_playing)
24
+ char_width = (percent_playing * @size.width).to_i
25
+ return if char_width == @progress_width
26
+
27
+ with_lock do
28
+ @progress_width = char_width
29
+ want_redraw
30
+ end
31
+ end
32
+
33
+ def draw
34
+ @win.setpos(0,0)
35
+
36
+ @progress_width ||= 0
37
+ @progress_char ||= Config[:'progressbar.progress_char']
38
+ @rest_char ||= Config[:'progressbar.rest_char']
39
+
40
+ @win.with_attr(Theme[:'progressbar.progress']) do
41
+ repeat = (@progress_width - @progress_char.size)
42
+ @win << @progress_char[0] * repeat if repeat > 0
43
+ @win << @progress_char[1..-1] if @progress_width > 0
44
+ end
45
+
46
+ @win.attron(Theme[:'progressbar.rest'])
47
+ @win << @rest_char * (@size.width - @win.curx)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,99 @@
1
+ require_relative '../ui/colors'
2
+ require_relative '../ui/widgets'
3
+ require_relative '../theme'
4
+ require_relative '../common'
5
+
6
+ module Ektoplayer
7
+ module Views
8
+ class Splash < UI::Window
9
+ EKTOPLAZM_LOGO = %q.
10
+ ____ _ _ _ ____ _ _____ ______ _ ___ ___
11
+ / __) ; | | ; | | | _ \ | | /___ \ |____ | | '_ `_ \
12
+ / / | | | | _| |__ ___ | | | | | | | | | | | | | | | |
13
+ ( ( | | | | |_ __) / _ \ | | | | | | ___| | / , | | | | | |
14
+ \ \_ | | | | | | | | | | | | | | | | / _| | / / | | | | | |
15
+ ) _) | | | | | | | | | | | |_| ; | | | | | | / / | | | | | |
16
+ / / | |_|/ | | | |_| | | __/ | | | | | | / / | | | | | |
17
+ ( ( | _{ | | \___/ | | | | | | | | / / | | |_| | |
18
+ \ \__ | | |\ | |__ | | | :___ | |_| | , /____ | | | |
19
+ \____) |_| |_| \___/ |_| \____/ \_____| |______| |_| |_|..
20
+ split(?\n)[1..-1].freeze
21
+ EKTOPLAZM_SIGNATURE = %q;
22
+ ___ _ _ _ _ _ _
23
+ / __| ___ _ _ _ _ __| | | | (_) |__ ___ _ _ __ _| |_(_)___ _ _
24
+ \__ \/ _ \ || | ' \/ _` | | |__| | '_ \/ -_) '_/ _` | _| / _ \ ' \
25
+ |___/\___/\_,_|_||_\__,_| |____|_|_.__/\___|_| \__,_|\__|_\___/_||_|;.
26
+ split(?\n)[1..-1].freeze
27
+
28
+ BUBBLES = [
29
+ UI::Point.new(x: 6, y: 3).frz, UI::Point.new(x: 6, y: 7).frz,
30
+ UI::Point.new(x: 28, y: 1).frz, UI::Point.new(x: 28, y: 9).frz,
31
+ UI::Point.new(x: 46, y: 7).frz, UI::Point.new(x: 71, y: 9).frz
32
+ ].freeze
33
+
34
+ def load_colors
35
+ @signature_fade = @ekto_logo_fade = @bubble_fade = [-1].freeze
36
+
37
+ if Theme.current == 256
38
+ @bubble_fade = [161,162,167,168]
39
+ @signature_fade = [99, 105, 111, 117]
40
+ @ekto_logo_fade = [23, 23, 29, 36, 42, 48, 42, 36, 29, 23]
41
+ elsif Theme.current == 8
42
+ @bubble_fade = [:red]
43
+ @ekto_logo_fade = [:blue]
44
+ @signature_fade = [:magenta]
45
+ end
46
+
47
+ @bubble_fade = UI::ColorFader.new(@bubble_fade)
48
+ @signature_fade = UI::ColorFader.new(@signature_fade)
49
+ @ekto_logo_fade = UI::ColorFader.new(@ekto_logo_fade)
50
+ end
51
+
52
+ def draw
53
+ @win.erase
54
+ return if (EKTOPLAZM_LOGO.size >= @size.height or
55
+ EKTOPLAZM_LOGO.max.size >= @size.width)
56
+ load_colors
57
+
58
+ w_center = @size.width / 2
59
+ h_center = @size.height / 2
60
+ left_pad = w_center - (EKTOPLAZM_LOGO.max.size / 2)
61
+
62
+ if EKTOPLAZM_LOGO.size + EKTOPLAZM_SIGNATURE.size + 3 > @size.height
63
+ top_pad = h_center - (EKTOPLAZM_LOGO.size / 2)
64
+ draw_signature = false
65
+ else
66
+ top_pad = h_center - (EKTOPLAZM_LOGO.size / 2 + 3)
67
+ draw_signature = true
68
+ end
69
+
70
+ @ekto_logo_fade.fade(EKTOPLAZM_LOGO.size).each_with_index do |c,i|
71
+ @win.with_attr(c) do
72
+ @win.setpos(top_pad + i, left_pad)
73
+ @win << EKTOPLAZM_LOGO[i]
74
+ end
75
+ end
76
+
77
+ f = @bubble_fade.fade(EKTOPLAZM_LOGO.size)
78
+ BUBBLES.each do |p|
79
+ @win.setpos(top_pad + p.y - 1, left_pad + p.x + 1)
80
+ @win.attron(f[p.y - 1]) { @win.addch(?_) }
81
+ @win.setpos(top_pad + p.y, left_pad + p.x)
82
+ @win.attron(f[p.y]) { @win << '(_)' }
83
+ end
84
+
85
+ return unless draw_signature
86
+
87
+ top_pad += EKTOPLAZM_LOGO.size + 2
88
+ left_pad = w_center - (EKTOPLAZM_SIGNATURE.max.size / 2)
89
+
90
+ EKTOPLAZM_SIGNATURE.each_with_index do |line, i|
91
+ @win.setpos(top_pad + i, left_pad)
92
+ @signature_fade.fade2(line.size).each_with_index do |color,y|
93
+ @win.with_attr(color) { @win << line[y] }
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,137 @@
1
+ require_relative '../ui/widgets'
2
+
3
+ class PercentualDistributor
4
+ def initialize(total: 0, parts: [])
5
+ @total, @parts = total, parts
6
+ @results = nil
7
+ end
8
+
9
+ def increment_total(n)
10
+ @total += n
11
+ @results = nil
12
+ end
13
+
14
+ def add_part(n)
15
+ @parts << n
16
+ @results = nil
17
+ end
18
+
19
+ def get_for(part)
20
+ fail ArgumentError unless @parts.include? part
21
+
22
+ unless @results
23
+ @results = Hash.new { |h,k| h[k] = [] }
24
+
25
+ part_total, results_total = @parts.sum, 0
26
+ @parts.each_with_index do |p,i|
27
+ v = @total * p / part_total
28
+ @results[p] << v
29
+ results_total += v
30
+ end
31
+
32
+ @results.each do |k, values|
33
+ values.map! do |v|
34
+ if results_total > @total
35
+ results_total -= 1
36
+ v - 1
37
+ elsif results_total < @total
38
+ results_total += 1
39
+ v + 1
40
+ else
41
+ v
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ @results[part].unshift(r = @results[part].pop)
48
+ r
49
+ end
50
+ end
51
+
52
+ module Ektoplayer
53
+ module Views
54
+ class TrackRenderer < UI::ListItemRenderer
55
+ def initialize(width: nil, format: nil)
56
+ super(width: width)
57
+ self.column_format=(format)
58
+ end
59
+
60
+ def column_format=(format)
61
+ return unless format
62
+ @column_format = format
63
+ layout
64
+ end
65
+
66
+ def layout
67
+ return unless @column_format
68
+ fail if @column_format.empty?
69
+ fail unless @width
70
+
71
+ pd = PercentualDistributor.new(
72
+ total: (@width - (@column_format.size - 1))
73
+ )
74
+
75
+ @column_format.each do |c|
76
+ if c[:rel]
77
+ pd.add_part(c[:rel])
78
+ else
79
+ c[:render_size] = c[:size]
80
+ pd.increment_total(-1 * c[:size])
81
+ end
82
+
83
+ c[:curses_codes] = UI::Colors.set(nil, *c[:curses_attrs])
84
+ end
85
+
86
+ @column_format.each do |c|
87
+ if c[:rel]
88
+ c[:render_size] = (pd.get_for(c[:rel]) or fail)
89
+ end
90
+ end
91
+ end
92
+
93
+ def render(scr, item, index, selected: false, marked: false)
94
+ fail ArgumentError, 'item is nil' unless item
95
+ return unless @column_format
96
+
97
+ additional_attributes = 0
98
+ additional_attributes |= Curses::A_BOLD if marked
99
+ additional_attributes |= Curses::A_STANDOUT if selected
100
+
101
+ if item.is_a? String or item.is_a? Symbol
102
+ if index % 2 == 0
103
+ color = Theme[:'list.item_even']
104
+ else
105
+ color = Theme[:'list.item_odd']
106
+ end
107
+
108
+ scr.with_attr(color | additional_attributes) do
109
+ scr << "[#{item}]".ljust(@width)
110
+ end
111
+ return
112
+ end
113
+
114
+ @column_format.each_with_index do |c,i|
115
+ scr.with_attr(c[:curses_codes] | additional_attributes) do
116
+ value = (item[c[:tag]] or '')
117
+
118
+ if value.is_a?(Integer)
119
+ value = "%.2d" % value
120
+ else
121
+ value = value.to_s[0..(c[:render_size] - 1)]
122
+ end
123
+
124
+ if c[:justify] == :right
125
+ value = value.rjust(c[:render_size])
126
+ else
127
+ value = value.ljust(c[:render_size])
128
+ end
129
+
130
+ scr.addstr(value)
131
+ scr.addstr(' ') if i < (@column_format.size - 1)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,74 @@
1
+ require_relative '../ui/widgets'
2
+ require_relative '../config'
3
+ require_relative '../theme'
4
+
5
+ module Ektoplayer
6
+ module Views
7
+ class VolumeMeter < UI::Window
8
+ def layout
9
+ super
10
+ load_colors(true)
11
+ end
12
+
13
+ def load_colors(force=false)
14
+ return if @fade and not force
15
+
16
+ if Theme.current == 256
17
+ fader = UI::ColorFader.new([25,26,27,32,39,38,44,44,45,51,87,159,195])
18
+ elsif Theme.current == 8
19
+ fader = UI::ColorFader.new([:blue])
20
+ else
21
+ fader = UI::ColorFader.new([-1])
22
+ end
23
+
24
+ @fade = fader.fade(@size.width)
25
+ @level_width = @size.width
26
+ @level_char = Config[:'volumemeter.level_char']
27
+ @rest_char = Config[:'volumemeter.rest_char']
28
+ end
29
+
30
+ def level=(level)
31
+ new_level_width = (1.4 * level * @size.width).to_i.clamp(0, @size.width - 1) rescue 0
32
+ return if @level_width == new_level_width
33
+ load_colors
34
+
35
+ if new_level_width > @level_width
36
+ @win.setpos(@win.cury, @level_width)
37
+ (@level_width).upto(new_level_width).each do |i|
38
+ @win.attron(@fade[i])
39
+ @win << @level_char
40
+ end
41
+ else
42
+ @win.setpos(@win.cury, new_level_width)
43
+ end
44
+
45
+ if (repeat = @size.width - @win.curx - 1) > 0
46
+ @win.attron(Theme[:'volumemeter.rest'])
47
+ @win << @rest_char * (repeat + 1)
48
+ end
49
+
50
+ @level_width = new_level_width
51
+ @win.refresh if visible?
52
+ end
53
+
54
+ def attach(player)
55
+ player.events.on(:position_change) { self.level=(player.level) }
56
+ player.events.on(:stop) { self.level=(90) }
57
+ player.events.on(:pause) { self.level=(90) }
58
+ end
59
+
60
+ def draw
61
+ load_colors
62
+ @win.setpos(0,0)
63
+
64
+ @level_width.times do |i|
65
+ @win.attron(@fade[i])
66
+ @win << @level_char
67
+ end
68
+
69
+ @win.attron(Theme[:'volumemeter.rest'])
70
+ @win << @rest_char * (@size.width - @win.curx)
71
+ end
72
+ end
73
+ end
74
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ektoplayer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Benjamin Abendroth
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: audite
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: curses
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: nokogiri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.7'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubyzip
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
83
+ description: Console audio player for ektoplazm.com
84
+ email: braph93@gmx.de
85
+ executables:
86
+ - ektoplayer
87
+ extensions: []
88
+ extra_rdoc_files:
89
+ - README.md
90
+ files:
91
+ - README.md
92
+ - bin/ektoplayer
93
+ - lib/ektoplayer.rb
94
+ - lib/ektoplayer/application.rb
95
+ - lib/ektoplayer/bindings.rb
96
+ - lib/ektoplayer/browsepage.rb
97
+ - lib/ektoplayer/client.rb
98
+ - lib/ektoplayer/common.rb
99
+ - lib/ektoplayer/config.rb
100
+ - lib/ektoplayer/controllers/browser.rb
101
+ - lib/ektoplayer/controllers/controller.rb
102
+ - lib/ektoplayer/controllers/help.rb
103
+ - lib/ektoplayer/controllers/info.rb
104
+ - lib/ektoplayer/controllers/mainwindow.rb
105
+ - lib/ektoplayer/controllers/playlist.rb
106
+ - lib/ektoplayer/database.rb
107
+ - lib/ektoplayer/events.rb
108
+ - lib/ektoplayer/models/browser.rb
109
+ - lib/ektoplayer/models/database.rb
110
+ - lib/ektoplayer/models/model.rb
111
+ - lib/ektoplayer/models/player.rb
112
+ - lib/ektoplayer/models/playlist.rb
113
+ - lib/ektoplayer/models/search.rb
114
+ - lib/ektoplayer/models/trackloader.rb
115
+ - lib/ektoplayer/mp3player.rb
116
+ - lib/ektoplayer/operations/browser.rb
117
+ - lib/ektoplayer/operations/operations.rb
118
+ - lib/ektoplayer/operations/player.rb
119
+ - lib/ektoplayer/operations/playlist.rb
120
+ - lib/ektoplayer/theme.rb
121
+ - lib/ektoplayer/trackloader.rb
122
+ - lib/ektoplayer/ui.rb
123
+ - lib/ektoplayer/ui/colors.rb
124
+ - lib/ektoplayer/ui/widgets.rb
125
+ - lib/ektoplayer/ui/widgets/container.rb
126
+ - lib/ektoplayer/ui/widgets/labelwidget.rb
127
+ - lib/ektoplayer/ui/widgets/listwidget.rb
128
+ - lib/ektoplayer/ui/widgets/tabbedcontainer.rb
129
+ - lib/ektoplayer/updater.rb
130
+ - lib/ektoplayer/views/browser.rb
131
+ - lib/ektoplayer/views/help.rb
132
+ - lib/ektoplayer/views/info.rb
133
+ - lib/ektoplayer/views/mainwindow.rb
134
+ - lib/ektoplayer/views/playinginfo.rb
135
+ - lib/ektoplayer/views/playlist.rb
136
+ - lib/ektoplayer/views/progressbar.rb
137
+ - lib/ektoplayer/views/splash.rb
138
+ - lib/ektoplayer/views/trackrenderer.rb
139
+ - lib/ektoplayer/views/volumemeter.rb
140
+ homepage: http://www.github.com/braph/ektoplayer
141
+ licenses:
142
+ - GPL-3.0
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.6.8
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: play music from ektoplazm.com
164
+ test_files: []