mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-15 10:33:59 +02:00
Move to new es6 based standalone resolvers
This commit is contained in:
@@ -39,21 +39,6 @@ if ((typeof Tomahawk === "undefined") || (Tomahawk === null)) {
|
||||
|
||||
Tomahawk.apiVersion = "0.2.2";
|
||||
|
||||
//Statuses considered a success for HTTP request
|
||||
var httpSuccessStatuses = [200, 201];
|
||||
|
||||
// install RSVP error handler for uncaught(!) errors
|
||||
RSVP.on('error', function (reason) {
|
||||
var resolverName = "";
|
||||
if (Tomahawk.resolver.instance) {
|
||||
resolverName = Tomahawk.resolver.instance.settings.name + " - ";
|
||||
}
|
||||
if (reason) {
|
||||
console.error(resolverName + 'Uncaught error:' + JSON.stringify(reason));
|
||||
} else {
|
||||
console.error(resolverName + 'Uncaught error: error thrown from RSVP but it was empty');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Compares versions strings
|
||||
@@ -158,14 +143,6 @@ Tomahawk.extend = function (object, members) {
|
||||
return newObject;
|
||||
};
|
||||
|
||||
//Deprecated for 0.9 resolvers. Reporting resolver capabilities is no longer necessary.
|
||||
var TomahawkResolverCapability = {
|
||||
NullCapability: 0,
|
||||
Browsable: 1,
|
||||
PlaylistSync: 2,
|
||||
AccountFactory: 4,
|
||||
UrlLookup: 8
|
||||
};
|
||||
|
||||
//Deprecated for 0.9 resolvers. Use Tomahawk.UrlType instead.
|
||||
var TomahawkUrlType = {
|
||||
@@ -249,106 +226,6 @@ var TomahawkResolver = {
|
||||
}
|
||||
};
|
||||
|
||||
Tomahawk.Resolver = {
|
||||
init: function () {
|
||||
},
|
||||
scriptPath: function () {
|
||||
return Tomahawk.resolverData().scriptPath;
|
||||
},
|
||||
getConfigUi: function () {
|
||||
return {};
|
||||
},
|
||||
getUserConfig: function () {
|
||||
return JSON.parse(window.localStorage[this.scriptPath()] || "{}");
|
||||
},
|
||||
saveUserConfig: function () {
|
||||
window.localStorage[this.scriptPath()] = JSON.stringify(Tomahawk.resolverData().config);
|
||||
this.newConfigSaved(Tomahawk.resolverData().config);
|
||||
},
|
||||
newConfigSaved: function () {
|
||||
},
|
||||
getStreamUrl: function (params) {
|
||||
return params;
|
||||
},
|
||||
|
||||
_convertUrls: function (results) {
|
||||
var that = this;
|
||||
return results.map(function (r) {
|
||||
if (r && r.url) {
|
||||
r.url = that._urlProtocol + '://' + r.url;
|
||||
}
|
||||
return r;
|
||||
});
|
||||
},
|
||||
|
||||
_adapter_resolve: function (qid, artist, album, title) {
|
||||
var that = this;
|
||||
var collectionPromises = [];
|
||||
Tomahawk.collections.forEach(function (col) {
|
||||
if (col.resolve) {
|
||||
collectionPromises.push(col.resolve({artist: artist, album: album, track: title}));
|
||||
}
|
||||
});
|
||||
RSVP.Promise.all(collectionPromises).then(function (collectionResults) {
|
||||
var merged = [];
|
||||
return merged.concat.apply(merged, collectionResults);
|
||||
}).then(function (collectionResults) {
|
||||
RSVP.Promise.resolve(that.resolve({
|
||||
artist: artist,
|
||||
album: album,
|
||||
track: title
|
||||
})).then(function (results) {
|
||||
Tomahawk.addTrackResults({
|
||||
'qid': qid,
|
||||
'results': that._convertUrls(results.concat(collectionResults))
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_adapter_init: function () {
|
||||
this._urlProtocol = this.settings.name.replace(/[^a-zA-Z]/g, '').toLowerCase();
|
||||
Tomahawk.addCustomUrlHandler(this._urlProtocol, '_adapter_getStreamUrl', true);
|
||||
Tomahawk.log('Registered custom url handler for protocol "' + this._urlProtocol + '"');
|
||||
this.init();
|
||||
},
|
||||
|
||||
_adapter_getStreamUrl: function (params) {
|
||||
params.url = params.url.slice(this._urlProtocol.length + 3);
|
||||
RSVP.Promise.resolve(this.getStreamUrl(params)).then(function (result) {
|
||||
Tomahawk.reportStreamUrl(params.qid, result.url, result.headers);
|
||||
});
|
||||
},
|
||||
|
||||
_adapter_search: function (qid, query) {
|
||||
var that = this;
|
||||
var collectionPromises = [];
|
||||
Tomahawk.collections.forEach(function (col) {
|
||||
if (col.search) {
|
||||
collectionPromises.push(col.search({query: query}));
|
||||
}
|
||||
});
|
||||
RSVP.Promise.all(collectionPromises).then(function (collectionResults) {
|
||||
var merged = [];
|
||||
return merged.concat.apply(merged, collectionResults);
|
||||
}).then(function (collectionResults) {
|
||||
RSVP.Promise.resolve(that.search({query: query})).then(function (results) {
|
||||
Tomahawk.addTrackResults({
|
||||
'qid': qid,
|
||||
'results': that._convertUrls(results.concat(collectionResults))
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_testConfig: function (config) {
|
||||
return RSVP.Promise.resolve(this.testConfig(config)).then(function () {
|
||||
return {result: Tomahawk.ConfigTestResultType.Success};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// help functions
|
||||
|
||||
Tomahawk.valueForSubNode = function (node, tag) {
|
||||
@@ -487,175 +364,7 @@ Tomahawk.nativeAsyncRequestDone = function (reqId, xhr) {
|
||||
delete Tomahawk.asyncRequestCallbacks[reqId];
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible options:
|
||||
* - method: The HTTP request method (default: GET)
|
||||
* - username: The username for HTTP Basic Auth
|
||||
* - password: The password for HTTP Basic Auth
|
||||
* - errorHandler: callback called if the request was not completed
|
||||
* - data: body data included in POST requests
|
||||
* - needCookieHeader: boolean indicating whether or not the request needs to be able to get the
|
||||
* "Set-Cookie" response header
|
||||
*/
|
||||
Tomahawk.asyncRequest = function (url, callback, extraHeaders, options) {
|
||||
// unpack options
|
||||
var opt = options || {};
|
||||
var method = opt.method || 'GET';
|
||||
|
||||
if (shouldDoNativeRequest(url, callback, extraHeaders, options)) {
|
||||
// Assign a request Id to the callback so we can use it when we are
|
||||
// returning from the native call.
|
||||
var reqId = Tomahawk.asyncRequestIdCounter;
|
||||
Tomahawk.asyncRequestIdCounter++;
|
||||
Tomahawk.asyncRequestCallbacks[reqId] = {
|
||||
callback: callback,
|
||||
errorHandler: opt.errorHandler
|
||||
};
|
||||
Tomahawk.nativeAsyncRequest(reqId, url, extraHeaders, options);
|
||||
} else {
|
||||
var xmlHttpRequest = new XMLHttpRequest();
|
||||
xmlHttpRequest.open(method, url, true, opt.username, opt.password);
|
||||
if (extraHeaders) {
|
||||
for (var headerName in extraHeaders) {
|
||||
xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]);
|
||||
}
|
||||
}
|
||||
xmlHttpRequest.onreadystatechange = function () {
|
||||
if (xmlHttpRequest.readyState == 4
|
||||
&& httpSuccessStatuses.indexOf(xmlHttpRequest.status) != -1) {
|
||||
callback.call(window, xmlHttpRequest);
|
||||
} else if (xmlHttpRequest.readyState === 4) {
|
||||
Tomahawk.log("Failed to do " + method + " request: to: " + url);
|
||||
Tomahawk.log("Status Code was: " + xmlHttpRequest.status);
|
||||
if (opt.hasOwnProperty('errorHandler')) {
|
||||
opt.errorHandler.call(window, xmlHttpRequest);
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlHttpRequest.send(opt.data || null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is externalized from Tomahawk.asyncRequest, so that other clients
|
||||
* (like tomahawk-android) can inject their own logic that determines whether or not to do a request
|
||||
* natively.
|
||||
*
|
||||
* @returns boolean indicating whether or not to do a request with the given parameters natively
|
||||
*/
|
||||
var shouldDoNativeRequest = function (url, callback, extraHeaders, options) {
|
||||
return (extraHeaders && (extraHeaders.hasOwnProperty("Referer")
|
||||
|| extraHeaders.hasOwnProperty("referer")
|
||||
|| extraHeaders.hasOwnProperty("User-Agent")));
|
||||
};
|
||||
|
||||
Tomahawk.ajax = function (url, settings) {
|
||||
if (typeof url === "object") {
|
||||
settings = url;
|
||||
} else {
|
||||
settings = settings || {};
|
||||
settings.url = url;
|
||||
}
|
||||
|
||||
settings.type = settings.type || settings.method || 'get';
|
||||
settings.method = settings.type;
|
||||
settings.dataFormat = settings.dataFormat || 'form';
|
||||
|
||||
if (settings.data) {
|
||||
var formEncode = function (obj) {
|
||||
var str = [];
|
||||
for (var p in obj) {
|
||||
if (obj[p] !== undefined) {
|
||||
if (Array.isArray(obj[p])) {
|
||||
for (var i = 0; i < obj[p].length; i++) {
|
||||
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p][i]));
|
||||
}
|
||||
} else {
|
||||
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str.sort();
|
||||
|
||||
return str.join("&");
|
||||
};
|
||||
if (typeof settings.data === 'object') {
|
||||
if (settings.dataFormat == 'form') {
|
||||
settings.data = formEncode(settings.data);
|
||||
settings.contentType = settings.contentType || 'application/x-www-form-urlencoded';
|
||||
} else if (settings.dataFormat == 'json') {
|
||||
settings.data = JSON.stringify(settings.data);
|
||||
settings.contentType = settings.contentType || 'application/json';
|
||||
} else {
|
||||
throw new Error("Tomahawk.ajax: unknown dataFormat requested: "
|
||||
+ settings.dataFormat);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Tomahawk.ajax: data should be either object or string");
|
||||
}
|
||||
|
||||
if (settings.type.toLowerCase() === 'get') {
|
||||
settings.url += '?' + settings.data;
|
||||
delete settings.data;
|
||||
} else {
|
||||
settings.headers = settings.headers || {};
|
||||
if (!settings.headers.hasOwnProperty('Content-Type')) {
|
||||
settings.headers['Content-Type'] = settings.contentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
settings.errorHandler = reject;
|
||||
Tomahawk.asyncRequest(settings.url, resolve, settings.headers, settings);
|
||||
}).then(function (xhr) {
|
||||
if (settings.rawResponse) {
|
||||
return xhr;
|
||||
}
|
||||
var responseText = xhr.responseText;
|
||||
var contentType;
|
||||
if (settings.dataType === 'json') {
|
||||
contentType = 'application/json';
|
||||
} else if (settings.dataType === 'xml') {
|
||||
contentType = 'text/xml';
|
||||
} else if (typeof xhr.getResponseHeader !== 'undefined') {
|
||||
contentType = xhr.getResponseHeader('Content-Type');
|
||||
} else if (xhr.hasOwnProperty('contentType')) {
|
||||
contentType = xhr['contentType'];
|
||||
} else {
|
||||
contentType = 'text/html';
|
||||
}
|
||||
|
||||
if (~contentType.indexOf('application/json')) {
|
||||
return JSON.parse(responseText);
|
||||
}
|
||||
|
||||
if (~contentType.indexOf('text/xml')) {
|
||||
var domParser = new DOMParser();
|
||||
return domParser.parseFromString(responseText, "text/xml");
|
||||
}
|
||||
|
||||
return xhr.responseText;
|
||||
});
|
||||
};
|
||||
|
||||
Tomahawk.post = function (url, settings) {
|
||||
if (typeof url === "object") {
|
||||
settings = url;
|
||||
} else {
|
||||
settings = settings || {};
|
||||
settings.url = url;
|
||||
}
|
||||
|
||||
settings.method = 'POST';
|
||||
|
||||
return Tomahawk.ajax(settings);
|
||||
};
|
||||
|
||||
Tomahawk.get = function (url, settings) {
|
||||
return Tomahawk.ajax(url, settings);
|
||||
};
|
||||
|
||||
Tomahawk.assert = function (assertion, message) {
|
||||
Tomahawk.nativeAssert(assertion, message);
|
||||
@@ -815,116 +524,6 @@ Tomahawk.base64Encode = function (b) {
|
||||
return window.btoa(b);
|
||||
};
|
||||
|
||||
Tomahawk.PluginManager = {
|
||||
objects: {},
|
||||
objectCounter: 0,
|
||||
identifyObject: function (object) {
|
||||
if (!object.hasOwnProperty('id')) {
|
||||
object.id = this.objectCounter++;
|
||||
}
|
||||
|
||||
return object.id;
|
||||
},
|
||||
registerPlugin: function (type, object) {
|
||||
this.objects[this.identifyObject(object)] = object;
|
||||
if (type === 'collection') {
|
||||
Tomahawk.collections.push(object);
|
||||
}
|
||||
|
||||
Tomahawk.log("registerPlugin: " + type + " id: " + object.id);
|
||||
Tomahawk.registerScriptPlugin(type, object.id);
|
||||
},
|
||||
|
||||
unregisterPlugin: function (type, object) {
|
||||
this.objects[this.identifyObject(object)] = object;
|
||||
|
||||
Tomahawk.log("unregisterPlugin: " + type + " id: " + object.id);
|
||||
Tomahawk.unregisterScriptPlugin(type, object.id);
|
||||
},
|
||||
|
||||
resolve: [],
|
||||
invokeSync: function (requestId, objectId, methodName, params) {
|
||||
if (!Tomahawk.resolver.instance.apiVersion || Tomahawk.resolver.instance.apiVersion < 0.9) {
|
||||
if (methodName === 'artistAlbums') {
|
||||
methodName = 'albums';
|
||||
} else if (methodName === 'albumTracks') {
|
||||
methodName = 'tracks';
|
||||
}
|
||||
}
|
||||
|
||||
var pluginManager = this;
|
||||
if (!this.objects[objectId]) {
|
||||
Tomahawk.log("Object not found! objectId: " + objectId + " methodName: " + methodName);
|
||||
} else {
|
||||
if (!this.objects[objectId][methodName]) {
|
||||
Tomahawk.log("Function not found: " + methodName);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof this.objects[objectId][methodName] === 'function') {
|
||||
if (!Tomahawk.resolver.instance.apiVersion
|
||||
|| Tomahawk.resolver.instance.apiVersion < 0.9) {
|
||||
if (methodName == 'artists') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.artists(requestId);
|
||||
});
|
||||
} else if (methodName == 'albums') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.albums(requestId, params.artist);
|
||||
});
|
||||
} else if (methodName == 'tracks') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.tracks(requestId, params.artist, params.album);
|
||||
});
|
||||
} else if (methodName == 'lookupUrl') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[params.url] = resolve;
|
||||
Tomahawk.resolver.instance.lookupUrl(params.url);
|
||||
});
|
||||
} else if (methodName == 'getStreamUrl') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.getStreamUrl(requestId, params.url);
|
||||
});
|
||||
} else if (methodName == 'resolve') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.resolve(requestId, params.artist,
|
||||
params.album, params.track);
|
||||
});
|
||||
} else if (methodName == 'search') {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
pluginManager.resolve[requestId] = resolve;
|
||||
Tomahawk.resolver.instance.search(requestId, params.query);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return this.objects[objectId][methodName](params);
|
||||
}
|
||||
|
||||
return this.objects[objectId][methodName];
|
||||
},
|
||||
|
||||
invoke: function (requestId, objectId, methodName, params) {
|
||||
RSVP.Promise.resolve(this.invokeSync(requestId, objectId, methodName, params))
|
||||
.then(function (result) {
|
||||
Tomahawk.reportScriptJobResults({
|
||||
requestId: requestId,
|
||||
data: result
|
||||
});
|
||||
}, function (error) {
|
||||
Tomahawk.reportScriptJobResults({
|
||||
requestId: requestId,
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Tomahawk.NativeScriptJobManager = {
|
||||
idCounter: 0,
|
||||
deferreds: {},
|
||||
@@ -943,15 +542,6 @@ Tomahawk.NativeScriptJobManager = {
|
||||
}
|
||||
};
|
||||
|
||||
Tomahawk.UrlType = {
|
||||
Any: 0,
|
||||
Playlist: 1,
|
||||
Track: 2,
|
||||
Album: 3,
|
||||
Artist: 4,
|
||||
XspfPlaylist: 5
|
||||
};
|
||||
|
||||
Tomahawk.ConfigTestResultType = {
|
||||
Other: 0,
|
||||
Success: 1,
|
||||
@@ -1213,8 +803,6 @@ Tomahawk.Country = {
|
||||
LatinAmericaAndTheCaribbean: 246
|
||||
};
|
||||
|
||||
Tomahawk.collections = [];
|
||||
|
||||
Tomahawk.Collection = {
|
||||
BrowseCapability: {
|
||||
Artists: 1,
|
||||
@@ -1709,7 +1297,7 @@ Tomahawk.Collection = {
|
||||
);
|
||||
return t.execDeferredStatements();
|
||||
}).then(function (results) {
|
||||
return {results: Tomahawk.resolver.instance._convertUrls(results[0])};
|
||||
return {results: resolverInstance._convertUrls(results[0])};
|
||||
});
|
||||
},
|
||||
|
||||
|
@@ -209,49 +209,17 @@ JSResolver::init()
|
||||
}
|
||||
const QByteArray scriptContents = scriptFile.readAll();
|
||||
|
||||
// tomahawk.js
|
||||
{
|
||||
// add c++ part of tomahawk javascript library
|
||||
d->scriptAccount->addToJavaScriptWindowObject( "Tomahawk", d->resolverHelper );
|
||||
|
||||
// load es6-promises shim
|
||||
d->scriptAccount->loadScript( RESPATH "js/rsvp-latest.min.js" );
|
||||
|
||||
|
||||
// Load CrytoJS core
|
||||
d->scriptAccount->loadScript( RESPATH "js/cryptojs-core.js" );
|
||||
|
||||
// Load CryptoJS modules
|
||||
QStringList jsfiles;
|
||||
jsfiles << "*.js";
|
||||
QDir cryptojs( RESPATH "js/cryptojs" );
|
||||
foreach ( QString jsfile, cryptojs.entryList( jsfiles ) )
|
||||
{
|
||||
d->scriptAccount->loadScript( RESPATH "js/cryptojs/" + jsfile );
|
||||
}
|
||||
|
||||
// Load tomahawk.js
|
||||
d->scriptAccount->loadScript( RESPATH "js/tomahawk.js" );
|
||||
}
|
||||
|
||||
// tomahawk-infosystem.js
|
||||
{
|
||||
// TODO: be smarter about this, only include this if the resolver supports infoplugins
|
||||
|
||||
// add deps
|
||||
d->scriptAccount->loadScript( RESPATH "js/tomahawk-infosystem.js" );
|
||||
}
|
||||
|
||||
// add resolver dependencies, if any
|
||||
d->scriptAccount->loadScripts( d->requiredScriptPaths );
|
||||
|
||||
d->scriptAccount->addToJavaScriptWindowObject( "Tomahawk", d->resolverHelper );
|
||||
|
||||
// add resolver
|
||||
d->scriptAccount->loadScript( filePath() );
|
||||
|
||||
// HACK: register resolver object
|
||||
d->scriptAccount->evaluateJavaScript( "Tomahawk.PluginManager.registerPlugin('resolver', Tomahawk.resolver.instance);" )
|
||||
;
|
||||
d->scriptAccount->evaluateJavaScript(
|
||||
"var resolverInstance = new (require('main').default);"
|
||||
"Tomahawk.PluginManager.registerPlugin('resolver', resolverInstance);"
|
||||
);
|
||||
|
||||
// init resolver
|
||||
resolverInit();
|
||||
|
||||
@@ -545,10 +513,10 @@ JSResolver::callOnResolver( const QString& scriptSource )
|
||||
QString propertyName = scriptSource.split('(').first();
|
||||
|
||||
return d->scriptAccount->evaluateJavaScriptWithResult( QString(
|
||||
"if(Tomahawk.resolver.instance['_adapter_%1']) {"
|
||||
" Tomahawk.resolver.instance._adapter_%2;"
|
||||
"if(resolverInstance['_adapter_%1']) {"
|
||||
" resolverInstance._adapter_%2;"
|
||||
"} else {"
|
||||
" Tomahawk.resolver.instance.%2"
|
||||
" resolverInstance.%2;"
|
||||
"}"
|
||||
).arg( propertyName ).arg( scriptSource ) );
|
||||
}
|
||||
|
@@ -712,10 +712,10 @@ JSResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr&, const QStr
|
||||
{
|
||||
QString qid = uuid();
|
||||
QString getUrl = QString(
|
||||
"if(Tomahawk.resolver.instance['_adapter_%1']) {"
|
||||
" Tomahawk.resolver.instance._adapter_%1( {qid: '%2', url: '%3'} );"
|
||||
"if(resolverInstance['_adapter_%1']) {"
|
||||
" resolverInstance._adapter_%1( {qid: '%2', url: '%3'} );"
|
||||
"} else {"
|
||||
" Tomahawk.resolver.instance.%1( {qid: '%2', url: '%3'} );"
|
||||
" resolverInstance.%1( {qid: '%2', url: '%3'} );"
|
||||
"}"
|
||||
).arg( m_urlCallback )
|
||||
.arg( qid )
|
||||
@@ -726,7 +726,7 @@ JSResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr&, const QStr
|
||||
}
|
||||
else
|
||||
{
|
||||
QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( m_urlCallback )
|
||||
QString getUrl = QString( "resolverInstance.%1( '%2' );" ).arg( m_urlCallback )
|
||||
.arg( url );
|
||||
|
||||
QString urlStr = m_resolver->d_func()->scriptAccount->evaluateJavaScriptWithResult( getUrl ).toString();
|
||||
|
Reference in New Issue
Block a user