Merge branch 'v0.19.x'
This commit is contained in:
		
							
								
								
									
										3
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								INSTALL
									
									
									
									
									
								
							| @@ -113,9 +113,6 @@ For WavPack playback. | ||||
| libadplug - http://adplug.sourceforge.net/ | ||||
| For AdLib playback. | ||||
|  | ||||
| despotify - https://github.com/SimonKagstrom/despotify | ||||
| For Spotify playback. | ||||
|  | ||||
|  | ||||
| Optional Miscellaneous Dependencies | ||||
| ----------------------------------- | ||||
|   | ||||
							
								
								
									
										25
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								Makefile.am
									
									
									
									
									
								
							| @@ -1155,7 +1155,6 @@ libinput_a_CPPFLAGS = $(AM_CPPFLAGS) \ | ||||
| 	$(NFS_CFLAGS) \ | ||||
| 	$(CDIO_PARANOIA_CFLAGS) \ | ||||
| 	$(FFMPEG_CFLAGS) \ | ||||
| 	$(DESPOTIFY_CFLAGS) \ | ||||
| 	$(MMS_CFLAGS) | ||||
|  | ||||
| INPUT_LIBS = \ | ||||
| @@ -1165,7 +1164,6 @@ INPUT_LIBS = \ | ||||
| 	$(NFS_LIBS) \ | ||||
| 	$(CDIO_PARANOIA_LIBS) \ | ||||
| 	$(FFMPEG_LIBS2) \ | ||||
| 	$(DESPOTIFY_LIBS) \ | ||||
| 	$(MMS_LIBS) | ||||
|  | ||||
| if ENABLE_ALSA | ||||
| @@ -1211,15 +1209,6 @@ libinput_a_SOURCES += \ | ||||
| 	src/input/plugins/MmsInputPlugin.cxx src/input/plugins/MmsInputPlugin.hxx | ||||
| endif | ||||
|  | ||||
| if ENABLE_DESPOTIFY | ||||
| libinput_a_SOURCES += \ | ||||
| 	src/lib/despotify/DespotifyUtils.cxx \ | ||||
| 	src/lib/despotify/DespotifyUtils.hxx \ | ||||
| 	src/input/plugins/DespotifyInputPlugin.cxx \ | ||||
| 	src/input/plugins/DespotifyInputPlugin.hxx | ||||
| endif | ||||
|  | ||||
|  | ||||
| liboutput_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \ | ||||
| 	$(AO_CFLAGS) \ | ||||
| 	$(ALSA_CFLAGS) \ | ||||
| @@ -1440,14 +1429,6 @@ libplaylist_plugins_a_SOURCES += \ | ||||
| 	src/playlist/plugins/EmbeddedCuePlaylistPlugin.hxx | ||||
| endif | ||||
|  | ||||
| if ENABLE_DESPOTIFY | ||||
| libplaylist_plugins_a_SOURCES += \ | ||||
| 	src/lib/despotify/DespotifyUtils.cxx \ | ||||
| 	src/lib/despotify/DespotifyUtils.hxx \ | ||||
|        src/playlist/plugins/DespotifyPlaylistPlugin.cxx \ | ||||
|        src/playlist/plugins/DespotifyPlaylistPlugin.hxx | ||||
| endif | ||||
|  | ||||
| if ENABLE_SOUNDCLOUD | ||||
| libplaylist_plugins_a_SOURCES += \ | ||||
| 	src/playlist/plugins/SoundCloudPlaylistPlugin.cxx \ | ||||
| @@ -1684,12 +1665,6 @@ if ENABLE_UPNP | ||||
| test_run_neighbor_explorer_SOURCES += src/lib/expat/ExpatParser.cxx | ||||
| endif | ||||
|  | ||||
| if ENABLE_DESPOTIFY | ||||
| test_run_neighbor_explorer_SOURCES += \ | ||||
| 	src/lib/despotify/DespotifyUtils.cxx \ | ||||
| 	src/lib/despotify/DespotifyUtils.hxx | ||||
| endif | ||||
|  | ||||
| endif | ||||
|  | ||||
| if ENABLE_ARCHIVE | ||||
|   | ||||
							
								
								
									
										9
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								NEWS
									
									
									
									
									
								
							| @@ -28,6 +28,10 @@ ver 0.20 (not yet released) | ||||
| * database | ||||
|   - proxy: add TCP keepalive option | ||||
|  | ||||
| ver 0.19.9 (not yet released) | ||||
| * fix build failure with uClibc | ||||
| * fix build failure on non-POSIX operating systems | ||||
|  | ||||
| ver 0.19.8 (2015/01/14) | ||||
| * input | ||||
|   - curl: fix bug after rewinding from end-of-file | ||||
| @@ -201,6 +205,11 @@ ver 0.19 (2014/10/10) | ||||
| * install systemd unit for socket activation | ||||
| * Android port | ||||
|  | ||||
| ver 0.18.23 (not yet released) | ||||
| * despotify: remove defunct plugin | ||||
| * fix gcc 5.0 warnings | ||||
|  | ||||
|  | ||||
| ver 0.18.22 (2014/01/14) | ||||
| * fix clang 3.6 warnings | ||||
|  | ||||
|   | ||||
| @@ -2,8 +2,8 @@ | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|           package="org.musicpd" | ||||
|           android:installLocation="auto" | ||||
|           android:versionCode="12" | ||||
|           android:versionName="0.19.8"> | ||||
|           android:versionCode="13" | ||||
|           android:versionName="0.19.9"> | ||||
|  | ||||
|   <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17"/> | ||||
|  | ||||
|   | ||||
| @@ -33,7 +33,7 @@ gcc_version = '4.9' | ||||
| llvm_version = '3.5' | ||||
|  | ||||
| # the path to the MPD sources | ||||
| mpd_path = os.path.dirname(os.path.dirname(sys.argv[0])) or '.' | ||||
| mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..')) | ||||
|  | ||||
| # output directories | ||||
| lib_path = os.path.abspath('lib') | ||||
|   | ||||
| @@ -223,6 +223,7 @@ if test x$host_is_linux = xyes; then | ||||
| fi | ||||
|  | ||||
| AC_CHECK_FUNCS(getpwnam_r getpwuid_r) | ||||
| AC_CHECK_FUNCS(strndup) | ||||
|  | ||||
| if test x$host_is_linux = xyes; then | ||||
| 	MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD) | ||||
| @@ -708,10 +709,6 @@ dnl ----------------------------------- NFS ----------------------------- | ||||
| MPD_ENABLE_AUTO_PKG(nfs, NFS, [libnfs], | ||||
| 	[NFS input plugin], [libnfs not found]) | ||||
|  | ||||
| dnl --------------------------------- Despotify --------------------------------- | ||||
| MPD_ENABLE_AUTO_PKG(despotify, DESPOTIFY, [despotify], | ||||
| 	[Despotify support], [despotify not found]) | ||||
|  | ||||
| dnl --------------------------------- Soundcloud ------------------------------ | ||||
| MPD_AUTO([soundcloud], [soundcloud.com support], [libyajl not found], | ||||
| 	[PKG_CHECK_MODULES([YAJL], [yajl >= 2.0], | ||||
| @@ -1456,7 +1453,6 @@ printf '\nStreaming support:\n\t' | ||||
| results(cdio_paranoia, [CDIO_PARANOIA]) | ||||
| results(curl,[CURL]) | ||||
| results(smbclient,[SMBCLIENT]) | ||||
| results(despotify,[Despotify]) | ||||
| results(soundcloud,[Soundcloud]) | ||||
| printf '\n\t' | ||||
| results(mms,[MMS]) | ||||
|   | ||||
| @@ -195,16 +195,6 @@ of database. | ||||
| Limit the depth of the directories being watched, 0 means only watch | ||||
| the music directory itself.  There is no limit by default. | ||||
| .TP | ||||
| .B despotify_user <name> | ||||
| This specifies the user to use when logging in to Spotify using the despotify plugins. | ||||
| .TP | ||||
| .B despotify_password <name> | ||||
| This specifies the password to use when logging in to Spotify using the despotify plugins. | ||||
| .TP | ||||
| .B despotify_high_bitrate <yes or no> | ||||
| This specifies if the requested bitrate for Spotify should be high or not. Higher sounds | ||||
| better but requires more processing and higher bandwidth. Default is yes. | ||||
| .TP | ||||
| .SH REQUIRED AUDIO OUTPUT PARAMETERS | ||||
| .TP | ||||
| .B type <type> | ||||
|   | ||||
| @@ -1151,7 +1151,7 @@ OK | ||||
|           </term> | ||||
|           <listitem> | ||||
|             <para> | ||||
|               Searches case-sensitively for partial matches in the | ||||
|               Searches case-insensitively for partial matches in the | ||||
|               current playlist. | ||||
|             </para> | ||||
|           </listitem> | ||||
|   | ||||
							
								
								
									
										129
									
								
								doc/user.xml
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								doc/user.xml
									
									
									
									
									
								
							| @@ -315,9 +315,8 @@ systemctl start mpd.socket</programlisting> | ||||
|       </para> | ||||
|  | ||||
|       <programlisting>input { | ||||
|     plugin "despotify" | ||||
|     user "foo" | ||||
|     password "bar" | ||||
|     plugin "curl" | ||||
|     proxy "proxy.local" | ||||
| } | ||||
|       </programlisting> | ||||
|  | ||||
| @@ -1588,66 +1587,6 @@ buffer_size: 16384</programlisting> | ||||
|         </informaltable> | ||||
|       </section> | ||||
|  | ||||
|       <section> | ||||
|         <title><varname>despotify</varname></title> | ||||
|  | ||||
|         <para> | ||||
|           Plays <ulink url="http://www.spotify.com">Spotify</ulink> tracks using the despotify | ||||
|           library. The despotify plugin uses a <filename>spt://</filename> URI and a Spotify | ||||
|           URL. So for example, you can add a song with: | ||||
|         </para> | ||||
|          | ||||
|         <para> | ||||
|           <filename>mpc add spt://spotify:track:5qENVY0YEdZ7fiuOax70x1</filename> | ||||
|         </para> | ||||
|          | ||||
|         <para> | ||||
|           You need a Spotify premium account to use this plugin, and you need | ||||
|           to setup username and password in the configuration file. The | ||||
|           configuration settings are global since the despotify playlist plugin | ||||
|           use the same settings. | ||||
|         </para> | ||||
|  | ||||
|         <informaltable> | ||||
|           <tgroup cols="2"> | ||||
|             <thead> | ||||
|               <row> | ||||
|                 <entry>Setting</entry> | ||||
|                 <entry>Description</entry> | ||||
|               </row> | ||||
|             </thead> | ||||
|             <tbody> | ||||
|               <row> | ||||
|                 <entry> | ||||
|                   <varname>despotify_user</varname> | ||||
|                 </entry> | ||||
|                 <entry> | ||||
|                   Sets up the Spotify username (required) | ||||
|                 </entry> | ||||
|               </row> | ||||
|               <row> | ||||
|                 <entry> | ||||
|                   <varname>despotify_password</varname> | ||||
|                 </entry> | ||||
|                 <entry> | ||||
|                   Sets up the Spotify password (required) | ||||
|                 </entry> | ||||
|               </row> | ||||
|               <row> | ||||
|                 <entry> | ||||
|                   <varname>despotify_high_bitrate</varname> | ||||
|                 </entry> | ||||
|                 <entry> | ||||
|                   Set up if high bitrate should be used for Spotify tunes. | ||||
|                   High bitrate sounds better but slow systems can have problems | ||||
|                   with playback (default yes). | ||||
|                 </entry> | ||||
|               </row> | ||||
|             </tbody> | ||||
|           </tgroup> | ||||
|         </informaltable> | ||||
|       </section> | ||||
|  | ||||
|       <section> | ||||
|         <title><varname>file</varname></title> | ||||
|  | ||||
| @@ -3486,70 +3425,6 @@ buffer_size: 16384</programlisting> | ||||
|           playlist files. | ||||
|         </para> | ||||
|       </section> | ||||
|  | ||||
|       <section> | ||||
|         <title><varname>despotify</varname></title> | ||||
|  | ||||
|         <para> | ||||
|           Adds <ulink url="http://www.spotify.com/">Spotify</ulink> | ||||
|           playlists. Spotify playlists use the <filename>spt://</filename> URI, | ||||
|           and a Spotify playlist URL. So for example, you can load a playlist | ||||
|           with | ||||
|         </para> | ||||
|          | ||||
|         <para> | ||||
|           <filename>mpc load spt://spotify:user:simon.kagstrom:playlist:3SUwkOe5VbVHysZcidEZtH</filename> | ||||
|         </para> | ||||
|          | ||||
|         <para> | ||||
|           See the despotify input plugin for configuration options (username | ||||
|           and password needs to be setup) | ||||
|         </para> | ||||
|       </section> | ||||
|  | ||||
|       <section> | ||||
|         <title><varname>soundcloud</varname></title> | ||||
|  | ||||
|         <para> | ||||
|           Adds <ulink url="https://www.soundcloud.com/">Soundcloud</ulink> | ||||
|           playlists. SoundCloud playlists use the <filename>soundcloud://</filename> URI, | ||||
|           and with a number of arguments, you may load different playlists with | ||||
|         </para> | ||||
|  | ||||
|         <programlisting> | ||||
| mpc load soundcloud://track/TRACK_ID | ||||
| mpc load soundcloud://playlist/PLAYLIST_ID | ||||
| mpc load soundcloud://user/USERNAME | ||||
| mpc load soundcloud://search/SEARCH_QUERY | ||||
| mpc load soundcloud://url/https://soundcloud.com/ARTIST/TRACK-NAME | ||||
|         </programlisting> | ||||
|  | ||||
|         <informaltable> | ||||
|           <tgroup cols="2"> | ||||
|             <thead> | ||||
|               <row> | ||||
|                 <entry>Setting</entry> | ||||
|                 <entry>Description</entry> | ||||
|               </row> | ||||
|             </thead> | ||||
|             <tbody> | ||||
|               <row> | ||||
|                 <entry> | ||||
|                   <varname>apikey</varname> | ||||
|                   <parameter>client_id</parameter> | ||||
|                 </entry> | ||||
|                 <entry> | ||||
|                   User apikey/client_id can override the | ||||
|                   <application>MPD</application> token provided by | ||||
|                   SoundCloud. | ||||
|                 </entry> | ||||
|               </row> | ||||
|             </tbody> | ||||
|           </tgroup> | ||||
|         </informaltable> | ||||
|  | ||||
|       </section> | ||||
|  | ||||
|     </section> | ||||
|   </chapter> | ||||
| </book> | ||||
|   | ||||
| @@ -41,7 +41,7 @@ client_process_command_list(Client &client, bool list_ok, | ||||
|  | ||||
| 		FormatDebug(client_domain, "process command \"%s\"", cmd); | ||||
| 		ret = command_process(client, num++, cmd); | ||||
| 		FormatDebug(client_domain, "command returned %i", ret); | ||||
| 		FormatDebug(client_domain, "command returned %i", int(ret)); | ||||
| 		if (ret != CommandResult::OK || client.IsExpired()) | ||||
| 			break; | ||||
| 		else if (list_ok) | ||||
| @@ -90,7 +90,7 @@ client_process_line(Client &client, char *line) | ||||
| 							  std::move(cmd_list)); | ||||
| 			FormatDebug(client_domain, | ||||
| 				    "[%u] process command " | ||||
| 				    "list returned %i", client.num, ret); | ||||
| 				    "list returned %i", client.num, int(ret)); | ||||
|  | ||||
| 			if (ret == CommandResult::CLOSE || | ||||
| 			    client.IsExpired()) | ||||
| @@ -126,7 +126,7 @@ client_process_line(Client &client, char *line) | ||||
| 			ret = command_process(client, 0, line); | ||||
| 			FormatDebug(client_domain, | ||||
| 				    "[%u] command returned %i", | ||||
| 				    client.num, ret); | ||||
| 				    client.num, int(ret)); | ||||
|  | ||||
| 			if (ret == CommandResult::CLOSE || | ||||
| 			    client.IsExpired()) | ||||
|   | ||||
| @@ -54,10 +54,6 @@ | ||||
| #include "plugins/CdioParanoiaInputPlugin.hxx" | ||||
| #endif | ||||
|  | ||||
| #ifdef ENABLE_DESPOTIFY | ||||
| #include "plugins/DespotifyInputPlugin.hxx" | ||||
| #endif | ||||
|  | ||||
| const InputPlugin *const input_plugins[] = { | ||||
| 	&input_plugin_file, | ||||
| #ifdef ENABLE_ALSA | ||||
| @@ -83,9 +79,6 @@ const InputPlugin *const input_plugins[] = { | ||||
| #endif | ||||
| #ifdef ENABLE_CDIO_PARANOIA | ||||
| 	&input_plugin_cdio_paranoia, | ||||
| #endif | ||||
| #ifdef ENABLE_DESPOTIFY | ||||
| 	&input_plugin_despotify, | ||||
| #endif | ||||
| 	nullptr | ||||
| }; | ||||
|   | ||||
| @@ -1,227 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2015 The Music Player Daemon Project | ||||
|  * http://www.musicpd.org | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  */ | ||||
|  | ||||
| #include "config.h" | ||||
| #include "DespotifyInputPlugin.hxx" | ||||
| #include "lib/despotify/DespotifyUtils.hxx" | ||||
| #include "../InputStream.hxx" | ||||
| #include "../InputPlugin.hxx" | ||||
| #include "tag/Tag.hxx" | ||||
| #include "util/StringUtil.hxx" | ||||
| #include "Log.hxx" | ||||
|  | ||||
| extern "C" { | ||||
| #include <despotify.h> | ||||
| } | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| class DespotifyInputStream final : public InputStream { | ||||
| 	struct despotify_session *session; | ||||
| 	struct ds_track *track; | ||||
| 	Tag tag; | ||||
| 	struct ds_pcm_data pcm; | ||||
| 	size_t len_available; | ||||
| 	bool eof; | ||||
|  | ||||
| 	DespotifyInputStream(const char *_uri, | ||||
| 			     Mutex &_mutex, Cond &_cond, | ||||
| 			     despotify_session *_session, | ||||
| 			     ds_track *_track) | ||||
| 		:InputStream(_uri, _mutex, _cond), | ||||
| 		 session(_session), track(_track), | ||||
| 		 tag(mpd_despotify_tag_from_track(*track)), | ||||
| 		 len_available(0), eof(false) { | ||||
|  | ||||
| 		memset(&pcm, 0, sizeof(pcm)); | ||||
|  | ||||
| 		/* Despotify outputs pcm data */ | ||||
| 		SetMimeType("audio/x-mpd-cdda-pcm"); | ||||
| 		SetReady(); | ||||
| 	} | ||||
|  | ||||
| public: | ||||
| 	~DespotifyInputStream(); | ||||
|  | ||||
| 	static InputStream *Open(const char *url, Mutex &mutex, Cond &cond, | ||||
| 				 Error &error); | ||||
|  | ||||
| 	void Callback(int sig); | ||||
|  | ||||
| 	/* virtual methods from InputStream */ | ||||
|  | ||||
| 	bool IsEOF() override { | ||||
| 		return eof; | ||||
| 	} | ||||
|  | ||||
| 	Tag *ReadTag() override { | ||||
| 		if (tag.IsEmpty()) | ||||
| 			return nullptr; | ||||
|  | ||||
| 		Tag *result = new Tag(std::move(tag)); | ||||
| 		tag.Clear(); | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	size_t Read(void *ptr, size_t size, Error &error) override; | ||||
|  | ||||
| private: | ||||
| 	void FillBuffer(); | ||||
| }; | ||||
|  | ||||
| inline void | ||||
| DespotifyInputStream::FillBuffer() | ||||
| { | ||||
| 	/* Wait until there is data */ | ||||
| 	while (1) { | ||||
| 		int rc = despotify_get_pcm(session, &pcm); | ||||
|  | ||||
| 		if (rc == 0 && pcm.len) { | ||||
| 			len_available = pcm.len; | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		if (eof == true) | ||||
| 			break; | ||||
|  | ||||
| 		if (rc < 0) { | ||||
| 			LogDebug(despotify_domain, "despotify_get_pcm error"); | ||||
| 			eof = true; | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		/* Wait a while until next iteration */ | ||||
| 		usleep(50 * 1000); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| inline void | ||||
| DespotifyInputStream::Callback(int sig) | ||||
| { | ||||
| 	switch (sig) { | ||||
| 	case DESPOTIFY_NEW_TRACK: | ||||
| 		break; | ||||
|  | ||||
| 	case DESPOTIFY_TIME_TELL: | ||||
| 		break; | ||||
|  | ||||
| 	case DESPOTIFY_TRACK_PLAY_ERROR: | ||||
| 		LogWarning(despotify_domain, "Track play error"); | ||||
| 		eof = true; | ||||
| 		len_available = 0; | ||||
| 		break; | ||||
|  | ||||
| 	case DESPOTIFY_END_OF_PLAYLIST: | ||||
| 		eof = true; | ||||
| 		LogDebug(despotify_domain, "End of playlist"); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void callback(gcc_unused struct despotify_session* ds, | ||||
| 		     int sig, gcc_unused void* data, void* callback_data) | ||||
| { | ||||
| 	DespotifyInputStream *ctx = (DespotifyInputStream *)callback_data; | ||||
|  | ||||
| 	ctx->Callback(sig); | ||||
| } | ||||
|  | ||||
| DespotifyInputStream::~DespotifyInputStream() | ||||
| { | ||||
| 	mpd_despotify_unregister_callback(callback); | ||||
| 	despotify_free_track(track); | ||||
| } | ||||
|  | ||||
| inline InputStream * | ||||
| DespotifyInputStream::Open(const char *url, | ||||
| 			   Mutex &mutex, Cond &cond, | ||||
| 			   gcc_unused Error &error) | ||||
| { | ||||
| 	if (!StringStartsWith(url, "spt://")) | ||||
| 		return nullptr; | ||||
|  | ||||
| 	despotify_session *session = mpd_despotify_get_session(); | ||||
| 	if (session == nullptr) | ||||
| 		return nullptr; | ||||
|  | ||||
| 	ds_link *ds_link = despotify_link_from_uri(url + 6); | ||||
| 	if (!ds_link) { | ||||
| 		FormatDebug(despotify_domain, "Can't find %s", url); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	if (ds_link->type != LINK_TYPE_TRACK) { | ||||
| 		despotify_free_link(ds_link); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	ds_track *track = despotify_link_get_track(session, ds_link); | ||||
| 	despotify_free_link(ds_link); | ||||
| 	if (!track) | ||||
| 		return nullptr; | ||||
|  | ||||
| 	DespotifyInputStream *ctx = | ||||
| 		new DespotifyInputStream(url, mutex, cond, | ||||
| 					 session, track); | ||||
|  | ||||
| 	if (!mpd_despotify_register_callback(callback, ctx)) { | ||||
| 		delete ctx; | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	if (despotify_play(ctx->session, ctx->track, false) == false) { | ||||
| 		mpd_despotify_unregister_callback(callback); | ||||
| 		delete ctx; | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	return ctx; | ||||
| } | ||||
|  | ||||
| static InputStream * | ||||
| input_despotify_open(const char *url, Mutex &mutex, Cond &cond, Error &error) | ||||
| { | ||||
| 	return DespotifyInputStream::Open(url, mutex, cond, error); | ||||
| } | ||||
|  | ||||
| size_t | ||||
| DespotifyInputStream::Read(void *ptr, size_t read_size, | ||||
| 			   gcc_unused Error &error) | ||||
| { | ||||
| 	if (len_available == 0) | ||||
| 		FillBuffer(); | ||||
|  | ||||
| 	size_t to_cpy = std::min(read_size, len_available); | ||||
| 	memcpy(ptr, pcm.buf, to_cpy); | ||||
| 	len_available -= to_cpy; | ||||
|  | ||||
| 	offset += to_cpy; | ||||
|  | ||||
| 	return to_cpy; | ||||
| } | ||||
|  | ||||
| const InputPlugin input_plugin_despotify = { | ||||
| 	"despotify", | ||||
| 	nullptr, | ||||
| 	nullptr, | ||||
| 	input_despotify_open, | ||||
| }; | ||||
| @@ -1,25 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2015 The Music Player Daemon Project | ||||
|  * http://www.musicpd.org | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef INPUT_DESPOTIFY_HXX | ||||
| #define INPUT_DESPOTIFY_HXX | ||||
|  | ||||
| extern const struct InputPlugin input_plugin_despotify; | ||||
|  | ||||
| #endif | ||||
| @@ -1,160 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2015 The Music Player Daemon Project | ||||
|  * http://www.musicpd.org | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  */ | ||||
|  | ||||
| #include "DespotifyUtils.hxx" | ||||
| #include "tag/Tag.hxx" | ||||
| #include "tag/TagBuilder.hxx" | ||||
| #include "config/ConfigGlobal.hxx" | ||||
| #include "config/ConfigOption.hxx" | ||||
| #include "util/Domain.hxx" | ||||
| #include "util/Macros.hxx" | ||||
| #include "Log.hxx" | ||||
|  | ||||
| extern "C" { | ||||
| #include <despotify.h> | ||||
| } | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| const Domain despotify_domain("despotify"); | ||||
|  | ||||
| static struct despotify_session *g_session; | ||||
| static void (*registered_callbacks[8])(struct despotify_session *, | ||||
| 		int, void *, void *); | ||||
| static void *registered_callback_data[8]; | ||||
|  | ||||
| static void | ||||
| callback(struct despotify_session* ds, int sig, | ||||
| 	 void *data, gcc_unused void *callback_data) | ||||
| { | ||||
| 	for (size_t i = 0; i < ARRAY_SIZE(registered_callbacks); ++i) { | ||||
| 		void (*cb)(struct despotify_session *, int, void *, void *) = registered_callbacks[i]; | ||||
| 		void *cb_data = registered_callback_data[i]; | ||||
|  | ||||
| 		if (cb != nullptr) | ||||
| 			cb(ds, sig, data, cb_data); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool | ||||
| mpd_despotify_register_callback(void (*cb)(struct despotify_session *, int, | ||||
| 					   void *, void *), | ||||
| 				void *cb_data) | ||||
| { | ||||
| 	for (size_t i = 0; i < ARRAY_SIZE(registered_callbacks); ++i) { | ||||
| 		if (!registered_callbacks[i]) { | ||||
| 			registered_callbacks[i] = cb; | ||||
| 			registered_callback_data[i] = cb_data; | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void | ||||
| mpd_despotify_unregister_callback(void (*cb)(struct despotify_session *, int, | ||||
| 					     void *, void *)) | ||||
| { | ||||
| 	for (size_t i = 0; i < ARRAY_SIZE(registered_callbacks); ++i) { | ||||
| 		if (registered_callbacks[i] == cb) { | ||||
| 			registered_callbacks[i] = nullptr; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| Tag | ||||
| mpd_despotify_tag_from_track(const ds_track &track) | ||||
| { | ||||
| 	if (!track.has_meta_data) | ||||
| 		return Tag(); | ||||
|  | ||||
| 	TagBuilder tag; | ||||
|  | ||||
| 	{ | ||||
| 		char tracknum[20]; | ||||
| 		snprintf(tracknum, sizeof(tracknum), "%d", track.tracknumber); | ||||
| 		tag.AddItem(TAG_TRACK, tracknum); | ||||
| 	} | ||||
|  | ||||
| 	{ | ||||
| 		char date[20]; | ||||
| 		snprintf(date, sizeof(date), "%d", track.year); | ||||
| 		tag.AddItem(TAG_DATE, date); | ||||
| 	} | ||||
|  | ||||
| 	{ | ||||
| 		char comment[80]; | ||||
| 		snprintf(comment, sizeof(comment), | ||||
| 			 "Bitrate %d Kbps, %sgeo restricted", | ||||
| 			 track.file_bitrate / 1000, | ||||
| 			 track.geo_restricted ? "" : "not "); | ||||
| 		tag.AddItem(TAG_COMMENT, comment); | ||||
| 	} | ||||
|  | ||||
| 	tag.AddItem(TAG_TITLE, track.title); | ||||
| 	tag.AddItem(TAG_ARTIST, track.artist->name); | ||||
| 	tag.AddItem(TAG_ALBUM, track.album); | ||||
| 	tag.SetDuration(SignedSongTime::FromMS(track.length)); | ||||
|  | ||||
| 	return tag.Commit(); | ||||
| } | ||||
|  | ||||
| struct despotify_session * | ||||
| mpd_despotify_get_session() | ||||
| { | ||||
| 	if (g_session) | ||||
| 		return g_session; | ||||
|  | ||||
| 	const char *const user = | ||||
| 		config_get_string(ConfigOption::DESPOTIFY_USER, nullptr); | ||||
| 	const char *const passwd = | ||||
| 		config_get_string(ConfigOption::DESPOTIFY_PASSWORD, nullptr); | ||||
|  | ||||
| 	if (user == nullptr || passwd == nullptr) { | ||||
| 		LogDebug(despotify_domain, | ||||
| 			 "disabling despotify because account is not configured"); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	if (!despotify_init()) { | ||||
| 		LogWarning(despotify_domain, "Can't initialize despotify"); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	const bool high_bitrate = | ||||
| 		config_get_bool(ConfigOption::DESPOTIFY_HIGH_BITRATE, true); | ||||
| 	g_session = despotify_init_client(callback, nullptr, | ||||
| 					  high_bitrate, true); | ||||
| 	if (!g_session) { | ||||
| 		LogWarning(despotify_domain, | ||||
| 			   "Can't initialize despotify client"); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	if (!despotify_authenticate(g_session, user, passwd)) { | ||||
| 		LogWarning(despotify_domain, | ||||
| 			   "Can't authenticate despotify session"); | ||||
| 		despotify_exit(g_session); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	return g_session; | ||||
| } | ||||
| @@ -1,76 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2015 The Music Player Daemon Project | ||||
|  * http://www.musicpd.org | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef MPD_DESPOTIFY_UTILS_HXX | ||||
| #define MPD_DESPOTIFY_UTILS_HXX | ||||
|  | ||||
| struct Tag; | ||||
| struct despotify_session; | ||||
| struct ds_track; | ||||
|  | ||||
| extern const class Domain despotify_domain; | ||||
|  | ||||
| /** | ||||
|  * Return the current despotify session. | ||||
|  * | ||||
|  * If the session isn't initialized, this function will initialize | ||||
|  * it and connect to Spotify. | ||||
|  * | ||||
|  * @return a pointer to the despotify session, or nullptr if it can't | ||||
|  *         be initialized (e.g., if the configuration isn't supplied) | ||||
|  */ | ||||
| struct despotify_session * | ||||
| mpd_despotify_get_session(); | ||||
|  | ||||
| /** | ||||
|  * Create a MPD tags structure from a spotify track | ||||
|  * | ||||
|  * @param track the track to convert | ||||
|  * | ||||
|  * @return filled in #Tag structure | ||||
|  */ | ||||
| Tag | ||||
| mpd_despotify_tag_from_track(const ds_track &track); | ||||
|  | ||||
| /** | ||||
|  * Register a despotify callback. | ||||
|  * | ||||
|  * Despotify calls this e.g., when a track ends. | ||||
|  * | ||||
|  * @param cb the callback | ||||
|  * @param cb_data the data to pass to the callback | ||||
|  * | ||||
|  * @return true if the callback could be registered | ||||
|  */ | ||||
| bool | ||||
| mpd_despotify_register_callback(void (*cb)(struct despotify_session *, int, | ||||
| 					   void *, void *), | ||||
| 				void *cb_data); | ||||
|  | ||||
| /** | ||||
|  * Unregister a despotify callback. | ||||
|  * | ||||
|  * @param cb the callback to unregister. | ||||
|  */ | ||||
| void | ||||
| mpd_despotify_unregister_callback(void (*cb)(struct despotify_session *, int, | ||||
| 					     void *, void *)); | ||||
|  | ||||
| #endif | ||||
|  | ||||
| @@ -58,9 +58,6 @@ static const char *const remoteUrlPrefixes[] = { | ||||
| #ifdef ENABLE_CDIO_PARANOIA | ||||
| 	"cdda://", | ||||
| #endif | ||||
| #ifdef ENABLE_DESPOTIFY | ||||
| 	"spt://", | ||||
| #endif | ||||
| #ifdef ENABLE_ALSA | ||||
| 	"alsa://", | ||||
| #endif | ||||
|   | ||||
| @@ -23,7 +23,6 @@ | ||||
| #include "plugins/ExtM3uPlaylistPlugin.hxx" | ||||
| #include "plugins/M3uPlaylistPlugin.hxx" | ||||
| #include "plugins/XspfPlaylistPlugin.hxx" | ||||
| #include "plugins/DespotifyPlaylistPlugin.hxx" | ||||
| #include "plugins/SoundCloudPlaylistPlugin.hxx" | ||||
| #include "plugins/PlsPlaylistPlugin.hxx" | ||||
| #include "plugins/AsxPlaylistPlugin.hxx" | ||||
| @@ -51,9 +50,6 @@ const struct playlist_plugin *const playlist_plugins[] = { | ||||
| 	&asx_playlist_plugin, | ||||
| 	&rss_playlist_plugin, | ||||
| #endif | ||||
| #ifdef ENABLE_DESPOTIFY | ||||
| 	&despotify_playlist_plugin, | ||||
| #endif | ||||
| #ifdef ENABLE_SOUNDCLOUD | ||||
| 	&soundcloud_playlist_plugin, | ||||
| #endif | ||||
|   | ||||
| @@ -1,142 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2015 The Music Player Daemon Project | ||||
|  * http://www.musicpd.org | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  */ | ||||
|  | ||||
| #include "config.h" | ||||
| #include "DespotifyPlaylistPlugin.hxx" | ||||
| #include "lib/despotify/DespotifyUtils.hxx" | ||||
| #include "../PlaylistPlugin.hxx" | ||||
| #include "../MemorySongEnumerator.hxx" | ||||
| #include "tag/Tag.hxx" | ||||
| #include "DetachedSong.hxx" | ||||
| #include "Log.hxx" | ||||
|  | ||||
| extern "C" { | ||||
| #include <despotify.h> | ||||
| } | ||||
|  | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| static void | ||||
| add_song(std::forward_list<DetachedSong> &songs, ds_track &track) | ||||
| { | ||||
| 	const char *dsp_scheme = despotify_playlist_plugin.schemes[0]; | ||||
| 	char uri[128]; | ||||
| 	char *ds_uri; | ||||
|  | ||||
| 	/* Create a spt://... URI for MPD */ | ||||
| 	snprintf(uri, sizeof(uri), "%s://", dsp_scheme); | ||||
| 	ds_uri = uri + strlen(dsp_scheme) + 3; | ||||
|  | ||||
| 	if (despotify_track_to_uri(&track, ds_uri) != ds_uri) { | ||||
| 		/* Should never really fail, but let's be sure */ | ||||
| 		FormatDebug(despotify_domain, | ||||
| 			    "Can't add track %s", track.title); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	songs.emplace_front(uri, mpd_despotify_tag_from_track(track)); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| parse_track(struct despotify_session *session, | ||||
| 	    std::forward_list<DetachedSong> &songs, | ||||
| 	    struct ds_link *link) | ||||
| { | ||||
| 	struct ds_track *track = despotify_link_get_track(session, link); | ||||
| 	if (track == nullptr) | ||||
| 		return false; | ||||
|  | ||||
| 	add_song(songs, *track); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| parse_playlist(struct despotify_session *session, | ||||
| 	       std::forward_list<DetachedSong> &songs, | ||||
| 	       struct ds_link *link) | ||||
| { | ||||
| 	ds_playlist *playlist = despotify_link_get_playlist(session, link); | ||||
| 	if (playlist == nullptr) | ||||
| 		return false; | ||||
|  | ||||
| 	for (ds_track *track = playlist->tracks; track != nullptr; | ||||
| 	     track = track->next) | ||||
| 		add_song(songs, *track); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| static SongEnumerator * | ||||
| despotify_playlist_open_uri(const char *url, | ||||
| 			    gcc_unused Mutex &mutex, gcc_unused Cond &cond) | ||||
| { | ||||
| 	despotify_session *session = mpd_despotify_get_session(); | ||||
| 	if (session == nullptr) | ||||
| 		return nullptr; | ||||
|  | ||||
| 	/* Get link without spt:// */ | ||||
| 	ds_link *link = | ||||
| 		despotify_link_from_uri(url + strlen(despotify_playlist_plugin.schemes[0]) + 3); | ||||
| 	if (link == nullptr) { | ||||
| 		FormatDebug(despotify_domain, "Can't find %s\n", url); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	std::forward_list<DetachedSong> songs; | ||||
|  | ||||
| 	bool parse_result; | ||||
| 	switch (link->type) { | ||||
| 	case LINK_TYPE_TRACK: | ||||
| 		parse_result = parse_track(session, songs, link); | ||||
| 		break; | ||||
| 	case LINK_TYPE_PLAYLIST: | ||||
| 		parse_result = parse_playlist(session, songs, link); | ||||
| 		break; | ||||
| 	default: | ||||
| 		parse_result = false; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	despotify_free_link(link); | ||||
| 	if (!parse_result) | ||||
| 		return nullptr; | ||||
|  | ||||
| 	songs.reverse(); | ||||
| 	return new MemorySongEnumerator(std::move(songs)); | ||||
| } | ||||
|  | ||||
| static const char *const despotify_schemes[] = { | ||||
| 	"spt", | ||||
| 	nullptr | ||||
| }; | ||||
|  | ||||
| const struct playlist_plugin despotify_playlist_plugin = { | ||||
| 	"despotify", | ||||
|  | ||||
| 	nullptr, | ||||
| 	nullptr, | ||||
| 	despotify_playlist_open_uri, | ||||
| 	nullptr, | ||||
|  | ||||
| 	despotify_schemes, | ||||
| 	nullptr, | ||||
| 	nullptr, | ||||
| }; | ||||
| @@ -1,25 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2003-2015 The Music Player Daemon Project | ||||
|  * http://www.musicpd.org | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  */ | ||||
|  | ||||
| #ifndef MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_HXX | ||||
| #define MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_HXX | ||||
|  | ||||
| extern const struct playlist_plugin despotify_playlist_plugin; | ||||
|  | ||||
| #endif | ||||
| @@ -23,7 +23,6 @@ | ||||
| #if defined(HAVE_PTHREAD_SETNAME_NP) && !defined(__NetBSD__) | ||||
| #  define HAVE_THREAD_NAME | ||||
| #  include <pthread.h> | ||||
| #  include <stdio.h> | ||||
| #elif defined(HAVE_PRCTL) | ||||
| #  include <sys/prctl.h> | ||||
| #  ifdef PR_SET_NAME | ||||
| @@ -31,6 +30,10 @@ | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| #ifdef HAVE_THREAD_NAME | ||||
| #  include <stdio.h> | ||||
| #endif | ||||
|  | ||||
| static inline void | ||||
| SetThreadName(const char *name) | ||||
| { | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  */ | ||||
|  | ||||
| #include "config.h" | ||||
| #include "Alloc.hxx" | ||||
|  | ||||
| #include <stdlib.h> | ||||
| @@ -62,14 +63,14 @@ xstrdup(const char *s) | ||||
| char * | ||||
| xstrndup(const char *s, size_t n) | ||||
| { | ||||
| #ifdef WIN32 | ||||
| 	char *p = (char *)xalloc(n + 1); | ||||
| 	memcpy(p, s, n); | ||||
| 	p[n] = 0; | ||||
| #else | ||||
| #ifdef HAVE_STRNDUP | ||||
| 	char *p = strndup(s, n); | ||||
| 	if (gcc_unlikely(p == nullptr)) | ||||
| 		oom(); | ||||
| #else | ||||
| 	char *p = (char *)xalloc(n + 1); | ||||
| 	memcpy(p, s, n); | ||||
| 	p[n] = 0; | ||||
| #endif | ||||
|  | ||||
| 	return p; | ||||
|   | ||||
| @@ -31,6 +31,7 @@ | ||||
| #include <assert.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| const struct filter_plugin * | ||||
| filter_plugin_by_name(gcc_unused const char *name) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann