rubio-radio 0.0.5 → 0.0.7

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: 251dc5095f4659c3598be19ed733cc71ed404957a582071eed209d0ae2d27757
4
- data.tar.gz: 8e1583db5b2a5b85838e5c314587a58365b8a74851855dca887a32c2b910a236
3
+ metadata.gz: 7aae7e45f3433a76e59a907ee6f8ca6c979b0f250236ed86261e841c1f3fd14b
4
+ data.tar.gz: 270b02be3f3e86878a0d0e4d763ce29a26a148ba3bcee40d1991415c528e3733
5
5
  SHA512:
6
- metadata.gz: 1866d8bd12d24ab570ab149d73e4ad166246f4160f80050de7ac4f2bf9d719befdf8cd04741593dbee5ac333f33a3b5ff4fa055d308747a490fd673137c21b4b
7
- data.tar.gz: bc817eda194e723664ab321c0be218856ac700230d70c0be210fcec78e4e615b5038bdc270dd0c2d696500895638f4338d9ba3fa1a86c8f92173cf29abf0913d
6
+ metadata.gz: 763eb84cfcee8ea9abb090b0e7b9c8b47e962fcfde3e6a6100b0e0e119d6a2b022e251cf81a6b19609494e3a106b9bc8e53025e525c702095092a84c46fc1947
7
+ data.tar.gz: 4bba95c7e203ba49c1cc96f6103fa57e4b4e2359141ed81f99e1799b3c81b301254a5a334f15f512326850a3156caa78101a1cb67aad2a57bc85ed327a52ca6a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.7
4
+
5
+ - Add country property to radio stations
6
+
7
+ ## 0.0.6
8
+
9
+ - Command option `--[no-]margins` to show/hide margins around window content
10
+ - Command option `--[no-]info` to show/hide currently playing (song) info when using `vlc -I rc` backend only [true]
11
+ - Change the default backend to `vlc -I rc` in order to show currently playing song
12
+ - Update command option `--count` to accept `-1` as a valid value for fetching all radio stations
13
+ - Make app fetch all radio stations by default (`--count -1`)
14
+ - Fix issue with bookmark/unbookmark menu items remaining enabled after stopping song
15
+
3
16
  ## 0.0.5
4
17
 
5
18
  - Upgrade to glimmer-dsl-libui v0.5.22
@@ -7,6 +20,9 @@
7
20
  - View menu with "All", "Bookmarks", and "Playing" View menu items
8
21
  - Command option `--[no-]bookmarks` to show/hide bookmarks in table
9
22
  - Command option `--[no-]gradual` to load radio stations gradually (preventing user from waiting for app to start) or avoid loading gradually
23
+ - Support AND-based filtering with multiple words separated by space treated as WORD1 AND WORD2, ...
24
+ - Support exact term filtering with double-quoted filter term (e.g. "WORD1 WORD2")
25
+ - Support column-based filtering by prefixing a query term with column name + colon (e.g. "language:english"), which can be combined with other words (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")
10
26
 
11
27
  ## 0.0.4
12
28
 
data/README.md CHANGED
@@ -1,17 +1,9 @@
1
1
  # rubio-radio
2
2
  [![Gem Version](https://badge.fury.io/rb/rubio-radio.svg)](https://badge.fury.io/rb/rubio-radio)
3
3
 
4
- Linux
5
-
6
- ![linux screenshot](screenshots/rubio-radio-linux.png)
7
-
8
- Mac
9
-
10
- ![mac screenshot](screenshots/rubio-radio-mac.png)
11
-
12
- Windows
13
-
14
- ![windows screenshot](screenshots/rubio-radio-windows.png)
4
+ | Mac | Linux | Windows |
5
+ |:---:|:-----:|:-------:|
6
+ |![mac screenshot](screenshots/rubio-radio-mac.png)|![linux screenshot](screenshots/rubio-radio-linux.png)|![windows screenshot](screenshots/rubio-radio-windows.png)|
15
7
 
16
8
  :bowtie: Alpha
17
9
 
@@ -21,7 +13,7 @@ Windows
21
13
 
22
14
  **[VLC](https://github.com/videolan/vlc)**
23
15
 
24
- `rubio` uses the `vlc -I dummy` as the audio playback backend.
16
+ `rubio` uses the `vlc -I rc` as the audio playback backend.
25
17
 
26
18
  On Mac, it is recommended that you install VLC via [Homebrew](https://brew.sh/) to ensure the `vlc` command is added to the PATH environment variable automatically:
27
19
 
@@ -45,7 +37,7 @@ Run with this command:
45
37
  rubio
46
38
  ```
47
39
 
48
- The top 10,000 [Radio Browser](https://www.radio-browser.info/) stations are displayed by default. But, you can customize the count (note that currently, there are only about 32,000 [Radio Browser](https://www.radio-browser.info/) stations total).
40
+ All [Radio Browser](https://www.radio-browser.info/) stations are displayed by default. But, you can customize the count with `--count COUNT` (note that currently, there are only about 33,000 [Radio Browser](https://www.radio-browser.info/) stations total). Setting the count to `-1` will fetch all stations.
49
41
 
50
42
  ```
51
43
  rubio --count 20000
@@ -57,7 +49,7 @@ The stations are fetched gradually (asynchronously) from the [Radio Browser](htt
57
49
  rubio --no-gradual
58
50
  ```
59
51
 
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.
52
+ Default player is `vlc -I rc`, which enables showing currently playing song info (except on Windows). But, you can use any command line player that can take URL of radio station as its first argument.
61
53
 
62
54
  ```
63
55
  rubio --backend mpg123
@@ -71,10 +63,10 @@ rubio --help
71
63
 
72
64
  ```
73
65
  Usage: rubio [options]
74
- --vlc [STR] use VLC interface STR on the backend [dummy]
66
+ --vlc [STR] use VLC interface STR on the backend [rc]
75
67
  --mpg123 use mpg123 on the backend
76
- -b, --backend STR command to use as backend player ['vlc -I dummy']
77
- -c, --count INT number of stations to fetch from radio-browser [10000]
68
+ -b, --backend STR command to use as backend player ['vlc -I rc']
69
+ -c, --count INT number of stations to fetch from radio-browser or -1 to fetch them all [-1]
78
70
  --per-page INT number of stations per page [20]
79
71
  -w, --width INT main window width
80
72
  -h, --height INT main window height
@@ -82,6 +74,8 @@ Usage: rubio [options]
82
74
  --[no-]menu show/hide menu [true]
83
75
  --[no-]bookmarks show/hide bookmarks [true]
84
76
  --[no-]gradual gradually/non-gradually fetch stations [true]
77
+ --[no-]margins show/hide margins [true]
78
+ --[no-]info show/hide currently playing (song) info when using 'vlc -I rc' backend only [true]
85
79
  --debug output status of monitored threads
86
80
  --help show this help message
87
81
  --version show the rubio version number
@@ -90,15 +84,15 @@ Usage: rubio [options]
90
84
  Examples:
91
85
 
92
86
  ```
93
- rubio --vlc # `vlc -I rc` (interactive command line interface)
94
- rubio --mpg123 # `rubio --backend mpg123`
87
+ rubio --vlc dummy # vlc -I dummy (interactive command line interface)
88
+ rubio --mpg123 # rubio --backend mpg123
95
89
  rubio --count 1000 # Displays the top 1,000 Radio Browser stations
96
90
  ```
97
91
 
98
92
  Minimalistic Example:
99
93
 
100
94
  ```
101
- rubio --per-page 6 --no-menu --no-bookmarks
95
+ rubio --per-page 6 --no-margins --no-info --no-menu --no-bookmarks
102
96
  ```
103
97
 
104
98
  ![small screen linux screenshot](screenshots/rubio-radio-linux-example-small.png)
@@ -111,13 +105,53 @@ rubio --page-count
111
105
 
112
106
  ![page count mac screenshot](screenshots/rubio-radio-mac-example-page-count.png)
113
107
 
108
+ ### Filtering
109
+
110
+ The filter field does AND-based filtering when you enter multiple words separated by spaces:
111
+
112
+ ```
113
+ jazz smooth
114
+ ```
115
+
116
+ Also, the filter field supports exact term filtering if you enter multiple words surrounded by double-quotes.
117
+
118
+ ```
119
+ "bossa nova"
120
+ ```
121
+
122
+ Last but not least, the filter field supports column-specific queries by including a full column name or the first few letters, followed by colon (:), followed by a single word or double-quoted multiple words for exact term matching against the column:
123
+
124
+ ```
125
+ name:talk language:eng
126
+ ```
127
+
128
+ or just:
129
+
130
+ ```
131
+ n:talk l:eng
132
+ ```
133
+
134
+ ![advanced filtering mac screenshot](screenshots/rubio-radio-mac-example-advanced-filtering.png)
135
+
136
+ This advanced example matches the word `FM` against the name column, and language `bahasa indonesia` against the language column.
137
+
138
+ ```
139
+ n:FM l:"bahasa indonesia"
140
+ ```
141
+
142
+ Finally, you can mix different types of filters:
143
+
144
+ ```
145
+ brasil "bossa jazz" l:brazilian l:portuguese
146
+ ```
147
+
114
148
  ### Menus
115
149
 
116
150
  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
151
 
118
152
  ![view book marks mac screenshot](screenshots/rubio-radio-mac-example-view-bookmarks.png)
119
153
 
120
- Bookmarks are stored in `File.join(Dir.home, '.rubio-radio', 'bookmarks.yml')`
154
+ Bookmarks are stored in `~/.rubio-radio/bookmarks.yml`
121
155
 
122
156
  ## Links
123
157
 
data/TODO.md CHANGED
@@ -1,9 +1,3 @@
1
1
  # TODO
2
2
 
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)
3
+ N/A
data/exe/rubio CHANGED
@@ -5,19 +5,20 @@ require 'puts_debuggerer' if ENV['PD'].to_s.downcase == 'true'
5
5
  require 'rubio'
6
6
  require 'optparse'
7
7
 
8
- options = { backend: 'vlc -I dummy' }
8
+ options = { backend: 'vlc -I rc' }
9
9
 
10
10
  opt = OptionParser.new
11
11
  opt.summary_width = 23
12
- opt.on('--vlc [STR]', 'use VLC interface STR on the backend [dummy]') do |i|
13
- i ||= 'dummy'
12
+ opt.on('--vlc [STR]', 'use VLC interface STR on the backend [rc]') do |i|
13
+ i ||= 'rc'
14
14
  options[:backend] = "vlc -I #{i}"
15
15
  end
16
16
  opt.on('--mpg123', 'use mpg123 on the backend') { options[:backend] = 'mpg123' }
17
- opt.on('-b', '--backend STR', String, 'command to use as backend player [\'vlc -I dummy\']') do |b|
17
+ opt.on('-b', '--backend STR', String, 'command to use as backend player [\'vlc -I rc\']') do |b|
18
18
  options[:backend] = b
19
19
  end
20
- opt.on('-c', '--count INT', Numeric, 'number of stations to fetch from radio-browser [10000]') do |c|
20
+ opt.on('-c', '--count INT', Numeric,
21
+ 'number of stations to fetch from radio-browser or -1 to fetch them all [-1]') do |c|
21
22
  options[:radio_station_count] = c
22
23
  end
23
24
  opt.on('--per-page INT', Numeric, 'number of stations per page [20]') { |c| options[:table_per_page] = c }
@@ -29,6 +30,11 @@ opt.on('--[no-]bookmarks', TrueClass, 'show/hide bookmarks [true]') { |b| option
29
30
  opt.on('--[no-]gradual', TrueClass, 'gradually/non-gradually fetch stations [true]') do |g|
30
31
  options[:gradually_fetch_stations] = g
31
32
  end
33
+ opt.on('--[no-]margins', TrueClass, 'show/hide margins [true]') { |m| options[:show_margins] = m }
34
+ opt.on('--[no-]info', TrueClass,
35
+ 'show/hide currently playing (song) info when using \'vlc -I rc\' backend only [true]') do |i|
36
+ options[:show_currently_playing] = i
37
+ end
32
38
  opt.on('--debug', 'output status of monitored threads') { options[:debug] = true }
33
39
  opt.on('--help', 'show this help message') do
34
40
  puts opt
@@ -49,7 +55,7 @@ end
49
55
 
50
56
  begin
51
57
  Rubio::View::Radio.launch(**options)
52
- rescue StandardError => e
53
- Rubio::View::Radio.launched_application&.player&.stop_all
58
+ rescue => e
59
+ Rubio::View::Radio.launched_application&.presenter&.player&.stop_all
54
60
  raise e
55
61
  end
@@ -33,7 +33,7 @@ module Rubio
33
33
  def save_all
34
34
  bookmarks_yaml = YAML.dump(all)
35
35
  File.write(FILE_RUBIO_RADIO_BOOKMARKS, bookmarks_yaml)
36
- rescue StandardError => e
36
+ rescue => e
37
37
  puts 'Failed in saving bookmarks!'
38
38
  puts all.inspect
39
39
  puts e.full_message
@@ -43,7 +43,7 @@ module Rubio
43
43
  def load_all
44
44
  bookmarks_yaml = File.read(FILE_RUBIO_RADIO_BOOKMARKS)
45
45
  YAML.load(bookmarks_yaml)
46
- rescue StandardError => e
46
+ rescue => e
47
47
  puts 'Failed in loading bookmarks! Returning empty bookmarks.'
48
48
  puts e.full_message
49
49
  []
@@ -3,29 +3,40 @@
3
3
  module Rubio
4
4
  module Model
5
5
  class Player
6
+ CURRENTLY_PLAYING_NONE = 'None'
7
+ CURRENTLY_PLAYING_LENGTH_PER_LINE = 90
8
+
6
9
  attr_accessor :backend, :pid, :thr, :status, :history
10
+ attr_reader :show_currently_playing, :currently_playing
11
+ alias show_currently_playing? show_currently_playing
7
12
 
8
- def initialize(backend = OS.linux? ? 'cvlc' : 'vlc -I rc')
13
+ def initialize(backend = 'vlc -I rc', show_currently_playing: true)
9
14
  raise unless backend.is_a?(String)
10
15
 
11
16
  @backend = backend
17
+ @show_currently_playing = show_currently_playing
12
18
  @pid = nil
13
19
  @thr = nil
14
- @status = []
20
+ @status = {}
15
21
  @history = []
22
+ self.currently_playing = CURRENTLY_PLAYING_NONE
16
23
  end
17
24
 
18
- def alive?
19
- return false if @thr.nil?
25
+ def currently_playing=(value)
26
+ value = "Playing: #{value}"
20
27
 
21
- @thr.alive?
28
+ @currently_playing = break_by_lines(value)
29
+ end
30
+
31
+ def alive?
32
+ @thr&.alive? || (@io && !@io.closed?)
22
33
  end
23
34
 
24
35
  def stop?
25
36
  @thr.nil? || @thr.stop?
26
37
  end
27
38
 
28
- def play(url)
39
+ def play(url, station_name: 'N/A')
29
40
  # Do not include spaces in the command line
30
41
  # if a space exist :
31
42
  # * sh -c command url # this process with @pid will be killed
@@ -34,25 +45,114 @@ module Rubio
34
45
  # * cmmand url # will be killed by @pid
35
46
  raise if url.match(/\s/)
36
47
 
37
- @pid = spawn(*backend.split(' '), url)
38
- @thr = Process.detach(@pid)
39
- @status = [@pid, @thr]
48
+ @playing_station_name = station_name
49
+
50
+ if show_currently_playing? && backend == 'vlc -I rc' && !OS.windows?
51
+ @io = IO.popen("#{backend} \"#{url}\"", 'r+')
52
+ update_currently_playing
53
+ continuously_fetch_currently_playing
54
+ else
55
+ @pid = spawn(*backend.split(' '), url)
56
+ @thr = Process.detach(@pid)
57
+ end
58
+
59
+ @status = { thr: @thr, pid: @pid, io: @io }
40
60
  @history << @status
41
61
  end
42
62
 
43
- def stop
44
- return unless alive?
63
+ def continuously_fetch_currently_playing
64
+ return if @continuously_fetching_currently_playing
45
65
 
46
- r = Process.kill(OS.windows? ? :KILL : :TERM, pid)
47
- @thr = nil
48
- @pid = nil
66
+ @continuously_fetching_currently_playing = true
67
+
68
+ Glimmer::LibUI.timer(1) do
69
+ update_currently_playing
70
+ @continuously_fetching_currently_playing
71
+ end
72
+ end
73
+
74
+ def update_currently_playing
75
+ Glimmer::LibUI.queue_main do
76
+ self.currently_playing = currently_playing_text if alive?
77
+ end
78
+ end
79
+
80
+ def currently_playing_text
81
+ currently_playing_info = info
82
+ if currently_playing_info && !currently_playing_info.strip.empty?
83
+ [@playing_station_name, currently_playing_info].join(' - ')
84
+ else
85
+ @playing_station_name
86
+ end
87
+ end
88
+
89
+ def info
90
+ result = io_command('info')
91
+ now_playing_line = result.lines.find {|l| l.include?('now_playing:')}
92
+ if now_playing_line
93
+ now_playing_line.split('now_playing:').last.chomp.strip
94
+ end
95
+ rescue
96
+ nil
97
+ end
98
+
99
+ def stop(thr: nil, pid: nil, io: nil)
100
+ thr ||= @thr
101
+ pid ||= @pid
102
+ io ||= @io
103
+ if thr&.alive?
104
+ r = Process.kill(OS.windows? ? :KILL : :TERM, pid)
105
+ elsif io && !io.closed?
106
+ io.close
107
+ r = io.closed?
108
+ self.currently_playing = CURRENTLY_PLAYING_NONE
109
+ end
110
+ thr = nil
111
+ pid = nil
112
+ io = nil
49
113
  r
50
114
  end
51
115
 
52
116
  def stop_all
53
- @history.each do |pid, thr|
54
- Process.kill(OS.windows? ? :KILL : :TERM, pid) if thr.alive?
117
+ @continuously_fetching_currently_playing = false
118
+ @history.each { |history| stop(**history) }
119
+ end
120
+
121
+ private
122
+
123
+ def break_by_lines(text, length_per_line: CURRENTLY_PLAYING_LENGTH_PER_LINE)
124
+ new_text_lines = ['']
125
+ text.chars.each_with_index do |char, i|
126
+ if (char != ' ' && new_text_lines[-1].length < length_per_line - 1) ||
127
+ (char == ' ' && new_text_lines[-1].length < length_per_line)
128
+ new_text_lines[-1] = new_text_lines[-1] + char
129
+ else
130
+ new_text_lines[-1] = new_text_lines[-1] + '-' if new_text_lines[-1][-1] != ' '
131
+ new_text_lines << char
132
+ end
133
+ end
134
+ new_text_lines.join("\n")
135
+ end
136
+
137
+ def io_command(command)
138
+ @io.puts(command)
139
+ io_all_gets
140
+ end
141
+
142
+ def io_all_gets
143
+ result = ''
144
+ while gets_result = io_gets
145
+ result += gets_result.to_s
146
+ end
147
+ result
148
+ end
149
+
150
+ def io_gets
151
+ Timeout.timeout(0.01) do
152
+ @io.gets
55
153
  end
154
+ rescue
155
+ nil
56
156
  end
57
157
  end
58
158
  end
@@ -19,7 +19,7 @@ module Rubio
19
19
  content = URI.parse(base_url + "stations/topvote/#{n}?offset=#{offset}")
20
20
  result = []
21
21
  JSON[content.read].each_with_index do |s, _i|
22
- result << Station.new(s['stationuuid'], s['name'], s['language'], s['url_resolved'])
22
+ result << Station.new(s['stationuuid'], s['name'], s['language'], s['country'], s['url_resolved'])
23
23
  end
24
24
  result
25
25
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../model/radio_browser'
4
+ require_relative '../model/player'
5
+
6
+ module Rubio
7
+ module Model
8
+ # This is a presenter for the Radio view, which is an advanced controller
9
+ class RadioPresenter
10
+ attr_reader :player, :initial_width, :initial_height, :options
11
+ attr_accessor :stations, :current_station, :view, :window_height
12
+
13
+ # Initializes with view options below:
14
+ # :backend, :initial_width, :initial_height, :radio_station_count, :debug,
15
+ # :show_menu, :show_page_count, :show_bookmarks, :show_margins
16
+ # :gradually_fetch_stations, :table_per_page
17
+ def initialize(options = {})
18
+ @options = options
19
+ @options[:radio_station_count] = 1_000_000 if options[:radio_station_count] == -1
20
+ @loaded_station_count = [options[:gradually_fetch_stations] ? 100 : options[:radio_station_count], options[:radio_station_count]].min
21
+ @loaded_station_offset = 0
22
+ @stations = Model::RadioBrowser.topvote(@loaded_station_count, offset: @loaded_station_offset)
23
+ @player = Model::Player.new(options[:backend], show_currently_playing: options[:show_currently_playing])
24
+ @initial_width = (options[:initial_width] || (options[:show_bookmarks] ? 740 : 620)).to_i
25
+ @initial_height = (options[:initial_height] || calculate_initial_height).to_i
26
+ @window_height = @initial_height
27
+ @view = :all
28
+
29
+ Glimmer::DataBinding::Observer::Proc.new do
30
+ self.window_height = calculate_initial_height
31
+ end.observe(@player, :currently_playing)
32
+ end
33
+
34
+ def select_station(station)
35
+ playing = station.playing?
36
+ stop_station
37
+ self.current_station = station
38
+ if playing
39
+ self.current_station = nil
40
+ else
41
+ play_station
42
+ end
43
+ end
44
+
45
+ def toggle_bookmarked_station(station)
46
+ return unless station
47
+
48
+ station.bookmarked = !station.bookmarked?
49
+ end
50
+
51
+ def play_station
52
+ @player.play(current_station.url, station_name: current_station.name)
53
+ current_station.playing = true
54
+ rescue => e
55
+ self.current_station = nil
56
+ raise e
57
+ end
58
+
59
+ def stop_station
60
+ return if current_station.nil?
61
+
62
+ @player.stop
63
+ current_station.playing = false
64
+ self.current_station = nil
65
+ end
66
+
67
+ def stations_incomplete?
68
+ !@all_stations_fetched && @stations.count < options[:radio_station_count]
69
+ end
70
+
71
+ def fetch_more_stations
72
+ @loaded_station_offset += @loaded_station_count
73
+ @loaded_station_count *= 2
74
+ new_station_count = [@loaded_station_count, options[:radio_station_count] - @loaded_station_offset].min
75
+ old_station_count = @stations.count
76
+ self.stations += Model::RadioBrowser.topvote(new_station_count, offset: @loaded_station_offset)
77
+ @all_stations_fetched = @stations.count == old_station_count
78
+ self.stations
79
+ end
80
+
81
+ private
82
+
83
+ def calculate_initial_height
84
+ window_margin = options[:show_margins] ? (OS.linux? ? 22 : 40) : 0
85
+ currently_playing_height = options[:show_currently_playing] ? ((@player.currently_playing ? @player.currently_playing.lines.size : 1)*16 + 8) : 0
86
+ table_per_page = options[:table_per_page].to_i
87
+ if OS.linux?
88
+ 108 + window_margin + currently_playing_height + (options[:show_menu] ? 26 : 0) + 24 * table_per_page
89
+ elsif OS.mac? && OS.host_cpu == 'arm64'
90
+ 90 + window_margin + currently_playing_height + 24 * table_per_page
91
+ elsif OS.mac?
92
+ 85 + window_margin + currently_playing_height + 19 * table_per_page
93
+ else # Windows
94
+ 95 + window_margin + currently_playing_height + 19 * table_per_page
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -4,7 +4,7 @@ require_relative 'bookmark'
4
4
 
5
5
  module Rubio
6
6
  module Model
7
- Station = Struct.new(:stationuuid, :name, :language, :url, :play, :bookmark) do
7
+ Station = Struct.new(:stationuuid, :name, :language, :country, :url, :play, :bookmark) do
8
8
  attr_reader :playing, :bookmarked
9
9
  alias_method :playing?, :playing
10
10
  alias_method :bookmarked?, :bookmarked
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.5'
4
+ VERSION = '0.0.7'
5
5
  end
@@ -2,8 +2,7 @@
2
2
 
3
3
  require 'glimmer-dsl-libui'
4
4
 
5
- require_relative '../model/radio_browser'
6
- require_relative '../model/player'
5
+ require_relative '../model/radio_presenter'
7
6
 
8
7
  module Rubio
9
8
  module View
@@ -11,49 +10,60 @@ module Rubio
11
10
  include Glimmer::LibUI::Application
12
11
 
13
12
  options :backend, :initial_width, :initial_height
14
- option :radio_station_count, default: 10_000
13
+ option :radio_station_count, default: -1
15
14
  option :debug, default: false
16
15
  option :show_menu, default: true
17
16
  option :show_page_count, default: false
18
17
  option :show_bookmarks, default: true
18
+ option :show_margins, default: true
19
+ option :show_currently_playing, default: true
19
20
  option :gradually_fetch_stations, default: true
20
21
  option :table_per_page, default: 20
21
22
 
22
- attr_reader :stations, :player
23
- attr_accessor :current_station, :view
23
+ attr_reader :presenter
24
24
 
25
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
26
+ # options is a method on Glimmer::LibUI::Application that contains all options declared above
27
+ @presenter = Model::RadioPresenter.new(options)
33
28
  end
34
29
 
35
30
  after_body do
36
31
  monitor_thread(debug)
37
- async_fetch_stations if gradually_fetch_stations && @stations.count < radio_station_count
32
+ async_fetch_stations if gradually_fetch_stations && @presenter.stations_incomplete?
38
33
  end
39
34
 
40
35
  body do
41
36
  radio_menu_bar
42
37
 
43
- window('Rubio', @initial_width, @initial_height) do
38
+ window('Rubio', @presenter.initial_width, @presenter.initial_height / (OS.linux? ? 2.0 : 1)) do
39
+ margined show_margins
40
+ height <= [@presenter, :window_height,
41
+ on_read: ->(value) {
42
+ w = body_root
43
+ if w.nil? # window not built yet
44
+ # Linux libui is weird. The first time height is set, it must be halved
45
+ value / (OS.linux? ? 2.0 : 1)
46
+ else
47
+ value -= 50 if OS.linux? # more Linux weirdness
48
+ value = value > w.height ? value : w.height # grow only, never shrink
49
+ value
50
+ end
51
+ }
52
+ ]
53
+
44
54
  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
55
+ currently_playing_label
56
+
57
+ @station_table = refined_table(
58
+ table_columns: station_table_columns,
59
+ model_array: @presenter.stations,
60
+ per_page: table_per_page.to_i,
61
+ visible_page_count: show_page_count
62
+ )
53
63
  end
54
64
 
55
65
  on_closing do
56
- @player.stop_all
66
+ @presenter.player.stop_all
57
67
  end
58
68
  end
59
69
  end
@@ -69,28 +79,28 @@ module Rubio
69
79
  def radio_menu
70
80
  menu('Radio') do
71
81
  menu_item('Stop') do
72
- enabled <= [self, 'current_station', { on_read: ->(value) { !!value } }]
73
-
82
+ enabled <= [@presenter, 'current_station', on_read: ->(value) { !!value }]
83
+
74
84
  on_clicked do
75
- stop_station
85
+ @presenter.stop_station
76
86
  end
77
87
  end
78
88
 
79
89
  separator_menu_item
80
90
 
81
91
  menu_item('Bookmark') do
82
- enabled <= [self, 'current_station.bookmarked', { on_read: :! }]
83
-
92
+ enabled <= [@presenter, 'current_station.bookmarked', on_read: ->(value) { value == false }]
93
+
84
94
  on_clicked do
85
- toggle_bookmarked_station(current_station) if current_station
95
+ toggle_bookmarked_station
86
96
  end
87
97
  end
88
98
 
89
99
  menu_item('Unbookmark') do
90
- enabled <= [self, 'current_station.bookmarked']
91
-
100
+ enabled <= [@presenter, 'current_station.bookmarked', on_read: ->(value) { value == true }]
101
+
92
102
  on_clicked do
93
- toggle_bookmarked_station(current_station) if current_station
103
+ toggle_bookmarked_station
94
104
  end
95
105
  end
96
106
 
@@ -106,7 +116,7 @@ module Rubio
106
116
 
107
117
  quit_menu_item do
108
118
  on_clicked do
109
- @player.stop_all
119
+ @presenter.player.stop_all
110
120
  end
111
121
  end
112
122
  end
@@ -115,30 +125,33 @@ module Rubio
115
125
  def view_menu
116
126
  menu('View') do
117
127
  radio_menu_item('All') do
118
- checked <=> [self, :view,
119
- { on_read: ->(value) { value == :all },
120
- on_write: ->(_value) { :all } }]
121
-
128
+ checked <=> [@presenter, :view,
129
+ on_read: ->(value) { value == :all },
130
+ on_write: ->(value) { :all },
131
+ ]
132
+
122
133
  on_clicked do
123
134
  view_all
124
135
  end
125
136
  end
126
137
 
127
138
  radio_menu_item('Bookmarks') do
128
- checked <=> [self, :view,
129
- { on_read: ->(value) { value == :bookmarks },
130
- on_write: ->(_value) { :bookmarks } }]
131
-
139
+ checked <=> [@presenter, :view,
140
+ on_read: ->(value) { value == :bookmarks },
141
+ on_write: ->(value) { :bookmarks },
142
+ ]
143
+
132
144
  on_clicked do
133
145
  view_bookmarks
134
146
  end
135
147
  end
136
148
 
137
149
  radio_menu_item('Playing') do
138
- checked <=> [self, :view,
139
- { on_read: ->(value) { value == :playing },
140
- on_write: ->(_value) { :playing } }]
141
-
150
+ checked <=> [@presenter, :view,
151
+ on_read: ->(value) { value == :playing },
152
+ on_write: ->(value) { :playing },
153
+ ]
154
+
142
155
  on_clicked do
143
156
  view_playing
144
157
  end
@@ -158,13 +171,27 @@ module Rubio
158
171
  end
159
172
  end
160
173
 
174
+ def currently_playing_label
175
+ return unless show_currently_playing && backend == 'vlc -I rc' && !OS.windows?
176
+
177
+ label do
178
+ stretchy false
179
+ text <= [@presenter.player, :currently_playing]
180
+ end
181
+ end
182
+
161
183
  def station_table_columns
162
184
  table_columns = {
163
185
  'Play' => {
164
186
  button: {
165
187
  on_clicked: lambda { |row|
166
188
  station = @station_table.refined_model_array[row]
167
- select_station(station)
189
+ begin
190
+ @presenter.select_station(station)
191
+ rescue => e
192
+ puts e.full_message if debug
193
+ message_box(e.message)
194
+ end
168
195
  }
169
196
  }
170
197
  }
@@ -185,66 +212,42 @@ module Rubio
185
212
 
186
213
  table_columns.merge!(
187
214
  'name' => :text,
188
- 'language' => :text
215
+ 'language' => :text,
216
+ 'country' => :text
189
217
  )
190
218
  end
191
219
 
192
220
  def about_message_box
193
221
  license = begin
194
222
  File.read(File.expand_path('../../../LICENSE.txt', __dir__))
195
- rescue StandardError
223
+ rescue => e
224
+ puts e.full_message if debug
196
225
  ''
197
226
  end
198
227
  product = "rubio-radio #{Rubio::VERSION}"
199
228
  message_box(product, "#{product}\n\n#{license}")
200
229
  end
201
230
 
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
231
+ def toggle_bookmarked_station(station = nil)
232
+ station ||= @presenter.current_station
233
+ @presenter.toggle_bookmarked_station(station)
234
+ view_bookmarks if @presenter.view == :bookmarks && !station.bookmarked
232
235
  end
233
236
 
234
237
  def view_all
235
- @station_table.model_array = stations
238
+ @station_table.model_array = @presenter.stations
236
239
  end
237
240
 
238
241
  def view_bookmarks
239
- @station_table.model_array = stations.select(&:bookmarked?)
242
+ @station_table.model_array = @presenter.stations.select(&:bookmarked?)
240
243
  end
241
244
 
242
245
  def view_playing
243
- @station_table.model_array = stations.select(&:playing?)
246
+ @station_table.model_array = @presenter.stations.select(&:playing?)
244
247
  end
245
248
 
246
249
  def refresh_view
247
- case view
250
+ case @presenter.view
248
251
  when :all
249
252
  view_all
250
253
  when :bookmarks
@@ -256,39 +259,24 @@ module Rubio
256
259
 
257
260
  private
258
261
 
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
262
  def monitor_thread(debug)
272
263
  Glimmer::LibUI.timer(1) do
273
- p @player.history if debug
274
- next if current_station.nil? || @player.alive?
264
+ p @presenter.player.history if debug
265
+ next if @presenter.current_station.nil? || @presenter.player.alive?
275
266
 
276
- message_box("player '#{@player.backend}' stopped!", @player.thr.to_s)
277
- stop_station
267
+ message_box("player '#{@presenter.player.backend}' stopped!", @presenter.player.thr.to_s)
268
+ @presenter.stop_station
278
269
  true
279
270
  end
280
271
  end
281
272
 
282
273
  def async_fetch_stations
283
- @loaded_station_offset += @loaded_station_count
284
- @loaded_station_count *= 2
285
274
  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)
275
+ @presenter.fetch_more_stations
288
276
 
289
277
  Glimmer::LibUI.queue_main do
290
278
  refresh_view
291
- async_fetch_stations if @stations.count < radio_station_count
279
+ async_fetch_stations if @presenter.stations_incomplete?
292
280
  end
293
281
  end
294
282
  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.5
4
+ version: 0.0.7
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-15 00:00:00.000000000 Z
12
+ date: 2023-01-05 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.22
20
+ version: 0.5.24
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.22
27
+ version: 0.5.24
28
28
  description: Rubio is a simple radio player written in Ruby.
29
29
  email:
30
30
  - 2xijok@gmail.com
@@ -42,6 +42,7 @@ files:
42
42
  - lib/rubio/model/bookmark.rb
43
43
  - lib/rubio/model/player.rb
44
44
  - lib/rubio/model/radio_browser.rb
45
+ - lib/rubio/model/radio_presenter.rb
45
46
  - lib/rubio/model/station.rb
46
47
  - lib/rubio/version.rb
47
48
  - lib/rubio/view/radio.rb
@@ -64,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
65
  - !ruby/object:Gem::Version
65
66
  version: '0'
66
67
  requirements: []
67
- rubygems_version: 3.3.7
68
+ rubygems_version: 3.3.26
68
69
  signing_key:
69
70
  specification_version: 4
70
71
  summary: Rubio - A simple radio player