sonice 2.0.0 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.jshintrc +3 -0
- data/.rubocop.yml +105 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +42 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +44 -23
- data/README.md +4 -4
- data/Rakefile +2 -1
- data/bin/rake +29 -0
- data/bin/sonice +2 -0
- data/config.ru +2 -1
- data/lib/sonice.rb +3 -2
- data/lib/sonice/app.rb +24 -21
- data/lib/sonice/command_line.rb +4 -2
- data/lib/sonice/noplayer.rb +40 -0
- data/lib/sonice/public/favicon.ico +0 -0
- data/lib/sonice/public/script.js +8 -63
- data/lib/sonice/public/stylesheet.css +44 -44
- data/lib/sonice/version.rb +4 -1
- data/lib/sonice/views/index.erb +81 -0
- data/sonice.gemspec +22 -18
- metadata +33 -42
- data/lib/sonice/views/index.haml +0 -31
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3663e23a3502f84a181a07d3a65323993980b9b0c97860b138b36e1fbd983f84
|
4
|
+
data.tar.gz: 121da492eac569ac3dced778d5e47212445fb35d0f38f265862e34ac4bd47c3d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f034dd6cae0e045236effdfb114f6ab75718d6fb3ec9d2d5e5f005c55caabb1f7f9aee664de70693ea5415eefb7a88fe04e27c21da6a98f70a8b585f2aa378ac
|
7
|
+
data.tar.gz: f70229248edc86a3ef54fc4b74ebac8dd5225bd9735d36c17618229dc3ca588f2249de18b34dd8a9bd99dd2030305054f3e204e8adf07aa7255ce97068164235
|
data/.jshintrc
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
Style/StringLiterals:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
Layout/BeginEndAlignment: # (new in 0.91)
|
5
|
+
Enabled: true
|
6
|
+
Layout/EmptyLinesAroundAttributeAccessor: # (new in 0.83)
|
7
|
+
Enabled: true
|
8
|
+
Layout/SpaceAroundMethodCallOperator: # (new in 0.82)
|
9
|
+
Enabled: true
|
10
|
+
Lint/BinaryOperatorWithIdenticalOperands: # (new in 0.89)
|
11
|
+
Enabled: true
|
12
|
+
Lint/ConstantDefinitionInBlock: # (new in 0.91)
|
13
|
+
Enabled: true
|
14
|
+
Lint/DeprecatedOpenSSLConstant: # (new in 0.84)
|
15
|
+
Enabled: true
|
16
|
+
Lint/DuplicateElsifCondition: # (new in 0.88)
|
17
|
+
Enabled: true
|
18
|
+
Lint/DuplicateRequire: # (new in 0.90)
|
19
|
+
Enabled: true
|
20
|
+
Lint/DuplicateRescueException: # (new in 0.89)
|
21
|
+
Enabled: true
|
22
|
+
Lint/EmptyConditionalBody: # (new in 0.89)
|
23
|
+
Enabled: true
|
24
|
+
Lint/EmptyFile: # (new in 0.90)
|
25
|
+
Enabled: true
|
26
|
+
Lint/FloatComparison: # (new in 0.89)
|
27
|
+
Enabled: true
|
28
|
+
Lint/HashCompareByIdentity: # (new in 0.93)
|
29
|
+
Enabled: true
|
30
|
+
Lint/IdentityComparison: # (new in 0.91)
|
31
|
+
Enabled: true
|
32
|
+
Lint/MissingSuper: # (new in 0.89)
|
33
|
+
Enabled: true
|
34
|
+
Lint/MixedRegexpCaptureTypes: # (new in 0.85)
|
35
|
+
Enabled: true
|
36
|
+
Lint/OutOfRangeRegexpRef: # (new in 0.89)
|
37
|
+
Enabled: true
|
38
|
+
Lint/RaiseException: # (new in 0.81)
|
39
|
+
Enabled: true
|
40
|
+
Lint/RedundantSafeNavigation: # (new in 0.93)
|
41
|
+
Enabled: true
|
42
|
+
Lint/SelfAssignment: # (new in 0.89)
|
43
|
+
Enabled: true
|
44
|
+
Lint/StructNewOverride: # (new in 0.81)
|
45
|
+
Enabled: true
|
46
|
+
Lint/TopLevelReturnWithArgument: # (new in 0.89)
|
47
|
+
Enabled: true
|
48
|
+
Lint/TrailingCommaInAttributeDeclaration: # (new in 0.90)
|
49
|
+
Enabled: true
|
50
|
+
Lint/UnreachableLoop: # (new in 0.89)
|
51
|
+
Enabled: true
|
52
|
+
Lint/UselessMethodDefinition: # (new in 0.90)
|
53
|
+
Enabled: true
|
54
|
+
Lint/UselessTimes: # (new in 0.91)
|
55
|
+
Enabled: true
|
56
|
+
Style/AccessorGrouping: # (new in 0.87)
|
57
|
+
Enabled: true
|
58
|
+
Style/BisectedAttrAccessor: # (new in 0.87)
|
59
|
+
Enabled: true
|
60
|
+
Style/CaseLikeIf: # (new in 0.88)
|
61
|
+
Enabled: true
|
62
|
+
Style/ClassEqualityComparison: # (new in 0.93)
|
63
|
+
Enabled: true
|
64
|
+
Style/CombinableLoops: # (new in 0.90)
|
65
|
+
Enabled: true
|
66
|
+
Style/ExplicitBlockArgument: # (new in 0.89)
|
67
|
+
Enabled: true
|
68
|
+
Style/ExponentialNotation: # (new in 0.82)
|
69
|
+
Enabled: true
|
70
|
+
Style/GlobalStdStream: # (new in 0.89)
|
71
|
+
Enabled: true
|
72
|
+
Style/HashAsLastArrayItem: # (new in 0.88)
|
73
|
+
Enabled: true
|
74
|
+
Style/HashEachMethods: # (new in 0.80)
|
75
|
+
Enabled: true
|
76
|
+
Style/HashLikeCase: # (new in 0.88)
|
77
|
+
Enabled: true
|
78
|
+
Style/HashTransformKeys: # (new in 0.80)
|
79
|
+
Enabled: true
|
80
|
+
Style/HashTransformValues: # (new in 0.80)
|
81
|
+
Enabled: true
|
82
|
+
Style/KeywordParametersOrder: # (new in 0.90)
|
83
|
+
Enabled: true
|
84
|
+
Style/OptionalBooleanParameter: # (new in 0.89)
|
85
|
+
Enabled: true
|
86
|
+
Style/RedundantAssignment: # (new in 0.87)
|
87
|
+
Enabled: true
|
88
|
+
Style/RedundantFetchBlock: # (new in 0.86)
|
89
|
+
Enabled: true
|
90
|
+
Style/RedundantFileExtensionInRequire: # (new in 0.88)
|
91
|
+
Enabled: true
|
92
|
+
Style/RedundantRegexpCharacterClass: # (new in 0.85)
|
93
|
+
Enabled: true
|
94
|
+
Style/RedundantRegexpEscape: # (new in 0.85)
|
95
|
+
Enabled: true
|
96
|
+
Style/RedundantSelfAssignment: # (new in 0.90)
|
97
|
+
Enabled: true
|
98
|
+
Style/SingleArgumentDig: # (new in 0.89)
|
99
|
+
Enabled: true
|
100
|
+
Style/SlicingWithRange: # (new in 0.83)
|
101
|
+
Enabled: true
|
102
|
+
Style/SoleNestedConditional: # (new in 0.89)
|
103
|
+
Enabled: true
|
104
|
+
Style/StringConcatenation: # (new in 0.89)
|
105
|
+
Enabled: true
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.7.1
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Changelog
|
2
|
+
=========
|
3
|
+
|
4
|
+
So Nice tries its best to follow Semantic Versioning.
|
5
|
+
|
6
|
+
## Unreleased
|
7
|
+
|
8
|
+
## v2.2.1
|
9
|
+
|
10
|
+
- Remove rake executable in gemspec.
|
11
|
+
- Bump anyplayer dependency
|
12
|
+
|
13
|
+
## v2.2.0
|
14
|
+
|
15
|
+
Fixes:
|
16
|
+
|
17
|
+
- Remove background image since LastFM API doesn’t contain images
|
18
|
+
|
19
|
+
Dependencies:
|
20
|
+
|
21
|
+
- Bump anyplayer dependency
|
22
|
+
- Remove Haml dependency
|
23
|
+
- Bump Sinatra dependency
|
24
|
+
- Replace Thin by Webrick
|
25
|
+
|
26
|
+
## v2.1.2
|
27
|
+
|
28
|
+
Dependencies:
|
29
|
+
|
30
|
+
- Fix Sinatra upgrade (#22)
|
31
|
+
- Fix Thin dependency so as not to break with thin versions > 2
|
32
|
+
|
33
|
+
## v2.1.1
|
34
|
+
|
35
|
+
Fixes:
|
36
|
+
|
37
|
+
- Fix LastFM JavaScript (thanks @datagutt)
|
38
|
+
- Fix Thin dependency with Sinatra
|
39
|
+
|
40
|
+
## v2.1.0 (2013-12-18)
|
41
|
+
|
42
|
+
First Gem version.
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,40 +1,61 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sonice (
|
5
|
-
anyplayer (
|
6
|
-
haml
|
4
|
+
sonice (2.2.1)
|
5
|
+
anyplayer (>= 1.2.1)
|
7
6
|
sinatra
|
8
|
-
|
7
|
+
webrick
|
9
8
|
xml-simple
|
10
9
|
|
11
10
|
GEM
|
12
11
|
remote: http://rubygems.org/
|
13
12
|
specs:
|
14
|
-
anyplayer (1.1
|
13
|
+
anyplayer (1.2.1)
|
15
14
|
ruby-mpd (~> 0.3.0)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
ast (2.4.1)
|
16
|
+
mustermann (1.1.1)
|
17
|
+
ruby2_keywords (~> 0.0.1)
|
18
|
+
parallel (1.19.2)
|
19
|
+
parser (2.7.2.0)
|
20
|
+
ast (~> 2.4.1)
|
21
|
+
rack (2.2.3)
|
22
|
+
rack-protection (2.1.0)
|
22
23
|
rack
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
rainbow (3.0.0)
|
25
|
+
rake (13.0.1)
|
26
|
+
regexp_parser (1.8.1)
|
27
|
+
rexml (3.2.4)
|
28
|
+
rubocop (0.93.0)
|
29
|
+
parallel (~> 1.10)
|
30
|
+
parser (>= 2.7.1.5)
|
31
|
+
rainbow (>= 2.2.2, < 4.0)
|
32
|
+
regexp_parser (>= 1.8)
|
33
|
+
rexml
|
34
|
+
rubocop-ast (>= 0.6.0)
|
35
|
+
ruby-progressbar (~> 1.7)
|
36
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
37
|
+
rubocop-ast (0.7.1)
|
38
|
+
parser (>= 2.7.1.5)
|
39
|
+
ruby-mpd (0.3.3)
|
40
|
+
ruby-progressbar (1.10.1)
|
41
|
+
ruby2_keywords (0.0.2)
|
42
|
+
sinatra (2.1.0)
|
43
|
+
mustermann (~> 1.0)
|
44
|
+
rack (~> 2.2)
|
45
|
+
rack-protection (= 2.1.0)
|
46
|
+
tilt (~> 2.0)
|
47
|
+
tilt (2.0.10)
|
48
|
+
unicode-display_width (1.7.0)
|
49
|
+
webrick (1.7.0)
|
50
|
+
xml-simple (1.1.7)
|
34
51
|
|
35
52
|
PLATFORMS
|
36
53
|
ruby
|
37
54
|
|
38
55
|
DEPENDENCIES
|
39
|
-
|
56
|
+
rake
|
57
|
+
rubocop
|
40
58
|
sonice!
|
59
|
+
|
60
|
+
BUNDLED WITH
|
61
|
+
2.1.4
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
So Nice ♫
|
2
2
|
=======
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
>
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/sonice.png)](http://badge.fury.io/rb/sonice)
|
5
|
+
|
6
|
+
> “Everynight with my star friends, we eat caviar and drink champage”
|
7
7
|
|
8
8
|
A small Web interface to play, pause, change volume or skip the currently
|
9
9
|
playing song in iTunes Mac, iTunes Windows, Spotify Mac, MPD, Rhythmbox, Amarok and XMMS2.
|
@@ -14,7 +14,7 @@ playing song in iTunes Mac, iTunes Windows, Spotify Mac, MPD, Rhythmbox, Amarok
|
|
14
14
|
Install
|
15
15
|
-------
|
16
16
|
|
17
|
-
Make sure you have Ruby and Rubygems installed. You can then type in a terminal:
|
17
|
+
Make sure you have Ruby > 1.9 and Rubygems installed. You can then type in a terminal:
|
18
18
|
|
19
19
|
```bash
|
20
20
|
$ gem install sonice
|
data/Rakefile
CHANGED
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/sonice
CHANGED
data/config.ru
CHANGED
data/lib/sonice.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Standard library
|
2
4
|
require 'open-uri'
|
3
5
|
|
4
6
|
# Gems
|
5
7
|
require 'anyplayer'
|
6
8
|
require 'sinatra'
|
7
|
-
require 'haml'
|
8
9
|
require 'xmlsimple' # xml-simple gem
|
9
10
|
require 'json'
|
10
|
-
require 'thin'
|
11
11
|
|
12
12
|
# So Nice
|
13
|
+
require 'sonice/noplayer'
|
13
14
|
require 'sonice/app'
|
data/lib/sonice/app.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sonice
|
4
|
+
# Sinatra application
|
2
5
|
class App < Sinatra::Base
|
3
6
|
set :port, ENV['SONICE_PORT'] || 3000
|
4
7
|
set :controls, ENV['SONICE_CONTROLS'] != '0'
|
@@ -7,47 +10,47 @@ module Sonice
|
|
7
10
|
|
8
11
|
set :logging, true
|
9
12
|
set :static, true
|
10
|
-
set :public_dir, File.expand_path('
|
11
|
-
set :views, File.expand_path('
|
12
|
-
set :haml, format: :html5
|
13
|
+
set :public_dir, File.expand_path('public', __dir__)
|
14
|
+
set :views, File.expand_path('views', __dir__)
|
13
15
|
set :protection, except: :frame_options
|
16
|
+
set :server, :webrick
|
14
17
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
abort "Error: no music player launched!" if !player
|
20
|
-
puts "Connected to #{player.name}"
|
21
|
-
player
|
22
|
-
end
|
18
|
+
def player_instance
|
19
|
+
return @player if @player&.launched?
|
20
|
+
|
21
|
+
@player = Anyplayer::Selector.new.player || Noplayer.new
|
23
22
|
end
|
24
23
|
|
25
24
|
put '/player' do
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
player = player_instance
|
26
|
+
|
27
|
+
player.vote if settings.voting && params['vote']
|
29
28
|
|
30
29
|
if settings.controls
|
31
|
-
methods = %w
|
30
|
+
methods = %w[playpause prev next voldown volup] & params.keys
|
32
31
|
methods.each { |method| player.send(method) }
|
33
32
|
end
|
34
33
|
|
35
|
-
|
36
|
-
redirect '/'
|
37
|
-
end
|
34
|
+
redirect "/" unless request.xhr?
|
38
35
|
end
|
39
36
|
|
40
37
|
get '/' do
|
38
|
+
player = player_instance
|
39
|
+
|
41
40
|
@title = player.track
|
42
41
|
@artist = player.artist
|
43
42
|
@album = player.album
|
43
|
+
@connected = player.launched?
|
44
|
+
|
44
45
|
if request.xhr?
|
45
46
|
content_type :json
|
46
|
-
{ :
|
47
|
+
{ title: @title,
|
48
|
+
artist: @artist,
|
49
|
+
album: @album,
|
50
|
+
connected: @connected }.to_json
|
47
51
|
else
|
48
|
-
|
52
|
+
erb :index
|
49
53
|
end
|
50
54
|
end
|
51
|
-
|
52
55
|
end
|
53
56
|
end
|
data/lib/sonice/command_line.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "sonice"
|
2
4
|
require 'sonice/version'
|
3
5
|
|
4
6
|
module Sonice
|
7
|
+
# Module CommandLine
|
5
8
|
module CommandLine
|
6
|
-
|
9
|
+
module_function
|
7
10
|
|
8
11
|
def parse(argv)
|
9
12
|
case argv
|
@@ -19,7 +22,6 @@ module Sonice
|
|
19
22
|
puts "Usage: sonice [--version]"
|
20
23
|
exit(1)
|
21
24
|
end
|
22
|
-
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sonice
|
4
|
+
# A null-object that represents a player when none was found.
|
5
|
+
class Noplayer < Anyplayer::Player
|
6
|
+
def playing?
|
7
|
+
false
|
8
|
+
end
|
9
|
+
|
10
|
+
def play; end
|
11
|
+
|
12
|
+
def pause; end
|
13
|
+
|
14
|
+
def voldown; end
|
15
|
+
|
16
|
+
def volup; end
|
17
|
+
|
18
|
+
def volume; end
|
19
|
+
|
20
|
+
def track
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def artist
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def album
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def launched?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def name
|
37
|
+
"no player"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
Binary file
|
data/lib/sonice/public/script.js
CHANGED
@@ -8,11 +8,6 @@ Array.prototype.random = function() {
|
|
8
8
|
|
9
9
|
/* jQuery helpers */
|
10
10
|
|
11
|
-
// Change CSS background image
|
12
|
-
$.fn.background = function(bg) {
|
13
|
-
return $(this).css('backgroundImage', bg ? 'url('+bg+')' : 'none')
|
14
|
-
}
|
15
|
-
|
16
11
|
// Assigns keyboard keys to elements and adds them to the title attributes
|
17
12
|
// Needs the data-keyboard-key attribute on elements and optionally accepts
|
18
13
|
// the data-keyboard-name attribute
|
@@ -29,47 +24,6 @@ $.fn.keyboardShortcut = function() {
|
|
29
24
|
})
|
30
25
|
}
|
31
26
|
|
32
|
-
|
33
|
-
/* So nice helpers */
|
34
|
-
|
35
|
-
// Get a new artist image from Last.fm via jsonp
|
36
|
-
// When found calls the `callback` with the image url as the first argument
|
37
|
-
function artistImage(artist, callback) {
|
38
|
-
// Commented out because Last.fm does not support this URL anymore.
|
39
|
-
|
40
|
-
// if (!artist)
|
41
|
-
// return callback()
|
42
|
-
// var cb = function() { callback(cache[artist].random()) },
|
43
|
-
// cache = artistImage.cache
|
44
|
-
// artist = encodeURI(artist)
|
45
|
-
|
46
|
-
// // Deliver from cache
|
47
|
-
// if (cache.hasOwnProperty(artist)) {
|
48
|
-
// // execute the callback asynchronously to minimize codepaths
|
49
|
-
// setTimeout(cb, 10)
|
50
|
-
// return
|
51
|
-
// }
|
52
|
-
|
53
|
-
// // Load
|
54
|
-
// var last_fm_uri = "http://ws.audioscrobbler.com/2.0/?format=json&method=artist.getimages&artist=%s&api_key=5636ca9fea36d0323a76638385aab1f3"
|
55
|
-
// $.ajax({
|
56
|
-
// url: last_fm_uri.replace('%s', artist),
|
57
|
-
// dataType: 'jsonp',
|
58
|
-
// success: function(obj) {
|
59
|
-
// if (obj.images.image) {
|
60
|
-
// cache[artist] = $.map(obj.images.image, function(img) {
|
61
|
-
// return img.sizes.size[0]['#text']
|
62
|
-
// })
|
63
|
-
// cb()
|
64
|
-
// } else {
|
65
|
-
// callback()
|
66
|
-
// }
|
67
|
-
// }
|
68
|
-
// })
|
69
|
-
}
|
70
|
-
artistImage.cache = {}
|
71
|
-
|
72
|
-
|
73
27
|
$(function() {
|
74
28
|
// Object that contains all the song info
|
75
29
|
var currentSong = {}
|
@@ -81,12 +35,15 @@ $(function() {
|
|
81
35
|
currentSong = obj = obj || {}
|
82
36
|
|
83
37
|
var artist = obj.artist || '',
|
84
|
-
|
85
|
-
|
38
|
+
album = obj.album || '',
|
39
|
+
title = obj.title || '',
|
40
|
+
connected = !!obj.connected
|
86
41
|
|
87
42
|
$('#title' ).text(title)
|
88
43
|
$('#artist').text(artist)
|
89
44
|
$('#album' ).text(album)
|
45
|
+
$('[data-sonice-show-if-connected]')[connected ? 'show' : 'hide']()
|
46
|
+
$('[data-sonice-hide-if-connected]')[connected ? 'hide' : 'show']()
|
90
47
|
|
91
48
|
if (!title)
|
92
49
|
$('title').text('So nice')
|
@@ -95,16 +52,6 @@ $(function() {
|
|
95
52
|
|
96
53
|
if (artistChange || songChange)
|
97
54
|
$('#vote').removeAttr('disabled').show()
|
98
|
-
|
99
|
-
if (artistChange)
|
100
|
-
changeBackground()
|
101
|
-
}
|
102
|
-
|
103
|
-
// Change background on the body regularly
|
104
|
-
var changeBackground = function(){
|
105
|
-
artistImage(currentSong.artist, function(url) {
|
106
|
-
$('body').background(url)
|
107
|
-
})
|
108
55
|
}
|
109
56
|
|
110
57
|
// XHR updating the text regularly
|
@@ -118,7 +65,7 @@ $(function() {
|
|
118
65
|
|
119
66
|
// XHR overriding the buttons
|
120
67
|
$(document).on('click', 'input', function(e) {
|
121
|
-
e.preventDefault()
|
68
|
+
e.preventDefault()
|
122
69
|
|
123
70
|
$.ajax({
|
124
71
|
type: 'put',
|
@@ -133,12 +80,10 @@ $(function() {
|
|
133
80
|
$(this).attr('disabled', true).fadeOut(500)
|
134
81
|
})
|
135
82
|
|
136
|
-
update()
|
83
|
+
update()
|
137
84
|
setInterval(update, 500)
|
138
|
-
setInterval(changeBackground, 10000)
|
139
85
|
|
140
86
|
// Keyboard shortcuts
|
141
|
-
$('
|
87
|
+
$('[data-key]').keyboardShortcut()
|
142
88
|
|
143
89
|
})
|
144
|
-
|
@@ -1,13 +1,15 @@
|
|
1
1
|
body {
|
2
2
|
padding: 2em;
|
3
3
|
margin: 0;
|
4
|
-
background-color:
|
4
|
+
background-color: #555;
|
5
|
+
color: white;
|
6
|
+
font: 1.5em Helvetica, sans-serif;
|
7
|
+
|
8
|
+
/* Prepare for having a background-image */
|
5
9
|
background-position: center center fixed no-repeat;
|
6
|
-
background-repeat:
|
10
|
+
background-repeat: no-repeat;
|
7
11
|
background-attachment: fixed;
|
8
12
|
background-size: cover;
|
9
|
-
color: white;
|
10
|
-
font: 1.5em Helvetica, sans-serif;
|
11
13
|
}
|
12
14
|
|
13
15
|
/* Overlay image */
|
@@ -31,19 +33,19 @@ h1, h2, h3 {
|
|
31
33
|
text-shadow: black 0 0 7px;
|
32
34
|
}
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
h1 {
|
37
|
+
font-size: 230%;
|
38
|
+
}
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
40
|
+
h2 {
|
41
|
+
font-size: 150%;
|
42
|
+
}
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
h3 {
|
45
|
+
font-size: 100%;
|
46
|
+
margin-top: 1ex;
|
47
|
+
font-weight: normal;
|
48
|
+
}
|
47
49
|
|
48
50
|
form {
|
49
51
|
opacity: .5;
|
@@ -52,35 +54,33 @@ form {
|
|
52
54
|
left: 42px;
|
53
55
|
}
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
input {
|
60
|
-
font-size: 1em;
|
61
|
-
color: inherit;
|
62
|
-
text-decoration: none;
|
63
|
-
padding: .2em .3em;
|
64
|
-
background: #222;
|
65
|
-
color: #aaa;
|
66
|
-
-webkit-border-radius: .4em;
|
67
|
-
-moz-border-radius: .4em;
|
68
|
-
-o-border-radius: .4em;
|
69
|
-
border-radius: .4em;
|
70
|
-
border: .1em solid #222;
|
71
|
-
cursor: pointer;
|
72
|
-
width: 2em;
|
73
|
-
height: 2em;
|
74
|
-
|
75
|
-
}
|
57
|
+
form:hover {
|
58
|
+
opacity: 1;
|
59
|
+
}
|
76
60
|
|
77
|
-
|
78
|
-
|
79
|
-
|
61
|
+
input {
|
62
|
+
font-size: 1em;
|
63
|
+
color: inherit;
|
64
|
+
text-decoration: none;
|
65
|
+
padding: .2em .3em;
|
66
|
+
background: #222;
|
67
|
+
color: #aaa;
|
68
|
+
-webkit-border-radius: .4em;
|
69
|
+
-moz-border-radius: .4em;
|
70
|
+
-o-border-radius: .4em;
|
71
|
+
border-radius: .4em;
|
72
|
+
border: .1em solid #222;
|
73
|
+
cursor: pointer;
|
74
|
+
width: 2em;
|
75
|
+
height: 2em;
|
76
|
+
}
|
80
77
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
}
|
85
|
-
}
|
78
|
+
input:hover {
|
79
|
+
border-color: inherit;
|
80
|
+
}
|
86
81
|
|
82
|
+
@media (max-width:800px) {
|
83
|
+
input {
|
84
|
+
font-size: 2em;
|
85
|
+
}
|
86
|
+
}
|
data/lib/sonice/version.rb
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>
|
5
|
+
<% if !@artist && !@title %>
|
6
|
+
So Nice ♫
|
7
|
+
<% else %>
|
8
|
+
<%= [@artist, @title].compact.join(" — ") %>
|
9
|
+
<% end %>
|
10
|
+
</title>
|
11
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
12
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
13
|
+
<link rel="stylesheet" href="/stylesheet.css" />
|
14
|
+
</head>
|
15
|
+
<body>
|
16
|
+
<h1 id="title"><%= @title %></h1>
|
17
|
+
<h2 id="artist"><%= @artist %></h2>
|
18
|
+
<h3 id="album"><%= @album %></h3>
|
19
|
+
|
20
|
+
<h1 style="display:none" data-sonice-hide-if-connected>Connecting…</h1>
|
21
|
+
|
22
|
+
<form method="post" action="player" data-sonice-show-if-connected>
|
23
|
+
<input name="_method" type="hidden" value="put">
|
24
|
+
<% if settings.controls %>
|
25
|
+
<input
|
26
|
+
type="button"
|
27
|
+
value="▶"
|
28
|
+
id="playpause"
|
29
|
+
name="playpause"
|
30
|
+
title="Play/Pause"
|
31
|
+
data-key-name="space"
|
32
|
+
data-key=" "
|
33
|
+
/>
|
34
|
+
<input
|
35
|
+
type="button"
|
36
|
+
value="←"
|
37
|
+
id="prev"
|
38
|
+
name="prev"
|
39
|
+
title="Previous"
|
40
|
+
data-key="p"
|
41
|
+
/>
|
42
|
+
<input
|
43
|
+
type="button"
|
44
|
+
value="→"
|
45
|
+
id="next"
|
46
|
+
name="next"
|
47
|
+
title="Next"
|
48
|
+
data-key="n"
|
49
|
+
/>
|
50
|
+
<input
|
51
|
+
type="button"
|
52
|
+
value="♪"
|
53
|
+
id="voldown"
|
54
|
+
name="voldown"
|
55
|
+
title="Quieter"
|
56
|
+
data-key="-"
|
57
|
+
/>
|
58
|
+
<input
|
59
|
+
type="button"
|
60
|
+
value="♫"
|
61
|
+
id="volup"
|
62
|
+
name="volup"
|
63
|
+
title="Louder"
|
64
|
+
data-key="+"
|
65
|
+
/>
|
66
|
+
<% end %>
|
67
|
+
<% if settings.voting %>
|
68
|
+
<input
|
69
|
+
type="button"
|
70
|
+
value="↡"
|
71
|
+
id="vote"
|
72
|
+
name="vote"
|
73
|
+
title="Vote to Skip"
|
74
|
+
data-key="s"
|
75
|
+
/>
|
76
|
+
<% end %>
|
77
|
+
</form>
|
78
|
+
<script src="/jquery.min.js"></script>
|
79
|
+
<script src="/script.js"></script>
|
80
|
+
</body>
|
81
|
+
</html>
|
data/sonice.gemspec
CHANGED
@@ -1,27 +1,31 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
3
4
|
require "sonice/version"
|
4
5
|
|
5
6
|
Gem::Specification.new do |s|
|
6
|
-
s.name
|
7
|
-
s.version
|
8
|
-
s.platform
|
9
|
-
s.authors
|
10
|
-
s.email
|
11
|
-
s.homepage
|
12
|
-
s.summary
|
13
|
-
s.description =
|
14
|
-
|
7
|
+
s.name = "sonice"
|
8
|
+
s.version = Sonice::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ["Sunny Ripert"]
|
11
|
+
s.email = ["sunny@sunfox.org"]
|
12
|
+
s.homepage = "http://github.com/sunny/so-nice"
|
13
|
+
s.summary = "Web interface to control your current music player"
|
14
|
+
s.description =
|
15
|
+
"Small Web interface to control iTunes, Spotify, Rdio, MPD, Rhythmbox, " \
|
16
|
+
"Amarok and XMMS2. ♫"
|
17
|
+
s.license = "WTFPL"
|
15
18
|
|
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
19
|
s.require_paths = ["lib"]
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = ["sonice"]
|
20
23
|
|
21
|
-
s.add_runtime_dependency 'anyplayer', '
|
24
|
+
s.add_runtime_dependency 'anyplayer', '>= 1.2.1'
|
22
25
|
s.add_runtime_dependency 'sinatra'
|
23
|
-
s.add_runtime_dependency '
|
26
|
+
s.add_runtime_dependency 'webrick'
|
24
27
|
s.add_runtime_dependency 'xml-simple'
|
25
|
-
|
26
|
-
s.add_development_dependency '
|
28
|
+
|
29
|
+
s.add_development_dependency 'rake'
|
30
|
+
s.add_development_dependency 'rubocop'
|
27
31
|
end
|
metadata
CHANGED
@@ -1,110 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sonice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
5
|
-
prerelease:
|
4
|
+
version: 2.2.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Sunny Ripert
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2020-12-19 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: anyplayer
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
19
|
+
version: 1.2.1
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.
|
26
|
+
version: 1.2.1
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: sinatra
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
42
|
+
name: webrick
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: xml-simple
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - ">="
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - ">="
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
70
|
+
name: rake
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - ">="
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: '0'
|
86
|
-
type: :
|
76
|
+
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - ">="
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: '0'
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
84
|
+
name: rubocop
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
|
-
- -
|
87
|
+
- - ">="
|
100
88
|
- !ruby/object:Gem::Version
|
101
89
|
version: '0'
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
|
-
- -
|
94
|
+
- - ">="
|
108
95
|
- !ruby/object:Gem::Version
|
109
96
|
version: '0'
|
110
97
|
description: Small Web interface to control iTunes, Spotify, Rdio, MPD, Rhythmbox,
|
@@ -116,46 +103,50 @@ executables:
|
|
116
103
|
extensions: []
|
117
104
|
extra_rdoc_files: []
|
118
105
|
files:
|
119
|
-
- .gitignore
|
106
|
+
- ".gitignore"
|
107
|
+
- ".jshintrc"
|
108
|
+
- ".rubocop.yml"
|
109
|
+
- ".ruby-version"
|
110
|
+
- CHANGELOG.md
|
120
111
|
- Gemfile
|
121
112
|
- Gemfile.lock
|
122
113
|
- README.md
|
123
114
|
- Rakefile
|
115
|
+
- bin/rake
|
124
116
|
- bin/sonice
|
125
117
|
- config.ru
|
126
118
|
- lib/sonice.rb
|
127
119
|
- lib/sonice/app.rb
|
128
120
|
- lib/sonice/command_line.rb
|
121
|
+
- lib/sonice/noplayer.rb
|
129
122
|
- lib/sonice/public/favicon.ico
|
130
123
|
- lib/sonice/public/jquery.min.js
|
131
124
|
- lib/sonice/public/script.js
|
132
125
|
- lib/sonice/public/stylesheet.css
|
133
126
|
- lib/sonice/version.rb
|
134
|
-
- lib/sonice/views/index.
|
127
|
+
- lib/sonice/views/index.erb
|
135
128
|
- sonice.gemspec
|
136
129
|
homepage: http://github.com/sunny/so-nice
|
137
130
|
licenses:
|
138
131
|
- WTFPL
|
132
|
+
metadata: {}
|
139
133
|
post_install_message:
|
140
134
|
rdoc_options: []
|
141
135
|
require_paths:
|
142
136
|
- lib
|
143
137
|
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
-
none: false
|
145
138
|
requirements:
|
146
|
-
- -
|
139
|
+
- - ">="
|
147
140
|
- !ruby/object:Gem::Version
|
148
141
|
version: '0'
|
149
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
-
none: false
|
151
143
|
requirements:
|
152
|
-
- -
|
144
|
+
- - ">="
|
153
145
|
- !ruby/object:Gem::Version
|
154
146
|
version: '0'
|
155
147
|
requirements: []
|
156
|
-
|
157
|
-
rubygems_version: 1.8.23
|
148
|
+
rubygems_version: 3.1.2
|
158
149
|
signing_key:
|
159
|
-
specification_version:
|
150
|
+
specification_version: 4
|
160
151
|
summary: Web interface to control your current music player
|
161
152
|
test_files: []
|
data/lib/sonice/views/index.haml
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
!!! 5
|
2
|
-
%html
|
3
|
-
%head
|
4
|
-
%title
|
5
|
-
- if !@artist && !@title
|
6
|
-
So nice
|
7
|
-
- else
|
8
|
-
= [@artist, @title].compact.join(" — ")
|
9
|
-
%meta{'http-equiv' => 'Content-Type', :content => 'text/html; charset=utf-8'}
|
10
|
-
%meta{:name => 'viewport', :content => 'width=device-width, initial-scale=1.0' }
|
11
|
-
%link{:rel => 'stylesheet', :href => '/stylesheet.css'}
|
12
|
-
|
13
|
-
%body{:style => @image_uri ? "background-image:url(#{@image_uri})" : nil }
|
14
|
-
%h1#title= @title
|
15
|
-
%h2#artist= @artist
|
16
|
-
%h3#album= @album
|
17
|
-
|
18
|
-
%form{:method => 'post', :action => 'player'}
|
19
|
-
%input{:type => "hidden", :name => "_method", :value => "put"}
|
20
|
-
- if settings.controls
|
21
|
-
%input#playpause{:type=>'button', :value=>'▸', :name=>'playpause', :title=>"Play/Pause", :'data-key'=>" ", :'data-key-name'=>"space"}
|
22
|
-
%input#prev{ :type=>'button', :value=>'←', :name=>'prev', :title=>"Previous", :'data-key'=>"p"}
|
23
|
-
%input#next{ :type=>'button', :value=>'→', :name=>'next', :title=>"Next", :'data-key'=>"n"}
|
24
|
-
%input#voldown{ :type=>'button', :value=>'♪', :name=>'voldown', :title=>"Quieter", :'data-key'=>"-"}
|
25
|
-
%input#volup{ :type=>'button', :value=>'♫', :name=>'volup', :title=>"Louder", :'data-key'=>"+"}
|
26
|
-
- if settings.voting
|
27
|
-
%input#vote{ :type=>'button', :value=>'↡', :name=>'vote', :title=>"Vote to Skip", :'data-key' => "s" }
|
28
|
-
|
29
|
-
%script{:src => '/jquery.min.js'}
|
30
|
-
%script{:src => '/script.js'}
|
31
|
-
|