qtunes 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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]