Index: src/Device.cs
===================================================================
--- src/Device.cs	(revision 149271)
+++ src/Device.cs	(working copy)
@@ -78,6 +78,11 @@
             }
         }
         
+        public bool SupportsSparseArtwork
+        {
+            get { return ModelInfo.SparseAlbumArtSupported; }
+        }
+        
         public SportKitManager SportKitManager {
             get {
                 if (sport_kit_manager == null) {
Index: src/Utility.cs
===================================================================
--- src/Utility.cs	(revision 149271)
+++ src/Utility.cs	(working copy)
@@ -85,5 +85,31 @@
                 return val;
             }
         }
+        
+        public static bool Equals (byte[] a, byte[] b) {
+            if (a == null || b == null || a.Length != b.Length)
+                return false;
+            
+            for (int i = 0; i < a.Length; i++) {
+                if (!a[i].Equals (b[i]))
+                    return false;
+            }
+            
+            return true;
+        }
+        
+        public static int Sum (byte[] a) {
+            if (a == null)
+                return 0;
+                
+            int sum = 0;
+            foreach (byte b in a) {
+                unchecked {
+                    sum += b;
+                }
+            }
+            
+            return sum;
+        }
     }
 }
Index: src/Track.cs
===================================================================
--- src/Track.cs	(revision 149271)
+++ src/Track.cs	(working copy)
@@ -333,6 +333,17 @@
         public bool IsProtected {
             get { return record.UserId != 0; }
         }
+        
+        public int CoverPhotoId {
+            get {
+                FindCoverPhoto ();
+                
+                if (coverPhoto != null)
+                    return coverPhoto.Id;
+                else
+                    return 0;
+            }
+        }
 
         public TrackDatabase TrackDatabase {
             get { return db; }
@@ -362,7 +373,11 @@
 
         private void FindCoverPhoto () {
             if (coverPhoto == null && db.ArtworkDatabase != null) {
-                coverPhoto = db.ArtworkDatabase.LookupPhotoByTrackId (record.DatabaseId);
+                if (db.Device.SupportsSparseArtwork && record.RightSideArtworkId != 0)
+                    coverPhoto = db.ArtworkDatabase.LookupPhotoById (record.RightSideArtworkId);
+                
+                if (coverPhoto == null)
+                    coverPhoto = db.ArtworkDatabase.LookupPhotoByTrackId (record.DatabaseId);
             }
         }
 
@@ -409,18 +424,32 @@
         }
 
         public void SetCoverArt (ArtworkFormat format, byte[] data) {
+            // Prevent changing the art of other tracks if this art is shared
+            // (Assumes all formats are always changed together rather than individually)
+            if (!coverPhoto.Dirty)
+                RemoveCoverArt ();
+            
             Thumbnail thumbnail = GetThumbnail (format, true);
             thumbnail.SetData (data);
 
             record.HasArtwork = true;
             record.ArtworkCount = 1; // this is actually for artwork in mp3 tags, but it seems to be needed anyway
         }
-
+        
+        public void ShareCoverArt (Track track) {
+            RemoveCoverArt ();
+            record.RightSideArtworkId = track.Record.RightSideArtworkId;
+        }
+        
         public void RemoveCoverArt () {
             FindCoverPhoto ();
 
             if (coverPhoto != null && db.ArtworkDatabase != null) {
-                db.ArtworkDatabase.RemovePhoto (coverPhoto);
+                coverPhoto.Record.TrackId = 0;
+                if (!db.Device.SupportsSparseArtwork)
+                    db.ArtworkDatabase.RemovePhoto (coverPhoto);
+                record.RightSideArtworkId = 0;
+                coverPhoto = null;
             }
         }
         
Index: src/ModelInfo.cs
===================================================================
--- src/ModelInfo.cs	(revision 149271)
+++ src/ModelInfo.cs	(working copy)
@@ -8,6 +8,7 @@
     {
         private bool is_unknown;
         private bool album_art_supported;
+        private bool sparse_album_art_supported;
         private bool photos_supported;
         private string device_class;
         private string shell_color;
@@ -36,6 +37,11 @@
             protected set { album_art_supported = value; }
         }
         
+        public bool SparseAlbumArtSupported {
+            get { return sparse_album_art_supported; }
+            protected set { sparse_album_art_supported = value; }
+        }
+        
         public bool PhotosSupported {
             get { return photos_supported; }
             protected set { photos_supported = value; }
@@ -80,6 +86,7 @@
             Console.WriteLine ("  Advertised Capacity: {0}", AdvertisedCapacity);
             Console.WriteLine ("  Photos Supported: {0}", PhotosSupported);
             Console.WriteLine ("  Album Art Supported: {0}", AlbumArtSupported);
+            Console.WriteLine ("  Sparse Album Art Supported: {0}", SparseAlbumArtSupported);
             
             Console.Write ("  Extra Capabilities: ");
             
Index: src/TrackDatabase.cs
===================================================================
--- src/TrackDatabase.cs	(revision 149271)
+++ src/TrackDatabase.cs	(working copy)
@@ -1320,6 +1320,9 @@
                 GaplessAlbumFlag = ToInt16 (body, 246) == 1;
             }
                 
+            if (db.Version >= 25 && body.Length >= 344) {
+                RightSideArtworkId = ToInt32(body, 340);
+            }
 
             details.Clear();
 
@@ -2719,6 +2722,77 @@
 
             try
             {
+                // Optimize for sparse artwork if supported (use smallest thumbnail for speed)
+                var formats = new List<ArtworkFormat> (device.ArtworkFormats);
+                formats = formats.FindAll(delegate(ArtworkFormat a) { return a.Usage == ArtworkUsage.Cover; });
+                formats.Sort(delegate(ArtworkFormat a, ArtworkFormat b) { return (a.Width * a.Height).CompareTo(b.Width * b.Height); });
+                
+                if (device.SupportsSparseArtwork && formats.Count > 0)
+                {
+                    ArtworkFormat comparisonFormat = formats[0];
+                    
+                    var artworkLookup = new Dictionary<int, List<Track>> ();
+
+                    foreach (Track track in tracks)
+                    {
+                        byte[] coverArt = track.GetCoverArt(comparisonFormat);
+                        
+                        if (comparisonFormat == null || coverArt == null)
+                            continue;
+                        
+                        int hash = Utility.Sum(coverArt);
+                        bool matchFound = false;
+                        List<Track> possibleMatches = null;
+                        
+                        track.Record.RightSideArtworkId = track.CoverPhotoId;
+                        
+                        if (artworkLookup.TryGetValue(hash, out possibleMatches))
+                        {
+                            foreach (Track matchingTrack in possibleMatches)
+                            {
+                                // they are already the same
+                                if (track.Record.RightSideArtworkId == matchingTrack.Record.RightSideArtworkId)
+                                {
+                                    matchFound = true;
+                                    break;
+                                }
+                                
+                                // check to see if thumb and album name are the same
+                                if (track.Album.Equals(matchingTrack.Album) &&
+                                    Utility.Equals(coverArt, matchingTrack.GetCoverArt(comparisonFormat)))
+                                {
+                                    track.ShareCoverArt(matchingTrack);
+                                    
+                                    matchFound = true;
+                                    break;
+                                }
+                            }
+                        } else {
+                            possibleMatches = new List<Track> ();
+                            artworkLookup.Add(hash, possibleMatches);
+                        }
+                        
+                        if (!matchFound)
+                            possibleMatches.Add(track);
+                    }
+                }
+                
+                // Prune unused covers
+                var usedArtwork = new Dictionary<int, bool> ();
+
+                foreach (Track track in tracks)
+                {
+                    int coverId = track.CoverPhotoId;
+                    if (coverId != 0)
+                        usedArtwork[coverId] = true;
+                }
+                
+                foreach (Photo photo in artdb.Photos)
+                {
+                    if (!usedArtwork.ContainsKey(photo.Id))
+                        artdb.RemovePhoto(photo);
+                }
+                
                 // Save the tracks db
                 using (BinaryWriter writer = new EndianBinaryWriter(new FileStream(TrackDbPath, FileMode.Create),
                                                                     dbrec.IsBE))
@@ -2911,16 +2985,6 @@
                 dbrec[DataSetIndex.Library].TrackList.Remove(track.Record.Id);
                 dbrec[DataSetIndex.Playlist].Library.RemoveTrack(track.Record.Id);
 
-                // remove from cover art db
-                if (artdb != null)
-                {
-                    Photo artPhoto = artdb.LookupPhotoByTrackId(track.Record.DatabaseId);
-                    if (artPhoto != null)
-                    {
-                        artdb.RemovePhoto(artPhoto);
-                    }
-                }
-
                 // remove from the "normal" playlists
                 foreach (Playlist list in playlists)
                 {
Index: src/Hal/HalDevice.cs
===================================================================
--- src/Hal/HalDevice.cs	(revision 149271)
+++ src/Hal/HalDevice.cs	(working copy)
@@ -68,6 +68,10 @@
                     AlbumArtSupported = volume.GetPropertyBoolean (PodsleuthPrefix + "images.album_art_supported");
                 }
                 
+                if (volume.PropertyExists (PodsleuthPrefix + "images.sparse_album_art_supported")) {
+                    SparseAlbumArtSupported = volume.GetPropertyBoolean (PodsleuthPrefix + "images.sparse_album_art_supported");
+                }
+                
                 if (volume.PropertyExists (PodsleuthPrefix + "images.photos_supported")) {
                     PhotosSupported = volume.GetPropertyBoolean (PodsleuthPrefix + "images.photos_supported");
                 }
