File indexing completed on 2024-05-12 16:21:17

0001 // SPDX-FileCopyrightText: 2023 Théophile Gilgien <theophile@gilgien.net>
0002 //
0003 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 #include "playlistimporter.h"
0006 #include "playlistutils.h"
0007 
0008 #include "library.h"
0009 #include <qglobal.h>
0010 #include <qsqldatabase.h>
0011 #include <threadeddatabase.h>
0012 
0013 #include <KLocalizedString>
0014 
0015 PlaylistImporter::PlaylistImporter(QObject* parent)
0016     :QObject(parent)
0017 {}
0018 
0019 
0020 void PlaylistImporter::importPlaylist(const QString &url)
0021 {
0022     const QString croppedURL = this->cropURL(url).toString(), title = i18n("Unknown"), description = i18n("No description");
0023     QCoro::connect(Library::instance().database().execute("insert into playlists (title, description) values (?, ?)", title, description), &Library::instance(), [this, croppedURL]() {
0024         QCoro::connect(Library::instance().database().getResults<SingleValue<qint64>>("select * from playlists"), &Library::instance(), [this, croppedURL](auto &&playlists) {
0025             const quint64 playlistId = playlists.back().value;
0026             Q_EMIT Library::instance().playlistsChanged();
0027 
0028             QCoro::connect(YTMusicThread::instance()->fetchPlaylist(croppedURL), this, [this, playlistId](auto &&playlist) {
0029                 this->renamePlaylist(playlistId, QString::fromStdString(playlist.title), QString::fromStdString(playlist.author.name));
0030 
0031                 for (const auto& track : playlist.tracks) {
0032                     if (track.is_available && track.video_id) {
0033                         this->addPlaylistEntry(playlistId, track);
0034                     }
0035                 }
0036 
0037                 Q_EMIT Library::instance().playlistsChanged();
0038                 Q_EMIT importFinished();
0039             });
0040         });
0041     });
0042 }
0043 
0044 void PlaylistImporter::addPlaylistEntry(qint64 playlistId, const QString &videoId, const QString &title, const QString &artist, const QString &album)
0045 {
0046     QCoro::connect(Library::instance().addSong(videoId, title, artist, album), this, [=, this] {
0047         QCoro::connect(Library::instance().database().execute("insert into playlist_entries (playlist_id, video_id) values (?, ?)", playlistId, videoId), this, [=, this] {
0048             Q_EMIT playlistEntriesChanged(playlistId);
0049         });
0050     });
0051 }
0052 
0053 void PlaylistImporter::addPlaylistEntry(qint64 playlistId, const playlist::Track &track)
0054 {
0055     const QString videoId = track.video_id.value().c_str();
0056     const QString title   = (!track.title.empty()) ? QString::fromStdString(track.title) : i18n("No title");
0057     const QString artists = PlaylistUtils::artistsToString(track.artists);
0058     const QString album   = (track.album ) ? QString::fromStdString(track.album->name) : i18n("No album");
0059     this->addPlaylistEntry(playlistId, videoId, title, artists, album);
0060 }
0061 
0062 void PlaylistImporter::renamePlaylist(qint64 playlistId, const QString &name, const QString &description)
0063 {
0064     QCoro::connect(Library::instance().database().execute("update playlists set title = ? , description = ? where playlist_id = ?", name, description, playlistId), this, &PlaylistImporter::refreshModel);
0065 }
0066 
0067 
0068 QStringView PlaylistImporter::cropURL(QStringView srcUrl)
0069 {
0070     // Find entry point
0071     constexpr auto urlFragment = QStringView(u"?list=");
0072     qsizetype urlPos = srcUrl.indexOf(urlFragment);
0073     if (urlPos != -1) {
0074         urlPos += urlFragment.size();
0075     } else {
0076         urlPos = 0;
0077     }
0078     auto mid = srcUrl.mid(urlPos);
0079 
0080     // Find exit point
0081     urlPos = std::min(mid.indexOf(u"?"), mid.indexOf(u"&"));
0082     return mid.mid(0, urlPos);
0083 }