vlcraptor 0.2.0 → 0.5.0

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: 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