sonice 2.1.2 → 2.2.0
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.
- checksums.yaml +5 -5
- data/.rubocop.yml +103 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +19 -2
- data/Gemfile +2 -0
- data/Gemfile.lock +43 -23
- data/Rakefile +2 -1
- data/bin/rake +29 -0
- data/bin/sonice +2 -1
- data/config.ru +2 -1
- data/lib/sonice.rb +2 -3
- data/lib/sonice/app.rb +20 -19
- data/lib/sonice/command_line.rb +2 -1
- data/lib/sonice/noplayer.rb +40 -0
- data/lib/sonice/public/script.js +8 -62
- data/lib/sonice/public/stylesheet.css +44 -44
- data/lib/sonice/version.rb +3 -2
- data/lib/sonice/views/index.erb +81 -0
- data/sonice.gemspec +22 -19
- metadata +20 -18
- data/lib/sonice/views/index.haml +0 -31
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c1c7a1deda335995e891d6f54421d20eaa907ba9cae2a9c93355c48a0c8632d4
|
|
4
|
+
data.tar.gz: e3288af2d916f33b6967294dbbc6be4c72f841a9929916a592d43b30543e35e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 310128496854d2a199b5f9d24cf2b4cbcaa559912f298198931dbce6b19f7f4b90a24e51a6178ec03b8e7f5269dfa616e5f8946cc9aa9df6ef8263e9f69ca024
|
|
7
|
+
data.tar.gz: 7356fa01c4b96809bfd9ff5071069cf840895a8e35445969f5ed0e385d90321ba074ce64f3c316f0fec026e7d0d421b8d363acb16daa733addc5098b0958a39b
|
data/.rubocop.yml
CHANGED
|
@@ -1,2 +1,105 @@
|
|
|
1
1
|
Style/StringLiterals:
|
|
2
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
CHANGED
|
@@ -3,14 +3,31 @@ Changelog
|
|
|
3
3
|
|
|
4
4
|
So Nice tries its best to follow Semantic Versioning.
|
|
5
5
|
|
|
6
|
+
## Unreleased
|
|
7
|
+
|
|
8
|
+
## v2.2.0
|
|
9
|
+
|
|
10
|
+
Fixes:
|
|
11
|
+
|
|
12
|
+
- Remove background image since LastFM API doesn’t contain images
|
|
13
|
+
|
|
14
|
+
Dependencies:
|
|
15
|
+
|
|
16
|
+
- Bump anyplayer dependency
|
|
17
|
+
- Remove Haml dependency
|
|
18
|
+
- Bump Sinatra dependency
|
|
19
|
+
- Replace Thin by Webrick
|
|
20
|
+
|
|
6
21
|
## v2.1.2
|
|
7
22
|
|
|
8
|
-
|
|
23
|
+
Dependencies:
|
|
24
|
+
|
|
25
|
+
- Fix Sinatra upgrade (#22)
|
|
9
26
|
- Fix Thin dependency so as not to break with thin versions > 2
|
|
10
27
|
|
|
11
28
|
## v2.1.1
|
|
12
29
|
|
|
13
|
-
|
|
30
|
+
Fixes:
|
|
14
31
|
|
|
15
32
|
- Fix LastFM JavaScript (thanks @datagutt)
|
|
16
33
|
- Fix Thin dependency with Sinatra
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,41 +1,61 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
sonice (2.
|
|
5
|
-
anyplayer (
|
|
6
|
-
haml
|
|
4
|
+
sonice (2.2.0)
|
|
5
|
+
anyplayer (>= 1.2.0)
|
|
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.
|
|
13
|
+
anyplayer (1.2.0)
|
|
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
|
-
|
|
34
|
-
|
|
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.6.1)
|
|
50
|
+
xml-simple (1.1.5)
|
|
35
51
|
|
|
36
52
|
PLATFORMS
|
|
37
53
|
ruby
|
|
38
54
|
|
|
39
55
|
DEPENDENCIES
|
|
40
56
|
rake
|
|
57
|
+
rubocop
|
|
41
58
|
sonice!
|
|
59
|
+
|
|
60
|
+
BUNDLED WITH
|
|
61
|
+
2.1.4
|
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,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Standard library
|
|
4
4
|
require 'open-uri'
|
|
@@ -6,10 +6,9 @@ require 'open-uri'
|
|
|
6
6
|
# Gems
|
|
7
7
|
require 'anyplayer'
|
|
8
8
|
require 'sinatra'
|
|
9
|
-
require 'haml'
|
|
10
9
|
require 'xmlsimple' # xml-simple gem
|
|
11
10
|
require 'json'
|
|
12
|
-
require 'thin'
|
|
13
11
|
|
|
14
12
|
# So Nice
|
|
13
|
+
require 'sonice/noplayer'
|
|
15
14
|
require 'sonice/app'
|
data/lib/sonice/app.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Sonice
|
|
3
4
|
# Sinatra application
|
|
4
5
|
class App < Sinatra::Base
|
|
@@ -9,31 +10,24 @@ module Sonice
|
|
|
9
10
|
|
|
10
11
|
set :logging, true
|
|
11
12
|
set :static, true
|
|
12
|
-
set :public_dir, File.expand_path('
|
|
13
|
-
set :views, File.expand_path('
|
|
14
|
-
set :haml, format: :html5
|
|
13
|
+
set :public_dir, File.expand_path('public', __dir__)
|
|
14
|
+
set :views, File.expand_path('views', __dir__)
|
|
15
15
|
set :protection, except: :frame_options
|
|
16
|
+
set :server, :webrick
|
|
16
17
|
|
|
17
|
-
def
|
|
18
|
-
player
|
|
19
|
-
super
|
|
20
|
-
end
|
|
18
|
+
def player_instance
|
|
19
|
+
return @player if @player&.launched?
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
@player ||= begin
|
|
24
|
-
puts "Looking for a player..."
|
|
25
|
-
player = Anyplayer::Selector.new.player
|
|
26
|
-
abort "Error: no music player launched!" unless player
|
|
27
|
-
puts "Connected to #{player.name}"
|
|
28
|
-
player
|
|
29
|
-
end
|
|
21
|
+
@player = Anyplayer::Selector.new.player || Noplayer.new
|
|
30
22
|
end
|
|
31
23
|
|
|
32
24
|
put '/player' do
|
|
25
|
+
player = player_instance
|
|
26
|
+
|
|
33
27
|
player.vote if settings.voting && params['vote']
|
|
34
28
|
|
|
35
29
|
if settings.controls
|
|
36
|
-
methods = %w
|
|
30
|
+
methods = %w[playpause prev next voldown volup] & params.keys
|
|
37
31
|
methods.each { |method| player.send(method) }
|
|
38
32
|
end
|
|
39
33
|
|
|
@@ -41,14 +35,21 @@ module Sonice
|
|
|
41
35
|
end
|
|
42
36
|
|
|
43
37
|
get '/' do
|
|
38
|
+
player = player_instance
|
|
39
|
+
|
|
44
40
|
@title = player.track
|
|
45
41
|
@artist = player.artist
|
|
46
42
|
@album = player.album
|
|
43
|
+
@connected = player.launched?
|
|
44
|
+
|
|
47
45
|
if request.xhr?
|
|
48
46
|
content_type :json
|
|
49
|
-
{ title: @title,
|
|
47
|
+
{ title: @title,
|
|
48
|
+
artist: @artist,
|
|
49
|
+
album: @album,
|
|
50
|
+
connected: @connected }.to_json
|
|
50
51
|
else
|
|
51
|
-
|
|
52
|
+
erb :index
|
|
52
53
|
end
|
|
53
54
|
end
|
|
54
55
|
end
|
data/lib/sonice/command_line.rb
CHANGED
|
@@ -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
|
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
|
-
if (!artist)
|
|
39
|
-
return callback()
|
|
40
|
-
var cb = function() { callback(cache[artist].random()) },
|
|
41
|
-
cache = artistImage.cache
|
|
42
|
-
artist = encodeURI(artist)
|
|
43
|
-
|
|
44
|
-
// Deliver from cache
|
|
45
|
-
if (cache.hasOwnProperty(artist)) {
|
|
46
|
-
// execute the callback asynchronously to minimize codepaths
|
|
47
|
-
setTimeout(cb, 10)
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Load
|
|
52
|
-
var last_fm_uri = "http://ws.audioscrobbler.com/2.0/?format=json&method=artist.getinfo&artist=%s&api_key=5636ca9fea36d0323a76638385aab1f3"
|
|
53
|
-
$.ajax({
|
|
54
|
-
url: last_fm_uri.replace('%s', artist),
|
|
55
|
-
dataType: 'jsonp',
|
|
56
|
-
success: function(obj) {
|
|
57
|
-
if (obj.artist.image) {
|
|
58
|
-
cache[artist] = $.map(obj.artist.image, function(img) {
|
|
59
|
-
if (img.size == 'mega') {
|
|
60
|
-
return img['#text']
|
|
61
|
-
}
|
|
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,11 +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
|
})
|
|
@@ -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,29 +1,32 @@
|
|
|
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
|
-
|
|
15
|
-
|
|
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"
|
|
16
18
|
|
|
17
19
|
s.require_paths = ["lib"]
|
|
18
|
-
s.files
|
|
19
|
-
s.test_files
|
|
20
|
-
s.executables
|
|
21
|
-
|
|
20
|
+
s.files = `git ls-files`.split("\n")
|
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
22
|
+
s.executables =
|
|
23
|
+
`git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
|
22
24
|
|
|
23
|
-
s.add_runtime_dependency 'anyplayer', '
|
|
25
|
+
s.add_runtime_dependency 'anyplayer', '>= 1.2.0'
|
|
24
26
|
s.add_runtime_dependency 'sinatra'
|
|
25
|
-
s.add_runtime_dependency '
|
|
27
|
+
s.add_runtime_dependency 'webrick'
|
|
26
28
|
s.add_runtime_dependency 'xml-simple'
|
|
27
|
-
|
|
29
|
+
|
|
28
30
|
s.add_development_dependency 'rake'
|
|
31
|
+
s.add_development_dependency 'rubocop'
|
|
29
32
|
end
|
metadata
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sonice
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sunny Ripert
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-10-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: anyplayer
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 1.
|
|
19
|
+
version: 1.2.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 1.
|
|
26
|
+
version: 1.2.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: sinatra
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -39,7 +39,7 @@ dependencies:
|
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: webrick
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - ">="
|
|
@@ -67,21 +67,21 @@ dependencies:
|
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: rake
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
|
-
- - "
|
|
73
|
+
- - ">="
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
76
|
-
type: :
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
|
-
- - "
|
|
80
|
+
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
82
|
+
version: '0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: rubocop
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - ">="
|
|
@@ -99,28 +99,32 @@ description: Small Web interface to control iTunes, Spotify, Rdio, MPD, Rhythmbo
|
|
|
99
99
|
email:
|
|
100
100
|
- sunny@sunfox.org
|
|
101
101
|
executables:
|
|
102
|
+
- rake
|
|
102
103
|
- sonice
|
|
103
104
|
extensions: []
|
|
104
105
|
extra_rdoc_files: []
|
|
105
106
|
files:
|
|
106
107
|
- ".gitignore"
|
|
107
108
|
- ".rubocop.yml"
|
|
109
|
+
- ".ruby-version"
|
|
108
110
|
- CHANGELOG.md
|
|
109
111
|
- Gemfile
|
|
110
112
|
- Gemfile.lock
|
|
111
113
|
- README.md
|
|
112
114
|
- Rakefile
|
|
115
|
+
- bin/rake
|
|
113
116
|
- bin/sonice
|
|
114
117
|
- config.ru
|
|
115
118
|
- lib/sonice.rb
|
|
116
119
|
- lib/sonice/app.rb
|
|
117
120
|
- lib/sonice/command_line.rb
|
|
121
|
+
- lib/sonice/noplayer.rb
|
|
118
122
|
- lib/sonice/public/favicon.ico
|
|
119
123
|
- lib/sonice/public/jquery.min.js
|
|
120
124
|
- lib/sonice/public/script.js
|
|
121
125
|
- lib/sonice/public/stylesheet.css
|
|
122
126
|
- lib/sonice/version.rb
|
|
123
|
-
- lib/sonice/views/index.
|
|
127
|
+
- lib/sonice/views/index.erb
|
|
124
128
|
- sonice.gemspec
|
|
125
129
|
homepage: http://github.com/sunny/so-nice
|
|
126
130
|
licenses:
|
|
@@ -141,10 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
141
145
|
- !ruby/object:Gem::Version
|
|
142
146
|
version: '0'
|
|
143
147
|
requirements: []
|
|
144
|
-
|
|
145
|
-
rubygems_version: 2.2.2
|
|
148
|
+
rubygems_version: 3.1.2
|
|
146
149
|
signing_key:
|
|
147
150
|
specification_version: 4
|
|
148
151
|
summary: Web interface to control your current music player
|
|
149
152
|
test_files: []
|
|
150
|
-
has_rdoc:
|
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
|
-
|