1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
mod music_meta;

use anyhow::{Context, Ok, Result};
use id3::TagLike;
use miniserde::json;
use ncm_core::{audio::Type as AudioType, decoder::Decoder};
use std::{
    io::{Cursor, Read, Write},
    vec,
};

use crate::music_meta::MusicMeta;

const TOOL_INFO: &str = include_str!("tool_info");

pub struct Encoder {
    pub data: Vec<u8>,
    pub meta: String,
}

impl Encoder {
    pub fn encode<R>(decoder: Decoder<R>) -> Result<Self>
    where
        R: Read,
    {
        let mut buffer = vec![];
        let audio_type = decoder.audio_type();

        let Decoder { comment, meta, image, mut audio, .. } = decoder;

        audio.read_to_end(&mut buffer)?;

        if meta.is_empty() {
            return Ok(Self { data: buffer, meta: "meta not found".into() });
        }

        let meta = String::from_utf8_lossy(&meta);
        let music_meta: MusicMeta =
            json::from_str(&meta).with_context(|| format!("failed to unpack: {meta}"))?;

        match audio_type {
            AudioType::Flac => {
                let mut tag = metaflac::Tag::read_from(&mut Cursor::new(&buffer))?;
                let data = metaflac::Tag::skip_metadata(&mut Cursor::new(&buffer));

                let vorbis_comment = tag.vorbis_comments_mut();
                vorbis_comment.set_title(vec![music_meta.music_name]);
                vorbis_comment.set_album(vec![music_meta.album]);
                vorbis_comment
                    .set_artist(music_meta.artist.into_iter().map(|ar| ar.0).collect::<Vec<_>>());
                vorbis_comment
                    .set("DESCRIPTION", vec![String::from_utf8_lossy(&comment), TOOL_INFO.into()]);
                vorbis_comment.set("TOOL", vec![TOOL_INFO]);

                if let Some(image) = image {
                    tag.add_picture(
                        image.mime_type(),
                        metaflac::block::PictureType::CoverFront,
                        image.into_data(),
                    );
                }
                buffer.clear();
                tag.remove_blocks(metaflac::BlockType::Padding);
                tag.write_to(&mut buffer)?;
                buffer.write_all(&data)?;
            }
            AudioType::Mp3 => {
                let mut tag = id3::Tag::read_from2(&mut Cursor::new(&buffer))?;
                let mut data_reader = Cursor::new(&buffer);
                id3::Tag::skip(&mut data_reader)?;

                tag.set_title(music_meta.music_name);
                tag.set_album(music_meta.album);
                tag.set_artist(
                    music_meta.artist.into_iter().map(|ar| ar.0).collect::<Vec<_>>().join("/"),
                );
                tag.add_frame(id3::frame::Comment {
                    lang: "eng".into(),
                    description: "".into(),
                    text: String::from_utf8_lossy(&comment).into(),
                });
                tag.set_text("TSSE", TOOL_INFO);
                tag.set_text("TENC", TOOL_INFO);
                if let Some(image) = image {
                    tag.add_frame(id3::frame::Picture {
                        mime_type: image.mime_type().into(),
                        picture_type: id3::frame::PictureType::CoverFront,
                        description: "Cover".into(),
                        data: image.into_data(),
                    });
                }

                let mut result = vec![];
                tag.write_to(&mut result, id3::Version::Id3v24)?;
                data_reader.read_to_end(&mut result)?;
                buffer = result;
            }
            _ => {}
        }

        Ok(Self { data: buffer, meta: meta.into() })
    }
}