*исправления по считыванию данных без BOM
*добавлены работающие тесты
This commit is contained in:
1 parent
d03f6214aa
commit
aa04fd4df0
11 files changed
+175
-39
No files matched your search
@@ -1,13 +1,14 @@
|
|||||||
module main
|
module main
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import io
|
// import io
|
||||||
import metadata
|
import metadata
|
||||||
|
|
||||||
fn id3(){
|
fn id3(){
|
||||||
// mut audio := os.open("./data/АЛИСА 11000.mp3") or { panic(err) }
|
// mut audio := os.open("./data/АЛИСА 11000.mp3") or { panic(err) }
|
||||||
// mut audio := os.open("./data/Глава 2. 16 и 17 июля.mp3") or { panic(err) }
|
// mut audio := os.open("./data/Глава 2. 16 и 17 июля.mp3") or { panic(err) }
|
||||||
mut audio := os.open("./out.mp3") or { panic(err) }
|
// mut audio := os.open("./out.mp3") or { panic(err) }
|
||||||
|
mut audio := os.open("./data/test_id3v23.mp3") or { panic(err) }
|
||||||
// mut audio := os.open("./data/01_01.mp3") or { panic(err) }
|
// mut audio := os.open("./data/01_01.mp3") or { panic(err) }
|
||||||
// mut audio := os.open("./test.mp3") or { panic(err) }
|
// mut audio := os.open("./test.mp3") or { panic(err) }
|
||||||
|
|
||||||
@@ -26,9 +27,18 @@ fn id3(){
|
|||||||
last_bytes := metadata.get_bytes(mut audio, -128, 128)
|
last_bytes := metadata.get_bytes(mut audio, -128, 128)
|
||||||
wav.id3v1.get_metadata(last_bytes)
|
wav.id3v1.get_metadata(last_bytes)
|
||||||
|
|
||||||
|
// wav.id3v1.genre = "Rock"
|
||||||
|
// wav.id3v1.title = "Test title"
|
||||||
|
// wav.id3v1.artist = "Test artist"
|
||||||
|
// wav.id3v1.album = "Test albulm"
|
||||||
|
// wav.id3v1.comment = "2/5"
|
||||||
|
// wav.id3v1.track = "2/5"
|
||||||
|
|
||||||
println(wav.id3v1)
|
println(wav.id3v1)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if wav.id3v23.embedded {
|
if wav.id3v23.embedded {
|
||||||
wav.id3v23.get_full_size(mut audio)
|
wav.id3v23.get_full_size(mut audio)
|
||||||
wav.id3v23.fill_tags(mut audio)
|
wav.id3v23.fill_tags(mut audio)
|
||||||
@@ -36,7 +46,7 @@ fn id3(){
|
|||||||
wav.id3v23.tit2.encode_size(3)
|
wav.id3v23.tit2.encode_size(3)
|
||||||
tit2 := wav.id3v23.tit2.get_encoded_frame_tag(3)
|
tit2 := wav.id3v23.tit2.get_encoded_frame_tag(3)
|
||||||
println(tit2)
|
println(tit2)
|
||||||
// println(wav.id3v23.tit2)
|
println(wav.id3v23)
|
||||||
}
|
}
|
||||||
|
|
||||||
if wav.id3v24.embedded {
|
if wav.id3v24.embedded {
|
||||||
@@ -52,28 +62,28 @@ fn id3(){
|
|||||||
// println(wav.id3v24.tdrc.data)
|
// println(wav.id3v24.tdrc.data)
|
||||||
// wav.id3v24.tdrc.set_data("2017")
|
// wav.id3v24.tdrc.set_data("2017")
|
||||||
|
|
||||||
// enc_size := metadata.encode_header_size(wav.id3v24.size, wav.id3v24.version)
|
// // enc_size := metadata.encode_header_size(wav.id3v24.size, wav.id3v24.version)
|
||||||
// println(enc_size)
|
// // println(enc_size)
|
||||||
wav.id3v24.tit2.set_data("2017")
|
// wav.id3v24.tit2.set_data("2017")
|
||||||
wav.id3v24.tpe1.init("tpe1")
|
// wav.id3v24.tpe1.init("tpe1")
|
||||||
wav.id3v24.tpe1.set_data("Hello")
|
// wav.id3v24.tpe1.set_data("Hello")
|
||||||
wav.id3v24.tpe2.init("tpe2")
|
// wav.id3v24.tpe2.init("tpe2")
|
||||||
wav.id3v24.tpe2.set_data("Hello2")
|
// wav.id3v24.tpe2.set_data("Hello2")
|
||||||
// metadata.encode_header(mut wav.id3v24)
|
// // metadata.encode_header(mut wav.id3v24)
|
||||||
// println(wav.id3v24.encoded_header)
|
// // println(wav.id3v24.encoded_header)
|
||||||
// println(wav.id3v24.tpe1.name)
|
// // println(wav.id3v24.tpe1.name)
|
||||||
|
|
||||||
wav.id3v24.encode_embed_tags()
|
// wav.id3v24.encode_embed_tags()
|
||||||
println(wav.id3v24.encoded_header.len)
|
// println(wav.id3v24.encoded_header.len)
|
||||||
|
|
||||||
wav.id3v24.insert_tags_into_audio(mut audio)
|
// wav.id3v24.insert_tags_into_audio(mut audio)
|
||||||
|
|
||||||
// println(wav.id3v24)
|
// // println(wav.id3v24)
|
||||||
|
|
||||||
mut f := os.create("./temp.mp3") or { panic(err) }
|
// mut f := os.create("./temp.mp3") or { panic(err) }
|
||||||
|
|
||||||
f.write(wav.id3v24.encoded_header) or { panic(err) }
|
// f.write(wav.id3v24.encoded_header) or { panic(err) }
|
||||||
f.close()
|
// f.close()
|
||||||
|
|
||||||
// println(wav.id3v24)
|
// println(wav.id3v24)
|
||||||
// mut audio_2 := os.open("./out.mp3") or { panic(err) }
|
// mut audio_2 := os.open("./out.mp3") or { panic(err) }
|
||||||
@@ -109,7 +119,7 @@ fn id3(){
|
|||||||
|
|
||||||
// all_bytes := wav.id3v1.insert(mut audio, -128)
|
// all_bytes := wav.id3v1.insert(mut audio, -128)
|
||||||
|
|
||||||
// os.write_bytes("./test.mp3", all_bytes) or { panic(err) }
|
// os.write_bytes("./test.mp3", new_bytes) or { panic(err) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@ pub enum EnumID3v24 as u8 {
|
|||||||
tcon
|
tcon
|
||||||
tcop
|
tcop
|
||||||
apic
|
apic
|
||||||
comment
|
txxx
|
||||||
unknown
|
unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +24,6 @@ pub enum EnumID3v23 as u8 {
|
|||||||
tcon
|
tcon
|
||||||
tcop
|
tcop
|
||||||
apic
|
apic
|
||||||
comment
|
txxx
|
||||||
unknown
|
unknown
|
||||||
}
|
}
|
||||||
+12
-3
@@ -54,10 +54,19 @@ fn (mut frame Frame) fill(bytes []u8, start_position u64, idv3_version u8) {
|
|||||||
// Фрейм целиком вместе с заголовком, чтобы записать его обратно без изменений
|
// Фрейм целиком вместе с заголовком, чтобы записать его обратно без изменений
|
||||||
frame.apic = bytes[frame.start..frame.end]
|
frame.apic = bytes[frame.start..frame.end]
|
||||||
} else {
|
} else {
|
||||||
// Выбор шага в записимости от версии ID3
|
// Данные начинаются после 10 байт заголовка и байта кодировки
|
||||||
stride := if idv3_version == 3 { 13 } else { 11 }
|
mut data_start := frame.start + 11
|
||||||
|
|
||||||
|
// UTF-16 с BOM (01): 2 байта маркера, по ним определяется порядок байт
|
||||||
|
if frame.encoding_name_idx == 1 && data_start + 2 <= frame.end {
|
||||||
|
if bytes[data_start] == 0xFE && bytes[data_start + 1] == 0xFF {
|
||||||
|
frame.encoding_name = "UTF-16BE"
|
||||||
|
}
|
||||||
|
data_start += 2
|
||||||
|
}
|
||||||
|
|
||||||
// Замыкающие нули не относятся к данным
|
// Замыкающие нули не относятся к данным
|
||||||
frame.data = (iconv.encoding_to_vstring(bytes[frame.start+u64(stride)..frame.end], frame.encoding_name) or { "" }).trim_right('\x00')
|
frame.data = (iconv.encoding_to_vstring(bytes[data_start..frame.end], frame.encoding_name) or { "" }).trim_right('\x00')
|
||||||
|
|
||||||
frame.addition = bytes[frame.start..frame.start + 10]
|
frame.addition = bytes[frame.start..frame.start + 10]
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -48,7 +48,7 @@ pub fn (id3v1 ID3v1) to_v23() ID3v23 {
|
|||||||
tyer: metadata.Frame{
|
tyer: metadata.Frame{
|
||||||
data: id3v1.year
|
data: id3v1.year
|
||||||
}
|
}
|
||||||
comment: metadata.Frame{
|
txxx: metadata.Frame{
|
||||||
data: id3v1.comment
|
data: id3v1.comment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ pub fn (id3v1 ID3v1) to_v23() ID3v23 {
|
|||||||
fn cut_or_trim(data string, capacity i8) []u8 {
|
fn cut_or_trim(data string, capacity i8) []u8 {
|
||||||
mut final_data := []u8{len: capacity, init: 0}
|
mut final_data := []u8{len: capacity, init: 0}
|
||||||
|
|
||||||
|
if data.len > 0 {
|
||||||
bytes_data := iconv.vstring_to_encoding(data, "CP1251") or { []u8{len: capacity} }
|
bytes_data := iconv.vstring_to_encoding(data, "CP1251") or { []u8{len: capacity} }
|
||||||
|
|
||||||
diff := capacity - bytes_data.len
|
diff := capacity - bytes_data.len
|
||||||
@@ -70,12 +70,13 @@ fn cut_or_trim(data string, capacity i8) []u8 {
|
|||||||
} else {
|
} else {
|
||||||
final_data = bytes_data.clone()[..capacity]
|
final_data = bytes_data.clone()[..capacity]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return final_data
|
return final_data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Перевести тэг в байты
|
// Перевести тэг в байты
|
||||||
pub fn (id3v1 ID3v1) to_bytes() []u8 {
|
pub fn (mut id3v1 ID3v1) to_bytes() []u8 {
|
||||||
mut bytes := []u8{cap: 128}
|
mut bytes := []u8{cap: 128}
|
||||||
|
|
||||||
bytes << "TAG".bytes()
|
bytes << "TAG".bytes()
|
||||||
@@ -88,14 +89,17 @@ pub fn (id3v1 ID3v1) to_bytes() []u8 {
|
|||||||
// bytes << cut_or_trim(id3v1.track, i8(2))
|
// bytes << cut_or_trim(id3v1.track, i8(2))
|
||||||
bytes << if id3v1.track.len != 0 { [u8(0), id3v1.track.u8()]} else { [u8(1), u8(0)] }
|
bytes << if id3v1.track.len != 0 { [u8(0), id3v1.track.u8()]} else { [u8(1), u8(0)] }
|
||||||
|
|
||||||
id_genre := Genre.from(id3v1.genre) or { Genre.unknown }
|
id_genre := Genre.from(id3v1.genre.to_lower()) or { Genre.unknown }
|
||||||
bytes << u8(id_genre) // cut_or_trim([u8(id_genre)], i8(2))
|
bytes << u8(id_genre) // cut_or_trim([u8(id_genre)], i8(2))
|
||||||
|
|
||||||
|
id3v1.embedded = true
|
||||||
|
|
||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Добавление изменённого тэга
|
// Добавление изменённого тэга
|
||||||
pub fn (id3v1 ID3v1) insert(mut audio File, position i8) []u8 {
|
pub fn (mut id3v1 ID3v1) insert(mut audio File, position i8) []u8 {
|
||||||
|
// if !id3v1.embedded {
|
||||||
bytes_tag := id3v1.to_bytes()
|
bytes_tag := id3v1.to_bytes()
|
||||||
// Уcтановка указателя на последний байт
|
// Уcтановка указателя на последний байт
|
||||||
audio.seek(0, os.SeekMode.end) or { panic(err) }
|
audio.seek(0, os.SeekMode.end) or { panic(err) }
|
||||||
@@ -105,6 +109,7 @@ pub fn (id3v1 ID3v1) insert(mut audio File, position i8) []u8 {
|
|||||||
mut all_bytes := audio.read_bytes(int(size))#[..position]
|
mut all_bytes := audio.read_bytes(int(size))#[..position]
|
||||||
|
|
||||||
all_bytes << bytes_tag
|
all_bytes << bytes_tag
|
||||||
|
// }
|
||||||
|
|
||||||
return all_bytes
|
return all_bytes
|
||||||
}
|
}
|
||||||
+4
-1
@@ -59,6 +59,9 @@ pub fn (mut tag ID3v23) add_frame(frame Frame) {
|
|||||||
.apic {
|
.apic {
|
||||||
tag.apic = frame
|
tag.apic = frame
|
||||||
}
|
}
|
||||||
|
.txxx {
|
||||||
|
tag.txxx = frame
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
tag.others << frame
|
tag.others << frame
|
||||||
}
|
}
|
||||||
@@ -96,7 +99,7 @@ pub fn (id3v23 ID3v23) to_v1() ID3v1 {
|
|||||||
album: id3v23.talb.data
|
album: id3v23.talb.data
|
||||||
track: id3v23.trck.data.split("/")[0]
|
track: id3v23.trck.data.split("/")[0]
|
||||||
year: id3v23.tyer.data
|
year: id3v23.tyer.data
|
||||||
comment: id3v23.comment.data
|
comment: id3v23.txxx.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+4
-1
@@ -35,6 +35,9 @@ pub fn (mut tag ID3v24) add_frame(frame Frame) {
|
|||||||
.apic {
|
.apic {
|
||||||
tag.apic = frame
|
tag.apic = frame
|
||||||
}
|
}
|
||||||
|
.txxx {
|
||||||
|
tag.txxx = frame
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
tag.others << frame
|
tag.others << frame
|
||||||
}
|
}
|
||||||
@@ -71,7 +74,7 @@ pub fn (id3v24 ID3v24) to_v1() ID3v1 {
|
|||||||
album: id3v24.talb.data
|
album: id3v24.talb.data
|
||||||
track: id3v24.trck.data.split('/')[0]
|
track: id3v24.trck.data.split('/')[0]
|
||||||
year: id3v24.tdrc.data
|
year: id3v24.tdrc.data
|
||||||
comment: id3v24.comment.data
|
comment: id3v24.txxx.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -17,8 +17,11 @@ pub struct ID3v1 {
|
|||||||
@[heap; minify]
|
@[heap; minify]
|
||||||
pub struct ID3v23 {
|
pub struct ID3v23 {
|
||||||
pub mut:
|
pub mut:
|
||||||
size u64 // Размер тэга
|
// Размер тэга
|
||||||
tit2 Frame // Название аудиодорожки
|
size u64
|
||||||
|
// Название аудиодорожки
|
||||||
|
tit2 Frame
|
||||||
|
|
||||||
tpe1 Frame // Автор
|
tpe1 Frame // Автор
|
||||||
tpe2 Frame // Исполнитель
|
tpe2 Frame // Исполнитель
|
||||||
talb Frame // Название альбома
|
talb Frame // Название альбома
|
||||||
@@ -27,9 +30,10 @@ pub struct ID3v23 {
|
|||||||
tcon Frame // Жанр
|
tcon Frame // Жанр
|
||||||
tcop Frame // Композитор (автор)
|
tcop Frame // Композитор (автор)
|
||||||
apic Frame // Обложка
|
apic Frame // Обложка
|
||||||
comment Frame // Комментарий
|
txxx Frame // Комментарий
|
||||||
unknown Frame // Затычка
|
unknown Frame // Затычка
|
||||||
others []Frame // Остальные фреймы
|
others []Frame // Остальные фреймы
|
||||||
|
encoded_header []u8
|
||||||
embedded bool // Присутвует ли тэг
|
embedded bool // Присутвует ли тэг
|
||||||
version u8 = 3 // Версия тэга
|
version u8 = 3 // Версия тэга
|
||||||
title string = "ID3"
|
title string = "ID3"
|
||||||
@@ -59,7 +63,7 @@ pub struct ID3v24 {
|
|||||||
// Обложка
|
// Обложка
|
||||||
apic Frame
|
apic Frame
|
||||||
// Комментарий
|
// Комментарий
|
||||||
comment Frame
|
txxx Frame
|
||||||
// Затычка
|
// Затычка
|
||||||
modified_frames []Frame
|
modified_frames []Frame
|
||||||
// Остальные фреймы
|
// Остальные фреймы
|
||||||
|
|||||||
@@ -105,8 +105,6 @@ pub fn encode_header[T](mut id3v T) {
|
|||||||
// Количество нулей в конце тэга
|
// Количество нулей в конце тэга
|
||||||
const tag_padding = 256
|
const tag_padding = 256
|
||||||
|
|
||||||
type ID3vType = ID3v23 | ID3v24
|
|
||||||
|
|
||||||
// Формируем полный полный тэг в байтах
|
// Формируем полный полный тэг в байтах
|
||||||
pub fn encode_embed_tags[T](mut id3v2 T) {
|
pub fn encode_embed_tags[T](mut id3v2 T) {
|
||||||
// Проход по всем полям стуктуры
|
// Проход по всем полям стуктуры
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import os
|
||||||
|
import metadata
|
||||||
|
|
||||||
|
// Проверка чтения id3v1
|
||||||
|
fn test_idv3v1() {
|
||||||
|
mut audio := os.open("./data/test_id3v1.mp3") or { panic(err) }
|
||||||
|
defer {
|
||||||
|
audio.close()
|
||||||
|
}
|
||||||
|
mut wav := metadata.Audio{}
|
||||||
|
wav.detect_tags(mut audio)
|
||||||
|
|
||||||
|
assert wav.id3v1.embedded == true, 'Тег показан false, а должен быть true'
|
||||||
|
assert wav.id3v23.embedded == false, 'Тег показан true, а должен быть false'
|
||||||
|
assert wav.id3v24.embedded == false, 'Тег показан true, а должен быть false'
|
||||||
|
|
||||||
|
last_bytes := metadata.get_bytes(mut audio, -128, 128)
|
||||||
|
wav.id3v1.get_metadata(last_bytes)
|
||||||
|
|
||||||
|
assert wav.id3v1.genre == "Rock"
|
||||||
|
assert wav.id3v1.title == "Test Title"
|
||||||
|
assert wav.id3v1.artist == "Test Artist"
|
||||||
|
assert wav.id3v1.album == "Test Album"
|
||||||
|
assert wav.id3v1.track == "6"
|
||||||
|
assert wav.id3v1.year == "2026"
|
||||||
|
assert wav.id3v1.comment == "Test comment"
|
||||||
|
assert wav.id3v1.embedded == true
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import os
|
||||||
|
import metadata
|
||||||
|
|
||||||
|
// Проверка чтения id3v23
|
||||||
|
fn test_idv3v23() {
|
||||||
|
mut audio := os.open("./data/test_id3v23.mp3") or { panic(err) }
|
||||||
|
defer {
|
||||||
|
audio.close()
|
||||||
|
}
|
||||||
|
mut wav := metadata.Audio{}
|
||||||
|
wav.detect_tags(mut audio)
|
||||||
|
|
||||||
|
assert wav.id3v1.embedded == false, 'Тег показан false, а должен быть true'
|
||||||
|
assert wav.id3v23.embedded == true, 'Тег показан true, а должен быть false'
|
||||||
|
assert wav.id3v24.embedded == false, 'Тег показан true, а должен быть false'
|
||||||
|
wav.id3v23.get_full_size(mut audio)
|
||||||
|
wav.id3v23.fill_tags(mut audio)
|
||||||
|
|
||||||
|
assert wav.id3v23.tit2.data == "Test Title"
|
||||||
|
assert wav.id3v23.tpe1.data == "Test Author"
|
||||||
|
assert wav.id3v23.tpe2.data == "Test Narator"
|
||||||
|
assert wav.id3v23.talb.data == "Test Album"
|
||||||
|
assert wav.id3v23.tyer.data == "2026"
|
||||||
|
assert wav.id3v23.trck.data == "6/7"
|
||||||
|
assert wav.id3v23.tcon.data == "Rock"
|
||||||
|
assert wav.id3v23.tcop.data == "Test"
|
||||||
|
assert wav.id3v23.txxx.data == "comment"
|
||||||
|
|
||||||
|
id3v1 := wav.id3v23.to_v1()
|
||||||
|
|
||||||
|
assert id3v1.genre == "Rock"
|
||||||
|
assert id3v1.title == "Test Title"
|
||||||
|
assert id3v1.artist == "Test Narator"
|
||||||
|
assert id3v1.album == "Test Album"
|
||||||
|
assert id3v1.track == "6"
|
||||||
|
assert id3v1.year == "2026"
|
||||||
|
assert id3v1.comment == "comment"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка чтения id3v24
|
||||||
|
fn test_idv3v24() {
|
||||||
|
mut audio := os.open("./data/test_id3v24.mp3") or { panic(err) }
|
||||||
|
defer {
|
||||||
|
audio.close()
|
||||||
|
}
|
||||||
|
mut wav := metadata.Audio{}
|
||||||
|
wav.detect_tags(mut audio)
|
||||||
|
|
||||||
|
assert wav.id3v1.embedded == false, 'Тег показан false, а должен быть true'
|
||||||
|
assert wav.id3v23.embedded == false, 'Тег показан true, а должен быть false'
|
||||||
|
assert wav.id3v24.embedded == true, 'Тег показан true, а должен быть false'
|
||||||
|
wav.id3v24.get_full_size(mut audio)
|
||||||
|
wav.id3v24.fill_tags(mut audio)
|
||||||
|
|
||||||
|
assert wav.id3v24.tit2.data == "Test Title"
|
||||||
|
assert wav.id3v24.tpe1.data == "Test Author"
|
||||||
|
assert wav.id3v24.tpe2.data == "Test Narator"
|
||||||
|
assert wav.id3v24.talb.data == "Test Album"
|
||||||
|
assert wav.id3v24.tdrc.data == "2026"
|
||||||
|
assert wav.id3v24.trck.data == "6/7"
|
||||||
|
assert wav.id3v24.tcon.data == "Rock"
|
||||||
|
assert wav.id3v24.tcop.data == "Test"
|
||||||
|
assert wav.id3v24.txxx.data == "comment"
|
||||||
|
|
||||||
|
id3v1 := wav.id3v24.to_v1()
|
||||||
|
|
||||||
|
assert id3v1.genre == "Rock"
|
||||||
|
assert id3v1.title == "Test Title"
|
||||||
|
assert id3v1.artist == "Test Narator"
|
||||||
|
assert id3v1.album == "Test Album"
|
||||||
|
assert id3v1.track == "6"
|
||||||
|
assert id3v1.year == "2026"
|
||||||
|
assert id3v1.comment == "comment"
|
||||||
|
}
|
||||||
|
|
||||||
Whitespace-only changes.
Reference in new issue
Block a user