Skip to content

Commit aa18887

Browse files
committedDec 20, 2023
Added error indicator for when an audio file can not be played; a list without a working file no longer gets stuck in an endless loop
1 parent 2a4bf52 commit aa18887

16 files changed

+129
-39
lines changed
 

‎app/ui/tools/audio/AudioInfoView.qml

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
pragma ComponentBehavior: Bound
2-
32
import QtQuick
43
import QtQuick.Controls
54
import src
5+
import IconFonts
6+
import common
67

78
Item {
89
id: audio_info_frame
@@ -67,13 +68,27 @@ Item {
6768
delegate: Item {
6869
id: playlist_delegate
6970

70-
// TODO: type
7171
required property AudioFile modelData
7272
required property int index
7373

74-
width: playlist_view.width
74+
width: error_indicator.visible ? playlist_view.width + error_indicator.width : playlist_view.width
7575
height: playlist_text.height + 10
7676

77+
Text {
78+
id: error_indicator
79+
80+
visible: playlist_delegate.modelData.hadError
81+
82+
font: FontAwesome.fontSolid
83+
text: FontAwesome.triangleExclamation
84+
color: SettingsManager.colors.error
85+
anchors.top: parent.top
86+
anchors.bottom: parent.bottom
87+
anchors.left: parent.left
88+
anchors.leftMargin: 5
89+
verticalAlignment: Text.AlignVCenter
90+
}
91+
7792
Text {
7893
id: playlist_text
7994
clip: true
@@ -83,6 +98,7 @@ Item {
8398
font.pointSize: 10
8499
anchors.centerIn: parent
85100
width: parent.width - 10
101+
leftPadding: error_indicator.visible ? error_indicator.width + error_indicator.anchors.leftMargin : 0
86102
}
87103

88104
ToolTip {

‎src/tools/audio/audiotool.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ void AudioTool::next()
185185
{
186186
if (m_musicElementType == AudioElement::Type::Music)
187187
{
188-
musicPlayer.next();
188+
musicPlayer.next(false);
189189
}
190190
}
191191

‎src/tools/audio/metadata/metadatareader.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ void MetaDataReader::setMetaData(QMediaMetaData::Key key, const QVariant &value)
3838
case QMediaMetaData::CoverArtImage: {
3939
if (m_coverFile) m_coverFile->deleteLater();
4040

41+
if (value.value<QImage>().isNull())
42+
{
43+
m_metaData.cover({});
44+
break;
45+
}
46+
4147
m_coverFile = std::make_unique<QTemporaryFile>();
4248

4349
if (m_coverFile->open())
@@ -144,7 +150,7 @@ void MetaDataReader::loadMetaData(const QString &path, const QByteArray &data)
144150

145151
if (auto artist = tag->artist(); !artist.isEmpty())
146152
{
147-
m_metaData.artist(QString::fromStdString(artist.to8Bit(true)).split(", "));
153+
m_metaData.artist(QString::fromStdString(artist.to8Bit(true)).split(", "_L1));
148154
}
149155

150156
if (auto album = tag->album(); !album.isEmpty())

‎src/tools/audio/players/audioplayer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public slots:
3131
virtual void stop() = 0;
3232
virtual void setVolume(int linear, int logarithmic) = 0;
3333
virtual void again() = 0;
34-
virtual void next() = 0;
34+
virtual void next(bool withError) = 0;
3535

3636
protected:
3737
static auto normalizeVolume(int volume) -> float;

‎src/tools/audio/players/bufferedaudioplayer.cpp

+42-13
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void BufferedAudioPlayer::setIndex(qsizetype index)
5353
}
5454
else
5555
{
56-
next();
56+
next(true);
5757
}
5858
}
5959
}
@@ -110,14 +110,14 @@ auto BufferedAudioPlayer::loadPlaylist() -> QFuture<void>
110110
void BufferedAudioPlayer::handleUnsupportedMediaSource(const AudioFile &file)
111111
{
112112
qCWarning(gmAudioBufferedPlayer()) << "Media type" << file.source() << "is currently not supported.";
113-
next();
113+
next(true);
114114
}
115115

116116
void BufferedAudioPlayer::onFileReceived(const Files::FileDataResult &result)
117117
{
118118
if (!result.success() || result.data().isEmpty())
119119
{
120-
next();
120+
next(true);
121121
return;
122122
}
123123

@@ -149,8 +149,6 @@ void BufferedAudioPlayer::stop()
149149

150150
m_mediaPlayer.stop();
151151
state(AudioPlayer::State::Stopped);
152-
153-
m_playlist->clear();
154152
}
155153

156154
void BufferedAudioPlayer::setVolume(int linear, int logarithmic)
@@ -164,14 +162,29 @@ void BufferedAudioPlayer::again()
164162
m_mediaPlayer.setPosition(0);
165163
}
166164

167-
void BufferedAudioPlayer::next()
165+
void BufferedAudioPlayer::next(bool withError)
168166
{
169167
if (!m_element || m_playlist->isEmpty())
170168
{
171169
stop();
172170
return;
173171
}
174172

173+
if (withError)
174+
{
175+
auto *file = m_playlist->at(playlistIndex());
176+
if (file)
177+
{
178+
file->hadError(true);
179+
}
180+
181+
if (!m_playlist->hasElementsWithoutErrors())
182+
{
183+
stop();
184+
return;
185+
}
186+
}
187+
175188
// Complete random
176189
if (m_element->mode() == AudioElement::Mode::Random)
177190
{
@@ -201,7 +214,16 @@ void BufferedAudioPlayer::next()
201214
void BufferedAudioPlayer::onMediaPlayerPlaybackStateChanged(QMediaPlayer::PlaybackState newState)
202215
{
203216
qCDebug(gmAudioBufferedPlayer) << "Media player playback state changed:" << newState;
204-
if (newState == QMediaPlayer::PlayingState) state(State::Playing);
217+
if (newState == QMediaPlayer::PlayingState)
218+
{
219+
state(State::Playing);
220+
221+
auto *file = m_playlist->at(playlistIndex());
222+
if (file)
223+
{
224+
file->hadError(false);
225+
}
226+
}
205227
}
206228

207229
void BufferedAudioPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
@@ -212,7 +234,7 @@ void BufferedAudioPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
212234
{
213235
case QMediaPlayer::EndOfMedia:
214236
qCDebug(gmAudioBufferedPlayer()) << "End of media was reached, playing next file ...";
215-
next();
237+
next(false);
216238
break;
217239
case QMediaPlayer::BufferingMedia:
218240
state(State::Loading);
@@ -234,7 +256,7 @@ void BufferedAudioPlayer::onMediaPlayerErrorOccurred(QMediaPlayer::Error error,
234256

235257
if (error != QMediaPlayer::NoError)
236258
{
237-
next();
259+
next(true);
238260
}
239261
}
240262

@@ -244,7 +266,7 @@ void BufferedAudioPlayer::startPlaying()
244266

245267
if (m_element->mode() == AudioElement::Mode::Random)
246268
{
247-
next();
269+
next(false);
248270
return;
249271
}
250272

@@ -298,14 +320,21 @@ void BufferedAudioPlayer::loadWebFile(const QString &url)
298320
m_mediaPlayer.setSource(QUrl(url));
299321
m_mediaPlayer.play();
300322
m_audioOutput.setMuted(false);
323+
324+
QMediaMetaData metaData;
325+
metaData.insert(QMediaMetaData::Key::Title, "-");
326+
metaData.insert(QMediaMetaData::Key::Author, "-");
327+
metaData.insert(QMediaMetaData::Key::AlbumTitle, "-");
328+
metaData.insert(QMediaMetaData::Key::CoverArtImage, QImage());
329+
emit metaDataChanged(metaData);
301330
}
302331

303332
void BufferedAudioPlayer::loadYouTubeFile(AudioFile &file)
304333
{
305334
const Services::VideoId id(file.url());
306335
if (!id.isValid())
307336
{
308-
next();
337+
next(true);
309338
return;
310339
}
311340

@@ -314,7 +343,7 @@ void BufferedAudioPlayer::loadYouTubeFile(AudioFile &file)
314343
.then([this, &file](const Services::YouTubeVideo &video) {
315344
if (video.audioStreamUrl.isEmpty())
316345
{
317-
next();
346+
next(true);
318347
return;
319348
}
320349

@@ -333,7 +362,7 @@ void BufferedAudioPlayer::loadYouTubeFile(AudioFile &file)
333362
emit metaDataChanged(metaData);
334363
});
335364
})
336-
.onCanceled([this]() { next(); });
365+
.onCanceled([this]() { next(true); });
337366
}
338367

339368
void BufferedAudioPlayer::applyShuffleMode()

‎src/tools/audio/players/bufferedaudioplayer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public slots:
4242
void stop() override;
4343
void setVolume(int linear, int logarithmic) override;
4444
void again() override;
45-
void next() override;
45+
void next(bool withError) override;
4646

4747
signals:
4848
void playlistChanged();

‎src/tools/audio/players/musicplayer.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,27 @@ void MusicPlayer::handleUnsupportedMediaSource(const AudioFile &file)
8181
break;
8282
default:
8383
qCCritical(gmAudioMusic()) << "loadMedia() is not implemented for type" << file.source();
84-
next();
84+
next(true);
8585
break;
8686
}
8787
}
8888

8989
void MusicPlayer::loadSpotifyFile(const AudioFile &file)
9090
{
91+
if (!SpotifyPlayer::canPlay())
92+
{
93+
next(true);
94+
return;
95+
}
96+
9197
m_spotifyPlayer.play(file.url());
9298
state(State::Playing);
9399
}
94100

95101
void MusicPlayer::onSpotifySongEnded()
96102
{
97103
qCDebug(gmAudioMusic()) << "Spotify song ended, starting next song ...";
98-
next();
104+
next(false);
99105
}
100106

101107
void MusicPlayer::onSpotifyStateChanged(State state)

‎src/tools/audio/players/soundplayercontroller.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ public slots:
3333
emit stopAll();
3434
}
3535
void setVolume(int linear, int logarithmic) override;
36-
void next() override
37-
{ /* Not Implemented */
36+
void next(bool withError) override
37+
{
38+
/* Not Implemented */
39+
Q_UNUSED(withError)
3840
}
3941
void again() override
4042
{ /* Not Implemented */

‎src/tools/audio/players/spotifyplayer.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ SpotifyPlayer::SpotifyPlayer(MetaDataReader &mDReader, QObject *parent)
1818
connect(&m_metaDataTimer, &QTimer::timeout, this, &SpotifyPlayer::onMetaDataTimerTimeout);
1919
}
2020

21+
auto SpotifyPlayer::canPlay() -> bool
22+
{
23+
return isSpotifyAvailable();
24+
}
25+
2126
/// The current song has ended, stop any spotify activity and notify music player
2227
void SpotifyPlayer::onDurationTimerTimeout()
2328
{
@@ -42,7 +47,7 @@ auto SpotifyPlayer::isSpotifyAvailable() -> bool
4247
return false;
4348
}
4449

45-
qCWarning(gmAudioSpotify) << "Spotify connection is disabled.";
50+
qCWarning(gmAudioSpotify) << "Not connected to Spotify.";
4651
return false;
4752
}
4853

@@ -153,7 +158,7 @@ void SpotifyPlayer::pausePlay()
153158
/**
154159
* @brief Switch to next song in playlist
155160
*/
156-
void SpotifyPlayer::next()
161+
void SpotifyPlayer::next(bool /*withError*/)
157162
{
158163
qCDebug(gmAudioSpotify) << "Skipping to next track ...";
159164

‎src/tools/audio/players/spotifyplayer.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ class SpotifyPlayer : public AudioPlayer
1313
public:
1414
SpotifyPlayer(MetaDataReader &mDReader, QObject *parent = nullptr);
1515

16+
[[nodiscard]] static auto canPlay() -> bool;
17+
1618
public slots:
1719
void play(const QString &uri);
1820
void play() override;
1921
void pause() override;
2022
void stop() override;
2123
void pausePlay();
22-
void next() override;
24+
void next(bool withError) override;
2325
void again() override;
2426
void setVolume(int linear, int logarithmic) override;
2527

‎src/tools/audio/playlist/audioplaylist.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,13 @@ void AudioPlaylist::clear()
8787
{
8888
m_files.clear();
8989
}
90+
91+
auto AudioPlaylist::hasElementsWithoutErrors() const -> bool
92+
{
93+
foreach (const auto *file, m_files)
94+
{
95+
if (!file->hadError()) return true;
96+
}
97+
98+
return false;
99+
}

‎src/tools/audio/playlist/audioplaylist.h

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class AudioPlaylist
3737
void shuffle();
3838
void clear();
3939

40+
[[nodiscard]] auto hasElementsWithoutErrors() const -> bool;
41+
4042
private:
4143
QList<AudioFile *> m_files;
4244
Type m_type = Type::Undefined;

‎src/tools/audio/playlist/resolvingaudioplaylist.cpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ auto ResolvingAudioPlaylist::resolve() -> QFuture<void>
3838
auto ResolvingAudioPlaylist::unwrapEntries() -> QFuture<void>
3939
{
4040
QList<QFuture<void>> futures;
41-
const AudioFile *audioFile = nullptr;
41+
AudioFile *audioFile = nullptr;
4242

4343
for (qsizetype i = 0; i < length(); i++)
4444
{
@@ -73,19 +73,21 @@ auto ResolvingAudioPlaylist::unwrapEntries() -> QFuture<void>
7373
});
7474
}
7575

76-
auto ResolvingAudioPlaylist::unwrapPlaylistFile(qsizetype index, const AudioFile &file) -> QFuture<void>
76+
auto ResolvingAudioPlaylist::unwrapPlaylistFile(qsizetype index, AudioFile &file) -> QFuture<void>
7777
{
78-
auto callback = [this, index](const QByteArray &data) {
78+
auto callback = [this, index, &file](const QByteArray &data) {
7979
if (data.isEmpty())
8080
{
8181
qCWarning(gmAudioPlaylistResolving()) << "Error: File is empty!";
82+
file.hadError(true);
8283
return;
8384
}
8485

8586
auto playlist = AudioPlaylistFactory::build(data, &m_fileParent);
8687
if (playlist->isEmpty())
8788
{
8889
qCWarning(gmAudioPlaylistResolving()) << "Playlist is empty";
90+
file.hadError(true);
8991
return;
9092
}
9193

@@ -116,12 +118,18 @@ auto ResolvingAudioPlaylist::unwrapPlaylistFile(qsizetype index, const AudioFile
116118
}
117119
}
118120

119-
auto ResolvingAudioPlaylist::unwrapSpotify(qsizetype index, const AudioFile &file) -> QFuture<void>
121+
auto ResolvingAudioPlaylist::unwrapSpotify(qsizetype index, AudioFile &file) -> QFuture<void>
120122
{
121123
const auto uri = SpotifyUtils::makeUri(file.url());
122124
const auto type = SpotifyUtils::getUriType(uri);
123125
const auto id = SpotifyUtils::getIdFromUri(uri);
124126

127+
if (!Spotify::instance()->connected())
128+
{
129+
file.hadError(true);
130+
return QtFuture::makeReadyFuture();
131+
}
132+
125133
if (!SpotifyUtils::isContainerType(type)) return QtFuture::makeReadyFuture();
126134

127135
const auto callback = [this, index](const SpotifyTrackList &tracklist) {
@@ -160,7 +168,7 @@ auto ResolvingAudioPlaylist::unwrapSpotify(qsizetype index, const AudioFile &fil
160168
}
161169
}
162170

163-
auto ResolvingAudioPlaylist::unwrapYouTube(qsizetype index, const AudioFile &file) -> QFuture<void>
171+
auto ResolvingAudioPlaylist::unwrapYouTube(qsizetype index, AudioFile &file) -> QFuture<void>
164172
{
165173
const PlaylistId id(file.url());
166174
if (!id.isValid()) return QtFuture::makeReadyFuture();
@@ -177,7 +185,8 @@ auto ResolvingAudioPlaylist::unwrapYouTube(qsizetype index, const AudioFile &fil
177185
files << new AudioFile(video.id.toUrl(), AudioFile::Source::Youtube, video.title, &m_fileParent);
178186
}
179187
replace(index, files);
180-
});
188+
})
189+
.onCanceled([&file]() { file.hadError(true); });
181190
}
182191

183192
void ResolvingAudioPlaylist::loadTitles()

‎src/tools/audio/playlist/resolvingaudioplaylist.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ class ResolvingAudioPlaylist : public AudioPlaylist
1414

1515
private:
1616
auto unwrapEntries() -> QFuture<void>;
17-
auto unwrapPlaylistFile(qsizetype index, const AudioFile &file) -> QFuture<void>;
18-
auto unwrapSpotify(qsizetype index, const AudioFile &file) -> QFuture<void>;
19-
auto unwrapYouTube(qsizetype index, const AudioFile &file) -> QFuture<void>;
17+
auto unwrapPlaylistFile(qsizetype index, AudioFile &file) -> QFuture<void>;
18+
auto unwrapSpotify(qsizetype index, AudioFile &file) -> QFuture<void>;
19+
auto unwrapYouTube(qsizetype index, AudioFile &file) -> QFuture<void>;
2020

2121
void loadTitles();
2222
void loadSpotifyTitles(const QList<AudioFile *> &tracks) const;

‎src/tools/audio/project/audiofile.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ using namespace Qt::Literals::StringLiterals;
66
AudioFile::AudioFile(const QString &url, Source source, const QString &title, QObject *parent)
77
: QObject(parent), a_url(url), a_title(title), a_source(source)
88
{
9+
connect(this, &AudioFile::missingChanged, this, [this](bool missing) {
10+
if (missing) hadError(true);
11+
});
912
}
1013

11-
AudioFile::AudioFile(const QJsonObject &object, QObject *parent) : QObject(parent)
14+
AudioFile::AudioFile(const QJsonObject &object, QObject *parent)
15+
: AudioFile(object["url"_L1].toString(), static_cast<Source>(object["source"_L1].toInt()), u""_s, parent)
1216
{
13-
url(object["url"_L1].toString());
14-
a_source = static_cast<Source>(object["source"_L1].toInt());
1517
}
1618

1719
AudioFile::AudioFile(const AudioFile &other) : AudioFile(other.url(), other.source(), other.title(), other.parent())

‎src/tools/audio/project/audiofile.h

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class AudioFile : public QObject
3737
AUTO_PROPERTY(QString, title)
3838
AUTO_PROPERTY_VAL(Source, source)
3939
AUTO_PROPERTY_VAL2(bool, missing, false)
40+
AUTO_PROPERTY_VAL2(bool, hadError, false)
4041
Q_PROPERTY(QString printableUrl READ printableUrl NOTIFY urlChanged)
4142
};
4243

0 commit comments

Comments
 (0)
Please sign in to comment.