Add radios
This commit is contained in:
@@ -91,6 +91,9 @@
|
||||
# include "moodbar/moodbarloader.h"
|
||||
#endif
|
||||
|
||||
#include "radios/radioservices.h"
|
||||
#include "radios/radiobackend.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class ApplicationImpl {
|
||||
@@ -171,15 +174,13 @@ class ApplicationImpl {
|
||||
#endif
|
||||
return internet_services;
|
||||
}),
|
||||
radio_services_([=]() { return new RadioServices(app, app); }),
|
||||
scrobbler_([=]() { return new AudioScrobbler(app, app); }),
|
||||
lastfm_import_([=]() { return new LastFMImport(app); }),
|
||||
|
||||
#ifdef HAVE_MOODBAR
|
||||
moodbar_loader_([=]() { return new MoodbarLoader(app, app); }),
|
||||
moodbar_controller_([=]() { return new MoodbarController(app, app); }),
|
||||
#endif
|
||||
dummy_([=]() { return nullptr; })
|
||||
|
||||
lastfm_import_([=]() { return new LastFMImport(app); })
|
||||
{}
|
||||
|
||||
Lazy<TagReaderClient> tag_reader_client_;
|
||||
@@ -199,13 +200,13 @@ class ApplicationImpl {
|
||||
Lazy<CurrentAlbumCoverLoader> current_albumcover_loader_;
|
||||
Lazy<LyricsProviders> lyrics_providers_;
|
||||
Lazy<InternetServices> internet_services_;
|
||||
Lazy<RadioServices> radio_services_;
|
||||
Lazy<AudioScrobbler> scrobbler_;
|
||||
Lazy<LastFMImport> lastfm_import_;
|
||||
#ifdef HAVE_MOODBAR
|
||||
Lazy<MoodbarLoader> moodbar_loader_;
|
||||
Lazy<MoodbarController> moodbar_controller_;
|
||||
#endif
|
||||
Lazy<QVariant> dummy_;
|
||||
Lazy<LastFMImport> lastfm_import_;
|
||||
|
||||
};
|
||||
|
||||
@@ -265,7 +266,8 @@ void Application::Exit() {
|
||||
#ifndef Q_OS_WIN
|
||||
<< device_manager()
|
||||
#endif
|
||||
<< internet_services();
|
||||
<< internet_services()
|
||||
<< radio_services()->radio_backend();
|
||||
|
||||
QObject::connect(tag_reader_client(), &TagReaderClient::ExitFinished, this, &Application::ExitReceived);
|
||||
tag_reader_client()->ExitAsync();
|
||||
@@ -287,6 +289,9 @@ void Application::Exit() {
|
||||
QObject::connect(internet_services(), &InternetServices::ExitFinished, this, &Application::ExitReceived);
|
||||
internet_services()->Exit();
|
||||
|
||||
QObject::connect(radio_services()->radio_backend(), &RadioBackend::ExitFinished, this, &Application::ExitReceived);
|
||||
radio_services()->radio_backend()->ExitAsync();
|
||||
|
||||
}
|
||||
|
||||
void Application::ExitReceived() {
|
||||
@@ -328,6 +333,7 @@ LyricsProviders *Application::lyrics_providers() const { return p_->lyrics_provi
|
||||
PlaylistBackend *Application::playlist_backend() const { return p_->playlist_backend_.get(); }
|
||||
PlaylistManager *Application::playlist_manager() const { return p_->playlist_manager_.get(); }
|
||||
InternetServices *Application::internet_services() const { return p_->internet_services_.get(); }
|
||||
RadioServices *Application::radio_services() const { return p_->radio_services_.get(); }
|
||||
AudioScrobbler *Application::scrobbler() const { return p_->scrobbler_.get(); }
|
||||
LastFMImport *Application::lastfm_import() const { return p_->lastfm_import_.get(); }
|
||||
#ifdef HAVE_MOODBAR
|
||||
|
||||
@@ -58,6 +58,7 @@ class LyricsProviders;
|
||||
class AudioScrobbler;
|
||||
class LastFMImport;
|
||||
class InternetServices;
|
||||
class RadioServices;
|
||||
#ifdef HAVE_MOODBAR
|
||||
class MoodbarController;
|
||||
class MoodbarLoader;
|
||||
@@ -94,15 +95,17 @@ class Application : public QObject {
|
||||
LyricsProviders *lyrics_providers() const;
|
||||
|
||||
AudioScrobbler *scrobbler() const;
|
||||
LastFMImport *lastfm_import() const;
|
||||
|
||||
InternetServices *internet_services() const;
|
||||
RadioServices *radio_services() const;
|
||||
|
||||
#ifdef HAVE_MOODBAR
|
||||
MoodbarController *moodbar_controller() const;
|
||||
MoodbarLoader *moodbar_loader() const;
|
||||
#endif
|
||||
|
||||
LastFMImport *lastfm_import() const;
|
||||
|
||||
void Exit();
|
||||
|
||||
QThread *MoveToNewThread(QObject *object);
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
#include "scopedtransaction.h"
|
||||
|
||||
const char *Database::kDatabaseFilename = "strawberry.db";
|
||||
const int Database::kSchemaVersion = 14;
|
||||
const int Database::kSchemaVersion = 15;
|
||||
const char *Database::kMagicAllSongsTables = "%allsongstables";
|
||||
|
||||
int Database::sNextConnectionId = 1;
|
||||
|
||||
@@ -180,6 +180,9 @@
|
||||
#include "internet/internetcollectionview.h"
|
||||
#include "internet/internetsearchview.h"
|
||||
|
||||
#include "radios/radioservices.h"
|
||||
#include "radios/radioviewcontainer.h"
|
||||
|
||||
#include "scrobbler/audioscrobbler.h"
|
||||
#include "scrobbler/lastfmimport.h"
|
||||
|
||||
@@ -277,6 +280,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
||||
#ifdef HAVE_QOBUZ
|
||||
qobuz_view_(new InternetTabsView(app_, app->internet_services()->ServiceBySource(Song::Source_Qobuz), QobuzSettingsPage::kSettingsGroup, SettingsDialog::Page_Qobuz, this)),
|
||||
#endif
|
||||
radio_view_(new RadioViewContainer(this)),
|
||||
lastfm_import_dialog_(new LastFMImportDialog(app_->lastfm_import(), this)),
|
||||
collection_show_all_(nullptr),
|
||||
collection_show_duplicates_(nullptr),
|
||||
@@ -316,8 +320,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
||||
hidden_(false),
|
||||
exit_(false),
|
||||
exit_count_(0),
|
||||
delete_files_(false)
|
||||
{
|
||||
delete_files_(false) {
|
||||
|
||||
qLog(Debug) << "Starting";
|
||||
|
||||
@@ -343,6 +346,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
||||
ui_->tabs->AddTab(playlist_list_, "playlists", IconLoader::Load("view-media-playlist"), tr("Playlists"));
|
||||
ui_->tabs->AddTab(smartplaylists_view_, "smartplaylists", IconLoader::Load("view-media-playlist"), tr("Smart playlists"));
|
||||
ui_->tabs->AddTab(file_view_, "files", IconLoader::Load("document-open"), tr("Files"));
|
||||
ui_->tabs->AddTab(radio_view_, "radios", IconLoader::Load("radio"), tr("Radios"));
|
||||
#ifndef Q_OS_WIN
|
||||
ui_->tabs->AddTab(device_view_, "devices", IconLoader::Load("device"), tr("Devices"));
|
||||
#endif
|
||||
@@ -401,6 +405,8 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
||||
|
||||
organize_dialog_->SetDestinationModel(app_->collection()->model()->directory_model());
|
||||
|
||||
radio_view_->view()->setModel(app_->radio_services()->radio_model());
|
||||
|
||||
// Icons
|
||||
qLog(Debug) << "Creating UI";
|
||||
|
||||
@@ -675,6 +681,10 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
||||
QObject::connect(qobuz_view_->search_view(), &InternetSearchView::AddToPlaylist, this, &MainWindow::AddToPlaylist);
|
||||
#endif
|
||||
|
||||
QObject::connect(radio_view_, &RadioViewContainer::Refresh, app_->radio_services(), &RadioServices::RefreshChannels);
|
||||
QObject::connect(radio_view_->view(), &RadioView::GetChannels, app_->radio_services(), &RadioServices::GetChannels);
|
||||
QObject::connect(radio_view_->view(), &RadioView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
|
||||
|
||||
// Playlist menu
|
||||
QObject::connect(playlist_menu_, &QMenu::aboutToHide, this, &MainWindow::PlaylistMenuHidden);
|
||||
playlist_play_pause_ = playlist_menu_->addAction(tr("Play"), this, &MainWindow::PlaylistPlay);
|
||||
@@ -1126,6 +1136,9 @@ void MainWindow::ReloadAllSettings() {
|
||||
queue_view_->ReloadSettings();
|
||||
playlist_list_->ReloadSettings();
|
||||
smartplaylists_view_->ReloadSettings();
|
||||
radio_view_->ReloadSettings();
|
||||
app_->internet_services()->ReloadSettings();
|
||||
app_->radio_services()->ReloadSettings();
|
||||
app_->cover_providers()->ReloadSettings();
|
||||
app_->lyrics_providers()->ReloadSettings();
|
||||
#ifdef HAVE_MOODBAR
|
||||
|
||||
@@ -100,6 +100,7 @@ class Windows7ThumbBar;
|
||||
#endif
|
||||
class AddStreamDialog;
|
||||
class LastFMImportDialog;
|
||||
class RadioViewContainer;
|
||||
|
||||
class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
Q_OBJECT
|
||||
@@ -338,6 +339,8 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
InternetTabsView *tidal_view_;
|
||||
InternetTabsView *qobuz_view_;
|
||||
|
||||
RadioViewContainer *radio_view_;
|
||||
|
||||
LastFMImportDialog *lastfm_import_dialog_;
|
||||
|
||||
QAction *collection_show_all_;
|
||||
|
||||
@@ -72,6 +72,8 @@
|
||||
|
||||
#include "smartplaylists/playlistgenerator_fwd.h"
|
||||
|
||||
#include "radios/radiochannel.h"
|
||||
|
||||
void RegisterMetaTypes() {
|
||||
|
||||
qRegisterMetaType<const char*>("const char*");
|
||||
@@ -141,4 +143,6 @@ void RegisterMetaTypes() {
|
||||
|
||||
qRegisterMetaType<PlaylistGeneratorPtr>("PlaylistGeneratorPtr");
|
||||
|
||||
qRegisterMetaType<RadioChannelList>("RadioChannelList");
|
||||
|
||||
}
|
||||
|
||||
@@ -375,7 +375,13 @@ double Song::rating() const { return d->rating_; }
|
||||
|
||||
bool Song::is_collection_song() const { return d->source_ == Source_Collection; }
|
||||
bool Song::is_metadata_good() const { return !d->url_.isEmpty() && !d->artist_.isEmpty() && !d->title_.isEmpty(); }
|
||||
bool Song::is_stream() const { return d->source_ == Source_Stream || d->source_ == Source_Tidal || d->source_ == Source_Subsonic || d->source_ == Source_Qobuz; }
|
||||
bool Song::is_stream() const { return d->source_ == Source_Stream ||
|
||||
d->source_ == Source_Tidal ||
|
||||
d->source_ == Source_Subsonic ||
|
||||
d->source_ == Source_Qobuz ||
|
||||
d->source_ == Source_SomaFM ||
|
||||
d->source_ == Source_RadioParadise;
|
||||
}
|
||||
bool Song::is_cdda() const { return d->source_ == Source_CDDA; }
|
||||
bool Song::is_compilation() const { return (d->compilation_ || d->compilation_detected_ || d->compilation_on_) && !d->compilation_off_; }
|
||||
bool Song::stream_url_can_expire() const { return d->source_ == Song::Source_Tidal || d->source_ == Song::Source_Qobuz; }
|
||||
@@ -490,7 +496,13 @@ Song::Source Song::SourceFromURL(const QUrl &url) {
|
||||
else if (url.scheme() == "tidal") return Source_Tidal;
|
||||
else if (url.scheme() == "subsonic") return Source_Subsonic;
|
||||
else if (url.scheme() == "qobuz") return Source_Qobuz;
|
||||
else if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "rtsp") return Source_Stream;
|
||||
else if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "rtsp") {
|
||||
if (url.host().endsWith("tidal.com", Qt::CaseInsensitive)) { return Source_Tidal; }
|
||||
if (url.host().endsWith("qobuz.com", Qt::CaseInsensitive)) { return Source_Qobuz; }
|
||||
if (url.host().endsWith("somafm.com", Qt::CaseInsensitive)) { return Source_SomaFM; }
|
||||
if (url.host().endsWith("radioparadise.com", Qt::CaseInsensitive)) { return Source_RadioParadise; }
|
||||
return Source_Stream;
|
||||
}
|
||||
else return Source_Unknown;
|
||||
|
||||
}
|
||||
@@ -498,15 +510,36 @@ Song::Source Song::SourceFromURL(const QUrl &url) {
|
||||
QString Song::TextForSource(Source source) {
|
||||
|
||||
switch (source) {
|
||||
case Song::Source_LocalFile: return "file";
|
||||
case Song::Source_Collection: return "collection";
|
||||
case Song::Source_CDDA: return "cd";
|
||||
case Song::Source_Device: return "device";
|
||||
case Song::Source_Stream: return "stream";
|
||||
case Song::Source_Tidal: return "tidal";
|
||||
case Song::Source_Subsonic: return "subsonic";
|
||||
case Song::Source_Qobuz: return "qobuz";
|
||||
case Song::Source_Unknown: return "unknown";
|
||||
case Song::Source_LocalFile: return "file";
|
||||
case Song::Source_Collection: return "collection";
|
||||
case Song::Source_CDDA: return "cd";
|
||||
case Song::Source_Device: return "device";
|
||||
case Song::Source_Stream: return "stream";
|
||||
case Song::Source_Tidal: return "tidal";
|
||||
case Song::Source_Subsonic: return "subsonic";
|
||||
case Song::Source_Qobuz: return "qobuz";
|
||||
case Song::Source_SomaFM: return "somafm";
|
||||
case Song::Source_RadioParadise: return "radioparadise";
|
||||
case Song::Source_Unknown: return "unknown";
|
||||
}
|
||||
return "unknown";
|
||||
|
||||
}
|
||||
|
||||
QString Song::DescriptionForSource(Source source) {
|
||||
|
||||
switch (source) {
|
||||
case Song::Source_LocalFile: return "File";
|
||||
case Song::Source_Collection: return "Collection";
|
||||
case Song::Source_CDDA: return "CD";
|
||||
case Song::Source_Device: return "Device";
|
||||
case Song::Source_Stream: return "Stream";
|
||||
case Song::Source_Tidal: return "Tidal";
|
||||
case Song::Source_Subsonic: return "Subsonic";
|
||||
case Song::Source_Qobuz: return "Qobuz";
|
||||
case Song::Source_SomaFM: return "SomaFM";
|
||||
case Song::Source_RadioParadise: return "Radio Paradise";
|
||||
case Song::Source_Unknown: return "Unknown";
|
||||
}
|
||||
return "unknown";
|
||||
|
||||
@@ -522,6 +555,8 @@ Song::Source Song::SourceFromText(const QString &source) {
|
||||
if (source == "tidal") return Source_Tidal;
|
||||
if (source == "subsonic") return Source_Subsonic;
|
||||
if (source == "qobuz") return Source_Qobuz;
|
||||
if (source == "somafm") return Source_SomaFM;
|
||||
if (source == "radioparadise") return Source_RadioParadise;
|
||||
|
||||
return Source_Unknown;
|
||||
|
||||
@@ -530,15 +565,17 @@ Song::Source Song::SourceFromText(const QString &source) {
|
||||
QIcon Song::IconForSource(Source source) {
|
||||
|
||||
switch (source) {
|
||||
case Song::Source_LocalFile: return IconLoader::Load("folder-sound");
|
||||
case Song::Source_Collection: return IconLoader::Load("library-music");
|
||||
case Song::Source_CDDA: return IconLoader::Load("media-optical");
|
||||
case Song::Source_Device: return IconLoader::Load("device");
|
||||
case Song::Source_Stream: return IconLoader::Load("applications-internet");
|
||||
case Song::Source_Tidal: return IconLoader::Load("tidal");
|
||||
case Song::Source_Subsonic: return IconLoader::Load("subsonic");
|
||||
case Song::Source_Qobuz: return IconLoader::Load("qobuz");
|
||||
case Song::Source_Unknown: return IconLoader::Load("edit-delete");
|
||||
case Song::Source_LocalFile: return IconLoader::Load("folder-sound");
|
||||
case Song::Source_Collection: return IconLoader::Load("library-music");
|
||||
case Song::Source_CDDA: return IconLoader::Load("media-optical");
|
||||
case Song::Source_Device: return IconLoader::Load("device");
|
||||
case Song::Source_Stream: return IconLoader::Load("applications-internet");
|
||||
case Song::Source_Tidal: return IconLoader::Load("tidal");
|
||||
case Song::Source_Subsonic: return IconLoader::Load("subsonic");
|
||||
case Song::Source_Qobuz: return IconLoader::Load("qobuz");
|
||||
case Song::Source_SomaFM: return IconLoader::Load("somafm");
|
||||
case Song::Source_RadioParadise: return IconLoader::Load("radioparadise");
|
||||
case Song::Source_Unknown: return IconLoader::Load("edit-delete");
|
||||
}
|
||||
return IconLoader::Load("edit-delete");
|
||||
|
||||
@@ -721,6 +758,8 @@ QString Song::ImageCacheDir(const Song::Source source) {
|
||||
case Song::Source_LocalFile:
|
||||
case Song::Source_CDDA:
|
||||
case Song::Source_Stream:
|
||||
case Song::Source_SomaFM:
|
||||
case Song::Source_RadioParadise:
|
||||
case Song::Source_Unknown:
|
||||
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/albumcovers";
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@ class Song {
|
||||
Source_Tidal = 6,
|
||||
Source_Subsonic = 7,
|
||||
Source_Qobuz = 8,
|
||||
Source_SomaFM = 9,
|
||||
Source_RadioParadise = 10
|
||||
};
|
||||
|
||||
// Don't change these values - they're stored in the database, and defined in the tag reader protobuf.
|
||||
@@ -134,6 +136,7 @@ class Song {
|
||||
|
||||
static Source SourceFromURL(const QUrl &url);
|
||||
static QString TextForSource(Source source);
|
||||
static QString DescriptionForSource(Source source);
|
||||
static Song::Source SourceFromText(const QString &source);
|
||||
static QIcon IconForSource(Source source);
|
||||
static QString TextForFiletype(FileType filetype);
|
||||
@@ -141,6 +144,7 @@ class Song {
|
||||
static QIcon IconForFiletype(FileType filetype);
|
||||
|
||||
QString TextForSource() const { return TextForSource(source()); }
|
||||
QString DescriptionForSource() const { return DescriptionForSource(source()); }
|
||||
QIcon IconForSource() const { return IconForSource(source()); }
|
||||
QString TextForFiletype() const { return TextForFiletype(filetype()); }
|
||||
QIcon IconForFiletype() const { return IconForFiletype(filetype()); }
|
||||
|
||||
Reference in New Issue
Block a user