vlcraptor 0.2.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6303432e0bfc5db3263ba6121fff94d9652dc0df2b00d427f06febeef2f8f27c
4
- data.tar.gz: 2f6af90fb8a4a589f9e58d5bd7dc0bdbdb6fc7520051c4682ea9caa5183c71b3
3
+ metadata.gz: e68bc937ca2016f17771ea0b7db19729f0b91eb3a7cd94e8dae305e5d5feff9b
4
+ data.tar.gz: 3197d9195b81187bf3109e99440c61c906e5007095da0466098a15ad8d3b5fed
5
5
  SHA512:
6
- metadata.gz: 88c1e136354b579b937860753c4874f1af62bdf0bd0ebcf7f49e6cea0be96969c16c17423ddd228e745ac72a78936c08a4bc16cc724a973353d90edbab20cb98
7
- data.tar.gz: 0e229b3e1db2d596661593d9a85866e5d234fc705b0d019ec468a8a174bb0ae3b1e6d47a19b46390f688e4583d0aa87cfb8fb4f5177ce0528b3c830ed279512c
6
+ metadata.gz: b64e6b465e12a323b47ef33cbc3132f0f3256cb7c87f2b56c514f70bb8254f901f8e4e581b5873d1d0d328fc5ddfa589a0c4c585e75ee45315356856fcab6d86
7
+ data.tar.gz: 7b32b59ca121f4e35a10cacf7766dcb5c6e76a1cf0f47f0522e91425d476645d24f415943b864aee295534f579285903ad53ab47ae0cfeeb60adeb50d659c637
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- vlcraptor (0.1.0)
4
+ vlcraptor (0.5.0)
5
+ curses
5
6
  rainbow
6
7
  vlc-client
7
8
 
@@ -11,6 +12,7 @@ GEM
11
12
  ast (2.4.2)
12
13
  backport (1.2.0)
13
14
  benchmark (0.2.0)
15
+ curses (1.4.4)
14
16
  diff-lcs (1.5.0)
15
17
  e2mmap (0.1.0)
16
18
  jaro_winkler (1.5.4)
data/README.md CHANGED
@@ -1,28 +1,73 @@
1
1
  # Vlcraptor
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/vlcraptor`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ This is a queueing daemon for VLC - kind of like `mpd` but nowhere near as flexible or useful.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ The player daemon starts two instances of VLC and then uses those to play any tracks placed in the queue.
6
6
 
7
- ## Installation
7
+ Why two VLC instances? VLC doesn't support cross fading between tracks so this crossfades by starting the
8
+ other VLC instance playing the next track and adjusting volume between both.
8
9
 
9
- Add this line to your application's Gemfile:
10
+ At the moment, only mac os is supported - minor changes would be required to allow this to work on linux.
10
11
 
11
- ```ruby
12
- gem 'vlcraptor'
13
- ```
12
+ ## Installation
14
13
 
15
- And then execute:
14
+ You need to install VLC in the default location for mac os (`/Applications/VLC.app`).
16
15
 
17
- $ bundle install
16
+ `brew install ffmpeg` is required by the `queue` command for extracting tags to place in the queue.
18
17
 
19
- Or install it yourself as:
18
+ `brew install terminal-notifier` is optional depending if you want terminal notifications when new tracks start.
20
19
 
21
- $ gem install vlcraptor
20
+ This gem can be installed with `gem install vlcraptor`.
22
21
 
23
22
  ## Usage
24
23
 
25
- TODO: Write usage instructions here
24
+ Running `vlcraptor` without any parameters will list the available subcommands.
25
+
26
+ ### Player
27
+
28
+ Run `vlcraptor player` in a shell session.
29
+
30
+ This is the player daemon that controls two instances
31
+ of VLC and is an ncurses application which will take over the display in that terminal.
32
+
33
+ You can quit with 'q', pause with ' ', stop with 's', play (resume) with 'p' and skip with 'n'.
34
+
35
+ ### Adding tracks to the queue
36
+
37
+ `vlcraptor queue folder_containing_audio_files audio_file.mp3` will place any number of audio files in the
38
+ queue and the player should immediately start playing the first track.
39
+
40
+ ### Viewing queue contents
41
+
42
+ `vlcraptor list` will list currently queued tracks with an estimated start time if the player is currently
43
+ running and playing a track.
44
+
45
+ ### Managing queue
46
+
47
+ `vlcraptor clear` will clear all queued tracks.
48
+
49
+ `vlcraptor remove 2` will remove queued track at index position 2.
50
+
51
+ `vlcraptor swap 2 4` will swap the tracks at index positions 2 and 4.
52
+
53
+ ### Media controls
54
+
55
+ `vlcraptor pause` will pause, `vlcraptor stop` will stop and `vlcraptor play` will resume.
56
+
57
+ `vlcraptor skip` will fade out the current track and start the next one (unless the queue is empty).
58
+
59
+ ### Optional features
60
+
61
+ A number of features can be turned on/off while the player is running that will determine certain behaviour:
62
+
63
+ `vlcraptor autoplay off` will cause the player to stop and politely wait after the current track has finished.
64
+ `vlcraptor autoplay on` and tracks will start playing again.
65
+
66
+ `vlcraptor crossfade off` will turn off crossfading so new tracks will start once the previous one is
67
+ completely finished.
68
+
69
+ `vlcraptor scrobble on` will turn on last.fm scrobbling - you will require your own application api key
70
+ and secret to enable this.
26
71
 
27
72
  ## Development
28
73
 
@@ -32,4 +77,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
77
 
33
78
  ## Contributing
34
79
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/vlcraptor.
80
+ Bug reports and pull requests are welcome on GitHub at https://github.com/markryall/vlcraptor.
data/exe/vlcraptor CHANGED
@@ -11,8 +11,12 @@ command = ARGV.shift
11
11
  case command
12
12
  when "autoplay"
13
13
  Vlcraptor.autoplay(ARGV.shift)
14
+ when "clear"
15
+ Vlcraptor.clear
14
16
  when "crossfade"
15
17
  Vlcraptor.crossfade(ARGV.shift)
18
+ when "history"
19
+ Vlcraptor.history
16
20
  when "list"
17
21
  Vlcraptor.list
18
22
  when "pause"
@@ -21,6 +25,8 @@ when "play"
21
25
  Vlcraptor.play
22
26
  when "player"
23
27
  Vlcraptor.player
28
+ when "remove"
29
+ Vlcraptor.remove(ARGV.shift)
24
30
  when "queue"
25
31
  Vlcraptor.queue(ARGV)
26
32
  when "scrobble"
@@ -29,16 +35,22 @@ when "skip"
29
35
  Vlcraptor.skip
30
36
  when "stop"
31
37
  Vlcraptor.stop
38
+ when "swap"
39
+ Vlcraptor.swap(ARGV)
32
40
  else
33
41
  puts "Unknown command \"#{command}\":"
34
42
  puts " autoplay on/off: continue playing tracks or stop at the end of current track"
43
+ puts " clear: clear queue"
35
44
  puts " crossfade on/off: 5 second crossfade when changing tracks"
45
+ puts " history: display play history"
36
46
  puts " list: list current queue"
37
47
  puts " pause: pause current track (resume with play)"
38
48
  puts " play: resume after pause/stop"
39
49
  puts " player: start the player"
40
50
  puts " queue paths: queue folders or files containing music tracks"
51
+ puts " remove a: remove track from queue at index position a"
41
52
  puts " scrobble on/off: send track information to last.fm (requires an api key)"
42
53
  puts " skip: skip the current track"
43
54
  puts " stop: stop the player (resume with play)"
55
+ puts " swap a b: swap tracks in queue at index positions a and b"
44
56
  end
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rainbow"
4
- require_relative "console"
4
+ require_relative "preferences"
5
5
  require_relative "scrobbler"
6
6
 
7
7
  module Vlcraptor
8
8
  class Notifiers
9
- def initialize(preferences)
10
- @preferences = preferences
11
- @console = Vlcraptor::Console.new
9
+ def initialize
10
+ @preferences = Vlcraptor::Preferences.new
11
+ @history = "#{File.expand_path("~")}/.player_history"
12
12
  end
13
13
 
14
14
  def track_suspended
@@ -22,48 +22,39 @@ module Vlcraptor
22
22
  @preferences[:started] = track[:start_time].to_i
23
23
  end
24
24
 
25
- def track_progress(track, remaining)
26
- return unless track
27
-
28
- rem = if remaining > 60
29
- "#{remaining / 60} minutes and #{remaining % 60} seconds remaining"
30
- else
31
- "#{remaining} seconds remaining"
32
- end
33
- @console.change(
34
- [
35
- " ",
36
- display_time(Time.now + remaining),
37
- remaining < 20 ? Rainbow(rem).tomato : rem,
38
- ].join(" ")
39
- )
40
- end
41
-
42
25
  def track_started(track)
43
26
  return unless track
44
27
 
45
- @preferences[:started] = Time.now.to_i
46
28
  track[:start_time] = Time.now
29
+ @preferences[:started] = track[:start_time].to_i
47
30
  scrobbler&.now_playing(track[:artist], track[:title])
48
31
  terminal_notify(
49
32
  message: "#{track[:title]} by #{track[:artist]}",
50
33
  title: "Now Playing",
51
34
  )
52
- @console.replace(
53
- [
54
- display_time(Time.now),
55
- display_time(Time.now + track[:length]),
56
- Rainbow(track[:title]).green,
57
- "by",
58
- Rainbow(track[:artist]).yellow,
59
- "from",
60
- Rainbow(track[:album]).cyan,
61
- "(#{track[:length] / 60}:#{track[:length] % 60})",
62
- ].join(" ")
63
- )
35
+
36
+ len = if track[:length] > 60
37
+ "(#{track[:length] / 60}m and #{track[:length] % 60}s)"
38
+ else
39
+ "(#{track[:length]}s)"
40
+ end
41
+
42
+ message = [
43
+ display_time(track[:start_time]),
44
+ Rainbow(track[:title]).green,
45
+ "by",
46
+ Rainbow(track[:artist]).yellow,
47
+ "from",
48
+ Rainbow(track[:album]).cyan,
49
+ len,
50
+ ].join(" ")
51
+
52
+ File.open(@history, "a") { |file| file.puts message }
64
53
  end
65
54
 
66
55
  def track_finished(track)
56
+ @preferences[:started] = nil
57
+
67
58
  return unless track
68
59
 
69
60
  scrobbler&.scrobble(track[:artist], track[:title], timestamp: track[:start_time].to_i)
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "player"
4
+ require_relative "preferences"
5
+ require_relative "queue"
6
+ require_relative "notifiers"
7
+
8
+ module Vlcraptor
9
+ class PlayerController
10
+ def initialize
11
+ @player = Vlcraptor::Player.new
12
+ @preferences = Vlcraptor::Preferences.new
13
+ @queue = Vlcraptor::Queue.new
14
+ @notifiers = Vlcraptor::Notifiers.new
15
+ @track = nil
16
+ @suspended = false
17
+ end
18
+
19
+ def next
20
+ return on_play if @preferences.play? && @suspended
21
+ return on_pause if @preferences.pause? && !@suspended
22
+ return on_stop if @preferences.stop? && !@suspended
23
+ return build if @suspended
24
+ return when_playing if @track && @player.playing?
25
+ return when_auto if @preferences.continue?
26
+
27
+ when_manual
28
+ end
29
+
30
+ def cleanup
31
+ @notifiers.track_suspended
32
+ @player.fadeout
33
+ @player.cleanup
34
+ end
35
+
36
+ private
37
+
38
+ def on_pause
39
+ suspend("Now Paused", :pause)
40
+ end
41
+
42
+ def on_stop
43
+ suspend("Now Stopped", :stop)
44
+ end
45
+
46
+ def suspend(status, method)
47
+ @player.fadeout
48
+ @player.send(method)
49
+ @status = status
50
+ @suspended = true
51
+ @notifiers.track_suspended
52
+ build
53
+ end
54
+
55
+ def on_play
56
+ @player.fadein
57
+ @suspended = false
58
+ @notifiers.track_resumed(@track, @player.time)
59
+ when_playing_track(@player.remaining)
60
+ end
61
+
62
+ def when_playing
63
+ return on_skip if @preferences.skip?
64
+ return on_crossfade if @preferences.crossfade? && @player.remaining < 5
65
+
66
+ when_playing_track(@player.remaining)
67
+ end
68
+
69
+ def on_skip
70
+ @track = @queue.next
71
+ @notifiers.track_suspended
72
+ if @track
73
+ @notifiers.track_started(@track)
74
+ @player.crossfade(@track[:path])
75
+ when_playing_track(@player.remaining)
76
+ else
77
+ @player.fadeout
78
+ when_empty
79
+ end
80
+ end
81
+
82
+ def on_crossfade
83
+ @notifiers.track_finished(@track)
84
+ @track = @queue.next
85
+ if @track
86
+ @notifiers.track_started(@track)
87
+ @player.crossfade(@track[:path])
88
+ when_playing_track(@player.remaining)
89
+ else
90
+ @player.fadeout
91
+ when_empty
92
+ end
93
+ end
94
+
95
+ def when_auto
96
+ @notifiers.track_finished(@track)
97
+ @track = @queue.next
98
+ return when_empty unless @track
99
+
100
+ @notifiers.track_started(@track)
101
+ @player.play(@track[:path])
102
+ when_playing_track(@track[:length])
103
+ end
104
+
105
+ def when_playing_track(remaining)
106
+ @status = "Now Playing"
107
+ remaining_color = remaining < 30 ? 9 : 5
108
+ build(
109
+ [2, @track[:title]],
110
+ [0, "\n"],
111
+ [0, "by "],
112
+ [11, @track[:artist]],
113
+ [0, "\n"],
114
+ [0, "from "],
115
+ [6, @track[:album]],
116
+ [0, "\n"],
117
+ [remaining_color, duration(remaining)],
118
+ [0, " of "],
119
+ [0, duration(@track[:length])],
120
+ [0, " remaining\n"],
121
+ )
122
+ end
123
+
124
+ def when_empty
125
+ @status = "Now Waiting"
126
+ build
127
+ end
128
+
129
+ def when_manual
130
+ @status = "Now Waiting"
131
+ build
132
+ end
133
+
134
+ def display_time(time)
135
+ time.strftime("%I:%M:%S")
136
+ end
137
+
138
+ def duration(seconds)
139
+ if seconds > 60
140
+ "#{seconds / 60}m and #{seconds % 60}s"
141
+ else
142
+ "#{seconds}s"
143
+ end
144
+ end
145
+
146
+ def build(*extra)
147
+ autoplay = @preferences[:autoplay] ? "+" : "-"
148
+ crossfade = @preferences[:crossfade] ? "+" : "-"
149
+ scrobble = @preferences[:scrobble] ? "+" : "-"
150
+ [
151
+ [0, display_time(Time.now)],
152
+ [0, "\n"],
153
+ [0, @status],
154
+ [0, "\n"],
155
+ [0, "#{Vlcraptor::Queue.length} queued tracks"],
156
+ [0, "\n"],
157
+ [8, "#{autoplay}autoplay #{crossfade}crossfade #{scrobble}scrobble"],
158
+ [0, "\n"],
159
+ ] + extra
160
+ end
161
+ end
162
+ end
@@ -12,7 +12,18 @@ module Vlcraptor
12
12
  def next
13
13
  `rm -f #{@current_path}` if @current_path
14
14
  @current_path = Dir["/tmp/queue/*.yml"].min
15
- YAML.load_file(@current_path) if @current_path
15
+ return unless @current_path
16
+
17
+ result = YAML.load_file(@current_path)
18
+ File.exist?(result[:path]) ? result : self.next
19
+ end
20
+
21
+ def self.clear
22
+ `rm -rf /tmp/queue`
23
+ end
24
+
25
+ def self.length
26
+ Dir["/tmp/queue/*.yml"].length
16
27
  end
17
28
 
18
29
  def self.each
@@ -21,6 +32,31 @@ module Vlcraptor
21
32
  end
22
33
  end
23
34
 
35
+ def self.remove(index)
36
+ path = Dir["/tmp/queue/*.yml"].sort[index.to_i]
37
+ if path
38
+ `rm #{path}`
39
+ yield
40
+ else
41
+ puts "Could not find track at position #{index}"
42
+ end
43
+ end
44
+
45
+ def self.swap(a, b)
46
+ all = Dir["/tmp/queue/*.yml"].sort
47
+ path_a = all[a.to_i]
48
+ path_b = all[b.to_i]
49
+
50
+ if path_a && path_b
51
+ `mv #{path_a} #{path_a}.tmp`
52
+ `mv #{path_b} #{path_a}`
53
+ `mv #{path_a}.tmp #{path_b}`
54
+ yield
55
+ else
56
+ puts "Could not find tracks at positions #{a} and #{b}"
57
+ end
58
+ end
59
+
24
60
  def self.add(path)
25
61
  unless %w[.mp3 .m4a].include?(File.extname(path))
26
62
  puts "skipping #{path}"
@@ -29,15 +65,20 @@ module Vlcraptor
29
65
 
30
66
  puts "adding #{path}"
31
67
  tags = Vlcraptor::Ffmpeg.new(path)
32
- meta = {
68
+ enqueue(
33
69
  title: tags.title,
34
70
  artist: tags.artist,
35
71
  album: tags.album,
36
72
  length: tags.time,
37
- path: File.expand_path(path),
38
- }
73
+ path: File.expand_path(path)
74
+ )
75
+ end
76
+
77
+ def self.enqueue(track)
39
78
  `mkdir -p /tmp/queue`
40
- File.open("/tmp/queue/#{(Time.now.to_f * 1000).to_i}.yml", "w") { |f| f.puts meta.to_yaml }
79
+ File.open("/tmp/queue/#{(Time.now.to_f * 1000).to_i}.yml", "w") do |file|
80
+ file.puts track.to_yaml
81
+ end
41
82
  end
42
83
  end
43
84
  end
@@ -16,24 +16,26 @@ module Vlcraptor
16
16
 
17
17
  def self.ask(prompt)
18
18
  puts prompt
19
- gets.chomp
19
+ gets.chomp.strip
20
+ end
21
+
22
+ def self.blank(attribute)
23
+ (attribute || "").length.zero?
20
24
  end
21
25
 
22
26
  def self.load
23
- conf = Vlcraptor::Settings.new("~/lastfm.yaml")
27
+ conf = Vlcraptor::Settings.new("~/.lastfm.yml")
24
28
 
25
- unless conf["api_key"] && conf["secret"]
26
- puts "You will need an api key and secret for last fm integration"
27
- conf["api_key"] = ask("What is the api key? ")
28
- conf["secret"] = ask("What is the secret ")
29
- end
29
+ conf[:api_key] = ask("What is the api key? ") if blank(conf[:api_key])
30
+ conf[:secret] = ask("What is the secret? ") if blank(conf[:secret])
31
+ conf[:user] = ask("What is your lastfm username? ") if blank(conf[:user])
30
32
 
31
- conf["user"] = ask("What is your lastfm username? ") unless conf["user"]
33
+ return nil if blank(conf[:api_key]) || blank(conf[:secret]) || blank(conf[:user])
32
34
 
33
- scrobbler = Vlcraptor::Scrobbler.new(conf["api_key"], conf["secret"], conf["user"], conf["session"])
35
+ scrobbler = Vlcraptor::Scrobbler.new(conf[:api_key], conf[:secret], conf[:user], conf[:session])
34
36
 
35
- unless conf["session"]
36
- conf["session"] = scrobbler.fetch_session_key do |url|
37
+ unless conf[:session]
38
+ conf[:session] = scrobbler.fetch_session_key do |url|
37
39
  puts "A browser will now launch to allow to authorise this application to access your lastfm account"
38
40
  `open '#{url}'`
39
41
  puts "Press enter when you have authorised the application"
@@ -41,6 +43,8 @@ module Vlcraptor
41
43
  end
42
44
  end
43
45
 
46
+ return nil if blank(conf[:session])
47
+
44
48
  scrobbler
45
49
  end
46
50
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vlcraptor
4
- VERSION = "0.2.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/vlcraptor.rb CHANGED
@@ -1,25 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "curses"
3
4
  require "rainbow"
4
5
  require_relative "vlcraptor/player"
6
+ require_relative "vlcraptor/player_controller"
5
7
  require_relative "vlcraptor/preferences"
6
8
  require_relative "vlcraptor/queue"
7
9
  require_relative "vlcraptor/notifiers"
10
+ require_relative "vlcraptor/scrobbler"
8
11
 
9
12
  module Vlcraptor
10
13
  def self.autoplay(value)
11
14
  Vlcraptor::Preferences.new[:autoplay] = value == "on"
12
15
  end
13
16
 
17
+ def self.clear
18
+ Vlcraptor::Queue.clear
19
+ end
20
+
14
21
  def self.crossfade(value)
15
22
  Vlcraptor::Preferences.new[:crossfade] = value == "on"
16
23
  end
17
24
 
25
+ def self.history
26
+ history_path = "#{File.expand_path("~")}/.player_history"
27
+ `touch #{history_path}`
28
+ system("cat #{history_path}")
29
+ end
30
+
18
31
  def self.list
19
32
  started = Vlcraptor::Preferences.new[:started]
20
33
  offset = 0
34
+ index = 0
21
35
  Vlcraptor::Queue.each do |track|
22
- array = []
36
+ array = [Rainbow(index.to_s).magenta]
23
37
  array << Time.at(started + offset).strftime("%I:%M:%S") if started
24
38
  array += [Rainbow(track[:title]).green, "by", Rainbow(track[:artist]).yellow]
25
39
  array += ["from", Rainbow(track[:album]).cyan] if (track[:album] || "").length.positive?
@@ -30,6 +44,7 @@ module Vlcraptor
30
44
  end
31
45
  puts array.join(" ")
32
46
  offset += track[:length]
47
+ index += 1
33
48
  end
34
49
  end
35
50
 
@@ -42,83 +57,55 @@ module Vlcraptor
42
57
  end
43
58
 
44
59
  def self.player
45
- player = Vlcraptor::Player.new
46
- queue = Vlcraptor::Queue.new
47
- preferences = Vlcraptor::Preferences.new
48
- notifiers = Vlcraptor::Notifiers.new(preferences)
49
- track = nil
50
- suspended = false
60
+ Curses.init_screen
61
+ Curses.start_color
62
+ Curses.curs_set(0)
63
+ Curses.noecho
64
+
65
+ Curses.init_pair(0, 0, 0) # white
66
+ Curses.init_pair(2, 2, 0) # green
67
+ Curses.init_pair(5, 5, 0) # magenta
68
+ Curses.init_pair(6, 6, 0) # cyan
69
+ Curses.init_pair(8, 8, 0) # grey
70
+ Curses.init_pair(9, 9, 0) # orange
71
+ Curses.init_pair(11, 11, 0) # yellow
72
+
73
+ player_controller = Vlcraptor::PlayerController.new
74
+ window = Curses::Window.new(0, 0, 1, 2)
75
+ window.nodelay = true
51
76
 
52
77
  loop do
53
- sleep 0.2
54
-
55
- if preferences.pause?
56
- player.fadeout
57
- player.pause
58
- suspended = true
59
- notifiers.track_suspended
78
+ window.setpos(0, 0)
60
79
 
61
- next
80
+ player_controller.next.each do |pair|
81
+ window.attron(Curses.color_pair(pair.first)) { window << pair.last }
82
+ Curses.clrtoeol
62
83
  end
63
-
64
- if preferences.stop?
65
- player.fadeout
66
- player.stop
67
- suspended = true
68
- notifiers.track_suspended
69
-
70
- next
84
+ (window.maxy - window.cury).times { window.deleteln }
85
+ window.refresh
86
+
87
+ case window.getch.to_s
88
+ when " "
89
+ pause
90
+ when "n"
91
+ skip
92
+ when "p"
93
+ play
94
+ when "s"
95
+ stop
96
+ when "q"
97
+ break
71
98
  end
72
99
 
73
- if preferences.play?
74
- player.fadein
75
- suspended = false
76
- notifiers.track_resumed(track, player.time)
77
-
78
- next
79
- end
80
-
81
- next if suspended
82
-
83
- if player.playing?
84
- if preferences.skip?
85
- track = queue.next
86
- if track
87
- notifiers.track_started(track)
88
- player.crossfade(track[:path])
89
- else
90
- player.fadeout
91
- end
92
- next
93
- end
94
-
95
- if preferences.crossfade? && player.remaining < 5
96
- notifiers.track_finished(track)
97
- track = queue.next
98
- if track
99
- notifiers.track_started(track)
100
- player.crossfade(track[:path])
101
- end
102
- end
103
-
104
- notifiers.track_progress(track, player.remaining)
105
-
106
- next
107
- end
108
-
109
- next unless preferences.continue?
110
-
111
- notifiers.track_finished(track)
112
- track = queue.next
113
- next unless track
114
-
115
- notifiers.track_started(track)
116
- player.play(track[:path])
100
+ sleep 0.2
117
101
  end
118
- rescue Interrupt
119
- notifiers.track_suspended
120
- player.cleanup
121
- puts "Exiting"
102
+ ensure
103
+ player_controller.cleanup
104
+ Curses.close_screen
105
+ end
106
+
107
+ def self.remove(index)
108
+ Vlcraptor::Queue.remove(index) { list }
122
109
  end
123
110
 
124
111
  def self.queue(paths)
@@ -134,7 +121,10 @@ module Vlcraptor
134
121
  end
135
122
 
136
123
  def self.scrobble(value)
137
- Vlcraptor::Preferences.new[:scrobble] = value == "on"
124
+ preferences = Vlcraptor::Preferences.new
125
+ preferences[:scrobble] = value == "on"
126
+ scrobbler = Vlcraptor::Scrobbler.load if preferences.scrobble?
127
+ preferences[:scrobble] = false unless scrobbler
138
128
  end
139
129
 
140
130
  def self.skip
@@ -144,4 +134,9 @@ module Vlcraptor
144
134
  def self.stop
145
135
  Vlcraptor::Preferences.new[:stop] = true
146
136
  end
137
+
138
+ def self.swap(args)
139
+ a, b = *args
140
+ Vlcraptor::Queue.swap(a, b) { list }
141
+ end
147
142
  end
data/vlcraptor.gemspec CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
+ spec.add_dependency "curses"
30
31
  spec.add_dependency "rainbow"
31
32
  spec.add_dependency "vlc-client"
32
33
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vlcraptor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Ryall
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-16 00:00:00.000000000 Z
11
+ date: 2022-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curses
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rainbow
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -57,10 +71,10 @@ files:
57
71
  - bin/setup
58
72
  - exe/vlcraptor
59
73
  - lib/vlcraptor.rb
60
- - lib/vlcraptor/console.rb
61
74
  - lib/vlcraptor/ffmpeg.rb
62
75
  - lib/vlcraptor/notifiers.rb
63
76
  - lib/vlcraptor/player.rb
77
+ - lib/vlcraptor/player_controller.rb
64
78
  - lib/vlcraptor/preferences.rb
65
79
  - lib/vlcraptor/queue.rb
66
80
  - lib/vlcraptor/scrobbler.rb
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Vlcraptor
4
- class Console
5
- LENGTH = 120
6
-
7
- def initialize
8
- @first = true
9
- end
10
-
11
- def change(line)
12
- print "\b" * LENGTH unless @first
13
- @first = false
14
- print line[0...LENGTH].ljust LENGTH
15
- end
16
-
17
- def replace(line)
18
- print "\b" * LENGTH unless @first
19
- @first = true
20
- puts line
21
- end
22
- end
23
- end