rubio-radio 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cfd627d6056a51e35b6ba16a55f6e87ad2e05820ffe16172862c2df5222242b7
4
- data.tar.gz: 0bbdcb38795e7a55e00a0699bc0a30e5e2f53ed6b0a0defcaf43d81b0ea641c3
3
+ metadata.gz: 251dc5095f4659c3598be19ed733cc71ed404957a582071eed209d0ae2d27757
4
+ data.tar.gz: 8e1583db5b2a5b85838e5c314587a58365b8a74851855dca887a32c2b910a236
5
5
  SHA512:
6
- metadata.gz: 4d6682d2602e24709eabcf65f1110acaf04b6f543e516775f6b9b29661e1c886fbf3c3d647a7e33cba78b159a044aa42a823de0e1046b1cf37b749b778e98907
7
- data.tar.gz: d5c4ae797ab9d3985fdeb56c135738f545226dcb0eb5ca199624a17d72a645f4ee4abfbdb0687492099edfa75137527e658d78f2df0414e737e55b5969304ea5
6
+ metadata.gz: 1866d8bd12d24ab570ab149d73e4ad166246f4160f80050de7ac4f2bf9d719befdf8cd04741593dbee5ac333f33a3b5ff4fa055d308747a490fd673137c21b4b
7
+ data.tar.gz: bc817eda194e723664ab321c0be218856ac700230d70c0be210fcec78e4e615b5038bdc270dd0c2d696500895638f4338d9ba3fa1a86c8f92173cf29abf0913d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.5
4
+
5
+ - Upgrade to glimmer-dsl-libui v0.5.22
6
+ - Add/Remove currently playing radio station to bookmarks (remembered across app restarts by storing station UUID in a YAML file locally)
7
+ - View menu with "All", "Bookmarks", and "Playing" View menu items
8
+ - Command option `--[no-]bookmarks` to show/hide bookmarks in table
9
+ - Command option `--[no-]gradual` to load radio stations gradually (preventing user from waiting for app to start) or avoid loading gradually
10
+
3
11
  ## 0.0.4
4
12
 
5
13
  - Upgrade to glimmer-dsl-libui v0.5.18
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2022 kojix2
3
+ Copyright (c) 2022 kojix2, Andy Maleh
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -51,6 +51,12 @@ The top 10,000 [Radio Browser](https://www.radio-browser.info/) stations are dis
51
51
  rubio --count 20000
52
52
  ```
53
53
 
54
+ The stations are fetched gradually (asynchronously) from the [Radio Browser](https://www.radio-browser.info/) web API to have the app start instantly (avoid having the user wait for the app to start) no matter what the total count of stations is. But, you can avoid gradual prefetching if you prefer.
55
+
56
+ ```
57
+ rubio --no-gradual
58
+ ```
59
+
54
60
  Default player is `vlc -I dummy`. But, you can use any command line player that can take URL of radio station as its first argument.
55
61
 
56
62
  ```
@@ -70,10 +76,12 @@ Usage: rubio [options]
70
76
  -b, --backend STR command to use as backend player ['vlc -I dummy']
71
77
  -c, --count INT number of stations to fetch from radio-browser [10000]
72
78
  --per-page INT number of stations per page [20]
73
- --[no-]page-count show/hide page count
74
79
  -w, --width INT main window width
75
80
  -h, --height INT main window height
76
- --[no-]menu show/hide menu
81
+ --[no-]page-count show/hide page count [false]
82
+ --[no-]menu show/hide menu [true]
83
+ --[no-]bookmarks show/hide bookmarks [true]
84
+ --[no-]gradual gradually/non-gradually fetch stations [true]
77
85
  --debug output status of monitored threads
78
86
  --help show this help message
79
87
  --version show the rubio version number
@@ -87,10 +95,10 @@ rubio --mpg123 # `rubio --backend mpg123`
87
95
  rubio --count 1000 # Displays the top 1,000 Radio Browser stations
88
96
  ```
89
97
 
90
- Small Screen Example:
98
+ Minimalistic Example:
91
99
 
92
100
  ```
93
- rubio --per-page 6 --no-menu
101
+ rubio --per-page 6 --no-menu --no-bookmarks
94
102
  ```
95
103
 
96
104
  ![small screen linux screenshot](screenshots/rubio-radio-linux-example-small.png)
@@ -103,6 +111,14 @@ rubio --page-count
103
111
 
104
112
  ![page count mac screenshot](screenshots/rubio-radio-mac-example-page-count.png)
105
113
 
114
+ ### Menus
115
+
116
+ You can use the top menu bar to stop the currently playing radio station, bookmark, unbookmark, view only bookmarked stations, view only currently playing station, and read the about dialog.
117
+
118
+ ![view book marks mac screenshot](screenshots/rubio-radio-mac-example-view-bookmarks.png)
119
+
120
+ Bookmarks are stored in `File.join(Dir.home, '.rubio-radio', 'bookmarks.yml')`
121
+
106
122
  ## Links
107
123
 
108
124
  * [Ruby](https://github.com/ruby/ruby)
data/TODO.md CHANGED
@@ -1,3 +1,9 @@
1
1
  # TODO
2
2
 
3
- N/A
3
+ - Support OR-based FTS (Full-Text-Search) queries by treating multiple words as WORD1 OR WORD2, etc...
4
+ - Support exact FTS (Full-Text-Search) queries using double-quotes (e.g. "WORD1 WORD2")
5
+ - Support column-based queries by prefixing query term with column name + colon (e.g. "language:english"), which can be combined with FTS queries (e.g. "jazz language:english"). Also, there is no need to enter all of the column letters, yet only the first few letters that distinguish it from other columns (e.g. "jazz l:english")
6
+
7
+ - Make window margined and provide option to disable margins if preferred (`--no-margins`)
8
+
9
+ - Show current playing song (use `vlc -I dummy --extraintf http --http-host localhost --http-port 9877 --http-password pass1234` backend, and then make an HTTP request to http://localhost:9877/requests/status.xml in order to obtain song information and update it every second; maybe regenerate a new password on every run) (alternatively, I can use backend `vlc -I rc` and call `info` to obtain song details, parsing the text after `now_playing:` .... can use `io = IO.popen('vlc -I rc http://radio.canstream.co.uk:8075/live.mp3', 'r+')` with `io.puts('inf')` and `io.gets` until all input is done; also use `Timeout::timeout(0.5) {}` to avoid timing out on `gets` when there is no more input)
data/exe/rubio CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'puts_debuggerer' if ENV['PD'].to_s.downcase == 'true'
4
5
  require 'rubio'
5
6
  require 'optparse'
6
7
 
@@ -20,10 +21,14 @@ opt.on('-c', '--count INT', Numeric, 'number of stations to fetch from radio-bro
20
21
  options[:radio_station_count] = c
21
22
  end
22
23
  opt.on('--per-page INT', Numeric, 'number of stations per page [20]') { |c| options[:table_per_page] = c }
23
- opt.on('--[no-]page-count', TrueClass, 'show/hide page count') { |b| options[:show_page_count] = b }
24
24
  opt.on('-w', '--width INT', Numeric, 'main window width') { |w| options[:initial_width] = w }
25
25
  opt.on('-h', '--height INT', Numeric, 'main window height') { |h| options[:initial_height] = h }
26
- opt.on('--[no-]menu', TrueClass, 'show/hide menu') { |b| options[:visible_menu] = b }
26
+ opt.on('--[no-]page-count', TrueClass, 'show/hide page count [false]') { |b| options[:show_page_count] = b }
27
+ opt.on('--[no-]menu', TrueClass, 'show/hide menu [true]') { |b| options[:show_menu] = b }
28
+ opt.on('--[no-]bookmarks', TrueClass, 'show/hide bookmarks [true]') { |b| options[:show_bookmarks] = b }
29
+ opt.on('--[no-]gradual', TrueClass, 'gradually/non-gradually fetch stations [true]') do |g|
30
+ options[:gradually_fetch_stations] = g
31
+ end
27
32
  opt.on('--debug', 'output status of monitored threads') { options[:debug] = true }
28
33
  opt.on('--help', 'show this help message') do
29
34
  puts opt
@@ -43,8 +48,8 @@ rescue OptionParser::InvalidOption, OptionParser::AmbiguousOption => e
43
48
  end
44
49
 
45
50
  begin
46
- Rubio::Radio.launch(**options)
51
+ Rubio::View::Radio.launch(**options)
47
52
  rescue StandardError => e
48
- Rubio::Radio.launched_application&.player&.stop_all
53
+ Rubio::View::Radio.launched_application&.player&.stop_all
49
54
  raise e
50
55
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+
6
+ module Rubio
7
+ module Model
8
+ module Bookmark
9
+ DIR_RUBIO_RADIO = File.join(Dir.home, '.rubio-radio')
10
+ FileUtils.mkdir_p(DIR_RUBIO_RADIO)
11
+ FILE_RUBIO_RADIO_BOOKMARKS = File.join(DIR_RUBIO_RADIO, 'bookmarks.yml')
12
+ FileUtils.touch(FILE_RUBIO_RADIO_BOOKMARKS)
13
+
14
+ class << self
15
+ def add(stationuuid)
16
+ unless all.include?(stationuuid)
17
+ all << stationuuid
18
+ save_all
19
+ end
20
+ end
21
+
22
+ def remove(stationuuid)
23
+ if all.include?(stationuuid)
24
+ all.delete(stationuuid)
25
+ save_all
26
+ end
27
+ end
28
+
29
+ def all
30
+ @all ||= load_all || []
31
+ end
32
+
33
+ def save_all
34
+ bookmarks_yaml = YAML.dump(all)
35
+ File.write(FILE_RUBIO_RADIO_BOOKMARKS, bookmarks_yaml)
36
+ rescue StandardError => e
37
+ puts 'Failed in saving bookmarks!'
38
+ puts all.inspect
39
+ puts e.full_message
40
+ # No Op
41
+ end
42
+
43
+ def load_all
44
+ bookmarks_yaml = File.read(FILE_RUBIO_RADIO_BOOKMARKS)
45
+ YAML.load(bookmarks_yaml)
46
+ rescue StandardError => e
47
+ puts 'Failed in loading bookmarks! Returning empty bookmarks.'
48
+ puts e.full_message
49
+ []
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rubio
4
+ module Model
5
+ class Player
6
+ attr_accessor :backend, :pid, :thr, :status, :history
7
+
8
+ def initialize(backend = OS.linux? ? 'cvlc' : 'vlc -I rc')
9
+ raise unless backend.is_a?(String)
10
+
11
+ @backend = backend
12
+ @pid = nil
13
+ @thr = nil
14
+ @status = []
15
+ @history = []
16
+ end
17
+
18
+ def alive?
19
+ return false if @thr.nil?
20
+
21
+ @thr.alive?
22
+ end
23
+
24
+ def stop?
25
+ @thr.nil? || @thr.stop?
26
+ end
27
+
28
+ def play(url)
29
+ # Do not include spaces in the command line
30
+ # if a space exist :
31
+ # * sh -c command url # this process with @pid will be killed
32
+ # * cmmand url # will not be killd because pid is differennt
33
+ # if no space :
34
+ # * cmmand url # will be killed by @pid
35
+ raise if url.match(/\s/)
36
+
37
+ @pid = spawn(*backend.split(' '), url)
38
+ @thr = Process.detach(@pid)
39
+ @status = [@pid, @thr]
40
+ @history << @status
41
+ end
42
+
43
+ def stop
44
+ return unless alive?
45
+
46
+ r = Process.kill(OS.windows? ? :KILL : :TERM, pid)
47
+ @thr = nil
48
+ @pid = nil
49
+ r
50
+ end
51
+
52
+ def stop_all
53
+ @history.each do |pid, thr|
54
+ Process.kill(OS.windows? ? :KILL : :TERM, pid) if thr.alive?
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'open-uri'
5
+
6
+ require_relative 'station'
7
+
8
+ module Rubio
9
+ module Model
10
+ # https://www.radio-browser.info
11
+ module RadioBrowser
12
+ module_function
13
+
14
+ def base_url
15
+ 'http://all.api.radio-browser.info/json/'
16
+ end
17
+
18
+ def topvote(n = 100, offset: 0)
19
+ content = URI.parse(base_url + "stations/topvote/#{n}?offset=#{offset}")
20
+ result = []
21
+ JSON[content.read].each_with_index do |s, _i|
22
+ result << Station.new(s['stationuuid'], s['name'], s['language'], s['url_resolved'])
23
+ end
24
+ result
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'bookmark'
4
+
5
+ module Rubio
6
+ module Model
7
+ Station = Struct.new(:stationuuid, :name, :language, :url, :play, :bookmark) do
8
+ attr_reader :playing, :bookmarked
9
+ alias_method :playing?, :playing
10
+ alias_method :bookmarked?, :bookmarked
11
+
12
+ def initialize(*args, **kwargs)
13
+ super(*args, **kwargs)
14
+ self.playing = false
15
+ self.bookmarked = Bookmark.all.include?(stationuuid)
16
+ end
17
+
18
+ def playing=(value)
19
+ self.play = value ? '■' : '▶'
20
+ @playing = value
21
+ end
22
+
23
+ def bookmarked=(value)
24
+ self.bookmark = value ? '★' : '☆'
25
+ @bookmarked = value
26
+ if @bookmarked
27
+ Bookmark.add(stationuuid)
28
+ else
29
+ Bookmark.remove(stationuuid)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/rubio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubio
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  end
@@ -0,0 +1,297 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'glimmer-dsl-libui'
4
+
5
+ require_relative '../model/radio_browser'
6
+ require_relative '../model/player'
7
+
8
+ module Rubio
9
+ module View
10
+ class Radio
11
+ include Glimmer::LibUI::Application
12
+
13
+ options :backend, :initial_width, :initial_height
14
+ option :radio_station_count, default: 10_000
15
+ option :debug, default: false
16
+ option :show_menu, default: true
17
+ option :show_page_count, default: false
18
+ option :show_bookmarks, default: true
19
+ option :gradually_fetch_stations, default: true
20
+ option :table_per_page, default: 20
21
+
22
+ attr_reader :stations, :player
23
+ attr_accessor :current_station, :view
24
+
25
+ before_body do
26
+ @loaded_station_count = [gradually_fetch_stations ? 100 : radio_station_count, radio_station_count].min
27
+ @loaded_station_offset = 0
28
+ @stations = Model::RadioBrowser.topvote(@loaded_station_count, offset: @loaded_station_offset)
29
+ @player = Model::Player.new(backend)
30
+ @initial_width = (initial_width || (show_bookmarks ? 740 : 620)).to_i
31
+ @initial_height = (initial_height || calculate_initial_height).to_i
32
+ @view = :all
33
+ end
34
+
35
+ after_body do
36
+ monitor_thread(debug)
37
+ async_fetch_stations if gradually_fetch_stations && @stations.count < radio_station_count
38
+ end
39
+
40
+ body do
41
+ radio_menu_bar
42
+
43
+ window('Rubio', @initial_width, @initial_height) do
44
+ vertical_box do
45
+ horizontal_box do
46
+ @station_table = refined_table(
47
+ table_columns: station_table_columns,
48
+ model_array: stations,
49
+ per_page: table_per_page.to_i,
50
+ visible_page_count: show_page_count
51
+ )
52
+ end
53
+ end
54
+
55
+ on_closing do
56
+ @player.stop_all
57
+ end
58
+ end
59
+ end
60
+
61
+ def radio_menu_bar
62
+ return unless OS.mac? || show_menu
63
+
64
+ radio_menu
65
+ view_menu
66
+ help_menu
67
+ end
68
+
69
+ def radio_menu
70
+ menu('Radio') do
71
+ menu_item('Stop') do
72
+ enabled <= [self, 'current_station', { on_read: ->(value) { !!value } }]
73
+
74
+ on_clicked do
75
+ stop_station
76
+ end
77
+ end
78
+
79
+ separator_menu_item
80
+
81
+ menu_item('Bookmark') do
82
+ enabled <= [self, 'current_station.bookmarked', { on_read: :! }]
83
+
84
+ on_clicked do
85
+ toggle_bookmarked_station(current_station) if current_station
86
+ end
87
+ end
88
+
89
+ menu_item('Unbookmark') do
90
+ enabled <= [self, 'current_station.bookmarked']
91
+
92
+ on_clicked do
93
+ toggle_bookmarked_station(current_station) if current_station
94
+ end
95
+ end
96
+
97
+ separator_menu_item
98
+
99
+ if OS.mac?
100
+ about_menu_item do
101
+ on_clicked do
102
+ about_message_box
103
+ end
104
+ end
105
+ end
106
+
107
+ quit_menu_item do
108
+ on_clicked do
109
+ @player.stop_all
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ def view_menu
116
+ menu('View') do
117
+ radio_menu_item('All') do
118
+ checked <=> [self, :view,
119
+ { on_read: ->(value) { value == :all },
120
+ on_write: ->(_value) { :all } }]
121
+
122
+ on_clicked do
123
+ view_all
124
+ end
125
+ end
126
+
127
+ radio_menu_item('Bookmarks') do
128
+ checked <=> [self, :view,
129
+ { on_read: ->(value) { value == :bookmarks },
130
+ on_write: ->(_value) { :bookmarks } }]
131
+
132
+ on_clicked do
133
+ view_bookmarks
134
+ end
135
+ end
136
+
137
+ radio_menu_item('Playing') do
138
+ checked <=> [self, :view,
139
+ { on_read: ->(value) { value == :playing },
140
+ on_write: ->(_value) { :playing } }]
141
+
142
+ on_clicked do
143
+ view_playing
144
+ end
145
+ end
146
+
147
+ separator_menu_item if OS.mac?
148
+ end
149
+ end
150
+
151
+ def help_menu
152
+ menu('Help') do
153
+ menu_item('About') do
154
+ on_clicked do
155
+ about_message_box
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ def station_table_columns
162
+ table_columns = {
163
+ 'Play' => {
164
+ button: {
165
+ on_clicked: lambda { |row|
166
+ station = @station_table.refined_model_array[row]
167
+ select_station(station)
168
+ }
169
+ }
170
+ }
171
+ }
172
+
173
+ if show_bookmarks
174
+ table_columns.merge!(
175
+ 'Bookmark' => {
176
+ button: {
177
+ on_clicked: lambda { |row|
178
+ station = @station_table.refined_model_array[row]
179
+ toggle_bookmarked_station(station)
180
+ }
181
+ }
182
+ }
183
+ )
184
+ end
185
+
186
+ table_columns.merge!(
187
+ 'name' => :text,
188
+ 'language' => :text
189
+ )
190
+ end
191
+
192
+ def about_message_box
193
+ license = begin
194
+ File.read(File.expand_path('../../../LICENSE.txt', __dir__))
195
+ rescue StandardError
196
+ ''
197
+ end
198
+ product = "rubio-radio #{Rubio::VERSION}"
199
+ message_box(product, "#{product}\n\n#{license}")
200
+ end
201
+
202
+ def select_station(station)
203
+ playing = station.playing?
204
+ stop_station
205
+ self.current_station = station
206
+ if playing
207
+ self.current_station = nil
208
+ else
209
+ play_station
210
+ end
211
+ end
212
+
213
+ def toggle_bookmarked_station(station)
214
+ station.bookmarked = !station.bookmarked?
215
+ view_bookmarks if view == :bookmarks && !station.bookmarked
216
+ end
217
+
218
+ def play_station
219
+ @player.play(current_station.url)
220
+ current_station.playing = true
221
+ rescue StandardError => e
222
+ message_box(e.message)
223
+ self.current_station = nil
224
+ end
225
+
226
+ def stop_station
227
+ return if current_station.nil?
228
+
229
+ @player.stop
230
+ current_station.playing = false
231
+ self.current_station = nil
232
+ end
233
+
234
+ def view_all
235
+ @station_table.model_array = stations
236
+ end
237
+
238
+ def view_bookmarks
239
+ @station_table.model_array = stations.select(&:bookmarked?)
240
+ end
241
+
242
+ def view_playing
243
+ @station_table.model_array = stations.select(&:playing?)
244
+ end
245
+
246
+ def refresh_view
247
+ case view
248
+ when :all
249
+ view_all
250
+ when :bookmarks
251
+ view_bookmarks
252
+ when :playing
253
+ view_playing
254
+ end
255
+ end
256
+
257
+ private
258
+
259
+ def calculate_initial_height
260
+ if OS.linux?
261
+ 107 + (show_menu ? 26 : 0) + 24 * table_per_page.to_i
262
+ elsif OS.mac? && OS.host_cpu == 'arm64'
263
+ 90 + 24 * table_per_page.to_i
264
+ elsif OS.mac?
265
+ 85 + 19 * table_per_page.to_i
266
+ else # Windows
267
+ 95 + 19 * table_per_page.to_i
268
+ end
269
+ end
270
+
271
+ def monitor_thread(debug)
272
+ Glimmer::LibUI.timer(1) do
273
+ p @player.history if debug
274
+ next if current_station.nil? || @player.alive?
275
+
276
+ message_box("player '#{@player.backend}' stopped!", @player.thr.to_s)
277
+ stop_station
278
+ true
279
+ end
280
+ end
281
+
282
+ def async_fetch_stations
283
+ @loaded_station_offset += @loaded_station_count
284
+ @loaded_station_count *= 2
285
+ Thread.new do
286
+ new_station_count = [@loaded_station_count, radio_station_count - @loaded_station_offset].min
287
+ @stations += Model::RadioBrowser.topvote(new_station_count, offset: @loaded_station_offset)
288
+
289
+ Glimmer::LibUI.queue_main do
290
+ refresh_view
291
+ async_fetch_stations if @stations.count < radio_station_count
292
+ end
293
+ end
294
+ end
295
+ end
296
+ end
297
+ end
data/lib/rubio.rb CHANGED
@@ -1,12 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'glimmer-dsl-libui'
4
-
5
3
  require_relative 'rubio/version'
6
- require_relative 'rubio/station'
7
- require_relative 'rubio/radio_browser'
8
- require_relative 'rubio/player'
9
- require_relative 'rubio/radio'
4
+ require_relative 'rubio/view/radio'
10
5
 
11
6
  module Rubio
12
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubio-radio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-08-05 00:00:00.000000000 Z
12
+ date: 2022-08-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: glimmer-dsl-libui
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - '='
19
19
  - !ruby/object:Gem::Version
20
- version: 0.5.18
20
+ version: 0.5.22
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - '='
26
26
  - !ruby/object:Gem::Version
27
- version: 0.5.18
27
+ version: 0.5.22
28
28
  description: Rubio is a simple radio player written in Ruby.
29
29
  email:
30
30
  - 2xijok@gmail.com
@@ -39,11 +39,12 @@ files:
39
39
  - TODO.md
40
40
  - exe/rubio
41
41
  - lib/rubio.rb
42
- - lib/rubio/player.rb
43
- - lib/rubio/radio.rb
44
- - lib/rubio/radio_browser.rb
45
- - lib/rubio/station.rb
42
+ - lib/rubio/model/bookmark.rb
43
+ - lib/rubio/model/player.rb
44
+ - lib/rubio/model/radio_browser.rb
45
+ - lib/rubio/model/station.rb
46
46
  - lib/rubio/version.rb
47
+ - lib/rubio/view/radio.rb
47
48
  homepage: https://github.com/kojix2/rubio
48
49
  licenses:
49
50
  - MIT
data/lib/rubio/player.rb DELETED
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rubio
4
- class Player
5
- attr_accessor :backend, :pid, :thr, :status, :history
6
-
7
- def initialize(backend = OS.linux? ? 'cvlc' : 'vlc -I rc')
8
- raise unless backend.is_a?(String)
9
-
10
- @backend = backend
11
- @pid = nil
12
- @thr = nil
13
- @status = []
14
- @history = []
15
- end
16
-
17
- def alive?
18
- return false if @thr.nil?
19
-
20
- @thr.alive?
21
- end
22
-
23
- def stop?
24
- @thr.nil? || @thr.stop?
25
- end
26
-
27
- def play(url)
28
- # Do not include spaces in the command line
29
- # if a space exist :
30
- # * sh -c command url # this process with @pid will be killed
31
- # * cmmand url # will not be killd because pid is differennt
32
- # if no space :
33
- # * cmmand url # will be killed by @pid
34
- raise if url.match(/\s/)
35
-
36
- @pid = spawn(*backend.split(' '), url)
37
- @thr = Process.detach(@pid)
38
- @status = [@pid, @thr]
39
- @history << @status
40
- end
41
-
42
- def stop
43
- return unless alive?
44
-
45
- r = Process.kill(OS.windows? ? :KILL : :TERM, pid)
46
- @thr = nil
47
- @pid = nil
48
- r
49
- end
50
-
51
- def stop_all
52
- @history.each do |pid, thr|
53
- Process.kill(OS.windows? ? :KILL : :TERM, pid) if thr.alive?
54
- end
55
- end
56
- end
57
- end
data/lib/rubio/radio.rb DELETED
@@ -1,164 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'glimmer-dsl-libui'
4
-
5
- module Rubio
6
- class Radio
7
- include Glimmer::LibUI::Application
8
-
9
- options :backend, :initial_width, :initial_height
10
- option :radio_station_count, default: 10_000
11
- option :debug, default: false
12
- option :visible_menu, default: true
13
- option :show_page_count, default: false
14
- option :table_per_page, default: 20
15
-
16
- attr_reader :stations, :player
17
-
18
- before_body do
19
- @stations_all, @table = RadioBrowser.topvote(radio_station_count)
20
- @stations = @stations_all.dup
21
- @station_uuid = nil
22
- @player = Player.new(backend)
23
- @initial_width = (initial_width || 400).to_i
24
- @initial_height = (initial_height || calculate_initial_height).to_i
25
-
26
- monitor_thread(debug)
27
- end
28
-
29
- body do
30
- radio_menu_bar
31
-
32
- window('Rubio', @initial_width, @initial_height) do
33
- vertical_box do
34
- horizontal_box do
35
- @station_table = refined_table(
36
- table_columns: {
37
- 'Play' => { button: {
38
- on_clicked: lambda { |row|
39
- station = @station_table.paginated_model_array[row]
40
- select_station(station)
41
- }
42
- } },
43
- 'name' => :text,
44
- 'language' => :text
45
- },
46
- model_array: stations,
47
- per_page: table_per_page.to_i,
48
- visible_page_count: show_page_count
49
- )
50
- end
51
- end
52
-
53
- on_closing do
54
- @player.stop_all
55
- end
56
- end
57
- end
58
-
59
- def radio_menu_bar
60
- return unless OS.mac? || visible_menu
61
-
62
- menu('Radio') do
63
- menu_item('Stop') do
64
- on_clicked do
65
- stop_uuid(@station_uuid)
66
- @station_uuid = nil
67
- end
68
- end
69
-
70
- if OS.mac?
71
- about_menu_item do
72
- on_clicked do
73
- about_message_box
74
- end
75
- end
76
- end
77
-
78
- quit_menu_item do
79
- on_clicked do
80
- @player.stop_all
81
- end
82
- end
83
- end
84
-
85
- menu('Help') do
86
- menu_item('About') do
87
- on_clicked do
88
- about_message_box
89
- end
90
- end
91
- end
92
- end
93
-
94
- def about_message_box
95
- license = begin
96
- File.read(File.expand_path('../../LICENSE.txt', __dir__))
97
- rescue StandardError
98
- ''
99
- end
100
- product = "rubio-radio #{Rubio::VERSION}"
101
- message_box(product, "#{product}\n\n#{license}")
102
- end
103
-
104
- def select_station(station)
105
- station_uuid = station.stationuuid
106
- stop_uuid(@station_uuid)
107
- if @station_uuid == station_uuid
108
- @station_uuid = nil
109
- elsif play_uuid(station_uuid)
110
- @station_uuid = station_uuid
111
- end
112
- end
113
-
114
- def play_uuid(station_uuid)
115
- station = uuid_to_station(station_uuid)
116
- begin
117
- @player.play(station.url)
118
- rescue StandardError => e
119
- message_box(e.message)
120
- return false
121
- end
122
- station.playing = true
123
- end
124
-
125
- def stop_uuid(station_uuid)
126
- return if station_uuid.nil?
127
-
128
- station = uuid_to_station(station_uuid)
129
- @player.stop
130
- station.playing = false
131
- end
132
-
133
- private
134
-
135
- def calculate_initial_height
136
- if OS.linux?
137
- 107 + (visible_menu ? 26 : 0) + 24 * table_per_page.to_i
138
- elsif OS.mac? && OS.host_cpu == 'arm64'
139
- 90 + 24 * table_per_page.to_i
140
- elsif OS.mac?
141
- 85 + 19 * table_per_page.to_i
142
- else # Windows
143
- 95 + 19 * table_per_page.to_i
144
- end
145
- end
146
-
147
- def monitor_thread(debug)
148
- Glimmer::LibUI.timer(1) do
149
- p @player.history if debug
150
- next if @station_uuid.nil? || @player.alive?
151
-
152
- message_box("player '#{@player.backend}' stopped!", @player.thr.to_s)
153
- stop_uuid(@station_uuid)
154
- @station_uuid = nil
155
- true
156
- end
157
- end
158
-
159
- def uuid_to_station(uuid)
160
- idx = @table[uuid]
161
- @stations_all[idx]
162
- end
163
- end
164
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
- require 'open-uri'
5
-
6
- module Rubio
7
- # https://www.radio-browser.info
8
- module RadioBrowser
9
- module_function
10
-
11
- def base_url
12
- 'http://all.api.radio-browser.info/json/'
13
- end
14
-
15
- def topvote(n = 100)
16
- content = URI.parse(base_url + "stations/topvote/#{n}")
17
- table = {} # uuid => index
18
- result = []
19
- JSON[content.read].each_with_index do |s, i|
20
- table[s['stationuuid']] = i
21
- result << Station.new(s['stationuuid'], s['name'], s['language'], s['url_resolved'])
22
- end
23
- [result, table]
24
- end
25
- end
26
- end
data/lib/rubio/station.rb DELETED
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rubio
4
- Station = Struct.new(:stationuuid, :name, :language, :url, :play) do
5
- attr_reader :playing
6
-
7
- def initialize(*args, **kwargs)
8
- super(*args, **kwargs)
9
- self.playing = false
10
- end
11
-
12
- def playing=(value)
13
- self.play = value ? '■' : '▶'
14
- @playing = value
15
- end
16
- end
17
- end