mpris_scrobbler 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2b86ec7868b89617a259868a94721b511963521e
4
+ data.tar.gz: c6f0cfe820851c6f816d18acf9c6f3d8a1e1a84d
5
+ SHA512:
6
+ metadata.gz: 21ad45f00ef98e20cde5703d4cb8a730a56a5ea6d44a6312bf54faf61685423eed125da802cfbfb8681ccd153441bfeea6cfd6f81ddbdff939bff9cc93055afe
7
+ data.tar.gz: 3c6f5bccba90ab5688e299dc9d20d31260d5a912f31f8c42ad208d2357a091e1a7d95956cf51efeff8ee9693629e2457b3296dceed6e871bedeb25636d85a9ed
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mpris_scrobbler.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Bruno Antunes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ # MPRIS Scrobbler
2
+
3
+ I sometimes listen to music using Audacious (I'm a sucker for classic Winamp skins), and I've noticed the Last.fm plugin doesn't work for me on Fedora 23. But I also noticed that it supports [MPRIS], and I've always wanted to play with D-Bus.
4
+
5
+ So this project scrobbles your tracks to Last.fm as long as Audacious is running concurrently, and its `MPRIS 2 Server` plugin is enabled. It's a quick and dirty hack, but I might come back to it in the future.
6
+
7
+ [MPRIS]: https://specifications.freedesktop.org/mpris-spec/latest/
8
+
9
+ ## Installation
10
+
11
+ ```ruby
12
+ gem install mpris_scrobbler
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ It's a long running binary - feel free to use whatever daemon wrapper for it.
18
+ The first time you run it, it creates a `config.yml` file in your home folder. In it, you have to fill in your Last.fm app API key and secret (create a new app [here], no need for a callback URL). You also need to fill in your Last.fm username, in order to fetch your last scrobbled track and determine if it needs updating. Do not fill in the `session_key` key.
19
+
20
+ After you fill in the API keys in the config file, you need to run the binary one more time to generate a session key. After this, subsequent runs have no output.
21
+
22
+ You can try to change the `player` key to support other MPRIS 2 compliant players, but I haven't tried this. Submit an issue, and I'll have a look if it doesn't work for your player - but it should, in theory!
23
+
24
+ [here]: http://www.last.fm/api/account/create
25
+
26
+ ## Contributing
27
+
28
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sardaukar/mpris_scrobbler.
29
+
30
+
31
+ ## License
32
+
33
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
34
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mpris_scrobbler"
5
+
6
+ MprisScrobbler::Spy.new.run
@@ -0,0 +1,5 @@
1
+ module MprisScrobbler
2
+ VERSION = "1.0.0"
3
+ end
4
+
5
+ require "mpris_scrobbler/spy"
@@ -0,0 +1,187 @@
1
+ module MprisScrobbler
2
+ require 'dbus'
3
+ require 'rockstar'
4
+ require 'yaml'
5
+ class Spy
6
+
7
+ CONFIG_DIR = "~/.config/mpris_scrobbler"
8
+ CONFIG_FILE = "config.yml"
9
+
10
+ def initialize
11
+ @config =
12
+ if File.exists?(config_file_path)
13
+ load_config
14
+ else
15
+ gen_config
16
+ puts "Config example saved to #{File.join(CONFIG_DIR, CONFIG_FILE)}"
17
+ puts "Refer to the README file for next steps."
18
+ exit(0)
19
+ end
20
+
21
+ init_rockstar
22
+ ask_auth unless session_key
23
+
24
+ @interface = get_dbus_interface
25
+ @queue = []
26
+ end
27
+
28
+ def run
29
+ user = Rockstar::User.new(lastfm_config["username"])
30
+ last_track = user.recent_tracks.first.name rescue nil
31
+
32
+ loop do
33
+ current_track, artist, album, length = get_dbus_metadata
34
+
35
+ if current_track != last_track
36
+ @queue << {
37
+ track: current_track,
38
+ artist: artist.first,
39
+ album: album,
40
+ length: length,
41
+ scrobbled: false
42
+ }
43
+
44
+ if queue.size == 1
45
+ update_now_playing
46
+ else
47
+ scrobble_previous_track
48
+ update_now_playing
49
+ end
50
+
51
+ last_track = current_track
52
+ end
53
+
54
+ trim_queue if queue.size > 5
55
+
56
+ sleep sleep_period
57
+ end
58
+ end
59
+
60
+ private
61
+ attr_reader :interface, :config, :queue
62
+
63
+ def trim_queue
64
+ @queue = @queue[-3..-1]
65
+ end
66
+
67
+ def scrobble_previous_track
68
+ track_info = queue[-2]
69
+ return if track_info[:scrobbled]
70
+
71
+ Rockstar::Track.scrobble(
72
+ session_key: session_key,
73
+ track: track_info[:track],
74
+ artist: track_info[:artist],
75
+ album: track_info[:album],
76
+ time: Time.now - (track_info[:length] / 1_000_000),
77
+ length: track_info[:length]
78
+ )
79
+
80
+ @queue[-2][:scrobbled] = true
81
+ end
82
+
83
+ def update_now_playing
84
+ track_info = queue.last
85
+
86
+ Rockstar::Track.updateNowPlaying(
87
+ session_key: session_key,
88
+ track: track_info[:track],
89
+ artist: track_info[:artist],
90
+ album: track_info[:album],
91
+ time: Time.now,
92
+ length: track_info[:length]
93
+ )
94
+ end
95
+
96
+ def get_dbus_metadata
97
+ interface["Metadata"].values_at(
98
+ "xesam:title",
99
+ "xesam:artist",
100
+ "xesam:album",
101
+ "mpris:length"
102
+ )
103
+ end
104
+
105
+ def config_file_path
106
+ File.expand_path(File.join(CONFIG_DIR, CONFIG_FILE))
107
+ end
108
+
109
+ def ask_auth
110
+ auth = Rockstar::Auth.new
111
+ token = auth.token
112
+
113
+ puts
114
+ puts "Please open http://www.last.fm/api/auth/?api_key=#{Rockstar.lastfm_api_key}&token=#{token}"
115
+ puts
116
+ puts "Press enter when done."
117
+
118
+ gets
119
+
120
+ session = auth.session(token)
121
+
122
+ save_session(session)
123
+ end
124
+
125
+ def save_session(session)
126
+ @config["lastfm"]["session_key"] = session.key
127
+
128
+ File.open(config_file_path,"w") { |f| f.write @config.to_yaml }
129
+ end
130
+
131
+ def session_key
132
+ lastfm_config["session_key"]
133
+ end
134
+
135
+ def sleep_period
136
+ mpris_config["poll_every_seconds"]
137
+ end
138
+
139
+ def lastfm_config
140
+ config["lastfm"]
141
+ end
142
+
143
+ def mpris_config
144
+ config["mpris"]
145
+ end
146
+
147
+ def init_rockstar
148
+ Rockstar.lastfm = {
149
+ api_key: lastfm_config["api_key"],
150
+ api_secret: lastfm_config["api_secret"]
151
+ }
152
+ end
153
+
154
+ def gen_config
155
+ require 'fileutils'
156
+ FileUtils.mkdir_p File.expand_path(CONFIG_DIR)
157
+
158
+ template = {
159
+ lastfm: {
160
+ username: "XXX",
161
+ api_key: "XXX",
162
+ api_secret: "XXX",
163
+ session_key: nil
164
+ },
165
+ mpris: {
166
+ player: "audacious",
167
+ poll_every_seconds: 10
168
+ }
169
+ }
170
+
171
+ File.open(config_file_path,"w") { |f| f.write template.to_yaml }
172
+ end
173
+
174
+ def load_config
175
+ YAML.load_file(config_file_path)
176
+ end
177
+
178
+ def get_dbus_interface
179
+ bus = DBus::SessionBus.instance
180
+ service = bus.service("org.mpris.MediaPlayer2.#{mpris_config["player"]}")
181
+ player = service.object("/org/mpris/MediaPlayer2")
182
+
183
+ player.introspect
184
+ player["org.mpris.MediaPlayer2.Player"]
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mpris_scrobbler'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mpris_scrobbler"
8
+ spec.version = MprisScrobbler::VERSION
9
+ spec.authors = ["Bruno Antunes"]
10
+ spec.email = ["sardaukar.siet@gmail.com"]
11
+
12
+ spec.summary = %q{Last.fm scrobbler for Linux music players that follow the MPRIS 2 specification}
13
+ spec.description = ""
14
+ spec.homepage = "https://github.com/sardaukar/mpris_scrobbler"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "bin"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "rockstar"
23
+ spec.add_dependency "ruby-dbus"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.11"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "pry"
29
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mpris_scrobbler
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Bruno Antunes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rockstar
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby-dbus
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.11'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.11'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: ''
98
+ email:
99
+ - sardaukar.siet@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - bin/mpris_scrobbler
111
+ - lib/mpris_scrobbler.rb
112
+ - lib/mpris_scrobbler/spy.rb
113
+ - mpris_scrobbler.gemspec
114
+ homepage: https://github.com/sardaukar/mpris_scrobbler
115
+ licenses:
116
+ - MIT
117
+ metadata: {}
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ requirements: []
133
+ rubyforge_project:
134
+ rubygems_version: 2.4.8
135
+ signing_key:
136
+ specification_version: 4
137
+ summary: Last.fm scrobbler for Linux music players that follow the MPRIS 2 specification
138
+ test_files: []