1
1
use anyhow:: Result ;
2
- use audiotags :: { MimeType , Tag } ;
2
+ use lofty :: { Accessor , AudioFile , PictureType , Tag , TaggedFile , TaggedFileExt , MimeType , TagExt , ItemKey , ItemValue , TagItem } ;
3
3
4
4
#[ derive( Debug ) ]
5
5
pub struct Picture {
@@ -27,24 +27,32 @@ pub struct Metadata {
27
27
}
28
28
29
29
pub fn read_metadata ( file : String ) -> Result < Metadata > {
30
- let tag = Tag :: default ( ) . read_from_path ( & file) ?;
31
- let cover = tag. album_cover ( ) ;
30
+ let ( tagged_file, tag) = get_tag_for_file ( & file) ?;
31
+ let cover = tag
32
+ . get_picture_type ( PictureType :: CoverFront )
33
+ . or ( tag. pictures ( ) . first ( ) ) ;
32
34
Ok ( Metadata {
33
35
title : tag. title ( ) . and_then ( |s| Some ( s. to_string ( ) ) ) ,
34
- duration_ms : tag. duration ( ) ,
35
- album : tag. album_title ( ) . and_then ( |s| Some ( s. to_string ( ) ) ) ,
36
- album_artist : tag. album_artist ( ) . and_then ( |s| Some ( s. to_string ( ) ) ) ,
36
+ duration_ms : Some ( tagged_file. properties ( ) . duration ( ) . as_millis ( ) as f64 ) ,
37
+ album : tag. album ( ) . and_then ( |s| Some ( s. to_string ( ) ) ) ,
38
+ album_artist : tag. get ( & ItemKey :: AlbumArtist ) . and_then ( |s| {
39
+ match s. value ( ) {
40
+ ItemValue :: Text ( t) => Some ( t. to_string ( ) ) ,
41
+ _ => None
42
+ }
43
+ }
44
+ ) ,
37
45
artist : tag. artist ( ) . and_then ( |s| Some ( s. to_string ( ) ) ) ,
38
- track_number : tag. track_number ( ) ,
39
- track_total : tag. total_tracks ( ) ,
40
- disc_number : tag. disc_number ( ) ,
41
- disc_total : tag. total_discs ( ) ,
42
- year : tag. year ( ) ,
46
+ track_number : tag. track ( ) . map ( |f| f as u16 ) ,
47
+ track_total : tag. track_total ( ) . map ( |f| f as u16 ) ,
48
+ disc_number : tag. disk ( ) . map ( |f| f as u16 ) ,
49
+ disc_total : tag. disk_total ( ) . map ( |f| f as u16 ) ,
50
+ year : tag. year ( ) . map ( |f| f as i32 ) ,
43
51
genre : tag. genre ( ) . and_then ( |s| Some ( s. to_string ( ) ) ) ,
44
52
picture : ( match cover {
45
53
Some ( cover) => Some ( Picture {
46
- mime_type : String :: from ( cover. mime_type ) ,
47
- data : cover. data . to_vec ( ) ,
54
+ mime_type : cover. mime_type ( ) . to_string ( ) ,
55
+ data : cover. data ( ) . to_vec ( ) ,
48
56
} ) ,
49
57
None => None ,
50
58
} ) ,
@@ -53,46 +61,70 @@ pub fn read_metadata(file: String) -> Result<Metadata> {
53
61
}
54
62
55
63
pub fn write_metadata ( file : String , metadata : Metadata ) -> Result < ( ) > {
56
- let mut tag = Tag :: default ( ) . read_from_path ( & file) ?;
64
+ let ( _tagged_file , mut tag) = get_tag_for_file ( & file) ?;
57
65
58
66
if metadata. title . is_some ( ) {
59
- tag. set_title ( metadata. title . unwrap ( ) . as_str ( ) ) ;
67
+ tag. set_title ( metadata. title . unwrap ( ) ) ;
60
68
}
61
69
if metadata. album . is_some ( ) {
62
- tag. set_album_title ( metadata. album . unwrap ( ) . as_str ( ) ) ;
70
+ tag. set_album ( metadata. album . unwrap ( ) ) ;
63
71
}
64
72
if metadata. album_artist . is_some ( ) {
65
- tag. set_album_artist ( metadata. album_artist . unwrap ( ) . as_str ( ) ) ;
73
+ tag. insert ( TagItem :: new ( ItemKey :: AlbumArtist , ItemValue :: Text ( metadata. album_artist . unwrap ( ) ) ) ) ;
66
74
}
67
75
if metadata. artist . is_some ( ) {
68
- tag. set_artist ( metadata. artist . unwrap ( ) . as_str ( ) ) ;
76
+ tag. set_artist ( metadata. artist . unwrap ( ) ) ;
69
77
}
70
78
if metadata. track_number . is_some ( ) {
71
- tag. set_track_number ( metadata. track_number . unwrap ( ) ) ;
79
+ tag. set_track ( metadata. track_number . unwrap ( ) as u32 ) ;
72
80
}
73
81
if metadata. track_total . is_some ( ) {
74
- tag. set_total_tracks ( metadata. track_total . unwrap ( ) ) ;
82
+ tag. set_track_total ( metadata. track_total . unwrap ( ) as u32 ) ;
75
83
}
76
84
if metadata. disc_number . is_some ( ) {
77
- tag. set_disc_number ( metadata. disc_number . unwrap ( ) ) ;
85
+ tag. set_disk ( metadata. disc_number . unwrap ( ) as u32 ) ;
78
86
}
79
87
if metadata. disc_total . is_some ( ) {
80
- tag. set_total_discs ( metadata. disc_total . unwrap ( ) ) ;
88
+ tag. set_disk_total ( metadata. disc_total . unwrap ( ) as u32 ) ;
81
89
}
82
90
if metadata. year . is_some ( ) {
83
- tag. set_year ( metadata. year . unwrap ( ) ) ;
91
+ tag. set_year ( metadata. year . unwrap ( ) as u32 ) ;
84
92
}
85
93
if metadata. genre . is_some ( ) {
86
- tag. set_genre ( metadata. genre . unwrap ( ) . as_str ( ) ) ;
94
+ tag. set_genre ( metadata. genre . unwrap ( ) ) ;
87
95
}
88
96
if metadata. picture . is_some ( ) {
89
97
let image = metadata. picture . unwrap ( ) ;
90
- tag. set_album_cover ( audiotags:: Picture {
91
- mime_type : MimeType :: try_from ( image. mime_type . as_str ( ) ) . unwrap ( ) ,
92
- data : & image. data ,
93
- } ) ;
98
+ tag. push_picture ( lofty:: Picture :: new_unchecked (
99
+ PictureType :: CoverFront ,
100
+ MimeType :: from_str ( & image. mime_type ) ,
101
+ None ,
102
+ image. data ,
103
+ ) ) ;
94
104
}
95
105
96
- tag. write_to_path ( & file) ?;
106
+ tag. save_to_path ( & file) ?;
97
107
Ok ( ( ) )
98
108
}
109
+
110
+ fn get_tag_for_file ( file : & str ) -> Result < ( TaggedFile , Tag ) > {
111
+ let mut tagged_file = lofty:: read_from_path ( file) ?;
112
+
113
+ let tag = match tagged_file. primary_tag_mut ( ) {
114
+ Some ( primary_tag) => primary_tag,
115
+ None => {
116
+ if let Some ( first_tag) = tagged_file. first_tag_mut ( ) {
117
+ first_tag
118
+ } else {
119
+ let tag_type = tagged_file. primary_tag_type ( ) ;
120
+
121
+ eprintln ! ( "WARN: No tags found, creating a new tag of type `{tag_type:?}`" ) ;
122
+ tagged_file. insert_tag ( Tag :: new ( tag_type) ) ;
123
+
124
+ tagged_file. primary_tag_mut ( ) . unwrap ( )
125
+ }
126
+ }
127
+ }
128
+ . to_owned ( ) ;
129
+ Ok ( ( tagged_file, tag) )
130
+ }
0 commit comments