Compare commits

..

25 Commits

Author SHA1 Message Date
Max Kellermann
5761800197 release v0.19.9 2015-02-06 17:08:25 +01:00
Max Kellermann
0eebacc521 Merge tag 'v0.18.23' into v0.19.x 2015-02-06 17:07:47 +01:00
Max Kellermann
4a5528697d release v0.18.23 2015-02-06 17:04:14 +01:00
Max Kellermann
d38034bb5c fs/io/FileOutputStream: don't auto-delete file on WIN32
The file handle is never reset to INVALID_HANDLE_VALUE, and thus the
destructor will assume the operation shall be cancelled and will
delete the temporary file.

This was a major breakage for saving the database file and the state
file.
2015-02-06 14:36:55 +01:00
Max Kellermann
b3fe3e8b3d TagBuilder: allow adding duplicate tag types in Complement()
Build a table of pre-existing tag types before adding new items.  The
old way would check HasType() each time, which would return true after
the first instance of that tag type had been added, preventing
duplicate tag types to be merged.

This broke duplicate tag types loaded from the state file, because
this code path uses TagBuilder::Complement().
2015-02-06 12:25:34 +01:00
Max Kellermann
5489dec28d NEWS: fix v0.18.22 release date 2015-02-01 12:22:24 +01:00
Max Kellermann
8a6b4db19f Makefile.am: move org_musicpd_Bridge.h to BUILT_SOURCES 2015-01-31 00:05:30 +01:00
Max Kellermann
df43b6a05c Makefile.am: generate icon before compiling JNI classes
Apparently, Android's build.xml requires the icon to be available,
even when only running the Java compiler.
2015-01-31 00:05:30 +01:00
Max Kellermann
3adca3c2fa db/update/Walk: use std::unique_ptr instead of std::auto_ptr
std::auto_ptr is deprecated, and std::unique_ptr is much better
anyway.
2015-01-29 08:37:23 +01:00
PHO
39abd3ecb4 Avoid integer overflow in MonotonicClock{S,MS,US}
This is Darwin specific: the previous implementation was causing an integer
overflow when base.numer is very large. On PPC Darwin, the timebase info is 1000000000/33330116 and this is too large for integer arithmetic.
2015-01-29 08:34:37 +01:00
PHO
a4f4fc50b9 Avoid integer overflow in MonotonicClock{S,MS,US}
This is Darwin specific: the previous implementation was causing an integer
overflow when base.numer is very large. On PPC Darwin, the timebase info is 1000000000/33330116 and this is too large for integer arithmetic.
2015-01-29 08:33:48 +01:00
Max Kellermann
7bf638b0de decoder/DsdLib: use new[] to allocate the ID3 buffer
Don't abort the process if there's not enough memory.  This buffer is
not important and can be large.
2015-01-29 08:24:34 +01:00
Max Kellermann
56662a703c decoder/DsdLib: free ID3 buffer right after id3_tag_parse()
Merge two free() calls.
2015-01-29 08:24:34 +01:00
Max Kellermann
8b5f47d3a3 decoder/DsdLib: raise ID3 tag limit to 1 MB
A bug report was submitted with a 600 kB ID3 tag that could not be
read by MPD.
2015-01-29 08:20:14 +01:00
Max Kellermann
a289dcb9ee Merge branch 'v0.18.x' into v0.19.x 2015-01-26 20:48:19 +01:00
PHO
023b9c1e7e Test the existence of strndup(3) before using it.
This can eliminate the ad-hoc "#ifdef WIN32" and can also support other platforms lacking it as well (including Darwin 9).
2015-01-26 20:39:49 +01:00
Max Kellermann
4c61662644 test/read_mixer: add missing stdlib.h include 2015-01-26 20:39:49 +01:00
Max Kellermann
ad1b6ef0ac {playlist,input}/despotify: remove defunct plugin 2015-01-26 09:55:31 +01:00
Max Kellermann
ed5c6be2f1 util/list: disable gcc5 warning
This file has been removed in newer MPD versions, so don't care about
it now.
2015-01-23 16:50:31 +01:00
Max Kellermann
30cb082932 ClientProcess: cast enum to int before passing to printf()
Fixes gcc5 warning.
2015-01-23 16:50:31 +01:00
Max Kellermann
645554d12f configure.ac: prepare for 0.18.23 2015-01-23 16:47:13 +01:00
Max Kellermann
212b0faf0c android/build.py: use os.path.abspath() to build mpd_path
Fixes a bug that occurs when runing "build.py" from inside the
"android" directory.
2015-01-22 18:51:53 +01:00
Max Kellermann
276a0d9500 thread/Name: include stdio.h if HAVE_PRCTL
Caused a build failure with uClibc because snprintf() was not
available.
2015-01-21 20:40:56 +01:00
Max Kellermann
384b6c8288 doc/protocol: "playlistsearch" is case insensitive 2015-01-16 17:27:19 +01:00
Max Kellermann
a2af158fd3 configure.ac: prepare for 0.19.9 2015-01-16 17:26:50 +01:00
27 changed files with 69 additions and 872 deletions

View File

@@ -116,9 +116,6 @@ For WavPack playback.
libadplug - http://adplug.sourceforge.net/
For AdLib playback.
despotify - https://github.com/SimonKagstrom/despotify
For Spotify playback.
Optional Miscellaneous Dependencies
-----------------------------------

View File

@@ -28,8 +28,6 @@ noinst_LIBRARIES = \
libmixer_plugins.a \
liboutput_plugins.a
libmpd_a_DEPENDENCIES =
libmpd_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(LIBMPDCLIENT_CFLAGS) \
$(AVAHI_CFLAGS) \
@@ -283,13 +281,13 @@ android/build/build.xml: android/AndroidManifest.xml
ln -s $(abs_srcdir)/android/res/values android/build/res
$(ANDROID_SDK)/tools/android update project --path android/build --target android-17
android/build/bin/classes/org/musicpd/Bridge.class: android/src/Bridge.java android/build/build.xml
android/build/bin/classes/org/musicpd/Bridge.class: android/src/Bridge.java android/build/build.xml android/build/res/drawable/icon.png
cd android/build && ant compile-jni-classes
android/build/include/org_musicpd_Bridge.h: android/build/bin/classes/org/musicpd/Bridge.class
javah -classpath $(ANDROID_SDK)/platforms/android-17/android.jar:android/build/bin/classes -d $(@D) org.musicpd.Bridge
libmpd_a_DEPENDENCIES += android/build/include/org_musicpd_Bridge.h
BUILT_SOURCES = android/build/include/org_musicpd_Bridge.h
android/build/libs/armeabi-v7a/libmpd.so: libmpd.so android/build/build.xml
mkdir -p $(@D)
@@ -1125,7 +1123,6 @@ libinput_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(NFS_CFLAGS) \
$(CDIO_PARANOIA_CFLAGS) \
$(FFMPEG_CFLAGS) \
$(DESPOTIFY_CFLAGS) \
$(MMS_CFLAGS)
INPUT_LIBS = \
@@ -1135,7 +1132,6 @@ INPUT_LIBS = \
$(NFS_LIBS) \
$(CDIO_PARANOIA_LIBS) \
$(FFMPEG_LIBS2) \
$(DESPOTIFY_LIBS) \
$(MMS_LIBS)
if HAVE_ALSA
@@ -1181,15 +1177,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) \
@@ -1394,14 +1381,6 @@ PLAYLIST_LIBS = \
$(EXPAT_LIBS) \
$(FLAC_LIBS)
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 \
@@ -1638,12 +1617,6 @@ if HAVE_LIBUPNP
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

19
NEWS
View File

@@ -1,3 +1,15 @@
ver 0.19.9 (2015/02/06)
* decoder
- dsdiff, dsf: raise ID3 tag limit to 1 MB
* playlist: fix loading duplicate tag types from state file
* despotify: remove defunct plugin
* fix clock integer overflow on OS X
* fix gcc 5.0 warnings
* fix build failure with uClibc
* fix build failure on non-POSIX operating systems
* fix dependency issue on parallel Android build
* fix database/state file saving on Windows
ver 0.19.8 (2015/01/14)
* input
- curl: fix bug after rewinding from end-of-file
@@ -171,7 +183,12 @@ ver 0.19 (2014/10/10)
* install systemd unit for socket activation
* Android port
ver 0.18.22 (2014/01/14)
ver 0.18.23 (2015/02/06)
* despotify: remove defunct plugin
* fix clock integer overflow on OS X
* fix gcc 5.0 warnings
ver 0.18.22 (2015/01/14)
* fix clang 3.6 warnings
ver 0.18.21 (2014/12/17)

View File

@@ -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"/>

View File

@@ -23,7 +23,7 @@ if not os.path.isdir(ndk_path):
sys.exit(1)
# 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')

View File

@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.19.8, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.19.9, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=19
VERSION_REVISION=8
VERSION_REVISION=9
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -206,6 +206,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)
@@ -445,11 +446,6 @@ MPD_DEPENDS([enable_jack], [enable_glib],
AC_SYS_LARGEFILE
AC_ARG_ENABLE(despotify,
AS_HELP_STRING([--enable-despotify],
[enable support for despotify (default: disable)]),,
[enable_despotify=no])
AC_ARG_ENABLE(soundcloud,
AS_HELP_STRING([--enable-soundcloud],
[enable support for soundcloud.com]),,
@@ -979,14 +975,6 @@ if test x$enable_nfs = xyes; then
fi
AM_CONDITIONAL(ENABLE_NFS, test x$enable_nfs = xyes)
dnl --------------------------------- Despotify ---------------------------------
MPD_AUTO_PKG(despotify, DESPOTIFY, [despotify],
[Despotify support], [despotify not found])
if test x$enable_despotify = xyes; then
AC_DEFINE(ENABLE_DESPOTIFY, 1, [Define when despotify is enabled])
fi
AM_CONDITIONAL(ENABLE_DESPOTIFY, test x$enable_despotify = xyes)
dnl --------------------------------- Soundcloud ------------------------------
if test x$enable_soundcloud != xno; then
PKG_CHECK_MODULES([YAJL], [yajl >= 2.0],
@@ -1903,7 +1891,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])

View File

@@ -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>

View File

@@ -1141,7 +1141,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>

View File

@@ -315,9 +315,8 @@ systemctl start mpd.socket</programlisting>
</para>
<programlisting>input {
plugin "despotify"
user "foo"
password "bar"
plugin "curl"
proxy "proxy.local"
}
</programlisting>
@@ -1740,66 +1739,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>
@@ -3286,70 +3225,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>

View File

@@ -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())

View File

@@ -334,7 +334,7 @@ UpdateWalk::UpdateDirectory(Directory &directory, const FileInfo &info)
directory_set_stat(directory, info);
Error error;
const std::auto_ptr<StorageDirectoryReader> reader(storage.OpenDirectory(directory.GetPath(), error));
const std::unique_ptr<StorageDirectoryReader> reader(storage.OpenDirectory(directory.GetPath(), error));
if (reader.get() == nullptr) {
LogError(error);
return false;

View File

@@ -125,27 +125,26 @@ dsdlib_tag_id3(InputStream &is,
const id3_length_t count = size - offset;
if (count < 10 || count > 256*1024)
if (count < 10 || count > 1024 * 1024)
return;
id3_byte_t *const id3_buf = static_cast<id3_byte_t*>(xalloc(count));
id3_byte_t *const id3_buf = new id3_byte_t[count];
if (id3_buf == nullptr)
return;
if (!decoder_read_full(nullptr, is, id3_buf, count)) {
free(id3_buf);
delete[] id3_buf;
return;
}
struct id3_tag *id3_tag = id3_tag_parse(id3_buf, count);
if (id3_tag == nullptr) {
free(id3_buf);
delete[] id3_buf;
if (id3_tag == nullptr)
return;
}
scan_id3_tag(id3_tag, handler, handler_ctx);
id3_tag_delete(id3_tag);
free(id3_buf);
return;
}
#endif

View File

@@ -62,6 +62,7 @@ FileOutputStream::Commit(gcc_unused Error &error)
assert(IsDefined());
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
return true;
}
@@ -71,6 +72,7 @@ FileOutputStream::Cancel()
assert(IsDefined());
CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
RemoveFile(path);
}

View File

@@ -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 HAVE_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
};

View File

@@ -1,227 +0,0 @@
/*
* Copyright (C) 2003-2014 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,
};

View File

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2003-2014 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

View File

@@ -1,153 +0,0 @@
/*
* Copyright (C) 2003-2014 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 "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)
{
size_t i;
for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); i++) {
void (*cb)(struct despotify_session *, int, void *, void *) = registered_callbacks[i];
void *cb_data = registered_callback_data[i];
if (cb)
cb(ds, sig, data, cb_data);
}
}
bool mpd_despotify_register_callback(void (*cb)(struct despotify_session *, int, void *, void *),
void *cb_data)
{
size_t i;
for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); 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 *))
{
size_t i;
for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); i++) {
if (registered_callbacks[i] == cb) {
registered_callbacks[i] = nullptr;
}
}
}
Tag
mpd_despotify_tag_from_track(const ds_track &track)
{
char tracknum[20];
char comment[80];
char date[20];
if (!track.has_meta_data)
return Tag();
TagBuilder tag;
snprintf(tracknum, sizeof(tracknum), "%d", track.tracknumber);
snprintf(date, sizeof(date), "%d", track.year);
snprintf(comment, sizeof(comment), "Bitrate %d Kbps, %sgeo restricted",
track.file_bitrate / 1000,
track.geo_restricted ? "" : "not ");
tag.AddItem(TAG_TITLE, track.title);
tag.AddItem(TAG_ARTIST, track.artist->name);
tag.AddItem(TAG_TRACK, tracknum);
tag.AddItem(TAG_ALBUM, track.album);
tag.AddItem(TAG_DATE, date);
tag.AddItem(TAG_COMMENT, comment);
tag.SetDuration(SignedSongTime::FromMS(track.length));
return tag.Commit();
}
struct despotify_session *mpd_despotify_get_session(void)
{
const char *user;
const char *passwd;
bool high_bitrate;
if (g_session)
return g_session;
user = config_get_string(CONF_DESPOTIFY_USER, nullptr);
passwd = config_get_string(CONF_DESPOTIFY_PASSWORD, nullptr);
high_bitrate = config_get_bool(CONF_DESPOTIFY_HIGH_BITRATE, true);
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;
}
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;
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright (C) 2003-2014 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_H
#define MPD_DESPOTIFY_H
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(void);
/**
* 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

View File

@@ -58,9 +58,6 @@ static const char *remoteUrlPrefixes[] = {
#ifdef ENABLE_CDIO_PARANOIA
"cdda://",
#endif
#ifdef ENABLE_DESPOTIFY
"spt://",
#endif
#ifdef HAVE_ALSA
"alsa://",
#endif

View File

@@ -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"
@@ -54,9 +53,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

View File

@@ -1,142 +0,0 @@
/*
* Copyright (C) 2003-2014 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,
};

View File

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2003-2014 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

View File

@@ -40,8 +40,8 @@ MonotonicClockS(void)
if (base.denom == 0)
(void)mach_timebase_info(&base);
return (unsigned)((mach_absolute_time() * base.numer / 1000)
/ (1000000 * base.denom));
return (unsigned)(((double)mach_absolute_time() * base.numer / 1000)
/ base.denom / 1000000);
#elif defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -62,8 +62,8 @@ MonotonicClockMS(void)
if (base.denom == 0)
(void)mach_timebase_info(&base);
return (unsigned)((mach_absolute_time() * base.numer)
/ (1000000 * base.denom));
return (unsigned)(((double)mach_absolute_time() * base.numer)
/ base.denom / 1000000);
#elif defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -104,8 +104,8 @@ MonotonicClockUS(void)
if (base.denom == 0)
(void)mach_timebase_info(&base);
return ((uint64_t)mach_absolute_time() * (uint64_t)base.numer)
/ (1000 * (uint64_t)base.denom);
return (uint64_t)(((double)mach_absolute_time() * base.numer)
/ base.denom / 1000);
#elif defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);

View File

@@ -25,6 +25,8 @@
#include "Tag.hxx"
#include "util/WritableBuffer.hxx"
#include <array>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
@@ -168,12 +170,19 @@ TagBuilder::Complement(const Tag &other)
has_playlist |= other.has_playlist;
/* build a table of tag types that were already present in
this object, which will not be copied from #other */
std::array<bool, TAG_NUM_OF_ITEM_TYPES> present;
present.fill(false);
for (const TagItem *i : items)
present[i->type] = true;
items.reserve(items.size() + other.num_items);
tag_pool_lock.lock();
for (unsigned i = 0, n = other.num_items; i != n; ++i) {
TagItem *item = other.items[i];
if (!HasType(item->type))
if (!present[item->type])
items.push_back(tag_pool_dup_item(item));
}
tag_pool_lock.unlock();

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -35,6 +35,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)