summaryrefslogtreecommitdiff
path: root/libre/clementine-libre/remove-and-disable-spotify.patch
diff options
context:
space:
mode:
authorroot <root@rshg054.dnsready.net>2012-05-31 16:24:59 +0000
committerroot <root@rshg054.dnsready.net>2012-05-31 16:24:59 +0000
commitf5a8de28b86c2c838a28e79aa54f8b4c3fbd869e (patch)
tree26873b23c15ea28962e55ab4dc7ae94b468089cf /libre/clementine-libre/remove-and-disable-spotify.patch
parentf1ae949e08a764ac063703dc9bb7f0afd7c16e96 (diff)
Thu May 31 16:24:59 UTC 2012
Diffstat (limited to 'libre/clementine-libre/remove-and-disable-spotify.patch')
-rw-r--r--libre/clementine-libre/remove-and-disable-spotify.patch3268
1 files changed, 3268 insertions, 0 deletions
diff --git a/libre/clementine-libre/remove-and-disable-spotify.patch b/libre/clementine-libre/remove-and-disable-spotify.patch
new file mode 100644
index 000000000..9cfc3092a
--- /dev/null
+++ b/libre/clementine-libre/remove-and-disable-spotify.patch
@@ -0,0 +1,3268 @@
+diff -rauN clementine-1.0.1/3rdparty/SPMediaKeyTap/SPMediaKeyTap.m clementine-libre-1.0.1/3rdparty/SPMediaKeyTap/SPMediaKeyTap.m
+--- clementine-1.0.1/3rdparty/SPMediaKeyTap/SPMediaKeyTap.m 2011-12-02 19:24:43.000000000 -0200
++++ clementine-libre-1.0.1/3rdparty/SPMediaKeyTap/SPMediaKeyTap.m 2012-05-28 17:19:14.612750904 -0300
+@@ -98,7 +98,6 @@
+ {
+ return [NSArray arrayWithObjects:
+ [[NSBundle mainBundle] bundleIdentifier], // your app
+- @"com.spotify.client",
+ @"com.apple.iTunes",
+ @"com.apple.QuickTimePlayerX",
+ @"com.apple.quicktimeplayer",
+diff -rauN clementine-1.0.1/Changelog clementine-libre-1.0.1/Changelog
+--- clementine-1.0.1/Changelog 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/Changelog 2012-05-28 13:50:10.422664725 -0300
+@@ -1,3 +1,7 @@
++Version 1.0.1 (libre version):
++ Major features:
++ * Disabled and removed Spotify.
++
+ Version 1.0.1:
+ Bugfixes:
+ * Use Chromaprinter and Acoustid instead of Echoprint and MusicDNS.
+diff -rauN clementine-1.0.1/cmake/SpotifyVersion.cmake /dev/null
+--- clementine-1.0.1/cmake/SpotifyVersion.cmake 2011-12-02 19:24:43.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,3 +0,0 @@
+-# Increment this whenever the user needs to download a new blob
+-# Remember to upload and sign the new version of the blob.
+-set(SPOTIFY_BLOB_VERSION 11)
+diff -rauN clementine-1.0.1/CMakeLists.txt clementine-libre-1.0.1/CMakeLists.txt
+--- clementine-1.0.1/CMakeLists.txt 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/CMakeLists.txt 2012-05-28 17:32:48.690568781 -0300
+@@ -6,7 +6,6 @@
+ include(cmake/Version.cmake)
+ include(cmake/Deb.cmake)
+ include(cmake/Rpm.cmake)
+-include(cmake/SpotifyVersion.cmake)
+ include(cmake/OptionalSource.cmake)
+
+ if (UNIX AND NOT APPLE)
+@@ -66,7 +65,6 @@
+ pkg_check_modules(USBMUXD libusbmuxd)
+ pkg_check_modules(LIBMTP libmtp>=1.0)
+ pkg_check_modules(INDICATEQT indicate-qt)
+-pkg_check_modules(SPOTIFY libspotify>=10.1.16)
+ pkg_check_modules(CDIO libcdio)
+ pkg_check_modules(QCA qca2)
+ pkg_check_modules(CHROMAPRINT libchromaprint)
+@@ -90,13 +88,6 @@
+ set(HAVE_SPARKLE ON)
+ endif (ENABLE_SPARKLE AND SPARKLE)
+
+- find_library(SPOTIFY libspotify)
+- if (SPOTIFY)
+- set (SPOTIFY_FOUND ON)
+- set (SPOTIFY_INCLUDE_DIRS ${SPOTIFY})
+- set (SPOTIFY_LIBRARIES ${SPOTIFY})
+- endif (SPOTIFY)
+-
+ add_subdirectory(3rdparty/SPMediaKeyTap)
+ set(SPMEDIAKEYTAP_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/SPMediaKeyTap)
+ set(SPMEDIAKEYTAP_LIBRARIES SPMediaKeyTap)
+@@ -191,8 +182,8 @@
+ option(ENABLE_LIBLASTFM "Use liblastfm for fetching song info, scrobbling and radio streams" ON)
+ option(ENABLE_REMOTE "Enable support for using remote controls with Clementine" OFF)
+ option(ENABLE_BREAKPAD "Enable crash reporting" OFF)
+-option(ENABLE_SPOTIFY_BLOB "Build the spotify non-GPL binary" ON)
+-option(ENABLE_SPOTIFY "Enable spotify support" ON)
++option(ENABLE_SPOTIFY_BLOB "Build the spotify non-GPL binary" OFF)
++option(ENABLE_SPOTIFY "Enable spotify support" OFF)
+ option(ENABLE_PLASMARUNNER "Enable plasma krunner global search" OFF)
+
+ if(WIN32)
+@@ -235,24 +226,6 @@
+ set(HAVE_BREAKPAD ON)
+ endif(ENABLE_BREAKPAD)
+
+-if(ENABLE_SPOTIFY AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE)
+- set(HAVE_SPOTIFY ON)
+-endif(ENABLE_SPOTIFY AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE)
+-
+-if(ENABLE_SPOTIFY_BLOB AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE AND SPOTIFY_FOUND)
+- set(HAVE_SPOTIFY_BLOB ON)
+-endif(ENABLE_SPOTIFY_BLOB AND PROTOBUF_FOUND AND PROTOBUF_PROTOC_EXECUTABLE AND SPOTIFY_FOUND)
+-
+-if((NOT HAVE_SPOTIFY_BLOB) AND (NOT QCA_FOUND))
+- # If we're not bundling the spotify blob then we must ensure QCA is available
+- # so we can verify the blob we download at runtime.
+- unset(HAVE_SPOTIFY)
+-endif((NOT HAVE_SPOTIFY_BLOB) AND (NOT QCA_FOUND))
+-
+-if(QCA_FOUND AND HAVE_SPOTIFY)
+- set(HAVE_QCA ON)
+-endif(QCA_FOUND AND HAVE_SPOTIFY)
+-
+
+ if(ENABLE_VISUALISATIONS)
+ # When/if upstream accepts our patches then these options can be used to link
+@@ -391,14 +364,6 @@
+ add_subdirectory(3rdparty/google-breakpad)
+ endif(HAVE_BREAKPAD)
+
+-if(HAVE_SPOTIFY)
+- add_subdirectory(spotifyblob/common)
+-endif(HAVE_SPOTIFY)
+-
+-if(HAVE_SPOTIFY_BLOB)
+- add_subdirectory(spotifyblob/blob)
+-endif(HAVE_SPOTIFY_BLOB)
+-
+ # This goes after everything else because KDE fucks everything else up with its
+ # cmake includes.
+ find_package(KDE4 4.3.60)
+@@ -430,8 +395,6 @@
+ summary_add("Devices: GIO backend" HAVE_GIO)
+ summary_add("Gnome sound menu integration" HAVE_LIBINDICATE)
+ summary_add("Last.fm support" HAVE_LIBLASTFM)
+-summary_add("Spotify support: core code" HAVE_SPOTIFY)
+-summary_add("Spotify support: non-GPL binary helper" HAVE_SPOTIFY_BLOB)
+ summary_add("Visualisations" ENABLE_VISUALISATIONS)
+ summary_add("Wiimote support" HAVE_WIIMOTEDEV)
+ summary_add("(KDE) Plasma global search" HAVE_PLASMARUNNER)
+diff -rauN clementine-1.0.1/data/data.qrc clementine-libre-1.0.1/data/data.qrc
+--- clementine-1.0.1/data/data.qrc 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/data/data.qrc 2012-05-28 17:50:22.768352061 -0300
+@@ -49,9 +49,6 @@
+ <file>providers/magnatune.png</file>
+ <file>schema/schema-8.sql</file>
+ <file>schema/schema-9.sql</file>
+- <file>icons/22x22/spotify.png</file>
+- <file>icons/32x32/spotify.png</file>
+- <file>icons/48x48/spotify.png</file>
+ <file>icons/22x22/application-exit.png</file>
+ <file>icons/22x22/applications-internet.png</file>
+ <file>icons/22x22/configure.png</file>
+@@ -320,7 +317,6 @@
+ <file>icons/32x32/edit-find.png</file>
+ <file>icons/48x48/edit-find.png</file>
+ <file>schema/schema-33.sql</file>
+- <file>spotify-core-logo-128x128.png</file>
+ <file>icons/22x22/dialog-warning.png</file>
+ <file>icons/22x22/dialog-ok-apply.png</file>
+ <file>schema/schema-34.sql</file>
+@@ -331,7 +327,6 @@
+ <file>providers/grooveshark.png</file>
+ <file>allthethings.png</file>
+ <file>globalsearch.css</file>
+- <file>clementine-spotify-public.pem</file>
+ <file>icons/22x22/user-away.png</file>
+ <file>icons/32x32/search.png</file>
+ <file>schema/schema-35.sql</file>
+diff -rauN clementine-1.0.1/data/icons/svg/spotify.svg /dev/null
+--- clementine-1.0.1/data/icons/svg/spotify.svg 2011-12-02 19:24:43.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,285 +0,0 @@
+-<?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>
+diff -rauN clementine-1.0.1/data/schema/schema-30.sql clementine-libre-1.0.1/data/schema/schema-30.sql
+--- clementine-1.0.1/data/schema/schema-30.sql 2011-12-02 19:24:43.000000000 -0200
++++ clementine-libre-1.0.1/data/schema/schema-30.sql 2012-05-28 17:55:40.840489308 -0300
+@@ -1,45 +1 @@
+-CREATE TABLE spotify_search_songs (
+- title TEXT,
+- album TEXT,
+- artist TEXT,
+- albumartist TEXT,
+- composer TEXT,
+- track INTEGER,
+- disc INTEGER,
+- bpm REAL,
+- year INTEGER,
+- genre TEXT,
+- comment TEXT,
+- compilation INTEGER,
+-
+- length INTEGER,
+- bitrate INTEGER,
+- samplerate INTEGER,
+-
+- directory INTEGER NOT NULL,
+- filename TEXT NOT NULL,
+- mtime INTEGER NOT NULL,
+- ctime INTEGER NOT NULL,
+- filesize INTEGER NOT NULL,
+- sampler INTEGER NOT NULL DEFAULT 0,
+- art_automatic TEXT,
+- art_manual TEXT,
+- filetype INTEGER NOT NULL DEFAULT 0,
+- playcount INTEGER NOT NULL DEFAULT 0,
+- lastplayed INTEGER,
+- rating INTEGER,
+- forced_compilation_on INTEGER NOT NULL DEFAULT 0,
+- forced_compilation_off INTEGER NOT NULL DEFAULT 0,
+- effective_compilation NOT NULL DEFAULT 0,
+- skipcount INTEGER NOT NULL DEFAULT 0,
+- score INTEGER NOT NULL DEFAULT 0,
+- beginning INTEGER NOT NULL DEFAULT 0,
+- cue_path TEXT
+-);
+-
+-CREATE VIRTUAL TABLE spotify_search_songs_fts USING fts3 (
+- ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsgenre, ftscomment,
+- tokenize=unicode
+-);
+-
+ UPDATE schema_version SET version=30;
+diff -rauN clementine-1.0.1/dist/macdeploy.py clementine-libre-1.0.1/dist/macdeploy.py
+--- clementine-1.0.1/dist/macdeploy.py 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/dist/macdeploy.py 2012-05-28 17:58:29.937662793 -0300
+@@ -367,11 +367,6 @@
+
+ FixPlugin(FindGstreamerPlugin('gst-plugin-scanner'), '.')
+
+-try:
+- FixPlugin('clementine-spotifyblob', '.')
+-except:
+- print 'Failed to find spotify blob'
+-
+ for plugin in QT_PLUGINS:
+ FixPlugin(FindQtPlugin(plugin), os.path.dirname(plugin))
+
+diff -rauN clementine-1.0.1/dist/windows/clementine.nsi clementine-libre-1.0.1/dist/windows/clementine.nsi
+--- clementine-1.0.1/dist/windows/clementine.nsi 2012-01-22 10:43:46.000000000 -0200
++++ clementine-libre-1.0.1/dist/windows/clementine.nsi 2012-05-28 18:06:56.812551755 -0300
+@@ -95,7 +95,6 @@
+ Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
+
+ ; 1.0 prerelease
+- Delete "$INSTDIR\spotify.dll"
+
+ ; 1.0
+ Delete "$INSTDIR\libofa.dll"
+@@ -109,7 +108,6 @@
+ File "avformat-52.dll"
+ File "avutil-50.dll"
+ File "clementine.exe"
+- File "clementine-spotifyblob.exe"
+ File "clementine.ico"
+ File "glew32.dll"
+ File "intl.dll"
+@@ -163,7 +161,6 @@
+ File "libqjson.dll"
+ File "libsoup-2.4-1.dll"
+ File "libspeex-1.dll"
+- File "libspotify.dll"
+ File "libtag.dll"
+ File "libtasn1-3.dll"
+ File "libusbmuxd.dll"
+@@ -949,7 +946,6 @@
+ Delete "$INSTDIR\avutil-50.dll"
+ Delete "$INSTDIR\clementine.ico"
+ Delete "$INSTDIR\clementine.exe"
+- Delete "$INSTDIR\clementine-spotifyblob.exe"
+ Delete "$INSTDIR\glew32.dll"
+ Delete "$INSTDIR\intl.dll"
+ Delete "$INSTDIR\libcdio-12.dll"
+@@ -1002,7 +998,6 @@
+ Delete "$INSTDIR\libqjson.dll"
+ Delete "$INSTDIR\libsoup-2.4-1.dll"
+ Delete "$INSTDIR\libspeex-1.dll"
+- Delete "$INSTDIR\libspotify.dll"
+ Delete "$INSTDIR\libtag.dll"
+ Delete "$INSTDIR\libtasn1-3.dll"
+ Delete "$INSTDIR\libusbmuxd.dll"
+diff -rauN clementine-1.0.1/dist/windows/clementine.nsi.in clementine-libre-1.0.1/dist/windows/clementine.nsi.in
+--- clementine-1.0.1/dist/windows/clementine.nsi.in 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/dist/windows/clementine.nsi.in 2012-05-28 18:09:14.664818947 -0300
+@@ -95,7 +95,6 @@
+ Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll"
+
+ ; 1.0 prerelease
+- Delete "$INSTDIR\spotify.dll"
+
+ ; 1.0
+ Delete "$INSTDIR\libofa.dll"
+@@ -109,7 +108,6 @@
+ File "avformat-52.dll"
+ File "avutil-50.dll"
+ File "clementine.exe"
+- File "clementine-spotifyblob.exe"
+ File "clementine.ico"
+ File "glew32.dll"
+ File "intl.dll"
+@@ -163,7 +161,6 @@
+ File "libqjson.dll"
+ File "libsoup-2.4-1.dll"
+ File "libspeex-1.dll"
+- File "libspotify.dll"
+ File "libtag.dll"
+ File "libtasn1-3.dll"
+ File "libusbmuxd.dll"
+@@ -949,7 +946,6 @@
+ Delete "$INSTDIR\avutil-50.dll"
+ Delete "$INSTDIR\clementine.ico"
+ Delete "$INSTDIR\clementine.exe"
+- Delete "$INSTDIR\clementine-spotifyblob.exe"
+ Delete "$INSTDIR\glew32.dll"
+ Delete "$INSTDIR\intl.dll"
+ Delete "$INSTDIR\libcdio-12.dll"
+@@ -1002,7 +998,6 @@
+ Delete "$INSTDIR\libqjson.dll"
+ Delete "$INSTDIR\libsoup-2.4-1.dll"
+ Delete "$INSTDIR\libspeex-1.dll"
+- Delete "$INSTDIR\libspotify.dll"
+ Delete "$INSTDIR\libtag.dll"
+ Delete "$INSTDIR\libtasn1-3.dll"
+ Delete "$INSTDIR\libusbmuxd.dll"
+diff -rauN clementine-1.0.1/src/CMakeLists.txt clementine-libre-1.0.1/src/CMakeLists.txt
+--- clementine-1.0.1/src/CMakeLists.txt 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/src/CMakeLists.txt 2012-05-30 02:50:15.725755468 -0300
+@@ -552,7 +552,6 @@
+ internet/internetviewcontainer.ui
+ internet/magnatunedownloaddialog.ui
+ internet/magnatunesettingspage.ui
+- internet/spotifysettingspage.ui
+
+ library/groupbydialog.ui
+ library/libraryfilterwidget.ui
+@@ -690,23 +689,6 @@
+ internet/lastfmstationdialog.ui
+ )
+
+-# Spotify
+-optional_source(HAVE_SPOTIFY
+- SOURCES
+- globalsearch/spotifysearchprovider.cpp
+- internet/spotifyblobdownloader.cpp
+- internet/spotifysearchplaylisttype.cpp
+- internet/spotifyserver.cpp
+- internet/spotifyservice.cpp
+- internet/spotifysettingspage.cpp
+- HEADERS
+- globalsearch/spotifysearchprovider.h
+- internet/spotifyblobdownloader.h
+- internet/spotifyserver.h
+- internet/spotifyservice.h
+- internet/spotifysettingspage.h
+-)
+-
+ optional_source(HAVE_QCA INCLUDE_DIRECTORIES ${QCA_INCLUDE_DIRS})
+
+ # Platform specific - OS X
+@@ -1037,14 +1019,6 @@
+ endif (LINUX)
+ endif(HAVE_BREAKPAD)
+
+-if(HAVE_SPOTIFY)
+- target_link_libraries(clementine_lib
+- clementine-spotifyblob-messages
+- ${QCA_LIBRARIES}
+- )
+- link_directories(${QCA_LIBRARY_DIRS})
+-endif(HAVE_SPOTIFY)
+-
+ if (APPLE)
+ target_link_libraries(clementine_lib
+ ${GROWL}
+@@ -1118,11 +1092,6 @@
+ clementine_lib
+ )
+
+-# macdeploy.py relies on the blob being built first.
+-if(HAVE_SPOTIFY_BLOB)
+- add_dependencies(clementine clementine-spotifyblob)
+-endif(HAVE_SPOTIFY_BLOB)
+-
+ set_target_properties(clementine PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "../dist/Info.plist"
+ )
+diff -rauN clementine-1.0.1/src/config.h.in clementine-libre-1.0.1/src/config.h.in
+--- clementine-1.0.1/src/config.h.in 2011-12-02 19:24:43.000000000 -0200
++++ clementine-libre-1.0.1/src/config.h.in 2012-05-28 18:17:13.027993639 -0300
+@@ -35,7 +35,6 @@
+ #cmakedefine HAVE_QCA
+ #cmakedefine HAVE_REMOTE
+ #cmakedefine HAVE_SPARKLE
+-#cmakedefine HAVE_SPOTIFY
+ #cmakedefine HAVE_STATIC_SQLITE
+ #cmakedefine HAVE_WIIMOTEDEV
+ #cmakedefine LEOPARD
+diff -rauN clementine-1.0.1/src/core/utilities.cpp clementine-libre-1.0.1/src/core/utilities.cpp
+--- clementine-1.0.1/src/core/utilities.cpp 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/src/core/utilities.cpp 2012-05-28 18:25:43.252728803 -0300
+@@ -277,9 +277,6 @@
+ return QDir::homePath();
+ #endif
+
+- case Path_LocalSpotifyBlob:
+- return GetConfigPath(Path_Root) + "/spotifyblob";
+-
+ default:
+ qFatal("%s", Q_FUNC_INFO);
+ return QString::null;
+diff -rauN clementine-1.0.1/src/core/utilities.h clementine-libre-1.0.1/src/core/utilities.h
+--- clementine-1.0.1/src/core/utilities.h 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/src/core/utilities.h 2012-05-28 18:27:31.686659381 -0300
+@@ -88,7 +88,6 @@
+ Path_NetworkCache,
+ Path_GstreamerRegistry,
+ Path_DefaultMusicLibrary,
+- Path_LocalSpotifyBlob,
+ };
+ QString GetConfigPath(ConfigPath config);
+
+diff -rauN clementine-1.0.1/src/covers/albumcoverloader.cpp clementine-libre-1.0.1/src/covers/albumcoverloader.cpp
+--- clementine-1.0.1/src/covers/albumcoverloader.cpp 2011-12-02 19:24:44.000000000 -0200
++++ clementine-libre-1.0.1/src/covers/albumcoverloader.cpp 2012-05-28 18:34:26.543457483 -0300
+@@ -28,10 +28,6 @@
+ #include <QUrl>
+ #include <QNetworkReply>
+
+-#ifdef HAVE_SPOTIFY
+-# include "internet/spotifyservice.h"
+-#endif
+-
+
+ AlbumCoverLoader::AlbumCoverLoader(QObject* parent)
+ : QObject(parent),
+@@ -40,8 +36,7 @@
+ scale_(true),
+ padding_(true),
+ next_id_(0),
+- network_(new NetworkAccessManager(this)),
+- connected_spotify_(false)
++ network_(new NetworkAccessManager(this))
+ {
+ }
+
+@@ -148,46 +143,12 @@
+
+ remote_tasks_.insert(reply, task);
+ return TryLoadResult(true, false, QImage());
+- } else if (filename.toLower().startsWith("spotify://image/")) {
+- // HACK: we should add generic image URL handlers
+- #ifdef HAVE_SPOTIFY
+- SpotifyService* spotify = InternetModel::Service<SpotifyService>();
+-
+- if (!connected_spotify_) {
+- connect(spotify, SIGNAL(ImageLoaded(QString,QImage)),
+- SLOT(SpotifyImageLoaded(QString,QImage)));
+- connected_spotify_ = true;
+- }
+-
+- QString id = QUrl(filename).path();
+- if (id.startsWith('/')) {
+- id.remove(0, 1);
+- }
+- remote_spotify_tasks_.insert(id, task);
+-
+- // Need to schedule this in the spotify service's thread
+- QMetaObject::invokeMethod(spotify, "LoadImage", Qt::QueuedConnection,
+- Q_ARG(QString, id));
+- return TryLoadResult(true, false, QImage());
+- #else
+- return TryLoadResult(false, false, QImage());
+- #endif
+ }
+
+ QImage image(filename);
+ return TryLoadResult(false, !image.isNull(), image.isNull() ? default_ : image);
+ }
+
+-void AlbumCoverLoader::SpotifyImageLoaded(const QString& id, const QImage& image) {
+- if (!remote_spotify_tasks_.contains(id))
+- return;
+-
+- Task task = remote_spotify_tasks_.take(id);
+- QImage scaled = ScaleAndPad(image);
+- emit ImageLoaded(task.id, scaled);
+- emit ImageLoaded(task.id, scaled, image);
+-}
+-
+ void AlbumCoverLoader::RemoteFetchFinished() {
+ QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
+ if (!reply)
+diff -rauN clementine-1.0.1/src/covers/albumcoverloader.h clementine-libre-1.0.1/src/covers/albumcoverloader.h
+--- clementine-1.0.1/src/covers/albumcoverloader.h 2011-12-02 19:24:44.000000000 -0200
++++ clementine-libre-1.0.1/src/covers/albumcoverloader.h 2012-05-28 18:38:03.228006474 -0300
+@@ -65,7 +65,6 @@
+ protected slots:
+ void ProcessTasks();
+ void RemoteFetchFinished();
+- void SpotifyImageLoaded(const QString& url, const QImage& image);
+
+ protected:
+ enum State {
+@@ -108,13 +107,10 @@
+ QMutex mutex_;
+ QQueue<Task> tasks_;
+ QMap<QNetworkReply*, Task> remote_tasks_;
+- QMap<QString, Task> remote_spotify_tasks_;
+ quint64 next_id_;
+
+ NetworkAccessManager* network_;
+
+- bool connected_spotify_;
+-
+ static const int kMaxRedirects = 3;
+ };
+
+diff -rauN clementine-1.0.1/src/engines/gstenginepipeline.cpp clementine-libre-1.0.1/src/engines/gstenginepipeline.cpp
+--- clementine-1.0.1/src/engines/gstenginepipeline.cpp 2011-12-02 19:24:44.000000000 -0200
++++ clementine-libre-1.0.1/src/engines/gstenginepipeline.cpp 2012-05-28 18:51:35.779395089 -0300
+@@ -26,11 +26,6 @@
+ #include "core/utilities.h"
+ #include "internet/internetmodel.h"
+
+-#ifdef HAVE_SPOTIFY
+-# include "internet/spotifyserver.h"
+-# include "internet/spotifyservice.h"
+-#endif
+-
+ #include <QtConcurrentRun>
+
+ const int GstEnginePipeline::kGstStateTimeoutNanosecs = 10000000;
+@@ -131,36 +126,6 @@
+ bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) {
+ GstElement* new_bin = NULL;
+
+- if (url.scheme() == "spotify") {
+- #ifdef HAVE_SPOTIFY
+- new_bin = gst_bin_new("spotify_bin");
+-
+- // Create elements
+- GstElement* src = engine_->CreateElement("tcpserversrc", new_bin);
+- GstElement* gdp = engine_->CreateElement("gdpdepay", new_bin);
+- if (!src || !gdp)
+- return false;
+-
+- // Pick a port number
+- const int port = Utilities::PickUnusedPort();
+- g_object_set(G_OBJECT(src), "host", "127.0.0.1", NULL);
+- g_object_set(G_OBJECT(src), "port", port, NULL);
+-
+- // Link the elements
+- gst_element_link(src, gdp);
+-
+- // Add a ghost pad
+- GstPad* pad = gst_element_get_static_pad(gdp, "src");
+- gst_element_add_pad(GST_ELEMENT(new_bin), gst_ghost_pad_new("src", pad));
+- gst_object_unref(GST_OBJECT(pad));
+-
+- // Tell spotify to start sending data to us.
+- InternetModel::Service<SpotifyService>()->server()->StartPlaybackLater(url.toString(), port);
+- #else // HAVE_SPOTIFY
+- qLog(Error) << "Tried to play a spotify:// url, but spotify support is not compiled in";
+- return false;
+- #endif
+- } else {
+ new_bin = engine_->CreateElement("uridecodebin");
+ g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(), NULL);
+ g_object_set(G_OBJECT(new_bin), "buffer-duration", buffer_duration_nanosec_, NULL);
+@@ -169,7 +134,6 @@
+ g_signal_connect(G_OBJECT(new_bin), "drained", G_CALLBACK(SourceDrainedCallback), this);
+ g_signal_connect(G_OBJECT(new_bin), "pad-added", G_CALLBACK(NewPadCallback), this);
+ g_signal_connect(G_OBJECT(new_bin), "notify::source", G_CALLBACK(SourceSetupCallback), this);
+- }
+
+ return ReplaceDecodeBin(new_bin);
+ }
+diff -rauN clementine-1.0.1/src/globalsearch/spotifysearchprovider.cpp /dev/null
+--- clementine-1.0.1/src/globalsearch/spotifysearchprovider.cpp 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,208 +0,0 @@
+-/* 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 "spotifysearchprovider.h"
+-#include "core/logging.h"
+-#include "internet/internetmodel.h"
+-#include "internet/spotifyserver.h"
+-#include "internet/spotifyservice.h"
+-#include "playlist/songmimedata.h"
+-#include "spotifyblob/common/spotifymessagehandler.h"
+-
+-SpotifySearchProvider::SpotifySearchProvider(QObject* parent)
+- : SearchProvider(parent),
+- server_(NULL),
+- service_(NULL)
+-{
+- Init("Spotify", "spotify", QIcon(":icons/32x32/spotify.png"),
+- WantsDelayedQueries | WantsSerialisedArtQueries | ArtIsProbablyRemote |
+- CanShowConfig);
+-}
+-
+-SpotifyServer* SpotifySearchProvider::server() {
+- if (server_)
+- return server_;
+-
+- if (!service_)
+- service_ = InternetModel::Service<SpotifyService>();
+-
+- if (service_->login_state() != SpotifyService::LoginState_LoggedIn)
+- return NULL;
+-
+- server_ = service_->server();
+- connect(server_, SIGNAL(SearchResults(spotify_pb::SearchResponse)),
+- SLOT(SearchFinishedSlot(spotify_pb::SearchResponse)));
+- connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
+- SLOT(ArtLoadedSlot(QString,QImage)));
+- connect(server_, SIGNAL(AlbumBrowseResults(spotify_pb::BrowseAlbumResponse)),
+- SLOT(AlbumBrowseResponse(spotify_pb::BrowseAlbumResponse)));
+- connect(server_, SIGNAL(destroyed()), SLOT(ServerDestroyed()));
+-
+- return server_;
+-}
+-
+-void SpotifySearchProvider::ServerDestroyed() {
+- server_ = NULL;
+-}
+-
+-void SpotifySearchProvider::SearchAsync(int id, const QString& query) {
+- SpotifyServer* s = server();
+- if (!s) {
+- emit SearchFinished(id);
+- return;
+- }
+-
+- PendingState state;
+- state.orig_id_ = id;
+- state.tokens_ = TokenizeQuery(query);
+-
+- const QString query_string = state.tokens_.join(" ");
+- s->Search(query_string, 5, 5);
+- queries_[query_string] = state;
+-}
+-
+-void SpotifySearchProvider::SearchFinishedSlot(const spotify_pb::SearchResponse& response) {
+- QString query_string = QString::fromUtf8(response.request().query().c_str());
+- QMap<QString, PendingState>::iterator it = queries_.find(query_string);
+- if (it == queries_.end())
+- return;
+-
+- PendingState state = it.value();
+- queries_.erase(it);
+-
+- ResultList ret;
+- for (int i=0; i < response.result_size() ; ++i) {
+- const spotify_pb::Track& track = response.result(i);
+-
+- Result result(this);
+- result.type_ = globalsearch::Type_Track;
+- SpotifyService::SongFromProtobuf(track, &result.metadata_);
+- result.match_quality_ = MatchQuality(state.tokens_, result.metadata_.title());
+-
+- ret << result;
+- }
+-
+- for (int i=0 ; i<response.album_size() ; ++i) {
+- const spotify_pb::Album& album = response.album(i);
+-
+- Result result(this);
+- result.type_ = globalsearch::Type_Album;
+- SpotifyService::SongFromProtobuf(album.metadata(), &result.metadata_);
+- result.match_quality_ =
+- qMin(MatchQuality(state.tokens_, result.metadata_.album()),
+- MatchQuality(state.tokens_, result.metadata_.artist()));
+- result.album_size_ = album.metadata().track();
+-
+- for (int j=0; j < album.track_size() ; ++j) {
+- Song track_song;
+- SpotifyService::SongFromProtobuf(album.track(j), &track_song);
+- result.album_songs_ << track_song;
+- }
+-
+- ret << result;
+- }
+-
+- emit ResultsAvailable(state.orig_id_, ret);
+- emit SearchFinished(state.orig_id_);
+-}
+-
+-void SpotifySearchProvider::LoadArtAsync(int id, const Result& result) {
+- SpotifyServer* s = server();
+- if (!s) {
+- emit ArtLoaded(id, QImage());
+- return;
+- }
+-
+- QString image_id = QUrl(result.metadata_.art_automatic()).path();
+- if (image_id.startsWith('/'))
+- image_id.remove(0, 1);
+-
+- pending_art_[image_id] = id;
+- s->LoadImage(image_id);
+-}
+-
+-void SpotifySearchProvider::ArtLoadedSlot(const QString& id, const QImage& image) {
+- QMap<QString, int>::iterator it = pending_art_.find(id);
+- if (it == pending_art_.end())
+- return;
+-
+- const int orig_id = it.value();
+- pending_art_.erase(it);
+-
+- emit ArtLoaded(orig_id, ScaleAndPad(image));
+-}
+-
+-void SpotifySearchProvider::LoadTracksAsync(int id, const Result& result) {
+- switch (result.type_) {
+- case globalsearch::Type_Track: {
+- SongMimeData* mime_data = new SongMimeData;
+- mime_data->songs = SongList() << result.metadata_;
+- emit TracksLoaded(id, mime_data);
+- break;
+- }
+-
+- case globalsearch::Type_Album: {
+- SpotifyServer* s = server();
+- if (!s) {
+- emit TracksLoaded(id, NULL);
+- return;
+- }
+-
+- QString uri = result.metadata_.url().toString();
+-
+- pending_tracks_[uri] = id;
+- s->AlbumBrowse(uri);
+- break;
+- }
+-
+- default:
+- break;
+- }
+-}
+-
+-void SpotifySearchProvider::AlbumBrowseResponse(const spotify_pb::BrowseAlbumResponse& response) {
+- QString uri = QStringFromStdString(response.uri());
+- QMap<QString, int>::iterator it = pending_tracks_.find(uri);
+- if (it == pending_tracks_.end())
+- return;
+-
+- const int orig_id = it.value();
+- pending_tracks_.erase(it);
+-
+- SongMimeData* mime_data = new SongMimeData;
+-
+- for (int i=0 ; i<response.track_size() ; ++i) {
+- Song song;
+- SpotifyService::SongFromProtobuf(response.track(i), &song);
+- mime_data->songs << song;
+- }
+-
+- emit TracksLoaded(orig_id, mime_data);
+-}
+-
+-bool SpotifySearchProvider::IsLoggedIn() {
+- if (server()) {
+- return service_->IsLoggedIn();
+- }
+- return false;
+-}
+-
+-void SpotifySearchProvider::ShowConfig() {
+- if (service_) {
+- return service_->ShowConfig();
+- }
+-}
+diff -rauN clementine-1.0.1/src/globalsearch/spotifysearchprovider.h /dev/null
+--- clementine-1.0.1/src/globalsearch/spotifysearchprovider.h 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,60 +0,0 @@
+-/* 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 SPOTIFYSEARCHPROVIDER_H
+-#define SPOTIFYSEARCHPROVIDER_H
+-
+-#include "searchprovider.h"
+-#include "spotifyblob/common/spotifymessages.pb.h"
+-
+-class SpotifyServer;
+-class SpotifyService;
+-
+-
+-class SpotifySearchProvider : public SearchProvider {
+- Q_OBJECT
+-
+-public:
+- SpotifySearchProvider(QObject* parent = 0);
+-
+- void SearchAsync(int id, const QString& query);
+- void LoadArtAsync(int id, const Result& result);
+- void LoadTracksAsync(int id, const Result& result);
+-
+- bool IsLoggedIn();
+- void ShowConfig();
+-
+-private slots:
+- void ServerDestroyed();
+- void SearchFinishedSlot(const spotify_pb::SearchResponse& response);
+- void ArtLoadedSlot(const QString& id, const QImage& image);
+-
+- void AlbumBrowseResponse(const spotify_pb::BrowseAlbumResponse& response);
+-
+-private:
+- SpotifyServer* server();
+-
+-private:
+- SpotifyServer* server_;
+- SpotifyService* service_;
+-
+- QMap<QString, PendingState> queries_;
+- QMap<QString, int> pending_art_;
+- QMap<QString, int> pending_tracks_;
+-};
+-
+-#endif // SPOTIFYSEARCHPROVIDER_H
+diff -rauN clementine-1.0.1/src/internet/internetmodel.cpp clementine-libre-1.0.1/src/internet/internetmodel.cpp
+--- clementine-1.0.1/src/internet/internetmodel.cpp 2011-12-02 19:24:44.000000000 -0200
++++ clementine-libre-1.0.1/src/internet/internetmodel.cpp 2012-05-28 18:56:58.934758916 -0300
+@@ -32,9 +32,6 @@
+ #ifdef HAVE_LIBLASTFM
+ #include "lastfmservice.h"
+ #endif
+-#ifdef HAVE_SPOTIFY
+- #include "spotifyservice.h"
+-#endif
+
+ #include <QMimeData>
+ #include <QtDebug>
+@@ -75,9 +72,6 @@
+ AddService(new SavedRadio(this));
+ AddService(new SkyFmService(this));
+ AddService(new SomaFMService(this));
+-#ifdef HAVE_SPOTIFY
+- AddService(new SpotifyService(this));
+-#endif
+ }
+
+ void InternetModel::AddService(InternetService *service) {
+diff -rauN clementine-1.0.1/src/internet/spotifyblobdownloader.cpp /dev/null
+--- clementine-1.0.1/src/internet/spotifyblobdownloader.cpp 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,222 +0,0 @@
+-/* 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 "config.h"
+-#include "spotifyblobdownloader.h"
+-#include "spotifyservice.h"
+-#include "core/logging.h"
+-#include "core/network.h"
+-#include "core/utilities.h"
+-
+-#include <QDir>
+-#include <QMessageBox>
+-#include <QNetworkReply>
+-#include <QProgressDialog>
+-
+-#ifdef HAVE_QCA
+- #include <QtCrypto>
+-#endif // HAVE_QCA
+-
+-const char* SpotifyBlobDownloader::kSignatureSuffix = ".sha1";
+-
+-
+-SpotifyBlobDownloader::SpotifyBlobDownloader(
+- const QString& version, const QString& path, QObject* parent)
+- : QObject(parent),
+- version_(version),
+- path_(path),
+- network_(new NetworkAccessManager(this)),
+- progress_(new QProgressDialog(tr("Downloading Spotify plugin"), tr("Cancel"), 0, 0))
+-{
+- progress_->setWindowTitle(QCoreApplication::applicationName());
+- connect(progress_, SIGNAL(canceled()), SLOT(Cancel()));
+-}
+-
+-SpotifyBlobDownloader::~SpotifyBlobDownloader() {
+- qDeleteAll(replies_);
+- replies_.clear();
+-
+- delete progress_;
+-}
+-
+-bool SpotifyBlobDownloader::Prompt() {
+- QMessageBox::StandardButton ret = QMessageBox::question(NULL,
+- tr("Spotify plugin not installed"),
+- tr("An additional plugin is required to use Spotify in Clementine. Would you like to download and install it now?"),
+- QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+- return ret == QMessageBox::Yes;
+-}
+-
+-void SpotifyBlobDownloader::Start() {
+- qDeleteAll(replies_);
+- replies_.clear();
+-
+- const QStringList filenames = QStringList()
+- << "blob"
+- << "blob" + QString(kSignatureSuffix)
+- << "libspotify.so.10.1.16"
+- << "libspotify.so.10.1.16" + QString(kSignatureSuffix);
+-
+- foreach (const QString& filename, filenames) {
+- const QUrl url(SpotifyService::kBlobDownloadUrl + version_ + "/" + filename);
+- qLog(Info) << "Downloading" << url;
+-
+- QNetworkReply* reply = network_->get(QNetworkRequest(url));
+- connect(reply, SIGNAL(finished()), SLOT(ReplyFinished()));
+- connect(reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(ReplyProgress()));
+-
+- replies_ << reply;
+- }
+-
+- progress_->show();
+-}
+-
+-void SpotifyBlobDownloader::ReplyFinished() {
+- QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
+- if (reply->error() != QNetworkReply::NoError) {
+- // Handle network errors
+- ShowError(reply->errorString());
+- return;
+- }
+-
+- // Is everything finished?
+- foreach (QNetworkReply* reply, replies_) {
+- if (!reply->isFinished()) {
+- return;
+- }
+- }
+-
+- // Read files into memory first.
+- QMap<QString, QByteArray> file_data;
+- QStringList signature_filenames;
+-
+- foreach (QNetworkReply* reply, replies_) {
+- const QString filename = reply->url().path().section('/', -1, -1);
+-
+- if (filename.endsWith(kSignatureSuffix)) {
+- signature_filenames << filename;
+- }
+-
+- file_data[filename] = reply->readAll();
+- }
+-
+-#ifdef HAVE_QCA
+- // Load the public key
+- QCA::ConvertResult conversion_result;
+- QCA::PublicKey key = QCA::PublicKey::fromPEMFile(":/clementine-spotify-public.pem",
+- &conversion_result);
+- if (QCA::ConvertGood != conversion_result) {
+- ShowError("Failed to load Spotify public key");
+- return;
+- }
+-
+- // Verify signatures
+- foreach (const QString& signature_filename, signature_filenames) {
+- QString actual_filename = signature_filename;
+- actual_filename.remove(kSignatureSuffix);
+-
+- qLog(Debug) << "Verifying" << actual_filename << "against" << signature_filename;
+-
+- if (!key.verifyMessage(file_data[actual_filename],
+- file_data[signature_filename],
+- QCA::EMSA3_SHA1)) {
+- ShowError("Invalid signature: " + actual_filename);
+- return;
+- }
+- }
+-#endif // HAVE_QCA
+-
+- // Make the destination directory and write the files into it
+- QDir().mkpath(path_);
+-
+- foreach (const QString& filename, file_data.keys()) {
+- const QString dest_path = path_ + "/" + filename;
+-
+- if (filename.endsWith(kSignatureSuffix))
+- continue;
+-
+- qLog(Info) << "Writing" << dest_path;
+-
+- QFile file(dest_path);
+- if (!file.open(QIODevice::WriteOnly)) {
+- ShowError("Failed to open " + dest_path + " for writing");
+- return;
+- }
+-
+- file.write(file_data[filename]);
+- file.close();
+- file.setPermissions(QFile::Permissions(0x7755));
+-
+-#ifdef Q_OS_UNIX
+- const int so_pos = filename.lastIndexOf(".so.");
+- if (so_pos != -1) {
+- QString link_path = path_ + "/" + filename.left(so_pos + 3);
+- QStringList version_parts = filename.mid(so_pos + 4).split('.');
+-
+- while (!version_parts.isEmpty()) {
+- qLog(Debug) << "Linking" << dest_path << "to" << link_path;
+- int ret = symlink(dest_path.toLocal8Bit().constData(),
+- link_path.toLocal8Bit().constData());
+-
+- if (ret != 0) {
+- qLog(Warning) << "Creating symlink failed with return code" << ret;
+- }
+-
+- link_path += "." + version_parts.takeFirst();
+- }
+- }
+-#endif // Q_OS_UNIX
+- }
+-
+- EmitFinished();
+-}
+-
+-void SpotifyBlobDownloader::ReplyProgress() {
+- int progress = 0;
+- int total = 0;
+-
+- foreach (QNetworkReply* reply, replies_) {
+- progress += reply->bytesAvailable();
+- total += reply->rawHeader("Content-Length").toInt();
+- }
+-
+- progress_->setMaximum(total);
+- progress_->setValue(progress);
+-}
+-
+-void SpotifyBlobDownloader::Cancel() {
+- deleteLater();
+-}
+-
+-void SpotifyBlobDownloader::ShowError(const QString& message) {
+- // Stop any remaining replies before showing the dialog so they don't
+- // carry on in the background
+- foreach (QNetworkReply* reply, replies_) {
+- disconnect(reply, 0, this, 0);
+- reply->abort();
+- }
+-
+- qLog(Warning) << message;
+- QMessageBox::warning(NULL, tr("Error downloading Spotify plugin"), message,
+- QMessageBox::Close);
+- deleteLater();
+-}
+-
+-void SpotifyBlobDownloader::EmitFinished() {
+- emit Finished();
+- deleteLater();
+-}
+diff -rauN clementine-1.0.1/src/internet/spotifyblobdownloader.h /dev/null
+--- clementine-1.0.1/src/internet/spotifyblobdownloader.h 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,63 +0,0 @@
+-/* 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 SPOTIFYBLOBDOWNLOADER_H
+-#define SPOTIFYBLOBDOWNLOADER_H
+-
+-#include <QObject>
+-
+-class QNetworkAccessManager;
+-class QNetworkReply;
+-class QProgressDialog;
+-
+-class SpotifyBlobDownloader : public QObject {
+- Q_OBJECT
+-
+-public:
+- SpotifyBlobDownloader(const QString& version, const QString& path,
+- QObject* parent = 0);
+- ~SpotifyBlobDownloader();
+-
+- static const char* kSignatureSuffix;
+-
+- static bool Prompt();
+-
+- void Start();
+-
+-signals:
+- void Finished();
+-
+-private slots:
+- void ReplyFinished();
+- void ReplyProgress();
+- void Cancel();
+-
+-private:
+- void ShowError(const QString& message);
+- void EmitFinished();
+-
+-private:
+- QString version_;
+- QString path_;
+-
+- QNetworkAccessManager* network_;
+- QList<QNetworkReply*> replies_;
+-
+- QProgressDialog* progress_;
+-};
+-
+-#endif // SPOTIFYBLOBDOWNLOADER_H
+diff -rauN clementine-1.0.1/src/internet/spotifysearchplaylisttype.cpp /dev/null
+--- clementine-1.0.1/src/internet/spotifysearchplaylisttype.cpp 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,49 +0,0 @@
+-/* 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 "spotifysearchplaylisttype.h"
+-#include "spotifyservice.h"
+-
+-const char* SpotifySearchPlaylistType::kName = "spotify-search";
+-
+-SpotifySearchPlaylistType::SpotifySearchPlaylistType(SpotifyService* service)
+- : service_(service) {
+-}
+-
+-QIcon SpotifySearchPlaylistType::icon(Playlist* playlist) const {
+- return QIcon(":icons/32x32/spotify.png");
+-}
+-
+-QString SpotifySearchPlaylistType::search_hint_text(Playlist* playlist) const {
+- return QObject::tr("Search Spotify");
+-}
+-
+-QString SpotifySearchPlaylistType::empty_playlist_text(Playlist* playlist) const {
+- return QObject::tr("Start typing in the search box above to find music on %1.").arg("Spotify");
+-}
+-
+-bool SpotifySearchPlaylistType::has_special_search_behaviour(Playlist* playlist) const {
+- return true;
+-}
+-
+-void SpotifySearchPlaylistType::Search(const QString& text, Playlist* playlist) {
+- service_->Search(text, playlist);
+-}
+-
+-void SpotifySearchPlaylistType::DidYouMeanClicked(const QString& text, Playlist* playlist) {
+- service_->Search(text, playlist, true);
+-}
+diff -rauN clementine-1.0.1/src/internet/spotifysearchplaylisttype.h /dev/null
+--- clementine-1.0.1/src/internet/spotifysearchplaylisttype.h 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,44 +0,0 @@
+-/* 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 SPOTIFYSEARCHPLAYLISTTYPE_H
+-#define SPOTIFYSEARCHPLAYLISTTYPE_H
+-
+-#include "playlist/specialplaylisttype.h"
+-
+-class SpotifyService;
+-
+-class SpotifySearchPlaylistType : public SpecialPlaylistType {
+-public:
+- SpotifySearchPlaylistType(SpotifyService* service);
+-
+- static const char* kName;
+- virtual QString name() const { return kName; }
+-
+- virtual QIcon icon(Playlist* playlist) const;
+- virtual QString search_hint_text(Playlist* playlist) const;
+- virtual QString empty_playlist_text(Playlist* playlist) const;
+-
+- virtual bool has_special_search_behaviour(Playlist* playlist) const;
+- virtual void Search(const QString& text, Playlist* playlist);
+- virtual void DidYouMeanClicked(const QString& text, Playlist* playlist);
+-
+-private:
+- SpotifyService* service_;
+-};
+-
+-#endif // SPOTIFYSEARCHPLAYLISTTYPE_H
+diff -rauN clementine-1.0.1/src/internet/spotifyserver.cpp /dev/null
+--- clementine-1.0.1/src/internet/spotifyserver.cpp 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,261 +0,0 @@
+-/* 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/closure.h"
+-#include "core/logging.h"
+-
+-#include "spotifyblob/common/spotifymessages.pb.h"
+-#include "spotifyblob/common/spotifymessagehandler.h"
+-
+-#include <QTcpServer>
+-#include <QTcpSocket>
+-#include <QTimer>
+-
+-SpotifyServer::SpotifyServer(QObject* parent)
+- : QObject(parent),
+- server_(new QTcpServer(this)),
+- protocol_socket_(NULL),
+- handler_(NULL),
+- logged_in_(false)
+-{
+- 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() {
+- delete protocol_socket_;
+- delete handler_;
+-
+- protocol_socket_ = server_->nextPendingConnection();
+- handler_ = new SpotifyMessageHandler(protocol_socket_, this);
+- connect(handler_, SIGNAL(MessageArrived(spotify_pb::SpotifyMessage)),
+- SLOT(HandleMessage(spotify_pb::SpotifyMessage)));
+-
+- qLog(Info) << "Connection from port" << protocol_socket_->peerPort();
+-
+- // Send any login messages that were queued before the client connected
+- foreach (const spotify_pb::SpotifyMessage& message, queued_login_messages_) {
+- SendMessage(message);
+- }
+- queued_login_messages_.clear();
+-}
+-
+-void SpotifyServer::SendMessage(const spotify_pb::SpotifyMessage& message) {
+- const bool is_login_message = message.has_login_request();
+-
+- QList<spotify_pb::SpotifyMessage>* queue =
+- is_login_message ? &queued_login_messages_ : &queued_messages_;
+-
+- if (!protocol_socket_ || (!is_login_message && !logged_in_)) {
+- queue->append(message);
+- } else {
+- handler_->SendMessage(message);
+- }
+-}
+-
+-void SpotifyServer::Login(const QString& username, const QString& password,
+- spotify_pb::Bitrate bitrate, bool volume_normalisation) {
+- spotify_pb::SpotifyMessage message;
+-
+- spotify_pb::LoginRequest* request = message.mutable_login_request();
+- request->set_username(DataCommaSizeFromQString(username));
+- if (!password.isEmpty()) {
+- request->set_password(DataCommaSizeFromQString(password));
+- }
+- request->mutable_playback_settings()->set_bitrate(bitrate);
+- request->mutable_playback_settings()->set_volume_normalisation(volume_normalisation);
+-
+- SendMessage(message);
+-}
+-
+-void SpotifyServer::SetPlaybackSettings(spotify_pb::Bitrate bitrate, bool volume_normalisation) {
+- spotify_pb::SpotifyMessage message;
+-
+- spotify_pb::PlaybackSettings* request = message.mutable_set_playback_settings_request();
+- request->set_bitrate(bitrate);
+- request->set_volume_normalisation(volume_normalisation);
+-
+- SendMessage(message);
+-}
+-
+-void SpotifyServer::HandleMessage(const spotify_pb::SpotifyMessage& message) {
+- if (message.has_login_response()) {
+- const spotify_pb::LoginResponse& response = message.login_response();
+- logged_in_ = response.success();
+-
+- if (response.success()) {
+- // Send any messages that were queued before the client logged in
+- foreach (const spotify_pb::SpotifyMessage& message, queued_messages_) {
+- SendMessage(message);
+- }
+- queued_messages_.clear();
+- }
+-
+- emit LoginCompleted(response.success(), QStringFromStdString(response.error()),
+- response.error_code());
+- } else if (message.has_playlists_updated()) {
+- emit PlaylistsUpdated(message.playlists_updated());
+- } else if (message.has_load_playlist_response()) {
+- const spotify_pb::LoadPlaylistResponse& response = message.load_playlist_response();
+-
+- switch (response.request().type()) {
+- case spotify_pb::Inbox:
+- emit InboxLoaded(response);
+- break;
+-
+- case spotify_pb::Starred:
+- emit StarredLoaded(response);
+- break;
+-
+- case spotify_pb::UserPlaylist:
+- emit UserPlaylistLoaded(response);
+- break;
+- }
+- } else if (message.has_playback_error()) {
+- emit PlaybackError(QStringFromStdString(message.playback_error().error()));
+- } else if (message.has_search_response()) {
+- emit SearchResults(message.search_response());
+- } else if (message.has_image_response()) {
+- const spotify_pb::ImageResponse& response = message.image_response();
+- const QString id = QStringFromStdString(response.id());
+-
+- if (response.has_data()) {
+- emit ImageLoaded(id, QImage::fromData(QByteArray(
+- response.data().data(), response.data().size())));
+- } else {
+- emit ImageLoaded(id, QImage());
+- }
+- } else if (message.has_sync_playlist_progress()) {
+- emit SyncPlaylistProgress(message.sync_playlist_progress());
+- } else if (message.has_browse_album_response()) {
+- emit AlbumBrowseResults(message.browse_album_response());
+- }
+-}
+-
+-void SpotifyServer::LoadPlaylist(spotify_pb::PlaylistType type, int index) {
+- spotify_pb::SpotifyMessage message;
+- spotify_pb::LoadPlaylistRequest* req = message.mutable_load_playlist_request();
+-
+- req->set_type(type);
+- if (index != -1) {
+- req->set_user_playlist_index(index);
+- }
+-
+- SendMessage(message);
+-}
+-
+-void SpotifyServer::SyncPlaylist(
+- spotify_pb::PlaylistType type, int index, bool offline) {
+- spotify_pb::SpotifyMessage message;
+- spotify_pb::SyncPlaylistRequest* req = message.mutable_sync_playlist_request();
+- req->mutable_request()->set_type(type);
+- if (index != -1) {
+- req->mutable_request()->set_user_playlist_index(index);
+- }
+- req->set_offline_sync(offline);
+-
+- SendMessage(message);
+-}
+-
+-void SpotifyServer::SyncInbox() {
+- SyncPlaylist(spotify_pb::Inbox, -1, true);
+-}
+-
+-void SpotifyServer::SyncStarred() {
+- SyncPlaylist(spotify_pb::Starred, -1, true);
+-}
+-
+-void SpotifyServer::SyncUserPlaylist(int index) {
+- Q_ASSERT(index >= 0);
+- SyncPlaylist(spotify_pb::UserPlaylist, index, true);
+-}
+-
+-void SpotifyServer::LoadInbox() {
+- LoadPlaylist(spotify_pb::Inbox);
+-}
+-
+-void SpotifyServer::LoadStarred() {
+- LoadPlaylist(spotify_pb::Starred);
+-}
+-
+-void SpotifyServer::LoadUserPlaylist(int index) {
+- Q_ASSERT(index >= 0);
+- LoadPlaylist(spotify_pb::UserPlaylist, index);
+-}
+-
+-void SpotifyServer::StartPlaybackLater(const QString& uri, quint16 port) {
+- QTimer* timer = new QTimer(this);
+- connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater()));
+-
+- timer->start(100); // lol
+- NewClosure(timer, SIGNAL(timeout()),
+- this, SLOT(StartPlayback(QString,quint16)),
+- uri, port);
+-}
+-
+-void SpotifyServer::StartPlayback(const QString& uri, quint16 port) {
+- spotify_pb::SpotifyMessage message;
+- spotify_pb::PlaybackRequest* req = message.mutable_playback_request();
+-
+- req->set_track_uri(DataCommaSizeFromQString(uri));
+- req->set_media_port(port);
+- SendMessage(message);
+-}
+-
+-void SpotifyServer::Seek(qint64 offset_bytes) {
+- spotify_pb::SpotifyMessage message;
+- spotify_pb::SeekRequest* req = message.mutable_seek_request();
+-
+- req->set_offset_bytes(offset_bytes);
+- SendMessage(message);
+-}
+-
+-void SpotifyServer::Search(const QString& text, int limit, int limit_album) {
+- spotify_pb::SpotifyMessage message;
+- spotify_pb::SearchRequest* req = message.mutable_search_request();
+-
+- req->set_query(DataCommaSizeFromQString(text));
+- req->set_limit(limit);
+- req->set_limit_album(limit_album);
+- SendMessage(message);
+-}
+-
+-void SpotifyServer::LoadImage(const QString& id) {
+- spotify_pb::SpotifyMessage message;
+- spotify_pb::ImageRequest* req = message.mutable_image_request();
+-
+- req->set_id(DataCommaSizeFromQString(id));
+- SendMessage(message);
+-}
+-
+-void SpotifyServer::AlbumBrowse(const QString& uri) {
+- spotify_pb::SpotifyMessage message;
+- spotify_pb::BrowseAlbumRequest* req = message.mutable_browse_album_request();
+-
+- req->set_uri(DataCommaSizeFromQString(uri));
+- SendMessage(message);
+-}
+diff -rauN clementine-1.0.1/src/internet/spotifyserver.h /dev/null
+--- clementine-1.0.1/src/internet/spotifyserver.h 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,91 +0,0 @@
+-/* 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 "spotifyblob/common/spotifymessages.pb.h"
+-
+-#include <QImage>
+-#include <QObject>
+-
+-class SpotifyMessageHandler;
+-
+-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,
+- spotify_pb::Bitrate bitrate, bool volume_normalisation);
+-
+- void LoadStarred();
+- void SyncStarred();
+- void LoadInbox();
+- void SyncInbox();
+- void LoadUserPlaylist(int index);
+- void SyncUserPlaylist(int index);
+- void StartPlaybackLater(const QString& uri, quint16 port);
+- void Search(const QString& text, int limit, int limit_album = 0);
+- void LoadImage(const QString& id);
+- void AlbumBrowse(const QString& uri);
+- void SetPlaybackSettings(spotify_pb::Bitrate bitrate, bool volume_normalisation);
+-
+- int server_port() const;
+-
+-public slots:
+- void StartPlayback(const QString& uri, quint16 port);
+- void Seek(qint64 offset_bytes);
+-
+-signals:
+- void LoginCompleted(bool success, const QString& error,
+- spotify_pb::LoginResponse_Error error_code);
+- void PlaylistsUpdated(const spotify_pb::Playlists& playlists);
+-
+- void StarredLoaded(const spotify_pb::LoadPlaylistResponse& response);
+- void InboxLoaded(const spotify_pb::LoadPlaylistResponse& response);
+- void UserPlaylistLoaded(const spotify_pb::LoadPlaylistResponse& response);
+- void PlaybackError(const QString& message);
+- void SearchResults(const spotify_pb::SearchResponse& response);
+- void ImageLoaded(const QString& id, const QImage& image);
+- void SyncPlaylistProgress(const spotify_pb::SyncPlaylistProgress& progress);
+- void AlbumBrowseResults(const spotify_pb::BrowseAlbumResponse& response);
+-
+-private slots:
+- void NewConnection();
+- void HandleMessage(const spotify_pb::SpotifyMessage& message);
+-
+-private:
+- void LoadPlaylist(spotify_pb::PlaylistType type, int index = -1);
+- void SyncPlaylist(spotify_pb::PlaylistType type, int index, bool offline);
+- void SendMessage(const spotify_pb::SpotifyMessage& message);
+-
+- QTcpServer* server_;
+- QTcpSocket* protocol_socket_;
+- SpotifyMessageHandler* handler_;
+- bool logged_in_;
+-
+- QList<spotify_pb::SpotifyMessage> queued_login_messages_;
+- QList<spotify_pb::SpotifyMessage> queued_messages_;
+-};
+-
+-#endif // SPOTIFYSERVER_H
+diff -rauN clementine-1.0.1/src/internet/spotifyservice.cpp /dev/null
+--- clementine-1.0.1/src/internet/spotifyservice.cpp 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,669 +0,0 @@
+-#include "config.h"
+-#include "internetmodel.h"
+-#include "spotifyblobdownloader.h"
+-#include "spotifyserver.h"
+-#include "spotifyservice.h"
+-#include "spotifysearchplaylisttype.h"
+-#include "core/database.h"
+-#include "core/logging.h"
+-#include "core/player.h"
+-#include "core/taskmanager.h"
+-#include "core/timeconstants.h"
+-#include "core/utilities.h"
+-#include "globalsearch/globalsearch.h"
+-#include "globalsearch/spotifysearchprovider.h"
+-#include "playlist/playlist.h"
+-#include "playlist/playlistcontainer.h"
+-#include "playlist/playlistmanager.h"
+-#include "spotifyblob/common/blobversion.h"
+-#include "spotifyblob/common/spotifymessagehandler.h"
+-#include "widgets/didyoumean.h"
+-#include "ui/iconloader.h"
+-
+-#include <QCoreApplication>
+-#include <QFile>
+-#include <QFileInfo>
+-#include <QMenu>
+-#include <QMessageBox>
+-#include <QProcess>
+-#include <QSettings>
+-#include <QVariant>
+-
+-Q_DECLARE_METATYPE(QStandardItem*);
+-
+-const char* SpotifyService::kServiceName = "Spotify";
+-const char* SpotifyService::kSettingsGroup = "Spotify";
+-const char* SpotifyService::kBlobDownloadUrl = "http://spotify.clementine-player.org/";
+-const int SpotifyService::kSearchDelayMsec = 400;
+-
+-SpotifyService::SpotifyService(InternetModel* parent)
+- : InternetService(kServiceName, parent, parent),
+- server_(NULL),
+- blob_process_(NULL),
+- root_(NULL),
+- search_(NULL),
+- starred_(NULL),
+- inbox_(NULL),
+- login_task_id_(0),
+- pending_search_playlist_(NULL),
+- context_menu_(NULL),
+- search_delay_(new QTimer(this)),
+- login_state_(LoginState_OtherError),
+- bitrate_(spotify_pb::Bitrate320k),
+- volume_normalisation_(false)
+-{
+- // Build the search path for the binary blob.
+- // Look for one distributed alongside clementine first, then check in the
+- // user's home directory for any that have been downloaded.
+-#ifdef Q_OS_MAC
+- system_blob_path_ = QCoreApplication::applicationDirPath() +
+- "/../PlugIns/clementine-spotifyblob";
+-#else
+- system_blob_path_ = QCoreApplication::applicationDirPath() +
+- "/clementine-spotifyblob" CMAKE_EXECUTABLE_SUFFIX;
+-#endif
+-
+- local_blob_version_ = QString("version%1-%2bit").arg(SPOTIFY_BLOB_VERSION).arg(sizeof(void*) * 8);
+- local_blob_path_ = Utilities::GetConfigPath(Utilities::Path_LocalSpotifyBlob) +
+- "/" + local_blob_version_ + "/blob";
+-
+- qLog(Debug) << "Spotify system blob path:" << system_blob_path_;
+- qLog(Debug) << "Spotify local blob path:" << local_blob_path_;
+-
+- model()->player()->playlists()->RegisterSpecialPlaylistType(
+- new SpotifySearchPlaylistType(this));
+-
+- model()->global_search()->AddProvider(new SpotifySearchProvider(this));
+-
+- search_delay_->setInterval(kSearchDelayMsec);
+- search_delay_->setSingleShot(true);
+- connect(search_delay_, SIGNAL(timeout()), SLOT(DoSearch()));
+-}
+-
+-SpotifyService::~SpotifyService() {
+- if (blob_process_ && blob_process_->state() == QProcess::Running) {
+- qLog(Info) << "Terminating blob process...";
+- blob_process_->terminate();
+- blob_process_->waitForFinished(1000);
+- }
+-}
+-
+-QStandardItem* SpotifyService::CreateRootItem() {
+- root_ = new QStandardItem(QIcon(":icons/22x22/spotify.png"), kServiceName);
+- root_->setData(true, InternetModel::Role_CanLazyLoad);
+- return root_;
+-}
+-
+-void SpotifyService::LazyPopulate(QStandardItem* item) {
+- switch (item->data(InternetModel::Role_Type).toInt()) {
+- case InternetModel::Type_Service:
+- EnsureServerCreated();
+- break;
+-
+- case Type_SearchResults:
+- break;
+-
+- case Type_InboxPlaylist:
+- EnsureServerCreated();
+- server_->LoadInbox();
+- break;
+-
+- case Type_StarredPlaylist:
+- EnsureServerCreated();
+- server_->LoadStarred();
+- break;
+-
+- case InternetModel::Type_UserPlaylist:
+- EnsureServerCreated();
+- server_->LoadUserPlaylist(item->data(Role_UserPlaylistIndex).toInt());
+- break;
+-
+- default:
+- break;
+- }
+-
+- return;
+-}
+-
+-QModelIndex SpotifyService::GetCurrentIndex() {
+- return QModelIndex();
+-}
+-
+-void SpotifyService::Login(const QString& username, const QString& password) {
+- Logout();
+- EnsureServerCreated(username, password);
+-}
+-
+-void SpotifyService::LoginCompleted(bool success, const QString& error,
+- spotify_pb::LoginResponse_Error error_code) {
+- if (login_task_id_) {
+- model()->task_manager()->SetTaskFinished(login_task_id_);
+- login_task_id_ = 0;
+- }
+-
+- if (!success) {
+- bool show_error_dialog = true;
+- QString error_copy(error);
+-
+- switch (error_code) {
+- case spotify_pb::LoginResponse_Error_BadUsernameOrPassword:
+- login_state_ = LoginState_BadCredentials;
+- break;
+-
+- case spotify_pb::LoginResponse_Error_UserBanned:
+- login_state_ = LoginState_Banned;
+- break;
+-
+- case spotify_pb::LoginResponse_Error_UserNeedsPremium:
+- login_state_ = LoginState_NoPremium;
+- break;
+-
+- case spotify_pb::LoginResponse_Error_ReloginFailed:
+- if (login_state_ == LoginState_LoggedIn) {
+- // This is the first time the relogin has failed - show a message this
+- // time only.
+- error_copy = tr("You have been logged out of Spotify, please re-enter your password in the Settings dialog.");
+- } else {
+- show_error_dialog = false;
+- }
+-
+- login_state_ = LoginState_ReloginFailed;
+- break;
+-
+- default:
+- login_state_ = LoginState_OtherError;
+- break;
+- }
+-
+- if (show_error_dialog) {
+- QMessageBox::warning(NULL, tr("Spotify login error"), error_copy, QMessageBox::Close);
+- }
+- } else {
+- login_state_ = LoginState_LoggedIn;
+- }
+-
+- QSettings s;
+- s.beginGroup(kSettingsGroup);
+- s.setValue("login_state", login_state_);
+-
+- emit LoginFinished(success);
+-}
+-
+-void SpotifyService::BlobProcessError(QProcess::ProcessError error) {
+- qLog(Error) << "Spotify blob process failed:" << error;
+- blob_process_->deleteLater();
+- blob_process_ = NULL;
+-
+- if (login_task_id_) {
+- model()->task_manager()->SetTaskFinished(login_task_id_);
+- }
+-}
+-
+-void SpotifyService::ReloadSettings() {
+- QSettings s;
+- s.beginGroup(kSettingsGroup);
+-
+- login_state_ = LoginState(s.value("login_state", LoginState_OtherError).toInt());
+- bitrate_ = static_cast<spotify_pb::Bitrate>(
+- s.value("bitrate", spotify_pb::Bitrate320k).toInt());
+- volume_normalisation_ = s.value("volume_normalisation", false).toBool();
+-
+- if (server_ && blob_process_) {
+- server_->SetPlaybackSettings(bitrate_, volume_normalisation_);
+- }
+-}
+-
+-void SpotifyService::EnsureServerCreated(const QString& username,
+- const QString& password) {
+- if (server_ && blob_process_) {
+- return;
+- }
+-
+- delete server_;
+- server_ = new SpotifyServer(this);
+-
+- connect(server_, SIGNAL(LoginCompleted(bool,QString,spotify_pb::LoginResponse_Error)),
+- SLOT(LoginCompleted(bool,QString,spotify_pb::LoginResponse_Error)));
+- connect(server_, SIGNAL(PlaylistsUpdated(spotify_pb::Playlists)),
+- SLOT(PlaylistsUpdated(spotify_pb::Playlists)));
+- connect(server_, SIGNAL(InboxLoaded(spotify_pb::LoadPlaylistResponse)),
+- SLOT(InboxLoaded(spotify_pb::LoadPlaylistResponse)));
+- connect(server_, SIGNAL(StarredLoaded(spotify_pb::LoadPlaylistResponse)),
+- SLOT(StarredLoaded(spotify_pb::LoadPlaylistResponse)));
+- connect(server_, SIGNAL(UserPlaylistLoaded(spotify_pb::LoadPlaylistResponse)),
+- SLOT(UserPlaylistLoaded(spotify_pb::LoadPlaylistResponse)));
+- connect(server_, SIGNAL(PlaybackError(QString)),
+- SIGNAL(StreamError(QString)));
+- connect(server_, SIGNAL(SearchResults(spotify_pb::SearchResponse)),
+- SLOT(SearchResults(spotify_pb::SearchResponse)));
+- connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
+- SIGNAL(ImageLoaded(QString,QImage)));
+- connect(server_, SIGNAL(SyncPlaylistProgress(spotify_pb::SyncPlaylistProgress)),
+- SLOT(SyncPlaylistProgress(spotify_pb::SyncPlaylistProgress)));
+-
+- server_->Init();
+-
+- login_task_id_ = model()->task_manager()->StartTask(tr("Connecting to Spotify"));
+-
+- QString login_username = username;
+- QString login_password = password;
+-
+- if (username.isEmpty()) {
+- QSettings s;
+- s.beginGroup(kSettingsGroup);
+-
+- login_username = s.value("username").toString();
+- login_password = QString();
+- }
+-
+- server_->Login(login_username, login_password, bitrate_, volume_normalisation_);
+-
+- StartBlobProcess();
+-}
+-
+-void SpotifyService::StartBlobProcess() {
+- // Try to find an executable to run
+- QString blob_path;
+- QProcessEnvironment env(QProcessEnvironment::systemEnvironment());
+-
+- // Look in the system search path first
+- if (QFile::exists(system_blob_path_)) {
+- blob_path = system_blob_path_;
+- }
+-
+- // Next look in the local path
+- if (blob_path.isEmpty()) {
+- if (QFile::exists(local_blob_path_)) {
+- blob_path = local_blob_path_;
+- env.insert("LD_LIBRARY_PATH", QFileInfo(local_blob_path_).path());
+- }
+- }
+-
+- if (blob_path.isEmpty()) {
+- // If the blob still wasn't found then we'll prompt the user to download one
+- if (login_task_id_) {
+- model()->task_manager()->SetTaskFinished(login_task_id_);
+- }
+-
+- #ifdef Q_OS_LINUX
+- if (SpotifyBlobDownloader::Prompt()) {
+- InstallBlob();
+- }
+- #endif
+-
+- return;
+- }
+-
+- delete blob_process_;
+- blob_process_ = new QProcess(this);
+- blob_process_->setProcessChannelMode(QProcess::ForwardedChannels);
+- blob_process_->setProcessEnvironment(env);
+-
+- connect(blob_process_,
+- SIGNAL(error(QProcess::ProcessError)),
+- SLOT(BlobProcessError(QProcess::ProcessError)));
+-
+- qLog(Info) << "Starting" << blob_path;
+- blob_process_->start(
+- blob_path, QStringList() << QString::number(server_->server_port()));
+-}
+-
+-bool SpotifyService::IsBlobInstalled() const {
+- return QFile::exists(system_blob_path_) ||
+- QFile::exists(local_blob_path_);
+-}
+-
+-void SpotifyService::InstallBlob() {
+- // The downloader deletes itself when it finishes
+- SpotifyBlobDownloader* downloader = new SpotifyBlobDownloader(
+- local_blob_version_, QFileInfo(local_blob_path_).path(), this);
+- connect(downloader, SIGNAL(Finished()), SLOT(BlobDownloadFinished()));
+- connect(downloader, SIGNAL(Finished()), SIGNAL(BlobStateChanged()));
+- downloader->Start();
+-}
+-
+-void SpotifyService::BlobDownloadFinished() {
+- EnsureServerCreated();
+-}
+-
+-void SpotifyService::PlaylistsUpdated(const spotify_pb::Playlists& response) {
+- if (login_task_id_) {
+- model()->task_manager()->SetTaskFinished(login_task_id_);
+- login_task_id_ = 0;
+- }
+-
+- // Create starred and inbox playlists if they're not here already
+- if (!search_) {
+- search_ = new QStandardItem(IconLoader::Load("edit-find"),
+- tr("Search Spotify (opens a new tab)"));
+- search_->setData(Type_SearchResults, InternetModel::Role_Type);
+- search_->setData(InternetModel::PlayBehaviour_DoubleClickAction,
+- InternetModel::Role_PlayBehaviour);
+-
+- starred_ = new QStandardItem(QIcon(":/star-on.png"), tr("Starred"));
+- starred_->setData(Type_StarredPlaylist, InternetModel::Role_Type);
+- starred_->setData(true, InternetModel::Role_CanLazyLoad);
+-
+- inbox_ = new QStandardItem(IconLoader::Load("mail-message"), tr("Inbox"));
+- inbox_->setData(Type_InboxPlaylist, InternetModel::Role_Type);
+- inbox_->setData(true, InternetModel::Role_CanLazyLoad);
+-
+- root_->appendRow(search_);
+- root_->appendRow(starred_);
+- root_->appendRow(inbox_);
+- }
+-
+- // Don't do anything if the playlists haven't changed since last time.
+- if (!DoPlaylistsDiffer(response)) {
+- qLog(Debug) << "Playlists haven't changed - not updating";
+- return;
+- }
+-
+- // Remove and recreate the other playlists
+- foreach (QStandardItem* item, playlists_) {
+- item->parent()->removeRow(item->row());
+- }
+- playlists_.clear();
+-
+- for (int i=0 ; i<response.playlist_size() ; ++i) {
+- const spotify_pb::Playlists::Playlist& msg = response.playlist(i);
+-
+- QStandardItem* item = new QStandardItem(QStringFromStdString(msg.name()));
+- item->setData(InternetModel::Type_UserPlaylist, InternetModel::Role_Type);
+- item->setData(true, InternetModel::Role_CanLazyLoad);
+- item->setData(msg.index(), Role_UserPlaylistIndex);
+- item->setData(InternetModel::PlayBehaviour_SingleItem, InternetModel::Role_PlayBehaviour);
+-
+- root_->appendRow(item);
+- playlists_ << item;
+-
+- // Preload the playlist items so that drag & drop works immediately.
+- LazyPopulate(item);
+- }
+-}
+-
+-bool SpotifyService::DoPlaylistsDiffer(const spotify_pb::Playlists& response) const {
+- if (playlists_.count() != response.playlist_size()) {
+- return true;
+- }
+-
+- for (int i=0 ; i<response.playlist_size() ; ++i) {
+- const spotify_pb::Playlists::Playlist& msg = response.playlist(i);
+- const QStandardItem* item = PlaylistBySpotifyIndex(msg.index());
+-
+- if (!item) {
+- return true;
+- }
+-
+- if (QStringFromStdString(msg.name()) != item->text()) {
+- return true;
+- }
+- }
+-
+- return false;
+-}
+-
+-void SpotifyService::InboxLoaded(const spotify_pb::LoadPlaylistResponse& response) {
+- FillPlaylist(inbox_, response);
+-}
+-
+-void SpotifyService::StarredLoaded(const spotify_pb::LoadPlaylistResponse& response) {
+- FillPlaylist(starred_, response);
+-}
+-
+-QStandardItem* SpotifyService::PlaylistBySpotifyIndex(int index) const {
+- foreach (QStandardItem* item, playlists_) {
+- if (item->data(Role_UserPlaylistIndex).toInt() == index) {
+- return item;
+- }
+- }
+- return NULL;
+-}
+-
+-void SpotifyService::UserPlaylistLoaded(const spotify_pb::LoadPlaylistResponse& response) {
+- // Find a playlist with this index
+- QStandardItem* item = PlaylistBySpotifyIndex(response.request().user_playlist_index());
+- if (item) {
+- FillPlaylist(item, response);
+- }
+-}
+-
+-void SpotifyService::FillPlaylist(QStandardItem* item, const spotify_pb::LoadPlaylistResponse& response) {
+- qLog(Debug) << "Filling playlist:" << item->text();
+- if (item->hasChildren())
+- item->removeRows(0, item->rowCount());
+-
+- for (int i=0 ; i<response.track_size() ; ++i) {
+- Song song;
+- SongFromProtobuf(response.track(i), &song);
+-
+- QStandardItem* child = new QStandardItem(song.PrettyTitleWithArtist());
+- child->setData(Type_Track, InternetModel::Role_Type);
+- child->setData(QVariant::fromValue(song), InternetModel::Role_SongMetadata);
+- child->setData(InternetModel::PlayBehaviour_SingleItem, InternetModel::Role_PlayBehaviour);
+- child->setData(song.url(), InternetModel::Role_Url);
+-
+- item->appendRow(child);
+- }
+-}
+-
+-void SpotifyService::SongFromProtobuf(const spotify_pb::Track& track, Song* song) {
+- song->set_rating(track.starred() ? 1.0 : 0.0);
+- song->set_title(QStringFromStdString(track.title()));
+- song->set_album(QStringFromStdString(track.album()));
+- song->set_length_nanosec(track.duration_msec() * kNsecPerMsec);
+- song->set_score(track.popularity());
+- song->set_disc(track.disc());
+- song->set_track(track.track());
+- song->set_year(track.year());
+- song->set_url(QUrl(QStringFromStdString(track.uri())));
+- song->set_art_automatic("spotify://image/" + QStringFromStdString(track.album_art_id()));
+-
+- QStringList artists;
+- for (int i=0 ; i<track.artist_size() ; ++i) {
+- artists << QStringFromStdString(track.artist(i));
+- }
+-
+- song->set_artist(artists.join(", "));
+-
+- song->set_filetype(Song::Type_Stream);
+- song->set_valid(true);
+- song->set_directory_id(0);
+- song->set_mtime(0);
+- song->set_ctime(0);
+- song->set_filesize(0);
+-}
+-
+-PlaylistItem::Options SpotifyService::playlistitem_options() const {
+- return PlaylistItem::PauseDisabled | PlaylistItem::SeekDisabled;
+-}
+-
+-void SpotifyService::EnsureMenuCreated() {
+- if (context_menu_)
+- return;
+-
+- context_menu_ = new QMenu;
+-
+- context_menu_->addActions(GetPlaylistActions());
+- context_menu_->addSeparator();
+- context_menu_->addAction(IconLoader::Load("edit-find"), tr("Search Spotify (opens a new tab)..."), this, SLOT(OpenSearchTab()));
+- context_menu_->addSeparator();
+- context_menu_->addAction(IconLoader::Load("configure"), tr("Configure Spotify..."), this, SLOT(ShowConfig()));
+-
+- playlist_context_menu_ = new QMenu;
+- playlist_sync_action_ = playlist_context_menu_->addAction(
+- IconLoader::Load("view-refresh"),
+- tr("Make playlist available offline"),
+- this,
+- SLOT(SyncPlaylist()));
+-}
+-
+-void SpotifyService::SyncPlaylist() {
+- QStandardItem* item = playlist_sync_action_->data().value<QStandardItem*>();
+- Q_ASSERT(item);
+-
+- switch (item->data(InternetModel::Role_Type).toInt()) {
+- case InternetModel::Type_UserPlaylist: {
+- int index = item->data(Role_UserPlaylistIndex).toInt();
+- server_->SyncUserPlaylist(index);
+- playlist_sync_ids_[index] =
+- model()->task_manager()->StartTask(tr("Syncing Spotify playlist"));
+- break;
+- }
+- case Type_InboxPlaylist:
+- server_->SyncInbox();
+- inbox_sync_id_ = model()->task_manager()->StartTask(tr("Syncing Spotify inbox"));
+- break;
+- case Type_StarredPlaylist:
+- server_->SyncStarred();
+- starred_sync_id_ = model()->task_manager()->StartTask(tr("Syncing Spotify starred tracks"));
+- break;
+- default:
+- break;
+- }
+-}
+-
+-void SpotifyService::Search(const QString& text, Playlist* playlist, bool now) {
+- EnsureServerCreated();
+-
+- pending_search_ = text;
+- pending_search_playlist_ = playlist;
+-
+- if (now) {
+- search_delay_->stop();
+- DoSearch();
+- } else {
+- search_delay_->start();
+- }
+-}
+-
+-void SpotifyService::DoSearch() {
+- if (!pending_search_.isEmpty()) {
+- server_->Search(pending_search_, 200);
+- }
+-}
+-
+-void SpotifyService::SearchResults(const spotify_pb::SearchResponse& response) {
+- if (QStringFromStdString(response.request().query()) != pending_search_) {
+- qLog(Debug) << "Old search result for"
+- << QStringFromStdString(response.request().query())
+- << "expecting" << pending_search_;
+- return;
+- }
+- pending_search_.clear();
+-
+- SongList songs;
+- for (int i=0 ; i<response.result_size() ; ++i) {
+- Song song;
+- SongFromProtobuf(response.result(i), &song);
+- songs << song;
+- }
+-
+- qLog(Debug) << "Got" << songs.count() << "results";
+-
+- pending_search_playlist_->Clear();
+- pending_search_playlist_->InsertSongs(songs);
+-
+- const QString did_you_mean = QStringFromStdString(response.did_you_mean());
+- if (!did_you_mean.isEmpty()) {
+- model()->player()->playlists()->playlist_container()->did_you_mean()->Show(did_you_mean);
+- }
+-}
+-
+-SpotifyServer* SpotifyService::server() const {
+- SpotifyService* nonconst_this = const_cast<SpotifyService*>(this);
+-
+- if (QThread::currentThread() != thread()) {
+- metaObject()->invokeMethod(nonconst_this, "EnsureServerCreated",
+- Qt::BlockingQueuedConnection);
+- } else {
+- nonconst_this->EnsureServerCreated();
+- }
+-
+- return server_;
+-}
+-
+-void SpotifyService::ShowContextMenu(const QModelIndex& index, const QPoint& global_pos) {
+- EnsureMenuCreated();
+- QStandardItem* item = model()->itemFromIndex(index);
+- if (item) {
+- int type = item->data(InternetModel::Role_Type).toInt();
+- if (type == Type_InboxPlaylist ||
+- type == Type_StarredPlaylist ||
+- type == InternetModel::Type_UserPlaylist) {
+- playlist_sync_action_->setData(qVariantFromValue(item));
+- playlist_context_menu_->popup(global_pos);
+- return;
+- }
+- }
+-
+- context_menu_->popup(global_pos);
+-}
+-
+-void SpotifyService::OpenSearchTab() {
+- model()->player()->playlists()->New(tr("Search Spotify"), SongList(),
+- SpotifySearchPlaylistType::kName);
+-}
+-
+-void SpotifyService::ItemDoubleClicked(QStandardItem* item) {
+- if (item == search_) {
+- OpenSearchTab();
+- }
+-}
+-
+-void SpotifyService::LoadImage(const QString& id) {
+- EnsureServerCreated();
+- server_->LoadImage(id);
+-}
+-
+-void SpotifyService::SyncPlaylistProgress(
+- const spotify_pb::SyncPlaylistProgress& progress) {
+- qLog(Debug) << "Sync progress:" << progress.sync_progress();
+- int task_id = -1;
+- switch (progress.request().type()) {
+- case spotify_pb::Inbox:
+- task_id = inbox_sync_id_;
+- break;
+- case spotify_pb::Starred:
+- task_id = starred_sync_id_;
+- break;
+- case spotify_pb::UserPlaylist: {
+- QMap<int, int>::const_iterator it = playlist_sync_ids_.constFind(
+- progress.request().user_playlist_index());
+- if (it != playlist_sync_ids_.constEnd()) {
+- task_id = it.value();
+- }
+- break;
+- }
+- default:
+- break;
+- }
+- if (task_id == -1) {
+- qLog(Warning) << "Received sync progress for unknown playlist";
+- return;
+- }
+- model()->task_manager()->SetTaskProgress(task_id, progress.sync_progress(), 100);
+- if (progress.sync_progress() == 100) {
+- model()->task_manager()->SetTaskFinished(task_id);
+- if (progress.request().type() == spotify_pb::UserPlaylist) {
+- playlist_sync_ids_.remove(task_id);
+- }
+- }
+-}
+-
+-void SpotifyService::ShowConfig() {
+- emit OpenSettingsAtPage(SettingsDialog::Page_Spotify);
+-}
+-
+-void SpotifyService::Logout() {
+- delete server_;
+- delete blob_process_;
+- server_ = NULL;
+- blob_process_ = NULL;
+-
+- login_state_ = LoginState_OtherError;
+-
+- QSettings s;
+- s.beginGroup(kSettingsGroup);
+- s.setValue("login_state", login_state_);
+-}
+diff -rauN clementine-1.0.1/src/internet/spotifyservice.h /dev/null
+--- clementine-1.0.1/src/internet/spotifyservice.h 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,147 +0,0 @@
+-#ifndef SPOTIFYSERVICE_H
+-#define SPOTIFYSERVICE_H
+-
+-#include "internetmodel.h"
+-#include "internetservice.h"
+-#include "spotifyblob/common/spotifymessages.pb.h"
+-
+-#include <QProcess>
+-#include <QTimer>
+-
+-#include <boost/shared_ptr.hpp>
+-
+-class Playlist;
+-class SpotifyServer;
+-
+-class QMenu;
+-
+-class SpotifyService : public InternetService {
+- Q_OBJECT
+-
+-public:
+- SpotifyService(InternetModel* parent);
+- ~SpotifyService();
+-
+- enum Type {
+- Type_SearchResults = InternetModel::TypeCount,
+- Type_StarredPlaylist,
+- Type_InboxPlaylist,
+- Type_Track,
+- };
+-
+- enum Role {
+- Role_UserPlaylistIndex = InternetModel::RoleCount,
+- };
+-
+- // Values are persisted - don't change.
+- enum LoginState {
+- LoginState_LoggedIn = 1,
+- LoginState_Banned = 2,
+- LoginState_BadCredentials = 3,
+- LoginState_NoPremium = 4,
+- LoginState_OtherError = 5,
+- LoginState_ReloginFailed = 6
+- };
+-
+- static const char* kServiceName;
+- static const char* kSettingsGroup;
+- static const char* kBlobDownloadUrl;
+- static const int kSearchDelayMsec;
+-
+- void ReloadSettings();
+-
+- QStandardItem* CreateRootItem();
+- void LazyPopulate(QStandardItem* parent);
+- void ShowContextMenu(const QModelIndex& index, const QPoint& global_pos);
+- void ItemDoubleClicked(QStandardItem* item);
+- PlaylistItem::Options playlistitem_options() const;
+-
+- void Logout();
+- void Login(const QString& username, const QString& password);
+- void Search(const QString& text, Playlist* playlist, bool now = false);
+- Q_INVOKABLE void LoadImage(const QString& id);
+-
+- SpotifyServer* server() const;
+-
+- bool IsBlobInstalled() const;
+- void InstallBlob();
+-
+- // Persisted in the settings and updated on each Login().
+- LoginState login_state() const { return login_state_; }
+- bool IsLoggedIn() const { return login_state_ == LoginState_LoggedIn; }
+-
+- static void SongFromProtobuf(const spotify_pb::Track& track, Song* song);
+-
+-signals:
+- void BlobStateChanged();
+- void LoginFinished(bool success);
+- void ImageLoaded(const QString& id, const QImage& image);
+-
+-public slots:
+- void ShowConfig();
+-
+-protected:
+- virtual QModelIndex GetCurrentIndex();
+-
+-private:
+- void StartBlobProcess();
+- void FillPlaylist(QStandardItem* item, const spotify_pb::LoadPlaylistResponse& response);
+- void EnsureMenuCreated();
+-
+- QStandardItem* PlaylistBySpotifyIndex(int index) const;
+- bool DoPlaylistsDiffer(const spotify_pb::Playlists& response) const;
+-
+-private slots:
+- void EnsureServerCreated(const QString& username = QString(),
+- const QString& password = QString());
+- void BlobProcessError(QProcess::ProcessError error);
+- void LoginCompleted(bool success, const QString& error,
+- spotify_pb::LoginResponse_Error error_code);
+- void PlaylistsUpdated(const spotify_pb::Playlists& response);
+- void InboxLoaded(const spotify_pb::LoadPlaylistResponse& response);
+- void StarredLoaded(const spotify_pb::LoadPlaylistResponse& response);
+- void UserPlaylistLoaded(const spotify_pb::LoadPlaylistResponse& response);
+- void SearchResults(const spotify_pb::SearchResponse& response);
+- void SyncPlaylistProgress(const spotify_pb::SyncPlaylistProgress& progress);
+-
+- void OpenSearchTab();
+- void DoSearch();
+-
+- void SyncPlaylist();
+- void BlobDownloadFinished();
+-
+-private:
+- SpotifyServer* server_;
+-
+- QString system_blob_path_;
+- QString local_blob_version_;
+- QString local_blob_path_;
+- QProcess* blob_process_;
+-
+- QStandardItem* root_;
+- QStandardItem* search_;
+- QStandardItem* starred_;
+- QStandardItem* inbox_;
+- QList<QStandardItem*> playlists_;
+-
+- int login_task_id_;
+- QString pending_search_;
+- Playlist* pending_search_playlist_;
+-
+- QMenu* context_menu_;
+- QMenu* playlist_context_menu_;
+- QAction* playlist_sync_action_;
+- QModelIndex context_item_;
+-
+- QTimer* search_delay_;
+-
+- int inbox_sync_id_;
+- int starred_sync_id_;
+- QMap<int, int> playlist_sync_ids_;
+-
+- LoginState login_state_;
+- spotify_pb::Bitrate bitrate_;
+- bool volume_normalisation_;
+-};
+-
+-#endif
+diff -rauN clementine-1.0.1/src/internet/spotifysettingspage.cpp /dev/null
+--- clementine-1.0.1/src/internet/spotifysettingspage.cpp 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,172 +0,0 @@
+-/* 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 "spotifysettingspage.h"
+-
+-#include "spotifyservice.h"
+-#include "internetmodel.h"
+-#include "ui_spotifysettingspage.h"
+-#include "core/network.h"
+-#include "spotifyblob/common/spotifymessages.pb.h"
+-#include "ui/iconloader.h"
+-
+-#include <QMessageBox>
+-#include <QNetworkReply>
+-#include <QNetworkRequest>
+-#include <QSettings>
+-#include <QtDebug>
+-
+-SpotifySettingsPage::SpotifySettingsPage(SettingsDialog* dialog)
+- : SettingsPage(dialog),
+- network_(new NetworkAccessManager(this)),
+- ui_(new Ui_SpotifySettingsPage),
+- service_(InternetModel::Service<SpotifyService>()),
+- validated_(false)
+-{
+- ui_->setupUi(this);
+-
+- setWindowIcon(QIcon(":/icons/48x48/spotify.png"));
+-
+- QFont bold_font(font());
+- bold_font.setBold(true);
+- ui_->blob_status->setFont(bold_font);
+-
+- connect(ui_->download_blob, SIGNAL(clicked()), SLOT(DownloadBlob()));
+- connect(ui_->login, SIGNAL(clicked()), SLOT(Login()));
+- connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(Logout()));
+- connect(ui_->login_state, SIGNAL(LoginClicked()), SLOT(Login()));
+-
+- connect(service_, SIGNAL(LoginFinished(bool)), SLOT(LoginFinished(bool)));
+- connect(service_, SIGNAL(BlobStateChanged()), SLOT(BlobStateChanged()));
+-
+- ui_->login_state->AddCredentialField(ui_->username);
+- ui_->login_state->AddCredentialField(ui_->password);
+- ui_->login_state->AddCredentialGroup(ui_->account_group);
+-
+- ui_->bitrate->addItem("96 " + tr("kbps"), spotify_pb::Bitrate96k);
+- ui_->bitrate->addItem("160 " + tr("kbps"), spotify_pb::Bitrate160k);
+- ui_->bitrate->addItem("320 " + tr("kbps"), spotify_pb::Bitrate320k);
+-
+- BlobStateChanged();
+-}
+-
+-SpotifySettingsPage::~SpotifySettingsPage() {
+- delete ui_;
+-}
+-
+-void SpotifySettingsPage::BlobStateChanged() {
+- const bool installed = service_->IsBlobInstalled();
+-
+- ui_->account_group->setEnabled(installed);
+- ui_->blob_status->setText(installed ? tr("Installed") : tr("Not installed"));
+-
+-#ifdef Q_OS_LINUX
+- ui_->download_blob->setEnabled(!installed);
+-#else
+- ui_->download_blob->setEnabled(false);
+-#endif
+-}
+-
+-void SpotifySettingsPage::DownloadBlob() {
+- service_->InstallBlob();
+-}
+-
+-void SpotifySettingsPage::Login() {
+- if (!service_->IsBlobInstalled()) {
+- return;
+- }
+-
+- if (ui_->username->text() == original_username_ &&
+- ui_->password->text() == original_password_ &&
+- service_->login_state() == SpotifyService::LoginState_LoggedIn) {
+- return;
+- }
+-
+- ui_->login_state->SetLoggedIn(LoginStateWidget::LoginInProgress);
+- service_->Login(ui_->username->text(), ui_->password->text());
+-}
+-
+-void SpotifySettingsPage::Load() {
+- QSettings s;
+- s.beginGroup(SpotifyService::kSettingsGroup);
+-
+- original_username_ = s.value("username").toString();
+-
+- ui_->username->setText(original_username_);
+- validated_ = false;
+-
+- ui_->bitrate->setCurrentIndex(ui_->bitrate->findData(
+- s.value("bitrate", spotify_pb::Bitrate320k).toInt()));
+- ui_->volume_normalisation->setChecked(
+- s.value("volume_normalisation", false).toBool());
+-
+- UpdateLoginState();
+-}
+-
+-void SpotifySettingsPage::Save() {
+- QSettings s;
+- s.beginGroup(SpotifyService::kSettingsGroup);
+-
+- s.setValue("username", ui_->username->text());
+- s.setValue("password", ui_->password->text());
+-
+- s.setValue("bitrate", ui_->bitrate->itemData(ui_->bitrate->currentIndex()).toInt());
+- s.setValue("volume_normalisation", ui_->volume_normalisation->isChecked());
+-}
+-
+-void SpotifySettingsPage::LoginFinished(bool success) {
+- validated_ = success;
+-
+- Save();
+- UpdateLoginState();
+-}
+-
+-void SpotifySettingsPage::UpdateLoginState() {
+- const bool logged_in =
+- service_->login_state() == SpotifyService::LoginState_LoggedIn;
+-
+- ui_->login_state->SetLoggedIn(logged_in ? LoginStateWidget::LoggedIn
+- : LoginStateWidget::LoggedOut,
+- ui_->username->text());
+- ui_->login_state->SetAccountTypeVisible(!logged_in);
+-
+- switch (service_->login_state()) {
+- case SpotifyService::LoginState_NoPremium:
+- ui_->login_state->SetAccountTypeText(tr("You do not have a Spotify Premium account."));
+- break;
+-
+- case SpotifyService::LoginState_Banned:
+- case SpotifyService::LoginState_BadCredentials:
+- ui_->login_state->SetAccountTypeText(tr("Your username or password was incorrect."));
+- break;
+-
+- case SpotifyService::LoginState_ReloginFailed:
+- ui_->login_state->SetAccountTypeText(tr("You have been logged out of Spotify, please re-enter your password."));
+- break;
+-
+- default:
+- ui_->login_state->SetAccountTypeText(tr("A Spotify Premium account is required."));
+- break;
+- }
+-}
+-
+-void SpotifySettingsPage::Logout() {
+- service_->Logout();
+- UpdateLoginState();
+-
+- ui_->username->clear();
+-}
+diff -rauN clementine-1.0.1/src/internet/spotifysettingspage.h /dev/null
+--- clementine-1.0.1/src/internet/spotifysettingspage.h 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,59 +0,0 @@
+-/* 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 SPOTIFYSETTINGSPAGE_H
+-#define SPOTIFYSETTINGSPAGE_H
+-
+-#include "ui/settingspage.h"
+-
+-class NetworkAccessManager;
+-class Ui_SpotifySettingsPage;
+-class SpotifyService;
+-
+-class SpotifySettingsPage : public SettingsPage {
+- Q_OBJECT
+-
+-public:
+- SpotifySettingsPage(SettingsDialog* dialog);
+- ~SpotifySettingsPage();
+-
+- void Load();
+- void Save();
+-
+-public slots:
+- void BlobStateChanged();
+- void DownloadBlob();
+-
+-private slots:
+- void Login();
+- void LoginFinished(bool success);
+- void Logout();
+-
+-private:
+- void UpdateLoginState();
+-
+-private:
+- NetworkAccessManager* network_;
+- Ui_SpotifySettingsPage* ui_;
+- SpotifyService* service_;
+-
+- bool validated_;
+- QString original_username_;
+- QString original_password_;
+-};
+-
+-#endif // SPOTIFYSETTINGSPAGE_H
+diff -rauN clementine-1.0.1/src/internet/spotifysettingspage.ui /dev/null
+--- clementine-1.0.1/src/internet/spotifysettingspage.ui 2011-12-02 19:24:44.000000000 -0200
++++ /dev/null 2012-05-28 12:50:04.796939473 -0300
+@@ -1,214 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<ui version="4.0">
+- <class>SpotifySettingsPage</class>
+- <widget class="QWidget" name="SpotifySettingsPage">
+- <property name="geometry">
+- <rect>
+- <x>0</x>
+- <y>0</y>
+- <width>545</width>
+- <height>458</height>
+- </rect>
+- </property>
+- <property name="windowTitle">
+- <string>Spotify</string>
+- </property>
+- <layout class="QVBoxLayout" name="verticalLayout_2">
+- <item>
+- <widget class="LoginStateWidget" name="login_state" native="true"/>
+- </item>
+- <item>
+- <widget class="QGroupBox" name="account_group">
+- <property name="title">
+- <string>Account details</string>
+- </property>
+- <layout class="QVBoxLayout" name="verticalLayout_3">
+- <item>
+- <widget class="QWidget" name="login_container" native="true">
+- <property name="enabled">
+- <bool>true</bool>
+- </property>
+- <layout class="QGridLayout" name="gridLayout">
+- <property name="margin">
+- <number>0</number>
+- </property>
+- <item row="1" column="0">
+- <widget class="QLabel" name="username_label">
+- <property name="text">
+- <string>Username</string>
+- </property>
+- </widget>
+- </item>
+- <item row="1" column="1">
+- <widget class="QLineEdit" name="username"/>
+- </item>
+- <item row="2" column="0">
+- <widget class="QLabel" name="password_label">
+- <property name="text">
+- <string>Password</string>
+- </property>
+- </widget>
+- </item>
+- <item row="2" column="1" colspan="2">
+- <widget class="QLineEdit" name="password">
+- <property name="echoMode">
+- <enum>QLineEdit::Password</enum>
+- </property>
+- </widget>
+- </item>
+- <item row="1" column="2">
+- <widget class="QPushButton" name="login">
+- <property name="text">
+- <string>Login</string>
+- </property>
+- </widget>
+- </item>
+- </layout>
+- </widget>
+- </item>
+- </layout>
+- </widget>
+- </item>
+- <item>
+- <widget class="QGroupBox" name="groupBox_2">
+- <property name="title">
+- <string>Spotify plugin</string>
+- </property>
+- <layout class="QVBoxLayout" name="verticalLayout">
+- <item>
+- <widget class="QLabel" name="label">
+- <property name="text">
+- <string>For licensing reasons Spotify support is in a separate plugin.</string>
+- </property>
+- </widget>
+- </item>
+- <item>
+- <layout class="QHBoxLayout" name="horizontalLayout_2">
+- <item>
+- <widget class="QLabel" name="label_2">
+- <property name="text">
+- <string>Plugin status:</string>
+- </property>
+- </widget>
+- </item>
+- <item>
+- <widget class="QLabel" name="blob_status"/>
+- </item>
+- <item>
+- <spacer name="horizontalSpacer">
+- <property name="orientation">
+- <enum>Qt::Horizontal</enum>
+- </property>
+- <property name="sizeHint" stdset="0">
+- <size>
+- <width>40</width>
+- <height>20</height>
+- </size>
+- </property>
+- </spacer>
+- </item>
+- <item>
+- <widget class="QPushButton" name="download_blob">
+- <property name="text">
+- <string>Download...</string>
+- </property>
+- </widget>
+- </item>
+- </layout>
+- </item>
+- </layout>
+- </widget>
+- </item>
+- <item>
+- <widget class="QGroupBox" name="groupBox">
+- <property name="title">
+- <string>Preferences</string>
+- </property>
+- <layout class="QFormLayout" name="formLayout">
+- <item row="0" column="0">
+- <widget class="QLabel" name="label_4">
+- <property name="text">
+- <string>Preferred bitrate</string>
+- </property>
+- </widget>
+- </item>
+- <item row="0" column="1">
+- <widget class="QComboBox" name="bitrate"/>
+- </item>
+- <item row="1" column="0" colspan="2">
+- <widget class="QCheckBox" name="volume_normalisation">
+- <property name="text">
+- <string>Use volume normalisation</string>
+- </property>
+- </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>
+- <layout class="QHBoxLayout" name="horizontalLayout_3">
+- <item>
+- <spacer name="horizontalSpacer_2">
+- <property name="orientation">
+- <enum>Qt::Horizontal</enum>
+- </property>
+- <property name="sizeHint" stdset="0">
+- <size>
+- <width>40</width>
+- <height>20</height>
+- </size>
+- </property>
+- </spacer>
+- </item>
+- <item>
+- <widget class="QLabel" name="label_3">
+- <property name="minimumSize">
+- <size>
+- <width>64</width>
+- <height>64</height>
+- </size>
+- </property>
+- <property name="maximumSize">
+- <size>
+- <width>64</width>
+- <height>64</height>
+- </size>
+- </property>
+- <property name="pixmap">
+- <pixmap resource="../../data/data.qrc">:/spotify-core-logo-128x128.png</pixmap>
+- </property>
+- <property name="scaledContents">
+- <bool>true</bool>
+- </property>
+- </widget>
+- </item>
+- </layout>
+- </item>
+- </layout>
+- </widget>
+- <customwidgets>
+- <customwidget>
+- <class>LoginStateWidget</class>
+- <extends>QWidget</extends>
+- <header>widgets/loginstatewidget.h</header>
+- <container>1</container>
+- </customwidget>
+- </customwidgets>
+- <resources>
+- <include location="../../data/data.qrc"/>
+- </resources>
+- <connections/>
+-</ui>
+diff -rauN clementine-1.0.1/src/ui/about.cpp clementine-libre-1.0.1/src/ui/about.cpp
+--- clementine-1.0.1/src/ui/about.cpp 2012-01-22 10:43:26.000000000 -0200
++++ clementine-libre-1.0.1/src/ui/about.cpp 2012-05-28 19:44:38.760244927 -0300
+@@ -79,12 +79,6 @@
+ ret += QString("<br /><a href=\"http://www.smitelli.com/?page=blog&p=54\">Scott Smitelli</a>");
+ ret += QString("<br /><a href=\"http://hyperboleandahalf.blogspot.com\">Allie Brosh</a></p>");
+
+-#ifdef HAVE_SPOTIFY
+- ret += "<p>This product uses SPOTIFY(R) CORE but is not endorsed, certified "
+- "or otherwise approved in any way by Spotify. Spotify is the "
+- "registered trade mark of the Spotify Group.</p>";
+-#endif // HAVE_SPOTIFY
+-
+ return ret;
+ }
+
+diff -rauN clementine-1.0.1/src/ui/settingsdialog.cpp clementine-libre-1.0.1/src/ui/settingsdialog.cpp
+--- clementine-1.0.1/src/ui/settingsdialog.cpp 2011-12-02 19:24:44.000000000 -0200
++++ clementine-libre-1.0.1/src/ui/settingsdialog.cpp 2012-05-28 19:46:49.506369764 -0300
+@@ -55,10 +55,6 @@
+ # include "remote/remotesettingspage.h"
+ #endif
+
+-#ifdef HAVE_SPOTIFY
+-# include "internet/spotifysettingspage.h"
+-#endif
+-
+ #include <QDesktopWidget>
+ #include <QPainter>
+ #include <QPushButton>
+@@ -140,10 +136,6 @@
+
+ AddPage(Page_Grooveshark, new GroovesharkSettingsPage(this), providers);
+
+-#ifdef HAVE_SPOTIFY
+- AddPage(Page_Spotify, new SpotifySettingsPage(this), providers);
+-#endif
+-
+ AddPage(Page_Magnatune, new MagnatuneSettingsPage(this), providers);
+ AddPage(Page_DigitallyImported, new DigitallyImportedSettingsPage(this), providers);
+ AddPage(Page_BackgroundStreams, new BackgroundStreamsSettingsPage(this), providers);
+diff -rauN clementine-1.0.1/src/ui/settingsdialog.h clementine-libre-1.0.1/src/ui/settingsdialog.h
+--- clementine-1.0.1/src/ui/settingsdialog.h 2011-12-02 19:24:44.000000000 -0200
++++ clementine-libre-1.0.1/src/ui/settingsdialog.h 2012-05-28 19:48:55.399426104 -0300
+@@ -65,7 +65,6 @@
+ Page_Library,
+ Page_Lastfm,
+ Page_Grooveshark,
+- Page_Spotify,
+ Page_Magnatune,
+ Page_DigitallyImported,
+ Page_BackgroundStreams,
+--- clementine-1.0.1/src/core/logging.cpp 2011-12-02 19:24:43.000000000 -0200
++++ clementine-libre-1.0.1/src/core/logging.cpp 2012-05-30 03:09:25.554790760 -0300
+@@ -14,10 +14,6 @@
+ limitations under the License.
+ */
+
+-// Note: this file is licensed under the Apache License instead of GPL because
+-// it is used by the Spotify blob which links against libspotify and is not GPL
+-// compatible.
+-
+
+ #include <QCoreApplication>
+ #include <QDateTime>
+--- clementine-1.0.1/src/core/logging.h 2011-12-02 19:24:43.000000000 -0200
++++ clementine-libre-1.0.1/src/core/logging.h 2012-05-30 03:09:44.390404481 -0300
+@@ -14,10 +14,6 @@
+ limitations under the License.
+ */
+
+-// Note: this file is licensed under the Apache License instead of GPL because
+-// it is used by the Spotify blob which links against libspotify and is not GPL
+-// compatible.
+-
+
+ #ifndef LOGGING_H
+ #define LOGGING_H
+--- clementine-1.0.1/src/core/timeconstants.h 2011-12-02 19:24:44.000000000 -0200
++++ clementine-libre-1.0.1/src/core/timeconstants.h 2012-05-30 03:10:10.338953893 -0300
+@@ -14,10 +14,6 @@
+ limitations under the License.
+ */
+
+-// Note: this file is licensed under the Apache License instead of GPL because
+-// it is used by the Spotify blob which links against libspotify and is not GPL
+-// compatible.
+-
+ #ifndef TIMECONSTANTS_H
+ #define TIMECONSTANTS_H
+