Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bulk Import option for playlists #7261

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/playlist/playlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,7 @@ void Playlist::UpdateItems(const SongList& songs) {
}
}
}
connect(backend_,SIGNAL(PlaylistSaved(int)),SIGNAL(PlaylistSongsLoaded(int)));
Save();
}

Expand Down
3 changes: 3 additions & 0 deletions src/playlist/playlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,9 @@ class Playlist : public QAbstractListModel {
// Signals that the queue has changed, meaning that the remaining queued
// items should update their position.
void QueueChanged();
// Signals that the playlist has finished asynchronously loading songs
// the playlist can now be safely processed or closed
void PlaylistSongsLoaded(int id);

private:
void SetCurrentIsPaused(bool paused);
Expand Down
1 change: 1 addition & 0 deletions src/playlist/playlistbackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items,
if (db_->CheckErrors(update)) return;

transaction.Commit();
emit PlaylistSaved(playlist);
}

int PlaylistBackend::CreatePlaylist(const QString& name,
Expand Down
4 changes: 3 additions & 1 deletion src/playlist/playlistbackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ class PlaylistBackend : public QObject {
public slots:
void SavePlaylist(int playlist, const PlaylistItemList& items,
int last_played, smart_playlists::GeneratorPtr dynamic);

signals:
void PlaylistSaved(int id);

private:
struct NewSongFromQueryState {
QHash<QString, SongList> cached_cues_;
Expand Down
97 changes: 97 additions & 0 deletions src/playlist/playlistlistcontainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,22 @@
#include <QPainter>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QFileDialog>
#include <QDirIterator>
#include <iostream>

#include "core/application.h"
#include "core/logging.h"
#include "core/player.h"
#include "core/utilities.h"
#include "playlist.h"
#include "playlistlistmodel.h"
#include "playlistmanager.h"
#include "ui/iconloader.h"
#include "ui_playlistlistcontainer.h"
#include "playlistparsers/playlistparser.h"

const char* PlaylistListContainer::kSettingsGroup = "PlaylistList";

/* This filter proxy will:
- Accept all ancestors if at least a single child matches
Expand Down Expand Up @@ -146,6 +152,7 @@ PlaylistListContainer::PlaylistListContainer(QWidget* parent)
action_new_folder_(new QAction(this)),
action_remove_(new QAction(this)),
action_save_playlist_(new QAction(this)),
action_bulk_import_playlists_(new QAction(this)),
model_(new PlaylistListModel(this)),
proxy_(new PlaylistListFilterProxyModel(this)),
loaded_icons_(false),
Expand All @@ -158,16 +165,20 @@ PlaylistListContainer::PlaylistListContainer(QWidget* parent)
action_remove_->setText(tr("Delete"));
action_save_playlist_->setText(
tr("Save playlist", "Save playlist menu action."));
action_bulk_import_playlists_->setText(tr("Bulk Import Playlists"));

ui_->new_folder->setDefaultAction(action_new_folder_);
ui_->remove->setDefaultAction(action_remove_);
ui_->save_playlist->setDefaultAction(action_save_playlist_);
ui_->bulk_import_playlists->setDefaultAction(action_bulk_import_playlists_);


connect(action_new_folder_, SIGNAL(triggered()), SLOT(NewFolderClicked()));
connect(action_remove_, SIGNAL(triggered()), SLOT(DeleteClicked()));
connect(action_save_playlist_, SIGNAL(triggered()), SLOT(SavePlaylist()));
connect(model_, SIGNAL(PlaylistPathChanged(int, QString)),
SLOT(PlaylistPathChanged(int, QString)));
connect(action_bulk_import_playlists_, SIGNAL(triggered()), SLOT(BulkImportPlaylists()));

proxy_->setSourceModel(model_);
proxy_->setDynamicSortFilter(true);
Expand All @@ -182,6 +193,9 @@ PlaylistListContainer::PlaylistListContainer(QWidget* parent)

connect(ui_->search, SIGNAL(textChanged(QString)),
SLOT(SearchTextEdited(QString)));

//access to global settings using the QSettings object. Use this to get data about last opened folder etc.
settings_.beginGroup(kSettingsGroup);
}

PlaylistListContainer::~PlaylistListContainer() { delete ui_; }
Expand All @@ -198,6 +212,8 @@ void PlaylistListContainer::showEvent(QShowEvent* e) {
action_remove_->setIcon(IconLoader::Load("edit-delete", IconLoader::Base));
action_save_playlist_->setIcon(
IconLoader::Load("document-save", IconLoader::Base));
action_bulk_import_playlists_->setIcon(
IconLoader::Load("document-open-folder", IconLoader::Base));

model_->SetIcons(IconLoader::Load("view-media-playlist", IconLoader::Base),
IconLoader::Load("folder", IconLoader::Base));
Expand Down Expand Up @@ -330,6 +346,86 @@ void PlaylistListContainer::SavePlaylist() {
}
}

/*
Open filepicker and Use QDirIterator to recursively find subdirectories
within the chosen directory. create an empty
*/
void PlaylistListContainer::BulkImportPlaylists() {
QString base_path(settings_.value("last_path", Utilities::GetConfigPath(
Utilities::Path_DefaultMusicLibrary)).toString());
base_path = QFileDialog::getExistingDirectory(this, tr("Add directory..."), base_path);

if (base_path.isNull()) {
return;
}

//Create Root Folder
QFileInfo child_info(base_path);
QStandardItem* root_folder = model_->NewFolder(child_info.fileName());
model_->invisibleRootItem()->appendRow(root_folder);

bulk_imported_id_list_ = new QList<int>();
bulk_imported_count_ = 0;

RecursivelyCreateSubfolders(root_folder, base_path, child_info.baseName());

settings_.setValue("last_path", base_path);
}

void PlaylistListContainer::RecursivelyCreateSubfolders(QStandardItem* parent_folder, QString path, QString ui_path){
QStringList filters;
filters = app_->playlist_manager()->parser()->file_extensions();
for(int i=0; i<filters.count(); i++){
filters[i] = "*." + filters[i];
}

QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot);
while(it.hasNext()) {
QString child(it.next());
QFileInfo child_info(child);
if (child_info.isDir()) {
QStandardItem* folder = model_->NewFolder(child_info.fileName());
parent_folder->appendRow(folder);
RecursivelyCreateSubfolders(folder, child_info.absoluteFilePath(), ui_path + "/" + child_info.baseName());
}else if(child_info.isFile()){
if(QDir::match(filters, child_info.fileName())){
bulk_imported_count_++;
int id = app_->playlist_manager()->LoadBulkPlaylists(child, ui_path);
Playlist* playlist = app_->playlist_manager()->playlist(id);
connect(playlist, SIGNAL(PlaylistSongsLoaded(int)), SLOT(BulkImportPlaylistsCallback(int)));
PlaylistPathChanged(id, ui_path);
}
}
}
}

/*
* After the bulk imported playlist has asynchronously had its songs
* loaded, add it to the list of finished playlists
* once the quota has been filled, close the temporary tabs
*/
void PlaylistListContainer::BulkImportPlaylistsCallback (int id){
if(bulk_imported_count_ == 0){
return;
}
if(bulk_imported_id_list_->contains(id)){
return;
}
app_->playlist_manager()->BulkImportPlaylistsCallback(id);
const QString& name = app_->playlist_manager()->GetPlaylistName(id);
AddPlaylist(id, name, true);
bulk_imported_id_list_->append(id);
if(bulk_imported_id_list_->count() == bulk_imported_count_){
//clean up tabs
for(qsizetype i =0; i < bulk_imported_id_list_->count(); i++){
app_->playlist_manager()->Close(bulk_imported_id_list_->at(i));
}
app_->playlist_manager()->ChangePlaylistOrder(app_->playlist_manager()->GetAllPlaylistIds());
bulk_imported_count_ = 0;
bulk_imported_id_list_ = new QList<int>();
}
}

void PlaylistListContainer::PlaylistFavoriteStateChanged(int id,
bool favorite) {
if (favorite) {
Expand Down Expand Up @@ -473,6 +569,7 @@ void PlaylistListContainer::contextMenuEvent(QContextMenuEvent* e) {
menu_->addAction(action_remove_);
menu_->addSeparator();
menu_->addAction(action_save_playlist_);
menu_->addAction(action_bulk_import_playlists_);
}
menu_->popup(e->globalPos());
}
Expand Down
13 changes: 13 additions & 0 deletions src/playlist/playlistlistcontainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#ifndef PLAYLISTLISTCONTAINER_H
#define PLAYLISTLISTCONTAINER_H

#include <QSettings>
#include <QWidget>

#include "playlistbackend.h"
Expand All @@ -42,6 +43,8 @@ class PlaylistListContainer : public QWidget {

void SetApplication(Application* app);

static const char* kSettingsGroup;

protected:
void showEvent(QShowEvent* e);
void contextMenuEvent(QContextMenuEvent* e);
Expand All @@ -63,6 +66,9 @@ class PlaylistListContainer : public QWidget {
const QString* ui_path = nullptr);
void RemovePlaylist(int id);
void SavePlaylist();
void BulkImportPlaylists();
void RecursivelyCreateSubfolders(QStandardItem* parent_folder, QString path, QString ui_path);
void BulkImportPlaylistsCallback (int id);
void PlaylistFavoriteStateChanged(int id, bool favorite);
void CurrentChanged(Playlist* new_playlist);
void ActiveChanged(Playlist* new_playlist);
Expand All @@ -89,6 +95,7 @@ class PlaylistListContainer : public QWidget {
QAction* action_new_folder_;
QAction* action_remove_;
QAction* action_save_playlist_;
QAction* action_bulk_import_playlists_;

PlaylistListModel* model_;
PlaylistListFilterProxyModel* proxy_;
Expand All @@ -97,6 +104,12 @@ class PlaylistListContainer : public QWidget {
QIcon padded_play_icon_;

int active_playlist_id_;

QSettings settings_;

QList<int>* bulk_imported_id_list_;
int bulk_imported_count_;
int debug_count_;
};

#endif // PLAYLISTLISTCONTAINER_H
7 changes: 7 additions & 0 deletions src/playlist/playlistlistcontainer.ui
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@
<item>
<widget class="QToolButton" name="save_playlist"/>
</item>
<item>
<widget class="QToolButton" name="bulk_import_playlists">
<property name="toolTip">
<string>Bulk Import Playlists</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
Expand Down
39 changes: 39 additions & 0 deletions src/playlist/playlistmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ QList<Playlist*> PlaylistManager::GetAllPlaylists() const {
return result;
}

QList<int> PlaylistManager::GetAllPlaylistIds() const {
QList<int> result;

for (const int data : playlists_.keys()) {
result.append(data);
}

return result;
}

QItemSelection PlaylistManager::selection(int id) const {
QMap<int, Data>::const_iterator it = playlists_.find(id);
return it->selection;
Expand Down Expand Up @@ -196,6 +206,35 @@ void PlaylistManager::Save(int id, const QString& filename,
}
}

int PlaylistManager::LoadBulkPlaylists(const QString& filename, const QString& ui_path){
QFileInfo info(filename);

int id = playlist_backend_->CreatePlaylist(info.baseName(), QString());

if (id == -1) {
emit Error(tr("Couldn't create playlist"));
return id;
}

Playlist* playlist =
AddPlaylist(id, info.baseName(), QString(), ui_path, false);

QList<QUrl> urls;
playlist->InsertUrls(urls << QUrl::fromLocalFile(filename));

return id;
}

void PlaylistManager::BulkImportPlaylistsCallback(int id){
if (playlists_.contains(id)) {
// If playlists_ contains this playlist, its means it's opened: star or
// unstar it.
bool favorite = true;
playlist_backend_->FavoritePlaylist(id, favorite);
playlists_[id].p->set_favorite(favorite);
}
}

void PlaylistManager::ItemsLoadedForSavePlaylist(QFuture<SongList> future,
const QString& filename,
Playlist::Path path_type) {
Expand Down
4 changes: 4 additions & 0 deletions src/playlist/playlistmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class PlaylistManagerInterface : public QObject {

// Returns the collection of playlists managed by this PlaylistManager.
virtual QList<Playlist*> GetAllPlaylists() const = 0;
virtual QList<int> GetAllPlaylistIds() const = 0;
// Grays out and reloads all deleted songs in all playlists.
virtual void InvalidateDeletedSongs() = 0;
// Removes all deleted songs from all playlists.
Expand Down Expand Up @@ -151,6 +152,7 @@ class PlaylistManager : public PlaylistManagerInterface {

// Returns the collection of playlists managed by this PlaylistManager.
QList<Playlist*> GetAllPlaylists() const;
QList<int> GetAllPlaylistIds() const;
// Grays out and reloads all deleted songs in all playlists.
void InvalidateDeletedSongs();
// Removes all deleted songs from all playlists.
Expand Down Expand Up @@ -185,6 +187,8 @@ class PlaylistManager : public PlaylistManagerInterface {
const QString& special_type = QString());
void Load(const QString& filename);
void Save(int id, const QString& filename, Playlist::Path path_type);
int LoadBulkPlaylists(const QString& filename, const QString& ui_path);
void BulkImportPlaylistsCallback(int id);
// Display a file dialog to let user choose a file before saving the file
void SaveWithUI(int id, const QString& playlist_name);
void Rename(int id, const QString& new_name);
Expand Down