1
0
mirror of https://github.com/strawberrymusicplayer/strawberry synced 2025-01-28 08:09:40 +01:00

Fix paths

- Use QStandardPaths
- Load settings in StatusView widget
- Update about
- Remove redundant code
- Temporary hide missing audiopanorama error as workaround for windows build
This commit is contained in:
Jonas Kvinge 2018-04-06 22:13:11 +02:00
parent 43bf7e3ca8
commit 917b9c39b8
21 changed files with 88 additions and 167 deletions

View File

@ -108,7 +108,6 @@ bool QtLocalPeer::isClient()
if (lockFile.isLocked())
return false;
//if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
if (!lockFile.lock(QtLockedFile::WriteLock, false))
return true;

View File

@ -49,8 +49,7 @@ Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
{
if (mutexname.isEmpty()) {
QFileInfo fi(*this);
mutexname = QString::fromLatin1(MUTEX_PREFIX)
+ fi.absoluteFilePath().toLower();
mutexname = QString::fromLatin1(MUTEX_PREFIX) + fi.absoluteFilePath().toLower();
}
QString mname(mutexname);
if (idx >= 0)
@ -151,8 +150,7 @@ bool QtLockedFile::lock(LockMode mode, bool block)
rmutexes.append(mutex);
}
if (rmutexes.size()) {
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
TRUE, block ? INFINITE : 0);
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(), TRUE, block ? INFINITE : 0);
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
if (res != WAIT_TIMEOUT)
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");

24
README
View File

@ -2,23 +2,23 @@ Strawberry Music Player
=======================
README
Strawberry is a modern audio player and music collection organiser. It was forked from Clementine in 2013, and has a diffrent goal.
Strawberry is a audio player and music collection organiser. It was forked from Clementine in 2013 with a diffrent goal.
It's written in C++ and Qt 5 and runs on Linux. The name is inspired by the band Strawbs.
The main goal was to create a player for playing local music files that looked a bit more like Amarok 1.4 amd with advanced soundcard options.
You will find that Strawberry is lacking internet services and some other features found in Clementine.
Some differences between Strawberry and Clementine are:
Features:
- Status widget similar to context in Amarok 1.4
- Settings have been reorganized
- Advanced backend settings with support for several backends and advanced options
- No Smart playlists, visualizations or cd ripping support
- No LastFM, podcast or internet features except for fetching album covers
There are no plans to add internet streaming features, but if we would add something it has to be a service providing high quality audio and not low audio quality like Spotify.
* Play and organize music
* Edit tags on music files
* Album cover art from Lastfm, Musicbrainz, Discogs and Amazon
* Native desktop notifications
* Playlists in multiple formats
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
* Support for multiple backends
You can obtain and view the sourcecode on github at: https://github.com/jonaski/strawberry
It has so far been tested on Linux and cross compiled for Windows. I have not had a chance to test it on Mac OS X since I don't have a mac.
Requirements
------------
@ -27,7 +27,7 @@ To build Strawberry from source you need the following installed on your system:
* glib2, glib2-devel, git, cmake, make, gcc and gcc-c++
* protobuf and development packages
* boost development package
* boost development headers
* The following Qt5 components are required with additional development packages:

View File

@ -80,7 +80,7 @@ Requires: gstreamer1.0(decoder-audio/x-wav)
%endif
%description
Strawberry is a modern audio player and music collection organiser.
Strawberry is a audio player and music collection organiser.
It is a fork of Clementine. The name is inspired by the band Strawbs.
Features:

View File

@ -22,7 +22,6 @@
#include "database.h"
#include "scopedtransaction.h"
#include "utilities.h"
#include "core/application.h"
#include "core/logging.h"
#include "core/taskmanager.h"
@ -32,6 +31,7 @@
#include <sqlite3.h>
#include <QCoreApplication>
#include <QStandardPaths>
#include <QDir>
#include <QLibrary>
#include <QLibraryInfo>
@ -225,7 +225,7 @@ Database::Database(Application *app, QObject *parent, const QString &database_na
connection_id_ = sNextConnectionId++;
}
directory_ = QDir::toNativeSeparators(Utilities::GetConfigPath(Utilities::Path_Root));
directory_ = QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
QMutexLocker l(&mutex_);
Connect();

View File

@ -120,8 +120,8 @@ int main(int argc, char* argv[]) {
QCoreApplication::setOrganizationDomain("strawbs.org");
// This makes us show up nicely in gnome-volume-control
#if !GLIB_CHECK_VERSION(2, 36, 0)
g_type_init(); // Deprecated in glib 2.36.0
#if !GLIB_CHECK_VERSION(2, 36, 0) // Deprecated in glib 2.36.0
g_type_init();
#endif
g_set_application_name(QCoreApplication::applicationName().toLocal8Bit());
@ -156,7 +156,7 @@ int main(int argc, char* argv[]) {
#ifdef Q_OS_DARWIN
// Must happen after QCoreApplication::setOrganizationName().
setenv("XDG_CONFIG_HOME", Utilities::GetConfigPath(Utilities::Path_Root).toLocal8Bit().constData(), 1);
setenv("XDG_CONFIG_HOME", QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation).toLocal8Bit().constData(), 1);
#endif
// Output the version, so when people attach log output to bug reports they don't have to tell us which version they're using.

View File

@ -23,13 +23,14 @@
#include "network.h"
#include <QCoreApplication>
#include <QStandardPaths>
#include <QDir>
#include <QNetworkAccessManager>
#include <QNetworkDiskCache>
#include <QNetworkReply>
#include "core/closure.h"
#include "utilities.h"
#include "core/logging.h"
QMutex ThreadSafeNetworkDiskCache::sMutex;
QNetworkDiskCache *ThreadSafeNetworkDiskCache::sCache = nullptr;
@ -39,7 +40,11 @@ ThreadSafeNetworkDiskCache::ThreadSafeNetworkDiskCache(QObject *parent)
QMutexLocker l(&sMutex);
if (!sCache) {
sCache = new QNetworkDiskCache;
sCache->setCacheDirectory(Utilities::GetConfigPath(Utilities::Path_NetworkCache));
#ifdef Q_OS_WIN32
sCache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/strawberry/networkcache");
#else
sCache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/networkcache");
#endif
}
}
@ -93,18 +98,15 @@ QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkR
QByteArray user_agent = QString("%1 %2").arg(QCoreApplication::applicationName(), QCoreApplication::applicationVersion()).toUtf8();
if (request.hasRawHeader("User-Agent")) {
// Append the existing user-agent set by a client collection (such as
// libmygpo-qt).
// Append the existing user-agent set by a client collection (such as libmygpo-qt).
user_agent += " " + request.rawHeader("User-Agent");
}
QNetworkRequest new_request(request);
new_request.setRawHeader("User-Agent", user_agent);
if (op == QNetworkAccessManager::PostOperation &&
!new_request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
new_request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded");
if (op == QNetworkAccessManager::PostOperation && !new_request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
new_request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
}
// Prefer the cache unless the caller has changed the setting already

View File

@ -87,8 +87,7 @@ QString PrettyTimeDelta(int seconds) {
QString PrettyTime(int seconds) {
// last.fm sometimes gets the track length wrong, so you end up with
// negative times.
// last.fm sometimes gets the track length wrong, so you end up with negative times.
seconds = qAbs(seconds);
int hours = seconds / (60 * 60);
@ -181,9 +180,7 @@ quint64 FileSystemCapacity(const QString &path) {
return quint64(fs_info.f_blocks) * quint64(fs_info.f_bsize);
#elif defined(Q_OS_WIN32)
_ULARGE_INTEGER ret;
if (GetDiskFreeSpaceEx(
QDir::toNativeSeparators(path).toLocal8Bit().constData(), nullptr,
&ret, nullptr) != 0)
if (GetDiskFreeSpaceEx(QDir::toNativeSeparators(path).toLocal8Bit().constData(), nullptr,&ret, nullptr) != 0)
return ret.QuadPart;
#endif
@ -199,9 +196,7 @@ quint64 FileSystemFreeSpace(const QString &path) {
return quint64(fs_info.f_bavail) * quint64(fs_info.f_bsize);
#elif defined(Q_OS_WIN32)
_ULARGE_INTEGER ret;
if (GetDiskFreeSpaceEx(
QDir::toNativeSeparators(path).toLocal8Bit().constData(), &ret,
nullptr, nullptr) != 0)
if (GetDiskFreeSpaceEx(QDir::toNativeSeparators(path).toLocal8Bit().constData(), &ret, nullptr, nullptr) != 0)
return ret.QuadPart;
#endif
@ -346,66 +341,6 @@ QString ColorToRgba(const QColor &c) {
}
QString GetConfigPath(ConfigPath config) {
switch (config) {
case Path_Root: {
if (Application::kIsPortable) {
return QString("%1/data").arg(QCoreApplication::applicationDirPath());
}
#ifdef Q_OS_DARWIN
return mac::GetApplicationSupportPath() + "/strawberry";
#else
return QString("%1/.config/strawberry").arg(QDir::homePath());
#endif
}
break;
case Path_CacheRoot: {
if (Application::kIsPortable) {
return GetConfigPath(Path_Root) + "/cache";
}
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
char *xdg = getenv("XDG_CACHE_HOME");
if (!xdg || !*xdg) {
return QString("%1/.cache/strawberry").arg(QDir::homePath());
}
else {
return QString("%1/strawberry").arg(xdg);
}
#else
return GetConfigPath(Path_Root);
#endif
}
break;
case Path_Icons:
return GetConfigPath(Path_Root) + "/customiconset";
case Path_AlbumCovers:
return GetConfigPath(Path_Root) + "/albumcovers";
case Path_NetworkCache:
return GetConfigPath(Path_CacheRoot) + "/networkcache";
case Path_GstreamerRegistry:
return GetConfigPath(Path_Root) + QString("/gst-registry-%1-bin").arg(QCoreApplication::applicationVersion());
case Path_DefaultMusicCollection:
#ifdef Q_OS_DARWIN
return mac::GetMusicDirectory();
#else
return QDir::homePath();
#endif
default:
qFatal("%s", Q_FUNC_INFO);
return QString::null;
}
}
#ifdef Q_OS_DARWIN
qint32 GetMacVersion() {
@ -801,8 +736,7 @@ void SetEnv(const char *key, const QString &value) {
void IncreaseFDLimit() {
#ifdef Q_OS_DARWIN
// Bump the soft limit for the number of file descriptors from the default of 256 to
// the maximum (usually 10240).
// Bump the soft limit for the number of file descriptors from the default of 256 to the maximum (usually 10240).
struct rlimit limit;
getrlimit(RLIMIT_NOFILE, &limit);

View File

@ -126,19 +126,6 @@ void SetEnv(const char *key, const QString &value);
void IncreaseFDLimit();
void CheckPortable();
enum ConfigPath {
Path_Root,
Path_Icons,
Path_AlbumCovers,
Path_NetworkCache,
Path_GstreamerRegistry,
Path_DefaultMusicCollection,
Path_LocalSpotifyBlob,
Path_MoodbarCache,
Path_CacheRoot,
};
QString GetConfigPath(ConfigPath config);
// Returns the minor version of OS X (ie. 6 for Snow Leopard, 7 for Lion).
qint32 GetMacVersion();

View File

@ -211,8 +211,7 @@ void AlbumCoverChoiceController::ShowCover(const Song &song) {
// add (WxHpx) to the title before possibly resizing
title_text += " (" + QString::number(label->pixmap()->width()) + "x" + QString::number(label->pixmap()->height()) + "px)";
// if the cover is larger than the screen, resize the window
// 85% seems to be enough to account for title bar and taskbar etc.
// if the cover is larger than the screen, resize the window 85% seems to be enough to account for title bar and taskbar etc.
QDesktopWidget desktop;
int current_screen = desktop.screenNumber(this);
int desktop_height = desktop.screenGeometry(current_screen).height();
@ -222,15 +221,13 @@ void AlbumCoverChoiceController::ShowCover(const Song &song) {
if (desktop_width < desktop_height) {
const int new_width = (double)desktop_width * 0.95;
if (new_width < label->pixmap()->width()) {
label->setPixmap(
label->pixmap()->scaledToWidth(new_width, Qt::SmoothTransformation));
label->setPixmap(label->pixmap()->scaledToWidth(new_width, Qt::SmoothTransformation));
}
}
else {
const int new_height = (double)desktop_height * 0.85;
if (new_height < label->pixmap()->height()) {
label->setPixmap(label->pixmap()->scaledToHeight(
new_height, Qt::SmoothTransformation));
label->setPixmap(label->pixmap()->scaledToHeight(new_height, Qt::SmoothTransformation));
}
}

View File

@ -22,18 +22,22 @@
#include "albumcoverloader.h"
#include <QPainter>
#include <QDir>
#include <QCoreApplication>
#include <QStandardPaths>
#include <QString>
#include <QDir>
#include <QUrl>
#include <QNetworkReply>
#include <QImage>
#include <QPixmap>
#include <QPainter>
#include <QMutexLocker>
#include "config.h"
#include "core/closure.h"
#include "core/logging.h"
#include "core/network.h"
#include "core/tagreaderclient.h"
#include "core/utilities.h"
AlbumCoverLoader::AlbumCoverLoader(QObject *parent)
: QObject(parent),
@ -42,7 +46,7 @@ AlbumCoverLoader::AlbumCoverLoader(QObject *parent)
network_(new NetworkAccessManager(this)){}
QString AlbumCoverLoader::ImageCacheDir() {
return Utilities::GetConfigPath(Utilities::Path_AlbumCovers);
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/albumcovers";
}
void AlbumCoverLoader::CancelTask(quint64 id) {
@ -139,6 +143,7 @@ void AlbumCoverLoader::NextState(Task *task) {
emit ImageLoaded(task->id, task->options.default_output_image_);
emit ImageLoaded(task->id, task->options.default_output_image_, task->options.default_output_image_);
}
}
AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(const Task &task) {
@ -241,6 +246,7 @@ QImage AlbumCoverLoader::ScaleAndPad(const AlbumCoverLoaderOptions &options, con
p.end();
return padded_image;
}
QPixmap AlbumCoverLoader::TryLoadPixmap(const QString &automatic, const QString &manual, const QString &filename) {
@ -255,4 +261,5 @@ QPixmap AlbumCoverLoader::TryLoadPixmap(const QString &automatic, const QString
ret.load(automatic);
}
return ret;
}

View File

@ -772,6 +772,7 @@ void AlbumCoverManager::SaveAndSetCover(QListWidgetItem *item, const QImage &ima
quint64 id = app_->album_cover_loader()->LoadImageAsync(cover_loader_options_, QString(), path);
item->setData(Role_PathManual, path);
cover_loading_tasks_[id] = item;
}
void AlbumCoverManager::ExportCovers() {

View File

@ -64,8 +64,6 @@ About::About(QWidget *parent):QDialog(parent) {
title_font.setPointSize(title_font.pointSize() + 4);
ui_.title->setFont(title_font);
ui_.text->setWordWrap(true);
ui_.text->setText(MakeHtml());
@ -80,13 +78,14 @@ QString About::MakeHtml() const {
ret = tr("<p>Version %1</p>").arg(QCoreApplication::applicationVersion());
ret += tr("<p>");
ret += tr("Strawberry is a fork of Clementine created in 2013, it's written in C++ and Qt5. So far it works on Linux, it is currently untested on Mac OS X and Windows.<br />");
ret += tr("The main goal was to create a player for playing local music files that looked a bit more like Amarok 1.4.");
ret += tr("Strawberry is a audio player and music collection organiser.<br />");
ret += tr("It is a fork of Clementine. The name is inspired by the band Strawbs.");
ret += tr("</p>");
//ret += tr("<p><a href=\"%1\">%2</a></p><p><b>%3:</b>").arg(kUrl, kUrl, tr("Authors"));
ret += QString("<p><b>%1</b>").arg(tr("Authors"));
ret += QString("<p><b>%1</b>").arg(tr("Strawberry Authors"));
for (const Person &person : authors_) {
ret += "<br />" + MakeHtml(person);

View File

@ -33,14 +33,15 @@
#include <memory>
#include <vector>
#include <QTimer>
#include <QRegExp>
#include <QFile>
#include <QSettings>
#include <QCoreApplication>
#include <QTimeLine>
#include <QDir>
#include <QStandardPaths>
#include <QtConcurrentRun>
#include <QSettings>
#include <QDir>
#include <QFile>
#include <QRegExp>
#include <QTimer>
#include <QTimeLine>
#include "enginetype.h"
#include "enginebase.h"
@ -169,7 +170,7 @@ void GstEngine::SetEnvironment() {
#endif
#if defined(Q_OS_WIN32) || defined(Q_OS_DARWIN)
registry_filename = Utilities::GetConfigPath(Utilities::Path_GstreamerRegistry);
registry_filename = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QString("/gst-registry-%1-bin").arg(QCoreApplication::applicationVersion());
#endif
if (!scanner_path.isEmpty()) Utilities::SetEnv("GST_PLUGIN_SCANNER", scanner_path);
@ -750,7 +751,7 @@ void GstEngine::NewMetaData(int pipeline_id, const Engine::SimpleMetaBundle &bun
emit MetaData(bundle);
}
GstElement *GstEngine::CreateElement(const QString &factoryName, GstElement *bin) {
GstElement *GstEngine::CreateElement(const QString &factoryName, GstElement *bin, bool showerror) {
// Make a unique name
QString name = factoryName + "-" + QString::number(next_element_id_++);
@ -758,7 +759,7 @@ GstElement *GstEngine::CreateElement(const QString &factoryName, GstElement *bin
GstElement *element = gst_element_factory_make(factoryName.toUtf8().constData(), name.toUtf8().constData());
if (!element) {
emit Error(QString("GStreamer could not create the element: %1. Please make sure that you have installed all necessary GStreamer plugins").arg(factoryName));
if (showerror) emit Error(QString("GStreamer could not create the element: %1. Please make sure that you have installed all necessary GStreamer plugins").arg(factoryName));
gst_object_unref(GST_OBJECT(bin));
return nullptr;
}

View File

@ -85,7 +85,7 @@ class GstEngine : public Engine::Base, public BufferConsumer {
static bool ALSADeviceSupport(const QString &name);
GstElement *CreateElement(const QString &factoryName, GstElement *bin = 0);
GstElement *CreateElement(const QString &factoryName, GstElement *bin = 0, bool showerror = true);
// BufferConsumer
void ConsumeBuffer(GstBuffer *buffer, int pipeline_id);

View File

@ -230,7 +230,7 @@ bool GstEnginePipeline::InitAudioBin() {
audio_queue = engine_->CreateElement("queue", audiobin_);
equalizer_preamp_ = engine_->CreateElement("volume", audiobin_);
equalizer_ = engine_->CreateElement("equalizer-nbands", audiobin_);
stereo_panorama_ = engine_->CreateElement("audiopanorama", audiobin_);
stereo_panorama_ = engine_->CreateElement("audiopanorama", audiobin_, false);
volume_ = engine_->CreateElement("volume", audiobin_);
audioscale_ = engine_->CreateElement("audioresample", audiobin_);
convert = engine_->CreateElement("audioconvert", audiobin_);

View File

@ -47,9 +47,6 @@ class PlaylistBackend : public QObject {
QString ui_path;
bool favorite;
int last_played;
// Special playlists have different behaviour, eg. the "spotify-search"
// type has a spotify search box at the top, replacing the ordinary filter.
QString special_type;
};
typedef QList<Playlist> PlaylistList;

View File

@ -84,7 +84,7 @@ void BackendSettingsPage::Load() {
configloaded_ = false;
engineloaded_ = Engine::None;
Engine::EngineType enginetype = Engine::EngineTypeFromName(s_.value("engine", EngineText_Xine).toString());
Engine::EngineType enginetype = Engine::EngineTypeFromName(s_.value("engine", EngineText_GStreamer).toString());
ui_->combobox_engine->clear();
#ifdef HAVE_XINE

View File

@ -22,16 +22,15 @@
#include <QDir>
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <QtConcurrentRun>
#include <QStandardPaths>
#include "collectionsettingspage.h"
#include "ui_collectionsettingspage.h"
#include "settings/settingsdialog.h"
#include "core/application.h"
#include "core/utilities.h"
#include "core/iconloader.h"
#include "playlist/playlistdelegates.h"
@ -65,7 +64,7 @@ void CollectionSettingsPage::Add() {
QSettings settings;
settings.beginGroup(kSettingsGroup);
QString path(settings.value("last_path", Utilities::GetConfigPath(Utilities::Path_DefaultMusicCollection)).toString());
QString path(settings.value("last_path", QStandardPaths::writableLocation(QStandardPaths::MusicLocation)).toString());
path = QFileDialog::getExistingDirectory(this, tr("Add directory..."), path);
if (!path.isNull()) {

View File

@ -78,15 +78,11 @@ PlayingWidget::PlayingWidget(QWidget *parent)
previous_track_opacity_(0.0),
downloading_covers_(false) {
enabled_ = false;
visible_ = false;
active_ = false;
// Load settings
QSettings s;
s.beginGroup(kSettingsGroup);
mode_ = Mode(s.value("mode", LargeSongDetails).toInt());
album_cover_choice_controller_->search_cover_auto_action()->setChecked(s.value("search_for_cover_auto", false).toBool());
album_cover_choice_controller_->search_cover_auto_action()->setChecked(s.value("search_for_cover_auto", true).toBool());
fit_width_ = s.value("fit_cover_width", false).toBool();
// Accept drops for setting album art
@ -473,7 +469,6 @@ void PlayingWidget::SearchCoverAutomatically() {
s.beginGroup(kSettingsGroup);
s.setValue("search_for_cover_auto", album_cover_choice_controller_->search_cover_auto_action()->isChecked());
// Search for cover automatically?
GetCoverAutomatically();
}

View File

@ -106,6 +106,12 @@ StatusView::StatusView(CollectionViewContainer *collectionviewcontainer, QWidget
NoSong();
AddActions();
// Load settings
QSettings s;
s.beginGroup(kSettingsGroup);
album_cover_choice_controller_->search_cover_auto_action()->setChecked(s.value("search_for_cover_auto", true).toBool());
s.endGroup();
}
StatusView::~StatusView() {
@ -620,7 +626,6 @@ void StatusView::SearchCoverAutomatically() {
s.beginGroup(kSettingsGroup);
s.setValue("search_for_cover_auto", album_cover_choice_controller_->search_cover_auto_action()->isChecked());
// Search for cover automatically?
GetCoverAutomatically();
}