Git Product home page Git Product logo

spotify-connect-scrobbler's Introduction

spotify-connect-scrobbler

This project deprecated since Spotify changed the way their Last.fm integration works. Scrobbling now happens on Spotify's servers, rather than the client, so all Connect devices can now scrobble. This is left here for posterity as it's one of my favourite hacks.

spotify-connect-scrobbler is a Last.fm music logging ("scrobbling") service for Spotify. It uses Spotify Connect to allow you to log music played on any Spotify device, including those which do not have any Last.fm support (such as Amazon Echo).

Usage

To use spotify-connect-scrobbler have your Spotify username & password, your Last.fm username & password, plus a Last.fm API key and API secret to hand.

Clone the repo,have Rust installed (v1.18 minimum required) build with Cargo (cargo build). Then run:

./target/debug/spotify-connect-scrobbler --spotify-username <Spotify username> --spotify-password <Spotify password> --lastfm-username <Last.fm username> --lastfm-password <Last.fm password> --lastfm-api-key <Last.fm API key> --lastfm-api-secret <Last.fm API secret>

The service will sit in the background and log all Spotify tracks played from any Connect enabled client to the given Last.fm account. It is strongly recommended that you turn off Last.fm integration in any Spotify client where it is enabled (Desktop & Mobile apps). Instructions for the opposite here.

Other Options

  • --name <Device name> - Sets the Spotify Connect device name (defaults to 'Scrobbler'), this name is visible in the Spotify Connect device chooser in Spotify clients

Implementation

spotify-connect-scrobbler is built on top (more accurately, is a fork of) of Paul Lietar's librespot project, an open-source Spotify Connect implementation in Rust. It connects to Spotify as a fully-fledged Spotify Connect device. The active Spotify Connect device (the one playing music) broadcasts its status to all other Connect devices on an account, in order to show now-playing track data on other clients. For example, when playing Spotify tracks on an Amazon Echo, the Echo device will broadcast the currently playing track so that it can be shown on the Spotify app on your phone). Thus spotify-connect-scrobbler can see the currently playing track and send that to be logged on your Last.fm account.

License

Released under the MIT license. See LICENSE.

spotify-connect-scrobbler's People

Contributors

alboyer avatar awiouy avatar badaix avatar christianhersevoort avatar dmfutcher avatar egnwd avatar eladnava avatar fabian-z avatar herrernst avatar janderholm avatar jayrod12 avatar joerg-krause avatar jonil avatar jsopenrb avatar lawrencejones avatar marcust avatar michaelherger avatar moses-palmer avatar plietar avatar psych0d0g avatar realtwister avatar respotify avatar romerod avatar s1lvester avatar sashahilton00 avatar serprex avatar shanemeagher avatar simonteixidor avatar torarnv avatar xdjackiexd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

spotify-connect-scrobbler's Issues

Deprecation notice

Add deprecation notice now that Spotify handles scrobbling server-side.

Pipe audio data to /dev/null

This is a minor issue but when I connect my Spotify client to the Scrobbler, i.e. set s-c-s as the audio source, I get the audio data output in my terminal.

I also noticed when building s-c-s, it compiled ogg and vorbis packages. Is these even necessary? Or are they up for removal in the remove-audio-backends branch?

error: Could not compile `libflate`.

Seems like a bug, but I'm not in any way familiar with Rust. I have no idea how to solve this.

   Compiling libflate v0.1.11
error: `pub(restricted)` syntax is experimental (see issue #32409)
   --> /home/d/.cargo/registry/src/github.com-1ecc6299db9ec823/libflate-0.1.11/src/zlib.rs:202:9
    |
202 |     pub(crate) fn read_from<R>(mut reader: R) -> io::Result<Self>
    |         ^^^^^

error: `pub(restricted)` syntax is experimental (see issue #32409)
  --> /home/d/.cargo/registry/src/github.com-1ecc6299db9ec823/libflate-0.1.11/src/gzip.rs:98:5
   |
98 | pub(crate) struct Trailer {
   |     ^^^^^

error: `pub(restricted)` syntax is experimental (see issue #32409)
   --> /home/d/.cargo/registry/src/github.com-1ecc6299db9ec823/libflate-0.1.11/src/gzip.rs:370:9
    |
370 |     pub(crate) fn read_from<R>(mut reader: R) -> io::Result<Self>
    |         ^^^^^

error: `pub(restricted)` syntax is experimental (see issue #32409)
  --> /home/d/.cargo/registry/src/github.com-1ecc6299db9ec823/libflate-0.1.11/src/deflate/mod.rs:29:5
   |
29 | pub(crate) mod symbol;
   |     ^^^^^

error: `pub(restricted)` syntax is experimental (see issue #32409)
  --> /home/d/.cargo/registry/src/github.com-1ecc6299db9ec823/libflate-0.1.11/src/non_blocking/deflate/decode.rs:72:9
   |
72 |     pub(crate) fn bit_reader_mut(&mut self) -> &mut TransactionalBitReader<R> {
   |         ^^^^^

error: `pub(restricted)` syntax is experimental (see issue #32409)
   --> /home/d/.cargo/registry/src/github.com-1ecc6299db9ec823/libflate-0.1.11/src/bit.rs:143:9
    |
143 |     pub(crate) fn state(&self) -> BitReaderState {
    |         ^^^^^

error: `pub(restricted)` syntax is experimental (see issue #32409)
   --> /home/d/.cargo/registry/src/github.com-1ecc6299db9ec823/libflate-0.1.11/src/bit.rs:150:9
    |
150 |     pub(crate) fn restore_state(&mut self, state: BitReaderState) {
    |         ^^^^^

error: `pub(restricted)` syntax is experimental (see issue #32409)
   --> /home/d/.cargo/registry/src/github.com-1ecc6299db9ec823/libflate-0.1.11/src/bit.rs:171:5
    |
171 | pub(crate) struct BitReaderState {
    |     ^^^^^

error: aborting due to 8 previous errors

error: Could not compile `libflate`.
Build failed, waiting for other jobs to finish...
error: build failed

Artist with strange unicode name: thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value

Trying to scrobble a track by an artist with the name "ร“" causes spotify-connect-scrobbler to panic.

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: WireError(InvalidEnumValue(4))', src/libcore/result.rs:906:4
stack backtrace:
   0:        0x110ac5633 - std::sys::imp::backtrace::tracing::imp::unwind_backtrace::h8740ec5f0c4b942c
   1:        0x110ac17b0 - std::sys_common::backtrace::_print::h66778b19a7f789e1
   2:        0x110ac9573 - std::panicking::default_hook::{{closure}}::h5fc5b4a89582e405
   3:        0x110ac9272 - std::panicking::default_hook::h82f0ea57dcfad5fa
   4:        0x110ac9a82 - std::panicking::rust_panic_with_hook::h78c1e2c6542e66a6
   5:        0x110ac9964 - std::panicking::begin_panic::he25b9f01922caf6e
   6:        0x110ac9832 - std::panicking::begin_panic_fmt::h2f0e57c4c4d4d42d
   7:        0x110ac979a - rust_begin_unwind
   8:        0x110b00ad3 - core::panicking::panic_fmt::hb452ab28ce2bd54d
   9:        0x10fb3ac05 - core::result::unwrap_failed::h1ac30ca2315574b4
  10:        0x10fb4afa1 - <core::result::Result<T, E>>::unwrap::h89881f5cb4f2515d
  11:        0x10fb6ff3f - librespot::metadata::MetadataManager::get::{{closure}}::hf91f30d9be79de5e
  12:        0x10fb43a2f - <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll::{{closure}}::{{closure}}::hbb23c5f5b4dd3ded
  13:        0x10fb48ed0 - <core::result::Result<T, E>>::map::hb4d70105336ad59d
  14:        0x10fb416d6 - <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll::{{closure}}::h9660b89799704dbc
  15:        0x10fb613c5 - <futures::future::chain::Chain<A, B, C>>::poll::h1ddb6d8b14bdb4d8
  16:        0x10fab4f43 - <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll::hd20eeeb0b27d985f
  17:        0x10fa62146 - <alloc::boxed::Box<F> as futures::future::Future>::poll::h12d0a32f1420152c
  18:        0x10fc4dbbe - <futures::future::map::Map<A, F> as futures::future::Future>::poll::h4833961d7dbfcd83
  19:        0x10fb620a5 - <futures::future::chain::Chain<A, B, C>>::poll::h3383ed9ce147dcf2
  20:        0x10fab4e53 - <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll::h507e88e2d7c3217f
  21:        0x10fa9523a - <futures::future::map_err::MapErr<A, F> as futures::future::Future>::poll::h83f6dec292e2d877
  22:        0x10fb666ce - <futures::future::chain::Chain<A, B, C>>::poll::h7bf96698a932cb68
  23:        0x10fab4d33 - <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll::h144e9c7edef658db
  24:        0x10fa62196 - <alloc::boxed::Box<F> as futures::future::Future>::poll::h20298f4e26968c35
  25:        0x10fb3692b - <librespot::scrobbler::Scrobbler as futures::future::Future>::poll::h905fa654d2eaa4c9
  26:        0x10fbec8a8 - <librespot::spirc::SpircTask as futures::future::Future>::poll::h4b63ee5d989fa176
  27:        0x10f901362 - <spotify_connect_scrobbler::Main as futures::future::Future>::poll::h3adc116e2820dcbc
  28:        0x10f93785c - <futures::task_impl::Spawn<F>>::poll_future_notify::{{closure}}::h17bde513a0cca7ec
  29:        0x10f9378af - <futures::task_impl::Spawn<T>>::enter::{{closure}}::h165b959405270892
  30:        0x10f938056 - futures::task_impl::std::set::h0a164a3279512f3c
  31:        0x10f925340 - <futures::task_impl::Spawn<T>>::enter::h0597951ae5d6aa6f
  32:        0x10f925174 - <futures::task_impl::Spawn<F>>::poll_future_notify::hbbf438ae2bfa411b
  33:        0x10f90d2dc - tokio_core::reactor::Core::run::{{closure}}::ha5996258d407d59f
  34:        0x10f90d557 - <scoped_tls::ScopedKey<T>>::set::hdc873c6fef81866f
  35:        0x10f9246bb - tokio_core::reactor::Core::run::h3fc1761826d31a30
  36:        0x10f901e99 - spotify_connect_scrobbler::main::hc89200998ccc5ded
  37:        0x110ad684c - __rust_maybe_catch_panic
  38:        0x110ac9f88 - std::rt::lang_start::hafe790440cbd1b77
  39:        0x10f902074 - main

Warning: variable does not need to be mutable

Occurs when compiling

warning: doc comment not used by rustdoc
  --> src/apresolve.rs:10:1
   |
10 | error_chain! { }
   | ^^^^^^^^^^^^^^^^
   |
   = note: #[warn(unused_doc_comment)] on by default
   = note: this error originates in a macro outside of the current crate

warning: doc comment not used by rustdoc
  --> src/apresolve.rs:10:1
   |
10 | error_chain! { }
   | ^^^^^^^^^^^^^^^^
   |
   = note: this error originates in a macro outside of the current crate

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:167:29
    |
167 |                         let mut msg = msg.mut_build_info();
    |                             ^^^^^^^
    |
    = note: #[warn(unused_mut)] on by default

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:178:29
    |
178 |                         let mut msg =
    |                             ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:201:29
    |
201 |                         let mut msg =
    |                             ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:318:25
    |
318 |                     let mut msg = msg.mut_login_credentials();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:325:25
    |
325 |                     let mut msg = msg.mut_system_info();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:448:25
    |
448 |                     let mut msg = repeated.push_default();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:454:25
    |
454 |                     let mut msg = repeated.push_default();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:460:25
    |
460 |                     let mut msg = repeated.push_default();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:466:25
    |
466 |                     let mut msg = repeated.push_default();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:472:25
    |
472 |                     let mut msg = repeated.push_default();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:478:25
    |
478 |                     let mut msg = repeated.push_default();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:484:25
    |
484 |                     let mut msg = repeated.push_default();
    |                         ^^^^^^^

warning: variable does not need to be mutable
   --> /tmp/spotify-connect-scrobbler/target/debug/build/spotify-connect-scrobbler-93e09b0021019303/out/lib.rs:500:25
    |
500 |                     let mut msg = repeated.push_default();
    |                         ^^^^^^^

Publishable to Crates.io

We want to start publishing spotify-connect-scrobbler to Crates.io. Currently, this crate is not publishable due to some unpublished dependencies. I'm working with their author to have them published. Tracking list:

  • rust-protobuf-macros
  • librespot-core
  • librespot-metadata
  • librespot-protocol

Repeat tracks do not Scrobble

Playing the same track many times in a row only registers as a single scrobble. The new track detection works only by Spotify ID. There may be more useful information in the SPIRC frame to detect this better.

Merge latest librespot

plietar/librespot's development has been wound up by the primary developer. The eventual plan for spotify-connect-scrobbler was to cease building directly on top of the librespot codebase and use it as a library, but the conversion to a library with a well documented public API won't happen now.

s-c-s should merge the latest librespot upstream and plan for stalled librespot development.

Include Album name in Scrobble

When tracks are scrobbled, only the track name and artist name are sent. This updates Last.fm but it does not appear to increase the album play count (ie. currently see 19 scrobbles with Zola Jesus sent by spotify-connect-scrobbler, from the same album, but the album does not appear in the played albums panel).

Cannot Gain Last FM Authentication

Hello,

Spotify seems fine but I am unable to authenticate with Last FM

Following the readme instructions leaves the following messages:

INFO:librespot_core::session: Connecting to AP "gew1-accesspoint-b-5z6g.ap.spotify.com:4070"
INFO:librespot_core::session: Authenticated as "myusername" !
ERROR:librespot::scrobbler: Authentication error: ScrobblerError { err_msg: "Authentication failed: Non Success status (403 Forbidden)" }
ERROR:librespot::spirc: Scrobbler error: ()
thread 'main' panicked at 'cannot poll Result twice', src/libcore/option.rs:839:4
note: Run with RUST_BACKTRACE=1 for a backtrace.

Investigate credential caching

librespot-core provides some sort of credential caching system. Work out if it can be extended to cache all s-c-s credentials.

Tracks can fail to scrobble

Tracks fail to scrobble when scrobbler future isn't during playback. Support for scrobbling on end-of-track must be added.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.