qtunes 0.0.2 → 0.0.3

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.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ Qtunes
2
+ ========
3
+
4
+ Qtunes let's you control the queue of a local cmus-player via a web-interface (which is a rip-off of [Holman's Play](https://github.com/holman/play)).
5
+
6
+ Requirements
7
+ ------------
8
+
9
+ - [cmus](http://cmus.sourceforge.net/)
10
+
11
+ OSX: `brew install cmus`
12
+
13
+ Installation
14
+ ------------
15
+
16
+ $ gem install qtunes
17
+
18
+
19
+ Usage
20
+ ------------
21
+
22
+ $ qtunes
23
+ Tasks:
24
+ qtunes help [TASK] # Describe available tasks or one specific task
25
+ qtunes server # Serve Qtunes frontend
26
+ qtunes version # Display installed Qtunes version
27
+
28
+ Author
29
+ ------
30
+
31
+ Gert Goet (eval) :: gert@thinkcreate.nl :: @gertgoet
32
+
33
+ License
34
+ ------
35
+
36
+ (The MIT license)
37
+
38
+ Copyright (c) 2011 Gert Goet, ThinkCreate
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining
41
+ a copy of this software and associated documentation files (the
42
+ "Software"), to deal in the Software without restriction, including
43
+ without limitation the rights to use, copy, modify, merge, publish,
44
+ distribute, sublicense, and/or sell copies of the Software, and to
45
+ permit persons to whom the Software is furnished to do so, subject to
46
+ the following conditions:
47
+
48
+ The above copyright notice and this permission notice shall be
49
+ included in all copies or substantial portions of the Software.
50
+
51
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
52
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
53
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
54
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
55
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
56
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
57
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/config.ru ADDED
@@ -0,0 +1,4 @@
1
+ # Use this config to develop the webinterface with shotgun (which gives you reload-per-request):
2
+ # $> bundle exec shotgun config.ru
3
+ require './lib/qtunes'
4
+ run Qtunes::Server
@@ -0,0 +1,13 @@
1
+ module Qtunes
2
+ module Paginatable
3
+ attr_accessor :per_page
4
+
5
+ def page(n)
6
+ slice(*[n - 1, 1].map{|i| i * self.per_page }) || []
7
+ end
8
+
9
+ def per_page
10
+ @per_page ||= 10
11
+ end
12
+ end
13
+ end
data/lib/qtunes/player.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'cocaine'
2
+ require 'shellwords'
2
3
 
3
4
  module Qtunes
4
5
  class Player
@@ -29,6 +30,18 @@ module Qtunes
29
30
  info['status']
30
31
  end
31
32
 
33
+ def playing?
34
+ status == 'playing'
35
+ end
36
+
37
+ def stopped?
38
+ status == 'stopped'
39
+ end
40
+
41
+ def paused?
42
+ status == 'paused'
43
+ end
44
+
32
45
  def file
33
46
  info['file']
34
47
  end
@@ -70,7 +83,7 @@ module Qtunes
70
83
  end
71
84
 
72
85
  def enqueue(file)
73
- Cocaine::CommandLine.new('cmus-remote', "-q '#{file}'").run
86
+ Cocaine::CommandLine.new('cmus-remote', "-q #{file.shellescape}").run
74
87
  end
75
88
 
76
89
  def queue
data/lib/qtunes/server.rb CHANGED
@@ -1,9 +1,14 @@
1
1
  require 'sinatra/base'
2
+ require 'rack-flash'
2
3
  require 'digest/sha2'
3
4
  require 'audioinfo'
5
+ require 'qtunes/paginatable'
4
6
 
5
7
  module Qtunes
6
8
  class Server < Sinatra::Base
9
+ enable :sessions
10
+ use Rack::Flash, :sweep => false
11
+
7
12
  dir = File.dirname(File.expand_path(__FILE__))
8
13
 
9
14
  set :views, "#{dir}/server/views"
@@ -11,45 +16,49 @@ module Qtunes
11
16
  set :static, true
12
17
 
13
18
  get '/' do
14
- @song = PLAYER.file
15
- @songs = queue
19
+ @song = player.file
20
+ @songs = queue.values
16
21
 
17
22
  erb :songs
18
23
  end
19
24
 
20
25
  get '/library' do
21
- @song = PLAYER.file
22
- @songs = library
26
+ @page = params[:page] ? params[:page].to_i : 1
27
+ @song = player.file
28
+ @songs = library.values.extend(Qtunes::Paginatable).page(@page)
23
29
 
24
30
  erb :songs
25
31
  end
26
32
 
27
33
  get '/add/:id' do
28
- PLAYER.enqueue(library[params[:id]][:path])
34
+ player.enqueue(library[params[:id]]['path']) && flash[:notice] = "Song added"
35
+ player.play if player.stopped?
29
36
 
30
- redirect '/'
37
+ redirect back
31
38
  end
32
39
 
33
40
  get '/remove/:id' do
34
- ix = library.keys.index(params[:id])
41
+ ix = queue.keys.index(params[:id])
35
42
 
36
43
  # badass!
37
- PLAYER.view_queue
38
- PLAYER.win_top
39
- ix.times{ PLAYER.win_down }
40
- PLAYER.win_remove
41
-
42
- redirect '/'
44
+ player.view_queue
45
+ player.win_top
46
+ ix.times{ player.win_down }
47
+ player.win_remove && flash[:notice] = "Song removed"
48
+
49
+ redirect back
43
50
  end
44
51
 
45
- configure do
46
- puts "Configure"
52
+ def self.player
53
+ @player ||= Qtunes::Player.new
54
+ end
47
55
 
48
- PLAYER = Qtunes::Player.new
56
+ def player
57
+ self.class.player
49
58
  end
50
59
 
51
60
  def self.queue
52
- songs_to_hash{ PLAYER.queue }
61
+ songs_to_hash{ player.queue }
53
62
  end
54
63
 
55
64
  def queue
@@ -57,22 +66,32 @@ module Qtunes
57
66
  end
58
67
 
59
68
  def self.library
60
- @library ||= songs_to_hash{ PLAYER.library }
69
+ @library ||= begin
70
+ print "Loading library..."
71
+ result = songs_to_hash{ player.library }
72
+ puts "Done"
73
+ result
74
+ end
61
75
  end
62
76
 
63
77
  def library
64
78
  self.class.library
65
79
  end
66
80
 
81
+ helpers do
82
+ include Rack::Utils
83
+ alias_method :h, :escape_html
84
+ end
85
+
67
86
  protected
68
87
  def self.songs_to_hash
69
88
  yield.inject({}) do |res,path|
70
89
  begin
71
- song = {:path => path}.merge(AudioInfo.open(path).to_h)
90
+ song = AudioInfo.open(path).to_h
72
91
  rescue AudioInfoError
73
92
  next res
74
93
  end
75
- res[song_id(path)] = song
94
+ res[song_id(path)] = song.merge('path' => path, 'id' => song_id(path))
76
95
  res
77
96
  end
78
97
  end
@@ -80,5 +99,21 @@ module Qtunes
80
99
  def self.song_id(file)
81
100
  Digest::SHA256.hexdigest(file)[0,10]
82
101
  end
102
+
103
+ def debug(object)
104
+ begin
105
+ Marshal::dump(object)
106
+ "<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", "&nbsp; ")}</pre>"
107
+ rescue Exception => e # errors from Marshal or YAML
108
+ # Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback
109
+ "<code class='debug_dump'>#{h(object.inspect)}</code>"
110
+ end
111
+ end
112
+
113
+ configure do
114
+ puts "Configure"
115
+
116
+ Qtunes::Server.library
117
+ end
83
118
  end
84
119
  end
@@ -30,7 +30,7 @@ a:hover{
30
30
  }
31
31
 
32
32
  .navigation{
33
- text-align: right;
33
+ text-align: left;
34
34
  padding: 2px 10px;
35
35
  font-weight: bold;
36
36
  letter-spacing: -1px;
@@ -76,9 +76,9 @@ a:hover{
76
76
  .song .artist{
77
77
  font-size: 3em;
78
78
  letter-spacing: -5px;
79
+ color: #485460;
79
80
  }
80
81
  .song .artist a{
81
- color: #485460;
82
82
  }
83
83
  .song .title{
84
84
  padding-left: 10px;
@@ -6,17 +6,20 @@
6
6
  </head>
7
7
 
8
8
  <body>
9
- <h1>Title</h1>
9
+ <h1><a href='/'>Qtunes</a></h1>
10
10
 
11
11
  <div class="navigation">
12
- <form method="get" action="/search">
13
- <input type="search" name="q" />
14
- </form>
15
-
16
12
  <a href="/">Queue</a>
17
13
  <a href="/library">Library</a>
18
14
  </div>
19
15
 
16
+ <% if flash[:notice] %>
17
+ <p class="notice"><%= flash[:notice] %></p>
18
+ <% end %>
19
+ <% if flash[:error] %>
20
+ <p class="error"><%= flash[:error] %></p>
21
+ <% end %>
22
+
20
23
  <%= yield %>
21
24
  </body>
22
25
  </html>
@@ -1,31 +1,34 @@
1
- <p>Now playing: '<%= @song %>'</p>
1
+ <h3>Now playing: '<%= @song %>'</h3>
2
2
 
3
- <% @songs.each do |id, song| %>
3
+ <% if @page %>
4
+ <a href="?page=<%= @page - 1 %>">Previous</a>
5
+ <a href="?page=<%= @page + 1 %>">Next</a>
6
+ <% end %>
7
+
8
+ <% @songs.each do |song| %>
4
9
  <div class="song">
5
10
  <span class="controls">
6
- <% if queue[id] %>
7
- <a href="/remove/<%= id %>" title="remove from queue">-</a>
11
+ <% if queue[song['id']] %>
12
+ <a href="/remove/<%= song['id'] %>" title="remove from queue">-</a>
8
13
  <% else %>
9
- <a href="/add/<%= id %>" title="add to queue">+</a>
14
+ <a href="/add/<%= song['id'] %>" title="add to queue">+</a>
10
15
  <% end %>
11
16
  </span>
12
17
 
13
-
14
- <span class="artist">
15
- <a href="/artist/{{artist_name}}"><%= song['artist'] %></a>
16
- </span>
17
-
18
- <span class="title">
19
- <a href="/song/{{id}}"><%= song['title'] %></a>
20
- </span>
21
- <span class="album">
22
- <a href="/artist/{{artist_name}}/album/{{album_name}}"><%= song['album'] %></a>
23
- </span>
18
+ <span class="artist"><%= song['artist'] %></span>
19
+ <span class="title"><%= song['title'] %></span>
20
+ <span class="album"><%= song['album'] %></span>
24
21
  </div>
25
22
  <% end %>
26
23
 
27
24
  <% if @songs.empty? %>
28
25
  <div class="content">
29
- The queue is empty. Quick, play some <a href="/artist/Ace+of+Base">Ace of Base</a>; no one's looking.
26
+ No songs found!
30
27
  </div>
31
28
  <% end %>
29
+
30
+ <% if @page %>
31
+ <a href="?page=<%= @page - 1 %>">Previous</a>
32
+ <a href="?page=<%= @page + 1 %>">Next</a>
33
+ <% end %>
34
+
@@ -1,3 +1,3 @@
1
1
  module Qtunes
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/qtunes.gemspec CHANGED
@@ -18,10 +18,11 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
23
- s.add_runtime_dependency "sinatra"
24
- s.add_runtime_dependency "thor"
25
- s.add_runtime_dependency "cocaine"
26
- s.add_runtime_dependency "ruby-audioinfo"
21
+ s.add_development_dependency "shotgun"
22
+
23
+ s.add_runtime_dependency "sinatra", "~> 1.2.6"
24
+ s.add_runtime_dependency "rack-flash", "~> 0.1.2"
25
+ s.add_runtime_dependency "thor", "~> 0.14.6"
26
+ s.add_runtime_dependency "cocaine", "~> 0.2.0"
27
+ s.add_runtime_dependency "ruby-audioinfo", "~> 0.1.7"
27
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qtunes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,53 +9,75 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-23 00:00:00.000000000 +02:00
12
+ date: 2011-08-25 00:00:00.000000000 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: sinatra
17
- requirement: &11079020 !ruby/object:Gem::Requirement
16
+ name: shotgun
17
+ requirement: &18146680 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
21
21
  - !ruby/object:Gem::Version
22
22
  version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *18146680
26
+ - !ruby/object:Gem::Dependency
27
+ name: sinatra
28
+ requirement: &18146180 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.6
23
34
  type: :runtime
24
35
  prerelease: false
25
- version_requirements: *11079020
36
+ version_requirements: *18146180
37
+ - !ruby/object:Gem::Dependency
38
+ name: rack-flash
39
+ requirement: &18145680 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 0.1.2
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *18145680
26
48
  - !ruby/object:Gem::Dependency
27
49
  name: thor
28
- requirement: &11078600 !ruby/object:Gem::Requirement
50
+ requirement: &18145220 !ruby/object:Gem::Requirement
29
51
  none: false
30
52
  requirements:
31
- - - ! '>='
53
+ - - ~>
32
54
  - !ruby/object:Gem::Version
33
- version: '0'
55
+ version: 0.14.6
34
56
  type: :runtime
35
57
  prerelease: false
36
- version_requirements: *11078600
58
+ version_requirements: *18145220
37
59
  - !ruby/object:Gem::Dependency
38
60
  name: cocaine
39
- requirement: &11078180 !ruby/object:Gem::Requirement
61
+ requirement: &18144760 !ruby/object:Gem::Requirement
40
62
  none: false
41
63
  requirements:
42
- - - ! '>='
64
+ - - ~>
43
65
  - !ruby/object:Gem::Version
44
- version: '0'
66
+ version: 0.2.0
45
67
  type: :runtime
46
68
  prerelease: false
47
- version_requirements: *11078180
69
+ version_requirements: *18144760
48
70
  - !ruby/object:Gem::Dependency
49
71
  name: ruby-audioinfo
50
- requirement: &11077760 !ruby/object:Gem::Requirement
72
+ requirement: &18144300 !ruby/object:Gem::Requirement
51
73
  none: false
52
74
  requirements:
53
- - - ! '>='
75
+ - - ~>
54
76
  - !ruby/object:Gem::Version
55
- version: '0'
77
+ version: 0.1.7
56
78
  type: :runtime
57
79
  prerelease: false
58
- version_requirements: *11077760
80
+ version_requirements: *18144300
59
81
  description: add songs to queue, let cmus eat it
60
82
  email:
61
83
  - gert@thinkcreate.nl
@@ -66,10 +88,12 @@ extra_rdoc_files: []
66
88
  files:
67
89
  - .gitignore
68
90
  - Gemfile
69
- - README
91
+ - README.md
70
92
  - Rakefile
71
93
  - bin/qtunes
94
+ - config.ru
72
95
  - lib/qtunes.rb
96
+ - lib/qtunes/paginatable.rb
73
97
  - lib/qtunes/player.rb
74
98
  - lib/qtunes/server.rb
75
99
  - lib/qtunes/server/public/base.css
data/README DELETED
@@ -1,4 +0,0 @@
1
- Qtunes let's you control the queue of a local cmus-player via a web-interface.
2
-
3
- # start server
4
- $> qtunes s[erver]