MMM-SpotifyControl . Control your Spotify music player using Mk2 assistant.


  • Project Sponsor Module Developer

    @F17MC @Cr4z33
    I don’t think the issue is with the module but with what the assistant return to the module .

    the module is expecting something like “”(open.spotify.com - https://open.spotify.com/artist/2Gkz5N7rWiCE3jlCgsw1yp""

    So i’m not getting why your assistant doesn’t understand what to search for.

    I’ll continue digging

    Ejay



  • @ejay-ibm OK thanks I might ask also @Sean tomorrow to see if he knows anything we don’t. 😃


  • Project Sponsor Module Developer

    @Cr4z33 I’m already working on it with @Sean 😉

    quick question : if you just say “micheal jackson smooth criminal”
    does it start playing youtube ?
    if yes then just try “micheal jackson smooth criminal spotify”
    and let me know

    If that doesn’t work I’ll ask you some patience so I can implement the spotify search function directly in my module and not from the assistant. We will just use a hook in the assisant .

    Ejay



  • @ejay-ibm yes, with YouTube it works. But with Spotify no. I try with “artist + song Spotify”, “artist + song on Spotify” etc. Always run the video in YouTube.


  • Project Sponsor Module Developer

    @F17MC That is interesting … that mean the result of the assistant research never bring a spotify url but a youtube one . a openspotify url is what the module expect to work .

    So we know now that under some circumpstance the module doesn’t get the right payload from assistant to work.
    Thanks for testing and reporting this guys .

    I’ll work with sean to implement a search function directly with the spotify APIs call . With that we will make the search directly on spotify ( and not on google ) so we will bypass this issue .

    I’m wondering where the difference is between you and I, because it work fine here and as well another German guy Mantha who is the original code creator .

    Anyway, there’s no problem … only solution .

    I’ll keep you informed once the module is updated .

    Ejay .



  • @ejay-ibm
    I tried again and I receive this:

    [AMK2] end-of-utterance
    [AMK2] Transcription: los planetas Spotify  --- Done: true
    [AMK2] openSpotify found: https://open.spotify.com/artist/0N1TIXCk9Q9JbEPXQDclEL
    { requestId: '5c8b16da-0000-2878-a45c-...' } { profileFile: 'default.json', lang: 'es-ES' }
    [AMK2] Device Action: { requestId: '5c8b16da-0000-2878-a45c-...' }
    [AMK2] Assistant Text Response: 
    [HOTWORD] begins listening.
    Refreshed access token because it has expired. Expired at: 11:26:53 now is: 11:27:56
    Error while refreshing:
    { StatusCodeError: 404 - {"error":{"status":404,"message":"Device not found"}}
        at new StatusCodeError (/home/pi/MagicMirror/modules/MMM-SpotifyControl/node_modules/request-promise-core/lib/errors.js:32:15)
        at Request.plumbing.callback (/home/pi/MagicMirror/modules/MMM-SpotifyControl/node_modules/request-promise-core/lib/plumbing.js:104:33)
        at Request.RP$callback [as _callback] (/home/pi/MagicMirror/modules/MMM-SpotifyControl/node_modules/request-promise-core/lib/plumbing.js:46:31)
        at Request.self.callback (/home/pi/MagicMirror/modules/MMM-SpotifyControl/node_modules/request/request.js:185:22)
        at emitTwo (events.js:126:13)
        at Request.emit (events.js:214:7)
        at Request. (/home/pi/MagicMirror/modules/MMM-SpotifyControl/node_modules/request/request.js:1161:10)
        at emitOne (events.js:116:13)
        at Request.emit (events.js:211:7)
        at IncomingMessage. (/home/pi/MagicMirror/modules/MMM-SpotifyControl/node_modules/request/request.js:1083:12)
      name: 'StatusCodeError',
      statusCode: 404,
      message: '404 - {"error":{"status":404,"message":"Device not found"}}',
      error: { error: { status: 404, message: 'Device not found' } },
      options: 
       { url: 'https://api.spotify.com/v1/me/player/play',
         body: 
          { context_uri: 'spotify:artist:0N1TIXCk9Q9JbEPXQDclEL',
            position_ms: 0 },
         qs: { device_id: 'a8caee9b12196a964f5a...' },
         headers: 
          { Authorization: 'Bearer BQDuIGXWvxdIB5T...' },
         json: true,
         method: 'PUT',
         callback: [Function: RP$callback],
         transform: undefined,
         simple: true,
         resolveWithFullResponse: false,
         transform2xxOnly: false },
      response: 
       IncomingMessage {
         _readableState: 
          ReadableState {
            objectMode: false,
            highWaterMark: 16384,
            buffer: [Object],
            length: 0,
            pipes: null,
            pipesCount: 0,
            flowing: true,
            ended: true,
            endEmitted: true,
            reading: false,
            sync: true,
            needReadable: false,
            emittedReadable: false,
            readableListening: false,
            resumeScheduled: false,
            destroyed: false,
            defaultEncoding: 'utf8',
            awaitDrain: 0,
            readingMore: false,
            decoder: null,
            encoding: null },
         readable: false,
         domain: null,
         _events: 
          { end: [Array],
            close: [Array],
            data: [Function],
            error: [Function] },
         _eventsCount: 4,
         _maxListeners: undefined,
         socket: 
          TLSSocket {
            _tlsOptions: [Object],
            _secureEstablished: true,
            _securePending: false,
            _newSessionPending: false,
            _controlReleased: true,
            _SNICallback: null,
            servername: null,
            npnProtocol: false,
            alpnProtocol: false,
            authorized: true,
            authorizationError: null,
            encrypted: true,
            _events: [Object],
            _eventsCount: 9,
            connecting: false,
            _hadError: false,
            _handle: null,
            _parent: null,
            _host: 'api.spotify.com',
            _readableState: [Object],
            readable: false,
            domain: null,
            _maxListeners: undefined,
            _writableState: [Object],
            writable: false,
            allowHalfOpen: false,
            _bytesDispatched: 479,
            _sockname: null,
            _pendingData: null,
            _pendingEncoding: '',
            server: undefined,
            _server: null,
            ssl: null,
            _requestCert: true,
            _rejectUnauthorized: true,
            parser: null,
            _httpMessage: [Object],
            read: [Function],
            _consuming: true,
            _idleNext: null,
            _idlePrev: null,
            _idleTimeout: -1,
            [Symbol(asyncId)]: 7397,
            [Symbol(bytesRead)]: 555 },
         connection: 
          TLSSocket {
            _tlsOptions: [Object],
            _secureEstablished: true,
            _securePending: false,
            _newSessionPending: false,
            _controlReleased: true,
            _SNICallback: null,
            servername: null,
            npnProtocol: false,
            alpnProtocol: false,
            authorized: true,
            authorizationError: null,
            encrypted: true,
            _events: [Object],
            _eventsCount: 9,
            connecting: false,
            _hadError: false,
            _handle: null,
            _parent: null,
            _host: 'api.spotify.com',
            _readableState: [Object],
            readable: false,
            domain: null,
            _maxListeners: undefined,
            _writableState: [Object],
            writable: false,
            allowHalfOpen: false,
            _bytesDispatched: 479,
            _sockname: null,
            _pendingData: null,
            _pendingEncoding: '',
            server: undefined,
            _server: null,
            ssl: null,
            _requestCert: true,
            _rejectUnauthorized: true,
            parser: null,
            _httpMessage: [Object],
            read: [Function],
            _consuming: true,
            _idleNext: null,
            _idlePrev: null,
            _idleTimeout: -1,
            [Symbol(asyncId)]: 7397,
            [Symbol(bytesRead)]: 555 },
         httpVersionMajor: 1,
         httpVersionMinor: 1,
         httpVersion: '1.1',
         complete: true,
         headers: 
          { 'content-type': 'application/json; charset=utf-8',
            'cache-control': 'private, max-age=0',
            'access-control-allow-origin': '*',
            'access-control-allow-headers': 'Accept, Authorization, Origin, Content-Type, Retry-After',
            'access-control-allow-methods': 'GET, POST, OPTIONS, PUT, DELETE, PATCH',
            'access-control-allow-credentials': 'true',
            'access-control-max-age': '604800',
            'content-length': '76',
            date: 'Fri, 15 Mar 2019 10:27:56 GMT',
            via: '1.1 google',
            'alt-svc': 'clear',
            connection: 'close' },
         rawHeaders: 
          [ 'Content-Type',
            'application/json; charset=utf-8',
            'Cache-Control',
            'private, max-age=0',
            'Access-Control-Allow-Origin',
            '*',
            'Access-Control-Allow-Headers',
            'Accept, Authorization, Origin, Content-Type, Retry-After',
            'Access-Control-Allow-Methods',
            'GET, POST, OPTIONS, PUT, DELETE, PATCH',
            'Access-Control-Allow-Credentials',
            'true',
            'Access-Control-Max-Age',
            '604800',
            'Content-Length',
            '76',
            'Date',
            'Fri, 15 Mar 2019 10:27:56 GMT',
            'Via',
            '1.1 google',
            'Alt-Svc',
            'clear',
            'Connection',
            'close' ],
         trailers: {},
         rawTrailers: [],
         upgrade: false,
         url: '',
         method: null,
         statusCode: 404,
         statusMessage: 'Not Found',
         client: 
          TLSSocket {
            _tlsOptions: [Object],
            _secureEstablished: true,
            _securePending: false,
            _newSessionPending: false,
            _controlReleased: true,
            _SNICallback: null,
            servername: null,
            npnProtocol: false,
            alpnProtocol: false,
            authorized: true,
            authorizationError: null,
            encrypted: true,
            _events: [Object],
            _eventsCount: 9,
            connecting: false,
            _hadError: false,
            _handle: null,
            _parent: null,
            _host: 'api.spotify.com',
            _readableState: [Object],
            readable: false,
            domain: null,
            _maxListeners: undefined,
            _writableState: [Object],
            writable: false,
            allowHalfOpen: false,
            _bytesDispatched: 479,
            _sockname: null,
            _pendingData: null,
            _pendingEncoding: '',
            server: undefined,
            _server: null,
            ssl: null,
            _requestCert: true,
            _rejectUnauthorized: true,
            parser: null,
            _httpMessage: [Object],
            read: [Function],
            _consuming: true,
            _idleNext: null,
            _idlePrev: null,
            _idleTimeout: -1,
            [Symbol(asyncId)]: 7397,
            [Symbol(bytesRead)]: 555 },
         _consuming: true,
         _dumped: false,
         req: 
          ClientRequest {
            domain: null,
            _events: [Object],
            _eventsCount: 5,
            _maxListeners: undefined,
            output: [],
            outputEncodings: [],
            outputCallbacks: [],
            outputSize: 0,
            writable: true,
            _last: true,
            upgrading: false,
            chunkedEncoding: false,
            shouldKeepAlive: false,
            useChunkedEncodingByDefault: true,
            sendDate: false,
            _removedConnection: false,
            _removedContLen: false,
            _removedTE: false,
            _contentLength: null,
            _hasBody: true,
            _trailer: '',
            finished: true,
            _headerSent: true,
            socket: [Object],
            connection: [Object],
            _header: 'PUT /v1/me/player/play?device_id=a8caee9b1219... HTTP/1.1\r\nAuthorization: Bearer BQDuIGXWvxdIB5TBbyg...\r\nhost: api.spotify.com\r\naccept: application/json\r\ncontent-type: application/json\r\ncontent-length: 71\r\nConnection: close\r\n\r\n',
            _onPendingData: [Function: noopPendingOutput],
            agent: [Object],
            socketPath: undefined,
            timeout: undefined,
            method: 'PUT',
            path: '/v1/me/player/play?device_id=a8caee9b12196...',
            _ended: true,
            res: [Circular],
            aborted: undefined,
            timeoutCb: null,
            upgradeOrConnect: false,
            parser: null,
            maxHeadersCount: null,
            [Symbol(outHeadersKey)]: [Object] },
         request: 
          Request {
            domain: null,
            _events: [Object],
            _eventsCount: 5,
            _maxListeners: undefined,
            body: '{"context_uri":"spotify:artist:0N1TIXCk9Q9JbEPXQDclEL","position_ms":0}',
            headers: [Object],
            method: 'PUT',
            readable: true,
            writable: true,
            explicitMethod: true,
            _qs: [Object],
            _auth: [Object],
            _oauth: [Object],
            _multipart: [Object],
            _redirect: [Object],
            _tunnel: [Object],
            _rp_resolve: [Function],
            _rp_reject: [Function],
            _rp_promise: [Object],
            _rp_callbackOrig: undefined,
            callback: [Function],
            _rp_options: [Object],
            setHeader: [Function],
            hasHeader: [Function],
            getHeader: [Function],
            removeHeader: [Function],
            localAddress: undefined,
            pool: {},
            dests: [],
            __isRequestRequest: true,
            _callback: [Function: RP$callback],
            uri: [Object],
            proxy: null,
            tunnel: true,
            setHost: true,
            originalCookieHeader: undefined,
            _disableCookies: true,
            _jar: undefined,
            port: 443,
            host: 'api.spotify.com',
            url: [Object],
            path: '/v1/me/player/play?device_id=a8caee9b12196...',
            _json: true,
            httpModule: [Object],
            agentClass: [Object],
            agent: [Object],
            _started: true,
            href: 'https://api.spotify.com/v1/me/player/play?device_id=a8caee9b12196a96...',
            req: [Object],
            ntick: true,
            response: [Circular],
            originalHost: 'api.spotify.com',
            originalHostHeaderName: 'host',
            responseContent: [Circular],
            _destdata: true,
            _ended: true,
            _callbackCalled: true },
         toJSON: [Function: responseToJSON],
         caseless: Caseless { dict: [Object] },
         read: [Function],
         body: { error: [Object] } } }
    
    
    

    The result is perfect.
    But I get error 404, Device not found. I try while I listen to music on my laptop and my magic mirror with raspotify, and I get the same error.
    I have edit my deviceID and my Authorization in the code for privacy.

    EDIT:

    I think I know what is the problem.
    I have tried with two devices, and it don’t work. But when I try it with the device which is the deviceID that I wrote in the module code, it works.

    If I don’t say a command before, I get error 404.

    Working:

    [AMK2] end-of-utterance
    [AMK2] Transcription: para la música  --- Done: true
    { requestId: '5c883e4a-0000-24fa-b7be-...' } { profileFile: 'default.json', lang: 'es-ES' }
    [AMK2] Device Action: { requestId: '5c883e4a-0000-24fa-b7be-...' }
    [AMK2] Assistant Text Response: 
    [AMK2] Conversation Completed
    [HOTWORD] begins listening.
    Refreshed access token because it has expired. Expired at: 11:45:40 now is: 11:48:02
    [HOTWORD] <<  espejito  >> is detected. //My hotword
    [HOTWORD] stops listening
    [AMK2] assistant ready
    [AMK2] Conversation starts.
    [AMK2] Assistant Text Response: 
    [AMK2] end-of-utterance
    [AMK2] Transcription: Rafa Pons en Spotify  --- Done: true
    [AMK2] openSpotify found: https://open.spotify.com/artist/0DnmOp2SUaeavTi6a32pGY
    { requestId: '5c884094-0000-27db-94c8-...' } { profileFile: 'default.json', lang: 'es-ES' }
    [AMK2] Device Action: { requestId: '5c884094-0000-27db-94c8-...' }
    [AMK2] Assistant Text Response: 
    play on: a8caee9b12196a964f5a9b0fafaf7ef1
    [HOTWORD] begins listening.
    
    

  • Project Sponsor Module Developer

    @F17MC
    So in your config.js you have set your device id to ; a8caee9b12196a964f5a9b0fafaf7ef1

    at this step
    Error while refreshing:
    { StatusCodeError: 404 - {“error”:{“status”:404,“message”:“Device not found”}}

    currentDeviceID variable is passed by case ‘PLAY_SPOTIFY’:
    payload[“deviceId”] = this.config.deviceId;

    "If I don’t say a command before, I get error 404. " what do you mean ? could you clarify ?

    “But when I try it with the device which is the deviceID that I wrote in the module code, it works.”
    Yes that is expected .

    For now you can only start playing on the device ID given in the config file as mentioned in the readme :

    This Module allow to control Spotify player on your Mirror . For now you can only control a single device. It could be your mirror if you are running Raspotify on it. Request to play a song it will be played on your select device in the config.js file. other command doesn’t need a device to be set. So if you are already playing a song on another device, the modules allow you to control this device from your module. But if you request a new song or playlist the set device in config file will play it on it you can not start a new song on a different device from now .

    Does that clarify the point ?

    Ejay



  • @ejay-ibm said in MMM-SpotifyControl . Control your Spotify music player using Mk2 assistant.:

    @F17MC
    So in your config.js you have set your device id to ; a8caee9b12196a964f5a9b0fafaf7ef1

    at this step
    Error while refreshing:
    { StatusCodeError: 404 - {“error”:{“status”:404,“message”:“Device not found”}}

    currentDeviceID variable is passed by case ‘PLAY_SPOTIFY’:
    payload[“deviceId”] = this.config.deviceId;

    "If I don’t say a command before, I get error 404. " what do you mean ? could you clarify ?

    “But when I try it with the device which is the deviceID that I wrote in the module code, it works.”
    Yes that is expected .

    For now you can only start playing on the device ID given in the config file as mentioned in the readme :

    This Module allow to control Spotify player on your Mirror . For now you can only control a single device. It could be your mirror if you are running Raspotify on it. Request to play a song it will be played on your select device in the config.js file. other command doesn’t need a device to be set. So if you are already playing a song on another device, the modules allow you to control this device from your module. But if you request a new song or playlist the set device in config file will play it on it you can not start a new song on a different device from now .

    Does that clarify the point ?

    Ejay

    If I don’t say a command before, I get error 404. " what do you mean ? could you clarify ?
    I wanted to erase this sentence but I could not edit my post. It should not be there.

    Yes, the module is working perfect now!
    Thanks.


  • Project Sponsor Module Developer

    Fantastic news !
    So just for other user.
    Could you clarify what you did wrong earlier ? and what you changed to make it work ?
    Any special sentence to call the module ? any change in config file ?

    thank you



  • @ejay-ibm
    I really want the module to control only one device. I configured that device in the configuration file, but then used the magicmirror as an output device. Then that was the error.
    I started disabling youtube and its automatic playback of mmm-assistantmk2, but then I turned it back on.

    A doubt. As I really only want to control a device with your module, I could do that if, for example, I’m listening to spotify on my computer, but I say to magicmirror: “start music on spotify” make the change directly to the deviceID that I have in the config file and start the music?