protected void AssertTitleSort(string title, string title_sort, byte[] expected)
 {
     DatabaseTrackInfo info = new DatabaseTrackInfo ();
     info.TrackTitle = title;
     info.TrackTitleSort = title_sort;
     Assert.AreEqual (expected, info.TrackTitleSortKey);
 }
Exemplo n.º 2
0
 protected static PrimarySource DefaultTrackPrimarySourceChooser (DatabaseTrackInfo track)
 {
     if ((track.MediaAttributes & TrackMediaAttributes.VideoStream) != 0) {
         return ServiceManager.SourceManager.VideoLibrary;
     } else {
         return ServiceManager.SourceManager.MusicLibrary;
     }
 }
Exemplo n.º 3
0
 public override void CopyTrackTo (DatabaseTrackInfo track, SafeUri uri, BatchUserJob job)
 {
     if (track.PrimarySource == this && track.Uri.Scheme.StartsWith ("http")) {
         foreach (double percent in database.DownloadTrack ((int)track.ExternalId, track.MimeType, uri.AbsolutePath)) {
             job.DetailedProgress = percent;
         }
     }
 }
Exemplo n.º 4
0
        public Bookmark(DatabaseTrackInfo track, int position_ms, string type)
        {
            Track = track;
            Position = TimeSpan.FromMilliseconds (position_ms);
            CreatedAt = DateTime.Now;
            Type = type;

            Save ();
        }
        private void DownloadLyrics(DatabaseTrackInfo track)
        {
            string lyrics = null;
            try {
                lyrics = LyricsManager.Instance.DownloadLyrics (track);
            } catch (Exception e) {
                Log.Warning (e);
                return;
            }

            LyricsManager.Instance.SaveLyrics (track, lyrics, true);
        }
        public PodcastPropertiesDialog (DatabaseTrackInfo track)
        {
            PodcastTrackInfo pi = PodcastTrackInfo.From (track);
            if (pi == null)
            {
                throw new ArgumentNullException ("pi");
            }

            this.pi = pi;

            Title = track.TrackTitle;
            BuildWindow ();
            //IconThemeUtils.SetWindowIcon (this);
        }
        public ContactTrackInfo(DatabaseTrackInfo track, ContactSource source)
            : this()
        {
            if (track == null) {
                throw new ArgumentNullException ("track");
            }
            else if (source == null) {
                throw new ArgumentNullException ("source");
            }

            this.TrackId = track.TrackId;
            this.ExternalId = track.ExternalId;
            this.AlbumTitle = track.AlbumTitle;
            this.ArtistName = track.ArtistName;
            this.TrackNumber = track.TrackNumber;
            this.TrackTitle = track.TrackTitle;
            this.Uri = track.Uri;

            PrimarySource = source;
        }
        protected override void AddTrackToDevice (DatabaseTrackInfo track, SafeUri fromUri)
        {
            if (track.PrimarySourceId == DbId)
                return;

            SafeUri new_uri = new SafeUri (GetTrackPath (track, System.IO.Path.GetExtension (fromUri.LocalPath)));
            // If it already is on the device but it's out of date, remove it
            //if (File.Exists(new_uri) && File.GetLastWriteTime(track.Uri.LocalPath) > File.GetLastWriteTime(new_uri))
                //RemoveTrack(new MassStorageTrackInfo(new SafeUri(new_uri)));

            if (!File.Exists (new_uri)) {
                Directory.Create (System.IO.Path.GetDirectoryName (new_uri.LocalPath));
                File.Copy (fromUri, new_uri, false);

                DatabaseTrackInfo copied_track = new DatabaseTrackInfo (track);
                copied_track.PrimarySource = this;
                copied_track.Uri = new_uri;

                // Write the metadata in db to the file on the DAP if it has changed since file was modified
                // to ensure that when we load it next time, it's data will match what's in the database
                // and the MetadataHash will actually match.  We do this by comparing the time
                // stamps on files for last update of the db metadata vs the sync to file.
                // The equals on the inequality below is necessary for podcasts who often have a sync and
                // update time that are the same to the second, even though the album metadata has changed in the
                // DB to the feedname instead of what is in the file.  It should be noted that writing the metadata
                // is a small fraction of the total copy time anyway.

                if (track.LastSyncedStamp >= Hyena.DateTimeUtil.ToDateTime (track.FileModifiedStamp)) {
                    Log.DebugFormat ("Copying Metadata to File Since Sync time >= Updated Time");
                    bool write_metadata = Metadata.SaveTrackMetadataService.WriteMetadataEnabled.Value;
                    bool write_ratings_and_playcounts = Metadata.SaveTrackMetadataService.WriteRatingsAndPlayCountsEnabled.Value;
                    Banshee.Streaming.StreamTagger.SaveToFile (copied_track, write_metadata, write_ratings_and_playcounts);
                }

                copied_track.Save (false);
            }

            if (CoverArtSize > -1 && !String.IsNullOrEmpty (CoverArtFileType) &&
                    !String.IsNullOrEmpty (CoverArtFileName) && (FolderDepth == -1 || FolderDepth > 0)) {
                SafeUri cover_uri = new SafeUri (System.IO.Path.Combine (System.IO.Path.GetDirectoryName (new_uri.LocalPath),
                                                                         CoverArtFileName));
                string coverart_id = track.ArtworkId;

                if (!File.Exists (cover_uri) && CoverArtSpec.CoverExists (coverart_id)) {
                    Gdk.Pixbuf pic = null;

                    if (CoverArtSize == 0) {
                        if (CoverArtFileType == "jpg" || CoverArtFileType == "jpeg") {
                            SafeUri local_cover_uri = new SafeUri (Banshee.Base.CoverArtSpec.GetPath (coverart_id));
                            Banshee.IO.File.Copy (local_cover_uri, cover_uri, false);
                        } else {
                            pic = artwork_manager.LookupPixbuf (coverart_id);
                        }
                    } else {
                        pic = artwork_manager.LookupScalePixbuf (coverart_id, CoverArtSize);
                    }

                    if (pic != null) {
                        try {
                            byte [] bytes = pic.SaveToBuffer (CoverArtFileType);
                            System.IO.Stream cover_art_file = File.OpenWrite (cover_uri, true);
                            cover_art_file.Write (bytes, 0, bytes.Length);
                            cover_art_file.Close ();
                        } catch (GLib.GException){
                            Log.DebugFormat ("Could not convert cover art to {0}, unsupported filetype?", CoverArtFileType);
                        } finally {
                            Banshee.Collection.Gui.ArtworkManager.DisposePixbuf (pic);
                        }
                    }
                }
            }
        }
 public override void CopyTrackTo (DatabaseTrackInfo track, SafeUri uri, BatchUserJob job)
 {
     if (track.PrimarySourceId == DbId) {
         Banshee.IO.File.Copy (track.Uri, uri, false);
     }
 }
Exemplo n.º 10
0
        public DatabaseTrackInfo ImportTrack(SafeUri uri)
        {
            if (!IsWhiteListedFile(uri.AbsoluteUri))
            {
                return(null);
            }

            if (DatabaseTrackInfo.ContainsUri(uri, PrimarySourceIds))
            {
                // TODO add DatabaseTrackInfo.SyncedStamp property, and if the file has been
                // updated since the last sync, fetch its metadata into the db.
                return(null);
            }

            if (Banshee.IO.File.GetSize(uri) == 0)
            {
                throw new InvalidFileException(String.Format(
                                                   Catalog.GetString("File is empty so it could not be imported: {0}"),
                                                   Path.GetFileName(uri.LocalPath)));
            }

            DatabaseTrackInfo track = new DatabaseTrackInfo()
            {
                Uri = uri
            };

            using (var file = StreamTagger.ProcessUri(uri)) {
                StreamTagger.TrackInfoMerge(track, file, false, true, true);
            }

            track.Uri = uri;

            if (FindOutdatedDupe(track))
            {
                return(null);
            }

            track.PrimarySource = trackPrimarySourceChooser(track);

            // TODO note, there is deadlock potential here b/c of locking of shared commands and blocking
            // because of transactions.  Needs to be fixed in HyenaDatabaseConnection.
            ServiceManager.DbConnection.BeginTransaction();
            try {
                bool save_track = true;
                if (track.PrimarySource is Banshee.Library.LibrarySource)
                {
                    save_track = track.CopyToLibraryIfAppropriate(force_copy);
                }

                if (save_track)
                {
                    track.Save(false);
                }

                ServiceManager.DbConnection.CommitTransaction();
            } catch (Exception) {
                ServiceManager.DbConnection.RollbackTransaction();
                throw;
            }

            counts[track.PrimarySourceId] = counts.ContainsKey(track.PrimarySourceId) ? counts[track.PrimarySourceId] + 1 : 1;

            // Reload every 20% or every 250 tracks, whatever is more (eg at most reload 5 times during an import)
            if (counts[track.PrimarySourceId] >= Math.Max(TotalCount / 5, 250))
            {
                counts[track.PrimarySourceId] = 0;
                track.PrimarySource.NotifyTracksAdded();
            }

            return(track);
        }
Exemplo n.º 11
0
        protected override bool DeleteTrack (DatabaseTrackInfo track)
        {
            lock (mtp_device) {
                Track mtp_track = track_map [track.TrackId];
                track_map.Remove (track.TrackId);

                // Remove from device
                mtp_device.Remove (mtp_track);

                // Remove track from album, and remove album from device if it no longer has tracks
                string key = MakeAlbumKey (track.ArtistName, track.AlbumTitle);
                if (album_cache.ContainsKey (key)) {
                    Album album = album_cache[key];
                    album.RemoveTrack (mtp_track);
                    if (album.Count == 0) {
                        album.Remove ();
                        album_cache.Remove (key);
                    }
                }

                return true;
            }
        }
Exemplo n.º 12
0
 public override void CopyTrackTo (DatabaseTrackInfo track, SafeUri uri, BatchUserJob job)
 {
     if (track_map.ContainsKey (track.TrackId)) {
         track_map[track.TrackId].Download (uri.LocalPath, delegate (ulong current, ulong total, IntPtr data) {
             job.DetailedProgress = (double) current / total;
             return 0;
         });
     } else {
         throw new Exception ("Error copying track from MTP device");
     }
 }
Exemplo n.º 13
0
        private bool RenameFile (DatabaseTrackInfo track)
        {
            SafeUri old_uri = track.Uri;
            bool in_library = old_uri.AbsolutePath.StartsWith (musicLibrarySource.BaseDirectoryWithSeparator);

            if (!in_library) {
                return false;
            }

            string new_filename = track.PathPattern.BuildFull (musicLibrarySource.BaseDirectory, track, System.IO.Path.GetExtension (old_uri.ToString ()));
            SafeUri new_uri = new SafeUri (new_filename);

            if (!new_uri.Equals (old_uri) && !Banshee.IO.File.Exists (new_uri)) {
                Banshee.IO.File.Move (old_uri, new_uri);
                Banshee.IO.Utilities.TrimEmptyDirectories (old_uri);
                track.Uri = new_uri;
                return true;
            }

            return false;
        }
Exemplo n.º 14
0
 private void EditStation (DatabaseTrackInfo track)
 {
     StationEditor editor = new StationEditor (track);
     editor.Response += OnStationEditorResponse;
     editor.Show ();
 }
Exemplo n.º 15
0
        protected virtual bool DeleteTrack (DatabaseTrackInfo track)
        {
            if (!track.Uri.IsLocalPath)
                throw new Exception ("Cannot delete a non-local resource: " + track.Uri.Scheme);

            try {
                Banshee.IO.Utilities.DeleteFileTrimmingParentDirectories (track.Uri);
            } catch (System.IO.FileNotFoundException) {
            } catch (System.IO.DirectoryNotFoundException) {
            }

            return true;
        }
Exemplo n.º 16
0
 public virtual void UpdateMetadata (DatabaseTrackInfo track)
 {
 }
        protected override bool DeleteTrack (DatabaseTrackInfo track)
        {
            try {
                if (ms_device != null && !ms_device.DeleteTrackHook (track)) {
                    return false;
                }

                string track_file = System.IO.Path.GetFileName (track.Uri.LocalPath);
                string track_dir = System.IO.Path.GetDirectoryName (track.Uri.LocalPath);
                int files = 0;

                // Count how many files remain in the track's directory,
                // excluding self or cover art
                foreach (string file in System.IO.Directory.GetFiles (track_dir)) {
                    string relative = System.IO.Path.GetFileName (file);
                    if (relative != track_file && relative != CoverArtFileName) {
                        files++;
                    }
                }

                // If we are the last track, go ahead and delete the artwork
                // to ensure that the directory tree can get trimmed away too
                if (files == 0 && CoverArtFileName != null) {
                    System.IO.File.Delete (Paths.Combine (track_dir, CoverArtFileName));
                }

                Banshee.IO.Utilities.DeleteFileTrimmingParentDirectories (track.Uri);
            } catch (System.IO.FileNotFoundException) {
            } catch (System.IO.DirectoryNotFoundException) {
            }

            return true;
        }
Exemplo n.º 18
0
 public static bool TrackEqual(DatabaseTrackInfo a, DatabaseTrackInfo b)
 {
     return(a != null && b != null && a.TrackId == b.TrackId);
 }
Exemplo n.º 19
0
 public DatabaseTrackInfo(DatabaseTrackInfo original) : base()
 {
     Provider.Copy(original, this);
 }
Exemplo n.º 20
0
 private void FetchForTrack(DatabaseTrackInfo track)
 {
     bool save = true;
     try {
         if (String.IsNullOrEmpty (track.AlbumTitle) || String.IsNullOrEmpty (track.ArtistName)) {
             // Do not try to fetch album art for these
         } else {
             IMetadataLookupJob job = MetadataService.Instance.CreateJob (track);
             job.Run ();
         }
     } catch (System.Threading.ThreadAbortException) {
         save = false;
         throw;
     } catch (Exception e) {
         Log.Exception (e);
     } finally {
         if (save) {
             bool have_cover_art = CoverArtSpec.CoverExists (track.ArtistName, track.AlbumTitle);
             ServiceManager.DbConnection.Execute (
                 "INSERT OR REPLACE INTO CoverArtDownloads (AlbumID, Downloaded, LastAttempt) VALUES (?, ?, ?)",
                 track.AlbumId, have_cover_art, DateTime.Now);
         }
     }
 }
Exemplo n.º 21
0
        public override bool DeleteTrackHook (DatabaseTrackInfo track)
        {
            // Do not allow removing purchased tracks if not in the
            // Amazon Purchased Music source; this should prevent
            // accidental deletion of purchased music that may not
            // have been copied from the device yet.
            //
            // TODO: Provide some feedback when a purchased track is
            // skipped from deletion
            //
            // FIXME: unfortunately this does not work due to
            // the cache models being potentially different
            // even though they will always reference the same tracks
            // amazon_source.TrackModel.IndexOf (track) >= 0
            if (!amazon_source.Active && amazon_source.Count > 0 && track.Uri.LocalPath.StartsWith (amazon_base_dir)) {
                return false;
            }

            return true;
        }
Exemplo n.º 22
0
 public virtual void CopyTrackTo (DatabaseTrackInfo track, SafeUri uri, BatchUserJob job)
 {
     Log.WarningFormat ("CopyTrackTo not implemented for source {0}", this);
 }
Exemplo n.º 23
0
 protected override void AddTrack(DatabaseTrackInfo track)
 {
     AddTrack (track.TrackId);
 }
Exemplo n.º 24
0
 protected virtual void AddTrackAndIncrementCount (DatabaseTrackInfo track)
 {
     AddTrackJob.Status = String.Format ("{0} - {1}", track.ArtistName, track.TrackTitle);
     AddTrack (track);
     IncrementAddedTracks ();
 }
Exemplo n.º 25
0
        /*public override void CopyTrackTo (DatabaseTrackInfo track, SafeUri uri, UserJob job)
        {
            Banshee.IO.File.Copy (track.Uri, uri, false);
        }*/

        protected override void AddTrack (DatabaseTrackInfo track)
        {
            // Ignore if already have it
            if (track.PrimarySourceId == DbId)
                return;

            PrimarySource source = track.PrimarySource;

            // If it's from a local primary source, change its PrimarySource
            if (source.IsLocal || source is LibrarySource) {
                track.PrimarySource = this;

                if (!(source is LibrarySource)) {
                    track.CopyToLibraryIfAppropriate (false);
                }

                track.Save (false);

                // TODO optimize, remove this?  I think it makes moving items
                // between local libraries very slow.
                //source.NotifyTracksChanged ();
            } else {
                // Figure out where we should put it if were to copy it
                var pattern = this.PathPattern ?? MusicLibrarySource.MusicFileNamePattern;
                string path = pattern.BuildFull (BaseDirectory, track);
                SafeUri uri = new SafeUri (path);

                // Make sure it's not already in the library
                // TODO optimize - no need to recreate this int [] every time
                if (DatabaseTrackInfo.ContainsUri (uri, new int [] {DbId})) {
                    return;
                }

                // Since it's not, copy it and create a new TrackInfo object
                track.PrimarySource.CopyTrackTo (track, uri, AddTrackJob);

                // Create a new entry in CoreTracks for the copied file
                DatabaseTrackInfo new_track = new DatabaseTrackInfo (track);
                new_track.Uri = uri;
                new_track.PrimarySource = this;
                new_track.Save (false);
            }
        }
        /// <summary>
        /// Adds the currently selected item(s) of the active source to the internet radio source
        /// as new stations. Any session data (as in live365 with activated user login) will previously
        /// be cleared.
        /// </summary>
        /// <param name="o">
        /// A <see cref="System.Object"/> -- not used
        /// </param>
        /// <param name="e">
        /// A <see cref="EventArgs"/> -- not used
        /// </param>
        protected void OnAddToInternetRadio(object o, EventArgs e)
        {
            PrimarySource internet_radio_source = GetInternetRadioSource ();
            PrimarySource current_source = ServiceManager.SourceManager.ActiveSource as PrimarySource;
            if (current_source == null) {
                Log.Debug ("[LiveRadioSource]<OnAddToInternetRadio> ActiveSource not Primary");
                return;
            }
            if (internet_radio_source == null) {
                Log.Debug ("[LiveRadioSource]<OnAddToInternetRadio> Internet Radio not found");
                return;
            }

            ITrackModelSource active_track_model_source = (ITrackModelSource) current_source;

            if (active_track_model_source.TrackModel.SelectedItems == null ||
                active_track_model_source.TrackModel.SelectedItems.Count <= 0) {
                return;
            }

            ILiveRadioPlugin current_plugin = null;
            foreach (ILiveRadioPlugin plugin in plugins)
            {
                if (plugin.PluginSource != null && plugin.PluginSource.Equals (current_source))
                {
                    current_plugin = plugin;
                }
            }

            foreach (TrackInfo track in active_track_model_source.TrackModel.SelectedItems) {
                DatabaseTrackInfo station_track = new DatabaseTrackInfo (track as DatabaseTrackInfo);
                if (station_track != null) {
                    station_track.PrimarySource = internet_radio_source;
                    if (current_plugin != null)
                        station_track.Uri = current_plugin.CleanUpUrl (station_track.Uri);
                    station_track.Save ();
                }
            }
        }
Exemplo n.º 27
0
 protected virtual void OnImportResult (DatabaseTrackInfo track, string path, Exception error)
 {
     DatabaseImportResultHandler handler = ImportResult;
     if (handler != null) {
         handler (this, new DatabaseImportResultArgs (track, path, error));
     }
 }
Exemplo n.º 28
0
 public virtual bool DeleteTrackHook (DatabaseTrackInfo track)
 {
     return true;
 }
Exemplo n.º 29
0
        public DatabaseTrackInfo ImportTrack (SafeUri uri)
        {
            if (!IsWhiteListedFile (uri.AbsoluteUri)) {
                return null;
            }

            if (DatabaseTrackInfo.ContainsUri (uri, PrimarySourceIds)) {
                // TODO add DatabaseTrackInfo.SyncedStamp property, and if the file has been
                // updated since the last sync, fetch its metadata into the db.
                return null;
            }

            if (Banshee.IO.File.GetSize (uri) == 0) {
                throw new InvalidFileException (String.Format (
                    Catalog.GetString ("File is empty so it could not be imported: {0}"),
                    Path.GetFileName (uri.LocalPath)));
            }

            DatabaseTrackInfo track = new DatabaseTrackInfo () { Uri = uri };
            using (var file = StreamTagger.ProcessUri (uri)) {
                StreamTagger.TrackInfoMerge (track, file, false, true, true);
            }

            track.Uri = uri;

            if (FindOutdatedDupe (track)) {
                return null;
            }

            track.PrimarySource = trackPrimarySourceChooser (track);

            // TODO note, there is deadlock potential here b/c of locking of shared commands and blocking
            // because of transactions.  Needs to be fixed in HyenaDatabaseConnection.
            ServiceManager.DbConnection.BeginTransaction ();
            try {
                bool save_track = true;
                if (track.PrimarySource is Banshee.Library.LibrarySource) {
                    save_track = track.CopyToLibraryIfAppropriate (force_copy);
                }

                if (save_track) {
                    track.Save (false);
                }

                ServiceManager.DbConnection.CommitTransaction ();
            } catch (Exception) {
                ServiceManager.DbConnection.RollbackTransaction ();
                throw;
            }

            counts[track.PrimarySourceId] = counts.ContainsKey (track.PrimarySourceId) ? counts[track.PrimarySourceId] + 1 : 1;

            // Reload every 20% or every 250 tracks, whatever is more (eg at most reload 5 times during an import)
            if (counts[track.PrimarySourceId] >= Math.Max (TotalCount/5, 250)) {
                counts[track.PrimarySourceId] = 0;
                track.PrimarySource.NotifyTracksAdded ();
            }

            return track;
        }
Exemplo n.º 30
0
        protected override void AddTrackToDevice (DatabaseTrackInfo track, SafeUri fromUri)
        {
            if (track.PrimarySourceId == DbId)
                return;

            lock (mtp_device) {
                Track mtp_track = TrackInfoToMtpTrack (track, fromUri);
                bool video = track.HasAttribute (TrackMediaAttributes.VideoStream);
                mtp_device.UploadTrack (fromUri.LocalPath, mtp_track, GetFolderForTrack (track), OnUploadProgress);

                // Add/update album art
                if (!video) {
                    string key = MakeAlbumKey (track.AlbumArtist, track.AlbumTitle);
                    if (!album_cache.ContainsKey (key)) {
                        // LIBMTP 1.0.3 BUG WORKAROUND
                        // In libmtp.c the 'LIBMTP_Create_New_Album' function invokes 'create_new_abstract_list'.
                        // The latter calls strlen on the 'name' parameter without null checking. If AlbumTitle is
                        // null, this causes a sigsegv. Lets be safe and always pass non-null values.
                        Album album = new Album (mtp_device, track.AlbumTitle ?? "", track.AlbumArtist ?? "", track.Genre ?? "", track.Composer ?? "");
                        album.AddTrack (mtp_track);

                        if (supports_jpegs && can_sync_albumart) {
                            try {
                                Gdk.Pixbuf pic = ServiceManager.Get<Banshee.Collection.Gui.ArtworkManager> ().LookupScalePixbuf (
                                    track.ArtworkId, thumb_width
                                );
                                if (pic != null) {
                                    byte [] bytes = pic.SaveToBuffer ("jpeg");
                                    album.Save (bytes, (uint)pic.Width, (uint)pic.Height);
                                    Banshee.Collection.Gui.ArtworkManager.DisposePixbuf (pic);
                                }
                                album_cache[key] = album;
                            } catch (Exception e) {
                                Log.Debug ("Failed to create MTP Album", e.Message);
                            }
                        } else {
                            album.Save ();
                            album_cache[key] = album;
                        }
                    } else {
                        Album album = album_cache[key];
                        album.AddTrack (mtp_track);
                        album.Save ();
                    }
                }

                MtpTrackInfo new_track = new MtpTrackInfo (mtp_device, mtp_track);
                new_track.PrimarySource = this;
                new_track.Save (false);
                track_map[new_track.TrackId] = mtp_track;
            }
        }
Exemplo n.º 31
0
        private bool FindOutdatedDupe (DatabaseTrackInfo track)
        {
            if (DatabaseTrackInfo.MetadataHashCount (track.MetadataHash, PrimarySourceIds) != 1) {
                return false;
            }

            var track_to_update = DatabaseTrackInfo.GetTrackForMetadataHash (track.MetadataHash, PrimarySourceIds);

            if (track_to_update == null || Banshee.IO.File.Exists (track_to_update.Uri)) {
                return false;
            }

            track_to_update.Uri = track.Uri;
            track_to_update.Save ();
            return true;
        }
 public void Add(DatabaseTrackInfo track)
 {
     AddTrack(track);
 }
Exemplo n.º 33
0
 public bool Contains(DatabaseTrackInfo track)
 {
     return track != null && connection.Query<bool> (
         String.Format ("SELECT COUNT(*) > 0 {0} AND CoreTracks.TrackID = ? LIMIT 1", UnfilteredQuery),
         track.TrackId
     );
 }