Compare commits

...

80 Commits
0.3.3 ... 0.4.1

Author SHA1 Message Date
Jonas Kvinge
b782a2c8a2 Release 0.4.1 2018-11-01 21:18:57 +01:00
Jonas Kvinge
298783e2c5 Attempt to login if streamurl fails 2018-11-01 21:18:09 +01:00
Jonas Kvinge
bc9ec8025c Move some settings 2018-10-31 19:44:24 +01:00
Jonas Kvinge
26459763e5 Only set QtDebugMsg when build type is debug 2018-10-31 19:41:52 +01:00
Jonas Kvinge
1213306657 Update libcdio 2018-10-31 01:30:15 +01:00
Jonas Kvinge
50add12e4b Update changelog 2018-10-30 23:47:51 +01:00
Jonas Kvinge
67c889f982 Improve Xine engine code 2018-10-30 23:40:41 +01:00
Jonas Kvinge
08cba25071 Improve VLC error handling 2018-10-30 23:40:05 +01:00
Jonas Kvinge
ff35b01bac Improve gst engine error handling 2018-10-30 23:39:08 +01:00
Jonas Kvinge
faee1977fe Add better error handling between engine and player 2018-10-30 23:21:51 +01:00
Jonas Kvinge
6105b99a7f Add option to continue to next song in playlist on error
Also rename some settings. Add option to grey out songs both on playback and
on startup.
2018-10-30 23:20:02 +01:00
Jonas Kvinge
4993201b70 Fix deezer url handler 2018-10-30 23:18:25 +01:00
Jonas Kvinge
f456ca674d Update taglib 2018-10-27 12:15:52 +02:00
Jonas Kvinge
2ba350f76f Attempt to fix crash in setStyleSheet() 2018-10-26 20:05:37 +02:00
Jonas Kvinge
3fe92a62ac Add DSF and DSDIFF to IsFileLossless 2018-10-24 00:58:03 +02:00
Jonas Kvinge
f4dcf6821f Rename class InternetModel to InternetServices 2018-10-23 23:25:02 +02:00
Jonas Kvinge
0c10013858 Ops 2018-10-23 21:14:58 +02:00
Jonas Kvinge
3e9530fa8d Set metadata from deezer engine 2018-10-23 20:21:33 +02:00
Jonas Kvinge
0f4ffe4fce Add PCM as filetype 2018-10-23 20:21:01 +02:00
Jonas Kvinge
e1c01e5d25 Fix device selection 2018-10-23 20:18:07 +02:00
Jonas Kvinge
51021131d7 Allow compile on Qt 5.5.1 or above 2018-10-23 20:17:29 +02:00
Jonas Kvinge
89a08d1d5e Fix RPM build 2018-10-22 23:23:25 +02:00
Jonas Kvinge
ba8717f95a Fix Deezer engine error state 2018-10-22 23:04:34 +02:00
Jonas Kvinge
c8dfb9b0db Fix loading custom device 2018-10-22 22:10:27 +02:00
Jonas Kvinge
3a02ece169 Add EnsureInitialised() 2018-10-22 20:40:02 +02:00
Jonas Kvinge
262df6b461 Merge pull request #24 from eclipseo/use_qt5_deps
Use qt5 libraries of system-wide libraries
2018-10-22 19:00:07 +02:00
Jonas Kvinge
b9516fdfd4 Merge pull request #23 from eclipseo/add_appdata_file
Add AppStream data file
2018-10-22 18:49:28 +02:00
Robert-André Mauchin
9de41bc027 Use qt5 version of system-wide libraries 2018-10-22 17:45:47 +02:00
Robert-André Mauchin
53b5cf3855 Add AppStream data file 2018-10-22 16:44:35 +02:00
Jonas Kvinge
0567358783 Update README.md 2018-10-21 20:49:35 +02:00
Jonas Kvinge
c97bc55c6f Move queuemanager to fancytabbar 2018-10-21 15:13:48 +02:00
Jonas Kvinge
3ef0bf60d0 Correct text for right click configure 2018-10-20 22:33:23 +02:00
Jonas Kvinge
b7b8084a38 Remove setExpanding 2018-10-20 22:18:56 +02:00
Jonas Kvinge
5221f13498 Minor code cleanup and fixes 2018-10-20 22:16:22 +02:00
Jonas Kvinge
0c0a8d70f3 Change darwin to macos 2018-10-20 22:15:32 +02:00
Jonas Kvinge
2ff971878d Enable debug logging on Fedora 2018-10-20 22:13:51 +02:00
Jonas Kvinge
1a0dc1e614 Update README 2018-10-20 22:13:21 +02:00
Jonas Kvinge
4a0bd99654 Enable deezer engine by default 2018-10-20 22:13:02 +02:00
Jonas Kvinge
5cb98e44cb Update README 2018-10-19 20:42:58 +02:00
Jonas Kvinge
13ed99b9c3 Update README and Changelog 2018-10-19 20:37:42 +02:00
Jonas Kvinge
0cda4e27aa Replace qSort/qStableSort/qSwap 2018-10-19 20:18:46 +02:00
Jonas Kvinge
0969e7f504 Remove cachedlist.h 2018-10-19 19:38:30 +02:00
Jonas Kvinge
cad73e18e2 Remove unused code 2018-10-19 19:20:29 +02:00
Jonas Kvinge
9eadeddfd9 Fixup and finish deezer engine 2018-10-19 19:15:33 +02:00
Jonas Kvinge
de11cb173b Use previews as default setting if deezer engine and dzmedia is missing 2018-10-19 19:14:49 +02:00
Jonas Kvinge
5853bc68d1 Replace depreciated macro 2018-10-19 19:13:40 +02:00
Jonas Kvinge
7d1fd9d46f Add missing names 2018-10-19 19:13:24 +02:00
Jonas Kvinge
c977c822d5 Add info about Deezer 2018-10-19 19:13:01 +02:00
Jonas Kvinge
c05fb33ea2 Replace FancyTabWidget with improved version 2018-10-19 19:10:22 +02:00
Jonas Kvinge
b9d0b3e152 Add option to diable Tidal and Deezer 2018-10-17 23:49:02 +02:00
Jonas Kvinge
a9e905b301 Fix bug not loading engine 2018-10-17 22:55:36 +02:00
Jonas Kvinge
a8a714c820 Use common classes for Tidal and Deezer 2018-10-17 21:18:39 +02:00
Jonas Kvinge
9349ad9383 Fix missing icon 2018-10-17 00:46:08 +02:00
Jonas Kvinge
f686f00951 Fix missing icon 2018-10-17 00:43:05 +02:00
Jonas Kvinge
3d13c12cb7 Update taglib 2018-10-16 23:58:26 +02:00
Jonas Kvinge
2384a42d33 Update .gitignore 2018-10-16 21:37:27 +02:00
Jonas Kvinge
f507fec905 Update Changelog 2018-10-16 21:32:03 +02:00
Jonas Kvinge
83a9724d17 Improve Tidal code 2018-10-16 21:31:28 +02:00
Jonas Kvinge
4156e26f76 Fix some minor code bugs in deezer 2018-10-16 21:30:27 +02:00
Jonas Kvinge
6d269e1786 Add libdeezer dll to windows nsi 2018-10-16 21:29:40 +02:00
Jonas Kvinge
ea447cab37 Remove quotes 2018-10-16 21:29:21 +02:00
Jonas Kvinge
4f3e7de441 Exclude debian changelog 2018-10-16 21:29:00 +02:00
Jonas Kvinge
0a81fa99fc Add Deezer support 2018-10-14 00:08:33 +02:00
Jonas Kvinge
4aad44cb62 Create timer for login attempts for Tidal 2018-10-13 00:30:52 +02:00
Jonas Kvinge
69dda39d02 Create timer for login attempts for Tidal 2018-10-13 00:18:38 +02:00
Jonas Kvinge
ca3ba6f136 Increase kTrackSliderUpdateTimeMs 2018-10-02 01:01:31 +02:00
Jonas Kvinge
044cf4624a Add hide() 2018-10-02 00:58:46 +02:00
Jonas Kvinge
1fbfabdf66 Remove whitespaces 2018-10-02 00:46:54 +02:00
Jonas Kvinge
db035351be Remove whitespaces 2018-10-02 00:38:52 +02:00
Jonas Kvinge
2883ef840e Fix track stop on error 2018-10-02 00:21:50 +02:00
Jonas Kvinge
8254ee911d Fix default setting for system tray 2018-10-01 00:31:02 +02:00
Jonas Kvinge
560bc0a150 Fix default setting for system tray 2018-10-01 00:29:06 +02:00
Jonas Kvinge
827898cd38 Fix taglib includes 2018-09-30 22:32:56 +02:00
Jonas Kvinge
184dec146c Move resume playback outside of startup group 2018-09-30 15:55:02 +02:00
Jonas Kvinge
298dbe96c8 Check if system has system tray using QSystemTrayIcon::isSystemTrayAvailable() 2018-09-30 15:33:27 +02:00
Jonas Kvinge
6d888eb51a Analyzer code cleanup and try to fix crash on Fedora 2018-09-30 15:32:21 +02:00
Jonas Kvinge
3694765611 Add error handling for enabling FTS3 2018-09-30 14:54:14 +02:00
Jonas Kvinge
b07ae3d34e Remove reset 2018-09-30 00:08:09 +02:00
Jonas Kvinge
64bcdf4734 Fix spelling 2018-09-30 00:07:59 +02:00
Jonas Kvinge
1c23756fc4 Turn on git revision 2018-09-30 00:07:05 +02:00
227 changed files with 6299 additions and 3721 deletions

1
.gitignore vendored
View File

@@ -38,6 +38,7 @@ Thumbs.db
*.nsi
*.plist
maketarball.sh
dist/debian/changelog
# qtcreator generated files
*.pro.user*

View File

@@ -28,6 +28,7 @@
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include "tagunion.h"
#include "dsdifffile.h"
@@ -97,6 +98,18 @@ public:
bool hasDiin;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool DSDIFF::File::isSupported(IOStream *stream)
{
// A DSDIFF file has to start with "FRM8????????DSD ".
const ByteVector id = Utils::readHeader(stream, 16, false);
return (id.startsWith("FRM8") && id.containsAt("DSD ", 12));
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

View File

@@ -185,6 +185,15 @@ namespace TagLib {
*/
bool hasDIINTag() const;
/*!
* Returns whether or not the given \a stream can be opened as a DSDIFF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
protected:
enum Endianness { BigEndian, LittleEndian };

View File

@@ -1,5 +1,5 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
copyright : (C) 2013 - 2018 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
@@ -28,6 +28,7 @@
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include "dsffile.h"
@@ -56,6 +57,17 @@ public:
ID3v2::Tag *tag;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool DSF::File::isSupported(IOStream *stream)
{
// A DSF file has to start with "DSD "
const ByteVector id = Utils::readHeader(stream, 4, false);
return id.startsWith("DSD ");
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,5 +1,5 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
copyright : (C) 2013 - 2018 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
@@ -103,6 +103,15 @@ namespace TagLib {
*/
virtual bool save();
/*!
* Returns whether or not the given \a stream can be opened as a DSF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);

View File

@@ -180,10 +180,10 @@ namespace
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(APE::File::isSupported(stream))
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
//else if(DSF::File::isSupported(stream))
//return new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
//else if(DSDIFF::File::isSupported(stream))
//return new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(DSDIFF::File::isSupported(stream))
file = new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(DSF::File::isSupported(stream))
file = new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
// isSupported() only does a quick check, so double check the file here.

View File

@@ -216,7 +216,23 @@ void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id)
String TableOfContentsFrame::toString() const
{
return String();
String s = String(d->elementID) +
": top level: " + (d->isTopLevel ? "true" : "false") +
", ordered: " + (d->isOrdered ? "true" : "false");
if(!d->childElements.isEmpty()) {
s+= ", chapters: [ " + String(d->childElements.toByteVector(", ")) + " ]";
}
if(!d->embeddedFrameList.isEmpty()) {
StringList frameIDs;
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
it != d->embeddedFrameList.end(); ++it)
frameIDs.append((*it)->frameID());
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
}
return s;
}
PropertyMap TableOfContentsFrame::asProperties() const

View File

@@ -339,7 +339,13 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const String &descripti
String UserTextIdentificationFrame::toString() const
{
return "[" + description() + "] " + fieldList().toString();
// first entry is the description itself, drop from values list
StringList l = fieldList();
for(StringList::Iterator it = l.begin(); it != l.end(); ++it) {
l.erase(it);
break;
}
return "[" + description() + "] " + l.toString();
}
String UserTextIdentificationFrame::description() const

View File

@@ -231,11 +231,21 @@ void Ogg::FLAC::File::scan()
if(!metadataHeader.startsWith("fLaC")) {
// FLAC 1.1.2+
// See https://xiph.org/flac/ogg_mapping.html for the header specification.
if(metadataHeader.size() < 13)
return;
if(metadataHeader[0] != 0x7f)
return;
if(metadataHeader.mid(1, 4) != "FLAC")
return;
if(metadataHeader[5] != 1)
return; // not version 1
if(metadataHeader[5] != 1 && metadataHeader[6] != 0)
return; // not version 1.0
if(metadataHeader.mid(9, 4) != "fLaC")
return;
metadataHeader = metadataHeader.mid(13);
}

View File

@@ -58,6 +58,11 @@ namespace
#endif
}
FileHandle openFile(const int fileDescriptor, bool readOnly)
{
return InvalidFileHandle;
}
void closeFile(FileHandle file)
{
CloseHandle(file);
@@ -98,6 +103,11 @@ namespace
return fopen(path, readOnly ? "rb" : "rb+");
}
FileHandle openFile(const int fileDescriptor, bool readOnly)
{
return fdopen(fileDescriptor, readOnly ? "rb" : "rb+");
}
void closeFile(FileHandle file)
{
fclose(file);
@@ -149,13 +159,28 @@ FileStream::FileStream(FileName fileName, bool openReadOnly)
d->file = openFile(fileName, true);
if(d->file == InvalidFileHandle)
{
# ifdef _WIN32
debug("Could not open file " + fileName.toString());
# else
debug("Could not open file " + String(static_cast<const char *>(d->name)));
# endif
}
}
FileStream::FileStream(int fileDescriptor, bool openReadOnly)
: d(new FileStreamPrivate(""))
{
// First try with read / write mode, if that fails, fall back to read only.
if(!openReadOnly)
d->file = openFile(fileDescriptor, false);
if(d->file != InvalidFileHandle)
d->readOnly = false;
else
d->file = openFile(fileDescriptor, true);
if(d->file == InvalidFileHandle)
debug("Could not open file using file descriptor");
}
FileStream::~FileStream()
@@ -255,8 +280,7 @@ void FileStream::insert(const ByteVector &data, unsigned long start, unsigned lo
ByteVector buffer = data;
ByteVector aboutToOverwrite(static_cast<unsigned int>(bufferLength));
while(true)
{
while(true) {
// Seek to the current read position and read the data that we're about
// to overwrite. Appropriately increment the readPosition.
@@ -304,8 +328,7 @@ void FileStream::removeBlock(unsigned long start, unsigned long length)
ByteVector buffer(static_cast<unsigned int>(bufferLength));
for(unsigned int bytesRead = -1; bytesRead != 0;)
{
for(unsigned int bytesRead = -1; bytesRead != 0;) {
seek(readPosition);
bytesRead = static_cast<unsigned int>(readFile(d->file, buffer));
readPosition += bytesRead;
@@ -401,7 +424,8 @@ long FileStream::tell() const
const LARGE_INTEGER zero = {};
LARGE_INTEGER position;
if(SetFilePointerEx(d->file, zero, &position, FILE_CURRENT) && position.QuadPart <= LONG_MAX) {
if(SetFilePointerEx(d->file, zero, &position, FILE_CURRENT) &&
position.QuadPart <= LONG_MAX) {
return static_cast<long>(position.QuadPart);
}
else {
@@ -470,9 +494,8 @@ void FileStream::truncate(long length)
#else
const int error = ftruncate(fileno(d->file), length);
if(error != 0) {
if(error != 0)
debug("FileStream::truncate() -- Coundn't truncate the file.");
}
#endif
}

View File

@@ -54,6 +54,11 @@ namespace TagLib {
*/
FileStream(FileName file, bool openReadOnly = false);
/*!
* Construct a File object and opens the \a file using file descriptor.
*/
FileStream(int fileDescriptor, bool openReadOnly = false);
/*!
* Destroys this FileStream instance.
*/

View File

@@ -1,7 +1,5 @@
# Strawberry Music Player
# Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
# This file was part of Clementine.
# Copyright 2010, David Sansome <me@davidsansome.com>
#
# Strawberry is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -37,24 +35,27 @@ include(cmake/Rpm.cmake)
include(cmake/Deb.cmake)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(LINUX 1)
set(LINUX ON)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set(FREEBSD 1)
set(FREEBSD ON)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
set(OPENBSD 1)
set(OPENBSD ON)
endif()
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
#set(CMAKE_BUILD_TYPE Debug)
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
add_definitions(-DNDEBUG)
add_definitions(-DQT_NO_DEBUG_OUTPUT)
#add_definitions(-DQT_NO_WARNING_OUTPUT)
endif(${CMAKE_BUILD_TYPE} MATCHES "Release")
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
set(DEBUG ON)
endif()
if (CMAKE_CXX_COMPILER MATCHES ".*clang")
set(CMAKE_COMPILER_IS_CLANGXX 1)
@@ -111,21 +112,20 @@ pkg_check_modules(PHONON phonon4qt5)
pkg_check_modules(SQLITE REQUIRED sqlite3>=3.7)
pkg_check_modules(LIBPULSE libpulse)
pkg_check_modules(CHROMAPRINT libchromaprint)
#if(CHROMAPRINT_FOUND)
# set(HAVE_CHROMAPRINT ON)
#endif()
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0)
pkg_check_modules(IMOBILEDEVICE libimobiledevice-1.0)
pkg_check_modules(USBMUXD libusbmuxd)
pkg_check_modules(PLIST libplist)
pkg_check_modules(LIBDEEZER libdeezer)
pkg_check_modules(LIBDZMEDIA libdzmedia)
if(WIN32)
find_package(ZLIB REQUIRED)
endif(WIN32)
# QT
set(QT_MIN_VERSION 5.6.0)
set(QT_MIN_VERSION 5.5.1)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Concurrent Widgets Network Sql OpenGL Xml)
if(X11_FOUND)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS X11Extras)
@@ -211,9 +211,9 @@ endif()
option(USE_SYSTEM_QTSINGLEAPPLICATION "Use system QtSingleApplication library" OFF)
if(USE_SYSTEM_QTSINGLEAPPLICATION)
message(STATUS "Using system QtSingleApplication library")
find_path(QTSINGLEAPPLICATION_INCLUDE_DIRS qtsingleapplication.h PATH_SUFFIXES QtSolutions)
find_library(QTSINGLEAPPLICATION_LIBRARIES QtSolutions_SingleApplication-2.6)
find_library(QTSINGLECOREAPPLICATION_LIBRARIES QtSolutions_SingleCoreApplication-2.6)
find_path(QTSINGLEAPPLICATION_INCLUDE_DIRS qtsingleapplication.h PATH_SUFFIXES qt5/QtSolutions)
find_library(QTSINGLEAPPLICATION_LIBRARIES Qt5Solutions_SingleApplication-2.6)
find_library(QTSINGLECOREAPPLICATION_LIBRARIES Qt5Solutions_SingleCoreApplication-2.6)
else(USE_SYSTEM_QTSINGLEAPPLICATION)
message(STATUS "Using builtin QtSingleApplication library")
add_subdirectory(3rdparty/qtsingleapplication)
@@ -225,11 +225,11 @@ endif(USE_SYSTEM_QTSINGLEAPPLICATION)
option(USE_SYSTEM_QXT "Use system Qxt library" OFF)
if (USE_SYSTEM_QXT)
message(STATUS "Using system Qxt library")
find_path(QXTCORE_INCLUDE_DIRS qxtglobal.h PATH_SUFFIXES QxtCore)
find_path(QXTGUI_INCLUDE_DIRS qxtglobalshortcut.h PATH_SUFFIXES QxtGui)
find_path(QXTCORE_INCLUDE_DIRS qxtglobal.h PATH_SUFFIXES qt5/QxtCore)
find_path(QXTGUI_INCLUDE_DIRS qxtglobalshortcut.h PATH_SUFFIXES qt5/QxtWidgets)
set(QXT_INCLUDE_DIRS ${QXTCORE_INCLUDE_DIRS} ${QXTGUI_INCLUDE_DIRS})
# We only need its header. We don't need to link to QxtCore.
find_library(QXT_LIBRARIES QxtGui)
find_library(QXT_LIBRARIES QxtWidgets-qt5)
else (USE_SYSTEM_QXT)
message(STATUS "Using builtin Qxt library")
add_definitions(-DQXT_STATIC -DBUILD_QXT_GUI -DBUILD_QXT_CORE)
@@ -283,10 +283,22 @@ optional_component(VLC ON "Engine: VLC backend"
DEPENDS "libvlc" LIBVLC_FOUND
)
optional_component(PHONON OFF "Engine: Phonon backend"
optional_component(PHONON OFF "Engine: Phonon backend (UNSTABLE)"
DEPENDS "phonon4qt5" PHONON_FOUND
)
if (WIN32)
optional_component(DEEZER ON "Engine: Deezer backend"
DEPENDS "libdeezer" LIBDEEZER_FOUND
)
else ()
optional_component(DEEZER ON "Engine: Deezer backend"
DEPENDS "Linux" LINUX
DEPENDS "libdeezer" LIBDEEZER_FOUND
DEPENDS "libpulse" LIBPULSE_FOUND
)
endif()
optional_component(LIBPULSE ON "Pulse audio integration"
DEPENDS "libpulse" LIBPULSE_FOUND
)
@@ -336,6 +348,18 @@ optional_component(SPARKLE ON "Sparkle integration"
DEPENDS "Sparkle" SPARKLE
)
optional_component(STREAM_TIDAL ON "Streaming: Tidal support")
optional_component(STREAM_DEEZER ON "Streaming: Deezer support")
optional_component(DZMEDIA ON "DZMedia"
DEPENDS "libdzmedia" LIBDZMEDIA_FOUND
DEPENDS "Deezer support" HAVE_STREAM_DEEZER
)
if (HAVE_STREAM_DEEZER AND NOT HAVE_DZMEDIA AND NOT HAVE_DEEZER)
message(STATUS "Deezer is enabled, but not DZMedia or Deezer engine, only preview streams will be available.")
endif()
#if(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
#add_subdirectory(ext/gstafc)
#endif(IMOBILEDEVICE_FOUND AND PLIST_FOUND)
@@ -374,6 +398,8 @@ add_custom_target(uninstall
# Show a summary of what we have enabled
summary_show()
if(NOT HAVE_GSTREAMER AND NOT HAVE_XINE AND NOT HAVE_VLC AND NOT HAVE_PHONON)
message(FATAL_ERROR "You need to enable either GStreamer, Xine, VLC or Phonon to compile!")
if(NOT HAVE_GSTREAMER AND NOT HAVE_XINE AND NOT HAVE_VLC AND NOT HAVE_PHONON AND NOT HAVE_DEEZER)
message(FATAL_ERROR "You need to have either GStreamer, Xine, VLC, Phonon or Deezer to compile!")
elseif(NOT HAVE_GSTREAMER)
message(WARNING "GStreamer is the only engine that is fully implemented. Using other engines is possible but not recommended.")
endif()

View File

@@ -2,6 +2,24 @@ Strawberry Music Player
=======================
ChangeLog
Version 0.4.1:
* Fixed crash in analyzer
* Fixed trying to use systray even if the desktop had no systray
* Fixed Tidal login loop bug
* Added Deezer support
* New improved fancy tabwidget
* Fixed bug not loading engine settings
* Moved queue manager into tabbar for easier access
* Fixed crash when changing appearance colors
* Improved error handling between player and engine
* Added setting to allow continue to the next song in the playlist based on error
* Improved Xine engine code
* Moved some settings
* Updated builtin taglib
* Added AppStream data file
* Fixed compiling with Qt 5 versions of system QtSingleApplication and Qxt library
Version 0.3.3:
* Fixed Tidal login
@@ -9,7 +27,7 @@ Version 0.3.3:
Version 0.3.2:
* Fixed search error not shown in Tidal search
* Added URL handler for Tidal, now retriving URL's when playing instead of when searching
* Added URL handler for Tidal, now retrieving URL's when playing instead of when searching
* Fixed bug in pipeline not setting url
* Fixed bug setting wrong temporary metadata
* Removed device module from windows, since it's not implemented for windows
@@ -65,7 +83,7 @@ Version 0.1.4:
Version 0.1.3:
* Audio file detection by content
* Added builtin taglib to 3rdparty to support detecting audio by content instead of just file extension
* Removed unneeded bulitin qsqlite from 3rdparty
* Removed unneeded qsqlite from 3rdparty
* Added sqldrivers\qsqlite.dll for windows build
* Replaced incorrect DLL libgstdirectsoundsink.dll (from gst 1.12.4) instead of libgstdirectsound.dll (from gst 1.14.0) for windows build
* Fixed git versioning

View File

@@ -25,7 +25,7 @@ It's written in C++ and Qt 5. The name is inspired by the band Strawbs.
* Audio analyzer
* Equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Integrated Tidal support
* Integrated Tidal and Deezer support
It has so far been tested to work on Linux, OpenBSD, MacOs and Windows.
@@ -47,9 +47,13 @@ To build Strawberry from source you need the following installed on your system
* [DBus (linux)](https://www.freedesktop.org/wiki/Software/dbus/)
* [PulseAudio (linux optional)](https://www.freedesktop.org/wiki/Software/PulseAudio/?)
Either GStreamer, Xine or VLC engine is required, but only GStreamer is fully implemented so far.
Either GStreamer, Xine, VLC, Deezer or Phonon engine is required, but only GStreamer is fully implemented so far.
You should also install the gstreamer plugins base and good, and optionally bad and ugly.
Deezer streams with full songs are encrypted and only urls for preview streams (MP3) are exposed by the API.
Full length songs requires the use of deezers own engine (Deezer SDK) or the dzmedia library (I dont have it).
Deezer SDK can be found here: https://build-repo.deezer.com/native_sdk/deezer-native-sdk-v1.2.10.zip
Optional:
* The Qt 5 LastFM library is required for fetching album covers from LastFM.
@@ -72,5 +76,8 @@ Optional:
sudo make install
(dont change to the source directory, if you created the build directory inside the source directory type: cmake .. instead).
### :computer: Screenshot
![Browse](https://www.strawbs.org/pictures/screenshot-002-large.png)

View File

@@ -1,6 +1,7 @@
find_program(LSB_RELEASE_EXEC lsb_release)
find_program(RPMBUILD_EXEC rpmbuild)
if (LSB_RELEASE_EXEC)
if (LSB_RELEASE_EXEC AND RPMBUILD_EXEC)
execute_process(COMMAND /bin/sh "-c" "${LSB_RELEASE_EXEC} -is | tr '[:upper:]' '[:lower:]' | cut -d' ' -f1"
OUTPUT_VARIABLE DIST_NAME
OUTPUT_STRIP_TRAILING_WHITESPACE
@@ -42,8 +43,8 @@ if (LSB_RELEASE_EXEC)
add_custom_target(rpm
COMMAND ${CMAKE_SOURCE_DIR}/dist/scripts/maketarball.sh
COMMAND ${CMAKE_COMMAND} -E copy strawberry-${STRAWBERRY_VERSION_PACKAGE}.tar.xz ${RPMBUILD_DIR}/SOURCES/
COMMAND rpmbuild -bs ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
COMMAND rpmbuild -bb ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
COMMAND ${RPMBUILD_EXEC} -bs ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
COMMAND ${RPMBUILD_EXEC} -bb ${CMAKE_SOURCE_DIR}/dist/opensuse/strawberry.spec
)
elseif (${DIST_NAME} STREQUAL "fedora")
if (DIST_VERSION)

View File

@@ -50,7 +50,7 @@ function(optional_component name default description)
set(current_dep_name)
set(missing_deps)
foreach(arg ${ARGN})
foreach(arg ${ARGN})
if(${next_arg_is_dep_name})
set(current_dep_name "${arg}")
set(next_arg_is_dep_name FALSE)

View File

@@ -1,6 +1,6 @@
set(STRAWBERRY_VERSION_MAJOR 0)
set(STRAWBERRY_VERSION_MINOR 3)
set(STRAWBERRY_VERSION_PATCH 3)
set(STRAWBERRY_VERSION_MINOR 4)
set(STRAWBERRY_VERSION_PATCH 1)
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
set(INCLUDE_GIT_REVISION OFF)

View File

@@ -7,6 +7,7 @@
<file>schema/device-schema.sql</file>
<file>style/strawberry.css</file>
<file>misc/playing_tooltip.txt</file>
<file>misc/oauthsuccess.html</file>
<file>pictures/strawberry.png</file>
<file>pictures/strawbs-transparent.png</file>
<file>pictures/noalbumart.png</file>
@@ -27,442 +28,7 @@
<file>pictures/osd_background.png</file>
<file>pictures/osd_shadow_corner.png</file>
<file>pictures/osd_shadow_edge.png</file>
<file>icons/128x128/albums.png</file>
<file>icons/128x128/alsa.png</file>
<file>icons/128x128/application-exit.png</file>
<file>icons/128x128/applications-internet.png</file>
<file>icons/128x128/bluetooth.png</file>
<file>icons/128x128/cdcase.png</file>
<file>icons/128x128/cd.png</file>
<file>icons/128x128/configure.png</file>
<file>icons/128x128/device-ipod-nano.png</file>
<file>icons/128x128/device-ipod.png</file>
<file>icons/128x128/device-phone.png</file>
<file>icons/128x128/device.png</file>
<file>icons/128x128/device-usb-drive.png</file>
<file>icons/128x128/device-usb-flash.png</file>
<file>icons/128x128/dialog-error.png</file>
<file>icons/128x128/dialog-information.png</file>
<file>icons/128x128/dialog-ok-apply.png</file>
<file>icons/128x128/dialog-password.png</file>
<file>icons/128x128/dialog-warning.png</file>
<file>icons/128x128/document-download.png</file>
<file>icons/128x128/document-new.png</file>
<file>icons/128x128/document-open-folder.png</file>
<file>icons/128x128/document-open.png</file>
<file>icons/128x128/document-save.png</file>
<file>icons/128x128/document-search.png</file>
<file>icons/128x128/download.png</file>
<file>icons/128x128/edit-clear-list.png</file>
<file>icons/128x128/edit-clear-locationbar-ltr.png</file>
<file>icons/128x128/edit-copy.png</file>
<file>icons/128x128/edit-delete.png</file>
<file>icons/128x128/edit-find.png</file>
<file>icons/128x128/edit-redo.png</file>
<file>icons/128x128/edit-rename.png</file>
<file>icons/128x128/edit-undo.png</file>
<file>icons/128x128/electrocompaniet.png</file>
<file>icons/128x128/equalizer.png</file>
<file>icons/128x128/folder-new.png</file>
<file>icons/128x128/folder.png</file>
<file>icons/128x128/folder-sound.png</file>
<file>icons/128x128/footsteps.png</file>
<file>icons/128x128/go-down.png</file>
<file>icons/128x128/go-home.png</file>
<file>icons/128x128/go-jump.png</file>
<file>icons/128x128/go-next.png</file>
<file>icons/128x128/go-previous.png</file>
<file>icons/128x128/go-up.png</file>
<file>icons/128x128/gstreamer.png</file>
<file>icons/128x128/headset.png</file>
<file>icons/128x128/help-hint.png</file>
<file>icons/128x128/intel.png</file>
<file>icons/128x128/jack.png</file>
<file>icons/128x128/keyboard.png</file>
<file>icons/128x128/list-add.png</file>
<file>icons/128x128/list-remove.png</file>
<file>icons/128x128/mcintosh-player.png</file>
<file>icons/128x128/mcintosh-text.png</file>
<file>icons/128x128/media-eject.png</file>
<file>icons/128x128/media-forward.png</file>
<file>icons/128x128/media-pause.png</file>
<file>icons/128x128/media-play.png</file>
<file>icons/128x128/media-rewind.png</file>
<file>icons/128x128/media-stop.png</file>
<file>icons/128x128/nvidia.png</file>
<file>icons/128x128/play2.png</file>
<file>icons/128x128/realtek.png</file>
<file>icons/128x128/search.png</file>
<file>icons/128x128/soundcard.png</file>
<file>icons/128x128/speaker.png</file>
<file>icons/128x128/star-grey.png</file>
<file>icons/128x128/star.png</file>
<file>icons/128x128/strawberry.png</file>
<file>icons/128x128/strawberry.svg</file>
<file>icons/128x128/tools-wizard.png</file>
<file>icons/128x128/view-choose.png</file>
<file>icons/128x128/view-fullscreen.png</file>
<file>icons/128x128/view-media-lyrics.png</file>
<file>icons/128x128/view-media-playlist.png</file>
<file>icons/128x128/view-media-visualization.png</file>
<file>icons/128x128/view-refresh.png</file>
<file>icons/128x128/vinyl.png</file>
<file>icons/128x128/vlc.png</file>
<file>icons/128x128/xine.png</file>
<file>icons/128x128/zoom-in.png</file>
<file>icons/128x128/zoom-out.png</file>
<file>icons/128x128/tidal.png</file>
<file>icons/64x64/albums.png</file>
<file>icons/64x64/alsa.png</file>
<file>icons/64x64/application-exit.png</file>
<file>icons/64x64/applications-internet.png</file>
<file>icons/64x64/bluetooth.png</file>
<file>icons/64x64/cdcase.png</file>
<file>icons/64x64/cd.png</file>
<file>icons/64x64/configure.png</file>
<file>icons/64x64/device-ipod-nano.png</file>
<file>icons/64x64/device-ipod.png</file>
<file>icons/64x64/device-phone.png</file>
<file>icons/64x64/device.png</file>
<file>icons/64x64/device-usb-drive.png</file>
<file>icons/64x64/device-usb-flash.png</file>
<file>icons/64x64/dialog-error.png</file>
<file>icons/64x64/dialog-information.png</file>
<file>icons/64x64/dialog-ok-apply.png</file>
<file>icons/64x64/dialog-password.png</file>
<file>icons/64x64/dialog-warning.png</file>
<file>icons/64x64/document-download.png</file>
<file>icons/64x64/document-new.png</file>
<file>icons/64x64/document-open-folder.png</file>
<file>icons/64x64/document-open.png</file>
<file>icons/64x64/document-save.png</file>
<file>icons/64x64/document-search.png</file>
<file>icons/64x64/download.png</file>
<file>icons/64x64/edit-clear-list.png</file>
<file>icons/64x64/edit-clear-locationbar-ltr.png</file>
<file>icons/64x64/edit-copy.png</file>
<file>icons/64x64/edit-delete.png</file>
<file>icons/64x64/edit-find.png</file>
<file>icons/64x64/edit-redo.png</file>
<file>icons/64x64/edit-rename.png</file>
<file>icons/64x64/edit-undo.png</file>
<file>icons/64x64/electrocompaniet.png</file>
<file>icons/64x64/equalizer.png</file>
<file>icons/64x64/folder-new.png</file>
<file>icons/64x64/folder.png</file>
<file>icons/64x64/folder-sound.png</file>
<file>icons/64x64/footsteps.png</file>
<file>icons/64x64/go-down.png</file>
<file>icons/64x64/go-home.png</file>
<file>icons/64x64/go-jump.png</file>
<file>icons/64x64/go-next.png</file>
<file>icons/64x64/go-previous.png</file>
<file>icons/64x64/go-up.png</file>
<file>icons/64x64/gstreamer.png</file>
<file>icons/64x64/headset.png</file>
<file>icons/64x64/help-hint.png</file>
<file>icons/64x64/intel.png</file>
<file>icons/64x64/jack.png</file>
<file>icons/64x64/keyboard.png</file>
<file>icons/64x64/list-add.png</file>
<file>icons/64x64/list-remove.png</file>
<file>icons/64x64/mcintosh-player.png</file>
<file>icons/64x64/mcintosh-text.png</file>
<file>icons/64x64/media-eject.png</file>
<file>icons/64x64/media-forward.png</file>
<file>icons/64x64/media-pause.png</file>
<file>icons/64x64/media-play.png</file>
<file>icons/64x64/media-rewind.png</file>
<file>icons/64x64/media-stop.png</file>
<file>icons/64x64/nvidia.png</file>
<file>icons/64x64/play2.png</file>
<file>icons/64x64/pulseaudio.png</file>
<file>icons/64x64/realtek.png</file>
<file>icons/64x64/search.png</file>
<file>icons/64x64/soundcard.png</file>
<file>icons/64x64/speaker.png</file>
<file>icons/64x64/star-grey.png</file>
<file>icons/64x64/star.png</file>
<file>icons/64x64/strawberry.png</file>
<file>icons/64x64/tools-wizard.png</file>
<file>icons/64x64/view-choose.png</file>
<file>icons/64x64/view-fullscreen.png</file>
<file>icons/64x64/view-media-lyrics.png</file>
<file>icons/64x64/view-media-playlist.png</file>
<file>icons/64x64/view-media-visualization.png</file>
<file>icons/64x64/view-refresh.png</file>
<file>icons/64x64/vinyl.png</file>
<file>icons/64x64/vlc.png</file>
<file>icons/64x64/xine.png</file>
<file>icons/64x64/zoom-in.png</file>
<file>icons/64x64/zoom-out.png</file>
<file>icons/64x64/tidal.png</file>
<file>icons/48x48/albums.png</file>
<file>icons/48x48/alsa.png</file>
<file>icons/48x48/application-exit.png</file>
<file>icons/48x48/applications-internet.png</file>
<file>icons/48x48/bluetooth.png</file>
<file>icons/48x48/cdcase.png</file>
<file>icons/48x48/cd.png</file>
<file>icons/48x48/configure.png</file>
<file>icons/48x48/device-ipod-nano.png</file>
<file>icons/48x48/device-ipod.png</file>
<file>icons/48x48/device-phone.png</file>
<file>icons/48x48/device.png</file>
<file>icons/48x48/device-usb-drive.png</file>
<file>icons/48x48/device-usb-flash.png</file>
<file>icons/48x48/dialog-error.png</file>
<file>icons/48x48/dialog-information.png</file>
<file>icons/48x48/dialog-ok-apply.png</file>
<file>icons/48x48/dialog-password.png</file>
<file>icons/48x48/dialog-warning.png</file>
<file>icons/48x48/document-download.png</file>
<file>icons/48x48/document-new.png</file>
<file>icons/48x48/document-open-folder.png</file>
<file>icons/48x48/document-open.png</file>
<file>icons/48x48/document-save.png</file>
<file>icons/48x48/document-search.png</file>
<file>icons/48x48/download.png</file>
<file>icons/48x48/edit-clear-list.png</file>
<file>icons/48x48/edit-clear-locationbar-ltr.png</file>
<file>icons/48x48/edit-copy.png</file>
<file>icons/48x48/edit-delete.png</file>
<file>icons/48x48/edit-find.png</file>
<file>icons/48x48/edit-redo.png</file>
<file>icons/48x48/edit-rename.png</file>
<file>icons/48x48/edit-undo.png</file>
<file>icons/48x48/electrocompaniet.png</file>
<file>icons/48x48/equalizer.png</file>
<file>icons/48x48/folder-new.png</file>
<file>icons/48x48/folder.png</file>
<file>icons/48x48/folder-sound.png</file>
<file>icons/48x48/footsteps.png</file>
<file>icons/48x48/go-down.png</file>
<file>icons/48x48/go-home.png</file>
<file>icons/48x48/go-jump.png</file>
<file>icons/48x48/go-next.png</file>
<file>icons/48x48/go-previous.png</file>
<file>icons/48x48/go-up.png</file>
<file>icons/48x48/gstreamer.png</file>
<file>icons/48x48/headset.png</file>
<file>icons/48x48/help-hint.png</file>
<file>icons/48x48/intel.png</file>
<file>icons/48x48/jack.png</file>
<file>icons/48x48/keyboard.png</file>
<file>icons/48x48/list-add.png</file>
<file>icons/48x48/list-remove.png</file>
<file>icons/48x48/mcintosh-player.png</file>
<file>icons/48x48/mcintosh.png</file>
<file>icons/48x48/mcintosh-text.png</file>
<file>icons/48x48/media-eject.png</file>
<file>icons/48x48/media-forward.png</file>
<file>icons/48x48/media-pause.png</file>
<file>icons/48x48/media-playlist-repeat.png</file>
<file>icons/48x48/media-playlist-shuffle.png</file>
<file>icons/48x48/media-play.png</file>
<file>icons/48x48/media-rewind.png</file>
<file>icons/48x48/media-stop.png</file>
<file>icons/48x48/nvidia.png</file>
<file>icons/48x48/play2.png</file>
<file>icons/48x48/pulseaudio.png</file>
<file>icons/48x48/realtek.png</file>
<file>icons/48x48/search.png</file>
<file>icons/48x48/soundcard.png</file>
<file>icons/48x48/speaker.png</file>
<file>icons/48x48/star-grey.png</file>
<file>icons/48x48/star.png</file>
<file>icons/48x48/strawberry.png</file>
<file>icons/48x48/tools-wizard.png</file>
<file>icons/48x48/view-choose.png</file>
<file>icons/48x48/view-fullscreen.png</file>
<file>icons/48x48/view-media-lyrics.png</file>
<file>icons/48x48/view-media-playlist.png</file>
<file>icons/48x48/view-media-visualization.png</file>
<file>icons/48x48/view-refresh.png</file>
<file>icons/48x48/vinyl.png</file>
<file>icons/48x48/vlc.png</file>
<file>icons/48x48/xine.png</file>
<file>icons/48x48/zoom-in.png</file>
<file>icons/48x48/zoom-out.png</file>
<file>icons/48x48/tidal.png</file>
<file>icons/32x32/albums.png</file>
<file>icons/32x32/alsa.png</file>
<file>icons/32x32/application-exit.png</file>
<file>icons/32x32/applications-internet.png</file>
<file>icons/32x32/bluetooth.png</file>
<file>icons/32x32/cdcase.png</file>
<file>icons/32x32/cd.png</file>
<file>icons/32x32/configure.png</file>
<file>icons/32x32/device-ipod-nano.png</file>
<file>icons/32x32/device-ipod.png</file>
<file>icons/32x32/device-phone.png</file>
<file>icons/32x32/device.png</file>
<file>icons/32x32/device-usb-drive.png</file>
<file>icons/32x32/device-usb-flash.png</file>
<file>icons/32x32/dialog-error.png</file>
<file>icons/32x32/dialog-information.png</file>
<file>icons/32x32/dialog-ok-apply.png</file>
<file>icons/32x32/dialog-password.png</file>
<file>icons/32x32/dialog-warning.png</file>
<file>icons/32x32/document-download.png</file>
<file>icons/32x32/document-new.png</file>
<file>icons/32x32/document-open-folder.png</file>
<file>icons/32x32/document-open.png</file>
<file>icons/32x32/document-save.png</file>
<file>icons/32x32/document-search.png</file>
<file>icons/32x32/download.png</file>
<file>icons/32x32/edit-clear-list.png</file>
<file>icons/32x32/edit-clear-locationbar-ltr.png</file>
<file>icons/32x32/edit-copy.png</file>
<file>icons/32x32/edit-delete.png</file>
<file>icons/32x32/edit-find.png</file>
<file>icons/32x32/edit-redo.png</file>
<file>icons/32x32/edit-rename.png</file>
<file>icons/32x32/edit-undo.png</file>
<file>icons/32x32/electrocompaniet.png</file>
<file>icons/32x32/equalizer.png</file>
<file>icons/32x32/folder-new.png</file>
<file>icons/32x32/folder.png</file>
<file>icons/32x32/folder-sound.png</file>
<file>icons/32x32/footsteps.png</file>
<file>icons/32x32/go-down.png</file>
<file>icons/32x32/go-home.png</file>
<file>icons/32x32/go-jump.png</file>
<file>icons/32x32/go-next.png</file>
<file>icons/32x32/go-previous.png</file>
<file>icons/32x32/go-up.png</file>
<file>icons/32x32/gstreamer.png</file>
<file>icons/32x32/headset.png</file>
<file>icons/32x32/help-hint.png</file>
<file>icons/32x32/intel.png</file>
<file>icons/32x32/jack.png</file>
<file>icons/32x32/keyboard.png</file>
<file>icons/32x32/list-add.png</file>
<file>icons/32x32/list-remove.png</file>
<file>icons/32x32/mcintosh-player.png</file>
<file>icons/32x32/mcintosh.png</file>
<file>icons/32x32/mcintosh-text.png</file>
<file>icons/32x32/media-eject.png</file>
<file>icons/32x32/media-forward.png</file>
<file>icons/32x32/media-pause.png</file>
<file>icons/32x32/media-playlist-repeat.png</file>
<file>icons/32x32/media-playlist-shuffle.png</file>
<file>icons/32x32/media-play.png</file>
<file>icons/32x32/media-rewind.png</file>
<file>icons/32x32/media-stop.png</file>
<file>icons/32x32/nvidia.png</file>
<file>icons/32x32/play2.png</file>
<file>icons/32x32/pulseaudio.png</file>
<file>icons/32x32/realtek.png</file>
<file>icons/32x32/search.png</file>
<file>icons/32x32/soundcard.png</file>
<file>icons/32x32/speaker.png</file>
<file>icons/32x32/star-grey.png</file>
<file>icons/32x32/star.png</file>
<file>icons/32x32/strawberry.png</file>
<file>icons/32x32/strawberry.svg</file>
<file>icons/32x32/tools-wizard.png</file>
<file>icons/32x32/view-choose.png</file>
<file>icons/32x32/view-fullscreen.png</file>
<file>icons/32x32/view-media-lyrics.png</file>
<file>icons/32x32/view-media-playlist.png</file>
<file>icons/32x32/view-media-visualization.png</file>
<file>icons/32x32/view-refresh.png</file>
<file>icons/32x32/vinyl.png</file>
<file>icons/32x32/vlc.png</file>
<file>icons/32x32/xine.png</file>
<file>icons/32x32/zoom-in.png</file>
<file>icons/32x32/zoom-out.png</file>
<file>icons/32x32/tidal.png</file>
<file>icons/22x22/albums.png</file>
<file>icons/22x22/alsa.png</file>
<file>icons/22x22/application-exit.png</file>
<file>icons/22x22/applications-internet.png</file>
<file>icons/22x22/bluetooth.png</file>
<file>icons/22x22/cdcase.png</file>
<file>icons/22x22/cd.png</file>
<file>icons/22x22/configure.png</file>
<file>icons/22x22/device-ipod-nano.png</file>
<file>icons/22x22/device-ipod.png</file>
<file>icons/22x22/device-phone.png</file>
<file>icons/22x22/device.png</file>
<file>icons/22x22/device-usb-drive.png</file>
<file>icons/22x22/device-usb-flash.png</file>
<file>icons/22x22/dialog-error.png</file>
<file>icons/22x22/dialog-information.png</file>
<file>icons/22x22/dialog-ok-apply.png</file>
<file>icons/22x22/dialog-password.png</file>
<file>icons/22x22/dialog-warning.png</file>
<file>icons/22x22/document-download.png</file>
<file>icons/22x22/document-new.png</file>
<file>icons/22x22/document-open-folder.png</file>
<file>icons/22x22/document-open.png</file>
<file>icons/22x22/document-save.png</file>
<file>icons/22x22/document-search.png</file>
<file>icons/22x22/download.png</file>
<file>icons/22x22/edit-clear-list.png</file>
<file>icons/22x22/edit-clear-locationbar-ltr.png</file>
<file>icons/22x22/edit-copy.png</file>
<file>icons/22x22/edit-delete.png</file>
<file>icons/22x22/edit-find.png</file>
<file>icons/22x22/edit-redo.png</file>
<file>icons/22x22/edit-rename.png</file>
<file>icons/22x22/edit-undo.png</file>
<file>icons/22x22/electrocompaniet.png</file>
<file>icons/22x22/equalizer.png</file>
<file>icons/22x22/folder-new.png</file>
<file>icons/22x22/folder.png</file>
<file>icons/22x22/folder-sound.png</file>
<file>icons/22x22/footsteps.png</file>
<file>icons/22x22/go-down.png</file>
<file>icons/22x22/go-home.png</file>
<file>icons/22x22/go-jump.png</file>
<file>icons/22x22/go-next.png</file>
<file>icons/22x22/go-previous.png</file>
<file>icons/22x22/go-up.png</file>
<file>icons/22x22/gstreamer.png</file>
<file>icons/22x22/headset.png</file>
<file>icons/22x22/help-hint.png</file>
<file>icons/22x22/intel.png</file>
<file>icons/22x22/jack.png</file>
<file>icons/22x22/keyboard.png</file>
<file>icons/22x22/list-add.png</file>
<file>icons/22x22/list-remove.png</file>
<file>icons/22x22/mcintosh-player.png</file>
<file>icons/22x22/mcintosh.png</file>
<file>icons/22x22/mcintosh-text.png</file>
<file>icons/22x22/media-eject.png</file>
<file>icons/22x22/media-forward.png</file>
<file>icons/22x22/media-pause.png</file>
<file>icons/22x22/media-playlist-repeat.png</file>
<file>icons/22x22/media-playlist-shuffle.png</file>
<file>icons/22x22/media-play.png</file>
<file>icons/22x22/media-rewind.png</file>
<file>icons/22x22/media-stop.png</file>
<file>icons/22x22/nvidia.png</file>
<file>icons/22x22/play2.png</file>
<file>icons/22x22/pulseaudio.png</file>
<file>icons/22x22/realtek.png</file>
<file>icons/22x22/search.png</file>
<file>icons/22x22/soundcard.png</file>
<file>icons/22x22/speaker.png</file>
<file>icons/22x22/star-grey.png</file>
<file>icons/22x22/star.png</file>
<file>icons/22x22/strawberry.png</file>
<file>icons/22x22/strawberry.svg</file>
<file>icons/22x22/tools-wizard.png</file>
<file>icons/22x22/view-choose.png</file>
<file>icons/22x22/view-fullscreen.png</file>
<file>icons/22x22/view-media-lyrics.png</file>
<file>icons/22x22/view-media-playlist.png</file>
<file>icons/22x22/view-media-visualization.png</file>
<file>icons/22x22/view-refresh.png</file>
<file>icons/22x22/vinyl.png</file>
<file>icons/22x22/vlc.png</file>
<file>icons/22x22/xine.png</file>
<file>icons/22x22/zoom-in.png</file>
<file>icons/22x22/zoom-out.png</file>
<file>icons/22x22/tidal.png</file>
<file>pictures/deezer.png</file>
<file>fonts/HumongousofEternitySt.ttf</file>
</qresource>
</RCC>

View File

@@ -1,4 +1,444 @@
<RCC>
<qresource prefix="/">
</qresource>
<qresource prefix="/">
<file>icons/128x128/albums.png</file>
<file>icons/128x128/alsa.png</file>
<file>icons/128x128/application-exit.png</file>
<file>icons/128x128/applications-internet.png</file>
<file>icons/128x128/bluetooth.png</file>
<file>icons/128x128/cdcase.png</file>
<file>icons/128x128/cd.png</file>
<file>icons/128x128/configure.png</file>
<file>icons/128x128/device-ipod-nano.png</file>
<file>icons/128x128/device-ipod.png</file>
<file>icons/128x128/device-phone.png</file>
<file>icons/128x128/device.png</file>
<file>icons/128x128/device-usb-drive.png</file>
<file>icons/128x128/device-usb-flash.png</file>
<file>icons/128x128/dialog-error.png</file>
<file>icons/128x128/dialog-information.png</file>
<file>icons/128x128/dialog-ok-apply.png</file>
<file>icons/128x128/dialog-password.png</file>
<file>icons/128x128/dialog-warning.png</file>
<file>icons/128x128/document-download.png</file>
<file>icons/128x128/document-new.png</file>
<file>icons/128x128/document-open-folder.png</file>
<file>icons/128x128/document-open.png</file>
<file>icons/128x128/document-save.png</file>
<file>icons/128x128/document-search.png</file>
<file>icons/128x128/download.png</file>
<file>icons/128x128/edit-clear-list.png</file>
<file>icons/128x128/edit-clear-locationbar-ltr.png</file>
<file>icons/128x128/edit-copy.png</file>
<file>icons/128x128/edit-delete.png</file>
<file>icons/128x128/edit-find.png</file>
<file>icons/128x128/edit-redo.png</file>
<file>icons/128x128/edit-rename.png</file>
<file>icons/128x128/edit-undo.png</file>
<file>icons/128x128/electrocompaniet.png</file>
<file>icons/128x128/equalizer.png</file>
<file>icons/128x128/folder-new.png</file>
<file>icons/128x128/folder.png</file>
<file>icons/128x128/folder-sound.png</file>
<file>icons/128x128/footsteps.png</file>
<file>icons/128x128/go-down.png</file>
<file>icons/128x128/go-home.png</file>
<file>icons/128x128/go-jump.png</file>
<file>icons/128x128/go-next.png</file>
<file>icons/128x128/go-previous.png</file>
<file>icons/128x128/go-up.png</file>
<file>icons/128x128/gstreamer.png</file>
<file>icons/128x128/headset.png</file>
<file>icons/128x128/help-hint.png</file>
<file>icons/128x128/intel.png</file>
<file>icons/128x128/jack.png</file>
<file>icons/128x128/keyboard.png</file>
<file>icons/128x128/list-add.png</file>
<file>icons/128x128/list-remove.png</file>
<file>icons/128x128/mcintosh-player.png</file>
<file>icons/128x128/mcintosh-text.png</file>
<file>icons/128x128/media-eject.png</file>
<file>icons/128x128/media-forward.png</file>
<file>icons/128x128/media-pause.png</file>
<file>icons/128x128/media-play.png</file>
<file>icons/128x128/media-rewind.png</file>
<file>icons/128x128/media-stop.png</file>
<file>icons/128x128/nvidia.png</file>
<file>icons/128x128/play2.png</file>
<file>icons/128x128/realtek.png</file>
<file>icons/128x128/search.png</file>
<file>icons/128x128/soundcard.png</file>
<file>icons/128x128/speaker.png</file>
<file>icons/128x128/star-grey.png</file>
<file>icons/128x128/star.png</file>
<file>icons/128x128/strawberry.png</file>
<file>icons/128x128/strawberry.svg</file>
<file>icons/128x128/tools-wizard.png</file>
<file>icons/128x128/view-choose.png</file>
<file>icons/128x128/view-fullscreen.png</file>
<file>icons/128x128/view-media-lyrics.png</file>
<file>icons/128x128/view-media-playlist.png</file>
<file>icons/128x128/view-media-visualization.png</file>
<file>icons/128x128/view-refresh.png</file>
<file>icons/128x128/vinyl.png</file>
<file>icons/128x128/vlc.png</file>
<file>icons/128x128/xine.png</file>
<file>icons/128x128/zoom-in.png</file>
<file>icons/128x128/zoom-out.png</file>
<file>icons/128x128/tidal.png</file>
<file>icons/128x128/deezer.png</file>
<file>icons/64x64/albums.png</file>
<file>icons/64x64/alsa.png</file>
<file>icons/64x64/application-exit.png</file>
<file>icons/64x64/applications-internet.png</file>
<file>icons/64x64/bluetooth.png</file>
<file>icons/64x64/cdcase.png</file>
<file>icons/64x64/cd.png</file>
<file>icons/64x64/configure.png</file>
<file>icons/64x64/device-ipod-nano.png</file>
<file>icons/64x64/device-ipod.png</file>
<file>icons/64x64/device-phone.png</file>
<file>icons/64x64/device.png</file>
<file>icons/64x64/device-usb-drive.png</file>
<file>icons/64x64/device-usb-flash.png</file>
<file>icons/64x64/dialog-error.png</file>
<file>icons/64x64/dialog-information.png</file>
<file>icons/64x64/dialog-ok-apply.png</file>
<file>icons/64x64/dialog-password.png</file>
<file>icons/64x64/dialog-warning.png</file>
<file>icons/64x64/document-download.png</file>
<file>icons/64x64/document-new.png</file>
<file>icons/64x64/document-open-folder.png</file>
<file>icons/64x64/document-open.png</file>
<file>icons/64x64/document-save.png</file>
<file>icons/64x64/document-search.png</file>
<file>icons/64x64/download.png</file>
<file>icons/64x64/edit-clear-list.png</file>
<file>icons/64x64/edit-clear-locationbar-ltr.png</file>
<file>icons/64x64/edit-copy.png</file>
<file>icons/64x64/edit-delete.png</file>
<file>icons/64x64/edit-find.png</file>
<file>icons/64x64/edit-redo.png</file>
<file>icons/64x64/edit-rename.png</file>
<file>icons/64x64/edit-undo.png</file>
<file>icons/64x64/electrocompaniet.png</file>
<file>icons/64x64/equalizer.png</file>
<file>icons/64x64/folder-new.png</file>
<file>icons/64x64/folder.png</file>
<file>icons/64x64/folder-sound.png</file>
<file>icons/64x64/footsteps.png</file>
<file>icons/64x64/go-down.png</file>
<file>icons/64x64/go-home.png</file>
<file>icons/64x64/go-jump.png</file>
<file>icons/64x64/go-next.png</file>
<file>icons/64x64/go-previous.png</file>
<file>icons/64x64/go-up.png</file>
<file>icons/64x64/gstreamer.png</file>
<file>icons/64x64/headset.png</file>
<file>icons/64x64/help-hint.png</file>
<file>icons/64x64/intel.png</file>
<file>icons/64x64/jack.png</file>
<file>icons/64x64/keyboard.png</file>
<file>icons/64x64/list-add.png</file>
<file>icons/64x64/list-remove.png</file>
<file>icons/64x64/mcintosh-player.png</file>
<file>icons/64x64/mcintosh-text.png</file>
<file>icons/64x64/media-eject.png</file>
<file>icons/64x64/media-forward.png</file>
<file>icons/64x64/media-pause.png</file>
<file>icons/64x64/media-play.png</file>
<file>icons/64x64/media-rewind.png</file>
<file>icons/64x64/media-stop.png</file>
<file>icons/64x64/nvidia.png</file>
<file>icons/64x64/play2.png</file>
<file>icons/64x64/pulseaudio.png</file>
<file>icons/64x64/realtek.png</file>
<file>icons/64x64/search.png</file>
<file>icons/64x64/soundcard.png</file>
<file>icons/64x64/speaker.png</file>
<file>icons/64x64/star-grey.png</file>
<file>icons/64x64/star.png</file>
<file>icons/64x64/strawberry.png</file>
<file>icons/64x64/tools-wizard.png</file>
<file>icons/64x64/view-choose.png</file>
<file>icons/64x64/view-fullscreen.png</file>
<file>icons/64x64/view-media-lyrics.png</file>
<file>icons/64x64/view-media-playlist.png</file>
<file>icons/64x64/view-media-visualization.png</file>
<file>icons/64x64/view-refresh.png</file>
<file>icons/64x64/vinyl.png</file>
<file>icons/64x64/vlc.png</file>
<file>icons/64x64/xine.png</file>
<file>icons/64x64/zoom-in.png</file>
<file>icons/64x64/zoom-out.png</file>
<file>icons/64x64/tidal.png</file>
<file>icons/64x64/deezer.png</file>
<file>icons/48x48/albums.png</file>
<file>icons/48x48/alsa.png</file>
<file>icons/48x48/application-exit.png</file>
<file>icons/48x48/applications-internet.png</file>
<file>icons/48x48/bluetooth.png</file>
<file>icons/48x48/cdcase.png</file>
<file>icons/48x48/cd.png</file>
<file>icons/48x48/configure.png</file>
<file>icons/48x48/device-ipod-nano.png</file>
<file>icons/48x48/device-ipod.png</file>
<file>icons/48x48/device-phone.png</file>
<file>icons/48x48/device.png</file>
<file>icons/48x48/device-usb-drive.png</file>
<file>icons/48x48/device-usb-flash.png</file>
<file>icons/48x48/dialog-error.png</file>
<file>icons/48x48/dialog-information.png</file>
<file>icons/48x48/dialog-ok-apply.png</file>
<file>icons/48x48/dialog-password.png</file>
<file>icons/48x48/dialog-warning.png</file>
<file>icons/48x48/document-download.png</file>
<file>icons/48x48/document-new.png</file>
<file>icons/48x48/document-open-folder.png</file>
<file>icons/48x48/document-open.png</file>
<file>icons/48x48/document-save.png</file>
<file>icons/48x48/document-search.png</file>
<file>icons/48x48/download.png</file>
<file>icons/48x48/edit-clear-list.png</file>
<file>icons/48x48/edit-clear-locationbar-ltr.png</file>
<file>icons/48x48/edit-copy.png</file>
<file>icons/48x48/edit-delete.png</file>
<file>icons/48x48/edit-find.png</file>
<file>icons/48x48/edit-redo.png</file>
<file>icons/48x48/edit-rename.png</file>
<file>icons/48x48/edit-undo.png</file>
<file>icons/48x48/electrocompaniet.png</file>
<file>icons/48x48/equalizer.png</file>
<file>icons/48x48/folder-new.png</file>
<file>icons/48x48/folder.png</file>
<file>icons/48x48/folder-sound.png</file>
<file>icons/48x48/footsteps.png</file>
<file>icons/48x48/go-down.png</file>
<file>icons/48x48/go-home.png</file>
<file>icons/48x48/go-jump.png</file>
<file>icons/48x48/go-next.png</file>
<file>icons/48x48/go-previous.png</file>
<file>icons/48x48/go-up.png</file>
<file>icons/48x48/gstreamer.png</file>
<file>icons/48x48/headset.png</file>
<file>icons/48x48/help-hint.png</file>
<file>icons/48x48/intel.png</file>
<file>icons/48x48/jack.png</file>
<file>icons/48x48/keyboard.png</file>
<file>icons/48x48/list-add.png</file>
<file>icons/48x48/list-remove.png</file>
<file>icons/48x48/mcintosh-player.png</file>
<file>icons/48x48/mcintosh.png</file>
<file>icons/48x48/mcintosh-text.png</file>
<file>icons/48x48/media-eject.png</file>
<file>icons/48x48/media-forward.png</file>
<file>icons/48x48/media-pause.png</file>
<file>icons/48x48/media-playlist-repeat.png</file>
<file>icons/48x48/media-playlist-shuffle.png</file>
<file>icons/48x48/media-play.png</file>
<file>icons/48x48/media-rewind.png</file>
<file>icons/48x48/media-stop.png</file>
<file>icons/48x48/nvidia.png</file>
<file>icons/48x48/play2.png</file>
<file>icons/48x48/pulseaudio.png</file>
<file>icons/48x48/realtek.png</file>
<file>icons/48x48/search.png</file>
<file>icons/48x48/soundcard.png</file>
<file>icons/48x48/speaker.png</file>
<file>icons/48x48/star-grey.png</file>
<file>icons/48x48/star.png</file>
<file>icons/48x48/strawberry.png</file>
<file>icons/48x48/tools-wizard.png</file>
<file>icons/48x48/view-choose.png</file>
<file>icons/48x48/view-fullscreen.png</file>
<file>icons/48x48/view-media-lyrics.png</file>
<file>icons/48x48/view-media-playlist.png</file>
<file>icons/48x48/view-media-visualization.png</file>
<file>icons/48x48/view-refresh.png</file>
<file>icons/48x48/vinyl.png</file>
<file>icons/48x48/vlc.png</file>
<file>icons/48x48/xine.png</file>
<file>icons/48x48/zoom-in.png</file>
<file>icons/48x48/zoom-out.png</file>
<file>icons/48x48/tidal.png</file>
<file>icons/32x32/albums.png</file>
<file>icons/32x32/alsa.png</file>
<file>icons/32x32/application-exit.png</file>
<file>icons/32x32/applications-internet.png</file>
<file>icons/32x32/bluetooth.png</file>
<file>icons/32x32/cdcase.png</file>
<file>icons/32x32/cd.png</file>
<file>icons/32x32/configure.png</file>
<file>icons/32x32/device-ipod-nano.png</file>
<file>icons/32x32/device-ipod.png</file>
<file>icons/32x32/device-phone.png</file>
<file>icons/32x32/device.png</file>
<file>icons/32x32/device-usb-drive.png</file>
<file>icons/32x32/device-usb-flash.png</file>
<file>icons/32x32/dialog-error.png</file>
<file>icons/32x32/dialog-information.png</file>
<file>icons/32x32/dialog-ok-apply.png</file>
<file>icons/32x32/dialog-password.png</file>
<file>icons/32x32/dialog-warning.png</file>
<file>icons/32x32/document-download.png</file>
<file>icons/32x32/document-new.png</file>
<file>icons/32x32/document-open-folder.png</file>
<file>icons/32x32/document-open.png</file>
<file>icons/32x32/document-save.png</file>
<file>icons/32x32/document-search.png</file>
<file>icons/32x32/download.png</file>
<file>icons/32x32/edit-clear-list.png</file>
<file>icons/32x32/edit-clear-locationbar-ltr.png</file>
<file>icons/32x32/edit-copy.png</file>
<file>icons/32x32/edit-delete.png</file>
<file>icons/32x32/edit-find.png</file>
<file>icons/32x32/edit-redo.png</file>
<file>icons/32x32/edit-rename.png</file>
<file>icons/32x32/edit-undo.png</file>
<file>icons/32x32/electrocompaniet.png</file>
<file>icons/32x32/equalizer.png</file>
<file>icons/32x32/folder-new.png</file>
<file>icons/32x32/folder.png</file>
<file>icons/32x32/folder-sound.png</file>
<file>icons/32x32/footsteps.png</file>
<file>icons/32x32/go-down.png</file>
<file>icons/32x32/go-home.png</file>
<file>icons/32x32/go-jump.png</file>
<file>icons/32x32/go-next.png</file>
<file>icons/32x32/go-previous.png</file>
<file>icons/32x32/go-up.png</file>
<file>icons/32x32/gstreamer.png</file>
<file>icons/32x32/headset.png</file>
<file>icons/32x32/help-hint.png</file>
<file>icons/32x32/intel.png</file>
<file>icons/32x32/jack.png</file>
<file>icons/32x32/keyboard.png</file>
<file>icons/32x32/list-add.png</file>
<file>icons/32x32/list-remove.png</file>
<file>icons/32x32/mcintosh-player.png</file>
<file>icons/32x32/mcintosh.png</file>
<file>icons/32x32/mcintosh-text.png</file>
<file>icons/32x32/media-eject.png</file>
<file>icons/32x32/media-forward.png</file>
<file>icons/32x32/media-pause.png</file>
<file>icons/32x32/media-playlist-repeat.png</file>
<file>icons/32x32/media-playlist-shuffle.png</file>
<file>icons/32x32/media-play.png</file>
<file>icons/32x32/media-rewind.png</file>
<file>icons/32x32/media-stop.png</file>
<file>icons/32x32/nvidia.png</file>
<file>icons/32x32/play2.png</file>
<file>icons/32x32/pulseaudio.png</file>
<file>icons/32x32/realtek.png</file>
<file>icons/32x32/search.png</file>
<file>icons/32x32/soundcard.png</file>
<file>icons/32x32/speaker.png</file>
<file>icons/32x32/star-grey.png</file>
<file>icons/32x32/star.png</file>
<file>icons/32x32/strawberry.png</file>
<file>icons/32x32/strawberry.svg</file>
<file>icons/32x32/tools-wizard.png</file>
<file>icons/32x32/view-choose.png</file>
<file>icons/32x32/view-fullscreen.png</file>
<file>icons/32x32/view-media-lyrics.png</file>
<file>icons/32x32/view-media-playlist.png</file>
<file>icons/32x32/view-media-visualization.png</file>
<file>icons/32x32/view-refresh.png</file>
<file>icons/32x32/vinyl.png</file>
<file>icons/32x32/vlc.png</file>
<file>icons/32x32/xine.png</file>
<file>icons/32x32/zoom-in.png</file>
<file>icons/32x32/zoom-out.png</file>
<file>icons/32x32/tidal.png</file>
<file>icons/32x32/deezer.png</file>
<file>icons/22x22/albums.png</file>
<file>icons/22x22/alsa.png</file>
<file>icons/22x22/application-exit.png</file>
<file>icons/22x22/applications-internet.png</file>
<file>icons/22x22/bluetooth.png</file>
<file>icons/22x22/cdcase.png</file>
<file>icons/22x22/cd.png</file>
<file>icons/22x22/configure.png</file>
<file>icons/22x22/device-ipod-nano.png</file>
<file>icons/22x22/device-ipod.png</file>
<file>icons/22x22/device-phone.png</file>
<file>icons/22x22/device.png</file>
<file>icons/22x22/device-usb-drive.png</file>
<file>icons/22x22/device-usb-flash.png</file>
<file>icons/22x22/dialog-error.png</file>
<file>icons/22x22/dialog-information.png</file>
<file>icons/22x22/dialog-ok-apply.png</file>
<file>icons/22x22/dialog-password.png</file>
<file>icons/22x22/dialog-warning.png</file>
<file>icons/22x22/document-download.png</file>
<file>icons/22x22/document-new.png</file>
<file>icons/22x22/document-open-folder.png</file>
<file>icons/22x22/document-open.png</file>
<file>icons/22x22/document-save.png</file>
<file>icons/22x22/document-search.png</file>
<file>icons/22x22/download.png</file>
<file>icons/22x22/edit-clear-list.png</file>
<file>icons/22x22/edit-clear-locationbar-ltr.png</file>
<file>icons/22x22/edit-copy.png</file>
<file>icons/22x22/edit-delete.png</file>
<file>icons/22x22/edit-find.png</file>
<file>icons/22x22/edit-redo.png</file>
<file>icons/22x22/edit-rename.png</file>
<file>icons/22x22/edit-undo.png</file>
<file>icons/22x22/electrocompaniet.png</file>
<file>icons/22x22/equalizer.png</file>
<file>icons/22x22/folder-new.png</file>
<file>icons/22x22/folder.png</file>
<file>icons/22x22/folder-sound.png</file>
<file>icons/22x22/footsteps.png</file>
<file>icons/22x22/go-down.png</file>
<file>icons/22x22/go-home.png</file>
<file>icons/22x22/go-jump.png</file>
<file>icons/22x22/go-next.png</file>
<file>icons/22x22/go-previous.png</file>
<file>icons/22x22/go-up.png</file>
<file>icons/22x22/gstreamer.png</file>
<file>icons/22x22/headset.png</file>
<file>icons/22x22/help-hint.png</file>
<file>icons/22x22/intel.png</file>
<file>icons/22x22/jack.png</file>
<file>icons/22x22/keyboard.png</file>
<file>icons/22x22/list-add.png</file>
<file>icons/22x22/list-remove.png</file>
<file>icons/22x22/mcintosh-player.png</file>
<file>icons/22x22/mcintosh.png</file>
<file>icons/22x22/mcintosh-text.png</file>
<file>icons/22x22/media-eject.png</file>
<file>icons/22x22/media-forward.png</file>
<file>icons/22x22/media-pause.png</file>
<file>icons/22x22/media-playlist-repeat.png</file>
<file>icons/22x22/media-playlist-shuffle.png</file>
<file>icons/22x22/media-play.png</file>
<file>icons/22x22/media-rewind.png</file>
<file>icons/22x22/media-stop.png</file>
<file>icons/22x22/nvidia.png</file>
<file>icons/22x22/play2.png</file>
<file>icons/22x22/pulseaudio.png</file>
<file>icons/22x22/realtek.png</file>
<file>icons/22x22/search.png</file>
<file>icons/22x22/soundcard.png</file>
<file>icons/22x22/speaker.png</file>
<file>icons/22x22/star-grey.png</file>
<file>icons/22x22/star.png</file>
<file>icons/22x22/strawberry.png</file>
<file>icons/22x22/strawberry.svg</file>
<file>icons/22x22/tools-wizard.png</file>
<file>icons/22x22/view-choose.png</file>
<file>icons/22x22/view-fullscreen.png</file>
<file>icons/22x22/view-media-lyrics.png</file>
<file>icons/22x22/view-media-playlist.png</file>
<file>icons/22x22/view-media-visualization.png</file>
<file>icons/22x22/view-refresh.png</file>
<file>icons/22x22/vinyl.png</file>
<file>icons/22x22/vlc.png</file>
<file>icons/22x22/xine.png</file>
<file>icons/22x22/zoom-in.png</file>
<file>icons/22x22/zoom-out.png</file>
<file>icons/22x22/tidal.png</file>
<file>icons/22x22/deezer.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
data/icons/22x22/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
data/icons/32x32/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
data/icons/48x48/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
data/icons/64x64/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
data/icons/full/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<link href="http://www.strawbs.org/favicon.ico" rel="shortcut icon">
<title>tr("Return to Strawberry")</title>
<style>
#container {
margin: 6em auto 0px auto;
max-width: 400px;
font-family: 'arial regular', arial, sans-serif;
}
#container img {
width: 16px;
height: 16px;
float: left;
margin-right: 0.5em;
}
#container h1 {
margin: 0px 0px 0.75em 0px;
font-size: 16px;
}
#container p {
margin-top: 0px;
margin-left: 10px;
font-size: 13px;
}
</style>
</head>
<body>
<div id="container">
<h1>tr("Success!")</h1>
<img src="data:image/png;base64,@IMAGE_DATA@"/>
<p>tr("Please close your browser and return to Strawberry.")</p>
</div>
</body>
</html>

BIN
data/pictures/deezer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -57,7 +57,7 @@ CREATE TABLE device_%deviceid_songs (
effective_albumartist TEXT,
effective_originalyear INTEGER NOT NULL DEFAULT 0,
cue_path TEXT
);

View File

@@ -1,7 +1,6 @@
#playlist {
background-color: %palette-base;
alternate-background-color: %palette-alternate-base;
}
#playlist[default_background_enabled = "true"] {
@@ -45,11 +44,11 @@ QToolButton:pressed[popupMode="1"] {
padding-right: 16px;
}
darwin {
macos {
font-size: 11pt;
}
darwin QMenu {
macos QMenu {
font-size: 13pt;
}

1
dist/CMakeLists.txt vendored
View File

@@ -19,6 +19,7 @@ if (UNIX AND NOT APPLE)
install(FILES ../data/icons/128x128/strawberry.png DESTINATION share/icons/hicolor/128x128/apps/)
install(FILES ../data/icons/128x128/strawberry.svg DESTINATION share/icons/hicolor/scalable/apps/)
install(FILES unix/strawberry.desktop DESTINATION share/applications)
install(FILES unix/strawberry.appdata.xml DESTINATION share/metainfo)
install(FILES man/strawberry.1 man/strawberry-tagreader.1 DESTINATION share/man/man1)
endif()

2
dist/debian/control vendored
View File

@@ -1,7 +1,7 @@
Source: strawberry
Section: sound
Priority: optional
Maintainer: "Jonas Kvinge" <jonas@jkvinge.net>
Maintainer: Jonas Kvinge <jonas@jkvinge.net>
Build-Depends: debhelper (>= 7),
make,
cmake,

2
dist/debian/rules vendored
View File

@@ -35,7 +35,7 @@ install: build
dh_testroot
dh_prep
dh_installdirs
make install
binary-indep: install

View File

@@ -2,9 +2,8 @@ Name: strawberry
Version: @STRAWBERRY_VERSION_RPM_V@
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
Summary: A audio player and music collection organiser
Group: Applications/Multimedia
License: GPL-3.0+
License: GPLv3+
URL: http://www.strawbs.org/
Source0: %{name}-@STRAWBERRY_VERSION_PACKAGE@.tar.xz
@@ -82,7 +81,6 @@ export CXXFLAGS="%{optflags} -fpermissive"
mkdir %{_target_platform}
pushd %{_target_platform}
%{cmake} \
-DBUILD_WERROR:BOOL=OFF \
-DCMAKE_BUILD_TYPE:STRING=Release \
@@ -93,18 +91,15 @@ popd
%install
make install DESTDIR=%{buildroot} -C %{_target_platform}
rm -rf %{buildroot}%{_datadir}/man
rm -rf %{buildroot}%{_datadir}/metainfo
%check
desktop-file-validate %{buildroot}%{_datadir}/applications/strawberry.desktop
pushd %{_target_platform}
popd
%clean
%files
%defattr(-,root,root,-)
%doc
%doc README.md Changelog
%license COPYING
%{_bindir}/strawberry
%{_bindir}/strawberry-tagreader
%{_datadir}/applications/strawberry.desktop
@@ -112,6 +107,8 @@ popd
%{_datadir}/icons/hicolor/64x64/apps/strawberry.png
%{_datadir}/icons/hicolor/128x128/apps/strawberry.png
%{_datadir}/icons/hicolor/scalable/apps/strawberry.svg
%{_mandir}/man1/strawberry.1.*
%{_mandir}/man1/strawberry-tagreader.1.*
%changelog
* @RPM_DATE@ Jonas Kvinge <jonas@strawbs.net> - @STRAWBERRY_VERSION_RPM_V@

View File

@@ -2,7 +2,6 @@ Name: strawberry
Version: @STRAWBERRY_VERSION_RPM_V@
Release: @STRAWBERRY_VERSION_RPM_R@.@RPM_DISTRO@
Summary: A audio player and music collection organiser
Group: Applications/Multimedia
License: GPL-3.0+
URL: http://www.strawbs.org/
@@ -89,6 +88,7 @@ make %{?_smp_mflags}
%install
cd build
make install DESTDIR=$RPM_BUILD_ROOT
rm -rf %{buildroot}%{_datadir}/metainfo
%clean
cd build
@@ -96,7 +96,8 @@ make clean
%files
%defattr(-,root,root,-)
%doc
%doc README.md Changelog
%license COPYING
%{_bindir}/strawberry
%{_bindir}/strawberry-tagreader
%{_datadir}/applications/strawberry.desktop

View File

@@ -19,7 +19,7 @@ do
echo "ERROR: Cannot dermine geometry for image: \"$i\"."
continue
fi
# Geometry can be 563x144+0+0 or 75x98
# we need to get rid of the plus (+) and the x characters:
w=`echo $g | sed 's/[^0-9]/ /g' | awk '{print $1}'` || exit 1
@@ -32,10 +32,10 @@ do
echo "ERROR: Cannot dermine height for image: \"$x\"."
continue
fi
for x in $sizes
do
dest="$x/$file"
if [ -f $dest ]; then
continue

View File

@@ -26,4 +26,5 @@ tar -cJf $name-$version.tar.xz \
--exclude="*.nsi" \
--exclude="$root/CMakeLists.txt.user" \
--exclude="$root/build" \
--exclude="$root/dist/debian/changelog" \
"$root"

38
dist/unix/strawberry.appdata.xml vendored Normal file
View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<application>
<id type="desktop">strawberry.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0+</project_license>
<name>Strawberry Music Player</name>
<summary>An audio player and music collection organizer</summary>
<description>
<p>
Strawberry is a audio player and music collection organizer.
It is a fork of Clementine. The name is inspired by the band Strawbs.
</p>
<p>Features::</p>
<ul>
<li>Play and organize music</li>
<li>Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg Vorbis, Speex, MPC, TrueAudio, AIFF, MP4, MP3 and ASF</li>
<li>Audio CD playback</li>
<li>Native desktop notifications</li>
<li>Playlists in multiple formats</li>
<li>Advanced output and device options with support for bit perfect playback on Linux</li>
<li>Edit tags on music files</li>
<li>Fetch tags from MusicBrainz</li>
<li>Album cover art from Last.fm, Musicbrainz and Discogs</li>
<li>Song lyrics from AudD and API Seeds</li>
<li>Support for multiple backends</li>
<li>Audio analyzer</li>
<li>Equalizer</li>
<li>Transfer music to iPod, iPhone, MTP or mass-storage USB player</li>
<li>Integrated Tidal support</li>
</ul>
</description>
<screenshots>
<screenshot type="default" width="1920" height="1049">https://www.strawbs.org/pictures/screenshot-002-large.png</screenshot>
<screenshot width="1920" height="1080">https://www.strawbs.org/pictures/screenshot-006-large.png</screenshot>
</screenshots>
<url type="homepage">http://www.strawbs.org/</url>
<updatecontact>eclipseo@fedoraproject.org</updatecontact>
</application>

View File

@@ -9,107 +9,107 @@ _____________________________________________________________________________
These functions register an application with Windows Vista's and Windows 7's
Default Programs window.
Usage:
!include "Capabilities.nsh"
!define CAPABILITIES_NAME "[program name]"
!define CAPABILITIES_DESCRIPTION "[description]"
!define CAPABILITIES_PROGID "[progid]"
!define CAPABILITIES_PATH "[path]"
...
During install, call ${RegisterCapabilities}, then use the other register
macros to create file type, MIME, and protocol associations.
During uninstall, call ${UnRegisterCapabilities}
_______________________________________________________________________________
More information about Default Programs and Client Types can be found here:
http://msdn.microsoft.com/en-us/library/cc144154(VS.85).aspx
http://msdn.microsoft.com/en-us/library/cc144109(v=VS.85).aspx
Defines: All defines not marked [optional] are required.
CAPABILITIES_NAME
The canonical name of the program.
CAPABILITIES_LOCAL_NAME [optional]
The localized name of the program as it appears in Default Programs.
This should be in the format "@FilePath,-StringID" where FilePath is the
path to a .dll or .exe file and StringID is the ID of a resource contained
in the file.
CAPABILITIES_DESCRIPTION
The localized description shown in Default Programs. This can be either a
string or in the same format as CAPABILITIES_LOCAL_NAME
CAPABILITIES_PROGID
An identifier used in file associations. Usually, this is the name of the
program. This should not have any spaces in it.
CAPABILITIES_PATH
The location where capabilities info is stored in the registry.
The "Capabilities" key will automatically be added. If the application is
a client of some sort, (browser, email, media player, etc.) use
"Software\Clients\[ClientType]\[ProgramName]". Otherwise, use
"Software\[CompanyName]\[ProgramName]" or just "Software\[ProgramName]".
CAPABILITIES_ICON [optional]
The icon shown in Default Programs. This should be in the format
"FilePath,IconIndex" where FilePath is the path to a file containing the
icon. If IconIndex is positive, the number is used as the index of the
zero-based array of icons stored in the file. If IconIndex is negative,
the absolute value is used as a resource ID.
CAPABILITIES_REINSTALL [optional]
The command executed when a user uses Set Program Access and Computer
Defaults to select this application as the default for its client type.
This command should launch a program that associates the application with
all the file and protocol types it can handle.
CAPABILITIES_HIDE_ICONS [optional]
The command executed when a user uses Set Program Access and Computer
Defaults to disable access to this application. This command should launch
a program that hides all shortcuts and access points to this application.
It should also prevent the application from being run automatically and
update the IconsVisible registry value to 0.
CAPABILITIES_SHOW_ICONS [optional]
The command executed when a user uses Set Program Access and Computer
Defaults to enable access to this application. This command should launch
a program that restores shortcuts and access points to the application,
allows the program to run, and updates the IconsVisible registry value to 1.
Macros:
${RegisterCapabilities}
Registers the program with Default Programs. Call this once on install
before using any other functions.
${UnRegisterCapabilities}
Un-registers the program and all its associations. Call this once on
uninstall to clean up all installed registry values.
${RegisterFileType} "[extension]" "[executable]" "[icon]" "[description]"
Registers a file type with the program
extension: The file extension to register (ex: .txt)
executable: The executable that opens the file type
icon: The icon shown for the file type
description: Description for the file type shown in Explorer
${RegisterMediaType} "[extension]" "[executable]" "[icon]" "[description]"
Registers a media file type with the program (has a "Play" command)
(arguments are same as RegisterFileType)
${RegisterMimeType} "[mime type]" "[shortname]" "[clsid]"
Registers a mime type with the program
mime type: The MIME type to register (ex: audio/mp3)
shortname: A short identifier for the type (ex: mp3)
clsid: The CLSID of the program to handle files of this type
${RegisterProtocol} "[protocol]" "[executable]" "[icon]" "[description]"
Registers a URL protocol with the program
protocol: The protocol to register (ex: http)
@@ -118,15 +118,15 @@ ${RegisterProtocol} "[protocol]" "[executable]" "[icon]" "[description]"
${UnRegisterFileType} "[extension]"
Un-registers a previously registered file type
extension: The file extension to un-register
${UnRegisterMimeType} "[mime type]"
Un-registers a previously registered MEME type
mime type: The MIME type to un-register
${UnRegisterProtocol} "[protocol]"
Un-registers a previously registered URL protocol
protocol: The URL protocol to un-register
*/
@@ -254,7 +254,7 @@ ${StrCase}
!verbose push
!verbose ${_Capabilities_VERBOSE}
Push $0
!ifndef CAPABILITIES_PATH
!error "CAPABILITIES_PATH not defined"
!endif
@@ -267,21 +267,21 @@ ${StrCase}
!ifndef CAPABILITIES_DESCRIPTION
!error "CAPABILITIES_DESCRIPTION not defined"
!endif
StrCpy $0 "${CAPABILITIES_PATH}\Capabilities"
; add the application to RegisteredApplications
WriteRegStr HKLM "Software\RegisteredApplications" "${CAPABILITIES_NAME}" "$0"
; write application info
WriteRegStr HKLM "${CAPABILITIES_PATH}" "" "${CAPABILITIES_NAME}"
!ifdef CAPABILITIES_LOCAL_NAME
WriteRegStr HKLM "${CAPABILITIES_PATH}" "LocalizedString" "${CAPABILITIES_LOCAL_NAME}"
!endif
!ifdef CAPABILITIES_ICON
WriteRegStr HKLM "${CAPABILITIES_PATH}\DefaultIcon" "" "${CAPABILITIES_ICON}"
!endif
; write installinfo if defined
!ifdef CAPABILITIES_REINSTALL
WriteRegStr HKLM "${CAPABILITIES_PATH}\InstallInfo" "ReinstallCommand" "${CAPABILITIES_REINSTALL}"
@@ -294,7 +294,7 @@ ${StrCase}
WriteRegStr HKLM "${CAPABILITIES_PATH}\InstallInfo" "ShowIconsCommand" "${CAPABILITIES_SHOW_ICONS}"
WriteRegDWORD HKLM "${CAPABILITIES_PATH}\InstallInfo" "IconsVisible" 0x1
!endif
; write application capabilities info
!ifdef CAPABILITIES_LOCAL_NAME
WriteRegStr HKLM "$0" "ApplicationName" "${CAPABILITIES_LOCAL_NAME}"
@@ -302,7 +302,7 @@ ${StrCase}
WriteRegStr HKLM "$0" "ApplicationName" "${CAPABILITIES_NAME}"
!endif
WriteRegStr HKLM "$0" "ApplicationDescription" "${CAPABILITIES_DESCRIPTION}"
Pop $0
!verbose pop
!macroend
@@ -322,7 +322,7 @@ ${StrCase}
!define MacroID ${__LINE__}
!verbose push
!verbose ${_Capabilities_VERBOSE}
Push $0
Push $1
@@ -330,43 +330,43 @@ ${StrCase}
FileTypeLoop_${MacroID}:
EnumRegValue $0 HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" 0
StrCmp $0 "" FileTypeDone_${MacroID}
ReadRegStr $1 HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$0"
DeleteRegKey HKCR $1
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$0"
Goto FileTypeLoop_${MacroID}
FileTypeDone_${MacroID}:
; remove all MIME associations
MimeTypeLoop_${MacroID}:
EnumRegValue $0 HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" 0
StrCmp $0 "" MimeTypeDone_${MacroID}
ReadRegStr $1 HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$0"
DeleteRegKey HKCR "$1"
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$0"
Goto MimeTypeLoop_${MacroID}
MimeTypeDone_${MacroID}:
; remove all protocol associations
ProtocolLoop_${MacroID}:
EnumRegValue $0 HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" 0
StrCmp $0 "" ProtocolDone_${MacroID}
ReadRegStr $1 HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$0"
DeleteRegKey HKCR "$1"
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$0"
Goto ProtocolLoop_${MacroID}
ProtocolDone_${MacroID}:
; remove capabilities keys
DeleteRegValue HKLM "Software\RegisteredApplications" "${CAPABILITIES_NAME}"
DeleteRegKey HKLM ${CAPABILITIES_PATH}
Pop $1
Pop $0
!verbose pop
@@ -390,7 +390,7 @@ ${StrCase}
!macro RegisterFileType_
!verbose push
!verbose ${_Capabilities_VERBOSE}
Exch $R3 ;ext
Exch
Exch $R2 ;exe
@@ -405,10 +405,10 @@ ${StrCase}
; ex: .mp3 becomes ProgID.AssocFile.MP3
${StrCase} $0 "$R3" "U"
StrCpy $0 "${CAPABILITIES_PROGID}.AssocFile$0"
; link capabilities to association in classes root
WriteRegStr HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$R3" "$0"
; write file association in classes root
WriteRegStr HKCR "$0" "" "$R0"
WriteRegStr HKCR "$0\DefaultIcon" "" "$R1"
@@ -441,7 +441,7 @@ ${StrCase}
!macro RegisterMediaType_
!verbose push
!verbose ${_Capabilities_VERBOSE}
Exch $R3 ;ext
Exch
Exch $R2 ;exe
@@ -457,10 +457,10 @@ ${StrCase}
; ex: .mp3 becomes ProgID.AssocFile.MP3
${StrCase} $0 "$R3" "U"
StrCpy $0 "${CAPABILITIES_PROGID}.AssocFile$0"
; link capabilities to association in classes root
WriteRegStr HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$R3" "$0"
; write file association in classes root
WriteRegStr HKCR "$0" "" "$R0"
WriteRegStr HKCR "$0\DefaultIcon" "" "$R1"
@@ -495,24 +495,24 @@ ${StrCase}
!macro RegisterMimeType_
!verbose push
!verbose ${_Capabilities_VERBOSE}
Exch $R2 ;mime
Exch
Exch $R1 ;shortname
Exch
Exch 2
Exch $R0 ;clsid
Push $0
; create an association name
; ex: audio/mp3 becomes ProgID.AssocMIME.MP3
${StrCase} $0 "$R1" "U"
StrCpy $0 "${CAPABILITIES_PROGID}.AssocMIME.$0"
; link capabilities to association in classes root
WriteRegStr HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$R2" "$0"
; write file association in classes root
WriteRegStr HKCR "$0\CLSID" "" "$R0"
@@ -538,7 +538,7 @@ ${StrCase}
!macro RegisterProtocol_
!verbose push
!verbose ${_Capabilities_VERBOSE}
Exch $R3 ;protocol
Exch
Exch $R2 ;exe
@@ -554,10 +554,10 @@ ${StrCase}
; ex: http becomes ProgID.AssocProtocol.HTTP
${StrCase} $0 "$R3" "U"
StrCpy $0 "${CAPABILITIES_PROGID}.AssocProtocol.$0"
; link capabilities to association in classes root
WriteRegStr HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$R3" "$0"
; write file association in classes root
WriteRegStr HKCR "$0" "" "$R0"
WriteRegStr HKCR "$0\DefaultIcon" "" "$R1"
@@ -592,14 +592,14 @@ ${StrCase}
Exch $R0 ;ext
Push $0
ReadRegStr $0 HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$R0"
StrCmp $0 "" skip_${MacroID}
DeleteRegKey HKCR "$0"
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\FileAssociations" "$R0"
skip_${MacroID}:
Pop $0
Pop $R0
!verbose pop
@@ -624,14 +624,14 @@ ${StrCase}
Exch $R0 ;mime
Push $0
ReadRegStr $0 HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$R0"
StrCmp $0 "" skip_${MacroID}
DeleteRegKey HKCR "$0"
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\MimeAssociations" "$R0"
skip_${MacroID}:
Pop $0
Pop $R0
!verbose pop
@@ -656,14 +656,14 @@ ${StrCase}
Exch $R0 ;protocol
Push $0
ReadRegStr $0 HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$R0"
StrCmp $0 "" skip_${MacroID}
DeleteRegKey HKCR "$0"
DeleteRegValue HKLM "${CAPABILITIES_PATH}\Capabilities\UrlAssociations" "$R0"
skip_${MacroID}:
Pop $0
Pop $R0
!verbose pop

View File

@@ -102,7 +102,7 @@ Section "Strawberry" Strawberry
File "strawberry.ico"
File "libbz2.dll"
File "libcdio-16.dll"
File "libcdio-18.dll"
File "libchromaprint.dll"
File "libcrypto-1_1-x64.dll"
File "libfaad-2.dll"
@@ -163,6 +163,7 @@ Section "Strawberry" Strawberry
File "libxml2-2.dll"
File "libsoup-2.4-1.dll"
File "liblzma-5.dll"
File "libdeezer.x64.dll"
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
@@ -263,7 +264,7 @@ Section "Start menu items" startmenu
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
Section "Uninstaller"
@@ -289,7 +290,7 @@ Section "Uninstall"
;StrCmp $1 "-1" wooops
;StrCmp $0 "0" completed
;DetailPrint "Killing running strawberry.exe..."
;StrCpy $0 "strawberry.exe"
@@ -312,7 +313,7 @@ Section "Uninstall"
Delete "$INSTDIR\strawberry-tagreader.exe"
Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-16.dll"
Delete "$INSTDIR\libcdio-18.dll"
Delete "$INSTDIR\libchromaprint.dll"
Delete "$INSTDIR\libcrypto-1_1.dll"
Delete "$INSTDIR\libfaad-2.dll"
@@ -373,6 +374,7 @@ Section "Uninstall"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\libdeezer.x64.dll"
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"

View File

@@ -102,7 +102,7 @@ Section "Strawberry" Strawberry
File "strawberry.ico"
File "libbz2.dll"
File "libcdio-16.dll"
File "libcdio-18.dll"
File "libchromaprint.dll"
File "libcrypto-1_1-x64.dll"
File "libfaad-2.dll"
@@ -164,6 +164,7 @@ Section "Strawberry" Strawberry
File "libxml2-2.dll"
File "libsoup-2.4-1.dll"
File "liblzma-5.dll"
File "libdeezer.x64.dll"
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
@@ -295,7 +296,7 @@ Section "Start menu items" startmenu
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
Section "Uninstaller"
@@ -321,7 +322,7 @@ Section "Uninstall"
;StrCmp $1 "-1" wooops
;StrCmp $0 "0" completed
;DetailPrint "Killing running strawberry.exe..."
;StrCpy $0 "strawberry.exe"
@@ -344,7 +345,7 @@ Section "Uninstall"
Delete "$INSTDIR\strawberry-tagreader.exe"
Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-16.dll"
Delete "$INSTDIR\libcdio-18.dll"
Delete "$INSTDIR\libchromaprint.dll"
Delete "$INSTDIR\libcrypto-1_1.dll"
Delete "$INSTDIR\libfaad-2.dll"
@@ -406,6 +407,7 @@ Section "Uninstall"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\libdeezer.x64.dll"
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"

View File

@@ -102,7 +102,7 @@ Section "Strawberry" Strawberry
File "strawberry.ico"
File "libbz2.dll"
File "libcdio-16.dll"
File "libcdio-18.dll"
File "libchromaprint.dll"
File "libcrypto-1_1.dll"
File "libfaad-2.dll"
@@ -164,6 +164,7 @@ Section "Strawberry" Strawberry
File "libxml2-2.dll"
File "libsoup-2.4-1.dll"
File "liblzma-5.dll"
File "libdeezer.x86.dll"
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
@@ -295,7 +296,7 @@ Section "Start menu items" startmenu
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
Section "Uninstaller"
@@ -321,7 +322,7 @@ Section "Uninstall"
;StrCmp $1 "-1" wooops
;StrCmp $0 "0" completed
;DetailPrint "Killing running strawberry.exe..."
;StrCpy $0 "strawberry.exe"
@@ -344,7 +345,7 @@ Section "Uninstall"
Delete "$INSTDIR\strawberry-tagreader.exe"
Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-16.dll"
Delete "$INSTDIR\libcdio-18.dll"
Delete "$INSTDIR\libchromaprint.dll"
Delete "$INSTDIR\libcrypto-1_1.dll"
Delete "$INSTDIR\libfaad-2.dll"
@@ -406,6 +407,7 @@ Section "Uninstall"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\libdeezer.x86.dll"
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"

View File

@@ -102,7 +102,7 @@ Section "Strawberry" Strawberry
File "strawberry.ico"
File "libbz2.dll"
File "libcdio-16.dll"
File "libcdio-18.dll"
File "libchromaprint.dll"
File "libcrypto-1_1.dll"
File "libfaad-2.dll"
@@ -163,6 +163,7 @@ Section "Strawberry" Strawberry
File "libxml2-2.dll"
File "libsoup-2.4-1.dll"
File "liblzma-5.dll"
File "libdeezer.x86.dll"
; Register Strawberry with Default Programs
Var /GLOBAL AppIcon
@@ -263,7 +264,7 @@ Section "Start menu items" startmenu
CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\strawberry.exe"
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
Section "Uninstaller"
@@ -289,7 +290,7 @@ Section "Uninstall"
;StrCmp $1 "-1" wooops
;StrCmp $0 "0" completed
;DetailPrint "Killing running strawberry.exe..."
;StrCpy $0 "strawberry.exe"
@@ -312,7 +313,7 @@ Section "Uninstall"
Delete "$INSTDIR\strawberry-tagreader.exe"
Delete "$INSTDIR\libbz2.dll"
Delete "$INSTDIR\libcdio-16.dll"
Delete "$INSTDIR\libcdio-18.dll"
Delete "$INSTDIR\libchromaprint.dll"
Delete "$INSTDIR\libcrypto-1_1.dll"
Delete "$INSTDIR\libfaad-2.dll"
@@ -373,6 +374,7 @@ Section "Uninstall"
Delete "$INSTDIR\libxml2-2.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\liblzma-5.dll"
Delete "$INSTDIR\libdeezer.x86.dll"
Delete "$INSTDIR\platforms\qwindows.dll"
Delete "$INSTDIR\sqldrivers\qsqlite.dll"

View File

@@ -64,7 +64,7 @@ void GLog(const char *domain, int level, const char *message, void *user_data) {
case G_LOG_LEVEL_DEBUG:
default: qLog(Debug) << message; break;
}
}
static void MessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message) {
@@ -93,7 +93,7 @@ static void MessageHandler(QtMsgType type, const QMessageLogContext &context, co
}
void Init() {
delete sClassLevels;
delete sNullDevice;

View File

@@ -43,7 +43,7 @@
#include <taglib/tag.h>
#include <taglib/apetag.h>
#include <taglib/id3v2tag.h>
#include "taglib/id3v2frame.h"
#include <taglib/id3v2frame.h>
#include <taglib/flacfile.h>
#include <taglib/oggflacfile.h>
#include <taglib/flacproperties.h>
@@ -54,12 +54,12 @@
#include <taglib/wavpackfile.h>
#include <taglib/aifffile.h>
#include <taglib/asffile.h>
#include "taglib/asftag.h"
#include "taglib/asfattribute.h"
#include "taglib/asfproperties.h"
#include <taglib/asftag.h>
#include <taglib/asfattribute.h>
#include <taglib/asfproperties.h>
#include <taglib/mp4file.h>
#include <taglib/mp4tag.h>
#include "taglib/mp4item.h"
#include <taglib/mp4item.h>
#include <taglib/mp4coverart.h>
#include <taglib/mp4properties.h>
#include <taglib/mpcfile.h>
@@ -269,7 +269,7 @@ void TagReader::ReadFile(const QString &filename, pb::tagreader::SongMetadata *s
else if (TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
song->set_bitdepth(file->audioProperties()->bitsPerSample());
if (file->tag()) {
TagLib::MP4::Tag *mp4_tag = file->tag();
const TagLib::MP4::ItemListMap& items = mp4_tag->itemListMap();
@@ -387,7 +387,7 @@ void TagReader::Decode(const TagLib::String &tag, const QTextCodec *codec, std::
}
void TagReader::Decode(const QString &tag, const QTextCodec *codec, std::string *output) {
if (!codec) {
output->assign(DataCommaSizeFromQString(tag));
}
@@ -399,10 +399,10 @@ void TagReader::Decode(const QString &tag, const QTextCodec *codec, std::string
}
void TagReader::ParseFMPSFrame(const QString &name, const QString &value, pb::tagreader::SongMetadata *song) const {
qLog(Debug) << "Parsing FMPSFrame" << name << ", " << value;
FMPSParser parser;
if (!parser.Parse(value) || parser.is_empty()) return;
QVariant var;
@@ -426,7 +426,7 @@ void TagReader::ParseFMPSFrame(const QString &name, const QString &value, pb::ta
}
void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap &map, const QTextCodec *codec, QString *disc, QString *compilation, pb::tagreader::SongMetadata *song) const {
if (!map["COMPOSER"].isEmpty()) Decode(map["COMPOSER"].front(), codec, song->mutable_composer());
if (!map["PERFORMER"].isEmpty()) Decode(map["PERFORMER"].front(), codec, song->mutable_performer());
if (!map["CONTENT GROUP"].isEmpty()) Decode(map["CONTENT GROUP"].front(), codec, song->mutable_grouping());
@@ -569,16 +569,16 @@ bool TagReader::SaveFile(const QString &filename, const pb::tagreader::SongMetad
}
void TagReader::SetUserTextFrame(const QString &description, const QString &value, TagLib::ID3v2::Tag *tag) const {
const QByteArray descr_utf8(description.toUtf8());
const QByteArray value_utf8(value.toUtf8());
qLog(Debug) << "Setting FMPSFrame:" << description << ", " << value;
SetUserTextFrame(std::string(descr_utf8.constData(), descr_utf8.length()), std::string(value_utf8.constData(), value_utf8.length()), tag);
}
void TagReader::SetUserTextFrame(const std::string &description, const std::string &value, TagLib::ID3v2::Tag *tag) const {
const TagLib::String t_description = StdStringToTaglibString(description);
// Remove the frame if it already exists
TagLib::ID3v2::UserTextIdentificationFrame *frame = TagLib::ID3v2::UserTextIdentificationFrame::find(tag, t_description);
@@ -596,13 +596,13 @@ void TagReader::SetUserTextFrame(const std::string &description, const std::stri
}
void TagReader::SetTextFrame(const char *id, const QString &value, TagLib::ID3v2::Tag *tag) const {
const QByteArray utf8(value.toUtf8());
SetTextFrame(id, std::string(utf8.constData(), utf8.length()), tag);
}
void TagReader::SetTextFrame(const char *id, const std::string &value, TagLib::ID3v2::Tag *tag) const {
TagLib::ByteVector id_vector(id);
QVector<TagLib::ByteVector> frames_buffer;
@@ -627,20 +627,20 @@ void TagReader::SetTextFrame(const char *id, const std::string &value, TagLib::I
// add frame takes ownership and clears the memory
tag->addFrame(frame);
}
}
bool TagReader::IsMediaFile(const QString &filename) const {
qLog(Debug) << "Checking for valid file" << filename;
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
return !fileref->isNull() && fileref->tag();
}
QByteArray TagReader::LoadEmbeddedArt(const QString &filename) const {
if (filename.isEmpty()) return QByteArray();
qLog(Debug) << "Loading art from" << filename;

View File

@@ -21,6 +21,7 @@ message SongMetadata {
TRUEAUDIO = 13;
DSF = 14;
DSDIFF = 15;
PCM = 16;
CDDA = 90;
STREAM = 91;
}

View File

@@ -1,7 +1,5 @@
# Strawberry Music Player
# Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
# This file was part of Clementine.
# Copyright 2010, David Sansome <me@davidsansome.com>
#
# Strawberry is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -59,6 +57,14 @@ if(HAVE_PHONON)
include_directories(${PHONON_INCLUDE_DIRS})
endif()
if(HAVE_LIBDEEZER)
include_directories(${DEEZER_INCLUDE_DIRS})
endif()
if(HAVE_LIBDZMEDIA)
include_directories(${DZMEDIA_INCLUDE_DIRS})
endif()
link_directories(${TAGLIB_LIBRARY_DIRS})
include_directories(${TAGLIB_INCLUDE_DIRS})
@@ -109,17 +115,17 @@ set(SOURCES
core/windows7thumbbar.cpp
core/screensaver.cpp
core/scopedtransaction.cpp
engine/enginetype.cpp
engine/enginebase.cpp
engine/enginedevice.cpp
engine/devicefinder.cpp
analyzer/fht.cpp
analyzer/analyzerbase.cpp
analyzer/analyzercontainer.cpp
analyzer/blockanalyzer.cpp
equalizer/equalizer.cpp
equalizer/equalizerslider.cpp
@@ -158,11 +164,12 @@ set(SOURCES
playlist/playlisttabbar.cpp
playlist/playlistundocommands.cpp
playlist/playlistview.cpp
playlist/queue.cpp
playlist/queuemanager.cpp
playlist/songloaderinserter.cpp
playlist/songplaylistitem.cpp
queue/queue.cpp
queue/queueview.cpp
playlistparsers/asxiniparser.cpp
playlistparsers/asxparser.cpp
playlistparsers/cueparser.cpp
@@ -173,7 +180,7 @@ set(SOURCES
playlistparsers/wplparser.cpp
playlistparsers/xmlparser.cpp
playlistparsers/xspfparser.cpp
covermanager/albumcovermanager.cpp
covermanager/albumcovermanagerlist.cpp
covermanager/albumcoverloader.cpp
@@ -211,7 +218,6 @@ set(SOURCES
settings/shortcutssettingspage.cpp
settings/appearancesettingspage.cpp
settings/notificationssettingspage.cpp
settings/tidalsettingspage.cpp
dialogs/about.cpp
dialogs/console.cpp
@@ -244,27 +250,25 @@ set(SOURCES
widgets/tracksliderpopup.cpp
widgets/tracksliderslider.cpp
widgets/loginstatewidget.cpp
musicbrainz/acoustidclient.cpp
musicbrainz/musicbrainzclient.cpp
globalshortcuts/globalshortcutbackend.cpp
globalshortcuts/globalshortcuts.cpp
globalshortcuts/gnomeglobalshortcutbackend.cpp
globalshortcuts/qxtglobalshortcutbackend.cpp
globalshortcuts/globalshortcutgrabber.cpp
internet/internetmodel.cpp
internet/internetservices.cpp
internet/internetservice.cpp
internet/internetplaylistitem.cpp
tidal/tidalservice.cpp
tidal/tidalsearch.cpp
tidal/tidalsearchview.cpp
tidal/tidalsearchmodel.cpp
tidal/tidalsearchsortmodel.cpp
tidal/tidalsearchitemdelegate.cpp
tidal/tidalurlhandler.cpp
internet/internetsearch.cpp
internet/internetsearchview.cpp
internet/internetsearchmodel.cpp
internet/internetsearchsortmodel.cpp
internet/internetsearchitemdelegate.cpp
internet/localredirectserver.cpp
)
@@ -294,10 +298,10 @@ set(HEADERS
analyzer/analyzerbase.h
analyzer/analyzercontainer.h
analyzer/blockanalyzer.h
equalizer/equalizer.h
equalizer/equalizerslider.h
context/contextview.h
context/contextalbumsmodel.h
context/contextalbumsview.h
@@ -328,11 +332,12 @@ set(HEADERS
playlist/playlisttabbar.h
playlist/playlistview.h
playlist/playlistitemmimedata.h
playlist/queue.h
playlist/queuemanager.h
playlist/songloaderinserter.h
playlist/songmimedata.h
queue/queue.h
queue/queueview.h
playlistparsers/asxiniparser.h
playlistparsers/asxparser.h
playlistparsers/cueparser.h
@@ -341,7 +346,7 @@ set(HEADERS
playlistparsers/playlistparser.h
playlistparsers/plsparser.h
playlistparsers/xspfparser.h
covermanager/albumcovermanager.h
covermanager/albumcovermanagerlist.h
covermanager/albumcoverloader.h
@@ -378,7 +383,6 @@ set(HEADERS
settings/shortcutssettingspage.h
settings/appearancesettingspage.h
settings/notificationssettingspage.h
settings/tidalsettingspage.h
dialogs/about.h
dialogs/errordialog.h
@@ -409,25 +413,22 @@ set(HEADERS
widgets/tracksliderpopup.h
widgets/tracksliderslider.h
widgets/loginstatewidget.h
musicbrainz/acoustidclient.h
musicbrainz/musicbrainzclient.h
globalshortcuts/globalshortcutbackend.h
globalshortcuts/globalshortcuts.h
globalshortcuts/gnomeglobalshortcutbackend.h
globalshortcuts/globalshortcutgrabber.h
internet/internetmodel.h
internet/internetservices.h
internet/internetservice.h
internet/internetmimedata.h
internet/internetsongmimedata.h
tidal/tidalservice.h
tidal/tidalsearch.h
tidal/tidalsearchview.h
tidal/tidalsearchmodel.h
tidal/tidalurlhandler.h
internet/internetsearch.h
internet/internetsearchview.h
internet/internetsearchmodel.h
internet/localredirectserver.h
)
@@ -446,7 +447,8 @@ set(UI
playlist/playlistlistcontainer.ui
playlist/playlistsaveoptionsdialog.ui
playlist/playlistsequence.ui
playlist/queuemanager.ui
queue/queueview.ui
covermanager/albumcoverexport.ui
covermanager/albumcovermanager.ui
@@ -464,7 +466,6 @@ set(UI
settings/shortcutssettingspage.ui
settings/appearancesettingspage.ui
settings/notificationssettingspage.ui
settings/tidalsettingspage.ui
equalizer/equalizer.ui
equalizer/equalizerslider.ui
@@ -479,14 +480,14 @@ set(UI
widgets/osdpretty.ui
widgets/fileview.ui
widgets/loginstatewidget.ui
globalshortcuts/globalshortcutgrabber.ui
tidal/tidalsearchview.ui
internet/internetsearchview.ui
)
set(RESOURCES ../data/data.qrc)
set(RESOURCES ../data/data.qrc ../data/icons.qrc)
set(OTHER_SOURCES)
option(USE_INSTALL_PREFIX "Look for data in CMAKE_INSTALL_PREFIX" ON)
@@ -524,6 +525,12 @@ optional_source(HAVE_PHONON
HEADERS engine/phononengine.h
)
# Deezer
optional_source(HAVE_DEEZER
SOURCES engine/deezerengine.cpp
HEADERS engine/deezerengine.h
)
# Lastfm
optional_source(HAVE_LIBLASTFM
SOURCES
@@ -848,6 +855,32 @@ optional_source(WIN32
widgets/osd_win.cpp
)
optional_source(HAVE_STREAM_TIDAL
SOURCES
tidal/tidalservice.cpp
tidal/tidalurlhandler.cpp
settings/tidalsettingspage.cpp
HEADERS
tidal/tidalservice.h
tidal/tidalurlhandler.h
settings/tidalsettingspage.h
UI
settings/tidalsettingspage.ui
)
optional_source(HAVE_STREAM_DEEZER
SOURCES
deezer/deezerservice.cpp
deezer/deezerurlhandler.cpp
settings/deezersettingspage.cpp
HEADERS
deezer/deezerservice.h
deezer/deezerurlhandler.h
settings/deezersettingspage.h
UI
settings/deezersettingspage.ui
)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h)
@@ -880,6 +913,7 @@ target_link_libraries(strawberry_lib
${QT_LIBRARIES}
${CHROMAPRINT_LIBRARIES}
${QTSINGLEAPPLICATION_LIBRARIES}
${QTSINGLECOREAPPLICATION_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${SQLITE_LIBRARIES}
${QOCOA_LIBRARIES}
@@ -906,6 +940,14 @@ if(HAVE_PHONON)
target_link_libraries(strawberry_lib ${PHONON_LIBRARIES})
endif()
if(HAVE_DEEZER)
target_link_libraries(strawberry_lib ${LIBDEEZER_LIBRARIES})
endif()
if(HAVE_DZMEDIA)
target_link_libraries(strawberry_lib ${LIBDZMEDIA_LIBRARIES})
endif()
if(HAVE_LIBLASTFM)
target_link_libraries(strawberry_lib ${LASTFM5_LIBRARIES})
endif(HAVE_LIBLASTFM)

View File

@@ -27,14 +27,13 @@
#include "analyzerbase.h"
#include "core/logging.h"
#include "engine/enginebase.h"
// INSTRUCTIONS Base2D
// 1. do anything that depends on height() in init(), Base2D will call it before
// you are shown
// 1. do anything that depends on height() in init(), Base2D will call it before you are shown
// 2. otherwise you can use the constructor to initialise things
// 3. reimplement analyze(), and paint to canvas(), Base2D will update the
// widget when you return control to it
// 3. reimplement analyze(), and paint to canvas(), Base2D will update the widget when you return control to it
// 4. if you want to manipulate the scope, reimplement transform()
// 5. for convenience <vector> <qpixmap.h> <qwdiget.h> are pre-included
// TODO make an INSTRUCTIONS file
@@ -50,37 +49,32 @@ template class Analyzer::Base<QWidget>;
Analyzer::Base::Base(QWidget *parent, uint scopeSize)
: QWidget(parent),
m_timeout(40) // msec
,
m_fht(new FHT(scopeSize)),
m_engine(nullptr),
m_lastScope(512),
timeout_(40),
fht_(new FHT(scopeSize)),
engine_(nullptr),
lastscope_(512),
current_chunk_(0),
new_frame_(false),
is_playing_(false) {}
void Analyzer::Base::hideEvent(QHideEvent*) { m_timer.stop(); }
void Analyzer::Base::hideEvent(QHideEvent*) { timer_.stop(); }
void Analyzer::Base::showEvent(QShowEvent*) { m_timer.start(timeout(), this); }
void Analyzer::Base::showEvent(QShowEvent*) { timer_.start(timeout(), this); }
void Analyzer::Base::transform(Scope& scope) // virtual
{
void Analyzer::Base::transform(Scope& scope) {
// this is a standard transformation that should give
// an FFT scope that has bands for pretty analyzers
// This is a standard transformation that should give an FFT scope that has bands for pretty analyzers
// NOTE resizing here is redundant as FHT routines only calculate FHT::size()
// values
// scope.resize( m_fht->size() );
// NOTE: Resizing here is redundant as FHT routines only calculate FHT::size() values scope.resize( fht_->size() );
float *front = static_cast<float*>(&scope.front());
float *f = new float[m_fht->size()];
m_fht->copy(&f[0], front);
m_fht->logSpectrum(front, &f[0]);
m_fht->scale(front, 1.0 / 20);
float *f = new float[fht_->size()];
fht_->copy(&f[0], front);
fht_->logSpectrum(front, &f[0]);
fht_->scale(front, 1.0 / 20);
scope.resize(m_fht->size() / 2); // second half of values are rubbish
scope.resize(fht_->size() / 2); // second half of values are rubbish
delete[] f;
}
@@ -90,28 +84,28 @@ void Analyzer::Base::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.fillRect(e->rect(), palette().color(QPalette::Window));
switch (m_engine->state()) {
switch (engine_->state()) {
case Engine::Playing: {
const Engine::Scope& thescope = m_engine->scope(m_timeout);
const Engine::Scope& thescope = engine_->scope(timeout_);
int i = 0;
// convert to mono here - our built in analyzers need mono, but the engines provide interleaved pcm
for (uint x = 0; (int)x < m_fht->size(); ++x) {
m_lastScope[x] = double(thescope[i] + thescope[i + 1]) / (2 * (1 << 15));
for (uint x = 0; (int)x < fht_->size(); ++x) {
lastscope_[x] = double(thescope[i] + thescope[i + 1]) / (2 * (1 << 15));
i += 2;
}
is_playing_ = true;
transform(m_lastScope);
analyze(p, m_lastScope, new_frame_);
transform(lastscope_);
analyze(p, lastscope_, new_frame_);
// scope.resize( m_fht->size() );
lastscope_.resize(fht_->size());
break;
}
case Engine::Paused:
is_playing_ = false;
analyze(p, m_lastScope, new_frame_);
analyze(p, lastscope_, new_frame_);
break;
default:
@@ -124,16 +118,18 @@ void Analyzer::Base::paintEvent(QPaintEvent *e) {
}
int Analyzer::Base::resizeExponent(int exp) {
if (exp < 3)
exp = 3;
else if (exp > 9)
exp = 9;
if (exp != m_fht->sizeExp()) {
delete m_fht;
m_fht = new FHT(exp);
if (exp != fht_->sizeExp()) {
delete fht_;
fht_ = new FHT(exp);
}
return exp;
}
int Analyzer::Base::resizeForBands(int bands) {
@@ -153,12 +149,11 @@ int Analyzer::Base::resizeForBands(int bands) {
exp = 9;
resizeExponent(exp);
return m_fht->size() / 2;
return fht_->size() / 2;
}
void Analyzer::Base::demo(QPainter& p) // virtual
{
void Analyzer::Base::demo(QPainter& p) {
static int t = 201; // FIXME make static to namespace perhaps
@@ -171,7 +166,8 @@ void Analyzer::Base::demo(QPainter& p) // virtual
s[i] = dt * (sin(M_PI + (i * M_PI) / s.size()) + 1.0);
analyze(p, s, new_frame_);
} else
}
else
analyze(p, Scope(32, 0), new_frame_);
++t;
@@ -179,7 +175,7 @@ void Analyzer::Base::demo(QPainter& p) // virtual
}
void Analyzer::Base::polishEvent() {
init(); // virtual
init();
}
void Analyzer::interpolate(const Scope& inVec, Scope& outVec) {
@@ -189,13 +185,13 @@ void Analyzer::interpolate(const Scope& inVec, Scope& outVec) {
for (uint i = 0; i < outVec.size(); ++i, pos += step) {
const double error = pos - std::floor(pos);
const unsigned long offset = (unsigned long)pos;
const uint64_t offset = (uint64_t)pos;
unsigned long indexLeft = offset + 0;
uint64_t indexLeft = offset + 0;
if (indexLeft >= inVec.size()) indexLeft = inVec.size() - 1;
unsigned long indexRight = offset + 1;
uint64_t indexRight = offset + 1;
if (indexRight >= inVec.size()) indexRight = inVec.size() - 1;
@@ -205,6 +201,7 @@ void Analyzer::interpolate(const Scope& inVec, Scope& outVec) {
}
void Analyzer::initSin(Scope& v, const uint size) {
double step = (M_PI * 2) / size;
double radian = 0;
@@ -212,12 +209,15 @@ void Analyzer::initSin(Scope& v, const uint size) {
v.push_back(sin(radian));
radian += step;
}
}
void Analyzer::Base::timerEvent(QTimerEvent *e) {
QWidget::timerEvent(e);
if (e->timerId() != m_timer.timerId()) return;
if (e->timerId() != timer_.timerId()) return;
new_frame_ = true;
update();
}

View File

@@ -37,17 +37,17 @@ class Base : public QWidget {
Q_OBJECT
public:
~Base() { delete m_fht; }
~Base() { delete fht_; }
uint timeout() const { return m_timeout; }
uint timeout() const { return timeout_; }
void set_engine(EngineBase *engine) { m_engine = engine; }
void set_engine(EngineBase *engine) { engine_ = engine; }
void changeTimeout(uint newTimeout) {
m_timeout = newTimeout;
if (m_timer.isActive()) {
m_timer.stop();
m_timer.start(m_timeout, this);
timeout_ = newTimeout;
if (timer_.isActive()) {
timer_.stop();
timer_.start(timeout_, this);
}
}
@@ -71,13 +71,12 @@ class Base : public QWidget {
virtual void demo(QPainter& p);
protected:
QBasicTimer m_timer;
uint m_timeout;
FHT* m_fht;
EngineBase* m_engine;
Scope m_lastScope;
QBasicTimer timer_;
uint timeout_;
FHT *fht_;
EngineBase *engine_;
Scope lastscope_;
int current_chunk_;
bool new_frame_;
bool is_playing_;
};

View File

@@ -26,109 +26,105 @@ const uint BlockAnalyzer::MIN_COLUMNS = 32; // arbituary
const uint BlockAnalyzer::MAX_COLUMNS = 256; // must be 2**n
const uint BlockAnalyzer::FADE_SIZE = 90;
const char *BlockAnalyzer::kName =
QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
const char *BlockAnalyzer::kName = QT_TRANSLATE_NOOP("AnalyzerContainer", "Block analyzer");
BlockAnalyzer::BlockAnalyzer(QWidget *parent)
: Analyzer::Base(parent, 9),
m_columns(0) // uint
,
m_rows(0) // uint
,
m_y(0) // uint
,
m_barPixmap(1, 1) // null qpixmaps cause crashes
,
m_topBarPixmap(WIDTH, HEIGHT),
m_scope(MIN_COLUMNS) // Scope
,
m_store(1 << 8, 0) // vector<uint>
,
m_fade_bars(FADE_SIZE) // vector<QPixmap>
,
m_fade_pos(1 << 8, 50) // vector<uint>
,
m_fade_intensity(1 << 8, 32) // vector<uint>
{
columns_(0),
rows_(0),
y_(0),
barpixmap_(1, 1),
topbarpixmap_(WIDTH, HEIGHT),
scope_(MIN_COLUMNS),
store_(1 << 8, 0),
fade_bars_(FADE_SIZE),
fade_pos_(1 << 8, 50),
fade_intensity_(1 << 8, 32) {
setMinimumSize(MIN_COLUMNS * (WIDTH + 1) - 1, MIN_ROWS * (HEIGHT + 1) - 1); //-1 is padding, no drawing takes place there
setMaximumWidth(MAX_COLUMNS * (WIDTH + 1) - 1);
// mxcl says null pixmaps cause crashes, so let's play it safe
for (uint i = 0; i < FADE_SIZE; ++i) m_fade_bars[i] = QPixmap(1, 1);
for (uint i = 0; i < FADE_SIZE; ++i) fade_bars_[i] = QPixmap(1, 1);
}
BlockAnalyzer::~BlockAnalyzer() {}
void BlockAnalyzer::resizeEvent(QResizeEvent *e) {
QWidget::resizeEvent(e);
m_background = QPixmap(size());
background_ = QPixmap(size());
canvas_ = QPixmap(size());
const uint oldRows = m_rows;
const uint oldRows = rows_;
// all is explained in analyze()..
//+1 to counter -1 in maxSizes, trust me we need this!
m_columns = qMax(uint(double(width() + 1) / (WIDTH + 1)), MAX_COLUMNS);
m_rows = uint(double(height() + 1) / (HEIGHT + 1));
columns_ = qMax(uint(double(width() + 1) / (WIDTH + 1)), MAX_COLUMNS);
rows_ = uint(double(height() + 1) / (HEIGHT + 1));
// this is the y-offset for drawing from the top of the widget
m_y = (height() - (m_rows * (HEIGHT + 1)) + 2) / 2;
y_ = (height() - (rows_ * (HEIGHT + 1)) + 2) / 2;
m_scope.resize(m_columns);
scope_.resize(columns_);
if (m_rows != oldRows) {
m_barPixmap = QPixmap(WIDTH, m_rows * (HEIGHT + 1));
if (rows_ != oldRows) {
barpixmap_ = QPixmap(WIDTH, rows_ * (HEIGHT + 1));
for (uint i = 0; i < FADE_SIZE; ++i)
m_fade_bars[i] = QPixmap(WIDTH, m_rows * (HEIGHT + 1));
fade_bars_[i] = QPixmap(WIDTH, rows_ * (HEIGHT + 1));
m_yscale.resize(m_rows + 1);
yscale_.resize(rows_ + 1);
const uint PRE = 1,
PRO = 1; // PRE and PRO allow us to restrict the range somewhat
const uint PRE = 1, PRO = 1; // PRE and PRO allow us to restrict the range somewhat
for (uint z = 0; z < m_rows; ++z)
m_yscale[z] = 1 - (log10(PRE + z) / log10(PRE + m_rows + PRO));
for (uint z = 0; z < rows_; ++z)
yscale_[z] = 1 - (log10(PRE + z) / log10(PRE + rows_ + PRO));
m_yscale[m_rows] = 0;
yscale_[rows_] = 0;
determineStep();
paletteChange(palette());
}
drawBackground();
}
void BlockAnalyzer::determineStep() {
// falltime is dependent on rowcount due to our digital resolution (ie we have boxes/blocks of pixels)
// I calculated the value 30 based on some trial and error
// the fall time of 30 is too slow on framerates above 50fps
const double fallTime = timeout() < 20 ? 20 * m_rows : 30 * m_rows;
const double fallTime = timeout() < 20 ? 20 * rows_ : 30 * rows_;
step_ = double(rows_ * timeout()) / fallTime;
m_step = double(m_rows * timeout()) / fallTime;
}
void BlockAnalyzer::framerateChanged() { // virtual
void BlockAnalyzer::framerateChanged() {
determineStep();
}
void BlockAnalyzer::transform(Analyzer::Scope& s) // pure virtual
{
void BlockAnalyzer::transform(Analyzer::Scope &s) {
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
float* front = static_cast<float*>(&s.front());
m_fht->spectrum(front);
m_fht->scale(front, 1.0 / 20);
fht_->spectrum(front);
fht_->scale(front, 1.0 / 20);
// the second half is pretty dull, so only show it if the user has a large analyzer by setting to scope_.size() if large we prevent interpolation of large analyzers, this is good!
s.resize(scope_.size() <= MAX_COLUMNS / 2 ? MAX_COLUMNS / 2 : scope_.size());
// the second half is pretty dull, so only show it if the user has a large analyzer by setting to m_scope.size() if large we prevent interpolation of large analyzers, this is good!
s.resize(m_scope.size() <= MAX_COLUMNS / 2 ? MAX_COLUMNS / 2 : m_scope.size());
}
void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
bool new_frame) {
void BlockAnalyzer::analyze(QPainter &p, const Analyzer::Scope &s, bool new_frame) {
// y = 2 3 2 1 0 2
// . . . . # .
// . . . # # .
@@ -139,7 +135,7 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
// y represents the number of blanks
// y starts from the top and increases in units of blocks
// m_yscale looks similar to: { 0.7, 0.5, 0.25, 0.15, 0.1, 0 }
// yscale_ looks similar to: { 0.7, 0.5, 0.25, 0.15, 0.1, 0 }
// if it contains 6 elements there are 5 rows in the analyzer
if (!new_frame) {
@@ -149,50 +145,51 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
QPainter canvas_painter(&canvas_);
Analyzer::interpolate(s, m_scope);
Analyzer::interpolate(s, scope_);
// Paint the background
canvas_painter.drawPixmap(0, 0, m_background);
canvas_painter.drawPixmap(0, 0, background_);
for (uint y, x = 0; x < m_scope.size(); ++x) {
for (uint y, x = 0; x < scope_.size(); ++x) {
// determine y
for (y = 0; m_scope[x] < m_yscale[y]; ++y)
;
for (y = 0; scope_[x] < yscale_[y]; ++y) continue;
// this is opposite to what you'd think, higher than y means the bar is lower than y (physically)
if ((float)y > m_store[x])
y = int(m_store[x] += m_step);
if ((float)y > store_[x])
y = int(store_[x] += step_);
else
m_store[x] = y;
store_[x] = y;
// if y is lower than m_fade_pos, then the bar has exceeded the height of the fadeout
// if y is lower than fade_pos_, then the bar has exceeded the height of the fadeout
// if the fadeout is quite faded now, then display the new one
if (y <= m_fade_pos[x] /*|| m_fade_intensity[x] < FADE_SIZE / 3*/) {
m_fade_pos[x] = y;
m_fade_intensity[x] = FADE_SIZE;
if (y <= fade_pos_[x] /*|| fade_intensity_[x] < FADE_SIZE / 3*/) {
fade_pos_[x] = y;
fade_intensity_[x] = FADE_SIZE;
}
if (m_fade_intensity[x] > 0) {
const uint offset = --m_fade_intensity[x];
const uint y = m_y + (m_fade_pos[x] * (HEIGHT + 1));
canvas_painter.drawPixmap(x * (WIDTH + 1), y, m_fade_bars[offset], 0, 0, WIDTH, height() - y);
if (fade_intensity_[x] > 0) {
const uint offset = --fade_intensity_[x];
const uint y = y_ + (fade_pos_[x] * (HEIGHT + 1));
canvas_painter.drawPixmap(x * (WIDTH + 1), y, fade_bars_[offset], 0, 0, WIDTH, height() - y);
}
if (m_fade_intensity[x] == 0) m_fade_pos[x] = m_rows;
if (fade_intensity_[x] == 0) fade_pos_[x] = rows_;
// REMEMBER: y is a number from 0 to m_rows, 0 means all blocks are glowing, m_rows means none are
canvas_painter.drawPixmap(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, *bar(),
// REMEMBER: y is a number from 0 to rows_, 0 means all blocks are glowing, rows_ means none are
canvas_painter.drawPixmap(x * (WIDTH + 1), y * (HEIGHT + 1) + y_, *bar(),
0, y * (HEIGHT + 1), bar()->width(),
bar()->height());
}
for (uint x = 0; x < m_store.size(); ++x)
canvas_painter.drawPixmap(x * (WIDTH + 1), int(m_store[x]) * (HEIGHT + 1) + m_y, m_topBarPixmap);
for (uint x = 0; x < store_.size(); ++x)
canvas_painter.drawPixmap(x * (WIDTH + 1), int(store_[x]) * (HEIGHT + 1) + y_, topbarpixmap_);
p.drawPixmap(0, 0, canvas_);
}
static inline void adjustToLimits(int& b, int& f, uint& amount) {
static inline void adjustToLimits(int &b, int &f, uint &amount) {
// with a range of 0-255 and maximum adjustment of amount, maximise the difference between f and b
if (b < f) {
@@ -215,6 +212,7 @@ static inline void adjustToLimits(int& b, int& f, uint& amount) {
f = 255;
}
}
}
/**
@@ -225,17 +223,18 @@ static inline void adjustToLimits(int& b, int& f, uint& amount) {
* It won't modify the hue of fg unless absolutely necessary
* @return the adjusted form of fg
*/
QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) {
QColor ensureContrast(const QColor &bg, const QColor &fg, uint _amount = 150) {
class OutputOnExit {
public:
OutputOnExit(const QColor& color) : c(color) {}
OutputOnExit(const QColor &color) : c(color) {}
~OutputOnExit() {
int h, s, v;
c.getHsv(&h, &s, &v);
}
private:
const QColor& c;
const QColor &c;
};
// hack so I don't have to cast everywhere
@@ -352,24 +351,25 @@ QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) {
#undef amount
// #undef STAMP
}
void BlockAnalyzer::paletteChange(const QPalette&) // virtual
{
void BlockAnalyzer::paletteChange(const QPalette&) {
const QColor bg = palette().color(QPalette::Background);
const QColor fg = ensureContrast(bg, palette().color(QPalette::Highlight));
m_topBarPixmap.fill(fg);
topbarpixmap_.fill(fg);
const double dr = 15 * double(bg.red() - fg.red()) / (m_rows * 16);
const double dg = 15 * double(bg.green() - fg.green()) / (m_rows * 16);
const double db = 15 * double(bg.blue() - fg.blue()) / (m_rows * 16);
const double dr = 15 * double(bg.red() - fg.red()) / (rows_ * 16);
const double dg = 15 * double(bg.green() - fg.green()) / (rows_ * 16);
const double db = 15 * double(bg.blue() - fg.blue()) / (rows_ * 16);
const int r = fg.red(), g = fg.green(), b = fg.blue();
bar()->fill(bg);
QPainter p(bar());
for (int y = 0; (uint)y < m_rows; ++y)
for (int y = 0; (uint)y < rows_; ++y)
// graduate the fg color
p.fillRect(0, y * (HEIGHT + 1), WIDTH, HEIGHT, QColor(r + int(dr * y), g + int(dg * y), b + int(db * y)));
@@ -389,9 +389,9 @@ void BlockAnalyzer::paletteChange(const QPalette&) // virtual
// Precalculate all fade-bar pixmaps
for (uint y = 0; y < FADE_SIZE; ++y) {
m_fade_bars[y].fill(palette().color(QPalette::Background));
QPainter f(&m_fade_bars[y]);
for (int z = 0; (uint)z < m_rows; ++z) {
fade_bars_[y].fill(palette().color(QPalette::Background));
QPainter f(&fade_bars_[y]);
for (int z = 0; (uint)z < rows_; ++z) {
const double Y = 1.0 - (log10(FADE_SIZE - y) / log10(FADE_SIZE));
f.fillRect(0, z * (HEIGHT + 1), WIDTH, HEIGHT, QColor(r + int(dr * Y), g + int(dg * Y), b + int(db * Y)));
}
@@ -399,16 +399,19 @@ void BlockAnalyzer::paletteChange(const QPalette&) // virtual
}
drawBackground();
}
void BlockAnalyzer::drawBackground() {
const QColor bg = palette().color(QPalette::Background);
const QColor bgdark = bg.dark(112);
m_background.fill(bg);
background_.fill(bg);
QPainter p(&background_);
for (int x = 0; (uint)x < columns_; ++x)
for (int y = 0; (uint)y < rows_; ++y)
p.fillRect(x * (WIDTH + 1), y * (HEIGHT + 1) + y_, WIDTH, HEIGHT, bgdark);
QPainter p(&m_background);
for (int x = 0; (uint)x < m_columns; ++x)
for (int y = 0; (uint)y < m_rows; ++y)
p.fillRect(x * (WIDTH + 1), y * (HEIGHT + 1) + m_y, WIDTH, HEIGHT, bgdark);
}

View File

@@ -51,24 +51,24 @@ class BlockAnalyzer : public Analyzer::Base {
void determineStep();
private:
QPixmap* bar() { return &m_barPixmap; }
QPixmap *bar() { return &barpixmap_; }
uint m_columns, m_rows; // number of rows and columns of blocks
uint m_y; // y-offset from top of widget
QPixmap m_barPixmap;
QPixmap m_topBarPixmap;
QPixmap m_background;
uint columns_, rows_; // number of rows and columns of blocks
uint y_; // y-offset from top of widget
QPixmap barpixmap_;
QPixmap topbarpixmap_;
QPixmap background_;
QPixmap canvas_;
Analyzer::Scope m_scope; // so we don't create a vector every frame
std::vector<float> m_store; // current bar heights
std::vector<float> m_yscale;
Analyzer::Scope scope_; // so we don't create a vector every frame
std::vector<float> store_; // current bar heights
std::vector<float> yscale_;
// FIXME why can't I namespace these? c++ issue?
std::vector<QPixmap> m_fade_bars;
std::vector<uint> m_fade_pos;
std::vector<int> m_fade_intensity;
std::vector<QPixmap> fade_bars_;
std::vector<uint> fade_pos_;
std::vector<int> fade_intensity_;
float m_step; // rows to fall per frame
float step_; // rows to fall per frame
};
#endif

View File

@@ -69,7 +69,7 @@ SCollection::~SCollection() {
}
void SCollection::Init() {
watcher_ = new CollectionWatcher;
watcher_thread_ = new Thread(this);
watcher_thread_->SetIoPriority(Utilities::IOPRIO_CLASS_IDLE);
@@ -116,7 +116,7 @@ void SCollection::Stopped() {
}
void SCollection::CurrentSongChanged(const Song &song) {
TagReaderReply *reply = nullptr;
if (reply) {

View File

@@ -531,7 +531,7 @@ void CollectionBackend::MarkSongsUnavailable(const SongList &songs, bool unavail
}
QStringList CollectionBackend::GetAll(const QString &column, const QueryOptions &opt) {
CollectionQuery query(opt);
query.SetColumnSpec("DISTINCT " + column);
query.AddCompilationRequirement(false);

View File

@@ -21,6 +21,7 @@
#include "config.h"
#include <functional>
#include <algorithm>
#include <QObject>
#include <QtGlobal>
@@ -61,6 +62,8 @@
#include "playlist/songmimedata.h"
#include "covermanager/albumcoverloader.h"
using std::bind;
using std::sort;
using std::placeholders::_1;
using std::placeholders::_2;
@@ -329,10 +332,10 @@ QString CollectionModel::DividerKey(GroupBy type, CollectionItem *item) const {
case GroupBy_Bitrate:
return SortTextForNumber(item->metadata.bitrate());
case GroupBy_Samplerate:
return SortTextForNumber(item->metadata.samplerate());
case GroupBy_Bitdepth:
return SortTextForNumber(item->metadata.bitdepth());
@@ -374,11 +377,11 @@ QString CollectionModel::DividerDisplayText(GroupBy type, const QString &key) co
case GroupBy_Bitrate:
if (key == "000") return tr("Unknown");
return QString::number(key.toInt()); // To remove leading 0s
case GroupBy_Samplerate:
if (key == "000") return tr("Unknown");
return QString::number(key.toInt()); // To remove leading 0s
case GroupBy_Bitdepth:
if (key == "000") return tr("Unknown");
return QString::number(key.toInt()); // To remove leading 0s
@@ -1125,13 +1128,13 @@ CollectionItem *CollectionModel::ItemFromSong(GroupBy type, bool signal, bool cr
item->key = QString::number(bitrate);
item->sort_text = SortTextForNumber(bitrate) + " ";
break;
case GroupBy_Samplerate:
samplerate = qMax(0, s.samplerate());
item->key = QString::number(samplerate);
item->sort_text = SortTextForNumber(samplerate) + " ";
break;
case GroupBy_Bitdepth:
bitdepth = qMax(0, s.bitdepth());
item->key = QString::number(bitdepth);
@@ -1312,7 +1315,7 @@ void CollectionModel::GetChildSongs(CollectionItem *item, QList<QUrl> *urls, Son
const_cast<CollectionModel*>(this)->LazyPopulate(item);
QList<CollectionItem*> children = item->children;
qSort(children.begin(), children.end(), std::bind(&CollectionModel::CompareItems, this, _1, _2));
std::sort(children.begin(), children.end(), std::bind(&CollectionModel::CompareItems, this, _1, _2));
for (CollectionItem *child : children)
GetChildSongs(child, urls, songs, song_ids);

View File

@@ -346,7 +346,7 @@ void CollectionView::ReloadSettings() {
app_->collection_model()->set_pretty_covers(settings.value("pretty_covers", true).toBool());
app_->collection_model()->set_show_dividers(settings.value("show_dividers", true).toBool());
}
settings.endGroup();
}
@@ -371,7 +371,7 @@ void CollectionView::TotalSongCountUpdated(int count) {
setCursor(Qt::PointingHandCursor);
else
unsetCursor();
emit TotalSongCountUpdated_();
}
@@ -386,7 +386,7 @@ void CollectionView::TotalArtistCountUpdated(int count) {
setCursor(Qt::PointingHandCursor);
else
unsetCursor();
emit TotalArtistCountUpdated_();
}
@@ -401,7 +401,7 @@ void CollectionView::TotalAlbumCountUpdated(int count) {
setCursor(Qt::PointingHandCursor);
else
unsetCursor();
emit TotalAlbumCountUpdated_();
}

View File

@@ -84,7 +84,7 @@ class CollectionView : public AutoExpandingTreeView {
// QTreeView
void keyboardSearch(const QString &search);
void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible);
int TotalSongs();
int TotalArtists();
int TotalAlbums();

View File

@@ -14,7 +14,7 @@
<string>Collection advanced grouping</string>
</property>
<property name="windowIcon">
<iconset resource="../../data/data.qrc">
<iconset resource="../../data/icons.qrc">
<normaloff>:/icons/64x64/strawberry.png</normaloff>:/icons/64x64/strawberry.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -358,6 +358,7 @@
</tabstops>
<resources>
<include location="../../data/data.qrc"/>
<include location="../../data/icons.qrc"/>
</resources>
<connections>
<connection>

View File

@@ -106,6 +106,7 @@
</widget>
<resources>
<include location="../../data/data.qrc"/>
<include location="../../data/icons.qrc"/>
</resources>
<connections>
<connection>

View File

@@ -37,7 +37,7 @@ class SqlRow {
SqlRow(const CollectionQuery &query);
const QVariant &value(int i) const { return columns_[i]; }
QList<QVariant> columns_;
private:

View File

@@ -1,25 +1,30 @@
/* This file is part of Strawberry.
Strawberry 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.
Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Strawberry Music Player
* Copyright 2013, Jonas Kvinge <jonas@strawbs.net>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CONFIG_H_IN
#define CONFIG_H_IN
#define CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}"
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
#define CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}"
#cmakedefine DEBUG
#cmakedefine HAVE_GIO
#cmakedefine HAVE_DBUS
#cmakedefine HAVE_X11
@@ -38,6 +43,7 @@
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_CHROMAPRINT
#cmakedefine HAVE_TAGLIB_DSFFILE
#cmakedefine HAVE_DZMEDIA
#cmakedefine IMOBILEDEVICE_USES_UDIDS
#cmakedefine USE_INSTALL_PREFIX
#cmakedefine USE_SYSTEM_SHA2
@@ -46,6 +52,10 @@
#cmakedefine HAVE_VLC
#cmakedefine HAVE_XINE
#cmakedefine HAVE_PHONON
#cmakedefine HAVE_DEEZER
#cmakedefine HAVE_STREAM_TIDAL
#cmakedefine HAVE_STREAM_DEEZER
#endif // CONFIG_H_IN

View File

@@ -22,6 +22,7 @@
#include "config.h"
#include <functional>
#include <algorithm>
#include <QObject>
#include <QtGlobal>
@@ -55,6 +56,8 @@
#include "contextalbumsmodel.h"
using std::bind;
using std::sort;
using std::placeholders::_1;
using std::placeholders::_2;
@@ -93,7 +96,7 @@ void ContextAlbumsModel::set_pretty_covers(bool use_pretty_covers) {
use_pretty_covers_ = use_pretty_covers;
Reset();
}
}
void ContextAlbumsModel::AddSongs(const SongList &songs) {
@@ -479,7 +482,7 @@ void ContextAlbumsModel::GetChildSongs(CollectionItem *item, QList<QUrl> *urls,
const_cast<ContextAlbumsModel*>(this)->LazyPopulate(item);
QList<CollectionItem*> children = item->children;
qSort(children.begin(), children.end(), std::bind(&ContextAlbumsModel::CompareItems, this, _1, _2));
std::sort(children.begin(), children.end(), std::bind(&ContextAlbumsModel::CompareItems, this, _1, _2));
for (CollectionItem *child : children)
GetChildSongs(child, urls, songs, song_ids);

View File

@@ -155,7 +155,7 @@ void ContextItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o
}
bool ContextItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) {
return true;
Q_UNUSED(option);
@@ -326,7 +326,7 @@ void ContextAlbumsView::ReloadSettings() {
if (app_ && model_) {
model_->set_pretty_covers(settings.value("pretty_covers", true).toBool());
}
settings.endGroup();
}
@@ -334,7 +334,7 @@ void ContextAlbumsView::ReloadSettings() {
void ContextAlbumsView::SetApplication(Application *app) {
app_ = app;
model_ = new ContextAlbumsModel(app_->collection_backend(), app_, this);
model_->Reset();
@@ -342,7 +342,7 @@ void ContextAlbumsView::SetApplication(Application *app) {
connect(model_, SIGNAL(modelAboutToBeReset()), this, SLOT(SaveFocus()));
connect(model_, SIGNAL(modelReset()), this, SLOT(RestoreFocus()));
ReloadSettings();
}

View File

@@ -78,7 +78,7 @@ class ContextAlbumsView : public AutoExpandingTreeView {
// QTreeView
void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible);
ContextAlbumsModel *albums_model() { return model_; }
public slots:
@@ -146,9 +146,9 @@ signals:
Song last_selected_song_;
QString last_selected_container_;
QSet<QString> last_selected_path_;
ContextAlbumsModel *model_;
};
#endif // CONTEXTALBUMSVIEW_H

View File

@@ -133,7 +133,7 @@ void ContextView::AddActions() {
action_show_output_ = new QAction(tr("Show engine and device"), this);
action_show_output_->setCheckable(true);
action_show_output_->setChecked(true);
action_show_output_->setChecked(true);
action_show_albums_ = new QAction(tr("Show albums by artist"), this);
action_show_albums_->setCheckable(true);
@@ -141,7 +141,7 @@ void ContextView::AddActions() {
action_show_lyrics_ = new QAction(tr("Show song lyrics"), this);
action_show_lyrics_->setCheckable(true);
action_show_lyrics_->setChecked(false);
action_show_lyrics_->setChecked(false);
menu_->addAction(action_show_data_);
menu_->addAction(action_show_output_);
@@ -512,13 +512,13 @@ void ContextView::UpdateLyrics(quint64 id, const QString lyrics) {
bool ContextView::eventFilter(QObject *object, QEvent *event) {
switch(event->type()) {
case QEvent::Paint:{
switch(event->type()) {
case QEvent::Paint:{
handlePaintEvent(object, event);
}
default:{
}
default:{
return QObject::eventFilter(object, event);
}
}
}
return(true);
@@ -530,7 +530,7 @@ void ContextView::handlePaintEvent(QObject *object, QEvent *event) {
if (object == ui_->label_play_album) {
PaintEventAlbum(event);
}
return;
}

View File

@@ -562,6 +562,7 @@
</customwidgets>
<resources>
<include location="../../data/data.qrc"/>
<include location="../../data/icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -26,11 +26,13 @@
#include <QObject>
#include <QThread>
#include <QVariant>
#include <QString>
#include "core/closure.h"
#include "core/lazy.h"
#include "core/tagreaderclient.h"
#include "core/song.h"
#include "database.h"
#include "taskmanager.h"
@@ -58,8 +60,15 @@
#include "lyrics/auddlyricsprovider.h"
#include "lyrics/apiseedslyricsprovider.h"
#include "internet/internetmodel.h"
#include "tidal/tidalsearch.h"
#include "internet/internetservices.h"
#include "internet/internetsearch.h"
#ifdef HAVE_STREAM_TIDAL
# include "tidal/tidalservice.h"
#endif
#ifdef HAVE_STREAM_DEEZER
# include "deezer/deezerservice.h"
#endif
bool Application::kIsPortable = false;
@@ -108,15 +117,30 @@ class ApplicationImpl {
return loader;
}),
current_art_loader_([=]() { return new CurrentArtLoader(app, app); }),
internet_model_([=]() { return new InternetModel(app, app); }),
tidal_search_([=]() { return new TidalSearch(app, app); }),
lyrics_providers_([=]() {
LyricsProviders *lyrics_providers = new LyricsProviders(app);
lyrics_providers->AddProvider(new AuddLyricsProvider(app));
lyrics_providers->AddProvider(new APISeedsLyricsProvider(app));
return lyrics_providers;
})
{ }
lyrics_providers->AddProvider(new APISeedsLyricsProvider(app));
return lyrics_providers;
}),
internet_services_([=]() {
InternetServices *internet_services = new InternetServices(app);
#ifdef HAVE_STREAM_TIDAL
internet_services->AddService(new TidalService(app, internet_services));
#endif
#ifdef HAVE_STREAM_DEEZER
internet_services->AddService(new DeezerService(app, internet_services));
#endif
return internet_services;
}),
#ifdef HAVE_STREAM_TIDAL
tidal_search_([=]() { return new InternetSearch(app, Song::Source_Tidal, app); }),
#endif
#ifdef HAVE_STREAM_DEEZER
deezer_search_([=]() { return new InternetSearch(app, Song::Source_Deezer, app); }),
#endif
dummy_([=]() { return new QVariant; })
{}
Lazy<TagReaderClient> tag_reader_client_;
Lazy<Database> database_;
@@ -133,9 +157,15 @@ class ApplicationImpl {
Lazy<CoverProviders> cover_providers_;
Lazy<AlbumCoverLoader> album_cover_loader_;
Lazy<CurrentArtLoader> current_art_loader_;
Lazy<InternetModel> internet_model_;
Lazy<TidalSearch> tidal_search_;
Lazy<LyricsProviders> lyrics_providers_;
Lazy<InternetServices> internet_services_;
#ifdef HAVE_STREAM_TIDAL
Lazy<InternetSearch> tidal_search_;
#endif
#ifdef HAVE_STREAM_DEEZER
Lazy<InternetSearch> deezer_search_;
#endif
Lazy<QVariant> dummy_;
};
@@ -181,73 +211,31 @@ void Application::MoveToThread(QObject *object, QThread *thread) {
}
void Application::AddError(const QString& message) { emit ErrorAdded(message); }
void Application::ReloadSettings() { emit SettingsChanged(); }
void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) { emit SettingsDialogRequested(page); }
void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) {
emit SettingsDialogRequested(page);
}
AlbumCoverLoader *Application::album_cover_loader() const {
return p_->album_cover_loader_.get();
}
TagReaderClient *Application::tag_reader_client() const { return p_->tag_reader_client_.get(); }
Appearance *Application::appearance() const { return p_->appearance_.get(); }
CoverProviders *Application::cover_providers() const {
return p_->cover_providers_.get();
}
CurrentArtLoader *Application::current_art_loader() const {
return p_->current_art_loader_.get();
}
Database *Application::database() const { return p_->database_.get(); }
#ifndef Q_OS_WIN
DeviceManager *Application::device_manager() const {
return p_->device_manager_.get();
}
#endif
SCollection *Application::collection() const { return p_->collection_.get(); }
CollectionBackend *Application::collection_backend() const {
return collection()->backend();
}
CollectionModel *Application::collection_model() const { return collection()->model(); }
TaskManager *Application::task_manager() const { return p_->task_manager_.get(); }
Player *Application::player() const { return p_->player_.get(); }
PlaylistBackend *Application::playlist_backend() const {
return p_->playlist_backend_.get();
}
PlaylistManager *Application::playlist_manager() const {
return p_->playlist_manager_.get();
}
TagReaderClient *Application::tag_reader_client() const {
return p_->tag_reader_client_.get();
}
TaskManager *Application::task_manager() const {
return p_->task_manager_.get();
}
EngineDevice *Application::enginedevice() const {
return p_->enginedevice_.get();
}
InternetModel* Application::internet_model() const {
return p_->internet_model_.get();
}
TidalSearch* Application::tidal_search() const {
return p_->tidal_search_.get();
}
LyricsProviders *Application::lyrics_providers() const {
return p_->lyrics_providers_.get();
}
EngineDevice *Application::enginedevice() const { return p_->enginedevice_.get(); }
#ifndef Q_OS_WIN
DeviceManager *Application::device_manager() const { return p_->device_manager_.get(); }
#endif
SCollection *Application::collection() const { return p_->collection_.get(); }
CollectionBackend *Application::collection_backend() const { return collection()->backend(); }
CollectionModel *Application::collection_model() const { return collection()->model(); }
AlbumCoverLoader *Application::album_cover_loader() const { return p_->album_cover_loader_.get(); }
CoverProviders *Application::cover_providers() const { return p_->cover_providers_.get(); }
CurrentArtLoader *Application::current_art_loader() const { return p_->current_art_loader_.get(); }
LyricsProviders *Application::lyrics_providers() const { return p_->lyrics_providers_.get(); }
PlaylistBackend *Application::playlist_backend() const { return p_->playlist_backend_.get(); }
PlaylistManager *Application::playlist_manager() const { return p_->playlist_manager_.get(); }
InternetServices *Application::internet_services() const { return p_->internet_services_.get(); }
#ifdef HAVE_STREAM_TIDAL
InternetSearch *Application::tidal_search() const { return p_->tidal_search_.get(); }
#endif
#ifdef HAVE_STREAM_DEEZER
InternetSearch *Application::deezer_search() const { return p_->deezer_search_.get(); }
#endif

View File

@@ -33,6 +33,8 @@
#include "settings/settingsdialog.h"
using std::unique_ptr;
class TaskManager;
class ApplicationImpl;
class TagReaderClient;
@@ -51,9 +53,9 @@ class DeviceManager;
class CoverProviders;
class AlbumCoverLoader;
class CurrentArtLoader;
class InternetModel;
class TidalSearch;
class LyricsProviders;
class InternetServices;
class InternetSearch;
class Application : public QObject {
Q_OBJECT
@@ -75,6 +77,8 @@ class Application : public QObject {
#endif
SCollection *collection() const;
CollectionBackend *collection_backend() const;
CollectionModel *collection_model() const;
PlaylistBackend *playlist_backend() const;
PlaylistManager *playlist_manager() const;
@@ -83,14 +87,16 @@ class Application : public QObject {
AlbumCoverLoader *album_cover_loader() const;
CurrentArtLoader *current_art_loader() const;
CollectionBackend *collection_backend() const;
CollectionModel *collection_model() const;
InternetModel *internet_model() const;
TidalSearch *tidal_search() const;
LyricsProviders *lyrics_providers() const;
InternetServices *internet_services() const;
#ifdef HAVE_STREAM_TIDAL
InternetSearch *tidal_search() const;
#endif
#ifdef HAVE_STREAM_DEEZER
InternetSearch *deezer_search() const;
#endif
void MoveToNewThread(QObject *object);
void MoveToThread(QObject *object, QThread *thread);

View File

@@ -1,105 +0,0 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2011, David Sansome <me@davidsansome.com>
*
* Strawberry 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.
*
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CACHEDLIST_H
#define CACHEDLIST_H
#include "config.h"
#include <QList>
#include <QString>
#include <QDateTime>
#include <QSettings>
template <typename T>
class CachedList {
public:
// Use a CachedList when you want to download and save a list of things from a
// remote service, updating it only periodically.
// T must be a registered metatype and must support being stored in
// QSettings. This usually means you have to implement QDataStream streaming
// operators, and use qRegisterMetaTypeStreamOperators.
typedef QList<T> ListType;
CachedList(const QString &settings_group, const QString &name, int cache_duration_secs)
: settings_group_(settings_group), name_(name), cache_duration_secs_(cache_duration_secs) {
}
void Load() {
QSettings s;
s.beginGroup(settings_group_);
last_updated_ = s.value("last_refreshed_" + name_).toDateTime();
data_.clear();
const int count = s.beginReadArray(name_ + "_data");
for (int i = 0; i < count; ++i) {
s.setArrayIndex(i);
data_ << s.value("value").value<T>();
}
s.endArray();
}
void Save() const {
QSettings s;
s.beginGroup(settings_group_);
s.setValue("last_refreshed_" + name_, last_updated_);
s.beginWriteArray(name_ + "_data", data_.size());
for (int i = 0; i < data_.size(); ++i) {
s.setArrayIndex(i);
s.setValue("value", QVariant::fromValue(data_[i]));
}
s.endArray();
}
void Update(const ListType &data) {
data_ = data;
last_updated_ = QDateTime::currentDateTime();
Save();
}
bool IsStale() const {
return last_updated_.isNull() || last_updated_.secsTo(QDateTime::currentDateTime()) > cache_duration_secs_;
}
void Sort() { qSort(data_); }
const ListType &Data() const { return data_; }
operator ListType() const { return data_; }
// Q_FOREACH support
typedef typename ListType::const_iterator const_iterator;
const_iterator begin() const { return data_.begin(); }
const_iterator end() const { return data_.end(); }
private:
const QString settings_group_;
const QString name_;
const int cache_duration_secs_;
QDateTime last_updated_;
ListType data_;
};
#endif // CACHEDLIST_H

View File

@@ -62,7 +62,7 @@ Database::Token::Token(const QString &token, int start, int end)
: token(token), start_offset(start), end_offset(end) {}
struct sqlite3_tokenizer_module {
int iVersion;
int (*xCreate)(int argc, /* Size of argv array */
const char *const *argv, /* Tokenizer argument strings */
@@ -106,7 +106,7 @@ int Database::FTSCreate(int argc, const char *const *argv, sqlite3_tokenizer **t
}
int Database::FTSDestroy(sqlite3_tokenizer *tokenizer) {
UnicodeTokenizer *real_tokenizer = reinterpret_cast<UnicodeTokenizer*>(tokenizer);
delete real_tokenizer;
return SQLITE_OK;
@@ -283,7 +283,11 @@ QSqlDatabase Database::Connect() {
QVariant v = db.driver()->handle();
if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0) {
sqlite3 *handle = *static_cast<sqlite3**>(v.data());
if (handle) sqlite3_db_config(handle, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, NULL);
if (handle) {
int result = sqlite3_db_config(handle, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, NULL);
if (result != SQLITE_OK) qLog(Fatal) << "Unable to enable FTS3 tokenizer";
}
else qLog(Fatal) << "Unable to enable FTS3 tokenizer";
}
#endif
QSqlQuery set_fts_tokenizer(db);
@@ -456,7 +460,7 @@ void Database::UrlEncodeFilenameColumn(const QString &table, QSqlDatabase &db) {
update.prepare(QString("UPDATE %1 SET filename=:filename WHERE ROWID=:id").arg(table));
select.exec();
if (CheckErrors(select)) return;
while (select.next()) {
const int rowid = select.value(0).toInt();
const QString filename = select.value(1).toString();
@@ -561,7 +565,7 @@ QStringList Database::SongsTables(QSqlDatabase &db, int schema_version) const {
}
bool Database::CheckErrors(const QSqlQuery &query) {
QSqlError last_error = query.lastError();
if (last_error.isValid()) {
qLog(Error) << "db error: " << last_error;

View File

@@ -11,7 +11,7 @@ class PlatformInterface;
NSMenu* dock_menu_;
MacGlobalShortcutBackend* shortcut_handler_;
SPMediaKeyTap* key_tap_;
}
- (id) initWithHandler: (PlatformInterface*)handler;

View File

@@ -17,7 +17,7 @@
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include "macsystemtrayicon.h"
@@ -183,7 +183,7 @@ void MacSystemTrayIcon::SetupMenu(QAction* previous, QAction* play, QAction* sto
SetupMenuItem(mute);
p_->AddSeparator();
Q_UNUSED(quit); // Mac already has a Quit item.
}
void MacSystemTrayIcon::SetupMenuItem(QAction* action) {

View File

@@ -58,6 +58,7 @@
#include <QString>
#include <QImage>
#include <QSettings>
#include <QLoggingCategory>
#include <QtDebug>
#ifdef HAVE_DBUS
# include <QDBusArgument>
@@ -200,6 +201,11 @@ int main(int argc, char* argv[]) {
// Resources
Q_INIT_RESOURCE(data);
Q_INIT_RESOURCE(icons);
#ifdef DEBUG
QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, true);
#endif
Application app;

View File

@@ -29,6 +29,7 @@
#include <QApplication>
#include <QObject>
#include <QWidget>
#include <QSystemTrayIcon>
#include <QSortFilterProxyModel>
#include <QByteArray>
#include <QDir>
@@ -111,8 +112,8 @@
#include "playlist/playlistmanager.h"
#include "playlist/playlistsequence.h"
#include "playlist/playlistview.h"
#include "playlist/queue.h"
#include "playlist/queuemanager.h"
#include "queue/queue.h"
#include "queue/queueview.h"
#include "playlistparsers/playlistparser.h"
#include "analyzer/analyzercontainer.h"
#include "equalizer/equalizer.h"
@@ -128,12 +129,20 @@
# include "device/deviceviewcontainer.h"
#endif
#include "transcoder/transcodedialog.h"
#include "settings/settingsdialog.h"
#include "settings/behavioursettingspage.h"
#include "settings/playbacksettingspage.h"
#include "settings/playlistsettingspage.h"
#include "settings/settingsdialog.h"
#ifdef HAVE_STREAM_TIDAL
# include "settings/tidalsettingspage.h"
#endif
#ifdef HAVE_STREAM_DEEZER
# include "settings/deezersettingspage.h"
#endif
#include "tidal/tidalsearchview.h"
#include "internet/internetservices.h"
#include "internet/internetservice.h"
#include "internet/internetsearchview.h"
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
# include "musicbrainz/tagfetcher.h"
@@ -143,6 +152,10 @@
# include "core/macsystemtrayicon.h"
#endif
using std::bind;
using std::floor;
using std::stable_sort;
#ifdef Q_OS_MACOS
// Non exported mac-specific function.
void qt_mac_set_dock_menu(QMenu*);
@@ -152,7 +165,7 @@ const char *MainWindow::kSettingsGroup = "MainWindow";
const char *MainWindow::kAllFilesFilterSpec = QT_TR_NOOP("All Files (*)");
namespace {
const int kTrackSliderUpdateTimeMs = 40;
const int kTrackSliderUpdateTimeMs = 200;
const int kTrackPositionUpdateTimeMs = 1000;
}
@@ -174,6 +187,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
device_view_(device_view_container_->view()),
#endif
playlist_list_(new PlaylistListContainer(this)),
queue_view_(new QueueView(this)),
settings_dialog_(std::bind(&MainWindow::CreateSettingsDialog, this)),
cover_manager_([=]() {
AlbumCoverManager *cover_manager = new AlbumCoverManager(app, app->collection_backend());
@@ -193,12 +207,12 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
return dialog;
}),
#endif
queue_manager_([=]() {
QueueManager *manager = new QueueManager;
manager->SetPlaylistManager(app->playlist_manager());
return manager;
}),
tidal_search_view_(new TidalSearchView(app_, this)),
#ifdef HAVE_STREAM_TIDAL
tidal_search_view_(new InternetSearchView(app_, app_->tidal_search(), TidalSettingsPage::kSettingsGroup, SettingsDialog::Page_Tidal, this)),
#endif
#ifdef HAVE_STREAM_DEEZER
deezer_search_view_(new InternetSearchView(app_, app_->deezer_search(), DeezerSettingsPage::kSettingsGroup, SettingsDialog::Page_Deezer, this)),
#endif
playlist_menu_(new QMenu(this)),
playlist_add_to_another_(nullptr),
playlistitem_actions_separator_(nullptr),
@@ -242,24 +256,29 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
ui_->volume->setValue(volume);
VolumeChanged(volume);
// Initialise the tidal search widget
// Initialise the search widget
StyleHelper::setBaseColor(palette().color(QPalette::Highlight).darker());
// Add tabs to the fancy tab widget
ui_->tabs->addTab(context_view_, IconLoader::Load("strawberry"), tr("Context"));
ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), tr("Collection"));
ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), tr("Files"));
ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), tr("Playlists"));
ui_->tabs->addTab(context_view_, IconLoader::Load("strawberry"), "Context");
ui_->tabs->addTab(collection_view_, IconLoader::Load("vinyl"), "Collection");
ui_->tabs->addTab(file_view_, IconLoader::Load("document-open"), "Files");
ui_->tabs->addTab(playlist_list_, IconLoader::Load("view-media-playlist"), "Playlists");
ui_->tabs->addTab(queue_view_, IconLoader::Load("footsteps"), "Queue");
#ifndef Q_OS_WIN
ui_->tabs->addTab(device_view_, IconLoader::Load("device"), tr("Devices"));
ui_->tabs->addTab(device_view_, IconLoader::Load("device"), "Devices");
#endif
#ifdef HAVE_STREAM_TIDAL
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), "Tidal");
#endif
#ifdef HAVE_STREAM_DEEZER
ui_->tabs->addTab(deezer_search_view_, IconLoader::Load("deezer"), "Deezer");
#endif
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), tr("Tidal", "Tidal"));
//ui_->tabs->AddSpacer();
// Add the playing widget to the fancy tab widget
ui_->tabs->addBottomWidget(ui_->widget_playing);
//ui_->tabs->SetBackgroundPixmap(QPixmap(":/pictures/strawberry-background.png"));
ui_->tabs->loadSettings(kSettingsGroup);
track_position_timer_->setInterval(kTrackPositionUpdateTimeMs);
connect(track_position_timer_, SIGNAL(timeout()), SLOT(UpdateTrackPosition()));
@@ -279,7 +298,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
collection_sort_model_->setDynamicSortFilter(true);
collection_sort_model_->setSortLocaleAware(true);
collection_sort_model_->sort(0);
qLog(Debug) << "Creating models finished";
connect(ui_->playlist, SIGNAL(ViewSelectionModelChanged()), SLOT(PlaylistViewSelectionModelChanged()));
@@ -316,7 +335,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
ui_->action_stop->setIcon(IconLoader::Load("media-stop"));
ui_->action_stop_after_this_track->setIcon(IconLoader::Load("media-stop"));
ui_->action_next_track->setIcon(IconLoader::Load("media-forward"));
ui_->action_quit->setIcon(IconLoader::Load("application-exit"));
ui_->action_quit->setIcon(IconLoader::Load("application-exit"));
// Playlist
@@ -338,7 +357,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
// Configure
ui_->action_cover_manager->setIcon(IconLoader::Load("document-download"));
ui_->action_queue_manager->setIcon(IconLoader::Load("footsteps"));
ui_->action_edit_track->setIcon(IconLoader::Load("edit-rename"));
ui_->action_equalizer->setIcon(IconLoader::Load("equalizer"));
ui_->action_update_collection->setIcon(IconLoader::Load("view-refresh"));
@@ -391,7 +409,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
connect(ui_->action_jump, SIGNAL(triggered()), ui_->playlist->view(), SLOT(JumpToCurrentlyPlayingTrack()));
connect(ui_->action_update_collection, SIGNAL(triggered()), app_->collection(), SLOT(IncrementalScan()));
connect(ui_->action_full_collection_scan, SIGNAL(triggered()), app_->collection(), SLOT(FullScan()));
connect(ui_->action_queue_manager, SIGNAL(triggered()), SLOT(ShowQueueManager()));
//connect(ui_->action_add_files_to_transcoder, SIGNAL(triggered()), SLOT(AddFilesToTranscoder()));
// Playlist view actions
@@ -512,8 +529,12 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
collection_view_->filter()->AddMenuAction(separator);
collection_view_->filter()->AddMenuAction(collection_config_action);
// Tidal
#ifdef HAVE_STREAM_TIDAL
connect(tidal_search_view_, SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
#endif
#ifdef HAVE_STREAM_DEEZER
connect(deezer_search_view_, SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
#endif
// Playlist menu
playlist_play_pause_ = playlist_menu_->addAction(tr("Play"), this, SLOT(PlaylistPlay()));
@@ -574,15 +595,16 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
mac::SetApplicationHandler(this);
#endif
// Tray icon
tray_icon_->SetupMenu(ui_->action_previous_track, ui_->action_play_pause, ui_->action_stop, ui_->action_stop_after_this_track, ui_->action_next_track, ui_->action_mute, ui_->action_quit);
connect(tray_icon_, SIGNAL(PlayPause()), app_->player(), SLOT(PlayPause()));
connect(tray_icon_, SIGNAL(SeekForward()), app_->player(), SLOT(SeekForward()));
connect(tray_icon_, SIGNAL(SeekBackward()), app_->player(), SLOT(SeekBackward()));
connect(tray_icon_, SIGNAL(NextTrack()), app_->player(), SLOT(Next()));
connect(tray_icon_, SIGNAL(PreviousTrack()), app_->player(), SLOT(Previous()));
connect(tray_icon_, SIGNAL(ShowHide()), SLOT(ToggleShowHide()));
connect(tray_icon_, SIGNAL(ChangeVolume(int)), SLOT(VolumeWheelEvent(int)));
if (tray_icon_) {
tray_icon_->SetupMenu(ui_->action_previous_track, ui_->action_play_pause, ui_->action_stop, ui_->action_stop_after_this_track, ui_->action_next_track, ui_->action_mute, ui_->action_quit);
connect(tray_icon_, SIGNAL(PlayPause()), app_->player(), SLOT(PlayPause()));
connect(tray_icon_, SIGNAL(SeekForward()), app_->player(), SLOT(SeekForward()));
connect(tray_icon_, SIGNAL(SeekBackward()), app_->player(), SLOT(SeekBackward()));
connect(tray_icon_, SIGNAL(NextTrack()), app_->player(), SLOT(Next()));
connect(tray_icon_, SIGNAL(PreviousTrack()), app_->player(), SLOT(Previous()));
connect(tray_icon_, SIGNAL(ShowHide()), SLOT(ToggleShowHide()));
connect(tray_icon_, SIGNAL(ChangeVolume(int)), SLOT(VolumeWheelEvent(int)));
}
// Windows 7 thumbbar buttons
thumbbar_->SetActions(QList<QAction*>() << ui_->action_previous_track << ui_->action_play_pause << ui_->action_stop << ui_->action_next_track << nullptr); // spacer
@@ -615,7 +637,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
connect(ui_->tabs, SIGNAL(ModeChanged(FancyTabWidget::Mode)), SLOT(SaveGeometry()));
connect(ui_->tabs, SIGNAL(CurrentChanged(int)), SLOT(TabSwitched()));
connect(ui_->tabs, SIGNAL(CurrentChanged(int)), SLOT(SaveGeometry()));
// Context
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)), context_view_, SLOT(SongChanged(Song)));
connect(app_->player(), SIGNAL(PlaylistFinished()), context_view_, SLOT(Stopped()));
@@ -672,6 +694,8 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
// Load playlists
app_->playlist_manager()->Init(app_->collection_backend(), app_->playlist_backend(), ui_->playlist_sequence, ui_->playlist);
queue_view_->SetPlaylistManager(app_->playlist_manager());
// This connection must be done after the playlists have been initialized.
connect(this, SIGNAL(StopAfterToggled(bool)), osd_, SLOT(StopAfterToggle(bool)));
@@ -698,7 +722,10 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
ui_->tabs->setCurrentIndex(settings_.value("current_tab", 1 /* Collection tab */ ).toInt());
FancyTabWidget::Mode default_mode = FancyTabWidget::Mode_LargeSidebar;
ui_->tabs->SetMode(FancyTabWidget::Mode(settings_.value("tab_mode", default_mode).toInt()));
int tab_mode_int = settings_.value("tab_mode", default_mode).toInt();
FancyTabWidget::Mode tab_mode = FancyTabWidget::Mode(tab_mode_int);
if (tab_mode == FancyTabWidget::Mode_None) tab_mode = default_mode;
ui_->tabs->SetMode(tab_mode);
file_view_->SetPath(settings_.value("file_path", QDir::homePath()).toString());
TabSwitched();
@@ -708,43 +735,38 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
ReloadSettings();
// Tidal search shortcut
QAction *tidal_search_action = new QAction(this);
tidal_search_action->setShortcuts(QList<QKeySequence>() << QKeySequence("Ctrl+F") << QKeySequence("Ctrl+L"));
addAction(tidal_search_action);
connect(tidal_search_action, SIGNAL(triggered()), SLOT(FocusTidalSearchField()));
// Reload pretty OSD to avoid issues with fonts
osd_->ReloadPrettyOSDSettings();
// Reload playlist settings, for BG and glowing
ui_->playlist->view()->ReloadSettings();
#ifndef Q_OS_MACOS
#ifdef Q_OS_MACOS // Always show mainwindow on startup if on macos
show();
#else
QSettings settings;
settings.beginGroup(BehaviourSettingsPage::kSettingsGroup);
StartupBehaviour behaviour = StartupBehaviour(settings.value("startupbehaviour", Startup_Remember).toInt());
settings.endGroup();
bool hidden = settings_.value("hidden", false).toBool();
switch (behaviour) {
case Startup_AlwaysHide: hide(); break;
case Startup_AlwaysShow: show(); break;
case Startup_Remember:
setVisible(!hidden);
break;
}
// Force the window to show in case somehow the config has tray and window set to hide
if (hidden && !tray_icon_->IsVisible()) {
if (hidden && (!QSystemTrayIcon::isSystemTrayAvailable() || !tray_icon_ || !tray_icon_->IsVisible())) {
hidden = false;
settings_.setValue("hidden", false);
show();
}
#else // Q_OS_MACOS
// Always show mainwindow on startup on OS X.
show();
else {
switch (behaviour) {
case Startup_AlwaysHide:
hide();
break;
case Startup_AlwaysShow:
show();
break;
case Startup_Remember:
setVisible(!hidden);
break;
}
}
#endif
QShortcut *close_window_shortcut = new QShortcut(this);
@@ -757,9 +779,9 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
if (!options.contains_play_options()) LoadPlaybackStatus();
qLog(Debug) << "Started";
RefreshStyleSheet();
qLog(Debug) << "Started";
initialised_ = true;
}
@@ -774,16 +796,14 @@ void MainWindow::ReloadSettings() {
QSettings settings;
#ifndef Q_OS_MACOS
settings.beginGroup(BehaviourSettingsPage::kSettingsGroup);
bool showtrayicon = settings.value("showtrayicon", true).toBool();
bool showtrayicon = settings.value("showtrayicon", QSystemTrayIcon::isSystemTrayAvailable()).toBool();
settings.endGroup();
tray_icon_->SetVisible(showtrayicon);
if (!showtrayicon && !isVisible()) show();
if (tray_icon_) tray_icon_->SetVisible(showtrayicon);
if ((!showtrayicon || !QSystemTrayIcon::isSystemTrayAvailable()) && !isVisible()) show();
#endif
settings.beginGroup(PlaylistSettingsPage::kSettingsGroup);
settings.beginGroup(BehaviourSettingsPage::kSettingsGroup);
doubleclick_addmode_ = AddBehaviour(settings.value("doubleclick_addmode", AddBehaviour_Append).toInt());
doubleclick_playmode_ = PlayBehaviour(settings.value("doubleclick_playmode", PlayBehaviour_IfStopped).toInt());
doubleclick_playlist_addmode_ = PlaylistAddBehaviour(settings.value("doubleclick_playlist_addmode", PlaylistAddBehaviour_Play).toInt());
@@ -794,6 +814,26 @@ void MainWindow::ReloadSettings() {
album_cover_choice_controller_->search_cover_auto_action()->setChecked(settings.value("search_for_cover_auto", true).toBool());
settings.endGroup();
#ifdef HAVE_STREAM_TIDAL
settings.beginGroup(TidalSettingsPage::kSettingsGroup);
bool enable_tidal = settings.value("enabled", false).toBool();
settings.endGroup();
if (enable_tidal)
ui_->tabs->addTab(tidal_search_view_, IconLoader::Load("tidal"), "Tidal");
else
ui_->tabs->delTab("Tidal");
#endif
#ifdef HAVE_STREAM_DEEZER
settings.beginGroup(DeezerSettingsPage::kSettingsGroup);
bool enable_deezer = settings.value("enabled", false).toBool();
settings.endGroup();
if (enable_deezer)
ui_->tabs->addTab(deezer_search_view_, IconLoader::Load("deezer"), "Deezer");
else
ui_->tabs->delTab("Deezer");
#endif
}
void MainWindow::ReloadAllSettings() {
@@ -807,13 +847,21 @@ void MainWindow::ReloadAllSettings() {
osd_->ReloadSettings();
collection_view_->ReloadSettings();
ui_->playlist->view()->ReloadSettings();
#ifdef HAVE_STREAM_TIDAL
tidal_search_view_->ReloadSettings();
#endif
#ifdef HAVE_STREAM_DEEZER
deezer_search_view_->ReloadSettings();
#endif
}
void MainWindow::RefreshStyleSheet() {
setStyleSheet(styleSheet());
QString contents(styleSheet());
setStyleSheet("");
setStyleSheet(contents);
}
void MainWindow::MediaStopped() {
setWindowTitle("Strawberry Music Player");
@@ -828,8 +876,10 @@ void MainWindow::MediaStopped() {
track_position_timer_->stop();
track_slider_timer_->stop();
ui_->track_slider->SetStopped();
tray_icon_->SetProgress(0);
tray_icon_->SetStopped();
if (tray_icon_) {
tray_icon_->SetProgress(0);
tray_icon_->SetStopped();
}
song_playing_ = Song();
song_ = Song();
@@ -838,7 +888,7 @@ void MainWindow::MediaStopped() {
}
void MainWindow::MediaPaused() {
ui_->action_stop->setEnabled(true);
ui_->action_stop_after_this_track->setEnabled(true);
ui_->action_play_pause->setIcon(IconLoader::Load("media-play"));
@@ -849,7 +899,7 @@ void MainWindow::MediaPaused() {
track_position_timer_->stop();
track_slider_timer_->stop();
tray_icon_->SetPaused();
if (tray_icon_) tray_icon_->SetPaused();
}
@@ -860,13 +910,15 @@ void MainWindow::MediaPlaying() {
ui_->action_play_pause->setIcon(IconLoader::Load("media-pause"));
ui_->action_play_pause->setText(tr("Pause"));
bool enable_play_pause = !(app_->player()->GetCurrentItem()->options() & PlaylistItem::PauseDisabled);
bool enable_play_pause(false);
bool can_seek(false);
if (app_->player()->GetCurrentItem()) {
enable_play_pause = !(app_->player()->GetCurrentItem()->options() & PlaylistItem::PauseDisabled);
can_seek = !(app_->player()->GetCurrentItem()->options() & PlaylistItem::SeekDisabled);
}
ui_->action_play_pause->setEnabled(enable_play_pause);
bool can_seek = !(app_->player()->GetCurrentItem()->options() & PlaylistItem::SeekDisabled);
ui_->track_slider->SetCanSeek(can_seek);
tray_icon_->SetPlaying(enable_play_pause);
if (tray_icon_) tray_icon_->SetPlaying(enable_play_pause);
track_position_timer_->start();
track_slider_timer_->start();
@@ -876,7 +928,7 @@ void MainWindow::MediaPlaying() {
void MainWindow::VolumeChanged(int volume) {
ui_->action_mute->setChecked(!volume);
tray_icon_->MuteButtonStateChanged(!volume);
if (tray_icon_) tray_icon_->MuteButtonStateChanged(!volume);
}
void MainWindow::SongChanged(const Song &song) {
@@ -884,11 +936,12 @@ void MainWindow::SongChanged(const Song &song) {
song_playing_ = song;
song_ = song;
setWindowTitle(song.PrettyTitleWithArtist());
tray_icon_->SetProgress(0);
if (tray_icon_) tray_icon_->SetProgress(0);
}
void MainWindow::TrackSkipped(PlaylistItemPtr item) {
// If it was a collection item then we have to increment its skipped count in the database.
if (item && item->IsLocalCollectionItem() && item->Metadata().id() != -1) {
@@ -905,6 +958,7 @@ void MainWindow::TrackSkipped(PlaylistItemPtr item) {
app_->collection_backend()->IncrementSkipCountAsync(song.id(), percentage);
}
}
}
void MainWindow::changeEvent(QEvent *event) {
@@ -913,16 +967,18 @@ void MainWindow::changeEvent(QEvent *event) {
}
void MainWindow::resizeEvent(QResizeEvent *event) {
if (!initialised_) return;
SaveGeometry();
}
void MainWindow::TabSwitched() {
if (ui_->tabs->currentIndex() > 0)
ui_->widget_playing->SetEnabled();
else
ui_->widget_playing->SetDisabled();
if (ui_->tabs->tabBar()->tabData(ui_->tabs->currentIndex()).toString().toLower() == "context")
ui_->widget_playing->SetDisabled();
else
ui_->widget_playing->SetEnabled();
if (!initialised_) return;
SaveGeometry();
}
@@ -936,11 +992,12 @@ void MainWindow::SaveGeometry() {
settings_.setValue("splitter_state", ui_->splitter->saveState());
settings_.setValue("current_tab", ui_->tabs->currentIndex());
settings_.setValue("tab_mode", ui_->tabs->mode());
ui_->tabs->saveSettings(kSettingsGroup);
}
void MainWindow::SavePlaybackStatus() {
QSettings settings;
settings.beginGroup("Player");
@@ -951,13 +1008,13 @@ void MainWindow::SavePlaybackStatus() {
else {
settings.setValue("playback_position", 0);
}
settings.endGroup();
}
void MainWindow::LoadPlaybackStatus() {
QSettings settings;
settings.beginGroup(BehaviourSettingsPage::kSettingsGroup);
@@ -970,7 +1027,7 @@ void MainWindow::LoadPlaybackStatus() {
saved_playback_state_ = static_cast<Engine::State> (settings.value("playback_state", Engine::Empty).toInt());
saved_playback_position_ = settings.value("playback_position", 0).toDouble();
settings.endGroup();
if (saved_playback_state_ == Engine::Empty || saved_playback_state_ == Engine::Idle) {
return;
}
@@ -995,7 +1052,7 @@ void MainWindow::ResumePlayback() {
}
void MainWindow::PlayIndex(const QModelIndex &index) {
if (!index.isValid()) return;
int row = index.row();
@@ -1040,7 +1097,7 @@ void MainWindow::VolumeWheelEvent(int delta) {
}
void MainWindow::ToggleShowHide() {
if (settings_.value("hidden").toBool()) {
show();
SetHiddenInTray(false);
@@ -1078,7 +1135,7 @@ void MainWindow::closeEvent(QCloseEvent *event) {
bool keep_running = settings.value("keeprunning", false).toBool();
settings.endGroup();
if (keep_running && event->spontaneous()) {
if (keep_running && event->spontaneous() && QSystemTrayIcon::isSystemTrayAvailable()) {
event->ignore();
SetHiddenInTray(true);
}
@@ -1111,16 +1168,17 @@ void MainWindow::Seeked(qlonglong microseconds) {
const int position = microseconds / kUsecPerSec;
const int length = app_->player()->GetCurrentItem()->Metadata().length_nanosec() / kNsecPerSec;
tray_icon_->SetProgress(double(position) / length * 100);
if (tray_icon_) tray_icon_->SetProgress(double(position) / length * 100);
}
void MainWindow::UpdateTrackPosition() {
// Track position in seconds
//Playlist *playlist = app_->playlist_manager()->active();
PlaylistItemPtr item(app_->player()->GetCurrentItem());
if (!item) return;
const int position = std::floor(float(app_->player()->engine()->position_nanosec()) / kNsecPerSec + 0.5);
const int length = item->Metadata().length_nanosec() / kNsecPerSec;
@@ -1132,9 +1190,8 @@ void MainWindow::UpdateTrackPosition() {
}
// Update the tray icon every 10 seconds
if (position % 10 == 0) {
tray_icon_->SetProgress(double(position) / length * 100);
}
if (position % 10 == 0 && tray_icon_) tray_icon_->SetProgress(double(position) / length * 100);
}
void MainWindow::UpdateTrackSliderPosition() {
@@ -1215,7 +1272,7 @@ void MainWindow::AddToPlaylist(QMimeData *data) {
}
void MainWindow::AddToPlaylist(QAction *action) {
int destination = action->data().toInt();
PlaylistItemList items;
@@ -1287,17 +1344,17 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
int not_in_queue = 0;
int in_skipped = 0;
int not_in_skipped = 0;
for (const QModelIndex &index : selection) {
all++;
if (index.column() != 0) continue;
selected++;
PlaylistItemPtr item = app_->playlist_manager()->current()->item_at(index.row());
if (item->Metadata().has_cue()) {
cue_selected = true;
}
@@ -1344,10 +1401,6 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
#endif
playlist_open_in_browser_->setVisible(false);
//qLog(Debug) << "selected" << selected;
//qLog(Debug) << "in_queue" << in_queue << "not_in_queue" << not_in_queue;
//qLog(Debug) << "in_skipped" << in_skipped << "not_in_skipped" << not_in_skipped;
if (selected < 1) {
playlist_queue_->setVisible(false);
playlist_skip_->setVisible(false);
@@ -1380,8 +1433,8 @@ void MainWindow::PlaylistRightClick(const QPoint &global_pos, const QModelIndex
ui_->action_edit_value->setVisible(false);
}
else {
Playlist::Column column = (Playlist::Column)index.column();
bool column_is_editable = Playlist::column_is_editable(column) && editable;
@@ -1471,6 +1524,7 @@ void MainWindow::PlaylistStopAfter() {
}
void MainWindow::EditTracks() {
SongList songs;
PlaylistItemList items;
@@ -1489,9 +1543,11 @@ void MainWindow::EditTracks() {
//EnsureEditTagDialogCreated();
edit_tag_dialog_->SetSongs(songs, items);
edit_tag_dialog_->show();
}
void MainWindow::EditTagDialogAccepted() {
for (PlaylistItemPtr item : edit_tag_dialog_->playlist_items()) {
item->Reload();
}
@@ -1500,14 +1556,16 @@ void MainWindow::EditTagDialogAccepted() {
ui_->playlist->view()->update();
app_->playlist_manager()->current()->Save();
}
void MainWindow::RenumberTracks() {
QModelIndexList indexes =ui_->playlist->view()->selectionModel()->selection().indexes();
int track = 1;
// Get the index list in order
qStableSort(indexes);
std::stable_sort(indexes.begin(), indexes.end());
// if first selected song has a track number set, start from that offset
if (!indexes.isEmpty()) {
@@ -1532,6 +1590,7 @@ void MainWindow::RenumberTracks() {
}
track++;
}
}
void MainWindow::SongSaveComplete(TagReaderReply *reply,const QPersistentModelIndex &index) {
@@ -1542,6 +1601,7 @@ void MainWindow::SongSaveComplete(TagReaderReply *reply,const QPersistentModelIn
}
void MainWindow::SelectionSetValue() {
Playlist::Column column = (Playlist::Column)playlist_menu_index_.column();
QVariant column_value =app_->playlist_manager()->current()->data(playlist_menu_index_);
@@ -1560,9 +1620,11 @@ void MainWindow::SelectionSetValue() {
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*, QPersistentModelIndex)),reply, QPersistentModelIndex(source_index));
}
}
}
void MainWindow::EditValue() {
QModelIndex current = ui_->playlist->view()->currentIndex();
if (!current.isValid()) return;
@@ -1582,7 +1644,7 @@ void MainWindow::EditValue() {
}
void MainWindow::AddFile() {
// Last used directory
QString directory =settings_.value("add_media_path", QDir::currentPath()).toString();
@@ -1605,9 +1667,11 @@ void MainWindow::AddFile() {
MimeData *data = new MimeData;
data->setUrls(urls);
AddToPlaylist(data);
}
void MainWindow::AddFolder() {
// Last used directory
QString directory =settings_.value("add_folder_path", QDir::currentPath()).toString();
@@ -1622,6 +1686,7 @@ void MainWindow::AddFolder() {
MimeData *data = new MimeData;
data->setUrls(QList<QUrl>() << QUrl::fromLocalFile(QFileInfo(directory).canonicalFilePath()));
AddToPlaylist(data);
}
void MainWindow::AddCDTracks() {
@@ -2050,7 +2115,7 @@ SettingsDialog *MainWindow::CreateSettingsDialog() {
}
void MainWindow::EnsureSettingsDialogCreated() {
//if (settings_dialog_) return;
//settings_dialog_.reset(new SettingsDialog(app_));
@@ -2062,14 +2127,14 @@ void MainWindow::EnsureSettingsDialogCreated() {
// Allows custom notification preview
//connect(settings_dialog_.get(), SIGNAL(NotificationPreview(OSD::Behaviour,QString,QString)), SLOT(HandleNotificationPreview(OSD::Behaviour, QString, QString)));
}
void MainWindow::OpenSettingsDialog() {
EnsureSettingsDialogCreated();
settings_dialog_->show();
}
void MainWindow::OpenSettingsDialogAtPage(SettingsDialog::Page page) {
@@ -2125,7 +2190,7 @@ void MainWindow::ShowErrorDialog(const QString &message) {
}
void MainWindow::CheckFullRescanRevisions() {
int from = app_->database()->startup_schema_version();
int to = app_->database()->current_schema_version();
@@ -2152,22 +2217,14 @@ void MainWindow::CheckFullRescanRevisions() {
}
message += "</ul>" + tr("Would you like to run a full rescan right now?");
if(QMessageBox::question(this, tr("Collection rescan notice"), message, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
if (QMessageBox::question(this, tr("Collection rescan notice"), message, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
app_->collection()->FullScan();
}
}
}
void MainWindow::ShowQueueManager() {
//if (!queue_manager_) {
//queue_manager_.reset(new QueueManager);
//queue_manager_->SetPlaylistManager(app_->playlist_manager());
//}
queue_manager_->show();
}
void MainWindow::PlaylistViewSelectionModelChanged() {
connect(ui_->playlist->view()->selectionModel(),SIGNAL(currentChanged(QModelIndex, QModelIndex)), SLOT(PlaylistCurrentChanged(QModelIndex)));
}
@@ -2193,8 +2250,8 @@ bool MainWindow::winEvent(MSG *msg, long*) {
void MainWindow::Exit() {
SaveGeometry();
SavePlaybackStatus();
//settings_.setValue("show_sidebar", ui_->action_toggle_show_sidebar->isChecked());
if (app_->player()->engine()->is_fadeout_enabled()) {
// To shut down the application when fadeout will be finished
@@ -2202,7 +2259,7 @@ void MainWindow::Exit() {
if (app_->player()->GetState() == Engine::Playing) {
app_->player()->Stop();
hide();
tray_icon_->SetVisible(false);
if (tray_icon_) tray_icon_->SetVisible(false);
return; // Don't quit the application now: wait for the fadeout finished signal
}
}
@@ -2249,7 +2306,7 @@ void MainWindow::AutoCompleteTags() {
}
void MainWindow::AutoCompleteTagsAccepted() {
for (PlaylistItemPtr item : autocomplete_tag_items_) {
item->Reload();
}
@@ -2309,39 +2366,6 @@ void MainWindow::keyPressEvent(QKeyEvent *event) {
}
}
void MainWindow::FocusTidalSearchField() {
ui_->tabs->setCurrentWidget(tidal_search_view_);
tidal_search_view_->FocusSearchField();
}
void MainWindow::DoTidalSearch(const QString& query) {
FocusTidalSearchField();
tidal_search_view_->StartSearch(query);
}
void MainWindow::SearchForArtist() {
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(playlist_menu_index_.row()));
Song song = item->Metadata();
if (!song.albumartist().isEmpty()) {
DoTidalSearch(song.albumartist().simplified());
}
else if (!song.artist().isEmpty()) {
DoTidalSearch(song.artist().simplified());
}
}
void MainWindow::SearchForAlbum() {
PlaylistItemPtr item(app_->playlist_manager()->current()->item_at(playlist_menu_index_.row()));
Song song = item->Metadata();
if (!song.album().isEmpty()) {
DoTidalSearch(song.album().simplified());
}
}
void MainWindow::LoadCoverFromFile() {
album_cover_choice_controller_->LoadCoverFromFile(&song_);
}
@@ -2387,7 +2411,7 @@ void MainWindow::AlbumArtLoaded(const Song &song, const QString&, const QImage &
}
void MainWindow::GetCoverAutomatically() {
// Search for cover automatically?
bool search =
album_cover_choice_controller_->search_cover_auto_action()->isChecked() &&
@@ -2400,4 +2424,3 @@ void MainWindow::GetCoverAutomatically() {
if (search) album_cover_choice_controller_->SearchCoverAutomatically(song_);
}

View File

@@ -57,6 +57,8 @@
#include "playlist/playlistitem.h"
#include "settings/settingsdialog.h"
using std::unique_ptr;
class About;
class AlbumCoverManager;;
class Application;
@@ -76,7 +78,7 @@ class GlobalShortcuts;
class MimeData;
class OrganiseDialog;
class PlaylistListContainer;
class QueueManager;
class QueueView;
class Song;
class SystemTrayIcon;
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
@@ -88,7 +90,7 @@ class TranscodeDialog;
#endif
class Ui_MainWindow;
class Windows7ThumbBar;
class TidalSearchView;
class InternetSearchView;
class MainWindow : public QMainWindow, public PlatformInterface {
Q_OBJECT
@@ -250,7 +252,6 @@ signals:
void ShowTranscodeDialog();
#endif
void ShowErrorDialog(const QString& message);
void ShowQueueManager();
void EnsureSettingsDialogCreated();
void EnsureEditTagDialogCreated();
SettingsDialog *CreateSettingsDialog();
@@ -273,11 +274,6 @@ signals:
void ShowConsole();
void FocusTidalSearchField();
void DoTidalSearch(const QString& query);
void SearchForArtist();
void SearchForAlbum();
void LoadCoverFromFile();
void SaveCoverToFile();
void LoadCoverFromURL();
@@ -296,7 +292,7 @@ signals:
// creates the icon by painting the full one depending on the current position
QPixmap CreateOverlayedIcon(int position, int scrobble_point);
void GetCoverAutomatically();
private:
@@ -320,6 +316,7 @@ signals:
DeviceView *device_view_;
#endif
PlaylistListContainer *playlist_list_;
QueueView *queue_view_;
Lazy<SettingsDialog> settings_dialog_;
Lazy<AlbumCoverManager> cover_manager_;
@@ -331,7 +328,6 @@ signals:
#ifdef HAVE_GSTREAMER
Lazy<OrganiseDialog> organise_dialog_;
#endif
Lazy<QueueManager> queue_manager_;
#if defined(HAVE_GSTREAMER) && defined(HAVE_CHROMAPRINT)
std::unique_ptr<TagFetcher> tag_fetcher_;
@@ -341,7 +337,8 @@ signals:
PlaylistItemList autocomplete_tag_items_;
#endif
TidalSearchView *tidal_search_view_;
InternetSearchView *tidal_search_view_;
InternetSearchView *deezer_search_view_;
QAction *collection_show_all_;
QAction *collection_show_duplicates_;

View File

@@ -14,7 +14,7 @@
<string>Strawberry Music Player</string>
</property>
<property name="windowIcon">
<iconset resource="../../data/data.qrc">
<iconset resource="../../data/icons.qrc">
<normaloff>:/icons/64x64/strawberry.png</normaloff>:/icons/64x64/strawberry.png</iconset>
</property>
<widget class="QWidget" name="centralWidget">
@@ -435,7 +435,6 @@
<string>&amp;Tools</string>
</property>
<addaction name="action_cover_manager"/>
<addaction name="action_queue_manager"/>
<addaction name="action_equalizer"/>
<addaction name="separator"/>
<addaction name="action_update_collection"/>
@@ -553,7 +552,7 @@
</action>
<action name="action_about_strawberry">
<property name="icon">
<iconset resource="../../data/data.qrc">
<iconset resource="../../data/icons.qrc">
<normaloff>:/icons/64x64/strawberry.png</normaloff>:/icons/64x64/strawberry.png</iconset>
</property>
<property name="text">
@@ -674,11 +673,6 @@
<string>&amp;Update changed collection folders</string>
</property>
</action>
<action name="action_queue_manager">
<property name="text">
<string>&amp;Queue Manager</string>
</property>
</action>
<action name="action_about_qt">
<property name="text">
<string>About &amp;Qt</string>
@@ -782,6 +776,7 @@
</customwidgets>
<resources>
<include location="../../data/data.qrc"/>
<include location="../../data/icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -453,7 +453,7 @@ bool MergedProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action
}
QModelIndex MergedProxyModel::FindSourceParent(const QModelIndex &proxy_index) const {
if (!proxy_index.isValid()) return QModelIndex();
QModelIndex source_index = mapToSource(proxy_index);
@@ -463,7 +463,7 @@ QModelIndex MergedProxyModel::FindSourceParent(const QModelIndex &proxy_index) c
}
bool MergedProxyModel::canFetchMore(const QModelIndex &parent) const {
QModelIndex source_index = mapToSource(parent);
if (!source_index.isValid())
@@ -473,7 +473,7 @@ bool MergedProxyModel::canFetchMore(const QModelIndex &parent) const {
}
void MergedProxyModel::fetchMore(const QModelIndex &parent) {
QModelIndex source_index = mapToSource(parent);
if (!source_index.isValid())

View File

@@ -60,7 +60,7 @@
# include "dbus/metatypes.h"
#endif
#include "tidal/tidalsearch.h"
#include "internet/internetsearch.h"
void RegisterMetaTypes() {
@@ -115,7 +115,7 @@ void RegisterMetaTypes() {
#endif
#endif
qRegisterMetaType<TidalSearch::ResultList>("TidalSearch::ResultList");
qRegisterMetaType<TidalSearch::Result>("TidalSearch::Result");
qRegisterMetaType<InternetSearch::ResultList>("InternetSearch::ResultList");
qRegisterMetaType<InternetSearch::Result>("InternetSearch::Result");
}

View File

@@ -52,7 +52,7 @@ class MimeData : public QMimeData {
// If this is set then the items are added to the queue after being inserted.
bool enqueue_now_;
// If this is set then the items are added to the beginning of the queue after being inserted.
bool enqueue_next_now_;

View File

@@ -121,7 +121,7 @@ Mpris2::Mpris2(Application *app, QObject *parent) : QObject(parent), app_(app) {
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)), SLOT(CurrentSongChanged(Song)));
connect(app_->playlist_manager(), SIGNAL(PlaylistChanged(Playlist*)), SLOT(PlaylistChanged(Playlist*)));
connect(app_->playlist_manager(), SIGNAL(CurrentChanged(Playlist*)), SLOT(PlaylistCollectionChanged(Playlist*)));
}
// when PlaylistManager gets it ready, we connect PlaylistSequence with this

View File

@@ -59,6 +59,9 @@
#ifdef HAVE_VLC
# include "engine/vlcengine.h"
#endif
#ifdef HAVE_DEEZER
# include "engine/deezerengine.h"
#endif
#include "collection/collectionbackend.h"
#include "playlist/playlist.h"
@@ -68,8 +71,11 @@
#include "equalizer/equalizer.h"
#include "analyzer/analyzercontainer.h"
#include "settings/backendsettingspage.h"
#include "settings/playbacksettingspage.h"
#include "settings/behavioursettingspage.h"
#include "settings/playlistsettingspage.h"
#include "internet/internetservices.h"
#include "internet/internetservice.h"
using std::shared_ptr;
@@ -81,6 +87,8 @@ Player::Player(Application *app, QObject *parent)
nb_errors_received_(0),
volume_before_mute_(50),
last_pressed_previous_(QDateTime::currentDateTime()),
continue_on_error_(false),
greyout_(true),
menu_previousmode_(PreviousBehaviour_DontRestart),
seek_step_sec_(10) {
@@ -101,9 +109,9 @@ Player::~Player() {
settings_.endGroup();
}
void Player::CreateEngine(Engine::EngineType enginetype) {
Engine::EngineType Player::CreateEngine(Engine::EngineType enginetype) {
Engine::EngineType use_enginetype = Engine::None;
Engine::EngineType use_enginetype(Engine::None);
for (int i = 0 ; use_enginetype == Engine::None ; i++) {
switch(enginetype) {
@@ -131,6 +139,15 @@ void Player::CreateEngine(Engine::EngineType enginetype) {
use_enginetype=Engine::Phonon;
engine_.reset(new PhononEngine(app_->task_manager()));
break;
#endif
#ifdef HAVE_DEEZER
case Engine::Deezer:{
use_enginetype=Engine::Deezer;
DeezerEngine *deezerengine = new DeezerEngine(app_->task_manager());
connect(this, SIGNAL(Authenticated()), deezerengine, SLOT(LoadAccessToken()));
engine_.reset(deezerengine);
break;
}
#endif
default:
if (i > 0) { qFatal("No engine available!"); }
@@ -144,7 +161,7 @@ void Player::CreateEngine(Engine::EngineType enginetype) {
s.beginGroup(BackendSettingsPage::kSettingsGroup);
s.setValue("engine", EngineName(use_enginetype));
s.setValue("output", engine_->DefaultOutput());
s.setValue("device", QVariant(""));
s.setValue("device", QVariant());
s.endGroup();
}
@@ -152,15 +169,18 @@ void Player::CreateEngine(Engine::EngineType enginetype) {
qFatal("Failed to create engine!");
}
return use_enginetype;
}
void Player::Init() {
if (!engine_->Init()) { qFatal("Error initialising audio engine"); }
analyzer_->SetEngine(engine_.get());
connect(engine_.get(), SIGNAL(Error(QString)), SIGNAL(Error(QString)));
connect(engine_.get(), SIGNAL(FatalError()), SLOT(FatalError()));
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)), SLOT(ValidSongRequested(QUrl)));
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)), SLOT(InvalidSongRequested(QUrl)));
connect(engine_.get(), SIGNAL(StateChanged(Engine::State)), SLOT(EngineStateChanged(Engine::State)));
@@ -190,6 +210,8 @@ void Player::ReloadSettings() {
QSettings s;
s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
continue_on_error_ = s.value("continue_on_error", false).toBool();
greyout_ = s.value("greyout_songs_play", true).toBool();
menu_previousmode_ = PreviousBehaviour(s.value("menu_previousmode", PreviousBehaviour_DontRestart).toInt());
s.endGroup();
@@ -272,7 +294,7 @@ void Player::NextInternal(Engine::TrackChangeFlags change) {
if (app_->playlist_manager()->active()->current_item()) {
const QUrl url = app_->playlist_manager()->active()->current_item()->Url();
if (url_handlers_.contains(url.scheme())) {
if (url_handlers_.contains(url.scheme()) && !(engine_->type() == Engine::Deezer && url.scheme() == "dzmedia")) {
// The next track is already being loaded
if (url == loading_async_) return;
@@ -283,6 +305,7 @@ void Player::NextInternal(Engine::TrackChangeFlags change) {
}
NextItem(change);
}
void Player::NextItem(Engine::TrackChangeFlags change) {
@@ -332,6 +355,7 @@ bool Player::HandleStopAfter() {
return true;
}
return false;
}
void Player::TrackEnded() {
@@ -343,10 +367,11 @@ void Player::TrackEnded() {
}
NextInternal(Engine::Auto);
}
void Player::PlayPause() {
switch (engine_->state()) {
case Engine::Paused:
engine_->Unpause();
@@ -476,10 +501,10 @@ int Player::GetVolume() const { return engine_->volume(); }
void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle) {
if (change == Engine::Manual && engine_->position_nanosec() != engine_->length_nanosec()) {
if (current_item_ && change == Engine::Manual && engine_->position_nanosec() != engine_->length_nanosec()) {
emit TrackSkipped(current_item_);
const QUrl &url = current_item_->Url();
if (url_handlers_.contains(url.scheme())) {
if (url_handlers_.contains(url.scheme()) && !(engine_->type() == Engine::Deezer && url.scheme() == "dzmedia")) {
url_handlers_[url.scheme()]->TrackSkipped();
}
}
@@ -490,7 +515,6 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle)
if (reshuffle) app_->playlist_manager()->active()->ReshuffleIndices();
app_->playlist_manager()->active()->set_current_row(index);
if (app_->playlist_manager()->active()->current_row() == -1) {
// Maybe index didn't exist in the playlist.
return;
@@ -499,7 +523,7 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle)
current_item_ = app_->playlist_manager()->active()->current_item();
const QUrl url = current_item_->Url();
if (url_handlers_.contains(url.scheme())) {
if (url_handlers_.contains(url.scheme()) && !(engine_->type() == Engine::Deezer && url.scheme() == "dzmedia")) {
// It's already loading
if (url == loading_async_) return;
@@ -520,7 +544,7 @@ void Player::CurrentMetadataChanged(const Song &metadata) {
}
void Player::SeekTo(int seconds) {
const qint64 length_nanosec = engine_->length_nanosec();
// If the length is 0 then either there is no song playing, or the song isn't seekable.
@@ -631,7 +655,7 @@ void Player::TrackAboutToEnd() {
// We don't want to preload (and scrobble) the next item in the playlist if it's just going to be stopped again immediately after.
if (app_->playlist_manager()->active()->current_item()) {
const QUrl url = app_->playlist_manager()->active()->current_item()->Url();
if (url_handlers_.contains(url.scheme())) {
if (url_handlers_.contains(url.scheme()) && !(engine_->type() == Engine::Deezer && url.scheme() == "dzmedia")) {
url_handlers_[url.scheme()]->TrackAboutToEnd();
return;
}
@@ -664,7 +688,7 @@ void Player::TrackAboutToEnd() {
QUrl url = next_item->Url();
// Get the actual track URL rather than the stream URL.
if (url_handlers_.contains(url.scheme())) {
if (url_handlers_.contains(url.scheme()) && !(engine_->type() == Engine::Deezer && url.scheme() == "dzmedia")) {
UrlHandler::LoadResult result = url_handlers_[url.scheme()]->LoadNext(url);
switch (result.type_) {
case UrlHandler::LoadResult::NoMoreTracks:
@@ -685,17 +709,25 @@ void Player::TrackAboutToEnd() {
void Player::IntroPointReached() { NextInternal(Engine::Intro); }
void Player::FatalError() {
nb_errors_received_ = 0;
Stop();
}
void Player::ValidSongRequested(const QUrl &url) {
emit SongChangeRequestProcessed(url, true);
}
void Player::InvalidSongRequested(const QUrl &url) {
// first send the notification to others...
emit SongChangeRequestProcessed(url, false);
// ... and now when our listeners have completed their processing of the current item we can change
// the current item by skipping to the next song
//NextItem(Engine::Auto);
if (greyout_) emit SongChangeRequestProcessed(url, false);
if (!continue_on_error_) {
FatalError();
return;
}
NextItem(Engine::Auto);
}
@@ -712,7 +744,7 @@ void Player::RegisterUrlHandler(UrlHandler *handler) {
url_handlers_.insert(scheme, handler);
connect(handler, SIGNAL(destroyed(QObject*)), SLOT(UrlHandlerDestroyed(QObject*)));
connect(handler, SIGNAL(AsyncLoadComplete(UrlHandler::LoadResult)), SLOT(HandleLoadResult(UrlHandler::LoadResult)));
}
void Player::UnregisterUrlHandler(UrlHandler *handler) {
@@ -749,3 +781,7 @@ void Player::UrlHandlerDestroyed(QObject *object) {
}
}
void Player::HandleAuthentication() {
emit Authenticated();
}

View File

@@ -114,6 +114,9 @@ class PlayerInterface : public QObject {
// The toggle parameter is true when user requests to toggle visibility for Pretty OSD
void ForceShowOSD(Song, bool toogle);
void Authenticated();
};
class Player : public PlayerInterface {
@@ -131,7 +134,7 @@ class Player : public PlayerInterface {
PreviousBehaviour_Restart = 2
};
void CreateEngine(Engine::EngineType enginetype);
Engine::EngineType CreateEngine(Engine::EngineType enginetype);
void Init();
EngineBase *engine() const { return engine_.get(); }
@@ -177,6 +180,8 @@ class Player : public PlayerInterface {
void ShowOSD();
void TogglePrettyOSD();
void HandleAuthentication();
private slots:
void EngineStateChanged(Engine::State);
void EngineMetadataReceived(const Engine::SimpleMetaBundle &bundle);
@@ -188,6 +193,7 @@ class Player : public PlayerInterface {
void NextInternal(Engine::TrackChangeFlags);
void FatalError();
void ValidSongRequested(const QUrl&);
void InvalidSongRequested(const QUrl&);
@@ -214,10 +220,11 @@ class Player : public PlayerInterface {
QMap<QString, UrlHandler*> url_handlers_;
QUrl loading_async_;
int volume_before_mute_;
QDateTime last_pressed_previous_;
bool continue_on_error_;
bool greyout_;
PreviousBehaviour menu_previousmode_;
int seek_step_sec_;

View File

@@ -44,23 +44,12 @@ QtSystemTrayIcon::QtSystemTrayIcon(QObject *parent)
action_play_pause_(nullptr),
action_stop_(nullptr),
action_stop_after_this_track_(nullptr),
action_mute_(nullptr)
{
action_mute_(nullptr) {
QIcon theme_icon = IconLoader::Load("strawberry", 48);
QIcon theme_icon_grey = IconLoader::Load("strawberry-grey", 48);
QIcon icon(":/icons/48x48/strawberry.png");
if (theme_icon.isNull() || theme_icon_grey.isNull()) {
// Load the default icon
QIcon icon(":/icons/48x48/strawberry.png");
normal_icon_ = icon.pixmap(48, QIcon::Normal);
grey_icon_ = icon.pixmap(48, QIcon::Disabled);
}
else {
// Use the icons from the theme
normal_icon_ = theme_icon.pixmap(48);
grey_icon_ = theme_icon_grey.pixmap(48);
}
normal_icon_ = icon.pixmap(48, QIcon::Normal);
grey_icon_ = icon.pixmap(48, QIcon::Disabled);
tray_->setIcon(normal_icon_);
tray_->installEventFilter(this);
@@ -79,7 +68,7 @@ QtSystemTrayIcon::~QtSystemTrayIcon() {
}
bool QtSystemTrayIcon::eventFilter(QObject *object, QEvent *event) {
if (QObject::eventFilter(object, event)) return true;
if (object != tray_) return false;
@@ -136,7 +125,7 @@ void QtSystemTrayIcon::SetupMenu(QAction *previous, QAction *play, QAction *stop
}
void QtSystemTrayIcon::Clicked(QSystemTrayIcon::ActivationReason reason) {
switch (reason) {
case QSystemTrayIcon::DoubleClick:
case QSystemTrayIcon::Trigger:

View File

@@ -1,5 +1,5 @@
/*
* Strawberry Music Player
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*

View File

@@ -21,6 +21,8 @@
#include "config.h"
#include <algorithm>
#include <taglib/fileref.h>
#include <taglib/id3v1genres.h>
@@ -66,6 +68,8 @@
#include "covermanager/albumcoverloader.h"
#include "tagreadermessages.pb.h"
using std::sort;
const QStringList Song::kColumns = QStringList() << "title"
<< "album"
<< "artist"
@@ -298,7 +302,7 @@ uint Song::mtime() const { return d->mtime_; }
uint Song::ctime() const { return d->ctime_; }
int Song::filesize() const { return d->filesize_; }
Song::FileType Song::filetype() const { return d->filetype_; }
bool Song::is_stream() const { return d->source_ == Source_Stream || d->source_ == Source_Tidal; }
bool Song::is_stream() const { return d->source_ == Source_Stream || d->source_ == Source_Tidal || d->source_ == Source_Deezer; }
bool Song::is_cdda() const { return d->source_ == Source_CDDA; }
bool Song::is_collection_song() const {
return !is_cdda() && !is_stream() && id() != -1;
@@ -384,6 +388,7 @@ QString Song::TextForSource(Source source) {
case Song::Source_Device: return QObject::tr("Device");
case Song::Source_Stream: return QObject::tr("Stream");
case Song::Source_Tidal: return QObject::tr("Tidal");
case Song::Source_Deezer: return QObject::tr("Deezer");
default: return QObject::tr("Unknown");
}
@@ -398,6 +403,7 @@ QIcon Song::IconForSource(Source source) {
case Song::Source_Device: return IconLoader::Load("device");
case Song::Source_Stream: return IconLoader::Load("applications-internet");
case Song::Source_Tidal: return IconLoader::Load("tidal");
case Song::Source_Deezer: return IconLoader::Load("deezer");
default: return IconLoader::Load("edit-delete");
}
@@ -421,6 +427,7 @@ QString Song::TextForFiletype(FileType filetype) {
case Song::FileType_TrueAudio: return QObject::tr("TrueAudio");
case Song::FileType_DSF: return QObject::tr("DSF");
case Song::FileType_DSDIFF: return QObject::tr("DSDIFF");
case Song::FileType_PCM: return QObject::tr("PCM");
case Song::FileType_CDDA: return QObject::tr("CDDA");
case Song::FileType_Stream: return QObject::tr("Stream");
case Song::FileType_Unknown:
@@ -447,6 +454,7 @@ QIcon Song::IconForFiletype(FileType filetype) {
case Song::FileType_TrueAudio: return IconLoader::Load("trueaudio");
case Song::FileType_DSF: return IconLoader::Load("dsf");
case Song::FileType_DSDIFF: return IconLoader::Load("dsd");
case Song::FileType_PCM: return IconLoader::Load("pcm");
case Song::FileType_CDDA: return IconLoader::Load("cd");
case Song::FileType_Stream: return IconLoader::Load("applications-internet");
case Song::FileType_Unknown:
@@ -462,6 +470,8 @@ bool Song::IsFileLossless() const {
case Song::FileType_OggFlac:
case Song::FileType_WavPack:
case Song::FileType_AIFF:
case Song::FileType_DSF:
case Song::FileType_DSDIFF:
return true;
default:
return false;
@@ -493,7 +503,7 @@ int CompareSongsName(const Song &song1, const Song &song2) {
void Song::SortSongsListAlphabetically(SongList *songs) {
Q_ASSERT(songs);
qSort(songs->begin(), songs->end(), CompareSongsName);
std::sort(songs->begin(), songs->end(), CompareSongsName);
}
void Song::Init(const QString &title, const QString &artist, const QString &album, qint64 length_nanosec) {
@@ -996,12 +1006,14 @@ void Song::MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle) {
if (!bundle.album.isEmpty()) d->album_ = bundle.album;
if (!bundle.comment.isEmpty()) d->comment_ = bundle.comment;
if (!bundle.genre.isEmpty()) d->genre_ = bundle.genre;
if (bundle.bitrate > 0) d->bitrate_ = bundle.bitrate;
if (bundle.samplerate > 0) d->samplerate_ = bundle.samplerate;
if (bundle.bitdepth > 0) d->samplerate_ = bundle.bitdepth;
if (bundle.length > 0) set_length_nanosec(bundle.length);
if (bundle.year > 0) d->year_ = bundle.year;
if (bundle.tracknr > 0) d->track_ = bundle.tracknr;
if (bundle.filetype != FileType_Unknown) d->filetype_ = bundle.filetype;
if (bundle.samplerate > 0) d->samplerate_ = bundle.samplerate;
if (bundle.bitdepth > 0) d->samplerate_ = bundle.bitdepth;
if (bundle.bitrate > 0) d->bitrate_ = bundle.bitrate;
if (!bundle.lyrics.isEmpty()) d->lyrics_ = bundle.lyrics;
}
@@ -1051,7 +1063,7 @@ void Song::BindToQuery(QSqlQuery *query) const {
query->bindValue(":mtime", notnullintval(d->mtime_));
query->bindValue(":ctime", notnullintval(d->ctime_));
query->bindValue(":unavailable", d->unavailable_ ? 1 : 0);
query->bindValue(":playcount", d->playcount_);
query->bindValue(":skipcount", d->skipcount_);
query->bindValue(":lastplayed", intval(d->lastplayed_));
@@ -1060,13 +1072,13 @@ void Song::BindToQuery(QSqlQuery *query) const {
query->bindValue(":compilation_on", d->compilation_on_ ? 1 : 0);
query->bindValue(":compilation_off", d->compilation_off_ ? 1 : 0);
query->bindValue(":compilation_effective", is_compilation() ? 1 : 0);
query->bindValue(":art_automatic", d->art_automatic_);
query->bindValue(":art_manual", d->art_manual_);
query->bindValue(":effective_albumartist", this->effective_albumartist());
query->bindValue(":effective_originalyear", intval(this->effective_originalyear()));
query->bindValue(":cue_path", d->cue_path_);
#undef intval

View File

@@ -82,7 +82,7 @@ class Song {
static const QString kManuallyUnsetCover;
static const QString kEmbeddedCover;
static const QRegExp kCoverRemoveDisc;
static QString JoinSpec(const QString &table);
@@ -98,6 +98,7 @@ class Song {
Source_Device = 4,
Source_Stream = 5,
Source_Tidal = 6,
Source_Deezer = 7,
};
enum FileType {
@@ -117,6 +118,7 @@ class Song {
FileType_TrueAudio = 13,
FileType_DSF = 14,
FileType_DSDIFF = 15,
FileType_PCM = 16,
FileType_CDDA = 90,
FileType_Stream = 91,
};
@@ -214,18 +216,18 @@ class Song {
const QString &art_automatic() const;
const QString &art_manual() const;
const QString &cue_path() const;
bool has_cue() const;
const QString &effective_album() const;
int effective_originalyear() const;
const QString &effective_albumartist() const;
bool is_collection_song() const;
bool is_stream() const;
bool is_cdda() const;
// Playlist views are special because you don't want to fill in album artists automatically for compilations, but you do for normal albums:
const QString &playlist_albumartist() const;
@@ -248,7 +250,7 @@ class Song {
QString PrettyYear() const;
QString TitleWithCompilationArtist() const;
QString SampleRateBitDepthToText() const;
// Setters
@@ -292,7 +294,7 @@ class Song {
void set_mtime(int v);
void set_ctime(int v);
void set_unavailable(bool v);
void set_playcount(int v);
void set_skipcount(int v);
void set_lastplayed(int v);
@@ -300,12 +302,12 @@ class Song {
void set_compilation_detected(bool v);
void set_compilation_on(bool v);
void set_compilation_off(bool v);
void set_art_automatic(const QString &v);
void set_art_manual(const QString &v);
void set_cue_path(const QString &v);
void set_image(const QImage &i);
// Comparison functions

View File

@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <memory>
#include <algorithm>
#ifdef HAVE_GSTREAMER
# include <gst/gst.h>
@@ -65,6 +66,9 @@
#endif
using std::placeholders::_1;
using std::bind;
using std::stable_sort;
using std::shared_ptr;
QSet<QString> SongLoader::sRawUriSchemes;
const int SongLoader::kDefaultTimeout = 5000;
@@ -96,7 +100,7 @@ SongLoader::SongLoader(CollectionBackendInterface *collection, const Player *pla
timeout_timer_->setSingleShot(true);
connect(timeout_timer_, SIGNAL(timeout()), SLOT(Timeout()));
}
SongLoader::~SongLoader() {
@@ -323,7 +327,7 @@ void SongLoader::LoadLocalDirectory(const QString &filename) {
LoadLocalPartial(it.next());
}
qStableSort(songs_.begin(), songs_.end(), CompareSongs);
std::stable_sort(songs_.begin(), songs_.end(), CompareSongs);
// Load the first song:
// all songs will be loaded async, but we want the first one in our list to be fully loaded,
@@ -520,7 +524,7 @@ GstBusSyncReply SongLoader::BusCallbackSync(GstBus *, GstMessage *msg, gpointer
#ifdef HAVE_GSTREAMER
void SongLoader::ErrorMessageReceived(GstMessage *msg) {
if (state_ == Finished) return;
GError *error;

View File

@@ -44,6 +44,8 @@ void StyleSheetLoader::SetStyleSheet(QWidget *widget, const QString &filename) {
void StyleSheetLoader::UpdateStyleSheet(QWidget *widget) {
if (!widget || !filenames_.contains(widget)) return;
QString filename(filenames_[widget]);
// Load the file
@@ -88,9 +90,10 @@ void StyleSheetLoader::UpdateStyleSheet(QWidget *widget) {
ReplaceColor(&contents, "LinkVisited", p, QPalette::LinkVisited);
#ifdef Q_OS_MACOS
contents.replace("darwin", "*");
contents.replace("macos", "*");
#endif
widget->setStyleSheet("");
widget->setStyleSheet(contents);
}

View File

@@ -23,6 +23,7 @@
#include <cmath>
#include <QObject>
#include <QSystemTrayIcon>
#include <QPixmap>
#include <QPainter>
#include <QPoint>
@@ -105,10 +106,11 @@ void SystemTrayIcon::SetStopped() {
UpdateIcon();
}
SystemTrayIcon* SystemTrayIcon::CreateSystemTrayIcon(QObject *parent) {
SystemTrayIcon *SystemTrayIcon::CreateSystemTrayIcon(QObject *parent) {
#ifdef Q_OS_MACOS
return new MacSystemTrayIcon(parent);
#else
return new QtSystemTrayIcon(parent);
if (QSystemTrayIcon::isSystemTrayAvailable()) return new QtSystemTrayIcon(parent);
else return nullptr;
#endif
}

View File

@@ -55,7 +55,7 @@ void TagReaderClient::WorkerFailedToStart() {
}
TagReaderReply *TagReaderClient::ReadFile(const QString &filename) {
pb::tagreader::Message message;
pb::tagreader::ReadFileRequest *req = message.mutable_read_file_request();
@@ -78,7 +78,7 @@ TagReaderReply *TagReaderClient::SaveFile(const QString &filename, const Song &m
}
TagReaderReply *TagReaderClient::IsMediaFile(const QString &filename) {
pb::tagreader::Message message;
pb::tagreader::IsMediaFileRequest *req = message.mutable_is_media_file_request();
@@ -89,7 +89,7 @@ TagReaderReply *TagReaderClient::IsMediaFile(const QString &filename) {
}
TagReaderReply *TagReaderClient::LoadEmbeddedArt(const QString &filename) {
pb::tagreader::Message message;
pb::tagreader::LoadEmbeddedArtRequest *req = message.mutable_load_embedded_art_request();
@@ -100,7 +100,7 @@ TagReaderReply *TagReaderClient::LoadEmbeddedArt(const QString &filename) {
}
void TagReaderClient::ReadFileBlocking(const QString &filename, Song *song) {
Q_ASSERT(QThread::currentThread() != thread());
TagReaderReply *reply = ReadFile(filename);
@@ -112,7 +112,7 @@ void TagReaderClient::ReadFileBlocking(const QString &filename, Song *song) {
}
bool TagReaderClient::SaveFileBlocking(const QString &filename, const Song &metadata) {
Q_ASSERT(QThread::currentThread() != thread());
bool ret = false;
@@ -128,7 +128,7 @@ bool TagReaderClient::SaveFileBlocking(const QString &filename, const Song &meta
}
bool TagReaderClient::IsMediaFileBlocking(const QString &filename) {
Q_ASSERT(QThread::currentThread() != thread());
bool ret = false;
@@ -144,7 +144,7 @@ bool TagReaderClient::IsMediaFileBlocking(const QString &filename) {
}
QImage TagReaderClient::LoadEmbeddedArtBlocking(const QString &filename) {
Q_ASSERT(QThread::currentThread() != thread());
QImage ret;

View File

@@ -298,7 +298,7 @@ bool RemoveRecursive(const QString &path) {
}
bool CopyRecursive(const QString &source, const QString &destination) {
// Make the destination directory
QString dir_name = source.section('/', -1, -1);
QString dest_path = destination + "/" + dir_name;
@@ -323,7 +323,7 @@ bool CopyRecursive(const QString &source, const QString &destination) {
}
bool Copy(QIODevice *source, QIODevice *destination) {
if (!source->open(QIODevice::ReadOnly)) return false;
if (!destination->open(QIODevice::WriteOnly)) return false;
@@ -493,7 +493,7 @@ QByteArray Sha1CoverHash(const QString &artist, const QString &album) {
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(artist.toLower().toUtf8().constData());
hash.addData(album.toLower().toUtf8().constData());
//qLog(Debug) << artist << album << hash.result();
return hash.result();

View File

@@ -143,7 +143,7 @@ void AlbumCoverChoiceController::SaveCoverToFile(const Song &song, const QImage
}
QString AlbumCoverChoiceController::GetInitialPathForFileDialog(const Song &song, const QString &filename) {
// Art automatic is first to show user which cover the album may be using now;
// The song is using it if there's no manual path but we cannot use manual path here because it can contain cached paths
if (!song.art_automatic().isEmpty() && !song.has_embedded_cover()) {
@@ -162,7 +162,7 @@ QString AlbumCoverChoiceController::GetInitialPathForFileDialog(const Song &song
}
QString AlbumCoverChoiceController::LoadCoverFromURL(Song *song) {
if (!cover_from_url_dialog_) { cover_from_url_dialog_ = new CoverFromURLDialog(this); }
QImage image = cover_from_url_dialog_->Exec();
@@ -174,7 +174,7 @@ QString AlbumCoverChoiceController::LoadCoverFromURL(Song *song) {
return cover;
}
else { return QString(); }
}
QString AlbumCoverChoiceController::SearchForCover(Song *song) {
@@ -192,7 +192,7 @@ QString AlbumCoverChoiceController::SearchForCover(Song *song) {
return cover;
}
else { return QString(); }
}
QString AlbumCoverChoiceController::UnsetCover(Song *song) {
@@ -217,7 +217,7 @@ void AlbumCoverChoiceController::ShowCover(const Song &song, const QImage image)
QUrl url_automatic(song.art_automatic());
if (url_manual.isLocalFile() || url_automatic.isLocalFile()) {
QPixmap pixmap = AlbumCoverLoader::TryLoadPixmap(song.art_automatic(), song.art_manual(), song.url().toLocalFile());
QPixmap pixmap = AlbumCoverLoader::TryLoadPixmap(song.art_automatic(), song.art_manual(), song.url().toLocalFile());
ShowCover(song, pixmap);
}
else if (!image.isNull()) ShowCover(song, QPixmap::fromImage(image));

View File

@@ -20,7 +20,7 @@
<string>Export covers</string>
</property>
<property name="windowIcon">
<iconset resource="../../data/data.qrc">
<iconset resource="../../data/icons.qrc">
<normaloff>:/icons/64x64/strawberry.png</normaloff>:/icons/64x64/strawberry.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -202,6 +202,7 @@
</widget>
<resources>
<include location="../../data/data.qrc"/>
<include location="../../data/icons.qrc"/>
</resources>
<connections>
<connection>

View File

@@ -112,7 +112,7 @@ signals:
QHash<quint64, AlbumCoverFetcherSearch*> active_requests_;
QTimer *request_starter_;
};
#endif // ALBUMCOVERFETCHER_H

View File

@@ -43,6 +43,8 @@
#include "coverprovider.h"
#include "coverproviders.h"
using std::stable_sort;
const int AlbumCoverFetcherSearch::kSearchTimeoutMs = 12000;
const int AlbumCoverFetcherSearch::kImageLoadTimeoutMs = 3000;
const int AlbumCoverFetcherSearch::kTargetSize = 500;
@@ -148,7 +150,7 @@ void AlbumCoverFetcherSearch::AllProvidersFinished() {
// Now we have to load some images and figure out which one is the best.
// We'll sort the list of results by category, then load the first few images from each category and use some heuristics to score them.
// If no images are good enough we'll keep loading more images until we find one that is or we run out of results.
qStableSort(results_.begin(), results_.end(), CompareProviders);
std::stable_sort(results_.begin(), results_.end(), CompareProviders);
FetchMoreImages();
}

View File

@@ -102,7 +102,7 @@ class AlbumCoverFetcherSearch : public QObject {
QNetworkAccessManager *network_;
bool cancel_requested_;
};
#endif // ALBUMCOVERFETCHERSEARCH_H

View File

@@ -56,7 +56,7 @@ QString AlbumCoverLoader::ImageCacheDir() {
}
void AlbumCoverLoader::CancelTask(quint64 id) {
QMutexLocker l(&mutex_);
for (QQueue<Task>::iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
if (it->id == id) {
@@ -67,7 +67,7 @@ void AlbumCoverLoader::CancelTask(quint64 id) {
}
void AlbumCoverLoader::CancelTasks(const QSet<quint64> &ids) {
QMutexLocker l(&mutex_);
for (QQueue<Task>::iterator it = tasks_.begin(); it != tasks_.end();) {
if (ids.contains(it->id)) {
@@ -226,7 +226,7 @@ void AlbumCoverLoader::RemoteFetchFinished(QNetworkReply *reply) {
}
NextState(&task);
}
QImage AlbumCoverLoader::ScaleAndPad(const AlbumCoverLoaderOptions &options, const QImage &image) {

View File

@@ -21,6 +21,7 @@
#include "config.h"
#include <memory>
#include <algorithm>
#include <QtGlobal>
#include <QObject>
@@ -81,6 +82,8 @@
#include "ui_albumcovermanager.h"
using std::stable_sort;
const char *AlbumCoverManager::kSettingsGroup = "CoverManager";
AlbumCoverManager::AlbumCoverManager(Application *app, CollectionBackend *collection_backend, QWidget *parent, QNetworkAccessManager *network)
@@ -266,7 +269,7 @@ void AlbumCoverManager::CancelRequests() {
abort_progress_->hide();
statusBar()->clearMessage();
EnableCoversButtons();
}
static bool CompareNocase(const QString &left, const QString &right) {
@@ -286,13 +289,13 @@ void AlbumCoverManager::Reset() {
new QListWidgetItem(artist_icon_, tr("Various artists"), ui_->artists, Various_Artists);
QStringList artists(collection_backend_->GetAllArtistsWithAlbums());
qStableSort(artists.begin(), artists.end(), CompareNocase);
std::stable_sort(artists.begin(), artists.end(), CompareNocase);
for (const QString &artist : artists) {
if (artist.isEmpty()) continue;
new QListWidgetItem(artist_icon_, artist, ui_->artists, Specific_Artist);
}
}
void AlbumCoverManager::EnableCoversButtons() {
@@ -326,7 +329,7 @@ void AlbumCoverManager::ArtistChanged(QListWidgetItem *current) {
}
// Sort by album name. The list is already sorted by sqlite but it was done case sensitively.
qStableSort(albums.begin(), albums.end(), CompareAlbumNameNocase);
std::stable_sort(albums.begin(), albums.end(), CompareAlbumNameNocase);
for (const CollectionBackend::Album &info : albums) {
// Don't show songs without an album, obviously
@@ -375,7 +378,7 @@ void AlbumCoverManager::CoverImageLoaded(quint64 id, const QImage &image) {
}
void AlbumCoverManager::UpdateFilter() {
const QString filter = ui_->filter->text().toLower();
const bool hide_with_covers = filter_without_covers_->isChecked();
const bool hide_without_covers = filter_with_covers_->isChecked();
@@ -479,7 +482,7 @@ void AlbumCoverManager::AlbumCoverFetched(quint64 id, const QImage &image, const
}
void AlbumCoverManager::UpdateStatusText() {
QString message = tr("Got %1 covers out of %2 (%3 failed)")
.arg(fetch_statistics_.chosen_images_)
.arg(jobs_)
@@ -540,7 +543,7 @@ Song AlbumCoverManager::GetFirstSelectedAsSong() {
}
Song AlbumCoverManager::ItemAsSong(QListWidgetItem *item) {
Song result;
QString title = item->data(Role_AlbumName).toString();
@@ -569,7 +572,7 @@ Song AlbumCoverManager::ItemAsSong(QListWidgetItem *item) {
}
void AlbumCoverManager::ShowCover() {
Song song = GetSingleSelectionAsSong();
if (!song.is_valid()) return;
@@ -592,15 +595,15 @@ void AlbumCoverManager::FetchSingleCover() {
}
void AlbumCoverManager::UpdateCoverInList(QListWidgetItem *item, const QString &cover) {
quint64 id = app_->album_cover_loader()->LoadImageAsync(cover_loader_options_, QString(), cover);
item->setData(Role_PathManual, cover);
cover_loading_tasks_[id] = item;
}
void AlbumCoverManager::LoadCoverFromFile() {
Song song = GetSingleSelectionAsSong();
if (!song.is_valid()) return;
@@ -611,7 +614,7 @@ void AlbumCoverManager::LoadCoverFromFile() {
if (!cover.isEmpty()) {
UpdateCoverInList(item, cover);
}
}
void AlbumCoverManager::SaveCoverToFile() {
@@ -631,14 +634,14 @@ void AlbumCoverManager::SaveCoverToFile() {
}
else if(!song.art_automatic().isEmpty() && QFile::exists(song.art_automatic())) {
image = QImage(song.art_automatic());
}
}
else {
image = no_cover_image_;
}
}
album_cover_choice_controller_->SaveCoverToFile(song, image);
}
void AlbumCoverManager::LoadCoverFromURL() {
@@ -676,11 +679,11 @@ void AlbumCoverManager::SearchForCover() {
UpdateCoverInList(current, cover);
}
}
void AlbumCoverManager::UnsetCover() {
Song song = GetFirstSelectedAsSong();
if (!song.is_valid()) return;
@@ -699,11 +702,11 @@ void AlbumCoverManager::UnsetCover() {
album_cover_choice_controller_->SaveCover(&current_song, cover);
}
}
}
SongList AlbumCoverManager::GetSongsInAlbum(const QModelIndex &index) const {
SongList ret;
CollectionQuery q;
@@ -731,7 +734,7 @@ SongList AlbumCoverManager::GetSongsInAlbum(const QModelIndex &index) const {
ret << song;
}
return ret;
}
SongList AlbumCoverManager::GetSongsInAlbums(const QModelIndexList &indexes) const {
@@ -741,7 +744,7 @@ SongList AlbumCoverManager::GetSongsInAlbums(const QModelIndexList &indexes) con
ret << GetSongsInAlbum(index);
}
return ret;
}
SongMimeData *AlbumCoverManager::GetMimeDataForAlbums(const QModelIndexList &indexes) const {
@@ -781,7 +784,7 @@ void AlbumCoverManager::LoadSelectedToPlaylist() {
}
void AlbumCoverManager::SaveAndSetCover(QListWidgetItem *item, const QImage &image) {
const QString artist = item->data(Role_ArtistName).toString();
const QString albumartist = item->data(Role_AlbumArtistName).toString();
const QString album = item->data(Role_AlbumName).toString();
@@ -799,7 +802,7 @@ void AlbumCoverManager::SaveAndSetCover(QListWidgetItem *item, const QImage &ima
}
void AlbumCoverManager::ExportCovers() {
AlbumCoverExport::DialogResult result = cover_export_->Exec();
if (result.cancelled_) {
@@ -838,7 +841,7 @@ void AlbumCoverManager::ExportCovers() {
}
void AlbumCoverManager::UpdateExportStatus(int exported, int skipped, int max) {
progress_bar_->setValue(exported);
QString message = tr("Exported %1 covers out of %2 (%3 skipped)")

View File

@@ -14,7 +14,7 @@
<string>Cover Manager</string>
</property>
<property name="windowIcon">
<iconset resource="../../data/data.qrc">
<iconset resource="../../data/icons.qrc">
<normaloff>:/icons/64x64/strawberry.png</normaloff>:/icons/64x64/strawberry.png</iconset>
</property>
<widget class="QWidget" name="centralWidget">
@@ -297,6 +297,7 @@
</tabstops>
<resources>
<include location="../../data/data.qrc"/>
<include location="../../data/icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -55,13 +55,13 @@ const char *AmazonCoverProvider::kSecretAccessKeyB64 = "TjFZU3F2c2hJZDVtUGxKVW1K
AmazonCoverProvider::AmazonCoverProvider(QObject *parent) : CoverProvider("Amazon", true, parent), network_(new NetworkAccessManager(this)) {}
bool AmazonCoverProvider::StartSearch(const QString &artist, const QString &album, int id) {
typedef QPair<QString, QString> Arg;
typedef QList<Arg> ArgList;
typedef QPair<QByteArray, QByteArray> EncodedArg;
typedef QList<EncodedArg> EncodedArgList;
// Must be sorted by parameter name
ArgList args = ArgList()
<< Arg("AWSAccessKeyId", QByteArray::fromBase64(kAccessKeyB64))
@@ -108,9 +108,9 @@ void AmazonCoverProvider::QueryError(QNetworkReply::NetworkError error, QNetwork
}
void AmazonCoverProvider::QueryFinished(QNetworkReply *reply, int id) {
reply->deleteLater();
QString data(reply->readAll());
CoverSearchResults results;

Some files were not shown because too many files have changed in this diff Show More