diff --git a/src/databaseinterface.h b/src/databaseinterface.h --- a/src/databaseinterface.h +++ b/src/databaseinterface.h @@ -595,6 +595,8 @@ void upgradeDatabaseV14(); + void upgradeDatabaseV15(); + void checkDatabaseSchema(); void checkAlbumsTableSchema(); diff --git a/src/databaseinterface.cpp b/src/databaseinterface.cpp --- a/src/databaseinterface.cpp +++ b/src/databaseinterface.cpp @@ -1217,6 +1217,7 @@ upgradeDatabaseV12(); upgradeDatabaseV13(); upgradeDatabaseV14(); + upgradeDatabaseV15(); checkDatabaseSchema(); } else if (listTables.contains(QLatin1String("DatabaseVersionV9"))) { @@ -1232,14 +1233,18 @@ if (!listTables.contains(QLatin1String("DatabaseVersionV14"))) { upgradeDatabaseV14(); } + if (!listTables.contains(QStringLiteral("DatabaseVersionV15"))) { + upgradeDatabaseV15(); + } checkDatabaseSchema(); } else { createDatabaseV9(); upgradeDatabaseV11(); upgradeDatabaseV12(); upgradeDatabaseV13(); upgradeDatabaseV14(); + upgradeDatabaseV15(); } } @@ -2868,15 +2873,16 @@ //Find webradios (french): https://doc.ubuntu-fr.org/liste_radio_france //English: https://www.radio.fr/language/english (to get the link play a radio and look for streamUrl in the html elements page). - const auto &result = createSchemaQuery.exec(QStringLiteral("INSERT INTO `Radios` (`HttpAddress`, `Priority`, `Title`) " - "SELECT 'http://classicrock.stream.ouifm.fr/ouifm3.mp3', 1, 'OuiFM_Classic_Rock' UNION ALL " - "SELECT 'http://rock70s.stream.ouifm.fr/ouifmseventies.mp3', 1, 'OuiFM_70s' UNION ALL " - "SELECT 'http://jazzradio.ice.infomaniak.ch/jazzradio-high.mp3', 2 , 'Jazz_Radio' UNION ALL " - "SELECT 'http://cdn.nrjaudio.fm/audio1/fr/30601/mp3_128.mp3?origine=playerweb', 1, 'Nostalgie' UNION ALL " - "SELECT 'https://scdn.nrjaudio.fm/audio1/fr/30713/aac_64.mp3?origine=playerweb', 1, 'Nostalgie Johnny' UNION ALL " - "SELECT 'http://sc-classrock.1.fm:8200', 1, 'Classic rock replay' UNION ALL " - "SELECT 'http://agnes.torontocast.com:8151/stream', 1, 'Instrumentals Forever' UNION ALL " - "SELECT 'https://stream.laut.fm/jahfari', 1, 'Jahfari'" + const auto &result = createSchemaQuery.exec(QStringLiteral("INSERT INTO `Radios` (`HttpAddress`, `ImageAddress`, `Title`) " + "SELECT 'http://classicrock.stream.ouifm.fr/ouifm3.mp3', '', 'OuiFM_Classic_Rock' UNION ALL " + "SELECT 'http://rock70s.stream.ouifm.fr/ouifmseventies.mp3', '', 'OuiFM_70s' UNION ALL " + "SELECT 'http://jazzradio.ice.infomaniak.ch/jazzradio-high.mp3', '' , 'Jazz_Radio' UNION ALL " + "SELECT 'http://cdn.nrjaudio.fm/audio1/fr/30601/mp3_128.mp3?origine=playerweb', '', 'Nostalgie' UNION ALL " + "SELECT 'https://scdn.nrjaudio.fm/audio1/fr/30713/aac_64.mp3?origine=playerweb', '', 'Nostalgie Johnny' UNION ALL " + "SELECT 'http://sc-classrock.1.fm:8200', '', 'Classic rock replay' UNION ALL " + "SELECT 'http://agnes.torontocast.com:8151/stream', '', 'Instrumentals Forever' UNION ALL " + "SELECT 'https://stream.laut.fm/jahfari', '', 'Jahfari' UNION ALL " + "SELECT 'https://chai5she.cdn.dvmr.fr/francemusique-lofi.mp3', 'https://static.radio.fr/images/broadcasts/07/f7/3366/c44.png', 'France Musique'" )); if (!result) { qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::initRequest" << createSchemaQuery.lastQuery(); @@ -2904,6 +2910,123 @@ qCInfo(orgKdeElisaDatabase) << "finished update to v14 of database schema"; } +void DatabaseInterface::upgradeDatabaseV15() +{ + qCInfo(orgKdeElisaDatabase) << "begin update to v15 of database schema"; + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `DatabaseVersionV15` (`Version` INTEGER PRIMARY KEY NOT NULL)")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery disableForeignKeys(d->mTracksDatabase); + + auto result = disableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=OFF")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << disableForeignKeys.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << disableForeignKeys.lastError(); + + Q_EMIT databaseError(); + } + } + + d->mTracksDatabase.transaction(); + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("CREATE TABLE `RadiosNew` (" + "`ID` INTEGER PRIMARY KEY AUTOINCREMENT, " + "`HttpAddress` VARCHAR(255) NOT NULL, " + "`ImageAddress` VARCHAR(255) NOT NULL, " + "`Title` VARCHAR(85) NOT NULL, " + "`Rating` INTEGER NOT NULL DEFAULT 0, " + "`Genre` VARCHAR(55), " + "`Comment` VARCHAR(255), " + "UNIQUE (" + "`HttpAddress`" + "), " + "UNIQUE (" + "`Title`, `HttpAddress`" + ") " + "CONSTRAINT fk_tracks_genre FOREIGN KEY (`Genre`) REFERENCES `Genre`(`Name`))" + )); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV14" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV14" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("INSERT INTO RadiosNew SELECT ID, HttpAddress, '', Title, Rating, Genre, Comment FROM Radios")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("DROP TABLE `Radios`")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + { + QSqlQuery createSchemaQuery(d->mTracksDatabase); + + const auto &result = createSchemaQuery.exec(QStringLiteral("ALTER TABLE `RadiosNew` RENAME TO `Radios`")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << createSchemaQuery.lastError(); + + Q_EMIT databaseError(); + } + } + + d->mTracksDatabase.commit(); + + { + QSqlQuery enableForeignKeys(d->mTracksDatabase); + + auto result = enableForeignKeys.exec(QStringLiteral(" PRAGMA foreign_keys=ON")); + + if (!result) { + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << enableForeignKeys.lastQuery(); + qCDebug(orgKdeElisaDatabase) << "DatabaseInterface::upgradeDatabaseV15" << enableForeignKeys.lastError(); + + Q_EMIT databaseError(); + } + } + + qCInfo(orgKdeElisaDatabase) << "finished update to v15 of database schema"; +} + void DatabaseInterface::checkDatabaseSchema() { checkAlbumsTableSchema(); @@ -3629,6 +3752,7 @@ "radios.`ID`, " "radios.`Title`, " "radios.`HttpAddress`, " + "radios.`ImageAddress`, " "radios.`Rating`, " "trackGenre.`Name`, " "radios.`Comment` " @@ -4447,6 +4571,7 @@ "radios.`ID`, " "radios.`Title`, " "radios.`HttpAddress`, " + "radios.`ImageAddress`, " "radios.`Rating`, " "trackGenre.`Name`, " "radios.`Comment` " @@ -5117,14 +5242,14 @@ "`httpAddress`, " "`Comment`, " "`Rating`, " - "`Priority`) " + "`ImageAddress`) " "VALUES " "(" ":title, " ":httpAddress, " ":comment, " ":trackRating," - "1)"); + ":imageAddress)"); auto result = prepareQuery(d->mInsertRadioQuery, insertRadioQueryText); @@ -5156,7 +5281,8 @@ "`HttpAddress` = :httpAddress, " "`Title` = :title, " "`Comment` = :comment, " - "`Rating` = :trackRating " + "`Rating` = :trackRating, " + "`ImageAddress` = :imageAddress " "WHERE " "`ID` = :radioId"); @@ -6416,11 +6542,12 @@ result[TrackDataType::key_type::ArtistRole] = trackRecord.value(1); result[TrackDataType::key_type::ResourceRole] = trackRecord.value(2); - result[TrackDataType::key_type::RatingRole] = trackRecord.value(3); + result[TrackDataType::key_type::ImageUrlRole] = trackRecord.value(3); + result[TrackDataType::key_type::RatingRole] = trackRecord.value(4); if (!trackRecord.value(4).isNull()) { - result[TrackDataType::key_type::GenreRole] = trackRecord.value(4); + result[TrackDataType::key_type::GenreRole] = trackRecord.value(5); } - result[TrackDataType::key_type::CommentRole] = trackRecord.value(5); + result[TrackDataType::key_type::CommentRole] = trackRecord.value(6); result[TrackDataType::key_type::ElementTypeRole] = ElisaUtils::Radio; return result; @@ -6826,6 +6953,7 @@ query.bindValue(QStringLiteral(":title"), oneTrack.title()); query.bindValue(QStringLiteral(":comment"), oneTrack.comment()); query.bindValue(QStringLiteral(":trackRating"), oneTrack.rating()); + query.bindValue(QStringLiteral(":imageAddress"), oneTrack.albumCover()); auto result = execQuery(query); diff --git a/src/elisautils.h b/src/elisautils.h --- a/src/elisautils.h +++ b/src/elisautils.h @@ -73,6 +73,8 @@ Q_ENUM_NS(FilterType) +bool checkUrl(QUrl url); + } Q_DECLARE_METATYPE(ElisaUtils::EntryData) diff --git a/src/elisautils.cpp b/src/elisautils.cpp --- a/src/elisautils.cpp +++ b/src/elisautils.cpp @@ -17,4 +17,26 @@ #include "elisautils.h" +#include +#include +#include +#include + +bool ElisaUtils::checkUrl(QUrl url) { + if(url.isEmpty() || url.isLocalFile()) { + return true; + } + + QNetworkAccessManager qNetworkAccessManager; + QNetworkRequest request; + request.setUrl(url); + + QEventLoop signalWaitLoop; + QObject::connect(&qNetworkAccessManager, SIGNAL(finished(QNetworkReply*)),&signalWaitLoop, SLOT(quit())); + QNetworkReply *response = qNetworkAccessManager.head(request); + signalWaitLoop.exec(); + + return QNetworkReply::NoError == response->error(); +} + #include "moc_elisautils.cpp" diff --git a/src/models/datamodel.cpp b/src/models/datamodel.cpp --- a/src/models/datamodel.cpp +++ b/src/models/datamodel.cpp @@ -19,6 +19,7 @@ #include "modeldataloader.h" #include "musiclistenersmanager.h" +#include "elisautils.h" #include #include @@ -227,6 +228,9 @@ break; case ElisaUtils::Radio: result = d->mAllRadiosData[index.row()][static_cast(role)]; + if(role == DatabaseInterface::ColumnsRoles::ImageUrlRole && !ElisaUtils::checkUrl(result.toUrl())) { + result = QUrl(QStringLiteral("image://icon/media-optical-audio")); + } break; case ElisaUtils::Lyricist: case ElisaUtils::Composer: diff --git a/src/models/trackmetadatamodel.cpp b/src/models/trackmetadatamodel.cpp --- a/src/models/trackmetadatamodel.cpp +++ b/src/models/trackmetadatamodel.cpp @@ -18,6 +18,7 @@ #include "trackmetadatamodel.h" #include "musiclistenersmanager.h" +#include "elisautils.h" #include @@ -165,8 +166,10 @@ case DatabaseInterface::ResourceRole: result = i18nc("Radio HTTP address for radio metadata view", "Stream Http Address"); break; - case DatabaseInterface::SecondaryTextRole: case DatabaseInterface::ImageUrlRole: + result = i18nc("Image address for radio metadata view", "Image Address"); + break; + case DatabaseInterface::SecondaryTextRole: case DatabaseInterface::ShadowForImageRole: case DatabaseInterface::ChildModelRole: case DatabaseInterface::StringDurationRole: @@ -195,6 +198,7 @@ result = TextEntry; break; case DatabaseInterface::ResourceRole: + case DatabaseInterface::ImageUrlRole: result = TextEntry; break; case DatabaseInterface::ArtistRole: @@ -244,7 +248,6 @@ case DatabaseInterface::BitRateRole: case DatabaseInterface::ChannelsRole: case DatabaseInterface::SecondaryTextRole: - case DatabaseInterface::ImageUrlRole: case DatabaseInterface::ShadowForImageRole: case DatabaseInterface::ChildModelRole: case DatabaseInterface::StringDurationRole: @@ -302,7 +305,12 @@ if (mCoverImage.isEmpty()) { return QUrl(QStringLiteral("image://icon/media-optical-audio")); } else { - return mCoverImage; + if(ElisaUtils::checkUrl(mCoverImage)) { + return mCoverImage; + } else { + return QUrl(QStringLiteral("image://icon/media-optical-audio")); + } + } } @@ -535,6 +543,14 @@ void TrackMetadataModel::saveData() { + QString imageUrl = mTrackData[DatabaseInterface::ImageUrlRole].toString(); + if (!imageUrl.isEmpty() + && !imageUrl.startsWith(QStringLiteral("http://")) + && !imageUrl.startsWith(QStringLiteral("https://")) + && !imageUrl.startsWith(QStringLiteral("file://"))) { + mTrackData[DatabaseInterface::ImageUrlRole] = QStringLiteral("file:/").append(imageUrl); + } + Q_EMIT saveRadioData(mTrackData); } @@ -553,7 +569,8 @@ } const QList fieldsForTrack({DatabaseInterface::TitleRole, DatabaseInterface::ResourceRole, - DatabaseInterface::CommentRole, DatabaseInterface::DatabaseIdRole}); + DatabaseInterface::CommentRole, DatabaseInterface::ImageUrlRole, + DatabaseInterface::DatabaseIdRole}); fillDataFromTrackData(radiosData, fieldsForTrack); } diff --git a/src/qml/DataListView.qml b/src/qml/DataListView.qml --- a/src/qml/DataListView.qml +++ b/src/qml/DataListView.qml @@ -44,11 +44,12 @@ { "initialDatabaseId": databaseId, "modelType": modelType, - "showImage": false, + "showImage": true, "showTrackFileName": false, "showDeleteButton": databaseId !== -1, "showApplyButton": true, "editableMetadata": true, + "widthIndex": 4.5, }); } else { metadataLoader.setSource("MediaTrackMetadataView.qml", diff --git a/src/qml/MediaTrackMetadataView.qml b/src/qml/MediaTrackMetadataView.qml --- a/src/qml/MediaTrackMetadataView.qml +++ b/src/qml/MediaTrackMetadataView.qml @@ -35,6 +35,7 @@ property alias showTrackFileName: fileNameRow.visible property alias showDeleteButton: deleteButtonBox.visible property alias showApplyButton: applyButton.visible + property double widthIndex: 2.8 signal rejected() @@ -55,7 +56,7 @@ color: myPalette.window minimumHeight: elisaTheme.coverImageSize * 1.8 - minimumWidth: elisaTheme.coverImageSize * 2.8 + minimumWidth: elisaTheme.coverImageSize * trackMetadata.widthIndex ColumnLayout { anchors.fill: parent