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/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; }
@@ -344,7 +355,7 @@
         }
         
         public override string ToString () {
-            return String.Format ("({0}) {1} - {2} - {3} ({4})", Id, Artist, Album, Title, FileName);
+            return String.Format ("({0}/{5}) {1} - {2} - {3} ({4})", Id, Artist, Album, Title, FileName, CoverPhotoId);
         }
 
         public override bool Equals (object a) {
@@ -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,46 @@
 
             try
             {
+                if (device.SupportsSparseArtwork)
+                {
+                    var artworkLookup = new Dictionary<string, Track> ();
+
+                    foreach (Track track in tracks)
+                    {
+                        Track matchingTrack = null;
+                        string key = track.AlbumArtist + "|" + track.Album;
+                        
+                        track.Record.RightSideArtworkId = track.CoverPhotoId;
+                        
+                        if (artworkLookup.TryGetValue(key, out matchingTrack))
+                        {
+                            // they are already the same
+                            if (track.Record.RightSideArtworkId == matchingTrack.Record.RightSideArtworkId)
+                                continue;
+                            
+                            track.ShareCoverArt(matchingTrack);
+                        } else {
+                            artworkLookup.Add(key, track);
+                        }
+                    }
+                }
+                
+                // Prune unused covers
+                var usedArtwork = new HashSet<int> ();
+
+                foreach (Track track in tracks)
+                {
+                    int coverId = track.CoverPhotoId;
+                    if (coverId != 0)
+                        usedArtwork.Add(coverId);
+                }
+                
+                foreach (Photo photo in artdb.Photos)
+                {
+                    if (!usedArtwork.Contains(photo.Id))
+                        artdb.RemovePhoto(photo);
+                }
+                
                 // Save the tracks db
                 using (BinaryWriter writer = new EndianBinaryWriter(new FileStream(TrackDbPath, FileMode.Create),
                                                                     dbrec.IsBE))
@@ -2911,16 +2954,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");
                 }
