@@ -19,6 +19,7 @@ use crate::util;
1919use crate :: Config ;
2020use crate :: TaggedFile ;
2121use itertools:: Itertools ;
22+ use regex:: { Regex , RegexBuilder } ;
2223use std:: borrow:: Cow ;
2324use std:: collections:: HashMap ;
2425
@@ -117,6 +118,23 @@ fn find_most_common_tag_value<'a>(
117118 MostCommonItem :: find ( tracks. filter_map ( |tagged_file| tagged_file. first_tag_value ( key) ) )
118119}
119120
121+ /// Strip disc suffix from the end of the `Cow` string.
122+ fn strip_disc_suffix < ' a > ( title : Cow < ' a , str > , pattern : & Regex ) -> Cow < ' a , str > {
123+ match pattern. find ( & title) {
124+ Some ( m) => {
125+ let start = m. start ( ) ;
126+ match title {
127+ Cow :: Borrowed ( s) => Cow :: Borrowed ( & s[ ..start] ) ,
128+ Cow :: Owned ( mut s) => {
129+ s. truncate ( start) ;
130+ Cow :: Owned ( s)
131+ }
132+ }
133+ }
134+ None => title,
135+ }
136+ }
137+
120138/// A collection of tracks on the local disk.
121139#[ derive( Debug ) ]
122140pub struct TaggedFileCollection {
@@ -319,7 +337,19 @@ impl FromIterator<TaggedFile> for TaggedFileCollection {
319337
320338impl ReleaseLike for TaggedFileCollection {
321339 fn release_title ( & self ) -> Option < Cow < ' _ , str > > {
322- self . find_consensual_tag_value ( & TagKey :: Album )
340+ let disc_pattern = RegexBuilder :: new ( r"\s*[(\[-]\s*(?:CD|Disc)\s*\d+\s*[)\]]?\s*$" )
341+ . case_insensitive ( true )
342+ . build ( )
343+ . unwrap ( ) ;
344+
345+ MostCommonItem :: find (
346+ self . media
347+ . iter ( )
348+ . flat_map ( |media| media. tracks . iter ( ) )
349+ . filter_map ( |tagged_file| tagged_file. first_tag_value ( & TagKey :: Album ) )
350+ . map ( |title| strip_disc_suffix ( title, & disc_pattern) ) ,
351+ )
352+ . and_then ( MostCommonItem :: into_concensus)
323353 }
324354
325355 fn release_artist ( & self ) -> Option < Cow < ' _ , str > > {
0 commit comments