mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-21 03:11:30 +02:00
Compare commits
117 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9a5750c6f4 | ||
|
3b6ba36e83 | ||
|
cf6a37ae45 | ||
|
690a87f1eb | ||
|
6842da7240 | ||
|
6910e5dd3b | ||
|
584aa76582 | ||
|
7e96285132 | ||
|
c996a8b90e | ||
|
c705013ee1 | ||
|
84360aed2f | ||
|
ada03e1a8d | ||
|
3a71da5705 | ||
|
214e310c91 | ||
|
ed9a027644 | ||
|
3e2d74128d | ||
|
84ed59f4be | ||
|
5dd36cbd4e | ||
|
7e38d94fe5 | ||
|
28ee9180c8 | ||
|
09e9a6e960 | ||
|
ffa098e52d | ||
|
a439427ca5 | ||
|
a9505f75c5 | ||
|
7e54e506df | ||
|
abc00b4758 | ||
|
77e9b69679 | ||
|
58b640d389 | ||
|
1a5f073437 | ||
|
c9ef7e74d8 | ||
|
34448b1b46 | ||
|
4408ba275c | ||
|
dfd71d7010 | ||
|
170e2e1c86 | ||
|
0047763188 | ||
|
525068a706 | ||
|
85657e40a6 | ||
|
af459afb0b | ||
|
5bbc39e6a5 | ||
|
c88640268a | ||
|
8749a04e23 | ||
|
d45917d14a | ||
|
c87b1390e5 | ||
|
bf28f6856e | ||
|
ceab0f9cf2 | ||
|
a562e75937 | ||
|
81eb226146 | ||
|
ec88cf27f3 | ||
|
931562fbe5 | ||
|
77593e32a7 | ||
|
bac38e4555 | ||
|
980ee97c97 | ||
|
26ad51f4b8 | ||
|
21bdb0bc89 | ||
|
0a560f2f27 | ||
|
9c9f5e4dae | ||
|
fb38735936 | ||
|
c62ae52bfe | ||
|
0341492069 | ||
|
879df894c3 | ||
|
0c9f1be2c8 | ||
|
f7a3d441a1 | ||
|
e9a1135525 | ||
|
bdce4f7636 | ||
|
de65e19cb7 | ||
|
ce3647a4a6 | ||
|
f498570a0e | ||
|
9a741cd2db | ||
|
102c9c6846 | ||
|
1fa35ae827 | ||
|
26c0f35d21 | ||
|
9acbb48659 | ||
|
cc9f287b41 | ||
|
99abd7434b | ||
|
f38f3ca367 | ||
|
773ecea0da | ||
|
620d3fe3fc | ||
|
8679fd5055 | ||
|
d7eccea4c0 | ||
|
2ab9418a9e | ||
|
285333d43b | ||
|
3bcf854a4f | ||
|
61a15cafac | ||
|
2d141ccb5e | ||
|
4c023b7d2f | ||
|
ceb5dc6aa4 | ||
|
13fa9c7c53 | ||
|
4c946b304c | ||
|
5075c9ddbf | ||
|
8b3a916aa6 | ||
|
cd412add8f | ||
|
68851843f5 | ||
|
af8811af30 | ||
|
fa38ed5e91 | ||
|
b7ff630808 | ||
|
196256d77b | ||
|
79cd3a7f0a | ||
|
f0f45673b1 | ||
|
86cd7c1be0 | ||
|
f74c6ae429 | ||
|
015b24479c | ||
|
8b904cf806 | ||
|
175e498c43 | ||
|
65908f9dfa | ||
|
3c9deb6389 | ||
|
978c1e58de | ||
|
0722dd7812 | ||
|
ff34afb4e3 | ||
|
bd607b6c54 | ||
|
81f7e3f8f4 | ||
|
798ca62190 | ||
|
f2631cda74 | ||
|
4813698a9a | ||
|
dc80d19a08 | ||
|
1b0517efc5 | ||
|
e6a8a41c31 | ||
|
193beda2bc |
@@ -179,7 +179,7 @@ if( NOT BUILD_WITH_QT4 )
|
||||
set(HAVE_X11 FALSE)
|
||||
endif()
|
||||
|
||||
message(STATUS "Found Qt5! Be aware that Qt5-support is still experimental and not officially supported!")
|
||||
message(STATUS "Found Qt5!")
|
||||
|
||||
if( UNIX AND NOT APPLE )
|
||||
# We need this to find the paths to qdbusxml2cpp and co
|
||||
@@ -228,6 +228,10 @@ endif()
|
||||
if( NOT Qt5Core_DIR )
|
||||
message(STATUS "Could not find Qt5, searching for Qt4 instead...")
|
||||
|
||||
if(NOT FORCE_QT4)
|
||||
message(FATAL_ERROR "Qt4 support is broken, if you plan to fix it, add -DFORCE_QT4=ON to your cmake arguments otherwise you should compile Tomahawk with Qt5")
|
||||
endif()
|
||||
|
||||
set(NEEDED_QT4_COMPONENTS "QtCore" "QtXml" "QtNetwork")
|
||||
if( BUILD_GUI )
|
||||
list(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" "QtSvg")
|
||||
@@ -311,9 +315,6 @@ if(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR APPLE) AND LIBCPP_FOUND)
|
||||
tomahawk_add_cxx_flags( "-stdlib=libc++" )
|
||||
endif()
|
||||
|
||||
macro_optional_find_package(Echonest 2.3.0)
|
||||
macro_log_feature(ECHONEST_FOUND "Echonest" "Qt library for communicating with The Echo Nest" "http://projects.kde.org/libechonest" TRUE "" "libechonest 2.3.0 is needed for dynamic playlists and the infosystem")
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS filesystem system)
|
||||
macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++ source libraries" "http://www.boost.org" TRUE "" "") #FIXME: give useful explanation
|
||||
|
||||
|
@@ -1,42 +0,0 @@
|
||||
# - Find libechonest
|
||||
# Find the libechonest includes and the libechonest libraries
|
||||
# This module defines
|
||||
# ECHONEST_INCLUDE_DIR, root echonest include dir. Include echonest includes with echonest/foo.h
|
||||
# ECHONEST_LIBRARIES, the path to libechonest
|
||||
# ECHONEST_FOUND, whether libechonest was found
|
||||
|
||||
FIND_PACKAGE(PkgConfig QUIET)
|
||||
|
||||
if( TOMAHAWK_QT5 )
|
||||
set(LIBECHONEST_SUFFIX "5")
|
||||
endif()
|
||||
|
||||
PKG_CHECK_MODULES(PC_ECHONEST QUIET libechonest${LIBECHONEST_SUFFIX})
|
||||
|
||||
FIND_PATH(ECHONEST_INCLUDE_DIR NAMES echonest${LIBECHONEST_SUFFIX}/Track.h
|
||||
HINTS
|
||||
${PC_ECHONEST_INCLUDEDIR}
|
||||
${PC_ECHONEST_INCLUDE_DIRS}
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
${KDE4_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ECHONEST_LIBRARIES NAMES echonest${LIBECHONEST_SUFFIX}
|
||||
HINTS
|
||||
${PC_ECHONEST_LIBDIR}
|
||||
${PC_ECHONEST_LIBRARY_DIRS}
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
${KDE4_LIB_DIR}
|
||||
)
|
||||
|
||||
IF(ECHONEST_LIBRARIES AND ECHONEST_INCLUDE_DIR AND NOT PC_ECHONEST_VERSION)
|
||||
MESSAGE(WARNING "You don't have pkg-config and so the libechonest version check does not work!")
|
||||
set(PC_ECHONEST_VERSION "999.9.9")
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Echonest
|
||||
REQUIRED_VARS ECHONEST_LIBRARIES ECHONEST_INCLUDE_DIR
|
||||
VERSION_VAR PC_ECHONEST_VERSION)
|
||||
|
||||
MARK_AS_ADVANCED(ECHONEST_INCLUDE_DIR ECHONEST_LIBRARIES)
|
@@ -1,6 +1,7 @@
|
||||
Version 0.9.0:
|
||||
* Resolved various playback issues by switching to a new audio engine.
|
||||
* Fixed collection sorting.
|
||||
* Fixed volume/mute state not being reset correctly on startup.
|
||||
|
||||
Version 0.8.4:
|
||||
* Fixed drag & drop issues on sidebar.
|
||||
|
@@ -79,7 +79,6 @@ Required dependencies:
|
||||
* [TagLib 1.8](https://taglib.github.io/)
|
||||
* [Boost 1.3](http://www.boost.org/)
|
||||
* [Lucene++ 3.0.6](https://github.com/luceneplusplus/LucenePlusPlus/)
|
||||
* [libechonest 2.3.1](http://projects.kde.org/projects/playground/libs/libechonest/)
|
||||
* [Attica 5.6.0](http://ftp.kde.org/stable/attica/)
|
||||
* [QuaZip 0.4.3](http://quazip.sourceforge.net/)
|
||||
* [liblastfm 1.0.9](https://github.com/lastfm/liblastfm/)
|
||||
|
@@ -3,8 +3,6 @@
|
||||
set( TOMAHAWK_QT5 @TOMAHAWK_QT5@ )
|
||||
|
||||
if(TOMAHAWK_QT5)
|
||||
message(STATUS "Found Qt5! Be aware that Qt5-support is still experimental and not officially supported!")
|
||||
|
||||
# CMAKE 2.8.13+/3.0.0+ requires these for IMPORTed targets
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Concurrent REQUIRED)
|
||||
|
@@ -46,7 +46,7 @@ CERT_SIGNER=$2
|
||||
cd ..
|
||||
if [ -f ~/sign_step.sh ];
|
||||
then
|
||||
~/sign_step.sh "$CERT_SIGNER" "${TARGET_NAME}.app" || true
|
||||
~/sign_step.sh "$CERT_SIGNER" "${TARGET_NAME}.app"
|
||||
fi
|
||||
|
||||
header "Creating DMG"
|
||||
|
@@ -9,19 +9,20 @@ fi
|
||||
|
||||
rm -rvf vlc/
|
||||
|
||||
VLC_TARBALL="vlc.tar.bz2"
|
||||
|
||||
echo "Download phonon archive..."
|
||||
# wget -c "http://downloads.sourceforge.net/project/vlc/1.1.9/win32/vlc-1.1.9-win32.7z?r=http%3A%2F%2Fwww.videolan.org%2Fvlc%2Fdownload-windows.html&ts=1306272584&use_mirror=leaseweb"
|
||||
# wget -c "http://download.tomahawk-player.org/tomahawk-vlc-0.1.zip"
|
||||
# wget -c http://people.videolan.org/~jb/phonon/phonon-vlc-last.7z
|
||||
# wget -c http://people.videolan.org/~jb/phonon/phonon_phonon-vlc_20111128.7z
|
||||
wget -c http://download.tomahawk-player.org/test/vlc.tar.bz2
|
||||
wget -c "http://download.tomahawk-player.org/test/$VLC_TARBALL"
|
||||
|
||||
echo "Extract binary..."
|
||||
# 7z x phonon*.7z
|
||||
# mv -v vlc-*/ vlc/
|
||||
# unzip tomahawk-vlc-0.1.zip
|
||||
tar xvjf vlc.tar.bz2
|
||||
tar xvjf "$VLC_TARBALL"
|
||||
|
||||
# echo "Download phonon_vlc_no_video.dll..."
|
||||
# wget -c http://people.videolan.org/~jb/phonon/phonon_vlc_no_video.dll
|
||||
@@ -72,7 +73,9 @@ rm -rvf \
|
||||
**/libi420* \
|
||||
**/libi422* \
|
||||
mux/ \
|
||||
stream_filter/ \
|
||||
stream_filter/*dash* \
|
||||
stream_filter/*smooth* \
|
||||
stream_filter/*record* \
|
||||
**/libtheora_plugin* \
|
||||
**/liblibbluray_plugin* \
|
||||
**/libdtv_plugin* \
|
||||
|
13
data/images/folder.svg
Normal file
13
data/images/folder.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="86px" height="86px" viewBox="0 0 86 86" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<title>folder</title>
|
||||
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="folder" sketch:type="MSLayerGroup" transform="translate(0.000000, 13.000000)" fill="#000000">
|
||||
<g id="Page-1" sketch:type="MSShapeGroup">
|
||||
<path d="M84.1450038,10.4833376 C82.8248024,9.1092149 80.9427764,8.3195294 78.9789985,8.3195294 L72.233622,8.3195294 L34.4730823,8.3195294 L34.4730823,7.0184614 C34.4730823,3.1483061 31.3247762,0 27.4563602,0 L10.1441555,0 C6.27226058,0 3.12569415,3.1500456 3.12569415,7.0184614 L3.12569415,9.4918821 C1.2088801,10.761641 0,12.9237099 0,15.3362515 L0,54.4987445 C0,54.5057021 0,54.5178779 0.0017394,54.5265748 L0,54.5439688 C0,58.3897726 3.14656684,61.5154666 7.0184614,61.5154666 L72.2336242,61.5154666 C72.4736608,61.5154666 72.7102186,61.5050302 72.9432977,61.4789393 C72.9850432,61.4771999 73.028528,61.4650241 73.0702735,61.4615453 C73.2616071,61.4389332 73.4529406,61.4145816 73.6390559,61.3745755 C73.6686257,61.3693573 73.6947166,61.3606604 73.7242863,61.3519634 C73.9225774,61.3119573 74.1208685,61.2597754 74.3139414,61.200636 C74.3243778,61.1954178 74.3348142,61.191939 74.3452506,61.1884602 C76.756053,60.4300837 78.5998126,58.4123847 79.1059765,55.9198305 C79.1077159,55.912873 79.1077159,55.9024366 79.1077159,55.895479 C79.1512008,55.6937091 79.18251,55.4919392 79.2051221,55.2797329 C79.2103403,55.2240723 79.2155585,55.1684116 79.2190373,55.1092721 C79.2277343,55.0136054 79.2433888,54.9266356 79.2451282,54.8309688 L85.9539776,15.7937099 L85.9939837,15.4127822 C86.0705187,13.5587047 85.4147685,11.8086925 84.1450038,10.4833376 C84.1450038,10.4833376 85.4147685,11.8086925 84.1450038,10.4833376 L84.1450038,10.4833376" id="Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
@@ -42,6 +42,8 @@ Tomahawk.apiVersion = "0.2.2";
|
||||
//Statuses considered a success for HTTP request
|
||||
var httpSuccessStatuses = [200, 201];
|
||||
|
||||
Tomahawk.error = console.error;
|
||||
|
||||
// install RSVP error handler for uncaught(!) errors
|
||||
RSVP.on('error', function (reason) {
|
||||
var resolverName = "";
|
||||
@@ -49,9 +51,9 @@ RSVP.on('error', function (reason) {
|
||||
resolverName = Tomahawk.resolver.instance.settings.name + " - ";
|
||||
}
|
||||
if (reason) {
|
||||
console.error(resolverName + 'Uncaught error:', reason);
|
||||
Tomahawk.error(resolverName + 'Uncaught error:', reason);
|
||||
} else {
|
||||
console.error(resolverName + 'Uncaught error: error thrown from RSVP but it was empty');
|
||||
Tomahawk.error(resolverName + 'Uncaught error: error thrown from RSVP but it was empty');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -273,6 +275,9 @@ Tomahawk.Resolver = {
|
||||
getStreamUrl: function (params) {
|
||||
return params;
|
||||
},
|
||||
getDownloadUrl: function (params) {
|
||||
return params;
|
||||
},
|
||||
resolve: function() {
|
||||
},
|
||||
_adapter_resolve: function (params) {
|
||||
@@ -300,13 +305,15 @@ Tomahawk.Resolver = {
|
||||
},
|
||||
|
||||
_adapter_testConfig: function (config) {
|
||||
return RSVP.Promise.resolve(this.testConfig(config)).then(function () {
|
||||
return {result: Tomahawk.ConfigTestResultType.Success};
|
||||
return RSVP.Promise.resolve(this.testConfig(config)).then(function (results) {
|
||||
results = results || Tomahawk.ConfigTestResultType.Success;
|
||||
return results;
|
||||
}, function (error) {
|
||||
return error;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// help functions
|
||||
|
||||
Tomahawk.valueForSubNode = function (node, tag) {
|
||||
@@ -377,48 +384,6 @@ Tomahawk.retrievedMetadata = function (metadataId, metadata, error) {
|
||||
delete Tomahawk.retrieveMetadataCallbacks[metadataId];
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal counter used to identify asyncRequest callback from native code.
|
||||
*/
|
||||
Tomahawk.asyncRequestIdCounter = 0;
|
||||
/**
|
||||
* Internal map used to map asyncRequestIds to the respective javascript
|
||||
* callback functions.
|
||||
*/
|
||||
Tomahawk.asyncRequestCallbacks = {};
|
||||
|
||||
/**
|
||||
* Pass the natively retrieved reply back to the javascript callback
|
||||
* and augment the fake XMLHttpRequest object.
|
||||
*
|
||||
* Internal use only!
|
||||
*/
|
||||
Tomahawk.nativeAsyncRequestDone = function (reqId, xhr) {
|
||||
// Check that we have a matching callback stored.
|
||||
if (!Tomahawk.asyncRequestCallbacks.hasOwnProperty(reqId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the real callback
|
||||
if (xhr.readyState == 4 && httpSuccessStatuses.indexOf(xhr.status) != -1) {
|
||||
// Call the real callback
|
||||
if (Tomahawk.asyncRequestCallbacks[reqId].callback) {
|
||||
Tomahawk.asyncRequestCallbacks[reqId].callback(xhr);
|
||||
}
|
||||
} else if (xhr.readyState === 4) {
|
||||
Tomahawk.log("Failed to do nativeAsyncRequest");
|
||||
Tomahawk.log("Status Code was: " + xhr.status);
|
||||
if (Tomahawk.asyncRequestCallbacks[reqId].errorHandler) {
|
||||
Tomahawk.asyncRequestCallbacks[reqId].errorHandler(xhr);
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks are only used once.
|
||||
delete Tomahawk.asyncRequestCallbacks[reqId];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -433,9 +398,9 @@ var shouldDoNativeRequest = function (options) {
|
||||
|| extraHeaders.hasOwnProperty("User-Agent")));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Possible options:
|
||||
* - url: The URL to call
|
||||
* - method: The HTTP request method (default: GET)
|
||||
* - username: The username for HTTP Basic Auth
|
||||
* - password: The password for HTTP Basic Auth
|
||||
@@ -453,7 +418,12 @@ var doRequest = function(options) {
|
||||
return this.responseHeaders;
|
||||
};
|
||||
xhr.getResponseHeader = function (header) {
|
||||
return this.responseHeaders[header];
|
||||
for(key in xhr.responseHeaders) {
|
||||
if(key.toLowerCase() === header.toLowerCase()) {
|
||||
return xhr.responseHeaders[key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
return xhr;
|
||||
@@ -745,7 +715,6 @@ Tomahawk.base64Encode = function (b) {
|
||||
return window.btoa(b);
|
||||
};
|
||||
|
||||
|
||||
Tomahawk.PluginManager = {
|
||||
wrapperPrefix: '_adapter_',
|
||||
objects: {},
|
||||
@@ -776,8 +745,6 @@ Tomahawk.PluginManager = {
|
||||
methodName = this.wrapperPrefix + methodName;
|
||||
}
|
||||
|
||||
|
||||
var pluginManager = this;
|
||||
if (!this.objects[objectId]) {
|
||||
Tomahawk.log("Object not found! objectId: " + objectId + " methodName: " + methodName);
|
||||
} else {
|
||||
@@ -798,20 +765,21 @@ Tomahawk.PluginManager = {
|
||||
invoke: function (requestId, objectId, methodName, params) {
|
||||
RSVP.Promise.resolve(this.invokeSync(requestId, objectId, methodName, params))
|
||||
.then(function (result) {
|
||||
Tomahawk.reportScriptJobResults({
|
||||
var params = {
|
||||
requestId: requestId,
|
||||
data: result
|
||||
});
|
||||
};
|
||||
Tomahawk.reportScriptJobResults(encodeParamsToNativeFunctions(params));
|
||||
}, function (error) {
|
||||
Tomahawk.reportScriptJobResults({
|
||||
var params = {
|
||||
requestId: requestId,
|
||||
error: error
|
||||
});
|
||||
};
|
||||
Tomahawk.reportScriptJobResults(encodeParamsToNativeFunctions(params));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var encodeParamsToNativeFunctions = function(param) {
|
||||
return param;
|
||||
};
|
||||
@@ -825,7 +793,7 @@ Tomahawk.NativeScriptJobManager = {
|
||||
var requestId = this.idCounter++;
|
||||
var deferred = RSVP.defer();
|
||||
this.deferreds[requestId] = deferred;
|
||||
Tomahawk.invokeNativeScriptJob(requestId, methodName, encodeParamsToNativeFunctions(params));;
|
||||
Tomahawk.invokeNativeScriptJob(requestId, methodName, encodeParamsToNativeFunctions(params));
|
||||
return deferred.promise;
|
||||
},
|
||||
reportNativeScriptJobResult: function(requestId, result) {
|
||||
@@ -1494,9 +1462,7 @@ Tomahawk.Collection = {
|
||||
return new RSVP.Promise(function (resolve, reject) {
|
||||
that.cachedDbs[id].changeVersion(that.cachedDbs[id].version, "", null,
|
||||
function (err) {
|
||||
if (console.error) {
|
||||
console.error("Error!: %o", err);
|
||||
}
|
||||
Tomahawk.error("Error trying to change db version!", err);
|
||||
reject();
|
||||
}, function () {
|
||||
delete that.cachedDbs[id];
|
||||
@@ -1800,6 +1766,9 @@ Tomahawk.Collection = {
|
||||
this.settings.capabilities = [Tomahawk.Collection.BrowseCapability.Artists,
|
||||
Tomahawk.Collection.BrowseCapability.Albums,
|
||||
Tomahawk.Collection.BrowseCapability.Tracks];
|
||||
if (!this.settings.weight && this.resolver && this.resolver.settings.weight) {
|
||||
this.settings.weight = this.resolver.settings.weight;
|
||||
}
|
||||
return this.settings;
|
||||
},
|
||||
|
||||
@@ -1808,6 +1777,14 @@ Tomahawk.Collection = {
|
||||
return this.resolver.getStreamUrl(params);
|
||||
}
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
getDownloadUrl: function(params) {
|
||||
if(this.resolver) {
|
||||
return this.resolver.getDownloadUrl(params);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
};
|
||||
|
BIN
data/sounds/silence.ogg
Normal file
BIN
data/sounds/silence.ogg
Normal file
Binary file not shown.
@@ -3,6 +3,7 @@
|
||||
<file>data/images/collection_background.png</file>
|
||||
<file>data/images/playlist_background.png</file>
|
||||
<file>data/images/filter.svg</file>
|
||||
<file>data/images/folder.svg</file>
|
||||
<file>data/images/loved.svg</file>
|
||||
<file>data/images/love.svg</file>
|
||||
<file>data/images/not-loved.svg</file>
|
||||
@@ -169,5 +170,6 @@
|
||||
<file>data/images/downloadbutton.svg</file>
|
||||
<file>data/images/nav-back.svg</file>
|
||||
<file>data/images/nav-forward.svg</file>
|
||||
<file>data/sounds/silence.ogg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -44,12 +44,12 @@ namespace Tomahawk {
|
||||
void publishTune( QUrl url, Tomahawk::InfoSystem::InfoStringHash trackInfo );
|
||||
|
||||
public slots:
|
||||
void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ) override;
|
||||
|
||||
protected slots:
|
||||
void init();
|
||||
void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData );
|
||||
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
|
||||
void init() override;
|
||||
void pushInfo( Tomahawk::InfoSystem::InfoPushData pushData ) override;
|
||||
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ) override;
|
||||
|
||||
private slots:
|
||||
void audioStarted( const Tomahawk::InfoSystem::PushInfoPair& pushInfoPair );
|
||||
|
@@ -54,14 +54,14 @@ public:
|
||||
Account::ConnectionState connectionState() const;
|
||||
|
||||
public slots:
|
||||
void connectPlugin();
|
||||
void disconnectPlugin();
|
||||
void connectPlugin() override;
|
||||
void disconnectPlugin() override;
|
||||
|
||||
void advertise();
|
||||
|
||||
virtual void sendSipInfos( const Tomahawk::peerinfo_ptr& /* receiver */, const QList<SipInfo>& /* info */ ) {}
|
||||
virtual void sendSipInfos( const Tomahawk::peerinfo_ptr& /* receiver */, const QList<SipInfo>& /* info */ ) override {}
|
||||
void broadcastMsg( const QString& ) {}
|
||||
bool addContact( const QString&, AddContactOptions, const QString& ) { return false; }
|
||||
bool addContact( const QString&, AddContactOptions, const QString& ) override { return false; }
|
||||
|
||||
private slots:
|
||||
void lanHostFound( const QString& host, int port, const QString& name, const QString& nodeid );
|
||||
|
@@ -1,5 +1,4 @@
|
||||
include_directories(
|
||||
${ECHONEST_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIR}
|
||||
)
|
||||
if(WIN32 OR APPLE)
|
||||
@@ -15,14 +14,13 @@ endif()
|
||||
endif(WIN32 OR APPLE)
|
||||
|
||||
list(APPEND simple_plugins
|
||||
Echonest
|
||||
Charts
|
||||
NewReleases
|
||||
Spotify
|
||||
#Spotify
|
||||
Hypem
|
||||
MusixMatch
|
||||
MusicBrainz
|
||||
Rovi
|
||||
#Rovi
|
||||
Discogs
|
||||
)
|
||||
|
||||
|
@@ -80,7 +80,7 @@ FdoNotifyPlugin::FdoNotifyPlugin()
|
||||
, m_wmSupportsBodyMarkup( false )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
|
||||
m_supportedPushTypes << InfoNotifyUser << InfoNowPlaying << InfoTrackUnresolved << InfoNowStopped << InfoInboxReceived;
|
||||
m_supportedPushTypes << InfoNotifyUser << InfoNowPlaying << InfoNowResumed << InfoTrackUnresolved << InfoNowStopped << InfoInboxReceived;
|
||||
|
||||
// Query the window manager for its capabilties in styling notifications.
|
||||
notifications_interface = new org::freedesktop::Notifications( "org.freedesktop.Notifications", "/org/freedesktop/Notifications",
|
||||
@@ -139,6 +139,7 @@ FdoNotifyPlugin::pushInfo( Tomahawk::InfoSystem::InfoPushData pushData )
|
||||
return;
|
||||
|
||||
case Tomahawk::InfoSystem::InfoNowPlaying:
|
||||
case Tomahawk::InfoSystem::InfoNowResumed:
|
||||
nowPlaying( pushData.infoPair.second );
|
||||
return;
|
||||
|
||||
|
@@ -24,6 +24,7 @@ tomahawk_add_library(${TOMAHAWK_PLAYDARAPI_LIBRARY_TARGET}
|
||||
qtcertificateaddon
|
||||
${GNUTLS_LIBRARIES}
|
||||
EXPORT TomahawkLibraryDepends
|
||||
EXPORT_MACRO TOMAHAWK_WIDGETS_EXPORT_PRO
|
||||
VERSION ${TOMAHAWK_VERSION_SHORT}
|
||||
)
|
||||
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef TOMAHAWK_PLAYDARAPI_EXPORT
|
||||
# if defined (tomahawk_playdarapi_EXPORTS)
|
||||
# if defined (TOMAHAWK_WIDGETS_EXPORT_PRO)
|
||||
# define TOMAHAWK_PLAYDARAPI_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define TOMAHAWK_PLAYDARAPI_EXPORT Q_DECL_IMPORT
|
||||
|
@@ -13,5 +13,6 @@ tomahawk_add_library(${TOMAHAWK_WIDGETS_LIBRARY_TARGET}
|
||||
SOURCES ${${TOMAHAWK_WIDGETS_LIBRARY_TARGET}_SOURCES}
|
||||
UI ${${TOMAHAWK_WIDGETS_LIBRARY_TARGET}_UI}
|
||||
EXPORT TomahawkLibraryDepends
|
||||
EXPORT_MACRO TOMAHAWK_WIDGETS_EXPORT_PRO
|
||||
VERSION ${TOMAHAWK_VERSION_SHORT}
|
||||
)
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef TOMAHAWK_WIDGETS_EXPORT
|
||||
# if defined (tomahawk_widgets_EXPORTS)
|
||||
# if defined (TOMAHAWK_WIDGETS_EXPORT_PRO)
|
||||
# define TOMAHAWK_WIDGETS_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define TOMAHAWK_WIDGETS_EXPORT Q_DECL_IMPORT
|
||||
|
@@ -120,9 +120,12 @@ ActionCollection::initActions()
|
||||
m_actionCollection[ "createPlaylist" ] = new QAction( tr( "Create Playlist" ), this );
|
||||
m_actionCollection[ "createPlaylist" ]->setShortcut( QKeySequence( "Ctrl+N" ) );
|
||||
m_actionCollection[ "createPlaylist" ]->setShortcutContext( Qt::ApplicationShortcut );
|
||||
// echonest is dead, disable stations
|
||||
/*
|
||||
m_actionCollection[ "createStation" ] = new QAction( tr( "Create Station" ), this );
|
||||
m_actionCollection[ "createStation" ]->setShortcut( QKeySequence( "Ctrl+S" ) );
|
||||
m_actionCollection[ "createStation" ]->setShortcutContext( Qt::ApplicationShortcut );
|
||||
*/
|
||||
#ifdef Q_OS_MAC
|
||||
m_actionCollection[ "minimize" ] = new QAction( tr( "Minimize" ), this );
|
||||
m_actionCollection[ "minimize" ]->setShortcut( QKeySequence( "Ctrl+M" ) );
|
||||
@@ -171,7 +174,8 @@ ActionCollection::createMenuBar( QWidget *parent )
|
||||
controlsMenu->addAction( m_actionCollection[ "showOfflineSources" ] );
|
||||
controlsMenu->addSeparator();
|
||||
controlsMenu->addAction( m_actionCollection[ "createPlaylist" ] );
|
||||
controlsMenu->addAction( m_actionCollection[ "createStation" ] );
|
||||
// echonest is dead, disable stations
|
||||
// controlsMenu->addAction( m_actionCollection[ "createStation" ] );
|
||||
controlsMenu->addAction( m_actionCollection[ "importPlaylist" ] );
|
||||
controlsMenu->addAction( m_actionCollection[ "updateCollection" ] );
|
||||
controlsMenu->addAction( m_actionCollection[ "rescanCollection" ] );
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <QReadWriteLock>
|
||||
#include <QPixmapCache>
|
||||
#include <QCoreApplication>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -75,6 +76,7 @@ Album::get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCr
|
||||
}
|
||||
|
||||
album_ptr album = album_ptr( new Album( name, artist ), &Album::deleteLater );
|
||||
album->moveToThread( QCoreApplication::instance()->thread() );
|
||||
album->setWeakRef( album.toWeakRef() );
|
||||
album->loadId( autoCreate );
|
||||
s_albumsByName.insert( key, album );
|
||||
|
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <QReadWriteLock>
|
||||
#include <QPixmapCache>
|
||||
#include <QCoreApplication>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -109,6 +110,7 @@ Artist::get( unsigned int id, const QString& name )
|
||||
}
|
||||
|
||||
artist_ptr a = artist_ptr( new Artist( id, name ), &Artist::deleteLater );
|
||||
a->moveToThread( QCoreApplication::instance()->thread() );
|
||||
a->setWeakRef( a.toWeakRef() );
|
||||
s_artistsByName.insert( key, a );
|
||||
|
||||
|
@@ -74,9 +74,6 @@ set( libGuiSources
|
||||
playlist/dynamic/DynamicPlaylist.cpp
|
||||
playlist/dynamic/DynamicView.cpp
|
||||
playlist/dynamic/DynamicModel.cpp
|
||||
playlist/dynamic/echonest/EchonestGenerator.cpp
|
||||
playlist/dynamic/echonest/EchonestControl.cpp
|
||||
playlist/dynamic/echonest/EchonestSteerer.cpp
|
||||
playlist/dynamic/widgets/DynamicWidget.cpp
|
||||
playlist/dynamic/widgets/DynamicControlWrapper.cpp
|
||||
playlist/dynamic/widgets/DynamicControlList.cpp
|
||||
@@ -146,6 +143,7 @@ set( libGuiSources
|
||||
widgets/ClickableLabel.cpp
|
||||
widgets/ComboBox.cpp
|
||||
widgets/DropDownButton.cpp
|
||||
widgets/DownloadButton.cpp
|
||||
widgets/ElidedLabel.cpp
|
||||
widgets/FilterHeader.cpp
|
||||
widgets/CaptionLabel.cpp
|
||||
@@ -207,7 +205,6 @@ list(APPEND libSources
|
||||
PlaylistInterface.cpp
|
||||
UrlHandler.cpp
|
||||
|
||||
EchonestCatalogSynchronizer.cpp
|
||||
|
||||
accounts/AccountManager.cpp
|
||||
accounts/Account.cpp
|
||||
@@ -412,7 +409,6 @@ include_directories(
|
||||
|
||||
${QT_INCLUDE_DIR}
|
||||
${QJSON_INCLUDE_DIR}
|
||||
${ECHONEST_INCLUDE_DIR}
|
||||
${LUCENEPP_INCLUDE_DIRS}
|
||||
${LIBVLC_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIR}
|
||||
@@ -534,7 +530,6 @@ TARGET_LINK_LIBRARIES( ${TOMAHAWK_LIBRARY}
|
||||
# External deps
|
||||
${QJSON_LIBRARIES}
|
||||
${LUCENEPP_LIBRARIES}
|
||||
${ECHONEST_LIBRARIES}
|
||||
${QT_QTSQL_LIBRARY}
|
||||
${QT_QTUITOOLS_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
@@ -578,7 +573,7 @@ file( GLOB networkHeaders "network/*.h" )
|
||||
file( GLOB playlistHeaders "playlist/*.h" )
|
||||
file( GLOB playlistDynamicHeaders "playlist/dynamic/*.h" )
|
||||
file( GLOB playlistDynamicDatabaseHeaders "playlist/dynamic/database/*.h" )
|
||||
file( GLOB playlistDynamicEchonestHeaders "playlist/dynamic/echonest/*.h" )
|
||||
# file( GLOB playlistDynamicEchonestHeaders "playlist/dynamic/echonest/*.h" )
|
||||
file( GLOB playlistDynamicWidgetsHeaders "playlist/dynamic/widgets/*.h" )
|
||||
file( GLOB resolversHeaders "resolvers/*.h" )
|
||||
file( GLOB sipHeaders "sip/*.h" )
|
||||
@@ -607,7 +602,7 @@ install( FILES ${networkHeaders} DESTINATION include/libtomahawk/network )
|
||||
install( FILES ${playlistHeaders} DESTINATION include/libtomahawk/playlist )
|
||||
install( FILES ${playlistDynamicHeaders} DESTINATION include/libtomahawk/playlist/dynamic )
|
||||
install( FILES ${playlistDynamicDatabaseHeaders} DESTINATION include/libtomahawk/playlist/dynamic/database )
|
||||
install( FILES ${playlistDynamicEchonestHeaders} DESTINATION include/libtomahawk/playlist/dynamic/echonest )
|
||||
# install( FILES ${playlistDynamicEchonestHeaders} DESTINATION include/libtomahawk/playlist/dynamic/echonest )
|
||||
install( FILES ${playlistDynamicWidgetsHeaders} DESTINATION include/libtomahawk/playlist/dynamic/widgets )
|
||||
install( FILES ${resolversHeaders} DESTINATION include/libtomahawk/resolvers )
|
||||
install( FILES ${sipHeaders} DESTINATION include/libtomahawk/sip )
|
||||
|
@@ -37,6 +37,9 @@
|
||||
#include "utils/ImageRegistry.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QFileInfo>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
@@ -51,7 +54,7 @@ ContextMenu::ContextMenu( QWidget* parent )
|
||||
m_sigmap = new QSignalMapper( this );
|
||||
connect( m_sigmap, SIGNAL( mapped( int ) ), SLOT( onTriggered( int ) ) );
|
||||
|
||||
m_supportedActions = ActionPlay | ActionQueue | ActionPlaylist | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage | ActionEditMetadata | ActionSend;
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +72,7 @@ ContextMenu::clear()
|
||||
m_albums.clear();
|
||||
m_artists.clear();
|
||||
|
||||
m_supportedActions = ActionPlay | ActionQueue | ActionPlaylist | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage | ActionEditMetadata | ActionSend;
|
||||
m_supportedActions = ActionPlay | ActionQueue | ActionPlaylist | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage | ActionEditMetadata | ActionSend | ActionOpenFileManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -216,10 +219,23 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
|
||||
addSeparator();
|
||||
|
||||
if ( m_supportedActions & ActionCopyLink && itemCount() == 1 )
|
||||
{
|
||||
m_sigmap->setMapping( addAction( tr( "&Copy Track Link" ) ), ActionCopyLink );
|
||||
}
|
||||
|
||||
if ( m_supportedActions & ActionOpenFileManager &&
|
||||
queries.length() == 1 &&
|
||||
queries.first()->numResults() &&
|
||||
queries.first()->results().first()->isLocal() )
|
||||
{
|
||||
m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/folder.svg" ),
|
||||
tr( "Open Folder in File Manager..." ) ), ActionOpenFileManager );
|
||||
}
|
||||
|
||||
if ( m_supportedActions & ActionEditMetadata && itemCount() == 1 )
|
||||
{
|
||||
m_sigmap->setMapping( addAction( tr( "Properties..." ) ), ActionEditMetadata );
|
||||
}
|
||||
|
||||
addSeparator();
|
||||
|
||||
@@ -239,6 +255,8 @@ ContextMenu::setQueries( const QList<Tomahawk::query_ptr>& queries )
|
||||
m_sigmap->setMapping( addAction( tr( "Mark as &Listened" ) ), ActionMarkListened );
|
||||
}
|
||||
|
||||
addSeparator();
|
||||
|
||||
if ( m_supportedActions & ActionDelete )
|
||||
m_sigmap->setMapping( addAction( queries.count() > 1 ? tr( "&Remove Items" ) : tr( "&Remove Item" ) ), ActionDelete );
|
||||
|
||||
@@ -394,6 +412,15 @@ ContextMenu::onTriggered( int action )
|
||||
}
|
||||
break;
|
||||
|
||||
case ActionOpenFileManager:
|
||||
{
|
||||
result_ptr result = m_queries.first()->results().first();
|
||||
QString path = QFileInfo( result->url() ).path();
|
||||
tLog() << Q_FUNC_INFO << "open directory" << path;
|
||||
QDesktopServices::openUrl( path );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
emit triggered( action );
|
||||
}
|
||||
|
@@ -37,21 +37,22 @@ Q_OBJECT
|
||||
public:
|
||||
enum MenuActions
|
||||
{
|
||||
ActionPlay = 1,
|
||||
ActionQueue = 2,
|
||||
ActionDelete = 4,
|
||||
ActionCopyLink = 8,
|
||||
ActionLove = 16,
|
||||
ActionStopAfter = 32,
|
||||
ActionPage = 64,
|
||||
ActionTrackPage = 128,
|
||||
ActionArtistPage = 256,
|
||||
ActionAlbumPage = 512,
|
||||
ActionEditMetadata = 1024,
|
||||
ActionPlaylist = 2048,
|
||||
ActionSend = 4096,
|
||||
ActionMarkListened = 8192,
|
||||
ActionDownload = 16384
|
||||
ActionPlay = 1,
|
||||
ActionQueue = 2,
|
||||
ActionDelete = 4,
|
||||
ActionCopyLink = 8,
|
||||
ActionLove = 16,
|
||||
ActionStopAfter = 32,
|
||||
ActionPage = 64,
|
||||
ActionTrackPage = 128,
|
||||
ActionArtistPage = 256,
|
||||
ActionAlbumPage = 512,
|
||||
ActionEditMetadata = 1024,
|
||||
ActionPlaylist = 2048,
|
||||
ActionSend = 4096,
|
||||
ActionMarkListened = 8192,
|
||||
ActionDownload = 16384,
|
||||
ActionOpenFileManager = 32768
|
||||
};
|
||||
|
||||
explicit ContextMenu( QWidget* parent = 0 );
|
||||
|
@@ -118,7 +118,7 @@ DownloadJob::localFile() const
|
||||
|
||||
|
||||
QString
|
||||
DownloadJob::localPath() const
|
||||
DownloadJob::localPath( const Tomahawk::album_ptr& album )
|
||||
{
|
||||
QDir dir = TomahawkSettings::instance()->downloadsPath();
|
||||
|
||||
@@ -127,7 +127,7 @@ DownloadJob::localPath() const
|
||||
dir.mkpath( "." );
|
||||
}
|
||||
|
||||
QString path = QString( "%1/%2" ).arg( safeEncode( m_track->artist(), true ) ).arg( safeEncode( m_track->album(), true ) );
|
||||
QString path = QString( "%1/%2" ).arg( safeEncode( album->artist()->name(), true ) ).arg( safeEncode( album->name(), true ) );
|
||||
dir.mkpath( path );
|
||||
|
||||
return QString( dir.path() + "/" + path ).replace( "//", "/" );
|
||||
@@ -138,7 +138,7 @@ QUrl
|
||||
DownloadJob::prepareFilename()
|
||||
{
|
||||
QString filename = QString( "%1. %2.%3" ).arg( m_track->albumpos() ).arg( safeEncode( m_track->track() ) ).arg( m_format.extension );
|
||||
QString path = localPath();
|
||||
QString path = localPath( m_track->albumPtr() );
|
||||
QString localFile = QString( path + "/" + filename );
|
||||
|
||||
if ( !m_tryResuming )
|
||||
@@ -206,22 +206,17 @@ DownloadJob::download()
|
||||
{
|
||||
if ( m_state == Running )
|
||||
return true;
|
||||
|
||||
setState( Running );
|
||||
|
||||
if ( m_result->resolvedByCollection() )
|
||||
{
|
||||
Tomahawk::ScriptCollection* collection = qobject_cast<Tomahawk::ScriptCollection*>( m_result->resolvedByCollection().data() );
|
||||
if ( collection )
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments[ "url" ] = m_format.url;
|
||||
|
||||
// HACK: *shrug* WIP.
|
||||
Tomahawk::ScriptJob* job = collection->scriptObject()->invoke( "getStreamUrl", arguments );
|
||||
connect( job, SIGNAL( done(QVariantMap) ), SLOT( onUrlRetrieved(QVariantMap) ) );
|
||||
job->start();
|
||||
}
|
||||
if (m_result->resolvedBy() != nullptr) {
|
||||
Tomahawk::ScriptJob *job = m_result->resolvedBy()->getDownloadUrl( m_result, m_format );
|
||||
connect( job, SIGNAL( done(QVariantMap) ), SLOT( onUrlRetrieved(QVariantMap) ) );
|
||||
job->start();
|
||||
} else {
|
||||
onUrlRetrieved({{"url", m_format.url}});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -444,7 +439,7 @@ DownloadJob::checkForResumedFile()
|
||||
|
||||
|
||||
QString
|
||||
DownloadJob::safeEncode( const QString& filename, bool removeTrailingDots ) const
|
||||
DownloadJob::safeEncode( const QString& filename, bool removeTrailingDots )
|
||||
{
|
||||
//FIXME: make it a regexp
|
||||
QString res = QString( filename ).toLatin1().replace( "/", "_" ).replace( "\\", "_" )
|
||||
|
@@ -58,7 +58,7 @@ public:
|
||||
long receivedSize() const { return m_rcvdSize; }
|
||||
long fileSize() const { return m_fileSize; }
|
||||
|
||||
QString localPath() const;
|
||||
static QString localPath( const Tomahawk::album_ptr& album );
|
||||
QString localFile() const;
|
||||
DownloadFormat format() const;
|
||||
|
||||
@@ -90,7 +90,7 @@ private slots:
|
||||
|
||||
private:
|
||||
void storeState();
|
||||
QString safeEncode( const QString& filename, bool removeTrailingDots = false ) const;
|
||||
static QString safeEncode( const QString& filename, bool removeTrailingDots = false );
|
||||
bool checkForResumedFile();
|
||||
QUrl prepareFilename();
|
||||
|
||||
|
@@ -24,6 +24,8 @@
|
||||
#include "TomahawkSettings.h"
|
||||
#include "infosystem/InfoSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "Result.h"
|
||||
#include "Query.h"
|
||||
|
||||
DownloadManager* DownloadManager::s_instance = 0;
|
||||
|
||||
@@ -85,6 +87,36 @@ DownloadManager::localFileForDownload( const QString& url ) const
|
||||
}
|
||||
|
||||
|
||||
QUrl
|
||||
DownloadManager::localUrlForDownload( const Tomahawk::query_ptr& query ) const
|
||||
{
|
||||
Tomahawk::result_ptr result = query->numResults( true ) ? query->results().first() : Tomahawk::result_ptr();
|
||||
if ( result )
|
||||
{
|
||||
return localUrlForDownload( result );
|
||||
}
|
||||
|
||||
return QUrl();
|
||||
}
|
||||
|
||||
|
||||
QUrl
|
||||
DownloadManager::localUrlForDownload( const Tomahawk::result_ptr& result ) const
|
||||
{
|
||||
if ( result && !result->downloadFormats().isEmpty() &&
|
||||
!localFileForDownload( result->downloadFormats().first().url.toString() ).isEmpty() )
|
||||
{
|
||||
return QUrl::fromLocalFile( QFileInfo( DownloadManager::instance()->localFileForDownload( result->downloadFormats().first().url.toString() ) ).absolutePath() );
|
||||
}
|
||||
else if ( result && result->downloadJob() && result->downloadJob()->state() == DownloadJob::Finished )
|
||||
{
|
||||
return QUrl::fromLocalFile( QFileInfo( result->downloadJob()->localFile() ).absolutePath() );
|
||||
}
|
||||
|
||||
return QUrl();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DownloadManager::storeJobs( const QList<downloadjob_ptr>& jobs )
|
||||
{
|
||||
|
@@ -45,6 +45,8 @@ public:
|
||||
|
||||
void storeJobs( const QList<downloadjob_ptr>& jobs );
|
||||
QString localFileForDownload( const QString& url ) const;
|
||||
QUrl localUrlForDownload( const Tomahawk::result_ptr& result ) const;
|
||||
QUrl localUrlForDownload( const Tomahawk::query_ptr& query ) const;
|
||||
|
||||
public slots:
|
||||
bool addJob( const downloadjob_ptr& job );
|
||||
|
@@ -980,7 +980,7 @@ DropJob::removeRemoteSources()
|
||||
|
||||
foreach ( const Tomahawk::result_ptr& result, item->results() )
|
||||
{
|
||||
if ( !result->resolvedByCollection().isNull() && !result->resolvedByCollection()->isLocal() )
|
||||
if ( !result->isLocal() )
|
||||
{
|
||||
list.append( item );
|
||||
break;
|
||||
|
@@ -1,14 +1,14 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright (C) 2011, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright (C) 2011-2014, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright (C) 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
* Copyright (C) 2013, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2011-2016, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
@@ -20,7 +20,6 @@
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "GlobalActionManager.h"
|
||||
|
||||
#include "accounts/AccountManager.h"
|
||||
@@ -47,12 +46,6 @@
|
||||
#include "TomahawkSettings.h"
|
||||
#include "ViewManager.h"
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
#include <echonest5/Playlist.h>
|
||||
#else
|
||||
#include <echonest/Playlist.h>
|
||||
#endif
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QFileInfo>
|
||||
|
||||
@@ -913,144 +906,144 @@ GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistRadioType ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistRadioType ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first == "artist_limitto" )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Artist" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistType ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistType ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first == "description" )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Artist Description" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistDescriptionType ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistDescriptionType ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first == "variety" )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Variety" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Variety ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Variety ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "tempo" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Tempo" );
|
||||
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinTempo + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinTempo + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "duration" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Duration" );
|
||||
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinDuration + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinDuration + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "loudness" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Loudness" );
|
||||
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinLoudness + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinLoudness + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "danceability" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Danceability" );
|
||||
int extra = param.first.endsWith( "_max" ) ? 1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinDanceability + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinDanceability + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "energy" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Energy" );
|
||||
int extra = param.first.endsWith( "_max" ) ? 1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinEnergy + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::MinEnergy + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "artist_familiarity" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Artist Familiarity" );
|
||||
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinFamiliarity + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinFamiliarity + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "artist_hotttnesss" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Artist Hotttnesss" );
|
||||
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinHotttnesss + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinHotttnesss + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "song_hotttnesss" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Song Hotttnesss" );
|
||||
int extra = param.first.endsWith( "_max" ) ? -1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::SongMinHotttnesss + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::SongMinHotttnesss + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "longitude" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Longitude" );
|
||||
int extra = param.first.endsWith( "_max" ) ? 1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinLongitude + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinLongitude + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first.startsWith( "latitude" ) )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Latitude" );
|
||||
int extra = param.first.endsWith( "_max" ) ? 1 : 0;
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinLatitude + extra ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::ArtistMinLatitude + extra ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first == "key" )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Key" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Key ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Key ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first == "mode" )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Mode" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Mode ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Mode ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first == "mood" )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Mood" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Mood ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Mood ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first == "style" )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Style" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Style ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::Style ) );
|
||||
// controls << c;
|
||||
}
|
||||
else if ( param.first == "song" )
|
||||
{
|
||||
dyncontrol_ptr c = pl->generator()->createControl( "Song" );
|
||||
c->setInput( param.second );
|
||||
c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::SongRadioType ) );
|
||||
controls << c;
|
||||
// c->setMatch( QString::number( (int)Echonest::DynamicPlaylist::SongRadioType ) );
|
||||
// controls << c;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2011-2016, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLOBALACTIONMANAGER_H
|
||||
#define GLOBALACTIONMANAGER_H
|
||||
|
@@ -36,7 +36,7 @@
|
||||
#define MAX_CONCURRENT_QUERIES 16
|
||||
#define CLEANUP_TIMEOUT 5 * 60 * 1000
|
||||
#define MINSCORE 0.5
|
||||
#define DEFAULT_RESOLVER_TIMEOUT 5000 //5 seconds
|
||||
#define DEFAULT_RESOLVER_TIMEOUT 5000 // 5 seconds
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -542,12 +542,12 @@ Pipeline::shuntNext()
|
||||
q->setCurrentResolver( 0 );
|
||||
}
|
||||
|
||||
//Zero-patient, a stub so that query is not resolved until we go through
|
||||
//all resolvers
|
||||
//As query considered as 'finished trying to resolve' when there are no
|
||||
//more qid entries in qidsState we'll put one as sort of 'keep this until
|
||||
//we kick off all our resolvers' entry
|
||||
//once we kick off all resolvers we'll remove this entry
|
||||
// Zero-patient, a stub so that query is not resolved until we go through
|
||||
// all resolvers
|
||||
// As query considered as 'finished trying to resolve' when there are no
|
||||
// more qid entries in qidsState we'll put one as sort of 'keep this until
|
||||
// we kick off all our resolvers' entry
|
||||
// once we kick off all resolvers we'll remove this entry
|
||||
incQIDState( q, nullptr );
|
||||
checkQIDState( q );
|
||||
}
|
||||
@@ -673,7 +673,7 @@ Pipeline::decQIDState( const Tomahawk::query_ptr& query, Tomahawk::Resolver* r )
|
||||
{
|
||||
{
|
||||
QMutexLocker lock( &d->mut );
|
||||
d->qidsState.remove( query->id(), r );//Removes all matching pairs
|
||||
d->qidsState.remove( query->id(), r ); // Removes all matching pairs
|
||||
}
|
||||
|
||||
checkQIDState( query );
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <QtAlgorithms>
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -47,6 +48,7 @@ Query::get( const QString& artist, const QString& track, const QString& album, c
|
||||
autoResolve = false;
|
||||
|
||||
query_ptr q = query_ptr( new Query( Track::get( artist, track, album ), qid, autoResolve ), &QObject::deleteLater );
|
||||
q->moveToThread( QCoreApplication::instance()->thread() );
|
||||
q->setWeakRef( q.toWeakRef() );
|
||||
|
||||
if ( autoResolve )
|
||||
@@ -192,7 +194,7 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults )
|
||||
}*/
|
||||
|
||||
d->results << newresults;
|
||||
qStableSort( d->results.begin(), d->results.end(), std::bind( &Query::resultSorter, this, std::placeholders::_1, std::placeholders::_2 ) );
|
||||
sortResults();
|
||||
|
||||
// hook up signals, and check solved status
|
||||
foreach( const result_ptr& rp, newresults )
|
||||
@@ -256,7 +258,7 @@ Query::onResultStatusChanged()
|
||||
Q_D( Query );
|
||||
QMutexLocker lock( &d->mutex );
|
||||
if ( !d->results.isEmpty() )
|
||||
qStableSort( d->results.begin(), d->results.end(), std::bind( &Query::resultSorter, this, std::placeholders::_1, std::placeholders::_2 ) );
|
||||
sortResults();
|
||||
}
|
||||
|
||||
checkResults();
|
||||
@@ -271,6 +273,11 @@ Query::removeResult( const Tomahawk::result_ptr& result )
|
||||
Q_D( Query );
|
||||
QMutexLocker lock( &d->mutex );
|
||||
d->results.removeAll( result );
|
||||
if ( d->preferredResult == result )
|
||||
{
|
||||
d->preferredResult.clear();
|
||||
}
|
||||
sortResults();
|
||||
}
|
||||
|
||||
emit resultsRemoved( result );
|
||||
@@ -394,12 +401,21 @@ Query::id() const
|
||||
bool
|
||||
Query::resultSorter( const result_ptr& left, const result_ptr& right )
|
||||
{
|
||||
Q_D( Query );
|
||||
if ( !d->preferredResult.isNull() )
|
||||
{
|
||||
if ( d->preferredResult == left )
|
||||
return true;
|
||||
if ( d->preferredResult == right )
|
||||
return false;
|
||||
}
|
||||
|
||||
const float ls = left->isOnline() ? howSimilar( left ) : 0.0;
|
||||
const float rs = right->isOnline() ? howSimilar( right ) : 0.0;
|
||||
|
||||
if ( ls == rs )
|
||||
{
|
||||
if ( right->resolvedByCollection() && right->resolvedByCollection()->isLocal() )
|
||||
if ( right->isLocal() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -425,6 +441,30 @@ Query::resultSorter( const result_ptr& left, const result_ptr& right )
|
||||
}
|
||||
|
||||
|
||||
result_ptr
|
||||
Query::preferredResult() const
|
||||
{
|
||||
Q_D( const Query );
|
||||
return d->preferredResult;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Query::setPreferredResult( const result_ptr& result )
|
||||
{
|
||||
{
|
||||
Q_D( Query );
|
||||
QMutexLocker lock( &d->mutex );
|
||||
|
||||
Q_ASSERT( d->results.contains( result ) );
|
||||
d->preferredResult = result;
|
||||
sortResults();
|
||||
}
|
||||
|
||||
emit resultsChanged();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Query::setCurrentResolver( Tomahawk::Resolver* resolver )
|
||||
{
|
||||
@@ -620,6 +660,10 @@ float
|
||||
Query::howSimilar( const Tomahawk::result_ptr& r )
|
||||
{
|
||||
Q_D( Query );
|
||||
if (d->howSimilarCache.find(r->id()) != d->howSimilarCache.end())
|
||||
{
|
||||
return d->howSimilarCache[r->id()];
|
||||
}
|
||||
// result values
|
||||
const QString& rArtistname = r->track()->artistSortname();
|
||||
const QString& rAlbumname = r->track()->albumSortname();
|
||||
@@ -641,10 +685,12 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
|
||||
qTrackname = queryTrack()->trackSortname();
|
||||
}
|
||||
|
||||
static const QRegExp filterOutChars = QRegExp(QString::fromUtf8("[-`´~!@#$%^&*\\(\\)_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]"));
|
||||
|
||||
//Cleanup symbols for minor naming differences
|
||||
qArtistname.remove(QRegExp(QString::fromUtf8("[-`~!@#$%^&*()_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]")));
|
||||
qTrackname.remove(QRegExp(QString::fromUtf8("[-`~!@#$%^&*()_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]")));
|
||||
qAlbumname.remove(QRegExp(QString::fromUtf8("[-`~!@#$%^&*()_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]")));
|
||||
qArtistname.remove(filterOutChars);
|
||||
qTrackname.remove(filterOutChars);
|
||||
qAlbumname.remove(filterOutChars);
|
||||
|
||||
// normal edit distance
|
||||
const int artdist = TomahawkUtils::levenshtein( qArtistname, rArtistname );
|
||||
@@ -676,12 +722,16 @@ Query::howSimilar( const Tomahawk::result_ptr& r )
|
||||
const int mlatr = qMax( artistTrackname.length(), rArtistTrackname.length() );
|
||||
const float dcatr = (float)( mlatr - atrdist ) / mlatr;
|
||||
|
||||
return qMax( dctrk, qMax( dcatr, qMax( dcart, dcalb ) ) );
|
||||
float resultScore = qMax( dctrk, qMax( dcatr, qMax( dcart, dcalb ) ) );
|
||||
d->howSimilarCache[r->id()] = resultScore;
|
||||
return resultScore;
|
||||
}
|
||||
else
|
||||
{
|
||||
// weighted, so album match is worth less than track title
|
||||
return ( dcart * 4 + dcalb + dctrk * 5 ) / 10;
|
||||
float resultScore = ( dcart * 4 + dcalb + dctrk * 5 ) / 10;
|
||||
d->howSimilarCache[r->id()] = resultScore;
|
||||
return resultScore;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,3 +782,11 @@ Query::setWeakRef( QWeakPointer<Query> weakRef )
|
||||
Q_D( Query );
|
||||
d->ownRef = weakRef;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Query::sortResults()
|
||||
{
|
||||
Q_D( Query );
|
||||
qStableSort( d->results.begin(), d->results.end(), std::bind( &Query::resultSorter, this, std::placeholders::_1, std::placeholders::_2 ) );
|
||||
}
|
||||
|
@@ -112,6 +112,8 @@ public:
|
||||
|
||||
/// sorter for list of results
|
||||
bool resultSorter( const result_ptr& left, const result_ptr& right );
|
||||
result_ptr preferredResult() const;
|
||||
void setPreferredResult( const result_ptr& result );
|
||||
|
||||
signals:
|
||||
void resultsAdded( const QList<Tomahawk::result_ptr>& );
|
||||
@@ -158,6 +160,7 @@ private:
|
||||
void setCurrentResolver( Tomahawk::Resolver* resolver );
|
||||
void clearResults();
|
||||
void checkResults();
|
||||
void sortResults();
|
||||
};
|
||||
|
||||
} //ns
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "Query.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <map>
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
@@ -39,6 +40,7 @@ private:
|
||||
QList< Tomahawk::artist_ptr > artists;
|
||||
QList< Tomahawk::album_ptr > albums;
|
||||
QList< Tomahawk::result_ptr > results;
|
||||
Tomahawk::result_ptr preferredResult;
|
||||
|
||||
float score;
|
||||
bool solved;
|
||||
@@ -58,6 +60,8 @@ private:
|
||||
|
||||
mutable QMutex mutex;
|
||||
QWeakPointer< Tomahawk::Query > ownRef;
|
||||
|
||||
std::map<QString, float> howSimilarCache;
|
||||
};
|
||||
|
||||
} // Tomahawk
|
||||
|
@@ -35,6 +35,8 @@
|
||||
#include "Track.h"
|
||||
#include "Typedefs.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
static QHash< QString, result_wptr > s_results;
|
||||
@@ -69,6 +71,7 @@ Result::get( const QString& url, const track_ptr& track )
|
||||
}
|
||||
|
||||
result_ptr r = result_ptr( new Result( url, track ), &Result::deleteLater );
|
||||
r->moveToThread( QCoreApplication::instance()->thread() );
|
||||
r->setWeakRef( r.toWeakRef() );
|
||||
s_results.insert( url, r );
|
||||
|
||||
@@ -132,21 +135,25 @@ Result::deleteLater()
|
||||
void
|
||||
Result::onResolverRemoved( Tomahawk::Resolver* resolver )
|
||||
{
|
||||
QMutexLocker lock( &m_mutex );
|
||||
m_mutex.lock();
|
||||
|
||||
if ( m_resolver.data() == resolver )
|
||||
{
|
||||
m_resolver = 0;
|
||||
m_mutex.unlock();
|
||||
|
||||
emit statusChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
collection_ptr
|
||||
Result::resolvedByCollection() const
|
||||
{
|
||||
QMutexLocker lock( &m_mutex );
|
||||
|
||||
return m_collection;
|
||||
}
|
||||
|
||||
@@ -227,6 +234,13 @@ Result::playable() const
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Result::isLocal() const
|
||||
{
|
||||
return resolvedByCollection().isNull() ? false : resolvedByCollection()->isLocal();
|
||||
}
|
||||
|
||||
|
||||
QVariant
|
||||
Result::toVariant() const
|
||||
{
|
||||
@@ -323,11 +337,9 @@ Result::onOffline()
|
||||
|
||||
|
||||
void
|
||||
Result::setResolvedByCollection( const Tomahawk::collection_ptr& collection , bool emitOnlineEvents )
|
||||
Result::setResolvedByCollection( const Tomahawk::collection_ptr& collection, bool emitOnlineEvents )
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_collection = collection;
|
||||
m_mutex.unlock();
|
||||
|
||||
if ( emitOnlineEvents )
|
||||
{
|
||||
|
@@ -94,6 +94,12 @@ public:
|
||||
bool isOnline() const;
|
||||
bool playable() const;
|
||||
|
||||
/**
|
||||
* @brief whether this result isLocal, i.e. resolved by a local collection
|
||||
* @return isLocal
|
||||
*/
|
||||
bool isLocal() const;
|
||||
|
||||
QString url() const;
|
||||
/**
|
||||
* Has the given url been checked that it is accessible/valid.
|
||||
|
@@ -929,6 +929,20 @@ TomahawkSettings::setVolume( unsigned int volume )
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TomahawkSettings::muted() const
|
||||
{
|
||||
return value( "audio/muted" ).toBool();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkSettings::setMuted( bool muted )
|
||||
{
|
||||
setValue( "audio/muted", muted );
|
||||
}
|
||||
|
||||
|
||||
QString
|
||||
TomahawkSettings::proxyHost() const
|
||||
{
|
||||
@@ -1750,3 +1764,15 @@ TomahawkSettings::setPlaydarKey( const QByteArray& key )
|
||||
setValue( "playdar/key", key );
|
||||
}
|
||||
|
||||
QString
|
||||
TomahawkSettings::vlcArguments() const
|
||||
{
|
||||
return value( "vlc/cmdline_args" ).value< QString >();
|
||||
}
|
||||
|
||||
void
|
||||
TomahawkSettings::setVlcArguments( const QString& args )
|
||||
{
|
||||
setValue( "vlc/cmdline_args", args);
|
||||
}
|
||||
|
||||
|
@@ -107,6 +107,9 @@ public:
|
||||
unsigned int volume() const;
|
||||
void setVolume( unsigned int volume );
|
||||
|
||||
bool muted() const;
|
||||
void setMuted( bool muted );
|
||||
|
||||
/// Playlist stuff
|
||||
QByteArray playlistColumnSizes( const QString& playlistid ) const;
|
||||
void setPlaylistColumnSizes( const QString& playlistid, const QByteArray& state );
|
||||
@@ -250,6 +253,10 @@ public:
|
||||
QByteArray playdarKey() const;
|
||||
void setPlaydarKey( const QByteArray& key );
|
||||
|
||||
// VLC Settings
|
||||
QString vlcArguments() const;
|
||||
void setVlcArguments( const QString& arguments );
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
void recentlyPlayedPlaylistAdded( const QString& playlistId, int sourceId );
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include <QtAlgorithms>
|
||||
#include <QDateTime>
|
||||
#include <QReadWriteLock>
|
||||
#include <QCoreApplication>
|
||||
|
||||
|
||||
using namespace Tomahawk;
|
||||
@@ -92,6 +93,7 @@ Track::get( const QString& artist, const QString& track, const QString& album, c
|
||||
}
|
||||
|
||||
track_ptr t = track_ptr( new Track( artist, track, album, albumArtist, duration, composer, albumpos, discnumber ), &Track::deleteLater );
|
||||
t->moveToThread( QCoreApplication::instance()->thread() );
|
||||
t->setWeakRef( t.toWeakRef() );
|
||||
s_tracksByName.insert( key, t );
|
||||
|
||||
|
@@ -19,8 +19,7 @@
|
||||
|
||||
#include "TrackData.h"
|
||||
|
||||
#include <QtAlgorithms>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
|
||||
#include "audio/AudioEngine.h"
|
||||
#include "collection/Collection.h"
|
||||
@@ -41,6 +40,10 @@
|
||||
#include "PlaylistEntry.h"
|
||||
#include "SourceList.h"
|
||||
|
||||
#include <QtAlgorithms>
|
||||
#include <QReadWriteLock>
|
||||
#include <QCoreApplication>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
QHash< QString, trackdata_wptr > TrackData::s_trackDatasByName = QHash< QString, trackdata_wptr >();
|
||||
@@ -84,6 +87,7 @@ TrackData::get( unsigned int id, const QString& artist, const QString& track )
|
||||
}
|
||||
|
||||
trackdata_ptr t = trackdata_ptr( new TrackData( id, artist, track ), &TrackData::deleteLater );
|
||||
t->moveToThread( QCoreApplication::instance()->thread() );
|
||||
t->setWeakRef( t.toWeakRef() );
|
||||
s_trackDatasByName.insert( key, t );
|
||||
|
||||
|
@@ -167,7 +167,7 @@ signals:
|
||||
void connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState state );
|
||||
|
||||
void configurationChanged();
|
||||
void configTestResult( Tomahawk::Accounts::ConfigTestResultType );
|
||||
void configTestResult( int, const QString& = QString() );
|
||||
|
||||
protected:
|
||||
virtual void loadFromConfig( const QString &accountId );
|
||||
|
@@ -68,6 +68,7 @@ DelegateConfigWrapper::DelegateConfigWrapper( Tomahawk::Accounts::Account* accou
|
||||
h->setContentsMargins( m_widget->contentsMargins() );
|
||||
|
||||
m_errorLabel->setAlignment( Qt::AlignCenter );
|
||||
m_errorLabel->setWordWrap( true );
|
||||
v->addWidget( m_errorLabel );
|
||||
|
||||
v->addLayout( h );
|
||||
@@ -81,7 +82,7 @@ DelegateConfigWrapper::DelegateConfigWrapper( Tomahawk::Accounts::Account* accou
|
||||
if ( m_widget->metaObject()->indexOfSignal( "sizeHintChanged()" ) > -1 )
|
||||
connect( m_widget, SIGNAL( sizeHintChanged() ), this, SLOT( updateSizeHint() ) );
|
||||
|
||||
connect( m_account, SIGNAL( configTestResult( Tomahawk::Accounts::ConfigTestResultType ) ), SLOT( onConfigTestResult( Tomahawk::Accounts::ConfigTestResultType ) ) );
|
||||
connect( m_account, SIGNAL( configTestResult( int, const QString& ) ), SLOT( onConfigTestResult( int, const QString& ) ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -192,11 +193,11 @@ DelegateConfigWrapper::aboutClicked( bool )
|
||||
|
||||
|
||||
void
|
||||
DelegateConfigWrapper::onConfigTestResult( Tomahawk::Accounts::ConfigTestResultType result )
|
||||
DelegateConfigWrapper::onConfigTestResult( int code, const QString& message )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << result;
|
||||
tLog() << Q_FUNC_INFO << code << ": " << message;
|
||||
|
||||
if( result == Tomahawk::Accounts::ConfigTestResultSuccess )
|
||||
if( code == Tomahawk::Accounts::ConfigTestResultSuccess )
|
||||
{
|
||||
m_invalidData = QVariantMap();
|
||||
closeDialog( QDialog::Accepted );
|
||||
@@ -226,8 +227,25 @@ DelegateConfigWrapper::onConfigTestResult( Tomahawk::Accounts::ConfigTestResultT
|
||||
|
||||
m_invalidData = m_widget->readData();
|
||||
|
||||
// TODO: generate message based on status code
|
||||
m_errorLabel->setText( QString( "<font color='red'>%1</font>" ).arg( tr( "Your config is invalid." ) ) );
|
||||
QString msg = !message.isEmpty() ? message : getTestConfigMessage( code );
|
||||
m_errorLabel->setText( QString( "<font color='red'>%1</font>" ).arg( msg ) );
|
||||
}
|
||||
}
|
||||
|
||||
QString
|
||||
DelegateConfigWrapper::getTestConfigMessage( int code )
|
||||
{
|
||||
switch(code) {
|
||||
case Tomahawk::Accounts::ConfigTestResultCommunicationError:
|
||||
return tr( "Unable to authenticate. Please check your connection." );
|
||||
case Tomahawk::Accounts::ConfigTestResultInvalidCredentials:
|
||||
return tr( "Username or password incorrect." );
|
||||
case Tomahawk::Accounts::ConfigTestResultInvalidAccount:
|
||||
return tr( "Account rejected by server." );
|
||||
case Tomahawk::Accounts::ConfigTestResultPlayingElsewhere:
|
||||
return tr( "Action not allowed, account is in use elsewhere." );
|
||||
case Tomahawk::Accounts::ConfigTestResultAccountExpired:
|
||||
return tr( "Your account has expired." );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -60,10 +60,11 @@ protected:
|
||||
|
||||
private slots:
|
||||
void aboutClicked( bool );
|
||||
void onConfigTestResult( Tomahawk::Accounts::ConfigTestResultType );
|
||||
void onConfigTestResult( int, const QString& );
|
||||
|
||||
private:
|
||||
void closeDialog( QDialog::DialogCode code );
|
||||
QString getTestConfigMessage( int code );
|
||||
|
||||
Tomahawk::Accounts::Account* m_account;
|
||||
AccountConfigWidget* m_widget;
|
||||
|
@@ -542,7 +542,7 @@ ResolverAccount::testConfig()
|
||||
{
|
||||
QVariantMap data = resolver->loadDataFromWidgets();
|
||||
ScriptJob* job = resolver->scriptObject()->invoke( "testConfig", data );
|
||||
connect( job, SIGNAL( done( QVariantMap ) ), SLOT( onTestConfig( QVariantMap ) ) );
|
||||
connect( job, SIGNAL( done( QVariant ) ), SLOT( onTestConfig( QVariant ) ) );
|
||||
job->start();
|
||||
}
|
||||
else
|
||||
@@ -560,18 +560,17 @@ ResolverAccount::resolver() const
|
||||
|
||||
|
||||
void
|
||||
ResolverAccount::onTestConfig( const QVariantMap& result )
|
||||
ResolverAccount::onTestConfig( const QVariant& result )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << result;
|
||||
|
||||
int resultCode = result[ "result" ].toInt();
|
||||
if ( resultCode == 1 )
|
||||
if ( result.type() == QVariant::String )
|
||||
{
|
||||
emit configTestResult( Accounts::ConfigTestResultSuccess );
|
||||
emit configTestResult( Accounts::ConfigTestResultOther, result.toString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
emit configTestResult( Accounts::ConfigTestResultOther );
|
||||
emit configTestResult( result.toInt() );
|
||||
}
|
||||
|
||||
sender()->deleteLater();
|
||||
@@ -590,6 +589,7 @@ AtticaResolverAccount::AtticaResolverAccount( const QString& accountId )
|
||||
|
||||
}
|
||||
|
||||
|
||||
AtticaResolverAccount::AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId, const QVariantHash& initialConfiguration )
|
||||
: ResolverAccount( accountId, path, initialConfiguration )
|
||||
, m_atticaId( atticaId )
|
||||
@@ -619,8 +619,6 @@ AtticaResolverAccount::init()
|
||||
loadIcon();
|
||||
else
|
||||
connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( loadIcon() ) );
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -110,7 +110,7 @@ public:
|
||||
|
||||
private slots:
|
||||
void resolverChanged();
|
||||
void onTestConfig( const QVariantMap& result );
|
||||
void onTestConfig( const QVariant& result );
|
||||
|
||||
protected:
|
||||
// Created by factory, when user installs a new resolver
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2016, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
|
||||
* Copyright 2013, Teo Mrnjavac <teo@kde.org>
|
||||
*
|
||||
@@ -165,12 +165,19 @@ AudioEngine::AudioEngine()
|
||||
d->s_instance = this;
|
||||
tDebug() << "Init AudioEngine";
|
||||
|
||||
d->audioOutput = new AudioOutput(this);
|
||||
d->audioOutput = new AudioOutput( this );
|
||||
|
||||
connect( d->audioOutput, SIGNAL( initialized() ), this, SIGNAL( initialized() ) );
|
||||
connect( d->audioOutput, SIGNAL( stateChanged( AudioOutput::AudioState, AudioOutput::AudioState ) ), d_func(), SLOT( onStateChanged( AudioOutput::AudioState, AudioOutput::AudioState ) ) );
|
||||
connect( d->audioOutput, SIGNAL( tick( qint64 ) ), SLOT( timerTriggered( qint64 ) ) );
|
||||
connect( d->audioOutput, SIGNAL( positionChanged( float ) ), SLOT( onPositionChanged( float ) ) );
|
||||
connect( d->audioOutput, SIGNAL( volumeChanged( qreal ) ), SLOT( onVolumeChanged( qreal ) ) );
|
||||
connect( d->audioOutput, SIGNAL( mutedChanged( bool ) ), SIGNAL( mutedChanged( bool ) ) );
|
||||
|
||||
if ( TomahawkSettings::instance()->muted() )
|
||||
{
|
||||
mute();
|
||||
}
|
||||
setVolume( TomahawkSettings::instance()->volume() );
|
||||
|
||||
qRegisterMetaType< AudioErrorCode >("AudioErrorCode");
|
||||
@@ -183,6 +190,7 @@ AudioEngine::~AudioEngine()
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
TomahawkSettings::instance()->setVolume( volume() );
|
||||
TomahawkSettings::instance()->setMuted( isMuted() );
|
||||
|
||||
delete d_ptr;
|
||||
}
|
||||
@@ -289,8 +297,11 @@ AudioEngine::stop( AudioErrorCode errorCode )
|
||||
if ( d->waitingOnNewTrack )
|
||||
sendWaitingNotification();
|
||||
|
||||
Tomahawk::InfoSystem::InfoPushData pushData( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowStopped, QVariant(), Tomahawk::InfoSystem::PushNoFlag );
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData );
|
||||
if ( d->audioOutput->isInitialized() )
|
||||
{
|
||||
Tomahawk::InfoSystem::InfoPushData pushData( s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowStopped, QVariant(), Tomahawk::InfoSystem::PushNoFlag );
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -455,6 +466,8 @@ AudioEngine::mute()
|
||||
{
|
||||
Q_D( AudioEngine );
|
||||
d->audioOutput->setMuted( true );
|
||||
|
||||
emit volumeChanged( volume() );
|
||||
}
|
||||
|
||||
|
||||
@@ -463,6 +476,8 @@ AudioEngine::toggleMute()
|
||||
{
|
||||
Q_D( AudioEngine );
|
||||
d->audioOutput->setMuted( !d->audioOutput->isMuted() );
|
||||
|
||||
emit volumeChanged( volume() );
|
||||
}
|
||||
|
||||
|
||||
@@ -557,10 +572,16 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type )
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
||||
AudioEngine::loadTrack( const Tomahawk::result_ptr& result, bool preload )
|
||||
{
|
||||
Q_D( AudioEngine );
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() );
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() ) << " preload:" << preload;
|
||||
|
||||
|
||||
if ( !d->audioOutput->isInitialized() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
@@ -568,36 +589,82 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
||||
return;
|
||||
}
|
||||
|
||||
// We do this to stop the audio as soon as a user activated another track
|
||||
// If we don't block the audioOutput signals, the state change will trigger
|
||||
// loading yet another track
|
||||
d->audioOutput->blockSignals( true );
|
||||
d->audioOutput->stop();
|
||||
d->audioOutput->blockSignals( false );
|
||||
if (preload && d->preloadedTrack == result)
|
||||
return;
|
||||
|
||||
setCurrentTrack( result );
|
||||
if (preload)
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO << "not preloaded yet, preloading";
|
||||
|
||||
if (preload)
|
||||
{
|
||||
setPreloadTrack( result );
|
||||
}
|
||||
else
|
||||
{
|
||||
// We do this to stop the audio as soon as a user activated another track
|
||||
// If we don't block the audioOutput signals, the state change will trigger
|
||||
// loading yet another track
|
||||
d->audioOutput->blockSignals( true );
|
||||
d->audioOutput->stop();
|
||||
d->audioOutput->blockSignals( false );
|
||||
|
||||
setCurrentTrack( result );
|
||||
if ( result == d->preloadedTrack )
|
||||
{
|
||||
setPreloadTrack( Tomahawk::result_ptr(nullptr) );
|
||||
d->state = Loading;
|
||||
emit loading( d->currentTrack );
|
||||
d->audioOutput->switchToPreloadedMedia();
|
||||
if ( !d->input.isNull() )
|
||||
{
|
||||
d->input->close();
|
||||
d->input.clear();
|
||||
}
|
||||
d->input = d->inputPreloaded;
|
||||
|
||||
d->audioOutput->play();
|
||||
|
||||
if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate )
|
||||
{
|
||||
d->currentTrack->track()->startPlaying();
|
||||
}
|
||||
|
||||
sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowPlaying );
|
||||
return;
|
||||
}
|
||||
setPreloadTrack( Tomahawk::result_ptr(nullptr) );
|
||||
}
|
||||
|
||||
ScriptJob* job = result->resolvedBy()->getStreamUrl( result );
|
||||
connect( job, SIGNAL( done( QVariantMap ) ), SLOT( gotStreamUrl( QVariantMap ) ) );
|
||||
job->setProperty( "result", QVariant::fromValue( result ) );
|
||||
job->setProperty( "isPreload", QVariant::fromValue(preload) );
|
||||
tDebug() << "preload:" << preload << ", for result:" << result;
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::gotStreamUrl( const QVariantMap& data )
|
||||
{
|
||||
QString streamUrl = data[ "url" ].toString();
|
||||
QVariantMap headers = data[ "headers" ].toMap();
|
||||
Tomahawk::result_ptr result = sender()->property( "result" ).value<result_ptr>();
|
||||
bool isPreload = sender()->property( "isPreload" ).value<bool>();
|
||||
|
||||
if ( streamUrl.isEmpty() || !( TomahawkUtils::isHttpResult( streamUrl ) || TomahawkUtils::isHttpsResult( streamUrl ) || TomahawkUtils::isRtmpResult( streamUrl ) ) )
|
||||
tDebug() << Q_FUNC_INFO << " is preload:" << isPreload << ", for result:" << result;
|
||||
|
||||
if ( streamUrl.isEmpty() || headers.isEmpty() ||
|
||||
!( TomahawkUtils::isHttpResult( streamUrl ) || TomahawkUtils::isHttpsResult( streamUrl ) ) )
|
||||
{
|
||||
// Not an http(s) or RTMP URL, get IO device
|
||||
// We can't supply custom headers to VLC - but prefer using its HTTP streaming due to improved seeking ability
|
||||
// Not an RTMP or HTTP-with-headers URL, get IO device
|
||||
QSharedPointer< QIODevice > sp;
|
||||
performLoadIODevice( result, streamUrl );
|
||||
performLoadIODevice( result, streamUrl, isPreload );
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need our own QIODevice for streaming
|
||||
// TODO: just make this part of the http(s) IoDeviceFactory (?)
|
||||
QUrl url = QUrl::fromEncoded( streamUrl.toUtf8() );
|
||||
QNetworkRequest req( url );
|
||||
@@ -619,35 +686,42 @@ AudioEngine::gotStreamUrl( const QVariantMap& data )
|
||||
|
||||
tDebug() << "Creating a QNetworkReply with url:" << req.url().toString();
|
||||
NetworkReply* reply = new NetworkReply( Tomahawk::Utils::nam()->get( req ) );
|
||||
NewClosure( reply, SIGNAL( finalUrlReached() ), this, SLOT( gotRedirectedStreamUrl( Tomahawk::result_ptr, NetworkReply* )), result, reply );
|
||||
NewClosure( reply, SIGNAL( finalUrlReached() ), this, SLOT( gotRedirectedStreamUrl( Tomahawk::result_ptr, NetworkReply* ) ), result, reply );
|
||||
}
|
||||
|
||||
sender()->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::gotRedirectedStreamUrl( const Tomahawk::result_ptr& result, NetworkReply* reply )
|
||||
{
|
||||
Q_D( AudioEngine );
|
||||
// std::functions cannot accept temporaries as parameters
|
||||
QSharedPointer< QIODevice > sp ( reply->reply(), &QObject::deleteLater );
|
||||
QString url = reply->reply()->url().toString();
|
||||
reply->disconnectFromReply();
|
||||
reply->deleteLater();
|
||||
|
||||
performLoadTrack( result, url, sp );
|
||||
bool isPreload = result == d->preloadedTrack;
|
||||
tDebug() << Q_FUNC_INFO << " is preload:" << isPreload;
|
||||
|
||||
performLoadTrack( result, url, sp, isPreload );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::onPositionChanged( float new_position )
|
||||
{
|
||||
if ( new_position >= 0.90 )
|
||||
loadNextTrack(true);
|
||||
// tDebug() << Q_FUNC_INFO << new_position << state();
|
||||
emit trackPosition( new_position );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::performLoadIODevice( const result_ptr& result, const QString& url )
|
||||
AudioEngine::performLoadIODevice( const result_ptr& result, const QString& url, bool preload )
|
||||
{
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : url );
|
||||
|
||||
@@ -657,37 +731,39 @@ AudioEngine::performLoadIODevice( const result_ptr& result, const QString& url )
|
||||
std::function< void ( const QString, QSharedPointer< QIODevice > ) > callback =
|
||||
std::bind( &AudioEngine::performLoadTrack, this, result,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2 );
|
||||
std::placeholders::_2,
|
||||
preload );
|
||||
Tomahawk::UrlHandler::getIODeviceForUrl( result, url, callback );
|
||||
}
|
||||
else
|
||||
{
|
||||
QSharedPointer< QIODevice > io;
|
||||
performLoadTrack( result, url, io );
|
||||
performLoadTrack( result, url, io, preload );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io )
|
||||
AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io, bool preload )
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "performLoadTrack", Qt::QueuedConnection,
|
||||
Q_ARG( const Tomahawk::result_ptr, result ),
|
||||
Q_ARG( const QString, url ),
|
||||
Q_ARG( QSharedPointer< QIODevice >, io )
|
||||
Q_ARG( QSharedPointer< QIODevice >, io ),
|
||||
Q_ARG( bool, preload )
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Q_D( AudioEngine );
|
||||
if ( currentTrack() != result )
|
||||
if ( !preload && currentTrack() != result )
|
||||
{
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Track loaded too late, skip.";
|
||||
return;
|
||||
}
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() );
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() ) << preload;
|
||||
QSharedPointer< QIODevice > ioToKeep = io;
|
||||
|
||||
bool err = false;
|
||||
@@ -701,9 +777,16 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
|
||||
|
||||
if ( !err )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Starting new song:" << url;
|
||||
d->state = Loading;
|
||||
emit loading( d->currentTrack );
|
||||
if (preload)
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Preloading new song:" << url;
|
||||
}
|
||||
else
|
||||
{
|
||||
tLog() << Q_FUNC_INFO << "Starting new song:" << url;
|
||||
d->state = Loading;
|
||||
emit loading( d->currentTrack );
|
||||
}
|
||||
|
||||
if ( !TomahawkUtils::isLocalResult( url )
|
||||
&& !( TomahawkUtils::isHttpResult( url ) && io.isNull() )
|
||||
@@ -712,18 +795,18 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
|
||||
QSharedPointer<QNetworkReply> qnr = io.objectCast<QNetworkReply>();
|
||||
if ( !qnr.isNull() )
|
||||
{
|
||||
d->audioOutput->setCurrentSource( new QNR_IODeviceStream( qnr, this ) );
|
||||
d->audioOutput->setCurrentSource( new QNR_IODeviceStream( qnr, this ), preload );
|
||||
// We keep track of the QNetworkReply in QNR_IODeviceStream
|
||||
// and AudioOutput handles the deletion of the
|
||||
// QNR_IODeviceStream object
|
||||
ioToKeep.clear();
|
||||
d->audioOutput->setAutoDelete( true );
|
||||
d->audioOutput->setAutoDelete( true, preload );
|
||||
}
|
||||
else
|
||||
{
|
||||
d->audioOutput->setCurrentSource( io.data() );
|
||||
d->audioOutput->setCurrentSource( io.data(), preload);
|
||||
// We handle the deletion via tracking in d->input
|
||||
d->audioOutput->setAutoDelete( false );
|
||||
d->audioOutput->setAutoDelete( false, preload);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -742,7 +825,7 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
|
||||
}
|
||||
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Passing to VLC:" << furl;
|
||||
d->audioOutput->setCurrentSource( furl );
|
||||
d->audioOutput->setCurrentSource( furl, preload );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -751,26 +834,37 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
|
||||
furl = furl.right( furl.length() - 7 );
|
||||
|
||||
tLog( LOGVERBOSE ) << Q_FUNC_INFO << "Passing to VLC:" << QUrl::fromLocalFile( furl );
|
||||
d->audioOutput->setCurrentSource( QUrl::fromLocalFile( furl ) );
|
||||
d->audioOutput->setCurrentSource( QUrl::fromLocalFile( furl ), preload );
|
||||
}
|
||||
|
||||
d->audioOutput->setAutoDelete( true );
|
||||
d->audioOutput->setAutoDelete( true, preload );
|
||||
}
|
||||
|
||||
if ( !d->input.isNull() )
|
||||
if ( preload ) {
|
||||
if ( !d->inputPreloaded.isNull() )
|
||||
{
|
||||
d->inputPreloaded->close();
|
||||
d->inputPreloaded.clear();
|
||||
}
|
||||
d->inputPreloaded = ioToKeep;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->input->close();
|
||||
d->input.clear();
|
||||
}
|
||||
d->input = ioToKeep;
|
||||
d->audioOutput->play();
|
||||
if ( !d->input.isNull() )
|
||||
{
|
||||
d->input->close();
|
||||
d->input.clear();
|
||||
}
|
||||
d->input = ioToKeep;
|
||||
d->audioOutput->play();
|
||||
|
||||
if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate )
|
||||
{
|
||||
d->currentTrack->track()->startPlaying();
|
||||
}
|
||||
if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate )
|
||||
{
|
||||
d->currentTrack->track()->startPlaying();
|
||||
}
|
||||
|
||||
sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowPlaying );
|
||||
sendNowPlayingNotification( Tomahawk::InfoSystem::InfoNowPlaying );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,7 +874,10 @@ AudioEngine::performLoadTrack( const Tomahawk::result_ptr result, const QString&
|
||||
return;
|
||||
}
|
||||
|
||||
d->waitingOnNewTrack = false;
|
||||
if ( !preload )
|
||||
{
|
||||
d->waitingOnNewTrack = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -812,18 +909,19 @@ AudioEngine::loadPreviousTrack()
|
||||
}
|
||||
|
||||
if ( result )
|
||||
loadTrack( result );
|
||||
loadTrack( result, false );
|
||||
else
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::loadNextTrack()
|
||||
AudioEngine::loadNextTrack( bool preload )
|
||||
{
|
||||
if ( QThread::currentThread() != thread() )
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "loadNextTrack", Qt::QueuedConnection );
|
||||
QMetaObject::invokeMethod( this, "loadNextTrack", Qt::QueuedConnection,
|
||||
Q_ARG( bool, preload ));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -837,8 +935,11 @@ AudioEngine::loadNextTrack()
|
||||
{
|
||||
if ( d->stopAfterTrack->track()->equals( d->currentTrack->track() ) )
|
||||
{
|
||||
d->stopAfterTrack.clear();
|
||||
stop();
|
||||
if ( !preload )
|
||||
{
|
||||
d->stopAfterTrack.clear();
|
||||
stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -856,17 +957,24 @@ AudioEngine::loadNextTrack()
|
||||
|
||||
if ( d->playlist.data()->nextResult() )
|
||||
{
|
||||
result = d->playlist.data()->setSiblingResult( 1 );
|
||||
setCurrentTrackPlaylist( d->playlist );
|
||||
if ( preload )
|
||||
{
|
||||
result = d->playlist.data()->nextResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = d->playlist.data()->setSiblingResult( 1 );
|
||||
setCurrentTrackPlaylist( d->playlist );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( result )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Got next item, loading track";
|
||||
loadTrack( result );
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Got next item, loading track, preload:" << preload;
|
||||
loadTrack( result, preload );
|
||||
}
|
||||
else
|
||||
else if ( !preload )
|
||||
{
|
||||
if ( !d->playlist.isNull() && d->playlist.data()->retryMode() == Tomahawk::PlaylistModes::Retry )
|
||||
d->waitingOnNewTrack = true;
|
||||
@@ -935,7 +1043,7 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk:
|
||||
|
||||
if ( result )
|
||||
{
|
||||
loadTrack( result );
|
||||
loadTrack( result, false );
|
||||
}
|
||||
else if ( !d->playlist.isNull() && d->playlist.data()->retryMode() == PlaylistModes::Retry )
|
||||
{
|
||||
@@ -951,9 +1059,9 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk:
|
||||
void
|
||||
AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::query_ptr& query )
|
||||
{
|
||||
if ( query->resolvingFinished() )
|
||||
if ( query->resolvingFinished() || query->numResults( true ) )
|
||||
{
|
||||
if ( query->numResults() && query->results().first()->isOnline() )
|
||||
if ( query->numResults( true ) )
|
||||
{
|
||||
playItem( playlist, query->results().first(), query );
|
||||
return;
|
||||
@@ -969,7 +1077,7 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk:
|
||||
{
|
||||
Pipeline::instance()->resolve( query );
|
||||
|
||||
NewClosure( query.data(), SIGNAL( resolvingFinished( bool ) ),
|
||||
NewClosure( query.data(), SIGNAL( resultsChanged() ),
|
||||
const_cast<AudioEngine*>(this), SLOT( playItem( Tomahawk::playlistinterface_ptr, Tomahawk::query_ptr ) ), playlist, query );
|
||||
}
|
||||
}
|
||||
@@ -1210,6 +1318,14 @@ AudioEngine::setStopAfterTrack( const query_ptr& query )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::setPreloadTrack( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
Q_D( AudioEngine );
|
||||
|
||||
d->preloadedTrack = result;
|
||||
}
|
||||
|
||||
void
|
||||
AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
@@ -1236,7 +1352,6 @@ AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::setState( AudioState state )
|
||||
{
|
||||
|
@@ -135,10 +135,10 @@ public slots:
|
||||
void toggleMute();
|
||||
|
||||
void play( const QUrl& url );
|
||||
void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::result_ptr& result, const Tomahawk::query_ptr& fromQuery = Tomahawk::query_ptr() );
|
||||
void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::query_ptr& query );
|
||||
void playItem( const Tomahawk::artist_ptr& artist );
|
||||
void playItem( const Tomahawk::album_ptr& album );
|
||||
void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::result_ptr& result, const Tomahawk::query_ptr& fromQuery = Tomahawk::query_ptr());
|
||||
void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::query_ptr& query);
|
||||
void playItem( const Tomahawk::artist_ptr& artist);
|
||||
void playItem( const Tomahawk::album_ptr& album);
|
||||
void playPlaylistInterface( const Tomahawk::playlistinterface_ptr& playlist );
|
||||
void setPlaylist( Tomahawk::playlistinterface_ptr playlist );
|
||||
void setQueue( const Tomahawk::playlistinterface_ptr& queue );
|
||||
@@ -149,6 +149,8 @@ public slots:
|
||||
void setShuffled( bool enabled );
|
||||
|
||||
signals:
|
||||
void initialized();
|
||||
|
||||
void loading( const Tomahawk::result_ptr track );
|
||||
void started( const Tomahawk::result_ptr track );
|
||||
void finished( const Tomahawk::result_ptr track );
|
||||
@@ -180,21 +182,22 @@ signals:
|
||||
void error( AudioEngine::AudioErrorCode errorCode );
|
||||
|
||||
private slots:
|
||||
void loadTrack( const Tomahawk::result_ptr& result ); //async!
|
||||
void loadTrack( const Tomahawk::result_ptr& result, bool preload ); //async!
|
||||
void gotStreamUrl( const QVariantMap& data );
|
||||
void gotRedirectedStreamUrl( const Tomahawk::result_ptr& result, NetworkReply* reply );
|
||||
|
||||
|
||||
void performLoadIODevice( const Tomahawk::result_ptr& result, const QString& url ); //only call from loadTrack kthxbi
|
||||
void performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io ); //only call from loadTrack or performLoadIODevice kthxbi
|
||||
void performLoadIODevice( const Tomahawk::result_ptr& result, const QString& url, bool preload ); //only call from loadTrack kthxbi
|
||||
void performLoadTrack( const Tomahawk::result_ptr result, const QString& url, QSharedPointer< QIODevice > io, bool preload ); //only call from loadTrack or performLoadIODevice kthxbi
|
||||
void loadPreviousTrack();
|
||||
void loadNextTrack();
|
||||
void loadNextTrack(bool preload = false);
|
||||
|
||||
void onVolumeChanged( qreal volume );
|
||||
void timerTriggered( qint64 time );
|
||||
void onPositionChanged( float new_position );
|
||||
|
||||
void setCurrentTrack( const Tomahawk::result_ptr& result );
|
||||
void setPreloadTrack( const Tomahawk::result_ptr& result );
|
||||
void onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type );
|
||||
void onPlaylistNextTrackAvailable();
|
||||
|
||||
|
@@ -28,9 +28,11 @@ public slots:
|
||||
|
||||
private:
|
||||
QSharedPointer<QIODevice> input;
|
||||
QSharedPointer<QIODevice> inputPreloaded;
|
||||
|
||||
Tomahawk::query_ptr stopAfterTrack;
|
||||
Tomahawk::result_ptr currentTrack;
|
||||
Tomahawk::result_ptr preloadedTrack;
|
||||
Tomahawk::playlistinterface_ptr playlist;
|
||||
Tomahawk::playlistinterface_ptr currentTrackPlaylist;
|
||||
Tomahawk::playlistinterface_ptr queue;
|
||||
|
@@ -22,21 +22,26 @@
|
||||
#include "AudioEngine.h"
|
||||
#include "AudioOutput.h"
|
||||
#include "TomahawkVersion.h"
|
||||
#include "TomahawkSettings.h"
|
||||
|
||||
#include "audio/MediaStream.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QVarLengthArray>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
|
||||
#include <vlc/libvlc.h>
|
||||
#include <vlc/libvlc_media.h>
|
||||
#include <vlc/libvlc_media_player.h>
|
||||
#include <vlc/libvlc_events.h>
|
||||
#include <vlc/libvlc_media_player.h>
|
||||
#include <vlc/libvlc_version.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
AudioOutput* AudioOutput::s_instance = 0;
|
||||
|
||||
|
||||
@@ -51,17 +56,22 @@ AudioOutput::AudioOutput( QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_currentState( Stopped )
|
||||
, m_currentStream( nullptr )
|
||||
, m_preloadedStream( nullptr )
|
||||
, m_seekable( true )
|
||||
, m_muted( false )
|
||||
, m_autoDelete( true )
|
||||
, m_preloadedAutoDelete( true )
|
||||
, m_volume( 1.0 )
|
||||
, m_currentTime( 0 )
|
||||
, m_totalTime( 0 )
|
||||
, m_justSeeked( false )
|
||||
, m_initialized( false )
|
||||
, dspPluginCallback( nullptr )
|
||||
, m_vlcInstance( nullptr )
|
||||
, m_vlcPlayer( nullptr )
|
||||
, m_vlcMedia( nullptr )
|
||||
, m_vlcPreloadedPlayer( nullptr )
|
||||
, m_vlcPreloadedMedia( nullptr )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
@@ -69,7 +79,7 @@ AudioOutput::AudioOutput( QObject* parent )
|
||||
|
||||
qRegisterMetaType<AudioOutput::AudioState>("AudioOutput::AudioState");
|
||||
|
||||
const char* vlcArgs[] = {
|
||||
QVector<const char*> vlcArgs = {
|
||||
"--ignore-config",
|
||||
"--extraintf=logger",
|
||||
qApp->arguments().contains( "--verbose" ) ? "--verbose=3" : "",
|
||||
@@ -81,11 +91,28 @@ AudioOutput::AudioOutput( QObject* parent )
|
||||
// "--no-snapshot-preview",
|
||||
// "--services-discovery=''",
|
||||
"--no-video",
|
||||
//"--network-caching=10000",
|
||||
//"--file-caching=10000",
|
||||
//"--clock-synchro=0",
|
||||
//"--cr-average=10000",
|
||||
//"--clock-jitter=1",
|
||||
"--no-xlib"
|
||||
};
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
//Save a list of Latin1 byte arrays for additional args
|
||||
auto additionalVlcArgs = s->vlcArguments().split(",");
|
||||
QVector<QByteArray> additionalArgsChar;
|
||||
|
||||
std::transform(additionalVlcArgs.begin(), additionalVlcArgs.end(),
|
||||
std::back_inserter(additionalArgsChar), [](QString str) { return str.toLatin1(); });
|
||||
|
||||
for (auto&& str : additionalArgsChar)
|
||||
{
|
||||
vlcArgs.append(str.constData());
|
||||
}
|
||||
|
||||
// Create and initialize a libvlc instance (it should be done only once)
|
||||
m_vlcInstance = libvlc_new( sizeof(vlcArgs) / sizeof(*vlcArgs), vlcArgs );
|
||||
m_vlcInstance = libvlc_new( vlcArgs.size(), vlcArgs.constData() );
|
||||
if ( !m_vlcInstance )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO << "libVLC: could not initialize";
|
||||
@@ -95,53 +122,133 @@ AudioOutput::AudioOutput( QObject* parent )
|
||||
TOMAHAWK_APPLICATION_NAME "/" TOMAHAWK_VERSION );
|
||||
// FIXME: icon is named tomahawk, so we need the lowercase application name
|
||||
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 1, 0, 0))
|
||||
libvlc_set_app_id( m_vlcInstance, "org.tomahawk-player.desktop",
|
||||
TOMAHAWK_VERSION, "tomahawk" );
|
||||
libvlc_set_app_id( m_vlcInstance, TOMAHAWK_APPLICATION_PACKAGE_NAME,
|
||||
TOMAHAWK_VERSION, TOMAHAWK_TARGET_NAME );
|
||||
#endif
|
||||
|
||||
m_vlcPlayer = libvlc_media_player_new( m_vlcInstance );
|
||||
libvlc_event_manager_t* manager = libvlc_media_player_event_manager( m_vlcPlayer );
|
||||
libvlc_event_type_t events[] = {
|
||||
libvlc_MediaPlayerMediaChanged,
|
||||
libvlc_MediaPlayerNothingSpecial,
|
||||
libvlc_MediaPlayerOpening,
|
||||
libvlc_MediaPlayerBuffering,
|
||||
libvlc_MediaPlayerPlaying,
|
||||
libvlc_MediaPlayerPaused,
|
||||
libvlc_MediaPlayerStopped,
|
||||
libvlc_MediaPlayerForward,
|
||||
libvlc_MediaPlayerBackward,
|
||||
libvlc_MediaPlayerEndReached,
|
||||
libvlc_MediaPlayerEncounteredError,
|
||||
libvlc_MediaPlayerTimeChanged,
|
||||
libvlc_MediaPlayerPositionChanged,
|
||||
libvlc_MediaPlayerSeekableChanged,
|
||||
libvlc_MediaPlayerPausableChanged,
|
||||
libvlc_MediaPlayerTitleChanged,
|
||||
libvlc_MediaPlayerSnapshotTaken,
|
||||
//libvlc_MediaPlayerLengthChanged,
|
||||
libvlc_MediaPlayerVout
|
||||
};
|
||||
const int eventCount = sizeof(events) / sizeof( *events );
|
||||
for ( int i = 0; i < eventCount; i++ )
|
||||
m_vlcPreloadedPlayer = libvlc_media_player_new( m_vlcInstance );
|
||||
|
||||
for( auto player : { m_vlcPlayer, m_vlcPreloadedPlayer } )
|
||||
{
|
||||
libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this );
|
||||
libvlc_audio_set_mute( player, 0 );
|
||||
{
|
||||
libvlc_event_manager_t* current_manager = libvlc_media_player_event_manager( player );
|
||||
libvlc_event_manager_t* new_manager = libvlc_media_player_event_manager( player );
|
||||
static libvlc_event_type_t events[] = {
|
||||
libvlc_MediaPlayerMediaChanged,
|
||||
libvlc_MediaPlayerNothingSpecial,
|
||||
libvlc_MediaPlayerOpening,
|
||||
libvlc_MediaPlayerBuffering,
|
||||
libvlc_MediaPlayerPlaying,
|
||||
libvlc_MediaPlayerPaused,
|
||||
libvlc_MediaPlayerStopped,
|
||||
libvlc_MediaPlayerForward,
|
||||
libvlc_MediaPlayerBackward,
|
||||
libvlc_MediaPlayerEndReached,
|
||||
libvlc_MediaPlayerEncounteredError,
|
||||
libvlc_MediaPlayerTimeChanged,
|
||||
libvlc_MediaPlayerPositionChanged,
|
||||
libvlc_MediaPlayerSeekableChanged,
|
||||
libvlc_MediaPlayerPausableChanged,
|
||||
libvlc_MediaPlayerTitleChanged,
|
||||
libvlc_MediaPlayerSnapshotTaken,
|
||||
//libvlc_MediaPlayerLengthChanged,
|
||||
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
|
||||
libvlc_MediaPlayerAudioVolume,
|
||||
libvlc_MediaPlayerMuted,
|
||||
libvlc_MediaPlayerUnmuted,
|
||||
#endif
|
||||
libvlc_MediaPlayerVout
|
||||
};
|
||||
const int eventCount = sizeof(events) / sizeof( *events );
|
||||
for ( int i = 0; i < eventCount; i++ )
|
||||
{
|
||||
libvlc_event_attach( new_manager, events[ i ], &AudioOutput::vlcEventCallback, this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tDebug() << Q_FUNC_INFO << "Init OK";
|
||||
// HACK: play silent ogg file and set volume on that to workaround vlc not allowing to set volume before a file is played
|
||||
m_silenceFile.setFileName( RESPATH "sounds/silence.ogg" );
|
||||
Q_ASSERT( m_silenceFile.exists() );
|
||||
Q_ASSERT( m_silenceFile.open( QIODevice::ReadOnly ) );
|
||||
|
||||
setCurrentSource( new MediaStream( &m_silenceFile, true ), false );
|
||||
setCurrentSource( new MediaStream( &m_silenceFile, true ), true );
|
||||
|
||||
libvlc_media_player_play( m_vlcPlayer );
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,4,0)
|
||||
// if the silence file did not play for 15 secs, we pretend the AudioOutput is initialized, to allow proper error reporting
|
||||
QTimer::singleShot( 15000, [&]()
|
||||
{
|
||||
if ( !m_initialized ) {
|
||||
m_initialized = 2;
|
||||
emit initialized();
|
||||
}
|
||||
} );
|
||||
#endif
|
||||
}
|
||||
|
||||
void AudioOutput::switchToPreloadedMedia( void )
|
||||
{
|
||||
|
||||
//Swap
|
||||
auto tempPlayer = m_vlcPreloadedPlayer;
|
||||
m_vlcPreloadedPlayer = m_vlcPlayer;
|
||||
m_vlcPlayer = tempPlayer;
|
||||
|
||||
libvlc_media_player_stop( m_vlcPreloadedPlayer );
|
||||
|
||||
if ( m_vlcMedia != nullptr )
|
||||
{
|
||||
libvlc_media_release( m_vlcMedia );
|
||||
}
|
||||
//Now Media
|
||||
{
|
||||
if ( m_autoDelete && m_currentStream != nullptr )
|
||||
{
|
||||
delete m_currentStream;
|
||||
}
|
||||
|
||||
m_vlcMedia = m_vlcPreloadedMedia;
|
||||
m_vlcPreloadedMedia = nullptr;
|
||||
m_currentStream = m_preloadedStream;
|
||||
m_preloadedStream = nullptr;
|
||||
m_autoDelete = m_preloadedAutoDelete;
|
||||
|
||||
m_totalTime = libvlc_media_get_duration( m_vlcMedia );
|
||||
|
||||
m_currentTime = 0;
|
||||
m_justSeeked = false;
|
||||
m_seekable = true;
|
||||
}
|
||||
|
||||
libvlc_media_player_set_position( m_vlcPlayer, 0.0 );
|
||||
}
|
||||
|
||||
AudioOutput::~AudioOutput()
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( m_vlcPreloadedPlayer != nullptr )
|
||||
{
|
||||
libvlc_media_player_stop( m_vlcPreloadedPlayer );
|
||||
libvlc_media_player_release( m_vlcPreloadedPlayer );
|
||||
m_vlcPreloadedPlayer = nullptr;
|
||||
}
|
||||
if ( m_vlcPlayer != nullptr )
|
||||
{
|
||||
libvlc_media_player_stop( m_vlcPlayer );
|
||||
libvlc_media_player_release( m_vlcPlayer );
|
||||
m_vlcPlayer = nullptr;
|
||||
}
|
||||
if ( m_vlcPreloadedMedia != nullptr )
|
||||
{
|
||||
libvlc_media_release( m_vlcPreloadedMedia );
|
||||
m_vlcPreloadedMedia = nullptr;
|
||||
}
|
||||
if ( m_vlcMedia != nullptr )
|
||||
{
|
||||
libvlc_media_release( m_vlcMedia );
|
||||
@@ -155,23 +262,56 @@ AudioOutput::~AudioOutput()
|
||||
|
||||
|
||||
void
|
||||
AudioOutput::setAutoDelete( bool ad )
|
||||
AudioOutput::onInitVlcEvent( const libvlc_event_t* event )
|
||||
{
|
||||
m_autoDelete = ad;
|
||||
switch ( event->type )
|
||||
{
|
||||
case libvlc_MediaPlayerTimeChanged:
|
||||
setVolume( volume() );
|
||||
setMuted( isMuted() );
|
||||
|
||||
m_initialized ++;
|
||||
|
||||
tDebug() << Q_FUNC_INFO << "Init OK";
|
||||
if (m_initialized >=2)
|
||||
{
|
||||
m_silenceFile.close();
|
||||
emit initialized();
|
||||
}
|
||||
else
|
||||
{
|
||||
switchToPreloadedMedia();
|
||||
libvlc_media_player_play( m_vlcPlayer );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioOutput::setCurrentSource( const QUrl& stream )
|
||||
AudioOutput::setAutoDelete( bool ad, bool preload )
|
||||
{
|
||||
setCurrentSource( new MediaStream( stream ) );
|
||||
if (preload)
|
||||
m_preloadedAutoDelete = ad;
|
||||
else
|
||||
m_autoDelete = ad;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioOutput::setCurrentSource( QIODevice* stream )
|
||||
AudioOutput::setCurrentSource( const QUrl& stream, bool preload )
|
||||
{
|
||||
setCurrentSource( new MediaStream( stream ) );
|
||||
setCurrentSource( new MediaStream( stream ), preload );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioOutput::setCurrentSource( QIODevice* stream, bool preload )
|
||||
{
|
||||
setCurrentSource( new MediaStream( stream ), preload );
|
||||
}
|
||||
|
||||
|
||||
@@ -191,29 +331,24 @@ readDoneCallback( void* data, const char* cookie, size_t bufferSize, void* buffe
|
||||
|
||||
|
||||
void
|
||||
AudioOutput::setCurrentSource( MediaStream* stream )
|
||||
AudioOutput::setCurrentSource( MediaStream* stream, bool preload )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
tDebug() << Q_FUNC_INFO << ", preload = " << preload;
|
||||
|
||||
setState( Loading );
|
||||
if ( !preload )
|
||||
setState( Loading );
|
||||
|
||||
if ( m_vlcMedia != nullptr )
|
||||
{
|
||||
// Ensure playback is stopped, then release media
|
||||
libvlc_media_player_stop( m_vlcPlayer );
|
||||
libvlc_media_release( m_vlcMedia );
|
||||
m_vlcMedia = nullptr;
|
||||
if ( m_vlcPreloadedMedia ) {
|
||||
libvlc_media_player_stop( m_vlcPreloadedPlayer );
|
||||
libvlc_media_release( m_vlcPreloadedMedia );
|
||||
m_vlcPreloadedMedia = nullptr;
|
||||
}
|
||||
if ( m_autoDelete && m_currentStream != nullptr )
|
||||
if ( m_preloadedAutoDelete && m_preloadedStream != nullptr )
|
||||
{
|
||||
delete m_currentStream;
|
||||
delete m_preloadedStream;
|
||||
}
|
||||
|
||||
m_currentStream = stream;
|
||||
m_totalTime = 0;
|
||||
m_currentTime = 0;
|
||||
m_justSeeked = false;
|
||||
m_seekable = true;
|
||||
m_preloadedStream = stream;
|
||||
|
||||
QByteArray url;
|
||||
switch ( stream->type() )
|
||||
@@ -247,34 +382,19 @@ AudioOutput::setCurrentSource( MediaStream* stream )
|
||||
|
||||
tDebug() << Q_FUNC_INFO << "MediaStream::Final Url:" << url;
|
||||
|
||||
m_vlcMedia = libvlc_media_new_location( m_vlcInstance, url.constData() );
|
||||
libvlc_event_manager_t* manager = libvlc_media_event_manager( m_vlcMedia );
|
||||
libvlc_event_type_t events[] = {
|
||||
libvlc_MediaDurationChanged,
|
||||
};
|
||||
const int eventCount = sizeof(events) / sizeof( *events );
|
||||
for ( int i = 0; i < eventCount; i++ )
|
||||
m_vlcPreloadedMedia = libvlc_media_new_location( m_vlcInstance, url.constData() );
|
||||
if ( stream->type() == MediaStream::Stream || stream->type() == MediaStream::IODevice )
|
||||
{
|
||||
libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this );
|
||||
}
|
||||
|
||||
libvlc_media_player_set_media( m_vlcPlayer, m_vlcMedia );
|
||||
|
||||
if ( stream->type() == MediaStream::Url )
|
||||
{
|
||||
m_totalTime = libvlc_media_get_duration( m_vlcMedia );
|
||||
}
|
||||
else if ( stream->type() == MediaStream::Stream || stream->type() == MediaStream::IODevice )
|
||||
{
|
||||
libvlc_media_add_option_flag(m_vlcMedia, "imem-cat=4", libvlc_media_option_trusted);
|
||||
const char* imemData = QString( "imem-data=%1" ).arg( (uintptr_t)stream ).toLatin1().constData();
|
||||
libvlc_media_add_option_flag(m_vlcMedia, imemData, libvlc_media_option_trusted);
|
||||
const char* imemGet = QString( "imem-get=%1" ).arg( (uintptr_t)&readCallback ).toLatin1().constData();
|
||||
libvlc_media_add_option_flag(m_vlcMedia, imemGet, libvlc_media_option_trusted);
|
||||
const char* imemRelease = QString( "imem-release=%1" ).arg( (uintptr_t)&readDoneCallback ).toLatin1().constData();
|
||||
libvlc_media_add_option_flag(m_vlcMedia, imemRelease, libvlc_media_option_trusted);
|
||||
const char* imemSeek = QString( "imem-seek=%1" ).arg( (uintptr_t)&MediaStream::seekCallback ).toLatin1().constData();
|
||||
libvlc_media_add_option_flag(m_vlcMedia, imemSeek, libvlc_media_option_trusted);
|
||||
QString tempString;
|
||||
libvlc_media_add_option_flag(m_vlcPreloadedMedia, "imem-cat=4", libvlc_media_option_trusted);
|
||||
tempString = QString( "imem-data=%1" ).arg( (uintptr_t)stream );
|
||||
libvlc_media_add_option_flag(m_vlcPreloadedMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted);
|
||||
tempString = QString( "imem-get=%1" ).arg( (uintptr_t)&readCallback );
|
||||
libvlc_media_add_option_flag(m_vlcPreloadedMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted);
|
||||
tempString = QString( "imem-release=%1" ).arg( (uintptr_t)&readDoneCallback );
|
||||
libvlc_media_add_option_flag(m_vlcPreloadedMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted);
|
||||
tempString = QString( "imem-seek=%1" ).arg( (uintptr_t)&MediaStream::seekCallback );
|
||||
libvlc_media_add_option_flag(m_vlcPreloadedMedia, tempString.toLatin1().constData(), libvlc_media_option_trusted);
|
||||
}
|
||||
if ( qApp->arguments().contains( "--chromecast-ip" ) )
|
||||
{
|
||||
@@ -290,7 +410,7 @@ AudioOutput::setCurrentSource( MediaStream* stream )
|
||||
{
|
||||
QString castIP = qApp->arguments().at( qApp->arguments().indexOf( "--chromecast-ip" ) + 1 );
|
||||
QString sout( ":sout=#transcode{vcodec=none,acodec=vorb,ab=320,channels=2,samplerate=44100}:chromecast{ip=%1,mux=webm}" );
|
||||
libvlc_media_add_option( m_vlcMedia, sout.arg( castIP ).toLatin1().constData() );
|
||||
libvlc_media_add_option( m_vlcPreloadedMedia, sout.arg( castIP ).toLatin1().constData() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -298,10 +418,35 @@ AudioOutput::setCurrentSource( MediaStream* stream )
|
||||
}
|
||||
}
|
||||
|
||||
libvlc_event_manager_t* manager = libvlc_media_event_manager( m_vlcPreloadedMedia );
|
||||
static libvlc_event_type_t events[] = {
|
||||
libvlc_MediaDurationChanged,
|
||||
};
|
||||
const int eventCount = sizeof(events) / sizeof( *events );
|
||||
for ( int i = 0; i < eventCount; i++ )
|
||||
{
|
||||
libvlc_event_attach( manager, events[ i ], &AudioOutput::vlcEventCallback, this );
|
||||
}
|
||||
|
||||
libvlc_media_player_set_media( m_vlcPreloadedPlayer, m_vlcPreloadedMedia );
|
||||
|
||||
libvlc_audio_set_volume( m_vlcPreloadedPlayer, 0.0 );
|
||||
libvlc_media_player_play( m_vlcPreloadedPlayer );
|
||||
|
||||
if ( !preload )
|
||||
switchToPreloadedMedia();
|
||||
|
||||
// setState( Stopped );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AudioOutput::isInitialized() const
|
||||
{
|
||||
return m_initialized > 1;
|
||||
}
|
||||
|
||||
|
||||
AudioOutput::AudioState
|
||||
AudioOutput::state() const
|
||||
{
|
||||
@@ -427,16 +572,19 @@ AudioOutput::seek( qint64 milliseconds )
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 duration = AudioEngine::instance()->currentTrackTotalTime();
|
||||
// for some tracks, seeking to an end seems not to work correctly with libvlc
|
||||
// (tracks enter a random and infinite loop) - this is a temporary fix for that
|
||||
if (duration == milliseconds)
|
||||
milliseconds -= 1;
|
||||
|
||||
if ( m_seekable )
|
||||
{
|
||||
|
||||
// tDebug() << Q_FUNC_INFO << "AudioOutput:: seeking" << milliseconds << "msec";
|
||||
libvlc_media_player_set_time( m_vlcPlayer, milliseconds );
|
||||
setCurrentTime( milliseconds );
|
||||
}
|
||||
else
|
||||
{
|
||||
qint64 duration = AudioEngine::instance()->currentTrackTotalTime();
|
||||
float position = float(float(milliseconds) / duration);
|
||||
libvlc_media_player_set_position(m_vlcPlayer, position);
|
||||
tDebug() << Q_FUNC_INFO << "AudioOutput:: seeking via position" << position << "pos";
|
||||
@@ -448,7 +596,7 @@ AudioOutput::seek( qint64 milliseconds )
|
||||
bool
|
||||
AudioOutput::isSeekable() const
|
||||
{
|
||||
// tDebug() << Q_FUNC_INFO << m_seekable << m_havePosition << m_totalTime << libvlc_media_player_is_seekable( m_vlcPlayer );
|
||||
tDebug() << Q_FUNC_INFO << m_seekable << m_havePosition << m_totalTime << libvlc_media_player_is_seekable( m_vlcPlayer );
|
||||
return m_havePosition || (libvlc_media_player_is_seekable( m_vlcPlayer ) && m_totalTime > 0 );
|
||||
}
|
||||
|
||||
@@ -466,11 +614,9 @@ AudioOutput::setMuted( bool m )
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_muted = m;
|
||||
if ( m_muted )
|
||||
{
|
||||
libvlc_audio_set_volume( m_vlcPlayer, 0 );
|
||||
}
|
||||
else
|
||||
libvlc_audio_set_mute( m_vlcPlayer, m );
|
||||
|
||||
if ( !m_muted )
|
||||
{
|
||||
libvlc_audio_set_volume( m_vlcPlayer, m_volume * 100.0 );
|
||||
}
|
||||
@@ -487,7 +633,7 @@ AudioOutput::volume() const
|
||||
void
|
||||
AudioOutput::setVolume( qreal vol )
|
||||
{
|
||||
tDebug() << Q_FUNC_INFO;
|
||||
tDebug() << Q_FUNC_INFO << vol << m_muted;
|
||||
|
||||
m_volume = vol;
|
||||
if ( !m_muted )
|
||||
@@ -500,50 +646,107 @@ AudioOutput::setVolume( qreal vol )
|
||||
void
|
||||
AudioOutput::onVlcEvent( const libvlc_event_t* event )
|
||||
{
|
||||
switch ( event->type )
|
||||
if ( event->p_obj == m_vlcPlayer || event->p_obj == m_vlcMedia )
|
||||
{
|
||||
case libvlc_MediaPlayerTimeChanged:
|
||||
setCurrentTime( event->u.media_player_time_changed.new_time );
|
||||
break;
|
||||
case libvlc_MediaPlayerPositionChanged:
|
||||
setCurrentPosition( event->u.media_player_position_changed.new_position );
|
||||
break;
|
||||
case libvlc_MediaPlayerSeekableChanged:
|
||||
// tDebug() << Q_FUNC_INFO << " : seekable changed : " << event->u.media_player_seekable_changed.new_seekable;
|
||||
break;
|
||||
case libvlc_MediaDurationChanged:
|
||||
setTotalTime( event->u.media_duration_changed.new_duration );
|
||||
break;
|
||||
case libvlc_MediaPlayerLengthChanged:
|
||||
// tDebug() << Q_FUNC_INFO << " : length changed : " << event->u.media_player_length_changed.new_length;
|
||||
break;
|
||||
case libvlc_MediaPlayerPlaying:
|
||||
setState( Playing );
|
||||
break;
|
||||
case libvlc_MediaPlayerPaused:
|
||||
setState( Paused );
|
||||
break;
|
||||
case libvlc_MediaPlayerEndReached:
|
||||
setState( Stopped );
|
||||
break;
|
||||
case libvlc_MediaPlayerEncounteredError:
|
||||
tDebug() << Q_FUNC_INFO << "LibVLC error: MediaPlayerEncounteredError. Stopping";
|
||||
// Don't call stop() here - it will deadlock libvlc
|
||||
setState( Error );
|
||||
break;
|
||||
case libvlc_MediaPlayerNothingSpecial:
|
||||
case libvlc_MediaPlayerOpening:
|
||||
case libvlc_MediaPlayerBuffering:
|
||||
case libvlc_MediaPlayerStopped:
|
||||
case libvlc_MediaPlayerVout:
|
||||
case libvlc_MediaPlayerMediaChanged:
|
||||
case libvlc_MediaPlayerForward:
|
||||
case libvlc_MediaPlayerBackward:
|
||||
case libvlc_MediaPlayerPausableChanged:
|
||||
case libvlc_MediaPlayerTitleChanged:
|
||||
case libvlc_MediaPlayerSnapshotTaken:
|
||||
default:
|
||||
break;
|
||||
switch ( event->type )
|
||||
{
|
||||
case libvlc_MediaPlayerTimeChanged:
|
||||
setCurrentTime( event->u.media_player_time_changed.new_time );
|
||||
break;
|
||||
case libvlc_MediaPlayerPositionChanged:
|
||||
setCurrentPosition( event->u.media_player_position_changed.new_position );
|
||||
break;
|
||||
case libvlc_MediaPlayerSeekableChanged:
|
||||
// tDebug() << Q_FUNC_INFO << " : seekable changed : " << event->u.media_player_seekable_changed.new_seekable;
|
||||
break;
|
||||
case libvlc_MediaDurationChanged:
|
||||
setTotalTime( event->u.media_duration_changed.new_duration );
|
||||
break;
|
||||
case libvlc_MediaPlayerLengthChanged:
|
||||
// tDebug() << Q_FUNC_INFO << " : length changed : " << event->u.media_player_length_changed.new_length;
|
||||
break;
|
||||
case libvlc_MediaPlayerPlaying:
|
||||
setState( Playing );
|
||||
break;
|
||||
case libvlc_MediaPlayerPaused:
|
||||
setState( Paused );
|
||||
break;
|
||||
case libvlc_MediaPlayerEndReached:
|
||||
setState( Stopped );
|
||||
break;
|
||||
case libvlc_MediaPlayerEncounteredError:
|
||||
tDebug() << Q_FUNC_INFO << "LibVLC error: MediaPlayerEncounteredError. Stopping";
|
||||
// Don't call stop() here - it will deadlock libvlc
|
||||
setState( Error );
|
||||
break;
|
||||
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
|
||||
case libvlc_MediaPlayerAudioVolume:
|
||||
m_volume = event->u.media_player_audio_volume.volume;
|
||||
tDebug() << Q_FUNC_INFO << "Got signal in current player that volume changed to:" << m_volume;
|
||||
emit volumeChanged( volume() );
|
||||
break;
|
||||
case libvlc_MediaPlayerMuted:
|
||||
m_muted = true;
|
||||
emit mutedChanged( true );
|
||||
break;
|
||||
case libvlc_MediaPlayerUnmuted:
|
||||
m_muted = false;
|
||||
emit mutedChanged( false );
|
||||
break;
|
||||
#endif
|
||||
case libvlc_MediaPlayerNothingSpecial:
|
||||
case libvlc_MediaPlayerOpening:
|
||||
case libvlc_MediaPlayerBuffering:
|
||||
case libvlc_MediaPlayerStopped:
|
||||
case libvlc_MediaPlayerVout:
|
||||
case libvlc_MediaPlayerMediaChanged:
|
||||
case libvlc_MediaPlayerForward:
|
||||
case libvlc_MediaPlayerBackward:
|
||||
case libvlc_MediaPlayerPausableChanged:
|
||||
case libvlc_MediaPlayerTitleChanged:
|
||||
case libvlc_MediaPlayerSnapshotTaken:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tDebug() << "Event for preloaded: " << libvlc_event_type_name(event->type);
|
||||
switch ( event->type )
|
||||
{
|
||||
case libvlc_MediaPlayerPausableChanged:
|
||||
case libvlc_MediaPlayerPlaying:
|
||||
case libvlc_MediaPlayerMediaChanged:
|
||||
case libvlc_MediaPlayerTitleChanged:
|
||||
case libvlc_MediaPlayerSeekableChanged:
|
||||
case libvlc_MediaDurationChanged:
|
||||
case libvlc_MediaPlayerPositionChanged:
|
||||
case libvlc_MediaPlayerPaused:
|
||||
case libvlc_MediaPlayerBuffering:
|
||||
libvlc_media_player_set_pause( m_vlcPreloadedPlayer, 1 );
|
||||
libvlc_audio_set_volume( m_vlcPreloadedPlayer, 0.0 );
|
||||
libvlc_media_player_set_position( m_vlcPreloadedPlayer, 0.0 );
|
||||
break;
|
||||
case libvlc_MediaPlayerTimeChanged:
|
||||
case libvlc_MediaPlayerLengthChanged:
|
||||
case libvlc_MediaPlayerOpening:
|
||||
case libvlc_MediaPlayerEndReached:
|
||||
case libvlc_MediaPlayerEncounteredError:
|
||||
//TODO
|
||||
#if (LIBVLC_VERSION_INT >= LIBVLC_VERSION(2, 2, 2, 0))
|
||||
case libvlc_MediaPlayerAudioVolume:
|
||||
case libvlc_MediaPlayerMuted:
|
||||
case libvlc_MediaPlayerUnmuted:
|
||||
#endif
|
||||
case libvlc_MediaPlayerNothingSpecial:
|
||||
case libvlc_MediaPlayerStopped:
|
||||
case libvlc_MediaPlayerVout:
|
||||
case libvlc_MediaPlayerForward:
|
||||
case libvlc_MediaPlayerBackward:
|
||||
case libvlc_MediaPlayerSnapshotTaken:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,7 +759,14 @@ AudioOutput::vlcEventCallback( const libvlc_event_t* event, void* opaque )
|
||||
AudioOutput* that = reinterpret_cast < AudioOutput * > ( opaque );
|
||||
Q_ASSERT( that );
|
||||
|
||||
that->onVlcEvent( event );
|
||||
if ( !that->isInitialized() )
|
||||
{
|
||||
that->onInitVlcEvent( event );
|
||||
}
|
||||
else
|
||||
{
|
||||
that->onVlcEvent( event );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -25,6 +25,8 @@
|
||||
#include "DllMacro.h"
|
||||
#include "Typedefs.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <functional>
|
||||
|
||||
struct libvlc_instance_t;
|
||||
@@ -44,11 +46,13 @@ public:
|
||||
explicit AudioOutput( QObject* parent = nullptr );
|
||||
~AudioOutput();
|
||||
|
||||
bool isInitialized() const;
|
||||
AudioState state() const;
|
||||
|
||||
void setCurrentSource( const QUrl& stream );
|
||||
void setCurrentSource( QIODevice* stream );
|
||||
void setCurrentSource( MediaStream* stream );
|
||||
void setCurrentSource( const QUrl& stream, bool preload );
|
||||
void setCurrentSource( QIODevice* stream, bool preload );
|
||||
void setCurrentSource( MediaStream* stream, bool preload );
|
||||
void setPreloadedSourceAsCurrent( void );
|
||||
|
||||
void play();
|
||||
void pause();
|
||||
@@ -62,26 +66,34 @@ public:
|
||||
qreal volume() const;
|
||||
qint64 currentTime() const;
|
||||
qint64 totalTime() const;
|
||||
void setAutoDelete ( bool ad );
|
||||
void setAutoDelete ( bool ad, bool preload );
|
||||
|
||||
void setDspCallback( std::function< void( int, int, float*, int, int ) > cb );
|
||||
|
||||
static AudioOutput* instance();
|
||||
libvlc_instance_t* vlcInstance() const;
|
||||
|
||||
void switchToPreloadedMedia( void );
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
void initialized();
|
||||
void stateChanged( AudioOutput::AudioState, AudioOutput::AudioState );
|
||||
void tick( qint64 );
|
||||
void positionChanged( float );
|
||||
void volumeChanged( qreal volume );
|
||||
void mutedChanged( bool );
|
||||
|
||||
private:
|
||||
void onInitVlcEvent( const libvlc_event_t* event );
|
||||
|
||||
void setState( AudioState state );
|
||||
void setCurrentTime( qint64 time );
|
||||
void setCurrentPosition( float position );
|
||||
void setTotalTime( qint64 time );
|
||||
|
||||
|
||||
void onVlcEvent( const libvlc_event_t* event );
|
||||
static void vlcEventCallback( const libvlc_event_t* event, void* opaque );
|
||||
static void s_dspCallback( int frameNumber, float* samples, int nb_channels, int nb_samples );
|
||||
@@ -89,9 +101,11 @@ private:
|
||||
static AudioOutput* s_instance;
|
||||
AudioState m_currentState;
|
||||
MediaStream* m_currentStream;
|
||||
MediaStream* m_preloadedStream;
|
||||
bool m_seekable;
|
||||
bool m_muted;
|
||||
bool m_autoDelete;
|
||||
bool m_preloadedAutoDelete;
|
||||
bool m_havePosition;
|
||||
bool m_haveTiming;
|
||||
qreal m_volume;
|
||||
@@ -99,11 +113,17 @@ private:
|
||||
qint64 m_totalTime;
|
||||
bool m_justSeeked;
|
||||
|
||||
int m_initialized;
|
||||
QFile m_silenceFile;
|
||||
|
||||
std::function< void( int state, int frameNumber, float* samples, int nb_channels, int nb_samples ) > dspPluginCallback;
|
||||
|
||||
libvlc_instance_t* m_vlcInstance;
|
||||
libvlc_media_player_t* m_vlcPlayer;
|
||||
libvlc_media_t* m_vlcMedia;
|
||||
libvlc_media_player_t* m_vlcBackPlayer;
|
||||
libvlc_media_player_t* m_vlcPreloadedPlayer;
|
||||
libvlc_media_t* m_vlcPreloadedMedia;
|
||||
};
|
||||
|
||||
#endif // AUDIOOUTPUT_H
|
||||
|
@@ -41,12 +41,16 @@ MediaStream::MediaStream( const QUrl &url )
|
||||
}
|
||||
|
||||
|
||||
MediaStream::MediaStream( QIODevice* device )
|
||||
MediaStream::MediaStream( QIODevice* device, bool bufferingFinished )
|
||||
: QObject( nullptr )
|
||||
, m_type( IODevice )
|
||||
, m_ioDevice ( device )
|
||||
, m_bufferingFinished( bufferingFinished )
|
||||
{
|
||||
QObject::connect( m_ioDevice, SIGNAL( readChannelFinished() ), this, SLOT( bufferingFinished() ) );
|
||||
if ( !bufferingFinished )
|
||||
{
|
||||
QObject::connect( m_ioDevice, SIGNAL( readChannelFinished() ), this, SLOT( bufferingFinished() ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +151,6 @@ int
|
||||
MediaStream::readDoneCallback ( const char *cookie, size_t bufferSize, void *buffer )
|
||||
{
|
||||
Q_UNUSED(cookie);
|
||||
Q_UNUSED(bufferSize);
|
||||
|
||||
if ( ( m_type == Stream ) && buffer != nullptr && bufferSize > 0 ) {
|
||||
delete[] reinterpret_cast< char* >( buffer );
|
||||
|
@@ -42,7 +42,7 @@ public:
|
||||
|
||||
MediaStream( QObject* parent = nullptr );
|
||||
explicit MediaStream( const QUrl &url );
|
||||
explicit MediaStream( QIODevice* device );
|
||||
explicit MediaStream( QIODevice* device, bool bufferingFinished = false );
|
||||
virtual ~MediaStream();
|
||||
|
||||
MediaType type() const;
|
||||
|
@@ -128,10 +128,13 @@ DatabaseCollection::playlists()
|
||||
QList< dynplaylist_ptr >
|
||||
DatabaseCollection::autoPlaylists()
|
||||
{
|
||||
// echonest is dead, disable all echonest code
|
||||
/*
|
||||
if ( Collection::autoPlaylists().isEmpty() )
|
||||
{
|
||||
loadAutoPlaylists();
|
||||
}
|
||||
*/
|
||||
|
||||
return Collection::autoPlaylists();
|
||||
}
|
||||
@@ -140,10 +143,13 @@ DatabaseCollection::autoPlaylists()
|
||||
QList< dynplaylist_ptr >
|
||||
DatabaseCollection::stations()
|
||||
{
|
||||
// echonest is dead, disable all echonest code
|
||||
/*
|
||||
if ( Collection::stations().isEmpty() )
|
||||
{
|
||||
loadStations();
|
||||
}
|
||||
*/
|
||||
|
||||
return Collection::stations();
|
||||
}
|
||||
|
@@ -59,10 +59,10 @@ public:
|
||||
void setLimit( unsigned int amount ) { m_amount = amount; }
|
||||
void setSortOrder( DatabaseCommand_AllArtists::SortOrder order ) { m_sortOrder = order; }
|
||||
void setSortDescending( bool descending ) { m_sortDescending = descending; }
|
||||
void setFilter( const QString& filter ) { m_filter = filter; }
|
||||
void setFilter( const QString& filter ) override { m_filter = filter; }
|
||||
|
||||
signals:
|
||||
void artists( const QList<Tomahawk::artist_ptr>& );
|
||||
void artists( const QList<Tomahawk::artist_ptr>& ) override;
|
||||
void done();
|
||||
|
||||
private:
|
||||
|
@@ -74,7 +74,7 @@ public:
|
||||
|
||||
signals:
|
||||
void tracks( const QList<Tomahawk::query_ptr>&, const QVariant& data );
|
||||
void tracks( const QList<Tomahawk::query_ptr>& );
|
||||
void tracks( const QList<Tomahawk::query_ptr>& ) override;
|
||||
void done( const Tomahawk::collection_ptr& );
|
||||
|
||||
private:
|
||||
|
@@ -21,7 +21,6 @@
|
||||
#include "Source.h"
|
||||
#include "network/Servent.h"
|
||||
#include "SourceList.h"
|
||||
#include "EchonestCatalogSynchronizer.h"
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
@@ -76,9 +75,11 @@ DatabaseCommand_SetCollectionAttributes::exec( DatabaseImpl *lib )
|
||||
void
|
||||
DatabaseCommand_SetCollectionAttributes::postCommitHook()
|
||||
{
|
||||
/*
|
||||
if ( m_type == EchonestSongCatalog ||
|
||||
m_type == EchonestArtistCatalog )
|
||||
Tomahawk::EchonestCatalogSynchronizer::instance()->knownCatalogsChanged();
|
||||
*/
|
||||
|
||||
if ( source()->isLocal() )
|
||||
Servent::instance()->triggerDBSync();
|
||||
|
@@ -34,11 +34,11 @@ public:
|
||||
explicit DatabaseResolver( int weight );
|
||||
|
||||
QString name() const override;
|
||||
virtual unsigned int weight() const { return m_weight; }
|
||||
virtual unsigned int timeout() const { return 0; }
|
||||
virtual unsigned int weight() const override{ return m_weight; }
|
||||
virtual unsigned int timeout() const override{ return 0; }
|
||||
|
||||
public slots:
|
||||
virtual void resolve( const Tomahawk::query_ptr& query );
|
||||
virtual void resolve( const Tomahawk::query_ptr& query ) override;
|
||||
|
||||
private slots:
|
||||
void gotResults( const Tomahawk::QID qid, QList< Tomahawk::result_ptr> results );
|
||||
|
@@ -1,21 +1,20 @@
|
||||
/*
|
||||
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "LocalCollection.h"
|
||||
|
||||
|
@@ -1,21 +1,20 @@
|
||||
/*
|
||||
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LOCALCOLLECTION_H
|
||||
#define LOCALCOLLECTION_H
|
||||
|
@@ -240,7 +240,7 @@ MetadataEditor::loadResult( const Tomahawk::result_ptr& result )
|
||||
return;
|
||||
|
||||
m_result = result;
|
||||
setEditable( result->resolvedByCollection() && result->resolvedByCollection()->isLocal() );
|
||||
setEditable( result->isLocal() );
|
||||
|
||||
setTitle( result->track()->track() );
|
||||
setArtist( result->track()->artist() );
|
||||
@@ -250,7 +250,7 @@ MetadataEditor::loadResult( const Tomahawk::result_ptr& result )
|
||||
setYear( result->track()->year() );
|
||||
setBitrate( result->bitrate() );
|
||||
|
||||
if ( result->resolvedByCollection() && result->resolvedByCollection()->isLocal() )
|
||||
if ( result->isLocal() )
|
||||
{
|
||||
QString furl = m_result->url();
|
||||
if ( furl.startsWith( "file://" ) )
|
||||
|
@@ -40,6 +40,11 @@ using namespace Tomahawk;
|
||||
void
|
||||
DirLister::go()
|
||||
{
|
||||
if ( m_dirs.isEmpty() )
|
||||
{
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
foreach ( const QString& dir, m_dirs )
|
||||
{
|
||||
m_opcount++;
|
||||
|
@@ -42,8 +42,8 @@ public:
|
||||
explicit DBSyncConnection( Servent* s, const Tomahawk::source_ptr& src );
|
||||
virtual ~DBSyncConnection();
|
||||
|
||||
void setup();
|
||||
Connection* clone();
|
||||
void setup() override;
|
||||
Connection* clone() override;
|
||||
|
||||
signals:
|
||||
void stateChanged( Tomahawk::DBSyncConnectionState newstate, Tomahawk::DBSyncConnectionState oldstate, const QString& info );
|
||||
|
@@ -1371,8 +1371,7 @@ Servent::isIPWhitelisted( QHostAddress ip )
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 0, 0 )
|
||||
// Qt4 cannot cope correctly with IPv4 addresses mapped into the IPv6
|
||||
// Qt cannot cope correctly with IPv4 addresses mapped into the IPv6
|
||||
// address space
|
||||
if ( ip.protocol() == QAbstractSocket::IPv6Protocol )
|
||||
{
|
||||
@@ -1397,7 +1396,6 @@ Servent::isIPWhitelisted( QHostAddress ip )
|
||||
return isIPWhitelisted( addr );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "failure";
|
||||
return false;
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/DpiScaler.h"
|
||||
#include "ViewManager.h"
|
||||
#include "widgets/DownloadButton.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
@@ -164,6 +165,10 @@ ColumnViewPreviewWidget::ColumnViewPreviewWidget( ColumnView* parent )
|
||||
m_ageValue->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
|
||||
gridLayout->addWidget( m_ageValue, 4, 1 );
|
||||
|
||||
|
||||
m_downloadButton = new DownloadButton( this );
|
||||
mainLayout->addWidget( m_downloadButton );
|
||||
|
||||
mainLayout->addStretch();
|
||||
|
||||
TomahawkUtils::unmarginLayout( mainLayout );
|
||||
@@ -217,6 +222,7 @@ ColumnViewPreviewWidget::setQuery( const Tomahawk::query_ptr& query )
|
||||
m_bitrateValue->setText( tr( "%1 kbps" ).arg( query->results().first()->bitrate() ) );
|
||||
m_durationValue->setText( TomahawkUtils::timeToString( query->track()->duration() ) );
|
||||
m_ageValue->setText( TomahawkUtils::ageToString( QDateTime::fromTime_t( query->results().first()->modificationTime() ) ) );
|
||||
m_downloadButton->setQuery( query );
|
||||
|
||||
m_yearValue->setVisible( query->track()->year() > 0 );
|
||||
m_yearLabel->setVisible( query->track()->year() > 0 );
|
||||
@@ -226,6 +232,7 @@ ColumnViewPreviewWidget::setQuery( const Tomahawk::query_ptr& query )
|
||||
m_durationValue->setVisible( query->track()->duration() > 0 );
|
||||
m_ageLabel->setVisible( query->results().first()->modificationTime() > 0 );
|
||||
m_ageValue->setVisible( query->results().first()->modificationTime() > 0 );
|
||||
m_downloadButton->setVisible( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -237,6 +244,7 @@ ColumnViewPreviewWidget::setQuery( const Tomahawk::query_ptr& query )
|
||||
m_durationValue->setVisible( false );
|
||||
m_ageLabel->setVisible( false );
|
||||
m_ageValue->setVisible( false );
|
||||
m_downloadButton->setVisible( false );
|
||||
}
|
||||
|
||||
setMinimumHeight( sizeHint().height() );
|
||||
|
@@ -30,6 +30,7 @@ class QueryLabel;
|
||||
class PlayableCover;
|
||||
class QLabel;
|
||||
class ScrollingLabel;
|
||||
class DownloadButton;
|
||||
|
||||
class DLLEXPORT ColumnViewPreviewWidget : public QWidget
|
||||
{
|
||||
@@ -71,6 +72,8 @@ private:
|
||||
ScrollingLabel* m_trackLabel;
|
||||
|
||||
QueryLabel* m_artistLabel;
|
||||
|
||||
DownloadButton* m_downloadButton;
|
||||
};
|
||||
|
||||
#endif // COLUMNVIEWPREVIEWWIDGET_H
|
||||
|
@@ -19,16 +19,6 @@
|
||||
|
||||
#include "GridItemDelegate.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopServices>
|
||||
#include <QPainter>
|
||||
#include <QAbstractItemView>
|
||||
#include <QMouseEvent>
|
||||
#include <QTimeLine>
|
||||
|
||||
#include "DownloadManager.h"
|
||||
#include "DownloadJob.h"
|
||||
|
||||
#include "Artist.h"
|
||||
#include "Query.h"
|
||||
#include "Result.h"
|
||||
@@ -39,17 +29,22 @@
|
||||
#include "playlist/PlayableItem.h"
|
||||
#include "playlist/PlayableProxyModel.h"
|
||||
#include "widgets/HoverControls.h"
|
||||
#include "widgets/DropDownButton.h"
|
||||
#include "widgets/DownloadButton.h"
|
||||
#include "widgets/ImageButton.h"
|
||||
#include "utils/TomahawkStyle.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/PixmapDelegateFader.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "utils/AnimatedSpinner.h"
|
||||
#include "utils/WebPopup.h"
|
||||
#include "utils/DpiScaler.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QAbstractItemView>
|
||||
#include <QMouseEvent>
|
||||
#include <QTimeLine>
|
||||
|
||||
namespace {
|
||||
static const int FADE_DURATION = 400;
|
||||
};
|
||||
@@ -325,39 +320,10 @@ GridItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
|
||||
QRect r = textRect;
|
||||
r.setY( textRect.y() + textRect.height() + 8 );
|
||||
r.setHeight( 32 );
|
||||
m_buyButtonRects[ index ] = r;
|
||||
|
||||
QString text;
|
||||
if ( item->result() &&
|
||||
( ( !item->result()->downloadFormats().isEmpty() && !DownloadManager::instance()->localFileForDownload( item->result()->downloadFormats().first().url.toString() ).isEmpty() ) ||
|
||||
( item->result()->downloadJob() && item->result()->downloadJob()->state() == DownloadJob::Finished ) ) )
|
||||
if( DownloadButton::drawPrimitive(painter, r, item->query(), m_hoveringOverBuyButton == index ) )
|
||||
{
|
||||
text = tr( "View in Finder" );
|
||||
}
|
||||
else if ( item->query() && item->query()->numResults( true ) && !item->query()->results().first()->downloadFormats().isEmpty() )
|
||||
{
|
||||
text = tr( "Download %1" ).arg( item->query()->results().first()->downloadFormats().first().extension.toUpper() );
|
||||
}
|
||||
else if ( item->query()->numResults( true ) && !item->query()->results().first()->purchaseUrl().isEmpty() )
|
||||
{
|
||||
text = tr( "Buy" );
|
||||
}
|
||||
|
||||
if ( !item->result() || !item->result()->downloadJob() )
|
||||
{
|
||||
if ( !text.isEmpty() )
|
||||
DropDownButton::drawPrimitive( painter, r, text, m_hoveringOverBuyButton == index, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
painter->setPen( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND.darker() );
|
||||
painter->setBrush( TomahawkStyle::PLAYLIST_PROGRESS_BACKGROUND );
|
||||
painter->drawRect( r.adjusted( 2, 2, -2, -2 ) );
|
||||
painter->setPen( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND );
|
||||
painter->setBrush( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND );
|
||||
QRect fillp = r.adjusted( 3, 3, -3, -3 );
|
||||
fillp.setWidth( float(fillp.width()) * ( float(item->result()->downloadJob()->progressPercentage()) / 100.0 ) );
|
||||
painter->drawRect( fillp );
|
||||
m_buyButtonRects[ index ] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,23 +585,7 @@ GridItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const Q
|
||||
|
||||
if ( hoveringBuyButton )
|
||||
{
|
||||
if ( event->type() == QEvent::MouseButtonRelease )
|
||||
{
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( index ) );
|
||||
if ( !item )
|
||||
return false;
|
||||
|
||||
if ( item->query() && item->query()->numResults( true ) && !item->query()->results().first()->downloadFormats().isEmpty() )
|
||||
{
|
||||
m_view->edit( index );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
WebPopup* popup = new WebPopup( item->query()->results().first()->purchaseUrl(), QSize( 400, 800 ) );
|
||||
connect( item->query()->results().first().data(), SIGNAL( destroyed() ), popup, SLOT( close() ) );
|
||||
}
|
||||
}
|
||||
return DownloadButton::handleEditorEvent( event, m_view, m_model, index );
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -865,63 +815,7 @@ GridItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& opt
|
||||
PlayableItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) );
|
||||
Q_ASSERT( item );
|
||||
|
||||
if ( item->result() && !item->result()->downloadFormats().isEmpty() &&
|
||||
!DownloadManager::instance()->localFileForDownload( item->result()->downloadFormats().first().url.toString() ).isEmpty() )
|
||||
{
|
||||
QDesktopServices::openUrl( QUrl::fromLocalFile( QFileInfo( DownloadManager::instance()->localFileForDownload( item->result()->downloadFormats().first().url.toString() ) ).absolutePath() ) );
|
||||
}
|
||||
else if ( item->result() && item->result()->downloadJob() && item->result()->downloadJob()->state() == DownloadJob::Finished )
|
||||
{
|
||||
QDesktopServices::openUrl( QUrl::fromLocalFile( QFileInfo( item->result()->downloadJob()->localFile() ).absolutePath() ) );
|
||||
}
|
||||
else if ( item->result() &&
|
||||
!item->result()->downloadFormats().isEmpty() && !item->result()->downloadJob() )
|
||||
{
|
||||
QStringList formats;
|
||||
foreach ( const DownloadFormat& format, item->result()->downloadFormats() )
|
||||
{
|
||||
formats << tr( "Download %1" ).arg( format.extension.toUpper() );
|
||||
}
|
||||
|
||||
DropDownButton* editor = new DropDownButton( parent );
|
||||
editor->addItems( formats );
|
||||
|
||||
NewClosure( editor, SIGNAL( clicked() ),
|
||||
const_cast<GridItemDelegate*>(this), SLOT( addDownloadJob( const QModelIndex&, QWidget* ) ), index, (QWidget*)editor );
|
||||
|
||||
NewClosure( editor, SIGNAL( activated( int ) ),
|
||||
const_cast<GridItemDelegate*>(this), SLOT( addDownloadJob( const QModelIndex&, QWidget* ) ), index, (QWidget*)editor );
|
||||
return editor;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GridItemDelegate::addDownloadJob( const QModelIndex& index, QWidget* editor )
|
||||
{
|
||||
PlayableItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) );
|
||||
Q_ASSERT( item );
|
||||
|
||||
m_view->closePersistentEditor( index );
|
||||
|
||||
DropDownButton* cb = static_cast< DropDownButton* >(editor);
|
||||
if ( !item->result()->downloadFormats().isEmpty() )
|
||||
DownloadManager::instance()->addJob( item->result()->toDownloadJob( item->result()->downloadFormats().at( cb->currentIndex() ) ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GridItemDelegate::closeEditor( const QModelIndex& index, QWidget* editor )
|
||||
{
|
||||
PlayableItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) );
|
||||
Q_ASSERT( item );
|
||||
|
||||
m_view->closePersistentEditor( index );
|
||||
|
||||
DropDownButton* cb = static_cast< DropDownButton* >(editor);
|
||||
editor->deleteLater();
|
||||
return DownloadButton::handleCreateEditor( parent, item->query(), m_view, index );
|
||||
}
|
||||
|
||||
|
||||
@@ -930,13 +824,13 @@ GridItemDelegate::updateEditorGeometry( QWidget* editor, const QStyleOptionViewI
|
||||
{
|
||||
QStyledItemDelegate::updateEditorGeometry( editor, option, index );
|
||||
|
||||
DropDownButton* comboBox = static_cast<DropDownButton*>(editor);
|
||||
DownloadButton* comboBox = static_cast<DownloadButton*>(editor);
|
||||
comboBox->resize( option.rect.size() - QSize( 8, 0 ) );
|
||||
comboBox->move( option.rect.x() + 4, option.rect.y() );
|
||||
|
||||
if ( m_downloadDropDownRects.contains( index ) )
|
||||
if ( m_buyButtonRects.contains( index ) )
|
||||
{
|
||||
editor->setGeometry( m_downloadDropDownRects.value( index ) );
|
||||
editor->setGeometry( m_buyButtonRects.value( index ) );
|
||||
}
|
||||
|
||||
if ( !comboBox->property( "shownPopup" ).toBool() )
|
||||
|
@@ -87,9 +87,6 @@ private slots:
|
||||
void fadingFrameChanged( const QPersistentModelIndex& );
|
||||
void fadingFrameFinished( const QPersistentModelIndex& );
|
||||
|
||||
void closeEditor( const QModelIndex& index, QWidget* editor );
|
||||
void addDownloadJob( const QModelIndex& index, QWidget* editor );
|
||||
|
||||
private:
|
||||
QTimeLine* createTimeline( QTimeLine::Direction direction, int startFrame = 0 );
|
||||
void clearButtons();
|
||||
@@ -104,7 +101,6 @@ private:
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_artistNameRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_albumNameRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_buyButtonRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_downloadDropDownRects;
|
||||
mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_covers;
|
||||
|
||||
QPersistentModelIndex m_hoverIndex;
|
||||
|
@@ -59,7 +59,7 @@ public:
|
||||
|
||||
PlayableModel* sourceModel() const { return m_model; }
|
||||
virtual void setSourcePlayableModel( PlayableModel* sourceModel );
|
||||
virtual void setSourceModel( QAbstractItemModel* model );
|
||||
virtual void setSourceModel( QAbstractItemModel* model ) override;
|
||||
|
||||
virtual bool isLoading() const;
|
||||
|
||||
@@ -91,9 +91,9 @@ public:
|
||||
|
||||
QList< double > columnWeights() const;
|
||||
|
||||
virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const;
|
||||
virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
|
||||
virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
|
||||
virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const override;
|
||||
virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override;
|
||||
virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const override;
|
||||
|
||||
virtual void setFilter( const QString& pattern );
|
||||
virtual void updateDetailedInfo( const QModelIndex& index );
|
||||
@@ -120,7 +120,7 @@ signals:
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const Q_DECL_OVERRIDE;
|
||||
virtual bool lessThan( const QModelIndex& left, const QModelIndex& right ) const;
|
||||
virtual bool lessThan( const QModelIndex& left, const QModelIndex& right ) const override;
|
||||
|
||||
Tomahawk::playlistinterface_ptr m_playlistInterface;
|
||||
|
||||
|
@@ -20,15 +20,6 @@
|
||||
|
||||
#include "PlaylistItemDelegate.h"
|
||||
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDesktopServices>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QDesktopServices>
|
||||
#include <QToolTip>
|
||||
|
||||
#include "Query.h"
|
||||
#include "Result.h"
|
||||
#include "Artist.h"
|
||||
@@ -36,8 +27,6 @@
|
||||
#include "Source.h"
|
||||
#include "SourceList.h"
|
||||
|
||||
#include "DownloadManager.h"
|
||||
#include "DownloadJob.h"
|
||||
#include "PlayableModel.h"
|
||||
#include "PlayableItem.h"
|
||||
#include "PlayableProxyModel.h"
|
||||
@@ -45,16 +34,22 @@
|
||||
#include "ViewHeader.h"
|
||||
#include "ViewManager.h"
|
||||
|
||||
#include "widgets/DropDownButton.h"
|
||||
#include "widgets/DownloadButton.h"
|
||||
#include "audio/AudioEngine.h"
|
||||
#include "utils/ImageRegistry.h"
|
||||
#include "utils/PixmapDelegateFader.h"
|
||||
#include "utils/Closure.h"
|
||||
#include "utils/TomahawkStyle.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "utils/WebPopup.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QApplication>
|
||||
#include <QDateTime>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QToolTip>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
@@ -125,63 +120,7 @@ PlaylistItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem&
|
||||
PlayableItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) );
|
||||
Q_ASSERT( item );
|
||||
|
||||
if ( /*index.column() == PlayableModel::Download &&*/ item->result() && !item->result()->downloadFormats().isEmpty() &&
|
||||
!DownloadManager::instance()->localFileForDownload( item->result()->downloadFormats().first().url.toString() ).isEmpty() )
|
||||
{
|
||||
QDesktopServices::openUrl( QUrl::fromLocalFile( QFileInfo( DownloadManager::instance()->localFileForDownload( item->result()->downloadFormats().first().url.toString() ) ).absolutePath() ) );
|
||||
}
|
||||
else if ( /*index.column() == PlayableModel::Download &&*/ item->result() && item->result()->downloadJob() && item->result()->downloadJob()->state() == DownloadJob::Finished )
|
||||
{
|
||||
QDesktopServices::openUrl( QUrl::fromLocalFile( QFileInfo( item->result()->downloadJob()->localFile() ).absolutePath() ) );
|
||||
}
|
||||
else if ( /*index.column() == PlayableModel::Download &&*/ item->result() &&
|
||||
!item->result()->downloadFormats().isEmpty() && !item->result()->downloadJob() )
|
||||
{
|
||||
QStringList formats;
|
||||
foreach ( const DownloadFormat& format, item->result()->downloadFormats() )
|
||||
{
|
||||
formats << tr( "Download %1" ).arg( format.extension );
|
||||
}
|
||||
|
||||
DropDownButton* editor = new DropDownButton( parent );
|
||||
editor->addItems( formats );
|
||||
|
||||
NewClosure( editor, SIGNAL( clicked() ),
|
||||
const_cast<PlaylistItemDelegate*>(this), SLOT( addDownloadJob( const QModelIndex&, QWidget* ) ), index, (QWidget*)editor );
|
||||
|
||||
NewClosure( editor, SIGNAL( activated( int ) ),
|
||||
const_cast<PlaylistItemDelegate*>(this), SLOT( addDownloadJob( const QModelIndex&, QWidget* ) ), index, (QWidget*)editor );
|
||||
return editor;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistItemDelegate::addDownloadJob( const QModelIndex& index, QWidget* editor )
|
||||
{
|
||||
PlayableItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) );
|
||||
Q_ASSERT( item );
|
||||
|
||||
m_view->closePersistentEditor( index );
|
||||
|
||||
DropDownButton* cb = static_cast< DropDownButton* >(editor);
|
||||
if ( !item->result()->downloadFormats().isEmpty() )
|
||||
DownloadManager::instance()->addJob( item->result()->toDownloadJob( item->result()->downloadFormats().at( cb->currentIndex() ) ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlaylistItemDelegate::closeEditor( const QModelIndex& index, QWidget* editor )
|
||||
{
|
||||
PlayableItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) );
|
||||
Q_ASSERT( item );
|
||||
|
||||
m_view->closePersistentEditor( index );
|
||||
|
||||
DropDownButton* cb = static_cast< DropDownButton* >(editor);
|
||||
editor->deleteLater();
|
||||
return DownloadButton::handleCreateEditor( parent, item->query(), m_view, index );
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +129,7 @@ PlaylistItemDelegate::updateEditorGeometry( QWidget* editor, const QStyleOptionV
|
||||
{
|
||||
QStyledItemDelegate::updateEditorGeometry( editor, option, index );
|
||||
|
||||
DropDownButton* comboBox = static_cast<DropDownButton*>(editor);
|
||||
DownloadButton* comboBox = static_cast<DownloadButton*>(editor);
|
||||
comboBox->resize( option.rect.size() - QSize( 8, 0 ) );
|
||||
comboBox->move( option.rect.x() + 4, option.rect.y() );
|
||||
|
||||
@@ -277,69 +216,7 @@ PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewIt
|
||||
else */
|
||||
if ( m_view->proxyModel()->style() == PlayableProxyModel::Locker && index.column() == PlayableModel::Download )
|
||||
{
|
||||
if ( item->result() && !item->result()->downloadFormats().isEmpty() )
|
||||
{
|
||||
QStyleOptionComboBox optc;
|
||||
optc.rect = opt.rect.adjusted( 4, 0, -4, 0 );
|
||||
optc.editable = false;
|
||||
optc.currentText = tr( "Download %1" ).arg( item->result()->downloadFormats().first().extension );
|
||||
optc.palette = m_view->palette();
|
||||
|
||||
if ( option.state & QStyle::State_Selected && option.state & QStyle::State_Active )
|
||||
optc.state = QStyle::State_Active | QStyle::State_Selected | QStyle::State_Enabled;
|
||||
else
|
||||
optc.state = QStyle::State_Active | QStyle::State_Enabled;
|
||||
|
||||
if ( !DownloadManager::instance()->localFileForDownload( item->result()->downloadFormats().first().url.toString() ).isEmpty() )
|
||||
{
|
||||
painter->setPen( opt.palette.text().color() );
|
||||
const QString text = painter->fontMetrics().elidedText( tr( "View in Finder" ), Qt::ElideRight, opt.rect.width() - 3 );
|
||||
painter->drawText( opt.rect, text, textOption );
|
||||
}
|
||||
else if ( !item->result()->downloadJob() )
|
||||
{
|
||||
DropDownButton::drawPrimitive( painter, optc.rect, optc.currentText, hoveringOver() == index, true );
|
||||
|
||||
/* QApplication::style()->drawComplexControl( QStyle::CC_ComboBox, &optc, painter, 0 );
|
||||
optc.rect.adjust( 4, 0, 0, 0 );
|
||||
QApplication::style()->drawControl( QStyle::CE_ComboBoxLabel, &optc, painter, 0 );*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( item->result()->downloadJob()->state() == DownloadJob::Finished )
|
||||
{
|
||||
painter->setPen( opt.palette.text().color() );
|
||||
const QString text = painter->fontMetrics().elidedText( tr( "View in Finder" ), Qt::ElideRight, opt.rect.width() - 3 );
|
||||
painter->drawText( opt.rect, text, textOption );
|
||||
}
|
||||
else
|
||||
{
|
||||
painter->setPen( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND.darker() );
|
||||
painter->setBrush( TomahawkStyle::PLAYLIST_PROGRESS_BACKGROUND );
|
||||
painter->drawRect( optc.rect.adjusted( 2, 2, -2, -2 ) );
|
||||
painter->setPen( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND );
|
||||
painter->setBrush( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND );
|
||||
QRect fillp = optc.rect.adjusted( 3, 3, -3, -3 );
|
||||
fillp.setWidth( float(fillp.width()) * ( float(item->result()->downloadJob()->progressPercentage()) / 100.0 ) );
|
||||
painter->drawRect( fillp );
|
||||
|
||||
/* QStyleOptionProgressBarV2 optp;
|
||||
optp.rect = optc.rect;
|
||||
optp.minimum = 0;
|
||||
optp.maximum = 100;
|
||||
optp.progress = item->result()->downloadJob()->progressPercentage();
|
||||
optp.palette = m_view->palette();
|
||||
optp.palette.setColor( QPalette::Highlight, QColor( "#E61878" ) );
|
||||
|
||||
if ( option.state & QStyle::State_Selected && option.state & QStyle::State_Active )
|
||||
optp.state = QStyle::State_Active | QStyle::State_Selected | QStyle::State_Enabled;
|
||||
else
|
||||
optp.state = QStyle::State_Active | QStyle::State_Enabled;
|
||||
|
||||
QApplication::style()->drawControl( QStyle::CE_ProgressBar, &optp, painter, 0 );*/
|
||||
}
|
||||
}
|
||||
}
|
||||
DownloadButton::drawPrimitive( painter, opt.rect.adjusted( 4, 0, -4, 0 ), item->query(), hoveringOver() == index );
|
||||
}
|
||||
else if ( item->isPlaying() )
|
||||
{
|
||||
@@ -657,67 +534,14 @@ PlaylistItemDelegate::drawTrack( QPainter* painter, const QStyleOptionViewItem&
|
||||
|
||||
stateWidth += r.width() + 16;
|
||||
}
|
||||
|
||||
if ( hasOnlineResults && !item->query()->results().first()->purchaseUrl().isEmpty() )
|
||||
{
|
||||
QRect r = stateRect.adjusted( -stateWidth -144, 6, 0, -6 );
|
||||
r.setWidth( 144 );
|
||||
DropDownButton::drawPrimitive( painter, r, tr( "Buy" ), m_hoveringOverBuyButton == index, false );
|
||||
|
||||
m_buyButtonRects[ index ] = r;
|
||||
|
||||
stateWidth += r.width() + 16;
|
||||
}
|
||||
}
|
||||
|
||||
if ( hasOnlineResults && !item->query()->results().first()->downloadFormats().isEmpty() )
|
||||
QRect downloadButtonRect = stateRect.adjusted( -stateWidth -144, 6, 0, -6 );
|
||||
downloadButtonRect.setWidth( 144 );
|
||||
stateWidth += downloadButtonRect.width() + 16;
|
||||
if ( DownloadButton::drawPrimitive( painter, downloadButtonRect, item->query(), m_hoveringOverDownloadButton == index ) )
|
||||
{
|
||||
painter->save();
|
||||
QStyleOptionComboBox optc;
|
||||
optc.rect = stateRect.adjusted( -stateWidth -144, 6, 0, -6 );
|
||||
optc.rect.setWidth( 144 );
|
||||
m_downloadDropDownRects[ index ] = optc.rect;
|
||||
stateWidth += optc.rect.width() + 16;
|
||||
optc.editable = false;
|
||||
optc.currentText = tr( "Download %1" ).arg( item->query()->results().first()->downloadFormats().first().extension.toUpper() );
|
||||
optc.palette = m_view->palette();
|
||||
|
||||
if ( option.state & QStyle::State_Selected && option.state & QStyle::State_Active )
|
||||
optc.state = QStyle::State_Active | QStyle::State_Selected | QStyle::State_Enabled;
|
||||
else
|
||||
optc.state = QStyle::State_Active | QStyle::State_Enabled;
|
||||
|
||||
if ( !DownloadManager::instance()->localFileForDownload( item->query()->results().first()->downloadFormats().first().url.toString() ).isEmpty() )
|
||||
{
|
||||
painter->setPen( optc.palette.text().color() );
|
||||
const QString text = painter->fontMetrics().elidedText( tr( "View in Finder" ), Qt::ElideRight, optc.rect.width() - 3 );
|
||||
painter->drawText( optc.rect, text, QTextOption( Qt::AlignCenter ) );
|
||||
}
|
||||
else if ( !item->query()->results().first()->downloadJob() )
|
||||
{
|
||||
DropDownButton::drawPrimitive( painter, optc.rect, optc.currentText, hoveringOver() == index, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( item->query()->results().first()->downloadJob()->state() == DownloadJob::Finished )
|
||||
{
|
||||
painter->setPen( optc.palette.text().color() );
|
||||
const QString text = painter->fontMetrics().elidedText( tr( "View in Finder" ), Qt::ElideRight, optc.rect.width() - 3 );
|
||||
painter->drawText( optc.rect, text, QTextOption( Qt::AlignCenter ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
painter->setPen( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND.darker() );
|
||||
painter->setBrush( TomahawkStyle::PLAYLIST_PROGRESS_BACKGROUND );
|
||||
painter->drawRect( optc.rect.adjusted( 2, 2, -2, -2 ) );
|
||||
painter->setPen( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND );
|
||||
painter->setBrush( TomahawkStyle::PLAYLIST_PROGRESS_FOREGROUND );
|
||||
QRect fillp = optc.rect.adjusted( 3, 3, -3, -3 );
|
||||
fillp.setWidth( float(fillp.width()) * ( float(item->query()->results().first()->downloadJob()->progressPercentage()) / 100.0 ) );
|
||||
painter->drawRect( fillp );
|
||||
}
|
||||
}
|
||||
painter->restore();
|
||||
m_downloadDropDownRects[ index ] = downloadButtonRect;
|
||||
}
|
||||
|
||||
const int remWidth = r.width() - numberWidth - durationWidth;
|
||||
@@ -835,7 +659,6 @@ PlaylistItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, con
|
||||
bool hoveringArtist = false;
|
||||
bool hoveringInfo = false;
|
||||
bool hoveringLove = false;
|
||||
bool hoveringBuy = false;
|
||||
bool hoveringDownloadDropDown = false;
|
||||
Tomahawk::source_ptr hoveredAvatar;
|
||||
QRect hoveredAvatarRect;
|
||||
@@ -858,12 +681,6 @@ PlaylistItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, con
|
||||
const QMouseEvent* ev = static_cast< QMouseEvent* >( event );
|
||||
hoveringLove = loveRect.contains( ev->pos() );
|
||||
}
|
||||
if ( m_buyButtonRects.contains( index ) )
|
||||
{
|
||||
const QRect buyRect = m_buyButtonRects[ index ];
|
||||
const QMouseEvent* ev = static_cast< QMouseEvent* >( event );
|
||||
hoveringBuy = buyRect.contains( ev->pos() );
|
||||
}
|
||||
if ( m_downloadDropDownRects.contains( index ) )
|
||||
{
|
||||
const QRect downloadDropDownRect = m_downloadDropDownRects[ index ];
|
||||
@@ -887,7 +704,7 @@ PlaylistItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, con
|
||||
|
||||
if ( event->type() == QEvent::MouseMove )
|
||||
{
|
||||
if ( hoveringInfo || hoveringLove || hoveringArtist || hoveringBuy )
|
||||
if ( hoveringInfo || hoveringLove || hoveringArtist || hoveringDownloadDropDown )
|
||||
m_view->setCursor( Qt::PointingHandCursor );
|
||||
else
|
||||
m_view->setCursor( Qt::ArrowCursor );
|
||||
@@ -911,19 +728,19 @@ PlaylistItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, con
|
||||
emit updateIndex( m_hoveringOverArtist );
|
||||
m_hoveringOverArtist = QModelIndex();
|
||||
}
|
||||
if ( hoveringBuy && m_hoveringOverBuyButton != index )
|
||||
if ( hoveringDownloadDropDown && m_hoveringOverDownloadButton != index )
|
||||
{
|
||||
QPersistentModelIndex ti = m_hoveringOverBuyButton;
|
||||
m_hoveringOverBuyButton = index;
|
||||
QPersistentModelIndex ti = m_hoveringOverDownloadButton;
|
||||
m_hoveringOverDownloadButton = index;
|
||||
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( ti ) );
|
||||
item->requestRepaint();
|
||||
emit updateIndex( m_hoveringOverBuyButton );
|
||||
emit updateIndex( m_hoveringOverDownloadButton );
|
||||
}
|
||||
if ( !hoveringBuy && m_hoveringOverBuyButton.isValid() )
|
||||
if ( !hoveringDownloadDropDown && m_hoveringOverDownloadButton.isValid() )
|
||||
{
|
||||
QPersistentModelIndex ti = m_hoveringOverBuyButton;
|
||||
m_hoveringOverBuyButton = QModelIndex();
|
||||
QPersistentModelIndex ti = m_hoveringOverDownloadButton;
|
||||
m_hoveringOverDownloadButton = QModelIndex();
|
||||
|
||||
PlayableItem* item = m_model->sourceModel()->itemFromIndex( m_model->mapToSource( ti ) );
|
||||
item->requestRepaint();
|
||||
@@ -957,10 +774,10 @@ PlaylistItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, con
|
||||
{
|
||||
item->query()->queryTrack()->setLoved( !item->query()->queryTrack()->loved() );
|
||||
}
|
||||
else if ( hoveringBuy )
|
||||
else if ( hoveringDownloadDropDown || ( m_view->proxyModel()->style() == PlayableProxyModel::Locker && index.column() == PlayableModel::Download ) )
|
||||
{
|
||||
WebPopup* popup = new WebPopup( item->query()->results().first()->purchaseUrl(), QSize( 400, 800 ) );
|
||||
connect( item->query()->results().first().data(), SIGNAL( destroyed() ), popup, SLOT( close() ) );
|
||||
if ( DownloadButton::handleEditorEvent( event , m_view, m_model, index ) )
|
||||
return true;
|
||||
}
|
||||
else if ( hoveringInfo )
|
||||
{
|
||||
@@ -996,13 +813,6 @@ PlaylistItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, con
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( ( m_view->proxyModel()->style() == PlayableProxyModel::Locker && index.column() == PlayableModel::Download ) || hoveringDownloadDropDown )
|
||||
{
|
||||
m_model->sourceModel()->setAllColumnsEditable( true );
|
||||
m_view->edit( index );
|
||||
m_model->sourceModel()->setAllColumnsEditable( false );
|
||||
return true;
|
||||
}
|
||||
|
||||
event->accept();
|
||||
return true;
|
||||
@@ -1022,10 +832,9 @@ PlaylistItemDelegate::resetHoverIndex()
|
||||
|
||||
m_hoveringOver = QModelIndex();
|
||||
m_hoveringOverArtist = QModelIndex();
|
||||
m_hoveringOverBuyButton = QModelIndex();
|
||||
m_hoveringOverDownloadButton = QModelIndex();
|
||||
m_infoButtonRects.clear();
|
||||
m_loveButtonRects.clear();
|
||||
m_buyButtonRects.clear();
|
||||
m_artistNameRects.clear();
|
||||
|
||||
QModelIndex itemIdx = m_model->mapToSource( idx );
|
||||
|
@@ -57,8 +57,6 @@ signals:
|
||||
|
||||
private slots:
|
||||
void doUpdateIndex( const QPersistentModelIndex& index );
|
||||
void closeEditor( const QModelIndex& index, QWidget* editor );
|
||||
void addDownloadJob( const QModelIndex& index, QWidget* editor );
|
||||
|
||||
protected:
|
||||
void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ) const;
|
||||
@@ -116,13 +114,12 @@ private:
|
||||
mutable QHash< QPersistentModelIndex, QSharedPointer< Tomahawk::PixmapDelegateFader > > m_pixmaps;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_infoButtonRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_loveButtonRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_buyButtonRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_downloadDropDownRects;
|
||||
mutable QHash< QPersistentModelIndex, QRect > m_artistNameRects;
|
||||
mutable QHash< QPersistentModelIndex, QHash< Tomahawk::source_ptr, QRect > > m_avatarBoxRects;
|
||||
QPersistentModelIndex m_hoveringOver;
|
||||
QPersistentModelIndex m_hoveringOverArtist;
|
||||
QPersistentModelIndex m_hoveringOverBuyButton;
|
||||
QPersistentModelIndex m_hoveringOverDownloadButton;
|
||||
mutable QPersistentModelIndex m_nowPlaying;
|
||||
|
||||
TrackView* m_view;
|
||||
|
@@ -18,12 +18,6 @@
|
||||
|
||||
#include "TrackDetailView.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QSizePolicy>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Album.h"
|
||||
#include "Track.h"
|
||||
#include "audio/AudioEngine.h"
|
||||
@@ -39,6 +33,13 @@
|
||||
#include "utils/WebPopup.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QSizePolicy>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDesktopServices>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
TrackDetailView::TrackDetailView( QWidget* parent )
|
||||
@@ -197,7 +198,7 @@ TrackDetailView::setQuery( const Tomahawk::query_ptr& query )
|
||||
|
||||
connect( m_query->track().data(), SIGNAL( updated() ), SLOT( onCoverUpdated() ) );
|
||||
connect( m_query->track().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ) );
|
||||
connect( m_query.data(), SIGNAL( resultsChanged() ), SLOT( onResultsChanged() ) );
|
||||
connect( m_query.data(), SIGNAL( resultsChanged() ), SLOT( onResultsChanged() ), Qt::QueuedConnection );
|
||||
connect( m_query.data(), SIGNAL( resultsChanged() ), SLOT( onAlbumUpdated() ) );
|
||||
}
|
||||
|
||||
@@ -219,8 +220,44 @@ TrackDetailView::onAlbumUpdated()
|
||||
{
|
||||
if ( m_query->track()->albumPtr()->purchased() )
|
||||
{
|
||||
m_buyButton->setText( tr( "Download Album" ) );
|
||||
m_buyButton->setVisible( true );
|
||||
m_allTracksAvailableLocally = true;
|
||||
foreach( const query_ptr& currentQuery, m_playlistInterface->tracks() )
|
||||
{
|
||||
if ( currentQuery->results().isEmpty() )
|
||||
{
|
||||
m_allTracksAvailableLocally = false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_allTracksAvailableLocally = false;
|
||||
foreach ( const result_ptr& currentResult, currentQuery->results() )
|
||||
{
|
||||
QList< DownloadFormat > formats = currentResult->downloadFormats();
|
||||
bool isDownloaded = formats.isEmpty() ? false : !DownloadManager::instance()->localFileForDownload( currentResult->downloadFormats().first().url.toString() ).isEmpty();
|
||||
if ( currentResult->isLocal() || isDownloaded )
|
||||
{
|
||||
m_allTracksAvailableLocally = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !m_allTracksAvailableLocally )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_allTracksAvailableLocally )
|
||||
{
|
||||
m_buyButton->setText( tr( "View in Folder" ) );
|
||||
m_buyButton->setVisible( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_buyButton->setText( tr( "Download Album" ) );
|
||||
m_buyButton->setVisible( true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -251,7 +288,14 @@ TrackDetailView::onBuyButtonClicked()
|
||||
{
|
||||
if ( m_query->track()->albumPtr()->purchased() )
|
||||
{
|
||||
emit downloadAll();
|
||||
if ( m_allTracksAvailableLocally )
|
||||
{
|
||||
QDesktopServices::openUrl( QUrl::fromLocalFile( DownloadJob::localPath( m_query->track()->albumPtr() ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
emit downloadAll();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -344,7 +388,7 @@ TrackDetailView::onResultsChanged()
|
||||
resolverIcon->setFixedWidth( 12 );
|
||||
resolverIcon->setPixmap( result->sourceIcon( TomahawkUtils::RoundedCorners, QSize( 12, 12 ) ) );
|
||||
|
||||
QLabel* resolverLabel = new ClickableLabel( this );
|
||||
ClickableLabel* resolverLabel = new ClickableLabel( this );
|
||||
resolverLabel->setFont( f );
|
||||
resolverLabel->setStyleSheet( "QLabel { color: rgba( 0, 0, 0, 50% ) }" );
|
||||
resolverLabel->setText( QString( "%1 - %2" ).arg( result->track()->track() ).arg( result->track()->artist() ) );
|
||||
@@ -359,8 +403,8 @@ TrackDetailView::onResultsChanged()
|
||||
;
|
||||
resolverLabel->setFixedWidth( width() - 32 - 4 );
|
||||
|
||||
NewClosure( resolverLabel, SIGNAL( clicked() ), const_cast< AudioEngine* >( AudioEngine::instance() ),
|
||||
SLOT( playItem( Tomahawk::playlistinterface_ptr, Tomahawk::result_ptr, Tomahawk::query_ptr ) ),
|
||||
NewClosure( resolverLabel, SIGNAL( clicked() ), const_cast< TrackDetailView* >( this ),
|
||||
SLOT( onResultClicked( Tomahawk::playlistinterface_ptr, Tomahawk::result_ptr, Tomahawk::query_ptr ) ),
|
||||
m_playlistInterface, result, m_query )->setAutoDelete( false );
|
||||
|
||||
QWidget* hbox = new QWidget;
|
||||
@@ -397,3 +441,13 @@ TrackDetailView::setBuyButtonVisible( bool visible )
|
||||
{
|
||||
m_buyButtonVisible = visible;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TrackDetailView::onResultClicked( const Tomahawk::playlistinterface_ptr& playlist, const Tomahawk::result_ptr& result, const Tomahawk::query_ptr& fromQuery )
|
||||
{
|
||||
fromQuery->setPreferredResult( result );
|
||||
if (AudioEngine::instance()->isPlaying() && fromQuery->results().contains( AudioEngine::instance()->currentTrack() )) {
|
||||
AudioEngine::instance()->playItem( playlist, result, fromQuery );
|
||||
}
|
||||
}
|
||||
|
@@ -64,6 +64,8 @@ private slots:
|
||||
void onBuyButtonClicked();
|
||||
void onDownloadManagerStateChanged( DownloadManager::DownloadManagerState newState, DownloadManager::DownloadManagerState oldState );
|
||||
|
||||
void onResultClicked( const Tomahawk::playlistinterface_ptr& playlist, const Tomahawk::result_ptr& result, const Tomahawk::query_ptr& fromQuery );
|
||||
|
||||
private:
|
||||
void setSocialActions();
|
||||
|
||||
@@ -77,6 +79,7 @@ private:
|
||||
CaptionLabel* m_resultsBoxLabel;
|
||||
QPushButton* m_buyButton;
|
||||
bool m_buyButtonVisible;
|
||||
bool m_allTracksAvailableLocally;
|
||||
|
||||
QWidget* m_infoBox;
|
||||
QWidget* m_resultsBox;
|
||||
|
@@ -383,6 +383,8 @@ void
|
||||
TrackView::currentChanged( const QModelIndex& current, const QModelIndex& previous )
|
||||
{
|
||||
QTreeView::currentChanged( current, previous );
|
||||
if ( !m_model )
|
||||
return;
|
||||
|
||||
PlayableItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( current ) );
|
||||
if ( item && item->query() )
|
||||
|
@@ -247,8 +247,8 @@ TreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent
|
||||
if ( !item->result()->isOnline() && ti->result()->isOnline() )
|
||||
return false;
|
||||
|
||||
if ( ( item->result()->resolvedByCollection().isNull() || !item->result()->resolvedByCollection()->isLocal() ) &&
|
||||
!ti->result()->resolvedByCollection().isNull() && ti->result()->resolvedByCollection()->isLocal() )
|
||||
if ( ( !item->result()->isLocal() ) &&
|
||||
!ti->result()->isLocal() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@@ -156,6 +156,7 @@ XspfUpdater::setAutoUpdate( bool autoUpdate )
|
||||
emit changed();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
XspfUpdater::setInterval( int intervalMsecs )
|
||||
{
|
||||
|
@@ -190,7 +190,7 @@ JSAccount::reportNativeScriptJobResult( int resultId, const QVariantMap& result
|
||||
.arg( serializeQVariantMap( result ) );
|
||||
|
||||
// Remove when new scripting api turned out to work reliably
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << eval;
|
||||
//tDebug( LOGVERBOSE ) << Q_FUNC_INFO << eval;
|
||||
|
||||
evaluateJavaScript( eval );
|
||||
}
|
||||
|
@@ -711,3 +711,14 @@ JSResolver::getStreamUrl( const result_ptr& result )
|
||||
|
||||
return scriptObject()->invoke( "getStreamUrl", arguments );
|
||||
}
|
||||
|
||||
ScriptJob*
|
||||
JSResolver::getDownloadUrl( const result_ptr& result, const DownloadFormat& format )
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments["url"] = format.url.toString();
|
||||
arguments["extension"] = format.extension;
|
||||
arguments["mimetype"] = format.mimetype;
|
||||
|
||||
return scriptObject()->invoke( "getDownloadUrl", arguments );
|
||||
}
|
||||
|
@@ -76,6 +76,8 @@ public:
|
||||
ScriptAccount* scriptAccount() const;
|
||||
|
||||
ScriptJob* getStreamUrl( const result_ptr& result ) override;
|
||||
ScriptJob* getDownloadUrl( const result_ptr& result, const DownloadFormat &format ) override;
|
||||
|
||||
|
||||
public slots:
|
||||
void resolve( const Tomahawk::query_ptr& query ) override;
|
||||
|
@@ -45,3 +45,12 @@ Tomahawk::Resolver::getStreamUrl( const result_ptr& result )
|
||||
|
||||
return new SyncScriptJob( data );
|
||||
}
|
||||
|
||||
Tomahawk::ScriptJob*
|
||||
Tomahawk::Resolver::getDownloadUrl( const result_ptr& result, const DownloadFormat& format )
|
||||
{
|
||||
QVariantMap data;
|
||||
data[ "url" ] = format.url.toString();
|
||||
|
||||
return new SyncScriptJob( data );
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "Typedefs.h"
|
||||
#include "DllMacro.h"
|
||||
#include "../DownloadJob.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
@@ -52,6 +53,7 @@ public:
|
||||
|
||||
virtual void resolve( const Tomahawk::query_ptr& query ) = 0;
|
||||
virtual ScriptJob* getStreamUrl( const result_ptr& result );
|
||||
virtual ScriptJob* getDownloadUrl( const result_ptr& result, const DownloadFormat& format );
|
||||
};
|
||||
|
||||
} //ns
|
||||
|
@@ -1,12 +1,12 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright (C) 2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2014, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2015-2016, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
@@ -17,6 +17,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptAccount.h"
|
||||
|
||||
#include "ScriptObject.h"
|
||||
@@ -31,11 +32,11 @@
|
||||
#include "ScriptLinkGeneratorPlugin.h"
|
||||
#include "ScriptInfoPlugin.h"
|
||||
|
||||
// TODO:
|
||||
#include "../Artist.h"
|
||||
#include "../Album.h"
|
||||
#include "../Result.h"
|
||||
#include "../Track.h"
|
||||
|
||||
#include <QTime>
|
||||
|
||||
|
||||
@@ -155,11 +156,17 @@ ScriptAccount::reportScriptJobResult( const QVariantMap& result )
|
||||
Q_ASSERT( job );
|
||||
|
||||
// got a successful job result
|
||||
if ( result[ "error"].isNull() )
|
||||
if ( result[ "error" ].isNull() )
|
||||
{
|
||||
const QVariantMap data = result[ "data" ].toMap();
|
||||
|
||||
job->reportResults( data );
|
||||
if ( result[ "data" ].type() == QVariant::Map )
|
||||
{
|
||||
const QVariantMap data = result[ "data" ].toMap();
|
||||
job->reportResultsMap( data );
|
||||
}
|
||||
else
|
||||
{
|
||||
job->reportResults( result[ "data" ] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -1,12 +1,12 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright (C) 2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
* Copyright 2014, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2015-2016, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
|
@@ -53,6 +53,7 @@ ScriptCollection::ScriptCollection( const scriptobject_ptr& scriptObject,
|
||||
qDebug() << Q_FUNC_INFO << scriptAccount->name() << Collection::name();
|
||||
|
||||
m_servicePrettyName = scriptAccount->name();
|
||||
m_weight = readMetaData().value( "weight", 99 ).toUInt();
|
||||
}
|
||||
|
||||
|
||||
@@ -235,6 +236,16 @@ ScriptCollection::getStreamUrl( const result_ptr& result )
|
||||
return scriptObject()->invoke( "getStreamUrl", arguments );
|
||||
}
|
||||
|
||||
ScriptJob*
|
||||
ScriptCollection::getDownloadUrl( const result_ptr& result, const DownloadFormat& format )
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments["url"] = format.url.toString();
|
||||
arguments["extension"] = format.extension;
|
||||
arguments["mimetype"] = format.mimetype;
|
||||
|
||||
return scriptObject()->invoke( "getDownloadUrl", arguments );
|
||||
}
|
||||
|
||||
void
|
||||
ScriptCollection::parseMetaData( const QVariantMap& metadata )
|
||||
@@ -350,7 +361,7 @@ ScriptCollection::timeout() const
|
||||
unsigned int
|
||||
ScriptCollection::weight() const
|
||||
{
|
||||
return 0;
|
||||
return m_weight;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -96,6 +96,7 @@ public:
|
||||
unsigned int timeout() const override;
|
||||
void resolve( const Tomahawk::query_ptr& query ) override;
|
||||
ScriptJob* getStreamUrl( const result_ptr& result ) override;
|
||||
ScriptJob* getDownloadUrl( const result_ptr& result, const DownloadFormat &format ) override;
|
||||
|
||||
private slots:
|
||||
void onIconFetched();
|
||||
@@ -106,6 +107,7 @@ private:
|
||||
QString m_servicePrettyName;
|
||||
QString m_description;
|
||||
int m_trackCount;
|
||||
int m_weight;
|
||||
QPixmap m_icon;
|
||||
bool m_isOnline;
|
||||
};
|
||||
|
@@ -41,12 +41,12 @@ public:
|
||||
void setFilter( const QString& filter ) override;
|
||||
|
||||
signals:
|
||||
void albums( const QList< Tomahawk::album_ptr >& );
|
||||
void done();
|
||||
void albums( const QList< Tomahawk::album_ptr >& ) override;
|
||||
void done() override;
|
||||
|
||||
protected:
|
||||
virtual void exec();
|
||||
virtual void reportFailure();
|
||||
virtual void exec() override;
|
||||
virtual void reportFailure() override;
|
||||
|
||||
private slots:
|
||||
void onAlbumsJobDone( const QVariantMap& result );
|
||||
|
@@ -42,8 +42,8 @@ public:
|
||||
void setFilter( const QString& filter ) override;
|
||||
|
||||
signals:
|
||||
void artists( const QList< Tomahawk::artist_ptr >& );
|
||||
void done();
|
||||
void artists( const QList< Tomahawk::artist_ptr >& ) override;
|
||||
void done() override;
|
||||
|
||||
protected:
|
||||
void exec() override;
|
||||
|
@@ -39,8 +39,8 @@ public:
|
||||
void enqueue() override;
|
||||
|
||||
signals:
|
||||
void tracks( const QList< Tomahawk::query_ptr >& );
|
||||
void done();
|
||||
void tracks( const QList< Tomahawk::query_ptr >& ) override;
|
||||
void done() override;
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void exec() override;
|
||||
|
@@ -45,7 +45,7 @@ public:
|
||||
|
||||
signals:
|
||||
void information( const QString& url, const QSharedPointer<QObject>& variant );
|
||||
void done();
|
||||
void done() override;
|
||||
|
||||
protected:
|
||||
void exec() override;
|
||||
|
@@ -82,7 +82,15 @@ ScriptJob::arguments() const
|
||||
|
||||
|
||||
void
|
||||
ScriptJob::reportResults( const QVariantMap& data )
|
||||
ScriptJob::reportResultsMap( const QVariantMap& data )
|
||||
{
|
||||
m_data = data;
|
||||
emit done( data );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptJob::reportResults( const QVariant& data )
|
||||
{
|
||||
m_data = data;
|
||||
emit done( data );
|
||||
@@ -94,5 +102,6 @@ ScriptJob::reportFailure( const QString& errorMessage )
|
||||
{
|
||||
emit error( errorMessage );
|
||||
|
||||
reportResults( QVariantMap() );
|
||||
reportResults();
|
||||
reportResultsMap();
|
||||
}
|
||||
|
@@ -49,11 +49,13 @@ public:
|
||||
QVariantMap arguments() const;
|
||||
|
||||
public slots:
|
||||
void reportResults( const QVariantMap& data = QVariantMap() );
|
||||
void reportResultsMap( const QVariantMap& data = QVariantMap() );
|
||||
void reportResults( const QVariant& data = QVariant() );
|
||||
void reportFailure( const QString& errorMessage );
|
||||
|
||||
signals:
|
||||
void done( const QVariantMap& result );
|
||||
void done( const QVariant& result );
|
||||
void error( const QString& errorMessage );
|
||||
|
||||
void destroyed( const QString& id );
|
||||
@@ -63,7 +65,7 @@ protected:
|
||||
bool m_error;
|
||||
QString m_id;
|
||||
scriptobject_ptr m_scriptObject;
|
||||
QVariantMap m_data;
|
||||
QVariant m_data;
|
||||
QString m_methodName;
|
||||
QVariantMap m_arguments;
|
||||
};
|
||||
|
@@ -42,7 +42,7 @@ ScriptJob*
|
||||
ScriptLinkGeneratorPlugin::openLink( const QString& title, const QString& artist, const QString& album ) const
|
||||
{
|
||||
QVariantMap arguments;
|
||||
arguments[ "title" ] = QVariant( title );
|
||||
arguments[ "track" ] = QVariant( title );
|
||||
arguments[ "artist" ] = QVariant( artist );
|
||||
arguments[ "album" ] = QVariant( album );
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2014, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
@@ -15,6 +15,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptPlugin.h"
|
||||
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2014, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
|
@@ -1,10 +1,10 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2015 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2015, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
@@ -15,4 +15,5 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptPluginFactory.h"
|
||||
|
@@ -1,10 +1,10 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2015 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2015, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
|
@@ -1,10 +1,10 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2014, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
@@ -15,6 +15,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SyncScriptJob.h"
|
||||
|
||||
#include "../Typedefs.h"
|
||||
@@ -30,5 +31,5 @@ Tomahawk::SyncScriptJob::SyncScriptJob( const QVariantMap& resultData )
|
||||
void
|
||||
Tomahawk::SyncScriptJob::start()
|
||||
{
|
||||
QMetaObject::invokeMethod( this, "reportResults", Qt::QueuedConnection, Q_ARG( QVariantMap, m_data ) );
|
||||
QMetaObject::invokeMethod( this, "reportResultsMap", Qt::QueuedConnection, Q_ARG( QVariantMap, m_data.toMap() ) );
|
||||
}
|
||||
|
@@ -1,10 +1,10 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2014 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2014, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
|
@@ -1,10 +1,10 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright (C) 2015 Dominik Schmidt <domme@tomahawk-player.org>
|
||||
* Copyright 2015, Dominik Schmidt <domme@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
@@ -15,6 +15,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptCollectionFactory.h"
|
||||
|
||||
#include "SourceList.h"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user