mirror of
https://github.com/spalencsar/bearwave.git
synced 2026-07-06 14:24:14 +02:00
Migrate to QtMultimedia and prepare for Flathub
This commit is contained in:
@@ -10,15 +10,14 @@ set(CMAKE_AUTORCC ON)
|
|||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
# Qt6
|
# Qt6
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core DBus Quick QuickControls2 Widgets LinguistTools)
|
find_package(Qt6 REQUIRED COMPONENTS Core DBus Quick QuickControls2 Widgets LinguistTools Multimedia)
|
||||||
|
|
||||||
# KDE Frameworks
|
# KDE Frameworks
|
||||||
find_package(KF6Kirigami REQUIRED)
|
find_package(KF6Kirigami REQUIRED)
|
||||||
find_package(KF6I18n REQUIRED)
|
find_package(KF6I18n REQUIRED)
|
||||||
find_package(KF6CoreAddons REQUIRED)
|
find_package(KF6CoreAddons REQUIRED)
|
||||||
|
|
||||||
# Phonon (Qt6)
|
|
||||||
find_package(Phonon4Qt6 REQUIRED)
|
|
||||||
|
|
||||||
# Add src directory
|
# Add src directory
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
@@ -33,3 +32,6 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.bearwave.desktop DESTINATION s
|
|||||||
|
|
||||||
# Install app icon
|
# Install app icon
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/app/bearwave.png DESTINATION share/icons/hicolor/256x256/apps RENAME org.kde.bearwave.png)
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/app/bearwave.png DESTINATION share/icons/hicolor/256x256/apps RENAME org.kde.bearwave.png)
|
||||||
|
|
||||||
|
# Install AppStream metadata
|
||||||
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.bearwave.metainfo.xml DESTINATION share/metainfo)
|
||||||
|
|||||||
2
PKGBUILD
2
PKGBUILD
@@ -5,7 +5,7 @@ pkgdesc="A KDE-focused desktop internet radio app"
|
|||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
url="https://github.com/bearwave/bearwave" # Replace with actual URL if different
|
url="https://github.com/bearwave/bearwave" # Replace with actual URL if different
|
||||||
license=('MIT')
|
license=('MIT')
|
||||||
depends=('qt6-base' 'qt6-declarative' 'kirigami' 'ki18n' 'kcoreaddons' 'phonon-qt6')
|
depends=('qt6-base' 'qt6-declarative' 'kirigami' 'ki18n' 'kcoreaddons' 'qt6-multimedia')
|
||||||
makedepends=('cmake' 'extra-cmake-modules' 'git')
|
makedepends=('cmake' 'extra-cmake-modules' 'git')
|
||||||
provides=('bearwave')
|
provides=('bearwave')
|
||||||
conflicts=('bearwave')
|
conflicts=('bearwave')
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -1,6 +1,6 @@
|
|||||||
# BearWave
|
# BearWave
|
||||||
|
|
||||||
KDE-focused desktop internet radio app for Linux, built with Qt 6, QML, KDE Frameworks, and Phonon.
|
KDE-focused desktop internet radio app for Linux, built with Qt 6, QML, KDE Frameworks, and QtMultimedia.
|
||||||
|
|
||||||
BearWave is designed for fast station browsing, simple playback controls, favorites, resume support, tray behavior, and clean Plasma integration without turning into a heavy media suite.
|
BearWave is designed for fast station browsing, simple playback controls, favorites, resume support, tray behavior, and clean Plasma integration without turning into a heavy media suite.
|
||||||
|
|
||||||
@@ -48,6 +48,16 @@ Then launch:
|
|||||||
~/.local/bin/bearwave
|
~/.local/bin/bearwave
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Option C: Flatpak (Local Build)
|
||||||
|
|
||||||
|
If you have `flatpak` and `flatpak-builder` installed, you can build and install BearWave via Flatpak:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flatpak-builder build-dir org.kde.bearwave.json --force-clean --user --install
|
||||||
|
flatpak run org.kde.bearwave
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## What BearWave Is
|
## What BearWave Is
|
||||||
|
|
||||||
BearWave focuses on:
|
BearWave focuses on:
|
||||||
@@ -98,8 +108,7 @@ Current priorities:
|
|||||||
Current distribution status:
|
Current distribution status:
|
||||||
|
|
||||||
- source repository is the primary delivery format
|
- source repository is the primary delivery format
|
||||||
- Arch Linux is the best-supported packaging path at the moment
|
- experimental Flatpak manifest included for local sandbox building
|
||||||
- no official Flatpak, AppImage, or broad distro release pipeline yet
|
|
||||||
|
|
||||||
## Platform And Support
|
## Platform And Support
|
||||||
|
|
||||||
@@ -118,7 +127,7 @@ BearWave is currently aligned with and tested primarily against:
|
|||||||
- KDE Plasma 6
|
- KDE Plasma 6
|
||||||
- Qt 6
|
- Qt 6
|
||||||
- KDE Frameworks 6
|
- KDE Frameworks 6
|
||||||
- Phonon4Qt6
|
- Qt6 Multimedia
|
||||||
|
|
||||||
If support for other distributions becomes reliable, they should be added here explicitly instead of implied.
|
If support for other distributions becomes reliable, they should be added here explicitly instead of implied.
|
||||||
|
|
||||||
@@ -139,7 +148,7 @@ BearWave should currently be understood as:
|
|||||||
|
|
||||||
- officially documented for source builds
|
- officially documented for source builds
|
||||||
- most naturally aligned with Arch Linux packaging
|
- most naturally aligned with Arch Linux packaging
|
||||||
- likely portable to other Linux distributions with Qt 6 / KF6 / Phonon packages available
|
- likely portable to other Linux distributions with Qt 6 / KF6 / QtMultimedia packages available
|
||||||
- not yet positioned as a broadly packaged consumer desktop app
|
- not yet positioned as a broadly packaged consumer desktop app
|
||||||
|
|
||||||
If you want the least surprising path today, use either:
|
If you want the least surprising path today, use either:
|
||||||
@@ -153,14 +162,14 @@ If you want the least surprising path today, use either:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo pacman -S cmake extra-cmake-modules qt6-base qt6-declarative qt6-tools \
|
sudo pacman -S cmake extra-cmake-modules qt6-base qt6-declarative qt6-tools \
|
||||||
kirigami phonon-qt6 phonon-qt6-vlc vlc
|
kirigami qt6-multimedia qt6-multimedia-ffmpeg
|
||||||
```
|
```
|
||||||
|
|
||||||
### KDE Neon / Ubuntu-based
|
### KDE Neon / Ubuntu-based
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt install cmake ninja-build qt6-base-dev qt6-declarative-dev qt6-tools-dev \
|
sudo apt install cmake ninja-build qt6-base-dev qt6-declarative-dev qt6-tools-dev \
|
||||||
libkf6kirigami-dev libkf6i18n-dev libkf6coreaddons-dev phonon4qt6-dev
|
libkf6kirigami-dev libkf6i18n-dev libkf6coreaddons-dev qt6-multimedia-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: exact package names can vary between distro releases, and non-Arch dependency sets should currently be treated as best-effort guidance rather than a guaranteed tested path.
|
Note: exact package names can vary between distro releases, and non-Arch dependency sets should currently be treated as best-effort guidance rather than a guaranteed tested path.
|
||||||
@@ -203,7 +212,7 @@ cmake --build build -j"$(nproc)"
|
|||||||
- Linux desktop session
|
- Linux desktop session
|
||||||
- KDE Plasma recommended
|
- KDE Plasma recommended
|
||||||
- Qt 6 runtime libraries
|
- Qt 6 runtime libraries
|
||||||
- Phonon4Qt6 with a working backend
|
- Qt6 Multimedia backend (e.g. ffmpeg or gstreamer)
|
||||||
- network access to Radio Browser instances
|
- network access to Radio Browser instances
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -266,8 +275,7 @@ rm -f "$HOME/.config/autostart/org.kde.bearwave.desktop"
|
|||||||
|
|
||||||
### No audio playback
|
### No audio playback
|
||||||
|
|
||||||
- ensure `phonon-qt6` and `phonon-qt6-vlc` or equivalent are installed
|
- ensure `qt6-multimedia` and a backend like `qt6-multimedia-ffmpeg` or `gst-plugins-good` are installed
|
||||||
- ensure `vlc` is installed
|
|
||||||
- test another station URL because some streams go offline
|
- test another station URL because some streams go offline
|
||||||
|
|
||||||
### App icon or launcher entry not updating
|
### App icon or launcher entry not updating
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 252 KiB After Width: | Height: | Size: 90 KiB |
29
org.kde.bearwave.json
Normal file
29
org.kde.bearwave.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"app-id": "org.kde.bearwave",
|
||||||
|
"runtime": "org.kde.Platform",
|
||||||
|
"runtime-version": "6.6",
|
||||||
|
"sdk": "org.kde.Sdk",
|
||||||
|
"command": "bearwave",
|
||||||
|
"finish-args": [
|
||||||
|
"--share=network",
|
||||||
|
"--socket=wayland",
|
||||||
|
"--socket=fallback-x11",
|
||||||
|
"--socket=pulseaudio",
|
||||||
|
"--own-name=org.mpris.MediaPlayer2.bearwave",
|
||||||
|
"--talk-name=org.freedesktop.Notifications",
|
||||||
|
"--talk-name=org.kde.StatusNotifierWatcher"
|
||||||
|
],
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"name": "bearwave",
|
||||||
|
"buildsystem": "cmake-ninja",
|
||||||
|
"builddir": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "dir",
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
67
org.kde.bearwave.metainfo.xml
Normal file
67
org.kde.bearwave.metainfo.xml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop-application">
|
||||||
|
<id>org.kde.bearwave</id>
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>MIT</project_license>
|
||||||
|
|
||||||
|
<name>BearWave</name>
|
||||||
|
<summary>KDE-focused desktop internet radio app</summary>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
BearWave is designed for fast station browsing, simple playback controls, favorites, resume support, tray behavior, and clean Plasma integration without turning into a heavy media suite.
|
||||||
|
</p>
|
||||||
|
<p>Features:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Internet radio via the Radio Browser API with local JSON caching</li>
|
||||||
|
<li>Station pages for Top, Germany, Netherlands, and quick world/genre filters</li>
|
||||||
|
<li>Local search and filtering by name, genre, and country</li>
|
||||||
|
<li>Sorting by name, bitrate, and votes</li>
|
||||||
|
<li>Favorites with persistent local storage</li>
|
||||||
|
<li>Playback metadata display when streams provide it</li>
|
||||||
|
<li>Resume support for last station and volume</li>
|
||||||
|
<li>MPRIS integration for Plasma media controls and media keys</li>
|
||||||
|
<li>System tray integration for background playback</li>
|
||||||
|
<li>Desktop notifications for song/track changes with local cover art caching</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<launchable type="desktop-id">org.kde.bearwave.desktop</launchable>
|
||||||
|
|
||||||
|
<screenshots>
|
||||||
|
<screenshot type="default">
|
||||||
|
<image>https://raw.githubusercontent.com/spalencsar/bearwave/main/screenshots/screen01.png</image>
|
||||||
|
<caption>Main window displaying radio categories</caption>
|
||||||
|
</screenshot>
|
||||||
|
<screenshot>
|
||||||
|
<image>https://raw.githubusercontent.com/spalencsar/bearwave/main/screenshots/screen02.png</image>
|
||||||
|
<caption>Station browser and search filters</caption>
|
||||||
|
</screenshot>
|
||||||
|
<screenshot>
|
||||||
|
<image>https://raw.githubusercontent.com/spalencsar/bearwave/main/screenshots/screen03.png</image>
|
||||||
|
<caption>The About dialog showing application info</caption>
|
||||||
|
</screenshot>
|
||||||
|
</screenshots>
|
||||||
|
|
||||||
|
<url type="homepage">https://github.com/spalencsar/bearwave</url>
|
||||||
|
<url type="bugtracker">https://github.com/spalencsar/bearwave/issues</url>
|
||||||
|
|
||||||
|
<developer_name>Sebastian (spalencsar)</developer_name>
|
||||||
|
|
||||||
|
<provides>
|
||||||
|
<binary>bearwave</binary>
|
||||||
|
</provides>
|
||||||
|
|
||||||
|
<releases>
|
||||||
|
<release version="1.0.1" date="2026-05-23">
|
||||||
|
<description>
|
||||||
|
<ul>
|
||||||
|
<li>Fixed NotificationManager crash (segfault)</li>
|
||||||
|
<li>Migrated to modern QtMultimedia engine from legacy Phonon</li>
|
||||||
|
<li>Added Flatpak manifest and build support</li>
|
||||||
|
<li>Added debounced online search</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
</releases>
|
||||||
|
</component>
|
||||||
@@ -19,7 +19,7 @@ add_executable(bearwave ${SOURCES})
|
|||||||
# Qt Resources
|
# Qt Resources
|
||||||
target_sources(bearwave PRIVATE qml.qrc)
|
target_sources(bearwave PRIVATE qml.qrc)
|
||||||
|
|
||||||
qt_add_lrelease(
|
qt_add_lrelease(bearwave
|
||||||
TS_FILES
|
TS_FILES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../translations/bearwave_de.ts
|
${CMAKE_CURRENT_SOURCE_DIR}/../translations/bearwave_de.ts
|
||||||
QM_FILES_OUTPUT_VARIABLE bearwave_qm_files
|
QM_FILES_OUTPUT_VARIABLE bearwave_qm_files
|
||||||
@@ -43,10 +43,10 @@ target_link_libraries(bearwave PRIVATE
|
|||||||
Qt6::Quick
|
Qt6::Quick
|
||||||
Qt6::QuickControls2
|
Qt6::QuickControls2
|
||||||
Qt6::Widgets
|
Qt6::Widgets
|
||||||
|
Qt6::Multimedia
|
||||||
KF6::Kirigami
|
KF6::Kirigami
|
||||||
KF6::I18n
|
KF6::I18n
|
||||||
KF6::CoreAddons
|
KF6::CoreAddons
|
||||||
Phonon::phonon4qt6
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Install
|
# Install
|
||||||
|
|||||||
@@ -2,36 +2,25 @@
|
|||||||
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QMediaMetaData>
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
QString firstMetaValue(const QMultiMap<QString, QString> &meta, const QStringList &keys)
|
|
||||||
{
|
|
||||||
for (const QString &key : keys) {
|
|
||||||
if (meta.contains(key)) {
|
|
||||||
const QString value = meta.value(key).trimmed();
|
|
||||||
if (!value.isEmpty()) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BearPlayer::BearPlayer(QObject *parent)
|
BearPlayer::BearPlayer(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
m_mediaObject = new Phonon::MediaObject(this);
|
m_audioOutput = new QAudioOutput(this);
|
||||||
m_audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
|
m_mediaPlayer = new QMediaPlayer(this);
|
||||||
|
m_mediaPlayer->setAudioOutput(m_audioOutput);
|
||||||
|
|
||||||
m_coverArtFetcher = new CoverArtFetcher(this);
|
m_coverArtFetcher = new CoverArtFetcher(this);
|
||||||
connect(m_coverArtFetcher, &CoverArtFetcher::coverUrlReady, this, &BearPlayer::onCoverUrlReady);
|
connect(m_coverArtFetcher, &CoverArtFetcher::coverUrlReady, this, &BearPlayer::onCoverUrlReady);
|
||||||
|
|
||||||
Phonon::createPath(m_mediaObject, m_audioOutput);
|
connect(m_mediaPlayer, &QMediaPlayer::playbackStateChanged,
|
||||||
|
this, &BearPlayer::onPlaybackStateChanged);
|
||||||
connect(m_mediaObject, &Phonon::MediaObject::stateChanged,
|
connect(m_mediaPlayer, &QMediaPlayer::mediaStatusChanged,
|
||||||
this, &BearPlayer::onStateChanged);
|
this, &BearPlayer::onMediaStatusChanged);
|
||||||
connect(m_mediaObject, &Phonon::MediaObject::metaDataChanged,
|
connect(m_mediaPlayer, &QMediaPlayer::metaDataChanged,
|
||||||
this, &BearPlayer::onMetaDataChanged);
|
this, &BearPlayer::onMetaDataChanged);
|
||||||
|
|
||||||
m_retryTimer.setSingleShot(true);
|
m_retryTimer.setSingleShot(true);
|
||||||
@@ -41,8 +30,8 @@ BearPlayer::BearPlayer(QObject *parent)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
++m_retryAttempts;
|
++m_retryAttempts;
|
||||||
m_mediaObject->setCurrentSource(QUrl(m_lastUrl));
|
m_mediaPlayer->setSource(QUrl(m_lastUrl));
|
||||||
m_mediaObject->play();
|
m_mediaPlayer->play();
|
||||||
qDebug() << "Retry stream" << m_retryAttempts << m_lastName;
|
qDebug() << "Retry stream" << m_retryAttempts << m_lastName;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -65,15 +54,15 @@ void BearPlayer::playUrl(const QString &url, const QString &name)
|
|||||||
emit currentStationChanged(m_currentStationName);
|
emit currentStationChanged(m_currentStationName);
|
||||||
clearTrackInfo();
|
clearTrackInfo();
|
||||||
|
|
||||||
m_mediaObject->setCurrentSource(QUrl(url));
|
m_mediaPlayer->setSource(QUrl(url));
|
||||||
m_mediaObject->play();
|
m_mediaPlayer->play();
|
||||||
|
|
||||||
qDebug() << "Playing:" << name << url;
|
qDebug() << "Playing:" << name << url;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BearPlayer::stop()
|
void BearPlayer::stop()
|
||||||
{
|
{
|
||||||
m_mediaObject->stop();
|
m_mediaPlayer->stop();
|
||||||
m_currentStationName.clear();
|
m_currentStationName.clear();
|
||||||
m_lastName.clear();
|
m_lastName.clear();
|
||||||
m_lastUrl.clear();
|
m_lastUrl.clear();
|
||||||
@@ -85,9 +74,9 @@ void BearPlayer::stop()
|
|||||||
void BearPlayer::togglePlayPause()
|
void BearPlayer::togglePlayPause()
|
||||||
{
|
{
|
||||||
if (m_playing) {
|
if (m_playing) {
|
||||||
m_mediaObject->pause();
|
m_mediaPlayer->pause();
|
||||||
} else {
|
} else {
|
||||||
m_mediaObject->play();
|
m_mediaPlayer->play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,18 +86,23 @@ void BearPlayer::setVolume(qreal vol)
|
|||||||
emit volumeChanged(m_audioOutput->volume());
|
emit volumeChanged(m_audioOutput->volume());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BearPlayer::onStateChanged(int state)
|
void BearPlayer::onPlaybackStateChanged(QMediaPlayer::PlaybackState state)
|
||||||
{
|
{
|
||||||
switch (state) {
|
m_playing = (state == QMediaPlayer::PlayingState);
|
||||||
case 2:
|
|
||||||
m_playing = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
m_playing = false;
|
|
||||||
scheduleRetry();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
emit playingChanged(m_playing);
|
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);
|
||||||
|
scheduleRetry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BearPlayer::scheduleRetry()
|
void BearPlayer::scheduleRetry()
|
||||||
@@ -123,28 +117,15 @@ void BearPlayer::scheduleRetry()
|
|||||||
|
|
||||||
void BearPlayer::onMetaDataChanged()
|
void BearPlayer::onMetaDataChanged()
|
||||||
{
|
{
|
||||||
const QMultiMap<QString, QString> meta = m_mediaObject->metaData();
|
QMediaMetaData meta = m_mediaPlayer->metaData();
|
||||||
|
|
||||||
const QString artist = firstMetaValue(meta, {
|
QString artist = meta.stringValue(QMediaMetaData::ContributingArtist);
|
||||||
QStringLiteral("ARTIST"),
|
if (artist.isEmpty()) {
|
||||||
QStringLiteral("artist"),
|
artist = meta.stringValue(QMediaMetaData::Author);
|
||||||
QStringLiteral("Artist")
|
|
||||||
});
|
|
||||||
|
|
||||||
QString title = firstMetaValue(meta, {
|
|
||||||
QStringLiteral("TITLE"),
|
|
||||||
QStringLiteral("title"),
|
|
||||||
QStringLiteral("Title")
|
|
||||||
});
|
|
||||||
|
|
||||||
if (title.isEmpty()) {
|
|
||||||
title = firstMetaValue(meta, {
|
|
||||||
QStringLiteral("icy-title"),
|
|
||||||
QStringLiteral("Icy-Title"),
|
|
||||||
QStringLiteral("StreamTitle")
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString title = meta.stringValue(QMediaMetaData::Title);
|
||||||
|
|
||||||
if (m_currentTrackArtist == artist && m_currentTrackTitle == title) {
|
if (m_currentTrackArtist == artist && m_currentTrackTitle == title) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include <phonon4qt6/phonon/MediaObject>
|
#include <QMediaPlayer>
|
||||||
#include <phonon4qt6/phonon/AudioOutput>
|
#include <QAudioOutput>
|
||||||
#include "coverartfetcher.h"
|
#include "coverartfetcher.h"
|
||||||
|
|
||||||
class BearPlayer : public QObject
|
class BearPlayer : public QObject
|
||||||
@@ -44,7 +44,8 @@ signals:
|
|||||||
void trackInfoChanged();
|
void trackInfoChanged();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onStateChanged(int state);
|
void onPlaybackStateChanged(QMediaPlayer::PlaybackState state);
|
||||||
|
void onMediaStatusChanged(QMediaPlayer::MediaStatus status);
|
||||||
void onMetaDataChanged();
|
void onMetaDataChanged();
|
||||||
void onCoverUrlReady(const QString &url);
|
void onCoverUrlReady(const QString &url);
|
||||||
|
|
||||||
@@ -52,8 +53,8 @@ private:
|
|||||||
void clearTrackInfo();
|
void clearTrackInfo();
|
||||||
void scheduleRetry();
|
void scheduleRetry();
|
||||||
|
|
||||||
Phonon::MediaObject *m_mediaObject = nullptr;
|
QMediaPlayer *m_mediaPlayer = nullptr;
|
||||||
Phonon::AudioOutput *m_audioOutput = nullptr;
|
QAudioOutput *m_audioOutput = nullptr;
|
||||||
QTimer m_retryTimer;
|
QTimer m_retryTimer;
|
||||||
QString m_currentStationName;
|
QString m_currentStationName;
|
||||||
QString m_currentTrackTitle;
|
QString m_currentTrackTitle;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication::setApplicationName(QStringLiteral("BearWave"));
|
QApplication::setApplicationName(QStringLiteral("BearWave"));
|
||||||
QApplication::setDesktopFileName(QStringLiteral("org.kde.bearwave.desktop"));
|
QApplication::setDesktopFileName(QStringLiteral("org.kde.bearwave"));
|
||||||
QApplication::setOrganizationName(QStringLiteral("BearWave"));
|
QApplication::setOrganizationName(QStringLiteral("BearWave"));
|
||||||
QApplication::setApplicationVersion(QStringLiteral("1.0.1"));
|
QApplication::setApplicationVersion(QStringLiteral("1.0.1"));
|
||||||
|
|
||||||
|
|||||||
@@ -45,9 +45,11 @@ void NotificationManager::onTrackInfoChanged()
|
|||||||
if (artist.isEmpty() && title.isEmpty()) {
|
if (artist.isEmpty() && title.isEmpty()) {
|
||||||
m_notifyTimer.stop();
|
m_notifyTimer.stop();
|
||||||
if (m_currentReply) {
|
if (m_currentReply) {
|
||||||
m_currentReply->abort();
|
QNetworkReply *reply = m_currentReply;
|
||||||
m_currentReply->deleteLater();
|
|
||||||
m_currentReply = nullptr;
|
m_currentReply = nullptr;
|
||||||
|
reply->disconnect(this);
|
||||||
|
reply->abort();
|
||||||
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
closeNotification();
|
closeNotification();
|
||||||
m_lastArtist.clear();
|
m_lastArtist.clear();
|
||||||
@@ -64,9 +66,11 @@ void NotificationManager::onTrackInfoChanged()
|
|||||||
if (trackChanged) {
|
if (trackChanged) {
|
||||||
m_notifyTimer.stop();
|
m_notifyTimer.stop();
|
||||||
if (m_currentReply) {
|
if (m_currentReply) {
|
||||||
m_currentReply->abort();
|
QNetworkReply *reply = m_currentReply;
|
||||||
m_currentReply->deleteLater();
|
|
||||||
m_currentReply = nullptr;
|
m_currentReply = nullptr;
|
||||||
|
reply->disconnect(this);
|
||||||
|
reply->abort();
|
||||||
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
m_lastArtist = artist;
|
m_lastArtist = artist;
|
||||||
m_lastTitle = title;
|
m_lastTitle = title;
|
||||||
@@ -115,9 +119,11 @@ void NotificationManager::onTrackInfoChanged()
|
|||||||
void NotificationManager::downloadCover(const QString &url)
|
void NotificationManager::downloadCover(const QString &url)
|
||||||
{
|
{
|
||||||
if (m_currentReply) {
|
if (m_currentReply) {
|
||||||
m_currentReply->abort();
|
QNetworkReply *reply = m_currentReply;
|
||||||
m_currentReply->deleteLater();
|
|
||||||
m_currentReply = nullptr;
|
m_currentReply = nullptr;
|
||||||
|
reply->disconnect(this);
|
||||||
|
reply->abort();
|
||||||
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pendingCoverUrl = url;
|
m_pendingCoverUrl = url;
|
||||||
|
|||||||
Reference in New Issue
Block a user