qtunes 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in qtunes.gemspec
4
+ gemspec
data/README ADDED
@@ -0,0 +1,4 @@
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]
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/qtunes ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "qtunes"
5
+ require "thor"
6
+
7
+ class QtunesCLI < Thor
8
+ include Thor::Actions
9
+
10
+ map 's' => :server
11
+ desc 'server', 'Serve Qtunes frontend'
12
+ def server
13
+ puts "== Starting Qtunes server"
14
+ Qtunes::Server.run!
15
+ end
16
+
17
+ map '-v' => :version
18
+ desc 'version', 'Display installed Qtunes version'
19
+ def version
20
+ puts "Qtunes #{Qtunes::VERSION}"
21
+ end
22
+ end
23
+
24
+ QtunesCLI.start
data/lib/qtunes.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "qtunes/player"
2
+ require "qtunes/version"
3
+ require "qtunes/server"
4
+
5
+ module Qtunes
6
+ end
@@ -0,0 +1,88 @@
1
+ require 'cocaine'
2
+
3
+ module Qtunes
4
+ class Player
5
+ INFO_KEYS = %w(status file duration position)
6
+
7
+ def info_raw
8
+ execute("status").split("\n")
9
+ end
10
+
11
+ def info
12
+ info_raw.inject({}) do |res,i|
13
+ k,v = i.split(" ", 2)
14
+ res[k] = v if INFO_KEYS.include?(k)
15
+ res
16
+ end
17
+ end
18
+
19
+ # The current state of the player.
20
+ #
21
+ # Examples
22
+ #
23
+ # player = Qtunes::Player.new
24
+ # player.status
25
+ # # => 'playing'
26
+ #
27
+ # returns String, being one of: 'playing', 'paused', 'stopped'.
28
+ def status
29
+ info['status']
30
+ end
31
+
32
+ def file
33
+ info['file']
34
+ end
35
+
36
+ def view_queue
37
+ execute('view queue')
38
+ end
39
+
40
+ def win_top
41
+ execute('win-top')
42
+ end
43
+
44
+ def win_down
45
+ execute('win-down')
46
+ end
47
+
48
+ def win_remove
49
+ execute('win-remove')
50
+ end
51
+
52
+ def play
53
+ execute('player-play')
54
+ end
55
+
56
+ def stop
57
+ execute('player-stop')
58
+ end
59
+
60
+ def pause
61
+ execute('player-pause')
62
+ end
63
+
64
+ def next
65
+ execute('player-next')
66
+ end
67
+
68
+ def prev
69
+ execute('player-prev')
70
+ end
71
+
72
+ def enqueue(file)
73
+ Cocaine::CommandLine.new('cmus-remote', "-q '#{file}'").run
74
+ end
75
+
76
+ def queue
77
+ execute('save -q -').split("\n")
78
+ end
79
+
80
+ def library
81
+ execute('save -l -').split("\n")
82
+ end
83
+
84
+ def execute(command)
85
+ Cocaine::CommandLine.new('cmus-remote', '-C :command', :command => command).run
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,76 @@
1
+ require 'sinatra/base'
2
+ require 'digest/sha2'
3
+ require 'audioinfo'
4
+
5
+ module Qtunes
6
+ class Server < Sinatra::Base
7
+ dir = File.dirname(File.expand_path(__FILE__))
8
+
9
+ set :views, "#{dir}/server/views"
10
+ set :public, "#{dir}/server/public"
11
+ set :static, true
12
+
13
+ get '/' do
14
+ @song = PLAYER.file
15
+ @songs = queue
16
+
17
+ erb :songs
18
+ end
19
+
20
+ get '/library' do
21
+ @song = PLAYER.file
22
+ @songs = library
23
+
24
+ erb :songs
25
+ end
26
+
27
+ get '/add/:id' do
28
+ PLAYER.enqueue(library[params[:id]][:path])
29
+
30
+ redirect '/'
31
+ end
32
+
33
+ get '/remove/:id' do
34
+ ix = library.keys.index(params[:id])
35
+
36
+ # badass!
37
+ PLAYER.view_queue
38
+ PLAYER.win_top
39
+ ix.times{ PLAYER.win_down }
40
+ PLAYER.win_remove
41
+
42
+ redirect '/'
43
+ end
44
+
45
+ configure do
46
+ puts "Configure"
47
+
48
+ PLAYER = Qtunes::Player.new
49
+ end
50
+
51
+ def self.queue
52
+ songs_to_hash{ PLAYER.queue }
53
+ end
54
+
55
+ def self.library
56
+ @library ||= songs_to_hash{ PLAYER.library }
57
+ end
58
+
59
+ protected
60
+ def self.songs_to_hash
61
+ yield.inject({}) do |res,path|
62
+ begin
63
+ song = {:path => path}.merge(AudioInfo.open(path).to_h)
64
+ rescue AudioInfoError
65
+ next res
66
+ end
67
+ res[song_id(path)] = song
68
+ res
69
+ end
70
+ end
71
+
72
+ def self.song_id(file)
73
+ Digest::SHA256.hexdigest(file)[0,10]
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,129 @@
1
+ /*
2
+
3
+ dark: 485460
4
+ 3D72AA
5
+ 5E7894
6
+ 438FDF
7
+ D0E4FA
8
+ */
9
+
10
+ html{
11
+ font-family: Helvetica;
12
+ }
13
+ body{
14
+ margin: 0;
15
+ padding: 0;
16
+ color: #5E7894;
17
+ }
18
+ h1{
19
+ margin: 1em 10px 0 10px;
20
+ padding: 0;
21
+ letter-spacing: -3px;
22
+ color: #000;
23
+ }
24
+ a{
25
+ color: #5E7894;
26
+ text-decoration: none;
27
+ }
28
+ a:hover{
29
+ color: #000;
30
+ }
31
+
32
+ .navigation{
33
+ text-align: right;
34
+ padding: 2px 10px;
35
+ font-weight: bold;
36
+ letter-spacing: -1px;
37
+ font-size: 1.4em;
38
+ }
39
+ .navigation a{
40
+ color: #485460;
41
+ padding-left: 10px;
42
+ text-decoration: none;
43
+ }
44
+ .navigation form{
45
+ display: inline;
46
+ }
47
+ .navigation input{
48
+ vertical-align: top;
49
+ width: 250px;
50
+ }
51
+ .content{
52
+ padding: 10px;
53
+ background-color: #D0E4FA;
54
+ }
55
+ .gravatar{
56
+ -webkit-border-radius: 5px;
57
+ }
58
+
59
+ /*
60
+ * SONGS
61
+ */
62
+ .songs{
63
+
64
+ }
65
+ .song{
66
+ letter-spacing: -1px;
67
+ background-color: #D0E4FA;
68
+ border-top: 2px solid #fff;
69
+ padding: .5em 10px;
70
+ font-size: 1.25em;
71
+ font-weight: bold;
72
+ }
73
+ .song a:hover{
74
+ color: #000 !important;
75
+ }
76
+ .song .artist{
77
+ font-size: 3em;
78
+ letter-spacing: -5px;
79
+ }
80
+ .song .artist a{
81
+ color: #485460;
82
+ }
83
+ .song .title{
84
+ padding-left: 10px;
85
+ font-size: 2.2em;
86
+ letter-spacing: -4px;
87
+ }
88
+ .song .album{
89
+ margin-left: 10px;
90
+ font-size: 1.1em;
91
+ letter-spacing: -2px;
92
+ }
93
+ .song .album a{
94
+ color: #438FDF;
95
+ }
96
+ .song .controls{
97
+ float: right;
98
+ font-size: .75em;
99
+ margin: -.5em -5px;
100
+ text-transform: uppercase;
101
+ }
102
+ .votes{
103
+ background-color: #485460;
104
+ padding: 5px 5px 0px 5px;
105
+ }
106
+ .votes img{
107
+ border: 1px solid #5E7894;
108
+ }
109
+ .votes img:hover{
110
+ border: 1px solid #D0E4FA;
111
+ }
112
+
113
+ /*
114
+ * PROFILE
115
+ */
116
+ .profile_box{
117
+ margin-right: 10px;
118
+ float: left;
119
+ font-size: 1.1em;
120
+ }
121
+ .bio{
122
+ padding: 15px 0;
123
+ }
124
+ .favorite_artists{
125
+ margin: 0 15px;
126
+ }
127
+ .favorite_artists h2{
128
+ color: #485460;
129
+ }
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Qtunes</title>
5
+ <link rel="stylesheet" href="/base.css" type="text/css" />
6
+ </head>
7
+
8
+ <body>
9
+ <h1>Title</h1>
10
+
11
+ <div class="navigation">
12
+ <form method="get" action="/search">
13
+ <input type="search" name="q" />
14
+ </form>
15
+
16
+ <a href="/">Queue</a>
17
+ <a href="/library">Library</a>
18
+ </div>
19
+
20
+ <%= yield %>
21
+ </body>
22
+ </html>
@@ -0,0 +1,31 @@
1
+ <p>Now playing: '<%= @song %>'</p>
2
+
3
+ <% @songs.each do |id, song| %>
4
+ <div class="song">
5
+ <span class="controls">
6
+ <% if queue[id] %>
7
+ <a href="/remove/<%= id %>" title="remove from queue">-</a>
8
+ <% else %>
9
+ <a href="/add/<%= id %>" title="add to queue">+</a>
10
+ <% end %>
11
+ </span>
12
+
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>
24
+ </div>
25
+ <% end %>
26
+
27
+ <% if @songs.empty? %>
28
+ <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.
30
+ </div>
31
+ <% end %>
@@ -0,0 +1,3 @@
1
+ module Qtunes
2
+ VERSION = "0.0.1"
3
+ end
data/qtunes.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "qtunes/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "qtunes"
7
+ s.version = Qtunes::VERSION
8
+ s.authors = ["Gert Goet"]
9
+ s.email = ["gert@thinkcreate.nl"]
10
+ s.homepage = ""
11
+ s.summary = %q{add songs to queue, let cmus eat it}
12
+ s.description = %q{add songs to queue, let cmus eat it}
13
+
14
+ s.rubyforge_project = "qtunes"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
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"
27
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qtunes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Gert Goet
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-23 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sinatra
17
+ requirement: &8511880 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *8511880
26
+ - !ruby/object:Gem::Dependency
27
+ name: thor
28
+ requirement: &8511460 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *8511460
37
+ - !ruby/object:Gem::Dependency
38
+ name: cocaine
39
+ requirement: &8511040 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *8511040
48
+ - !ruby/object:Gem::Dependency
49
+ name: ruby-audioinfo
50
+ requirement: &8510620 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *8510620
59
+ description: add songs to queue, let cmus eat it
60
+ email:
61
+ - gert@thinkcreate.nl
62
+ executables:
63
+ - qtunes
64
+ extensions: []
65
+ extra_rdoc_files: []
66
+ files:
67
+ - .gitignore
68
+ - Gemfile
69
+ - README
70
+ - Rakefile
71
+ - bin/qtunes
72
+ - lib/qtunes.rb
73
+ - lib/qtunes/player.rb
74
+ - lib/qtunes/server.rb
75
+ - lib/qtunes/server/public/base.css
76
+ - lib/qtunes/server/views/layout.erb
77
+ - lib/qtunes/server/views/songs.erb
78
+ - lib/qtunes/version.rb
79
+ - qtunes.gemspec
80
+ has_rdoc: true
81
+ homepage: ''
82
+ licenses: []
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project: qtunes
101
+ rubygems_version: 1.6.2
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: add songs to queue, let cmus eat it
105
+ test_files: []