module metadata import os { File } import encoding.iconv import utils // Определить кодировку utf-8 или cp-1251 @[inline] fn decode_bytes(bytes []u8) string { format := if utils.is_utf8(bytes) { "UTF-8" } else { "CP1251" } text := iconv.encoding_to_vstring(bytes, format) or { "Can't decode" } return text } // Извлечение метаданных из ID3 v1 pub fn (mut tag ID3v1) get_metadata(last_bytes []u8) { tag.title = decode_bytes(last_bytes[3..33]) tag.artist = decode_bytes(last_bytes[33..63]) tag.album = decode_bytes(last_bytes[63..92]) tag.year = decode_bytes(last_bytes[93..97]) tag.comment = decode_bytes(last_bytes[97..125]) tag.track = if last_bytes[125] == u8(0) {last_bytes[126].str()} else { "" } genre := Genre.from(last_bytes[127..128][0]) or { Genre.unknown } tag.genre = genre.str()} // Конвертировать ID3 v2.3 в ID3 v1 pub fn (id3v1 ID3v1) to_v23() ID3v23 { return ID3v23{ tcon: metadata.Frame{ data: id3v1.genre } tit2: metadata.Frame{ data: id3v1.title } tpe2: metadata.Frame{ data: id3v1.artist } talb: metadata.Frame{ data: id3v1.album } trck: metadata.Frame{ data: id3v1.track } tyer: metadata.Frame{ data: id3v1.year } comment: metadata.Frame{ data: id3v1.comment } } } // По ситуации отрезаем или добиваем нулями @[inline] fn cut_or_trim(data string, capacity i8) []u8 { mut final_data := []u8{len: capacity, init: 0} bytes_data := iconv.vstring_to_encoding(data, "CP1251") or { []u8{len: capacity} } diff := capacity - bytes_data.len if diff > 0 { for i, d in bytes_data { final_data[i] = d } } else { final_data = bytes_data.clone()[..capacity] } return final_data } // Перевести тэг в байты pub fn (id3v1 ID3v1) to_bytes() []u8 { mut bytes := []u8{cap: 128} bytes << "TAG".bytes() bytes << cut_or_trim(id3v1.title, i8(30)) bytes << cut_or_trim(id3v1.artist, i8(30)) bytes << cut_or_trim(id3v1.album, i8(30)) bytes << cut_or_trim(id3v1.year, i8(4)) bytes << cut_or_trim(id3v1.comment, i8(28)) // bytes << cut_or_trim(id3v1.track, i8(2)) 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 } bytes << u8(id_genre) // cut_or_trim([u8(id_genre)], i8(2)) return bytes } // Добавление изменённого тэга pub fn (id3v1 ID3v1) insert(mut audio File, position i8) []u8 { bytes_tag := id3v1.to_bytes() // Уcтановка указателя на последний байт audio.seek(0, os.SeekMode.end) or { panic(err) } // Положение указателя size := audio.tell() or { panic(err) } // Чтение всех байта, кроме последних 128 mut all_bytes := audio.read_bytes(int(size))#[..position] all_bytes << bytes_tag return all_bytes }