1 /****************************************************************************************
2  * Copyright (c) 2008 Ian Monroe <ian@monroe.nu>                                        *
3  * Copyright (c) 2013 Matěj Laitl <matej@laitl.cz>                                      *
4  *                                                                                      *
5  * This program is free software; you can redistribute it and/or modify it under        *
6  * the terms of the GNU General Public License as published by the Free Software        *
7  * Foundation; either version 2 of the License, or (at your option) version 3 or        *
8  * any later version accepted by the membership of KDE e.V. (or its successor approved  *
9  * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of  *
10  * version 3 of the license.                                                            *
11  *                                                                                      *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
14  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
15  *                                                                                      *
16  * You should have received a copy of the GNU General Public License along with         *
17  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
18  ****************************************************************************************/
19 
20 #ifndef AMAROK_TRACKLOADER_H
21 #define AMAROK_TRACKLOADER_H
22 
23 #include "amarok_export.h"
24 #include "core/meta/forward_declarations.h"
25 #include "core/meta/Observer.h"
26 #include "core/playlists/Playlist.h"
27 
28 namespace KIO {
29     class Job;
30     class UDSEntry;
31     typedef QList<UDSEntry> UDSEntryList;
32 }
33 
34 /**
35  * Helper class that helps with loading of urls (with local and remote tracks,
36  * playlists and local directories) to tracks.
37  *
38  * Only explicitly listed playlists are loaded, not the ones found in subdirectories.
39  * TrackLoader takes care to preserve order of urls you pass, and it sorts tracks in
40  * directories you pass it using directory- and locale-aware sort.
41  */
42 class AMAROK_EXPORT TrackLoader : public QObject, public Playlists::PlaylistObserver, public Meta::Observer
43 {
44     Q_OBJECT
45 
46     public:
47         /**
48          * FullMetadataRequired: signal TrackLoader that it should postpone the finished()
49          * signal until the any possible proxy tracks have resolved and their full
50          * metadata is available. Also use this flag when you need to immediately play
51          * the tracks. This no longer implies any blocking behaviour, you'll just get the
52          * finished signal a bit later.
53          *
54          * RemotePlaylistsAreStreams: treat playlists with remote urls as Streams with
55          * multiple alternative download locations (Meta::MultiTracks). Works even when
56          * you pass playlists.
57          */
58         enum Flag {
59             FullMetadataRequired = 1 << 0,
60             RemotePlaylistsAreStreams = 1 << 1,
61         };
62         Q_DECLARE_FLAGS( Flags, Flag )
63 
64         /**
65          * Construct TrackLoader. You must construct it on the heap, it will auto-delete
66          * itself.
67          *
68          * @param flags binary or of flags, see TrackLoader::Flags enum
69          * @param timeout if FullMetadataRequired is in flags, this is the timeout in
70          * milliseconds for waiting on track to resolve. Ignored otherwise.
71          */
72         explicit TrackLoader( Flags flags = 0, int timeout = 2000 );
73         ~TrackLoader() override;
74 
75         /**
76          * Convenience overload for init( const QList<QUrl> &urls )
77          */
78         void init( const QUrl &url );
79 
80         /**
81          * Starts TrackLoader's job, you'll get finished() signal in the end and
82          * TrackLoader will auto-delete itself.
83          *
84          * @param urls list of urls to load tracks from, you can pass local and remote urls
85          * pointing to directories, tracks and playlists.
86          */
87         void init( const QList<QUrl> &urls );
88 
89         /**
90          * Short-hand if you already have a list of playlists and want a convenient way
91          * to get notified of their loaded tracks. See init( const QList<QUrl> ) and
92          * class description.
93          */
94         void init( const Playlists::PlaylistList &playlists );
95 
96         /* PlaylistObserver methods */
97         using PlaylistObserver::metadataChanged;
98         void tracksLoaded( Playlists::PlaylistPtr playlist ) override;
99 
100         /* Meta::Observer methods */
101         using Observer::metadataChanged;
102         void metadataChanged( const Meta::TrackPtr &track ) override;
103 
104     Q_SIGNALS:
105         void finished( const Meta::TrackList &tracks );
106 
107     private Q_SLOTS:
108         void processNextSourceUrl();
109         void directoryListResults( KIO::Job *job, const KIO::UDSEntryList &list );
110         void processNextResultUrl();
111         /**
112          * Emits the result and auto-destroys the TrackLoader
113          */
114         void finish();
115 
116     private:
117         enum Status {
118             LoadingTracks,
119             MayFinish,
120             Finished
121         };
122         void mayFinish();
123 
124         static bool directorySensitiveLessThan( const QUrl &left, const QUrl &right );
125 
126         Status m_status;
127         const Flags m_flags;
128         int m_timeout;
129         /// passed urls, may contain urls of directories
130         QList<QUrl> m_sourceUrls;
131         /// contains just urls of tracks and playlists
132         QList<QUrl> m_resultUrls;
133         /// a list of playlists directly passed, same semantics as m_resultUrls
134         Playlists::PlaylistList m_resultPlaylists;
135         /// the tracks found
136         Meta::TrackList m_tracks;
137         /// set of unresolved MetaProxy::Tracks that we wait for
138         QSet<Meta::TrackPtr> m_unresolvedTracks;
139         QMutex m_unresolvedTracksMutex;
140 };
141 
142 Q_DECLARE_OPERATORS_FOR_FLAGS( TrackLoader::Flags )
143 
144 #endif // AMAROK_TRACKLOADER_H
145