Warning, /multimedia/amarok/HACKING/architecture/Playlists.txt is written in an unsupported language. File is not indexed.

0001 Playlist architecture
0002 ---------------------
0003 note: this is about the media sources playlist, *not* The Playlist as the playback queue has been called for historic reasons.
0004 
0005 A playlist is an ordered list of tracks. The creation method of this list determines the type (or category):
0006 * When created by the user themselves and manually editable it's a User Playlist.
0007 
0008 * A Dynamic Playlist is generated based on some statistical rules. It's an amarok specific type that also reacts to changes made in the playback queue by the user.
0009 
0010 * A Smart Playlist is the result of a query of the Collections. It doesn't change unless it's being re-generated at startup or at the user's request.
0011 
0012 A Radio Channel has tracks that are not or only limited determined by the user but rather come in as a "stream" (high level). Implementation can be a single HTTP/RTSP URL like icecast or a pre-selected list of stream-able URLs such as with last.fm. The implementations can allow some control over track selection with functionality like last.fm's love/ban or tag selection like spotify.
0013 
0014 * Podcast Channels are also playlists that are generated by parsing a podcast feed (RSS or atom). They only contain tracks of the PodcastEpisode type. In amarok they are displayed separately from the other playlists but internally they use the same code such as the ItemModels, PlaylistManager and the synchronization support.
0015 
0016 [note] The Playlist base class currently lives in the Playlists:: namespace. It is to be moved to Meta::.
0017 
0018 Asynchronous Track Loading
0019 --------------------------
0020 The tracks() method will return immediately, possibly with a list of tracks that were already in memory. A call to the tracks() method might also do a triggerTrackLoad() which will start the asynchronous loading of tracks in the background. PlaylistObserver::trackAdded() will be called for each track that is added additionally to the playlist. trackRemoved() can also be called when the previous tracklist is affected.
0021 [note] automatic loading and async depends on the implementation.
0022 
0023 PlaylistProvider
0024 ----------------
0025 The PlaylistProvider base class is registered with PlaylistManager so it can act as a central point to distribute playlist to other Amarok components.
0026 Playlist loading can also be made asynchronous in the implementations. PlaylistProvider::playlistCount() can return -1 to indicate a full load is required to calculate this. After calling playlists(), which can return an empty list, playlistAdded() signals might be emitted while the asynchronous loading is going on.
0027 PlaylistProviders can offer the UI QActions for the provider, a specific playlist or a specific track in a playlist. Playlist also has these last 2 methods which in the default implementation call the provider's implementations. It's recommended to implement playlist and track actions in the provider.
0028 
0029 Playlist Synchronization
0030 ------------------------
0031 It's possible to set up a link between playlists of the same category but from different PlaylistProviders. PlaylistManager will try to bring those playlists in the same state i.e. the same tracks in the same order.
0032 The synchronization logic is implemented in SyncedPlaylist, a virtual class created with a factory pattern so other syncing algorithms can be applied at runtime. An example where this could be used: GPodderProvider's playlists are representations of the state of data on a web-service (gpodder.net). It has certain restrictions but also features that go beyond regular playlist synchronization. GPodderProvider can create a SyncedPlaylist class that specifically handles podcasts and keeps the limitations of the service and PodcastChannels in mind.
0033 [note] currently podcast synchronization uses the special function Playlist::syncTrackStatus() which should be replaced by the above mechanism to avoid implementation-at-high-level-creep.
0034 
0035 A SynchronizedPlaylist will appear to the higher layers as one playlist which exists on multiple PlaylistProviders. In order to display the multiple copies to the user a QItemProxyModel is used by the UI.
0036 
0037 The synchronization algorithm uses only those functions that are also needed by the regular playlist use cases. In theory Playlist implementations don't need to think about synchronization. In practice synchronization will only properly work with fully functional PlaylistProvider and Playlist implementations, which are desirable anyway.
0038 
0039 PlaylistBrowserModel
0040 --------------------
0041 PlaylistBrowserModel is the base class for ItemModels used to display the various playlist types. Although all playlist can be displayed using this base class all categories have their own specialized implementation to implement setData(), dropMimeData() and category specific actions (ex. PodcastModel::refreshPodcasts()). Not that these are usually convenience version of Provider actions.
0042 PlaylistBrowser model requests playlist for it's category from PlaylistManager who gathers them from the providers and group Synchronized playlists together in a SyncedPlaylist. PlaylistBrowserModel is a tree with playlist on the first level and tracks as it's children. In order to have playlists grouped by origin (i.e. PlaylistProvider) the PlaylistByProvider proxy.
0043 
0044 Playlist Tracking by PlaybackQueue
0045 ----------------------------------
0046 The PlaybackQueue can be made to track a single playlist's state. In general this just means that all current tracks of the playlist are appended to the queue and that it will act on trackAdded() signals. However, because the playback queue only has the upcoming tracks changes to tracks that have already been played are not possible. The distinction between a playlist and the queue has to be clear to the user.
0047 Using playlist tracking it's possible to implement all modes of the old Playlist by creating categories implementing the behavior of the modes.
0048 
0049 User Playlists
0050 --------------
0051 File based: XSPFPlaylist, M3UPlaylist, PLSPlaylist
0052 Database based: SqlPlaylist
0053 
0054 These playlists will load tracks using MetaProxy::Track which will start a worker thread to get a real track object using CollectionManager::trackForUrl(). It depends on the implementation and contents of the file which URL is used to resolve the track.
0055 M3U and PLS by specification require their contents to be playable URLs. For most collections the playable URL and uidUrl won't match, so these tracks won't be playable until their "real" track is resolved.
0056 XSPF does support storing of the uidUrl (identifier tag). Amarok always writes track's uidUrl to XSPF. The current playback queue state is also saved with XSPF to a dedicated file ($KDEHOME/share/apps/amarok/current.xspf).
0057 The playlist implementation fills the proxy tracks with any tag information it has stored. This way a recently loaded playlist has usable content while loading tracks is done asynchronously.
0058 If the playback queue is restored with invalid (empty) tracks, XSPFPlaylist, MetaProxy and CollectionManager::trackForUrl() are to be investigated.
0059 
0060 Dynamic Playlists
0061 -----------------
0062 Using a custom UI the settings for selecting tracks are configured. The Dynamic Playlist will select tracks and make them available from the tracks() method. These tracks can be displayed to the user as a preview of the settings but are mainly used in the playback queue.
0063 Using the Selector/Bias system other components and plugins can add track selection conditions or statistical bias options to the dynamic playlist generator.
0064 [note] current implementation does not derive from Playlists::Playlist nor does it use a PlaylistProvider. It's a mode of the playback queue, not a loadable playlist.
0065 
0066 Smart Playlists
0067 ---------------
0068 The basis of a Smart Playlist is a QueryMaker query and some additional limiters such as track count and total file size (useful to fill a media player). The list of tracks is not kept between sessions so a smart playlist is generated when first accessed. To avoid unneeded recalculation an active smart playlist will only be regenerated when the user requests it or when the synchronization of a playlist requires an up-to-date list.
0069 
0070 Podcast Channels
0071 ----------------
0072 This type is used for both the local (SQL based) PodcastProvider, some media device implementations and the gpodder web service. In the local collection the utility class PodcastReader is used to parse a podcast feed and update the PodcastChannel implementation. The base classes of PodcastMeta.cpp are used as intermediary data storage for new Channels and Episodes that have not been saved in the PodcastProvider yet.
0073 
0074 Radio Channels
0075 --------------
0076 The most common form of a radio channel is a HTTP stream. This implementation listens to signals from EngineController/PlaybackController/Phonon while playing the stream and determines when a metadata change represents a real track change. It will then push append the a new track with that metadata but the same url. This will not cause a real track change but rather a transition in the PlaybackController to the new playing track. It's a seamless progression in the PlaybackQueue as well.
0077 
0078 Services like last.fm and spotify also provider Radio Channels but it's implementation in possible user interaction is implementation specific.
0079 
0080 Random/Shuffle Playlist
0081 -----------------------
0082 This is a very simple randomizing playlist that takes the current play queue and shuffles the upcoming tracks at the start of a playing track. This way the user can see the next upcoming track already and change or remove them if desired. This playlist will respect the manual changes made to the playback order and not shuffle any of the tracks queued by the user.
0083 The shuffling of tracks should be a visual animation to make it clear what is happening and be somewhat pleasing to watch.
0084 
0085 Old Playlist Queue Manager Behavior
0086 -----------------------------------
0087 
0088 Implemented in PlaybackQueue.