File size: 3,604 Bytes
3deab67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d7c6285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""受け取り方。ZIPでも音声ファイル単体でも、同じように扱えること。"""

import struct
import sys
import wave
import zipfile
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

import pipeline as pl  # noqa: E402


def make_wav(path: Path, seconds: float = 0.2) -> Path:
    path.parent.mkdir(parents=True, exist_ok=True)
    with wave.open(str(path), "wb") as f:
        f.setnchannels(1)
        f.setsampwidth(2)
        f.setframerate(16000)
        f.writeframes(b"".join(
            struct.pack("<h", (i % 100) * 50) for i in range(int(16000 * seconds))
        ))
    return path


def test_音声ファイルをそのまま受け取れる(tmp_path):
    src = make_wav(tmp_path / "受け取り" / "商談_A社.wav")
    found = pl.collect_audio([src], tmp_path / "audio")

    assert [name for name, _, _ in found] == ["商談_A社.wav"]
    assert found[0][1].exists()
    assert found[0][2]                      # 録音日時が入る


def test_ZIPと音声ファイルを混ぜても良い(tmp_path):
    wav = make_wav(tmp_path / "受け取り" / "単体.wav")

    inner = make_wav(tmp_path / "元" / "ZIPの中.wav")
    zip_path = tmp_path / "受け取り" / "まとめ.zip"
    with zipfile.ZipFile(zip_path, "w") as zf:
        zf.write(inner, "ZIPの中.wav")

    found = pl.collect_audio([zip_path, wav], tmp_path / "audio")
    assert sorted(name for name, _, _ in found) == ["ZIPの中.wav", "単体.wav"]


def test_同じ名前でも上書きしない(tmp_path):
    a = make_wav(tmp_path / "一つ目" / "同じ名前.wav")
    b = make_wav(tmp_path / "二つ目" / "同じ名前.wav")

    found = pl.collect_audio([a, b], tmp_path / "audio")
    paths = {path for _, path, _ in found}
    assert len(paths) == 2                  # 別々のファイルとして残る


def test_音声でないものは無視する(tmp_path):
    doc = tmp_path / "受け取り" / "資料.pdf"
    doc.parent.mkdir(parents=True, exist_ok=True)
    doc.write_bytes(b"%PDF-1.4")

    assert pl.collect_audio([doc], tmp_path / "audio") == []


def test_危ないファイル名は無害にする():
    assert pl.safe_filename("../../etc/passwd") == "passwd"
    assert "/" not in pl.safe_filename("a/b/c.wav")
    assert pl.safe_filename("") == "音声"
    assert pl.safe_filename("a:b*c?.m4a").endswith(".m4a")


def test_再生用の音声を作れる(tmp_path):
    """どのブラウザでも鳴らせるよう mp3 に揃える。"""
    src = make_wav(tmp_path / "元.wav", seconds=1.0)
    out = pl.to_playback(src, tmp_path / "再生用.mp3")

    assert out is not None and out.exists()
    assert out.stat().st_size > 0
    head = out.read_bytes()[:3]
    assert head == b"ID3" or head[:2] in (b"\xff\xfb", b"\xff\xf3")   # mp3の目印


def test_元の音質を落とさない(tmp_path):
    """聞き取りやすさを優先。周波数もチャンネル数も元のまま。"""
    src = make_wav(tmp_path / "元.wav", seconds=1.0)
    out = pl.to_playback(src, tmp_path / "再生用.mp3")

    assert out is not None
    assert abs(pl.probe_duration(out) - pl.probe_duration(src)) < 0.2   # 長さが変わらない


def test_すでにmp3ならそのまま使う(tmp_path):
    """変換を重ねるほど音は悪くなるので、作り直さない。"""
    src = pl.to_playback(make_wav(tmp_path / "元.wav", seconds=1.0), tmp_path / "元.mp3")
    out = pl.to_playback(src, tmp_path / "再生用.mp3")

    assert out is not None
    assert out.read_bytes() == src.read_bytes()      # 中身がそのまま