Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c039c9c8b | ||
|
|
c1d9bc046d | ||
|
|
cd99fac7ed | ||
|
|
f4489e6807 | ||
|
|
f2078271b6 | ||
|
|
a3ae9acebb | ||
|
|
b0580265ca | ||
|
|
b4f012392a | ||
|
|
1598809f55 | ||
|
|
6d4f7aa61f |
@@ -2,6 +2,15 @@ Strawberry Music Player
|
||||
=======================
|
||||
ChangeLog
|
||||
|
||||
Version 0.6.5:
|
||||
|
||||
* Fixed scrobbler not to send scrobbles multiple times when metadata is updated
|
||||
* Fixed Listenbrainz scrobbler not don't send "various artists" as album artist
|
||||
* Fixed missing cover image in OSD pretty reposition image
|
||||
* Fixed OSD pretty upper left positioning
|
||||
* Fixed OSD pretty positioning on Windows on screens with negative geometry
|
||||
* Fixed appdata file to pass full validation
|
||||
|
||||
Version 0.6.4:
|
||||
|
||||
* Added setting for fancy tabbar background color
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
set(STRAWBERRY_VERSION_MAJOR 0)
|
||||
set(STRAWBERRY_VERSION_MINOR 6)
|
||||
set(STRAWBERRY_VERSION_PATCH 4)
|
||||
set(STRAWBERRY_VERSION_PATCH 5)
|
||||
#set(STRAWBERRY_VERSION_PRERELEASE rc1)
|
||||
|
||||
set(INCLUDE_GIT_REVISION OFF)
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
<translation type="qt">strawberry</translation>
|
||||
<description>
|
||||
<p>
|
||||
Strawberry is a music player and music collection organizer.
|
||||
It is a fork of Clementine. The name is inspired by the band Strawbs.
|
||||
Strawberry is a music player and music collection organizer. It is a fork of Clementine released in 2018 aimed at music collectors, audio enthusiasts and audiophiles. The name is inspired by the band Strawbs. It's based on a heavily modified version of Clementine created in 2012-2013. It's written in C++ and Qt 5.
|
||||
</p>
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Play and organize music</li>
|
||||
<li>Supports WAV, FLAC, WavPack, DSF, DSDIFF, Ogg FLAC, Ogg Vorbis, Ogg Opus, Ogg Speex, MPC, TrueAudio, AIFF, MP4, MP3, ASF and Monkey's Audio.</li>
|
||||
<li>Audio CD playback</li>
|
||||
<li>Supports most popular audio formats and CD playback</li>
|
||||
<li>Native desktop notifications</li>
|
||||
<li>Playlists in multiple formats</li>
|
||||
<li>Advanced audio output and device configuration for bit-perfect playback on Linux</li>
|
||||
@@ -31,8 +29,7 @@
|
||||
<li>Album cover art from Last.fm, Musicbrainz and Discogs</li>
|
||||
<li>Song lyrics from AudD, lyrics.ovh and lololyrics.com</li>
|
||||
<li>Support for multiple backends</li>
|
||||
<li>Audio analyzer</li>
|
||||
<li>Audio equalizer</li>
|
||||
<li>Audio analyzer and equalizer</li>
|
||||
<li>Transfer music to iPod, iPhone, MTP or mass-storage USB player</li>
|
||||
<li>Streaming support for Tidal, Qobuz and Subsonic</li>
|
||||
<li>Scrobbler with support for Last.fm, Libre.fm and ListenBrainz</li>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: strawberry
|
||||
version: '0.6.4+git'
|
||||
version: '0.6.5+git'
|
||||
summary: music player and collection organizer
|
||||
description: |
|
||||
Strawberry is a music player and collection organizer.
|
||||
|
||||
@@ -156,8 +156,8 @@ void ContextView::AddActions() {
|
||||
s.beginGroup(kSettingsGroup);
|
||||
action_show_data_->setChecked(s.value("show_data", true).toBool());
|
||||
action_show_output_->setChecked(s.value("show_output", true).toBool());
|
||||
action_show_albums_->setChecked(s.value("show_albums", true).toBool());
|
||||
action_show_lyrics_->setChecked(s.value("show_lyrics", false).toBool());
|
||||
action_show_albums_->setChecked(s.value("show_albums", false).toBool());
|
||||
action_show_lyrics_->setChecked(s.value("show_lyrics", true).toBool());
|
||||
s.endGroup();
|
||||
|
||||
connect(action_show_data_, SIGNAL(triggered()), this, SLOT(ActionShowData()));
|
||||
|
||||
@@ -675,12 +675,6 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
|
||||
bundle.artist = ParseStrTag(taglist, GST_TAG_ARTIST);
|
||||
bundle.comment = ParseStrTag(taglist, GST_TAG_COMMENT);
|
||||
bundle.album = ParseStrTag(taglist, GST_TAG_ALBUM);
|
||||
bundle.length = 0;
|
||||
bundle.year = 0;
|
||||
bundle.track = 0;
|
||||
bundle.filetype = Song::FileType_Unknown;
|
||||
bundle.samplerate = 0;
|
||||
bundle.bitdepth = 0;
|
||||
bundle.bitrate = ParseUIntTag(taglist, GST_TAG_BITRATE) / 1000;
|
||||
bundle.lyrics = ParseStrTag(taglist, GST_TAG_LYRICS);
|
||||
|
||||
|
||||
@@ -1496,6 +1496,8 @@ void Playlist::SetStreamMetadata(const QUrl &url, const Song &song, const bool m
|
||||
|
||||
//qLog(Debug) << "Setting temporary metadata for" << url;
|
||||
|
||||
bool length_changed = song.length_nanosec() != current_item_metadata().length_nanosec();
|
||||
|
||||
current_item()->SetTemporaryMetadata(song);
|
||||
|
||||
if (minor) {
|
||||
@@ -1510,7 +1512,7 @@ void Playlist::SetStreamMetadata(const QUrl &url, const Song &song, const bool m
|
||||
InformOfCurrentSongChange();
|
||||
}
|
||||
|
||||
UpdateScrobblePoint();
|
||||
if (length_changed) UpdateScrobblePoint();
|
||||
|
||||
}
|
||||
|
||||
@@ -1977,7 +1979,7 @@ void Playlist::SkipTracks(const QModelIndexList &source_indexes) {
|
||||
|
||||
}
|
||||
|
||||
void Playlist::UpdateScrobblePoint(qint64 seek_point_nanosec) {
|
||||
void Playlist::UpdateScrobblePoint(const qint64 seek_point_nanosec) {
|
||||
|
||||
const qint64 length = current_item_metadata().length_nanosec();
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ class Playlist : public QAbstractListModel {
|
||||
void set_scrobbled(bool state) { scrobbled_ = state; }
|
||||
void set_nowplaying(bool state) { nowplaying_ = state; }
|
||||
qint64 scrobble_point_nanosec() const { return scrobble_point_; }
|
||||
void UpdateScrobblePoint(qint64 seek_point_nanosec = 0);
|
||||
void UpdateScrobblePoint(const qint64 seek_point_nanosec = 0);
|
||||
|
||||
// Changing the playlist
|
||||
void InsertItems (const PlaylistItemList &items, int pos = -1, bool play_now = false, bool enqueue = false, bool enqueue_next = false);
|
||||
|
||||
@@ -345,7 +345,12 @@ void ListenBrainzScrobbler::UpdateNowPlaying(const Song &song) {
|
||||
album = album.remove(Song::kAlbumRemoveMisc);
|
||||
|
||||
QJsonObject object_track_metadata;
|
||||
object_track_metadata.insert("artist_name", QJsonValue::fromVariant(song.effective_albumartist()));
|
||||
if (song.albumartist().isEmpty() || song.albumartist().toLower() == "various artists") {
|
||||
object_track_metadata.insert("artist_name", QJsonValue::fromVariant(song.artist()));
|
||||
}
|
||||
else {
|
||||
object_track_metadata.insert("artist_name", QJsonValue::fromVariant(song.albumartist()));
|
||||
}
|
||||
object_track_metadata.insert("release_name", QJsonValue::fromVariant(album));
|
||||
object_track_metadata.insert("track_name", QJsonValue::fromVariant(song.title()));
|
||||
|
||||
@@ -459,8 +464,10 @@ void ListenBrainzScrobbler::Submit() {
|
||||
QJsonObject object_listen;
|
||||
object_listen.insert("listened_at", QJsonValue::fromVariant(item->timestamp_));
|
||||
QJsonObject object_track_metadata;
|
||||
if (item->albumartist_.isEmpty()) object_track_metadata.insert("artist_name", QJsonValue::fromVariant(item->artist_));
|
||||
else object_track_metadata.insert("artist_name", QJsonValue::fromVariant(item->albumartist_));
|
||||
if (item->albumartist_.isEmpty() || item->albumartist_.toLower() == "various artists")
|
||||
object_track_metadata.insert("artist_name", QJsonValue::fromVariant(item->artist_));
|
||||
else
|
||||
object_track_metadata.insert("artist_name", QJsonValue::fromVariant(item->albumartist_));
|
||||
object_track_metadata.insert("release_name", QJsonValue::fromVariant(item->album_));
|
||||
object_track_metadata.insert("track_name", QJsonValue::fromVariant(item->song_));
|
||||
object_listen.insert("track_metadata", object_track_metadata);
|
||||
|
||||
@@ -62,7 +62,7 @@ NotificationsSettingsPage::NotificationsSettingsPage(SettingsDialog* dialog)
|
||||
ui_->setupUi(this);
|
||||
setWindowIcon(IconLoader::Load("help-hint"));
|
||||
|
||||
pretty_popup_->SetMessage(tr("OSD Preview"), tr("Drag to reposition"), QImage(":/pictures/nocover.png"));
|
||||
pretty_popup_->SetMessage(tr("OSD Preview"), tr("Drag to reposition"), QImage(":/pictures/cdcase.png"));
|
||||
|
||||
ui_->notifications_bg_preset->setItemData(0, QColor(OSDPretty::kPresetBlue), Qt::DecorationRole);
|
||||
ui_->notifications_bg_preset->setItemData(1, QColor(OSDPretty::kPresetRed), Qt::DecorationRole);
|
||||
|
||||
@@ -101,7 +101,7 @@ OSDPretty::OSDPretty(Mode mode, QWidget *parent)
|
||||
setAttribute(Qt::WA_ShowWithoutActivating, true);
|
||||
ui_->setupUi(this);
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#ifdef Q_OS_WIN
|
||||
// Don't show the window in the taskbar. Qt::ToolTip does this too, but it adds an extra ugly shadow.
|
||||
int ex_style = GetWindowLong((HWND) winId(), GWL_EXSTYLE);
|
||||
ex_style |= WS_EX_NOACTIVATE;
|
||||
@@ -130,7 +130,7 @@ OSDPretty::OSDPretty(Mode mode, QWidget *parent)
|
||||
connect(fader_, SIGNAL(valueChanged(qreal)), SLOT(FaderValueChanged(qreal)));
|
||||
connect(fader_, SIGNAL(finished()), SLOT(FaderFinished()));
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#ifdef Q_OS_WIN
|
||||
set_fading_enabled(true);
|
||||
#endif
|
||||
|
||||
@@ -179,7 +179,6 @@ void OSDPretty::showEvent(QShowEvent *e) {
|
||||
QWidget::showEvent(e);
|
||||
|
||||
Load();
|
||||
|
||||
Reposition();
|
||||
|
||||
if (fading_enabled_) {
|
||||
@@ -219,36 +218,48 @@ void OSDPretty::Load() {
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(kSettingsGroup);
|
||||
|
||||
foreground_color_ = QColor(s.value("foreground_color", 0).toInt());
|
||||
background_color_ = QColor(s.value("background_color", kPresetBlue).toInt());
|
||||
background_opacity_ = s.value("background_opacity", 0.85).toDouble();
|
||||
popup_screen_name_ = s.value("popup_screen").toString();
|
||||
popup_pos_ = s.value("popup_pos", QPoint()).toPoint();
|
||||
font_.fromString(s.value("font", "Verdana,9,-1,5,50,0,0,0,0,0").toString());
|
||||
disable_duration_ = s.value("disable_duration", false).toBool();
|
||||
s.endGroup();
|
||||
|
||||
if (screens_.contains(popup_screen_name_)) popup_screen_ = screens_[popup_screen_name_];
|
||||
if (s.contains("popup_screen")) {
|
||||
popup_screen_name_ = s.value("popup_screen").toString();
|
||||
if (screens_.contains(popup_screen_name_)) {
|
||||
popup_screen_ = screens_[popup_screen_name_];
|
||||
}
|
||||
else {
|
||||
popup_screen_ = current_screen();
|
||||
if (current_screen()) popup_screen_name_ = current_screen()->name();
|
||||
else popup_screen_name_.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
popup_screen_ = current_screen();
|
||||
if (current_screen()) popup_screen_name_ = current_screen()->name();
|
||||
}
|
||||
if (popup_pos_.isNull()) {
|
||||
if (current_screen()) {
|
||||
QRect screenResolution = current_screen()->availableGeometry();
|
||||
popup_pos_.setX(screenResolution.width() - width() - 10);
|
||||
popup_pos_.setY(10);
|
||||
|
||||
if (s.contains("popup_pos")) {
|
||||
popup_pos_ = s.value("popup_pos").toPoint();
|
||||
}
|
||||
else {
|
||||
if (popup_screen_) {
|
||||
QRect geometry = popup_screen_->availableGeometry();
|
||||
popup_pos_.setX(geometry.width() - width());
|
||||
popup_pos_.setY(0);
|
||||
}
|
||||
else {
|
||||
popup_pos_.setX(10);
|
||||
popup_pos_.setY(10);
|
||||
popup_pos_.setX(0);
|
||||
popup_pos_.setY(0);
|
||||
}
|
||||
}
|
||||
|
||||
set_font(font());
|
||||
set_foreground_color(foreground_color());
|
||||
|
||||
s.endGroup();
|
||||
|
||||
}
|
||||
|
||||
void OSDPretty::ReloadSettings() {
|
||||
@@ -388,12 +399,17 @@ void OSDPretty::Reposition() {
|
||||
|
||||
// Work out where to place the OSD. -1 for x or y means "on the right or bottom edge".
|
||||
if (popup_screen_) {
|
||||
|
||||
QRect geometry = popup_screen_->availableGeometry();
|
||||
|
||||
int x = popup_pos_.x() < 0 ? geometry.right() - width() : geometry.left() + popup_pos_.x();
|
||||
int y = popup_pos_.y() < 0 ? geometry.bottom() - height() : geometry.top() + popup_pos_.y();
|
||||
|
||||
move(qBound(0, x, geometry.right() - width()), qBound(0, y, geometry.bottom() - height()));
|
||||
#ifndef Q_OS_WIN
|
||||
x = qBound(0, x, geometry.right() - width());
|
||||
y = qBound(0, y, geometry.bottom() - height());
|
||||
#endif
|
||||
move(x, y);
|
||||
}
|
||||
|
||||
// Create a mask for the actual area of the OSD
|
||||
@@ -412,7 +428,7 @@ void OSDPretty::Reposition() {
|
||||
setMask(mask);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#ifdef Q_OS_WIN
|
||||
// On windows, enable blurbehind on the masked area
|
||||
QtWin::enableBlurBehindWindow(this, QRegion(mask));
|
||||
#endif
|
||||
@@ -467,6 +483,15 @@ void OSDPretty::mouseMoveEvent(QMouseEvent *e) {
|
||||
|
||||
popup_screen_ = screen;
|
||||
popup_screen_name_ = screen->name();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OSDPretty::mouseReleaseEvent(QMouseEvent *) {
|
||||
|
||||
if (mode_ == Mode_Draggable) {
|
||||
popup_screen_ = current_screen();
|
||||
popup_screen_name_ = current_screen()->name();
|
||||
popup_pos_ = current_pos();
|
||||
}
|
||||
|
||||
@@ -521,16 +546,6 @@ void OSDPretty::set_popup_duration(int msec) {
|
||||
timeout_->setInterval(msec);
|
||||
}
|
||||
|
||||
void OSDPretty::mouseReleaseEvent(QMouseEvent *) {
|
||||
|
||||
if (mode_ == Mode_Draggable) {
|
||||
popup_screen_ = current_screen();
|
||||
popup_screen_name_ = current_screen()->name();
|
||||
popup_pos_ = current_pos();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OSDPretty::set_font(QFont font) {
|
||||
|
||||
font_ = font;
|
||||
|
||||
@@ -111,13 +111,13 @@ class OSDPretty : public QWidget {
|
||||
void ReloadSettings();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
void enterEvent(QEvent *);
|
||||
void leaveEvent(QEvent *);
|
||||
void mousePressEvent(QMouseEvent *);
|
||||
void showEvent(QShowEvent *);
|
||||
void mouseMoveEvent(QMouseEvent *);
|
||||
void mouseReleaseEvent(QMouseEvent *);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void showEvent(QShowEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
|
||||
private:
|
||||
void Reposition();
|
||||
|
||||
Reference in New Issue
Block a user