Add SPDX license identifiers to all source files

This commit is contained in:
Sebastian Palencsar
2026-05-27 07:11:33 +02:00
parent 721900083c
commit 9c9b250e5e
20 changed files with 206 additions and 161 deletions

View File

@@ -1,195 +1,183 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "bearplayer.h"
#include <QUrl>
#include <QDebug>
#include <QMediaMetaData>
#include <QUrl>
BearPlayer::BearPlayer(QObject *parent) : QObject(parent) {
m_audioOutput = new QAudioOutput(this);
m_mediaPlayer = new QMediaPlayer(this);
m_mediaPlayer->setAudioOutput(m_audioOutput);
m_coverArtFetcher = new CoverArtFetcher(this);
connect(m_coverArtFetcher, &CoverArtFetcher::coverUrlReady, this,
&BearPlayer::onCoverUrlReady);
BearPlayer::BearPlayer(QObject *parent)
: QObject(parent)
{
m_audioOutput = new QAudioOutput(this);
m_mediaPlayer = new QMediaPlayer(this);
m_mediaPlayer->setAudioOutput(m_audioOutput);
m_icyReader = new IcyReader(this);
connect(m_icyReader, &IcyReader::metaDataReceived, this,
&BearPlayer::onIcyMetaDataReceived);
m_coverArtFetcher = new CoverArtFetcher(this);
connect(m_coverArtFetcher, &CoverArtFetcher::coverUrlReady, this, &BearPlayer::onCoverUrlReady);
connect(m_mediaPlayer, &QMediaPlayer::playbackStateChanged, this,
&BearPlayer::onPlaybackStateChanged);
connect(m_mediaPlayer, &QMediaPlayer::mediaStatusChanged, this,
&BearPlayer::onMediaStatusChanged);
connect(m_mediaPlayer, &QMediaPlayer::metaDataChanged, this,
&BearPlayer::onMetaDataChanged);
m_icyReader = new IcyReader(this);
connect(m_icyReader, &IcyReader::metaDataReceived, this, &BearPlayer::onIcyMetaDataReceived);
connect(m_mediaPlayer, &QMediaPlayer::playbackStateChanged,
this, &BearPlayer::onPlaybackStateChanged);
connect(m_mediaPlayer, &QMediaPlayer::mediaStatusChanged,
this, &BearPlayer::onMediaStatusChanged);
connect(m_mediaPlayer, &QMediaPlayer::metaDataChanged,
this, &BearPlayer::onMetaDataChanged);
m_retryTimer.setSingleShot(true);
m_retryTimer.setInterval(1200);
connect(&m_retryTimer, &QTimer::timeout, this, [this]() {
if (m_lastUrl.isEmpty() || m_playing || m_retryAttempts >= 2) {
return;
}
++m_retryAttempts;
m_mediaPlayer->setSource(QUrl(m_lastUrl));
m_mediaPlayer->play();
qDebug() << "Retry stream" << m_retryAttempts << m_lastName;
});
}
BearPlayer::~BearPlayer()
{
stop();
}
void BearPlayer::playUrl(const QString &url, const QString &name)
{
if (url.isEmpty()) {
return;
m_retryTimer.setSingleShot(true);
m_retryTimer.setInterval(1200);
connect(&m_retryTimer, &QTimer::timeout, this, [this]() {
if (m_lastUrl.isEmpty() || m_playing || m_retryAttempts >= 2) {
return;
}
m_currentStationName = name;
m_lastName = name;
m_lastUrl = url;
m_retryAttempts = 0;
emit currentStationChanged(m_currentStationName);
clearTrackInfo();
m_mediaPlayer->setSource(QUrl(url));
++m_retryAttempts;
m_mediaPlayer->setSource(QUrl(m_lastUrl));
m_mediaPlayer->play();
m_icyReader->start(url);
qDebug() << "Playing:" << name << url;
qDebug() << "Retry stream" << m_retryAttempts << m_lastName;
});
}
void BearPlayer::stop()
{
m_mediaPlayer->stop();
m_icyReader->stop();
m_currentStationName.clear();
m_lastName.clear();
m_lastUrl.clear();
m_retryAttempts = 0;
emit currentStationChanged(QString());
clearTrackInfo();
BearPlayer::~BearPlayer() { stop(); }
void BearPlayer::playUrl(const QString &url, const QString &name) {
if (url.isEmpty()) {
return;
}
m_currentStationName = name;
m_lastName = name;
m_lastUrl = url;
m_retryAttempts = 0;
emit currentStationChanged(m_currentStationName);
clearTrackInfo();
m_mediaPlayer->setSource(QUrl(url));
m_mediaPlayer->play();
m_icyReader->start(url);
qDebug() << "Playing:" << name << url;
}
void BearPlayer::togglePlayPause()
{
if (m_playing) {
m_mediaPlayer->pause();
} else {
m_mediaPlayer->play();
}
void BearPlayer::stop() {
m_mediaPlayer->stop();
m_icyReader->stop();
m_currentStationName.clear();
m_lastName.clear();
m_lastUrl.clear();
m_retryAttempts = 0;
emit currentStationChanged(QString());
clearTrackInfo();
}
void BearPlayer::setVolume(qreal vol)
{
m_audioOutput->setVolume(qBound(0.0, vol, 1.0));
emit volumeChanged(m_audioOutput->volume());
void BearPlayer::togglePlayPause() {
if (m_playing) {
m_mediaPlayer->pause();
} else {
m_mediaPlayer->play();
}
}
void BearPlayer::onPlaybackStateChanged(QMediaPlayer::PlaybackState state)
{
m_playing = (state == QMediaPlayer::PlayingState);
void BearPlayer::setVolume(qreal vol) {
m_audioOutput->setVolume(qBound(0.0, vol, 1.0));
emit volumeChanged(m_audioOutput->volume());
}
void BearPlayer::onPlaybackStateChanged(QMediaPlayer::PlaybackState state) {
m_playing = (state == QMediaPlayer::PlayingState);
emit playingChanged(m_playing);
if (state == QMediaPlayer::StoppedState) {
scheduleRetry();
}
}
void BearPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status) {
if (status == QMediaPlayer::InvalidMedia) {
m_playing = false;
emit playingChanged(m_playing);
if (state == QMediaPlayer::StoppedState) {
scheduleRetry();
}
scheduleRetry();
}
}
void BearPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
{
if (status == QMediaPlayer::InvalidMedia) {
m_playing = false;
emit playingChanged(m_playing);
scheduleRetry();
}
void BearPlayer::scheduleRetry() {
if (m_lastUrl.isEmpty() || m_retryAttempts >= 2 || m_playing) {
return;
}
if (!m_retryTimer.isActive()) {
m_retryTimer.start();
}
}
void BearPlayer::scheduleRetry()
{
if (m_lastUrl.isEmpty() || m_retryAttempts >= 2 || m_playing) {
return;
}
if (!m_retryTimer.isActive()) {
m_retryTimer.start();
}
void BearPlayer::onMetaDataChanged() {
QMediaMetaData meta = m_mediaPlayer->metaData();
QString artist = meta.stringValue(QMediaMetaData::ContributingArtist);
if (artist.isEmpty()) {
artist = meta.stringValue(QMediaMetaData::Author);
}
QString title = meta.stringValue(QMediaMetaData::Title);
// Ignore completely empty metadata from QMediaPlayer so we don't overwrite
// IcyReader
if (artist.isEmpty() && title.isEmpty()) {
return;
}
if (m_currentTrackArtist == artist && m_currentTrackTitle == title) {
return;
}
m_currentTrackArtist = artist;
m_currentTrackTitle = title;
m_currentCoverArtUrl.clear();
m_coverArtFetcher->fetch(artist, title);
emit trackInfoChanged();
}
void BearPlayer::onMetaDataChanged()
{
QMediaMetaData meta = m_mediaPlayer->metaData();
QString artist = meta.stringValue(QMediaMetaData::ContributingArtist);
if (artist.isEmpty()) {
artist = meta.stringValue(QMediaMetaData::Author);
}
QString title = meta.stringValue(QMediaMetaData::Title);
// Ignore completely empty metadata from QMediaPlayer so we don't overwrite IcyReader
if (artist.isEmpty() && title.isEmpty()) {
return;
}
if (m_currentTrackArtist == artist && m_currentTrackTitle == title) {
return;
}
m_currentTrackArtist = artist;
m_currentTrackTitle = title;
m_currentCoverArtUrl.clear();
m_coverArtFetcher->fetch(artist, title);
void BearPlayer::onCoverUrlReady(const QString &url) {
if (m_currentCoverArtUrl != url) {
m_currentCoverArtUrl = url;
emit trackInfoChanged();
}
}
void BearPlayer::onCoverUrlReady(const QString &url)
{
if (m_currentCoverArtUrl != url) {
m_currentCoverArtUrl = url;
emit trackInfoChanged();
}
void BearPlayer::onIcyMetaDataReceived(const QString &artist,
const QString &title) {
if (m_currentTrackArtist == artist && m_currentTrackTitle == title) {
return;
}
m_currentTrackArtist = artist;
m_currentTrackTitle = title;
m_currentCoverArtUrl.clear();
m_coverArtFetcher->fetch(artist, title);
emit trackInfoChanged();
}
void BearPlayer::onIcyMetaDataReceived(const QString &artist, const QString &title)
{
if (m_currentTrackArtist == artist && m_currentTrackTitle == title) {
return;
}
m_currentTrackArtist = artist;
m_currentTrackTitle = title;
m_currentCoverArtUrl.clear();
m_coverArtFetcher->fetch(artist, title);
emit trackInfoChanged();
QString BearPlayer::currentNowPlaying() const {
if (!m_currentTrackArtist.isEmpty() && !m_currentTrackTitle.isEmpty()) {
return m_currentTrackArtist + QStringLiteral(" - ") + m_currentTrackTitle;
}
if (!m_currentTrackTitle.isEmpty()) {
return m_currentTrackTitle;
}
if (!m_currentTrackArtist.isEmpty()) {
return m_currentTrackArtist;
}
return QString();
}
QString BearPlayer::currentNowPlaying() const
{
if (!m_currentTrackArtist.isEmpty() && !m_currentTrackTitle.isEmpty()) {
return m_currentTrackArtist + QStringLiteral(" - ") + m_currentTrackTitle;
}
if (!m_currentTrackTitle.isEmpty()) {
return m_currentTrackTitle;
}
if (!m_currentTrackArtist.isEmpty()) {
return m_currentTrackArtist;
}
return QString();
}
void BearPlayer::clearTrackInfo()
{
if (m_currentTrackArtist.isEmpty() && m_currentTrackTitle.isEmpty()) {
return;
}
m_currentTrackArtist.clear();
m_currentTrackTitle.clear();
m_currentCoverArtUrl.clear();
m_coverArtFetcher->fetch(QString(), QString());
emit trackInfoChanged();
void BearPlayer::clearTrackInfo() {
if (m_currentTrackArtist.isEmpty() && m_currentTrackTitle.isEmpty()) {
return;
}
m_currentTrackArtist.clear();
m_currentTrackTitle.clear();
m_currentCoverArtUrl.clear();
m_coverArtFetcher->fetch(QString(), QString());
emit trackInfoChanged();
}

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef BEARPLAYER_H
#define BEARPLAYER_H

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "bearwavecontroladaptor.h"
#include "radiobackend.h"

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef BEARWAVECONTROLADAPTOR_H
#define BEARWAVECONTROLADAPTOR_H

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "coverartfetcher.h"
#include <QUrlQuery>
#include <QJsonDocument>

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef COVERARTFETCHER_H
#define COVERARTFETCHER_H

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "icyreader.h"
#include <QNetworkRequest>
#include <QDebug>

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef ICYREADER_H
#define ICYREADER_H

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include <QApplication>
#include <QDBusConnection>
#include <QIcon>

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "mprisadaptor.h"
#include "radiobackend.h"

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef MPRISADAPTOR_H
#define MPRISADAPTOR_H

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "notificationmanager.h"
#include "radiobackend.h"
#include "bearplayer.h"

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef NOTIFICATIONMANAGER_H
#define NOTIFICATIONMANAGER_H

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "radiobackend.h"
#include <QDebug>

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef RADIOBACKEND_H
#define RADIOBACKEND_H

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "radiobrowser.h"
#include <QJsonDocument>

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef RADIOBROWSER_H
#define RADIOBROWSER_H

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#include "radiostation.h"
#include <QJsonObject>

View File

@@ -1,3 +1,6 @@
// Copyright (c) 2026 Sebastian Palencsar
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef RADIOSTATION_H
#define RADIOSTATION_H