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