*чтение: пустые или испорченные («�») название, альбом и автор в ID3v2 берутся из ID3v1 (старые файлы хранят там cp1251)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a3e244205a
commit
a76bbe18f1
2 files changed
+46
No files matched your search
@@ -348,11 +348,30 @@ fn read_book_tags_impl(path string) !FileTags {
|
|||||||
if t.series == '' {
|
if t.series == '' {
|
||||||
t.series = tit1
|
t.series = tit1
|
||||||
}
|
}
|
||||||
|
// Пустые или испорченные («�») поля — из ID3v1: старые файлы часто хранят там исходный текст в cp1251,
|
||||||
|
// а в ID3v2 он мог попасть уже испорченным (прочитан не в той кодировке и записан обратно)
|
||||||
|
if needs_v1(t.title) || needs_v1(t.album) || needs_v1(t.author) {
|
||||||
|
if v1 := read_v1(path) {
|
||||||
|
if needs_v1(t.title) && !needs_v1(v1.title) {
|
||||||
|
t.title = v1.title
|
||||||
|
}
|
||||||
|
if needs_v1(t.album) && !needs_v1(v1.album) {
|
||||||
|
t.album = v1.album
|
||||||
|
}
|
||||||
|
if needs_v1(t.author) && !needs_v1(v1.author) {
|
||||||
|
t.author = v1.author
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// TPE1 мог быть не задан, тогда автор остаётся из TPE2
|
// TPE1 мог быть не задан, тогда автор остаётся из TPE2
|
||||||
res.tags = t
|
res.tags = t
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn needs_v1(s string) bool {
|
||||||
|
return s.trim_space() == '' || s.contains('\uFFFD')
|
||||||
|
}
|
||||||
|
|
||||||
// "(101)" и "(101)Speech" из старых тэгов превращаем в название
|
// "(101)" и "(101)Speech" из старых тэгов превращаем в название
|
||||||
fn clean_genre(g string) string {
|
fn clean_genre(g string) string {
|
||||||
if g.starts_with('(') && g.contains(')') {
|
if g.starts_with('(') && g.contains(')') {
|
||||||
|
|||||||
@@ -200,3 +200,30 @@ fn test_rewrite_header_only() {
|
|||||||
end := os.read_bytes(path) or { panic(err) }
|
end := os.read_bytes(path) or { panic(err) }
|
||||||
assert end[end.len - tail..] == audio
|
assert end[end.len - tail..] == audio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Испорченное название в ID3v2 («�») — берётся исходное из ID3v1 (cp1251)
|
||||||
|
fn test_broken_v2_title_falls_back_to_v1() {
|
||||||
|
path := tmp_copy('test_id3v23.mp3')
|
||||||
|
defer {
|
||||||
|
os.rm(path) or {}
|
||||||
|
}
|
||||||
|
metadata.write_book_tags(path, metadata.BookTags{
|
||||||
|
title: '\uFFFD\uFFFD\uFFFD 1'
|
||||||
|
album: 'Книга'
|
||||||
|
}) or { panic(err) }
|
||||||
|
// ID3v1 в конце файла: «Глава 1» в cp1251
|
||||||
|
mut v1 := []u8{len: 128}
|
||||||
|
v1[0] = `T`
|
||||||
|
v1[1] = `A`
|
||||||
|
v1[2] = `G`
|
||||||
|
title := [u8(0xc3), 0xeb, 0xe0, 0xe2, 0xe0, 0x20, 0x31]
|
||||||
|
for i, c in title {
|
||||||
|
v1[3 + i] = c
|
||||||
|
}
|
||||||
|
mut f := os.open_append(path) or { panic(err) }
|
||||||
|
f.write(v1) or { panic(err) }
|
||||||
|
f.close()
|
||||||
|
t := metadata.read_book_tags(path) or { panic(err) }
|
||||||
|
assert t.tags.title == 'Глава 1'
|
||||||
|
assert t.tags.album == 'Книга'
|
||||||
|
}
|
||||||
Reference in new issue
Block a user