Files
id3_editor/metadata/utils.v
T
2026-10-07 23:03:27 +03:00

139 lines
4.6 KiB
V
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
module metadata
import os
pub fn (mut audio Audio) detect_tags(mut data os.File) {
// ? --- Проверка версии ID3v1 ---
last_bytes := get_bytes(mut data, -128, 3)
if last_bytes[0..3].bytestr() == "TAG" {
audio.id3v1.embedded = true
}
// ===============================
// ? --- Проверка версии ID3v23.3 ---
first_ten_bytes := get_bytes(mut data, 0, 4)
if first_ten_bytes[..3].bytestr() == "ID3" {
if first_ten_bytes[3] == 3 {
audio.id3v23.embedded = true
} else if first_ten_bytes[3] == 4 {
// Проверка версии ID3v23.4
audio.id3v24.embedded = true
}
}
// ===============================
}
pub fn get_bytes(mut audio os.File, position int, size int) []u8 {
// > ---------Работа с расположением указателя--------------
// Ставим указатель на 128 байт с конца
if position < 0 {
audio.seek(position, os.SeekMode.end) or { panic(err) }
}
// Получаем номер 128 байта с конца
pos := audio.tell() or { panic(err) }
// Читаем байты с конца
last_bytes := audio.read_bytes_at(size, u64(pos))
audio.seek(0, os.SeekMode.start) or { panic(err) }
// =========================================================
return last_bytes
}
pub fn dump_data[T](mut tag T, mut audio os.File) {
mut current_frame := &Frame{}
// Самая первая позиция
mut start_position := u64(10)
// Получаем вне возможные байты
all_tag_bytes := get_bytes(mut audio, 10, int(tag.size + start_position))
// Конец тэга с учётом 10 байт заголовка
tag_end := tag.size + 10
for start_position + 10 <= tag_end {
// Нулевой байт вместо названия фрейма — начался запас нулей
if all_tag_bytes[start_position] == 0 {
break
}
current_frame.fill(all_tag_bytes, start_position, tag.version)
start_position = current_frame.end
tag.add_frame(current_frame)
}
}
pub fn get_current_tag_size[T](mut tag T, mut audio os.File) {
// Первые 10 байт тэга
first_ten_bytes := get_bytes(mut audio, 0, 10)
tag.size = (u64(first_ten_bytes[6]) << 21) | (u64(first_ten_bytes[7]) << 14) | (u64(first_ten_bytes[8]) << 7) | u64(first_ten_bytes[9])
}
// Кодирование размера заголовка со всеми тэгами
pub fn encode_header_size(size u64, idv3_version u8) []u8 {
stride := if idv3_version == 3 {
[u64(24), u64(16), u64(8), u64(0xFF)]
} else {
[u64(21), u64(14), u64(7), u64(0x7F)]
}
mut encoded_size := []u8{len: 4}
encoded_size[0] = u8((size >> stride[0]) & stride[3])
encoded_size[1] = u8((size >> stride[1]) & stride[3])
encoded_size[2] = u8((size >> stride[2]) & stride[3])
encoded_size[3] = u8(size & stride[3])
return encoded_size
}
// Кодирование первых 10 байт ID3
pub fn encode_header[T](mut id3v T) {
// Байты для символов "ID3"
id3v.encoded_header << [u8(73), u8(68), u8(51)]
// Версия IDv3
id3v.encoded_header << [id3v.version]
// Минорная версия и спец. флаги
id3v.encoded_header << []u8{len: 2}
// Размер всего тэга в заголовке всегда syncsafe (по 7 бит в байте), в том числе в v2.3
id3v.encoded_header << metadata.encode_header_size(id3v.size, 4)
}
// Количество нулей в конце тэга
const tag_padding = 256
// Формируем полный полный тэг в байтах
pub fn encode_embed_tags[T](mut id3v2 T) {
// Проход по всем полям стуктуры
mut tag_bytes := []u8{}
// Именно T.fields: с id3v2.fields V пропускает поля, которых нет в другом типе (tyer в ID3v24)
$for field in T.fields {
$if field.typ is Frame {
// Читаются только заполненные тэги
if id3v2.$(field.name).cur_size > 0 {
if id3v2.$(field.name).name.to_lower() != "apic" {
// Кодируем значения полей
tag_bytes << id3v2.$(field.name).get_encoded_frame_tag(id3v2.version)
} else {
// Картинка не трогается
tag_bytes << id3v2.$(field.name).apic or { []u8{} }
}
}
}
}
// Запас нулей чтобы не пересчитывать весь тэг при маленьком редактировании
tag_bytes << []u8{len: tag_padding}
// Размер считается по уже закодированным фреймам
id3v2.size = u64(tag_bytes.len)
id3v2.encoded_header = []u8{}
encode_header(mut id3v2)
id3v2.encoded_header << tag_bytes
}