Start of some spotify support - builds a binary blob linked against libspotify that Clementine starts as a separate process.
This commit is contained in:
parent
4d19917b05
commit
e152e3a3e3
@ -46,6 +46,7 @@ find_package(OpenGL REQUIRED)
|
||||
find_package(Boost REQUIRED)
|
||||
find_package(Gettext REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Protobuf)
|
||||
|
||||
pkg_check_modules(TAGLIB REQUIRED taglib>=1.6)
|
||||
pkg_check_modules(GSTREAMER gstreamer-0.10)
|
||||
@ -61,6 +62,7 @@ pkg_check_modules(USBMUXD libusbmuxd)
|
||||
pkg_check_modules(LIBMTP libmtp>=1.0)
|
||||
pkg_check_modules(INDICATEQT indicate-qt)
|
||||
pkg_check_modules(ARCHIVE libarchive)
|
||||
pkg_check_modules(SPOTIFY libspotify)
|
||||
|
||||
if (WIN32)
|
||||
find_package(ZLIB REQUIRED)
|
||||
@ -103,11 +105,13 @@ find_path(LASTFM_INCLUDE_DIRS lastfm/ws.h)
|
||||
|
||||
if (APPLE)
|
||||
find_library(GROWL Growl)
|
||||
|
||||
option(ENABLE_SPARKLE "Sparkle updating" ON)
|
||||
find_library(SPARKLE Sparkle)
|
||||
if (ENABLE_SPARKLE AND SPARKLE)
|
||||
set(HAVE_SPARKLE ON)
|
||||
endif (ENABLE_SPARKLE AND SPARKLE)
|
||||
|
||||
# Uses Darwin kernel version.
|
||||
# 9.8.0 -> 10.5/Leopard
|
||||
# 10.4.0 -> 10.6/Snow Leopard
|
||||
@ -177,6 +181,7 @@ option(ENABLE_SCRIPTING_ARCHIVES "Enable support for loading scripts from archiv
|
||||
option(ENABLE_SCRIPTING_PYTHON "Enable python scripting" ON)
|
||||
option(ENABLE_REMOTE "Enable support for using remote controls with Clementine" OFF)
|
||||
option(ENABLE_BREAKPAD "Enable crash reporting" OFF)
|
||||
option(ENABLE_SPOTIFY "Enable spotify support" OFF)
|
||||
|
||||
if(WIN32)
|
||||
option(ENABLE_WIN32_CONSOLE "Show the windows console even outside Debug mode" OFF)
|
||||
@ -222,6 +227,11 @@ if(ENABLE_BREAKPAD)
|
||||
set(HAVE_BREAKPAD ON)
|
||||
endif(ENABLE_BREAKPAD)
|
||||
|
||||
if(ENABLE_SPOTIFY AND SPOTIFY_FOUND AND PROTOBUF_FOUND)
|
||||
set(HAVE_SPOTIFY ON)
|
||||
endif(ENABLE_SPOTIFY AND SPOTIFY_FOUND AND PROTOBUF_FOUND)
|
||||
|
||||
|
||||
if(ENABLE_VISUALISATIONS)
|
||||
# When/if upstream accepts our patches then these options can be used to link
|
||||
# to system installed projectM instead.
|
||||
@ -357,6 +367,10 @@ if(HAVE_BREAKPAD)
|
||||
add_subdirectory(3rdparty/google-breakpad)
|
||||
endif(HAVE_BREAKPAD)
|
||||
|
||||
if(HAVE_SPOTIFY)
|
||||
add_subdirectory(spotifyblob)
|
||||
endif(HAVE_SPOTIFY)
|
||||
|
||||
# Uninstall support
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
@ -382,4 +396,5 @@ summary_add("Scripting support: loading archives" HAVE_LIBARCHIVE)
|
||||
summary_add("Scripting support: Python" HAVE_SCRIPTING_PYTHON)
|
||||
summary_add("(Mac OS X) Sparkle integration" HAVE_SPARKLE)
|
||||
summary_add("(unstable) Remote control support" HAVE_REMOTE)
|
||||
summary_add("(unstable) Spotify support" HAVE_SPOTIFY)
|
||||
summary_show()
|
||||
|
@ -49,6 +49,7 @@
|
||||
<file>providers/magnatune.png</file>
|
||||
<file>schema/schema-8.sql</file>
|
||||
<file>schema/schema-9.sql</file>
|
||||
<file>icons/svg/spotify.svg</file>
|
||||
<file>icons/22x22/application-exit.png</file>
|
||||
<file>icons/22x22/applications-internet.png</file>
|
||||
<file>icons/22x22/configure.png</file>
|
||||
|
285
data/icons/svg/spotify.svg
Normal file
285
data/icons/svg/spotify.svg
Normal file
@ -0,0 +1,285 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="48"
|
||||
height="48"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
version="1.0"
|
||||
sodipodi:docname="spotify.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient7729">
|
||||
<stop
|
||||
style="stop-color:#467700;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop7731" />
|
||||
<stop
|
||||
style="stop-color:#518900;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop7733" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient7721">
|
||||
<stop
|
||||
style="stop-color:#1a4300;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop7723" />
|
||||
<stop
|
||||
style="stop-color:#215300;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop7725" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient7713">
|
||||
<stop
|
||||
style="stop-color:#193d00;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop7715" />
|
||||
<stop
|
||||
style="stop-color:#1f4b00;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop7717" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient6355">
|
||||
<stop
|
||||
style="stop-color:#23371c;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop6357" />
|
||||
<stop
|
||||
style="stop-color:#004100;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop6359" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient6347">
|
||||
<stop
|
||||
style="stop-color:#abd033;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop6349" />
|
||||
<stop
|
||||
style="stop-color:#9ec02d;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6351" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5519">
|
||||
<stop
|
||||
style="stop-color:#88ae04;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5521" />
|
||||
<stop
|
||||
style="stop-color:#73a400;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop5523" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective10" />
|
||||
<inkscape:perspective
|
||||
id="perspective5505"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5519"
|
||||
id="linearGradient6853"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="119.5"
|
||||
y1="91.362183"
|
||||
x2="102.5"
|
||||
y2="128.36218" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6355"
|
||||
id="radialGradient6855"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.1318093,0.197699,-0.1703116,0.9750189,-125.44033,-100.50883)"
|
||||
cx="147.76869"
|
||||
cy="120.16964"
|
||||
fx="147.76869"
|
||||
fy="120.16964"
|
||||
r="14.451495" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6347"
|
||||
id="linearGradient6857"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-125.45979,-77.491488)"
|
||||
x1="149.09062"
|
||||
y1="85.104187"
|
||||
x2="139.1649"
|
||||
y2="106.61218" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter7655"
|
||||
x="-1.0712544"
|
||||
width="3.1425087"
|
||||
y="-1.0712544"
|
||||
height="3.1425087">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="20.086019"
|
||||
id="feGaussianBlur7657" />
|
||||
</filter>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient7713"
|
||||
id="linearGradient7719"
|
||||
x1="38.714096"
|
||||
y1="17.417631"
|
||||
x2="31.1127"
|
||||
y2="15.165503"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.999924,1.232938e-2,-1.232938e-2,0.999924,0.2587749,-0.2864042)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient7721"
|
||||
id="linearGradient7727"
|
||||
x1="35.708893"
|
||||
y1="25.90625"
|
||||
x2="27.400389"
|
||||
y2="22.312458"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.965063,1.1899533e-2,-1.232938e-2,0.999924,1.1112913,-0.2758924)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient7729"
|
||||
id="linearGradient7735"
|
||||
x1="35.607697"
|
||||
y1="31.414557"
|
||||
x2="23.13369"
|
||||
y2="26.433243"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.8596429,1.059967e-2,-1.232938e-2,0.999924,3.5039934,-0.2463897)" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter7785"
|
||||
x="-0.089479765"
|
||||
width="1.1789595"
|
||||
y="-0.14834692"
|
||||
height="1.2966938">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="1.5684595"
|
||||
id="feGaussianBlur7787" />
|
||||
</filter>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
gridtolerance="10000"
|
||||
guidetolerance="10"
|
||||
objecttolerance="10"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.6568542"
|
||||
inkscape:cx="-0.10040691"
|
||||
inkscape:cy="47.355194"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-nodes="false"
|
||||
inkscape:window-width="1440"
|
||||
inkscape:window-height="853"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5511"
|
||||
visible="true"
|
||||
enabled="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g6847"
|
||||
transform="translate(-0.29021,-0.7456946)">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.64566926;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;filter:url(#filter7655);enable-background:accumulate"
|
||||
id="path6363"
|
||||
sodipodi:cx="112.5"
|
||||
sodipodi:cy="109.86218"
|
||||
sodipodi:rx="22.5"
|
||||
sodipodi:ry="22.5"
|
||||
d="M 135,109.86218 A 22.5,22.5 0 1 1 90,109.86218 A 22.5,22.5 0 1 1 135,109.86218 z"
|
||||
transform="matrix(0.4666666,0,0,0.111111,-28.709782,33.038802)" />
|
||||
<path
|
||||
transform="translate(-88.70979,-85.616488)"
|
||||
d="M 135,109.86218 A 22.5,22.5 0 1 1 90,109.86218 A 22.5,22.5 0 1 1 135,109.86218 z"
|
||||
sodipodi:ry="22.5"
|
||||
sodipodi:rx="22.5"
|
||||
sodipodi:cy="109.86218"
|
||||
sodipodi:cx="112.5"
|
||||
id="path5513"
|
||||
style="opacity:1;fill:url(#linearGradient6853);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:nodetypes="csccscc"
|
||||
id="path5529"
|
||||
d="M 7.6378996,39.420202 C 8.1682296,39.420202 11.29843,32.092852 23.23086,33.507062 C 35.16329,34.921272 36.54089,42.778952 36.54089,42.778952 C 34.49039,44.179572 32.3092,45.405922 29.55821,45.872552 C 29.55821,45.872552 26.55929,40.325532 21.1676,40.679082 C 15.77591,41.032632 13.91347,44.193172 13.91347,44.193172 C 11.14188,43.198092 8.9957096,41.593432 7.6378996,39.420202 z"
|
||||
style="fill:url(#radialGradient6855);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="path5531"
|
||||
d="M 2.6652096,29.120692 C 35.315841,10.631207 30.66521,27.370692 44.66521,26.495692 C 44.14296,15.562843 35.20292,3.7456934 23.66521,3.7456934 C 6.6997296,4.3119254 1.9479196,20.58416 2.6652096,29.120692 z"
|
||||
style="fill:url(#linearGradient6857);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter7785)" />
|
||||
</g>
|
||||
<path
|
||||
style="opacity:1;fill:url(#linearGradient7719);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 10.300245,11.619555 C 8.241027,12.012805 7.9425774,15.355405 10.765465,15.313073 C 21.977063,13.20149 31.048724,15.49889 39.670046,19.826041 C 40.808245,20.378971 42.647611,18.028703 41.02047,16.758511 C 31.316836,11.614062 19.960975,9.8780472 10.300245,11.619555 z"
|
||||
id="path7661"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="opacity:1;fill:url(#linearGradient7727);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 12.303532,19.144827 C 10.172718,19.381037 9.829391,22.969311 12.56196,22.64828 C 21.903655,21.50982 27.85363,22.62879 35.683323,25.808592 C 37.647192,26.873264 38.724998,23.482585 36.929338,22.604961 C 28.133565,18.889799 21.412131,18.726151 12.303532,19.144827 z"
|
||||
id="path7666"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="opacity:1;fill:url(#linearGradient7735);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 14.447653,25.703011 C 12.75416,26.30833 13.053805,29.148649 14.863112,29.052139 C 17.870832,28.722372 20.153948,28.706138 23.615532,29.097554 C 27.126432,29.494545 29.233258,30.435974 32.157356,31.453048 C 33.350406,31.961876 34.447173,29.764482 33.187538,28.528027 C 29.966426,27.274723 27.415802,26.174879 23.388506,25.719498 C 20.084015,25.348048 17.755584,25.371512 14.447653,25.703011 z"
|
||||
id="path7668"
|
||||
sodipodi:nodetypes="ccscccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
51
spotifyblob/CMakeLists.txt
Normal file
51
spotifyblob/CMakeLists.txt
Normal file
@ -0,0 +1,51 @@
|
||||
include_directories(${SPOTIFY_INCLUDE_DIRS})
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
|
||||
link_directories(${SPOTIFY_LIBRARY_DIRS})
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH ..)
|
||||
|
||||
|
||||
set(SOURCES
|
||||
main.cpp
|
||||
spotifyblob.cpp
|
||||
spotifyclient.cpp
|
||||
|
||||
../src/core/logging.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
spotifyblob.h
|
||||
spotifyclient.h
|
||||
)
|
||||
|
||||
set(MESSAGES
|
||||
messages.proto
|
||||
)
|
||||
|
||||
qt4_wrap_cpp(MOC ${HEADERS})
|
||||
protobuf_generate_cpp(PROTO_SOURCES PROTO_HEADERS ${MESSAGES})
|
||||
|
||||
|
||||
add_library(clementine-spotifyblob-messages STATIC
|
||||
${PROTO_SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(clementine-spotifyblob-messages
|
||||
${PROTOBUF_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
|
||||
add_executable(clementine-spotifyblob
|
||||
${SOURCES}
|
||||
${MOC}
|
||||
)
|
||||
|
||||
target_link_libraries(clementine-spotifyblob
|
||||
${SPOTIFY_LIBRARIES}
|
||||
${QT_LIBRARIES}
|
||||
clementine-spotifyblob-messages
|
||||
)
|
25
spotifyblob/main.cpp
Normal file
25
spotifyblob/main.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QStringList>
|
||||
|
||||
#include "spotifyblob.h"
|
||||
#include "spotifyclient.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
logging::Init();
|
||||
|
||||
const QStringList arguments(a.arguments());
|
||||
|
||||
if (arguments.length() != 2) {
|
||||
qFatal("Usage: %s port", argv[0]);
|
||||
}
|
||||
|
||||
SpotifyClient client;
|
||||
SpotifyBlob blob(&client);
|
||||
|
||||
client.Init(arguments[1].toInt());
|
||||
|
||||
return a.exec();
|
||||
}
|
17
spotifyblob/messages.proto
Normal file
17
spotifyblob/messages.proto
Normal file
@ -0,0 +1,17 @@
|
||||
message LoginRequest {
|
||||
required string username = 1;
|
||||
required string password = 2;
|
||||
}
|
||||
|
||||
message LoginResponse {
|
||||
required bool success = 1;
|
||||
required string error = 2;
|
||||
}
|
||||
|
||||
message RequestMessage {
|
||||
optional LoginRequest login_request = 1;
|
||||
}
|
||||
|
||||
message ResponseMessage {
|
||||
optional LoginResponse login_response = 1;
|
||||
}
|
0
spotifyblob/spotify.cpp
Normal file
0
spotifyblob/spotify.cpp
Normal file
0
spotifyblob/spotify.h
Normal file
0
spotifyblob/spotify.h
Normal file
124
spotifyblob/spotifyblob.cpp
Normal file
124
spotifyblob/spotifyblob.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include "spotifyblob.h"
|
||||
#include "spotifyclient.h"
|
||||
#include "spotifykey.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
SpotifyBlob::SpotifyBlob(SpotifyClient* client, QObject* parent)
|
||||
: QObject(parent),
|
||||
client_(client),
|
||||
session_(NULL),
|
||||
events_timer_(new QTimer(this)) {
|
||||
memset(&spotify_callbacks_, 0, sizeof(spotify_callbacks_));
|
||||
memset(&spotify_config_, 0, sizeof(spotify_config_));
|
||||
|
||||
spotify_callbacks_.logged_in = &LoggedIn;
|
||||
spotify_callbacks_.notify_main_thread = &NotifyMainThread;
|
||||
spotify_callbacks_.log_message = &LogMessage;
|
||||
|
||||
spotify_config_.api_version = SPOTIFY_API_VERSION; // From libspotify/api.h
|
||||
spotify_config_.cache_location = strdup(QDir::tempPath().toLocal8Bit().constData());
|
||||
spotify_config_.settings_location = strdup(QDir::tempPath().toLocal8Bit().constData());
|
||||
spotify_config_.application_key = g_appkey;
|
||||
spotify_config_.application_key_size = g_appkey_size;
|
||||
spotify_config_.callbacks = &spotify_callbacks_;
|
||||
spotify_config_.userdata = this;
|
||||
spotify_config_.user_agent = "Clementine Player";
|
||||
|
||||
events_timer_->setSingleShot(true);
|
||||
connect(events_timer_, SIGNAL(timeout()), SLOT(ProcessEvents()));
|
||||
|
||||
connect(client, SIGNAL(Login(QString,QString)), SLOT(Login(QString,QString)));
|
||||
}
|
||||
|
||||
SpotifyBlob::~SpotifyBlob() {
|
||||
if (session_) {
|
||||
sp_session_release(session_);
|
||||
}
|
||||
|
||||
free(const_cast<char*>(spotify_config_.cache_location));
|
||||
free(const_cast<char*>(spotify_config_.settings_location));
|
||||
}
|
||||
|
||||
void SpotifyBlob::Login(const QString& username, const QString& password) {
|
||||
sp_error error = sp_session_create(&spotify_config_, &session_);
|
||||
if (error != SP_ERROR_OK) {
|
||||
qWarning() << "Failed to create session" << sp_error_message(error);
|
||||
client_->LoginCompleted(false, sp_error_message(error));
|
||||
return;
|
||||
}
|
||||
|
||||
sp_session_login(session_, username.toUtf8().constData(), password.toUtf8().constData());
|
||||
}
|
||||
|
||||
void SpotifyBlob::LoggedIn(sp_session* session, sp_error error) {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
SpotifyBlob* me = reinterpret_cast<SpotifyBlob*>(sp_session_userdata(session));
|
||||
me->LoggedIn(error);
|
||||
}
|
||||
|
||||
void SpotifyBlob::LoggedIn(sp_error error) {
|
||||
if (error != SP_ERROR_OK) {
|
||||
qWarning() << "Failed to login" << sp_error_message(error);
|
||||
}
|
||||
|
||||
client_->LoginCompleted(error == SP_ERROR_OK, sp_error_message(error));
|
||||
}
|
||||
|
||||
void SpotifyBlob::NotifyMainThread(sp_session* session) {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
SpotifyBlob* me = reinterpret_cast<SpotifyBlob*>(sp_session_userdata(session));
|
||||
me->Notify();
|
||||
}
|
||||
|
||||
// Called by spotify from an internal thread to notify us that its events need processing.
|
||||
void SpotifyBlob::Notify() {
|
||||
metaObject()->invokeMethod(this, "ProcessEvents", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void SpotifyBlob::ProcessEvents() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
int next_timeout_ms;
|
||||
sp_session_process_events(session_, &next_timeout_ms);
|
||||
qDebug() << next_timeout_ms << events_timer_;
|
||||
events_timer_->start(next_timeout_ms);
|
||||
qDebug() << "Started";
|
||||
}
|
||||
|
||||
void SpotifyBlob::LogMessage(sp_session* session, const char* data) {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void SpotifyBlob::Search(const QString& query) {
|
||||
sp_search_create(
|
||||
session_,
|
||||
query.toUtf8().constData(),
|
||||
0, // track offset
|
||||
10, // track count
|
||||
0, // album offset
|
||||
10, // album count
|
||||
0, // artist offset
|
||||
10, // artist count
|
||||
&SearchComplete,
|
||||
this);
|
||||
}
|
||||
|
||||
void SpotifyBlob::SearchComplete(sp_search* result, void* userdata) {
|
||||
sp_error error = sp_search_error(result);
|
||||
if (error != SP_ERROR_OK) {
|
||||
qWarning() << "Search failed";
|
||||
sp_search_release(result);
|
||||
return;
|
||||
}
|
||||
|
||||
int artists = sp_search_num_artists(result);
|
||||
for (int i = 0; i < artists; ++i) {
|
||||
sp_artist* artist = sp_search_artist(result, i);
|
||||
qDebug() << "Found artist:" << sp_artist_name(artist);
|
||||
}
|
||||
|
||||
sp_search_release(result);
|
||||
}
|
||||
|
44
spotifyblob/spotifyblob.h
Normal file
44
spotifyblob/spotifyblob.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef SPOTIFY_H
|
||||
#define SPOTIFY_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <libspotify/api.h>
|
||||
|
||||
class SpotifyClient;
|
||||
|
||||
class QTimer;
|
||||
|
||||
class SpotifyBlob : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpotifyBlob(SpotifyClient* client, QObject* parent = 0);
|
||||
~SpotifyBlob();
|
||||
|
||||
private slots:
|
||||
void ProcessEvents();
|
||||
void Login(const QString& username, const QString& password);
|
||||
void Search(const QString& query);
|
||||
|
||||
private:
|
||||
// Spotify callbacks.
|
||||
static void LoggedIn(sp_session* session, sp_error error);
|
||||
static void NotifyMainThread(sp_session* session);
|
||||
static void LogMessage(sp_session* session, const char* data);
|
||||
|
||||
static void SearchComplete(sp_search* result, void* userdata);
|
||||
|
||||
void Notify();
|
||||
void LoggedIn(sp_error error);
|
||||
|
||||
SpotifyClient* client_;
|
||||
|
||||
sp_session_config spotify_config_;
|
||||
sp_session_callbacks spotify_callbacks_;
|
||||
sp_session* session_;
|
||||
|
||||
QTimer* events_timer_;
|
||||
};
|
||||
|
||||
#endif // SPOTIFY_H
|
90
spotifyblob/spotifyclient.cpp
Normal file
90
spotifyblob/spotifyclient.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "messages.pb.h"
|
||||
#include "spotifyclient.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include <boost/scoped_array.hpp>
|
||||
|
||||
SpotifyClient::SpotifyClient(QObject* parent)
|
||||
: QObject(parent),
|
||||
socket_(new QTcpSocket(this))
|
||||
{
|
||||
connect(socket_, SIGNAL(readyRead()), SLOT(SocketReadyRead()));
|
||||
}
|
||||
|
||||
void SpotifyClient::Init(quint16 port) {
|
||||
qLog(Debug) << "port" << port;
|
||||
|
||||
socket_->connectToHost(QHostAddress::LocalHost, port);
|
||||
}
|
||||
|
||||
void SpotifyClient::SocketReadyRead() {
|
||||
QDataStream s(socket_);
|
||||
|
||||
quint32 length = 0;
|
||||
s >> length;
|
||||
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::scoped_array<char> data(new char[length]);
|
||||
s.readRawData(data.get(), length);
|
||||
|
||||
RequestMessage message;
|
||||
if (!message.ParseFromArray(data.get(), length)) {
|
||||
qLog(Error) << "Malformed protobuf message";
|
||||
socket_->deleteLater();
|
||||
socket_ = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
qLog(Debug) << message.DebugString().c_str();
|
||||
|
||||
if (message.has_login_request()) {
|
||||
const LoginRequest& r = message.login_request();
|
||||
emit Login(QString::fromUtf8(r.username().data(), r.username().length()),
|
||||
QString::fromUtf8(r.password().data(), r.password().length()));
|
||||
}
|
||||
}
|
||||
|
||||
void SpotifyClient::SendMessage(const ResponseMessage& message) {
|
||||
qLog(Debug) << message.DebugString().c_str();
|
||||
|
||||
std::string data(message.SerializeAsString());
|
||||
|
||||
QDataStream s(socket_);
|
||||
s << quint32(data.length());
|
||||
s.writeRawData(data.data(), data.length());
|
||||
}
|
||||
|
||||
void SpotifyClient::LoginCompleted(bool success, const QString& error) {
|
||||
const QByteArray error_bytes(error.toUtf8());
|
||||
|
||||
ResponseMessage message;
|
||||
|
||||
LoginResponse* response = message.mutable_login_response();
|
||||
response->set_success(success);
|
||||
response->set_error(error_bytes.constData(), error_bytes.length());
|
||||
|
||||
SendMessage(message);
|
||||
}
|
32
spotifyblob/spotifyclient.h
Normal file
32
spotifyblob/spotifyclient.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef SPOTIFYCLIENT_H
|
||||
#define SPOTIFYCLIENT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QTcpSocket;
|
||||
|
||||
class ResponseMessage;
|
||||
|
||||
class SpotifyClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpotifyClient(QObject* parent = 0);
|
||||
|
||||
void Init(quint16 port);
|
||||
|
||||
void LoginCompleted(bool success, const QString& error);
|
||||
|
||||
signals:
|
||||
void Login(const QString& username, const QString& password);
|
||||
|
||||
private slots:
|
||||
void SocketReadyRead();
|
||||
|
||||
private:
|
||||
void SendMessage(const ResponseMessage& message);
|
||||
|
||||
QTcpSocket* socket_;
|
||||
};
|
||||
|
||||
#endif // SPOTIFYCLIENT_H
|
28
spotifyblob/spotifykey.h
Normal file
28
spotifyblob/spotifykey.h
Normal file
@ -0,0 +1,28 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const uint8_t g_appkey[] = {
|
||||
0x01, 0x59, 0x4E, 0xAE, 0xF2, 0x64, 0x2B, 0x1F, 0x13, 0xF8, 0xB1, 0x2C, 0x0A, 0x4F, 0x8A, 0xCA,
|
||||
0x5D, 0xB8, 0x23, 0x43, 0x12, 0xB2, 0x3A, 0x21, 0x64, 0x0B, 0x4C, 0x17, 0x39, 0xB6, 0x3B, 0x92,
|
||||
0xE6, 0xB3, 0x56, 0xE6, 0x01, 0x61, 0x56, 0x81, 0xD6, 0x5A, 0x1E, 0x4A, 0x72, 0xA7, 0x34, 0x89,
|
||||
0x3E, 0x64, 0x9D, 0xF9, 0x68, 0xB9, 0xD3, 0x0C, 0x20, 0x27, 0x05, 0x42, 0x53, 0x4B, 0x2A, 0xE0,
|
||||
0xB7, 0xA9, 0xD7, 0x30, 0x78, 0xB7, 0xA6, 0x7C, 0x87, 0x6E, 0x8D, 0x2B, 0xAF, 0xB3, 0xF2, 0x09,
|
||||
0xA4, 0x1D, 0x59, 0x15, 0xF4, 0x34, 0x4F, 0x91, 0x18, 0x1E, 0x6D, 0xC5, 0x24, 0x59, 0x30, 0xD3,
|
||||
0x7E, 0x5C, 0x15, 0x3C, 0xA5, 0x85, 0xE3, 0xE8, 0x1D, 0x46, 0x35, 0x30, 0xA6, 0xBB, 0x2A, 0x07,
|
||||
0x0E, 0x8E, 0x8A, 0x87, 0xD1, 0x2C, 0x9C, 0xDE, 0x29, 0xAC, 0x5B, 0x99, 0xA5, 0x06, 0xAA, 0x44,
|
||||
0xA4, 0xC5, 0x52, 0xCE, 0x89, 0x70, 0xBD, 0x97, 0x1C, 0xA5, 0x36, 0xAE, 0xA3, 0xBB, 0xB4, 0x3B,
|
||||
0xB9, 0x8F, 0x2E, 0xF1, 0x79, 0x03, 0x52, 0xC5, 0x4C, 0xDD, 0x82, 0x31, 0x89, 0x6C, 0xB6, 0xF8,
|
||||
0x43, 0x3B, 0x23, 0xF9, 0x61, 0x6A, 0xDC, 0xD3, 0xF7, 0x1A, 0xEA, 0xAF, 0x11, 0xDE, 0xDA, 0x58,
|
||||
0x3B, 0x0B, 0x33, 0xB0, 0x17, 0x99, 0x2E, 0x15, 0xDC, 0x20, 0x9A, 0x2F, 0x0C, 0x43, 0xBD, 0xB1,
|
||||
0x4D, 0x85, 0xC8, 0x2A, 0x73, 0x65, 0x3A, 0xBC, 0xBF, 0x84, 0x90, 0xE5, 0x37, 0xD9, 0x4A, 0xC6,
|
||||
0x46, 0xD4, 0x04, 0xB8, 0x7E, 0xA7, 0x36, 0xD8, 0xBC, 0xEF, 0x76, 0x4B, 0x67, 0xD8, 0x28, 0xAE,
|
||||
0x4F, 0x00, 0x7B, 0xD7, 0xE7, 0xE4, 0xA6, 0x48, 0x11, 0x9B, 0x87, 0xA7, 0x65, 0xA4, 0x77, 0x82,
|
||||
0x1A, 0xA6, 0xFC, 0x30, 0xF7, 0x5A, 0x79, 0x9E, 0x48, 0xD5, 0x8C, 0x4C, 0x70, 0x39, 0x31, 0x6B,
|
||||
0x6F, 0xAD, 0x6C, 0xB0, 0x3F, 0x32, 0xE6, 0xAD, 0xEE, 0x02, 0x80, 0xF6, 0xEE, 0x7B, 0x4C, 0x50,
|
||||
0xAD, 0x62, 0x3B, 0xA7, 0xFE, 0xEF, 0xE2, 0xFC, 0xE3, 0x70, 0x74, 0x12, 0x10, 0xAD, 0xE3, 0xF3,
|
||||
0x5D, 0x98, 0xE2, 0xA4, 0xED, 0xF6, 0x91, 0x89, 0x90, 0x02, 0x20, 0xA4, 0x37, 0x5A, 0x7C, 0xB2,
|
||||
0x04, 0x04, 0x70, 0x5E, 0x37, 0x43, 0x16, 0x95, 0xC1, 0x71, 0xA8, 0xD9, 0x7D, 0x2B, 0x46, 0x72,
|
||||
0x5F,
|
||||
};
|
||||
|
||||
const size_t g_appkey_size = sizeof(g_appkey);
|
@ -613,6 +613,21 @@ if(HAVE_LIBLASTFM)
|
||||
)
|
||||
endif(HAVE_LIBLASTFM)
|
||||
|
||||
if(HAVE_SPOTIFY)
|
||||
list(APPEND SOURCES
|
||||
radio/spotifyconfig.cpp
|
||||
radio/spotifyserver.cpp
|
||||
radio/spotifyservice.cpp
|
||||
)
|
||||
list(APPEND HEADERS
|
||||
radio/spotifyconfig.h
|
||||
radio/spotifyserver.h
|
||||
radio/spotifyservice.h
|
||||
)
|
||||
list(APPEND UI
|
||||
radio/spotifyconfig.ui)
|
||||
endif(HAVE_SPOTIFY)
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND HEADERS core/macglobalshortcutbackend.h)
|
||||
list(APPEND HEADERS devices/macdevicelister.h)
|
||||
@ -995,6 +1010,10 @@ if(HAVE_BREAKPAD)
|
||||
endif (LINUX)
|
||||
endif(HAVE_BREAKPAD)
|
||||
|
||||
if(HAVE_SPOTIFY)
|
||||
target_link_libraries(clementine_lib clementine-spotifyblob-messages)
|
||||
endif(HAVE_SPOTIFY)
|
||||
|
||||
if (APPLE)
|
||||
target_link_libraries(clementine_lib
|
||||
${GROWL}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#cmakedefine HAVE_REMOTE
|
||||
#cmakedefine HAVE_SCRIPTING_PYTHON
|
||||
#cmakedefine HAVE_SPARKLE
|
||||
#cmakedefine HAVE_SPOTIFY
|
||||
#cmakedefine HAVE_STATIC_SQLITE
|
||||
#cmakedefine HAVE_WIIMOTEDEV
|
||||
#cmakedefine LEOPARD
|
||||
|
@ -1,18 +1,17 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
Clementine 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.
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
@ -37,8 +36,7 @@ static const int kMessageHandlerMagicLength = strlen(kMessageHandlerMagic);
|
||||
static QtMsgHandler sOriginalMessageHandler = NULL;
|
||||
|
||||
|
||||
static void GLog(const gchar* domain, GLogLevelFlags level,
|
||||
const gchar* message, gpointer user_data) {
|
||||
void GLog(const char* domain, int level, const char* message, void* user_data) {
|
||||
switch (level) {
|
||||
case G_LOG_FLAG_RECURSION:
|
||||
case G_LOG_FLAG_FATAL:
|
||||
@ -84,9 +82,6 @@ void Init() {
|
||||
sClassLevels = new QMap<QString, Level>();
|
||||
sNullDevice = new NullDevice;
|
||||
|
||||
// Glib integration
|
||||
g_log_set_default_handler(&GLog, NULL);
|
||||
|
||||
// Catch other messages from Qt
|
||||
if (!sOriginalMessageHandler) {
|
||||
sOriginalMessageHandler = qInstallMsgHandler(MessageHandler);
|
||||
|
@ -1,18 +1,17 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
Clementine 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.
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef LOGGING_H
|
||||
@ -46,6 +45,8 @@ namespace logging {
|
||||
|
||||
QDebug CreateLogger(Level level, const char* pretty_function, int line);
|
||||
|
||||
void GLog(const char* domain, int level, const char* message, void* user_data);
|
||||
|
||||
extern const char* kDefaultLogLevels;
|
||||
}
|
||||
|
||||
|
@ -314,6 +314,7 @@ int main(int argc, char *argv[]) {
|
||||
// Initialise logging
|
||||
logging::Init();
|
||||
logging::SetLevels(options.log_levels());
|
||||
g_log_set_default_handler(reinterpret_cast<GLogFunc>(&logging::GLog), NULL);
|
||||
|
||||
QtSingleApplication a(argc, argv);
|
||||
#ifdef Q_OS_DARWIN
|
||||
|
@ -29,6 +29,9 @@
|
||||
#ifdef HAVE_LIBLASTFM
|
||||
#include "lastfmservice.h"
|
||||
#endif
|
||||
#ifdef HAVE_SPOTIFY
|
||||
#include "spotifyservice.h"
|
||||
#endif
|
||||
|
||||
#include <QMimeData>
|
||||
#include <QtDebug>
|
||||
@ -51,6 +54,9 @@ RadioModel::RadioModel(BackgroundThread<Database>* db_thread,
|
||||
|
||||
#ifdef HAVE_LIBLASTFM
|
||||
AddService(new LastFMService(this));
|
||||
#endif
|
||||
#ifdef HAVE_SPOTIFY
|
||||
AddService(new SpotifyService(this));
|
||||
#endif
|
||||
AddService(new SomaFMService(this));
|
||||
AddService(new MagnatuneService(this));
|
||||
@ -70,6 +76,7 @@ void RadioModel::AddService(RadioService *service) {
|
||||
root->setData(QVariant::fromValue(service), Role_Service);
|
||||
|
||||
invisibleRootItem()->appendRow(root);
|
||||
qDebug() << "Adding:" << service->name();
|
||||
sServices->insert(service->name(), service);
|
||||
|
||||
connect(service, SIGNAL(AsyncLoadFinished(PlaylistItem::SpecialLoadResult)), SIGNAL(AsyncLoadFinished(PlaylistItem::SpecialLoadResult)));
|
||||
|
80
src/radio/spotifyconfig.cpp
Normal file
80
src/radio/spotifyconfig.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "spotifyconfig.h"
|
||||
|
||||
#include "core/network.h"
|
||||
#include "spotifyservice.h"
|
||||
#include "radiomodel.h"
|
||||
#include "ui_spotifyconfig.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
|
||||
SpotifyConfig::SpotifyConfig(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
network_(new NetworkAccessManager(this)),
|
||||
ui_(new Ui_SpotifyConfig),
|
||||
service_(RadioModel::Service<SpotifyService>()),
|
||||
needs_validation_(true)
|
||||
{
|
||||
ui_->setupUi(this);
|
||||
ui_->busy->hide();
|
||||
connect(service_, SIGNAL(LoginFinished(bool)), SLOT(LoginFinished(bool)));
|
||||
}
|
||||
|
||||
SpotifyConfig::~SpotifyConfig() {
|
||||
delete ui_;
|
||||
}
|
||||
|
||||
bool SpotifyConfig::NeedsValidation() const {
|
||||
// FIXME
|
||||
return needs_validation_;
|
||||
}
|
||||
|
||||
void SpotifyConfig::Validate() {
|
||||
ui_->busy->show();
|
||||
service_->Login(ui_->username->text(), ui_->password->text());
|
||||
}
|
||||
|
||||
void SpotifyConfig::Load() {
|
||||
QSettings s;
|
||||
s.beginGroup(SpotifyService::kSettingsGroup);
|
||||
|
||||
ui_->username->setText(s.value("username").toString());
|
||||
ui_->password->setText(s.value("password").toString());
|
||||
}
|
||||
|
||||
void SpotifyConfig::Save() {
|
||||
QSettings s;
|
||||
s.beginGroup(SpotifyService::kSettingsGroup);
|
||||
|
||||
s.setValue("username", ui_->username->text());
|
||||
s.setValue("password", ui_->password->text());
|
||||
|
||||
RadioModel::Service<SpotifyService>()->ReloadSettings();
|
||||
}
|
||||
|
||||
void SpotifyConfig::LoginFinished(bool success) {
|
||||
qDebug() << Q_FUNC_INFO << success;
|
||||
needs_validation_ = !success;
|
||||
ui_->busy->hide();
|
||||
emit ValidationComplete(success);
|
||||
}
|
57
src/radio/spotifyconfig.h
Normal file
57
src/radio/spotifyconfig.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SPOTIFYCONFIG_H
|
||||
#define SPOTIFYCONFIG_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QAuthenticator;
|
||||
class QNetworkReply;
|
||||
|
||||
class NetworkAccessManager;
|
||||
class Ui_SpotifyConfig;
|
||||
class SpotifyService;
|
||||
|
||||
class SpotifyConfig : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpotifyConfig(QWidget* parent = 0);
|
||||
~SpotifyConfig();
|
||||
|
||||
bool NeedsValidation() const;
|
||||
void Validate();
|
||||
|
||||
signals:
|
||||
void ValidationComplete(bool success);
|
||||
|
||||
public slots:
|
||||
void Load();
|
||||
void Save();
|
||||
|
||||
private slots:
|
||||
void LoginFinished(bool success);
|
||||
|
||||
private:
|
||||
NetworkAccessManager* network_;
|
||||
Ui_SpotifyConfig* ui_;
|
||||
SpotifyService* service_;
|
||||
|
||||
bool needs_validation_;
|
||||
};
|
||||
|
||||
#endif // SPOTIFYCONFIG_H
|
125
src/radio/spotifyconfig.ui
Normal file
125
src/radio/spotifyconfig.ui
Normal file
@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SpotifyConfig</class>
|
||||
<widget class="QWidget" name="SpotifyConfig">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>448</width>
|
||||
<height>310</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Account details</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>A Spotify Premium account is required.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QWidget" name="login_container" native="true">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="username_label">
|
||||
<property name="text">
|
||||
<string>Username</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="username"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="password_label">
|
||||
<property name="text">
|
||||
<string>Password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="password">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="busy" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Authenticating...</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="BusyIndicator" name="label_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>BusyIndicator</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>widgets/busyindicator.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
108
src/radio/spotifyserver.cpp
Normal file
108
src/radio/spotifyserver.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "spotifyserver.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include "spotifyblob/messages.pb.h"
|
||||
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include <boost/scoped_array.hpp>
|
||||
|
||||
SpotifyServer::SpotifyServer(QObject* parent)
|
||||
: QObject(parent),
|
||||
server_(new QTcpServer(this)),
|
||||
protocol_socket_(NULL)
|
||||
{
|
||||
connect(server_, SIGNAL(newConnection()), SLOT(NewConnection()));
|
||||
}
|
||||
|
||||
void SpotifyServer::Init() {
|
||||
if (!server_->listen(QHostAddress::LocalHost)) {
|
||||
qLog(Error) << "Couldn't open server socket" << server_->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
int SpotifyServer::server_port() const {
|
||||
return server_->serverPort();
|
||||
}
|
||||
|
||||
void SpotifyServer::NewConnection() {
|
||||
protocol_socket_ = server_->nextPendingConnection();
|
||||
connect(protocol_socket_, SIGNAL(readyRead()), SLOT(ProtocolSocketReadyRead()));
|
||||
|
||||
qLog(Info) << "Connection from port" << protocol_socket_->peerPort();
|
||||
|
||||
emit ClientConnected();
|
||||
}
|
||||
|
||||
void SpotifyServer::Login(const QString& username, const QString& password) {
|
||||
const QByteArray username_bytes(username.toUtf8());
|
||||
const QByteArray password_bytes(password.toUtf8());
|
||||
|
||||
RequestMessage message;
|
||||
|
||||
LoginRequest* request = message.mutable_login_request();
|
||||
request->set_username(username_bytes.constData(), username_bytes.length());
|
||||
request->set_password(password_bytes.constData(), password_bytes.length());
|
||||
|
||||
SendMessage(message);
|
||||
}
|
||||
|
||||
void SpotifyServer::SendMessage(const RequestMessage& message) {
|
||||
qLog(Debug) << message.DebugString().c_str();
|
||||
|
||||
std::string data(message.SerializeAsString());
|
||||
|
||||
QDataStream s(protocol_socket_);
|
||||
s << quint32(data.length());
|
||||
s.writeRawData(data.data(), data.length());
|
||||
}
|
||||
|
||||
void SpotifyServer::ProtocolSocketReadyRead() {
|
||||
QDataStream s(protocol_socket_);
|
||||
|
||||
quint32 length = 0;
|
||||
s >> length;
|
||||
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::scoped_array<char> data(new char[length]);
|
||||
s.readRawData(data.get(), length);
|
||||
|
||||
ResponseMessage message;
|
||||
if (!message.ParseFromArray(data.get(), length)) {
|
||||
qLog(Error) << "Malformed protobuf message";
|
||||
protocol_socket_->deleteLater();
|
||||
protocol_socket_ = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
qLog(Debug) << message.DebugString().c_str();
|
||||
|
||||
if (message.has_login_response()) {
|
||||
const LoginResponse& response = message.login_response();
|
||||
if (!response.success()) {
|
||||
qLog(Info) << QString::fromUtf8(response.error().data(), response.error().size());
|
||||
}
|
||||
emit LoginCompleted(response.success());
|
||||
}
|
||||
}
|
54
src/radio/spotifyserver.h
Normal file
54
src/radio/spotifyserver.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* This file is part of Clementine.
|
||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
|
||||
Clementine 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.
|
||||
|
||||
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SPOTIFYSERVER_H
|
||||
#define SPOTIFYSERVER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class RequestMessage;
|
||||
|
||||
class QTcpServer;
|
||||
class QTcpSocket;
|
||||
|
||||
class SpotifyServer : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpotifyServer(QObject* parent = 0);
|
||||
|
||||
void Init();
|
||||
void Login(const QString& username, const QString& password);
|
||||
|
||||
int server_port() const;
|
||||
|
||||
signals:
|
||||
void ClientConnected();
|
||||
void LoginCompleted(bool success);
|
||||
|
||||
private slots:
|
||||
void NewConnection();
|
||||
void ProtocolSocketReadyRead();
|
||||
|
||||
private:
|
||||
void SendMessage(const RequestMessage& message);
|
||||
|
||||
QTcpServer* server_;
|
||||
QTcpSocket* protocol_socket_;
|
||||
};
|
||||
|
||||
#endif // SPOTIFYSERVER_H
|
72
src/radio/spotifyservice.cpp
Normal file
72
src/radio/spotifyservice.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include "core/logging.h"
|
||||
#include "radiomodel.h"
|
||||
#include "spotifyserver.h"
|
||||
#include "spotifyservice.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QProcess>
|
||||
|
||||
const char* SpotifyService::kServiceName = "Spotify";
|
||||
const char* SpotifyService::kSettingsGroup = "Spotify";
|
||||
|
||||
SpotifyService::SpotifyService(RadioModel* parent)
|
||||
: RadioService(kServiceName, parent),
|
||||
server_(NULL),
|
||||
blob_process_(NULL) {
|
||||
blob_path_ = QCoreApplication::applicationFilePath() + "-spotifyblob";
|
||||
}
|
||||
|
||||
SpotifyService::~SpotifyService() {
|
||||
}
|
||||
|
||||
QStandardItem* SpotifyService::CreateRootItem() {
|
||||
QStandardItem* item = new QStandardItem(QIcon(":icons/svg/spotify.svg"), kServiceName);
|
||||
item->setData(true, RadioModel::Role_CanLazyLoad);
|
||||
return item;
|
||||
}
|
||||
|
||||
void SpotifyService::LazyPopulate(QStandardItem* parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
QModelIndex SpotifyService::GetCurrentIndex() {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
void SpotifyService::Login(const QString& username, const QString& password) {
|
||||
qLog(Debug) << Q_FUNC_INFO;
|
||||
delete server_;
|
||||
delete blob_process_;
|
||||
|
||||
server_ = new SpotifyServer(this);
|
||||
blob_process_ = new QProcess(this);
|
||||
blob_process_->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
connect(server_, SIGNAL(ClientConnected()), SLOT(ClientConnected()));
|
||||
connect(server_, SIGNAL(LoginCompleted(bool)), SLOT(LoginCompleted(bool)));
|
||||
|
||||
connect(blob_process_,
|
||||
SIGNAL(error(QProcess::ProcessError)),
|
||||
SLOT(BlobProcessError(QProcess::ProcessError)));
|
||||
|
||||
pending_username_ = username;
|
||||
pending_password_ = password;
|
||||
|
||||
server_->Init();
|
||||
blob_process_->start(
|
||||
blob_path_, QStringList() << QString::number(server_->server_port()));
|
||||
}
|
||||
|
||||
void SpotifyService::ClientConnected() {
|
||||
qLog(Debug) << "ClientConnected";
|
||||
|
||||
server_->Login(pending_username_, pending_password_);
|
||||
}
|
||||
|
||||
void SpotifyService::LoginCompleted(bool success) {
|
||||
emit LoginFinished(success);
|
||||
}
|
||||
|
||||
void SpotifyService::BlobProcessError(QProcess::ProcessError error) {
|
||||
qLog(Error) << "Failed to start blob process:" << error;
|
||||
}
|
48
src/radio/spotifyservice.h
Normal file
48
src/radio/spotifyservice.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef SPOTIFYSERVICE_H
|
||||
#define SPOTIFYSERVICE_H
|
||||
|
||||
#include "radioservice.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
|
||||
class SpotifyServer;
|
||||
|
||||
class SpotifyService : public RadioService {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SpotifyService(RadioModel* parent);
|
||||
virtual ~SpotifyService();
|
||||
|
||||
virtual QStandardItem* CreateRootItem();
|
||||
virtual void LazyPopulate(QStandardItem* parent);
|
||||
|
||||
void Login(const QString& username, const QString& password);
|
||||
void Search(const QString& query);
|
||||
|
||||
static const char* kServiceName;
|
||||
static const char* kSettingsGroup;
|
||||
|
||||
signals:
|
||||
void LoginFinished(bool success);
|
||||
|
||||
protected:
|
||||
virtual QModelIndex GetCurrentIndex();
|
||||
|
||||
private slots:
|
||||
void ClientConnected();
|
||||
void LoginCompleted(bool success);
|
||||
void BlobProcessError(QProcess::ProcessError error);
|
||||
|
||||
private:
|
||||
SpotifyServer* server_;
|
||||
|
||||
QString blob_path_;
|
||||
QProcess* blob_process_;
|
||||
|
||||
QString pending_username_;
|
||||
QString pending_password_;
|
||||
};
|
||||
|
||||
#endif
|
@ -45,6 +45,10 @@
|
||||
# include "remote/remoteconfig.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SPOTIFY
|
||||
# include "radio/spotifyconfig.h"
|
||||
#endif
|
||||
|
||||
#include <QColorDialog>
|
||||
#include <QDir>
|
||||
#include <QFontDialog>
|
||||
@ -118,6 +122,21 @@ SettingsDialog::SettingsDialog(BackgroundStreams* streams, QWidget* parent)
|
||||
connect(lastfm_config_, SIGNAL(ValidationComplete(bool)), SLOT(ValidationComplete(bool)));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SPOTIFY
|
||||
ui_->list->insertItem(Page_Spotify, tr("Spotify"));
|
||||
ui_->list->item(Page_Spotify)->setIcon(QIcon(":/icons/svg/spotify.svg"));
|
||||
|
||||
QWidget* spotify_page = new QWidget;
|
||||
QVBoxLayout* spotify_layout = new QVBoxLayout;
|
||||
spotify_layout->setContentsMargins(0, 0, 0, 0);
|
||||
spotify_config_ = new SpotifyConfig;
|
||||
spotify_layout->addWidget(spotify_config_);
|
||||
spotify_page->setLayout(spotify_layout);
|
||||
|
||||
ui_->stacked_widget->insertWidget(Page_Spotify, spotify_page);
|
||||
connect(spotify_config_, SIGNAL(ValidationComplete(bool)), SLOT(ValidationComplete(bool)));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_REMOTE
|
||||
ui_->list->insertItem(Page_Remote, tr("Remote Control"));
|
||||
ui_->list->item(Page_Remote)->setIcon(IconLoader::Load("network-server"));
|
||||
@ -312,6 +331,16 @@ void SettingsDialog::accept() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SPOTIFY
|
||||
if (spotify_config_->NeedsValidation()) {
|
||||
spotify_config_->Validate();
|
||||
ui_->buttonBox->setEnabled(false);
|
||||
return;
|
||||
} else {
|
||||
spotify_config_->Save();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ui_->magnatune->NeedsValidation()) {
|
||||
ui_->magnatune->Validate();
|
||||
ui_->buttonBox->setEnabled(false);
|
||||
@ -524,6 +553,10 @@ void SettingsDialog::showEvent(QShowEvent*) {
|
||||
remote_config_->Load();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SPOTIFY
|
||||
spotify_config_->Load();
|
||||
#endif
|
||||
|
||||
// Magnatune
|
||||
ui_->magnatune->Load();
|
||||
|
||||
|
@ -44,6 +44,9 @@ class Ui_SettingsDialog;
|
||||
#ifdef HAVE_REMOTE
|
||||
class RemoteConfig;
|
||||
#endif
|
||||
#ifdef HAVE_SPOTIFY
|
||||
class SpotifyConfig;
|
||||
#endif
|
||||
|
||||
class GstEngine;
|
||||
|
||||
@ -63,6 +66,9 @@ class SettingsDialog : public QDialog {
|
||||
Page_Library,
|
||||
#ifdef HAVE_LIBLASTFM
|
||||
Page_Lastfm,
|
||||
#endif
|
||||
#ifdef HAVE_SPOTIFY
|
||||
Page_Spotify,
|
||||
#endif
|
||||
Page_Magnatune,
|
||||
Page_BackgroundStreams,
|
||||
@ -126,6 +132,9 @@ class SettingsDialog : public QDialog {
|
||||
#endif
|
||||
#ifdef HAVE_REMOTE
|
||||
RemoteConfig* remote_config_;
|
||||
#endif
|
||||
#ifdef HAVE_SPOTIFY
|
||||
SpotifyConfig* spotify_config_;
|
||||
#endif
|
||||
const GstEngine* gst_engine_;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user