Class MetadataFinder
- java.lang.Object
-
- org.deepsymmetry.beatlink.LifecycleParticipant
-
- org.deepsymmetry.beatlink.data.MetadataFinder
-
public class MetadataFinder extends LifecycleParticipant
Watches for new tracks to be loaded on players, and queries the appropriate player for the metadata information when that happens.
Maintains a hot cache of metadata about any track currently loaded in a player, either on the main playback deck, or as a hot cue, since those tracks could start playing instantly.
Can also create cache files containing metadata about either all tracks in a media library, or tracks from a specific play list, and attach those cache files to be used instead of actually querying the player about tracks loaded from that library. This can be used in busy performance situations where all four usable player numbers are in use by actual players, to avoid conflicting queries yet still have useful metadata available. In such situations, you may want to go into passive mode, using
setPassive(boolean), to prevent metadata queries about tracks that are not available from the attached metadata cache files.- Author:
- James Elliott
-
-
Field Summary
Fields Modifier and Type Field Description static intMENU_TIMEOUTHow many seconds are we willing to wait to lock the database client for menu operations.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description voidaddAutoAttachCacheFile(File metadataCacheFile)Add a metadata cache file to the set being automatically attached when matching media is inserted.voidaddCacheListener(MetadataCacheListener listener)Adds the specified cache update listener to receive updates when a metadata cache is attached or detached.voidaddMetadataProvider(MetadataProvider provider)Adds a metadata provider that will be consulted to see if it can provide metadata for newly-loaded tracks before we try to retrieve it from the players or our cache files.voidaddMountListener(MountListener listener)Adds the specified mount update listener to receive updates when media is mounted or unmounted by any player.voidaddTrackMetadataListener(TrackMetadataListener listener)Adds the specified track metadata listener to receive updates when the track metadata for a player changes.voidattachMetadataCache(SlotReference slot, File file)Attach a metadata cache file to a particular player media slot, so the cache will be used instead of querying the player for metadata.voiddetachMetadataCache(SlotReference slot)Removes any metadata cache file that might have been assigned to a particular player media slot, so metadata will be looked up from the player itself.List<File>getAutoAttachCacheFiles()Get the metadata cache files that are currently configured to be automatically attached when matching media is mounted in a player on the network.intgetAutoAttachProbeCount()Get the number of tracks examined when considering auto-attaching a metadata cache file to a newly-mounted media database.Set<MetadataCacheListener>getCacheListeners()Get the set of currently-registered metadata cache update listeners.static MetadataFindergetInstance()Get the singleton instance of this class.TrackMetadatagetLatestMetadataFor(int player)Look up the track metadata we have for the track loaded in the main deck of a given player number.TrackMetadatagetLatestMetadataFor(DeviceUpdate update)Look up the track metadata we have for a given player, identified by a status update received from that player.Map<DeckReference,TrackMetadata>getLoadedTracks()Get the metadata of all tracks currently loaded in any player, either on the play deck, or in a hot cue.MediaDetailsgetMediaDetailsFor(SlotReference slot)Look up the details we know about the media mounted in a particular slotMetadataCachegetMetadataCache(SlotReference slot)Finds the metadata cache file assigned to a particular player media slot, if any.Set<MetadataProvider>getMetadataProviders(MediaDetails sourceMedia)Get the set of metadata providers that can offer metadata for tracks loaded from the specified media.Collection<MediaDetails>getMountedMediaDetails()Get the details we know about all mounted media.Set<SlotReference>getMountedMediaSlots()Returns the set of media slots on the network that currently have media mounted in them.Set<MountListener>getMountListeners()Get the set of currently-registered mount update listeners.Set<TrackMetadataListener>getTrackMetadataListeners()Get the set of currently-registered track metadata update listeners.booleanisPassive()Check whether we are configured to use metadata only from caches, never actively requesting it from a player.booleanisRunning()Check whether we are currently running.voidremoveAutoAttacheCacheFile(File metadataCacheFile)Remove a metadata cache file from the set being automatically attached when matching media is inserted.voidremoveCacheListener(MetadataCacheListener listener)Removes the specified cache update listener so that it no longer receives updates when there are changes to the available set of metadata caches.voidremoveMetadataProvider(MetadataProvider provider)Removes a metadata provider so it will no longer be consulted to provide metadata for tracks loaded from any media.voidremoveMountListener(MountListener listener)Removes the specified mount update listener so that it no longer receives updates when a player mounts or unmounts media in one of its media slots.voidremoveTrackMetadataListener(TrackMetadataListener listener)Removes the specified track metadata update listener so that it no longer receives updates when track metadata for a player changes.TrackMetadatarequestMetadataFrom(CdjStatus status)Given a status update from a CDJ, find the metadata for the track that it has loaded, if any.TrackMetadatarequestMetadataFrom(DataReference track, CdjStatus.TrackType trackType)Ask the specified player for metadata about the track in the specified slot with the specified rekordbox ID, unless we have a metadata cache available for the specified media slot, in which case that will be used instead.List<Message>requestPlaylistItemsFrom(int player, CdjStatus.TrackSourceSlot slot, int sortOrder, int playlistOrFolderId, boolean folder)Ask the specified player's dbserver for the playlist entries of the specified playlist (iffolderisfalse, or the list of playlists and folders inside the specified playlist folder (iffolderistrue.voidsetAutoAttachProbeCount(int numTracks)Set the number of tracks examined when considering auto-attaching a metadata cache file to a newly-mounted media database.voidsetPassive(boolean passive)Set whether we are configured to use metadata only from caches, never actively requesting it from a player.voidstart()Start finding track metadata for all active players.voidstop()Stop finding track metadata for all active players.StringtoString()-
Methods inherited from class org.deepsymmetry.beatlink.LifecycleParticipant
addLifecycleListener, deliverLifecycleAnnouncement, ensureRunning, getLifecycleListeners, removeLifecycleListener
-
-
-
-
Field Detail
-
MENU_TIMEOUT
public static final int MENU_TIMEOUT
How many seconds are we willing to wait to lock the database client for menu operations.- See Also:
- Constant Field Values
-
-
Method Detail
-
requestMetadataFrom
public TrackMetadata requestMetadataFrom(CdjStatus status)
Given a status update from a CDJ, find the metadata for the track that it has loaded, if any. If there is an appropriate metadata cache, will use that, otherwise makes a query to the players dbserver.- Parameters:
status- the CDJ status update that will be used to determine the loaded track and ask the appropriate player for metadata about it- Returns:
- the metadata that was obtained, if any
-
requestMetadataFrom
public TrackMetadata requestMetadataFrom(DataReference track, CdjStatus.TrackType trackType)
Ask the specified player for metadata about the track in the specified slot with the specified rekordbox ID, unless we have a metadata cache available for the specified media slot, in which case that will be used instead.- Parameters:
track- uniquely identifies the track whose metadata is desiredtrackType- identifies the type of track being requested, which affects the type of metadata request message that must be used- Returns:
- the metadata, if any
-
requestPlaylistItemsFrom
public List<Message> requestPlaylistItemsFrom(int player, CdjStatus.TrackSourceSlot slot, int sortOrder, int playlistOrFolderId, boolean folder) throws Exception
Ask the specified player's dbserver for the playlist entries of the specified playlist (iffolderisfalse, or the list of playlists and folders inside the specified playlist folder (iffolderistrue.- Parameters:
player- the player number whose playlist entries are of interestslot- the slot in which the playlist can be foundsortOrder- the order in which responses should be sorted, 0 for default, see Section 6.11.1 of the Packet Analysis document for detailsplaylistOrFolderId- the database ID of the desired playlist or folderfolder- indicates whether we are asking for the contents of a folder or playlist- Returns:
- the items that are found in the specified playlist or folder; they will be tracks if we are asking for a playlist, or playlists and folders if we are asking for a folder
- Throws:
Exception- if there is a problem obtaining the playlist information
-
isRunning
public boolean isRunning()
Check whether we are currently running. Unless we are in passive mode, we will also automatically request metadata from the appropriate player when a new track is loaded that is not found in the hot cache or an attached metadata cache file.- Specified by:
isRunningin classLifecycleParticipant- Returns:
- true if track metadata is being kept track of for all active players
- See Also:
isPassive()
-
isPassive
public boolean isPassive()
Check whether we are configured to use metadata only from caches, never actively requesting it from a player. Note that this will implicitly mean all of the metadata-related finders (ArtFinder,BeatGridFinder, andWaveformFinder) are in passive mode as well, because their activity is triggered by the availability of new track metadata.- Returns:
trueif only cached metadata will be used, orfalseif metadata will be requested from a player if a track is loaded from a media slot to which no cache has been assigned
-
setPassive
public void setPassive(boolean passive)
Set whether we are configured to use metadata only from caches, never actively requesting it from a player. Note that this will implicitly put all of the metadata-related finders (ArtFinder,BeatGridFinder, andWaveformFinder) into a passive mode as well, because their activity is triggered by the availability of new track metadata.- Parameters:
passive-trueif only cached metadata will be used, orfalseif metadata will be requested from a player if a track is loaded from a media slot to which no cache has been assigned
-
getLoadedTracks
public Map<DeckReference,TrackMetadata> getLoadedTracks()
Get the metadata of all tracks currently loaded in any player, either on the play deck, or in a hot cue.- Returns:
- the track information reported by all current players, including any tracks loaded in their hot cue slots
- Throws:
IllegalStateException- if the MetadataFinder is not running
-
getLatestMetadataFor
public TrackMetadata getLatestMetadataFor(int player)
Look up the track metadata we have for the track loaded in the main deck of a given player number.- Parameters:
player- the device number whose track metadata for the playing track is desired- Returns:
- information about the track loaded on that player, if available
- Throws:
IllegalStateException- if the MetadataFinder is not running
-
getLatestMetadataFor
public TrackMetadata getLatestMetadataFor(DeviceUpdate update)
Look up the track metadata we have for a given player, identified by a status update received from that player.- Parameters:
update- a status update from the player for which track metadata is desired- Returns:
- information about the track loaded on that player, if available
- Throws:
IllegalStateException- if the MetadataFinder is not running
-
attachMetadataCache
public void attachMetadataCache(SlotReference slot, File file) throws IOException
Attach a metadata cache file to a particular player media slot, so the cache will be used instead of querying the player for metadata. This supports operation with metadata during shows where DJs are using all four player numbers and heavily cross-linking between them. If the media is ejected from that player slot, the cache will be detached.- Parameters:
slot- the media slot to which a meta data cache is to be attachedfile- the metadata cache to be attached- Throws:
IOException- if there is a problem reading the cache fileIllegalArgumentException- if an invalid player number or slot is suppliedIllegalStateException- if the metadata finder is not running
-
detachMetadataCache
public void detachMetadataCache(SlotReference slot)
Removes any metadata cache file that might have been assigned to a particular player media slot, so metadata will be looked up from the player itself.- Parameters:
slot- the media slot to which a meta data cache is to be attached
-
addAutoAttachCacheFile
public void addAutoAttachCacheFile(File metadataCacheFile) throws IOException
Add a metadata cache file to the set being automatically attached when matching media is inserted. Will try to auto-attach the new file to any already-mounted media. Adding a file that is already present in the set will have no effect, and if the file being added was created from the same media as any existing file in the set, the new file will replace the existing one, since only one file can match the media when it mounts. (Tracking of source media was only added in version 0.4.1.)- Parameters:
metadataCacheFile- the file to be auto-attached when matching media is seen on the network- Throws:
IOException- if the specified file cannot be read or is not a valid metadata cache
-
removeAutoAttacheCacheFile
public void removeAutoAttacheCacheFile(File metadataCacheFile)
Remove a metadata cache file from the set being automatically attached when matching media is inserted. This will not detach it from a slot if it has already been attached; for that you need to usedetachMetadataCache(SlotReference).- Parameters:
metadataCacheFile- the file that should no longer be auto-attached when matching media is seen
-
getAutoAttachCacheFiles
public List<File> getAutoAttachCacheFiles()
Get the metadata cache files that are currently configured to be automatically attached when matching media is mounted in a player on the network.- Returns:
- the current auto-attache cache files, sorted by name
-
setAutoAttachProbeCount
public void setAutoAttachProbeCount(int numTracks)
Set the number of tracks examined when considering auto-attaching a metadata cache file to a newly-mounted media database. The more examined, the more confident we can be in the cache matching the media, but the longer it will take and the more metadata queries will be required. The smallest legal value is 1. This value is only used for metadata caches created by versions older than 0.4.1, because they lacked the ability to match by the details of the media database itself.- Parameters:
numTracks- the number of tracks that will be compared between the cache files and the media in the player
-
getAutoAttachProbeCount
public int getAutoAttachProbeCount()
Get the number of tracks examined when considering auto-attaching a metadata cache file to a newly-mounted media database. The more examined, the more confident we can be in the cache matching the media, but the longer it will take and the more metadata queries will be required. This value is only used for metadata caches created by versions older than 0.4.1, because they lacked the ability to match by the details of the media database itself.- Returns:
- the number of tracks that will be compared between the cache files and the media in the player
-
getMetadataCache
public MetadataCache getMetadataCache(SlotReference slot)
Finds the metadata cache file assigned to a particular player media slot, if any.- Parameters:
slot- the media slot to which a meta data cache is to be attached- Returns:
- the metadata cache for that player and slot, or
nullif no cache has been attached
-
getMountedMediaSlots
public Set<SlotReference> getMountedMediaSlots()
Returns the set of media slots on the network that currently have media mounted in them. Note that computers running rekordbox are included; their collections are valid media databases to explore with theMenuLoader, and they are valid asSlotReferencearguments to tell players to load tracks from.- Returns:
- the slots with media currently available on the network, including rekordbox instances
-
getMountedMediaDetails
public Collection<MediaDetails> getMountedMediaDetails()
Get the details we know about all mounted media.- Returns:
- the media details the Virtual CDJ has been able to find for us about the mounted slots.
-
getMediaDetailsFor
public MediaDetails getMediaDetailsFor(SlotReference slot)
Look up the details we know about the media mounted in a particular slot- Parameters:
slot- the slot whose media is of interest- Returns:
- the details, or
nullif we don't have any
-
addMountListener
public void addMountListener(MountListener listener)
Adds the specified mount update listener to receive updates when media is mounted or unmounted by any player. Iflistenerisnullor already present in the set of registered listeners, no exception is thrown and no action is performed.Note that at the time a mount is detected, we will not yet know any details about the mounted media. If
listeneralso implementsMediaDetailsListener, then as soon as the media details have been reported by the mounting player,MediaDetailsListener.detailsAvailable(MediaDetails)will be called with them.To reduce latency, updates are delivered to listeners directly on the thread that is receiving packets from the network, so if you want to interact with user interface objects in listener methods, you need to use
javax.swing.SwingUtilities.invokeLater(Runnable)to do so on the Event Dispatch Thread.Even if you are not interacting with user interface objects, any code in the listener method must finish quickly, or it will add latency for other listeners, and updates will back up. If you want to perform lengthy processing of any sort, do so on another thread.
- Parameters:
listener- the mount update listener to add
-
removeMountListener
public void removeMountListener(MountListener listener)
Removes the specified mount update listener so that it no longer receives updates when a player mounts or unmounts media in one of its media slots. Iflistenerisnullor not present in the set of registered listeners, no exception is thrown and no action is performed.- Parameters:
listener- the mount update listener to remove
-
getMountListeners
public Set<MountListener> getMountListeners()
Get the set of currently-registered mount update listeners.- Returns:
- the listeners that are currently registered for mount updates
-
addCacheListener
public void addCacheListener(MetadataCacheListener listener)
Adds the specified cache update listener to receive updates when a metadata cache is attached or detached. Iflistenerisnullor already present in the set of registered listeners, no exception is thrown and no action is performed.To reduce latency, updates are delivered to listeners directly on the thread that is receiving packets from the network, so if you want to interact with user interface objects in listener methods, you need to use
javax.swing.SwingUtilities.invokeLater(Runnable)to do so on the Event Dispatch Thread. Even if you are not interacting with user interface objects, any code in the listener method must finish quickly, or it will add latency for other listeners, and updates will back up. If you want to perform lengthy processing of any sort, do so on another thread.- Parameters:
listener- the cache update listener to add
-
removeCacheListener
public void removeCacheListener(MetadataCacheListener listener)
Removes the specified cache update listener so that it no longer receives updates when there are changes to the available set of metadata caches. Iflistenerisnullor not present in the set of registered listeners, no exception is thrown and no action is performed.- Parameters:
listener- the cache update listener to remove
-
getCacheListeners
public Set<MetadataCacheListener> getCacheListeners()
Get the set of currently-registered metadata cache update listeners.- Returns:
- the listeners that are currently registered for metadata cache updates
-
addTrackMetadataListener
public void addTrackMetadataListener(TrackMetadataListener listener)
Adds the specified track metadata listener to receive updates when the track metadata for a player changes. Iflistenerisnullor already present in the set of registered listeners, no exception is thrown and no action is performed.To reduce latency, updates are delivered to listeners directly on the thread that is receiving packets from the network, so if you want to interact with user interface objects in listener methods, you need to use
javax.swing.SwingUtilities.invokeLater(Runnable)to do so on the Event Dispatch Thread. Even if you are not interacting with user interface objects, any code in the listener method must finish quickly, or it will add latency for other listeners, and updates will back up. If you want to perform lengthy processing of any sort, do so on another thread.- Parameters:
listener- the track metadata update listener to add
-
removeTrackMetadataListener
public void removeTrackMetadataListener(TrackMetadataListener listener)
Removes the specified track metadata update listener so that it no longer receives updates when track metadata for a player changes. Iflistenerisnullor not present in the set of registered listeners, no exception is thrown and no action is performed.- Parameters:
listener- the track metadata update listener to remove
-
getTrackMetadataListeners
public Set<TrackMetadataListener> getTrackMetadataListeners()
Get the set of currently-registered track metadata update listeners.- Returns:
- the listeners that are currently registered for track metadata updates
-
addMetadataProvider
public void addMetadataProvider(MetadataProvider provider)
Adds a metadata provider that will be consulted to see if it can provide metadata for newly-loaded tracks before we try to retrieve it from the players or our cache files. This function will immediately callMetadataProvider.supportedMedia()and will only consult the provider for tracks loaded from the media mentioned in the response. The function is only called once, when initially adding the provider, so if the set of supported media changes, you will need to remove the provider and re-add it. Providers that can provide metadata for all media can simply return an empty list of supported media, and they will always be consulted. Only do this if they truly can always provide metadata, or you will slow down the lookup process by having them frequently called in vain.- Parameters:
provider- the object that can supply metadata about tracks- Throws:
IllegalArgumentException- if you pass in aMetadataCache.
-
removeMetadataProvider
public void removeMetadataProvider(MetadataProvider provider)
Removes a metadata provider so it will no longer be consulted to provide metadata for tracks loaded from any media.- Parameters:
provider- the metadata provider to remove.
-
getMetadataProviders
public Set<MetadataProvider> getMetadataProviders(MediaDetails sourceMedia)
Get the set of metadata providers that can offer metadata for tracks loaded from the specified media.- Parameters:
sourceMedia- the media whose metadata providers are desired, ornullto get the set of metadata providers that can offer metadata for all media.- Returns:
- any registered metadata providers that reported themselves as supporting tracks from that media
-
start
public void start() throws ExceptionStart finding track metadata for all active players. Starts theVirtualCdjif it is not already running, because we need it to send us device status updates to notice when new tracks are loaded; this starts theDeviceFinder(which is also needed by theVirtualCdj) so we can keep track of the comings and goings of players themselves. We start theConnectionManagerin order to make queries to obtain metadata.- Throws:
Exception- if there is a problem starting the required components
-
stop
public void stop()
Stop finding track metadata for all active players.
-
getInstance
public static MetadataFinder getInstance()
Get the singleton instance of this class.- Returns:
- the only instance of this class which exists.
-
-