2015-10-16 23:44:35 +01:00
using Newtonsoft.Json ;
using SpotifyAPI.Local.Models ;
using System ;
2014-01-07 15:26:03 +00:00
using System.Collections.Generic ;
2018-01-10 13:56:50 +00:00
using System.Collections.Specialized ;
2014-01-07 15:26:03 +00:00
using System.Net ;
2018-01-10 13:56:50 +00:00
using System.Runtime.CompilerServices ;
2014-02-17 11:58:15 +00:00
using System.Threading.Tasks ;
2018-01-10 13:56:50 +00:00
using System.Web ;
[assembly: InternalsVisibleTo("SpotifyAPI.Tests")]
2014-01-07 15:26:03 +00:00
2015-07-07 17:11:11 +01:00
namespace SpotifyAPI.Local
2014-01-07 15:26:03 +00:00
{
2018-01-10 13:56:50 +00:00
2015-07-07 17:11:11 +01:00
internal class RemoteHandler
2014-01-07 15:26:03 +00:00
{
2016-03-31 11:08:23 +01:00
public string OauthKey { get ; private set ; }
public string CfidKey { get ; private set ; }
2015-01-02 21:57:12 +00:00
2017-09-03 13:44:11 +01:00
private SpotifyLocalAPIConfig _config ;
public RemoteHandler ( SpotifyLocalAPIConfig config )
{
_config = config ;
}
2015-01-02 21:57:12 +00:00
2018-01-15 22:07:50 +00:00
internal bool Init ( )
2014-01-07 15:26:03 +00:00
{
2015-07-07 17:11:11 +01:00
OauthKey = GetOAuthKey ( ) ;
CfidKey = GetCfid ( ) ;
2016-03-31 11:08:23 +01:00
return ! string . IsNullOrEmpty ( CfidKey ) ;
2014-01-07 15:26:03 +00:00
}
2015-01-02 21:57:12 +00:00
2016-09-08 11:38:37 +01:00
internal async Task SendPauseRequest ( )
2014-01-10 07:09:14 +00:00
{
2018-01-15 22:07:50 +00:00
NameValueCollection @params = new NameValueCollection { { "pause" , "true" } } ;
2018-01-10 13:56:50 +00:00
await QueryAsync ( "remote/pause.json" , true , true , - 1 , @params ) . ConfigureAwait ( false ) ;
2014-01-10 07:09:14 +00:00
}
2015-01-02 21:57:12 +00:00
2016-09-08 11:38:37 +01:00
internal async Task SendPlayRequest ( )
2014-01-10 07:09:14 +00:00
{
2018-01-15 22:07:50 +00:00
NameValueCollection @params = new NameValueCollection { { "pause" , "false" } } ;
2018-01-10 13:56:50 +00:00
await QueryAsync ( "remote/pause.json" , true , true , - 1 , @params ) . ConfigureAwait ( false ) ;
2014-01-10 07:09:14 +00:00
}
2015-01-02 21:57:12 +00:00
2016-09-08 11:38:37 +01:00
internal async Task SendPlayRequest ( string url , string context = "" )
2014-02-01 12:52:33 +00:00
{
2018-01-10 13:56:50 +00:00
2015-03-12 18:44:54 +00:00
// TODO: instead of having an empty context, one way to fix the bug with the playback time beyond the length of a song would be to provide a 1-song context, and it would be fixed.
2018-01-15 22:07:50 +00:00
NameValueCollection @params = new NameValueCollection
{
{ "uri" , url } ,
{ "context" , context }
} ;
2018-01-10 13:56:50 +00:00
await QueryAsync ( $"remote/play.json" , true , true , - 1 , @params ) . ConfigureAwait ( false ) ;
2014-02-01 12:52:33 +00:00
}
2015-01-02 21:57:12 +00:00
2016-09-08 11:38:37 +01:00
internal async Task SendQueueRequest ( string url )
2014-08-05 17:56:29 +01:00
{
2018-01-15 22:07:50 +00:00
NameValueCollection @params = new NameValueCollection
{
{ "uri" , url } ,
{ "action" , "queue" }
} ;
2018-01-10 13:56:50 +00:00
await QueryAsync ( "remote/play.json" , true , true , - 1 , @params ) . ConfigureAwait ( false ) ;
2014-08-05 17:56:29 +01:00
}
2015-01-02 21:57:12 +00:00
2015-07-07 17:11:11 +01:00
internal StatusResponse GetNewStatus ( )
2014-01-08 22:22:54 +00:00
{
2016-03-31 11:08:23 +01:00
string response = Query ( "remote/status.json" , true , true , - 1 ) ;
if ( string . IsNullOrEmpty ( response ) )
2014-02-13 13:23:52 +00:00
return null ;
2014-01-08 22:22:54 +00:00
response = response . Replace ( "\\n" , "" ) ;
2015-07-07 17:11:11 +01:00
List < StatusResponse > raw = JsonConvert . DeserializeObject < List < StatusResponse > > ( response ) ;
2014-01-08 22:22:54 +00:00
return raw [ 0 ] ;
}
2015-01-02 21:57:12 +00:00
2016-03-31 11:08:23 +01:00
internal string GetOAuthKey ( )
2014-01-07 15:26:03 +00:00
{
2016-03-31 11:08:23 +01:00
string raw ;
2017-03-09 20:58:48 +00:00
using ( WebClient wc = GetWebClientWithUserAgentHeader ( ) )
2014-01-07 15:26:03 +00:00
{
2014-01-10 07:09:14 +00:00
raw = wc . DownloadString ( "http://open.spotify.com/token" ) ;
2014-01-07 15:26:03 +00:00
}
2016-03-31 11:08:23 +01:00
Dictionary < string , object > dic = JsonConvert . DeserializeObject < Dictionary < string , object > > ( raw ) ;
return dic = = null ? "" : ( string ) dic [ "t" ] ;
2014-01-07 15:26:03 +00:00
}
2015-07-07 17:11:11 +01:00
internal string GetCfid ( )
2014-01-07 15:26:03 +00:00
{
2015-07-07 17:11:11 +01:00
string response = Query ( "simplecsrf/token.json" , false , false , - 1 ) ;
response = response . Replace ( @"\" , "" ) ;
List < Cfid > cfidList = ( List < Cfid > ) JsonConvert . DeserializeObject ( response , typeof ( List < Cfid > ) ) ;
if ( cfidList = = null )
2014-02-17 11:58:15 +00:00
return "" ;
2015-07-07 17:11:11 +01:00
if ( cfidList . Count ! = 1 )
2015-10-16 23:31:01 +01:00
throw new Exception ( "CFID could not be loaded" ) ;
2015-07-07 17:11:11 +01:00
return cfidList [ 0 ] . Error = = null ? cfidList [ 0 ] . Token : "" ;
2014-01-07 15:26:03 +00:00
}
2015-01-02 21:57:12 +00:00
2018-01-10 13:56:50 +00:00
internal string BuildQueryString ( bool oauth , bool cfid , int wait , NameValueCollection @params = null )
2014-01-07 15:26:03 +00:00
{
2018-01-10 13:56:50 +00:00
if ( @params = = null )
2014-01-07 15:26:03 +00:00
{
2018-01-10 13:56:50 +00:00
@params = new NameValueCollection ( ) ;
2014-01-07 15:26:03 +00:00
}
2018-01-15 22:07:50 +00:00
NameValueCollection queryParameter = HttpUtility . ParseQueryString ( string . Empty ) ;
2018-01-10 13:56:50 +00:00
queryParameter . Add ( @params ) ;
queryParameter . Add ( new NameValueCollection ( ) {
{ "ref" , string . Empty } ,
{ "cors" , string . Empty } ,
{ "_" , GetTimestamp ( ) . ToString ( ) }
} ) ;
2014-01-07 15:26:03 +00:00
if ( oauth )
{
2018-01-10 13:56:50 +00:00
queryParameter . Add ( "oauth" , OauthKey ) ;
2014-01-07 15:26:03 +00:00
}
if ( cfid )
{
2018-01-10 13:56:50 +00:00
queryParameter . Add ( "csrf" , CfidKey ) ;
2014-01-07 15:26:03 +00:00
}
if ( wait ! = - 1 )
{
2018-01-10 13:56:50 +00:00
queryParameter . Add ( "returnafter" , wait . ToString ( ) ) ;
queryParameter . Add ( "returnon" , "login%2Clogout%2Cplay%2Cpause%2Cerror%2Cap" ) ;
2014-01-07 15:26:03 +00:00
}
2018-01-10 13:56:50 +00:00
return queryParameter . ToString ( ) ;
}
internal string Query ( string baseUrl , bool oauth , bool cfid , int wait , NameValueCollection @params = null )
{
string parameters = BuildQueryString ( oauth , cfid , wait , @params ) ;
2018-01-15 22:05:58 +00:00
string address = $"{_config.HostUrl}:{_config.Port}/{baseUrl}?{parameters}" ;
2018-01-10 13:56:50 +00:00
string response = string . Empty ;
2014-01-07 15:26:03 +00:00
try
{
2018-01-15 22:07:50 +00:00
using ( ExtendedWebClient wc = new ExtendedWebClient ( ) )
2015-01-02 23:49:39 +00:00
{
2015-07-07 17:11:11 +01:00
if ( SpotifyLocalAPI . IsSpotifyRunning ( ) )
2017-08-29 15:52:34 +01:00
{
2015-07-07 17:11:11 +01:00
response = "[ " + wc . DownloadString ( address ) + " ]" ;
2017-08-29 15:52:34 +01:00
}
2015-01-02 23:49:39 +00:00
}
2014-01-07 15:26:03 +00:00
}
2015-10-16 23:31:01 +01:00
catch
2014-01-07 15:26:03 +00:00
{
2016-03-31 11:08:23 +01:00
return string . Empty ;
2015-01-02 21:57:12 +00:00
}
2015-07-07 17:11:11 +01:00
2015-01-02 21:57:12 +00:00
return response ;
}
2018-01-10 13:56:50 +00:00
internal async Task < string > QueryAsync ( string baseUrl , bool oauth , bool cfid , int wait , NameValueCollection @params = null )
2015-01-02 21:57:12 +00:00
{
2018-01-10 13:56:50 +00:00
string parameters = BuildQueryString ( oauth , cfid , wait , @params ) ;
2018-01-15 22:05:58 +00:00
string address = $"{_config.HostUrl}:{_config.Port}/{baseUrl}?{parameters}" ;
2015-01-02 21:57:12 +00:00
string response = "" ;
try
{
2018-01-15 22:07:50 +00:00
using ( ExtendedWebClient wc = new ExtendedWebClient ( ) )
2015-01-02 23:49:39 +00:00
{
2015-07-07 17:11:11 +01:00
if ( SpotifyLocalAPI . IsSpotifyRunning ( ) )
2016-09-08 11:06:24 +01:00
response = "[ " + await wc . DownloadStringTaskAsync ( new Uri ( address ) ) . ConfigureAwait ( false ) + " ]" ;
2015-01-02 23:49:39 +00:00
}
2015-01-02 21:57:12 +00:00
}
2015-10-16 23:31:01 +01:00
catch
2015-01-02 21:57:12 +00:00
{
2016-03-31 11:08:23 +01:00
return string . Empty ;
2014-01-07 15:26:03 +00:00
}
2015-01-02 21:57:12 +00:00
2014-02-13 13:23:52 +00:00
return response ;
2014-01-07 15:26:03 +00:00
}
2014-02-13 13:23:52 +00:00
internal int GetTimestamp ( )
2014-01-10 07:09:14 +00:00
{
2014-02-01 12:52:33 +00:00
return Convert . ToInt32 ( ( DateTime . UtcNow - new DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 ) ) . TotalSeconds ) ;
2014-01-10 07:09:14 +00:00
}
2017-03-09 20:58:48 +00:00
internal WebClient GetWebClientWithUserAgentHeader ( )
{
2018-03-25 18:39:19 +01:00
WebClient wc = new WebClient
{
Proxy = _config ? . ProxyConfig ? . CreateWebProxy ( )
} ;
2017-03-09 20:58:48 +00:00
wc . Headers . Add ( HttpRequestHeader . UserAgent , "Spotify (1.0.50.41368.gbd68dbef)" ) ;
return wc ;
}
2014-01-07 15:26:03 +00:00
}
2015-10-16 23:44:35 +01:00
}